Slide 1

Slide 1 text

(@Scior) LLDB Swift Python 1

Slide 2

Slide 2 text

AppBrew LIPS iOS PjM ( Keynote) ࣗݾ঺հ🦙 ෩ܠ΍޿֯޷͖ͷਓू·Εʙ📷

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

(lldb) e view.isHidden = false

Slide 5

Slide 5 text

Google UI

Slide 6

Slide 6 text

Python

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

( )

Slide 9

Slide 9 text

UIView Save

Slide 10

Slide 10 text

UIView UIView Data UIGraphicsImageRenderer SBProcess.ReadMemory Lib/io LLDB

Slide 11

Slide 11 text

(lldb) saveimage imageView /tmp/alpaca.png

Slide 12

Slide 12 text

Swift ( ) loadext DebugExtensions.swift evaluate DebugExtensions.swift

Slide 13

Slide 13 text

Swift (loadext) @lldb.command("loadext") def load(debugger, command, result, dict): path = os.path.join(os.path.dirname(__file__), 'swift/DebugExtensions.swift') with open(path, 'r') as f: common.evaluate(f.read()) * common.evaluate

Slide 14

Slide 14 text

DebugExtensions.swift extension UIView { func takeSnapshot() -> UIImage? { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { context in layer.render(in: context.cgContext) } } func convertToPNGData() -> Data { return takeSnapshot()!.pngData()! } } ΋ͪΖΜ#if DEBUG ~ #endifͰғͬͯίϯύΠϧͯ͠΋ྑ͍

Slide 15

Slide 15 text

saveimage ( ) saveimage convertToPNGData() evaluate convertToPNGData() DebugExtensions.swift

Slide 16

Slide 16 text

saveimage ( ) saveimage address size convertToPNGData() evaluate convertToPNGData() Data SBValue DebugExtensions.swift

Slide 17

Slide 17 text

saveimage ( ) @lldb.command("saveimage") def save_image(debugger, arguments, result, dict): view, path = arguments.split() var_name = str(uuid.uuid4()).replace('-', '') common.evaluate('let $%s = %s.convertToPNGData()' % (var_name, view)) address_str = common.evaluate('($%s as NSData).bytes' % var_name).GetObjectDescription().split()[1] address = int(address_str, 16) size = int(common.evaluate('$%s.count' % var_name).GetValue()) process = lldb.debugger.GetSelectedTarget().GetProcess() error = lldb.SBError() data = process.ReadMemory(address, size, error) with open(path, "wb") as f: f.write(data)

Slide 18

Slide 18 text

@lldb.command("saveimage") def save_image(debugger, arguments, result, dict): @lldb.command command script add -f LLDB

Slide 19

Slide 19 text

convertToPNGData() common.evaluate('let $%s = %s.convertToPNGData()' % (var_name, view)) let $hoge = imageView.convertToPNGData()

Slide 20

Slide 20 text

Data address_str = common.evaluate('($%s as NSData).bytes' % var_name).GetObjectDescription().split()[1] address = int(address_str, 16) size = int(common.evaluate('$%s.count' % var_name).GetValue()) ($hoge as NSData).bytes $hoge.count (Obj-C++ )

Slide 21

Slide 21 text

process = lldb.debugger.GetSelectedTarget().GetProcess() error = lldb.SBError() data = process.ReadMemory(address, size, error) with open(path, "wb") as f: f.write(data) SBProcess.ReadMemory Python

Slide 22

Slide 22 text

* GitHub

Slide 23

Slide 23 text

( )

Slide 24

Slide 24 text

UIView Overlay

Slide 25

Slide 25 text

UIView Data UIImage UnsafeMutablePointer UIImage.init(data:) Lib/io SBProcess.WriteMemory LLDB

Slide 26

Slide 26 text

(lldb) overlayimage imageView /tmp/alpaca.png

Slide 27

Slide 27 text

ImageBuffer final class ImageBuffer { typealias Pointer = UnsafeMutablePointer private let size: Int let pointer: Pointer init(size: Int) { self.size = size pointer = Pointer.allocate(capacity: size) } deinit { pointer.deallocate() } func getData() -> Data { let bufferPointer = UnsafeMutableBufferPointer(start: pointer, count: size) return .init(buffer: bufferPointer) } }

Slide 28

Slide 28 text

overlayimage @lldb.command("overlayimage") def overlay_image(debugger, arguments, result, dict): view, path = arguments.split() with open(path, 'rb') as f: data = f.read() buf_name = common.generateVarName() common.evaluate('let $%s = ImageBuffer(size: %s)' % (buf_name, len(data))) address_str = common.evaluate('$%s.pointer' % buf_name).GetObjectDescription().split()[1] address = int(address_str, 16) process = lldb.debugger.GetSelectedTarget().GetProcess() error = lldb.SBError() size = process.WriteMemory(address, data, error) view_name = common.generateVarName() common.evaluate('let $%s = DebugOverlayView(frame: %s.frame)' % (view_name, view)) common.evaluate('$%s.set(data: $%s.getData())' % (view_name, buf_name)) common.evaluate(‘%s.superview?.addSubview($%s)' % (view, view_name))

Slide 29

Slide 29 text

with open(path, 'rb') as f: data = f.read() common.evaluate('let $%s = ImageBuffer(size: %s)' % (buf_name, len(data))) address_str = common.evaluate('$%s.pointer' % buf_name).GetObjectDescription().split()[1] address = int(address_str, 16) ImageBuffer

Slide 30

Slide 30 text

process = lldb.debugger.GetSelectedTarget().GetProcess() error = lldb.SBError() size = process.WriteMemory(address, data, error) SBProcess.WriteMemory

Slide 31

Slide 31 text

View common.evaluate('let $%s = DebugOverlayView(frame: %s.frame)' % (view_name, view)) common.evaluate('$%s.set(data: $%s.getData())' % (view_name, buf_name)) common.evaluate(‘%s.superview?.addSubview($%s)' % (view, view_name)) let $view = DebugOverlayView(frame: view.frame) $view.set(data: $buf.getData()) view.superview?.addSubview($view)

Slide 32

Slide 32 text

☺ * GitHub

Slide 33

Slide 33 text

With OpenCV and scikit-image (in progress) View cv skimage (UILabel )

Slide 34

Slide 34 text

https://github.com/Scior/LLDBVisualDebug

Slide 35

Slide 35 text

Appendix

Slide 36

Slide 36 text

common.evaluate def evaluate(exp): options = lldb.SBExpressionOptions() options.SetLanguage(lldb.eLanguageTypeSwift) frame = ( lldb.debugger.GetSelectedTarget() .GetProcess() .GetSelectedThread() .GetSelectedFrame() ) return frame.EvaluateExpression(exp, options)

Slide 37

Slide 37 text

LLDB Python API: https://lldb.llvm.org/python_api.html facebook/chisel: https://github.com/facebook/chisel

Slide 38

Slide 38 text

🦙