Xcode / LLDB: Jak uzyskać informacje o wyjątku, który właśnie został zgłoszony?

84

OK, więc wyobraź sobie, że objc_exception_throwwł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ę?

Karoy Lorentey
źródło
2
Pamiętaj, że wyjątek został właśnie zgłoszony, jego opis nie został jeszcze wydrukowany na konsoli.
Karoy Lorentey
Sprawdź to pytanie: stackoverflow.com/questions/711650
Nikolai Fetissov

Odpowiedzi:

163

Obiekt wyjątku jest przekazywany jako pierwszy argument do objc_exception_throw. LLDB udostępnia zmienne $arg1.. $argndo 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_throwPrzed 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ć $exceptionautomatycznie, gdy punkt przerwania jest wyzwalany, dodając listę poleceń do objc_exception_throwpunktu przerwania.

(Zauważ, że we wszystkich testowanych przeze mnie przypadkach obiekt wyjątku był również obecny w rejestrze eaxi edxw 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_throwa następnie wprowadź następujące polecenie:

(lldb) po *(id *)($esp + 4)
Karoy Lorentey
źródło
6
Jak można to zrobić w lldb?
Pojawia
2
czy możesz podać źródło tych informacji? chciałbym przeczytać więcej na ten temat
João Nunes
3
Obecnie następujące prace dla mnie przed prologiem gdy breaing na objc_exception_throw w LLDB : po *(id *)($esp + 4).
2013
7
To zadziałało! Jednak nie zadziałało, dopóki nie wybrałem ramki stosu 0 . ( objc_exception_throw).
funroll
7
po $eaxdziała u mnie w symulatorze jako zawieszka $r0na urządzeniu.
monkeydom
11

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

Źródło wikipedia

João Nunes
źródło
Hmm ... W Xcode 6.1 otrzymuję: (lldb) błąd po $ rax: Nie można zmaterializować: nie można odczytać wartości rejestru rax Błąd w wykonaniu, nie można
wykonać polecenia PrepareToExecuteJITExpression
Symulator lub urządzenie @bradheintz? Próbowałem tego z 6.0.1
João Nunes
Czy możesz wskazać link do swojego źródła? Dzięki!
Chris Conover,
Właśnie napisałem w lldb: register read. Dzięki tym informacjom wiemy, że pierwszy rejestr w ramce wyjątku przechowuje komunikat wyjątku.
João Nunes
Ok, znalazłem kilka dokumentów: rax to rejestr 64-bitowy: W trybie 64-bitowym można używać rejestrów 64-bitowych (np. Rax zamiast eax, rbx zamiast ebx, itd.)
João Nunes
6

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 $eaxnie 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_throwramkę 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.

Jeff
źródło
1

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.

funroll
źródło