# mkdir /var/crash
# chmod 700 /var/crash
Глава 10. Отладка ядра
Этот перевод может быть устаревшим. Для того, чтобы помочь с переводом, пожалуйста, обратитесь к Сервер переводов FreeBSD.
Содержание
10.1. Получение аварийного дампа ядра
При работе с разрабатываемым ядром (например, FreeBSD-CURRENT), особенно в экстремальных условиях (например, при очень высокой загрузке, десятках тысяч соединений, чрезвычайно большом количестве одновременных пользователей, сотнях jail(8) и т.д.), или при использовании новой функции или драйвера устройства в FreeBSD-STABLE (например, PAE), иногда может возникнуть паника ядра. В случае, если это произойдет, данная глава покажет, как извлечь полезную информацию из аварийного дампа.
Перезагрузка системы неизбежна после паники ядра. После перезагрузки системы содержимое физической памяти (RAM) теряется, как и любые данные на устройстве подкачки перед паникой. Чтобы сохранить данные в физической памяти, ядро использует устройство подкачки как временное хранилище для данных из RAM после сбоя и перезагрузки. Благодаря этому, когда FreeBSD загружается после сбоя, образ ядра может быть извлечен и проведена отладка.
Устройство подкачки, настроенное как устройство для дампа, продолжает функционировать как устройство подкачки. В настоящее время дампы на устройства, не являющиеся устройствами подкачки (например, на ленты или CDRW), не поддерживаются. Термин "устройство подкачки" является синонимом термина "раздел подкачки". |
Есть несколько типов аварийных дампов ядра:
- Полные дампы памяти
Содержат полное содержимое физической памяти.
- Минидампы
Содержат только страницы памяти, используемые ядром (FreeBSD 6.2 и выше).
- Текстовые дампы
Содержать захваченные, записанные или интерактивные выходные данные отладчика (FreeBSD 7.1 и выше).
Минидампы являются типом дампа по умолчанию, начиная с FreeBSD 7.0, и в большинстве случаев они сохраняют всю необходимую информацию, присутствующую в полном дампе памяти, так как большинство проблем можно изолировать, используя только состояние ядра.
10.1.1. Настройка устройства дампа
Прежде чем ядро запишет содержимое своей физической памяти на устройство дампа, необходимо настроить это устройство. Устройство дампа указывается с помощью команды dumpon(8), чтобы сообщить ядру, куда сохранять аварийные дампы. Программа dumpon(8) должна быть вызвана после настройки раздела подкачки с помощью swapon(8). Обычно это обрабатывается установкой переменной dumpdev
в rc.conf(5) в путь к устройству подкачки (рекомендуемый способ извлечения дампа ядра) или в значение AUTO
для использования первого настроенного устройства подкачки. По умолчанию dumpdev
имеет значение AUTO
в HEAD и изменено на NO
в ветках RELENG_* (за исключением RELENG_7, где оставлено значение AUTO
). Начиная с FreeBSD 9.0-RELEASE и более поздних версий, bsdinstall будет спрашивать, следует ли включить аварийные дампы на целевой системе во время процесса установки.
Проверьте /etc/fstab или swapinfo(8) для получения списка устройств подкачки. |
Убедитесь, что каталог Также помните, что содержимое /var/crash является конфиденциальным и, скорее всего, содержит секретную информацию, такую как пароли. |
10.1.2. Извлечение дампа ядра
После записи дампа на устройство дампа, дамп должен быть извлечен до монтирования устройства подкачки. Для извлечения дампа с устройства дампа используйте программу savecore(8). Если в rc.conf(5) установлен параметр dumpdev
, savecore(8) будет автоматически вызван при первой загрузке в многопользовательском режиме после сбоя и до монтирования устройства подкачки. Расположение извлеченного ядра указывается в параметре dumpdir
файла rc.conf(5), по умолчанию это /var/crash, а имя файла будет vmcore.0.
В случае, если файл с именем vmcore.0 уже существует в /var/crash (или в каталоге, указанном в параметре dumpdir
), ядро будет увеличивать завершающее число при каждом сбое, чтобы избежать перезаписи существующего файла vmcore (например, vmcore.1). savecore(8) всегда создает символическую ссылку с именем vmcore.last в /var/crash после сохранения дампа. Эта символическая ссылка может быть использована для определения имени последнего дампа.
Утилита crashinfo(8) создаёт текстовый файл, содержащий сводную информацию из полного дампа памяти или минидампа. Если параметр dumpdev
установлен в rc.conf(5), crashinfo(8) будет автоматически вызван после savecore(8). Результат сохраняется в файл с именем core.txt.N в директории dumpdir
.
Если вы тестируете новое ядро, но вам нужно загрузить другое, чтобы снова запустить систему, загрузите его только в однопользовательском режиме, используя флаг
Это указывает savecore(8) извлечь дамп ядра из /dev/ad0s1b и поместить содержимое в /var/crash. Не забудьте убедиться, что целевой каталог /var/crash имеет достаточно места для дампа. Также не забудьте указать правильный путь к вашему swap-устройству, так как он, скорее всего, отличается от /dev/ad0s1b! |
10.1.3. Тестирование конфигурации дампа ядра
Ядро включает узел sysctl(8), который вызывает панику ядра. Это можно использовать для проверки того, что ваша система правильно настроена для сохранения дампов аварийного завершения работы ядра. Возможно, вы захотите перемонтировать существующие файловые системы в режиме только для чтения в однопользовательском режиме перед тем, как вызвать панику, чтобы избежать потери данных.
# shutdown now
...
Enter full pathname of shell or RETURN for /bin/sh:
# mount -a -u -r
# sysctl debug.kdb.panic=1
debug.kdb.panic:panic: kdb_sysctl_panic
...
После перезагрузки система должна сохранить дамп в /var/crash вместе с соответствующим отчетом из crashinfo(8).
10.2. Отладка аварийного дампа ядра с помощью kgdb
Чтобы войти в отладчик и начать получение информации из дампа, запустите kgdb:
# kgdb -n N
Где N — это суффикс файла vmcore.N, который нужно изучить. Чтобы открыть последний дамп, используйте:
# kgdb -n last
Обычно kgdb(1) должен быть способен найти ядро, работавшее в момент создания дампа. Если он не может найти нужное ядро, передайте путь к ядру и дампу в качестве двух аргументов для kgdb:
# kgdb /boot/kernel/kernel /var/crash/vmcore.0
Вы можете отлаживать дамп аварийного завершения, используя исходные коды ядра, так же, как и для любой другой программы.
Этот дамп получен из ядра версии 5.2-BETA, а крах произошел глубоко внутри ядра. Приведенный ниже вывод был изменен для добавления номеров строк слева. Первый трассировочный вывод проверяет указатель инструкции и получает обратную трассировку. Адрес, используемый в строке 41 для команды list
, является указателем инструкции и может быть найден в строке 17. Большинство разработчиков запросят как минимум эту информацию, если вы не сможете отладить проблему самостоятельно. Однако, если вы решите проблему, убедитесь, что ваш патч попадет в дерево исходников через отчет о проблеме, списки рассылки, или, может быть, у вас есть возможность его закоммитить!
1:# cd /usr/obj/usr/src/sys/KERNCONF
2:# kgdb kernel.debug /var/crash/vmcore.0
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:(kgdb) list *0xc0713860
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:(kgdb) backtrace
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:(kgdb) quit
Если ваша система регулярно завершается аварийно и у вас заканчивается место на диске, удаление старых файлов vmcore в /var/crash может освободить значительное количество дискового пространства! |
10.3. Онлайн-отладка ядра с использованием DDB
В то время как kgdb
как автономный отладчик предоставляет очень высокий уровень пользовательского интерфейса, есть некоторые вещи, которые он не может выполнить. Наиболее важные из них — установка точек останова и пошаговое выполнение кода ядра.
Если вам требуется выполнить низкоуровневую отладку ядра, доступен отладчик DDB, работающий в режиме реального времени. Он позволяет устанавливать точки останова, выполнять пошаговое выполнение функций ядра, проверять и изменять переменные ядра и т.д. Однако он не имеет доступа к исходным файлам ядра и работает только с глобальными и статическими символами, без доступа к полной отладочной информации, как это делает kgdb
.
Для настройки ядра с включенной поддержкой DDB добавьте параметры
options KDB
options DDB
в ваш конфигурационный файл, и пересоберите. (Подробности о настройке ядра FreeBSD см. в Руководстве FreeBSD).
После загрузки ядра DDB существует несколько способов войти в него. Первый и самый ранний способ — использовать флаг загрузки -d
. Ядро запустится в режиме отладки и перейдет в DDB до начала обнаружения любого из устройств. Таким образом, можно отлаживать даже функции обнаружить (probe)/ присоединить (attach) устройств. Для использования этого метода выйдите из меню загрузки загрузчика и введите boot -d
в командной строке загрузчика.
Второй сценарий — перейти в отладчик после загрузки системы. Есть два простых способа это сделать. Если вы хотите перейти в отладчик из командной строки, просто введите команду:
# sysctl debug.kdb.enter=1
В качестве альтернативы, если вы находитесь за системной консолью, можно использовать горячую клавишу на клавиатуре. Стандартной комбинацией для перехода в отладчик является Ctrl+Alt+ESC. В syscons эта последовательность может быть переназначена, и некоторые распространённые раскладки клавиатуры делают это, поэтому убедитесь, что знаете правильную комбинацию. Для последовательных консолей доступна опция, позволяющая использовать сигнал BREAK на линии консоли для входа в DDB (options BREAK_TO_DEBUGGER
в конфигурационном файле ядра). Это не установлено по умолчанию, так как существует множество последовательных адаптеров, которые излишне генерируют условие BREAK, например, при отключении кабеля.
Третий способ заключается в том, чтобы любое условие паники переходило в DDB, если ядро настроено на его использование. По этой причине не рекомендуется настраивать ядро с DDB для машины, работающей без присмотра.
Для получения неинтерактивной функциональности добавьте:
options KDB_UNATTENDED
в файл конфигурации ядра и пересоберите/переустановите ядро.
Команды DDB примерно напоминают некоторые команды gdb
. Первое, что вам, вероятно, нужно сделать, это установить точку останова:
break function-name address
Числа по умолчанию интерпретируются как шестнадцатеричные, но чтобы отличить
их от символьных имен, шестнадцатеричные числа, начинающиеся с букв a-f
,
должны предваряться префиксом 0x
(для остальных чисел это
необязательно). Допускаются простые выражения, например: function-name
.
0x103
Для выхода из отладчика и продолжения выполнения введите:
continue
Для получения трассировки стека текущего потока используйте:
trace
Для получения трассировки стека произвольного потока укажите идентификатор процесса или идентификатор потока в качестве второго аргумента команды trace
.
Если вы хотите удалить точку останова, используйте
del
del address-expression
Первая форма будет принята сразу после срабатывания точки останова и удаляет текущую точку останова. Вторая форма может удалить любую точку останова, но необходимо указать точный адрес; его можно получить из:
show b
или:
show break
Для пошагового выполнения ядра попробуйте:
s
Это позволит войти в функции, но вы можете заставить DDB отслеживать их до достижения соответствующего оператора return с помощью:
n
Это отличается от оператора |
Для просмотра данных в памяти используйте (например):
x/wx 0xf0133fe0,40
x/hd db_symtab_space
x/bc termbuf,10
x/s stringbuf
для доступа к словам/полусловам/байтам и отображения в шестнадцатеричном/десятичном/символьном/строковом формате. Число после запятой указывает количество объектов. Для отображения следующих 0x10 элементов просто введите:
x ,10
Аналогично, используйте
x/ia foofunc,10
для дизассемблирования первых 0x10 инструкций функции foofunc
и их отображения вместе с их смещением от начала foofunc
.
Для записи в память используйте команду write:
w/b termbuf 0xa 0xb 0
w/w 0xf0010030 0 0
Модификатор команды (b
/h
/w
) определяет размер данных для записи, первое следующее выражение — это адрес для записи, а остальное интерпретируется как данные для записи в последующие ячейки памяти.
Если вам необходимо узнать текущее содержимое регистров, введите:
show reg
Также можно отобразить значение одного регистра, например:
p $eax
и изменить его с помощью:
set $eax new-value
Если вам потребуется вызвать некоторые функции ядра из DDB, просто напишите:
call func(arg1, arg2, ...)
Будет выведено возвращаемое значение.
Для вывода информации о всех запущенных процессах в стиле ps(1) используйте:
ps
Теперь вы выяснили причину сбоя ядра и хотите выполнить перезагрузку. Помните, что в зависимости от серьезности предыдущего сбоя не все части ядра могут работать корректно. Выполните одно из следующих действий для завершения работы и перезагрузки системы:
panic
Это приведёт к дампу ядра и перезагрузке, чтобы позже можно было проанализировать дамп на более высоком уровне с помощью kgdb(1).
call boot(0)
Может быть хорошим способом чисто завершить работу работающей системы, sync()
все диски и, наконец, в некоторых случаях перезагрузиться. Пока интерфейсы дисков и файловых систем ядра не повреждены, это может быть хорошим способом для почти чистого завершения работы.
reset
Это последний способ избежать катастрофы, и он почти такой же, как нажатие на Большую Красную Кнопку.
Если вам нужна краткая сводка команд, просто введите:
help
Настоятельно рекомендуется иметь распечатанную копию страницы руководства ddb(4) для сеанса отладки. Помните, что читать онлайн-руководство во время пошагового выполнения ядра сложно.
10.4. Онлайн-отладка ядра с использованием удаленного GDB
Ядро FreeBSD предоставляет второй бэкенд KDB для отладки в реальном времени: gdb(4). Эта возможность поддерживается с FreeBSD 2.2 и является действительно очень удобной.
GDB давно поддерживает удалённую отладку. Это осуществляется с помощью очень простого протокола через последовательное соединение. В отличие от других методов отладки, описанных выше, для этого потребуются две машины. Одна — это хост, предоставляющий среду отладки, включая все исходные тексты и копию бинарного файла ядра со всеми символами. Другая — целевая машина, на которой запущена копия того же самого ядра (возможно, без отладочной информации).
Чтобы использовать удалённый GDB, убедитесь, что следующие параметры присутствуют в конфигурации вашего ядра:
makeoptions DEBUG=-g options KDB options GDB
Обратите внимание, что опция GDB
отключена по умолчанию в ядрах GENERIC
для веток -STABLE и -RELEASE, но включена в -CURRENT.
После сборки скопируйте ядро на целевую машину и загрузите его. Подключите последовательный порт целевой машины, у которого на устройстве uart установлены флаги "080", к любому последовательному порту отладочной машины. Подробности о настройке флагов на устройстве uart смотрите в uart(4).
Целевая машина должна быть переведена в режим отладчика GDB, либо из-за паники, либо путем преднамеренного перехода в отладчик. Перед этим выберите бэкенд отладчика GDB:
# sysctl debug.kdb.current=gdb
debug.kdb.current: ddb -> gdb
Поддерживаемые бэкенды можно вывести с помощью sysctl |
Затем принудительно войдите в отладчик:
# sysctl debug.kdb.enter=1
debug.kdb.enter: 0KDB: enter: sysctl debug.kdb.enter
Целевая машина теперь ожидает подключения от удалённого клиента GDB. На машине для отладки перейдите в каталог сборки целевого ядра и запустите gdb
:
# cd /usr/obj/usr/src/amd64.amd64/sys/GENERIC/
# kgdb kernel
GNU gdb (GDB) 10.2 [GDB v10.2 for FreeBSD]
Copyright (C) 2021 Free Software Foundation, Inc.
...
Reading symbols from kernel...
Reading symbols from /usr/obj/usr/src/amd64.amd64/sys/GENERIC/kernel.debug...
(kgdb)
Инициализируйте сеанс удаленной отладки (предполагая, что используется первый последовательный порт) с помощью:
(kgdb) target remote /dev/cuau0
Ваш хостинг GDB теперь получит контроль над целевым ядром:
Remote debugging using /dev/cuau0
kdb_enter (why=<optimized out>, msg=<optimized out>) at /usr/src/sys/kern/subr_kdb.c:506
506 kdb_why = KDB_WHY_UNSET;
(kgdb)
В зависимости от используемого компилятора, некоторые локальные переменные могут отображаться как |
Вы можете использовать этот сеанс почти как любой другой сеанс GDB, включая полный доступ к исходному коду, запуск в режиме gud (Grand Unified Debugger) внутри окна Emacs (что дает автоматическое отображение исходного кода в другом окне Emacs) и т.д.
10.5. Отладка драйвера консоли
Поскольку для работы DDB требуется драйвер консоли, ситуация усложняется, если сам драйвер консоли неисправен. Возможно, вы вспомните о возможности использования последовательной консоли (либо с модифицированными загрузочными блоками, либо указав -h
в строке Boot:
), подключив стандартный терминал к первому последовательному порту. DDB работает с любым настроенным драйвером консоли, включая последовательную консоль.
10.6. Отладка взаимоблокировок
Вы можете столкнуться с так называемыми взаимоблокировками — ситуацией, когда система перестает выполнять полезную работу. Чтобы предоставить полезный отчет об ошибке в такой ситуации, используйте ddb(4), как описано в предыдущем разделе. Включите в отчет вывод команд ps
и trace
для подозрительных процессов.
Если возможно, рассмотрите проведение дополнительного исследования. Приведенный ниже рецепт особенно полезен, если вы подозреваете, что взаимная блокировка происходит на уровне VFS. Добавьте следующие параметры в файл конфигурации ядра.
makeoptions DEBUG=-g options INVARIANTS options INVARIANT_SUPPORT options WITNESS options WITNESS_SKIPSPIN options DEBUG_LOCKS options DEBUG_VFS_LOCKS options DIAGNOSTIC
При возникновении взаимоблокировки, помимо вывода команды ps
, предоставьте информацию из show pcpu
, show allpcpu
, show locks
, show alllocks
, show lockedvnods
и alltrace
.
Для получения осмысленных трассировок стека для потоковых процессов используйте thread thread-id
для переключения на стек потока и выполните трассировку с помощью where
.
10.7. Отладка ядра с помощью Dcons
dcons(4) — это очень простой драйвер консоли, который не связан напрямую с какими-либо физическими устройствами. Он просто читает и записывает символы из буфера в ядре или загрузчике и обратно. Благодаря своей простоте он очень полезен для отладки ядра, особенно с устройством FireWire®. В настоящее время FreeBSD предоставляет два способа взаимодействия с буфером извне ядра с помощью dconschat(8).
10.7.1. Dcons через FireWire®
Большинство контроллеров FireWire® (IEEE1394) основаны на спецификации OHCI, которая поддерживает физический доступ к памяти хоста. Это означает, что после инициализации контроллера хоста мы можем получить доступ к памяти хоста без помощи программного обеспечения (ядра). Мы можем использовать эту возможность для взаимодействия с dcons(4). dcons(4) предоставляет функциональность, аналогичную последовательной консоли. Он эмулирует два последовательных порта: один для консоли и DDB, другой для GDB. Поскольку удалённый доступ к памяти полностью обрабатывается аппаратным обеспечением, буфер dcons(4) остаётся доступным даже при крахе системы.
Устройства FireWire® не только встраиваются в материнские платы. Для настольных компьютеров существуют PCI-карты, а для ноутбуков можно приобрести интерфейс CardBus.
10.7.1.1. Включение поддержки FireWire® и Dcons на целевой машине
Чтобы включить поддержку FireWire® и Dcons в ядре целевой машины:
Убедитесь, что ваше ядро поддерживает
dcons
,dcons_crom
иfirewire
.Dcons
должен быть статически связан с ядром. Дляdcons_crom
иfirewire
модули должны подойти.Убедитесь, что физический DMA включен. Возможно, потребуется добавить
hw.firewire.phydma_enable=1
в /boot/loader.conf.Добавьте параметры для отладки.
Добавьте
dcons_gdb=1
в /boot/loader.conf, если вы используете GDB через FireWire®.Включите
dcons
в /etc/ttys.Это необязательно: чтобы принудительно сделать
dcons
высокоуровневой консолью, добавьтеhw.firewire.dcons_crom.force_console=1
в loader.conf.
Чтобы включить поддержку FireWire® и Dcons в loader(8) на i386 или amd64:
Добавьте LOADER_FIREWIRE_SUPPORT=YES
в /etc/make.conf и пересоберите loader(8):
# cd /sys/boot/i386 && make clean && make && make install
Чтобы включить dcons(4) в качестве активной низкоуровневой консоли, добавьте boot_multicons="YES"
в /boot/loader.conf.
Вот несколько примеров конфигурации. Образец файла конфигурации ядра может содержать:
device dcons
device dcons_crom
options KDB
options DDB
options GDB
options ALT_BREAK_TO_DEBUGGER
И образец /boot/loader.conf может содержать:
dcons_crom_load="YES"
dcons_gdb=1
boot_multicons="YES"
hw.firewire.phydma_enable=1
hw.firewire.dcons_crom.force_console=1
10.7.1.2. Включение поддержки FireWire® и Dcons на главной машине
Чтобы включить поддержку FireWire® в ядре на основной машине:
# kldload firewire
Определите EUI64 (уникальный 64-битный идентификатор) контроллера FireWire® и используйте fwcontrol(8) или dmesg
, чтобы найти EUI64 целевой машины.
Запустите dconschat(8), с:
# dconschat -e \# -br -G 12345 -t 00-11-22-33-44-55-66-77
Следующие комбинации клавиш могут быть использованы после запуска dconschat(8):
~+. | Отсоединиться |
~ | ALT BREAK |
~ | ПЕРЕЗАГРУЗИТЬ (RESET) целевую машину |
~ | Приостановить dconschat |
Присоедините удаленный GDB, запустив kgdb(1) с сеансом удаленной отладки:
kgdb -r :12345 kernel
10.7.1.3. Некоторые общие рекомендации
Вот несколько общих советов:
Чтобы в полной мере использовать скорость FireWire®, отключите другие медленные драйверы консоли:
# conscontrol delete ttyd0 # serial console
# conscontrol delete consolectl # video/keyboard
Существует режим GDB для emacs(1); вот что нужно добавить в ваш .emacs:
(setq gud-gdba-command-name "kgdb -a -a -a -r :12345")
(setq gdb-many-windows t)
(xterm-mouse-mode 1)
M-x gdba
10.7.2. Dcons с KVM
Мы можем напрямую читать буфер dcons(4) через /dev/mem для работающих систем и в дампе памяти для систем после аварии. Это даёт аналогичный вывод команде dmesg -a
, но буфер dcons(4) содержит больше информации.
10.7.2.1. Использование Dcons с KVM
Для использования dcons(4) с KVM:
Дамп буфера dcons(4) работающей системы:
# dconschat -1
Дамп буфера dcons(4) аварийного дампа:
# dconschat -1 -M vmcore.XX
Отладка ядра в реальном времени может быть выполнена через:
# fwcontrol -m target_eui64
# kgdb kernel /dev/fwmem0.2
10.8. Глоссарий параметров ядра для отладки
В этом разделе представлен краткий глоссарий параметров ядра, указываемых при компиляции и относящихся к отладке:
options KDB
: включает фреймворк отладки ядра. Необходим дляoptions DDB
иoptions GDB
. Практически не влияет на производительность. По умолчанию отладчик будет запущен при панике вместо автоматической перезагрузки.options KDB_UNATTENDED
: изменяет значение по умолчанию системной настройкиdebug.debugger_on_panic
на 0, что управляет входом в отладчик при панике. Еслиoptions KDB
не вкомпилировано в ядро, поведение по умолчанию — автоматическая перезагрузка при панике; если оно вкомпилировано в ядро, поведение по умолчанию — переход в отладчик, если не вкомпилирована опцияoptions KDB_UNATTENDED
. Если вы хотите оставить отладчик ядра вкомпилированным в ядро, но желаете, чтобы система перезагружалась, пока вы не готовы использовать отладчик для диагностики, используйте эту опцию.options KDB_TRACE
: изменяет значение по умолчанию системной настройкиdebug.trace_on_panic
на 1, что управляет автоматическим выводом трассировки стека при панике. Особенно полезно при использовании сoptions KDB_UNATTENDED
, так как позволяет собрать базовую отладочную информацию на последовательной консоли или консоли FireWire, продолжая перезагрузку для восстановления.options DDB
: включает поддержку консольного отладчика DDB. Этот интерактивный отладчик работает на активной низкоуровневой консоли системы, включая видеоконсоль, последовательную консоль или консоль FireWire. Он предоставляет базовые встроенные средства отладки, такие как трассировка стека, список процессов и потоков, вывод состояния блокировок, состояния виртуальной памяти, состояния файловой системы и управления ядром памяти. DDB не требует работы программного обеспечения на второй машине или возможности создания дампа памяти или полных символов отладки ядра, а также предоставляет детальную диагностику ядра во время выполнения. Многие ошибки могут быть полностью диагностированы с использованием только вывода DDB. Эта опция зависит отoptions KDB
.options GDB
: включает поддержку удалённого отладчика GDB, который может работать через последовательный кабель или FireWire. При входе в отладчик можно подключить GDB для проверки содержимого структур, генерации трассировки стека и т.д. Некоторые состояния ядра сложнее исследовать, чем в DDB, который способен автоматически создавать полезные сводки состояния ядра, например, автоматически обходить структуры отладки блокировок или управления памятью ядра, но для этого требуется вторая машина с запущенным отладчиком. С другой стороны, GDB объединяет информацию из исходного кода ядра и полных отладочных символов, знает полные определения структур данных, локальные переменные и поддерживает написание скриптов. Эта опция не требуется для запуска GDB на дампе памяти ядра. Данная опция зависит отoptions KDB
.options BREAK_TO_DEBUGGER
,options ALT_BREAK_TO_DEBUGGER
: позволяют сигналу прерывания или альтернативному сигналу на консоли войти в отладчик. Если система зависает без паники, это полезный способ попасть в отладчик. Из-за текущей блокировки ядра сигнал прерывания, сгенерированный на последовательной консоли, значительно надежнее для входа в отладчик и обычно рекомендуется. Данная опция оказывает незначительное или нулевое влияние на производительность.options INVARIANTS
: включает в ядро большое количество проверок и тестов во время выполнения, которые постоянно проверяют целостность структур данных ядра и инварианты алгоритмов ядра. Эти тесты могут быть затратными, поэтому по умолчанию не включены, но они помогают обеспечить полезное поведение "fail stop", при котором определённые классы нежелательного поведения попадают в отладчик до возникновения повреждения данных ядра, что упрощает их отладку. Тесты включают в себя очистку памяти и проверку использования после освобождения, что является одним из наиболее значимых источников накладных расходов. Эта опция зависит отoptions INVARIANT_SUPPORT
.options INVARIANT_SUPPORT
: многие тесты, присутствующие вoptions INVARIANTS
, требуют модифицированных структур данных или определения дополнительных символов ядра.options WITNESS
: эта опция включает отслеживание и проверку порядка блокировок во время выполнения, что является неоценимым инструментом для диагностики взаимоблокировок. WITNESS поддерживает граф полученных порядков блокировок по типам блокировок и проверяет граф на каждом получении на наличие циклов (явных или неявных). Если цикл обнаружен, на консоль выводится предупреждение и трассировка стека, указывающие на возможное возникновение взаимоблокировки. WITNESS необходим для использования команд DDBshow locks
,show witness
иshow alllocks
. Эта отладочная опция создает значительную нагрузку на производительность, которую можно несколько уменьшить с помощьюoptions WITNESS_SKIPSPIN
. Подробная документация доступна в witness(4).options WITNESS_SKIPSPIN
: отключает проверку порядка блокировки spinlock во время выполнения с WITNESS. Поскольку spin-блокировки чаще всего захватываются в планировщике, а события планировщика происходят часто, эта опция может значительно ускорить системы, работающие с WITNESS. Эта опция зависит отoptions WITNESS
.options WITNESS_KDB
: изменяет значение по умолчанию системной настройкиdebug.witness.kdb
на 1, что приводит к входу в отладчик при обнаружении нарушения порядка блокировок вместо простого вывода предупреждения. Эта опция зависит отoptions WITNESS
.options SOCKBUF_DEBUG
: выполнять расширенную проверку согласованности сокетных буферов во время выполнения, что может быть полезно для отладки как ошибок в сокетах, так и состояний гонки в протоколах и драйверах устройств, взаимодействующих с сокетами. Данная опция значительно влияет на производительность сети и может изменить временные параметры в состояниях гонки драйверов устройств.options DEBUG_VFS_LOCKS
: отслеживает точки получения блокировок для lockmgr/vnode, расширяя объем информации, отображаемой командойshow lockedvnods
в DDB. Данная опция оказывает заметное влияние на производительность.options DEBUG_MEMGUARD
: замена для malloc(9), аллокатор памяти ядра, который использует систему VM для обнаружения чтения или записи в освобождённую память. Подробности можно найти в memguard(9). Данная опция значительно влияет на производительность, но может быть очень полезна при отладке ошибок повреждения памяти ядра.options DIAGNOSTIC
: включает дополнительные, более затратные диагностические тесты, аналогичныеoptions INVARIANTS
.options KASAN
: включает отладчик адресов ядра (Kernel Address Sanitizer). Это включает инструментирование компилятора, которое может использоваться для обнаружения недопустимых обращений к памяти в ядре, таких как использование после освобождения и переполнение буфера. В значительной степени заменяетoptions DEBUG_MEMGUARD
. Подробности и список поддерживаемых платформ см. в kasan(9).options KMSAN
: включить отладчик использования памяти ядра (Kernel Memory Sanitizer). Это включает инструментирование компилятора, которое может использоваться для обнаружения использования неинициализированной памяти. Подробности и список поддерживаемых платформ см. в kmsan(9).
Изменено: 12 октября 2025 г. by Vladlen Popolitov