lldb/

Бывает, что нужно отладить программу, а 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, к сожалению, нет совсем.

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

EnglishRussianUkrainian