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ę?
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:
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.
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.
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: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: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ń doobjc_exception_throw
punktu przerwania.(Zauważ, że we wszystkich testowanych przeze mnie przypadkach obiekt wyjątku był również obecny w rejestrze
eax
iedx
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)
źródło
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
w wersji 32-bitowej:
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
źródło
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.
źródło
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.
źródło