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

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

  • 相关阅读:
    git 忽略文件夹权限
    文字特效-shine.js-阴影随动
    微信小程序scroll-view中的坑(因为动态设置高度导致无法下拉)
    gitlab 403 forbidden 报错解决
    Vue子组件调用父组件的方法
    github的小笔记
    windows win10 重装系统 提示不是gpt分区不能安装
    使用html5播放m3u8直播源
    youtube-dl 使用简介
    ABAP RSA 加密
  • 原文地址:https://www.cnblogs.com/fellow1988/p/6172316.html
Copyright © 2011-2022 走看看