Подтвердить что ты не робот

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

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

Например:

(lldb) po 0x7df67c50 as MKPinAnnotationView

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

4b9b3361

Ответ 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

  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)