我的问题与其他询问故障地址的问题有所不同。我正在尝试实施一个可怕的技巧,通过检查保存的指令指针处的代码并将其与主机体系结构的可能的syscall输入指令进行比较,从信号处理程序中确定信号是否中断了syscall或普通用户代码。运行。这是实现正确的POSIX线程取消的一部分,该操作不会受到我的旧问题中描述的竞争条件和资源泄漏的影响:
如果这种方法不可靠或其他错误,我也想听听原因。
/ sigsegv.c / /* * This source file is used to print out a stack-trace when your program * segfaults. It is relatively reliable and spot-on accurate. * * This code is in the public domain. Use it as you see fit, some credit * would be appreciated, but is not a prerequisite for usage. Feedback * on it’s use would encourage further development and maintenance. * * Due to a bug in gcc-4.x.x you currently have to compile as C++ if you want * demangling to work. * * Please note that it’s been ported into my ULS library, thus the check for * HAS_ULSLIB and the use of the sigsegv_outp macro based on that define. * * Author: Jaco Kroon jaco@kroon.co.za * * Copyright (C) 2005 - 2010 Jaco Kroon / #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif
/* Bug in gcc prevents from using CPP_DEMANGLE in pure "C" */ #if !defined(__cplusplus) && !defined(NO_CPP_DEMANGLE) #define NO_CPP_DEMANGLE #endif #include <memory.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <signal.h> #include <ucontext.h> #include <dlfcn.h> #ifndef NO_CPP_DEMANGLE #include <cxxabi.h> #ifdef __cplusplus using __cxxabiv1::__cxa_demangle; #endif #endif #ifdef HAS_ULSLIB #include "uls/logger.h" #define sigsegv_outp(x) sigsegv_outp(,gx) #else #define sigsegv_outp(x, ...) fprintf(stderr, x "\n", ##__VA_ARGS__) #endif #if defined(REG_RIP) # define SIGSEGV_STACK_IA64 # define REGFORMAT "%016lx" #elif defined(REG_EIP) # define SIGSEGV_STACK_X86 # define REGFORMAT "%08x" #else # define SIGSEGV_STACK_GENERIC # define REGFORMAT "%x" #endif static void signal_segv(int signum, siginfo_t* info, void*ptr) { static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"}; int i, f = 0; ucontext_t *ucontext = (ucontext_t*)ptr; Dl_info dlinfo; void **bp = 0; void *ip = 0; sigsegv_outp("Segmentation Fault!"); sigsegv_outp("info.si_signo = %d", signum); sigsegv_outp("info.si_errno = %d", info->si_errno); sigsegv_outp("info.si_code = %d (%s)", info->si_code, si_codes[info->si_code]); sigsegv_outp("info.si_addr = %p", info->si_addr); for(i = 0; i < NGREG; i++) sigsegv_outp("reg[%02d] = 0x" REGFORMAT, i, ucontext->uc_mcontext.gregs[i]); #ifndef SIGSEGV_NOSTACK #if defined(SIGSEGV_STACK_IA64) || defined(SIGSEGV_STACK_X86) #if defined(SIGSEGV_STACK_IA64) ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP]; bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP]; #elif defined(SIGSEGV_STACK_X86) ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP]; bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP]; #endif sigsegv_outp("Stack trace:"); while(bp && ip) { if(!dladdr(ip, &dlinfo)) break; const char *symname = dlinfo.dli_sname; #ifndef NO_CPP_DEMANGLE int status; char * tmp = __cxa_demangle(symname, NULL, 0, &status); if (status == 0 && tmp) symname = tmp; #endif sigsegv_outp("% 2d: %p <%s+%lu> (%s)", ++f, ip, symname, (unsigned long)ip - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname); #ifndef NO_CPP_DEMANGLE if (tmp) free(tmp); #endif if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main")) break; ip = bp[1]; bp = (void**)bp[0]; } #else sigsegv_outp("Stack trace (non-dedicated):"); sz = backtrace(bt, 20); strings = backtrace_symbols(bt, sz); for(i = 0; i < sz; ++i) sigsegv_outp("%s", strings[i]); #endif sigsegv_outp("End of stack trace."); #else sigsegv_outp("Not printing stack strace."); #endif _exit (-1); } static void __attribute__((constructor)) setup_sigsegv() { struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_sigaction = signal_segv; action.sa_flags = SA_SIGINFO; if(sigaction(SIGSEGV, &action, NULL) < 0) perror("sigaction"); } $ g++ -fPIC -shared -o libsigsegv.so -ldl sigsegv $ export LD_PRELOAD=/path/to/libsigsegv.so
我在一个LUG上找到了此代码。无法进入页面将URL指向此处,因此粘贴了整个代码。发生SIGSEGV时,此代码将打印一条小的堆栈跟踪。不知道是否还有其他不使用ucontext_t的方式。