ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-04-13 09:32:54  阅读:198  来源: 互联网

标签:src gnu backtrace GNU 函数调用 test func print


【分享】使用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:~# ./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]

标签:src,gnu,backtrace,GNU,函数调用,test,func,print
来源: https://www.cnblogs.com/hankfu/p/16138721.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有