Initial import, synchronized with English 1.62
Obtained from: The FreeBSD Russian Documentation Project
This commit is contained in:
parent
083ba1adaf
commit
122586a044
Notes:
svn2git
2020-12-08 03:00:23 +00:00
svn path=/head/; revision=24808
1 changed files with 895 additions and 0 deletions
895
ru_RU.KOI8-R/books/developers-handbook/kerneldebug/chapter.sgml
Normal file
895
ru_RU.KOI8-R/books/developers-handbook/kerneldebug/chapter.sgml
Normal file
|
@ -0,0 +1,895 @@
|
|||
<!--
|
||||
The FreeBSD Russian Documentation Project
|
||||
|
||||
$FreeBSD$
|
||||
$FreeBSDru: frdp/doc/ru_RU.KOI8-R/books/developers-handbook/kerneldebug/chapter.sgml,v 1.16 2005/05/23 06:40:07 andy Exp $
|
||||
|
||||
Original revision: 1.62
|
||||
-->
|
||||
|
||||
<chapter id="kerneldebug">
|
||||
<chapterinfo>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Paul</firstname>
|
||||
|
||||
<surname>Richards</surname>
|
||||
|
||||
<contrib>Текст предоставили </contrib>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Jörg</firstname>
|
||||
|
||||
<surname>Wunsch</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</chapterinfo>
|
||||
|
||||
<title>Отладка ядра</title>
|
||||
|
||||
<sect1 id="kerneldebug-obtain">
|
||||
<title>Получение аварийного дампа ядра</title>
|
||||
|
||||
<para>При работе ядра, находящегося в разработке (например: &os.current;),
|
||||
при критичных условиях (к примеру: очень высокая средняя нагрузка,
|
||||
десятки тысяч соединений, исключительно большое количество одновременно
|
||||
работающих пользователей, сотни процессов &man.jail.8; и так далее) или
|
||||
при использовании новой возможности в драйвере устройства в &os.stable;
|
||||
(пример: <acronym>PAE</acronym>) оно иногда будет завершать свою работу
|
||||
аварийно. В случае, если это произошло, в этой главе показано, как
|
||||
извлекать полезную информацию из произошедшего сбоя.</para>
|
||||
|
||||
<para>При аварийном завершении работы ядра перезагрузка системы неизбежна.
|
||||
После перезагрузки системы содержимое физической памяти системы
|
||||
(<acronym>RAM</acronym>) теряется, так же как и всё содержимое раздела
|
||||
подкачки перед сбоем. Для сохранения состояния физической памяти ядро
|
||||
использует устройство подкачки в качестве места временного хранения
|
||||
содержимого оперативной памяти после перезагрузки, следующей за аварийным
|
||||
завершением работы. С этой целью при загрузке
|
||||
&os; после аварийного останова образ ядра может быть извлечён и
|
||||
применяться для отладки.</para>
|
||||
|
||||
<note>
|
||||
<para>Устройство подкачки, которое было отконфигурировано в качестве
|
||||
устройства для дампа продолжает выступать в роли устройства подкачки.
|
||||
В настоящее время выполнение дампов на устройства, не предназначенные
|
||||
для организации подкачки (например, ленты или CDRW), не поддерживается.
|
||||
Понятие <quote>устройство подкачки</quote> является синонимом
|
||||
<quote>раздела подкачки.</quote></para>
|
||||
</note>
|
||||
|
||||
<para>Чтобы суметь извлечь образ, который можно использовать, требуется,
|
||||
чтобы по крайней мере один раздел подкачки был достаточно большим, чтобы
|
||||
разместить на нём весь объём физической памяти. Когда ядро аварийно
|
||||
завершает работу, перед перезагрузкой системы, ядро достаточно умно,
|
||||
чтобы проверить, было ли отконфигурировано устройство подкачки в
|
||||
качестве устройства для хранения дампов. Если оно является устройством,
|
||||
подходящим для сброса дампа, то ядро сбрасывает содержимое физической
|
||||
памяти на устройство подкачки.</para>
|
||||
|
||||
<sect2 id="config-dumpdev">
|
||||
<title>Конфигурация устройства хранения дампов</title>
|
||||
|
||||
<para>До того, как ядро начнёт сбрасывать содержимое физической памяти
|
||||
на устройство хранения дампов, последнее должно быть
|
||||
отконфигурировано. Устройство хранения дампов задаётся при помощи
|
||||
команды &man.dumpon.8;, указывающей ядру, куда сохранять аварийные
|
||||
дампы ядра. Программа &man.dumpon.8; должна быть вызвана после
|
||||
конфигурации раздела подкачки по команде &man.swapon.8;. Обычно это
|
||||
осуществляется установкой переменной <varname>dumpdev</varname> в
|
||||
файле &man.rc.conf.5; в значение, соответствующее пути к устройству
|
||||
подкачки (рекомендованный способ извлечения дампа ядра).</para>
|
||||
|
||||
<para>Либо устройство для сброса образа памяти может быть задано явно
|
||||
в параметре <literal>dump</literal> строки &man.config.5;
|
||||
конфигурационного файла вашего ядра. Такой способ использовать не
|
||||
рекомендуется и он должен использоваться, только если ядро аварийно
|
||||
завершает свою работу до того, как можно было бы запустить
|
||||
&man.dumpon.8;.</para>
|
||||
|
||||
<tip>
|
||||
<para>Проверьте содержимое файла <filename>/etc/fstab</filename> или
|
||||
выдачу &man.swapinfo.8; на предмет наличия устройств
|
||||
подкачки.</para>
|
||||
</tip>
|
||||
|
||||
<important>
|
||||
<para>Удостоверьтесь, что каталог <varname>dumpdir</varname>,
|
||||
указанный в &man.rc.conf.5;, существует до аварийного останова
|
||||
ядра!</para>
|
||||
|
||||
<screen>&prompt.root; <userinput>mkdir /var/crash</userinput>
|
||||
&prompt.root; <userinput>chmod 700 /var/crash</userinput></screen>
|
||||
|
||||
<para>Запомните также, что содержимое <filename>/var/crash</filename>
|
||||
является важной информацией, весьма вероятно, содержащей
|
||||
конфиденциальную информацию, в частности, пароли.</para>
|
||||
</important>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="extract-dump">
|
||||
<title>Извлечение дампа ядра</title>
|
||||
|
||||
<para>После того, как аварийный образ был записан на соответствующее
|
||||
устройство, его нужно извлечь до момента монтирования устройства
|
||||
подкачки. Для извлечения дампа из
|
||||
устройства его сохранения, воспользуйтесь утилитой &man.savecore.8;.
|
||||
Если в файле &man.rc.conf.5; было задано устройство
|
||||
<varname>dumpdev</varname>, то &man.savecore.8; будет запущена
|
||||
автоматически при первой после аварийного останова загрузке в
|
||||
многопользовательском режиме и до монтирования устройства подкачки.
|
||||
Местоположение извлечённого образа памяти определяется значением
|
||||
переменной <varname>dumpdir</varname> из файла &man.rc.conf.5;,
|
||||
которое по умолчанию указывает на каталог
|
||||
<filename>/var/crash</filename>, а файл будет называться
|
||||
<filename>vmcore.0</filename>.</para>
|
||||
|
||||
<para>В случае, если в каталоге <filename>/var/crash</filename> (или в
|
||||
том, на который указывает <varname>dumpdir</varname>) уже существует
|
||||
файл с именем <filename>vmcore.0</filename>, то ядро будет увеличивать
|
||||
порядковый номер для каждого аварийного останова, чтобы избежать
|
||||
перезаписи существующих файлов <filename>vmcore</filename> (к
|
||||
примеру, <filename>vmcore.1</filename>). В процессе отладки скорее
|
||||
всего, в качестве нужного <filename>vmcore</filename> вы будете
|
||||
использовать версию <filename>vmcore</filename> с наибольшим номером
|
||||
в <filename>/var/crash</filename>.</para>
|
||||
|
||||
<tip>
|
||||
<para>Если вы тестируете новое ядро, но вам нужно загрузить и работать
|
||||
с другим ядром, чтобы получить нормально функционирующую систему, то
|
||||
загрузите его в однопользовательском режиме при помощи флага
|
||||
<option>-s</option>, указываемого при загрузке, а затем выполните
|
||||
такие шаги:</para>
|
||||
|
||||
<screen>&prompt.root; <userinput>fsck -p</userinput>
|
||||
&prompt.root; <userinput>mount -a -t ufs</userinput> # доступность /var/crash для записи
|
||||
&prompt.root; <userinput>savecore /var/crash /dev/ad0s1b</userinput>
|
||||
&prompt.root; <userinput>exit</userinput> # переход в многопользовательский режим</screen>
|
||||
|
||||
<para>Эти команды указывают &man.savecore.8; извлечь дамп ядра из
|
||||
устройства <filename>/dev/ad0s1b</filename> и поместить его
|
||||
содержимое в каталог <filename>/var/crash</filename>. Не забудьте
|
||||
проверить, что в целевом каталоге <filename>/var/crash</filename>
|
||||
достаточно места для хранения дампа. Кроме того, не забудьте
|
||||
проверить правильность маршрута к вашему устройству подкачки, так
|
||||
как он, скорее всего, отличается от
|
||||
<filename>/dev/ad0s1b</filename>!</para></tip>
|
||||
|
||||
<para>Рекомендуемым и определённо самым простым способом автоматизации
|
||||
формирования аварийных образов является указание переменной
|
||||
<varname>dumpdev</varname> в файле &man.rc.conf.5;.</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="kerneldebug-gdb">
|
||||
<title>Отладка аварийного образа памяти ядра при помощи
|
||||
<command>kgdb</command>
|
||||
</title>
|
||||
|
||||
<note>
|
||||
<para>В этом разделе описывается утилита &man.kgdb.1;, поставляемая с
|
||||
&os; 5.3 и более поздними версиями. В предыдущих версиях
|
||||
для чтения файла аварийного дампа ядра необходимо использовать
|
||||
команду <command>gdb -k</command>.</para>
|
||||
</note>
|
||||
|
||||
<para>После извлечения дампа памяти получение из него полезной информации
|
||||
для решения простых проблем является сравнительно лёгкой задачей. Перед
|
||||
тем, как погрузиться во внутренний интерфейс &man.kgdb.1; для
|
||||
отладки аварийного образа памяти, найдите отладочную версию вашего ядра
|
||||
(обычно она имеет название <filename>kernel.debug</filename>) и выясните
|
||||
маршрут к файлам исходных текстов, использованных для построения вашего
|
||||
ядра (обычно это
|
||||
<filename>/usr/obj/usr/src/sys/<replaceable>KERNCONF</replaceable></filename>),
|
||||
где в качестве <replaceable>KERNCONF</replaceable> выступает значение
|
||||
<varname>ident</varname>, указанное конфигуратору ядра
|
||||
&man.config.5;). Имея на руках эти два параметра, начнём отладку!</para>
|
||||
|
||||
<para>Чтобы войти в отладчик и начать получать информацию из дампа,
|
||||
как минимум необходимо сделать следующие шаги:</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>Вы можете отлаживать аварийный дамп, используя исходные
|
||||
тексты ядра точно также, как вы это делаете с любой другой
|
||||
программой.</para>
|
||||
|
||||
<para>Этот первый дамп взят из ядра 5.2-BETA, а сбой произошёл где-то
|
||||
глубоко внутри ядра. Нижеследующая выдача была модифицирована, в неё
|
||||
слева добавлены номера строк. При первой трассировке проверяется
|
||||
указатель команд и выдаётся обратная трассировка. Адрес,
|
||||
используемый в строке 41 для команды <command>list</command>, является
|
||||
указателем команд и он может быть найден в строке 17. Большинство
|
||||
разработчиков будут требовать предоставления им по крайней мере этой
|
||||
информации, если вы не можете отследить проблему самостоятельно. Если,
|
||||
однако, вы решите проблему, то обязательно добейтесь включения вашего
|
||||
патча в дерево исходных текстов, прислав его через сообщение об ошибке,
|
||||
списки рассылки или даже его непосредственным коммитом!</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>Во второй трассировке используется более старый дамп из времён
|
||||
FreeBSD 2, но он более сложный и показывает больше возможностей
|
||||
<command>gdb</command>. Длинные строки были усечены ради повышения
|
||||
читабельности, а также пронумерованы для того, чтобы ссылаться на них.
|
||||
Кроме этих отличий, это реальная трассировка ошибки, выполненная в
|
||||
процессе разработки консольного драйвера pcvt.</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>Комментарии к вышеприведенному журналу:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>строка 6:</term>
|
||||
|
||||
<listitem>
|
||||
<para>Это дамп, взятый при помощи DDB (смотри ниже), поэтому
|
||||
комментарий к аварийному останову имеет именно вид <quote>because
|
||||
you said to!</quote> и трассировка стека глубока; однако
|
||||
изначальной причиной перехода в DDB была аварийная остановка при
|
||||
возникновению ошибки страницы памяти.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>строка 20:</term>
|
||||
|
||||
<listitem>
|
||||
<para>Это местонахождение функции <function>trap()</function> в
|
||||
трассировке стека.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>строка 36:</term>
|
||||
|
||||
<listitem>
|
||||
<para>Принудительное использование новой границы стека; теперь это не
|
||||
нужно. Предполагается, что границы стека указывают на
|
||||
правильное расположение, даже в случае аварийного останова. Глядя
|
||||
на строку исходного кода 403, можно сказать, что весьма вероятно,
|
||||
что либо виноват доступ по указателю <quote>tp</quote>, либо был
|
||||
выход за границы массива.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>строка 52:</term>
|
||||
|
||||
<listitem>
|
||||
<para>Похоже, что виноват указатель, но он является допустимым
|
||||
адресом.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>строка 56:</term>
|
||||
|
||||
<listitem>
|
||||
<para>Однако, очевидно, что он указывает на мусор, так что мы нашли
|
||||
нашу ошибку! (Для тех, кто не знаком с этой частью кода:
|
||||
<literal>tp->t_line</literal> служит для хранения режима
|
||||
канала консольного устройства, и это должно быть достаточно
|
||||
маленькое целое число.)</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<tip>
|
||||
<para>Если в вашей системе регулярно происходят аварийные остановы,
|
||||
и вам не хватает места на диске, удаление старых файлов
|
||||
<filename>vmcore</filename> в каталоге <filename>/var/crash</filename>
|
||||
может сэкономить вам значительный объём дискового
|
||||
пространства!</para>
|
||||
</tip>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="kerneldebug-ddd">
|
||||
<title>Отладка аварийного дампа с помощью DDD</title>
|
||||
|
||||
<para>Возможно также и исследование аварийного дампа ядра при помощи
|
||||
такого графического отладчика, как <command>ddd</command> (вам
|
||||
потребуется установить порт <filename
|
||||
role="package">devel/ddd</filename>, чтобы
|
||||
использовать отладчик <command>ddd</command>). Добавьте
|
||||
флаг <option>-k</option> к командной строке <command>ddd</command>,
|
||||
которую вы обычно используете для его вызова. Например;</para>
|
||||
|
||||
<screen>&prompt.root; <userinput>ddd -k /var/crash/kernel.0 /var/crash/vmcore.0</userinput></screen>
|
||||
|
||||
<para>После этого у вас должно получиться исследование аварийного дампа
|
||||
при помощи графического интерфейса <command>ddd</command>.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="kerneldebug-post-mortem">
|
||||
<title>Посмертный анализ дампа</title>
|
||||
|
||||
<para>Что делать, если ядро аварийно завершает работу, хотя этого вы не
|
||||
хотели и поэтому командой <command>config -g</command> его не
|
||||
компилировали? Здесь не всё ещё потеряно. Не паникуйте!</para>
|
||||
|
||||
<para>Конечно, вам нужно включить создание аварийных дампов. Смотрите
|
||||
выше, что вы должны для этого сделать.</para>
|
||||
|
||||
<para>Перейдите в каталог конфигурации ядра
|
||||
(<filename>/usr/src/sys/<replaceable>arch</replaceable>/conf</filename>)
|
||||
и отредактируйте ваш конфигурационный файл. Раскомментируйте (или
|
||||
добавьте, если она не существует) такую строку:</para>
|
||||
|
||||
<programlisting>makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols</programlisting>
|
||||
|
||||
<para>Перестройте ядро. Из-за изменения метки времени в Makefile будут
|
||||
перестроены и некоторые другие объектные файлы, например,
|
||||
<filename>trap.o</filename>. К некоторому счастью, добавление опции
|
||||
<option>-g</option> не изменит все и вся в генерируемом коде, так что
|
||||
в конце концов вы получите новое ядро с тем же кодом, что и сбоящее
|
||||
ядро, но с отладочной информацией. По крайней мере,
|
||||
вы можете сравнить старый и новый размеры ядер командой &man.size.1;.
|
||||
Если они не совпадают, то вам придется отказаться от вашей
|
||||
затеи.</para>
|
||||
|
||||
<para>Исследуйте дамп так, как это описано выше. Отладочной информации
|
||||
может не хватать в некоторых местах, как это можно видеть в трассировке
|
||||
стека примера выше, когда некоторые функции выводятся без номеров строк
|
||||
и списка аргументов. Если вам нужно больше отладочной информации,
|
||||
удалите соответствующие объектные файлы, снова перекомпилируйте ядро и
|
||||
повторите сеанс работы <command>gdb <option>-k</option></command>,
|
||||
пока не получите достаточно подробную информацию.</para>
|
||||
|
||||
<para>Не гарантируется, что всё это будет работать, однако в большинстве
|
||||
случаев всё работает прекрасно.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="kerneldebug-online-ddb">
|
||||
<title>Отладка ядра в режиме реального времени с помощью DDB</title>
|
||||
|
||||
<para>Хотя <command>gdb <option>-k</option></command> является отладчиком
|
||||
не реального времени с высокоуровневым пользовательским интерфейсом,
|
||||
есть несколько вещей, которые он сделать не сможет. Самыми важными из
|
||||
них являются точки останова и пошаговое выполнение кода ядра.</para>
|
||||
|
||||
<para>Если вам нужно выполнять низкоуровневую отладку вашего ядра, то на
|
||||
этот случай имеется отладчик реального времени, который называется DDB.
|
||||
Он позволяет устанавливать точки останова, выполнять функции ядра по
|
||||
шагам, исследовать и изменять переменные ядра и прочее. Однако он не
|
||||
может использовать исходные тексты ядра и имеет доступ только к
|
||||
глобальным и статическим символам, а не ко всей отладочной информации,
|
||||
как в <command>gdb</command>.</para>
|
||||
|
||||
<para>Чтобы отконфигурировать ваше ядро для включения DDB, добавьте
|
||||
строчку с параметром
|
||||
|
||||
<programlisting>options DDB</programlisting>
|
||||
|
||||
в ваш конфигурационный файл, и перестройте ядро. (Обратитесь к <ulink
|
||||
url="&url.books.handbook;/index.html">Руководству по FreeBSD</ulink>
|
||||
для выяснения подробностей о конфигурации ядра FreeBSD).</para>
|
||||
|
||||
<note>
|
||||
<para>Если у вас устаревшая версия загрузочных блоков,
|
||||
то отладочная информация может оказаться не загруженной. Обновите
|
||||
блоки загрузки; самые новые загружают символы для DDB
|
||||
автоматически.</para>
|
||||
</note>
|
||||
|
||||
<para>После того, как ядро с DDB запущено, есть несколько способов войти
|
||||
в DDB. Первый, и самый простой, способ заключается в наборе флага
|
||||
загрузки <option>-d</option> прямо в приглашении загрузчика. Ядро
|
||||
будет запущено в режиме отладки и войдет в DDB до выполнения процедуры
|
||||
распознавания каких бы то ни было устройств. Поэтому вы можете
|
||||
выполнить отладку даже функций распознавания/присоединения
|
||||
устройств.</para>
|
||||
|
||||
<para>Вторым способом является переход в режим отладчика сразу после
|
||||
загрузки системы. Есть два простых способа этого добиться. Если вы
|
||||
хотите перейти в отладчик из командной строки, просто наберите
|
||||
команду:</para>
|
||||
|
||||
<screen>&prompt.root; <userinput>sysctl debug.enter_debugger=ddb</userinput></screen>
|
||||
|
||||
<para>Либо, если вы работаете за системной консолью, можете
|
||||
воспользоваться определенной комбинацией клавиш. По умолчанию
|
||||
для перехода в отладчик используется комбинация <keycombo
|
||||
action="simul"><keycap>Ctrl</keycap> <keycap>Alt</keycap>
|
||||
<keycap>ESC</keycap></keycombo>. Для драйвера syscons эта
|
||||
последовательность может быть изменена, и в некоторых распространяемых
|
||||
раскладках это сделано, так что обязательно выясните правильную
|
||||
комбинацию. Для последовательных консолей имеется параметр,
|
||||
позволяющий использовать последовательность BREAK на канале консоли для
|
||||
входа в DDB (<literal>options BREAK_TO_DEBUGGER</literal> в
|
||||
конфигурационном файле ядра). По умолчанию этого не делается, так как
|
||||
существует множество последовательных адаптеров, которые ошибочно
|
||||
генерируют последовательность BREAK, к примеру, при отключении
|
||||
кабеля.</para>
|
||||
|
||||
<para>Третий способ заключается во входе в DDB при возникновении
|
||||
любой аварийной ситуации, если ядро его использует. По этой причине
|
||||
не очень умно конфигурировать ядро с DDB для машины, которая работает
|
||||
без присмотра.</para>
|
||||
|
||||
<para>Команды DDB примерно повторяют некоторые команды
|
||||
<command>gdb</command>. Первым делом вам, наверное, нужно задать точку
|
||||
останова:</para>
|
||||
|
||||
<screen>
|
||||
<userinput>b function-name</userinput>
|
||||
<userinput>b address</userinput>
|
||||
</screen>
|
||||
|
||||
<para>Значения по умолчанию воспринимаются в шестнадцатеричном виде, но
|
||||
чтобы отличать их от имен символов; шестнадцатеричные числа,
|
||||
начинающиеся с букв <literal>a-f</literal>, должны предваряться
|
||||
символами <literal>0x</literal> (это опционально для других чисел).
|
||||
Разрешены простые выражения, например:
|
||||
<literal>function-name + 0x103</literal>.</para>
|
||||
|
||||
<para>Чтобы продолжить работу прерванного ядра, просто наберите:</para>
|
||||
|
||||
<screen><userinput>c</userinput></screen>
|
||||
|
||||
<para>Чтобы получить трассировку стека, задайте:</para>
|
||||
|
||||
<screen><userinput>trace</userinput></screen>
|
||||
|
||||
<note>
|
||||
<para>Заметьте, что при входе в DDB по специальной комбинации, ядро
|
||||
в данный момент обслуживает прерывание, так что трассировка стека
|
||||
может не дать вам много информации.</para>
|
||||
</note>
|
||||
|
||||
<para>Если вы хотите убрать точку останова, введите</para>
|
||||
|
||||
<screen>
|
||||
<userinput>del</userinput>
|
||||
<userinput>del address-expression</userinput>
|
||||
</screen>
|
||||
|
||||
<para>В первом варианте команда будет исполнена сразу же по достижении
|
||||
точки останова, а текущая точка останова будет удалена. Во второй
|
||||
форме можно удалить любую точку останова, однако вам нужно будет
|
||||
указать ее точный адрес; его можно получить из:</para>
|
||||
|
||||
<screen><userinput>show b</userinput></screen>
|
||||
|
||||
<para>Чтобы выполнить один шаг ядра, попробуйте:</para>
|
||||
|
||||
<screen><userinput>s</userinput></screen>
|
||||
|
||||
<para>При этом будет осуществляться пошаговое выполнение функций, однако
|
||||
вы можете трассировать их с помощью DDB, пока не будет достигнуто
|
||||
соответствие возвращаемому значению:</para>
|
||||
|
||||
<screen><userinput>n</userinput></screen>
|
||||
|
||||
<note>
|
||||
<para>Это отличается от команды <command>next</command> отладчика
|
||||
<command>gdb</command>; это похоже на команду <command>gdb</command>
|
||||
<command>finish</command>.</para>
|
||||
</note>
|
||||
|
||||
<para>Чтобы выводить значения в памяти, используйте, (к примеру):
|
||||
|
||||
<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>
|
||||
|
||||
для доступа к данным типа слово/полуслово/байт и вывода в
|
||||
шестнадцатеричном/десятичном/символьном виде. Число после запятой
|
||||
означает счетчик объектов. Чтобы вывести следующие 0x10 объектов,
|
||||
просто укажите:</para>
|
||||
|
||||
<screen><userinput>x ,10</userinput></screen>
|
||||
|
||||
<para>Подобным же образом используйте
|
||||
|
||||
<screen><userinput>x/ia foofunc,10</userinput></screen>
|
||||
|
||||
для дизассемблирования и вывода первых 0x10 инструкций функции
|
||||
<function>foofunc</function> вместе с их адресом относительно
|
||||
начала <function>foofunc</function>.</para>
|
||||
|
||||
<para>Чтобы изменить значения в памяти, используйте команду write:</para>
|
||||
|
||||
<screen>
|
||||
<userinput>w/b termbuf 0xa 0xb 0</userinput>
|
||||
<userinput>w/w 0xf0010030 0 0</userinput>
|
||||
</screen>
|
||||
|
||||
<para>Модификатор команды
|
||||
(<literal>b</literal>/<literal>h</literal>/<literal>w</literal>)
|
||||
указывает на размер записываемых данных, первое следующее за ним
|
||||
выражение является адресом для записи, а оставшаяся часть
|
||||
интерпретируется как данные для записи в доступные области
|
||||
памяти.</para>
|
||||
|
||||
<para>Если вам нужно узнать текущее содержимое регистров,
|
||||
используйте:</para>
|
||||
|
||||
<screen><userinput>show reg</userinput></screen>
|
||||
|
||||
<para>Альтернативно вы можете вывести содержимое одного регистра по
|
||||
команде, скажем,
|
||||
|
||||
<screen><userinput>p $eax</userinput></screen>
|
||||
|
||||
и изменить его по:</para>
|
||||
|
||||
<screen><userinput>set $eax new-value</userinput></screen>
|
||||
|
||||
<para>Если вам нужно вызвать некоторую функцию ядра из DDB, просто
|
||||
укажите:</para>
|
||||
|
||||
<screen><userinput>call func(arg1, arg2, ...)</userinput></screen>
|
||||
|
||||
<para>Будет выведено возвращаемое значение.</para>
|
||||
|
||||
<para>Для вывода суммарной статистики по всем работающим процессам в
|
||||
стиле команды &man.ps.1; воспользуйтесь такой командой:</para>
|
||||
|
||||
<screen><userinput>ps</userinput></screen>
|
||||
|
||||
<para>Теперь вы узнали, почему ядро работает с ошибками и хотите
|
||||
выполнить перезагрузку. Запомните, что в зависимости от влияния
|
||||
предыдущих ошибок, не все части ядра могут работать так, как ожидается.
|
||||
Выполните одно из следующих действий для закрытия и перезагрузки вашей
|
||||
системы:</para>
|
||||
|
||||
<screen><userinput>panic</userinput></screen>
|
||||
|
||||
<para>Это приведет к созданию дампа ядра и перезагрузке, так что позже
|
||||
вы можете проанализировать дамп на более высоком уровне при помощи
|
||||
<command>gdb</command>. Как правило, эта команда должна следовать за
|
||||
другой командой <command>continue</command>.</para>
|
||||
|
||||
<screen><userinput>call boot(0)</userinput></screen>
|
||||
|
||||
<para>Это может оказаться хорошим способом для корректного закрытия
|
||||
работающей системы, <function>sync()</function> для всех дисков и
|
||||
напоследок перезагрузка. Пока интерфейсы диска и файловой системы
|
||||
в ядре не повреждены, это может быть самым правильным способом закрытия
|
||||
системы.</para>
|
||||
|
||||
<screen><userinput>call cpu_reset()</userinput></screen>
|
||||
|
||||
<para>Это последнее средство при аварии и практически то же самое, что
|
||||
нажатие Большой Красной Кнопки.</para>
|
||||
|
||||
<para>Если вам нужен краткий справочник по командам, просто
|
||||
наберите:</para>
|
||||
|
||||
<screen><userinput>help</userinput></screen>
|
||||
|
||||
<para>Однако настоятельно рекомендуем отпечатать копию страницы
|
||||
справочника по &man.ddb.4; при подготовке к сеансу отладки. Помните,
|
||||
что трудно читать онлайновое руководство при пошаговом выполнении
|
||||
ядра.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="kerneldebug-online-gdb">
|
||||
<title>Отладка ядра в режиме реального времени при помощи удалённого
|
||||
GDB</title>
|
||||
|
||||
<para>Эта возможность поддерживается во FreeBSD начиная с версии 2.2,
|
||||
и она на самом деле очень удобна.</para>
|
||||
|
||||
<para>В GDB уже давно имеется поддержка <emphasis>удаленной
|
||||
отладки</emphasis>. Это делается при помощи весьма простого протокола
|
||||
по последовательному каналу. В отличие от других методов, описанных
|
||||
выше, для этого вам требуется наличие двух машин. Одна из них является
|
||||
хостом, предоставляющим ресурсы для отладки, включая все исходные
|
||||
тексты и копию ядра со всеми символами в нем, а другая является целевой
|
||||
машиной, на которой запущена та же копия того же ядра (но без
|
||||
отладочной информации).</para>
|
||||
|
||||
<para>Вы должны настроить исследуемое ядро при помощи команды
|
||||
<command>config -g</command>, включить <option>DDB</option> в
|
||||
конфигурацию и откомпилировать его обычным образом. Это даст большой
|
||||
бинарный файл из-за отладочной информации.
|
||||
Скопируйте это ядро на целевую машину, усеките отладочную информацию
|
||||
командой <command>strip -x</command> и загрузите это ядро с
|
||||
использованием параметра загрузки <option>-d</option>. Подключите
|
||||
последовательный канал целевой машины, имеющий установленные флаги
|
||||
"flags 080" на соответствующем устройстве sio к любому
|
||||
последовательному каналу отладочного хоста. А теперь на отладочной
|
||||
машине перейдите в каталог компиляции целевого ядра и запустите
|
||||
<command>gdb</command>:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>gdb -k 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>Проинициализируйте сеанс удаленной отладки (предполагается, что
|
||||
используется первый последовательный порт) такой командой:</para>
|
||||
|
||||
<screen>
|
||||
<prompt>(kgdb)</prompt> <userinput>target remote /dev/cuaa0</userinput>
|
||||
</screen>
|
||||
|
||||
<para>Теперь на целевом хосте (тот, который перешел в DDB даже до
|
||||
начала процесса обнаружения устройств) наберите:</para>
|
||||
|
||||
<screen>
|
||||
Debugger("Boot flags requested debugger")
|
||||
Stopped at Debugger+0x35: movb $0, edata+0x51bc
|
||||
<prompt>db></prompt> <userinput>gdb</userinput>
|
||||
</screen>
|
||||
|
||||
<para>DDB ответит следующим:</para>
|
||||
|
||||
<screen>Next trap will enter GDB remote protocol mode</screen>
|
||||
|
||||
<para>Каждый раз, когда вы будете набирать <command>gdb</command>, режим
|
||||
будет меняться между удаленным GDB и локальным DDB. Чтобы немедленно
|
||||
вызвать следующее прерывание, просто наберите <command>s</command>
|
||||
(step). Ваш хостирующий GDB получит управление над целевым
|
||||
ядром:</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>Вы можете работать в этом сеансе точно также, как и в любом другом
|
||||
сеансе GDB, включая полный доступ к исходным текстам, запуск его в
|
||||
режиме gud-mode внутри окна Emacs (что даёт вам автоматический вывод
|
||||
исходного кода в другом окне Emacs) и тому подобное.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="kerneldebug-kld">
|
||||
<title>Отладка загружаемых модулей с помощью GDB</title>
|
||||
|
||||
<para>При отладке аварийного останова системы, которое произошло в модуле,
|
||||
или при использовании GDB в режиме удаленного доступа к машине,
|
||||
использующей динамические модули, вам нужно указать GDB, как получить
|
||||
информацию о символах в этих модулях.</para>
|
||||
|
||||
<para>Первым делом вам нужно построить модуль (или модули) с включением
|
||||
отладочной информации:</para>
|
||||
|
||||
<screen>&prompt.root; <userinput>cd /sys/modules/linux</userinput>
|
||||
&prompt.root; <userinput>make clean; make COPTS=-g</userinput></screen>
|
||||
|
||||
<para>Если вы используете GDB в режиме удаленного доступа, то для
|
||||
определения того, куда был загружен модуль, можете запустить
|
||||
команду <command>kldstat</command> на целевой машине:</para>
|
||||
|
||||
<screen>&prompt.root; <userinput>kldstat</userinput>
|
||||
Id Refs Address Size Name
|
||||
1 4 0xc0100000 1c1678 kernel
|
||||
2 1 0xc0a9e000 6000 linprocfs.ko
|
||||
3 1 0xc0ad7000 2000 warp_saver.ko
|
||||
4 1 0xc0adc000 11000 linux.ko</screen>
|
||||
|
||||
<para>Если вы отлаживаете аварийный дамп, вам потребуется просмотреть
|
||||
список <literal>linker_files</literal> начиная с
|
||||
<literal>linker_files->tqh_first</literal> и следовать указателям
|
||||
<literal>link.tqe_next</literal> до тех пор, пока не найдете запись
|
||||
с тем <literal>filename</literal>, который вы ищете. Элемент
|
||||
<literal>address</literal> этой записи является адресом загрузки
|
||||
модуля.</para>
|
||||
|
||||
<para>Затем вам нужно определить смещение текстового сегмента
|
||||
модуля:</para>
|
||||
|
||||
<screen>&prompt.root; <userinput>objdump --section-headers /sys/modules/linux/linux.ko | grep text</userinput>
|
||||
3 .rel.text 000016e0 000038e0 000038e0 000038e0 2**2
|
||||
10 .text 00007f34 000062d0 000062d0 000062d0 2**2</screen>
|
||||
|
||||
<para>То, что вы ищете, является секцией <literal>.text</literal>, в
|
||||
примере выше это секция 10. Четвертое числовое поле (всего шестое по
|
||||
счёту) является смещением текстовой секции внутри файла. Добавьте это
|
||||
смещение к адресу загрузки, чтобы получить адрес, на который был
|
||||
перемещён код модуля. В нашем примере мы получим
|
||||
0xc0adc000 + 0x62d0 = c0ae22d0. Воспользуйтесь командой
|
||||
<command>add-symbol-file</command> в GDB для указания отладчику
|
||||
на модуль:</para>
|
||||
|
||||
<screen><prompt>(kgdb)</prompt> <userinput>add-symbol-file /sys/modules/linux/linux.ko 0xc0ae22d0</userinput>
|
||||
add symbol table from file "/sys/modules/linux/linux.ko" at text_addr = 0xc0ae22d0?
|
||||
(y or n) <userinput>y</userinput>
|
||||
Reading symbols from /sys/modules/linux/linux.ko...done.
|
||||
<prompt>(kgdb)</prompt></screen>
|
||||
|
||||
<para>Теперь вы должны получить доступ ко всем символам в модуле.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="kerneldebug-console">
|
||||
<title>Отладка драйвера консоли</title>
|
||||
|
||||
<para>Так как для работы DDB вам требуется драйвер консоли, то в случае
|
||||
неисправностей самого драйвера консоли все становится гораздо сложнее.
|
||||
Вы можете вспомнить об использовании последовательной консоли (либо с
|
||||
исправленными загрузочными блоками, либо при указании флага
|
||||
<option>-h</option> в приглашении <prompt>Boot:</prompt>) и подключить
|
||||
обычный терминал к первому последовательному порту. DDB работает с
|
||||
любым отконфигурированным драйвером консоли, в том числе с
|
||||
последовательной консолью.</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: sgml
|
||||
sgml-declaration: "../chapter.decl"
|
||||
sgml-indent-data: t
|
||||
sgml-omittag: nil
|
||||
sgml-always-quote-attributes: t
|
||||
sgml-parent-document: ("../book.sgml" "part" "chapter")
|
||||
End:
|
||||
-->
|
Loading…
Reference in a new issue