LLDB (Swift): conversion de l'adresse brute en type utilisable

93

Existe-t-il une commande LLDB qui peut convertir une adresse brute en une classe Swift utilisable?

Par exemple:

(lldb) po 0x7df67c50 as MKPinAnnotationView

Je sais que cette adresse pointe vers un MKPinAnnotationView, mais ce n'est pas dans un cadre que je peux sélectionner. Mais, je veux convertir l'adresse brute dans un MKPinAnnotationView afin que je puisse examiner ses propriétés. Est-ce possible?

jarrodparkes
la source

Réponses:

152

Sous Xcode 8.2.1 et Swift 3, la commande lldb po ou p ne fonctionnera pas avec la variable typée. Vous devrez utiliser la commande swift print pour examiner les propriétés de l'instance d'objet typé. (Merci à la réponse de cbowns !) Par exemple:

expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)
Xi Chen
la source
38
Cela ne devrait vraiment pas être si difficile
Departamento B
C'était un peu contre-intuitif. Je pensais que je n'avais pas besoin de taper le (lldb)dans ma console. Mais cela n'a pas fonctionné sans cela.
Honey
2
Y a-t-il un moyen de faire cela dans objective-c?
p0lAris
Je reviens toujours là-dessus. Je devrais probablement créer un alias lldb pour expr -l Swift -- ..
Koen.
49

Vous pouvez utiliser la unsafeBitCastfonction de Swift pour convertir une adresse en une instance d'objet:

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

Ensuite, vous pouvez travailler avec $pincomme d'habitude - accéder aux propriétés, aux méthodes d'appel, etc.

Consultez cet article pour plus d'informations: Swift Memory Dumping .

Gregheo
la source
Pour la première déclaration, je pense que vous avez oublié «expr» ou «expression». Sinon, cela fonctionne très bien!
jarrodparkes
2
J'obtiens une "erreur: utilisation de l'identifiant non déclaré 'unsafeBitCast'" dans Xcode 7.2.
devios1
8
Outre cette erreur (@devios), il y a une autre erreur qui apparaît dans la version 7.3.1: "erreur: nom de type inconnu 'let'"
carlos_ms
3
Notez que selon le contexte, vous devrez peut-être passer d'abord lldb en mode Swift en utilisant (lldb) settings set target.language swift. De plus, dans certains cas (par exemple, lorsque vous sortez du module de votre application lors de la diffusion vers un type de votre application), vous devrez peut-être suivre cela avec une import MyApp
Patrick Pijnappel
25

Le format lldb expressionsemble avoir changé dans Xcode 7.3. Ce qui suit m'a permis de démarrer:

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

Pour les classes personnalisées, vous devez importer votre projet

expr -l Swift -- import MyTestProject
expr -l Swift --  let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)
afinlayson
la source
1
J'obtiens une erreur: aucun module de ce type "MyProjectName". Des pensées comment résoudre ce problème?
Alexander Stepanish du
@AlexanderStepanishin essayez de définir le chemin du thread / pile, Exemple: "MyApp> Thread 1> 12 main"
Juanmi
12

À partir de Xcode 8 / Swift 3, voici ce qui a fonctionné pour moi. (Ceci est basé sur la réponse de @ sfaxon .)

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

Grâce à toutes les réponses ci-dessus, unsafeBitCast fonctionne également bien avec Xcode 8.3.2 / Swift 3 / macOS / Cocoa Application.

Mémoriser une adresse de l'instance actuelle

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

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

Plus tard, examinez-les

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

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

Si quelque chose comme ça arrive

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

assurez-vous de choisir l'un des cadres de pile du code source Swift plutôt que celui de l'assembleur.

Cela est susceptible de se produire lorsque l'application a été suspendue en cliquant sur un bouton Pause ou arrêtée avec une exception. En choisissant un cadre de pile en conséquence, laissez lldb déduire un langage de programmation approprié.

Tora
la source
10

Version Objective-C

po ((MKPinAnnotationView *)0x7df67c50).alpha
Rockhard
la source
1
Cela a parfaitement fonctionné pour moi. Dans mon cas, j'étais dans la Debug View Hierarchyvue, j'ai fait un clic droit sur une vue, puis j'ai été sélectionnée Print description of.... Cela m'a donné une adresse mémoire et un type que je pourrais insérer dans le code ci-dessus. C'est bien de savoir que le débogueur visuel place la console dans un cadre Obj-C.
Trev14
6

Il m'a fallu plus de temps pour comprendre que j'aimerais l'admettre. C'est similaire à la réponse @afinlayson, mais avec une meilleure explication (j'espère!) Et une syntaxe fixe

Si vous souhaitez vérifier les propriétés d'un objet à l'aide du débogueur de hiérarchie de vues de Xcode, cela fonctionnera: vous êtes dans le contexte objc par défaut, vous devrez donc le basculer vers le contexte Swift

  1. Importez d'abord votre projet (si vous souhaitez utiliser certaines des classes qui y sont définies)

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

  1. Cast objet en utilisant son adresse mémoire dans la classe de votre choix

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

  1. Accédez à toute valeur que vous souhaitez de l'objet

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

Exemple:

expr -l Swift -- import Football

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

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

Bartosz Kunat
la source
5

La réponse de @Xi Chen fonctionne parfaitement lorsque votre session LLDB a été lancée dans un contexte Swift. Cependant, dans certains cas, vous vous êtes peut-être arrêté dans un point d'arrêt en dehors d' un contexte Swift; par exemple, lorsqu'il s'agit d'un point d'arrêt symbolique vers l'API Objective-C, ou en mode Debug View Hierarchy (au moins à partir de Xcode 11.4).

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

Dans ce cas, vous devrez le faire à l'ancienne en utilisant Objective-C:

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

et maintenant vous pouvez utiliser $pincomme vous le feriez.

Gobe
la source
3

poest un alias, ce qui signifie qu'il peut être remplacé. Vous pouvez remplacer poen gérant les adresses hexadécimales en utilisant objc:

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

Pour voir quel effet cela a, vous pouvez dire à lldb de développer ces alias:

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

J'ai également créé https://github.com/kastiglione/swift_po , qui est un substitut poà Swift. Il gère les adresses d'objets et présente également quelques autres améliorations.

Dave Lee
la source
à partir de votre lien, expression -l objc -O -- 0x76543210est juste la réponse pour moi, et il n'est pas nécessaire de connaître la classe variable de l'adresse!
tontonCD
2

Le moyen le plus simple, rapide 4

expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
Kingsley Mitchell
la source