在程序中操作調(diào)用棧

翻譯自http://www.gnu.org/software/libc/manual/html_node/Backtraces.html#Backtraces


調(diào)用棧(Backtraces)

調(diào)用棧是線程中當(dāng)前激活的函數(shù)調(diào)用列表。通常借助外部調(diào)試工具如gdb來查看調(diào)用棧。然而,有時(shí)候在程序中通過編碼的方式獲取調(diào)用棧是非常有用的,例如,為了記錄日志或者診斷程序。

頭文件execinfo.h聲明了三個(gè)函數(shù),從當(dāng)前線程中獲取和操作調(diào)用棧。


函數(shù):int backtrace (void **buffer, int size)

Preliminary: | MT-Safe | AS-Unsafe init heap dlopen plugin lock | AC-Unsafe init mem lock fd | See POSIX Safety Concepts.

backtrace 函數(shù)獲取當(dāng)前線程的調(diào)用棧作為一個(gè)列表(list of pointers),并將信息裝入 buffer 中。參數(shù) size 應(yīng)當(dāng)是將要裝入 buffer 的 void * 類型元素的個(gè)數(shù)。返回值是實(shí)際裝入 buffer 的全部元素的個(gè)數(shù),最大值為 size

buffer 中的指針全部返回通過檢查堆棧(stack)獲得的實(shí)際地址,每個(gè)指針返回一層棧幀(stack frame)的地址。

需要注意的是某些編譯器優(yōu)化會(huì)打亂獲取的有效的調(diào)用棧。函數(shù)內(nèi)聯(lián)導(dǎo)致內(nèi)聯(lián)函數(shù)不擁有調(diào)用幀棧;尾調(diào)用優(yōu)化會(huì)用一個(gè)調(diào)用幀棧取代另一個(gè);幀指針缺失將阻止 backtrace 正確解釋堆棧內(nèi)容。


函數(shù):char ** backtrace_symbols (void *const *buffer int size)

Preliminary: | MT-Safe | AS-Unsafe heap | AC-Unsafe mem lock | See POSIX Safety Concepts.

backtrace_symbols 函數(shù)將 backtrace 函數(shù)獲取的信息轉(zhuǎn)換成一個(gè)字符串?dāng)?shù)組。參數(shù) buffer 應(yīng)但是指向通過 backtrace 函數(shù)獲取的地址數(shù)組的指針,size 是該數(shù)組的元素個(gè)數(shù)(backtrace的返回值)。

返回值是指向一個(gè)字符串?dāng)?shù)組的指針,改數(shù)組和 buffer 一樣擁有 size 個(gè)元素。每個(gè)字符轉(zhuǎn)都包含 buffer 中元素對(duì)應(yīng)的可閱讀描述。其中包含函數(shù)名(如果可以確定),進(jìn)入函數(shù)的偏移量,和實(shí)際返回地址(十六進(jìn)制)。

當(dāng)前,函數(shù)名和偏移量只能在使用 ELF 作為程序和庫的二進(jìn)制格式的系統(tǒng)上獲取。在其他系統(tǒng)上,只有十六進(jìn)制返回地址可以表示。當(dāng)然,你也可能需要通過向連接器傳遞額外標(biāo)記使程序可以獲取函數(shù)名。(例如,在使用 GNU ld 的系統(tǒng)上,你需要傳遞 -rdynamic)

backtrace_symbols 的返回值是通過 malloc 函數(shù)獲取的指針,調(diào)用者有義務(wù)釋放該指針。注意只有返回值需要被釋放,不是單獨(dú)的字符串。

如果沒有足夠的內(nèi)存存儲(chǔ)字符串,返回值為 NULL 。


函數(shù):void backtrace_symbols_fd (void *const *buffer, int size, int fd)

Preliminary: | MT-Safe | AS-Safe | AC-Unsafe lock | See POSIX Safety Concepts.

backtrace_symbols_fd 函數(shù)執(zhí)行與 backtrace_symbols 函數(shù)相同的轉(zhuǎn)換。該函數(shù)不將字符串返回給調(diào)用者,而是將字符串寫入描述符為 fd 的文件,每個(gè)一行。由于不使用 malloc 函數(shù),因此可以在該函數(shù)可能失敗的情況下使用。


下面的程序說明了這些函數(shù)的用法。注意包含由 backtrace 返回的地址的數(shù)組被分配到了棧上。因此這樣的代碼可以在無法通過 malloc 獲取內(nèi)存的情況下使用(同樣也是 backtrace_symbols 需要唄替換為 backtrace_symbols_fd 的情況)。一般情況下返回的地址的個(gè)數(shù)不會(huì)太多。即使復(fù)雜的程序也很少有超過50嵌套的層次,200條記錄應(yīng)該足以覆蓋所有程序了。

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

/* Obtain a backtrace and print it to stdout. */
void
print_trace (void)
{
  void *array[10];
  size_t size;
  char **strings;
  size_t i;

  size = backtrace (array, 10);
  strings = backtrace_symbols (array, size);

  printf ("Obtained %zd 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 ();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文地址:C語言函數(shù)調(diào)用棧(一)C語言函數(shù)調(diào)用棧(二) 0 引言 程序的執(zhí)行過程可看作連續(xù)的函數(shù)調(diào)用。當(dāng)一個(gè)函數(shù)執(zhí)...
    小豬啊嗚閱讀 4,957評(píng)論 1 19
  • 第一章 Nginx簡(jiǎn)介 Nginx是什么 沒有聽過Nginx?那么一定聽過它的“同行”Apache吧!Ngi...
    JokerW閱讀 33,017評(píng)論 24 1,002
  • PHP常用函數(shù)大全 usleep() 函數(shù)延遲代碼執(zhí)行若干微秒。 unpack() 函數(shù)從二進(jìn)制字符串對(duì)數(shù)據(jù)進(jìn)行解...
    上街買菜丶迷倒老太閱讀 1,487評(píng)論 0 20
  • 李叫獸,李靖,1991年出生,微信公眾號(hào)“李叫獸”的創(chuàng)始人之一,現(xiàn)為百度副總裁。從2014年起,李靖在公眾號(hào)“李叫...
    Lighthouse_長腿哥哥閱讀 3,306評(píng)論 1 8
  • 把水燒燙,開水壺里冒著泡 我縮成一團(tuán) 翻著書跪在床上 你就把毛巾擰干,絮絮叨叨 我總是回家以后就讓你操勞 洗臉,泡...
    子皿子皿閱讀 330評(píng)論 0 0

友情鏈接更多精彩內(nèi)容