Добре, так що уявіть, що моя точка зупинки в 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, 64 біт) xcode 6 im, використовуючи у фреймі винятку: objc_exception_throw
po $rax
32-бітним:
po $eax
Що таке ракс?
Rax - це 64-бітний регістр, який замінює старий eax
Як знайти всі реєстри?
register read
На момент написання цієї статті ця публікація є моїм найпопулярнішим хітом у Google для: lldb виняток для друку . Таким чином, я додаю цю відповідь до облікових записів lldb та x86_64.
Мої спроби знайти виняток, використовуючи po $eax
помилку з error: Couldn't materialize struct: Couldn't read eax (materialize)
. Інші спроби, описані у пов'язаних документах з попередніх відповідей, також не вдалися.
Ключ у тому, що мені довелося спочатку клацнути на objc_exception_throw
рамку в моїй головній темі. lldb не запускається в цьому кадрі.
У всіх моїх пошукових та наступних прикладах цей запис у блозі був першим, хто пояснив речі так, як мені вдалося. Він більш сучасний, розміщений у серпні 2012 року.
Якщо у вас є оператор catch, поставте там точку зупинки, і ви зможете перевірити об’єкт виключення в цій точці.
Якщо у вас немає заяви про улов, продовжуйте.
Ви отримаєте повідомлення у своєму терміналі таким чином:
Завершення програми через невпійманий виняток 'NSInvalidArgumentException', причина: ' * - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: спроба вставити нульовий об'єкт з об'єктів [0]'
Однак ви, мабуть, шукаєте спосіб перевірити його, не продовжуючи, оскільки ви втратите приємний слід стека, коли додаток буде припинено.
З цього звучить, що відповідь Фнорда найкраща, але мені не вдалося змусити її працювати в LLDB.