07-gdb

调试

gcc -Wall -pedantic -ansi

-Wall 参数表示输出所有警告, -pedantic -ansi 表示严格遵循语法规则。

取样法调试程序

宏定义

当定义宏DEBUG时才输出调试信息,如编译器标志 -DDEBUG

#ifdef DEBUE
    printf("variable x has value = %d\n", x);
#endif

还可以通过数字调试宏,如定义-DDEBUG=5将启用BASIC_DEBUGSUPER_DEBUG

#define BASIC_DEBUG 1
#define EXTRA_DEBUG 2
#define SUPER_DEBUG 4


#if (DEBUG & EXTRA_DEBUG)
    printf...
#endif

通过全局变量

可以在程序中添加一个全局变量,这样直接在启动的命令行上通过-d选项切换是否启用调试模式。

if (debug) {
    write_debug();
    // ...
}

gdb

编译程序时使用 -g 选项使程序生成调试信息提高调试灵活性,每一个需要调试的源文件都需要添加。调试信息加入使得程序长度成倍增加,但运行内存不变。可以使用strip <file>命令将可执行文件中调试信息删除。

> gdb <filename>
help
run             运行程序,将命令后的参数作为程序的参数传递给程序,出错时会输出错误提示
backtrace / bt / where
                查看堆栈,程序是如何到当前位置的
frame <堆栈编号> 切换到其他堆栈处



print           打印变量,可以使用几乎所有符合C语法的表达式打印变量、数组元素、指针值;
                并按打印顺序放入伪变量 $1 $2,最后一个为$ 倒数第二为$$
arr[0]@<number> 打印指定数目的数组元素
list            打印围绕当前位置前后的一段源码,也可以指定一个行号或函数名
whatis val      查看变量类型
ptype val       与whatis类似,但功能更强大,可查看复合数据类型,可打印成员变量


break 21        在第21行设置断点
tbreak          临时断点,出发后删除
next            单步步过
step            单步步进
cont/c          继续
return          立即退出函数,可指定返回值
finish          执行完剩余函数再正常退出
jump            跳过一段代码不执行,后续如果没有断点继续执行
    jump <line_no>    跳转到指定行
    jump +10          跳到当前行的下10行位置
    jump *0x12345678  跳转到 0x12345678 地址的代码处
watch           监视一个变量或者一段内存,当这个变量或者内存的值发生变化时,GDB就会中断下来。被监视的某个变量或内存地址会产生一个 watch point(观察点)。
    watch 整型变量
    watch 指针变量,监视的是指针变量本身
    watch *指针变量,监视的是指针所指的内容
    watch 数组变量或内存区间
call func()    执行func()函数,同print func()


display arr[0]@5每次到断点时自动显示数组中5个元素
commands        设置每次到断点时自动执行的命令,无需暂停
    > print x
    > end
info break      查看设置的断点
info display    查看设置的display命令
disable break 1      禁用断点1
enable break 1       启用断点1
delete break 1       删除断点1

disassemble    查看某段代码的汇编指令

<方向键>    回卷上一条命令
<空命令>    直接按下回车键执行最近执行的命令,使用step next单步执行时及其有用


set args "arg1" "arg2" 设置程序启动参数,后续为空则清楚之前设置的参数
show args        查看之前设置的参数
set variable n=n+1    设置变量的值,通过断点的设置和相应操作,可以尝试修改程序而无需改变程序的源代码并重新编译。


终端图形化

能调试的同时显示代码,在gdb内部使用 (gdb) tui enable,使用 help tui 查看详细帮助。

调试 core 文件

core文件用于在程序出错时记录内核信息。默认在出现错误时不会出现core文件,使用 ulimit -a 可以查看系统对于资源的限制。使用 ulimit -c unlimited 让系统不限制core文件的大小。在程序出错时就可以得到core文件。

使用 gdb execute core.1372 进行调试。

调试正在运行的程序

gdb execute -p pid 即可调试正在运行的程序,调试时程序会暂停。

调试多进程

set follow-fork-mod paren   默认,调试父进程
set follow-fork-mode child  调试子进程

set detach-on-fork [on|off] 默认on,调试当前进程时其他进程继续运行。为off时其他进程被挂起

info interiors    查看调试的进程
inferior <进程id> 切换当前调试的进程

调试多线程

info threads                  查看当前进程所有线程运行情况
thread <线程id>                切换到指定线程

set scheduler-locking on/off  只运行当前线程或运行全部线程

thread apply [id1 id2 ...]/[all] [cmd]
                              将命令cmd指定对应编号线程,可用all指定所有线程。
break <location> thread <thread_no>
                              在 location 位置设置普通断点,该断点只作用在特定编号的线程上

默认使用 all-stop mode,借用 set scheduler-locking 让特定线程运行,其他线程暂停

  • set scheduler-locking on,锁定线程,只有当前或指定线程可以运行;
  • set scheduler-locking off,不锁定线程,会有线程切换;
  • set scheduler-locking step,当单步执行某一线程时,其他线程不会执行,同时保证在调试过程中当前线程不会发生改变。但如果在该模式下执行 continue、until、finish 命令,则其他线程也会执行;
  • show scheduler-locking,查看线程锁定状态;

gdb 模式状态

  • all-stop mode,全停模式,当程序由于任何原因在GDB下停止时,不止当前的线程停止,所有的执行线程都停止。这样允许你检查程序的整体状态,包括线程切换,不用担心当下会有什么改变。

  • non-stop mode,不停模式,调试器(如VS2008和老版本的GDB)往往只支持 all-stop 模式,但在某些场景中,我们可能需要调试个别的线程,并且不想在调试过程中影响其他线程的运行,这样可以把GDB的调式模式由 all-stop 改成 non-stop7.0 版本的GDB引入了 non-stop 模式。在 non-stop 模式下 continue、next、step 命令只针对当前线程。

  • record mode,记录模式;

  • replay mode,回放模式;

  • scheduler-locking ,调度锁;

  • schedule-multiple,多进程调度;

常用命令

命令名称 命令缩写 命令说明
run r 运行一个待调试的程序
continue c 让暂停的程序继续运行
next n 运行到下一行
step s 单步执行,遇到函数会进入
until u 运行到指定行停下来
finish fi 结束当前调用函数,回到上一层调用函数处
return return 结束当前调用函数并返回指定值,到上一层函数调用处
jump j 将当前程序执行流跳转到指定行或地址
print p 打印变量或寄存器值
backtrace bt 查看当前线程的调用堆栈
frame f 切换到当前调用线程的指定堆栈
thread thread 切换到指定线程
break b 添加断点
tbreak tb 添加临时断点
delete d 删除断点
enable enable 启用某个断点
disable disable 禁用某个断点
watch watch 监视某一个变量或内存地址的值是否发生变化
list l 显示源码
info i 查看断点 / 线程等信息
ptype ptype 查看变量类型
disassemble dis 查看汇编代码
set args set args 设置程序启动命令行参数
show args show args 查看设置的命令行参数

prof gprof

在程序中链接特殊的函数库,编译时加上 -p 标志(针对prof)或 -pg 标志(针对gprof)。程序生成mon.out或gmon.out文件,使用prof/gprof读取v并生成报告。

断言

#include <assert.h>

void assert(int expression);

assert 宏对表达式进行求值,若结果非零则向标准错误写一些错误信息,然后调用abort结束程序。使用 -DNDEBUG 定义NDEBUG宏关闭断言。

posted @ 2022-06-16 09:41  某某人8265  阅读(42)  评论(0编辑  收藏  举报