嵌入式的gdb调试

时间:2021-12-17 20:15:48

在开发过程中有很多问题如果用gdb进行调试跟踪会大大提高效率,但是我发现不少同事对于gdb调试概念比较模糊,特别是跨平台的调试,以至于放弃用gdb调试而影响排除bug的效率。
 因此我这里主要对跨平台调试做一个简要的说明。

 我们对机顶盒上的软件进行调试主要有两种方式,本地调试和远程调试。

 首先说一下本地调试。本地调试就是gdb、可执行程序和源代码全部在目标机器的文件系统上,也就是说要么他们都存在机顶盒上,要么用nfs mount在机顶盒上;可执行程序需要是用-g参数编译出来的;直接在机顶盒上执行gdb app就可以进行调试了,但是有个问题,应用程序中的调试信息只有源代码的行号信息,源代码级调试需要能够读取到源代码,gdb读取源代码是采用绝对路径的,也就是说你在盒子*问源代码的路径要和在你编译的机器上源代码的路径一致。比如说,你的源代码在/home/xxx/source下面,那么在盒子上你也要能在/home/xxx/source下面找到你的源代码。这点如何做到呢?我是这样做的,大家可以参考:把/home/xxx作为nfs export出来,然后在盒子上建立/home/xxx目录,mount -o nolock ip:/home/xxx /home/xxx,这样盒子上和你编译的机器*问源代码的路径就一致了,剩下的就按照一般的gdb操作就可以了

 再说一下远程调试。远程调试gdb被分为两个部分,一个gdbserver,一个在pc上运行的gdb。调试之前,将编译好的程序传到盒子上,传到盒子上的程序可以strip掉,以减小体积,pc上的程序不能strip,而且两个程序必须一致。然后在盒子上执行gdbserver host:port app,例如gdbserver a:1234 /tmp/app,其中host可以是任意字符,port即1234是监听端口号。执行之后程序会停止下来,等待gdb的连接。然后在pc上执行gdb app,进入gdb之后执行target remote stb_ip:port,这时候盒子上的gdbserver会显示gdb连接上来了,在gdb里面输入c程序即开始执行(注意不是r,因为程序已经开始执行,当前是被中断的状态,只需要c就可以了),后面就和一般调试一样了。

 远程调试还有一个问题,就是关于so库。大家编译环境如果是linux平台,那么按照上面的方法开始调试的时候会发现,gdb加载的库是本机上/lib下面的库,而不是对应盒子上的库,因而造成对库里面的函数显示不正确,严重影响调试结果的准确性,因此需要在执行c之前,设置一下lib库的正确路径:
set solib-absolute-prefix /opt/rosewood/dbox2/cdk/powerpc-tuxbox-linux-gnu
这样gdb加载库文件就会在/opt/rosewood/dbox2/cdk/powerpc-tuxbox-linux-gnu/lib下面去找了。我们可以把这个设置命令写到gdb运行目录下的.gdbinit文件里面,gdb每次启动会自动读取当前目录下的.gdbinit并执行。

 我们盒子上还缺少一个进行多线程调试必须用到的libthread_db库,,虽然/opt/rosewood/dbox2/cdk/powerpc-tuxbox-linux-gnu/lib下面有这个库,但是经过试验并不能正常使用,而且libthread_db和libpthread版本必须一致,因此大家可以用附件中的libthread_db和libpthread覆盖盒子上/lib下相应的文件。

 盒子上进行本机调试的gdb是/opt/rosewood/dbox2/cdkroot/bin/gdb,文件很大,如果要放到盒子上,可以先strip。
进行远程调试用的cygwin下的gdb和linux下的gdb,以及对应版本的gdbserver我这里都有,如果需要可以找我。注意,普通的gdb是不能远程调试ppc程序的。

 另外,我这里也有cygwin下面的交叉编译环境,对于安装vmware内存特别紧张,或者不方便进入linux下工作而又需要有自己的编译环境的同事特别有用,如果有需要也可找我。

 最后,需要注意的是mount nfs的时候一定要加-o nolock参数,否则会尝试建立文件锁,但盒子的nfs并不支持文件锁,尝试文件锁的超时时间大概是20分钟,所以不加-o nolock参数mount会20分钟才成功。
        
 我希望我写的这个东西能起到抛砖引玉的作用,希望大家都能讲讲自己开发时候的经验,提高大家的工作效率。同时,我所写的某些方法只是多种方法中的一种,也许有其他更适合的方法,如有补充,请不吝告知。如果大家有问题,也可以一起探讨