ОК, поэтому представьте, что моя точка останова в objc_exception_throw
только что была запущена. Я сижу в приглашении отладчика, и я хочу получить дополнительную информацию об объекте исключения. Где его найти?
Xcode/LLDB: как получить информацию об исключении, которое было просто выброшено?
Ответ 1
Объект исключения передается как первый аргумент 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 все аргументы функции передаются в стеке, поэтому синтаксис значительно более ужасен. Самое короткое выражение, которое я мог бы построить, чтобы добраться до него, - *(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)
Ответ 2
на новых симуляторах (iOS 8, 64 бит) xcode 6 im, использующих в кадре исключения: objc_exception_throw
po $rax
в 32 бит:
po $eax
Что такое rax?
Rax - это регистр 64 бит, который заменяет старый eax
Как найти все регистры?
register read
Ответ 3
На момент написания этой статьи этот пост стал моим лучшим хитом Google для исключения: lldb print. Таким образом, я добавляю этот ответ в учетную запись для lldb и x86_64.
Мои попытки найти исключение с помощью po $eax
не удалось с помощью error: Couldn't materialize struct: Couldn't read eax (materialize)
. Другие попытки, описанные в связанных документах из более ранних ответов, также потерпели неудачу.
Ключ должен был сначала щелкнуть рамку objc_exception_throw
в моем основном потоке. lldb не запускается в этом фрейме.
Во всех моих поисковых и последующих примерах эта запись в блоге была первой, кто объяснил вещи таким образом, который работал на меня. Это более современное издание, размещенное в августе 2012 года.
Ответ 4
Проверьте это место, он расскажет вам, как справляться с этими ошибками:
http://www.markj.net/debugging-tip-objc_exception_throw-breakpoint/
Показывает, как добавить точки останова и выяснить, где это происходит в вашем коде. Это покажет вам, где эта вещь.
Ответ 5
Если у вас есть оператор catch, поставьте там точку останова, и вы можете проверить объект исключения в этой точке.
Если у вас нет оператора catch, продолжайте.
Вы получите сообщение в своем терминале следующим образом:
Завершение приложения из-за неперехваченного исключения "NSInvalidArgumentException", причина: '* - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: попытка вставить нулевой объект из объектов [0]'
Тем не менее, вы, вероятно, ищете способ проверить его, не продолжая, так как вы потеряете красивую трассировку стека при завершении приложения.
Для этого это звучит, как лучший ответ Fnord, но я не смог заставить его работать в LLDB.