OK, więc wyobraź sobie, że objc_exception_throw
właśnie został uruchomiony mój punkt przerwania . Siedzę w wierszu debugera i chcę uzyskać więcej informacji o obiekcie wyjątku. Gdzie ja to znajdę?
OK, więc wyobraź sobie, że objc_exception_throw
właśnie został uruchomiony mój punkt przerwania . Siedzę w wierszu debugera i chcę uzyskać więcej informacji o obiekcie wyjątku. Gdzie ja to znajdę?
Odpowiedzi:
Obiekt wyjątku jest przekazywany jako pierwszy argument do objc_exception_throw
. LLDB udostępnia zmienne $arg1
.. $argn
do odwoływania się do argumentów w prawidłowej konwencji wywoływania, co ułatwia wydrukowanie szczegółów wyjątku:
(lldb) po $arg1
(lldb) po [$arg1 name]
(lldb) po [$arg1 reason]
objc_exception_throw
Przed wykonaniem tych poleceń pamiętaj, aby zaznaczyć ramkę w stosie wywołań. Zobacz „Zaawansowane debugowanie i narzędzie do dezynfekcji adresów” w filmach z sesji WWDC15, aby zobaczyć, jak to działa na scenie.
Nieaktualne informacje
Jeśli korzystasz z GDB, składnia odnosząca się do pierwszego argumentu zależy od konwencji wywoływania architektury, na której pracujesz. Jeśli debugujesz na rzeczywistym urządzeniu z systemem iOS, wskaźnik do obiektu jest zarejestrowany r0
. Aby go wydrukować lub wysłać do niego wiadomości, użyj następującej prostej składni:
(gdb) po $r0
(gdb) po [$r0 name]
(gdb) po [$r0 reason]
W symulatorze iPhone'a wszystkie argumenty funkcji są przekazywane na stos, więc składnia jest znacznie okropniejsza. Najkrótszym wyrażeniem, jakie mogłem stworzyć, jest *(id *)($ebp + 8)
. Aby uczynić rzeczy mniej bolesnymi, sugeruję użycie zmiennej wygody:
(gdb) set $exception = *(id *)($ebp + 8)
(gdb) po $exception
(gdb) po [$exception name]
(gdb) po [$exception reason]
Możesz również ustawić $exception
automatycznie, gdy punkt przerwania jest wyzwalany, dodając listę poleceń do objc_exception_throw
punktu przerwania.
(Zauważ, że we wszystkich testowanych przeze mnie przypadkach obiekt wyjątku był również obecny w rejestrze eax
i edx
w momencie trafienia punktu przerwania. Nie jestem jednak pewien, czy zawsze tak będzie).
Dodano z komentarza poniżej:
W lldb wybierz ramkę stosu dla, objc_exception_throw
a następnie wprowadź następujące polecenie:
(lldb) po *(id *)($esp + 4)
objc_exception_throw
w LLDB : po *(id *)($esp + 4)
.
objc_exception_throw
).
po $eax
działa u mnie w symulatorze jako zawieszka $r0
na urządzeniu.
na nowych symulatorach (iOS 8, 64-bitowy) xcode 6 używam w ramce wyjątku: objc_exception_throw
po $rax
w wersji 32-bitowej:
po $eax
Co to jest rax?
Rax to rejestr 64-bitowy, który zastępuje stary eax
Jak znaleźć wszystkie rejestry?
register read
W chwili pisania tego posta jest moim największym hitem Google dla: wyjątku drukowania lldb . Dlatego dodaję tę odpowiedź, aby uwzględnić lldb i x86_64.
Moje próby znalezienia wyjątku za pomocą po $eax
nie powiodły się error: Couldn't materialize struct: Couldn't read eax (materialize)
. Inne próby opisane w połączonych dokumentach z wcześniejszych odpowiedzi również się nie powiodły.
Kluczem było to, że najpierw musiałem kliknąć objc_exception_throw
ramkę w moim głównym wątku. lldb nie zaczyna się w tej ramce.
We wszystkich moich poszukiwaniach i podążaniu za przykładami ten wpis na blogu był pierwszym, który wyjaśnił rzeczy w sposób, który działał dla mnie. Jest bardziej nowoczesny, opublikowany w sierpniu 2012.
Jeśli masz instrukcję catch, umieść tam punkt przerwania i możesz sprawdzić obiekt wyjątku w tym miejscu.
Jeśli nie masz instrukcji catch, kontynuuj.
Otrzymasz wiadomość na swoim terminalu w następujący sposób:
Zakończenie aplikacji z powodu nieprzechwyconego wyjątku „NSInvalidArgumentException”, przyczyna: „ * - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: próba wstawienia zerowego obiektu z obiektów [0]”
Jednak prawdopodobnie szukasz sposobu na sprawdzenie go bez kontynuowania, ponieważ utracisz ładny ślad stosu, gdy aplikacja zostanie zakończona.
Dlatego wydaje się, że odpowiedź Fnorda jest najlepsza, ale nie udało mi się uruchomić jej w LLDB.