Подтвердить что ты не робот

Xcode/LLDB: как получить информацию об исключении, которое было просто выброшено?

ОК, поэтому представьте, что моя точка останова в objc_exception_throw только что была запущена. Я сижу в приглашении отладчика, и я хочу получить дополнительную информацию об объекте исключения. Где его найти?

4b9b3361

Ответ 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

Источник wikipedia

Ответ 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.