linux中backtrace实战

main.c

cpp 复制代码
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <execinfo.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <execinfo.h>
 

void print_addr_info(void *addr) {
    Dl_info info;
    if (dladdr(addr, &info)) {
        printf("  Function: %s\n", info.dli_sname ? info.dli_sname : "??");
        printf("  Library:  %s\n", info.dli_fname ? info.dli_fname : "??");
        
        // 计算偏移量
        if (info.dli_saddr) {
            printf("  Offset:   %p\n", (void*)((char*)addr - (char*)info.dli_saddr));
        }
    }
}

void signal_handle(int signal) {
    void *buffer[100];
    char **strings;
    int nptrs;

    printf("\n==========> catch signal %d <==========\n", signal);
    printf("Dump stack start...\n");

    // 获取调用栈信息
    nptrs = backtrace(buffer, 100);
    strings = backtrace_symbols(buffer, nptrs);
    if (strings == NULL) {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }

    // 打印调用栈信息
    for (int i = 0; i < nptrs; i++) {
        printf("%s\n", strings[i]);
        print_addr_info(buffer[i]);
        printf("\n");
    }

    printf("Dump stack end...\n");
    free(strings);
    exit(EXIT_FAILURE);
}
 
// 模拟空指针引用的函数
void null_pointer_dereference() {
    int *ptr = NULL;
    *ptr = 10; // 空指针引用,会触发SIGSEGV信号
}
 
// 模拟除零操作的函数
void division_by_zero() {
    int a = 10;
    int b = 0;
    int result = a / b; // 除零操作,会触发SIGFPE信号
}
 
int main() {
    // 注册SIGSEGV信号的处理函数
    signal(SIGSEGV, signal_handle);
    // 注册SIGFPE信号的处理函数
    signal(SIGFPE, signal_handle);
 
    // 测试空指针引用
    null_pointer_dereference();
 
    // 测试除零操作
    // division_by_zero();
 
    return 0;
}

编译指令:

gcc main.c -o main -g -rdynamic -ldl

其中-g -rdynamic是backtrace需要的,-ldl是dladdr函数需要的。

执行可执行文件:

bash 复制代码
ubuntu@ubuntu:/tmp$ ./main

==========> catch signal 11 <==========
Dump stack start...
./main(signal_handle+0x59) [0x55dcf2b36d18]
  Function: signal_handle
  Library:  ./main
  Offset:   0x59

/lib/x86_64-linux-gnu/libc.so.6(+0x3ef10) [0x7fb5978a0f10]
  Function: ??
  Library:  /lib/x86_64-linux-gnu/libc.so.6

./main(null_pointer_dereference+0x10) [0x55dcf2b36df9]
  Function: null_pointer_dereference
  Library:  ./main
  Offset:   0x10

./main(main+0x30) [0x55dcf2b36e51]
  Function: main
  Library:  ./main
  Offset:   0x30

/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7fb597883c87]
  Function: __libc_start_main
  Library:  /lib/x86_64-linux-gnu/libc.so.6
  Offset:   0xe7

./main(_start+0x2a) [0x55dcf2b36b1a]
  Function: _start
  Library:  ./main
  Offset:   0x2a

Dump stack end...

从这个打印来看,0x55dcf2b36df9是null_pointer_dereference中失败的地方,但是这是程序执行地址,不能用于addr2line,我们需要找到null_pointer_dereference在可执行文件中的偏移地址。

bash 复制代码
ubuntu@ubuntu:/tmp$ objdump -t main | grep null_pointer_dereference
0000000000000de9 g     F .text	0000000000000019              null_pointer_dereference

从上面知道可执行文件中null_pointer_dereference偏移为de9,出错的地方是null_pointer_dereference+0x10,即出错的偏移为de9+10=0xdf9。现在用addr2line找到具体的行数:

bash 复制代码
ubuntu@ubuntu:/tmp$ addr2line -e main 0xdf9 -f
null_pointer_dereference
/tmp/main.c:59

看到在main.c的59行,没错:

相关推荐
rannn_1116 小时前
【力扣hot100】链表专题|160、206、234、141、142
java·算法·leetcode·链表·面试·开发
数模竞赛Paid answer6 小时前
2026年华东杯数学建模B题医药物流安排问题解题全过程文档及程序
算法·数学建模·数据分析·华东杯
leisoo80976 小时前
100GBA股股票数据怎么存ClickHouseRedisMySQLJSON完整对比
大数据·linux·服务器·开发语言·python
不会代码的小猴6 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
爱喝水的鱼丶7 小时前
SAP-ABAP:接口与报表场景专项优化:RFC/ODATA 接口、ALV 报表的性能提升方案
运维·性能优化·接口·sap·abap·rfc·经验交流
青瓦梦滋7 小时前
传输层UDP/TCP协议
linux·网络·c++·网络协议·tcp/ip·udp
ltl7 小时前
机密计算:SGX、SEV-SNP、TDX 与 ARM CCA
linux
AI备案指南-满满7 小时前
大模型与算法备案全流程详解:从零到通过的完整指南
人工智能·算法·备案·大模型备案·算法备案
江畔柳前堤7 小时前
LLM 训练核心机制深度解析:Warmup、Cosine Decay 与 Perplexity 的完整知识体系
网络·人工智能·深度学习·算法·机器学习·语音识别
ltl7 小时前
互联与网络:NVLink、InfiniBand、RoCE 与国产替代
linux