翻譯自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來(lái)查看調(diào)用棧论咏。然而,有時(shí)候在程序中通過(guò)編碼的方式獲取調(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 中的指針全部返回通過(guò)檢查堆棧(stack)獲得的實(shí)際地址棒旗,每個(gè)指針?lè)祷匾粚訔?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)但是指向通過(guò) 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 作為程序和庫(kù)的二進(jìn)制格式的系統(tǒng)上獲取。在其他系統(tǒng)上衍腥,只有十六進(jìn)制返回地址可以表示磺樱。當(dāng)然纳猫,你也可能需要通過(guò)向連接器傳遞額外標(biāo)記使程序可以獲取函數(shù)名。(例如竹捉,在使用 GNU ld 的系統(tǒng)上芜辕,你需要傳遞 -rdynamic)
backtrace_symbols 的返回值是通過(guò) malloc 函數(shù)獲取的指針击狮,調(diào)用者有義務(wù)釋放該指針劣摇。注意只有返回值需要被釋放,不是單獨(dú)的字符串喻鳄。
如果沒(méi)有足夠的內(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ù)可能失敗的情況下使用眶根。
下面的程序說(shuō)明了這些函數(shù)的用法。注意包含由 backtrace 返回的地址的數(shù)組被分配到了棧上边琉。因此這樣的代碼可以在無(wú)法通過(guò) malloc 獲取內(nèi)存的情況下使用(同樣也是 backtrace_symbols 需要唄替換為 backtrace_symbols_fd 的情況)属百。一般情況下返回的地址的個(gè)數(shù)不會(huì)太多。即使復(fù)雜的程序也很少有超過(guò)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 ();
}