天天看点

GDB堆栈跟踪与汇编调试

GDB堆栈跟踪与汇编调试

堆栈跟踪

  • 源代码:
    GDB堆栈跟踪与汇编调试
  • 对预先编写的

    stack.c

    文件进行编译,并且使用

    CGDB

    进行调试,对堆栈进行跟踪,了解该代码堆栈是如何变化的。
    GDB堆栈跟踪与汇编调试
  • CGDB

    中,先设置 main 断点,接着运行(run),使用

    frame

    info frame

    分别查看当前栈帧的简要信息,以及该栈帧的详细信息。其中:
    • frame

      打印出的信息:栈的层编号,当前的函数名,函数参数值,函数所在文件及行号,函数执行到的语句。
    • info frame

      打印出的信息:函数地址,调用函数的地址,被调用函数的地址,目前的函数是由什么样的程序语言写成的、函数参数地址及值、局部变量的地址等等。
      GDB堆栈跟踪与汇编调试
  • 输入命令

    disassemble

    ,显示出该代码(main())的汇编形式
    GDB堆栈跟踪与汇编调试
  • info registers

    ,显示当前(main()处)寄存器值
    GDB堆栈跟踪与汇编调试
  • 使用

    s

    单步运行程序:
    • 运行到 f1 函数内,观察此时堆栈情况
      GDB堆栈跟踪与汇编调试
    • 运行到 g1 函数内,观察此时堆栈情况
      GDB堆栈跟踪与汇编调试
    • up

      down

      ,跳转不同堆栈,查询其中的堆栈简要信息
      GDB堆栈跟踪与汇编调试
  • 该代码中,共存在过3个堆栈,对每个堆栈查询其详细信息,观察堆栈变化:
    • main()

      函数形成的堆栈(#2):
      GDB堆栈跟踪与汇编调试
    • f1

      函数形成的堆栈(#1):
      GDB堆栈跟踪与汇编调试
    • g1

      函数形成的堆栈(#0):
      GDB堆栈跟踪与汇编调试
  • 根据3个堆栈的详细信息,画出大致的堆栈示图(此时,程序运行在

    g1

    ,还没有返回):
    GDB堆栈跟踪与汇编调试

汇编调试

  • GDB

    指令加上i就显示汇编代码,例如:n(ext)i、s(tep)i,其中:
    • (gdb)p/x i

      :打印变量名为 i 的十六进制值
    • (gdb) display /3i $pc

      :这是一种设置,设置好了调试过程中每一步都回显一次,这里是一次显示 3 行,3 在这里是指一次显示几行,不输入,缺省为1
    • (e)xamine

      :功能和display差不太多,区别就是display是一种设置,每次跳命令显示一次,x是主动显示:

      x/<n/f/u> <addr>

      • n选择从当前地址向后显示几个
      • f是显示格式,还有s字符串和i整型
      • u表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
      • 例:x/3uh 0x54320表示,从地址0x54320读取,h表示以双字节为单位,3表示三个单位,u表示十六进制
  • main

    f1

    g1

    3个函数所对应的汇编代码:
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
  • 设置

    display

    ,每一步显示一行代码,查看当前

    main()

    断点处初始的寄存器值(主要观察%eax,%ebx,%esp,%eip)
GDB堆栈跟踪与汇编调试
  • printf("%d\n,f1(1)+6);

    ,转到fi函数地址处:
GDB堆栈跟踪与汇编调试
  • int f1(int x){

    ,建立f1函数的堆栈,保存数据,更新信息:
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
  • return g1(x);

    ,保存f1函数的数据,之后跳转到g1函数的地址:
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
  • int g1(int x)

    ,建立g1函数的堆栈,保存数据,更新信息:
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
  • return x+5;

    ,进行计算:
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
  • }

    ,销毁g1函数的堆栈,并且回到从f1函数跳出来的下一条指令:
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
  • }

    ,销毁f1函数的堆栈,并且回到从main函数跳出来的下一条指令:
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
  • printf("%d\n,f1(1)+6);

    ,进行运算,并且转到执行

    printf

    的代码处,使之打印出最终结果:
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试
GDB堆栈跟踪与汇编调试

栈帧变化

  • 其中,每条代码指令为正在执行的代码,所有后面的%esp、%ebp、%eax以及栈帧情况都是上一条指令的结果,在等待正在执行的指令完成后再更改
    GDB堆栈跟踪与汇编调试

参考资料

  • GDB调试汇编堆栈过程分析
  • 编程工具系列之一------使用GDB的堆栈跟踪功能
  • 一步一步学调试——gdb命令小结