最近读一份只能运行在嵌入式平台上的三无代码,由于数据结构比较复杂,没办法只能gdb一步步跟着读,gdb一边list、一边print还得一边next,效率很低下。在ubuntu上用过vscode之后,就觉得用vscode调嵌入式c程序应该不错,花了一些时间尝试了一下,果真不是很复杂。
原理上主要使用了gdb的远程调试,远程gdb调试时,使用了gdb的mi(machine interface)接口,把命令行调试界面化,以前DDD(Data Display Debugger)就是干这个事的,现在貌似停止维护了(宇宙最强调试器,可惜了),vscode灵活性比较大,比较通用,界面比较友好,如监控某一变量,添加到watch窗口,不用边next,边print,也方便代码修改,配置好了,就是一款嵌入式IDE。第一次配置稍微麻烦一点,但不复杂,vscode的操作习惯和vs比较像(本来就是微软的东西,这里要赞一下),上手难度低,也算是嵌入式调试较好的解决方案吧。
本文调试的是嵌入式C程序,但vscode可以说是语言无关的,大家也可以尝试调试其他语言程序。先放一张远程调试的截图:
单看截图看不出是远程调试,图中调的是一份开源代码(随便找的一份代码,不是开始说的三无代码),结构体显示这块比gdb的cli模式方便太多。
下面介绍vscode远程调试环境搭建方式,vscode调试嵌入式程序安装、配置要点如下。
安装vscode ubuntu版
相关资料比较多,可以自己查找安装。理论上用vscode的windows版本也可以,但前提是你得有windows版的交叉工具链。
交叉编译gdb与gdb-server程序
这是远程调试必要的步骤,编译时注意选项(这里以arm为例)
./configure是支持–build、–host、–target这几个选项,选项含义:
–build=编译平台,如x86,build一般不需要指定
–host=运行平台,软件本身运行的平台,如arm
–target=目标平台,即需处理的指令集,如arm
通常情况下交叉编译的host与target相同,即完全在嵌入式平台上跑的程序,但远程调试是gdb的host与target不一致,配置如下:
gdbserver: ./configure –host=arm –target=arm
gdb: ./configure –targe=arm
gdb是运行在x86的ubuntu中,所以host可以省略,而gdbserver是运行在嵌入式板子上的,则不能省略 。
注意: 不指定build、host、target时,默认用的就是当前编译平台,如x86,即./configure不带参数编译出来的就是当前平台的程序。
gdb和gdb_server编译不复杂,源码可以在官网上下载
https://ftp.gnu.org/gnu/gdb/ ,也可以使用平台厂商会提供相关源码(与工具链匹配的版本)。
本人使用gdb8.1版本碰到如下问题:
1. 由于两个东西configure配置选项不一致,gdbserver和gdb先后编译了两次,后编译的可能会出现如下错误:
configure: loading cache ./config.cache
configure: error: ‘host_alias’ has changed since the previous run:
configure: former value: ‘arm-linux’
configure: current value: ‘i686-pc-linux-gnu’
是因为上次编译的cache文件没删除,make clean不会删除cache,make distclean也只删除了部分cache文件,还是删掉这份源码,重新解压编译吧,或者按报错慢慢删cache文件。
2.如果不想安装(make install,可能会影响原gdb使用)该gdb,且gdb版本较高(如8.1,应该是7.0以上就可能有此问题),可能会报如下错误:
./gdb-arm8.1: warning:
Could not load the Python gdb module from `/usr/local/share/gdb/python’.
Limited Python support is available from the _gdb module.
Suggest passing –data-directory=/path/to/gdb/data-directory.
Python Exception type ‘exceptions.NameError’> Installation error: gdb.execute_unwinders function is missing:
按网上的操作,把gdb python相关东西(源码里面)copy进去可以解决
# mkdir -p /usr/local/share/gdb/python/gdb
# cp -rf ~/gdb-8.1/gdb/python/lib/gdb/* /usr/local/share/gdb/python/gdb/
配置vscode
这一步最关键,建议先了解vscode的用法,最重要的就是配置configuration,launch.json配置如下:
{
"version" : "0.2.0" ,
"configurations" : [
{
"name" : "(gdb) ARM remote debug" ,
"type" : "cppdbg" ,
"request" : "launch" ,
"program" : "/opt/nfs/test" ,
"args" : [],
"stopAtEntry" : false ,
"cwd" : "${workspaceFolder}/build/test" ,
"environment" : [],
"externalConsole" : true ,
"MIMode" : "gdb" ,
"miDebuggerPath" : "/home/sw/gdb-arm8.1" ,
"miDebuggerServerAddress" : "192.168.30.14:2018" ,
"setupCommands" : [
{
"description" : "Enable pretty-printing for gdb" ,
"text" : "-enable-pretty-printing" ,
"ignoreFailures" : true
}
],
}
]
}
远程调试launch.json配置要点:
“name” :这个还是有必要改下,如我们项目工程包括几个主进程,多个测试程序,可以为每个程序添加一个configuration,名称需区分开,用的时候切换一下configuration即可。
“program” :这个一般指向挂载目录的嵌入式可执行程序,也可以不指向板子上的程序,但该程序必须与板子上运行的程序一致,否则会出问题。
“cwd” : 当前工作目录,应指向需调试程序的编译目录,如例子中的”${workspaceFolder}/build/test”,设置不正确,可能会找不到源码。
“miDebuggerPath” :gdb路径,需执行前面编译的gdb
“miDebuggerServerAddress” :远程调试服务器地址,也就是gdbsever运行的ip地址,注意端口和服务器监听端口保持一致。
遇到问题:
本人的ubuntu下的vscode添加 configurations不会自动刷新,添了过后,需要重新打开一下工程才能刷新过来。
远程调试嵌入式程序
1.编译被调试程序
需注意,交叉编译板子上运行的程序时,需带-g选项,调试信息中有行号等信息,如项目部分没有源码或编译时未加-g选项,该部分就不能单步跟踪和设置断点(如c库),但不影响其他部分表示。
这里用vscode只是调试代码,源码的编译没必要用vscode,当然也可以配置,感觉有点费力不讨好,vscode中集成了terminal,可以直接在该terminal使用make来编译。
2.启动被调试程序
一般在挂载目录中,telnet或ssh到嵌入式上板子上通过上面编好的gdbserver启动被调试程序,需指定端口
/var/sw # ./gdbsever-arm 127.0.0.1:2018 ./test
这一步也可以通过vscode的terminal远程登录到板子上操作,避免频繁切换。
3.vscode连接被调试程序
配置好launch.json后,直接F5启动即可,可以通过F9设断点,F10单步等来调试程序。