在开发过程中有很多问题如果用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分钟才成功。
我希望我写的这个东西能起到抛砖引玉的作用,希望大家都能讲讲自己开发时候的经验,提高大家的工作效率。同时,我所写的某些方法只是多种方法中的一种,也许有其他更适合的方法,如有补充,请不吝告知。如果大家有问题,也可以一起探讨