zoukankan      html  css  js  c++  java
  • Linux 信号

    每个进程都需要有个信号处理函数,以捕捉异常信号。

    我们在写代码时,有时会有内存非法使用,这种问题一般比较难定位。但是如果有信号处理函数,就可以在捕捉到SEGV信号后打印出详细信息以定位问题。

    下面写一个简单的例子,来定位非法内存访问。

    #include <stdio.h>
    #define __USE_GNU
    #include <ucontext.h>
    #include <sys/prctl.h>
    #include <execinfo.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <errno.h>
    static void show_maps()
    {
      char cmd[128];
      snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid());
      system(cmd);
    }

    static void show_backtrace()
    {
      void *trace[32];
      int trace_size;
      char **messages;
      trace_size = backtrace(trace ,32);
      int idx;
      messages = backtrace_symbols(trace, trace_size);
      if (NULL != messages)
      {
        for (idx = 0; idx < trace_size; idx++)
        {
          printf("%s ", messages[idx]);
        }
        free(messages);
      }
    }
    static void show_regs(mcontext_t *regs)
    {
      char comm[20] = {''};
      prctl(PR_GET_NAME, comm);
      printf("PID:%d,comm:%20s ", getpid(), comm);
      printf("EIP:%p ",(void*) regs->gregs[REG_EIP]);
    }
    static void sighandler(int signo, siginfo_t *info, void *context)
    {
      ucontext_t *uc = (ucontext_t *)context;
      switch (signo)
      {
        case SIGSEGV :
        printf("Invalid mem!!! Fault addr:%p ",(void*)( info->si_addr));
        show_regs(&(uc->uc_mcontext));
        show_backtrace();
        show_maps();
        exit(0);
        break;
        default:
        break;
      }
    }
    int register_signalHandler()
    {
      struct sigaction sa;
      int ret;
      sa.sa_sigaction = &sighandler;
      sigemptyset(&sa.sa_mask);
      sa.sa_flags = SA_SIGINFO;
      if (0 != sigaction(SIGSEGV, &sa, NULL))
      {  
        printf("sigaction fail, errno:%d ", errno);
        return ret;
      }
      return 0;
    }
    void func()
    {

      printf("func! ");
      int *p;
      *p = 8;
    }

    int main(void)
    {
      register_signalHandler();
      func();
      return 0;
    }

    在func函数中有个非法内存使用。

    gcc -g signal.c -o signal

    运行signal进程:

    EIP寄存器地址在地址区间08048000~08049000是在进程的.text段。

    我们可以通过addr2line进行定位:

    76行正好是*p=8那一行。

    如果SEGEV不是发生在进程的代码段,发生在某个so内。假如发生在0x7553654,而且so load到进程中的0xb7553000,那么addr2line应该查看地址0x654;

    也可以在gdb中查看list *0x8048951

    也可以反编译可执行文件,来查看地址。

  • 相关阅读:
    算法导论第十八章 B树
    腾讯2016春招之算法编程解析
    LeetCode:5_Longest Palindromic Substring | 最长的回文子串 | Medium
    搜狗2016校园招聘之算法编程解析
    linux sed在某些字符串的下一行插入内容?sed在下一行插入?
    linux shell搜索某个字符串,然后在后面加上字符串?字符串后面插入字符串?sed字符串后面插入字符串?
    linux环境中,如何使用tar来创建压缩包?解压缩?
    linux环境中,ssh登录报错,Permission denied, please try again.
    linux环境中安装NRPE插件执行远程"本地资源"检查?NRPE安装?
    linux环境安装nagiosgraph将nagios的性能数据绘制成动态图表?
  • 原文地址:https://www.cnblogs.com/fellow1988/p/6172316.html
Copyright © 2011-2022 走看看