1127 lines
48 KiB
XML
1127 lines
48 KiB
XML
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
|
|
<!--
|
|
The FreeBSD Documentation Project
|
|
The FreeBSD German Documentation Project
|
|
|
|
$FreeBSD$
|
|
$FreeBSDde: de-docproj/books/developers-handbook/kerneldebug/chapter.sgml,v 1.16 2012/03/25 14:33:52 bcr Exp $
|
|
basiert auf: 1.81
|
|
-->
|
|
|
|
<chapter id="kerneldebug">
|
|
<chapterinfo>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Paul</firstname>
|
|
<surname>Richards</surname>
|
|
<contrib>Contributed by </contrib>
|
|
</author>
|
|
<author>
|
|
<firstname>Jörg</firstname>
|
|
<surname>Wunsch</surname>
|
|
</author>
|
|
<author>
|
|
<firstname>Robert</firstname>
|
|
<surname>Watson</surname>
|
|
</author>
|
|
</authorgroup>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Fabian</firstname>
|
|
<surname>Ruch</surname>
|
|
<contrib>Übersetzt von </contrib>
|
|
</author>
|
|
</authorgroup>
|
|
</chapterinfo>
|
|
|
|
<title>Kernel-Fehlersuche</title>
|
|
|
|
<sect1 id="kerneldebug-obtain">
|
|
<title>Besorgen eines Speicherauszugs nach einem
|
|
Kernel-Absturz (Kernel-Crash-Dump)</title>
|
|
|
|
<para>Wenn ein Entwicklungs-Kernel (z.B. &os.current;) wie zum
|
|
Beispiel ein Kernel unter Extrembedingungen (z.B. sehr hohe
|
|
Belastungsraten (Load), eine äußerst hohe Anzahl an
|
|
gleichzeitigen Benutzern, Hunderte &man.jail.8;s usw.)
|
|
eingesetzt oder eine neue Funktion oder ein neuer
|
|
Gerätetreiber in &os.stable; verwendet wird (z.B.
|
|
<acronym>PAE</acronym>), tritt manchmal eine Kernel-Panic ein.
|
|
In einem solchen Fall zeigt dieses Kapitel, wie dem Absturz
|
|
nützliche Informationen entnommen werden
|
|
können.</para>
|
|
|
|
<para>Bei Kernel-Panics ist ein Neustart unvermeidlich. Nachdem
|
|
ein System neu gestartet wurde, ist der Inhalt des
|
|
physikalischen Speichers (<acronym>RAM</acronym>), genauso wie
|
|
jedes Bit, das sich vor der Panic auf dem Swap-Gerät
|
|
befand, verloren. Um die Bits im physikalischen Speicher zu
|
|
erhalten, zieht der Kernel Nutzen aus dem Swap-Gerät als
|
|
vorübergehenden Ablageort, wo die Bits, welche sich im RAM
|
|
befinden, auch nach einem Neustart nach einem Absturz
|
|
verfügbar sind. Durch diese Vorgehensweise kann ein
|
|
Kernel-Abbild, wenn &os; nach einem Absturz startet, abgezogen
|
|
und mit der Fehlersuche begonnen werden.</para>
|
|
|
|
<note>
|
|
<para>Ein Swap-Gerät, das als Ausgabegerät
|
|
(Dump-Device) konfiguriert wurde, verhält sich immer noch
|
|
wie ein Swap-Gerät. Die Ausgabe auf
|
|
Nicht-Swap-Geräte (wie zum Beispiel Bänder oder
|
|
CDRWs) wird zur Zeit nicht unterstützt. Ein
|
|
<quote>Swap-Gerät</quote> ist gleichbedeutend mit einer
|
|
<quote>Swap-Partition</quote>.</para>
|
|
</note>
|
|
|
|
<para>Es stehen verschiedene Arten von Speicherabzügen zur
|
|
Verfügung: komplette Speicherabzüge (full memory dumps), welche
|
|
den gesamten Inhalt des physischen Speichers beinhalten, Miniauszüge
|
|
(minidumps), die nur die gerade verwendeten Speicherseiten des Kernels
|
|
enthalten (&os; 6.2 und höhere Versionen) und Textauszüge
|
|
(textdumps), welche geskriptete oder Debugger-Ausgaben enthalten
|
|
(&os; 7.1 und höher). Miniauszüge sind der Standardtyp
|
|
der Abzüge seit &os; 7.0 und fangen in den meisten Fällen
|
|
alle nötigen Informationen ein, die in einem kompletten
|
|
Kernel-Speicherabzug enthalten sind, da die meisten Probleme nur durch
|
|
den Zustand des Kernels isoliert werden können.</para>
|
|
|
|
<sect2 id="config-dumpdev">
|
|
<title>Konfigurieren des Ausgabegeräts</title>
|
|
|
|
<para>Bevor der Kernel den Inhalt seines physikalischen
|
|
Speichers auf einem Ausgabegerät ablegt, muss ein solches
|
|
konfiguriert werden. Ein Ausgabegerät wird durch Benutzen
|
|
des &man.dumpon.8;-Befehls festgelegt, um dem Kernel
|
|
mitzuteilen, wohin die Speicherauszüge bei einem
|
|
Kernel-Absturz gesichert werden sollen. Das
|
|
&man.dumpon.8;-Programm muss aufgerufen werden, nachdem die
|
|
Swap-Partition mit &man.swapon.8; konfiguriert wurde. Dies
|
|
wird normalerweise durch Setzen der
|
|
<varname>dumpdev</varname>-Variable in &man.rc.conf.5; auf den
|
|
Pfad des Swap-Geräts (der empfohlene Weg, um einen
|
|
Kernel-Speicherauszug zu entnehmen) bewerkstelligt, oder über
|
|
<literal>AUTO</literal>, um die erste konfigurierte Swap-Partition
|
|
zu verwenden. In HEAD ist die Standardeinstellung für
|
|
<varname>dumpdev</varname> <filename>AUTO</filename> und
|
|
änderte sich in den RELENG_*-Zweigen (mit Ausnahme von
|
|
RELENG_7, bei dem <literal>AUTO</literal> beibehalten wurde) auf
|
|
<literal>NO</literal>. In &os; 9.0-RELEASE und späteren
|
|
Versionen fragt <application>bsdinstall</application>, ob
|
|
Speicherauszüge für das Zielsystem während des
|
|
Installationsvorgangs aktiviert werden sollen.</para>
|
|
|
|
<tip>
|
|
<para>Vergleichen Sie <filename>/etc/fstab</filename> oder
|
|
&man.swapinfo.8; für eine Liste der
|
|
Swap-Geräte.</para>
|
|
</tip>
|
|
|
|
<important>
|
|
<para>Stellen Sie sicher, dass das in &man.rc.conf.5;
|
|
festgelegte <varname>dumpdir</varname> vor einem
|
|
Kernel-Absturz vorhanden ist.</para>
|
|
|
|
<screen>&prompt.root; <userinput>mkdir /var/crash</userinput>
|
|
&prompt.root; <userinput>chmod 700 /var/crash</userinput></screen>
|
|
|
|
<para>Denken Sie auch daran, dass der Inhalt von
|
|
<filename>/var/crash</filename> heikel ist und sehr
|
|
wahrscheinlich vertrauliche Informationen wie
|
|
Passwörter enthält.</para>
|
|
</important>
|
|
</sect2>
|
|
|
|
<sect2 id="extract-dump">
|
|
<title>Entnehmen eines Kernel-Speicherauszugs
|
|
(Kernel-Dump)</title>
|
|
|
|
<para>Sobald ein Speicherauszug auf ein Ausgabegerät
|
|
geschrieben wurde, muss er entnommen werden, bevor das
|
|
Swap-Gerät eingehängt wird. Um einen Speicherauszug
|
|
aus einem Ausgabegerät zu entnehmen, benutzen Sie das
|
|
&man.savecore.8;-Programm. Falls <varname>dumpdev</varname> in
|
|
&man.rc.conf.5; gesetzt wurde, wird &man.savecore.8;
|
|
automatisch beim ersten Start in den Multiuser-Modus nach dem
|
|
Absturz und vor dem Einhängen des Swap-Geräts
|
|
aufgerufen. Der Speicherort des entnommenen Kernels ist im
|
|
&man.rc.conf.5;-Wert <varname>dumpdir</varname>,
|
|
standardmäßig <filename>/var/crash</filename>,
|
|
festgelegt und der Dateiname wird
|
|
<filename>vmcore.0</filename> sein.</para>
|
|
|
|
<para>In dem Fall, dass bereits eine Datei mit dem Namen
|
|
<filename>vmcore.0</filename> in
|
|
<filename>/var/crash</filename> (oder auf was auch immer
|
|
<varname>dumpdir</varname> gesetzt ist) vorhanden ist,
|
|
erhöht der Kernel die angehängte Zahl bei jedem
|
|
Absturz um eins und verhindert damit, dass ein vorhandener
|
|
<filename>vmcore</filename> (z.B.
|
|
<filename>vmcore.1</filename>) überschrieben wird.
|
|
Während der Fehlersuche, möchten Sie höchst
|
|
wahrscheinlich den <filename>vmcore</filename> mit der
|
|
höchsten Version in <filename>/var/crash</filename>
|
|
benutzen, wenn Sie den passenden <filename>vmcore</filename>
|
|
suchen.</para>
|
|
|
|
<tip>
|
|
<para>Falls Sie einen neuen Kernel testen, aber einen anderen
|
|
starten müssen, um Ihr System wieder in Gang zu
|
|
bringen, starten Sie es nur in den Singleuser-Modus, indem
|
|
Sie das <option>-s</option>-Flag an der
|
|
Boot-Eingabeaufforderung benutzen, und nehmen dann folgende
|
|
Schritte vor:</para>
|
|
|
|
<screen>&prompt.root; <userinput>fsck -p</userinput>
|
|
&prompt.root; <userinput>mount -a -t ufs</userinput> # make sure /var/crash is writable
|
|
&prompt.root; <userinput>savecore /var/crash /dev/ad0s1b</userinput>
|
|
&prompt.root; <userinput>exit</userinput> # exit to multi-user</screen>
|
|
|
|
<para>Dies weist &man.savecore.8; an, einen
|
|
Kernel-Speicherauszug aus <filename>/dev/ad0s1b</filename>
|
|
zu entnehmen und den Inhalt in
|
|
<filename>/var/crash</filename> abzulegen. Vergessen Sie
|
|
nicht sicherzustellen, dass das Zielverzeichnis
|
|
<filename>/var/crash</filename> genug freien Speicherplatz
|
|
für den Speicherauszug zur Verfügung hat.
|
|
Vergessen Sie auch nicht, den korrekten Pfad des
|
|
Swap-Geräts anzugeben, da es sehr wahrscheinlich anders
|
|
als <filename>/dev/ad0s1b</filename> lautet!</para>
|
|
</tip>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="kerneldebug-gdb">
|
|
<title>Fehlersuche in einem Speicherauszug nach einem
|
|
Kernel-Absturz mit <command>kgdb</command></title>
|
|
|
|
<note>
|
|
<para>Dieser Abschnitt deckt &man.kgdb.1; ab, wie es in &os; 5.3
|
|
und später zu finden ist. In früheren Versionen muss
|
|
<command>gdb -k</command> benutzt werden, um einen
|
|
Kernspeicherauszug auszulesen.</para>
|
|
</note>
|
|
|
|
<para>Sobald ein Speicherauszug zur Verfügung steht, ist es
|
|
recht einfach nützliche Informationen für einfache
|
|
Probleme daraus zu bekommen. Bevor Sie sich auf die Interna von
|
|
&man.kgdb.1; stürzen, um die Fehler im Kernspeicherauszug
|
|
zu suchen und zu beheben, machen Sie die Debug-Version Ihres
|
|
Kernels (normalerweise <filename>kernel.debug</filename>
|
|
genannt) und den Pfad der Quelldateien, die zum Bau Ihres
|
|
Kernels verwendet wurden (normalerweise
|
|
<filename>/usr/obj/usr/src/sys/<replaceable>KERNCONF</replaceable></filename>,
|
|
wobei <filename><replaceable>KERNCONF</replaceable></filename>
|
|
das in einer Kernel-&man.config.5; festgelegte
|
|
<varname>ident</varname> ist), ausfindig. Mit diesen beiden
|
|
Informationen kann die Fehlersuche beginnen.</para>
|
|
|
|
<para>Um in den Debugger zu gelangen und mit dem
|
|
Informationserhalt aus dem Speicherauszug zu beginnen, sind
|
|
zumindest folgende Schritte nötig:</para>
|
|
|
|
<screen>&prompt.root; <userinput>cd /usr/obj/usr/src/sys/<replaceable>KERNCONF</replaceable></userinput>
|
|
&prompt.root; <userinput>kgdb kernel.debug /var/crash/vmcore.0</userinput></screen>
|
|
|
|
<para>Sie können Fehler im Speicherauszug nach dem Absturz
|
|
suchen, indem Sie die Kernel-Quellen benutzen, genauso wie Sie
|
|
es bei jedem anderen Programm können.</para>
|
|
|
|
<para>Dieser erste Speicherauszug ist aus einem 5.2-BETA-Kernel
|
|
und der Absturz ist tief im Kernel begründet. Die Ausgabe
|
|
unten wurde dahingehend bearbeitet, dass sie nun Zeilennummern
|
|
auf der linken Seite einschließt. Diese erste
|
|
Ablaufverfolgung (Trace) untersucht den Befehlszeiger
|
|
(Instruction-Pointer) und beschafft eine Zurückverfolgung
|
|
(Back-Trace). Die Adresse, die in Zeile 41 für den
|
|
<command>list</command>-Befehl benutzt wird, ist der
|
|
Befehlszeiger und kann in Zeile 17 gefunden werden. Die meisten
|
|
Entwickler wollen zumindest dies zugesendet bekommen, falls Sie
|
|
das Problem nicht selber untersuchen und beheben können.
|
|
Falls Sie jedoch das Problem lösen, stellen Sie sicher,
|
|
dass Ihr Patch seinen Weg in den Quellbaum mittels eines
|
|
Fehlerberichts, den Mailinglisten oder ihres Privilegs, zu
|
|
committen, findet!</para>
|
|
|
|
<screen> 1:&prompt.root; <userinput>cd /usr/obj/usr/src/sys/<replaceable>KERNCONF</replaceable></userinput>
|
|
2:&prompt.root; <userinput>kgdb kernel.debug /var/crash/vmcore.0</userinput>
|
|
3:GNU gdb 5.2.1 (FreeBSD)
|
|
4:Copyright 2002 Free Software Foundation, Inc.
|
|
5:GDB is free software, covered by the GNU General Public License, and you are
|
|
6:welcome to change it and/or distribute copies of it under certain conditions.
|
|
7:Type "show copying" to see the conditions.
|
|
8:There is absolutely no warranty for GDB. Type "show warranty" for details.
|
|
9:This GDB was configured as "i386-undermydesk-freebsd"...
|
|
10:panic: page fault
|
|
11:panic messages:
|
|
12:---
|
|
13:Fatal trap 12: page fault while in kernel mode
|
|
14:cpuid = 0; apic id = 00
|
|
15:fault virtual address = 0x300
|
|
16:fault code: = supervisor read, page not present
|
|
17:instruction pointer = 0x8:0xc0713860
|
|
18:stack pointer = 0x10:0xdc1d0b70
|
|
19:frame pointer = 0x10:0xdc1d0b7c
|
|
20:code segment = base 0x0, limit 0xfffff, type 0x1b
|
|
21: = DPL 0, pres 1, def32 1, gran 1
|
|
22:processor eflags = resume, IOPL = 0
|
|
23:current process = 14394 (uname)
|
|
24:trap number = 12
|
|
25:panic: page fault
|
|
26 cpuid = 0;
|
|
27:Stack backtrace:
|
|
28
|
|
29:syncing disks, buffers remaining... 2199 2199 panic: mi_switch: switch in a critical section
|
|
30:cpuid = 0;
|
|
31:Uptime: 2h43m19s
|
|
32:Dumping 255 MB
|
|
33: 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240
|
|
34:---
|
|
35:Reading symbols from /boot/kernel/snd_maestro3.ko...done.
|
|
36:Loaded symbols for /boot/kernel/snd_maestro3.ko
|
|
37:Reading symbols from /boot/kernel/snd_pcm.ko...done.
|
|
38:Loaded symbols for /boot/kernel/snd_pcm.ko
|
|
39:#0 doadump () at /usr/src/sys/kern/kern_shutdown.c:240
|
|
40:240 dumping++;
|
|
41:<prompt>(kgdb)</prompt> <userinput>list *0xc0713860</userinput>
|
|
42:0xc0713860 is in lapic_ipi_wait (/usr/src/sys/i386/i386/local_apic.c:663).
|
|
43:658 incr = 0;
|
|
44:659 delay = 1;
|
|
45:660 } else
|
|
46:661 incr = 1;
|
|
47:662 for (x = 0; x < delay; x += incr) {
|
|
48:663 if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE)
|
|
49:664 return (1);
|
|
50:665 ia32_pause();
|
|
51:666 }
|
|
52:667 return (0);
|
|
53:<prompt>(kgdb)</prompt> <userinput>backtrace</userinput>
|
|
54:#0 doadump () at /usr/src/sys/kern/kern_shutdown.c:240
|
|
55:#1 0xc055fd9b in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:372
|
|
56:#2 0xc056019d in panic () at /usr/src/sys/kern/kern_shutdown.c:550
|
|
57:#3 0xc0567ef5 in mi_switch () at /usr/src/sys/kern/kern_synch.c:470
|
|
58:#4 0xc055fa87 in boot (howto=256) at /usr/src/sys/kern/kern_shutdown.c:312
|
|
59:#5 0xc056019d in panic () at /usr/src/sys/kern/kern_shutdown.c:550
|
|
60:#6 0xc0720c66 in trap_fatal (frame=0xdc1d0b30, eva=0)
|
|
61: at /usr/src/sys/i386/i386/trap.c:821
|
|
62:#7 0xc07202b3 in trap (frame=
|
|
63: {tf_fs = -1065484264, tf_es = -1065484272, tf_ds = -1065484272, tf_edi = 1, tf_esi = 0, tf_ebp = -602076292, tf_isp = -602076324, tf_ebx = 0, tf_edx = 0, tf_ecx = 1000000, tf_eax = 243, tf_trapno = 12, tf_err = 0, tf_eip = -1066321824, tf_cs = 8, tf_eflags = 65671, tf_esp = 243, tf_ss = 0})
|
|
64: at /usr/src/sys/i386/i386/trap.c:250
|
|
65:#8 0xc070c9f8 in calltrap () at {standard input}:94
|
|
66:#9 0xc07139f3 in lapic_ipi_vectored (vector=0, dest=0)
|
|
67: at /usr/src/sys/i386/i386/local_apic.c:733
|
|
68:#10 0xc0718b23 in ipi_selected (cpus=1, ipi=1)
|
|
69: at /usr/src/sys/i386/i386/mp_machdep.c:1115
|
|
70:#11 0xc057473e in kseq_notify (ke=0xcc05e360, cpu=0)
|
|
71: at /usr/src/sys/kern/sched_ule.c:520
|
|
72:#12 0xc0575cad in sched_add (td=0xcbcf5c80)
|
|
73: at /usr/src/sys/kern/sched_ule.c:1366
|
|
74:#13 0xc05666c6 in setrunqueue (td=0xcc05e360)
|
|
75: at /usr/src/sys/kern/kern_switch.c:422
|
|
76:#14 0xc05752f4 in sched_wakeup (td=0xcbcf5c80)
|
|
77: at /usr/src/sys/kern/sched_ule.c:999
|
|
78:#15 0xc056816c in setrunnable (td=0xcbcf5c80)
|
|
79: at /usr/src/sys/kern/kern_synch.c:570
|
|
80:#16 0xc0567d53 in wakeup (ident=0xcbcf5c80)
|
|
81: at /usr/src/sys/kern/kern_synch.c:411
|
|
82:#17 0xc05490a8 in exit1 (td=0xcbcf5b40, rv=0)
|
|
83: at /usr/src/sys/kern/kern_exit.c:509
|
|
84:#18 0xc0548011 in sys_exit () at /usr/src/sys/kern/kern_exit.c:102
|
|
85:#19 0xc0720fd0 in syscall (frame=
|
|
86: {tf_fs = 47, tf_es = 47, tf_ds = 47, tf_edi = 0, tf_esi = -1, tf_ebp = -1077940712, tf_isp = -602075788, tf_ebx = 672411944, tf_edx = 10, tf_ecx = 672411600, tf_eax = 1, tf_trapno = 12, tf_err = 2, tf_eip = 671899563, tf_cs = 31, tf_eflags = 642, tf_esp = -1077940740, tf_ss = 47})
|
|
87: at /usr/src/sys/i386/i386/trap.c:1010
|
|
88:#20 0xc070ca4d in Xint0x80_syscall () at {standard input}:136
|
|
89:---Can't read userspace from dump, or kernel process---
|
|
90:<prompt>(kgdb)</prompt> <userinput>quit</userinput></screen>
|
|
|
|
<para>Diese nächste Ablaufverfolgung ist ein älterer
|
|
Speicherauszug aus FreeBSD 2-Zeiten, aber ist komplizierter und
|
|
zeigt mehr der <command>gdb</command>-Funktionen. Lange Zeilen
|
|
wurden gefaltet, um die Lesbarkeit zu verbessern, und die Zeilen
|
|
wurden zur Verweisung nummeriert. Trotzdem ist es eine reale
|
|
Fehlerverfolgung (Error-Trace), die während der Entwicklung
|
|
des pcvt-Konsolentreibers entstanden ist.</para>
|
|
|
|
<screen> 1:Script started on Fri Dec 30 23:15:22 1994
|
|
2:&prompt.root; <userinput>cd /sys/compile/URIAH</userinput>
|
|
3:&prompt.root; <userinput>gdb -k kernel /var/crash/vmcore.1</userinput>
|
|
4:Reading symbol data from /usr/src/sys/compile/URIAH/kernel
|
|
...done.
|
|
5:IdlePTD 1f3000
|
|
6:panic: because you said to!
|
|
7:current pcb at 1e3f70
|
|
8:Reading in symbols for ../../i386/i386/machdep.c...done.
|
|
9:<prompt>(kgdb)</prompt> <userinput>backtrace</userinput>
|
|
10:#0 boot (arghowto=256) (../../i386/i386/machdep.c line 767)
|
|
11:#1 0xf0115159 in panic ()
|
|
12:#2 0xf01955bd in diediedie () (../../i386/i386/machdep.c line 698)
|
|
13:#3 0xf010185e in db_fncall ()
|
|
14:#4 0xf0101586 in db_command (-266509132, -266509516, -267381073)
|
|
15:#5 0xf0101711 in db_command_loop ()
|
|
16:#6 0xf01040a0 in db_trap ()
|
|
17:#7 0xf0192976 in kdb_trap (12, 0, -272630436, -266743723)
|
|
18:#8 0xf019d2eb in trap_fatal (...)
|
|
19:#9 0xf019ce60 in trap_pfault (...)
|
|
20:#10 0xf019cb2f in trap (...)
|
|
21:#11 0xf01932a1 in exception:calltrap ()
|
|
22:#12 0xf0191503 in cnopen (...)
|
|
23:#13 0xf0132c34 in spec_open ()
|
|
24:#14 0xf012d014 in vn_open ()
|
|
25:#15 0xf012a183 in open ()
|
|
26:#16 0xf019d4eb in syscall (...)
|
|
27:<prompt>(kgdb)</prompt> <userinput>up 10</userinput>
|
|
28:Reading in symbols for ../../i386/i386/trap.c...done.
|
|
29:#10 0xf019cb2f in trap (frame={tf_es = -260440048, tf_ds = 16, tf_\
|
|
30:edi = 3072, tf_esi = -266445372, tf_ebp = -272630356, tf_isp = -27\
|
|
31:2630396, tf_ebx = -266427884, tf_edx = 12, tf_ecx = -266427884, tf\
|
|
32:_eax = 64772224, tf_trapno = 12, tf_err = -272695296, tf_eip = -26\
|
|
33:6672343, tf_cs = -266469368, tf_eflags = 66066, tf_esp = 3072, tf_\
|
|
34:ss = -266427884}) (../../i386/i386/trap.c line 283)
|
|
35:283 (void) trap_pfault(&frame, FALSE);
|
|
36:<prompt>(kgdb)</prompt> <userinput>frame frame->tf_ebp frame->tf_eip</userinput>
|
|
37:Reading in symbols for ../../i386/isa/pcvt/pcvt_drv.c...done.
|
|
38:#0 0xf01ae729 in pcopen (dev=3072, flag=3, mode=8192, p=(struct p\
|
|
39:roc *) 0xf07c0c00) (../../i386/isa/pcvt/pcvt_drv.c line 403)
|
|
40:403 return ((*linesw[tp->t_line].l_open)(dev, tp));
|
|
41:<prompt>(kgdb)</prompt> <userinput>list</userinput>
|
|
42:398
|
|
43:399 tp->t_state |= TS_CARR_ON;
|
|
44:400 tp->t_cflag |= CLOCAL; /* cannot be a modem (:-) */
|
|
45:401
|
|
46:402 #if PCVT_NETBSD || (PCVT_FREEBSD >= 200)
|
|
47:403 return ((*linesw[tp->t_line].l_open)(dev, tp));
|
|
48:404 #else
|
|
49:405 return ((*linesw[tp->t_line].l_open)(dev, tp, flag));
|
|
50:406 #endif /* PCVT_NETBSD || (PCVT_FREEBSD >= 200) */
|
|
51:407 }
|
|
52:<prompt>(kgdb)</prompt> <userinput>print tp</userinput>
|
|
53:Reading in symbols for ../../i386/i386/cons.c...done.
|
|
54:$1 = (struct tty *) 0x1bae
|
|
55:<prompt>(kgdb)</prompt> <userinput>print tp->t_line</userinput>
|
|
56:$2 = 1767990816
|
|
57:<prompt>(kgdb)</prompt> <userinput>up</userinput>
|
|
58:#1 0xf0191503 in cnopen (dev=0x00000000, flag=3, mode=8192, p=(st\
|
|
59:ruct proc *) 0xf07c0c00) (../../i386/i386/cons.c line 126)
|
|
60: return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
|
|
61:<prompt>(kgdb)</prompt> <userinput>up</userinput>
|
|
62:#2 0xf0132c34 in spec_open ()
|
|
63:<prompt>(kgdb)</prompt> <userinput>up</userinput>
|
|
64:#3 0xf012d014 in vn_open ()
|
|
65:<prompt>(kgdb)</prompt> <userinput>up</userinput>
|
|
66:#4 0xf012a183 in open ()
|
|
67:<prompt>(kgdb)</prompt> <userinput>up</userinput>
|
|
68:#5 0xf019d4eb in syscall (frame={tf_es = 39, tf_ds = 39, tf_edi =\
|
|
69: 2158592, tf_esi = 0, tf_ebp = -272638436, tf_isp = -272629788, tf\
|
|
70:_ebx = 7086, tf_edx = 1, tf_ecx = 0, tf_eax = 5, tf_trapno = 582, \
|
|
71:tf_err = 582, tf_eip = 75749, tf_cs = 31, tf_eflags = 582, tf_esp \
|
|
72:= -272638456, tf_ss = 39}) (../../i386/i386/trap.c line 673)
|
|
73:673 error = (*callp->sy_call)(p, args, rval);
|
|
74:<prompt>(kgdb)</prompt> <userinput>up</userinput>
|
|
75:Initial frame selected; you cannot go up.
|
|
76:<prompt>(kgdb)</prompt> <userinput>quit</userinput></screen>
|
|
|
|
<para>Kommentare zum Skript oben:</para>
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term>Zeile 6:</term>
|
|
|
|
<listitem>
|
|
<para>Dies ist ein Speicherauszug, der innerhalb von DDB
|
|
genommen wurde (siehe unten), deswegen der Kommentar zur
|
|
Panic <quote>because you said to!</quote> und die eher
|
|
lange Stack-Ablaufverfolgung (Stack-Trace); der
|
|
anfängliche Grund für das Starten von DDB war
|
|
jedoch ein Seitenfehler-Trap (Page-Fault-Trap).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Zeile 20:</term>
|
|
|
|
<listitem>
|
|
<para>Dies ist die Position der Funktion
|
|
<function>trap()</function> in der
|
|
Stack-Ablaufverfolgung.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Zeile 36:</term>
|
|
|
|
<listitem>
|
|
<para>Erzwingt die Benutzung eines neuen Stack-Frames; dies
|
|
ist nicht mehr notwendig. Die Stack-Frames sollen jetzt an
|
|
die richtige Stelle im Speicher zeigen, selbst im Falle
|
|
eines Traps. Nach einem Blick auf den Code in Zeile 403
|
|
ergibt sich mit hoher Wahrscheinlichkeit, dass entweder
|
|
der Zeigerzugriff auf <quote>tp</quote> fehlerbehaftet
|
|
oder der Array-Zugriff unerlaubt war.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Zeile 52:</term>
|
|
|
|
<listitem>
|
|
<para>Der Zeiger scheint verdächtig, aber besitzt
|
|
zufällig eine gültige Adresse.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Zeile 56:</term>
|
|
|
|
<listitem>
|
|
<para>Jedoch zeigt er offensichtlich auf nichts und so haben
|
|
wir unseren Fehler gefunden! (Für diejenigen, die
|
|
nichts mit diesem speziellen Stück Code anfangen
|
|
können: <literal>tp->t_line</literal> verweist
|
|
hier auf das Zeilenverhalten (Line-Discipline) des
|
|
Konsolen-Geräts, was eine ziemlich kleine Ganzzahl
|
|
(Integer) sein muss.)</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<tip>
|
|
<para>Falls Ihr System regelmäßig abstürzt und
|
|
und Sie bald keinen freien Speicherplatz mehr zur
|
|
Verfügung haben, könnte das Löschen alter
|
|
<filename>vmcore</filename>-Dateien in
|
|
<filename>/var/core</filename> einen beträchtlichen
|
|
Betrag an Speicherplatz einsparen.</para>
|
|
</tip>
|
|
</sect1>
|
|
|
|
<sect1 id="kerneldebug-ddd">
|
|
<title>Fehlersuche in einem Speicherauszug nach einem Absturz mit
|
|
DDD</title>
|
|
|
|
<para>Die Untersuchung eines Speicherauszugs nach einem
|
|
Kernel-Absturz mit einem grafischen Debugger wie
|
|
<command>ddd</command> ist auch möglich (Sie müssen
|
|
den <filename role="package">devel/ddd</filename>-Port
|
|
installieren, um den <command>ddd</command>-Debugger benutzen zu
|
|
können). Nehmen Sie die <option>-k</option> mit in die
|
|
<command>ddd</command>-Kommandozeile auf, die Sie normalerweise
|
|
benutzen würden. Zum Beispiel:</para>
|
|
|
|
<screen>&prompt.root; <userinput>ddd --debugger kgdb kernel.debug /var/crash/vmcore.0</userinput></screen>
|
|
|
|
<para>Sie sollten nun in der Lage sein, die Untersuchung des
|
|
Speicherauszugs nach dem Absturz unter Benutzung der grafischen
|
|
Schnittstelle von <command>ddd</command> anzugehen.</para>
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1 id="kerneldebug-online-ddb">
|
|
<title>Online-Kernel-Fehlersuche mit DDB</title>
|
|
|
|
<para>Während <command>kgdb</command> als Offline-Debugger
|
|
eine Benutzerschnittstelle auf höchster Ebene bietet, gibt
|
|
es einige Dinge, die es nicht kann. Die wichtigsten sind das
|
|
Setzen von Breakpoints und das Abarbeiten des Kernel-Codes in
|
|
Einzelschritten (Single-Stepping).</para>
|
|
|
|
<para>Falls Sie eine systemnahe Fehlersuche an Ihrem Kernel
|
|
vorhaben, steht Ihnen ein Online-Debugger mit dem Namen DDB zur
|
|
Verfügung. Er erlaubt Ihnen das Setzen von Breakpoints, die
|
|
Abarbeitung von Kernel-Funktionen in Einzelschritten, das
|
|
Untersuchen und Verändern von Kernel-Variablen usw. Jedoch
|
|
hat er keinen Zugriff auf Kernel-Quelldateien, sondern kann nur,
|
|
im Gegensatz zu <command>gdb</command>, welches auf die ganzen
|
|
Informationen zur Fehlersuche zurückgreifen kann, auf
|
|
globale und statische Symbole zugreifen.</para>
|
|
|
|
<para>Um DDB in Ihren Kernel einzubinden, fügen Sie die
|
|
Optionen
|
|
|
|
<programlisting>options KDB</programlisting>
|
|
<programlisting>options DDB</programlisting>
|
|
|
|
Ihrer Konfigurationsdatei hinzu und bauen Sie den Kernel neu.
|
|
(Details zur Konfiguration des FreeBSD-Kernels finden Sie im
|
|
<ulink
|
|
url="&url.books.handbook;/index.html">&os;-Handbuch</ulink>).</para>
|
|
|
|
<note>
|
|
<para>Falls Sie eine ältere Version des Boot-Blocks haben,
|
|
könnte es sein, dass Ihre Symbole zur Fehlersuche noch
|
|
nicht einmal geladen werden. Aktualisieren Sie den Boot-Block;
|
|
aktuelle Versionen laden die DDB-Symbole automatisch.</para>
|
|
</note>
|
|
|
|
<para>Sobald Ihr Kernel mit DDB startet, gibt es mehrere Wege, um
|
|
in DDB zu gelangen. Der erste und früheste Weg ist, das
|
|
Boot-Flag <option>-d</option> gleich an der
|
|
Boot-Eingabeaufforderung einzugeben. Der Kernel startet dann in
|
|
den Debug-Modus und betritt DDB noch vor jedweder
|
|
Gerätesuche. Somit können Sie Funktionen zur
|
|
Gerätesuche/-bereitstellung auf Fehler untersuchen.
|
|
&os.current;-Benutzer müssen die sechste Option im
|
|
Boot-Menü auswählen, um an eine Eingabeaufforderung zu
|
|
gelangen.</para>
|
|
|
|
<para>Das zweite Szenario ist der Gang in den Debugger, sobald das
|
|
System schon gestartet ist. Es gibt zwei einfache Wege dies zu
|
|
erreichen. Falls Sie von der Eingabeaufforderung aus in den
|
|
Debugger gelangen möchten, geben Sie einfach folgenden
|
|
Befehl ab:</para>
|
|
|
|
<screen>&prompt.root; <userinput>sysctl debug.kdb.enter=1</userinput></screen>
|
|
|
|
<note>
|
|
<para>Um eine schnelle Panic zu erzwingen, geben Sie das folgende
|
|
Kommando ein:</para>
|
|
<screen>&prompt.root; <userinput>sysctl debug.kdb.panic=1</userinput></screen>
|
|
</note>
|
|
|
|
<para>Anderenfalls können Sie ein Tastenkürzel auf der
|
|
Tastatur benutzen, wenn Sie an der Systemkonsole sind. Die
|
|
Voreinstellung für die break-to-debugger-Sequenz ist
|
|
<keycombo
|
|
action="simul"><keycap>Ctrl</keycap><keycap>Alt</keycap><keycap>ESC</keycap></keycombo>.
|
|
In syscons kann diese Sequenz auf eine andere Tastenkombination
|
|
gelegt werden (remap) und manche der verfügbaren
|
|
Tastaturlayouts tun dies, stellen Sie also sicher, dass Sie die
|
|
richtige Sequenz kennen, die benutzt werden soll. Für
|
|
serielle Konsolen ist eine Option vorhanden, die die Benutzung
|
|
einer Unterbrechung der seriellen Verbindung (BREAK) auf der
|
|
Kommandozeile erlaubt, um in DDB zu gelangen (<literal>options
|
|
BREAK_TO_DEBUGGER</literal> in der Kernel-Konfigurationsdatei).
|
|
Dies ist jedoch nicht der Standard, da viele serielle Adapter in
|
|
Verwendung sind, die grundlos eine BREAK-Bedingung erzeugen, zum
|
|
Beispiel bei Ziehen des Kabels.</para>
|
|
|
|
<para>Die dritte Möglichkeit ist, dass jede Panic-Bedingung
|
|
in DDB springt, falls der Kernel hierfür konfiguriert ist.
|
|
Aus diesem Grund ist es nicht sinnvoll einen Kernel mit DDB
|
|
für ein unbeaufsichtigtes System zu konfigurieren.</para>
|
|
|
|
<para>Um die unbeaufsichtigte Funktionsweise zu erreichen
|
|
fügen Sie:</para>
|
|
|
|
<programlisting>options KDB_UNATTENDED</programlisting>
|
|
|
|
<para>der Kernel-Konfigurationsdatei hinzu und bauen/installieren
|
|
Sie den Kernel neu.</para>
|
|
|
|
<para>Die DDB-Befehle ähneln grob einigen
|
|
<command>gdb</command>-Befehlen. Das Erste, das Sie vermutlich
|
|
tun müssen, ist einen Breakpoint zu setzen:</para>
|
|
|
|
<screen><userinput>break function-name address</userinput></screen>
|
|
|
|
<para>Zahlen werden standardmäßig hexadezimal
|
|
angegeben, aber um sie von Symbolnamen zu unterscheiden, muss
|
|
Zahlen, die mit den Buchstaben <literal>a-f</literal> beginnen,
|
|
<literal>0x</literal> vorangehen (dies ist für andere
|
|
Zahlen beliebig). Einfache Ausdrücke sind erlaubt, zum
|
|
Beispiel: <literal>function-name + 0x103</literal>.</para>
|
|
|
|
<para>Um den Debugger zu verlassen und mit der Abarbeitung
|
|
fortzufahren, geben Sie ein:</para>
|
|
|
|
<screen><userinput>continue</userinput></screen>
|
|
|
|
<para>Um eine Stack-Ablaufverfolgung zu erhalten, benutzen
|
|
Sie:</para>
|
|
|
|
<screen><userinput>trace</userinput></screen>
|
|
|
|
<note>
|
|
<para>Beachten Sie, dass wenn Sie DDB mittels einer
|
|
Schnelltaste betreten, der Kernel zurzeit einen Interrupt
|
|
bereitstellt, sodass die Stack-Ablaufverfolgung Ihnen nicht
|
|
viel nützen könnte.</para>
|
|
</note>
|
|
|
|
<para>Falls Sie einen Breakpoint entfernen möchten, benutzen
|
|
Sie</para>
|
|
|
|
<screen><userinput>del</userinput>
|
|
<userinput>del address-expression</userinput></screen>
|
|
|
|
<para>Die erste Form wird direkt, nachdem ein Breakpoint anschlug,
|
|
angenommen und entfernt den aktuellen Breakpoint. Die zweite
|
|
kann jeden Breakpoint löschen, aber Sie müssen die
|
|
genaue Adresse angeben; diese kann bezogen werden durch:</para>
|
|
|
|
<screen><userinput>show b</userinput></screen>
|
|
|
|
<para>oder:</para>
|
|
|
|
<screen><userinput>show break</userinput></screen>
|
|
|
|
<para>Um den Kernel in Einzelschritten auszuführen, probieren
|
|
Sie:</para>
|
|
|
|
<screen><userinput>s</userinput></screen>
|
|
|
|
<para>Dies springt in Funktionen, aber Sie können DDB
|
|
veranlassen, diese schrittweise zu verfolgen, bis die passende
|
|
Rückkehranweisung (Return-Statement) erreicht ist. Nutzen
|
|
Sie hierzu:</para>
|
|
|
|
<screen><userinput>n</userinput></screen>
|
|
|
|
<note>
|
|
<para>Dies ist nicht das gleiche wie die
|
|
<command>next</command>-Anweisung von <command>gdb</command>;
|
|
es ist wie <command>gdb</command>s <command>finish</command>.
|
|
Mehrmaliges Drücken von <keycap>n</keycap> führt zu
|
|
einer Fortsetzung.</para>
|
|
</note>
|
|
|
|
<para>Um Daten aus dem Speicher zu untersuchen, benutzen Sie (zum
|
|
Beispiel):
|
|
|
|
<screen><userinput>x/wx 0xf0133fe0,40</userinput>
|
|
<userinput>x/hd db_symtab_space</userinput>
|
|
<userinput>x/bc termbuf,10</userinput>
|
|
<userinput>x/s stringbuf</userinput></screen>
|
|
|
|
für Word/Halfword/Byte-Zugriff und
|
|
Hexadezimal/Dezimal/Character/String-Ausgabe. Die Zahl nach dem
|
|
Komma ist der Objektzähler. Um die nächsten 0x10
|
|
Objekte anzuzeigen benutzen Sie einfach:</para>
|
|
|
|
<screen><userinput>x ,10</userinput></screen>
|
|
|
|
<para>Gleichermaßen benutzen Sie
|
|
|
|
<screen><userinput>x/ia foofunc,10</userinput></screen>
|
|
|
|
um die ersten 0x10 Anweisungen aus <function>foofunc</function>
|
|
zu zerlegen (disassemble) und Sie zusammen mit ihrem
|
|
Adressabstand (Offset) vom Anfang von
|
|
<function>foofunc</function> auszugeben.</para>
|
|
|
|
<para>Um Speicher zu verändern benutzen Sie den
|
|
Schreibbefehl:</para>
|
|
|
|
<screen><userinput>w/b termbuf 0xa 0xb 0</userinput>
|
|
<userinput>w/w 0xf0010030 0 0</userinput></screen>
|
|
|
|
<para>Die Befehlsoption
|
|
(<literal>b</literal>/<literal>h</literal>/<literal>w</literal>)
|
|
legt die Größe der Daten fest, die geschrieben werden
|
|
sollen, der erste Ausdruck danach ist die Adresse, wohin
|
|
geschrieben werden soll, und der Rest wird als Daten
|
|
verarbeitet, die in aufeinander folgende Speicherstellen
|
|
geschrieben werden.</para>
|
|
|
|
<para>Falls Sie die aktuellen Register wissen möchten,
|
|
benutzen Sie:</para>
|
|
|
|
<screen><userinput>show reg</userinput></screen>
|
|
|
|
<para>Alternativ können Sie den Inhalt eines einzelnen
|
|
Registers ausgeben mit z.B.
|
|
|
|
<screen><userinput>p $eax</userinput></screen>
|
|
|
|
und ihn bearbeiten mit:</para>
|
|
|
|
<screen><userinput>set $eax new-value</userinput></screen>
|
|
|
|
<para>Sollten Sie irgendeine Kernel-Funktion aus DDB heraus
|
|
aufrufen wollen, geben Sie einfach ein:</para>
|
|
|
|
<screen><userinput>call func(arg1, arg2, ...)</userinput></screen>
|
|
|
|
<para>Der Rückgabewert wird ausgegeben.</para>
|
|
|
|
<para>Für eine Zusammenfassung aller laufenden Prozesse im
|
|
Stil von &man.ps.1; benutzen Sie:</para>
|
|
|
|
<screen><userinput>ps</userinput></screen>
|
|
|
|
<para>Nun haben Sie herausgefunden, warum Ihr Kernel
|
|
fehlschlägt, und möchten neu starten. Denken Sie
|
|
daran, dass, abhängig von der Schwere vorhergehender
|
|
Störungen, nicht alle Teile des Kernels wie gewohnt
|
|
funktionieren könnten. Führen Sie eine der folgenden
|
|
Aktionen durch, um Ihr System herunterzufahren und neu zu
|
|
starten:</para>
|
|
|
|
<screen><userinput>panic</userinput></screen>
|
|
|
|
<para>Dies wird Ihren Kernel dazu veranlassen abzustürzen,
|
|
einen Speicherauszug abzulegen und neu zu starten, sodass Sie
|
|
den Kernspeicherauszug später auf höherer Ebene mit
|
|
<command>gdb</command> auswerten können. Diesem Befehl muss
|
|
normalerweise eine weitere <command>continue</command>-Anweisung
|
|
folgen.</para>
|
|
|
|
<screen><userinput>call boot(0)</userinput></screen>
|
|
|
|
<para>Dürfte ein guter Weg sein, um das laufende System
|
|
sauber herunterzufahren, alle Festplatten mittels
|
|
<function>sync()</function> zu schreiben und schließlich,
|
|
in manchen Fällen, neu zu starten. Solange die Festplatten-
|
|
und Dateisystemschnittstellen des Kernels nicht beschädigt
|
|
sind, könnte dies ein guter Weg für ein beinahe
|
|
sauberes Abschalten sein.</para>
|
|
|
|
<screen><userinput>call cpu_reset()</userinput></screen>
|
|
|
|
<para>Dies ist der letzte Ausweg aus der Katastrophe und kommt
|
|
beinahe dem Drücken des Ausschaltknopfes gleich.</para>
|
|
|
|
<para>Falls Sie eine kurze Zusammenfassung aller Befehle
|
|
benötigen, geben Sie einfach ein:</para>
|
|
|
|
<screen><userinput>help</userinput></screen>
|
|
|
|
<para>Es ist strengstens empfohlen, eine ausgedruckte Version der
|
|
&man.ddb.4;-Manualpage während der Fehlersuche neben sich
|
|
liegen zu haben. Denken Sie daran, dass es schwer ist, die
|
|
Online-Hilfe zu lesen, während der Ausführung des
|
|
Kernels in Einzelschritten.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="kerneldebug-online-gdb">
|
|
<title>Online-Kernel-Fehlersuche mit GDB auf einem entfernten
|
|
System</title>
|
|
|
|
<para>Diese Funktion wird seit FreeBSD 2.2 unterstützt und
|
|
ist wirklich sehr geschickt.</para>
|
|
|
|
<para>GDB unterstützt <emphasis>die Fehlersuche von einem
|
|
entfernten System aus</emphasis> bereits einige Zeit. Dies
|
|
geschieht unter Benutzung eines sehr einfachen Protokolls
|
|
über eine serielle Verbindung. Anders als bei den anderen,
|
|
oben beschriebenen, Vorgehensweisen werden hier zwei Systeme
|
|
benötigt. Das eine ist das Hostsystem, welches die Umgebung
|
|
zur Fehlersuche, einschließlich aller Quellen und einer
|
|
Kopie der Kernel-Binärdatei mit allen Symbolen
|
|
bereitstellt, und das andere das Zielsystem, welches einfach nur
|
|
eine Kopie desselben Kernels ausführt (ohne die
|
|
Informationen zur Fehlersuche).</para>
|
|
|
|
<para>Sie sollten den Kernel im Zweifelsfall mit <command>config
|
|
-g</command> konfigurieren, <option>DDB</option> in die
|
|
Konfiguration aufnehmen und den Kernel, wie sonst auch,
|
|
kompilieren. Dies ergibt, aufgrund der zusätzlichen
|
|
Informationen zur Fehlersuche, eine umfangreiche
|
|
Binärdatei. Kopieren Sie diesen Kernel auf das Zielsystem,
|
|
entfernen Sie die Symbole zur Fehlersuche mit <command>strip
|
|
-x</command> und starten Sie ihn mit der
|
|
<option>-d</option>-Boot-Option. Stellen Sie die serielle
|
|
Verbindung zwischen dem Zielsystem, welches "flags 80" für
|
|
dessen sio-Gerät gesetzt hat, und dem Hostsystem, welches
|
|
die Fehlersuche übernimmt, her. Nun wechseln Sie auf dem
|
|
Hostsystem in das Bauverzeichnis des Ziel-Kernels und starten
|
|
<command>gdb</command>:</para>
|
|
|
|
<screen>&prompt.user; <userinput>kgdb kernel</userinput>
|
|
GDB is free software and you are welcome to distribute copies of it
|
|
under certain conditions; type "show copying" to see the conditions.
|
|
There is absolutely no warranty for GDB; type "show warranty" for details.
|
|
GDB 4.16 (i386-unknown-freebsd),
|
|
Copyright 1996 Free Software Foundation, Inc...
|
|
<prompt>(kgdb)</prompt> </screen>
|
|
|
|
<para>Stellen Sie die entfernte Sitzung zur Fehlersuche ein mit
|
|
(angenommen, der erste serielle Port ist in Verwendung):</para>
|
|
|
|
<screen><prompt>(kgdb)</prompt> <userinput>target remote /dev/cuaa0</userinput></screen>
|
|
|
|
<para>Jetzt geben Sie auf dem Zielsystem, welches noch vor Beginn
|
|
der Gerätesuche in DDB gelangt ist, ein:</para>
|
|
|
|
<screen>Debugger("Boot flags requested debugger")
|
|
Stopped at Debugger+0x35: movb $0, edata+0x51bc
|
|
<prompt>db></prompt> <userinput>gdb</userinput></screen>
|
|
|
|
<para>DDB antwortet dann mit:</para>
|
|
|
|
<screen>Next trap will enter GDB remote protocol mode</screen>
|
|
|
|
<para>Jedesmal wenn Sie <command>gdb</command> eingeben, wird
|
|
zwischen dem lokalen DDB und entfernten GDB umgeschaltet. Um
|
|
einen nächsten Trap sofort zu erzwingen, geben Sie einfach
|
|
<command>s</command> (step) ein. Ihr GDB auf dem Hostsystem
|
|
erhält nun die Kontrolle über den Ziel-Kernel:</para>
|
|
|
|
<screen>Remote debugging using /dev/cuaa0
|
|
Debugger (msg=0xf01b0383 "Boot flags requested debugger")
|
|
at ../../i386/i386/db_interface.c:257
|
|
<prompt>(kgdb)</prompt></screen>
|
|
|
|
<para>Sie können mit dieser Sitzung wie mit jeder anderen
|
|
GDB-Sitzung umgehen, einschließlich vollem Zugriff auf die
|
|
Quellen, Starten im gud-Modus innerhalb eines Emacs-Fensters
|
|
(was Ihnen automatische Quelltext-Ausgabe in einem weiteren
|
|
Emacs-Fenster bietet), usw.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="kerneldebug-console">
|
|
<title>Fehlersuche bei einem Konsolen-Treiber</title>
|
|
|
|
<para>Da Sie nunmal einen Konsolen-Treiber benötigen, um DDB
|
|
zu starten, ist alles ein wenig komplizierter, sobald der
|
|
Konsolen-Treiber selbst versagt. Sie erinnern sich vielleicht an
|
|
die Benutzung einer seriellen Konsole (entweder durch
|
|
Verändern des Boot-Blocks oder Eingabe von
|
|
<option>-h</option> an der
|
|
<prompt>Boot:</prompt>-Eingabeaufforderung) und das
|
|
Anschließen eines Standard-Terminals an Ihren ersten
|
|
seriellen Port. DDB funktioniert auf jedem konfigurierten
|
|
Konsolen-Treiber, auch auf einer seriellen Konsole.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="kerneldebug-deadlocks">
|
|
<title>Fehlersuche bei Deadlocks</title>
|
|
|
|
<para>Sie erleben vielleicht mal sogenannte Deadlocks, wobei ein
|
|
System aufhört, nützliche Arbeit zu machen. Um in
|
|
einer solchen Situation einen hilfreichen Fehlerbericht zu
|
|
liefern, benutzen Sie &man.ddb.4;, wie oben beschrieben.
|
|
Hängen Sie die Ausgabe von <command>ps</command> und
|
|
<command>trace</command> für verdächtige Prozesse an
|
|
den Bericht an.</para>
|
|
|
|
<para>Falls möglich, versuchen Sie, weitere Untersuchungen
|
|
anzustellen. Der Empfang der Ausgaben unten ist besonders dann
|
|
nützlich, wenn Sie den Auslöser für die Blockade
|
|
des Systems auf VFS-Ebene vermuten. Fügen Sie die folgenden
|
|
Optionen
|
|
|
|
<programlisting>makeoptions DEBUG=-g
|
|
options INVARIANTS
|
|
options INVARIANT_SUPPORT
|
|
options WITNESS
|
|
options DEBUG_LOCKS
|
|
options DEBUG_VFS_LOCKS
|
|
options DIAGNOSTIC</programlisting>
|
|
|
|
der Kernel-Konfigurationsdatei hinzu. Wenn die Blockade
|
|
ausgelöst wird, stellen Sie, zusätzlich der Ausgabe
|
|
vom <command>ps</command>-Befehl, die Informationen aus
|
|
<command>show pcpu</command>, <command>show allpcpu</command>,
|
|
<command>show locks</command>, <command>show alllocks</command>,
|
|
<command>show lockedvnods</command> und
|
|
<command>alltrace</command> bereit.</para>
|
|
|
|
<para>Um aussagekräftige Zurückverfolgungen von in
|
|
Threads aufgeteilten Prozesse zu erhalten, benutzen Sie
|
|
<command>thread thread-id</command>, um zum Thread-Stack zu
|
|
wechseln und eine Zurückverfolgung mit
|
|
<command>where</command> anzustellen.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="kerneldebug-options">
|
|
<title>Glossar der Kernel-Optionen zur Fehlersuche</title>
|
|
|
|
<para>Dieser Abschnitt bietet ein kurzes Glossar der zur
|
|
Kompilierzeit verfügbaren Kernel-Optionen, die die
|
|
Fehlersuche unterstützen:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal>options KDB</literal>: Kompiliert das
|
|
Kernel-Debugger-Framework ein. Wird von <literal>options
|
|
DDB</literal> und <literal>options GDB</literal>
|
|
benötigt. Kein oder nur geringer Leistungs-Overhead.
|
|
Standardmäßig wird bei einer Panic der Debugger
|
|
gestartet, anstatt automatisch neu zu starten.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options KDB_UNATTENDED</literal>: Setzt den
|
|
Standard des
|
|
<literal>debug.debugger_on_panic</literal>-sysctl-Werts auf
|
|
0, welcher regelt, ob der Debugger bei einer Panic gestartet
|
|
wird. Solange <literal>options KDB</literal> nicht in den
|
|
Kernel einkompiliert ist, wird bei einer Panic automatisch
|
|
neu gestartet; sobald es in den Kernel einkompiliert ist,
|
|
wird standardmäßig der Debugger gestartet,
|
|
solange <literal>options KDB_UNATTENDED</literal> nicht
|
|
einkompiliert ist. Falls Sie den Kernel-Debugger in den
|
|
Kernel einkompiliert lassen wollen, aber möchten, dass
|
|
das System neu startet, wenn Sie nicht zur Stelle sind, um
|
|
den Debugger zur Diagnose zu benutzen, wählen Sie diese
|
|
Option.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options KDB_TRACE</literal>: Setzt den Standard
|
|
des <literal>debug.trace_on_panic</literal>-sysctl-Werts auf
|
|
1, welcher regelt, ob der Debugger bei einer Panic
|
|
automatisch eine Stack-Ablaufverfolgung ausgibt. Besonders
|
|
wenn der Kernel mit <literal>KDB_UNATTENDED</literal>
|
|
läuft, kann dies hilfreich sein, um grundlegende
|
|
Informationen zur Fehlersuche auf der seriellen oder
|
|
Firewire-Konsole zu erhalten, während immer noch zur
|
|
Wiederherstellung neu gestartet wird.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options DDB</literal>: Kompiliert die
|
|
Unterstützung für den Konsolen-Debugger DDB ein.
|
|
Dieser interaktive Debugger läuft auf was auch immer
|
|
die aktive Konsole des Systems auf niedrigster Ebene ist,
|
|
dazu gehören die Video-, serielle und Firewire-Konsole.
|
|
Er bietet grundlegende, eingebaute Möglichkeiten zur
|
|
Fehlersuche wie zum Beispiel das Erstellen von
|
|
Stack-Ablaufverfolgungen, das Auflisten von Prozessen und
|
|
Threads, das Ablegen des Lock-, VM- und Dateisystemstatus
|
|
und die Verwaltung des Kernel-Speichers. DDB benötigt
|
|
keine Software, die auf einem zweiten System läuft,
|
|
oder die Fähigkeit, einen Kernspeicherauszug oder
|
|
Kernel-Symbole zur vollen Fehlersuche zu erzeugen und bietet
|
|
detaillierte Fehlerdiagnose des Kernels zur Laufzeit. Viele
|
|
Fehler können allein unter Benutzung der DDB-Ausgabe
|
|
untersucht werden. Diese Option hängt von
|
|
<literal>options KDB</literal> ab.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options GDB</literal>: Kompiliert die
|
|
Unterstützung für den Debugger GDB ein, welcher
|
|
von einem entfernten System aus über ein serielles
|
|
Kabel oder Firewire agieren kann. Wenn der Debugger
|
|
gestartet ist, kann GDB dazu verwendet werden, um
|
|
Struktur-Inhalte einzusehen, Stack-Ablaufverfolgungen zu
|
|
erzeugen, usw. Bei manchem Kernel-Status ist der Zugriff
|
|
ungeschickter als mit DDB, welcher dazu in der Lage ist,
|
|
nützliche Zusammenfassungen des Kernel-Status
|
|
automatisch zu erstellen wie zum Beispiel das automatische
|
|
Abgehen der Lock-Fehlersuche oder der Strukturen zur
|
|
Kernel-Speicher-Verwaltung, und es wird ein zweites System
|
|
benötigt. Auf der anderen Seite verbindet GDB
|
|
Informationen aus den Kernel-Quellen mit vollständigen
|
|
Symbolen zur Fehlersuche, erkennt komplette
|
|
Datenstrukturdefinitionen, lokale Variablen und ist in
|
|
Skripten einsetzbar. Diese Option hängt von
|
|
<literal>options KDB</literal> ab, ist aber nicht zur
|
|
Benutzung von GDB auf einem Kernel-Kernspeicherauszug
|
|
nötig.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options BREAK_TO_DEBUGGER</literal>,
|
|
<literal>options ALT_BREAK_TO_DEBUGGER</literal>: Erlaubt
|
|
ein Abbruch- oder Alternativ-Signal auf der Konsole, um in
|
|
den Debugger zu gelangen. Falls sich das System ohne eine
|
|
Panic aufhängt, ist dies ein nützlicher Weg, um
|
|
den Debugger zu erreichen. Aufgrund der aktuellen
|
|
Verriegelung durch den Kernel ist ein Abbruch-Signal, das
|
|
auf einer seriellen Konsole erzeugt wurde, deutlich
|
|
vertrauenswürdiger beim Gelangen in den Debugger und
|
|
wird allgemein empfohlen. Diese Option hat kaum oder keine
|
|
Auswirkung auf den Durchsatz.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options INVARIANTS</literal>: Kompiliert eine
|
|
große Anzahl an Aussageprüfungen und -tests
|
|
(Assertion-Checks und -Tests) ein, welche ständig die
|
|
Intaktheit der Kernel-Datenstrukturen und die Invarianten
|
|
der Kernel-Algorithmen prüfen. Diese Tests können
|
|
aufwendig sein und sind deswegen nicht von Anfang an
|
|
einkompiliert, aber helfen nützliches "fail
|
|
stop"-Verhalten, wobei bestimmte Gruppen nicht
|
|
erwünschten Verhaltens den Debugger öffnen, bevor
|
|
Beschädigungen an Kernel-Daten auftreten,
|
|
bereitzustellen, welches es einfacher macht, diese auf
|
|
Fehler hin zu untersuchen. Die Tests beinhalten Säubern
|
|
von Speicher und use-after-free-Prüfungen, was eine der
|
|
bedeutenderen Quellen von Overhead ist. Diese Option
|
|
hängt von <literal>options INVARIANT_SUPPORT</literal>
|
|
ab.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options INVARIANT_SUPPORT</literal>: Viele der
|
|
in <literal>options INVARIANTS</literal> vorhandenen Tests
|
|
benötigen veränderte Datenstrukturen und
|
|
zusätzliche Kernel-Symbole, die festgelegt werden
|
|
müssen.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options WITNESS</literal>: Diese Option
|
|
aktiviert Verfolgung und Prüfung von Lock-Anforderungen
|
|
zur Laufzeit und ist als Werkzeug für die
|
|
Deadlock-Diagnose von unschätzbarem Wert. WITNESS
|
|
pflegt ein Diagramm mit erworbenen Lock-Anträgen nach
|
|
Typ geordnet und prüft bei jedem Erwerb nach Zyklen
|
|
(implizit oder explizit). Falls ein Zyklus entdeckt wird,
|
|
werden eine Warnung und eine Stack-Ablaufverfolgung erzeugt
|
|
und als Hinweis, dass ein möglicher Deadlock gefunden
|
|
wurde, auf der Konsole ausgegeben. WITNESS wird
|
|
benötigt, um die DDB-Befehle <command>show
|
|
locks</command>, <command>show witness</command> und
|
|
<command>show alllocks</command> benutzen zu können.
|
|
Diese Debug-Option hat einen bedeutenden Leistung-Overhead,
|
|
welcher ein ein wenig durch Benutzung von <literal>options
|
|
WITNESS_SKIPSPIN</literal> gemildert werden kann.
|
|
Detaillierte Dokumentation kann in &man.witness.4; gefunden
|
|
werden.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options WITNESS_SKIPSPIN</literal>: Deaktiviert
|
|
die Prüfung von Spinlock-Lock-Anforderungen mit WITNESS
|
|
zur Laufzeit. Da Spinlocks am häufigsten im Scheduler
|
|
angefordert werden und Scheduler-Ereignisse oft auftreten,
|
|
kann diese Option Systeme, die mit WITNESS laufen, merklich
|
|
beschleunigen. Diese Option hängt von <literal>options
|
|
WITNESS</literal> ab.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options WITNESS_KDB</literal>: Setzt den
|
|
Standard des
|
|
<literal>debug.witness.kdb</literal>-sysctl-Werts auf 1, was
|
|
bewirkt, dass WITNESS den Debugger aufruft, sobald eine
|
|
Lock-Anforderungsverletzung vorliegt, anstatt einfach nur
|
|
eine Warnung auszugeben. Diese Option hängt von
|
|
<literal>options WITNESS</literal> ab.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options SOCKBUF_DEBUG</literal>: Führt
|
|
umfassende Beschaffenheitsprüfungen in Socket-Puffern
|
|
durch, was nützlich zur Fehlersuche bei Socket-Fehlern
|
|
und Anzeichen für Ressourceblockaden (Race) in
|
|
Protokollen und Gerätetreibern, die mit Sockets
|
|
arbeiten, sein kann. Diese Option hat bedeutende Auswirkung
|
|
auf die Netzwerkleistung und kann die Zeitverhältnisse
|
|
bei gegenseitiger Ressourceblockade in Gerätetreibern
|
|
ändern.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options DEBUG_VFS_LOCKS</literal>: Verfolgt
|
|
Lock-Anforderungs-Einzelheiten bei lockmgr/vnode-Locks, was
|
|
die Menge der Informationen, die von <command>show
|
|
lockdevnods</command> in DDB angezeigt werden,
|
|
vergrößert. Diese Option hat messbare Auswirkung
|
|
auf die Leistung.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options DEBUG_MEMGUARD</literal>: Ein Ersatz
|
|
für die Kernel-Speicher-Zuweisung durch &man.malloc.9;,
|
|
die das VM-System benutzt, um Lese- und Schreibzugriffe auf
|
|
zugewiesenen Speicher nach der Freigabe zu entdecken.
|
|
Details können in &man.memguard.9; gefunden werden.
|
|
Diese Option hat bedeutende Auswirkung auf die Leistung,
|
|
aber kann sehr nützlich bei der Fehlersuche sein, wenn
|
|
Kernel-Speicher-Beschädigungen durch Fehler verursacht
|
|
werden.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>options DIAGNOSTIC</literal>: Aktiviert
|
|
zusätzliche, aufwendigere Diagnosetests analog zu
|
|
<literal>options INVARIANTS</literal>.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect1>
|
|
</chapter>
|