Хорошо, представьте, что моя точка останова 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.