GNU Toolchain —— (三)gdb 调试

嵌入式系统中的gdb调试

1、首先你要下在gdb的源代码,然后把它编译并安装成你的平台的xxx-linux-gdb。比如说arm-linux-gdb的编译放法如下:
1) 下载GDB的源代码,如gdb-5.0
2) 执行如下指令:
cd gdb-5.0
./configure --target=arm-linux
make(生成gdb)
make install(生成arm-linux-gdb,并存入/usr/local/bin/)
2、在gdb源代码里有一个gdbserver目录,在这个目录下运行:
make gdbserver
生成gdbserver。当然,你要把gdbserver的Makefile中的CC设置成你的平台的交叉编译工具。
3、把gdbserver和待调试的应用程序下到你的板子上;而应用程序编译的时候要加-g选项,它的源代码要放在pc机上,用(正对你的平台的)xxx-linux-gdb调试时需要。
4、如果你用串口1调试hello的话,你就要现在板子上运行命令:
gdbserver hello /dev/ttyS0
这时gdbserver就在等待gdb的应答信号了。
5、然后在pc机上运行命令:
xxx-linux-gdb hello
6、在xxx-linux-gdb里敲入入下命令:
set remotedevice /dev/ttyS0(这里设置串口1)
set remote baud 9600 (这里设置串口波特率)
set debug remote 1(可选)
target remote /dev/ttyS0
操作到这儿,gdb就应该和gdbserver联系上了。
5) 运行其它GDB命令进行调试。
BTW:gdbserver可能不会一下子就能便已成功,你可能要修改一些配置,甚至要修改源代码。关键在于它里面针对串口的代码可能需要修改(我以前就遇到这样的问题)。




远程调试环境由宿主机GDB和目标机调试stub共同构成,两者通过串口或TCP连接。使用 GDB标准程串行协议协同工作,实现对目标机上的系统内核和上层应用的监控和调试功能。调试stub是嵌入式系统中的一段代码,作为宿主机GDB和目标机调试程序间的一个媒介而存在。

就目前而言,嵌入式Linux系统中,主要有三种远程调试方法,分别适用于不同场合的调试工作:用ROM Monitor调试目标机程序、用KGDB调试系统内核和用gdbserver调试用户空间程序。这三种调试方法的区别主要在于,目标机远程调试stub 的存在形式的不同,而其设计思路和实现方法则是大致相同的。

而我们最常用的是调试应用程序。就是采用gdb+gdbserver的方式进行调试。在很多情况下,用户需要对一个应用程序进行反复调试,特别是复杂的程序。采用GDB方法调试,由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,通常采用gdb+gdbserver的方式进行调试。 gdbserver在目标系统中运行,GDB则在宿主机上运行。

行GDB调试,目标系统必须包括gdbserver程序,宿主机也必须安装GDB 程序。一般Linux发行版中都有一个可以运行的GDB,但开发人员不能直接使用该发行版中的GDB来做远程调试,而要获取GDB的源代码包,针对arm 平台作一个简单配置,重新编译得到相应GDB。GDB的源代码包可以从 http: //ftp.cs.pu.edu.tw/linux/sourceware/gdb/releases/下载,最新版本为gdb-6.4。下载到某个目录,笔者下载到自己的用户目录:/home/vicky。

下载完后,进入/home/vicky目录,配置编译步骤如下:
#tar jxvf gdb-6.4-tar-bz2
#cd gdb-6.4
#./configure --target=arm-linux --prefix=/usr/local/arm-gdb -v
#make

这一步的时候可能会有问题,提示一个函数中(具体函数名不记得了)parse error,就是unsigned前边多了一个”}”,你用vi进入那一行把它删掉就行了。
#make install
#export PATH=$PATH:/usr/local/arm-gdb

进入gdbserver目录:
#./configure --target=arm-linux –host=arm-linux
#make CC=/usr/local/arm/2.95.3/bin/arm-linux-gcc

(这一步要指定arm-linux-gcc的位置)

没有错误的话就在gdbserver目录下生成gdbserver可执行文件,把它烧写到flash的根文件系统分区,或通过nfs mount的方式都可以。只要保证gdbserver能在开发板上运行就行。

下面就可以用gdb+gdbserver调试我们开发板上的程序了。在目标板上运行 gdbserver,其实就是在宿主机的minicom下,我的RedHat Linux装在vmware下的。我是在minicom下#mount 192.168.2.100:/ /tmp后做的(这里参数-o nolock可以不加,不加这一步执行得反而更快些),hello和gdbserver都是位于Linux根目录下,把主机根目录挂在到开发板的/tmp 目录下。

要进行gdb调试,首先要在目标系统上启动gdbserver服务。在gdbserver所在目录下输入命令:
(minicom下)
#cd /tmp
#./gdbserver 192.168.2.100:2345 hello

192.168.2.100为宿主机IP,在目标系统的2345端口开启了一个调试进程,hello为要调试的程序。

出现提示:
Process /tmp/hello created: pid=80
Listening on port 2345

(另一个终端下)
#cd /
#export PATH=$PATH:/usr/local/arm-gdb/bin
#arm-linux-gdb hello
(gdb) target remote 192.168.2.223:2345
(192.168.2.223为开发板IP)

出现提示:
Remote debugging using 192.168.2.223:2345
[New thread 80]
[Switching to thread 80]
0x40002a90 in ??()

同时在minicom下提示:
Remote debugging from host 192.168.2.100
(gdb)

连接成功,这时候就可以输入各种GDB命令如list、run、next、step、break等进行程序调试了。

以上针对通过nfs mount和tftp的方式,只能在主机上调试好后下载到开发板上运行,如果有错误要反复这个过程,繁琐不说,有些程序只能在开发板上调试。所以笔者采用了gdbserver的远程调试方式。希望对大家调试程序有用!

 

有两种方法可以查看当前进程的所有线程堆栈:

第一种:pstack 进程ID

第二种,使用gdb 然后attach 进程ID,然后再使用命令 thread apply all bt

两种方法都可以列出进程所有的线程的当前的调用栈。

不过,使用gdb的方法,还可以查看某些信息,例如局部变量,指针等。

不过,如果只看调用栈的话,pstack还是很方便的。

====================================================

GDB的一些技巧

===============================================

调试一运行的程序

两种方法:
1、在UNIX下用ps查看正在运行的程序的PID(进程ID),然后用gdb <program> PID格式挂接正在运行的程序。
2、先用gdb <program>关联上源代码,并进行gdb,在gdb中用attach命令来挂接进程的PID。并用detach来取消挂接的进程。


调试core dump

gdb <program> <core>

 

gdb启动程序

gdb <program>


查看堆栈

可以用bt,也可以用frame n,其中frame后面跟的n是第几层堆栈的信息,并可以在此堆栈下面显示相应的变量


打印为16进制
p/x buf



打印很长的字符串
方法一:set print element 0, 因为默认长度是200, 改成0为不限制
方法二:p *data@len, 即@加上长度

 

设置显示选项

    GDB中关于显示的选项比较多,这里我只例举大多数常用的选项。

    set print address
    set print address on
        打开地址输出,当程序显示函数信息时,GDB会显出函数的参数地址。系统默认为打开的,如:
       
        (gdb) f
        #0  set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>")
            at input.c:530
        530         if (lquote != def_lquote)


    set print address off
        关闭函数的参数地址显示,如:
       
        (gdb) set print addr off
        (gdb) f
        #0  set_quotes (lq="<<", rq=">>") at input.c:530
        530         if (lquote != def_lquote)

    show print address
        查看当前地址显示选项是否打开。
       
    set print array
    set print array on
        打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。这个选项默认是关闭的。与之相关的两个命令如下,我就不再多说了。
       
    set print array off
    show print array

    set print elements <number-of-elements>
        这个选项主要是设置数组的,如果你的数组太大了,那么就可以指定一个<number-of-elements>来指定数据显示的最大长度,当到达这个长度时,GDB就不再往下显示了。如果设置为0,则表示不限制。
       
    show print elements
        查看print elements的选项信息。
       
    set print null-stop <on/off>
        如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示。这个选项默认为off。
       
    set print pretty on
        如果打开printf pretty这个选项,那么当GDB显示结构体时会比较漂亮。如:

            $1 = {
              next = 0x0,
              flags = {
                sweet = 1,
                sour = 1
              },
              meat = 0x54 "Pork"
            }

    set print pretty off
        关闭printf pretty这个选项,GDB显示结构体时会如下显示:
       
            $1 = {next = 0x0, flags = {sweet = 1, sour = 1}, meat = 0x54 "Pork"}
           
    show print pretty
        查看GDB是如何显示结构体的。
       
   
    set print sevenbit-strings <on/off>
        设置字符显示,是否按“/nnn”的格式显示,如果打开,则字符串或字符数据按/nnn显示,如“/065”。
   
    show print sevenbit-strings
        查看字符显示开关是否打开。
       
    set print union <on/off>
        设置显示结构体时,是否显式其内的联合体数据。例如有以下数据结构:
       
        typedef enum {Tree, Bug} Species;
        typedef enum {Big_tree, Acorn, Seedling} Tree_forms;
        typedef enum {Caterpillar, Cocoon, Butterfly}
                      Bug_forms;
       
        struct thing {
          Species it;
          union {
            Tree_forms tree;
            Bug_forms bug;
          } form;
        };
       
        struct thing foo = {Tree, {Acorn}};

        当打开这个开关时,执行 p foo 命令后,会如下显示:
            $1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
       
        当关闭这个开关时,执行 p foo 命令后,会如下显示:
            $1 = {it = Tree, form = {...}}

    show print union
        查看联合体数据的显示方式
       
    set print object <on/off>
        在C++中,如果一个对象指针指向其派生类,如果打开这个选项,GDB会自动按照虚方法调用的规则显示输出,如果关闭这个选项的话,GDB就不管虚函数表了。这个选项默认是off。
   
    show print object
        查看对象选项的设置。
       
    set print static-members <on/off>
        这个选项表示,当显示一个C++对象中的内容是,是否显示其中的静态数据成员。默认是on。
   
    show print static-members
        查看静态数据成员选项设置。
       
    set print vtbl <on/off>
        当此选项打开时,GDB将用比较规整

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值