Debugging driver in linux

Драйверы устройств в Linux

Часть 10: Отладка в пространстве ядра Linux

Оригинал: «Device Drivers, Part 10: Kernel-Space Debuggers in Linux»
Автор: Anil Kumar Pugalia
Дата публикации: September 1, 2011
Перевод: Н.Ромоданов
Дата перевода: июнь 2012 г.

В этой статье, которая является частью серии статей о драйверах устройств в Linux, рассказывается об отладке в пространстве ядра Linux.

Светлана, вернувшись из больницы, отдыхала в библиотеке, читая разные книги. С тех пор, как она узнала о способе отладки с использованием ioctl , ей не терпелось узнать больше об отладке в пространстве ядра. Ей бы хотелось узнать, как и где можно запускать отладчик пространства ядра. Отладка в пространстве ядра отличается от отладки приложений в пользовательском пространстве, когда у нас в нижнем слое работает операционная система, а над ней есть оболочка или графический интерфейс для запуска отладчика (например, отладчика gdb и отладчика data display debugger — ddd ). Затем она наткнулась на интересный способ отладки в пространстве ядра с использованием отладчика kgdb , который, начиная с ядра 2.6.26, является частью ядра.

Изучаем отладку в пространстве ядра

Поскольку нам при отладке потребуется некоторый интерфейс, можно для визуализации процесса отладки воспользоваться одним из следующих двух способов:

  • Добавьте отладчик в само ядро, доступное через обычную консоль. Например, в случае kdb , который не был официальным отладчиком до ядра 2.6.35, нужно было с этого адреса FTP загрузить исходный код (два набора патчей: один — зависящий от архитектуры и один — не зависящий от архитектуры), а затем пропатчить ими исходный код ядра. Но, начиная с ядра 2.6.35, большая часть возможностей отладчика уже есть в официально выпущенном исходном коде ядра. В любом случае необходимо, чтобы поддержка kdb была добавлена в исходный код ядра при его компиляции, установке и загрузке. Отладочный интерфейс kdb будет предоставлен в загрузочном экране.
  • Установите в ядре минимальный отладочный сервер; клиент через определенный интерфейс (например, последовательный или Ethernet) будет подключаться к нему с удаленного хоста или из локального пользовательского пространства. Это kgdb , сервер gdb ядра, должен использоваться с gdb в качестве его клиента. Начиная с ядра 2.6.26, последовательный интерфейс этого сервера является частью официального релиза ядра. Но, если вам интересен сетевой интерфейс, вам все равно придется пропатчить ядро с использованием одного из релизов, взятых на странице проекта kgdb . В любом случае, вам потребуется включить в ядре поддержку kgdb , перекомпиировать, установить и загрузить новое ядро.

Пожалуйста, обратите внимание, что в обоих указанных выше случаях для того, чтобы в ядре выполнять отладку, необходим полный исходный код ядра, в отличие от случая сборки модулей, когда достаточно просто заголовочных файлов. Ниже рассказывается, как пользоваться отладчиком kgdb через последовательный интерфейс.

Настройка ядра Linux с kgdb

Предварительные требования: либо в вашей системе для используемого ядра должен быть установлен исходный код ядра, либо соответствующий релиз исходного кода ядра следует загрузить с сайта kernel.org .

Прежде всего, чтобы можно было в ядре осуществлять отладку, в нем должен присутствовать отладчик kgdb . Чтобы этого добиться, в исходном коде ядра следует указать параметр CONFIG_KGDB=y . Кроме того, чтобы можно было получать доступ к отладчику kgdb через последовательный порт, нужно указать параметр CONFIG_KGDB_SERIAL_CONSOLE=y . Чтобы сделать использование отладчика gdb более информативным, предпочтительно указать параметр CONFIG_DEBUG_INFO с тем, чтобы в ядре можно было формировать символьные данные. Параметр CONFIG_FRAME_POINTER=y разрешает в ядре использовать указатели фреймов, что позволяет gdb более точно выполнять трассировку стека. Все эти параметры есть в пункте «Kernel hacking» («Настройки ядра») в меню директория исходного кода (все это предпочтительнее выполнять в роли пользователя root или с помощью команды sudo ) с помощью следующей команды:

Читайте также:  Lenovo ideapad z500 драйвера для windows 10 64 bit

Рис.1: Конфигурирование параметров ядра для отладчика kgdb

На рис.1 эти параметры выделены:

  • «KGDB: kernel debugging with remote gdb» («KGDB: Отладка ядра с дистанционным использованием gdb») –> CONFIG_KGDB
  • «KGDB: use kgdb over the serial console» («KGDB: Использование kgdb черед консоль последовательного доступа») –> CONFIG_KGDB_SERIAL_CONSOLE
  • «Compile the kernel with debug info» («Компиляция ядра с добавленем отладочной информацией») –> CONFIG_DEBUG_INFO
  • «Compile the kernel with frame pointers» («Компиляция ядра с использование указателей фреймов») –> CONFIG_FRAME_POINTER

Как только вы сохраните конфигурацию, соберите ядро (запустите команду make ), а затем выполните команду make install для того, чтобы установить его, а также добавить в конфигурационный файл GRUB запись для установленного ядра. Конфигурационным файлом GRUB может быть, в зависимости от дистрибутива, файл /boot/grub/menu.lst , файл /etc/grub.cfg или аналогичный. После того, как выполните установку, в эту новую запись нужно будет добавить загрузочные ядра kgdb-related так, как показано в выделенном тексте на рис.2.

Рис.2: Конфигурирование GRUB для kgdb

Параметр kgdboc указывается при подключении к gdb через консоль; формат параметра kgdboc= , где:

  • — файл последовательного устройства (порт) в системе, работающей с отлаживаемым ядром
  • — скорость в бодах последовательного порта

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

После этого мы готовы начать. Сделайте копию образа ядра vmlinux для использования в клиентской системе gdb . Перезагрузитесь и в меню GRUB выберите новое ядро, после чего ядро будет ожидать, пока gdb не подключится через последовательный порт.

Все приведенные выше копии экранов сделаны для версии ядра 2.6.33.14. Для исходного кода ядра любого другого релиза 2.6.3x все должно работать точно также. Кроме того, копии экранов для kgdb были получены с использованием файла последовательного устройства /dev/ttyS0 , т. е. с использованием первого последовательного порта.

Настройка gdb на другой системе

Ниже приводятся требования к системе:

  • Последовательные порты системы, которая отлаживается, и второй системы, на которой запускается gdb , должны быть соединены с помощью кабеля «нуль-модем» (т. е. переходного последовательного кабеля).
  • Сборку образа ядра vmlinux с подключенным kgdb необходимо скопировать из системы, которая отлаживается, в рабочий директорий в системе, где будет выполняться gdb .

Чтобы подключить gdb к ожидающему ядру, запустите gdb в командной оболочке, а затем выполните следующие команды:

В приведенных выше командах vmlinux является ядром, скопированным из системы, которая отлаживается.

Отладка с использованием gdb и kgdb

Затем все остальные действия будут похожи на отладку приложений с использованием gdb . Можно остановить выполнение с помощью нажатия клавиш Ctrl+C , добавить точки останова с помощью команды b[reak], остановить исполнение с помощью команды s[tep] или команды n[ext] …. — точно также как и при обычном использовании gdb . Если вам потребуются учебники, то в сети есть достаточное количество учебников по GDB. В действительности, если вы не знакомы с текстовым режимом GDB, то воспользуйтесь для GDB любым из стандартных инструментов с графическим интерфейсом, например, ddd , Eclipse и др.

Читайте также:  Windows server system account

Подведем итог

В настоящий момент Светлане не терпелось попробовать kgdb . Поскольку ей для этого нужно было две системы, она отправилась в лабораторию драйверов устройств Linux. Там она настроила системы и запустила gdb так, как это было описано выше.

Источник

Tips and tricks in debugging kernel drivers in Linux

This post includes a couple of notes about linux kernel debugging, in particular the things that I keep forgetting.

Just in case take a look at this video: «Linux Kernel Debugging: Going Beyond Printk Messages».

If you are like me and use vim as a IDE you would like to have some navigation functionality via ctags or cscope : the linux kernel’s Makefile has some rules just for generating that

Log Levels

This is the most trivial thing and yet I forget it every single time

Configuration

If you have an old config and you want to generate a new config having non pre-existing configurations set to the default value you can issue a

If you don’t want to use menuconfig is possible to set configuration options via command line using the following

However, if you are in hurry, that is to compile for x86_64 :

Remember to clean before launching a completely new build:

Now some configuration values that can be useful when debugging

It’s important to know that you need gcc to compile the kernel since the code uses a couple of extensions of this compiler and in particular, depending on the version of the kernel you are trying to compile, a specific version; to find out which version is supported look in the directory include/linux/ for some file named compiler-gccX.h .

If you need to tell the compiler of a particular version use the CC variable

It’s a little tricky for very old kernel to find which version works and actually find the binary; if you are in a Debian distribution you can use snapshot.debian.org. YMMV but I’m not sure it will work at all 🙂

Remeber that is vmlinux that contains the debug symbol.

Cross Compile

This is something I forget about a lot

Initrd via buildroot

Enable BR2_TARGET_ROOTFS_CPIO with the right architecture

GDB scripts

To help with debugging running systems it’s possible to enable some scripts to use with gdb ; this is possible with the option

To load this script you need to enter in the kernel source tree and start gdb .

These are the available commands:

I think that are working correctly only after the system has completed the initialization process.

Dynamic debug

It’s possible to have the debug messages enabled only when and where necessary: here the documentation

To control this feature is necessary to enable a pseudo filesystem via the following option

that has to be mounted

and can be used for example to enable all the debug messages for drivers under sound/soc/ :

If you need something even before is possible to mount the debugfs, you can use the dyndbg kernel argument at boot time, like dyndbg=» » .

To see dev_dbg or you set debug from the kernel command line or you do a think like the following

To use pr_debug you can abilitate it with

Tracing

Once you have enabled the debugfs you can find a subdirectory named tracing ; it also contains a README that explains

Читайте также:  Как посмотреть во сколько был включен компьютер windows 10

Debugging

Take in mind that the kernel cannot be compiled without -O2 so optimization are a pain you have to live with (i.e. you can find inlined function and optimized out variable when you are debugging with gdb ).

If during debugging you find that doesn’t make sense how the flow jumps here and there, probably some functions have been inlined so try to single step instead of using the «next».

Breakpoints

Setting breakpoints works as usual but obviously there are some particular aspects of a operating system that you have to take into account, in particular symbols; It’s convenient to use the lx related functions to facilitate debugging like in these examples

if you need to debug a kernel module, you cannot set a breakpoint directly (I’m not sure really) but you can set a breakpoint to do_init_module() and then do whatever you want after you trigger it via a modprobe of the module; remember to use lx-symbol to load automatically the symbols

Printk based debugging

The Oops is what you probably find yourself staring at and is important to remember that the crash happens at the RIP address, a lot of times I’m distracted from the stacktrace; your usual Oops looks something like this

You can use the scripts/decode_stacktrace.sh to obtain source information from an OOPS

If you want to see the line in the code where the crash happened directly from the debugger, list is your friend

and in case the address you want to see is from a module

the base address at runtime can be read from /sys/modules/module name/sections/.text ( lx-symbol should do that for you but in case you have to work with an old kernel knowing the general case can help).

It’s possible to use qemu to debug the kernel take in mind some

  • use nokaslr to avoid randomization of the addresses
  • cd /path/to/linux/build/ if you want to use the scripts from the kernel and
  • use add-auto-load-safe-path /path/to/linux/build/scripts/gdb/vmlinux-gdb.py in gdb

To wait for the debugger to attach you can pass -s -S .

Forward USB devices to guest

It’s possible to debug a physical USB device attached to the host indicating the port it’s attached to; here we see a webcam

and since we need an high speed device we are telling qemu to use ehci

Miscellanea

errno is defined in include/uapi/asm-generic/errno.h

Under the directory named tools there a certain numbers of script useful to debug.

If you want to install the modules in another path use this

Enable configuration option that is not selectable

If you build an external module that needs some options that isn’t selectable directly you can manually add a prompt line; an example is VIDEOBUF_DMA_SG

Errors

gcc: error: elf_x86_64: No such file or directory -> change -m elf_x86_64 to -m64 .

can’t use ‘defined(@array)’ (Maybe you should just omit the defined()?) at kernel/timeconst.pl line 373 is fixed changing if (!defined(@val)) < to if (!@val) < .

Linkography

  • https://opensourceforu.com/2011/01/understanding-a-kernel-oops/
  • http://mokosays.com/work/?p=22
  • http://henryhermawan.blogspot.com/2011/02/bigger-buffer-log-dmesg-size.html
  • https://www.kernel.org/doc/html/v4.14/dev-tools/gdb-kernel-debugging.html
  • https://developer.ibm.com/articles/l-kernel-memory-access/
  • https://d3s.mff.cuni.cz/files/teaching/nswi161/slides/06_debugging.pdf
  • https://www.starlab.io/using-gdb-linux-kernel/
  • https://sysprogs.com/VisualKernel/documentation/kernelsymbols
  • https://www.oreilly.com/library/view/linux-device-drivers/0596005903/ch04.html
  • http://www.makelinux.net/ldd3/
  • Kernel dynamic memory analysis
  • drgn is a debugger with an emphasis on programmability. drgn exposes the types and variables in a program for easy, expressive scripting in Python

Comments

Contents В© 2021 Gianluca Pacchiella — Powered by Nikola

Источник

Оцените статью