我正在构建的内核模块中的某些结构有一个小问题,所以我认为,如果有一种简单的方法可以打印出结构及其值,那就太好了,下面是我意思的一个小用户实例。
假设我们有一个简单的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程序; 如下例所示:
johndoe
{age = 6, height = 0}
#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存在像这样的虚构函数-还是有另一种方法可以实现这种打印输出?
printout_struct
预先感谢您的任何帮助, 干杯!
只是想说-感谢您的所有出色且出奇的快速回答,它帮助我很多理解了这个问题(为什么C中没有这样的“本机”功能)!
( 并且很抱歉回答我自己的问题-这样做是为了避免使原始帖子乱码,并能够设置代码格式 )
该示例说明了使用gdb进程本身的pid进行调用的技巧,因此我修改了dumpstack此处找到的函数,以获取以下代码:
gdb
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的userland程序;并且我们只需gdb从该程序中调用,同时对它的PID进行指示- 这样gdb就可以“附加”到我们的过程中;然后,由于gdb还被指示使用调试符号加载可执行文件(因此它将“知道”该结构是什么),并被指示有关给定结构变量所在的地址,因此gdb可以打印出该结构。
对于内核模块- 首先,我认为它们不是具有唯一PID的“进程”,因此gdb没有任何附加条件!实际上,有一个内核调试器kgdb,它实际上可以分解为正在运行的内核并逐步查看 模块 源代码。但是,您需要第二台通过串行连接连接的计算机-或虚拟机,请参阅Linux Hacks:使用kvm / qemu设置kgdb。
因此,无论如何,似乎gdb将无法检查正在运行的当前正在运行的主机内核的内存gdb-但我将尝试进行实验,并且如果实验表明其他情况,我将确保发布:)