建立ARM平台上的交叉调试器gdb和gdbserver

2019-07-12 16:25发布

gdb-6.6使用了autoconf/automake,因此通过设置configure脚本的--target,--host,--prefix参数就可以方便的移植到别的平台。--target指定编译后的文件针对的是什么目标板,一般设置为交叉编译器的前缀,比如--target=arm-linux, --target=mips-linux,--target=armv5-linux-uclibc, --target的缺省值为i386-linux, 也就是PC机。 --host指定编译后的文件的运行环境,取值可以是i386-linux或者交叉编译器的前缀,缺省为i386-linux,--prefix指定要安装的目录。 1.到http://www.gnu.org/software/gdb下载gdb-6.6.tar.gz到/tmp解压到/opt下
   #cd /opt
   #tar xzvf /tmp/gdb-6.6.tar.gz
  
2、建立配置文件、编译
   gdb允许把编译配置和编译结果放到任意的目录,因此可以在gdb目录之外建立一个专门放编译文件的目录。
   #cd /opt
   #mkdir -p arm-gdb/build
   #cd arm-gdb/build    #/opt/gdb-6.6/configure --host=i386-linux --target=armv5-linux-uclibc --prefix=/opt/arm-gdb
   #make
   #make install
其中:host指定了运行环境为i386机器,target指定了需要调试的目标机环境(我使用的ARM toolchain是armv5-linux-uclibc-gcc,因此这样指定,如果是用arm-linux-gcc,则--target=arm-linux),prefix指定了编译后的结果存放的位置,也就是安装目录。
   如果在编译arm-linux-low.c这个文件时提示找不到“sys/reg.h”, 则修改arm-linux-low.c,注释掉#include "sys/reg.h"。    可以在/opt/arm-gdb/bin下找到可执行的armv5-linux-uclibc-gdb, armv5-linux-uclibc-gdbtui, armv5-linux-uclibc-run。 3、gdbserver的移植
   gdbserver要用到gdb源码目录下的一些头文件,因此无法在gdb源码目录之外建立编译文件。
   #cd /opt/gdb-6.6/gdb/gdbserver
   #vi build.arm        
   内容如下:
      ./configure --target=armv5-linux-uclibc --host=armv5-linux-uclibc --prefix=/opt/arm-gdb/gdbserver
      make
      make install
   #chmod +x build.arm
   #./build.arm    注意:此处target参数和host参数都要设置为armv5-linux-uclibc,因为gdbserver是放在目标板上运行的。
   编译后,可以在/opt/arm-gdb/gdbserver/bin下找到armv5-linux-uclibc-gdbserver,下载该文件到目标板并重命名为gdbserver,
   同时要下载gdbserver需要的库文件libthread_db-x.x.x.so,再建立两个符号链接libthread_db.so和libthread_db.so.1。 4、使用gdbserver
   在目标板上运行gdbserver
   #./gdbserver 192.168.0.2:2345 hello
 
   其中192.168.0.2为目标板的IP,可以写localhost,也可以不写。2345为gdbserver打开的端口,可以自己设置。
   #./gdbserver :2345 hello
 
   在宿主机上运行
   #armv5-linux-uclibc-gdb hello
   (gdb)target remote 192.168.0.2:2345
   (gdb)b main
   (gdb)continue    使用X-Windows下的DDD
   #ddd --debugger armv5-linux-uclibc-gdb    在DDD的GDB终端控制窗口中健入:
   (gdb) target 192.168.0.2:2345 6、问题
   移植的gdbserver可以和Host上的mips-linux-gdb连接上,但是run的时候gdbserver出现
   Killing inferior错误
   解决方法:因为执行完target命令后,目标板程序已经在运行,所有应该用continue命令而不是run命令。
7、附1:GDB的基本指令:    load:装入一个程序
   symbol-file:装入符号库文件,可以是用-g参数编译的可执行文件。
   f(ile):指定一个可执行文件进行调试,gdb将读取些文件的调试讯息,如f a.exe
   l(ist):列程序出源文件
   r(un) :装载完要调试的可执行文件后,可以用run命令运行可执行文件
   b(reak):设置断点(break point),如b 25,则在源程序的第25行设置一个断点,当程序执行到第25行时,就会产生中断;也可以使用b funcname,funcname为函数的名称,当程序调用些函数时,则产生中断
   c(ontinue):c命令可以另中断的程序继续执行,直到下一个中断点或程序结束
   p(rint):输入某个变量的值,如程序定义了一个int aa的就是,p aa就会输出aa的当前值
   n(ext):程序执行到断点时中断执行,可以用n指令进行单步执行
   s(tep):程序执行到断点时中断执行,可以用s指令进行单步执行进某一函数
   q(uit):退出GDB 8、附2:调试驱动程序和共享库   (1)调试LKM(Loadable Kernel Module)
  .在目标板上插入模块并输出map信息,查看.text入口地址:
   #insmod -m hello.ko > map
   #grep .text map  
   比如为0xc68c0060
  .在gdb中转入LKM的调试信息:
   (gdb) add-symbol-file hello.ko 0xc68c0060  /*注意必须是LKM .text的入口地址)
  .正常调试   (2)调试共享库
    .样例程序: 
    test.c:
    #include
    int test(int a, int b)
    {
    int s = a b;
    printf("%d/n", s);
    return s;
    }     main.c:
    #include
    extern int test(int a, int b);
    int main(int argc, char* argv[])
    {
    int s = test(10, 20);
    return s;
    }     Makefile:
    all: so main
    so:
    armv5-linux-uclibc-gcc -g test.c -shared -o libtest.so
    main:
    armv5-linux-uclibc-gcc -g main.c -L./ -ltest -o test.exe
    clean:
    rm -f *.exe *.so
   
    .编译并设置环境变量
 #make     在目标板上:
 #export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
 #gdbserver localhost:2345 ./test.exe     .运行gdb客户端
 #armv5-linux-uclibc-gdb
 (gdb)symbol-file test.exe
 (gdb)target remote 192.168.0.2:2345
 (gdb)b main
 (gdb)c     .查看libtest.so的代码在内存中的位置。(从gdbserver的输出或者用ps可以得到test.exe的进程ID,这里假设PID是11547)
     在目标板上:
     #cat /proc/11547/maps
 输出:  .........
 0076a000-0076c000 rwxp 0076a000 00:00 0
 00bbe000-00bbf000 r-xp 00bbe000 00:00 0
 00fcc000-00fcd000 r-xp 00000000 03:01 1238761 /root/test/gdbservertest/libtest.so
 00fcd000-00fce000 rwxp 00000000 03:01 1238761 /root/test/gdbservertest/libtest.so
 08048000-08049000 r-xp 00000000 03:01 1238765 /root/test/gdbservertest/test.exe
 08049000-0804a000 rw-p 00000000 03:01 1238765 /root/test/gdbservertest/test.exe
 ........
 
 由此可以知道:libtest.so的代码在00fcc000-00fcd000之间。    .查看libtest.so的.text段在内存中的偏移位置:
        armv5-linux-uclibc-objdump -h libtest.so |grep .text
 输出:
   .text 00000130 00000450 00000450 00000450 2**4
   即偏移位置为0x00000450 .回到板子上的gdb窗口,加载libtest.so的符号表。
 (gdb)add-symbol-file libtest.so 0x00fcc450
 (这里0x00fcc450 = 0x00fcc000 0x00000450)  .在共享库的函数中设置断点
 (gdb)b test  .继续调试共享库