1.gcc编译,首先使用编译选项-g(在编译的时候产生调试信息)。
2.进入gdb的方法:
(1)gdb a.out
(2)gdb进入调试界面,然后输入file a.out
3.list命令
list命令用于显示源代码,第一次的时候从起始位置开始显示,每次使用list都会接着显示后续的代码,其中list命令每次显示十行代码。
list n显示从第行开始十行代码。
list function_name显示以function_name的函数为中心的10行代码。
list - 显示刚才打印过的源代码之前的代码。
list <function> 显示函数名为 function 的函数的源代码
set listsize <count> 设置一次显示源代码的行数
show listsize 查看当前 listsize 的设置
list <first>,<last> 显示从 first 行到 last 行之间的源代码
list ,<last> 显示从当前行到 last 行之间的源代码
list + 往后显示源代码
4.break
break location:在location位置设置断点,location可以为某一行,某函数名或者其它结构的地址,gdb会在执行该位置的代码之前停下来,break后加数字代表行号。
使用delete breakpoints 断点号 删除断点,这里的断点号表示的是第几个断点,clear n表示清除第n行的断点,因此clear 10等同于delete breakpoints 1,disable/enable n表示使得编号为n的断点暂时失效或有效。delete breakpoints可以删除所有的断点。
可使用info查看断点相关的信息
其中info breakpoints可以显示出所有的断点信息。
删除断点以及监视点,delete命令删除断点和监视点,简写为d。格式为delete <断点编号>,表示删除编号指示的断点或监视点,编号可以用命令 info b 查看。
clear命令删除已定义的断点。可用命令包括:
clear <函数名>
clear <行号>
clear <文件名:行号>
clear <文件名:函数名>
disable命令禁用断点。命令格式如下:
disable:禁用所有断点。
disable <断点编号>:禁用指定断点。
disable display <显示编号>:禁用 display 命令定义的自动显示。
disable mem <内存显示>:禁用 mem 命令定义的内存区域。
enable命令用于启用断点。命令格式如下:
enable
enable <断点编号>
enable once <断点编号>:使指定的断点只启用一次。
enable delete <断点编号>
enable display <显示编号>
enable mem <内存显示>
5.display命令
查看参数的值,display以后gdb会自动进行展示,可以使用delete display来删除所有的自动展示
6.step及next命令
step可使得程序逐条执行,即执行完一条语句然后在下一跳语句前停下来,等待用户的命令,一般使用step命令是,可使用display或者watch命令查看变量的变化,从而判断程序行为是否符合要求,当下一条指令为函数时,s进入函数内部,在其第一条语句前停下来,step n,next n 表示连续但不执行n条指令,如果期间遇到断点,则停下来,此时可以用bt命令(backtrace,显示栈信息)查看调用堆栈。(next把函数当作一条简单的语句,s会进入函数体内)
7.watch
watch可设置观察点(watchpoint)。使用观察点可以使得当某表达式的值发生变化时,程序暂停执行。可以通过info watchpoints查看所有的watchpoint。同样可以delete掉watchpoint,watchpoint同样作为一种断点的存在,所以跟breakpoint有同样的性质。
watch <表达式>表达式发生变化时暂停运行。
awatch <表达式>表达式被访问、改变时暂停运行。
rwatch <表达式>表达式被访问时暂停运行。
设置监视点可能会降低运行速度。
8.print命令
用于打印变量的值。简写p
9.set var name=value
用于在程序运行过程中动态的改变变量的值。
10.backtrace
这是一个与函数调用相关的命令,意思是查看调用堆栈,可以使用frame查看堆栈中的某一帧信息。意思就是逐层查看调用堆栈。
frame n可以用来查看n号栈帧
如果我们想从当前栈帧中跳出,也就是把当前的函数运行结束,我们使用finish命令,意指从当前栈帧跳出
11.寄存器
使用info register(简写info reg)可以显示所有的寄存器值
在寄存器名之前添加 $,显示寄存器的内容,例如p $eax。
p/格式 $寄存器可以指定寄存器的显示格式,例如p/c $eax。可使用的格式如下:
程序指针可以写为$pc,也可以写为$eip,使用p $pc显示程序指针内容。程序指针指向当前程序的运行点的地址。
12.内存
x命令可以显示内存的内容,格式:x/<格式> <地址>。例如 x/i $ps,显示汇编指令。
一般使用 x 命令时,格式为 x/ 。此处 ADDR 为希望显示的地址,N 为重复次数,F 为前面的显示格式,U 代表的单位如下:
12.反汇编
使用指令disassemble(可以简写为disas)显示反汇编的代码
disassemble 程序计数器。反汇编程序计数器所在函数的整个函数。
disassemble 开始地址 结束地址。反汇编从开始地址到结束地址之间的部分。
在反汇编中单步执行使用ni/si。
13.内核转储
内核转储(core dump)的最大好处是,它能保存问题发生时的状态。只要有问题发生时程序的可执行文件和内核转储,就可以知道进程当前的状态。使用generate-core-file可将调试中的进程生成内核转储文件。通过内核转储文件和调试对象,查看生成转储文件时的运行历史。gcore命令可以从命令行直接生成内核转储文件。在命令行使用gcore pid,其中 pid 为进程号。该命令无须停止正在运行的程序以获得内核转储文件,当需要在其他机器上单独分析问题原因,或是分析客户现场发生的问题时十分有用。
大多数 Linux 发行版默认关闭了内核转储功能,使用ulimit命令可以查看当前的内核转储功能是否有效。
这里打开内核转储,设置成无限内存,可以把unlimited设置成适当的大小以字节为单位。
程序发生异常时会在当前目录下生成内核转储文件。例如程序 a.out 生成转储文件 core,使用以下方式启动 GDB:
gdb -c core ./a.out
13.其他
r表示运行程序,可以重新运行。
q(quit)表示退出gdb。
c(contiune)表示继续运行,可以带参数,c n表示忽略断点的次数n。
要调试已经启动的进程,或是调试陷入死循环而无法返回控制台的进程时,可以使用attach命令。格式:attach <pid>,执行这一命令可以 attach 到进程 ID 为 pid 的进程上。attach 之后就能使用普通的 gdb 命令。gdb 和进程分离时使用detach命令,调试的进程就从 gdb 的控制下释放出来。进程被 detach 后继续运行。进程信息可以用info proc命令显示。守护者进程在启动好子进程后,会自动关闭主进程,如果没有设定监控模式的话,gdb 会提示断开与进程的链接。所以必须设定监控对象,设置命令为set follow-fork-mode child/parent。
条件断点:
break <断点> if <条件>,这条命令将测试给定的条件,如果为帧则暂停运行。如果断点已经存在,condition <断点编号> <条件>命令给断点添加触发条件,condition <断点编号>命令删除指定编号断点的触发条件。
反复执行:
ignore <断点编号> <次数>:在编号指定的断点、监视点或捕获点忽略指定的次数。
continue <次数>: 达到指定次数前,执行到断电时不暂停。
s/stepi/n/nexti <次数>:执行指定次数的相应命令。
finish:执行完当前函数后暂停。
until:执行完当前函数等代码块后暂停,如果是循环,则在执行完循环后暂停,常用于跳出循环。
until <地址>:执行到指定地址停止。
断点命令:
commands命令可以定义在断点终端后自动执行的命令。格式如下:
(gdb) commands <断点编号>
<命令>...
end
值的历史:
通过 print 命令显示过的值会记录在内部的值历史中。这些值通过$进行引用,使用 show value 命令可以显示历史中的最后 10 个值。