GDB or LLDB?
较新的安卓NDK已经没有包括gdbserver了,而且安卓官网也说了,后续不会支持gdb了。我自己之前费了很大的功夫,去交叉编译一个gdbserver,但最后用起来一大堆莫名其妙的问题。所以还是使用LLDB吧。
获取相应的工具
https://developer.android.google.cn/ndk/downloads
这里下载NDK,直接下载最新版就好(太旧的安卓版本可以适当降低ndk的版本?)。解压之后在里面找到对应平台的lldb-server,将这个二进制文件adb push进去就行了。
生成带有调试信息的程序或者库
需要添加调试信息,即在Android.mk或者bp中添加LOCAL_CFLAGS += -g,或者通过在ndk-build命令行上传递NDK_DEBUG=1。或者在cppflags里添加"-g","-O0"选项。然后编译即可。注意这里无论是so库,还是可执行文件,只要是想断点调试的源码都必须要附带调试信息。
启动lldb-server
lldb-server platform --server --listen *:12345
这里比较需要注意的是,尽量在一个可读文件系统并且有较大权限的里执行,因为lldb与lldb-server连接时,有可能需要将一些可执行二进制文件push进去,并执行,如果文件系统不对的话,有可能会出现无论怎么样chmod +x都无法添加执行权限(比如sdcard)。可以试试cache文件夹。
CodeLLDB插件
搜索下载vscode插件 CodeLLDB。
launch.json
进入vscode调试界面,点击创建一个launch.json文件,已有launch.json文件的话,可以点击小齿轮,编译它。
例子如下
{"configurations": [{"name": "Remote launch","type": "lldb","request": "attach","program": "out/soong/.intermediates/external/libhiddroid/test/test_demo/android_arm64_armv8-a/unstripped/test_demo", // Local path."initCommands": ["platform select remote-android", // For example: 'remote-linux', 'remote-macosx', 'remote-android', etc."platform connect connect://172.20.11.154:12345","settings set target.inherit-env false", // See note below."platform process list"],"pid": "5262","env": {"PATH": "...", // See note below.},}],}
开始调试
然后点击绿色小三角就可以进行打断点调试了。
推荐直接使用attach,因为就算直接调试可执行二进制文件,也可以多开一个终端执行它,还可以方便输入信息来响应程序,然后找到pid,进行attach即可。
attach成功后,就可以开始调试了。可执行二进制内的符号一般是直接加载好的,(没有的话可以在调试控制台执行file 源码.cpp)。但其链接的动态库,需要手动file命令来加载符号。你也可以将这些file命令添加进initCommands里。
BUG
事情一般不会过于顺利。
如果你使用LLDB调试时,发现基本全都是汇编代码,即使是使用了file命令,也没办法看见c/c++代码,打断点也停不下来,那说明编译出来的文件调试信息出问题了。
dwarf版本
如果报的错有关dwarf版本的话,一般可能是dwarf版本过高,lldb/gdb无法支持什么的。只要下的nkd比较新,一般不会报这种错。这里可以使用objdump --dwarf=info 二进制文件
来查看dwarf的一些信息。也可以添加一些flag比如-gdwarf-4
来限制dwarf版本。(记得,参与链接编译的都要加这个)。但一般还是推荐更新LLDB工具,尽量使用高版本的dwarf。
调试信息不对劲
使用objdump -g 二进制文件
来查看调试信息。如果输出的内容非常多,甚至溢出终端的屏幕,那说明一般没问题,如果比较少,而且内容看起来信息熵很小,那多半出问题,这种情况可能会导致调试时只能看到汇编代码。
这种情况首先就是去排查是否添加了-g -O0
等等flag。可以对编译的工具链添加-v参数,让每条编译指令都答应出来。或者编译项目时,太难去找哪条编译指令的话,可以尝试添加一些必定会报错的flag。比如-jjjjjjjjjjjjjjjjjjjjjj
,这样就可以看看有没有这些参数。
在确定有这些参数,而且过后没有什么流程去strip的话,那就可以怀疑一下,编译使用的工具链了。有些厂商会使用一些自己魔改过的编译链工具,如果编译的源码比较少的话,你可以使用上述方法截取出命令自行替换工具链。编译文件多的话……我暂时也想不到什么好办法。
自己自行替换了工具链,进行编译、链接(链接的命令可以添加必定会报错的LDFLAGS,截取出来)后,使用objdump -g 二进制文件
查看,如果信息很多的话,一般就没问题了。