linux下用gdb调试程序

时间:2023-02-20 17:02:21

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具

一般来说,GDB主要完成下面四个方面的功能:

1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
3、当程序被停住时,可以检查此时你的程序中所发生的事。
4、动态的改变你程序的执行环境。

GDB的执行方式:

  • gdb <program> :program也就是你的执行文件,一般在当前目录下。
  • gdb <program> core:用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。
  • gdb <program> <PID>:如果你的程序是一个正在运行程序,那么你可以指定这个程序运行时的进程ID。gdb会自动attach上去,并调试他。

调试带参数的程序时,先gdb <program> 进入调试界面,然后设置程序运行时的参数,输入命令 :  

set args [para list]

GDB常用命令:

  • file <FILE>:指定一个可执行文件进行调试,读取指定文件的调试信息,如 file a.exe
  • l[ist] :从第一行开始例出原码
  • r[un] :装载完要调试的可执行文件后,可以用 run 命令运行可执行文件
  • b[reak] <n/FunctionName>:设置断点。如 b 25 ,则在源程序的第 25 行设置一个断点,当程序执行到第 25 行时,就会产生中断;也可以使用 b funcname ,当程序调用些函数时,则产生中断
  • i[nfo] b[reak]:查看断点信息
  • bt(backTrace):查看函数堆栈
  • c[ontinue] :让中断的程序执行直到下一个中断点或程序结束
  • p[rint] <args>:输出某个变量的值,如程序定义了一个 int aa 的就是, p aa 就会输出 aa 的当前值
  • n[ext] :程序执行到断点时中断执行,可以用 n 指令进行单步执行下一条语句,但是不进入函数
  • s[tep] :程序执行到断点时中断执行,可以用 s 指令进行单步执行下一条语句,并进入函数
  • finish:一直执行到正在运行的函数执行完毕
  • attach <PID>:使用该命令调试正在运行的程序之前,先用file命令读取程序的符号表,然后再attach正在运行的程序。调试完毕后detach,解除gdb和程序的链接,程序继续执行
  • info program: 显示有关你的程序的状态信息,你的程序是在运行还是停止,是什么进程,为什么停止,等等; 
  • info stack/frame: 显示栈/帧的摘要信息
  • f[rame] <STACK_FRAME_NO/ADDRESS>: 选择一个栈帧,并进入这个栈帧,同时打印被选择的栈帧的内容摘要信息;该命令的参数是一个栈帧的号码或者是一个栈帧地址
  • q[uit] :退出 GDB
  • help <Command>: 显示命令Command的详细用法

设置断点的高级方法:
  • break 类名::函数名
  • break +OFFSET 或 break -OFFSET:程序运行到当前行时的前几行或后几行; OFFSET表示行号
  • break FILENAME:LINENUM:在文件名为FILENAME的源文件中的第LINENUM行上设置断点
  • break FILENAME:FUNCTION:在文件名为FILENAME的源文件中的名为FUNCTION的函数上设置断点
  • break *ADDRESS:在地址ADDRESS上设置断点.这个命令允许你在没有调试信息的程序中设置断点
  • break:不含任何参数的break命令,会在当前执行到的程序运行栈中的下一条指令上设置一个断点.除了栈底以外,这个命令使程序在一旦从当前函数返回时停止
  • break [LOCATION] if CONDITION:设置一个条件断点,条件由CONDITION来决定.如果CONDITION条件为非0(条件成立时),程序就在LOCATION处停止。LOCATION 可能是line number, function name, 或者"*" 和an address。With no LOCATION, uses current execution address of the selected stack frame.  This is useful for breaking on return to a stack frame.
删除断点的方法:
  • clear:不带任何参数的clear命令会在当前所选择的栈上清除下一个所要执行到的断点(指令级).当你当前的栈帧是栈中最内层的时候,使用这个命令可以很方便地删除刚才程序停止处的断点;
  • clear FUNCTION 和 clear FILENAME:FUNCTION:删除名为FUNCTION的函数上的断点;
  • clear LINENUM 和 clear FILENAME:LINENUM:删除第LINENUM行上的断点;
  • delete [breakpoints] [BNUMS...]:删除参数所指定的断点,如果没有指定参数,则删除程序中所有的断点.这个命令可以缩写成d;
不常用的命令:
  • pwd: 查看gdb当前的工作路径
  • cd : 改变gdb当前的工作路径
  • info terminal:显示gdb当前所使用的终端的类型信息
  • show paths: 显示当前路径变量的设置情况
  • show environment/env [VARNAME]:显示程序的环境变量VARNAME的值;如果不指明环境变量名,那么该命令将显示所有环境变量的值
  • set environment/env VARNAME [=] VALUE:设置程序的某个环境变量VARNAME的值;不过,只对你所调试的程序有效,对gdb本身不起作用
  • unset environment/env VARNAME:删除程序的某个环境变量VARNAME;
设置观察点:
可以使用一个观察点来停止一个程序的执行,当某个表达式的值改变时,观察点将会停止程序,而不需要事先在某个地方设置一个断点。由于观察点的这个特性,使观察点的开销比较大,但是在捕捉错误时非常有用,特别是当你不知道程序到底在什么地方出了问题,设置观察点的命令:
  • watch EXPR:watch命令使用EXPR作为表达式设置一个观察点.gdb将把表达式加入到程序中,并监视程序的运行,当表达式的值被改变的时候,gdb将会停止程序;
  • rwatch EXPR:使用EXPR作为表达式设置一个观察点,当EXPR被程序读取时,程序被gdb暂停;
  • awatch EXPR:使用EXPR作为表达式设置一个观察点,当EXPR被读出然后被写入时,gdb会暂停程序;这个命令常和rwatch合用;
  • info watchpoints:显示所有设置的观察点的列表

对多线程程序的调试:
   A、thread <THREAD_NO>: 该命令用于在线程之间进行切换,把线程号为THREAD_NO(gdb设置的线程号)的线程设置为当前线程
    B、info threads: gdb按照顺序显示当前进程所拥有的所有线程的状态摘要信息

  • 线程号: gdb为被调试进程中的线程设置的顺序号
  • 目标系统的线程标识
  •  此线程的当前栈信息
       一些前面带'*'号的线程,表示该线程是当前线程
    C、thread apply [THREAD_NO] [ALL] ARGS: 该命令用于向线程提供命令
    另外,无论gdb何时中断了你的程序(因为一个断点或者是一个信号),gdb会自动选择信号或断点发生的线程作为当前线程

gdb选项:

  • -s(symbol) file 读出文件(file)中的符号表
  • -write 开通(enable)往可执行文件和核心文件写的权限
  • -se File 从File读取符号表并把它作为可执行文件,与第一个参数等价
  • -d Directory 把Dicrctory加入源文件搜索的路径中
  • -tty=Device 使用Device作为你程序运行的标准输入输出


关于core dump(核心转储):

这里的core不是核心,而是内存。在开发程序时,最怕的就是程序莫明其妙地挂掉。于是,操作系统就会把程序挂掉时的 内存内容写入一个叫做core的文件里(这个写入的动作就叫core dump),我们可以根据core文件分析程序出错的原因,以便于我们调试。

1. 在嵌入式系统中,有时core dump直接从串口打印出来结合objdump查找ra和epa地址,运用栈回溯,可以找到程序出错的地方。

2. 在一般Linux系统中,默认是不会产生core dump文件的,通过ulimit -c来查看core dump文件的大小,一般开始是0。可以设置core文件大小,例如:

ulimit -c 1024(kbytes单位)或者ulimit -c unlimited

3. core dump文件输出设置,一般默认是当前目录,并且文件名固定为core,如果程序产生多次崩溃,就会覆盖掉前一个core文件。可以通过

echo "/root/corefile/core-%e-%p-%t" > /proc/sys/kernel/core-pattern    控制core文件保存位置和文件名格式

查看core dump文件路径的命令:

cat /proc/sys/kernel/core-pattern

core-pattern中使用的参数列表:

  •     %p - insert pid into filename 添加pid
  •     %u - insert current uid into filename 添加当前uid
  •     %g - insert current gid into filename 添加当前gid
  •     %s - insert signal that caused the coredump into the filename 添加导致产生core的信号
  •     %t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
  •     %h - insert hostname where the coredump happened into filename 添加主机名
  •     %e - insert coredumping executable name into filename 添加命令名

需要说明的是,在内核中还有一个和core dump相关的文件,/proc/sys/kernel/core-user-pid,如果执行以下命令即使core-pattern中没有设置%p,也会在生成的core文件中添加上pid。

echo "1"
> /proc/sys/kernel/core-user-pid

4. 发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发core dump的行。
gdb [exec file] [core file]