博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

水龙卷

我是一个对自己进行debug的程序,所以行动迟缓些,不要见怪
  waterspout.cublog.cn

关于作者
姓名:何云龙
职业:Linux移动终端平台开发
介绍:走的更远些
|| << >> ||
我的分类


修改信号处理函数 -- sigaction

    程序在运行的时候经常会收到系统或其他进程发过来的信号,有时候我们希望改变对信号的缺省处理,这时候就需要使用信号处理程序了。

#include <signal.h>
   int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

struct sigaction {
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
}



       man手册上说sa_handler和sa_sigaction在某些系统是作为union实现的,不能一起使用。
       不过对我们来说只需要其中一个,信号处理函数或者定义成sa_handler形式或者sa_sigaction形式,完全根据我们程序的需要来定。按照POSIX的说法,sa_sigaction的第三个参数可以被转换成类型为
ucontext_t并指向信号发送时线程执行的上下文。而<ucontext.h>中另外定义了对ucontext的处理函数getcontext(), setcontext(), makecontext() 以及 swapcontext().
      
       man手册上说sa_restorer属于一个被废弃的域。

       sa_handler可以接受SIG_DFL(缺省处理)或者SIG_IGN(忽略该信号)。

       sa_mask 定义了在此信号处理程序执行时,哪些信号可以被阻塞住。

       sa_flags指定了一系列信号处理程序的选项:
              SA_NOCLDSTOP
                     不处理信号SIGCHLD.

              SA_ONESHOT 或 SA_RESETHAND
                     信号处理程序只使用一次。

              SA_ONSTACK
                     只在特定的调用栈中使用此处理程序,该调用栈由sigaltstack()指定。

              SA_RESTART
                     为了兼容BSD信号的语义

              SA_NOMASK or SA_NODEFER
                     缺省情况下触发信号处理程序的信号在处理期间会被阻塞,如果在sa_flags定义了SA_NODEFER或者SA_NOMASK就不再阻塞。

              SA_SIGINFO
                     信号处理程序时使用3各参数,见sa_sigaction(after Linux 2.1.86).

       下面是结构siginfo_t的定义:

siginfo_t {
    int si_signo; /* for all signals. Signal number */
    int si_errno; /* for all signals. An errno value */
    nt si_code; /* for all signals. why this signal occur */
    pid_t si_pid; /* Sending process ID */
    uid_t si_uid; /* Real user ID of sending process */
    int si_status; /* Exit value or signal */
    lock_t si_utime; /* User time consumed */
    clock_t si_stime; /* System time consumed */
    sigval_t si_value; /* Signal value */
    int si_int; /* POSIX.1b signal */
    void * si_ptr; /* POSIX.1b signal */
    void * si_addr; /* Memory location which caused fault */
    int si_band; /* Band event */
    int si_fd; /* File descriptor */
}


             
下面是使用sigaction处理SIGUSR1并且打印当前调用栈的代码。要注意的就是如果要在你的程序里引用sigsegv.h、sigsegv.c得到堆栈信息的话记得加上-rdynamic -ldl参数

sigsegv.h

#ifndef __sigsegv_h__
#define __sigsegv_h__

#ifdef __cplusplus
extern "C" {
#endif

  int setup_sigsegv();

#ifdef __cplusplus
}
#endif

#endif /* __sigsegv_h__ */



sigsegv.c

#define _GNU_SOURCE
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <ucontext.h>
#include <dlfcn.h>
#include <execinfo.h>
#ifndef NO_CPP_DEMANGLE
#include <cxxabi.h>
#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"};

  size_t i;
  ucontext_t *ucontext = (ucontext_t*)ptr;

#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
  int f = 0;
  Dl_info dlinfo;
  void **bp = 0;
  void *ip = 0;
#else
  void *bt[20];
  char **strings;
  size_t sz;
#endif

  fprintf(stderr, "Segmentation Fault!\n");
  fprintf(stderr, "info.si_signo = %d\n", signum);
  fprintf(stderr, "info.si_errno = %d\n", info->si_errno);
  fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, si_codes[info->si_code]);
  fprintf(stderr, "info.si_addr = %p\n", info->si_addr);
  for(i = 0; i < NGREG; i++)
    fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n", i, ucontext->uc_mcontext.gregs[i]);

#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
# 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

  fprintf(stderr, "Stack trace:\n");
  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

    fprintf(stderr, "% 2d: %p &lt;%s+%u&gt; (%s)\n",
            ++f,
            ip,
            symname,
            (unsigned)(ip - 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
  fprintf(stderr, "Stack trace (non-dedicated):\n");
  sz = backtrace(bt, 20);
  strings = backtrace_symbols(bt, sz);

  for(i = 0; i &lt; sz; ++i)
    fprintf(stderr, "%s\n", strings[i]);
#endif
  fprintf(stderr, "End of stack trace\n");
  exit (-1);
}

int 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) &lt; 0) {
    perror("sigaction");
    return 0;
  }

  return 1;
}

#ifndef SIGSEGV_NO_AUTO_INIT
static void __attribute((constructor)) init(void) {
  setup_sigsegv();
}
#endif



#include "sigsegv.h"
#include &lt;string.h&gt;

int die() {
  char *err = NULL;
  strcpy(err, "gonner");
  return 0;
}

int main() {
  return die();
}



其中,dladdr()是Glibc的扩展函数,在POSIX中并没有定义。


#define _GNU_SOURCE

#include <dlfcn.h>
int dladdr(void *addr, Dl_info *info);
void *dlvsym(void *handle, char *symbol, char *version);

typedef struct {
  const char *dli_fname;/* Filename of defining object */
  void *dli_fbase; /* Load address of that object */
  const char *dli_sname;/* Name of nearest lower symbol */
  void *dli_saddr; /* Exact value of nearest symbol */

} Dl_info;


reference:
http://blog.chinaunix.net/u/3425/showart_263408.html
http://linux.die.net/man/3/dladdr
http://www.opengroup.org/onlinepubs/009695399/functions/makecontext.html
http://www.delorie.com/gnu/docs/glibc/libc_465.html


发表于: 2007-08-08,修改于: 2007-08-08 11:56,已浏览491次,有评论0条 推荐 投诉


网友评论
 发表评论