LLDB (Swift): Fundição de endereço bruto em tipo utilizável

92

Existe um comando LLDB que pode converter um endereço bruto em uma classe Swift utilizável?

Por exemplo:

(lldb) po 0x7df67c50 as MKPinAnnotationView

Eu sei que este endereço aponta para um MKPinAnnotationView, mas não está em um quadro que posso selecionar. Mas, eu quero converter o endereço bruto em um MKPinAnnotationView para que possa examinar suas propriedades. Isso é possível?

jarrodparkes
fonte

Respostas:

152

No Xcode 8.2.1 e Swift 3, o comando lldb po ou p não funcionará com a variável digitada. Você precisará usar o comando rápido print para examinar as propriedades da instância do objeto digitado. (Graças à resposta de cbowns !) Por exemplo:

expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)
Xi Chen
fonte
37
Isso realmente não deveria ser tão difícil
Departamento B
Isso foi um pouco contra-intuitivo. Achei que não precisava digitar (lldb)no meu console. Mas não funcionou sem isso.
Mel
2
Existe uma maneira de fazer isso no objetivo-c?
p0lAris
Eu continuo voltando a isso. Eu provavelmente deveria criar um alias lldb para expr -l Swift -- ..
Koen.
49

Você pode usar a unsafeBitCastfunção do Swift para lançar um endereço para uma instância de objeto:

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

Então você pode trabalhar $pincomo de costume - propriedades de acesso, métodos de chamada, etc.

Confira este artigo para obter mais informações: Despejo de memória Swift .

Gregheo
fonte
Para a primeira declaração, acho que você esqueceu a 'expr' ou 'expressão'. Caso contrário, está funcionando muito bem!
jarrodparkes
2
Estou recebendo "erro: uso de identificador não declarado 'unsafeBitCast'" no Xcode 7.2.
devios1
8
Além desse erro (@devios) há outro erro que mostra em 7.3.1: "erro: nome de tipo desconhecido 'let'"
carlos_ms
3
Observe que, dependendo do contexto, você pode precisar mudar o lldb para o modo Swift primeiro usando (lldb) settings set target.language swift. Além disso, em alguns casos (por exemplo, ao quebrar fora do módulo do seu aplicativo durante a transmissão para um tipo do seu aplicativo), você pode precisar seguir com ume import MyApp
Patrick Pijnappel
25

O formato lldb para expressionparece ter mudado no Xcode 7.3. O seguinte me ajudou a começar:

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

Para aulas personalizadas, você precisa importar seu projeto

expr -l Swift -- import MyTestProject
expr -l Swift --  let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)
Afinlayson
fonte
1
Estou recebendo o erro: o módulo "MyProjectName" não existe. Alguma ideia de como consertar isso?
Alexander Stepanishin de
@AlexanderStepanishin tente definir o caminho do thread / pilha, Exemplo: "MyApp> Thread 1> 12 main"
Juanmi
12

No Xcode 8 / Swift 3, aqui está o que funcionou para mim. (Isso é baseado na resposta de @sfaxon .)

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

Graças a todas as respostas acima, unsafeBitCast também funciona bem com o aplicativo Xcode 8.3.2 / Swift 3 / macOS / Cocoa.

Memorize um endereço da instância atual

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

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

Mais tarde, examine-os

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

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

Se algo assim acontecer

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

certifique-se de escolher um dos frames de pilha do código-fonte Swift em vez de um montador.

É provável que aconteça quando o aplicativo foi pausado ao clicar no botão Pausar ou interrompido com uma exceção. Ao escolher um frame de pilha de acordo, deixe lldb inferir uma linguagem de programação adequada.

Tora
fonte
10

Versão Objective-C

po ((MKPinAnnotationView *)0x7df67c50).alpha
Rockhard
fonte
1
Isso funcionou perfeitamente para mim. No meu caso, eu estava na Debug View Hierarchyvisualização, cliquei com o botão direito do mouse em uma visualização e selecionei Print description of.... Isso me deu um endereço de memória e tipo que eu poderia inserir no código acima. É bom saber que o depurador visual coloca o console em um quadro Obj-C.
Trev14
6

Levei mais tempo para descobrir o que gostaria de admitir. É semelhante à resposta @afinlayson, mas com melhor explicação (espero!) E sintaxe fixa

Se você quiser verificar as propriedades de um objeto usando o depurador de hierarquia de visão do Xcode, isso funcionará: Você está no contexto do objeto por padrão, então terá que alterná-lo para o contexto Swift

  1. Primeiro importe seu projeto (se você quiser usar algumas das classes definidas lá)

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

  1. Lance o objeto usando seu endereço de memória para qualquer classe que você quiser

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

  1. Acesse qualquer valor que você quiser do objeto

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

Exemplo:

expr -l Swift -- import Football

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

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

Bartosz Kunat
fonte
5

A resposta de @Xi Chen funciona perfeitamente quando sua sessão LLDB foi iniciada em um contexto Swift. No entanto, em alguns casos, você pode ter parado em um ponto de interrupção fora de um contexto Swift; por exemplo, quando é um ponto de interrupção simbólico para a API Objective-C ou quando está no modo Debug View Hierarchy (pelo menos a partir do Xcode 11.4).

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

Nesse caso, você precisará fazer da maneira antiga, usando Objective-C:

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

e agora você pode usar $pincomo faria.

Gobe
fonte
3

poé um alias, o que significa que pode ser substituído. Você pode substituir pomanipulando endereços hexadecimais usando objc:

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

Para ver o efeito que isso tem, você pode dizer ao lldb para expandir estes aliases:

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

Além disso, criei https://github.com/kastiglione/swift_po , que é um substituto podo Swift. Ele lida com endereços de objetos e também possui algumas outras melhorias.

Dave Lee
fonte
do seu link, expression -l objc -O -- 0x76543210é só a resposta pra mim, e não precisa saber a classe da variável do endereço!
tontonCD
2

A maneira mais fácil, rápida 4

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