LLDB (Swift): Casting Raw Address in Usable Type


92

Esiste un comando LLDB in grado di trasmettere un indirizzo grezzo in una classe Swift utilizzabile?

Per esempio:

(lldb) po 0x7df67c50 as MKPinAnnotationView

So che questo indirizzo punta a un MKPinAnnotationView, ma non è in un frame che posso selezionare. Tuttavia, voglio eseguire il cast dell'indirizzo grezzo in un MKPinAnnotationView in modo da poter esaminare le sue proprietà. È possibile?

Risposte:


152

In Xcode 8.2.1 e Swift 3, il comando lldb po o p non funzionerà con la variabile digitata. Sarà necessario utilizzare il comando swift print per esaminare le proprietà dell'istanza dell'oggetto digitato. (Grazie alla risposta di cbowns !) Ad esempio:

expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)

37
Questo in realtà non dovrebbe essere così difficile
Departamento B

Questo era un po 'contro intuitivo. Pensavo di non aver bisogno di digitare (lldb)nella mia console. Ma non funzionava senza quello.
Honey

2
C'è un modo per farlo nell'obiettivo-c?
p0lAris

Continuo a tornare su questo. Probabilmente dovrei creare un alias lldb per expr -l Swift -- ..
Koen.

49

Puoi utilizzare la unsafeBitCastfunzione di Swift per trasmettere un indirizzo a un'istanza di un oggetto:

(lldb) e let $pin = unsafeBitCast(0x7df67c50, MKPinAnnotationView.self)
(lldb) po $pin

Quindi puoi lavorare $pincome al solito: accedi alle proprietà, ai metodi di chiamata, ecc.

Dai un'occhiata a questo articolo per ulteriori informazioni: Swift Memory Dumping .


Per la prima affermazione penso che tu abbia dimenticato "expr" o "espressione". Altrimenti funziona benissimo!
jarrodparkes

2
Ricevo "errore: utilizzo dell'identificatore non dichiarato" unsafeBitCast "" in Xcode 7.2.
devios1

8
Oltre a quell'errore (@devios) c'è un altro errore che mostra in 7.3.1: "errore: nome di tipo sconosciuto 'let'"
carlos_ms

3
Tieni presente che, a seconda del contesto, potresti dover prima passare da lldb alla modalità Swift utilizzando (lldb) settings set target.language swift. Inoltre, in alcuni casi (ad esempio, quando si interrompe il modulo della tua app durante la trasmissione a un tipo dalla tua app) potresti e import MyApp
doverlo

25

Il formato lldb per expressionsembra essere cambiato in Xcode 7.3. Quanto segue mi ha fatto iniziare:

(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $view = unsafeBitCast(0x7fb75d8349c0, UIView.self)

14

Per le classi personalizzate è necessario importare il progetto

expr -l Swift -- import MyTestProject
expr -l Swift --  let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)

1
Ricevo l'errore: nessun modulo di questo tipo "MyProjectName". Qualche idea su come risolvere questo problema?
Alexander Stepanishin

@AlexanderStepanishin prova a impostare il percorso thread / stack, Esempio: "MyApp> Thread 1> 12 main"
Juanmi

12

A partire da Xcode 8 / Swift 3, ecco cosa ha funzionato per me. (Questo è basato sulla risposta di @Sfaxon .)

(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $nav = unsafeBitCast(0x1030ff000, to: UINavigationController.self)

10

Grazie a tutte le risposte sopra, unsafeBitCast funziona bene anche con Xcode 8.3.2 / Swift 3 / macOS / Cocoa Application.

Memorizza un indirizzo dell'istanza corrente

(lldb) p tabView.controlTint
(NSControlTint) $R10 = defaultControlTint

(lldb) p self
(LearningStoryboard.NSTabViewController) $R11 = 0x00006080000e2280 {
.....

Successivamente, esaminali

(lldb) p unsafeBitCast(0x00006080000e2280, to: NSTabViewController.self).tabView.controlTint
(NSControlTint) $R20 = graphiteControlTint

(lldb) p $R11.tabView.controlTint
(NSControlTint) $R21 = graphiteControlTint

Se succede qualcosa del genere

(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'

assicurati di scegliere uno degli stack frame del codice sorgente Swift anziché uno dell'assemblatore.

È probabile che accada quando l'applicazione è stata messa in pausa facendo clic su un pulsante Pausa o interrotta con un'eccezione. Scegliendo uno stack frame di conseguenza, lascia che lldb deduca un linguaggio di programmazione appropriato.


10

Versione Objective-C

po ((MKPinAnnotationView *)0x7df67c50).alpha

1
Ha funzionato perfettamente per me. Nel mio caso ero nella Debug View Hierarchyvista, ho fatto clic con il tasto destro su una vista, quindi ho selezionato Print description of.... Questo mi ha dato un indirizzo di memoria e un tipo che potevo inserire nel codice sopra. È bello sapere che il debugger visivo inserisce la console in un frame Obj-C.
Trev14

6

Mi ci è voluto più tempo per capire che mi piacerebbe ammettere. È simile alla risposta di @afinlayson, ma con una spiegazione migliore (spero!) E una sintassi fissa

Se vuoi controllare le proprietà di un oggetto usando il debugger della gerarchia di visualizzazione di Xcode, allora funzionerà: sei nel contesto objc per impostazione predefinita, quindi dovrai passare al contesto Swift

  1. Per prima cosa importa il tuo progetto (se vuoi usare alcune delle classi qui definite)

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

  1. Trasmetti l'oggetto usando il suo indirizzo di memoria a qualsiasi classe tu voglia

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

  1. Accedi a qualsiasi valore desideri dall'oggetto

expr -l Swift -- print($vc.<PROPERTY NAME>)

Esempio:

expr -l Swift -- import Football

expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: Football.Ball.self)

expr -l Swift -- print($vc.velocity)


5

La risposta di @Xi Chen funziona perfettamente quando la tua sessione LLDB è stata avviata in un contesto Swift. Tuttavia, in alcuni casi potresti esserti fermato in un punto di interruzione al di fuori di un contesto Swift; ad esempio, quando è un punto di interruzione simbolico per l'API Objective-C o quando è in modalità Debug View Hierarchy (almeno a partire da Xcode 11.4).

error: unknown type name 'let'
error: use of undeclared identifier 'unsafeBitCast'

In tal caso, dovrai farlo alla vecchia maniera usando Objective-C:

e MKPinAnnotationView *$pin = (MKPinAnnotationView *)0x7df67c50

e ora puoi usare $pincome faresti.


3

poè un alias, il che significa che può essere sovrascritto. Puoi eseguire l'override pogestendo gli indirizzi esadecimali utilizzando objc:

command regex po
s/(0x[[:xdigit:]]+)/expression -l objc -O -- %1/
s/(.+)/expression -O -- %1/

Per vedere quale effetto ha, puoi dire a lldb di espandere questi alias:

(lldb) settings set interpreter.expand-regex-aliases true

Inoltre ho creato https://github.com/kastiglione/swift_po , che è un sostituto podi Swift. Gestisce gli indirizzi degli oggetti e ha anche alcuni altri miglioramenti.


dal tuo link, expression -l objc -O -- 0x76543210è solo la risposta per me, e non ha bisogno di conoscere la classe della variabile dall'indirizzo!
tontonCD

2

Il modo più semplice, rapido 4

expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.