ID482769950

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)







评论