zoukankan      html  css  js  c++  java
  • 如何记录程序调用栈

    先看效果

    [root@node223 test]# ls
    a.out  backtrace.c  core.2021-9-26_11_13_26
    [root@node223 test]# cat core.2021-9-26_11_13_26
    Dump Time: 2021-9-26 11:13:26
    Curr thread: 2905941824, Catch signal:11
    backtrace rank = 8
    ./a.out(server_backtrace+0x29c) [0x400f39]
    ./a.out(funcd+0xe) [0x400c6b]
    ./a.out(funcc+0xe) [0x400c7b]
    ./a.out(funcb+0xe) [0x400c8b]
    ./a.out(funca+0xe) [0x400c9b]
    ./a.out(main+0xe) [0x40107c]
    /lib64/libc.so.6(__libc_start_main+0xf5) [0x7fe8acb77625]
    ./a.out() [0x400b99]
    [root@node223 test]# addr2line -e a.out 0x400c6b
    /liuye/test/backtrace.c:15
    [root@node223 test]# addr2line -e a.out 0x400c7b
    /liuye/test/backtrace.c:24
    [root@node223 test]# addr2line -e a.out 0x400c8b
    /liuye/test/backtrace.c:33
    [root@node223 test]# addr2line -e a.out 0x400c9b
    /liuye/test/backtrace.c:42
    [root@node223 test]# addr2line -e a.out 0x40107c
    /liuye/test/backtrace.c:113
    [root@node223 test]#
    可用脚本翻译
    cat core.1085720-11-2021-9-26_14_24_18 | cut -d"[" -f2 | tr -d "]" | addr2line -e a.out
    cut主要参数
    -b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
    -c :以字符为单位进行分割。
    -d :自定义分隔符,默认为制表符。
    -f  :与-d一起使用,指定显示哪个区域。
    -n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的<br />范围之内,该字符将被写出;否则,该字符将被排除。

    Linux tr 命令用于转换或删除文件中的格式。
    • -c, 补:反设定编码。
    • -d, --delete:删除字符字符
    • -s, --squeeze-repeats:连续重复的字符成指定的字符字符
    • -t, --truncate-set1:缩小SET1指定范围,使之与SET2设定长度相等
    • --help:显示程序使用信息
    • --version:显示程序制作的版本信息

    [root@node223 test]# cat core.1085720-11-2021-9-26_14_24_18 | cut -d"[" -f2 | tr -d "]" | addr2line -e a.out
    ??:0
    ??:0
    ??:0
    ??:0
    /xxx/test/backtrace.c:75
    /xxx/test/backtrace.c:12
    /xxx/test/backtrace.c:16
    /xxx/test/backtrace.c:20
    /xxx/test/backtrace.c:24
    /xxx/test/backtrace.c:98
    ??:0
    ??:?



    贴源码:

    1 #include <stdio.h>
    2 #include <execinfo.h>
    3 #include <string.h>
    4 #include <stdlib.h>
    5 #include <pthread.h>
    6 #include <unistd.h>
    7 #include <fcntl.h>
    8 void server_backtrace(int sig);
    9 void funcd()
    10 {
    11 server_backtrace(11);
    12 }
    13 void funcc()
    14 {
    15 funcd();
    16 }
    17 void funcb()
    18 {
    19 funcc();
    20 }
    21 void funca()
    22 {
    23 funcb();
    24 }
    25 void server_backtrace(int sig)
    26 {
    27 //打开文件
    28 time_t tSetTime;
    29 time(&tSetTime);
    30 struct tm* ptm = localtime(&tSetTime);
    31 char fname[256] = {0};
    32 sprintf(fname, "core.%d-%d-%d-%d-%d_%d_%d_%d",
    33 getpid(),sig,
    34 ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
    35 ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    36 FILE* f = fopen(fname, "a");
    37 if (f == NULL){
    38 return;
    39 }
    40 int fd = fileno(f);
    41
    42 //锁定文件
    43 struct flock fl;
    44 fl.l_type = F_WRLCK;
    45 fl.l_start = 0;
    46 fl.l_whence = SEEK_SET;

    47 fl.l_len = 0;
    48 fl.l_pid = getpid();
    49 fcntl(fd, F_SETLKW, &fl);
    50
    51 //输出程序的绝对路径
    52 char buffer[4096];
    53 memset(buffer, 0, sizeof(buffer));
    54 int count = readlink("/proc/self/exe", buffer, sizeof(buffer));
    55 if(count > 0){
    56 buffer[count] = ' ';
    57 buffer[count + 1] = 0;
    58 fwrite(buffer, 1, count+1, f);
    59 }
    60
    61 //输出信息的时间
    62 memset(buffer, 0, sizeof(buffer));
    63 sprintf(buffer, "Dump Time: %d-%d-%d %d:%d:%d ",
    64 ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
    65 ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    66 fwrite(buffer, 1, strlen(buffer), f);
    67
    68 //线程和信号
    69 sprintf(buffer, "Curr thread: %u, Catch signal:%d ",
    70 (int)pthread_self(), sig);
    71 fwrite(buffer, 1, strlen(buffer), f);
    72
    73 //堆栈
    74 void* DumpArray[256];
    75 int nSize = backtrace(DumpArray, 256);
    76 sprintf(buffer, "backtrace rank = %d ", nSize);
    77 fwrite(buffer, 1, strlen(buffer), f);
    78 int i;
    79 if (nSize > 0){
    80 char** symbols = backtrace_symbols(DumpArray, nSize);
    81 if (symbols != NULL){
    82 for (i=0; i<nSize; i++){
    83 fwrite(symbols[i], 1, strlen(symbols[i]), f);
    84 fwrite(" ", 1, 1, f);
    85 }
    86 free(symbols);
    87 }
    88 }
    89
    90 //文件解锁后关闭
    91 fl.l_type = F_UNLCK;

    92 fcntl(fd, F_SETLK, &fl);
    93 fclose(f);
    94 }
    95 int main()
    96 {
    97 funca();
    98 return 0;
    99 }
    100

    编译:gcc -g -rdynamic -Wall  backtrace.c -pthread -Werror

      -rdynamic:选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中

    有时候,不小心知道了一些事,才发现自己所在乎的事是那么可笑。
  • 相关阅读:
    Linux-配置共享目录
    Linux-expect脚本-编写一个expect脚本
    MySQL-Linux下安装
    ETL-拉链算法-1
    ETL-拉链算法-带删除的拉链算法
    postgresql-基础-1
    Oracle-sql*plus
    【剑指offer11二进制中1的个数】
    【剑指offer10 矩形覆盖】
    【剑指offer080 09 跳台阶、变态跳台阶】
  • 原文地址:https://www.cnblogs.com/axjlxy/p/15338075.html
Copyright © 2011-2022 走看看