LLDB (Swift): преобразование необработанного адреса в полезный тип

95

Есть ли команда LLDB, которая может преобразовать необработанный адрес в пригодный для использования класс Swift?

Например:

(lldb) po 0x7df67c50 as MKPinAnnotationView

Я знаю, что этот адрес указывает на MKPinAnnotationView, но он не во фрейме, который я могу выбрать. Но я хочу преобразовать необработанный адрес в MKPinAnnotationView, чтобы я мог изучить его свойства. Это возможно?

Jarrodparkes
источник

Ответы:

154

В Xcode 8.2.1 и Swift 3 команда lldb po или p не будет работать с типизированной переменной. Вам нужно будет использовать команду swift print для проверки свойств экземпляра типизированного объекта. (Спасибо за ответ cbowns !) Например:

expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)
Си Чен
источник
42
Это действительно не должно быть так сложно
Departamento B
Это было немного противоречиво. Я думал, что мне не нужно набирать на (lldb)моей консоли. Но без этого не вышло.
Honey
2
Есть ли способ сделать это в объекте-c?
p0lAris
Я продолжаю возвращаться к этому. Я, наверное, должен создать псевдоним lldb для expr -l Swift -- ..
Коэн.
49

Вы можете использовать unsafeBitCastфункцию Swift для приведения адреса к экземпляру объекта:

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

Затем вы можете работать $pinкак обычно - свойства доступа, методы вызова и т. Д.

Ознакомьтесь с этой статьей для получения дополнительной информации: Swift Memory Dumping .

Грегео
источник
Для первого утверждения, я думаю, вы забыли «expr» или «выражение». В остальном он отлично работает!
jarrodparkes
2
Я получаю сообщение «ошибка: использование необъявленного идентификатора unsafeBitCast» в Xcode 7.2.
devios1 04
8
Помимо этой ошибки (@devios), есть еще одна ошибка, отображаемая в 7.3.1: «error: unknown type name 'let'»
carlos_ms
3
Обратите внимание, что в зависимости от контекста вам может потребоваться сначала переключить lldb в режим Swift, используя (lldb) settings set target.language swift. Кроме того, в некоторых случаях (например, при выходе за пределы модуля вашего приложения при приведении к типу из вашего приложения) вам может потребоваться выполнить это с помощьюe import MyApp
Патрик Пийнаппель
25

Формат lldb, expressionпохоже, изменился в Xcode 7.3. Следующее заставило меня начать:

(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $view = unsafeBitCast(0x7fb75d8349c0, UIView.self)
сфаксон
источник
15

Для пользовательских классов вам необходимо импортировать свой проект

expr -l Swift -- import MyTestProject
expr -l Swift --  let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)
Афинлейсон
источник
1
Я получаю сообщение об ошибке: такого модуля «MyProjectName» нет. Есть мысли, как это исправить?
Александр
@AlexanderStepanishin: попробуйте установить путь потока / стека, например: «MyApp> Thread 1> 12 main»
Хуанми,
12

Что касается Xcode 8 / Swift 3, вот что у меня сработало. (Это основано на ответе @sfaxon .)

(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $nav = unsafeBitCast(0x1030ff000, to: UINavigationController.self)
cbowns
источник
10

Благодаря всем вышеперечисленным ответам unsafeBitCast также хорошо работает с приложением Xcode 8.3.2 / Swift 3 / macOS / Cocoa.

Запомните адрес текущего экземпляра

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

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

Позже изучите их

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

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

Если что-то подобное случится

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

убедитесь, что вы выбрали один из фреймов стека исходного кода Swift, а не ассемблер.

Это может произойти, когда приложение было приостановлено нажатием кнопки « Пауза» или остановлено с исключением. Выбрав соответствующий кадр стека, позвольте lldb вывести правильный язык программирования.

Тора
источник
10

Версия Objective-C

po ((MKPinAnnotationView *)0x7df67c50).alpha
Rockhard
источник
1
Это отлично сработало для меня. В моем случае я был в Debug View Hierarchyпредставлении, щелкнул правой кнопкой мыши на представлении, а затем выбрал Print description of.... Это дало мне адрес памяти и тип, который я мог вставить в приведенный выше код. Приятно знать, что визуальный отладчик помещает консоль в кадр Obj-C.
Trev14
6

Мне потребовалось больше времени, чтобы понять, что я хочу признать. Он похож на ответ @afinlayson, но с лучшим объяснением (надеюсь!) И фиксированным синтаксисом

Если вы хотите проверить свойства объектов с помощью отладчика иерархии представлений Xcode, то это будет работать: по умолчанию вы находитесь в контексте objc, поэтому вам придется переключить его в контекст Swift.

  1. Сначала импортируйте свой проект (если вы хотите использовать некоторые из определенных там классов)

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

  1. Приведите объект, используя его адрес памяти, к любому классу, который вы хотите

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

  1. Доступ к любому значению, которое вы хотите от объекта

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

Пример:

expr -l Swift -- import Football

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

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

Бартош Кунат
источник
5

Ответ @Xi Chen отлично работает, когда ваш сеанс LLDB был запущен в контексте Swift. Однако в некоторых случаях вы могли остановиться в точке останова вне контекста Swift; например, когда это символическая точка останова для Objective-C API или когда находится в режиме иерархии представления отладки (по крайней мере, в Xcode 11.4).

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

В этом случае вам нужно будет сделать это по-старому, используя Objective-C:

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

и теперь вы можете использовать, $pinкак хотите.

Гобе
источник
3

poявляется псевдонимом, что означает, что его можно переопределить. Вы можете переопределить po, обработав шестнадцатеричные адреса с помощью objc:

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

Чтобы увидеть, какой эффект это имеет, вы можете указать lldb развернуть эти псевдонимы:

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

Также я создал https://github.com/kastiglione/swift_po , заменяющий poSwift. Он обрабатывает адреса объектов, а также имеет несколько других улучшений.

Дэйв Ли
источник
из вашей ссылки, expression -l objc -O -- 0x76543210это просто ответ для меня, и ему не нужно знать класс переменной из адреса!
tontonCD
2

Самый простой способ, быстрый 4

expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
Кингсли Митчелл
источник