1. 程式人生 > >【除錯】列印函式棧,以及由函式指標輸出函式名的方法

【除錯】列印函式棧,以及由函式指標輸出函式名的方法

Before All

以下皆在linux環境下。windows上用vs可隨時檢視函式棧。

使用者態

列印函式棧

使用backtrace()相關函式來達到輸出函式棧的目的,man backtrace檢視詳細的引數,返回值等資訊。
以下測試例,編譯時需加上-rdynamic選項:

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

#define SIZE 100

void myfunc3(void)
{
    int nptrs;
    void *buffer[100
]; char **strings; nptrs = backtrace(buffer, SIZE); printf("backtrace() returned %d addresses\n", nptrs); /* 1 means standard output */ backtrace_symbols_fd(buffer, nptrs, 1); /* or use backtrace_symbols() */ /* 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() { myfunc3(); } void myfunc() { myfunc2(); } int main() { myfunc(); return 0; }

簡單說下這3個函式的用法:

int backtrace(void **buffer, int size);
backtrace()把函式棧中的函式地址寫到buffer陣列,buffer陣列的成員即void *型別。size表示把棧頂size個函式地址搞出來,如果想把函式棧完全搞出來,確保buffer陣列和size足夠大。

char **backtrace_symbols(void *const *buffer, int size);
void backtrace_symbols_fd(void *const *buffer, int size, int fd);
backtrace_symbols()或者backtrace_symbols_fd()與上邊的backtrace()配合使用,起一個翻譯作用,即把函式地址翻譯為函式名(還有函式的偏移和返回地址)。backtrace_symbols()把buffer陣列中的size個元素翻譯為函式名,把字串陣列儲存在返回值char **中,自帶了malloc功能,用完需把返回值free,見測試例。backtrace_symbols_fd()前兩個引數和前者一樣,但是把結果字串陣列輸出到fd中,如fd=1,即輸出到螢幕。

由函式指標得到函式名

根據以上可以看出,backtrace_symbols和backtrace_symbols_fd可以用來將函式指標轉換為函式名,函式指標的講解可以參考這裡,以下是測試例:

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

void hello_world()
{
    printf("hello world!\n");
}

int main()
{
    void *func = hello_world; //注意這裡必須轉化為一個void *指標
    backtrace_symbols_fd(&func, 1, 1); 
    return 0;
}

這裡就把函式指標func的函式名輸出了出來。

核心態

列印函式棧

使用dump_stack()函式。直接在需要檢視函式棧的位置加入這一句,然後dmesg中就可以看到函式棧了。

由函式指標得到函式名

核心中可以直接使用printk的%pf,%pF選項,%pF選項多列印偏移地址。測試例:

void testname()
{
    return;
}
void test()
{
    void (*funcptr) = testname;
    printk("%pf\n", funcptr);
}

小結

以上就是在使用者態,核心態輸出函式棧,以及由函式指標輸出函式名的方法,在除錯的過程中有時能幫助加深對程式碼的理解。