Памятка по использованию отладчика LLDB
13 июля 2016
Бывает, что нужно отладить программу, а GDB при этом недоступен. Например, потому что программу вы отлаживаете под MacOS или FreeBSD, а в этих системах традиционно используется отладчик LLDB. Лично я в последнее время склонен отдавать предпочтение LLVM-стэку (CLang, LLDB) даже на Linux-машинах, где по дэфолту используется GNU-стэк (GCC, GDB). В LLDB все еще есть кое-какие шероховатости. Но команды структурированы намного лучше, чем в GDB, а шероховатости со временем все равно поправят. Так или иначе, в процессе изучения LLDB я составил шпаргалку по основным его командам, которой и хочу сегодня с вами поделиться.
Важно! LLDB и вообще LLVM-стэк является сравнительно молодым проектом. Желательно использовать последнюю его версию, так как в новых релизах исправляют существенное количество багов и недоработок. Во FreeBSD последнюю версию LLDB можно установить из портов. О том, как установить последний LLVM / CLang / LLDB в Ubuntu Linux, ранее рассказывалось в заметке Определение степени покрытия кода на C/C++ тестами.
Примечание: Хоть ниже часто приводятся полные версии команд, можно использовать и короткие, например fr v
вместо frame variables
. Также все команды автодополняются при нажатии Tab.
Подрубиться к процессу:
На момент написания этих строк в LLDB был неприятный баг. Под FreeBSD, если программа использовала вызов setproctitle()
, к ней не удастся подключиться. Эту проблему при желании можно обойти. Например, если вы пилите что-то для PostgreSQL, то для определения pid бэкенда можно использовать запрос SELECT pg_backend_pid();
(а еще удобнее прописать \set PROMPT1 '%p =# '
в ~/.psqlrc) и компилировать PostgreSQL примерно так:
echo '#undef HAVE_SETPROCTITLE' >> ./src/include/pg_config.h
Запуск программы с заданными аргументами:
Анализ корки:
Удаленная отладка. У меня лично не удалось ею воспользоваться на двух виртуалках с FreeBSD, происходила ошибка Process 1 exited with status = -1 (0xffffffff) lost connection
. Но в теории делается так.
На сервере в bash выполняем команду:
На клиенте запускаем LLDB без аргументов в нем:
platform select remote-freebsd
platform connect connect://192.168.122.184:1234
На сервере должны увидеть:
Теперь в LLDB на клиенте можно сказать:
platform process launch -c pwd
Просмотр справки:
help process
help process save-core
Выйти из отладчика (не прибивает процесс, как и в GDB):
Создать корку из отладчика:
Начать выполнение программы, если она еще не выполняется:
r (аргументы)
Продолжить выполнение программы:
process continue
Прервать выполнение программы:
Посмотреть исходный код:
list main.c:123
source list -f heapam.c -l 3050 -c 20
Когда исходников под рукой нет, можно посмотреть ассемблерный код:
disassemble --name main
disassemble --start-address 0x1a2b3c --end-address 0x4d5e6f
Чтение и запись регистров:
register read --all
register read rcx
register write al 0xCC
Step — шаг вперед или несколько шагов вперед:
s -c 10
Next — как step, только без захода внутрь других методов и процедур:
n -c 10
Until — выполнить программу до указанной строчки:
Продолжить выполнение до возвращения из текущей процедуры:
Посмотреть стэктрейс:
Перемещение между фреймами стака:
fr s 1
Информация о текущем фрейме:
Показать аргументы и переменные в текущем фрейме:
Показать только локальные переменные, без аргументов:
Показать только аргументы, без локальных переменных:
Ставим бряк:
b proc_name
Список бряков:
Удаление бряка по номеру:
Временное включение и выключение бряков:
breakpoint enable 1
Удаление всех бряков:
Вачпоинты — как бряки, только на обращение к памяти (заметьте, что одновременно можно создавать ограниченное количество вачпоинтов):
watchpoint list
watchpoint delete 1
Условные брейкпоинты ставятся как-то так (не забывайте взять условие в кавычки!):
b -f fasttab.c -l 679 --condition 'result <= 0'
Заметьте, что b fname.c:123 --condition
не работает!
Список нитей:
Переключение на нитку:
Вывести значение переменных:
p my_struct->my_field
Можно менять значения переменных в программе:
Также можно кастовать типы:
Вообще, можно использовать отладчик, как калькулятор:
Чтение памяти:
me r --size 4 --format u --count 6 &event --outfile /tmp/1.txt
Запись в память:
Выполнение пачки операций:
Пример файла lldb.batch:
quit
По моему опыту, описанных выше команд хватает практически на все случаи жизни. Действительно не хватает разве что поддержки reverse debugging, которой на момент написания этих строк в LLDB, к сожалению, нет совсем.
Дополнение: Один простой, но эффективный отладочный прием
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.