2011-03-22 10 views
12

मेरा प्रश्न कुछ अन्य लोगों से अलग है जो गलती पते के बारे में पूछे गए हैं। मैं सिग्नल हैंडलर से निर्धारित करने के लिए एक भयानक हैक को कार्यान्वित करने की कोशिश कर रहा हूं, सिग्नल ने सहेजे गए निर्देश सूचक पर कोड का निरीक्षण करके एक सिस्कोल या सामान्य उपयोगकर्ता कोड को बाधित कर दिया है और मेजबान आर्किटेक्चर के लिए संभावित syscall प्रविष्टि निर्देशों के विरुद्ध इसकी तुलना कर रहा है पर चल रहा है।सिग्नल हैंडलर से सहेजे गए निर्देश सूचक पते को प्राप्त करना

How are POSIX cancellation points supposed to behave?

यदि यह उपाय अविश्वसनीय है या नहीं तो गलत है, मैं भी करना चाहते हैं: यह सही POSIX धागे रद्द लागू करने की बात यह है कि मेरे पुराने प्रश्न में वर्णित रेस स्थिति और संसाधन रिसाव से ग्रस्त नहीं है कारण सुनें।

+0

यह भी देखें http://stackoverflow.com/q/4832743/371250 – ninjalj

+0

और यहां टिप्पणी http://lxr.free-electrons.com/source/arch/x86/kernel/signal.c?v=2.6 .37 # एल 320 – ninjalj

+0

मुझे यह निर्धारित करने की आवश्यकता नहीं है कि मैं सिग्नल हैंडलर में हूं या नहीं; यह कोड केवल सिग्नल हैंडलर से ही चलाया जाएगा। मुझे निर्धारित करने की आवश्यकता है कि अगले निर्देश का पता है जिसे सिग्नल हैंडलर लौटाए जाने पर निष्पादित किया जाएगा। मैं मानता हूं कि यह एक बदसूरत हैक है, लेकिन मुझे दौड़ की स्थिति के बिना एक सिस्कोल में रद्दीकरण करने का कोई अन्य तरीका नहीं मिल रहा है, जहां सिस्कल द्वारा आवंटित संसाधन लीक हो सकता है। –

उत्तर

14
/* 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 <[email protected]> 
* 
* 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 पर मिला। यहां यूआरएल को इंगित करने के लिए पेज पर नहीं जा सका, इसलिए पूरे कोड को चिपकाया गया। SIGSEGV होने पर यह कोड एक छोटे से स्टैक ट्रेस को प्रिंट करता है। सुनिश्चित नहीं है कि कोई अन्य तरीका है जो ucontext_t का उपयोग नहीं करता है।

+1

+1 और स्वीकार किया गया; यह कोड आवश्यक जानकारी प्राप्त करने के लिए 'SA_SIGINFO' सिग्नल हैंडलर को तीसरे तर्क का उपयोग करने का तरीका दिखाता है। –

संबंधित मुद्दे