Как всем нам известно, процесс отладки это такая вещь, важность которой трудно переоценить. Причем, понимая важность таких методов как дебажное моргание светодиодами и вывод дебажных сообщений в порт, я остаюсь при мнении, что эффективнее пошаговой отладки пока ничего не придумано. Однако, задача пошаговой отладки становится не такой тривиальной в случае программирования под Linux на встраиваемых системах (таких как rasbery pi, virt2real или промышленные процессорные модули).
Данную задачу в Linux призвана решать стандартная связка программ GDB и gdbserver. Идея в том, что пишешь на компе программу (host в терминологии GDB), компилируешь её и заливаешь на целевое устройство (target). Далее запускаешь на целевом устройстве (target) отлаживаемый файл и gdbserver, а на хосте GDB и вперед.
Схему взаимодействия такой отладки кратко можно представить так:
Исполняемый файл — это та самая программа, которую мы хотим удаленно отлаживать. Для корректной работы, экземпляр программы должен находиться не только на целевом усройстве, но и на компе (host) с которого идет отладка.
GDB — программа, которая непосредственно выполняет процесс отладки. Обычно, входит в состав тулчейна GCC и находится там же где и компилятор.
gdbserver — ответная часть GDB, которая запускает исполняемый файл в режиме отладки. Поскольку gdbserver запускается на удаленной стороне (target), то он должен быть собран под целевое устройство, при помощи кросс-компилятора. Собственно, сборке gdbserver'а из исходников и посвящена в основном данная статья.
В моём распоряжении есть плата virt2real, а так же процессорный модуль на базе процессора от TI серии AM335x. Ниже будет показана последовательность действий на примере virt2real, однако, всё тоже самое мною было успешно (и что важно — аналогично) проделано с чипом AM335x.
Примечание: операционная система, установленная на host'e — Ubuntu.12.04.
Подготовка
Создаем в своей домашней директории папку gdb, в которой и будем производить все наши манипуляции. Внутри создаем подпапку downloads:
mkdir -p ~/gdb/downloads
cd ~/gdb/downloads
Скачиваем необходимые нам исходники и распаковываем их. Нам понадобится сам GDB, а так же библиотека termcap (её использует GDB).
wget ftp://ftp.gnu.org/gnu/termcap/termcap-1.3.1.tar.gz
wget ftp://ftp.gnu.org/gnu/gdb/gdb-7.8.tar.gz
tar xvzf termcap-1.3.1.tar.gz
tar xvzf gdb-7.8.tar.gz
Обычно собирают прямо в папке с исходниками, но мы так делать не будем, для того что бы оставить исходники нетронутыми. Это пригодится на случай, если у Вас есть не одна, а несколько разновидностей целевых платформ. Тогда одни и те же скаченные исходники можно будет использовать несколько раз.
Собираем библиотеку termcap
Соответственно, начинаем с библиотеки termcap, потому что она потребуется позднее при сборке самого gdbserver'a. Создаем папку builds, в которую будем собирать наши программы. Внутри создаем папку v2r, в неё поместим все результаты для платформы virt2real. Ну а там уже папку termcap для построения библиотеки termcap. Переходим в созданную директорию.
mkdir -p ~/gdb/builds/v2r/termcap
cd ~/gdb/builds/v2r/termcap
Указываем системе компилятор и ranlib которые будем использовать. В моем случае это:
export CC=/opt/virt2real-sdk/codesourcery/arm-2013.05/bin/arm-none-linux-gnueabi-gcc
export RANLIB=/opt/virt2real-sdk/codesourcery/arm-2013.05/bin/arm-none-linux-gnueabi-ranlib
Теперь конфигурируем. Потребуется указать 2 параметра: --host и --prefix.
- Признаюсь, я так и не понял имеет ли значение, что указать в --host. У меня сложилось впечатление, что нет. В любом случае, я не сумел найти внятного объяснения, что именно нужно указывать в данном параметре, поэтому указал префикс компилятора. Т.е. мой компилятор называется arm-none-linux-gnueabi-gcc, поэтому в качестве --host я указал arm-none-linux-gnueabi.
- В качестве параметра --prefix указываем папку, в которую мы хотим поместить результаты работа (конфигурирования), т.е. ту папку в которой мы сейчас и находимся.
../../../downloads/termcap-1.3.1/configure --host=arm-none-linux-gnueabi --prefix=~/gdb/builds/v2r/termcap
Если все сделано правильно и прошло без ошибок, то в папке ~/gdb/builds/v2r/termcap будет создан Makefile.
Далее собираем библиотеку:
make
make install
Собираем gdbserver
Создаем папку в которой будем собирать сервер и переходим в неё:
mkdir -p ~/gdb/builds/v2r/gdbserver
cd ~/gdb/builds/v2r/gdbserver
Указываем где взять библиотеку termcap:
export LDFLAGS="-static -L~/gdb/builds/v2r/termcap/lib"
export CFLAGS="-g -O2 -I~/gdb/builds/v2r/termcap/include"
Конфигурируем аналогично termcap. Тут важно отметить, что мы собираем gdbserver (а не GDB), поэтому файл configure указываем именно из папки /gdb-7.8/gdb/gdbserver:
../../../downloads/gdb-7.8/gdb/gdbserver/configure --host=arm-none-linux-gnueabi --prefix=/home/den1s/gdb/builds/v2r/gdbserver --disable-werror # &&
Если все верно, будет создан Makefile. Далее стандартно:
make
make install
Пробуем
Что бы протестировать процесс отладки создадим короткий Hello world и скомпилируем его под целевую платформу.
mkdir -p ~/virt2real/hello_test/
cd ~/virt2real/hello_test/
/opt/virt2real-sdk/codesourcery/arm-2013.05/bin/arm-none-linux-gnueabi-g++ hello.cpp -O0 -g -o hello
Исходный код файла hello.cpp:
#include <iostream>
int main(int argc, char* argv[])
{
std::cout << "Hello,n" << std::endl;
std::cout << "debuggedn" << std::endl;
std::cout << "World!!!" << std::endl;
return 0;
}
Заливаем исполняемый файл hello и наш gdbserver на целевую плату.
Я заливаю в папку /usr/ используя SCP:
scp ~/gdb/builds/v2r/gdbserver/bin/gdbserver root@192.168.3.1:/usr/
scp ~/virt2real/hello_test/hello root@192.168.3.1:/usr/
Теперь запускаем второй экземпляр терминала и подключаемся к целевой плате по ssh и переходим в папку /usr/:
ssh root@192.168.3.1
cd /usr/
Запускаем на целевой плате gdbserver, и с его помощью наш исполняемый (отлаживаемый) файл hello. Затем открываем дебажную сессию на понравившемся нам порту:
[root@virt2real usr]# ./gdbserver :123 hello
Process hello created; pid = 5680;
listening on port 123
Возвращаемся на host и запускаем отлаживаемый файл hello с помощью GDB
/opt/virt2real-sdk/codesourcery/arm-2013.05/bin/arm-none-linux-gnueabi-gdb hello
export PATH=$PATH:/opt/virt2real-sdk/codesourcery/arm-2013.05/bin/
В ответ должны увидеть приглашение от GDB:
GNU gdb (Sourcery CodeBench Lite 2013.05-24) 7.4.50.20120716-cvs
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi".
For bug reporting instructions, please see:
<https://sourcery.mentor.com/GNUToolchain/>...
Reading symbols from /home/den1s/virt2real/hello_test/hello...done.
(gdb)
Подключаемся к удаленному gdbserver'у используя указанный выше порт:
(gdb) target remote 192.168.3.1:123
Получаем ответ и приглашение для ввода следующей команды:
Remote debugging using 192.168.3.1:123
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0x36fd7e30 in ?? ()
(gdb)
При этом удаленная сторона (gdbserver на target в лице virt2real) должна увидеть установку дебажной сессии:
Remote debugging from host 192.168.3.10 # где 192.168.3.10 - это IP нашего host'а с которого ведется отладка
Комментарий | host | target |
---|---|---|
Ставим breakpoint на main |
|
|
Идем до Breakpoint'а |
|
|
Переходим к следующей строке |
|
|
Переходим к следующей строке |
|
|
Переходим к следующей строке |
|
|
Переходим к следующей строке (которой, впрочем нет) |
|
|
Запускаем программу до конца, что приводит к её завершению |
|
|
На этом пример пошаговой отладки закончен. Отмечу:
- для получения полного списка команд можно воспользоваться командой help, а так же почитать книгу, посвященную отладке с помощью GDB (ссылку смотри в конце статьи)
- «ручная» отладка с помощью GDB дело весьма утомительное, так что рекомендую использовать для этих целей, например, Eclipse. К сожалению, описание подобной отладки в рамках данной статьи, увеличило бы её до неприличных размеров. В конце статьи указана ссылка на очень хорошее англоязычное описание данной темы.
Установка sysroot
Для корректной работы GDB, ему нужны так называемые debugging symbols, которые могут быть считаны из библиотек удаленной операционки (target). Их отсутствие является, например, причиной подобных сообщений:
(gdb) next
Cannot access memory at address 0x0
Cannot access memory at address 0x0
0x36d1f040 in ?? ()
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
А потенциально вызывать и другие неприятные проблемы отладки.
Для устранения проблемы GDB на host'е необходимо указать где взять эти самые библиотеки с помощью команды:
set sysroot [Directory]
Если у Вас на host'е где-то завалялся образ линукса Вашго target'а, то необходимо указать путь до папки с библиотеками.
Или предварительно эти библиотеки выкачать на host:
mkdir -p ~/virt2real/sysroot
cd ~/virt2real/sysroot
scp -r root@192.168.3.1:/lib lib
Возвращаемся в папку с проектом, снова запускаем GDB и указываем путь до библиотек:
cd ~/virt2real/hello_test/
arm-none-linux-gnueabi-gdb hello
(gdb) set sysroot ~/virt2real/hello_test/
Теперь, периодически будут появляться сообщения типа:
Reading symbols from ~/virt2real/sysroot/lib/libgcc_s.s...done.
Посмотреть список используемых в текущий момент библиотек можно так:
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x36fd77a0 0x36ff24d0 Yes (*) ~/virt2real/sysroot/lib/ld-linux.so.3
No /usr/lib/libstdc++.so.6
0x36e70e00 0x36ed107c Yes (*) ~/virt2real/sysroot/lib/libm.so.6
0x36e51028 0x36e63154 Yes (*) ~/virt2real/sysroot/lib/libgcc_s.so.1
0x36d1cb00 0x36e11ae8 Yes (*) ~/virt2real/sysroot/lib/libc.so.6
(*): Shared library is missing debugging information.
Список используемой «литературы»
- Способы отладки в Embedded Linux. На русском.
- Описание сборки gdbserver. На русском.
- Описание сборки gdbserver. На английском.
- Установка sysroot. На английском.
- Р.Столмен. Отладка с помощью GDB. На английском.
- Настройка GDB в Code Composer Studio (тот же Eclipse). На английском.
P.S.: данная статья не претендует на научную новизну, но является попыткой собрать в одном месте подробную информации по сборке и настройке связки GDB-gdbserver. Вероятно, что для продвинутых линуксоидов материал покажется банальным и «корявым», однако для тех людей, кто больше является «железячником», или для программистов микроконтроллеров переход на линукс является делом не таким уж и простым (сужу по себе). Так что, надеюсь, материал кому-либо сослужит полезную службу.
Автор: den1s1