一、环境介绍#
- Windows11 24H2
- WSL2
- Ubuntu 22.04
Linux系统下gdb工具默认安装好,使用VSCode进行WSL远程连接。
二、原理介绍#
VSCode进行调试时,需要一个launch.json,这个配置文件描述了使用什么样的调试器,以及进行调试时的其他配置。
如果在VSCode中要进行调试工作,必须要在.vscode文件夹中有一个能完成调试任务的json。
接下来借助我自己写的launch.json来讲解每个部分的功能,也作为一个写调试配置文件的参考。
{ "version": "0.2.0", // 使用的 launch.json 版本
"configurations": [ // 配置调试器的配置列表 { "name": "Hpatchi Debug", // 调试器配置的名称,可以自定义,可以区别不同的调试器配置 "type": "cppdbg", // 调试器类型为 C++ 调试 "request": "launch", // 请求启动调试会话 "program": "${workspaceFolder}/hpatchi", // 可执行文件的路径,主要的修改点,这里就是我的工作目录下的hpatchi
// 程序启动时的参数,会将这些参数依次输入给启动调试的程序 "args": [ "-f", "${workspaceFolder}/TestDemo/FBCM-0056.lbf", "${workspaceFolder}/DiffFile", "${workspaceFolder}/newFile-00D7.lbf" ],
"stopAtEntry": false, // 是否在程序入口处停止
"cwd": "${workspaceFolder}", // 工作目录 "environment": [], // 环境变量设置 "externalConsole": false, // 是否使用外部控制台
// 使用 gdb 调试器,也可以设置成别的调试器 "MIMode": "gdb",
// 配置 gdb的初始化命令 "setupCommands": [ //启用漂亮打印,输出格式对齐 { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true }, //防止gdb调试进入标准库函数,实测没啥用,可以不加 { "description": "防止 gdb 打开标准库函数", "text": "-interpreter-exec console \"skip -rfu std::.*\"", "ignoreFailures": false } ],
"symbolLoadInfo": { "loadAll": false, "exceptionList": "" }, // 在启动调试会话之前运行的任务,启动在task.json中提前配置好的任务名称。 //"preLaunchTask": "Build",
// gdb 调试器的路径,使用什么调试器就换成对应的路径,可以使用 which 命令找到一个程序的位置 "miDebuggerPath": "/usr/bin/gdb" } ]}三、GDB原理#
GDB是默认的c语言调试器,一般和gcc一起使用。
如果要使用gdb进行调试,使用gcc编译时就需要进行一些操作。
使用gcc编译需要在编译命令后加上-g,这样进行编译时gcc就会自动将源代码和编译后的机器语言对应,就可以进行调试追踪。
一定要在.c文件的编译阶段加上-g的命令才能正确生成调试信息,如果在链接阶段加上-g命令是指保留.o文件中的调试信息。即如果不在编译阶段生成调试信息,那这个文件在最后调试时就不会包含调试信息。
推荐在gcc时使用的命令
- -g 必须加上否则无法进行代码的追踪。
- -Wall,warn all的缩写,编译时会将所有的warn警告提示出来。
- -O0 不进行编译优化,防止代码的顺序被调整或者某些调试变量被优化掉。
GCC的编译优化问题#
gcc进行编译时会默认进行优化等级为O1的优化,编译器会尝试简单的优化代码流程和变量。
对应的如果进行了优化,部分调试信息就会减少,所以在调试过程中要慎重选择优化等级。
较低的优化等级可以提升编译速度,但是会导致较慢的执行速度或者较大的文件大小。使用比较高的优化等级时可以根据需要优化执行速度和文件大小,但是会牺牲编译的时间。
四、如何在Make项目中进行调试#
上面介绍了如果要进行调试需要在执行gcc命令进行编译时加上**-g**的命令。
在Make项目中往往很多文件都是通过隐含规则自动推导出来的,这时候我们就无法显式的加上-g命令来生成调试信息。只有在编译阶段生成了调试信息的文件,在最终调试时才能把代码运行过程和源文件对应起来。
遇到这种情况我们可以在CFLAGS变量中加入-g命令,CFLAGS中的所有参数都会被编译器默认使用,不管是自动推导还是使用gcc命令进行编译。
五、tips#
我在调试文件的过程中,只在最后一步可执行文件后面加入了-g命令,导致的后果就是只有这个可执行文件的源文件可以被调试模式追踪,其他的源文件都没法进行调试。
在这里我尝试对makefile进行修改,然后使用了一些命令来查看make将会执行的命令。
make -n可以将make将会执行的命令,不管是显式规则规定的还是自动推导的,所有的命令都会显示出来,然后我将这些信息直接重定向输出到一个文件,接着修改一次makefile,再进行一次输出,我就得到了包含着make执行的命令的两个文件。
使用vimdiff命令就可以在vim中看到两个文件的区别之处,但是vim毕竟是一个命令行工具,如果需要更复杂的文本操作,还是需要使用VSCode,并且VSCode支持更多的插件和操作,自然使用起来就更方便。