Oups est un message d'erreur spécial dans le noyau Linux. Il est utilisé pour indiquer qu'une exception non fatale s'est produite dans le noyau, telle qu'un déréférencement de pointeur nul, un accès illégal à la mémoire, une erreur de division par zéro, etc. L'apparition de Oups signifie généralement qu'il y a un bug dans le noyau ou un problème avec le pilote, ce qui peut provoquer une instabilité ou un crash du système. Dans cet article, nous présenterons les principes et les caractéristiques de Oops dans le noyau Linux, y compris le format, le contenu, les raisons, la classification, etc. de Oops, et donnerons des exemples de leur utilisation et de leurs précautions.
Qu'est-ce que Oops dans le développement du noyau Linux ? En fait, il n'y a pas de différence essentielle entre cela et l'explication ci-dessus, sauf que le protagoniste qui parle devient Linux. Lorsque certains des problèmes les plus fatals surviennent, notre noyau Linux nous dit également en s'excusant : "Oups, je suis désolé, j'ai raté." Lorsqu'une panique du noyau se produit, le noyau Linux imprimera les informations Oups et nous montrera l'état actuel du registre, le contenu de la pile et la trace complète des appels, ce qui peut nous aider à localiser l'erreur.
Maintenant, regardons un exemple. Afin de mettre en évidence le protagoniste de cet article - Oups, la seule fonction de cet exemple est de créer une erreur de référence de pointeur nul.
#include #include static int __init hello_init(void) { int *p = 0; *p = 1; return 0; } static void __exit hello_exit(void) { return; } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");
Évidemment, l'erreur est la ligne 8.
Ensuite, nous avons compilé ce module et utilisé insmod pour l'insérer dans l'espace du noyau, oups.
«
[ 100.243737] BUG : impossible de gérer le déréférencement du pointeur NULL du noyau à (null)
[100.244985] IP : [] hello_init+0x5/0x11 [bonjour]
[ 100.262266] *pde = 00000000
[100.288395] Oups : 0002 [#1] SMP
[100.305468] dernier fichier sysfs : /sys/devices/virtual/sound/timer/uevent
[ 100.325955] Modules liés dans : hello(+) vmblock vsock vmmemctl vmhgfs acpiphp snd_ens1371 gameport snd_ac97_codec ac97_bus snd_pcm_oss snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_se q_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device ppdev psmouse serio_raw fbcon tuileblit police bitblit softcursor snd parport_pc soundcore snd_page_alloc vmci i2c_piix4 vga16fb vgastate intel_agp agpgart shpchp lp parport disquette pcnet32 mii mptspi mptscsih mptbase scsi_transport_spi vmxnet
[ 100.472178] [ 100.494931] Pid : 1586, comm : insmod Non contaminé (2.6.32-21-generic #32-Ubuntu) Plateforme virtuelle VMware
[100.540018] EIP : 0060 : [] EFLAGS : 00010246 CPU : 0
[ 100.562844] EIP est à hello_init+0x5/0x11 [bonjour]
[ 100.584351] EAX : 00000000 EBX : ffffffffc ECX : f82cf040 EDX : 00000001
[ 100.609358] ESI : f82cf040 EDI : 00000000 EBP : f1b9ff5c ESP : f1b9ff5c
[ 100.631467] DS : 007b ES : 007b FS : 00d8 GS : 00e0 SS : 0068
[ 100.657664] Processus insmod (pid : 1586, ti=f1b9e000 task=f137b340 task.ti=f1b9e000)
[100.706083] Pile :
[ 100.731783] f1b9ff88 c0101131 f82cf040 c076d240 fffffffc f82cf040 0072cff4 f82d2000
[100.759324]fffffffc f82cf040 0072cff4 f1b9ffac c0182340 f19638f8 f137b340 f19638c0
[100.811396]00000004 09cc9018 09cc9018 00020000 f1b9e000 c01033ec 09cc9018 00015324
[100.891922] Appelez Trace :
[ 100.916257] [] ? do_one_initcall+0x31/0x190
[ 100.943670] [] ? hello_init+0x0/0x11 [bonjour]
[ 100.970905] [] ? sys_init_module+0xb0/0x210
[ 100.995542] [] ? syscall_call+0x7/0xb
[ 101.024087] Code : 05 00 00 00 00 01 00 00 00 5d c3 00 00 00 00 00 00 00 00 00 00
[ 101.079592] EIP : [] hello_init+0x5/0x11 [bonjour] SS : ESP 0068 : f1b9ff5c
[101.134682] CR2 : 0000000000000000
[ 101.158929] —[ fin de trace e294b69a66d752cb ]—
”
Oups a d'abord décrit de quel type de bug il s'agissait, puis a indiqué l'emplacement où le bug s'est produit, qui est "IP : [] hello_init+0x5/0x11 [hello]".
Ici, nous devons utiliser un outil auxiliaire objdump pour aider à analyser le problème. objdump peut être utilisé pour démonter, le format de commande est le suivant :
«
objdump -S bonjour.o
”
下面是hello.o反汇编的结果,而且是和C代码混排的,非常的直观。
hello.o: file format elf32-i386 Disassembly of section .init.text: 00000000 : #include #include static int __init hello_init(void) { 0: 55 push %ebp int *p = 0; *p = 1; return 0; } 1: 31 c0 xor %eax,%eax #include #include static int __init hello_init(void) { 3: 89 e5 mov %esp,%ebp int *p = 0; *p = 1; 5: c7 05 00 00 00 00 01 movl $0x1,0x0 c: 00 00 00 return 0; } f: 5d pop %ebp 10: c3 ret Disassembly of section .exit.text: 00000000 : static void __exit hello_exit(void) { 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: e8 fc ff ff ff call 4 return; } 8: 5d pop %ebp 9: c3 ret
对照Oops的提示,我们可以很清楚的看到,出错的位置hello_init+0x5的汇编代码是:
5:c7 05 00 00 00 00 01 movl $0x1,0x0
这句代码的作用是把数值1存入0这个地址,这个操作当然是非法的。
我们还能看到它对应的c代码是:
*p = 1;
Bingo!在Oops的帮助下我们很快就解决了问题。
我们再回过头来检查一下上面的Oops,看看Linux内核还有没有给我们留下其他的有用信息。
“
Oops: 0002 [#1]
”
这里面,0002表示Oops的错误代码(写错误,发生在内核空间),#1表示这个错误发生一次。
Oops的错误代码根据错误的原因会有不同的定义,本文中的例子可以参考下面的定义(如果发现自己遇到的Oops和下面无法对应的话,最好去内核代码里查找):
“
* error_code:
* bit 0 == 0 means no page found, 1 means protection fault
* bit 1 == 0 means read, 1 means write
* bit 2 == 0 means kernel, 1 means user-mode
* bit 3 == 0 means data, 1 means instruction”
有时候,Oops还会打印出Tainted信息。这个信息用来指出内核是因何种原因被tainted(直译为“玷污”)。具体的定义如下:
“
1: ‘G’ if all modules loaded have a GPL or compatible license, ‘P’ if any proprietary module has been loaded. Modules without a MODULE_LICENSE or with a MODULE_LICENSE that is not recognised by insmod as GPL compatible are assumed to be proprietary.
2: ‘F’ if any module was force loaded by “insmod -f”, ‘ ‘ if all modules were loaded normally.
3: ‘S’ if the oops occurred on an SMP kernel running on hardware that hasn’t been certified as safe to run multiprocessor. Currently this occurs only on various Athlons that are not SMP capable.
4: ‘R’ if a module was force unloaded by “rmmod -f”, ‘ ‘ if all modules were unloaded normally.
5: ‘M’ if any processor has reported a Machine Check Exception, ‘ ‘ if no Machine Check Exceptions have occurred.
6: ‘B’ if a page-release function has found a bad page reference or some unexpected page flags.
7: ‘U’ if a user or user application specifically requested that the Tainted flag be set, ‘ ‘ otherwise.
8: ‘D’ if the kernel has died recently, i.e. there was an OOPS or BUG.
9: ‘A’ if the ACPI table has been overridden.
10: ‘W’ if a warning has previously been issued by the kernel. (Though some warnings may set more specific taint flags.)
11: ‘C’ if a staging driver has been loaded.
12: ‘I’ if the kernel is working around a severe bug in the platform firmware (BIOS or similar).”
Fondamentalement, ces informations contaminées sont réservées aux développeurs du noyau. Si les utilisateurs rencontrent des Oops lorsqu'ils utilisent Linux, ils peuvent envoyer le contenu de Oops aux développeurs du noyau pour le débogage. Sur la base de ces informations corrompues, les développeurs du noyau peuvent probablement déterminer l'environnement dans lequel le noyau s'exécute lorsque le noyau panique. Si nous déboguons simplement notre propre pilote, ces informations n’auront aucun sens.
L'exemple dans cet article est très simple. Il n'y a eu aucun temps d'arrêt après l'apparition d'Oops, nous pouvons donc afficher les informations complètes de dmesg. Mais le plus souvent, le système sera en panne lorsqu'un Oups se produit. À ce moment-là, ces messages d'erreur n'ont pas le temps d'être stockés dans le fichier et ils ne sont plus visibles après la mise hors tension. Nous ne pouvons l’enregistrer que par d’autres moyens : en écrivant à la main ou en prenant des photos.
Il existe une situation pire. S'il y a trop d'informations Oups, l'écran d'une page ne sera pas entièrement affiché. Comment pouvons-nous afficher le contenu complet ? La première méthode consiste à utiliser le paramètre vga dans grub pour spécifier une résolution plus élevée afin que l'écran puisse afficher plus de contenu. De toute évidence, cette méthode ne peut pas réellement résoudre trop de problèmes : la deuxième méthode consiste à utiliser deux machines pour imprimer les informations Oops de la machine de débogage sur l'écran hôte via le port série. Mais la plupart des ordinateurs portables ne disposent désormais pas de ports série, et cette solution présente également de grandes limites ; la troisième méthode consiste à utiliser l'outil de vidage du noyau kdump pour vider le contenu de la mémoire et des registres du processeur lorsqu'un problème se produit dans un fichier. gdb pour analyser le problème.
Les problèmes que vous pouvez rencontrer dans le processus de développement des pilotes du noyau sont de toutes sortes étranges, et les méthodes de débogage sont également diverses. Oups, c'est un rappel que nous donne le noyau Linux, et nous devons en faire bon usage.
Grâce à cet article, nous avons découvert les principes et les caractéristiques de Oops dans le noyau Linux, qui peuvent être utilisés pour diagnostiquer et déboguer les problèmes dans le noyau. Nous devons choisir les outils appropriés en fonction des besoins réels et suivre certains principes de base, tels que la sauvegarde et l'analyse des informations Oops, l'utilisation des tables de symboles et du code source pour localiser les problèmes, l'utilisation des paramètres de module et des paramètres du noyau pour ajuster le comportement du noyau, etc. Oups est un message d'erreur courant dans le noyau Linux. Il peut refléter l'état et les exceptions du noyau, et peut également améliorer la qualité et la stabilité du noyau. J’espère que cet article pourra vous être utile et inspirant.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!