LLDB (Swift): литье исходного адреса в полезный тип
Есть ли команда LLDB, которая может передать необработанный адрес в пригодный для использования класс Swift?
Например:
(lldb) po 0x7df67c50 as MKPinAnnotationView
Я знаю, что этот адрес указывает на MKPinAnnotationView, но он не находится в кадре, который я могу выбрать. Но я хочу передать исходный адрес в MKPinAnnotationView, чтобы я мог изучить его свойства. Возможно ли это?
Ответы
Ответ 1
В 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)
Ответ 2
Вы можете использовать функцию Swift unsafeBitCast
, чтобы передать адрес экземпляру объекта:
(lldb) e let $pin = unsafeBitCast(0x7df67c50, MKPinAnnotationView.self)
(lldb) po $pin
Затем вы можете работать с $pin
, как обычно, - свойства доступа, методы вызова и т.д.
Ознакомьтесь с этой статьей для получения дополнительной информации: Swift Memory Dumping.
Ответ 3
Формат lldb для expression
кажется, изменился в Xcode 7.3. Следующее заставило меня начать:
(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $view = unsafeBitCast(0x7fb75d8349c0, UIView.self)
Ответ 4
Как и Xcode 8/Swift 3, вот что сработало для меня. (Это основано на ответе @sfaxon.)
(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $nav = unsafeBitCast(0x1030ff000, to: UINavigationController.self)
Ответ 5
Для пользовательских классов вам необходимо импортировать проект
expr -l Swift -- import MyTestProject
expr -l Swift -- let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)
Ответ 6
Благодаря всем вышеперечисленным ответам unsafeBitCast также хорошо работает с Xcode 8.3.2/Swift 3/macOS/ Cocoa Application.
Запоминать адрес текущего экземпляра
(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 выводит правильный язык программирования.
Ответ 7
Версия Objective-C
po ((MKPinAnnotationView *)0x7df67c50).alpha
Ответ 8
@Xi Chen ответ отлично работает, когда ваша сессия LLDB была запущена в контексте Swift. Однако в некоторых случаях вы могли остановиться в точке останова вне контекста Swift; например, когда это символическая точка останова для Objective-C API.
error: unknown type name 'let'
error: use of undeclared identifier 'unsafeBitCast'
В этом случае вам нужно будет сделать это по-старому, используя Objective-C:
e MKPinAnnotationView *$pin = (MKPinAnnotationView *)0x7df67c50
и теперь вы можете использовать $pin
как вы бы.
Ответ 9
Самый простой способ, Swift 4
expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
Ответ 10
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, который является заменой po
для Swift. Он обрабатывает адреса объектов, а также имеет несколько других улучшений.
Ответ 11
Мне потребовалось больше времени, чтобы понять, что я хотел бы признать. Это похоже на ответ @afinlayson, но с лучшим объяснением (надеюсь!) И фиксированным синтаксисом
Если вы хотите проверить свойства объектов с помощью отладчика иерархии представлений Xcodes, то это будет работать:
По умолчанию вы находитесь в контексте objc, поэтому вам придется переключить его в контекст Swift
- Сначала импортируйте ваш проект (если вы хотите использовать некоторые классы, определенные там)
expr -l Swift -- import <YOUR PROJECT NAME>
- Приведите объект, используя его адрес памяти к любому классу, который вы хотите
expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: <YOUR PROJECT NAME>.<YOUR CUSTOM CLASS NAME>.self)
- Получите доступ к любому значению из объекта
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)