程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Linux下追蹤函數調用,打印棧幀,linux追蹤函數調用

Linux下追蹤函數調用,打印棧幀,linux追蹤函數調用

編輯:C++入門知識

Linux下追蹤函數調用,打印棧幀,linux追蹤函數調用


      事情的起因是這樣的,之前同事的代碼有一個內存池出現了沒有回收的情況。也就是是Pop出來的對象沒有Push回去,情況很難復現,所以在Pop裡的打印日志,跟蹤是誰調用了它,我想在GDB調試裡可以追蹤調用的棧幀,那也一定有方法實現。首先上網搜索了一下,並沒有結果!還好代碼量不是很多,只能用最笨的方法,在每個調用Pop的地方,傳參,把調用的文件,行號作為字符串傳進去,在日志裡打印!忙活完了,總感覺一定是有方法可以實現查看調用棧幀的,於是在QQ群裡的問了下,果然有這方面經驗的同學給出了答案!

    主要是通過backtrace返回調用的棧幀,然後通過backtrace_symbols把地址轉換為字符串。最後,在Linux下有個工具addr2line可以將地址轉換為文件名和行號!通過管道調用addr2line,最後打印調用棧幀。

 1 #include <execinfo.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 /*
 6  * 打印棧幀
 7  * 
 8  * 通過backtrace,backtrace_symbols獲取棧幀信息,然後建立管道,通過addr2line解析
 9  * 
10  */
11 
12 int32_t myexec(const char *cmd) 
13 {
14     FILE *pp = popen(cmd, "r"); //建立管道
15     if (!pp) 
16     {
17         return -1;
18     }
19 char tmp[1024];
while (fgets(tmp, sizeof(tmp), pp) != NULL) 22 { 23 if (tmp[strlen(tmp) - 1] == '\n') 24 { 25 tmp[strlen(tmp) - 1] = '\0'; //去除換行符 26 } 27 28 printf("%-30s",tmp); 29 } 30 printf("\n"); 31 pclose(pp); //關閉管道 32 return 0; 33 } 34 35 void parseName(char * str,char *exeName,char *addr) 36 { 37 char *strTemp = str; 38 char * addrTemp; 39 while (*strTemp != NULL) 40 { 41 if (*strTemp == '(') 42 memcpy(exeName, str, strTemp - str); 43 44 if (*strTemp == '[') 45 addrTemp = strTemp; 46 47 if (*strTemp == ']') 48 memcpy(addr, str + (addrTemp - str) + 1, strTemp - addrTemp - 1); 49 strTemp++; 50 } 51 } 52 53 void print_trace(void) 54 { 55 void *array[10]; 56 size_t size; 57 char **strings; 58 59 size = backtrace(array,10); 60 strings = backtrace_symbols(array,size); 61 62 printf("Obtained %zd stack frames.\n",size); 63 char cmd[500] = {0}; 64 char exeName[100] = {0}; 65 char addr[100] = {0}; 66 for(size_t i = 0;i < size;i++) 67 { 68 memset(cmd,0,sizeof(cmd)); 69 memset(exeName,0,sizeof(exeName)); 70 memset(addr,0,sizeof(addr)); 71 72 parseName(strings[i],exeName,addr); 73 printf("%-15s",addr); 74 sprintf(cmd,"addr2line -f -e %s %s",exeName,addr); 75 myexec(cmd); 76 } 78 } 79 80 void dummp_function(void) 81 { 82 print_trace(); 83 } 84 85 int main(int argc,char *argv[]) 86 { 87 dummp_function(); 88 return 0; 89 }

編譯:

gcc -Wall -g backtrace.cpp -o bt

執行:

./bt

效果:

1 Obtained 5 stack frames.
2 0x4009e6       _Z11print_tracev              /home/dyf/Project/Tool/backtrace.cpp:59
3 0x400b71       _Z14dummp_functionv           /home/dyf/Project/Tool/backtrace.cpp:83
4 0x400b87       main                          /home/dyf/Project/Tool/backtrace.cpp:88
5 0x7fa51f761af5 ??                            ??:0                          
6 0x400769       _start                        ??:? 

大致滿足自己的需求效果,函數名稱還需要修飾一下!

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved