一. GDB简介及命令列表
本文写给主要工作在Windows操作系统下而又需要开发一些跨平台软件的程序员朋友,以及程序爱好者。
GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。
GDB中的命令固然很多,但我们只需掌握其中十个左右的命令,就大致可以完成日常的基本的程序调试工作。
命令 | 解释 | 示例 |
file <文件名> | 加载被调试的可执行程序文件。 因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径。 | (gdb) file gdb-sample |
r | Run的简写,运行被调试的程序。 如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。 | (gdb) r |
c | Continue的简写,继续执行被调试程序,直至下一个断点或程序结束。 | (gdb) c |
b <行号> b <函数名称> b *<函数名称> b *<代码地址> d [编号] | b: Breakpoint的简写,设置断点。两可以使用“行号”“函数名称”“执行地址”等方式指定断点位置。 其中在函数名称前面加“*”符号表示将断点设置在“由编译器生成的prolog代码处”。如果不了解汇编,可以不予理会此用法。 d: Delete breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。 | (gdb) b 8 (gdb) b main (gdb) b *main (gdb) b *0x804835c (gdb) d |
s, n | s: 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数; n: 执行一行源程序代码,此行代码中的函数调用也一并执行。 s 相当于其它调试器中的“Step Into (单步跟踪进入)”; 这两个命令必须在有源代码调试信息的情况下才可以使用(GCC编译时使用“-g”参数)。 | (gdb) s (gdb) n |
si, ni | si命令类似于s命令,ni命令类似于n命令。所不同的是,这两个命令(si/ni)所针对的是汇编指令,而s/n针对的是源代码。 | (gdb) si (gdb) ni |
p <变量名称> | Print的简写,显示指定变量(临时变量或全局变量)的值。 | (gdb) p i (gdb) p nGlobalVar |
display ... undisplay <编号> | display,设置程序中断后欲显示的数据及其格式。 例如,如果希望每次程序中断后可以看到即将被执行的下一条汇编指令,可以使用命令 “display /i $pc” 其中 $pc 代表当前汇编指令,/i 表示以十六进行显示。当需要关心汇编代码时,此命令相当有用。 undispaly,取消先前的display设置,编号从1开始递增。 | (gdb) display /i $pc (gdb) undisplay 1 |
i | Info的简写,用于显示各类信息,详情请查阅“help i”。 | (gdb) i r |
q | Quit的简写,退出GDB调试环境。 | (gdb) q |
help [命令名称] | GDB帮助命令,提供对GDB名种命令的解释说明。 如果指定了“命令名称”参数,则显示该命令的详细说明;如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。 | (gdb) help display |
二. 使用GDB调试程序
要使用GDB调试程序,在编译程序的时候需要加入 "-g"选项,例如:
$gcc –g –o helloworld helloworld.c |
1. gdb加载程序
命令格式:"gdb 要调试的文件全名"
$gdb helloworld |
2. 设置程序的输入参数
命令格式:"set args 参数值1 参数值2 … "
通常可执行文件在运行时需要输入参数,可以用上面命令在GDB中向可执行文件输入参数。例如,下面的命令"set args 3"表示向加载的程序中输入的参数为3。
(gdb) set args 3 |
3. 打印代码内容
命令格式:"list 开始的行号"
命令list用于列出已加载程序的源代码。例如,"list 1"表示从第一行开始列出代码,每次按下Enter键后顺序向下列出代码。
(gdb) list 1 |
4. 设置断点
命令格式:"b 行号/函数名"
例如,在源程序的第10行设置一个断点:
(gdb) b 10 |
程序在断点处暂停后,按"c"键继续运行。
5.运行程序
命令格式:"run (后面可以加上传递给程序的参数)"
(gdb) run |
6. 显示变量
命令格式:"display 变量"
程序运行到断点处暂停,此时可以使用display命令显示变量的值,以后每次停止都会显示此变量的值。例如,显示变量i的值:
(gdb) display i //每次停止时都会显示变量i的值 |
7. 修改变量的值
命令格式:"set 变量名=值"
例如,修改变量i的值为6:
(gdb) set i=6 |
8. 退出GDB
命令格式:"q"
(gdb) q |
三. 常用命令详解
1. 执行程序
用GDB执行程序可以使用 gdb program 的方式,program是程序的程序名。假如在启动GDB的时候没有选择程序名称,可以在GDB启动后使用file program的方法启动:
(gdb) file test |
2. 参数设置和显示
使用set args命令来设置发送给程序的参数;使用show args 命令显示其默认的参数:
(gdb) set args 1 2 3 (gdb) show args Argument list to give program being debugged when it is started is "1 2 3". |
3. 打印程序源代码
打印文件代码的命令时list,简写为l。
(gdb) list line1, line2 |
打印从line1到line2之间的代码,如果不输入参数,默认从当前行开始打印。
(gdb) l 1 #include<sys/stat.h> 2 #include<sys/types.h> 3 #include<unistd.h> 4 #include<stdio.h> 5 6 int main(void) 7 { 8 struct stat st; 9 10 if(-1==stat("test.txt",&st)) (gdb) 11 { 12 printf("get file status failure\n"); 13 return -1; 14 } 15 printf("此文件的大小:%d\n",st.st_size); 16 printf("此文件的租后修改时间:%d\n",st.st_mtime); 17 printf("此文件的节点:%d\n",st.st_ino); 18 printf("此文件的保护模式:%d\n",st.st_mode); 19 } |
4. 打印数据
打印变量或者表达式的值可以使用print命令,简写为p。
(gdb) print 变量名(或表达式) |
5. 断点
设置断点的命令时break,简写为b。有3种设置方式:
-
b 行号:程序停止在设定的行之前
-
b 函数名称:程序停止在设定的函数之前
-
b 行号或者函数 if条件:这是条件断点,如果条件为真,则程序在到达指定行或函数时停止。
(1)设置断点
如果程序由很多的文件构成,在设置断点时要指定文件名:
(gdb) b man.c 10 (gdb) b subfunction.c 20 |
要设置一个条件断点,可以利用b if 命令,在调试循环代码段时这样的设置比较有用,省略了大量的手动调试,例如,在一个循环函数中,在i=2时设置断点:
(gdb) b 46 if i==2 |
(2)显示当前GDB的断点信息
使用info break命令显示当前断点的信息
(gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x080484b1 in main at filestat.c:15 breakpoint already hit 1 time |
(3)删除指定的断点
删除断点使用 delete b 断点编号 命令。下面的命令会删除第8个断点:
(gdb) delete b 8 |
(4)禁止断点
禁止断点使用 disable b 断点编号 命令。下面的命令会禁用第9个断点:
(gdb) disable b 9 |
(5)允许断点
允许断点使用 enable b 断点编号 命令。下面的命令会禁用第9个断点:
(gdb) enable b 9 |
(6)清除断点
一次性的清除某行处的所有断点使用命令 clean 行号。下面的命令会清除在源代码中第32行的所设置的断点:
(gdb) clean 32 |
6. 变量类型检测
在调试过程中有需要查看变量类型的情况,需要使用命令whatis 和ptype等。
-
whatis 变量名 :查看变量的类型,只能查看变量的类型名称,不能得到类型的详细信息。
(gdb) whatis st type = struct stat |
-
ptype 变量名:查看变量类型的详细信息。
(gdb) ptype st type = struct stat { __dev_t st_dev; short unsigned int __pad1; __ino_t st_ino; __mode_t st_mode; __nlink_t st_nlink; __uid_t st_uid; __gid_t st_gid; __dev_t st_rdev; short unsigned int __pad2; __off_t st_size; __blksize_t st_blksize; __blkcnt_t st_blocks; struct timespec st_atim; struct timespec st_mtim; struct timespec st_ctim; long unsigned int __unused4; long unsigned int __unused5; } |
7. 单步调试
单步跟踪:next 简写为n
进入函数体:step 简写为 s
退出已进入的函数:finish
(gdb) n (gdb) s (gdb) finish |
8. 设置监测点
display命令可以设置监测变量的值,当遇到断点时,会显示监测变量的值。
(gdb) display i i=1 |
9. 调用路径
backtrace命令可以打印函数的调用路径,提供前向跟踪功能,此命令对跟踪函数很有用处。Backtrace打印一个顺序列表,函数从最近到最远的调用过程,包含调用函数和其中的参数。简写为bt。
10. 信息info
Info命令可获得当前命令的信息,例如获得断点的情况,参数的设置情况等。
例如:
(gdb) info frame //查看栈信息 Stack level 0, frame at 0xbffff760: eip = 0x80484c5 in main (filestat.c:16); saved eip 0xb7e88e46 source language c. Arglist at 0xbffff758, args: Locals at 0xbffff758, Previous frame's sp is 0xbffff760 Saved registers: ebp at 0xbffff758, eip at 0xbffff75c |
(gdb) info locals //查看所有局部变量 |
11. 多线程
多线程是现代程序中经常采用的编程方法,而多线程由于执行过程中的调度随机性,不好调试。多线程调试主要有两点:先获得线程的ID好,然后转到该线程进行调试。
Info thread 命令列出当前进程中的线程号,其中最前面的为调试用的ID。
thread id 命令进入需要调试的线程。
(gdb) info thread Id Target Id Frame * 1 process 7854 "filestat" main () at filestat.c:15 |
12. 反汇编
Disassamble命令打印指定处的汇编代码,例如printf的汇编代码如下:
(gdb) disassemble printf Dump of assembler code for function printf: 0xb7ebbc80 <+0>: push %ebp 0xb7ebbc81 <+1>: mov %esp,%ebp 0xb7ebbc83 <+3>: push %ebx 0xb7ebbc84 <+4>: call 0xb7f85bc6 0xb7ebbc89 <+9>: add $0x11a36b,%ebx 0xb7ebbc8f <+15>: sub $0xc,%esp 0xb7ebbc92 <+18>: lea 0xc(%ebp),%eax 0xb7ebbc95 <+21>: mov %eax,0x8(%esp) 0xb7ebbc99 <+25>: mov 0x8(%ebp),%eax 0xb7ebbc9c <+28>: mov %eax,0x4(%esp) 0xb7ebbca0 <+32>: mov -0x7c(%ebx),%eax 0xb7ebbca6 <+38>: mov (%eax),%eax 0xb7ebbca8 <+40>: mov %eax,(%esp) 0xb7ebbcab <+43>: call 0xb7eb17e0 <vfprintf> 0xb7ebbcb0 <+48>: add $0xc,%esp 0xb7ebbcb3 <+51>: pop %ebx 0xb7ebbcb4 <+52>: pop %ebp 0xb7ebbcb5 <+53>: ret End of assembler dump. |
13. help帮助信息
用法类似于man。例如想查看命令c的信息:
(gdb) help c Continue program being debugged, after signal or breakpoint. If proceeding from breakpoint, a number N may be used as an argument, which means to set the ignore count of that breakpoint to N - 1 (so that the breakpoint won't break until the Nth time it is reached).
If non-stop mode is enabled, continue only the current thread, otherwise all the threads in the program are continued. To continue all stopped threads in non-stop mode, use the -a option. Specifying -a and an ignore count simultaneously is an error. |