sda*_*aau 12 c linux printing struct 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
Run Code Online (Sandbox Code Playgroud)
如果我们运行这个例子,程序将编译,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
Run Code Online (Sandbox Code Playgroud)
如图所示,在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);
}
Run Code Online (Sandbox Code Playgroud)
这将产生如下输出:
Hello World - age: 6
$2 = {age = 6, height = 0}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是 - 是否printout_struct存在类似虚构的函数- 或者是否有另一种方法可以使这样的打印输出成为可能?
在此先感谢您的帮助,
干杯!
sda*_*aau 15
只是想说 - 感谢你所有的好和非常快速的答案,帮助我理解了这个问题(为什么在C中没有这样的'原生'功能)!
(并且很抱歉回答我自己的问题 - 这样做,以免乱丢原帖,并能够格式化代码)
在进一步观察的同时,我设法找到:
这说明了使用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
Run Code Online (Sandbox Code Playgroud)
这基本上最终显示我想要的东西:
0x00740422 in __kernel_vsyscall ()
$1 = {age = 6, height = 0}
0x00740422 in __kernel_vsyscall ()
$1 = {age = 8, height = 0}
Hello World - age: 8
Run Code Online (Sandbox Code Playgroud)
虽然,我不确定它是否适用于内核模块......
再次感谢您的帮助,
干杯!
编辑:我不认为它适用于内核模块的原因是,在这种情况下,我们有一个带有进程ID的用户程序; 我们只是gdb从这个程序调用,同时指示我们的PID - 所以gdb可以"附加"到我们的过程; 然后,因为gdb还被指示用调试符号加载可执行文件(因此它将'知道'结构是什么),并指示给定结构变量所在的地址,gdb然后可以打印输出结构.
对于内核模块 - 首先我不认为它们是具有唯一PID的'进程',因此gdb无需附加任何内容!实际上,有一个内核调试器,kgdb实际上可以分解为正在运行的内核并逐步执行模块源代码; 但是,您需要通过串行连接连接的第二台机器 - 或虚拟机,请参阅Linux Hacks:使用kvm/qemu设置kgdb.
所以,无论如何,似乎gdb无法检查当前运行的主机内核gdb正在运行的内存- 但我会尝试进行实验,如果实验显示不然,我一定会发帖:)