linux下的gdb本地调试及命令解析

GDB是GNU开源组织发布的一个强大的linux下的程序调试工具,可完成如下的调试任务: 
* 设置断点; 
* 监视程序变量的值; 
* 程序的单步执行; 
* 修改变量的值。 
在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 makefile 中如下定义 CFLAGS 变量: 
CFLAGS = -g 
运行 gdb 调试程序时通常使用如下的命令: 
gdb progname 
2015-08-26 09:16:29屏幕截图.png
在 gdb 提示符处键入help,将列出命令的分类,主要的分类有: 
* aliases:命令别名 
* breakpoints:断点定义; 
* data:数据查看; 
* files:指定并查看文件; 
* internals:维护命令; 
* running:程序执行; 
* stack:调用栈查看; 
* statu:状态查看; 
* tracepoints:跟踪程序执行。 
键入 help 后跟命令的分类名,可获得该类命令的详细清单。 
2015-08-26 09:18:18屏幕截图.png
常用命令
一list(l)查看源文件
list(l) 默认从代码开头 一次显示10行,若再次使用l会显示接下来的10行
list(l)[行号A] 从第A行开始显示
list(l)[函数名A] 显示函数A的源代码
list(l)[起始行],[结束行] 显示区间代码
2015-08-26 09:19:29屏幕截图.png
2015-08-26 09:20:14屏幕截图.png
2015-08-26 09:21:04屏幕截图.png
二run(r) 运行函数直到断点处停住
run(r)[参数1][参数2][参数3].....参数是传入main函数的参数
2015-08-26 11:12:22屏幕截图.png
三 break(b)设置断点

在gdb中用break命令来设置断点,设置断点的方法包括:

  • break <function>
在进入指定函数时停住,C++中可以使用class::function或function(type, type)格式来指定函数名。
  • break <linenum>
在指定行号停住。
  • break +offset / break -offset
在当前行号的前面或后面的offset行停住,offiset为自然数。
  • break filename:linenum
在源文件filename的linenum行处停住。
  • break filename:function
在源文件filename的function函数的入口处停住。
  • break *address
在程序运行的内存地址处停住。
  • break
break命令没有参数时,表示在下一条指令处停住。
  • break ... if <condition>

“...”可以是上述的break <linenum>break +offset / break –offset中的参数,condition表示条件,在条件成立时停住。比如在循环体中,可以设置break if i=100,表示当i为100时停住程序。

tbreak 设置临时断点 到达后自动删除 用法同break

注:断点管理

1. 显示当前gdb的断点信息: 
(gdb) info break 
他会以如下的形式显示所有的断点信息: 
Num Type Disp Enb Address What 
1 breakpoint keep y 0x000028bc in init_random at qsort2.c:155 
2 breakpoint keep y 0x0000291c in init_organ at qsort2.c:168 
(gdb) 

2015-08-26 11:06:46屏幕截图.png

2.删除指定的某个断点: 
(gdb)delete breakpoint 1 
该命令将会删除编号为1的断点,如果不带编号参数,将删除所有的断点 
(gdb) delete breakpoint 
3.禁止使用某个断点 
(gdb)disable breakpoint 1 
该命令将禁止断点 1,同时断点信息的 (Enb)域将变为 n 
4.允许使用某个断点 
(gdb)enable breakpoint 1 
该命令将允许断点 1,同时断点信息的 (Enb)域将变为 y 
5.清除原文件中某一代码行上的所有断点 
(gdb)cleannumber 
注:number 为原文件的某个代码行的行号 

例如:

2015-08-26 09:23:10屏幕截图.png

2015-08-26 09:22:57屏幕截图.png

四显示数据

1,print(p)命令

有一下几种格式

print(p) 变量名/数组名   打印变量值/数组所有值

print(p)函数调用  打印函数执行结果

print(p)指针 打印指针地址和指向的内容

print(p)表达式

print(p)/输出的格式 表达式

在表达式中,有几种GDB所支持的操作符,它们可以用在任何一种语言中,“@”是一个和数组有关的操作符,“::”指定一个在文件或是函数中的变量,“{<type>} <addr>”表示一个指向内存地址<addr>的类型为type的一个对象。

当需要查看一段连续内存空间的值的时间,可以使用GDB的“@”操作符,“@”的左边是第一个内存地址,“@”的右边则是想查看内存的长度。例如如下动态申请的内存:

int *array = (int *) malloc (len * sizeof (int));

在GDB调试过程中这样显示出这个动态数组的值:

p *array@len

print的输出格式包括:

  • x 按十六进制格式显示变量。
  • d 按十进制格式显示变量。
  • u 按十六进制格式显示无符号整型。
  • o 按八进制格式显示变量。
  • t 按二进制格式显示变量。
  • a 按十六进制格式显示变量。
  • c 按字符格式显示变量。
  • f 按浮点数格式显示变量。
注:当用GDB的print查看程序运行时的数据时,每一个print都会被GDB记录下来。GDB会以$1,$2,$3 …这样的方式为每一个print命令编号。我们可以使用这个编号访问以前的表达式,如$1
值的历史成分 
(gdb)print $1 ($1为历史记录变量,在以后可以直接引用 $1 的值
2015-08-26 09:26:17屏幕截图.png
2015-08-26 09:31:45屏幕截图.png
2 watch命令
watch一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。我们有下面的几种方法来设置观察点:   watch <expr> :为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。 rwatch <expr> :当表达式(变量)expr被读时,停住程序。 awatch <expr> :当表达式(变量)的值被读或被写时,停住程序。 info watchpoints :列出当前所设置了的所有观察点。 下面演示了观察i并在连续运行next时一旦发现i变化,i值就会显示出来的过程:

3whatis 命令可以显示某个变量的类型 
(gdb) whatis p 
type = int * 
2015-08-26 11:14:19屏幕截图.png
4examine命令

我们可以使用examine命令(缩写为x)来查看内存地址中的值。examine命令的语法如下所示:

x/<n/f/u><addr>

<addr>表示一个内存地址。“x/”后的n、f、u都是可选的参数,

n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容;

f 表示显示的格式,

    如果地址所指的是字符串,那么格式可以是s,

    如果地址是指令地址,那么格式可以是i;

u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4字节。u参数可以被一些字符代替:

                        b表示单字节,

                        h表示双字节,

                        w表示四字节,

                        g表示八字节。

当我们指定了字节长度后,GDB会从指定的内存地址开始,读写指定字节,并把其当作一个值取出来。n、f、u这3个参数可以一起使用,例如命令“x/3uh 0x54320”表示从内存地址0x54320开始以双字节为1个单位(h)、16进制方式(u)显示3个单位(3)的内存。 == 

2015-08-26 11:16:02屏幕截图.png

五 continue(n)

继续执行 直到结束或下一个断点处 可配合ignore命令使用

    ignore[断点号]<num> 执行时忽略对应断点num次


六单步执行命令

next(n)的单步不会进入函数的内部

step(缩写s)命令则在单步执行一个函数时,会进入其内部

2015-08-26 11:13:21屏幕截图.png

单步执行的更复杂用法包括:
  • step <count>

单步跟踪,如果有函数调用,则进入该函数(进入函数的前提是,此函数被编译有debug信息)。step后面不加count表示一条条地执行,加表示执行后面的count条指令,然后再停住。

  • next <count>
单步跟踪,如果有函数调用,它不会进入该函数。同样地,next后面不加count表示一条条地执行,加表示执行后面的count条指令,然后再停住。
  • set step-mode
set step-mode on用于打开step-mode模式,这样,在进行单步跟踪时,程序不会因为没有debug信息而不停住,这个参数的设置可便于查看机器码。set step-mod off用于关闭step-mode模式。
  • finish
运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。
  • until (缩写u)
一直在循环体内执行单步,退不出来是一件令人烦恼的事情,until命令可以运行程序直到退出循环体。
  • stepi(缩写si)和nexti(缩写ni)
stepi和nexti用于单步跟踪一条机器指令,一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令。 另外,运行“display/i $pc”命令后,单步跟踪会在打出程序代码的同时打出机器指令,即汇编代码。

set命令

修改变量的值
set 变量名=值
2015-08-26 11:17:32屏幕截图.png
修改寄存器:
修改内存:(gdb) set {unsigned int}0x8048a51=0x0

八quit 退出命令 call 强制调用函数
2015-08-26 09:33:37屏幕截图.png
九 info命令
显示与该程序有关的各种信息

2015-08-26 11:20:54屏幕截图.png

nfo registers (查看除了浮点寄存器以外的寄存器)

info all-registers (查看所有寄存器,包括浮点寄存器)

info registers <regname ...> (查看所指定的寄存器) 

要查看断点信息,可以使用如下命令:info break 

列出当前所设置的所有观察点,使用如下命令:info watchpoints

 查看有哪些信号正在被GDB检测,使用如下命令:info signals info handle

 也可以使用info line命令来查看源代码在内存中的地址。info threads可以看多线程。info line后面可以跟行号、函数名、文件名:行号、文件名:函数名等多种形式

file FILE 装载指定的可执行文件进行调试。 
help NAME 显示指定命令的帮助信息。 
info break 显示当前断点清单,包括到达断点处的次数等。 
info files 显示被调试文件的详细信息。 
info func 显示所有的函数名称。 
info local 显示当函数中的局部变量信息。 
info prog 显示被调试程序的执行状态。 
info var 显示所有的全局和静态变量名称。 

十多线程调试
基本命令:

info threads 显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。 前面有*的是当前调试的线程。

thread ID 切换当前调试的线程为指定ID的线程。

break thread_test.c:123 thread all 在所有线程中相应的行上设置断点

thread apply ID1 ID2 command 让一个或者多个线程执行GDB命令command。 

thread apply all command 让所有被调试线程执行GDB命令command。

set scheduler-locking off|on|step 估计是实际使用过多线程调试的人都可以发现,在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试程序执行呢?通过这个命令就可以实现这个需求。off 不锁定任何线程,也就是所有线程都执行,这是默认值。 on 只有当前被调试程序会执行。 step 在单步的时候,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行。

gdb对于多线程程序的调试有如下的支持:

  • 线程产生通知:在产生新的线程时, gdb会给出提示信息

2015-08-26 09:33:07屏幕截图.png

(gdb) r
Starting program: /root/thread 
[New Thread 1073951360 (LWP 12900)] 
[New Thread 1082342592 (LWP 12907)]---以下三个为新产生的线程
[New Thread 1090731072 (LWP 12908)]
[New Thread 1099119552 (LWP 12909)]

  • 查看线程:使用info threads可以查看运行的线程。

(gdb) info threads
  Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
  3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
  2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)

注意,行首的蓝色文字为gdb分配的线程号,对线程进行切换时,使用该该号码,而不是上文标出的绿色数字。

另外,行首的红色星号标识了当前活动的线程

  • 切换线程:使用 thread THREADNUMBER 进行切换,THREADNUMBER 为上文提到的线程号。下例显示将活动线程从 1 切换至 4。

(gdb) info threads
   4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
   3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
   2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0   0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
   3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
   2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
   1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)

 

后面就是直接在你的线程函数里面设置断点,然后continue到那个断点,一般情况下多线程的时候,由于是同时运行的,最好设置 set scheduler-locking on

这样的话,只调试当前线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值