LLDB (Swift): conversión de dirección sin procesar en tipo utilizable

94

¿Existe un comando LLDB que pueda convertir una dirección sin procesar en una clase Swift utilizable?

Por ejemplo:

(lldb) po 0x7df67c50 as MKPinAnnotationView

Sé que esta dirección apunta a un MKPinAnnotationView, pero no está en un marco que pueda seleccionar. Pero, quiero convertir la dirección sin procesar en un MKPinAnnotationView para poder examinar sus propiedades. es posible?

jarrodparkes
fuente

Respuestas:

153

En Xcode 8.2.1 y Swift 3, el comando lldb po o p no funcionará con la variable escrita. Deberá utilizar el comando rápido print para examinar las propiedades de la instancia del objeto escrito. (¡Gracias a la respuesta de cbowns !)

expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)
Xi Chen
fuente
39
Esto realmente no debería ser tan difícil
Departamento B
Esto fue un poco contrario a la intuición. Pensé que no necesitaba escribir (lldb)en mi consola. Pero no funcionó sin eso.
Cariño
2
¿Hay alguna forma de hacer esto en el objetivo-c?
p0lAris
Sigo vengando de esto. Probablemente debería crear un alias lldb para expr -l Swift -- ..
Koen.
49

Puede usar la unsafeBitCastfunción de Swift para enviar una dirección a una instancia de objeto:

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

Luego, puede trabajar $pincomo de costumbre: propiedades de acceso, métodos de llamada, etc.

Consulte este artículo para obtener más información: Swift Memory Dumping .

Gregheo
fuente
Para la primera declaración, creo que olvidó la 'expr' o la 'expresión'. De lo contrario, está funcionando muy bien.
jarrodparkes
2
Recibo "error: uso de identificador no declarado 'unsafeBitCast'" en Xcode 7.2.
devios1
8
Además de ese error (@devios), hay otro error que se muestra en 7.3.1: "error: nombre de tipo desconocido 'let'"
carlos_ms
3
Tenga en cuenta que, según el contexto, es posible que deba cambiar lldb al modo Swift primero usando (lldb) settings set target.language swift. Además, en algunos casos (por ejemplo, cuando se sale del módulo de su aplicación mientras se envía a un tipo desde su aplicación), es posible que deba seguir eso con une import MyApp
Patrick Pijnappel
25

El formato lldb expressionparece haber cambiado en Xcode 7.3. Lo siguiente me ayudó a comenzar:

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

Para las clases personalizadas necesita importar su proyecto

expr -l Swift -- import MyTestProject
expr -l Swift --  let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)
afinlayson
fuente
1
Recibo un error: no existe el módulo "MyProjectName". ¿Alguna idea de cómo solucionar este problema?
Alexander Stepanishin el
@AlexanderStepanishin intente configurar la ruta del hilo / pila, Ejemplo: "MyApp> Thread 1> 12 main"
Juanmi
12

A partir de Xcode 8 / Swift 3, esto es lo que funcionó para mí. (Esto se basa en la respuesta de @ sfaxon ).

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

Gracias a todas las respuestas anteriores, unsafeBitCast también funciona bien con Xcode 8.3.2 / Swift 3 / macOS / Cocoa Application.

Memorizar una dirección de instancia actual

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

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

Más tarde, examínelos

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

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

Si pasa algo como esto

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

asegúrese de elegir uno de los marcos de pila del código fuente de Swift en lugar de uno de ensamblador.

Es probable que suceda cuando la aplicación se pausó al hacer clic en un botón Pausa o se detuvo con una excepción. Al elegir un marco de pila en consecuencia, deje que lldb infiera un lenguaje de programación adecuado.

Tora
fuente
10

Versión Objective-C

po ((MKPinAnnotationView *)0x7df67c50).alpha
rock duro
fuente
1
Esto funcionó perfectamente para mí. En mi caso, estaba en la Debug View Hierarchyvista, hice clic derecho en una vista y luego la seleccioné Print description of.... Eso me dio una dirección de memoria y un tipo que podría colocar en el código anterior. Es bueno saber que el depurador visual coloca la consola en un marco Obj-C.
Trev14
6

Me tomó más tiempo darme cuenta de lo que me gustaría admitir. Es similar a la respuesta de @afinlayson, pero con una mejor explicación (¡espero!) Y una sintaxis fija

Si desea verificar las propiedades de un objeto utilizando el depurador de jerarquía de vistas de Xcode, esto funcionará: está en el contexto objc de forma predeterminada, por lo que tendrá que cambiarlo al contexto Swift

  1. Primero importe su proyecto (si desea utilizar algunas de las clases definidas allí)

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

  1. Transmita el objeto usando su dirección de memoria a cualquier clase que desee

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

  1. Acceda a cualquier valor que desee del objeto

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

Ejemplo:

expr -l Swift -- import Football

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

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

Bartosz Kunat
fuente
5

La respuesta de @Xi Chen funciona perfectamente cuando su sesión LLDB se inició en un contexto Swift. Sin embargo, en algunos casos, es posible que se haya detenido en un punto de interrupción fuera de un contexto Swift; por ejemplo, cuando es un punto de interrupción simbólico para la API de Objective-C, o cuando está en modo de jerarquía de vista de depuración (al menos a partir de Xcode 11.4).

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

En ese caso, deberá hacerlo de la manera anterior usando Objective-C:

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

y ahora puede usarlo $pincomo lo haría.

Gobe
fuente
3

poes un alias, lo que significa que se puede anular. Puede anular pomanejando direcciones hexadecimales usando objc:

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

Para ver qué efecto tiene esto, puede decirle a lldb que expanda estos alias:

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

También he creado https://github.com/kastiglione/swift_po , que es un sustituto pode Swift. Maneja direcciones de objetos y también tiene algunas otras mejoras.

Dave Lee
fuente
de su enlace, expression -l objc -O -- 0x76543210es solo la respuesta para mí, ¡y no necesita saber la clase de variable de la dirección!
tontonCD
2

La forma más fácil, rápida 4

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