- 论坛徽章:
- 0
|
利用空闲写了一个模拟GDB输出Call Stack的程序。
#include <stdio.h>
#define _bt() \
({ unsigned int ret;\
__asm__("mov 0x4(%%ebp), %0;"\
:"=r"(ret));\
printf("%s(%x)\n", __FUNCTION__, ret);\
ret;})
#define get_cur_ebp() \
({ unsigned int ebp;\
__asm__("mov %%ebp, %0;"\
:"=r"(ebp));\
ebp;})
#define get_ret() \
({ unsigned int ret;\
__asm__("mov 0x4(%%ebp), %0;"\
:"=r"(ret));\
ret;})
#define pop_frame() \
{__asm__("mov (%%ebp), %%eax;\
mov %%eax, %%ebp;":::"%eax");}
#define restore_ebp(ebp) \
{__asm__("mov %0, %%eax;\
mov %%eax, %%ebp;"\
::"r"(ebp):"%eax");}
int main(int, char**);
unsigned int org_ebp;
unsigned int ret;
void print_stack_trace()
{
org_ebp = get_cur_ebp();
printf("%x\n", get_ret());
pop_frame();
while (1)
{
ret = get_ret();
printf("%x\n", ret);
if ( ret > (unsigned int)main )
break;
else
pop_frame();
}
restore_ebp(org_ebp);
}
int foo(int arg)
{
print_stack_trace();
printf("left foo(%d)\n", arg);
return arg;
}
void bar()
{
foo(1);
print_stack_trace();
printf("left bar\n");
}
int main(int argc, char* argv[])
{
bar();
foo(0);
print_stack_trace();
return 0;
} |
gcc -Wall -g编译,部分objdump输出
080483fa <foo>:
80483fa: 55 push %ebp
80483fb: 89 e5 mov %esp,%ebp
80483fd: 83 ec 08 sub $0x8,%esp
8048400: e8 7f ff ff ff call 8048384 <print_stack_trace>
8048405: 8b 45 08 mov 0x8(%ebp),%eax
8048408: 89 44 24 04 mov %eax,0x4(%esp)
804840c: c7 04 24 bc 85 04 08 movl $0x80485bc,(%esp)
8048413: e8 a0 fe ff ff call 80482b8 <printf@plt>
8048418: 8b 45 08 mov 0x8(%ebp),%eax
804841b: c9 leave
804841c: c3 ret
0804841d <bar>:
804841d: 55 push %ebp
804841e: 89 e5 mov %esp,%ebp
8048420: 83 ec 08 sub $0x8,%esp
8048423: c7 04 24 01 00 00 00 movl $0x1,(%esp)
804842a: e8 cb ff ff ff call 80483fa <foo>
804842f: e8 50 ff ff ff call 8048384 <print_stack_trace>
8048434: c7 04 24 ca 85 04 08 movl $0x80485ca,(%esp)
804843b: e8 78 fe ff ff call 80482b8 <printf@plt>
8048440: c9 leave
8048441: c3 ret
08048442 <main>:
8048442: 55 push %ebp
8048443: 89 e5 mov %esp,%ebp
8048445: 83 ec 08 sub $0x8,%esp
8048448: 83 e4 f0 and $0xfffffff0,%esp
804844b: b8 00 00 00 00 mov $0x0,%eax
8048450: 83 c0 0f add $0xf,%eax
8048453: 83 c0 0f add $0xf,%eax
8048456: c1 e8 04 shr $0x4,%eax
8048459: c1 e0 04 shl $0x4,%eax
804845c: 29 c4 sub %eax,%esp
804845e: e8 ba ff ff ff call 804841d <bar>
8048463: c7 04 24 00 00 00 00 movl $0x0,(%esp)
804846a: e8 8b ff ff ff call 80483fa <foo>
804846f: e8 10 ff ff ff call 8048384 <print_stack_trace>
8048474: b8 00 00 00 00 mov $0x0,%eax
8048479: c9 leave
804847a: c3 ret |
程序的输出:
root:~/asm$ gcc -Wall -g -o bt bt.c
root:~/asm$ ./bt
8048405 <-- foo
804842f <-- bar
8048463 <-- main
left foo(1)
8048434 <-- bar
8048463 <-- main
left bar
8048405 <-- foo
804846f <-- main
left foo(0)
8048474 <-- main
b7e39e00 <-- code that call main |
<-- xxx 非程序输出。
GDB在断点处会打印EIP值,我这个没办法,内嵌的函数,选择同样打印返回地址。要完全模拟可以向上跳过call print_stack_trace(该死的变长指令)。
代码只是雏形,得保证foo、bar这样的函数体在main函数体之前。涉及到多个文件,需要这样 gcc -o xxx a.o b.o main.o
如果再进一步解析生成的ELF,就能像GDB一样打印 0xaabbccdd in foo()。当然-g参数很无敌,参数都能打印出来。 |
|