LLDB (Swift): rzutowanie adresu surowego na typ użytkowy

95

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?

jarrodparkes
źródło

Odpowiedzi:

154

W Xcode 8.2.1 i Swift 3 polecenie lldb po lub p nie będzie działać z wpisaną zmienną. Będziesz musiał użyć szybkiego polecenia print, aby sprawdzić właściwości instancji wpisanego obiektu. (Dzięki odpowiedzi cbownsa !) Np .:

expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)
Xi Chen
źródło
41
To naprawdę nie powinno być takie trudne
Departamento B
To było trochę sprzeczne z intuicją. Myślałem, że nie muszę wpisywać (lldb)w konsoli. Ale to nie zadziałało bez tego.
Miód
2
Czy istnieje sposób, aby to zrobić w celu-c?
p0lAris
Wciąż do tego wracam. Prawdopodobnie powinienem utworzyć alias lldb dla expr -l Swift -- ...
Koen.
49

Możesz użyć unsafeBitCastfunkcji 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 .

gregheo
źródło
Myślę, że w przypadku pierwszego stwierdzenia zapomniałeś „wyrażenia” lub „wyrażenia”. W przeciwnym razie działa świetnie!
jarrodparkes
2
Otrzymuję komunikat „błąd: użycie niezadeklarowanego identyfikatora„ unsafeBitCast ”” w Xcode 7.2.
devios1
8
Poza tym błędem (@devios) jest jeszcze jeden błąd, który wyświetla się w 7.3.1: „błąd: nieznana nazwa typu„ pozwól ””
carlos_ms
3
Zwróć uwagę, że w zależności od kontekstu może być konieczne najpierw przełączenie lldb w tryb Swift przy użyciu (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
Patrick Pijnappel,
25

expressionWyglą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)
sfaxon
źródło
15

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)
afinlayson
źródło
1
Otrzymuję błąd: nie ma takiego modułu „MyProjectName”. Jakieś pomysły, jak to naprawić?
Alexander Stepanishin
@AlexanderStepanishin spróbuj ustawić ścieżkę wątku / stosu, przykład: „MyApp> Thread 1> 12 main”
Juanmi
12

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)
cbowns
źródło
10

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.

Tora
źródło
10

Wersja Objective-C

po ((MKPinAnnotationView *)0x7df67c50).alpha
rockhard
źródło
1
To zadziałało idealnie dla mnie. W moim przypadku byłem w Debug View Hierarchywidoku, kliknąłem prawym przyciskiem myszy widok, a następnie wybrałem Print 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.
Trev14
6

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

  1. Najpierw zaimportuj swój projekt (jeśli chcesz użyć niektórych zdefiniowanych tam klas)

expr -l Swift -- import <YOUR PROJECT NAME>

  1. Przerzuć obiekt używając jego adresu pamięci do dowolnej wybranej klasy

expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: <YOUR PROJECT NAME>.<YOUR CUSTOM CLASS NAME>.self)

  1. Uzyskaj dostęp do dowolnej wartości z obiektu

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)

Bartosz Kunat
źródło
5

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ć $pintak, jak chcesz.

Gobe
źródło
3

pojest 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 poSwift. Obsługuje adresy obiektów i ma kilka innych ulepszeń.

Dave Lee
źródło
z twojego linku, expression -l objc -O -- 0x76543210to tylko odpowiedź dla mnie i nie musi znać zmiennej class z adresu!
tontonCD
2

Najłatwiej, szybko 4

expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
Kingsley Mitchell
źródło