zoukankan      html  css  js  c++  java
  • objdump和backtrace的配合使用

    在程序调试过程中程序崩溃的情况时有发生,把出问题时的调用栈信息打印出来是一种不错的解决办法。

    当然还有一些其他方法:https://www.cnblogs.com/jiangyibo/p/8653720.html

     

    首先,介绍三个函数:

      1.int backtrace(void **buffer,int size);

        该函数用于获取当前线程的调用堆栈信息,信息被存放在buffer中,它是一个指针数组。

        参数size表示buffer中可以存放void*元素的个数,函数返回值是实际获取到的void*元素的个数。

     

      2.char **backtrace_symbols(void *const *buffer, int size);

        backtrace_symbols将backtrace函数获取的信息转化为一个字符串数组,参数buffer是从backtrace函数获取的指针数组,size是该数组中的元素个数(backtrace函数的返回值)。

        函数返回值是一个指向字符串数组的指针,它的大小同buffer相同。

        需要注意的是该函数返回的地址是通过malloc函数申请的空间,为了防止内存泄露,我们要手动调用free来释放这块内存。"free(函数返回的指针)"

      

      3.void backtrace_symbols_fd (void *const *buffer, int size, int fd);

        该函数与backtrace_symbols 函数功能类似,不同的是,这个函数直接把结果输出到文件描述符为fd的文件中,且没有调用malloc,不需要手动释放空间。

     

    测试用例:

      main.c

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <signal.h>
     5 #include <execinfo.h>
     6 
     7 #define Size 128
     8 
     9 void fun(void)
    10 {
    11     int *piTest = NULL;
    12     *piTest = 2;
    13 }
    14 
    15 void signalHandler(int signalId)
    16 {
    17     int i = 0;
    18     int iNum = 0;
    19     void *pBuffer[Size] = {0};
    20     char **pszDebugInfo = NULL;
    21 
    22     iNum = backtrace(pBuffer, Size);
    23     pszDebugInfo = backtrace_symbols(pBuffer, iNum);
    24 
    25     if (pszDebugInfo == NULL)
    26     {
    27         perror("backtrace_symbols");
    28         exit(EXIT_FAILURE);         // 表示没有成功执行程序
    29     }
    30 
    31     for (i = 0; i < iNum; i++)
    32     {
    33         printf(" [%02d] %s
    ", i, pszDebugInfo[i]);
    34     }
    35 
    36     free(pszDebugInfo);
    37 
    38     signal(signalId, SIG_DFL);
    39 
    40     raise(signalId);
    41 }
    42 
    43 int main(int argc, char *argv[])
    44 {
    45     // SIGSEGV是当一个进程执行了一个无效的内存引用,
    46     // 或发生段错误时发送给它的信号
    47     signal(SIGSEGV, signalHandler);
    48 
    49     fun();
    50 
    51     printf("----
    ");
    52 
    53     return 0;
    54 }

     

     

    gcc -g -rdynamic main.c -o main

      -g      "objdump"的参数"-l","-S"要求编译时使用了-g之类的调试编译选项。 

      -rdynamic  该参数是链接选项,不是编译选项。这主要是对可执行程序(elf)而言的,而编译动态库时,即使没有rdynamic选项,默认也会将非静态函数放入动态符号表中(刻意隐藏的函数除外)。默认情况下,可执行程序(非动态库)文件内我们定义的非静态函数,是不放到动态符号表中的,链接时只有加上"-rdynamic"才能将所有非静态函数加到动态符号表中。

    ./main

    objdump -S -l ./main > info.txt

      objdump命令是用查看目标文件或者可执行的目标文件的构成的gcc工具。

      -l    --line-numbers 
      用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求编译时使用了-g之类的调试编译选项。

      -S    --source 
      尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。 

    上图可以看到发生了段错误,从下往上可以看到错误大概是发生在"fun"函数,然后打开info.txt,查找有关地址"0a16"的行号:
      vim info.txt
      命令模式:/0a16

      可以看到"0a16"所在"main.c"的12行,而12号正好是"*piTemp = 2;"。

      这里只举例了可执行文件,同理的动态库(记得加-g)也可以按照这个办法来查找错误,这里就不细说了。

  • 相关阅读:
    Algorithm Gossip (48) 上三角、下三角、对称矩阵
    .Algorithm Gossip (47) 多维矩阵转一维矩阵
    Algorithm Gossip (46) 稀疏矩阵存储
    Algorithm Gossip (45) 费氏搜寻法
    Algorithm Gossip (44) 插补搜寻法
    Algorithm Gossip (43) 二分搜寻法
    Algorithm Gossip (42) 循序搜寻法(使用卫兵)
    Algorithm Gossip (41) 基数排序法
    Algorithm Gossip (40) 合并排序法
    AlgorithmGossip (39) 快速排序法 ( 三 )
  • 原文地址:https://www.cnblogs.com/jiangyibo/p/9507555.html
Copyright © 2011-2022 走看看