您的位置:首页 > 其它

基于hisilicon的arm平台搭建gdb+gdbserver调试环境

2016-08-30 14:32 761 查看
一、安装GDB及GDB server

1.1 GDB简介

GDB调试环境由宿主机GDB和目标开发板的GDB server共同构成,两者通过串口或TCP连接。使用GDB标准串行协议协同工作,实现对目标机的系统内核和上层应用的监控和调试功能。

GdbServer是GDB的一个组件,但通常不随发行版本的GDB一同发布,需要用户自行编译GDB的源代码包得到相应的GDB和GDBServer,可以从下载地址:http://ftp.gnu.org/gnu/gdb/,或者百度获取下载地址。

1.2 安装GDB

本例中目标板为Hi3518C,使用的GDB是GDB 7.2,宿主机为ubuntu10.4(vmware),本机开发环境为win7 x64。在获取源码gdb-7.2a.tar.gz(24MB)后,将其解压:

1.tar zxvf gdb-7.2.tar.gz

2.配置GDB,./configure –target=arm-linux –enable-sim –prefix=/opt/arm-gdb(其中prefix为设置您所需要的安装目录)

3.编译及安装,执行make,然后执行make install

4.执行结束后,在/opt/arm-gdb/bin目录下可看到生成的应用程序。



5.将三个应用程序拷贝到/usr/local/bin或则在文件/etc/profile最后加上export
PATH=$PATH:/opt/arm-gdb/bin 使刚配置的环境变量生效: source/etc/profile

1.3 安装GDB server

在编译安装GDB后,进入到目录gdbserver下,我的目录为/home/arm/gdb/gdb-7.2/gdb/gdbserver,在该目录下进行配置。在命令行里输入:./configure –target=arm-linux –host=arm-linux。接着,配置所采用的交叉编译器。我用的是Hi3520D,所用的交叉编译器为arm-hisiv100nptl-linux-gcc,因此我在命令行里输入


make CC=/opt/hisi-linux-nptl/arm-hisiv100-linux/target/bin/arm-hisiv100nptl-linux-gcc

注意,一定要写交叉编译器的绝对路径!在make的过程中可能会出错,提示:

“linux-x86-low.c error: sys/reg.h: No such file or directory”。

这时候,在#ifdef HAVE_SYS_REG_H这句前面加上一句:

#undef HAVE_SYS_REG_H

然后重新编译即可。编译完成后,在gdbserver目录下就会生成gdbserver和gdbreplay。,这两个文件就可以放在目标板上和开发编译的程序一起进行调试。而主机上可以采用编译出来的arm-linux-gdb作为主机端运行的调试。



二、测试代码及应用程序生成

为简单起见,我们就用一个十余行的C程序进行GDB调试演示。以下是C代码:
<code class="hljs perl has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#include<stdio.h></span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> add(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> a,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> b) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> a+b; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc ,char* argv[]) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> num1=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,num2=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">time</span>; const <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> plusCount=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">time</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">time</span>!=plusCount;++<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">time</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%dplus</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%d</span>=<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%d</span>.\r\n"</span>,num1,num2,num1+num2); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%dplus</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%d</span>=<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%d</span> byfunc.\r\n"</span>,num1,num2,add(num1,num2)); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>


在命令行里输入:arm-hisiv100nptl-linux-gcc test.c -g -o test 即可生成应用程序test。注意,编译时一定要加入-g参数,表示应用程序调试。



三、GDB+GDB server nfs调试方法

进行调试前首先需要保证目标开发板与宿主机支持nfs。在宿主机上安装samba教程可自行百度获取,或者参考文章附录。本例中宿主机IP为218.192.171.55,目标板IP为218.192.171.72,开发环境(win7 x64)IP为218.192.171.78,宿主机的共享目录为/mnt/nfs。

1.将gdbserver和test拷贝到/mnt/nfs,更改应用程序权限:chmod 777 gdbserver test。

2.通过telnet或者minicom远程到目标板,挂载nfs:

mount -t nfs -o nolock -o tcp 218.192.171.55:/mnt/nfs /nfsroot



3.进入/nfsroot目录,输入指令:

./gdbserver 218.192.171.55:5000 test

其中,218.192.171.55为宿主机IP,5000表示目标开发板的调试端口(一般任意大于1024的端口号均可)。



4.在宿主机命令行输入:arm-linux-gdb test,接着输入:

target remote 218.192.171.72:5000

连接成功后,出现如下提示:



5.在宿主机命令行输入:b add 设置断点为函数add,然后再输入’c’,执行程序。效果如下:



目标板端输出提示如下:



6.输入’c’,继续运行程序,直到结束。然后输入’q’退出gdb。效果图如下:





注,本例仅进行简单测试,其它调试命令可参考附录。

四、GDB+GDB server串口调试

由于本人开发板未配有串口调试,故以下内容为搬运过来的。调试步骤如下:

1.如果你用串口1调试test的话,你就要现在板子上运行命令:gdbserver hello /dev/ttyS0 (详情可以参考gdbserver目录下的readme文件)。

2.在宿主机命令行输入:

arm-linux-gdb test

3.然后配置到串口,在宿主机命令行输入:

set remotedevice /dev/ttyS0(这里设置串口1)

set remote baud 9600 (这里设置串口波特率)

set debug remote 1(可选)

target remote /dev/ttyS0

4.操作到这儿,gdb就应该和gdbserver联系上了。接下来的操作和nfs中的操作保持一致,就不再赘述。

需要注意的地方:
1, 编译gdbserver时,一定要注意你的交叉编译器的绝对地址和你的开发板是什么类型的。如果交叉编译器是arm-linux-gcc,在配置的时候,则应该键入 cc=交叉编译器的绝对地址/arm-linux-gcc ./configure --host=arm-linux;这个是比较关键的地方,因为在开发板上运行的gdbserver必须要编译成ARM
ELF格式,否则无法运行。我所用的交叉编译器是arm-uclibc-linux-gcc,所以配置必须是
CC=/opt/hisi-linux-nptl/arm-hisiv100-linux/target/bin/arm-hisiv100nptl-linux-gcc
./configure --host=arm-uclibc-linux ,由于网上有人写经验说arm-uclibc-linux-gcc的交叉编译器在配置host的时候也是用arm-linux的,但是这样编译出来的gdbserver由于跟交叉编译器不匹配,所以格式会是intel 80383 elf的,而这种格式在开发板上是不能运行的。查看文件格式可以用命令file查看。正确的格式应该是这样:
键入file gdbserver
gdbserver: ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), not stripped
当查看到的gdbserver格式如上所示时,该gdbserver就是可以在开发板上运行的。
2, 编译应用程序的目标码时,一定要加上-g 编译,由于目标码也是在开发板上运行的,所以格式也必须是 arm elf的,查看方式同上。
编译格式为:arm-uclibc-linux-gcc –g –o 程序 目标码
键入file test
hello: ELF 32-bit LSB executable, ARM, version 1, statically linked, not stripped
如果上面file gdbserver输出的是stripped而不是not
stripped也是不能进行gdb调试的。所以在编译时就不能加strip选项了。。。。

3, 利用nfs挂载目录的时候,如果挂载失败,原因可能有二个:1,nfs未启动;2,网络未连通;可以使用mount 192.168.1.124(为本机的ip):/home /mnt 测试是否开通nfs服务。网络是否连通用ping 测试。
另外附上nfs配置的教程:ubuntu下配置nfs挂载
4, 网络无法ping通时,可以通过ifconfig –a查看网卡状态,利用ifconfig对网络IP重新配置,也可以通过route add修改路由。
在搭建环境过程中,如果出现指令不能执行,则必定是权限问题。在宿主机可以改变身份登录,修改权限,执行命令。对要运行的gdbserver和test可以用chmod命令改变他们的权限。Chmod
777 gdbserver ;chmod 777
test,使所有人都可以对他们进行读写执行操作。

错误处理:

编译ARM用的GDB时出现error: no termcap library found

checking for library containing gethostbyname... none required

checking for library containing socketpair... none required

checking for library containing waddstr... no

checking for library containing dlgetmodinfo... no

checking for library containing tgetent... no

configure: error: no termcap library found

make[1]: *** [configure-gdb] 错误 1

解决方法:sudo apt-get install libncurses5-dev
出现/bin/sh
./libtool --mode=compile gcc -DHAVE_CONFIG_H -I. -I.././bfd -I. -I. -I.././bfd -I.././bfd/../include -I.././bfd/../intl -I../intl -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror -g -O2 -c -o opncls.lo opncls.c

gcc -DHAVE_CONFIG_H -I. -I.././bfd -I. -I. -I.././bfd -I.././bfd/../include -I.././bfd/../intl -I../intl -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror -g -O2 -c opncls.c -o opncls.o

In file included from opncls.c:24:0:

opncls.c: In function 'bfd_fopen':

bfd.h:537:65: error: right-hand operand of comma expression has no effect [-Werror=unused-value]

#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE)

^

opncls.c:234:5: note: in expansion of macro 'bfd_set_cacheable'

bfd_set_cacheable (nbfd, TRUE);

^

cc1: all warnings being treated as errors

Makefile:1010: recipe for target 'opncls.lo' failed

make[4]: *** [opncls.lo] Error 1

make[4]: Leaving directory '/home/ygl/smb_share/work/nfs_pro/gdb-6.5/bfd'

Makefile:1029: recipe for target 'all-recursive' failed

make[3]: *** [all-recursive] Error 1

make[3]: Leaving directory '/home/ygl/smb_share/work/nfs_pro/gdb-6.5/bfd'

Makefile:924: recipe for target 'all' failed

make[2]: *** [all] Error 2

make[2]: Leaving directory '/home/ygl/smb_share/work/nfs_pro/gdb-6.5/bfd'

Makefile:2716: recipe for target 'all-bfd' failed

make[1]: *** [all-bfd] Error 2

make[1]: Leaving directory '/home/ygl/smb_share/work/nfs_pro/gdb-6.5'

Makefile:629: recipe for target 'all' failed

make: *** [all] Error 2

这是源码中有些函数定义不规范,用对函数格式非常严格的GCC 4.3编译就会出错,而GCC 4.1 不会报错。

自然不乐意重新安装GCC退回到4.1的版本来解决这个问题,我是这样做的。

解决方法:首先进入编译出错的bfd文件夹中修改makefile,去掉-Werror,然后make,还是会报错,从错误中可以看出是同样的错误,进入编译出错的目录opcodes下,修改makefile,去掉-Werror,然后make编译通过。

五、附录

本博文参考了多家之言,并且肯定存在许多不足。如果哪里表述有问题,还烦请指正。另外,推荐以下网页,可进一步学习相关内容。

1.GDB在ARM上的调试实战

http://blog.chinaunix.net/uid-2630593-id-2138581.html

2.CentOS 6.3下Samba服务器的安装与配置

http://www.cnblogs.com/mchina/archive/2012/12/18/2816717.html

3.GDB下载地址:

http://ftp.gnu.org/gnu/gdb/

4.GDB十分钟教程

http://blog.csdn.net/liigo/article/details/582231

出处:http://blog.csdn.net/kxc0720/article/details/45953563
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: