doc/de_DE.ISO8859-1/books/developers-handbook/kerneldebug/chapter.sgml
2012-09-14 17:47:48 +00:00

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;&nbsp;6.2 und höhere Versionen) und Textauszüge
(textdumps), welche geskriptete oder Debugger-Ausgaben enthalten
(&os;&nbsp;7.1 und höher). Miniauszüge sind der Standardtyp
der Abzüge seit &os;&nbsp;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;&nbsp;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 &lt; delay; x += incr) {
48:663 if ((lapic-&gt;icr_lo &amp; 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(&amp;frame, FALSE);
36:<prompt>(kgdb)</prompt> <userinput>frame frame-&gt;tf_ebp frame-&gt;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-&gt;t_line].l_open)(dev, tp));
41:<prompt>(kgdb)</prompt> <userinput>list</userinput>
42:398
43:399 tp-&gt;t_state |= TS_CARR_ON;
44:400 tp-&gt;t_cflag |= CLOCAL; /* cannot be a modem (:-) */
45:401
46:402 #if PCVT_NETBSD || (PCVT_FREEBSD &gt;= 200)
47:403 return ((*linesw[tp-&gt;t_line].l_open)(dev, tp));
48:404 #else
49:405 return ((*linesw[tp-&gt;t_line].l_open)(dev, tp, flag));
50:406 #endif /* PCVT_NETBSD || (PCVT_FREEBSD &gt;= 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-&gt;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-&gt;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-&gt;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&gt;</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>