У меня есть небольшая проблема с некоторыми структурами в модуле ядра, который я создаю, таким образом, я думал, что было бы хорошо, если бы был простой способ распечатать структуры и их значения - и ниже небольшой пример пространства пользователя того, что я имею в виду.
Скажите, что у нас есть простой пример 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
существуйте - или есть ли другой подход для создания распечатки как это возможной?
Заранее спасибо за любую справку,
Удачи!
Просто хотел сказать - спасибо за все ваши хорошие и невероятно быстрые ответы, очень помогли мне понять проблему (почему в 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
работает - но я попробую поэкспериментировать , а если эксперименты покажут обратное, обязательно выложу :)
Язык C не имеет метаданных ни во время компиляции, ни во время выполнения. Для этого могут существовать некоторые расширения, специфичные для конкретного производителя. Например, doxygen создаст XML файл со всей информацией о членах (имя и тип) каждого типа struct в вашей программе, не будет слишком сложно написать программу для обработки этого XML файла и автоматической генерации кода для функции printout_person(const struct person*).
Вот как я это делаю в 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 , хотя, похоже, он несколько устарел.
Вы должны добавить метаинформацию, описывающую структуру, чтобы printout_struct могла выполнять свою работу. В противном случае он ни о чем не догадывается. Попробуйте с помощью gdb удалить всю отладочную информацию, и вы увидите, что он не может «говорить» о «возрасте» или о чем-то еще.
недавно кто-то упомянул
обильные ctags
в stackoverflow для аналогичной задачи. Возможно, тебе удастся это откопать, но я не сразу нашел.