跳转至

函数调用栈实现

在编译时需要加上选项 -g -rdynamic
#include <stdio.h>
#include <execinfo.h>
#include <malloc.h>
#include <cxxabi.h>
void printCallStack_simple()
{
    int size = 16;                                 // 最多打印16层调用栈
    void *buffer[size];                            // 用于存放调用栈信息
    int count = backtrace(buffer, size);           // 获取调用栈
    char **ptr = backtrace_symbols(buffer, count); // 将调用栈信息转成字符串
    for (int i = 0; i < count; i++)
    { // 打印字符串
        printf("%s", ptr[i]);
    }
    free(ptr); // 释放分配的内存
}
void printCallStack()
{
    void *buffer[100] = {NULL};
    char **trace = NULL;
    int size = backtrace(buffer, 100);
    trace = backtrace_symbols(buffer, size);
    if (NULL == trace)
    {
        return;
    }

    size_t name_size = 100;
    char *name = (char *)malloc(name_size);
    for (int i = 0; i < size; ++i)
    {
        char *begin_name = 0;
        char *begin_offset = 0;
        char *end_offset = 0;
        for (char *p = trace[i]; *p; ++p)
        { // 利用了符号信息的格式
            if (*p == '(')
            { // 左括号
                begin_name = p;
            }
            else if (*p == '+' && begin_name)
            { // 地址偏移符号
                begin_offset = p;
            }
            else if (*p == ')' && begin_offset)
            { // 右括号
                end_offset = p;
                break;
            }
        }
        if (begin_name && begin_offset && end_offset)
        {
            *begin_name++ = '\0';
            *begin_offset++ = '\0';
            *end_offset = '\0';
            int status = -4; // 0 -1 -2 -3
            char *ret = abi::__cxa_demangle(begin_name, name, &name_size, &status);
            if (0 == status)
            {
                name = ret;
                printf("%s:%s+%s\n", trace[i], name, begin_offset);
            }
            else
            {
                printf("%s:%s()+%s\n", trace[i], begin_name, begin_offset);
            }
        }
        else
        {
            printf("%s\n", trace[i]);
        }
    }
    free(name);
    free(trace);
    printf("----------done----------\n");
}
void test3(int n) { printCallStack(); }
void test2(int n) { test3(3); }
void test1(int n) { test2(2); }
int main()
{
    test1(1);
}
  • 编译执行结果
[root@centos7 ~]# g++ -g -rdynamic test_trace.cc 
[root@centos7 ~]# ./a.out 
./a.out:printCallStack2()+0x41
./a.out:test3(int)+0x10
./a.out:test2(int)+0x15
./a.out:test1(int)+0x15
./a.out:main()+0xe
/lib64/libc.so.6:__libc_start_main()+0xf5
./a.out() [0x400969]
----------done----------