Xcode / LLDB: как получить информацию об только что сгенерированном исключении?
84
Хорошо, представьте, что моя точка останова objc_exception_throwтолько что сработала. Я сижу в приглашении отладчика и хочу получить дополнительную информацию об объекте исключения. Где мне это найти?
Объект исключения передается в качестве первого аргумента objc_exception_throw. LLDB предоставляет $arg1.. $argnпеременные для ссылки на аргументы в правильном соглашении о вызовах, что упрощает распечатку деталей исключения:
(lldb) po $arg1
(lldb) po [$arg1 name]
(lldb) po [$arg1 reason]
Перед objc_exception_throwвыполнением этих команд обязательно выберите фрейм в стеке вызовов. См. «Расширенная отладка и средство очистки адресов» в видеороликах сеанса WWDC15, чтобы увидеть, как это выполняется на сцене.
Устаревшая информация
Если вы используете GDB, синтаксис для ссылки на первый аргумент зависит от соглашений о вызовах архитектуры, в которой вы работаете. Если вы выполняете отладку на реальном устройстве iOS, указатель на объект находится в регистре r0. Чтобы распечатать его или отправить ему сообщение, используйте следующий простой синтаксис:
(gdb) po $r0
(gdb) po [$r0 name]
(gdb) po [$r0 reason]
В iPhone Simulator все аргументы функции передаются в стек, поэтому синтаксис значительно ужаснее. Самое короткое выражение, которое я смог построить, это *(id *)($ebp + 8). Чтобы сделать вещи менее болезненными, я предлагаю использовать вспомогательную переменную:
(gdb) set $exception = *(id *)($ebp + 8)
(gdb) po $exception
(gdb) po [$exception name]
(gdb) po [$exception reason]
Вы также можете установить $exceptionавтоматически всякий раз, когда срабатывает точка останова, добавив список команд к objc_exception_throwточке останова.
(Обратите внимание , что во всех случаях , которые я тестировал, объект исключения также присутствовал в eaxи edxреестрах в момент точки останова попадании. Я не уверен , что будет всегда так, хотя.)
Добавлено из комментария ниже:
В lldb выберите кадр стека для objc_exception_throwи затем введите эту команду:
Хм ... В Xcode 6.1 я получаю: (lldb) po $ rax error: Не удалось материализовать: не удалось прочитать значение регистра rax.
Ошибка
Симулятор или устройство @bradheintz? Я пробовал это с 6.0.1
Жуан Нуньес,
Не могли бы вы указать ссылку на свой источник для этого? Благодаря!
Крис Коновер,
Я просто написал в lldb: регистр читать. Затем с помощью этой информации мы знаем, что первый регистр в кадре исключения содержит сообщение об исключении.
Жуан Нуньес,
Хорошо, я нашел несколько документов: rax - это 64-битный регистр: в 64-битном длинном режиме вы можете использовать 64-битные регистры (например, rax вместо eax, rbx вместо ebx и т. Д.)
João Nunes
6
На момент написания этой статьи я стал самым популярным в Google по: lldb print exception . Таким образом, я добавляю этот ответ для учета lldb и x86_64.
Мои попытки найти исключение с помощью po $eaxне удались error: Couldn't materialize struct: Couldn't read eax (materialize). Другие попытки, описанные в связанных документах из более ранних ответов, также потерпели неудачу.
Ключевым моментом было то, что мне нужно было сначала щелкнуть objc_exception_throwфрейм в основном потоке. lldb не запускается в этом кадре.
Во всех моих поисках и следующих примерах эта запись в блоге была первой, которая объясняла вещи так, как это работало для меня. Он более современный, размещен в августе 2012 года.
Если у вас есть инструкция catch, поставьте там точку останова, и вы сможете проверить объект исключения в этой точке.
Если у вас нет оператора catch, продолжайте.
В терминале вы получите такое сообщение:
Завершение работы приложения из-за неперехваченного исключения «NSInvalidArgumentException», причина: « * - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: попытка вставить нулевой объект из объектов [0]»
Однако вы, вероятно, ищете способ проверить его, не продолжая, поскольку вы потеряете хорошую трассировку стека при завершении приложения.
Похоже, что ответ Фнорда лучше всего, но мне не удалось заставить его работать в LLDB.
Ответы:
Объект исключения передается в качестве первого аргумента
objc_exception_throw
. LLDB предоставляет$arg1
..$argn
переменные для ссылки на аргументы в правильном соглашении о вызовах, что упрощает распечатку деталей исключения:Перед
objc_exception_throw
выполнением этих команд обязательно выберите фрейм в стеке вызовов. См. «Расширенная отладка и средство очистки адресов» в видеороликах сеанса WWDC15, чтобы увидеть, как это выполняется на сцене.Устаревшая информация
Если вы используете GDB, синтаксис для ссылки на первый аргумент зависит от соглашений о вызовах архитектуры, в которой вы работаете. Если вы выполняете отладку на реальном устройстве iOS, указатель на объект находится в регистре
r0
. Чтобы распечатать его или отправить ему сообщение, используйте следующий простой синтаксис:В iPhone Simulator все аргументы функции передаются в стек, поэтому синтаксис значительно ужаснее. Самое короткое выражение, которое я смог построить, это
*(id *)($ebp + 8)
. Чтобы сделать вещи менее болезненными, я предлагаю использовать вспомогательную переменную:(gdb) set $exception = *(id *)($ebp + 8) (gdb) po $exception (gdb) po [$exception name] (gdb) po [$exception reason]
Вы также можете установить
$exception
автоматически всякий раз, когда срабатывает точка останова, добавив список команд кobjc_exception_throw
точке останова.(Обратите внимание , что во всех случаях , которые я тестировал, объект исключения также присутствовал в
eax
иedx
реестрах в момент точки останова попадании. Я не уверен , что будет всегда так, хотя.)Добавлено из комментария ниже:
В lldb выберите кадр стека для
objc_exception_throw
и затем введите эту команду:(lldb) po *(id *)($esp + 4)
источник
objc_exception_throw
в LLDB :po *(id *)($esp + 4)
.objc_exception_throw
).po $eax
у меня работает в симуляторе как привязка к$r0
устройству.на новых симуляторах (iOS 8, 64bit) xcode 6 im, используя в кадре исключения:
objc_exception_throw
в 32-битной версии:
Что такое rax?
Rax - это 64-битный регистр, который заменяет старый eax
Как найти все регистры?
register read
Источник википедия
источник
На момент написания этой статьи я стал самым популярным в Google по: lldb print exception . Таким образом, я добавляю этот ответ для учета lldb и x86_64.
Мои попытки найти исключение с помощью
po $eax
не удалисьerror: Couldn't materialize struct: Couldn't read eax (materialize)
. Другие попытки, описанные в связанных документах из более ранних ответов, также потерпели неудачу.Ключевым моментом было то, что мне нужно было сначала щелкнуть
objc_exception_throw
фрейм в основном потоке. lldb не запускается в этом кадре.Во всех моих поисках и следующих примерах эта запись в блоге была первой, которая объясняла вещи так, как это работало для меня. Он более современный, размещен в августе 2012 года.
источник
Если у вас есть инструкция catch, поставьте там точку останова, и вы сможете проверить объект исключения в этой точке.
Если у вас нет оператора catch, продолжайте.
В терминале вы получите такое сообщение:
Завершение работы приложения из-за неперехваченного исключения «NSInvalidArgumentException», причина: « * - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: попытка вставить нулевой объект из объектов [0]»
Однако вы, вероятно, ищете способ проверить его, не продолжая, поскольку вы потеряете хорошую трассировку стека при завершении приложения.
Похоже, что ответ Фнорда лучше всего, но мне не удалось заставить его работать в LLDB.
источник