gdb+gdbserver的远程调试笔记
创建时间:2017/3/9 15:37更新时间:2017/3/10 10:37作者:Robbie Jun
前言:
某些时候由于模拟环境的限制,调试必须要在目标板上进行。由于嵌入式系统资源比较有限,一般不能在目标板上直接构建GDB的调试环境,
这时我们通常采用gdb+gdbserver的远程调试方法:gdbserver在目标板中运行,而gdb则在主机上运行。
调试准备:
1.目标板与主机在同一个局域网:互相可以ping通
2.假设目标板的ip是:192.168.199.155 假设主机的ip是:192.168.199.118
3.交叉编译gdbserver并拷贝到目标板
4.交叉调试器arm-linux-gnueabihf-gdb可执行
运行应用程序:
gdbserver 192.168.199.118:5000 ./netflix # 192.168.199.118主机ip;5000监听的端口;netflix应用程序名称
运行上面的应用程序打印如下:
Process ./netflix created; pid = 5018
Listening on port 5000
主机端执行:
arm-linux-gdb ./netflix # arm-linux-gdb为gdb调试工具(名称不唯一);netflix应用程序名称,和上面是同一个bin
运行上面的程序后打印如下:
GNU gdb (crosstool-NG 1.20.0) 7.8
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
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=x86_64-build_unknown-linux-gnu --target=arm-unknown-linux-gnueabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<https://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./netflix...(no debugging symbols found)...done.
(gdb)
在(gdb)命令行执行如下:
target remote 192.168.199.155:5000 # 192.168.199.155为目标板ip
执行上面的指令后打印如下:
Remote debugging using 192.168.199.155:5000
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0xf70b2a40 in ?? ()
(gdb)
开始调试:
一般来说,GDB主要帮忙你完成下面四个方面的功能
1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
3、当程序被停住时,可以检查此时你的程序中所发生的事。
4、动态的改变你程序的执行环境。
调试源码如下:
root@vm:/home/xurenjun/share/debug# ls
func.c main.c test
func.c :
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 void print2(int size,char* string){
6 char* ptr;
7 ptr=(char*)malloc(size);
8 memset(ptr,'\0',size);
9 strcpy(ptr,string);
10 printf("[%s] %s\n",__FUNCTION__,ptr);
11 free(ptr);
12 ptr=(void*)0;
13 }
main.c :
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 void print2(int,char*);
6
7 void print1(int* val){
8 printf("[%s] val = %d\n",__FUNCTION__,*val);
9 }
10
11 int main(void){
12 int i = 0;
13 int res = 0;
14 for(i=0; i<=100; i++){
15 res += i;
16 }
17 print1(&res);
18 print2(100,"this is test demo!");
19 return 0;
20 }
编译:
arm-linux-gnueabihf-gcc -g -c main.c -o main.o
arm-linux-gnueabihf-gcc -g -c func.c -o func.o
arm-linux-gnueabihf-gcc -g main.o func.o -o test
注意此处编译带-g选项是为了产生调试的符号信息否则调试的时候会出现如下错误:No symbol table is loaded. Use the "file" command.
GDB调试常用命令:
list(l) 查看程序
break(b) 函数名 在某函数入口 加断点
run 开始执行程序
break(b) 行号 在指定行添加断点
break(b) 文件名:行号 在指定文件的指定行号加断点
info break 查看所有设置的断 点
delete 某断点编号 删除某断点
next(n) 单步运行程序(不进入子函数)
step(s) 单步运行程序(进入子函数)
continue(c) 继续运行程序
watch 变量名 监视某一个变量
backtrace 命令可以在遇到断点而暂停执行时显示栈帧。此外,backtrace 的别名还有 where 和 info stack
print(p) 变量名 查看指定变量值
set var=value 设置变量的值
quit(q) 退出gdb
针对上面的源码开始调试实验:
使用list或者l查看源码,enter键进入下一页:
(gdb) l ist
3 #include <string.h>
4
5 void print2(int,char*);
6
7 void print1(int* val){
8 printf("[%s] val = %d\n",__FUNCTION__,*val);
9 }
10
11 int main(void){
12 int i = 0;
(gdb)
13 int res = 0;
14 for(i=0; i<=100; i++){
15 res += i;
16 }
17 print1(&res);
18 print2(100,"this is test demo!");
19 return 0;
20 }
(gdb)
使用list + 行号 表示显示从指定行号的位置为中心开始上下显示10行,enter键进入下一页 :
(gdb) list 13
8 printf("[%s] val = %d\n",__FUNCTION__,*val);
9 }
10
11 int main(void){
12 int i = 0;
13 int res = 0;
14 for(i=0; i<=100; i++){
15 res += i;
16 }
17 print1(&res);
(gdb)
使用break + 函数名 表示在函数名处设置断点:
(gdb) break print2
Breakpoint 1 at 0x4006ec: file ./func.c, line 7.
(gdb)
使用info break 查看设置的所有断点:
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004006ec in print2 at ./func.c:7
breakpoint already hit 1 time
2 breakpoint keep y <PENDING> info
3 breakpoint keep y <PENDING> info
使用run即开始运行,遇到断点停止运行:
(gdb) break print2
Breakpoint 1 at 0x4006ec: file ./func.c, line 7.
(gdb) run
Starting program: /home/xurenjun/share/debug/test
[print1] val = 5050
Breakpoint 1, print2 (size=100, string=0x4007f3 "this is test demo!") at ./func.c:7
7 ptr=(char*)malloc(size);
(gdb)
使用next可以单步运行程序,如果不是在子程序中设置断点,那么next不会进入子程序(下面是进入子程序的情况):
(gdb) break print2
Breakpoint 1 at 0x4006ec: file ./func.c, line 7.
(gdb) run
Starting program: /home/xurenjun/share/debug/test
[print1] val = 5050
Breakpoint 1, print2 (size=100, string=0x4007f3 "this is test demo!") at ./func.c:7
7 ptr=(char*)malloc(size);
(gdb)
(gdb) next
8 memset(ptr,'\0',size);
(gdb) next
9 strcpy(ptr,string);
(gdb)
使用break(b) 文件名:行号在某个文件的某行打上断点;如在main.c的第8行打一个断点:
(gdb) break main.c:8
Breakpoint 1 at 0x40064c: file main.c, line 8.
使用delete 某断点编号 ;删除某个断点:
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040064c main.c:8
breakpoint already hit 1 time
2 breakpoint keep y <PENDING> info
(gdb) delete 1
(gdb) info break
Num Type Disp Enb Address What
2 breakpoint keep y <PENDING> info
(gdb) delete 2
(gdb) info break
No breakpoints or watchpoints.
使用step可以单步运行程序,会进入子程序:
(gdb) break 9
Breakpoint 1 at 0x400668: file main.c, line 9.
(gdb) break 17
Breakpoint 2 at 0x40069e: file main.c, line 17.
(gdb) run
Starting program: /home/xurenjun/share/debug/test
Breakpoint 2, 0x000000000040069e in main ()
(gdb) step
Single stepping until exit from function main,
which has no line number information.
[print1] val = 5050
Breakpoint 1, 0x0000000000400668 in print1 ()
(gdb)
Single stepping until exit from function print1,
which has no line number information.
0x00000000004006aa in main ()
(gdb)
Single stepping until exit from function main,
which has no line number information.
[print2] this is test demo!
__libc_start_main (main=0x40066a <main>, argc=1, ubp_av=0x7fffffffe578, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fffffffe568) at libc-start.c:258
258 libc-start.c: No such file or directory.
使用continue(c)继续运行程序(为了方便观看main程序多加一句打印)
continue 命令继续运行程序。程序会在遇到断点后再次暂停运行。如果没有遇到断点,就会一直运行到结束。
(gdb) continue
(gdb) continue 次数:
main.c :
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 void print2(int,char*);
6
7 void print1(int* val){
8 printf("[%s] val = %d\n",__FUNCTION__,*val);
9 }
10
11 int main(void){
12 int i = 0;
13 int res = 0;
14 for(i=0; i<=100; i++){
15 res += i;
16 printf("res=%d\n",res);
17 }
18 print1(&res);
19 print2(100,"this is test demo!");
20 return 0;
21 }
(gdb) break 16
Breakpoint 1 at 0x400694: file main.c, line 16.
(gdb) break 20
Breakpoint 2 at 0x4006cd: file main.c, line 20.
(gdb) run
Starting program: /home/xurenjun/share/debug/test
Breakpoint 1, 0x0000000000400694 in main ()
(gdb) next
Single stepping until exit from function main,
which has no line number information.
res=0
Breakpoint 1, 0x0000000000400694 in main ()
(gdb)
Single stepping until exit from function main,
which has no line number information.
res=1
Breakpoint 1, 0x0000000000400694 in main ()
(gdb)
Single stepping until exit from function main,
which has no line number information.
res=3
Breakpoint 1, 0x0000000000400694 in main ()
(gdb) continue
Continuing.
res=6
Breakpoint 1, 0x0000000000400694 in main ()
(gdb) continue 100
Will ignore next 99 crossings of breakpoint 1. Continuing.
res=10
res=15
res=21
res=28
res=36
res=45
res=55
res=66
res=78
res=91
res=105
res=120
res=136
res=153
res=171
res=190
res=210
res=231
res=253
res=276
res=300
res=325
res=351
res=378
res=406
res=435
res=465
res=496
res=528
res=561
res=595
res=630
res=666
res=703
res=741
res=780
res=820
res=861
res=903
res=946
res=990
res=1035
res=1081
res=1128
res=1176
res=1225
res=1275
res=1326
res=1378
res=1431
res=1485
res=1540
res=1596
res=1653
res=1711
res=1770
res=1830
res=1891
res=1953
res=2016
res=2080
res=2145
res=2211
res=2278
res=2346
res=2415
res=2485
res=2556
res=2628
res=2701
res=2775
res=2850
res=2926
res=3003
res=3081
res=3160
res=3240
res=3321
res=3403
res=3486
res=3570
res=3655
res=3741
res=3828
res=3916
res=4005
res=4095
res=4186
res=4278
res=4371
res=4465
res=4560
res=4656
res=4753
res=4851
res=4950
res=5050
[print1] val = 5050
[print2] this is test demo!
Breakpoint 2, 0x00000000004006cd in main () //再次遇到断点
print 变量名;查看变量的值:
main.c添加变量mval:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int mval;
6
7 void print2(int,char*);
8
9 void print1(int* val){
10 printf("[%s] val = %d\n",__FUNCTION__,*val);
11 }
12
13 int main(void){
14 int i = 0;
15 int res = 0;
16 mval=100;
17 for(i=0; i<=100; i++){
18 res += i;
19 printf("res=%d\n",res);
20 }
21 print1(&res);
22 print2(100,"this is test demo!");
23 return 0;
24 }
(gdb) break 14
Breakpoint 1 at 0x400672: file main.c, line 14.
(gdb) break 17
Breakpoint 2 at 0x40068a: main.c:17. (2 locations)
(gdb) print mval
$1 = 0
(gdb) run
Starting program: /home/xurenjun/share/debug/test
Breakpoint 1, 0x0000000000400672 in main ()
(gdb) print mval
$2 = 0
(gdb) next
Single stepping until exit from function main,
which has no line number information.
Breakpoint 2, 0x000000000040068a in main ()
(gdb) print mval
$3 = 100
watch 变量名;监视某一个变量:
(gdb) watch mval
Hardware watchpoint 1: mval
(gdb) run
Starting program: /home/xurenjun/share/debug/test
Hardware watchpoint 1: mval
Old value = 0
New value = 100
0x000000000040068a in main ()
backtrace 命令可以在遇到断点而暂停执行时显示栈帧。此外,backtrace 的别名还有 where 和 info stack
(gdb) break 17
Breakpoint 1 at 0x40068a: main.c:17. (2 locations)
(gdb) run
Starting program: /home/xurenjun/share/debug/test
Breakpoint 1, 0x000000000040068a in main ()
(gdb) backtrace
#0 0x000000000040068a in main ()
(gdb)
评论