翻譯自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 ();
}