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

8 篇文章 1 订阅

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

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

(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编译器






  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值