Памятка по использованию отладчика 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 -p 12345

На момент написания этих строк в LLDB был неприятный баг. Под FreeBSD, если программа использовала вызов setproctitle(), к ней не удастся подключиться. Эту проблему при желании можно обойти. Например, если вы пилите что-то для PostgreSQL, то для определения pid бэкенда можно использовать запрос SELECT pg_backend_pid(); (а еще удобнее прописать \set PROMPT1 '%p =# ' в ~/.psqlrc) и компилировать PostgreSQL примерно так:

./configure ... && \
  echo '#undef HAVE_SETPROCTITLE' >> ./src/include/pg_config.h

Запуск программы с заданными аргументами:

lldb -- ./proc arg1 arg2 arg3

Анализ корки:

lldb /path/to/executable -c 12345.core

Удаленная отладка. У меня лично не удалось ею воспользоваться на двух виртуалках с FreeBSD, происходила ошибка Process 1 exited with status = -1 (0xffffffff) lost connection. Но в теории делается так.

На сервере в bash выполняем команду:

lldb-server platform --listen *:1234

На клиенте запускаем LLDB без аргументов в нем:

platform list
platform select remote-freebsd
platform connect connect://192.168.122.184:1234

На сервере должны увидеть:

Connection established.

Теперь в LLDB на клиенте можно сказать:

platform process attach --pid 62433
platform process launch -c pwd

Просмотр справки:

help
help process
help process save-core

Выйти из отладчика (не прибивает процесс, как и в GDB):

q

Создать корку из отладчика:

process save-core /tmp/1.core

Начать выполнение программы, если она еще не выполняется:

r
r (аргументы)

Продолжить выполнение программы:

c
process continue

Прервать выполнение программы:

process interrupt

Посмотреть исходный код:

list
list main.c:123
source list -f heapam.c -l 3050 -c 20

Когда исходников под рукой нет, можно посмотреть ассемблерный код:

disassable
disassemble --name main
disassemble --start-address 0x1a2b3c --end-address 0x4d5e6f

Чтение и запись регистров:

register read
register read --all
register read rcx
register write al 0xCC

Step — шаг вперед или несколько шагов вперед:

s
s -c 10

Next — как step, только без захода внутрь других методов и процедур:

n
n -c 10

Until — выполнить программу до указанной строчки:

thread until 123

Продолжить выполнение до возвращения из текущей процедуры:

finish

Посмотреть стэктрейс:

bt

Перемещение между фреймами стака:

frame select 1
fr s 1

Информация о текущем фрейме:

frame info

Показать аргументы и переменные в текущем фрейме:

frame variable

Показать только локальные переменные, без аргументов:

frame variable --no-args

Показать только аргументы, без локальных переменных:

frame variable --no-locals

Ставим бряк:

b file.c:123
b proc_name

Список бряков:

breakpoint list

Удаление бряка по номеру:

breakpoint delete 1

Временное включение и выключение бряков:

breakpoint disable 1
breakpoint enable 1

Удаление всех бряков:

breakpoint delete

Вачпоинты — как бряки, только на обращение к памяти (заметьте, что одновременно можно создавать ограниченное количество вачпоинтов):

watchpoint set variable some_global_var
watchpoint list
watchpoint delete 1

Условные брейкпоинты ставятся как-то так (не забывайте взять условие в кавычки!):

b --name heap_delete --condition 'relation->rd_id == 1259'
b -f fasttab.c -l 679 --condition 'result <= 0'

Заметьте, что b fname.c:123 --condition не работает!

Список нитей:

thread list

Переключение на нитку:

thread select 5

Вывести значение переменных:

p my_var
p my_struct->my_field

Можно менять значения переменных в программе:

p someVar=123

Также можно кастовать типы:

p (long)argv[0]

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

p (10.0+20+30)/sizeof(int)

Чтение памяти:

memory read --size 1 --format x --count 24 &event
me r --size 4 --format u --count 6 &event --outfile /tmp/1.txt

Запись в память:

memory write --size 1 --format x &event 0xa1 0xb2 0xc3

Выполнение пачки операций:

lldb -p 62510 --batch -s lldb.batch

Пример файла lldb.batch:

bt
quit

По моему опыту, описанных выше команд хватает практически на все случаи жизни. Действительно не хватает разве что поддержки reverse debugging, которой на момент написания этих строк в LLDB, к сожалению, нет совсем.

Дополнение: Один простой, но эффективный отладочный прием

Метки: , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.