【linux】分享一个用户态crash跟踪方法

  1. crash handler
    这段代码是一个非常实用的 Linux 崩溃调试工具框架 —— 捕获常见崩溃信号(如 SIGSEGV),打印寄存器、崩溃地址、堆栈回溯等信息,并写入日志文件crash.log,别个大佬开源出来,仅做记录
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <signal.h>
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>




#include <ucontext.h>
#include <sys/ucontext.h>

#define BACKTRACE_SIZE 100  // 栈回溯深度
 
 #define DPRINTF(fd, format, ...) \
	if (fd > STDERR_FILENO) \
		dprintf(fd, format, ##__VA_ARGS__); \
		dprintf(STDERR_FILENO, format, ##__VA_ARGS__)
 
// 信号处理程序
void signal_handler(int sig, siginfo_t *info, void *ucontext) {
    void *buffer[BACKTRACE_SIZE];
    int nptrs = BACKTRACE_SIZE;
	FILE *log_file = fopen("crash.log", "w");
	int fd = fileno(log_file);
	if (fd < 0) {
		perror("open log file");
		fd = STDERR_FILENO;
	}
	
    // 打印信号信息
	DPRINTF(fd, "========== crash report ========\n");
    DPRINTF(fd, "Error: signal %d:\n", sig);

    // 打印导致崩溃的原因地址
    DPRINTF(fd, "Fault address: %p\n", info->si_addr);
	DPRINTF(fd, "Fault code: %d\n", info->si_code);

	DPRINTF(fd, "========== register info ========\n");
    DPRINTF(fd, "register\thex value\t\tdec value\n");
    // 打印寄存器信息
    ucontext_t *uc = (ucontext_t *)ucontext;
#if defined(__x86_64__)
    DPRINTF(fd, "RIP:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RIP], (unsigned long long)uc->uc_mcontext.gregs[REG_RIP]);
    DPRINTF(fd, "RSP:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RSP], (unsigned long long)uc->uc_mcontext.gregs[REG_RSP]);
    DPRINTF(fd, "RBP:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RBP], (unsigned long long)uc->uc_mcontext.gregs[REG_RBP]);
    DPRINTF(fd, "RAX:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RAX], (unsigned long long)uc->uc_mcontext.gregs[REG_RAX]);
    DPRINTF(fd, "RBX:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RBX], (unsigned long long)uc->uc_mcontext.gregs[REG_RBX]);
    DPRINTF(fd, "RCX:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RCX], (unsigned long long)uc->uc_mcontext.gregs[REG_RCX]);
    DPRINTF(fd, "RDX:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RDX], (unsigned long long)uc->uc_mcontext.gregs[REG_RDX]);
    DPRINTF(fd, "RSI:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RSI], (unsigned long long)uc->uc_mcontext.gregs[REG_RSI]);
    DPRINTF(fd, "RDI:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_RDI], (unsigned long long)uc->uc_mcontext.gregs[REG_RDI]);
    DPRINTF(fd, "R8:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_R8], (unsigned long long)uc->uc_mcontext.gregs[REG_R8]);
    DPRINTF(fd, "R9:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_R9], (unsigned long long)uc->uc_mcontext.gregs[REG_R9]);
    DPRINTF(fd, "R10:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_R10], (unsigned long long)uc->uc_mcontext.gregs[REG_R10]);
    DPRINTF(fd, "R11:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_R11], (unsigned long long)uc->uc_mcontext.gregs[REG_R11]);
    DPRINTF(fd, "R12:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_R12], (unsigned long long)uc->uc_mcontext.gregs[REG_R12]);
    DPRINTF(fd, "R13:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_R13], (unsigned long long)uc->uc_mcontext.gregs[REG_R13]);
    DPRINTF(fd, "R14:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_R14], (unsigned long long)uc->uc_mcontext.gregs[REG_R14]);
    DPRINTF(fd, "R15:\t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.gregs[REG_R15], (unsigned long long)uc->uc_mcontext.gregs[REG_R15]);
#elif defined(__aarch64__)
	DPRINTF(fd, "PC: \t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.pc, (unsigned long long)uc->uc_mcontext.pc);
    DPRINTF(fd, "SP: \t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.sp, (unsigned long long)uc->uc_mcontext.sp);
    DPRINTF(fd, "FP: \t%16llx\t%20lld\n", (unsigned long long)uc->uc_mcontext.regs[29], (unsigned long long)uc->uc_mcontext.regs[29]);
    for (int i = 0; i < 31; i++) {
        DPRINTF(fd, "X%d: \t%16llx\t%20lld\n", i, (unsigned long long)uc->uc_mcontext.regs[i], (unsigned long long)uc->uc_mcontext.regs[i]);
    }

#endif
	DPRINTF(fd, "\n========== backtrace info ========\n");
	nptrs = backtrace(buffer, BACKTRACE_SIZE);
	if (nptrs == 0) {
		DPRINTF(fd, "backtrace failed\n");
	}
    // 打印堆栈跟踪信息
    backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
    if (log_file) {
		backtrace_symbols_fd(buffer, nptrs, fd);
    }
	fclose(log_file);
    // 退出程序
    _exit(EXIT_FAILURE);
}
// 注册信号处理器
void register_signal_handlers() {
    struct sigaction sa;
    sa.sa_sigaction = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO | SA_RESTART;  // 关键标志
 
    // 注册常见崩溃信号
    sigaction(SIGSEGV, &sa, NULL);  // 段错误
    sigaction(SIGILL,  &sa, NULL);  // 非法指令
    sigaction(SIGFPE,  &sa, NULL);  // 算术异常
    sigaction(SIGABRT, &sa, NULL);  // 主动终止
}
 
// 测试函数(触发崩溃)
void trigger_crash() {
    volatile int *p = NULL;
    *p = 42;  // 触发 SIGSEGV
}
 
int main() {
    register_signal_handlers();
    trigger_crash();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值