gdb远程调试

来源:互联网 发布:relex软件模块 编辑:程序博客网 时间:2024/06/01 07:36
GDB调试器提供了两种不同的调试代理用于支持远程调试,即gdbserver方式和stub(插桩)方式。
这两种远程调试方式是有区别的。gdbserver本身的体积很小,能够在具有很少存储容量的目标系统上独立运行,因而非常适合于嵌入式环境;而stub方式则需要通过链接器把调试代理和要调试的程序链接成一个可执行的应用程序文件,如果程序运行在没有操作系统的机器上,那么stub需要提供异常和中断处理序,以及串口驱动程序,如果程序运行在有操作系统的嵌入式平台上,那么stub需要修改串口驱动程序和操作系统异常处理。显然,对于在有嵌入式操作系统支持下的开发而言,gdbserver比stub程序更容易使用。这里使用的是GDB+gdbserver的方式,建立远程调试的环境。
gdbserver是一个可以独立运行的控制程序,它可以运行在类UNIX操作系统上,当然,也可以运行在Linux的诸多变种。gdbserver允许远程GDB调试器通过targetremote命令与运行在目标板上的程序建立连接。
GDB和gdbserver之间可以通过串口线或TCP/IP网络连接通信,采用的通信协议是标准的GDB远程串行协议( RemoteSerial Protocol RSP)。
使用gdbserver调试方式时,在目标机端需要一份要调试的程序的拷贝,这通常是通过ftp或NFS下载到目标机上的,宿主机端也需要这信一份拷贝。由于gdbserver不处理程序符号表,所以如果有必要,可以用strip工具将要复制到目标机上的程序中的符号表去掉以节省空间。符号表是由运行在主机端的GDB调试器处理的,不能将主机端的程序中的符号表去掉。
虽然大部分的Linux发行版都已经安装了GDB,但是那都是基于PC的平台的,我们要使用的是在ARM平台上,所以要重新下载gdb的源码,并修改以适应自己的目标平台。可以从http://www.gnu.org/software/gdb/download,获得。这里使用的是GDB的最新的版本7.1。首先将下载到的gdb-7.1.tar.bz2复制到/home/zfz/gdb目录下。在控制台下输入下面的解包命令

#tar-jxvf gdb-7.1.tar.bz2

解包之后会生成gdb-7.1/目录,所有的源码都在这个目录下,在gdb目录下新建立一个目录arm-linux-gdb,把生成的可执行文件都放在这个目录下,
在gdb-7.1目录下,输入下面的命令,配置GDB源码:

./configure--target=arm-linux--prefix=/home/frank/gdb--program-prefix=arm-linux-

其中--target=arm-linux选项,表示针对的目标平台是运行linux内核的ARM体系结构的平台,后面的选项--prefix=/home/frank/gdb则是指定编译完成后的安装目录,最后一个选项--program-prefix=arm-
linux-用来指定在编译生成的二进制可执行文件名之前加上前缀,这里加上的前缀是arm-linux-。这样就可以和宿主机上的调试文件相区别。

make

把源文件编译成相应的目标文件,并连接成可执行的二进制文件。然后,再执行下面的命令,

make intall

执行完该命令后,就会在我们刚才建立的arm-linux-gdb目录下生成bin/,lib/,share/这几个子目录,其中在bin下有三个可执行文件分别为:arm-linux-gdb.arm-linux-run ,arm-linux-gdbui.arm-linux-gdb,就是我们需要的调试器。
编译完arm-linux-gdb之后,接下来就需要编译在目标板上运行的gdbserver了,在gdb/gdb7.1/gdb下有一个gdbserver的子目录,这个目录包括了编译gdbserver所需要的所有的东西。
首先,进行gdbserver目录

./configure--target=arm-linux--host=arm-linux

此时,如果要直接进行编译的话,会出现错误,

linux-arm-low.c:26:21:sys/reg.h: 没有那个文件 或目录
make:*****[linux-arm-low.0]Error1


这里的sys/reg.h是指/usr/include/sys/reg.h,在该文件中定义的寄存器都是针对x86平台的,对于运行
在ARM平台上的gdbserver显然是不对的,在configure后,将会生成一个config.h文件,在这个文件中定
义了相应的宏,在config.h中我们可以看到这样一个C语言的宏定义,


#defineHAVE_SYS_REG_H 1
在linux-arm-low.c文件中出错的代码行:
#ifdefHAVE_SYS_REG_H
#include<</SPAN>sys/reg.h>
#endif

这里我们只需要把conifg.h文件中的#defineHAVE_SYS_REG_H1注释掉就OK了。由于gdbserver是运行在ARM-linux平台上的,因此需要使用交叉编译器arm-linux-gcc,这可以通过给make加上CC参数来实现这里我使用的是默认的,你也可以使用一个绝对的路径来指定一个arm-linux-gcc.
所有的工作都已经完成了,只要把生成的gdbserver下载到目标板上,或者是通过NFS挂载到目标板上就可能进行远程的调试了,如果就是足够幸运的话,编译中没有出现什么错误的话,这样完全可以了,不过在我的系统上却不是那么幸运。我一直使用的是友善之臂的arm-linux-gcc-4.3.2交叉编译器,这个版本的编译器中,已经自带了arm-linux-gdb.
在终端中输入arm-linux-gdb -v 可以看到下面的信息

#make CC=arm-linux-gcc


GNUgdb(SourceryG++Lite 2008q3-72)6.8.50.20080821-cvs

Copyright(C) 2008Free SoftwareFoundation, Inc.
License GPLv3+: GNU GPL version 3or later<</SPAN>http://gnu.org/licenses/gpl.html>
This isfreesoftware: you arefree tochangeand redistributeit.
There is NO WARRANTY, to the extentpermitted by law. Type"showcopying"
and"showwarranty"fordetails.
This GDBwas configured as "--host=i686-pc-linux-gnu--target=arm-none-linux-gnueabi".
For bugreporting instructions, pleasesee:
<</SPAN>https:

这里可以看出arm-linux-gcc-4.3.2自带的arm-linux-gdb的版本是6.8版的,而我们一直编译的是7.1版本的。一开始我并没有注意arm-linux-gdb的版本信息,不过在使用过程中,我把用生成的gdbserver的7.1版本用NFS加载到目标板上,而在宿主机上用的arm-linux-gcc6.8版本,一直出现下面的错误:
先在目标机上运行下面的gdbserver,注意这里的IP地址是宿主机上的IP地址。

[root@Frankzfz]$gdbserver10.27.10.48:9000./test_seg_fault
Process ./test_seg_faultcreated;pid=760
Listening on port 9000
Remote debugging from host 10.27.10.48

然后在宿主机上运行

arm-linux-gdb/bin$arm-linux-gdb
GNU gdb (SourceryG++ Lite2008q3-72) 6.8.50.20080821-cvs
Copyright (C) 2008 Free SoftwareFoundation, Inc.
LicenseGPLv3+: GNU GPLversion3 or later<</SPAN>http://gnu.org/licenses/gpl.html>

Thisis freesoftware: you are free tochange and redistribute it.
There isNO WARRANTY, tothe extent permittedby law.Type"showcopying"
and "showwarranty" fordetails.
This GDBwas configured as "--host=i686-pc-linux-gnu--target=arm-none-linux-gnueabi".
For bugreporting instructions, pleasesee:
<</SPAN>https://support.codesourcery.com/GNUToolchain/>.

(gdb) target remote10.27.10.23:9000
Remote debugging using 10.27.10.23:9000
Malformed packet(b)(missingcolon): ore:0;
Packet:'T050b:00000000;0d:804ebdbe;0f:b0070040;thread:2f8;core:0;'

(gdb) symbol-filetest_seg_fault
Reading symbols from /home/zfz/kernel/fs/arm-linux-gdb/bin/test_seg_fault...done.
(gdb)break main
Breakpoint 1 at 0x84a8: filetest_seg_fault.c,line 7.
(gdb) info main
Undefined info command: "main". Try "helpinfo".
(gdb) info b
Num TypeDisp Enb Address What
1 breakpoint keep y 0x000084a8 in main attest_seg_fault.c:7
(gdb) c
Theprogram is not beingrun.
(gdb)

输入c命令时说是程序没有运行,可是程序已经在目标板上运行了,不用输入run命令,当输入target remote10.27.10.23:9000结束后,在minicom中可以看到目标板上的输出信息有了变化.

[root@Frankzfz]$gdbserver10.27.10.48:9000./test_seg_fault
Process ./test_seg_faultcreated;pid=760
Listening on port 9000
Remote debugging from host 10.27.10.48
readchar: Got EOF
Remote side has terminated connection. GDBserver will reopen theconnection.
Listening on port 9000

在这里捣鼓了一整天没有弄明白错误在那里,看到了arm-linux-gdb和gdbserver的版本不匹配,所以就变换arm-linux-gdb,这里要把arm-linux-gdb加入到.profile文件中,或者environment文件中,

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/j
dk1.6.0_17/bin:/home/zfz/kernel/fs/arm-linux-gdb/bin:/home/zfz/linux-
tool/usr/local/arm/4.3.2/bin"

当时一直在,arm-linux-gdb/bin目录下执行,其实执行的也都是arm-linux-gcc-4.3.2中的arm-linux-gdb,如果这样你看到的版本信息还是6.8版本的话,也可以直接在arm-linux-gcc-4.3.2中把arm-linux-gdb文件删除掉。
这样再一次查看arm-linux-gdb的信息。

GNU gdb(GDB) 7.1
Copyright (C) 2010Free SoftwareFoundation, Inc.
License GPLv3+: GNU GPL version 3or later<</SPAN>http://gnu.org/licenses/gpl.html>

This isfreesoftware: you arefree tochangeand redistributeit.
There is NO WARRANTY, to the extentpermitted by law. Type"showcopying"
and"showwarranty"fordetails.
This GDBwas configured as "--host=x86_64-unknown-linux-gnu--target=arm-linux".
For bugreporting instructions, pleasesee:
<</SPAN>http://www.gnu.org/software/gdb/bugs/>.

使用GDB进行调试,首先,我的宿主机的IP10.27.10.48,开发板上的IP 10.27.10.23在开发板上运行gdbserver 10.27.10.48:9000test,这里是通过NFS,把要调试的程序加载到目标版上面的。这样就可从在宿主机上运行。

zfz@zfz:~/kernel/fs/arm-linux-gdb/bin$./arm-linux-gdbtest
./arm-linux-gdb: Symbol`acs_map
' has different size inshared object, consider re-linking
GNU gdb (GDB) 7.1
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistributeit.
There is NO WARRANTY, to the extent permitted by law. Type "showcopying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu--target=arm-linux".
For bug reporting instructions, please see:
< http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from/home/zfz/kernel/fs/arm-linux-gdb/bin/test...done.
(gdb) target remote 10.27.10.23:9000
Remote debugging using 10.27.10.23:9000
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0x400007b0 in ?? ()
(gdb) l
Cannot access memory at address 0x0
1 #include
2 int main( void )
3 {
4 int i=2;
5 int x, y;
6
7 x=(++i);
8 printf(" %d %d\n", i,x);
9 x+=(++i);
10 printf(" %d %d\n", i,x);
(gdb) l
11 x+=(++i);
12 printf(" %d %d\n", i,x);
13 i=2;
14 y=(i++)+(i++)+(i++);
15 printf(" %d %d\n", i,y);
16
17 return 0;
18 }
19
(gdb) break 9
Breakpoint 1 at 0x83b8: file test.c, line 9.
(gdb) c
Continuing.
Error while mapping shared library sections:
`/lib/libc.so.6'
: not in executableformat:Fileformatnot recognized
Errorwhilemapping shared library sections:
/lib/ld-linux.so.3: No suchfileordirectory.

Breakpoint 1, main () at test.c:9
9 x+=(++i);
(gdb) step
10 printf(" %d%d\n", i,x);
(gdb) next
11 x+=(++i);
(gdb) next
12 printf(" %d%d\n", i,x);
(gdb) next
13 i=2;
(gdb) next
14 y=(i++)+(i++)+(i++);
(gdb) next
15 printf(" %d%d\n", i,y);
(gdb) next
17 return 0;
(gdb) next
18 }
(gdb)next

在目标板上的输出:

[root@Frankzfz]$gdbserver10.27.10.48:9000./test
Process ./testcreated;pid=746
Listening on port 9000
Remote debugging from host 10.27.10.48
3 3
4 7
5 12
5 6

补充:前面还有库文件错误的问题,这里可以通过下面这样的方法的来解决。需要说明的是,远程调试,可能程序动态库,我们可以这样设置:

set solib-absolute-prefix/nfsroot/rootfs
set solib-search-path/nfsroot/rootfs/lib

调试找不到源代码,如下设置:

directory xfer-1.0.0/src/

下面是调试的情况:

(gdb)setsolib-absolute-prefix/home/kernel/fs/root_nfs
(gdb)setsolib-search-path/home/kernel/fs/root_nfs/lib
(gdb) target remote10.27.10.23:9000
Remote debugging using 10.27.10.23:9000
Reading symbols from /home/kernel/fs/root_nfs/lib/ld-linux.so.3...(nodebugging symbols

found)...done.
Loaded symbols for /home/kernel/fs/root_nfs/lib/ld-linux.so.3
0x400007b0 in ??() from/home/kernel/fs/root_nfs/lib/ld-linux.so.3
(gdb) l
3 {
4 inti=2;
5 intx,y;
6
7 x=(++i);
8 printf(" %d%d\n", i,x);
9 x+=(++i);
10 printf(" %d%d\n", i,x);
11 x+=(++i);
12 printf(" %d%d\n", i,x);
(gdb) l
13 i=2;
14 y=(i++)+(i++)+(i++);
15 printf(" %d%d\n", i,y);
16
17 return 0;
18 }
19
(gdb) b 8
Note:breakpoint 1 also set at pc0x83a8.
Breakpoint 2 at 0x83a8: file test.c,line 8.
(gdb) c
Continuing.

Breakpoint 1, main () at test.c:8
8 printf(" %d%d\n", i,x);
(gdb) n
9 x+=(++i);
(gdb) b 12
Breakpoint 3 at 0x8400: file test.c,line 12.
(gdb) n
10 printf(" %d%d\n", i,x);
(gdb) n
11 x+=(++i);
(gdb) n

Breakpoint 3, main () at test.c:12
12 printf(" %d%d\n", i,x);
(gdb) n
13 i=2;
(gdb) n
14 y=(i++)+(i++)+(i++);
(gdb) n
15 printf(" %d%d\n", i,y);
(gdb) n
17 return 0;
(gdb) n
18 }
(gdb) n
0x4003b004 in __libc_start_main ()
from /home/kernel/fs/root_nfs/lib/libc.so.6
(gdb)

0 0