Linux内核调试方法总结之backtrace

摘要:
当用户模式或内核模式程序异常退出时,回溯堆栈信息。通过对当前堆栈的分析,将当前堆栈中上层函数的帧地址追溯到顶层函数。因为不同的处理器堆栈有不同的实现,所以这个函数的具体实现是在compiler__ buildin_ frame_ Address和__ buildin_ return_ Address函数中构建的。有关具体说明,请参阅manbacktrace帮助文档execinfo hintbacktrace backtrace函数获取当前线程的backtrace,作为端口列表,并将信息放入缓冲区。char**回溯符号回溯符号函数将从回溯函数获得的信息转换为一个字符串数组。参数缓冲区应指向具有反向跟踪功能的地址数组,大小为该数组中的检索数。voidbacktrace_symbols_fd#include#include#include#include#include#include#包含#包含#包含 #definePRINT_DEBUG#defineMAX_BACKTRACE_LEVEL10#defineBACKTRACE_LOG_NAME“BACKTRACE.LOG”staticvoidshow_reason{void*array[MAX_BACKTRACE_LEVEL〕;size_tsize;#ifdefPRINT_DEBUGchar**string;size_ti;size=BACKTRACE;strings=BACKTRACE_symbols;printf;for printf;free;#elseintfd=open;size=back trace;BACKTRACE_ssymbols_fd;close;#endifexit;}voidie(){char*str1;char*str2;char*str3;char*str4=NULL;strcpy;}voilet_it_die(){die();}intmain{structsigactionact;act.saSa_cation=show_reason;sigemptyset;act.sa_flags=sa_RESTART|sa_SIGINFO;sigaction;sigaction1) 编译huawei@WUH1000002965:~/test$gccbacktrace_test。c-obacktrace_Test-g–rddynamic(注意:-r dynamic,此选项传递给链接器,链接器会将符号放在.dymtable中,以便backtrace_symbols可以获得与地址相对应的符号。因此,即使使用-g编译程序,如果不使用-r dynamic的话,backtrace_ssymbols也无法找到与地址相对的符号。

backtrace

【用途】用户态或者内核态程序异常退出时回溯堆栈信息

【原理】通过对当前堆栈的分析,回溯上层函数在当前栈中的帧地址,直至顶层函数。帧地址是指在栈中存在局部变量、上一级函数返回地址、寄存器值的内存空间。由于不同处理器堆栈实现不同(向上增长和向下增长),此功能的具体实现是编译器内建的__buildin_frame_address及__buildin_return_address函数。如果编译器不支持此函数,也可以自己实现该函数。

【接口说明】具体说明可以参考man backtrace帮助文档

execinfo.h

int backtrace (void **buffer, int size)
The backtrace function obtains a backtrace for the current thread, as a list of pointers, and places the information into buffer.

char ** backtrace_symbols (void *const *buffer, int size)

The backtrace_symbols function translates the information obtained from the backtrace function into an array of strings. The argument buffer should be a pointer to an array of addresses obtained via the backtrace function, and size is the number of entries in that array (the return value of backtrace).

void backtrace_symbols_fd(void *const *buffer, int size, int fd)

【实例】

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <execinfo.h>

#include <fcntl.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#define PRINT_DEBUG

#define MAX_BACKTRACE_LEVEL 10

#define BACKTRACE_LOG_NAME "backtrace.log"

static void show_reason(int sig, siginfo_t *info, void *secret){

    void *array[MAX_BACKTRACE_LEVEL];

    size_t size;

#ifdef PRINT_DEBUG

    char **strings;

    size_t i;

    size = backtrace(array, MAX_BACKTRACE_LEVEL);

    strings = backtrace_symbols(array, size);

    printf("Obtain %zd stack frames. ", size);

    for(i = 0; i < size; i++)

    printf("%s ", strings[i]);

    free(strings);

#else

    int fd = open(BACKSTRACE_LOG_NAME, O_CREAT | O_WRONLY);

    size = backtrace(array, MAX_BACKTRACE_LEVEL);

    backtrace_symbols_fd(array, size, fd);

    close(fd);

#endif

    exit(0);

}

void die() {

    char *str1;

    char *str2;

    char *str3;

    char *str4 = NULL;

    strcpy(str4, "ab");

}

void let_it_die() {

    die();

}

int main(int argc, char **argv){

    struct sigaction act;

    act.sa_sigaction = show_reason;

    sigemptyset(&act.sa_mask);

    act.sa_flags = SA_RESTART | SA_SIGINFO;

    sigaction(SIGSEGV, &act, NULL);

    sigaction(SIGUSR1, &act, NULL);

    sigaction(SIGFPE, &act, NULL);

  sigaction(SIGILL, &act, NULL);

    sigaction(SIGBUS, &act, NULL);

    sigaction(SIGABRT, &act, NULL);

    sigaction(SIGSYS, &act, NULL);

    let_it_die();

   return  0;

}

                                       

【调试】

1) 编译

huawei@WUH1000002965:~/test$ gcc backtrace_test.c -o backtrace_test -g –rdynamic

(注:-rdynamic,这个option是传递给linker的,linker会将symbol放到.dydym table中,这样backtrace_symbols才能获取到地址对应的symbol。所以即使是使用了-g来编译程序,如果不使用-rdynamic的话,backtrace_symbols也找不到地址对应的symbol。这是backtrace系列函数的一个缺陷)

2) 运行

huawei@WUH1000002965:~/test$ ./backtrace_test

Obtain 7 stack frames.

./backtrace_test() [0x40096e]

/lib/x86_64-linux-gnu/libc.so.6(+0x364a0) [0x7f2ff171c4a0]

./backtrace_test(die+0x18) [0x400a03]

./backtrace_test(let_it_die+0xe) [0x400a1d]

./backtrace_test(main+0xf6) [0x400b15]

/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f2ff170776d]

./backtrace_test() [0x400889]

免责声明:文章转载自《Linux内核调试方法总结之backtrace》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇selenium常用命令之操作页面元素及获取元素内容的事件整理redux简明学习下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android Native C 之 Helloworld的四种编译方式_转载

一.编写helloworld.c Android.mk     [root@fontlose jni]# cat hello.c  [cpp] view plaincopyprint?  #include <stdio.h>   int main()   {       printf("Hello World!\n");       ...

cJSON 使用详解

由于c语言中,没有直接的字典,字符串数组等数据结构,所以要借助结构体定义,处理json。如果有对应的数据结构就方便一些, 如python中用json.loads(json)就把json字符串转变为内建的数据结构处理起来比较方便。     cjson库文件下载:     sourceforge地址     一个重要概念:         在cjson中,js...

简单入门linux设备驱动之第三部分:向设备驱动程序传递参数

声明:内容搬自阿三哥网站,只是翻译了一下。侵删。https://embetronicx.com/tutorials/linux/device-drivers/ 正文如下: 这是“linux设备驱动系列”的教程。本系列的目的是提供简单实用的示例,使每个人都能以简单的方式理解这些概念。现在让我们即将学习“linux设备驱动第三部分:向设备驱动程序传递参数”。...

mac上编译 arm linux gnueabi交叉编译工具链toolchain

crosstool-ng 编译和安装 交叉编译工具下载: git clone git@github.com:secularbird/crosstool-ng.git   切换到mac编译分支 git checkout origin/macporting -b macporting 该分支对编译中出现的一些编译error,进行了修正,并对mulitlib的...

linux时间同步ntp服务的安装与配置

当我们需要管理多台服务器的时间时,一台一台的修改未免太麻烦了,NTP服务就很好的为我们解决了这个问题! 1.首先安装NTP [root@localhost /]# yum install ntp -y 2.修改NTP配置文件,添加NTP服务器的网络位置    /etc/ntp.conf   # For more information about thi...

Linux下keepalived配置

1、背景 节点1:192.168.12.35 节点2:192.168.12.36 2、keepalived安装 使用yum仓库安装keepalived [root@node01 ~]# yum install -y keepalived [root@node02 ~]# yum install -y keepalived 安装完成后会在/etc文件夹路...