GDB 学习
本文是作者学习https://www.slideshare.net/owenhsu/introduction-to-gdb-3790833整理的学习笔记。希望大家有所收获。
1 速查表
https://github.com/skywind3000/awesome-cheatsheets/blob/master/tools/gdb.txt
2 GDB命令
-
基础GDB命令
Command 说明 run [args] 开始执行 start [args] 开始执行(自动在main break) break [line/function] 设定breakpoint break [condition] 在条件成立时中断 continue 执行到被中断为止 next 单步执行(不会进入function) step 单步执行(会进入function) list [line/function] 列出程序 print [exp] 显示expression的值 print [var=var] 修改变量的值 backtrace 显示堆栈状况 help [subcommand] 说明 -
Info
Command 说明 info breakpoints 查看目前设置过的breakpoint info watchpoints 查看目前设置过的watchpoint info locals 查看目前所有的变量 info registers 查看普通寄存器 info frame 查看目前所使用的栈帧(stack frame) info stack 查看程序的堆栈调用(同backtrace) info proc 查看进程信息 info threads 显示多线程信息 info source 查看程序源码文件状况 info shared 查看程序所载入的shared library信息 -
Breakpoint
Command 说明 watch [exp] 当expression变动是break delete [n] 删除breakpoint(编号) nexti 单指令执行(不会进入function) stepi 单指令执行(会进入function)
3 案例
2.1 HelloWorld
-
源码
-
代码:hello.c
#include <stdio.h> void func(char *pMem) { printf("- func: %p\n\n", pMem); } const char *szHello = "Hello World"; int main(int argc, char *argv[]) { printf("\n%s\n\n", szHello); int i; for (i = 0; i < argc; i++) { printf("argv[%d]\n", i); printf("- main: %s\n", argv[i]); func(argv[i]); } return 0; }
-
-
编译
gcc -Wall hello.c -o hello #Wall 展示所有信息
-
启动:
./hello 123 abc
-
输出
Hello World argv[0] - main: ./hello - func: 0x7ffee1f44719 argv[1] - main: 123 - func: 0x7ffee1f44721 argv[2] - main: abc - func: 0x7ffee1f44725
-
调试
-
重新构建
gcc -Wall -g hello.c -o hello #-g:添加调试信息
-
开启GDB:
gdb hello
-
调试
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-119.el7 Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://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 "x86_64-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/clearn/learngdb/hello...done. # 在mian函数上打断点 (gdb) break main Breakpoint 1 at 0x400560: file hello.c, line 9. # 运行程序 (gdb) run 123 abc Starting program: /home/clearn/learngdb/hello 123 abc Breakpoint 1, main (argc=3, argv=0x7fffffffe4b8) at hello.c:9 warning: Source file is more recent than executable. 9 int main(int argc, char *argv[]) Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 # 查看程序 (gdb) list 4 { 5 printf("- func: %p\n\n", pMem); 6 } 7 8 const char *szHello = "Hello World"; 9 int main(int argc, char *argv[]) 10 { 11 printf("\n%s\n\n", szHello); 12 13 int i; # 在14行设置断点 (gdb) break 14 Breakpoint 2 at 0x400596: file hello.c, line 14. # 执行到下一个断点 (gdb) continue Continuing. Hello World argv[0] Breakpoint 2, main (argc=3, argv=0x7fffffffe4b8) at hello.c:14 14 for (i = 0; i < argc; i++) # 单步执行(会进入函数) (gdb) s - main: /home/clearn/learngdb/hello 15 { # 单步执行(会进入函数) (gdb) s func (pMem=0x7fffffffe6e9 "/home/clearn/learngdb/hello") at hello.c:4 4 { # 查看程序 (gdb) list 1 #include <stdio.h> 2 3 void func(char *pMem) 4 { 5 printf("- func: %p\n\n", pMem); 6 } 7 8 const char *szHello = "Hello World"; 9 int main(int argc, char *argv[]) 10 { # 单步执行(不会进入程序) (gdb) n - func: 0x7fffffffe6e9 5 printf("- func: %p\n\n", pMem); # 打印堆栈 (gdb) backtrace #0 func (pMem=0x7fffffffe6e9 "/home/clearn/learngdb/hello") at hello.c:5 #1 0x00000000004005de in main (argc=1, argv=0x7fffffffe4c8) at hello.c:15 # 打印pMem信息 (gdb) print pMem $1 = 0x7fffffffe6e9 "/home/clearn/learngdb/hello" # 打印*pMem信息 (gdb) print *pMem $2 = 47 '/' # 执行 (gdb) continue Continuing. [Inferior 1 (process 7478) exited normally] (gdb)
-
2.2 链接库测试
-
源码
-
foo.c
#include "bar.h" int foo = 3; int main() { foo = 8; bar(&foo); return 0; }
-
bar.h
void bar(int *);
-
bar.c
#include <stdlib.h> void bar(int *val) { *val = 11; val = NULL; *val = 17; }
-
-
编译
gcc -Wall -g -fPIC -shared bar.c -o libbar.so gcc -Wall -g foo.c ./libbar.so -o foobar
-
启动:
./foobar
-
输出
段错误
-
调试
-
开启GDB:
gdb foobar
-
调试
# 在main函数上设置断点 (gdb) b main Breakpoint 1 at 0x400691: file foo.c, line 5. # 自动展示foo变量的信息 (gdb) disp foo # 查看自动展示的变量的信息 (gdb) info disp Auto-display expressions now in effect: Num Enb Expression 1: y foo # 执行 (gdb) r Starting program: /home/clearn/learngdb/foobar Breakpoint 1, main () at foo.c:5 5 foo = 8; 1: foo = 3 Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 # 查看源码 (gdb) list 1 #include "bar.h" 2 int foo = 3; 3 int main() 4 { 5 foo = 8; 6 bar(&foo); 7 8 return 0; 9 }(gdb) Line number 10 out of range; foo.c has 9 lines. # 单步执行(会进入函数) (gdb) s 6 bar(&foo); 1: foo = 8 # 单步执行(会进入函数) (gdb) s bar (val=0x601034 <foo>) at bar.c:4 4 *val = 11; 1: foo = 8 # 查看源码 (gdb) list 1 #include <stdlib.h> 2 void bar(int *val) 3 { 4 *val = 11; 5 val = NULL; 6 *val = 17; 7 } # 添加查看的变量 (gdb) disp val 2: val = (int *) 0x601034 <foo> # 添加查看的变量 (gdb) disp *val 3: *val = 8 # 单步执行(会进入函数) (gdb) s 5 val = NULL; 3: *val = 11 2: val = (int *) 0x601034 <foo> 1: foo = 11 # 单步执行(会进入函数) (gdb) s 6 *val = 17; 3: *val = <error: Cannot access memory at address 0x0> 2: val = (int *) 0x0 1: foo = 11 # 单步执行(会进入函数) (gdb) s #给空地址赋值发生了错误 Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7bd9693 in bar (val=0x0) at bar.c:6 6 *val = 17; 3: *val = <error: Cannot access memory at address 0x0> 2: val = (int *) 0x0 1: foo = 11 # 单步执行(会进入函数) (gdb) s Program terminated with signal SIGSEGV, Segmentation fault. The program no longer exists. # 反编译查看问题 (gdb) disas 0x00007ffff7bd9693 Dump of assembler code for function bar: 0x00007ffff7bd9675 <+0>: push %rbp 0x00007ffff7bd9676 <+1>: mov %rsp,%rbp 0x00007ffff7bd9679 <+4>: mov %rdi,-0x8(%rbp) 0x00007ffff7bd967d <+8>: mov -0x8(%rbp),%rax 0x00007ffff7bd9681 <+12>: movl $0xb,(%rax) 0x00007ffff7bd9687 <+18>: movq $0x0,-0x8(%rbp) 0x00007ffff7bd968f <+26>: mov -0x8(%rbp),%rax 0x00007ffff7bd9693 <+30>: movl $0x11,(%rax) # 发生错误。%rax = 0x0,找不到地址 0x00007ffff7bd9699 <+36>: pop %rbp 0x00007ffff7bd969a <+37>: retq End of assembler dump. (gdb) q
-
2.3 参数修改
-
源码
-
linklist.c
typedef struct node node; struct node { int data; node *next; }; int main(void) { node *p, *q, *r; p->next = q; return 0; }
-
-
编译:
gcc -Wall -g linklist.c -o linklist
-
运行:
./linklist
-
结果
段错误
-
调试
-
开启gdb:
gdb linklist
-
调试
# 在main函数上打断点 (gdb) b main Breakpoint 1 at 0x4004f1: file linklist.c, line 11. # 查看源码 (gdb) list 2 struct node 3 { 4 int data; 5 node *next; 6 }; 7 8 int main(void) 9 { 10 node *p, *q, *r; 11 p->next = q; # 执行 (gdb) r Starting program: /home/clearn/learngdb/linklist Breakpoint 1, main () at linklist.c:11 11 p->next = q; Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 # 查看变量 (gdb) i loc p = 0x0 q = 0x7fffffffe4c0 # 查看变量 (gdb) p *p Cannot access memory at address 0x0 # 查看变量 (gdb) p *q $1 = {data = 1, next = 0x7fffffffe6e7} # 赋值 (gdb) p p=(node*)malloc(sizeof(node)) $2 = (node *) 0x602010 # 赋值 (gdb) p q=(node*)melloc(sizeof(node)) No symbol "melloc" in current context. # 赋值 (gdb) p q=(node*)malloc(sizeof(node)) $3 = (node *) 0x602030 # 自动展示*p信息 (gdb) disp *p 1: *p = {data = 0, next = 0x0} # 自动展示*q信息 (gdb) disp *q 2: *q = {data = 0, next = 0x0} # 单步执行(不会进入函数) (gdb) n 13 return 0; 2: *q = {data = 0, next = 0x0} 1: *p = {data = 0, next = 0x602030} # 查看变量r。被编译器优化了 (gdb) disp r 3: r = <optimized out> (gdb)
-
参考
https://www.slideshare.net/owenhsu/introduction-to-gdb-3790833
https://github.com/skywind3000/awesome-cheatsheets/blob/master/tools/gdb.txt