gdb是UNIX及UNIX-like下的调试工具。在linux下开发的人一定不会陌生,在arm-linux下也有对应的调试版本。下面记录一下在工作中用到的一些在arm-linux下用gdb调试多线程的一些知识。
一、下载调试工具
工程中使用了arm-none-linux-gnueabi-gcc编译器,提供一个下载网站arm-none-linux-gnueabi-gcc。
安转以后执行 arm-arago-linux-gnueabi-gdb -v即可查看版本信息和安转成功与否。
[email protected]:~/workdir/$ arm-arago-linux-gnueabi-gdb -v
GNU gdb (GDB) 7.2
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 redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-linux --target=arm-arago-linux-gnueabi".
For bug reporting instructions, please see:
.
二、调试环境的建立
1、在下位机中输入:gdbserver 10.11.13.19:215 test.app
/mnt/test/ # gdbserver 10.11.13.19:215 test.app
Process test.app created; pid = 817
Listening on port 215
其中10.11.13.19为主机的ip地址,215为连接的端口号,test.app为要调试的应用程序。成功以后下位机将会监听215端口。
2、在主机输入:arm-arago-linux-gnueabi-gdb test.app
[email protected]:~/workdir/$arm-arago-linux-gnueabi-gdb test.app
GNU gdb (GDB) 7.2
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 redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-linux --target=arm-arago-linux-gnueabi".
For bug reporting instructions, please see:
...
Reading symbols from /home/xxx/workdir/test.app...done.
(gdb)
3、下位机与主机建立起连接,在(gdb)的后面输入: target remote 10.11.13.215:215
(gdb) target remote 10.11.13.215:215
Remote debugging using 10.11.13.215:215
Reading symbols from /lib/ld-linux.so.3...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.3
0x400b3790 in ?? () from /lib/ld-linux.so.3
(gdb)
10.11.13.215为下位机的ip地址,215为端口号。成功以后再下位机会答应一条Remote debugging from host 10.11.13.19 的信息。
三、调试过程
上述的一切步骤成功以后就可以执行相应的调试命令来调试程序了,下面介绍一些常用的调试命令。
1、打断点
可以用:b
(gdb) b cfg_bswv_main_t::set_pulse_duty
Breakpoint 1 at 0x48828: file cfg_bswv_main.cpp, line 1402.
(gdb)
或者用 b 文件名:行号。
(gdb) b cfg_bswv_valid_check.cpp :301
Breakpoint 2 at 0x565a4: file cfg_bswv_valid_check.cpp, line 301.
(gdb)
此外,disable n可以让n断点无效,如disable 2让断点2无效,有效为enable 2,删除断点用disable 2,清除断点用clear
2、让程序执行敲入c就可以了
(gdb)c
3、查看调试过程中的信息可以用info关键字。
例如查看断点信息可以用i(info b):
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00048828 in cfg_bswv_main_t::set_pulse_duty(cfg_data_t) at cfg_bswv_main.cpp:1402
breakpoint already hit 1 time
2 breakpoint keep y 0x000565a4 in cfg_bswv_valid_check_t::check_pulse_duty(fp64&, fp64, fp64, fp64, cfg_bswv_wave_t&) at cfg_bswv_valid_check.cpp:301
info还可以查看很多信息,如查看线程信息:info threads,可以输入info回车自行查找,再次不一一列举。
4、执行下一步用n,步进(可以进入函数内部)用s.
5、查看变量的值用p
(gdb) p data
$1 = {data = 20, unit = CFG_IU}
6、查看当前堆栈信息用bt
(gdb) bt
#0 cfg_bswv_main_t::set_pulse_duty (this=0x7bed50, data=...) at cfg_bswv_main.cpp:1405
#1 0x000487bc in cfg_bswv_main_t::set_pulse_width_duty_mode (this=0x7bed50, pulse_mode=CFG_PULSE_DUTY_MODE)
at cfg_bswv_main.cpp:1369
#2 0x0007356c in bswv_pulse_duty_width_mode_msg_t::deal_set_message (this=0x7c1144, msg_data=...)
at cfg_bswv_msg.cpp:1480
#3 0x000217b4 in cfg_msg_t::deal_message (this=0x7c1144, in_buffer=0x426da570) at cfg_lib_msg.cpp:49
#4 0x0015a168 in deal_message_t::deal (this=0x7c1144, message_buffer=0x426da570) at message.cpp:567
#5 0x00159d44 in message_receive_t::deal_message (this=0x426da568) at message.cpp:399
#6 0x00159820 in message_receive_t::wait_message (this=0x426da568, msgflg=4096, msg_id=0) at message.cpp:290
#7 0x0003c94c in cfg_main (arg=0x0) at cfg_main.cpp:80
#8 0x0003c820 in cfg_if_config_thread (arg=0x0) at cfg_if_main.cpp:40
#9 0x400ddcf8 in ?? () from /home/ding/ti-sdk-am335x/filesystem/lib/libpthread.so.0
#10 0x400ddcf8 in ?? () from /home/ding/ti-sdk-am335x/filesystem/lib/libpthread.so.0
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
可以看到程序在当前线程的调用堆栈。此外执行;thread apply all bt 可以查看所有线程的堆栈情况。从中我们也可以发现,每个线程都有各自的调用堆栈。
7、kill 终止调试。
8、break filename:line number 多文件设置断点
9、p/x 十六进制显示变量值
(gdb) p/x frq.data
$4 = 0x3e8
10、finish 继续执行知道当前函数结束
11、jump 跳到制定行
12、tbreak 设置临时断点(设置断点只执行一次)
13、p a=5 给变量赋值
14、show scheduler-locking
(gdb) show scheduler-locking
Mode for locking scheduler during execution is "off".
off时所有线程都可以得到调度,on时只有当前。
15、set scheduler-locking off|on|step
调试解锁|加锁|步进当前线程,其他线程停止。
16、thread num 查看指定的线程号的线程信息
(gdb) thread 2
[Switching to thread 2 (Thread 815)]#0 cfg_bswv_main_t::set_pulse_duty (this=0x7bed50, data=...)
at cfg_bswv_main.cpp:1407
1407 get_prd(prd);
17、x/4096xh 内存打印
18、b 477 if point_count=1000 条件断点
19、until 运行到指定行
20、thread apply id1 id2 command
22、 p addpadd + size
dump binary memory ./file 12
除此之外还有很多调试命令,在此不一一列举。可以查阅相关文档找到。不过以上的那些基本够用了~
四、总结
总而言之,在使用的过程中可以感觉到gdb的调试功能还是很强大的,程序有BUG时,先查看代码有没有错误,在适当的地方加上打印信息是一种有效的方法,但是当这些都解决不了时,不防试一试使用gdb。调试的命令还可以写在脚本里执行,执行脚本的命令是:source。
(gdb) source gdbmake.sh