The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Руководства по FreeBSD на русском" / Оглавление документа

Chapter 10 Отладка ядра

Table of Contents
10.1 Отладка аварийных образов ядра при помощи gdb
10.2 Отладка аварийного дампа с помощью DDD
10.3 Посмертный анализ дампа
10.4 Отладка ядра в режиме реального времени с помощью DDB
10.5 Отладка ядра в режиме реального времени при помощи удалённого GDB
10.6 Отладка загружаемых модулей с помощью GDB
10.7 Отладка драйвера консоли

Текст предоставили Paul Richards и Jörg Wunsch

10.1 Отладка аварийных образов ядра при помощи gdb

Вот некоторые указания по работе с отладкой ядра с аварийными дампами памяти. Как правило, вам нужно будет задать одно из устройств подкачки, перечисленных в файле /etc/fstab. Сброс образов памяти на устройства, не являющиеся устройствами подкачки, например, ленты, в данный момент не поддерживаются.

Note: Используйте команду dumpon(8) для указания ядру места, где нужно сохранять аварийные дампы. После настройки по команде swapon(8) раздела подкачки должна быть вызвана программа dumpon. Обычно это выполняется заданием переменной dumpdev в файле rc.conf(5). Если задана эта переменная, то после сбоя при первой многопользовательской перезагрузке будет автоматически запущена программа savecore(8). Она сохранит аварийный дамп ядра в каталог, заданный в переменной dumpdir файла rc.conf. По умолчанию каталогом для аварийных дампов является /var/crash.

Либо вы можете задать устройство для сброса образа памяти явно через параметр dump в строке config конфигурационного файла вашего ядра. Такой способ использовать не рекомендуется и он должен использоваться, только если вы хотите получать аварийные образы памяти ядра, которое аварийно завершает свою работу при загрузке.

Note: Далее термин gdb означает отладчик gdb, запущенный в ``режиме отладки ядра''. Переход в этот режим достигается запуском gdb с параметром -k. В режиме отладки ядра gdb изменяет своё приглашение на (kgdb).

Tip: Если вы используете FreeBSD версии 3 или более раннюю, вы должны выполнить усечение отладочного ядра командой strip, а не устанавливать большое отладочное ядро:

# cp kernel kernel.debug
# strip -g kernel

Этот шаг не так уж и необходим, но рекомендуем. (Во FreeBSD 4 и более поздних релизах этот шаг выполняется автоматически в конце процесса построения ядра make.) Когда ядро усечено, автоматически или при помощи команд выше, вы можете установить его обычным образом, набрав make install.

Заметьте, что в старых версиях FreeBSD (до 3.1, не включая этот релиз), используется ядра в формате a.out, поэтому их таблицы символов должны располагаться постоянно в памяти. С большой таблицей символов в не усеченном отладочном ядре это излишняя трата. Последние релизы FreeBSD используют ядра в формате ELF, где это не является проблемой.

Если вы тестируете новое ядро, скажем, набирая имя нового ядра в приглашении загрузчика, но вам нужно загружать и работать с другим ядром, чтобы снова вернуться к нормальному функционированию, загружайте его только в однопользовательском режиме при помощи флага -s, указываемого при загрузке, а затем выполните такие шаги:

# fsck -p
# mount -a -t ufs      # so your filesystem for /var/crash is writable
# savecore -N /kernel.panicked /var/crash
# exit          # ...to multi-user
   

Эта последовательность указывает программе savecore(8) на использование другого ядра для извлечения символических имен. Иначе она будет использовать ядро, работающее в данный момент и, скорее всего, ничего не сделает, потому что аварийный образ памяти и символы ядра будут отличаться.

А теперь, после сброса аварийного дампа, перейдите в каталог /sys/compile/WHATEVER и запустите команду gdb -k. Из программы gdb сделайте вот что:

symbol-file kernel.debug
exec-file /var/crash/kernel.0
core-file /var/crash/vmcore.0
и вуаля - вы можете отлаживать аварийный дамп, используя исходные тексты ядра точно также, как вы это делаете с любой другой программой.

Вот журнал команд сеанса работы gdb, иллюстрирующий эту процедуру. Длинные строки были разорваны для улучшения читабельности и для удобства строки были пронумерованы. Все остальное является трассировкой ошибки, реально возникнувшей во время работы над драйвером консоли pcvt.

 1:Script started on Fri Dec 30 23:15:22 1994
 2:# cd /sys/compile/URIAH
 3:# gdb -k kernel /var/crash/vmcore.1
 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:(kgdb) where
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:(kgdb) up 10
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:(kgdb) frame frame->tf_ebp frame->tf_eip
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:(kgdb) list
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:(kgdb) print tp
53:Reading in symbols for ../../i386/i386/cons.c...done.
54:$1 = (struct tty *) 0x1bae
55:(kgdb) print tp->t_line
56:$2 = 1767990816
57:(kgdb) up
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:(kgdb) up
62:#2  0xf0132c34 in spec_open ()
63:(kgdb) up
64:#3  0xf012d014 in vn_open ()
65:(kgdb) up
66:#4  0xf012a183 in open ()
67:(kgdb) up
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:(kgdb) up
75:Initial frame selected; you cannot go up.
76:(kgdb) quit
77:# exit
78:exit
79:
80:Script done on Fri Dec 30 23:18:04 1994

Комментарии к вышеприведенному журналу:

строка 6:

Это дамп, взятый при помощи DDB (смотри ниже), поэтому комментарий к аварийному останову имеет именно вид ``because you said to!'' и трассировка стека глубока; однако изначальной причиной перехода в DDB была аварийная остановка при возникновению ошибки страницы памяти.

строка 20:

Это местонахождение функции trap() в трассировке стека.

строка 36:

Принудительное использование новой границы стека; теперь это не нужно. Предполагается, что границы стека указывают на правильное расположение, даже в случае аварийного останова. Глядя на строку исходного кода 403, можно сказать, что весьма вероятно, что либо виноват доступ по указателю ``tp'', либо был выход за границы массива.

строка 52:

Похоже, что виноват указатель, но он является допустимым адресом.

строка 56:

Однако, очевидно, что он указывает на мусор, так что мы нашли нашу ошибку! (Для тех, кто не знаком с этой частью кода: tp->t_line служит для хранения режима канала консольного устройства, и это должно быть достаточно маленькое целое число.)

Этот, и другие документы, могут быть скачаны с ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

По вопросам связанными с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.
По вопросам связанным с этой документацией, пишите <doc@FreeBSD.org>.
По вопросам связанным с русским переводом документации, пишите <frdp@FreeBSD.org.ua>.




Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2020 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру