Gdb linux как использовать

Обновлено: 18.05.2024

Чтобы изучить отладку программы на C, давайте создадим следующую программу на C, которая вычисляет и печатает факториал числа. Однако эта программа C содержит некоторые ошибки для целей отладки.

Давайте отладим его, просматривая наиболее полезные команды в gdb.

Шаг 1. Скомпилируйте программу C с параметром отладки -g

Скомпилируйте программу на C с параметром -g. Это позволяет компилятору собирать отладочную информацию.

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

Шаг 2. Запуск gdb

Запустите отладчик C (gdb), как показано ниже.

Шаг 3. Установите точку останова внутри программы на C

  • разбить [имя_файла]:номер_строки
  • разбить [имя_файла]:имя_функции

Помещает точку останова в программу C, где вы подозреваете ошибки. Во время выполнения программы отладчик остановится в точке останова и выдаст запрос на отладку.

Поэтому перед запуском программы давайте поместим в нашу программу следующую точку останова.

Шаг 4. Выполните программу C в отладчике gdb

Вы можете запустить программу с помощью команды run в отладчике gdb. Вы также можете передать программе аргументы командной строки через аргументы запуска. Пример программы, которую мы здесь использовали, не требует никаких аргументов командной строки, поэтому давайте запустим и начнем выполнение программы.

После того как вы выполнили программу C, она будет выполняться до первой точки останова и выдаст вам запрос на отладку.

Вы можете использовать различные команды gdb для отладки программы C, как описано в разделах ниже.

Шаг 5. Печать значений переменных в отладчике gdb

Как вы видите выше, в factorial.c мы не инициализировали переменную j. Таким образом, он получает мусорное значение, в результате чего в качестве факторных значений получаются большие числа.

Исправьте эту проблему, инициализировав переменную j значением 1, скомпилируйте программу C и снова запустите ее.

Даже после этого исправления в программе factorial.c, по-видимому, есть проблема, так как она по-прежнему выдает неправильное значение factorial.

Поэтому поместите точку останова в 10-ю строку и продолжайте, как описано в следующем разделе.

Шаг 6. Продолжайте, переходя друг от друга к командам gdb

Есть три типа операций gdb, которые вы можете выбрать, когда программа останавливается в точке останова. Они продолжаются до следующей точки останова, вступая или проходя через следующие строки программы.

  • c или продолжить: отладчик продолжит выполнение до следующей точки останова.
  • n или next: отладчик выполнит следующую строку как одну инструкцию.
  • s или step: То же, что и далее, но функция не рассматривается как отдельная инструкция, а вместо этого входит в функцию и выполняет ее построчно.

Продолжив или пошагово, вы могли обнаружить, что проблема связана с тем, что мы не использовали 13 ответов

Рассмотрев приведенные выше значения более внимательно, мы понимаем, что вычисляем fact=fact * j, где fact инициализирован равным 0; fact должен был быть инициализирован равным 1. Мы выходим из GDB с помощью команды quit. Далее нам нужно изменить следующую строку: Перекомпилируйте код и запустите его, вы получите ожидаемый результат.

Отладка программы, создающей дамп ядра

Эта программа создает дамп памяти из-за ошибки сегментации. Мы постараемся отследить причину этого дампа ядра.

Загрузите программу отсюда.

<р>1. Скомпилируйте программу, используя следующую команду.

g++ testit.c �g �o testit

<р>2. Запустите его как обычно, вы должны получить следующий результат:

Ошибка сегментации (дамп ядра)

<р>3. Дамп ядра создает файл с именем core, который можно использовать для отладки. Поскольку эта программа очень короткая, нам не нужно устанавливать точки останова. Используйте следующую команду, чтобы запустить отладчик для отладки файла core, созданного testit.

ядро gdb testit

Вывод приведенной выше команды должен выглядеть следующим образом:

bash$ gdb тестирует ядро

GNU gdb 19991004

Авторское право 1998 г. Бесплатное программное обеспечение ���.�

Ядро было сгенерировано `testit'.

Программа завершена с сигналом 11, Ошибка сегментации.

Чтение символов из /usr/lib/libstdc++-libc6.1-1.so.2. сделано.

Чтение символов из /lib/libm.so.6. сделано.

Чтение символов из /lib/libc.so.6. сделано.

Чтение символов из /lib/ld-linux.so.2. сделано.

<р>4. Как видно из приведенного выше вывода, дамп ядра был создан

в результате выполнения оператора в строке 10: temp[3] =�F�;

Внимательно посмотрите на объявление temp в строке 5:

Строка 5 char *temp = "Paras";

Мы обнаружили, что temp — это char*, которому был назначен строковый литерал, поэтому мы не можем изменить содержимое литерала, как в строке 10.Вот что вызывает дамп памяти

Учебник по GDB

Gdb — это отладчик для C (и C++). Это позволяет вам делать такие вещи, как запуск программы до определенной точки, затем останавливаться и распечатывать значения определенных переменных в этой точке, или выполнять программу по одной строке за раз и распечатывать значения каждой переменной после выполнения каждой. линия. Он использует интерфейс командной строки.

Это краткое описание некоторых наиболее часто используемых функций gdb.

Компиляция

Чтобы подготовить программу к отладке с помощью gdb, ее необходимо скомпилировать с флагом -g. Итак, если ваша программа находится в исходном файле с именем memsim.c, и вы хотите поместить исполняемый файл в файл memsim , тогда вы должны скомпилировать следующую команду:

Вызов и выход из GDB

Чтобы запустить gdb, просто введите gdb в командной строке unix. Gdb выдаст вам подсказку, которая выглядит следующим образом: (gdb) . Из этого приглашения вы можете запустить свою программу, просмотреть переменные и т. д., используя команды, перечисленные ниже (и другие, не перечисленные). Или вы можете запустить gdb и дать ему имя исполняемого файла программы, которую вы хотите отладить, сказав

Чтобы выйти из программы, просто введите quit в командной строке (gdb) (на самом деле достаточно просто ввести q).

Команды

Gdb предоставляет онлайн-документацию. Просто набрав help, вы получите список тем. Затем вы можете ввести help topic, чтобы получить информацию по этой теме (или получить более конкретные термины, по которым вы можете обратиться за помощью). Или вы можете просто набрать help command и получить информацию о любой другой команде.

run запустит программу, работающую под управлением gdb. (Запускается программа, которую вы ранее выбрали с помощью команды file или в командной строке unix при запуске gdb. Вы можете указать аргументы командной строки для своей программы в командной строке gdb так же, как и в командной строке gdb. командной строки unix, за исключением того, что вы говорите run вместо имени программы: вы даже можете выполнить перенаправление ввода/вывода: run > outfile.txt .

перерыв

Точка останова – это место в вашей программе, где вы хотели бы временно остановить выполнение, чтобы проверить значения переменных или попытаться выяснить, где происходит сбой программы и т. д. Чтобы установить точку останова вы используете команду разрыва.

break function устанавливает точку останова в начале function . Если ваш код находится в нескольких файлах, вам может потребоваться указать filename:function .

break linenumber или break filename:linenumber устанавливает точку останова на указанный номер строки в исходном файле. Выполнение остановится до того, как эта строка будет выполнена.

удалить

delete number удалит точку останова с номером number . Вы можете узнать номер каждой точки останова, выполнив info breakpoints. (Информацию о команде также можно использовать, чтобы узнать множество других вещей. Для получения дополнительной информации обратитесь к справочной информации.)

очистить

clear function удалит точку останова, установленную в этой функции. Аналогично для номер_строки , имя_файла:функция и имя_файла:номер_строки .

продолжить

шаг продолжит и выполнит текущую строку исходного кода, а затем снова остановит выполнение перед следующей строкой исходного кода.

next будет продолжаться до следующей исходной строки в текущей функции (точнее, до текущего самого внутреннего кадра стека). Это похоже на step , за исключением того, что если строка, которая должна быть выполнена, является вызовом функции, то этот вызов функции будет полностью выполнен до того, как выполнение снова остановится, тогда как при step выполнение остановится на первой строке вызываемой функции.

до

until похож на next , за исключением того, что если вы находитесь в конце цикла, until будет продолжать выполнение до выхода из цикла, тогда как next просто вернет вас к началу цикла. Это удобно, если вы хотите увидеть, что происходит после цикла, но не хотите выполнять каждую итерацию пошагово.

list linenumber распечатает несколько строк из исходного кода вокруг linenumber . Если вы дадите ей аргумент function, она выведет строки с начала этой функции. Просто список без каких-либо аргументов распечатает строки сразу после строк, которые вы распечатали с помощью предыдущей команды списка.

печать

print expression распечатает значение выражения, которое может быть просто именем переменной. Чтобы распечатать первые 25 (например) значений в массиве с именем list , выполните

Рекомендуемое изображение для: Мгновенный повтор: отладка программ на C и C++ с помощью rr.

Эта статья является первой в серии, демонстрирующей, как эффективно использовать отладчик GNU Debugger (GDB) для отладки приложений на C и C++.Если у вас ограниченный опыт использования GDB или он отсутствует, эта серия статей научит вас более эффективно отлаживать свой код. Если вы уже являетесь опытным профессионалом, использующим GDB, возможно, вы откроете для себя то, чего раньше не видели.

Помимо советов и рекомендаций для разработчиков по многим командам GDB, в будущих статьях также будут рассмотрены такие темы, как отладка оптимизированного кода, отладка в автономном режиме (базовые файлы) и сеансы на основе сервера (aka gdbserver , используемый при отладке контейнера).

Почему еще один учебник по GDB?

Большинство руководств по GDB, доступных в Интернете, состоят лишь из введения в базовые команды list , break , print и run . Новые пользователи GDB также могут прочитать (или спеть) официальную песню GDB!

Вместо того, чтобы просто демонстрировать несколько полезных команд, каждая статья этой серии будет посвящена одному аспекту использования GDB с точки зрения того, кто разрабатывает GDB. Я использую GDB каждый день, и эти советы и рекомендации я (и многие другие продвинутые пользователи и разработчики GDB) использую для оптимизации наших сеансов отладки.

Поскольку это первая статья в серии, позвольте мне последовать рекомендации песни GDB и начать с самого начала: Как запустить GDB.

Параметры компилятора

TL;DR: не отлаживайте приложения с оптимизацией, если этого можно избежать. Следите за следующей статьей об оптимизации.

Оптимизация может привести к неожиданному поведению GDB, если вы не знаете, что может происходить "под прикрытием". Я всегда использую параметр компилятора C -O0 (это буква O, за которой следует цифра ноль) для сборки исполняемых файлов во время цикла разработки.

Я также всегда заставляю набор инструментов выдавать отладочную информацию. Это достигается с помощью опции -g. Указание точного формата отладки больше не требуется (или желательно); DWARF уже много лет является форматом отладочной информации по умолчанию в GNU/Linux. Поэтому игнорируйте советы использовать -ggdb или -gdwarf-2 .

Короче говоря, для лучшей отладки используйте -g3 -O0 при компиляции кода. Некоторые среды (например, использующие автоинструменты GNU) устанавливают переменные среды ( CFLAGS и CXXFLAGS ), которые управляют выводом компилятора. Установите эти флажки, чтобы убедиться, что ваши вызовы компилятора включают нужную среду отладки.

Дополнительную информацию о влиянии параметров -g и -O на процесс отладки см. в трактате Александра Оливы GCC gOlogy: Studying the Impact of Optimizations on Debugging.

Сценарии запуска

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

  1. /etc/gdbinit (не в FSF GNU GDB): во многих дистрибутивах GNU/Linux, включая Fedora и Red Hat Enterprise Linux, GDB сначала ищет системный файл инициализации по умолчанию и выполняет содержащиеся в нем команды. В системах на основе Red Hat этот файл выполняет любые файлы сценариев (включая сценарии Python), установленные в /etc/gdbinit.d .
  2. $HOME/.gdbinit : GDB затем прочитает сценарий глобальной инициализации пользователя из домашнего каталога, если этот файл существует.
  3. ./.gdbinit : Наконец, GDB будет искать сценарий запуска в текущем каталоге. Думайте об этом как о файле настройки для конкретного приложения, в который вы можете добавлять определяемые пользователем команды для каждого проекта, красивые принтеры и другие настройки.

Все эти файлы запуска содержат команды GDB для выполнения, но они также могут включать скрипты Python, если перед ними стоит команда python, например, python print('Привет из python!') .

Мой .gdbinit на самом деле довольно прост. Его наиболее важные строки включают историю команд, так что GDB запоминает заданное количество команд, которые были выполнены из предыдущего сеанса. Это аналогично механизму истории оболочки и .bash_history. Весь файл:

Первая строка отключает встроенную подкачку GDB. Следующая строка позволяет сохранить историю (по умолчанию в ~/.gdb_history), а последняя строка включает расширение истории в стиле оболочки с помощью символа восклицательного знака (!). Этот параметр обычно отключен, поскольку восклицательный знак также является логическим оператором в C.

Чтобы запретить GDB читать файлы инициализации, укажите параметр командной строки --nx.

Получение справки в GDB

Существует несколько способов получить помощь по использованию GDB, включая обширную, хотя и сухую, документацию, объясняющую каждый маленький переключатель, ручку и функцию.

Ресурсы сообщества GDB

Сообщество предлагает помощь пользователям в двух местах:

Однако, поскольку эта статья посвящена использованию GDB, самый простой способ для пользователей получить справку по команде — использовать встроенную справочную систему GDB, обсуждаемую далее.

Доступ к справочной системе

Получите доступ к встроенной справочной системе GDB с помощью команд help и apropos. Не знаете, как использовать команду printf? Спросите GDB:

help принимает имя любой команды или параметра GDB и выводит информацию об использовании этой команды или параметра.

Как и все команды GDB, команда help поддерживает завершение с помощью табуляции. Это, пожалуй, самый полезный способ выяснить, какие типы аргументов принимают многие команды. Например, если ввести help show ar и нажать клавишу табуляции, появится запрос на завершение:

GDB оставляет вас в командной строке, готовой принять дальнейшее уточнение ввода. Добавление g к команде, за которой следует табуляция, завершится, чтобы показать аргументы:

Не знаете точное название нужной команды? Используйте команду apropos для поиска в справочной системе определенных терминов. Думайте об этом как о поиске встроенной справки.

Теперь, когда вы знаете, как и где найти помощь, мы готовы перейти к запуску GDB (наконец-то).

Запуск ГБД

Неудивительно, что GDB принимает большое количество параметров командной строки для изменения своего поведения, но самый простой способ запустить GDB — это передать имя приложения в GDB в командной строке:

GDB запускается, выводит некоторую информацию о версии (показан GCC Toolset 10), загружает программу и ее отладочную информацию, а также отображает сообщения об авторских правах и справку, заканчивающиеся командной строкой (gdb) . Теперь GDB готов принять ввод.

Избегание сообщений: опция -q или --quiet

Я видел сообщение о запуске GDB тысячи раз, поэтому я подавляю (или "заглушаю") его с помощью параметра -q:

Читать гораздо меньше. Если вы действительно новичок в GDB, вы можете найти полный обмен сообщениями при запуске полезным или успокаивающим, но через некоторое время вы также будете использовать псевдоним gdb в своей оболочке для gdb -q . Если вам нужна скрытая информация, используйте параметр командной строки -v или команду show version.

Передача аргументов: параметр --args

Программам часто требуются аргументы командной строки. GDB предлагает несколько способов передать их в вашу программу (или "неполноценные" на языке GDB). Два наиболее полезных способа — передать аргументы приложения с помощью команды запуска или при запуске с помощью параметра командной строки --args. Если ваше приложение обычно запускается с myprogram 1 2 3 4 , просто предварите это gdb -q --args и GDB запомнит, как должно запускаться ваше приложение:

Присоединение к запущенному процессу: параметр --pid

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

С этой опцией GDB автоматически загружает символы для программ, которые имеют информацию об идентификаторе сборки, таких как пакеты, поставляемые с дистрибутивом, и прерывает программу, чтобы вы могли взаимодействовать с ней. Узнайте больше о том, как и где GDB находит отладочную информацию, в следующей статье.

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

Совет. Не можете найти основной файл? В системах GNU/Linux, использующих systemd, проверьте ulimit -c, чтобы узнать, не препятствует ли оболочка программам создавать файлы ядра. Если значение неограниченно, используйте coredumpctl, чтобы найти основной файл. В качестве альтернативы запустите sysctl -w kernel.core_pattern=core, чтобы настроить systemd для вывода файлов ядра с именем core. PID , как в предыдущем примере.

Ускоренное выполнение команды: параметры --ex, --iex, --x и --batch

Я часто повторно запускаю команды GDB из оболочки, чтобы проверить наличие проблем или запустить сценарии. Эти параметры командной строки помогают облегчить это. Большинство пользователей будут использовать (несколько) аргументов --ex для указания команд, запускаемых при запуске для воссоздания сеанса отладки, например, gdb -ex "break some_function if arg1 == nullptr" -ex r моя программа .

  • --ex CMD запускает команду GDB CMD после загрузки программы (и отладочной информации). --iex делает то же самое, но выполняет CMD до загрузки указанной программы.
  • -x FILE выполняет команды GDB из FILE после загрузки программы и выполнения команд --ex. Я использую этот параметр чаще всего, если мне нужно много аргументов --ex для воспроизведения определенного сеанса отладки.
  • --batch вызывает немедленный выход из GDB при первой командной строке; т. е. после выполнения всех команд или сценариев. Обратите внимание, что --batch заглушит еще больше вывода, чем -q, чтобы облегчить использование GDB в сценариях:

Далее

В этой статье я поделился подробностями о том, как GDB запускается, читает сценарии (и когда он читает сценарии), а также о нескольких параметрах запуска, обычно используемых опытными пользователями GDB.

В следующей статье этой серии будет небольшое отступление, чтобы объяснить, что такое отладочная информация, как ее проверять, где ее ищет GDB и как устанавливать ее в поставляемые с дистрибутивом пакеты.

Есть ли у вас предложение или совет, связанный со сценариями или запуском GDB, или предложение для будущей темы о том, как использовать GDB? Оставьте комментарий к этой статье и поделитесь с нами своей идеей.

Читайте также: