从信号处理程序获取已保存的指令指针地址 [英] Getting the saved instruction pointer address from a signal handler

查看:241
本文介绍了从信号处理程序获取已保存的指令指针地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是从别人已经问错地址有所不同。我试图执行一个可怕的黑客来确定,从信号处理程序,通过在保存的指令指针检查code和作比较可能的系统调用条目中的信号是否中断的系统调用或普通用户code它运行于主机体系结构的说明。这是实行正确的POSIX线程取消的一部分,这并不在我的老问题所描述的竞争条件和资源泄漏苦:

<一个href=\"http://stackoverflow.com/questions/4213203/how-are-posix-cancellation-points-supposed-to-behave\">How在POSIX取消点应该表现?

如果这种方法是不可靠的或错的,我也想听听理由。


解决方案

  / * * sigsegv.c /
/ **
 *这个源文件时使用你的程序打印出堆栈跟踪
 *段错误。这是比较可靠的,还有精准的准确。
 *
 *此code是在公共领域。使用它,你认为合适,一些信贷
 *将AP preciated,而不是使用一个prerequisite。反馈
 *它的使用将鼓励进一步的开发和维护。
 *
 *由于GCC-4.x.x您目前有编​​译为C ++,如果你想有一个错误
 * demangling工作。
 *
 *请注意,它被移植到我的ULS库,从而为检查
 * HAS_ULSLIB和使用基于定义sigsegv_outp宏。
 *
 *作者:寇克朗&LT; jaco@kroon.co.za>
 *
 *版权所有(C)2005 - 2010雅科克朗
 * /
的#ifndef _GNU_SOURCE
#定义_GNU_SOURCE
#万一/ *错误,从纯粹的C使用CPP_DEMANGLE GCC prevents * /
#如果定义(__ CPLUSPLUS)及!&安培; !定义(NO_CPP_DEMANGLE)
#定义NO_CPP_DEMANGLE
#万一#包括LT&;&memory.h GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&;&signal.h中GT;
#包括LT&;&ucontext.h GT;
#包括LT&;&dlfcn.h中GT;
的#ifndef NO_CPP_DEMANGLE
#包括LT&;&cxxabi.h GT;
#IFDEF __cplusplus
使用__cxxabiv1 :: __ cxa_demangle;
#万一
#万一#IFDEF HAS_ULSLIB
#包括ULS / logger.h
#定义sigsegv_outp(X)sigsegv_outp(和GX)
#其他
#定义sigsegv_outp(X,...)fprintf中(标准错误,X\\ n,## __ VA_ARGS__)
#万一#如果定义(REG_RIP)
#定义SIGSEGV_STACK_IA64
#定义REGFORMAT%016lx
#elif指令定义(REG_EIP)
#定义SIGSEGV_STACK_X86
#定义REGFORMAT%08X
#其他
#定义SIGSEGV_STACK_GENERIC
#定义REGFORMAT%X
#万一静态无效signal_segv(INT Signum的,siginfo_t *信息,无效* PTR){
    静态为const char * SI_ codeS [3] = {,SEGV_MAPERR,SEGV_ACCERR};    INT I,F = 0;
    ucontext_t * ucontext =(ucontext_t *)PTR;
    Dl_info dlinfo;
    无效** BP = 0;
    void *的IP = 0;    sigsegv_outp(段错误!);
    sigsegv_outp(info.si_signo =%d个,正负号);
    sigsegv_outp(info.si_errno =%d个信息 - &GT; si_errno);
    sigsegv_outp(info.si_ code =%D(%S),信息 - &GT; SI_ code,SI_ codeS [信息 - &GT; SI_ code]);
    sigsegv_outp(info.si_addr =%P,信息 - &GT; si_addr);
    对于(i = 0; I&LT; NGREG;我++)
        sigsegv_outp(REG [%02D] = 0XREGFORMAT,我,ucontext-&GT; uc_mcontext.gregs [I]);的#ifndef SIGSEGV_NOSTACK
#如果定义(SIGSEGV_STACK_IA64)||定义(SIGSEGV_STACK_X86)
#如果定义(SIGSEGV_STACK_IA64)
    IP =(无效*)ucontext-&GT; uc_mcontext.gregs [REG_RIP]
    BP =(无效**)ucontext-&GT; uc_mcontext.gregs [REG_RBP]
#elif指令定义(SIGSEGV_STACK_X86)
    IP =(无效*)ucontext-&GT; uc_mcontext.gregs [REG_EIP]
    BP =(无效**)ucontext-&GT; uc_mcontext.gregs [REG_EBP]
#万一    sigsegv_outp(堆栈跟踪:);
    而(BP&安培;&安培; IP){
        如果(提供dladdr(IP,&安培;!dlinfo))
            打破;        为const char * symname = dlinfo.dli_sname;的#ifndef NO_CPP_DEMANGLE
        INT状态;
        字符* TMP = __cxa_demangle(symname,NULL,0,&安培;状态);        如果(状态== 0安培;&安培; TMP)
            symname = tmp目录;
#万一        sigsegv_outp(%2D:%P&LT;%S +%禄&GT;(%S),
                 ++楼
                 IP,
                 symname,
                 (无符号长)IP - (无符号长)dlinfo.dli_saddr,
                 dlinfo.dli_fname);的#ifndef NO_CPP_DEMANGLE
        如果(TMP)
            免费(TMP);
#万一        如果(dlinfo.dli_sname&安培;&安培;!STRCMP(dlinfo.dli_sname,主))
            打破;        IP =碱基对[1];
        BP =(无效**)BP [0];
    }
#其他
    sigsegv_outp(堆栈跟踪(非专用));
    SZ =回溯(BT,20);
    字符串= backtrace_symbols(BT,SZ);
    对于(i = 0; I&LT; SZ ++ I)
        sigsegv_outp(%S,字符串[我]);
#万一
    sigsegv_outp(堆栈跟踪结束。);
#其他
    sigsegv_outp(不打印堆栈strace的。);
#万一
    _exit(-1);
}静态无效__attribute __((构造函数))setup_sigsegv(){
    结构sigaction的行动;
    memset的(安培;动作,0,sizeof的(动作));
    action.sa_sigaction = signal_segv;
    action.sa_flags = SA_SIGINFO;
    如果(sigaction的(SIGSEGV,&放大器;动作,NULL)℃的)
        PERROR(sigaction的);
}$ G ++ -fPIC -shared -o libsigsegv.so -ldl SIGSEGV$出口LD_ preLOAD = /路径/要/ libsigsegv.so

我发现一个LUG此code。无法获取页面指向这里的网址,所以粘贴整个code。当SIGSEGV会发生此code打印一个小的堆栈跟踪。不知道如果不使用ucontext_t其他方式。

My question is somewhat different from others that have asked about fault addresses. I'm trying to implement a horrible hack to determine, from a signal handler, whether the signal interrupted a syscall or ordinary user code by inspecting the code at the saved instruction pointer and comparing it against the possible syscall entry instructions for the host architecture it's running on. This is part of implementing correct POSIX thread cancellation that does not suffer from the race condition and resource leak described in my old question:

How are POSIX cancellation points supposed to behave?

If this approach is unreliable or otherwise wrong, I'd also like to hear reasons.

解决方案

/* 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

I found this code on a LUG. Couldn't get to the page to point the URL here, so pasted the whole code. This code prints a small stack trace when SIGSEGV occurs. Not sure if there is some other way that does not use ucontext_t.

这篇关于从信号处理程序获取已保存的指令指针地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆