OpenHarmony标准系统实践之GDB调试 原创 精华
作者:赵军霞
1.简介
OpenHarmony系统层代码大部分是C++ 实现的,运用了C++ 继承多态等特性,使得代码框架灵活,但是对于开发者代码走读,整理实现逻辑不太友好。利用GDB调试导出调用栈、查看中间变量状态,则能帮助开发者快速清晰化实现逻辑链,不仅提升代码走读效率,而且提高Issue定位效率。
2.实践过程
本文从以下几方面介绍使用GDB调试OpenHarmony源码的过程与案例:
-
如何制作OpenHarmony之GDB;
-
如何准备可调试动态库;
-
如何使用GDB调试动态库;
-
案例展示;
2.1 制作OpenHarmony之GDB
如果已经有配套版本的GDB程序了,可以跳过这节直接进入下一步:2.3.1 上传GDB,将GDB工具上传到目标开发板。另外,为了方便,以下所有命令都在ubuntu编译机的root用户下进行。
2.2.1准备arm-Linux交叉编译环境
-
新建目录
新建目录,路径如下:
/usr/local/ARM-toolchain/
-
获取工具包
使用如下命令或者从浏览器手工下载arm-Linux交叉编译工具包
wget https://releases.linaro.org/components/toolchain/binaries/latest-5/arm-linux-gnueabi/gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabi.tar.xz
-
解压工具包
将arm-Linux交叉编译工具包放在/usr/local/ARM-toolchain/目录下,使用以下命令解压:
tar xvf gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabi.tar.xz
-
将该版本gcc的bin路径配置到系统环境变量PATH中,以便后续脚本执行能找到bin下的工具程序。
export PATH=$PATH:/usr/local/ARM-toolchain/gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabi/bin/
2.2.2下载、编译GDB源码包
示例使用的版本是gdb-8.2.1.tar.gz,在以下路径获取
https://mirrors.ustc.edu.cn/gnu/gdb/
在ubuntu编译机上任意建一个目录存放该包。如:
/home/kaihong/zzcgdb/gdb
解压
tar zxvf gdb-8.2.1.tar.gz
进入解压后的文件目录
cd gdb-8.2.1
在该目录下新建build目录,用于生成Makefile文件
mkdir build
进入build目录
cd build/
使用…/configure生成gcc编译的Makefile文件,命令如下:
CC="/usr/local/ARM-toolchain/gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-gcc" CXX="/usr/local/ARM-toolchain/gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-g++" ../configure LDFLAGS=-static --prefix=$HOME/glibc32-2.6 -target=arm-linux-gnueabi --host=arm-linux-gnueabi
说明:
-
这里我用CC=和CXX=强行指定了arm编译器路径,因环境上/usr/bin/目录下有x86的gcc和g++,它们在PATH中可能会被优先找到,这样编出来就不是arm版的GDB程序了。
-
必须要指定LDFLAGS=-static (静态链接),这样编译时会把需要的库都一起编译进来,编译的结果会稍大一些,但能保证包含了所有需要的库。如果不指定这个参数,默认为动态链接方式,编译的GDB文件放到目标板上运行时可能会因找不到所需的依赖库而无法启动。
-
这一步执行完成后,builld目录下就成功生成了MakeFile文件。
开始编译
make -j32
make install
两步都成功后,在build/gdb/目录下就生成了目标文件GDB
可通过file命令检查编处的是否确实是arm版的GDB
2.2 准备可调试动态库
开发板中将待调试的libnapitest.z.so动态库替换为携带调试信息的动态库
-
源码当中找到携带调试信息的动态库,命令如下:
harmony@Ubuntu-64:~/OpenHarmony/out$ find ./ -name "*libnapites*" | xargs ls -lh -rwxrwxr-x 1 harmony harmony 47K 8月 5 09:29 ./rk3568-khdvk/innerkits/ohos-arm/napitest_interface/napitest/libnapitest.z.so -rwxrwxr-x 1 harmony harmony 766K 8月 5 09:28 ./rk3568-khdvk/lib.unstripped/napitest/napitest_interface/libnapitest.z.so -rwxrwxr-x 1 harmony harmony 47K 8月 5 09:28 ./rk3568-khdvk/napitest/napitest_interface/libnapitest.z.so -rw-rw-r-- 1 harmony harmony 10K 7月 29 18:07 ./rk3568-khdvk/packages/phone/NOTICE_FILES/system/lib/module/libnapitest.z.so.txt -rwxrwxr-x 1 harmony harmony 47K 8月 5 09:35 ./rk3568-khdvk/packages/phone/system/lib/module/libnapitest.z.so
其中./rk3568-khdvk/lib.unstripped/napitest/napitest_interface/目录下的动态库(文件大小比其他文件大)为携带符号信息动态库,将该动态库下载到本地。
-
将携带符号信息的libnapitest.z.so动态库替换开发板中/system/lib/module目录下的libnapitest.z.so动态库。
由于/system/lib/module目录下只有读写权限,无法直接将镜像上传到/system/lib/module目录下。因此可将镜像上传到data目录下,修改文件权限后,再将/system/lib/module目录下的libnapitest.z.so镜像替换为携带符号信息的镜像。具体操作命令如下:
PS E:\hdc> .\hdc_std.exe file send .\libnapitest.z.so /data FileTransfer finish, Size:784348 time:134ms rate:5853.34kB/s PS E:\hdc> .\hdc_std.exe shell # mount -o remount,rw / # cp /data/libnapitest.z.so /system/lib/module/
2.3 使用GDB调试动态库
2.3.1上传GDB
有了编译好的arm版GDB,把它上传到目标开发板。
这里我们以hdc_std工具上传为例,如果你有其他的文件传输方式也可以。
-
准备GDB和hdc_std工具
在window主机上建一个目录,将ubuntu虚拟机上编译好的GDB拷贝过来,并拷贝一个hdc_std工具到该目录。
将开发板与window主机连接,确保hdc_std工具能够连接访问。在windows目录中开启第一个cmd命令行窗口,执行hdc_std shell 连接开发板。
-
上传GDB程序
在windows目录下再开启第二个cmd命令行窗口,执行如下命令将GDB文件上传到开发版/data目录下(可以是任意目录,gdb大小约70M)
hdc_std file send gdb /data
发送成功后,可以回到第一个cmd窗口中看到/data目录下的GDB程序
备注:
有的开发板在上传时可能会报没有写权限,如果遇到,可在hdc_std shell中执行如下命令打开读写权限:
mount -o remount,rw /
2.3.2调试GDB
进入/data目录,先给gdb程序加上可执行权限:
chmod +x /data/gdb
然后运行/data/gdb,出现如下信息说明GDB已经可以正常使用了。
如果不想每次执行都带完整路径, 可以在系统默认运行路径 (/bin) 下给/data/gdb做一个软链接:
ln -s /data/gdb /bin/gdb
2.4 案例展示
Issue:zzcnative2的应用调用NAPI接口add(8,3),接口返回值预期是11,实际结果为5
以上述Issue为例,展示一下GDB调试的过程。
在开发板上加载运行zzcnative2应用,该应用包含部分c++的native代码,可以使用GDB对其进行调式。
-
找到需要跟踪的进程号。
OpenHarmony的应用进程都是由应用孵化器(appspawn)创建的,可以先执行如下命令找到孵化器的进程号(92)。
ps -ef | grep appspawn
-
然后再找所有父进程为孵化器(92)的进程
ps -ef | grep 92
-
找到要调试的程序进程号(1167)后,执行如下命令运行GDB并挂到目标进程中
gdb attach 1167
-
在需要的地方打上断点,然后让程序继续运行
在App上进行相关操作,触发断点所在的业务代码流程。
然后就可以开始各种调试手段了,如查看调用栈,打印变量,设置观测点等等,具体请参考GDB使用手册。
-
定位问题
设置断点位置为Add入口,查看运行时入参value0、value1以及运行结果ret的值,发现逻辑与预期不一致,进一步使用list查看代码,发现“double ret = value0 – value1”符号错误,问题快速成功定位。
另外使用bt命令可打印调用栈信息,其他命令大家可以自己试一下。
3. 总结
对于开发者来说,高效的调试手段至关重要,熟练使用GDB,可以帮忙大家提高代码走读、Issue定位效率,希望本次分享给大家一些启发,共同参与到OpenHarmony开发效率提升建设中。
更多原创内容请关注:深开鸿Kaihong
入门到精通、技巧到案例,系统化分享OpenHarmony开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
大佬,GDB工具是否通用的, 能上传一份吗?
GDB确实是调试神器
非常全面的GDB调试讲解
底层还是必须要用C或C++才更高效,不过确实对调试不太友好
gdb 32位工具包见附件
我尝试了一下,发现可能是由于GLIB的版本和作者的不一样,工具链和源码版本相同的情况下仍然编译失败,报“fntcl64无定义“,通过修改源码才勉强编译通过
请问编译好后,运行GDB直接报Signal 31退出是什么情况呢?包括
32bit_arm_gdb.zip里边解压出来的也是,master镜像
不错不错,很详细
gdb输入list命令无法显示源码
想问问能支持鸿蒙NEXT吗?