2010-07-22 71 views
10

我有一個內核模塊我建立在一些結構一個小問題,所以我認爲這將是很好,如果有打印出結構和值的簡單方法 - 以下是小用戶態例如什麼我的意思是。Linux C:輕鬆&'漂亮'轉儲/結構的打印輸出(如在gdb中) - 從源代碼?

假設我們有如下的簡單的C示例(在bash命令的形式給出):

FN=mtest 

cat > $FN.c <<EOF 
#include <stdio.h> //printf 
#include <stdlib.h> //calloc 

struct person 
{ 
int age; 
int height; 
}; 

static struct person *johndoe; 

main() 
{ 

johndoe = (struct person *)calloc(1, sizeof(struct person)); 
johndoe->age = 6; 

asm("int3"); //breakpoint for gdb 

printf("Hello World - age: %d\n", johndoe->age); 

free(johndoe); 
} 
EOF 

gcc -g -O0 $FN.c -o $FN 

# just a run command for gdb 
cat > ./gdbcmds <<EOF 
run 
EOF 

gdb --command=./gdbcmds ./$FN 

 

如果運行該示例中,程序將編譯和gdb將運行它,並在斷點處自動停止。在這裏,我們可以做到以下幾點:

Program received signal SIGTRAP, Trace/breakpoint trap. 
main() at mtest.c:20 
20 printf("Hello World - age: %d\n", johndoe->age); 
(gdb) p johndoe 
$1 = (struct person *) 0x804b008 
(gdb) p (struct person)*0x804b008 
$2 = {age = 6, height = 0} 
(gdb) c 
Continuing. 
Hello World - age: 6 

Program exited with code 0300. 
(gdb) q 

 

如圖所示,在gdb我們可以打印輸出(轉儲?)的結構指針johndoe的價值{age = 6, height = 0} ...我想這樣做,但直接來自C程序;也就是說,作爲在下面的示例:

#include <stdio.h> //printf 
#include <stdlib.h> //calloc 
#include <whatever.h> //for imaginary printout_struct 

struct person 
{ 
int age; 
int height; 
}; 

static struct person *johndoe; 
static char report[255]; 

main() 
{ 

johndoe = (struct person *)calloc(1, sizeof(struct person)); 
johndoe->age = 6; 

printout_struct(johndoe, report); //imaginary command 

printf("Hello World - age: %d\nreport: %s", johndoe->age, report); 

free(johndoe); 
} 

 

,這將導致與像輸出:

Hello World - age: 6 
$2 = {age = 6, height = 0} 

 

所以我的問題是 - 不會像想象中的函數printout_struct是否存在 - 還是有另一種方法來打印這樣的可能嗎?

在此先感謝您的幫助,
乾杯!

回答

12

只是想說 - 謝謝你的所有好的和令人難以置信的快速答案,幫助我瞭解了很多問題(爲什麼C中沒有這樣的「原生」功能)!

和回答我的問題對不起 - 這樣做,以免斷章取義原崗位,並能格式化代碼)雖然看着

進一步我設法找到:

其示出了三CK與調用gdb與過程本身的PID,所以我修改了dumpstack功能找到,得到下面的代碼:

FN=mtest 

cat > $FN.c <<EOF 
#include <stdio.h> //printf 
#include <stdlib.h> //calloc, system 

extern const char *__progname; 

struct person 
{ 
    int age; 
    int height; 
}; 

static struct person *johndoe; 
static char report[255]; 

static void printout_struct(void* invar, char* structname){ 
    /* dumpstack(void) Got this routine from http://www.whitefang.com/unix/faq_toc.html 
    ** Section 6.5. Modified to redirect to file to prevent clutter 
    */ 
    /* This needs to be changed... */ 
    char dbx[160]; 

    sprintf(dbx, "echo 'p (struct %s)*%p\n' > gdbcmds", structname, invar); 
    system(dbx); 

    sprintf(dbx, "echo 'where\ndetach' | gdb -batch --command=gdbcmds %s %d > struct.dump", __progname, getpid()); 
    system(dbx); 

    sprintf(dbx, "cat struct.dump"); 
    system(dbx); 

    return; 
} 

main() 
{ 

    johndoe = (struct person *)calloc(1, sizeof(struct person)); 

    johndoe->age = 6; 
    printout_struct(johndoe, "person"); 

    johndoe->age = 8; 
    printout_struct(johndoe, "person"); 

    printf("Hello World - age: %d\n:", johndoe->age); 

    free(johndoe); 
} 


EOF 

gcc -g -O0 $FN.c -o $FN 

./$FN 

  基本上結束了顯示我想要的東西:

0x00740422 in __kernel_vsyscall() 
$1 = {age = 6, height = 0} 
0x00740422 in __kernel_vsyscall() 
$1 = {age = 8, height = 0} 
Hello World - age: 8 

 

雖然,我不知道它會與內核模塊工作...

再次感謝您的幫助,
乾杯!

編輯:我不認爲它會適用於內核模塊的原因是,在這種情況下,我們有一個進程ID的用戶級程序;我們只需從該程序中調用gdb,同時指示它關於我們的PID - 因此gdb可以「附加」到我們的過程;那麼,因爲gdb也被指示使用調試符號加載可執行文件(所以它會'知道'結構是什麼),並且指示給定的結構變量所在的地址,然後gdb可以打印結構。

對於內核模塊 - 首先我不認爲它們是具有唯一PID的意義上的'進程',所以gdb將沒有任何附加內容!實際上,有一個內核調試器kgdb,它實際上可以闖入運行的內核,並通過模塊源代碼步進;但是,您需要通過串行連接或虛擬機連接第二臺機器,請參閱Linux Hacks: Setting up kgdb using kvm/qemu

因此,在任何情況下,似乎gdb將無法​​檢查當前運行的主機內核的內存gdb正在運行 - 但我會嘗試嘗試,如果實驗顯示其他情況,我會一定要發佈:)

+1

不要道歉回答你自己的問題,這是在這裏鼓勵。 – dmckee 2010-07-22 20:07:36

+0

SO的自我回答很好;在這種情況下,我會說如果您嘗試更新此答案,以便讓我們知道即使在內核模塊中該解決方案是否正常也會更好。 – ShinTakezou 2010-07-22 20:12:29

+0

好吧 - 謝謝你;我剛剛注意到「你確定要回答你自己的問題」部分,當我試圖發佈它:)此外,添加了一個爲什麼我認爲內核模塊將無法工作的編輯.. – sdaau 2010-07-24 07:43:59

1

您必須添加元信息描述的結構,使printout_struct可以做自己的工作。否則,它不能猜測任何東西。試着用gdb刪除每個調試信息,你會發現它不能「說」「年齡」或其他什麼。

+0

我的意思是,當然關於結構的元信息必須作爲參數給出printout_struct – ShinTakezou 2010-07-22 16:43:26

1

C語言沒有元數據,無論是在編譯時或運行時。可能有一些供應商特定的擴展來執行此操作。例如,doxygen將生成一個XML文件,其中包含程序中每個結構類型的所有成員信息(名稱和類型),編寫程序來處理該XML文件並生成printout_person的代碼不會太困難(const struct person *)函數。

+3

許多(大多數?)編譯器提供了一個「包含調試符號」選項,它可以精確地生成這樣的元數據。在'gcc'的情況下,該選項是'-g'也就是說,在那裏'gdb'獲取信息來完成這個.. – dmckee 2010-07-22 16:56:33

+0

確實。查看我的答案獲取信息的幾種可能性。 – bstpierre 2010-07-22 17:04:20

0

最近有人提到

旺盛的ctags

計算器上對類似的任務。也許你可以挖掘出來,但我沒有立即發現。

2

對結構解析一些信息見this related question。具體我參考pstruct

在你的情況,你想從一個正在運行的程序中獲取信息,你必須要麼調用這些外部工具之一,或解析出從你的可執行文件的調試信息,並適當地顯示它。

你也可以看看libgdb,雖然它看起來可能有些過時。