GDB堆栈跟踪与汇编调试
堆栈跟踪
源代码
使用
gcc - g example.c -o example -m32
指令在64位的机器上产生32位汇编,然后使用gdb example
指令进入gdb调试器:- 在main函数处设置一个断点,再run运行
- 使用
disassemble
获取汇编代码 用
info registers
指令查看各寄存器的值
- 由上图知此时主函数的栈基址为0xbffff324
用
x 0xbffff324
指令查看内存地址中的值使用
display /i $pc
:在每次执行下一条汇编语句时,都会显示出当前执行的是哪条语句
- 下面展示每一步时%esp、%ebp和堆栈内容的变化:
- call指令将下一条指令的地址入栈:
- 将上一个函数的基址入栈,从当前%esp开始作为新基址:
先为传参做准备:
实参的计算在%eax中进行:
- 实参入栈,call指令将下一条指令的地址入栈:
- 计算short+int:
pop %ebp指令将栈顶弹到%ebp中,同时%esp增加4字节:
ret指令将栈顶弹给%eip:
- 函数f修改了%esp,使用leave指令恢复
leave指令先将%esp对其到%ebp,然后把栈顶弹给%ebp:
执行过程中%ebp、%esp、堆栈值的变化
指令 | %esp | %ebp | 堆栈 |
---|---|---|---|
movl $0x8,(%esp) | 0xbffff324 | 0xbffff328 | 0x0 |
call 0x80483c4 | 0xbffff324 | 0xbffff328 | 0x8 0x0 |
push %ebp | 0xbffff320 | 0xbffff328 | 0x80483ee 0x8 0x0 |
mov %esp,%ebp | 0xbffff31c | 0xbffff328 | 0xbffff328 0x80483ee 0x8 0x0 |
mov 0x804a014,%eax | 0xbffff318 | 0xbffff31c | 0x8048409 0xbffff328 0x80483ee 0x8 0x0 |
call 0x80483b4 | 0xbffff318 | 0xbffff31c | 0xa 0x8048409 0xbffff328 0x80483ee 0x8 0x0 |
push %ebp | 0xbffff314 | 0xbffff31c | 0x80483da 0xa 0x8048409 0xbffff328 0x80483ee 0x8 0x0 |
mov %esp,%ebp | 0xbffff310 | 0xbffff31c | 0xbffff31c 0x80483da 0xa 0x8048409 0xbffff328 0x80483ee 0x8 0x0 |
Pop %ebp | 0xbffff310 | 0xbffff310 | 0xbffff31c 0x80483da 0xa 0x8048409 0xbffff328 0x80483ee 0x8 0x0 |
ret | 0xbffff314 | 0xbffff31c | 0x80483da 0xa 0x8048409 0xbffff328 0x80483ee 0x8 0x0 |
leave | 0xbffff318 | 0xbffff31c | 0x8048409 0xbffff328 0x80483ee 0x8 0x0 |
ret | 0xbffff320 | 0xbffff328 | 0xbffff328 0x80483ee 0x8 0x0 |
mov 0x80484d0,%edx | 0xbffff324 | 0xbffff328 | 0x8 0x0 |
add $edx,%eax | 0xbffff324 | 0xbffff328 | 0x0 |
ret | 0xbffff32c | 0x0 |
gdb小使用
使用gdb的bt/frame/up/down指令动态查看调用栈帧的情况