您的位置:首页 > 产品设计 > UI/UE

如何查看程序的运行栈 之 __builtin_return_address的使用

2014-05-14 21:07 387 查看
针对大型软件中,在调试问题时,经常会发现某些业务逻辑的调用路径很难查找,或者说是不清楚程序的运行栈。

想查看程序的运行栈有几种方法:

(1)程序编译时,带 -g 选项,直接在某个函数(接口)添加一行导致死机的代码,死机堆栈就可以找到程序的运行栈,很龊但是有时候挺管用;

(2)在函数里面添加__builtin_return_address来查找程序的运行栈;

本篇介绍一下的__builtin_return_address函数的使用

__builtin_return_address 函数的作用是返回所在函数被一级函数调用后,退出的地址(通常为return)。

英文原意是“When inlining the expected behavior is that the function returns the address of the function that is returned to”

此处参考网络上一个示例

示例代码test_build_return_address.c

#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 c(int temp)
{
temp++;

printf("%s(0): %p\n", __func__, __builtin_return_address(0));

a(123);

return temp;
}

int main()
{
//    signal(SIGINT, sigfunc);
//    a(123);
c(123);
return 0;
}


编译(gcc -g test_build_return_address.c -o test_build_return_address),运行(gdb -q test_build_return_address)

会打印运行栈的地址:

[root@localhost test]# gdb -q test_build_return_address

Using host libthread_db library "/lib/libthread_db.so.1".

(gdb) run

Starting program: /home/kehuanyu/test/test_build_return_address

c(0): 0x8048516

a(0): 0x80484f4

b(0): 0x80484be

接着ctrl+c ,通过gdb指令来找到对应的代码:

Program received signal SIGINT, Interrupt.

0x003d1402 in __kernel_vsyscall ()

(gdb) l *0x80484be

0x80484be is in a (test_build_return_address.c:32).

27 temp += 1;

28 printf("%s(0): %p\n", __func__, __builtin_return_address(0));

29

30 b();

31

32 return temp;

33 }

34

35 int c(int temp)

36 {

(gdb) l *0x80484f4

0x80484f4 is in c (test_build_return_address.c:43).

38

39 printf("%s(0): %p\n", __func__, __builtin_return_address(0));

40

41 a(123);

42

43 return temp;

44 }

45

46 int main()

47 {

(gdb) l *0x8048516

0x8048516 is in main (test_build_return_address.c:51).

46 int main()

47 {

48 // signal(SIGINT, sigfunc);

49 // a(123);

50 c(123);

51 return 0;

52 }

其实获取到运行栈地址之后,也可以通过ELF处理库直接解析符号列表。

友情链接:

http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html 关于函数调用返回信息的__builtin_系列函数

void *__builtin_return_address(unsigned
int level
)

void *__builtin_extract_return_addr(void
*addr
)

void
*
__builtin_frob_return_address(void
*addr
)

void
*
__builtin_frame_address(unsigned
int level
)

http://www.gnu.org/software/gdb/ gdb的使用

https://gcc.gnu.org/ gcc编译器
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: