Linux C语言函数调用栈打印

2023-12-15 15:37:44

代码

//main.c
extern void func_a();

int main (int argc, char *argv[])
{
    func_a();
    return 0;
}
//a.c
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

void print_trace (void){
    void *array[10];
    size_t size;
    char **strings;
    size_t i;
    
    size = backtrace(array, 10);
    strings = backtrace_symbols(array, size);
    if (NULL == strings){
        perror("backtrace_synbols failed:");
    }
    else{
        printf ("Obtained %zd stack frames.\n", size);
        for (i = 0; i < size; i++)
            printf ("%s\n", strings[i]);
        free (strings);
        strings = NULL;
    }
}

extern void func_b();

void func_a(){
    func_b();
}
//b.c
extern void print_trace (void);

void func_c(){
    print_trace();
}
void func_b(){
    func_c();
}

编译

gcc -c a.c -fpic
gcc -c b.c -fpic
gcc -shared a.o -o liba.so
gcc -shared b.o -o libb.so
gcc main.c -L ./ -la -lb -o test

Makefile

CFLAGS:= -fpic -Os

all: test
	# export LD_LIBRARY_PATH=/data1/liuxiaolian5/work/backtraceTest:$LD_LIBRARY_PATH

test: main.c liba.so libb.so
	gcc -L ./ -la -lb -o test main.c

liba.so: a.o
	gcc -shared -o liba.so a.o

libb.so: b.o
	gcc -shared -o libb.so b.o

a.o: a.c
	gcc $(CFLAGS) -c a.c

b.o: b.c
	gcc $(CFLAGS) -c b.c

clean: FORCE
	rm -rf *.o
	rm -rf *.so
	rm -rf test

FORCE:

运行

export LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH
./test

结果

./test
Obtained 8 stack frames.
/data1/liuxiaolian5/work/backtraceTest/liba.so(print_trace+0x19) [0x7fc23225317e]
/data1/liuxiaolian5/work/backtraceTest/libb.so(func_c+0x9) [0x7fc23224e11e]
/data1/liuxiaolian5/work/backtraceTest/libb.so(func_b+0xe) [0x7fc23224e12f]
/data1/liuxiaolian5/work/backtraceTest/liba.so(func_a+0xe) [0x7fc232253225]
./test() [0x40113b]
/usr/lib64/libc.so.6(+0x2d210) [0x7fc232069210]
/usr/lib64/libc.so.6(__libc_start_main+0x7c) [0x7fc2320692bc]
./test() [0x401065]

问题

strip 动态库或者可执行文件不会丢失函数名称,但是加入 -O优化选项之后丢失backtrace

$ ./test
Obtained 5 stack frames.
# 0: /data1/liuxiaolian5/work/backtraceTest/liba.so(print_trace+0x1a) [0x7fe17dee017f]
# 1: ./test() [0x40113b]
# 2: /usr/lib64/libc.so.6(+0x2d210) [0x7fe17dcf6210]
# 3: /usr/lib64/libc.so.6(__libc_start_main+0x7c) [0x7fe17dcf62bc]
# 4: ./test() [0x401065]

注意事项

  • backtrace的实现依赖于栈指针(fp寄存器),在gcc编译过程中任何非零的优化等级(-On参数)或加入了栈指针优化参数-fomit-frame-pointer后多将不能正确得到程序栈信息;
  • backtrace_symbols的实现需要符号名称的支持,在gcc编译过程中需要加入-rdynamic参数;
    内联函数没有栈帧,它在编译过程中被展开在调用的位置;
  • 尾调用优化(Tail-call Optimization)将复用当前函数栈,而不再生成新的函数栈,这将导致栈信息不能正确被获取。

文章来源:https://blog.csdn.net/qq_46136275/article/details/134885680
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。