web-dev-qa-db-fra.com

Comment inclure C backtrace dans un code de module de noyau?

J'essaie donc de savoir quels processus du noyau appellent certaines fonctions dans un pilote de bloc. Je pensais qu'inclure backtrace () dans la bibliothèque C faciliterait les choses. Mais j'ai du mal à charger la trace.

J'ai copié cet exemple de fonction pour afficher la trace:

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

Toutes les tentatives de compilation ont une erreur à un endroit ou à un autre, ce qui signifie qu'un fichier est introuvable ou que les fonctions ne sont pas définies.

Voici ce qui vient le plus près.

Dans le Makefile, j'ai mis les directives du compilateur:

 -rdynamic -I/usr/include 

Si je laisse de côté le second, -I/usr/include, le compilateur indique qu'il ne peut pas trouver l'en-tête requis execinfo.h.

Ensuite, dans le code où je veux faire la trace, j'ai copié la fonction de l'exemple:

//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

J'ai mis l'appel de cette fonction plus tard dans une fonction de gestionnaire de blocs où le premier signe de l'erreur se produit. Simplement:

show_stackframe();

Donc, quand je le compile, les erreurs suivantes:

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!

Remarque: block26.c est le fichier sur lequel j'espère récupérer la trace.

Existe-t-il une raison évidente pour laquelle les symboles backtrace et backtrace_symbols restent indéfinis lors de la compilation dans les modules .ko?

Je le devine parce que j'utilise le compilateur include execinfo.h qui réside sur l'ordinateur et n'est pas chargé dans le module.

Je suppose que c'est le moins qu'on puisse dire.

Est-ce que n'importe qui peut offrir une aide pour que les fonctions de trace soient chargées dans le module?

Merci d'avoir regardé cette demande.

Je travaille sur Debian. Lorsque je supprime la fonction, le module compile bien et fonctionne presque parfaitement.

De ndasusers

23
ndasusers

Pour imprimer le contenu de la pile et une trace du journal du noyau, utilisez la fonction dump_stack() dans votre module de noyau. Il est déclaré dans linux/kernel.h dans le dossier include du répertoire source du noyau.

45
jmkeyes

Si vous devez enregistrer la trace de la pile et traiter ses éléments d'une manière ou d'une autre, save_stack_trace() ou dump_trace() peut également être une option. Ces fonctions sont déclarées dans <linux/stacktrace.h> et <asm/stacktrace.h>, respectivement.

Celles-ci ne sont pas aussi faciles à utiliser que dump_stack(), mais si vous avez besoin de plus de flexibilité, elles peuvent être utiles. 

Voici comment save_stack_trace() peut être utilisé (remplacez HOW_MANY_ENTRIES_TO_STORE par la valeur qui vous convient, 16-32 est généralement plus que suffisant):

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);

Maintenant, le tableau stack_entries contient les adresses d'appel appropriées. Le nombre d'éléments remplis est nr_entries.

Une dernière chose à souligner. S'il est souhaitable de ne pas générer les entrées de pile appartenant à l'implémentation de save_stack_trace(), dump_trace() ou dump_stack() elles-mêmes (sur différents systèmes, le nombre d'entrées de ce type peut varier), vous pouvez utiliser l'astuce suivante si vous utilisez save_stack_trace(). Vous pouvez utiliser __builtin_return_address(0) comme entrée "ancre" et ne traiter que les entrées "non inférieures" à celle.

19
Eugene

dump_stack() is function peut être utilisé pour imprimer votre pile et peut donc être utilisé pour effectuer un retour en arrière. lors de son utilisation, veillez à ne pas le placer dans un chemin répétitif, tel que des boucles ou une fonction de réception de paquets, car il peut remplir votre mémoire tampon dmesg peut provoquer un crash dans le périphérique intégré (moins de mémoire et de ressources processeur).

Cette fonction est déclarée dans linux/kernel.h.

0
SHASHI BHUSAN

Je sais que cette question concerne Linux, mais comme il s'agit du premier résultat pour "backtrace kernel", voici quelques solutions supplémentaires:


DragonFly BSD

C'est print_backtrace(int count) de /sys/sys/systm.h . Il est implémenté dans /sys/kern/kern_debug.c et/ou /sys/platform/pc64/x86_64/db_trace.c . Vous pouvez le trouver en cherchant panic, qui est implémenté dans /sys/kern/kern_shutdown.c , et appelle print_backtrace(6) si DDB est défini et que trace_on_panic est défini, qui sont tous deux des paramètres par défaut.


FreeBSD

C'est kdb_backtrace(void) de /sys/sys/kdb.h . De même, il est facile à trouver en examinant ce que la panic implementation appelle lorsque trace_on_panic est vrai.


OpenBSD

En parcourant la panic route, il semble que ce soit db_stack_dump(), IMPL&EACUTE;MENT&EACUTE; DANS /sys/ddb/db_output.c . La seule mention d'en-tête est /sys/ddb/db_output.h .

0
cnst