• 【分享】使用GNU backtrace打印当前的函数调用关系(backtrace)


    【分享】使用GNU backtrace打印当前的函数调用关系(backtrace)

    概述

    作者: 付汉杰 hankf@xilinx.com hankf@amd.com

    通过GDB等调试器,可以检查一个软件线程当前的函数调用关系(backtrace),也就是a调用b,b调用c,c调用d之类的。
    当出现异常时,Linux kerenl会自动打印当前的函数调用关系(backtrace),为定位问题提供了不少信息。
    在Linux应用程序中,也可以打印当前的函数调用关系(backtrace),GNU为此提供了backtrace ( )和backtrace_symbols( )。以前曾经测试过,发现没有生效,backtrace ( )返回0。
    最近测试,发现backtrace ( )能返回大于0的数,说明工作正常。 另外,在编译器增加选项“-fno-omit-frame-pointer”,在连接器增加选项“-rdynamic”,可以打印出更多信息。

    GNU backtrace 代码

    GNU关于生成函数调用关系(backtrace)的文章在GNU backtrace

    其中的示例代码如下

    #include <execinfo.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    /* Obtain a backtrace and print it to stdout. */
    void
    print_trace (void)
    {
      void *array[10];
      char **strings;
      int size, i;
    
      size = backtrace (array, 10);
      strings = backtrace_symbols (array, size);
      if (strings != NULL)
      {
    
        printf ("Obtained %d stack frames.\n", size);
        for (i = 0; i < size; i++)
          printf ("%s\n", strings[i]);
      }
    
      free (strings);
    }
    
    /* A dummy function to make the backtrace more interesting. */
    void
    dummy_function (void)
    {
      print_trace ();
    }
    
    int
    main (void)
    {
      dummy_function ();
      return 0;
    }
    

    我的测试中,把print_trace()放在一个独立的文件中,编译成一个静态库。

    #include <execinfo.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    /* Obtain a backtrace and print it to stdout.
       https://www.gnu.org/software/libc/manual/html_node/Backtraces.html 
     */
    void print_trace (void)
    {
      void *array[32];
      char **strings;
      int size, i;
    
      // actually return addresses obtained by inspecting the stack
      //    one return address per stack frame.
      // frame pointer elimination will stop backtrace
      size = backtrace (array, 32);
    
      // Translates the return addresses obtained an array of strings.
      // Each string includes the function name, an offset into the function,
      //     and the actual return address (in hexadecimal).
      strings = backtrace_symbols (array, size);
      if (strings != NULL)
      {
    
        printf ("Obtained %d stack frames.\n", size);
        for (i = 0; i < size; i++)
          printf ("%s\n", strings[i]);
      }
    
      free (strings);
    }
    

    静态库的编译信息如下

    18:08:06 **** Incremental Build of configuration Debug for project gnu_backtrace ****
    make all 
    'Building file: ../src/gnu_print_backtrace.c'
    'Invoking: ARM v8 Linux gcc compiler'
    aarch64-linux-gnu-gcc -Wall -O0 -g3 -fno-omit-frame-pointer -c -fmessage-length=0 -MT"src/gnu_print_backtrace.o" -static  -mcpu=cortex-a72 -MMD -MP -MF"src/gnu_print_backtrace.d" -MT"src/gnu_print_backtrace.o" -o "src/gnu_print_backtrace.o" "../src/gnu_print_backtrace.c"
    'Finished building: ../src/gnu_print_backtrace.c'
    ' '
    'Building target: libgnu_backtrace.a'
    'Invoking: ARM v8 Linux archiver'
    aarch64-linux-gnu-ar -r  "libgnu_backtrace.a"  ./src/gnu_print_backtrace.o   
    aarch64-linux-gnu-ar: creating libgnu_backtrace.a
    'Finished building target: libgnu_backtrace.a'
    ' '
    18:08:09 Build Finished (took 2s.641ms)
    

    测试应用程序

    实际调用的print_trace()的代码是一个测试应用程序,代码如下:

    #include <stdio.h>
    
    #include "gnu_print_backtrace.h"
    
    int func_level_3( void )
    {
        printf("In Func: %s, at Line: %d\n", __func__, __LINE__ );
        print_trace ( );
    
        return 0;
    }
    
    int func_level_2( void )
    {
        printf("In Func: %s, at Line: %d\n", __func__, __LINE__ );
        func_level_3( );
    
        return 0;
    }
    
    int func_level_1( void )
    {
        printf("In Func: %s, at Line: %d\n", __func__, __LINE__ );
        func_level_2( );
    
        return 0;
    }
    
    
    int main()
    {
        printf("Hello World\n");
        func_level_1( );
    
        return 0;
    }
    

    测试的应用程序的编译信息如下

    18:10:05 **** Incremental Build of configuration Debug for project gnu_backtrace_test ****
    make all 
    'Building file: ../src/helloworld.c'
    'Invoking: ARM v8 Linux gcc compiler'
    aarch64-linux-gnu-gcc -Wall -O0 -g3 -fno-omit-frame-pointer -I../../gnu_backtrace/src/ -c -fmessage-length=0 -MT"src/helloworld.o" -mcpu=cortex-a72 -MMD -MP -MF"src/helloworld.d" -MT"src/helloworld.o" -o "src/helloworld.o" "../src/helloworld.c"
    'Finished building: ../src/helloworld.c'
    ' '
    'Building target: gnu_backtrace_test.elf'
    'Invoking: ARM v8 Linux gcc linker'
    aarch64-linux-gnu-gcc -L../../gnu_backtrace/Debug/ -mcpu=cortex-a72 -rdynamic -o "gnu_backtrace_test.elf"  ./src/helloworld.o   -lgnu_backtrace
    'Finished building target: gnu_backtrace_test.elf'
    ' '
    'Invoking: ARM v8 Linux Print Size'
    aarch64-linux-gnu-size gnu_backtrace_test.elf  |tee "gnu_backtrace_test.elf.size"
       text	   data	    bss	    dec	    hex	filename
       3478	    672	      8	   4158	   103e	gnu_backtrace_test.elf
    'Finished building: gnu_backtrace_test.elf.size'
    ' '
    18:10:09 Build Finished (took 4s.45ms)
    

    测试的应用程序的运行信息如下:

    root@dapd-0330-tpg-peta:~# uname -a
    Linux dapd-0330-tpg-peta 5.10.0-xilinx-v2021.2 #1 SMP Wed Apr 6 02:57:39 UTC 2022 aarch64 GNU/Linux
    
    root@dapd-0330-tpg-peta:~# ldd ./gnu_backtrace_test.elf
            linux-vdso.so.1 (0x0000ffff8db0c000)
            libc.so.6 => /lib/libc.so.6 (0x0000ffff8d95a000)
            /lib/ld-linux-aarch64.so.1 (0x0000ffff8dadb000)
    
    root@dapd-0330-tpg-peta:~# /lib/libc.so.6
    GNU C Library (GNU libc) stable release version 2.32.
    Copyright (C) 2020 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
    PARTICULAR PURPOSE.
    Compiled by GNU CC version 10.2.0.
    libc ABIs: UNIQUE ABSOLUTE
    For bug reporting instructions, please see:
    <https://www.gnu.org/software/libc/bugs.html>.
    
    root@dapd-0330-tpg-peta:~# ./gnu_backtrace_test_rdynamic.elf
    Hello World
    In Func: func_level_1, at Line: 41
    In Func: func_level_2, at Line: 33
    In Func: func_level_3, at Line: 25
    Obtained 7 stack frames.
    ./gnu_backtrace_test_rdynamic.elf(print_trace+0x14) [0xaaaad7af0c6c]
    ./gnu_backtrace_test_rdynamic.elf(func_level_3+0x24) [0xaaaad7af0bc8]
    ./gnu_backtrace_test_rdynamic.elf(func_level_2+0x24) [0xaaaad7af0bf8]
    ./gnu_backtrace_test_rdynamic.elf(func_level_1+0x24) [0xaaaad7af0c28]
    ./gnu_backtrace_test_rdynamic.elf(main+0x18) [0xaaaad7af0c4c]
    /lib/libc.so.6(__libc_start_main+0xe8) [0xffff9973f878]
    ./gnu_backtrace_test_rdynamic.elf(+0xac8) [0xaaaad7af0ac8]
    
  • 相关阅读:
    SAP MM MIGO过账报错
    SAP MM MB5L事务代码'仅总计'选项初探
    SAP MM 巴西采购订单中的NCM Code
    SAP MM Storage Location Missing in MD04 Result?
    SAP MM 预留单据的历史修改记录?
    2018-8-10-上传代码-CodePlex
    2019-9-2-win10-uwp-九幽图床
    2018-2-13-win10-UWP-应用设置
    2018-2-13-win10-UWP-你写我读
    2018-2-13-win10-UWP-九幽登录
  • 原文地址:https://www.cnblogs.com/hankfu/p/16138721.html
Copyright © 2020-2023  润新知