【分享】使用GNU backtrace列印當前的函式呼叫關係(backtrace)
阿新 • • 發佈:2022-04-13
【分享】使用GNU backtrace列印當前的函式呼叫關係(backtrace)
概述
作者: 付漢傑 [email protected] [email protected]
通過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靜態庫
我的測試中,把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]