Хорошо, представьте, что моя точка останова objc_exception_throw
только что сработала. Я сижу в приглашении отладчика и хочу получить дополнительную информацию об объекте исключения. Где мне это найти?
Хорошо, представьте, что моя точка останова 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
и затем введите эту команду:
(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
po $rax
в 32-битной версии:
po $eax
Что такое 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.