Wie füge ich C Backtrace in einen Kernelmodulcode ein?

Lesezeit: 7 Minuten

Also versuche ich herauszufinden, welche Kernelprozesse einige Funktionen in einem Blocktreiber aufrufen. Ich dachte, das Hinzufügen von backtrace() in die C-Bibliothek würde es einfach machen. Aber ich habe Probleme, den Backtrace zu laden.

Ich habe diese Beispielfunktion kopiert, um den Backtrace anzuzeigen:

http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/063/6391/6391l1.html

Alle Kompilierungsversuche haben an der einen oder anderen Stelle den Fehler, dass eine Datei nicht gefunden werden kann oder dass die Funktionen nicht definiert sind.

Hier ist, was am nächsten kommt.

In das Makefile habe ich die Compiler-Direktiven eingefügt:

 -rdynamic -I/usr/include 

Wenn ich das zweite weglasse, -I/usr/include, meldet der Compiler, dass er den erforderlichen Header execinfo.h nicht finden kann.

Als nächstes habe ich in dem Code, in dem ich den Backtrace ausführen möchte, die Funktion aus dem Beispiel kopiert:

//trying to include the c backtrace capability
#include <execinfo.h>

void show_stackframe() {
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;

trace_size = backtrace(trace, 16);
messages = backtrace_symbols(trace, trace_size);
printk(KERN_ERR "[bt] Execution path:\n");
for (i=0; i<trace_size; ++i)
    printk(KERN_ERR "[bt] %s\n", messages[i]);
}
//backtrace function

Ich habe den Aufruf dieser Funktion später in eine Blocktreiberfunktion eingefügt, in der das erste Anzeichen des Fehlers auftritt. Einfach:

show_stackframe();

Also, wenn ich es kompiliere, die folgenden Fehler:

user@slinux:~/2.6-32$ make -s
Invoking make againt the kernel at /lib/modules/2.6.32-5-686/build
In file included from /usr/include/features.h:346,
        from /usr/include/execinfo.h:22,
        from /home/linux/2.6-32/block/block26.c:49:
/usr/include/sys/cdefs.h:287:1: warning: "__always_inline" redefined
In file included from /usr/src/linux-headers-2.6.32-5-common/include/linux/compiler-gcc.h:86,
        from /usr/src/linux-headers-2.6.32-5-common/include/linux/compiler.h:40,
        from /usr/src/linux-headers-2.6.32-5-common/include/linux/stddef.h:4,
        from /usr/src/linux-headers-2.6.32-5-common/include/linux/list.h:4,
        from /usr/src/linux-headers-2.6.32-5-common/include/linux/module.h:9,
        from /home/linux/2.6-32/inc/linux_ver.h:40,
        from /home/linux/2.6-32/block/block26.c:32:
/usr/src/linux-headers-2.6.32-5-common/include/linux/compiler-gcc4.h:15:1: warning: this is the location of the previous definition
    /home/linux/2.6-32/block/block26.c:50: warning: function declaration isn’t a prototype
WARNING: "backtrace" [/home/linux/2.6-32/ndas_block.ko] undefined!
WARNING: "backtrace_symbols" [/home/linux/2.6-32/ndas_block.ko] undefined!

Hinweis: block26.c ist die Datei, von der ich hoffe, den Backtrace zu erhalten.

Gibt es einen offensichtlichen Grund, warum backtrace und backtrace_symbols undefiniert bleiben, wenn es in die .ko-Module kompiliert wird?

Ich vermute es, weil ich das Compiler-Include execinfo.h verwende, das sich auf dem Computer befindet und nicht in das Modul geladen wird.

Es ist meine ungebildete Vermutung, um es gelinde auszudrücken.

Kann jemand helfen, die Backtrace-Funktionen in das Modul zu laden?

Danke, dass Sie sich diese Anfrage angesehen haben.

Ich arbeite an Debian. Wenn ich die Funktion und dergleichen herausnehme, kompiliert das Modul einwandfrei und funktioniert fast perfekt.

Von ndasusers

  • Ich bin mir nicht sicher, ob Sie Bibliotheken wie diese in den Code des Kernelmoduls aufnehmen sollen. Haben Sie versucht, einfach gdb zu verwenden und einen Haltepunkt zu setzen? [1] [1]: xml.com/ldd/chapter/book/ch04.html#t5

    – zdav

    2. Mai 2011 um 22:37 Uhr


  • Ach Ratten! Ich hatte Angst, so etwas zu hören. Das sieht nach einem nützlichen Kapitel aus, mit dem Sie mich verlinkt haben. Dank dafür.

    – ndasusers

    2. Mai 2011 um 23:44 Uhr

  • Im Gegensatz zu User-Space-Programmen ist der Kernel nicht mit der Standard-C-Bibliothek (oder irgendeiner anderen Bibliothek, was das betrifft) gelinkt. kernelnewbies.org/FAQ/LibraryFunctionsInKernel

    – jschmier

    3. Mai 2011 um 18:21 Uhr

  • Jetzt, wo ich es verstehe, macht es absolut Sinn. Wie kann von einem Kernel erwartet werden, dass er viele Bibliotheken verwendet, die möglicherweise nicht einmal auf einem System vorhanden sind?

    – ndasusers

    7. Mai 2011 um 4:46 Uhr

Um den Stack-Inhalt und einen Backtrace zum Kernel-Log auszugeben, verwenden Sie die dump_stack() Funktion in Ihrem Kernel-Modul. Es ist deklariert in linux/kernel.h im include-Ordner im Kernel-Quellverzeichnis.

  • Danke. Das ist das, was ich mit dem c-Backtrace erwartet habe. Jetzt brauche ich nur noch einen neuen Beitrag, um ihn beim Lesen zu unterstützen.

    – ndasusers

    7. Mai 2011 um 4:45 Uhr

  • Die angezeigten Werte befinden sich in zwei Blöcken: Der erste ist der rohe Inhalt des Stacks, der durch die Adresse angezeigt wird, und der zweite zeigt jeden Stack-Frame wie einen regulären Backtrace.

    – jmkeyes

    7. Mai 2011 um 4:55 Uhr


Wenn Sie den Stack-Trace speichern und seine Elemente irgendwie verarbeiten müssen, save_stack_trace() oder dump_trace() wäre vielleicht auch eine Option. Diese Funktionen sind in deklariert <linux/stacktrace.h> und <asm/stacktrace.h>beziehungsweise.

Es ist nicht so einfach, diese zu verwenden dump_stack() Wenn Sie jedoch mehr Flexibilität benötigen, können sie hilfreich sein.

Hier ist, wie save_stack_trace() kann verwendet werden (ersetzen HOW_MANY_ENTRIES_TO_STORE mit dem Wert, der Ihren Bedürfnissen entspricht, ist 16-32 normalerweise mehr als genug):

unsigned long stack_entries[HOW_MANY_ENTRIES_TO_STORE];
struct stack_trace trace = {
    .nr_entries = 0,
    .entries = &stack_entries[0],

    .max_entries = HOW_MANY_ENTRIES_TO_STORE,

    /* How many "lower entries" to skip. */
    .skip = 0
}; 
save_stack_trace(&trace);

Jetzt stack_entries array enthält die entsprechenden Rufadressen. Die Anzahl der gefüllten Elemente ist nr_entries.

Eine weitere Sache, die darauf hingewiesen werden sollte. Wenn es erwünscht ist, die zur Implementierung gehörenden Stack-Einträge nicht auszugeben save_stack_trace(), dump_trace() oder dump_stack() selbst (auf verschiedenen Systemen kann die Anzahl solcher Einträge variieren), kann der folgende Trick angewendet werden, wenn Sie verwenden save_stack_trace(). Sie können verwenden __builtin_return_address(0) als “Anker”-Eintrag und verarbeiten nur die Einträge, die “nicht niedriger” als dieser sind.

  • Danke für die Hilfe. Ich habe diesen Trick nicht benutzt, aber ich könnte. Der stack_dump zeigte ungefähr alles, was ich mir vorgestellt hatte.

    – ndasusers

    7. Mai 2011 um 4:48 Uhr

  • Ich kann mit dieser Methode Adressen finden, aber diese Adressen scheinen mit keiner Adresse in übereinzustimmen System.map. Wie kann ich also eine solche Adresse in einen Funktionsnamen umwandeln?

    – René Nyffenegger

    27. Februar 2018 um 12:07 Uhr

  • @RenéNyffenegger: KASLR ist aktiv, nehme ich an (CONFIG_RANDOMIZE_BASE=y). Dies könnte der Grund dafür sein, dass sich die tatsächlichen Adressen von denen in System.map unterscheiden. Wenn /proc/kallsyms in Ihrem System verfügbar ist, können Sie die Adressen dort finden. Oder wenn Sie save_stack_trace von Ihrem Modul aufrufen, können Sie verwenden printk mit %pS-Spezifizierer dort, um die Funktionsnamen und Offsets aufzulösen. Auch hier sollte KALLSYMS im Kernel aktiviert sein, damit dies funktioniert.

    – Eugen

    27. Februar 2018 um 15:42 Uhr

Ich weiß, dass es bei dieser Frage um Linux geht, aber da es das erste Ergebnis für “Backtrace Kernel” ist, hier ein paar weitere Lösungen:


DragonFly-BSD

Es ist print_backtrace(int count) aus /sys/sys/systm.h. Es ist implementiert in
/sys/kern/kern_debug.c und/oder /sys/platform/pc64/x86_64/db_trace.c. Es kann gefunden werden, indem Sie nach suchen panicdie implementiert ist in /sys/kern/kern_shutdown.cund ruft an print_backtrace(6) wenn DDB definiert ist und trace_on_panic eingestellt ist, was beides Voreinstellungen sind.


FreeBSD

Es ist kdb_backtrace(void) aus /sys/sys/kdb.h. Ebenso ist es leicht zu finden, indem man nachsieht, was die panic Implementierung fordert wann trace_on_panic ist wahr.


OpenBSD

Gehen die panic Route, so scheint es zu sein db_stack_dump()Implementiert in /sys/ddb/db_output.c. Die einzige Header-Erwähnung ist /sys/ddb/db_output.h.

dump_stack() Diese Funktion kann verwendet werden, um Ihren Stapel zu drucken und kann somit zum Zurückverfolgen verwendet werden. Achten Sie bei der Verwendung darauf, dass Sie es nicht in sich wiederholende Pfade wie Schleifen oder Paketempfangsfunktionen einfügen, da dies Ihren dmesg-Puffer füllen kann, was zu einem Absturz des eingebetteten Geräts führen kann (mit weniger Speicher und CPU).

Diese Funktion ist in deklariert linux/kernel.h .

1369720cookie-checkWie füge ich C Backtrace in einen Kernelmodulcode ein?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy