Xcode / LLDB: Як отримати інформацію про щойно створений виняток?


83

Добре, так що уявіть, що моя точка зупинки в objc_exception_throwщойно спрацювала. Я сиджу за запитом налагоджувача і хочу отримати детальну інформацію про об’єкт виключення. Де я його знаходжу?


2
Пам’ятайте, що виняток щойно було застосовано, його опис ще не надруковано на консолі.
Karoy Lorentey

Перевірте це питання: stackoverflow.com/questions/711650
Микола Фетисов

Відповіді:


162

Об'єкт виключення передається як перший аргумент 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)

6
Як можна це зробити в lldb? Я отримую помилку "Помилка: посилання на" id "є неоднозначним"
обирати

2
Ви можете надати джерело цієї інформації? я хотів би прочитати більше про це
Жоао Нунес

3
В даний час наступних робіт для мене до прологу , коли breaing на objc_exception_throw в LLDB : po *(id *)($esp + 4).
wbyoung

7
Це спрацювало! Однак це не спрацювало, доки я не вибрав фрейм стека 0 . ( objc_exception_throw).
Фунрол

7
po $eaxпрацює у мене в тренажері як підвіска до $r0коли на пристрої.
monkeydom

10

на нових симуляторах (iOS 8, 64 біт) xcode 6 im, використовуючи у фреймі винятку: objc_exception_throw

po $rax

32-бітним:

po $eax

Що таке ракс?

Rax - це 64-бітний регістр, який замінює старий eax

Як знайти всі реєстри?

register read

Джерело wikipedia


Хм ... У Xcode 6.1 я отримую: (lldb) po $ rax помилка: Не вдалося матеріалізуватися: не вдалося прочитати значення регістру rax Помилка у виконанні, не вдалося PrepareToExecuteJITExpression
bradheintz

@bradheintz симулятор або пристрій? я спробував це з 6.0.1
Жоао Нунес

Ви можете вказати посилання на своє джерело для цього? Дякую!
Chris Conover

Я щойно писав у lldb: зареєструйте прочитане. Тоді з цією інформацією ми знаємо, що перший регістр у фреймі винятку містить повідомлення про виняток.
João Nunes

Гаразд, я знайшов деякі документи: rax - це 64-бітний регістр: У 64-розрядному довгому режимі ви можете використовувати 64-розрядні регістри (наприклад, rax замість eax, rbx замість ebx тощо)
João Nunes

6

На момент написання цієї статті ця публікація є моїм найпопулярнішим хітом у Google для: lldb виняток для друку . Таким чином, я додаю цю відповідь до облікових записів lldb та x86_64.

Мої спроби знайти виняток, використовуючи po $eaxпомилку з error: Couldn't materialize struct: Couldn't read eax (materialize). Інші спроби, описані у пов'язаних документах з попередніх відповідей, також не вдалися.

Ключ у тому, що мені довелося спочатку клацнути на objc_exception_throwрамку в моїй головній темі. lldb не запускається в цьому кадрі.

У всіх моїх пошукових та наступних прикладах цей запис у блозі був першим, хто пояснив речі так, як мені вдалося. Він більш сучасний, розміщений у серпні 2012 року.


1

Якщо у вас є оператор catch, поставте там точку зупинки, і ви зможете перевірити об’єкт виключення в цій точці.

Якщо у вас немає заяви про улов, продовжуйте.

Ви отримаєте повідомлення у своєму терміналі таким чином:

Завершення програми через невпійманий виняток 'NSInvalidArgumentException', причина: ' * - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: спроба вставити нульовий об'єкт з об'єктів [0]'

Однак ви, мабуть, шукаєте спосіб перевірити його, не продовжуючи, оскільки ви втратите приємний слід стека, коли додаток буде припинено.

З цього звучить, що відповідь Фнорда найкраща, але мені не вдалося змусити її працювати в LLDB.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.