php 打印函数调用栈,利用backtrace和backtrace_symbols函数打印调用栈信息
本帖最后由 kylin_try 于 2017-2-6 08:41 編輯
在頭文件"execinfo.h"中聲明了三個(gè)函數(shù)用于獲取當(dāng)前線程的函數(shù)調(diào)用堆棧。
#include
int backtrace(void **buffer, intsize);
char **backtrace_symbols(void *const *buffer, intsize);
void backtrace_symbols_fd(void *const *buffer, intsize, intfd);
man 幫助:
DESCRIPTION? ?? ?? ?backtrace() returns a backtrace for the calling program, in the array pointed to by buffer.??A backtrace is the series of currently active function calls for the program.??Each item in the array pointed to by buffer is of type void *, and is the return address from the corresponding stack frame.??The size argument specifies the maximum number of addresses that can be stored in buffer.??If the backtrace is larger than size, then the addresses corresponding to the size most recent function calls are returned; to obtain the complete backtrace, make sure that buffer and size are large enough.Given the set of addresses returned by backtrace() in buffer, backtrace_symbols() translates the addresses into an array of strings that describe the addresses symbolically. The size argument specifies the number of addresses in buffer.??The symbolic representation of each address consists of the function name (if this can be determined), a hexadecimal offset into the function, and the actual return address (in hexadecimal). The address of the array of string pointers is returned as the function result of backtrace_symbols().??This array ismalloc(3)ed by backtrace_symbols(), and must be freed by the caller.??(The strings pointed to by the array of pointers need not and should not be freed.)backtrace_symbols_fd() takes the same buffer and size arguments as backtrace_symbols(), but instead of returning an array of strings to the caller,it writes the strings, one per line, to the file descriptor fd.??backtrace_symbols_fd() does not call malloc(3), and so can be employed in situations where the latter function might fail.
int backtrace(void **buffer,int size)
該函數(shù)用與獲取當(dāng)前線程的調(diào)用堆棧,獲取的信息將會(huì)被存放在buffer中,它是一個(gè)指針數(shù)組。參數(shù) size 用來(lái)指定buffer中可以保存多少個(gè)void* 元素。函數(shù)返回值是實(shí)際獲取的指針個(gè)數(shù),最大不超過(guò)size大小在buffer中的指針實(shí)際是從堆棧中獲取的返回地址,每一個(gè)堆棧框架有一個(gè)返回地址。
注意某些編譯器的優(yōu)化選項(xiàng)對(duì)獲取正確的調(diào)用堆棧有干擾,另外內(nèi)聯(lián)函數(shù)沒(méi)有堆棧框架;刪除框架指針也會(huì)使無(wú)法正確解析堆棧內(nèi)容
char ** backtrace_symbols (void *const *buffer, int size)
backtrace_symbols將從backtrace函數(shù)獲取的信息轉(zhuǎn)化為一個(gè)字符串?dāng)?shù)組. 參數(shù)buffer應(yīng)該是從backtrace函數(shù)獲取的數(shù)組指針,size是該數(shù)組中的元素個(gè)數(shù)(backtrace的返回值),函數(shù)返回值是一個(gè)指向字符串?dāng)?shù)組的指針,它的大小同buffer相同.每個(gè)字符串包含了一個(gè)相對(duì)于buffer中對(duì)應(yīng)元素的可打印信息.它包括函數(shù)名,函數(shù)的偏移地址,和實(shí)際的返回地址
現(xiàn)在,只有使用ELF二進(jìn)制格式的程序和苦衷才能獲取函數(shù)名稱和偏移地址.在其他系統(tǒng),只有16進(jìn)制的返回地址能被獲取.另外,你可能需要傳遞相應(yīng)的標(biāo)志給鏈接器,以能支持函數(shù)名功能(比如,在使用GNU ld的系統(tǒng)中,你需要傳遞(-rdynamic))
backtrace_symbols生成的字符串都是malloc出來(lái)的,但是不要最后一個(gè)一個(gè)的free,因?yàn)閎acktrace_symbols是根據(jù)backtrace給出的call stack層數(shù),一次性的malloc出來(lái)一塊內(nèi)存來(lái)存放結(jié)果字符串的,所以,像上面代碼一樣,只需要在最后,free backtrace_symbols的返回指針就OK了。這一點(diǎn)backtrace的manual中也是特別提到的。
注意:如果不能為字符串獲取足夠的空間函數(shù)的返回值將會(huì)為NULL
void backtrace_symbols_fd (void *const *buffer, int size, int fd)
backtrace_symbols_fd與backtrace_symbols 函數(shù)具有相同的功能,不同的是它不會(huì)給調(diào)用者返回字符串?dāng)?shù)組,而是將結(jié)果寫入文件描述符為fd的文件中,每個(gè)函數(shù)對(duì)應(yīng)一行.它不需要調(diào)用malloc函數(shù),因此適用于有可能調(diào)用該函數(shù)會(huì)失敗的情況。man手冊(cè)中示例:#include
#include
#include
#include
void
myfunc3(void)
{
int j, nptrs;
#define SIZE 100
void *buffer[100];
char **strings;
nptrs = backtrace(buffer, SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
/* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
would produce similar output to the following: */
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf("%s\n", strings[j]);
free(strings);
}
static void? ?/* "static" means don't export the symbol... */
myfunc2(void)
{
myfunc3();
}
void
myfunc(int ncalls)
{
if (ncalls > 1)
myfunc(ncalls - 1);
else
myfunc2();
}
int
main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "%s num-calls\n", argv[0]);
exit(EXIT_FAILURE);
}
myfunc(atoi(argv[1]));
exit(EXIT_SUCCESS);
}
結(jié)果:
總結(jié):使用以下幾個(gè)函數(shù)既可完成堆棧信息的打印
int backtrace (void **buffer, int size)
char ** backtrace_symbols (void *const *buffer, int size)
char* abi::__cxa_demangle
(
const char * mangled_name,
char * output_buffer,
size_t * length,
int * status
)
1. backtrace可以在程序運(yùn)行的任何地方被調(diào)用,返回各個(gè)調(diào)用函數(shù)的返回地址,可以限制最大調(diào)用棧返回層數(shù)。
2. 在backtrace拿到函數(shù)返回地址之后,backtrace_symbols可以將其轉(zhuǎn)換為編譯符號(hào),這些符號(hào)是編譯期間就確定的
3. 根據(jù)backtrace_symbols返回的編譯符號(hào),abi::__cxa_demangle可以找到具體地函數(shù)方法
轉(zhuǎn):http://www.cnblogs.com/mickole/p/3246702.html
總結(jié)
以上是生活随笔為你收集整理的php 打印函数调用栈,利用backtrace和backtrace_symbols函数打印调用栈信息的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 涌泉穴的位置
- 下一篇: 动态规划算法php,php算法学习之动态