当前位置: 首页 > 面试题库 >

Linux C:结构的简单且“漂亮”的转储/打印输出(如gdb)-从源代码开始?

鲁永福
2023-03-14
问题内容

我正在构建的内核模块中的某些结构有一个小问题,所以我认为,如果有一种简单的方法可以打印出结构及其值,那就太好了,下面是我意思的一个小用户实例。

假设我们有一个简单的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存在像这样的虚构函数-还是有另一种方法可以实现这种打印输出?

预先感谢您的任何帮助,
干杯!


问题答案:

只是想说-感谢您的所有出色且出奇的快速回答,它帮助我很多理解了这个问题(为什么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

基本上最终显示了我想要的东西:

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-但我将尝试进行实验,并且如果实验表明其他情况,我将确保发布:)



 类似资料:
  • 问题内容: 我使用以下代码将a漂亮地打印到JSON中: 输出: 这有点 太多了 (每个列表元素的换行!)。 我应该使用哪种语法: 代替? 问题答案: 几年后,我找到了带有内置模块的解决方案: 输出:

  • # pprint_data.py data = [ (1, {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D'}), (2, {'e': 'E', 'f': 'F', 'g': 'G', 'h': 'H', 'i': 'I', 'j': 'J', 'k': 'K', 'l': 'L'}), (3, ['m', 'n']),

  • 如何从AWS漂亮地打印出Boto EC2输出? 这是原版(不太漂亮): s是什么? 如果我尝试使用Python的JSON转储,我得到:

  • 我正在解组一个结构,我希望它以格式化的方式打印它。 我的代码(https://play.golang.org/p/D0KwGP6Cxa0)当前生成以下输出: 我希望它只有名称和值,并在每个项目后有一个新行。例如: 你知道我该怎么做吗?

  • 问题内容: 我是一个json对象 在上面的说法应该是相当打印结果。如果我做类似的事情,它就是这样做的。但是,我想通过将其附加到div中来输出给用户。当我这样做时,我只会显示一行。(我认为它不起作用,因为中断和空格未解释为html?) 有没有办法以漂亮的打印方式将结果输出到div? 问题答案: 请使用 标签 演示:http : //jsfiddle.net/K83cK/

  • 我有一个Spring Boot控制台应用程序,我通过JMX访问执行器endpoint。问题是返回的文本打印得不好,也不是JSON。它看起来像这样: 将其转换为可读格式的最佳方法是什么?是否可以将JMX执行器配置为漂亮打印?是否可以将JMX执行器配置为使用JSON? 有一个关于Spring Boot Actuatorendpoint的漂亮打印JSON输出的相关问题,但在这种情况下,我被JMX卡住了,