Ups ist eine spezielle Fehlermeldung im Linux-Kernel. Sie wird verwendet, um anzuzeigen, dass im Kernel eine nicht schwerwiegende Ausnahme aufgetreten ist, z. B. eine Nullzeiger-Dereferenzierung, ein ungültiger Speicherzugriff, ein Fehler bei der Division durch Null usw. Das Auftreten von „Ups“ bedeutet normalerweise, dass ein Fehler im Kernel oder ein Problem mit dem Treiber vorliegt, was zu Systeminstabilität oder einem Absturz führen kann. In diesem Artikel stellen wir die Prinzipien und Eigenschaften von Oops im Linux-Kernel vor, einschließlich Format, Inhalt, Gründe, Klassifizierung usw. von Oops, und geben Beispiele für ihre Verwendung und Vorsichtsmaßnahmen.
Was ist Ups in der Linux-Kernel-Entwicklung? Tatsächlich gibt es keinen wesentlichen Unterschied zur obigen Erklärung, außer dass der Protagonist, der spricht, Linux wird. Wenn weitere schwerwiegende Probleme auftreten, wird unser Linux-Kernel auch entschuldigend zu uns sagen: „Ups, es tut mir leid, ich habe es vermasselt.“ Wenn eine Kernel-Panik auftritt, druckt der Linux-Kernel Oops-Informationen aus und zeigt uns den aktuellen Registerstatus, den Stapelinhalt und die vollständige Anrufverfolgung an, was uns bei der Fehlersuche helfen kann.
Schauen wir uns nun ein Beispiel an. Um den Protagonisten dieses Artikels hervorzuheben – Hoppla, die einzige Funktion dieses Beispiels besteht darin, einen Nullzeiger-Referenzfehler zu erstellen.
#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");
Offensichtlich liegt der Fehler in Zeile 8.
Als nächstes haben wir dieses Modul kompiliert und es mit insmod in den Kernelraum eingefügt. Wie erwartet erschien Ups.
“
[ 100.243737] FEHLER: Kernel-NULL-Zeiger-Dereferenzierung bei (null) kann nicht verarbeitet werden
[100.244985] IP: [] hello_init+0x5/0x11 [hallo]
[ 100.262266] *pde = 00000000
[100.288395] Ups: 0002 [#1] SMP
[100.305468] letzte sysfs-Datei: /sys/devices/virtual/sound/timer/uevent
[ 100.325955] Module verlinkt in: 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 Tileblit Schriftart Bitblit Softcursor snd parport_pc Soundcore snd_page_alloc vmci i2c_piix4 vga16fb vgastate intel_agp agpgart shpchp lp parport floppy pcnet32 mii mptspi mptscsih mptbase scsi_transport_spi vmxnet
[ 100.472178] [ 100.494931] Pid: 1586, Kommunikation: insmod Nicht tainted (2.6.32-21-generic #32-Ubuntu) VMware Virtual Platform
[100.540018] EIP: 0060:[] EFLAGS: 00010246 CPU: 0
[ 100.562844] EIP ist bei hello_init+0x5/0x11 [hello]
[ 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] Prozess insmod (pid: 1586, ti=f1b9e000 task=f137b340 task.ti=f1b9e000)
[100.706083] Stapel:
[ 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] Anrufverfolgung:
[ 100.916257] [] ? do_one_initcall+0x31/0x190
[ 100.943670] [] ? hello_init+0x0/0x11 [hallo]
[ 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 [hello] SS:ESP 0068:f1b9ff5c
[101.134682] CR2: 0000000000000000
[ 101.158929] –[ Endtrace e294b69a66d752cb ]—
“
Ups, ich habe zuerst beschrieben, um welche Art von Fehler es sich handelte, und dann auf den Ort hingewiesen, an dem der Fehler aufgetreten ist, nämlich „IP: [] hello_init+0x5/0x11 [hello]“.
Hier müssen wir ein Hilfstool objdump verwenden, um bei der Analyse des Problems zu helfen. Objdump kann zum Zerlegen verwendet werden. Das Befehlsformat lautet wie folgt:
“
objdump -S hallo.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).”
Grundsätzlich sind diese Tainted-Informationen Kernel-Entwicklern vorbehalten. Wenn Benutzer bei der Verwendung von Linux auf „Ups“ stoßen, können sie den Inhalt von „Ups“ zum Debuggen an Kernel-Entwickler senden. Basierend auf diesen Tainted-Informationen können Kernel-Entwickler wahrscheinlich die Umgebung bestimmen, in der der Kernel ausgeführt wird, wenn der Kernel in Panik gerät. Wenn wir nur unseren eigenen Treiber debuggen, sind diese Informationen bedeutungslos.
Das Beispiel in diesem Artikel ist sehr einfach. Es gab keine Ausfallzeit, nachdem Ups aufgetreten ist, daher können wir die vollständigen Informationen von dmesg einsehen. Aber in den meisten Fällen ist das System heruntergefahren, wenn Ups auftritt. Zu diesem Zeitpunkt haben diese Fehlermeldungen keine Zeit, in der Datei gespeichert zu werden, und sie sind nach dem Ausschalten nicht mehr sichtbar. Wir können es nur auf andere Weise festhalten: per Handschrift oder durch Fotografieren.
Es gibt eine schlimmere Situation, wenn zu viele Hoppla-Informationen vorhanden sind. Der Bildschirm wird nicht vollständig auf einer Seite angezeigt. Die erste Methode besteht darin, den vga-Parameter in Grub zu verwenden, um eine höhere Auflösung anzugeben, damit der Bildschirm mehr Inhalte anzeigen kann. Offensichtlich kann diese Methode nicht allzu viele Probleme lösen. Die zweite Methode besteht darin, zwei Maschinen zu verwenden, um die Oops-Informationen der Debug-Maschine über die serielle Schnittstelle auf dem Host-Bildschirm zu drucken. Die meisten Laptops verfügen jedoch nicht über serielle Schnittstellen, und diese Lösung weist auch große Einschränkungen auf. Die dritte Methode besteht darin, den Inhalt des Speichers und der CPU-Register in eine Datei zu übertragen, wenn „Ups“ auftritt gdb, um das Problem zu analysieren.
Die Probleme, auf die Sie bei der Entwicklung von Kernel-Treibern stoßen können, sind allerlei seltsam, und auch die Debugging-Methoden sind vielfältig. Ups ist eine Erinnerung, die uns der Linux-Kernel gibt, und wir müssen sie gut nutzen.
Durch diesen Artikel haben wir die Prinzipien und Eigenschaften von Oops im Linux-Kernel kennengelernt, die zur Diagnose und Fehlerbehebung im Kernel verwendet werden können. Wir sollten geeignete Tools basierend auf den tatsächlichen Anforderungen auswählen und einige Grundprinzipien befolgen, z. B. das Speichern und Analysieren von Oops-Informationen, die Verwendung von Symboltabellen und Quellcode zum Lokalisieren von Problemen, die Verwendung von Modulparametern und Kernelparametern zum Anpassen des Kernelverhaltens usw. Hoppla ist eine häufige Fehlermeldung im Linux-Kernel. Sie kann den Status und die Ausnahmen des Kernels widerspiegeln und auch die Qualität und Stabilität des Kernels verbessern. Ich hoffe, dass dieser Artikel für Sie hilfreich und inspirierend sein kann.
Das obige ist der detaillierte Inhalt vonAusnahmeinformationen im Linux-Kernel: Ausführliche Erklärung von Ups. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!