Linux C: Легкий и 'симпатичный' дамп/распечатка структур (как в gdb) - от исходного кода?

У меня есть небольшая проблема с некоторыми структурами в модуле ядра, который я создаю, таким образом, я думал, что было бы хорошо, если бы был простой способ распечатать структуры и их значения - и ниже небольшой пример пространства пользователя того, что я имею в виду.

Скажите, что у нас есть простой пример C как ниже (данный в форме удара, управляет):

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
задан sdaau 22 July 2010 в 18:30
поделиться

5 ответов

Просто хотел сказать - спасибо за все ваши хорошие и невероятно быстрые ответы, очень помогли мне понять проблему (почему в 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

Хотя я не уверен, что он будет работать с модулями ядра ...

Еще раз спасибо за помощь,
Ваше здоровье!

РЕДАКТИРОВАТЬ: Причина, по которой я не думаю, что это будет работать для модулей ядра, заключается в том, что в этом случае у нас есть программа пользовательского уровня с идентификатором процесса; и мы просто вызываем gdb из этой программы, сообщая ему о нашем PID - так gdb может «присоединиться» к нашему процессу; затем, поскольку gdb также получает указание загрузить исполняемый файл с помощью символов отладки (чтобы он «знал», что это за структура), и инструктируется об адресе, по которому находится данная переменная структуры, gdb Затем может распечатать структуру.

Для модулей ядра - во-первых, я не думаю, что они «процессы» в смысле наличия уникального PID, поэтому gdb не будет к чему подключаться! Фактически, существует отладчик ядра, kgdb , который фактически может проникать в работающее ядро ​​и проходить через исходный код модуля module ; однако для этого вам понадобится вторая машина, подключенная через последовательное соединение - или виртуальная машина, см. Linux Hacks: Настройка kgdb с помощью kvm / qemu .

Так что, в любом случае, похоже, что gdb не сможет проверить память запущенного в данный момент ядра хоста gdb работает - но я попробую поэкспериментировать , а если эксперименты покажут обратное, обязательно выложу :)

15
ответ дан 2 December 2019 в 18:18
поделиться

Язык C не имеет метаданных ни во время компиляции, ни во время выполнения. Для этого могут существовать некоторые расширения, специфичные для конкретного производителя. Например, doxygen создаст XML файл со всей информацией о членах (имя и тип) каждого типа struct в вашей программе, не будет слишком сложно написать программу для обработки этого XML файла и автоматической генерации кода для функции printout_person(const struct person*).

2
ответ дан 2 December 2019 в 18:18
поделиться

Вот как я это делаю в VB.NET:

For Each curBookMark In contractBookMarkStarts

      ''# Get the "Run" immediately following the bookmark and then
      ''# get the Run's "Text" field
      runAfterBookmark = curBookMark.NextSibling(Of Wordprocessing.Run)()
      textInRun = runAfterBookmark.LastChild

      ''# Decode the bookmark to a contract attribute
      lines = DecodeContractDataToContractDocFields(curBookMark.Name, curContract).Split(vbCrLf)

      ''# If there are multiple lines returned then some work needs to be done to create
      ''# the necessary Run/Text fields to hold lines 2 thru n.  If just one line then set the
      ''# Text field to the attribute from the contract
      For ptr = 0 To lines.Count - 1
          line = lines(ptr)
          If ptr = 0 Then
              textInRun.Text = line.Trim()
          Else
              ''# Add a <br> run/text component then add next line
              newRunForLf = New Run(runAfterBookmark.OuterXml)
              newRunForLf.LastChild.Remove()
              newBreak = New Break()
              newRunForLf.Append(newBreak)

              newRunForText = New Run(runAfterBookmark.OuterXml)
              DirectCast(newRunForText.LastChild, Text).Text = line.Trim

              curBookMark.Parent.Append(newRunForLf)
              curBookMark.Parent.Append(newRunForText)
          End If
      Next
Next
121---2203085-

См. этот связанный вопрос для получения некоторой информации о синтаксическом анализе структур. В частности, моя ссылка на pstruct .

В вашем случае, когда вы хотите получить информацию изнутри работающей программы, вам придется либо вызвать один из этих внешних инструментов, либо проанализировать отладочную информацию из вашего исполняемого файла и отобразить ее соответствующим образом.

Вы также можете посмотреть libgdb , хотя, похоже, он несколько устарел.

2
ответ дан 2 December 2019 в 18:18
поделиться

Вы должны добавить метаинформацию, описывающую структуру, чтобы printout_struct могла выполнять свою работу. В противном случае он ни о чем не догадывается. Попробуйте с помощью gdb удалить всю отладочную информацию, и вы увидите, что он не может «говорить» о «возрасте» или о чем-то еще.

1
ответ дан 2 December 2019 в 18:18
поделиться

недавно кто-то упомянул

обильные ctags

в stackoverflow для аналогичной задачи. Возможно, тебе удастся это откопать, но я не сразу нашел.

0
ответ дан 2 December 2019 в 18:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: