调试内核的时候,想打印当然进程的地址或者当前EIP。以前只是用stack_dump,还没有用到具体打该函数或者EIP的地址。搜索内核发现了
#define _RET_IP_ (unsigned long)__builtin_return_address(0)
#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
又搜索了下builtin_return_address,找了个网址,发现两者的区别,明白了_THIS_IP_是我想要的,能解决我的问题。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
使用__builtin_return_address获得程序运行栈情况 (2008-12-04 19:16)
项目中遇到了一个多线程的问题,系统总是莫名其妙的崩溃,而且bug不可重现,后来发现是接收到某些信号的问题,于是乎就加入了信号处理函数,想获得是什么地方触发了这个信号,因为感觉多线程调试比较麻烦,于是就想到了使用利用__builtin_return_address来获得函数运行栈的方法。
直接上测试代码:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #define MAX_LEVEL 4 void sigfunc(int signo) { printf("%s(0): %p\n", __func__, __builtin_return_address(0)); printf("%s(1): %p\n", __func__, __builtin_return_address(1)); printf("%s(2): %p\n", __func__, __builtin_return_address(2)); printf("%s(3): %p\n", __func__, __builtin_return_address(3)); printf("%s(4): %p\n", __func__, __builtin_return_address(4)); exit(1); } int b() { printf("%s(0): %p\n", __func__, __builtin_return_address(0)); while(1) { sleep(1); } } int a(int temp) { temp += 1; printf("%s(0): %p\n", __func__, __builtin_return_address(0)); b(); return temp; } int main() { signal(SIGINT, sigfunc); a(123); return 0; } |
运行结果:
wangyao@wangyao-laptop:~/Test$ ./a.out
a(0): 0x8048554
b(0): 0x804851e
sigfunc(0): 0xb7eef420
sigfunc(1): 0x80484f2
sigfunc(2): 0x804851e
sigfunc(3): 0x8048554
sigfunc(4): 0xb7da2450
我们已经拿到了程序运行轨迹中的逻辑地址,下面的就是在gdb里面l一下那些地址就可以了:
wangyao@wangyao-laptop:~/Test$ gdb -q a.out
(gdb) l *0x804851e
0x804851e is in a (t_return.c:37).
32 temp += 1;
33 printf("%s(0): %p\n", __func__, __builtin_return_address(0));
34
35 b();
36
37 return temp;
38 }
39
40 int main()
41 {
(gdb) q
这样就已经找到了程序运行的轨迹,如果使用一些ELF处理的库直接解析符号表的话,也可以不用gdb来做,直接通过得到的逻辑地址进行定位;-)
参考:
http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html
http://blog.csdn.net/celestialwy/archive/2006/10/23/1346155.aspx