Czy istnieje polecenie LLDB, które może rzutować surowy adres na użyteczną klasę Swift?
Na przykład:
(lldb) po 0x7df67c50 as MKPinAnnotationView
Wiem, że ten adres wskazuje na MKPinAnnotationView, ale nie ma go w ramce, którą mogę wybrać. Ale chcę rzutować surowy adres na MKPinAnnotationView, aby móc zbadać jego właściwości. czy to możliwe?
(lldb)
w konsoli. Ale to nie zadziałało bez tego.expr -l Swift --
...Możesz użyć
unsafeBitCast
funkcji Swift do rzutowania adresu na instancję obiektu:(lldb) e let $pin = unsafeBitCast(0x7df67c50, MKPinAnnotationView.self) (lldb) po $pin
Wtedy możesz pracować
$pin
jak zwykle - właściwości dostępu, metody wywołania itp.Przeczytaj ten artykuł, aby uzyskać więcej informacji: Szybkie zrzucanie pamięci .
źródło
(lldb) settings set target.language swift
. Ponadto w niektórych przypadkach (np. Podczas przerywania pracy poza modułem aplikacji podczas przesyłania do typu z aplikacji) może być konieczne wykonanie tego za pomocąe import MyApp
expression
Wygląda na to, że format lldb dla programu Xcode 7.3 zmienił się. Zacząłem od następujących rzeczy:(lldb) expr -l Swift -- import UIKit (lldb) expr -l Swift -- let $view = unsafeBitCast(0x7fb75d8349c0, UIView.self)
źródło
W przypadku klas niestandardowych musisz zaimportować swój projekt
expr -l Swift -- import MyTestProject expr -l Swift -- let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self) expr -l Swift -- print($vc.view)
źródło
Od Xcode 8 / Swift 3, oto co zadziałało dla mnie. (Jest to oparte na odpowiedzi @ sfaxon ).
(lldb) expr -l Swift -- import UIKit (lldb) expr -l Swift -- let $nav = unsafeBitCast(0x1030ff000, to: UINavigationController.self)
źródło
Dzięki wszystkim powyższym odpowiedziom, unsafeBitCast działa również dobrze z aplikacją Xcode 8.3.2 / Swift 3 / macOS / Cocoa.
Zapamiętaj adres bieżącej instancji
(lldb) p tabView.controlTint (NSControlTint) $R10 = defaultControlTint (lldb) p self (LearningStoryboard.NSTabViewController) $R11 = 0x00006080000e2280 { .....
Później je zbadaj
(lldb) p unsafeBitCast(0x00006080000e2280, to: NSTabViewController.self).tabView.controlTint (NSControlTint) $R20 = graphiteControlTint (lldb) p $R11.tabView.controlTint (NSControlTint) $R21 = graphiteControlTint
Jeśli coś takiego się wydarzy
(lldb) p unsafeBitCast(0x00006080000e2280, to: NSTabViewController.self).tabView.controlTint error: use of undeclared identifier 'to' (lldb) p $R11.tabView.controlTint error: use of undeclared identifier '$R11'
upewnij się, że wybierasz jedną z ramek stosu kodu źródłowego Swift zamiast jednej z asemblera.
Może się to zdarzyć, gdy aplikacja została wstrzymana przez kliknięcie przycisku Wstrzymaj lub zatrzymana z wyjątkiem. Wybierając odpowiednio ramkę stosu, pozwólmy lldb wywnioskować właściwy język programowania.
źródło
Wersja Objective-C
po ((MKPinAnnotationView *)0x7df67c50).alpha
źródło
Debug View Hierarchy
widoku, kliknąłem prawym przyciskiem myszy widok, a następnie wybrałemPrint description of...
. To dało mi adres pamięci i typ, który mogłem wrzucić do powyższego kodu. Dobrze wiedzieć, że wizualny debugger umieszcza konsolę w ramce Obj-C.Dłużej zajęło mi zorientowanie się, do czego chciałbym się przyznać. Jest podobny do odpowiedzi @afinlayson, ale z lepszym wyjaśnieniem (mam nadzieję!) I poprawioną składnią
Jeśli chcesz sprawdzić właściwości obiektów za pomocą debugera hierarchii widoków Xcode, to zadziała: Domyślnie jesteś w kontekście objc, więc musisz przełączyć go na kontekst Swift
expr -l Swift -- import <YOUR PROJECT NAME>
expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: <YOUR PROJECT NAME>.<YOUR CUSTOM CLASS NAME>.self)
expr -l Swift -- print($vc.<PROPERTY NAME>)
Przykład:
expr -l Swift -- import Football
expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: Football.Ball.self)
expr -l Swift -- print($vc.velocity)
źródło
Odpowiedź @Xi Chena działa doskonale, gdy sesja LLDB została uruchomiona w kontekście Swift. Jednak w niektórych przypadkach mogłeś zatrzymać się w punkcie przerwania poza kontekstem Swift; na przykład, gdy jest to symboliczny punkt przerwania interfejsu API Objective-C lub w trybie hierarchii widoku debugowania (przynajmniej od Xcode 11.4).
error: unknown type name 'let' error: use of undeclared identifier 'unsafeBitCast'
W takim przypadku musisz zrobić to w stary sposób, używając Objective-C:
e MKPinAnnotationView *$pin = (MKPinAnnotationView *)0x7df67c50
a teraz możesz używać
$pin
tak, jak chcesz.źródło
po
jest aliasem, co oznacza, że można go przesłonić. Możesz nadpisaćpo
, obsługując adresy szesnastkowe za pomocą objc:command regex po s/(0x[[:xdigit:]]+)/expression -l objc -O -- %1/ s/(.+)/expression -O -- %1/
Aby zobaczyć, jaki to ma wpływ, możesz powiedzieć lldb, aby rozwinął te aliasy:
(lldb) settings set interpreter.expand-regex-aliases true
Stworzyłem również https://github.com/kastiglione/swift_po , który jest substytutem
po
Swift. Obsługuje adresy obiektów i ma kilka innych ulepszeń.źródło
expression -l objc -O -- 0x76543210
to tylko odpowiedź dla mnie i nie musi znać zmiennej class z adresu!Najłatwiej, szybko 4
expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
źródło