【第21期】观点:人工智能到底用 GPU?还是用 FPGA?

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

原创 2016年08月30日 14:32:30

一、安装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



版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

VMWare+Ubuntu所遇问题解决之总结

实际上,本文内容不是原创,而是汇总了使用VMWare Worksation 10 + Ubuntu12 or 14所遇到的问题,并列出了网上针对这些问题的解决方案(经过本人验证通过的): 一、 VM...

程序中出现unexpected end of file in macro expansion

这是在宏扩展的文件意外结束的意思,说的是你用宏时没有收尾: 例如 #define max(a,b) a>b?a:b 假如你用宏的时候你缺了右括号   如 max(3,5;  编译器就会报这种错,...

C Reference Manual Reading Notes: 010 Definition and Replacement

1. synopsis     The #definepreprocessor command causes a name (identifier) to become defined as amac...
  • cppgp
  • cppgp
  • 2009-08-24 21:45
  • 866

m4

收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)