Данную задачу в 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 << "debugged\n" << 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). На английском.
- Инструкция1) cd ~/gdb/downloads
2) wget ftp.gnu.org/gnu/termcap/termcap-1.3.1.tar.gz
3) wget ftp.gnu.org/gnu/gdb/gdb-7.8.tar.gz
4) tar xvzf termcap-1.3.1.tar.gz
5) tar xvzf gdb-7.8.tar.gz
6) mkdir -p ~/gdb/builds/v2r/termcap
7) cd ~/gdb/builds/v2r/termcap
8) export CC=/opt/virt2real-sdk/codesourcery/arm-2013.05/bin/arm-none-linux-gnueabi-gcc
9) export RANLIB=/opt/virt2real-sdk/codesourcery/arm-2013.05/bin/arm-none-linux-gnueabi-ranlib
10) ../../../downloads/termcap-1.3.1/configure --host=arm-none-linux-gnueabi --prefix=~/gdb/builds/v2r/termcap
11) make
12) make install
13) mkdir -p ~/gdb/builds/v2r/gdbserver
14) cd ~/gdb/builds/v2r/gdbserver
15) export LDFLAGS="-static -L~/gdb/builds/v2r/termcap/lib"
16) export CFLAGS="-g -O2 -I~/gdb/builds/v2r/termcap/include"
17) ../../../downloads/gdb-7.8/gdb/gdbserver/configure --host=arm-none-linux-gnueabi --prefix=/home/den1s/gdb/builds/v2r/gdbserver --disable-werror # &&
18) make
19) make install
P.S.: данная статья не претендует на научную новизну, но является попыткой собрать в одном месте подробную информации по сборке и настройке связки GDB-gdbserver. Вероятно, что для продвинутых линуксоидов материал покажется банальным и «корявым», однако для тех людей, кто больше является «железячником», или для программистов микроконтроллеров переход на линукс является делом не таким уж и простым (сужу по себе). Так что, надеюсь, материал кому-либо сослужит полезную службу.

