GDB 是一个很好的命令行调试工具,这里对其用法做一些总结,方便查询,不定时更新。
1.启动 GDB:
首先使用 gcc 编译源文件时需要添加 -g 或者 -ggdb 选项,假设生成最终的应用程序 test, 启动 gdb 并打开应用程序 test:
gdb test
或者
gdb #进入gdb 命令行 (gdb) file test
2.开启 tui 图形调试模式 (也可直接输入 start 或者 run 启动调试);
layout src 显示源文件窗口;
layout asm 显示汇编窗口;
layout split 显示源代码和汇编窗口;
layout regs 显示寄存器窗口;
Ctrl + L 刷新窗口;
Ctrl + x,再按 1:显示单窗口;
Ctrl + x,再按 2:显示源代码和汇编窗口;
Ctrl + x,再按 a:恢复原状;
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这里要说明,用 tui 模式调试时如果遇到通过标准输入输出交互的应用程序时,窗口显示会发生错乱,经从网上查找资料得知有如下解决
方案(引用自 https://bbs.csdn.net/topics/392033826,见 nswcfd 的回答 ):
(1)首先新打开一个终端,用 tty 命令查看当前终端设备名字,比如 /dev/pts/1;
(2)然后在 gdb 里面,在使用 run/start 命令运行程序之前,使用 tty <终端名> 设置程序的输出(例如 /dev/pts/1);
(3)运行程序,这样程序的输出就不会送到 gdb/tui 所在的终端,而是新打开的终端;
(4)如果程序还需要从标准输入读,注意这会跟 /dev/pts/1 终端的 bash 冲突(因为 bash 也在等待新的命令输入),解决办法是:终端
/dev/pts/1 里先执行 sleep 10000,让 bash 进程阻塞在 sleep 程序里,这样就可以为 gdb 的程序提供输入了;
(5)注意,(4)有个缺点, /dev/pts/1 的终端控制信号(例如Ctrl + C)会终止 sleep,却不会终止被 gdb 的程序,要终止该程序需要回到
gdb 命令行界面输入 quit 命令或者继续执行调试程序直到退出。
关于这个问题在 https://blog.csdn.net/RichardYSteven RichardYSteven 的文章中有一篇名为 《gdb 重定向标准输出 -- 调试ncurse比较有用》
也有类似解决的方案(文中描述“gdb提供了重定向的方法”,当然是否是 gdb 官方给出的解决方案,我这里查了好久也没有找到官方网站上的原文)。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3.格式化显示结构体
set print pretty on
然后可以通过 “p” 或者 “print” 来查看结构体,如果是结构体指针,需要在变量前面加取值运算符 “*”。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4.VS Code 调试 C/C++ 时 GDB 的配置方法(确保系统支持 vscode,并且安装 gcc 、gdb,编译链接的 makefile 可以自己写):
(1) 点击菜单中的“运行”->“打开配置”,打开 launch.json;
(2) 配置 “ launch.json” 文件,主要是配置 “program” 一项为目标 target 的绝对路径,当然编译的时候肯定要添加 -g 选项;
(3) 配置 “launch.json” 文件中的 “miDebuggerPath” 为 gdb 的绝对路径,“preLaunchTask” 项为程序执行前的选项;
(4) 在 “launch.json” 同一目录下建立一个 “tasks.json” ,配置其 “type ” 为 “shell”,“option/cwd” 为 Makefile 所在的目录,
同时,更改 “label ” 标签名称作为任务名称(这个随意指定);
(5) 返回 “launch.json” 编辑 “preLaunchTask” 为第 4 步编辑的 “label” 名称。
此时,按下 F5 之后,程序会先执行 preLaunchTask 指定的这个任务(也就是 tasks.json 配置的 shell 命令),然后
再启动调试程序。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这里要注意 VSCode 比较新的版本在远程调试连接服务器的时候经常会被qiang,导致无法在目标机器上下载更新包,这里提供一个方法:
(1) 首先找到vscode输出日志,并将 commit id 拷贝一下(id应该是一串 SHA256 的摘要值);
(2) 直接在浏览器输入 https://update.code.visualstudio.com/commit:${commit_id}/server-linux-x64/stable,把 ${commit_id} 替换成你自己
拷贝的 id,然后敲回车,不出意外浏览器应该会下载一个vscode-server-linux-x64.tar.gz的包,下载完毕后将其拷贝到服务器的当前用户
目录/.vscode-server/bin下,这个目录下面会有几个${commit_id}命名的目录,找到你自己的 ${commit_id}(没有的话手动建立一个目录),
然后将压缩包解压到${commit_id}/目录下即可,解压完毕后的目录结构是这样的
.vscode-server
|---- bin
|------2d23c42a936dbccab3b06f918cdedd361cc47cd6
|-------bin
|-------extensions
|-------node_modules
|-------out
.....
5.GDB 调试 jni 程序(attach java)
(1) 启动 gdb,然后打开 /usr/bin/java;
(2) 启动 java 程序,然后在 gdb 中输入 attach xxx(这个进程号);
(3) 然后在 gdb 中设置 jni 程序中的断点,继续运行 java 程序(此时有可能java程序被阻塞,需要 gdb 运行 continue 命令);
(4) 运行到断点处时,gdb 会自动命中断点,此时按照常规方式来调试即可。