成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux下查看函數被那些函數調用過?

系統 Linux
有個打印log的函數,想知道該函數執行的時候,之前執行了哪些函數?

[[389563]]

 一、問題

有個打印log的函數,想知道該函數執行的時候,之前執行了哪些函數?


二、分析

在應用程序打印函數棧需要通過函數backtrace(),該函數對應頭文件如下:

  1. #include <execinfo.h> 

1、三個與打印調用棧相關的函數

打印函數棧需要使用到以下3個函數

  1. int backtrace(void** buffer, int size); 

函數功能:用于獲取當前線程的調用堆棧。參數:buffer:它是一個指針數組,函數獲取的當前線程的調用堆棧將會被存放在buffer中。在buffer中的指針實際是從堆棧中獲取的返回地址,每一個堆棧 框架有一個返回地址。size:用來指定buffer中可以保存多少個void*元素。返回值:實際獲取的指針個數,最大不超過size大小。

char** backtrace_symbols (void *const *buffer, int size);

函數功能:將從backtrace函數獲取的信息轉化為一個字符串數組。參數:buffer:從backtrace函數獲取的數組指針。size:是該數組中的元素個數(backtrace函數的返回值)。返回值:是一個指向字符串數組的指針,它的大小同buffer相同。每個字符串包含了一個相對于buffer中對應元素的 可打印信息。它包括函數名,函數的偏移地址,和實際的返回地址。

注:

  • 1、只有使用ELF二進制格式的程序才能獲取函數名稱和偏移地址。在其他系統,只有16進制的返回地址能被獲取。另外,需要傳遞相應的標志給鏈接器,以能支持函數名功能即編譯選項-rdynamic。
  • 2、backtrace_symbols生成的字符串都是malloc出來的,最后需要free該塊內存。
  1. void backtrace_symbols_fd (void *const *buffer, int sizeint fd) 

功能:backtrace_symbols_fd與backtrace_symbols函數具有相同的功能,不同的是它不會給調用者返回字符串數組,而是將結果寫入文件描述符為fd的文件中,每個函數對應一行.它不需要調用malloc函數,因此適用于有可能調用該函數會失敗的情況。參數:fd:通常填寫STDOUT_FILENO

2. 鏈接庫

在編譯的時候需要加上**-rdynamic**選項。

  1. -rdynamic 
  2.      Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of "dlopen" or to allow obtaining backtraces from within a program. 

該選項讓鏈接器將所有符號添加到動態符號表中,這樣才能將函數地址翻譯成函數名,否則打印的結果是不會打印函數名的。

另外,這個選項不會處理static函數,所以,static函數的符號無法得到。

3. 舉例

  1. #include <execinfo.h> 
  2. #include <stdio.h> 
  3. #include <stdlib.h> 
  4. #include <unistd.h> 
  5.   
  6. void fun1(); 
  7. void fun2(); 
  8. void fun3(); 
  9.   
  10. void print_stacktrace(); 
  11.   
  12. void print_stacktrace() 
  13.     int size = 16; 
  14.     void * array[100]; 
  15.   
  16.     int stack_num = backtrace(array, size); 
  17.   
  18.  char ** stacktrace = backtrace_symbols(array, stack_num); 
  19.   
  20.  backtrace_symbols_fd(array,size,STDOUT_FILENO); 
  21.   
  22. #if 0 
  23.     char ** stacktrace = backtrace_symbols(array, stack_num); 
  24.   
  25.     for (int i = 0; i < stack_num; ++i) 
  26.     { 
  27.         printf("%s\n", stacktrace[i]); 
  28.     } 
  29.     free(stacktrace); 
  30. #endif 
  31. void fun1() 
  32.     printf("stackstrace begin:\n"); 
  33.     print_stacktrace(); 
  34. void fun2() 
  35.     fun1(); 
  36. void fun3() 
  37.     fun2(); 
  38. int main() 
  39.     fun3(); 
  40.   

編譯運行gcc編譯時加上-rdynamic參數,通知鏈接器支持函數名功能(不加-rdynamic參數則無函數名打印):

  1. gcc 123.c -o run -rdynamic -g 

執行結果:


4. 補充 address2line

同一個函數可以在代碼中多個地方調用,如果我們只是知道函數,要想知道在哪里調用了該函數,可以通過address2line命令來完成,我們用第2步中編譯出來的test2來做實驗(address2line的-f選項可以打出函數名, -C選項也可以demangle):

address2line

三、內核代碼中如何打印函數棧?

在Linux內核中提供了一個可以打印出內核調用堆棧的函數 dump_stack()。

該函數在我們調試內核的過程中可以打印出函數調用關系,該函數可以幫助我們進行內核調試,以及讓我們了解內核的調用關系。

1. 頭文件

該函數頭文件為:

  1. #include <asm/ptrace.h> 

使用方式:

直接在想要查看的函數中添加

  1. dump_stack(); 

2. 舉例

測試代碼如下:hello.c

  1.  1 #include <linux/init.h> 
  2.  2 #include <linux/module.h> 
  3.  3 #include <asm/ptrace.h> 
  4.  4  
  5.  6 MODULE_LICENSE("GPL"); 
  6.  7 MODULE_AUTHOR("PD"); 
  7.  8 void aaa(int a); 
  8.  9 void bbb(int b); 
  9. 10 void ccc(int c); 
  10. 11 
  11. 14 void ccc(int c) 
  12. 15 { 
  13. 16     printk(KERN_SOH"cccc \n"); 
  14. 17     dump_stack(); 
  15. 18     printk("c is %d\n",c); 
  16. 19 } 
  17. 20 void bbb(int b) 
  18. 21 { 
  19. 22     int c = b + 10; 
  20. 23     printk(KERN_SOH"bbbb \n"); 
  21. 24     ccc(c); 
  22. 25 } 
  23. 26 void aaa(int a) 
  24. 27 { 
  25. 28     int b = a + 10; 
  26. 29     printk(KERN_SOH"aaaa \n"); 
  27. 30     bbb(b); 
  28. 31 } 
  29. 32  
  30. 34 static int hello_init(void) 
  31. 35 { 
  32. 36     int a = 10;                                                                 
  33. 37  
  34. 38     aaa(a); 
  35. 39     printk(KERN_SOH"hello_init \n"); 
  36. 40  
  37. 41     return 0; 
  38. 42 } 
  39. 43 static void hello_exit(void) 
  40. 44 { 
  41. 45     printk("hello_exit \n"); 
  42. 46     return
  43. 47 } 
  44. 48  
  45. 49 module_init(hello_init); //insmod 
  46. 50 module_exit(hello_exit);//rmmod 

Makefile

  1. ifneq ($(KERNELRELEASE),) 
  2. obj-m:=hello.o 
  3. else 
  4. KDIR :=/lib/modules/$(shell uname -r)/build 
  5. PWD  :=$(shell pwd) 
  6. all
  7.  make -C $(KDIR) M=$(PWD) modules 
  8. clean: 
  9.  rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order 
  10. endif 

編譯安裝模塊

  1. dmesg -c 
  2. make 
  3. insmod hello.ko 

【注意】 都在root權限下操作

結果

可以看到在函數ccc中使用dump_stack()打印出了ccc的函數調用棧。

在內核開發中,我們可以使用dump_stack()來打印相關信息,同時在內核源碼學習中也可以用來了解函數調用關系。

 

責任編輯:姜華 來源: 一口Linux
相關推薦

2011-04-25 16:35:06

Linux調用

2010-01-12 11:48:59

Linuxitoa函數

2009-08-05 09:40:02

C#調用DLL函數

2020-09-28 08:12:59

CC++時間

2020-01-17 20:00:25

SQL函數數據庫

2023-10-26 11:37:35

函數Python

2023-10-26 11:39:54

Linux系統CPU

2022-05-18 08:00:26

函數劫持JavaScript鉤子函數

2024-01-15 09:15:52

parallel語句函數

2021-11-30 08:44:29

SpringRouter Func函數式接口

2010-01-28 13:35:41

調用C++函數

2017-03-08 15:39:11

Linuxselect函數

2010-07-28 15:29:18

Flex函數

2023-12-22 16:39:47

Java函數式接口開發

2010-05-31 09:19:53

PHP

2017-03-16 14:37:05

LinuxShell函數

2020-08-16 10:58:20

Pandaspython開發

2023-09-09 12:23:24

函數式接口程序

2020-09-14 10:34:40

Dubbo

2013-01-21 10:27:47

蘋果App Store下架
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产高清在线精品一区二区三区 | 日本人爽p大片免费看 | 亚洲欧洲一区二区 | 一级黄色片毛片 | 91精品国产一二三 | 99re超碰 | 1000部精品久久久久久久久 | 亚洲精品日韩在线观看 | 精品福利在线 | 欧美91| 精品国产区| 亚洲精品久久久久久久久久久 | 欧美日韩国产一区二区三区 | 色婷婷久久综合 | 欧美激情国产日韩精品一区18 | 国产一区不卡 | 亚洲一级黄色 | 国产高清久久久 | 国产精品一区二区在线观看 | 日韩欧美三区 | www日本在线观看 | 一区二区三区视频 | 国产精品区一区二区三区 | 精久久久 | 综合五月| 一区二区三区四区在线视频 | 日本精品一区 | 日韩激情一区 | 亚洲综合在线一区二区 | 国产精品不卡视频 | 免费看a| 精品二区 | 美女黄18岁以下禁止观看 | 一级做a爰片性色毛片16 | 毛片一级黄色 | 欧美日韩大片 | 国产欧美精品区一区二区三区 | 欧美日韩久久 | 日韩精品区 | 在线一区二区三区 | a级网站 |