• 获取栈信息


    ■ API
        // 获取将backstrace信息,将地址存到buffer中。
        // 参数size指定buffer的最大值,返回值则是backstrace的实际大小
        int backtrace(void **buffer, int size)
       
        // 根据buffer指定的地址,返回符号信息。参数size指定返回符号信息的大小
        char ** backtrace_symbols(void *const *buffer, int size)
       
        // 类似backtrace_symbols()函数,但是不需要malloc空间来存放符号信息,
        // 而是将结果写到文件描述符fd所代表的文件中
        void backtrace_symbols_fd(void *const *buffer, int size, int fd)
       
        注意:

      . 使用函数backtrace_symbols()或者backtrace_symbols_fd()时,需要用-rdynamic编译才能得到正确的符号名,否则只能得到偏移地址。

      . 为了可以判断地址对应的代码行号,需要编译追加-g选项。

    ■ 实例

      ① 代码  

     1 //gcc test.c -g -rdynamic -o test
     2 #include <execinfo.h> 
     3 #include <stdio.h> 
     4 #include <stdlib.h> 
     5 #include <fcntl.h>
     6 
     7 #define PRINT_DEBUG
     8 
     9 /* Obtain a backtrace and print it to stdout. */ 
    10 void print_trace(void) 
    11 { 
    12      void *array[10]; 
    13      size_t size; 
    14      char **strings; 
    15      size_t i;
    16 
    17      size = backtrace(array, 10); 
    18 #ifdef PRINT_DEBUG
    19     strings = backtrace_symbols(array, size); 
    20      printf("Obtained %zd stack frames.
    ", size); 
    21      for(i = 0; i < size; i++) 
    22          printf("%s
    ", strings[i]); 
    23      free(strings); 
    24 #else
    25     int fd = open("err.log", O_CREAT | O_WRONLY);
    26     backtrace_symbols_fd(array, size, fd);
    27     close(fd);
    28 #endif
    29 
    30 }
    31 
    32 /* A dummy function to make the backtrace more interesting. */ 
    33 void dummy_function(void) 
    34 { 
    35     print_trace(); 
    36 } 
    37 
    38 int main(void) 
    39 { 
    40      dummy_function(); 
    41      return 0; 
    42 }

         ② 结果

       root@ubuntu:/home/linux/develop/backtrace# gcc test.c -g -rdynamic -o test
       root@ubuntu:/home/linux/develop/backtrace# ./test
       Obtained 4 stack frames.
       ./test(print_trace+0x19) [0x80486ad]
       ./test(dummy_function+0xb) [0x8048719]
       ./test(main+0xb) [0x8048726]
       /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7fb113]
       root@ubuntu:/home/linux/develop/backtrace# addr2line 0x80486ad -f -e test
       print_trace
       /home/linux/develop/backtrace/test.c:17
       root@ubuntu:/home/linux/develop/backtrace# addr2line 0x8048719 -f -e test
       dummy_function
       /home/linux/develop/backtrace/test.c:36
       root@ubuntu:/home/linux/develop/backtrace# addr2line 0x8048726 -f -e test
       main
       /home/linux/develop/backtrace/test.c:41    

    ■ 应用

      reset时,获取进程的栈信息

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <execinfo.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    #include <unistd.h>
    
    #define PRINT_DEBUG
    
    static void print_reason(int sig)
    {
        void *array[10];
        size_t size;
        size = backtrace(array, 10);
    #ifdef PRINT_DEBUG
        char **strings;
        int i;
        strings = backtrace_symbols(array, size);
        printf("Obtained %d stack frames.
    ", size);
        for (i = 0; i < size; i++)
            printf("%s
    ", strings[i]);
        free(strings);
    
        char cmd[256] = "addr2line -C -f -e ";
        char* prog = cmd + strlen(cmd);
        readlink("/proc/self/exe", prog, sizeof(cmd) - strlen(cmd) - 1);// 获取进程的完整路径
    
        FILE* fp = popen(cmd, "w");
        if (fp != NULL)
        {
            for (i = 0; i < size; ++i)
            {
                fprintf(fp, "%p
    ", array[i]);
            }
            pclose(fp);
        }
    #else
        int fd = open("err.log", O_CREAT | O_WRONLY);
        backtrace_symbols_fd(array, size, fd);
        close(fd);
    #endif
        exit(0);
    }
    void die()
    {
        char *test1;
        char *test2;
        char *test3;
        char *test4 = NULL;
        strcpy(test4, "ab");
    }
    void test1()
    {
        die();
    }
    int main(int argc, char **argv)
    {
        struct sigaction myAction;
        myAction.sa_handler = print_reason;
        sigemptyset(&myAction.sa_mask);
        myAction.sa_flags = SA_RESTART | SA_SIGINFO;
        sigaction(SIGSEGV, &myAction, NULL); // 无效内存引用
        sigaction(SIGABRT, &myAction, NULL); // 异常终止
        test1();
    }
  • 相关阅读:
    SNOI 2019 字符串
    1068: [SCOI2007]压缩
    POJ 1848 Tree 树形DP
    BZOJ bzoj1396 识别子串
    BZOJ 4503: 两个串
    BZOJ 2302: [HAOI2011]Problem c(数学+DP)
    BZOJ 3157: 国王奇遇记 (数学)
    CF_528D
    BZOJ 3000: Big Number (数学)
    新の开始
  • 原文地址:https://www.cnblogs.com/renhl/p/3308154.html
Copyright © 2020-2023  润新知