Debugging in Visual Studio Code

整体理解

从宏观上来讲,调试程序的两大场景:

  1. 单程序写完后直接运行调试
  2. 大型项目编译完成后,需要结合源码对某一个可执行程序进行执行流分析

实际上这看似是两种,但是底层本质的执行流是相同的,只不过前者被隐藏了一些过程。

整体的过程其实就是 vscode 在 debug 时所提供的两个 配置文件 tasks.jsonlaunch.json,其中前者表示编译过程,后者表示程序执行过程

最开始使用IDE,进行的其实始终就是第一种场景,但是不代表程序在没有编译的情况下就直接进入debug状态了(除非是解释形语言),一定是先编译成可执行文件后在进行debug,只不过IDE把编译这个过程给隐藏了

又一次感觉到初学者似乎不应该直接使用 IDE,IDE 把很多程序执行的关键过程都给隐藏掉了,搞得最后没有IDE都不知道这个程序该怎么跑起来,不过也可能是考虑到编译链接这些东西需要涉及到操作系统等其他方面的知识,让初学者太早接触可能会陷入过多的细节当中,使用 IDE 确实是可以让初学者只需要考虑语言本身,尽可能地隐藏掉一些底层细节

实际无论是哪种情况,debug 我们都可以直接通过命令行,利用 gdb 或 lldb 来实现,不过需要输入命令不太方便,所以考虑使用 vscode 的用户界面作为 gdb 和 lldb 的接口,而由于 vscode 只是个简单的文本编辑器,想让它对接 gdb 和 lldb,需要通过插件来实现对接(如果要要使用 lldb,需要安装 CodeLLDB 插件,官方的C/C++插件并不支持 lldb,会报错"The debug type is not recognized. make sure that you have a corresponding debug extension installed and that it is enabled.")

the debug type is not recognized. make sure that you have a corresponding debug extension installed and that it is enabled.

一旦对接上之后,只需要配置好 launch.json 就可以 debug 编译完成后的项目中的可执行文件了,而 launch.json 要编写的关键就是可执行程序的路径以及参数

debugging process

  1. 采用 debug 选项进行编译
  2. 安装 vscode debug 所需要的插件
  3. 编写 launch.json,指明所需调试的程序以及需要的参数

编译前

如果直接使用编译器进行编译,那么必须携带 debug 编译选项

如果使用 cmake 进行编译,那么需要添加 -dcmake_build_type=debug(对应的是 -dcmake_build_type=release

编译后如何查看文件是否含有 debug 信息

  1. 通过 file 命令

如果是携带 debug 选项编译出来的可执行程序,会携带 with debug_info 选项

  1. 通过 readelf 命令
1
readelf -a <file name> |grep debug

如果携带 debug 选项编译出来的可执行程序,以上代码会输出以下类似信息

1
2
3
4
5
6
7
8
[27] .debug_info       progbits         0000000000000000  00003165
[28] .debug_abbrev     progbits         0000000000000000  0000680a
[29] .debug_line       progbits         0000000000000000  00006e81
[30] .debug_str        progbits         0000000000000000  0000728d
[31] .debug_addr       progbits         0000000000000000  0000c533
[32] .debug_rnglists   progbits         0000000000000000  0000c5f3
[33] .debug_str_offset progbits         0000000000000000  0000c62f
[34] .debug_line_str   progbits         0000000000000000  0000d0e3

常见 debug 模式

此配置项在 vscode 的 launch.json 中对应 request 字段。

  1. launch 模式:配置调试器启动程序,与在命令行中执行一样。可以指定程序的执行路径、命令行参数、环境变量等,并且在程序开始执行时立即开始调试。这种模式适用于想要从头开始调试整个程序的情况,或者当程序是一个独立的可执行文件时。

  2. attach 模式:连接到已经在运行的进程进行调试。不需要启动程序,而是等待程序运行到一定的地方,然后通过调试器连接到该进程。这种模式适用于想要在程序已经运行一段时间之后进行调试,或者当程序是一个服务器或其他类型的长时间运行的进程时。

处理环境变量

假如我们希望完成 export ld_library_path=$ld_library_path:$(pwd)/lib

通过 envfile

方法一是通过设置 envfile, 结合 .env 文件

首先创建一个 .env 的文件,其中填写要配置的键值对。这里需要注意的是 VS Code 并不会自动解析 Shell 中的动态命令(如 $(pwd)),所以 xxx 部分只能使用绝对路径

1
2
3
// ${workspaceFolder}/.env

LD_LIBRARY_PATH="$LD_LIBRARY_PATH:xxx/lib"

然后在 launch.json 中指定 使用这一文件

1
2
3
4
5
6
7
// launch.json

"configurations": [
	{
		"envFile": "${workspaceFolder}/.env",
	}
]

通过 environment

直接在 launch.json 中指定,与 env 不同的是,因为这里的路径是写在 launch.json 中的,所以可以使用 VS Code 支持的变量来简化路径表述

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
"configurations": [
	{
		"environment": [
			{
				"name": "LD_LIBRARY_PATH",
				"value": "${workspaceFolder}/test/lib:$LD_LIBRARY_PATH"
			}
		],
	}
]
0%