GDB基础学习笔记

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值