GDB学习笔记

xeonds

2023.03.16 23:12:16

GDB(GNU Debug Bridge)是一个二进制程序调试工具,适用于调试C和C++程序。这种二进制程序工具统称为bin-utils。类似的还有strace,一个跟踪程序系统调用的工具。

快速上手

在此之前,编译程序时记得加上-g参数来生成调试信息。

gcc main.c -g -o main

首先,使用gdb <program>启动gdb并加载程序。随后,使用break mainmain函数入口设置断点,否则程序会直接执行完成。接着,使用run [args]执行程序并附加可选的参数。程序会在断点处停止,在这之后,就可以使用next(简写为n)或step单步执行,使用print expr打印表达式的值。完成后,用quit退出gdb。

解释说明

  1. 只有编译时加上了-g,gdb才能进行调试
  2. next表示执行下一条语句而不进入函数内部;step则会进入函数内部
  3. print expr可以输出表达式的值,一次一个参数。例如查看数组arr的第i个元素可以用print arr[i]

GDB的几种模式

GDB有多种模式,包括交互模式、批处理模式、远程调试模式等。交互模式是最常用的模式,用户可以在命令行界面中输入命令与GDB交互。批处理模式可以在不人工干预的情况下执行一系列GDB命令,通常用于自动化测试和调试。远程调试模式可以在远程主机上调试程序,通常用于嵌入式系统和分布式系统的调试。

GDB的软件结构可以分为以下几个部分:

  1. 前端:用户与GDB交互的界面,可以是命令行界面或者GUI界面。
  2. 后端:GDB的核心部分,负责解析用户输入的命令,控制程序的执行,以及与目标程序进行通信。
  3. 目标:被调试的程序,GDB通过与目标程序进行通信来控制其执行。

常用指令

以下是GDB常用的指令:

高级功能

除了常用指令外,GDB还有一些高级功能:

多线程调试

GDB支持多线程调试。可以使用info threads命令查看当前线程列表,使用thread <id>命令切换到指定线程,使用break <func> thread <id>命令在指定线程中设置断点。

例如,我们有一个多线程程序test,其中有两个线程thread1thread2,我们想在thread2中设置断点。首先,使用gdb test命令启动gdb并加载程序。接着,使用run命令运行程序。程序会在主线程中停止,使用info threads命令查看当前线程列表,找到thread2的ID。假设thread2的ID为2,使用thread 2命令切换到thread2,使用break <func> thread 2命令在thread2中设置断点。完成后,使用continue命令继续执行程序,程序会在断点处停止。

远程调试

GDB支持远程调试,可以使用target remote <host>:<port>连接到远程主机,使用file <path>加载可执行文件,使用run运行程序。

调试核心转储文件

当程序崩溃时,可以使用GDB调试核心转储文件。可以使用core <file>命令加载核心转储文件,使用bt命令查看函数调用栈。

调试动态链接库

GDB可以调试动态链接库,可以使用set solib-search-path <path>设置动态链接库搜索路径,使用info sharedlibrary查看已加载的动态链接库,使用break <func>在动态链接库中设置断点。

调试汇编代码

GDB可以调试汇编代码,可以使用layout asm查看汇编代码窗口,使用stepi单步执行汇编指令,使用disassemble <func>查看函数的汇编代码。

调试嵌入式系统

GDB可以调试嵌入式系统,可以使用target remote <host>:<port>连接到嵌入式系统,使用set remotebaud <baud>设置串口波特率,使用monitor reset复位嵌入式系统,使用load加载可执行文件,使用run运行程序。

调试内核

GDB可以调试内核,可以使用target remote <host>:<port>连接到内核,使用set architecture <arch>设置架构,使用set osabi <osabi>设置操作系统ABI,使用set solib-absolute-prefix <path>设置动态链接库路径,使用add-symbol-file <file> <addr>加载符号文件,使用break <func>在内核中设置断点。

调试追踪系统调用

GDB可以调试追踪系统调用,可以使用catch syscall <syscall>设置系统调用断点,使用info catch查看系统调用断点,使用stepi单步执行系统调用。

调试追踪信号

GDB可以调试追踪信号,可以使用catch signal <signal>设置信号断点,使用info catch查看信号断点,使用stepi单步执行信号处理函数。

调试追踪fork和exec

GDB可以调试追踪fork和exec,可以使用set follow-fork-mode <mode>设置fork和exec的跟踪模式,使用catch fork设置fork断点,使用catch exec设置exec断点,使用info catch查看fork和exec断点。

调试追踪动态内存分配

GDB可以调试追踪动态内存分配,可以使用catch syscall brk设置brk系统调用断点,使用catch syscall sbrk设置sbrk系统调用断点,使用info catch查看brk和sbrk断点。

调试追踪文件操作

GDB可以调试追踪文件操作,可以使用catch syscall open设置open系统调用断点,使用catch syscall close设置close系统调用断点,使用catch syscall read设置read系统调用断点,使用catch syscall write设置write系统调用断点,使用info catch查看文件操作断点。

调试追踪网络操作

GDB可以调试追踪网络操作,可以使用catch syscall socket设置socket系统调用断点,使用catch syscall connect设置connect系统调用断点,使用catch syscall accept设置accept系统调用断点,使用catch syscall send设置send系统调用断点,使用catch syscall recv设置recv系统调用断点,使用info catch查看网络操作断点。

调试追踪信号量和共享内存

GDB可以调试追踪信号量和共享内存,可以使用catch syscall semop设置semop系统调用断点,使用catch syscall semget设置semget系统调用断点,使用catch syscall semctl设置semctl系统调用断点,使用catch syscall shmget设置shmget系统调用断点,使用catch syscall shmat设置shmat系统调用断点,使用catch syscall shmdt设置shmdt系统调用断点,使用catch syscall shmctl设置shmctl系统调用断点,使用info catch查看信号量和共享内存断点。

调试追踪进程间通信

GDB可以调试追踪进程间通信,可以使用catch syscall msgget设置msgget系统调用断点,使用catch syscall msgsnd设置msgsnd系统调用断点,使用catch syscall msgrcv设置msgrcv系统调用断点,使用catch syscall semget设置semget系统调用断点,使用catch syscall semop设置semop系统调用断点,使用catch syscall semctl设置semctl系统调用断点,使用catch syscall shmget设置shmget系统调用断点,使用catch syscall shmat设置shmat系统调用断点,使用catch syscall shmdt设置shmdt系统调用断点,使用catch syscall shmctl设置shmctl系统调用断点,使用info catch查看进程间通信断点。

调试追踪信号处理

GDB可以调试追踪信号处理,可以使用catch syscall sigaction设置sigaction系统调用断点,使用catch syscall sigprocmask设置sigprocmask系统调用断点,使用catch syscall sigsuspend设置sigsuspend系统调用断点,使用catch syscall sigreturn设置sigreturn系统调用断点,使用info catch查看信号处理断点。

调试追踪定时器

GDB可以调试追踪定时器,可以使用catch syscall timer_create设置timer_create系统调用断点,使用catch syscall timer_settime设置timer_settime系统调用断点,使用catch syscall timer_gettime设置timer_gettime系统调用断点,使用catch syscall timer_delete设置timer_delete系统调用断点,使用info catch查看定时器断点。

调试追踪进程状态

GDB可以调试追踪进程状态,可以使用catch syscall wait4设置wait4系统调用断点,使用catch syscall waitpid设置waitpid系统调用断点,使用catch syscall waitid设置waitid系统调用断点,使用catch syscall exit设置exit系统调用断点,使用catch syscall _exit设置_exit系统调用断点,使用catch syscall kill设置kill系统调用断点,使用info catch查看进程状态断点。

调试追踪信号量和共享内存

GDB可以调试追踪信号量和共享内存,可以使用catch syscall semop设置semop系统调用断点,使用catch syscall semget设置semget系统调用断点,使用catch syscall semctl设置semctl系统调用断点,使用catch syscall shmget设置shmget系统调用断点,使用catch syscall shmat设置shmat系统调用断点,使用catch syscall shmdt设置shmdt系统调用断点,使用catch syscall shmctl设置shmctl系统调用断点,使用info catch查看信号量和共享内存断点。

调试追踪进程间通信

GDB可以调试追踪进程间通信,可以使用catch syscall msgget设置msgget系统调用断点,使用catch syscall msgsnd设置msgsnd系统调用断点,使用catch syscall msgrcv设置msgrcv系统调用断点,使用catch syscall semget设置semget系统调用断点,使用catch syscall semop设置semop系统调用断点,使用catch syscall semctl设置semctl系统调用断点,使用catch syscall shmget设置shmget系统调用断点,使用catch syscall shmat设置shmat系统调用断点,使用catch syscall shmdt设置shmdt系统调用断点,使用catch syscall shmctl设置shmctl系统调用断点,使用info catch查看进程间通信断点。