Swift 代码调试核武-LLDB调试基础

Swift 代码调试核武-LLDB调试基础,第1张

概述原创Blog,转载请注明出处 http://blog.csdn.net/hello_hwc?viewmode=list 我的stackoverflow 前言:LLDB是个开源的调试器,与XCode绑定的 LLDB的使用中,Swift与Objective C还是有一些差别的 本文主要侧重LLDB的常用命令 资料(目前状态XCode 7.2 Swift 2.1.1),非XCode 7.2+本文代码可能

原创Blog,转载请注明出处
http://blog.csdn.net/hello_hwc?viewmode=list
我的stackoverflow

前言:LLDB是个开源的调试器,与XCode绑定的

LLDB的使用中,Swift与Objective C还是有一些差别的

本文主要侧重LLDB的常用命令

资料(目前状态XCode 7.2 Swift 2.1.1),非XCode 7.2+本文代码可能不能运行 objc.io(强烈建议有Objective C经验,但是对LLDB不熟悉的深入研究下) Apple官方文档 LLDB的文档 一个封装LLDB的库,可以辅助调试 2015 WWDC视频

对了,Swift到现在也不过一岁半,所以LLDB对于Swift的支持肯定不如OC那么好。

如何打开LLDB如何使用?

通常的方式就是断点,另外,关于利用XCode图形化调试,在我这篇文章里有详细讲解

本文适合XCode 7.2 +
不管是在程序中加断点

还是手动的暂停程序

让代码停在Swift Error 或者Objective C异常

停在Objective C异常

(lldb) br s -E  objcBreakpoint 6: where = libobjc.A.dylib`objc_exception_throw,address = 0x000000010dededbb

停在Swift Error

(lldb) br s -E swiftBreakpoint 7: where = libswiftCore.dylib`swift_willThrow,address = 0x000000010e55ccc0

停在某一种类型的Swift Error

(lldb) br s -E swift -O EnumErrorBreakpoint 8: where = libswiftCore.dylib`swift_willThrow,address = 0x000000010e55ccc0

以此作为开端,希望读者能耐心看完,本文很长

准备工作

为了方便,我们先写好这样的一个Model类,定义个ErrorType,并且定义个实例方法抛出异常

enum CustomError:ErrorType{    case LeoError1    case LeoError2}class Person:NSObject{    var name:String    var age:UInt32    init(name:String,age:UInt32){        self.name = name        self.age = age    }    //重写description是为了方便调试    overrIDe var description:String{        return "name:\(name) age:\(age)"    }    func PersonException() throws{        throw CustomError.LeoError1    }}

然后在vIEwDIDLoad中初始化一个对象,并打一个断点

let person = Person(name: "Leo",age: 23)
打印命令 p/po

p

(lldb) p person(SwiftLLDBDemo.Person) $R0 = 0x00007f99b8d30b40 {  ObjectiveC.NSObject = {    isa = SwiftLLDBDemo.Person  }  name = "Leo"  age = 23}

po

(lldb) po personname:Leo age:23

p命令会打印出对象的类型,如果是Objective C对象,会打印出isa,以及属性的值
po 命令 对于继承自NSObject得对象,指示会打印出description中的内容

再举个例子

(lldb) po ["123","345"]▿ 2 elements  - [0] : "123"  - [1] : "345"(lldb) p ["123","345"]([String]) $R2 = 2 values {  [0] = "123"  [1] = "345"}

也可以,调用一段代码

(lldb) p for i in 1...3{ print(i) }123
执行代码 e

Expression命令可以帮助我们执行代码,

(lldb) e person.name = "Jack"(lldb) p person(SwiftLLDBDemo.Person) $R1 = 0x00007f9bf1424c20 {  ObjectiveC.NSObject = {    isa = SwiftLLDBDemo.Person  }  name = "Jack"  age = 23}

在这我们深入的研究所有命令

(lldb) help

内容太多,不拷贝进来了,自己在XCode里敲敲试试吧。

可以看到,有一部分是alias部分,有linux经验的同学应该知道,alias就是将一个简单的命令设置为复杂命令的别名。我们上面讲到的两个命令p/po就是两个alias命令

p         -- ('Expression --')  Evaluate an Expression (ObjC++ or Swift) in               the current program context,using user defined variables and               variables currently in scope.  po        -- ('Expression -O -- ')  Evaluate an Expression (ObjC++ or Swift)               in the current program context,using user defined variables and               variables currently in scope.

所以,p命令,本质是Expression -- ;po命令,本质是Expression -O --

(lldb) Expression -- person(SwiftLLDBDemo.Person) $R0 = 0x00007f96a3f792d0 {  ObjectiveC.NSObject = {    isa = SwiftLLDBDemo.Person  }  name = "Leo"  age = 23}(lldb) Expression -O -- personname:Leo age:23

更加复杂的执行

例如,动态的修改vIEw的背景色

e self.vIEw.backgroundcolor = UIcolor.bluecolor
Expression命令很灵活

格式化打印 -f (format)

(lldb) expr -f bin -- person.age (UInt32) $R2 = 0b00000000000000000000000000010111(lldb) expr -f oct -- person.age(UInt32) $R3 = 027(lldb) expr -f hex -- person.age(UInt32) $R4 = 0x00000017

格式化打印可以更简单

(lldb) p/x person.age(UInt32) $R5 = 0x00000017

打印Raw value expr -R -- 变量

(lldb) expr -R -- person(SwiftLLDBDemo.Person) $R6 = 0x00007f96a3f792d0 { ObjectiveC.NSObject = {}  name = { _core = { _baseAddress = { _rawValue = 0x0000000101041298 "Leo" }      _countAndFlags = { value = 3 }      _owner = None { Some = { instance_type = 0x0000000000000000 }      }    }  }  age = { value = 23 }}

显示变量类型expr -T -- 变量

(lldb) expr -T -- person(SwiftLLDBDemo.Person) $R7 = 0x00007f96a3f792d0 {  (NSObject) ObjectiveC.NSObject = {    (Class) isa = SwiftLLDBDemo.Person  }  (String) name = "Leo"  (UInt32) age = 23}

当然也可以结合多个使用expr -RRT -- person

帮助命令,可以再深入看看其他执行选项,不过不是很常用

help Expression
LLDB变量

LLDB的变量和脚本语言类似,以美元符号开头,使用的时候也要带着美元符号,调用的时候和Swift的语法一致
例如

(lldb) e var $a = 10(lldb) p $a(Int) $a = 10(lldb) e var $b = Person(name: "Jack",age: 25)(lldb) p $b(SWTest.Person) $b = 0x00007f8909539080 {  ObjectiveC.NSObject = {    isa = SWTest.Person  }  name = "Jack"  age = 25}
断点

断点采用这个命令breakpoint,缩写br
断点命令的文档较少,这里先列出文档

(lldb) help breakpointThe following subcommands are supported:      clear   -- Clears a breakpoint or set of breakpoints in the executable.      command -- A set of commands for adding,removing and examining bits of                 code to be executed when the breakpoint is hit (breakpoint                 'commands').      delete -- Delete the specifIEd breakpoint(s). If no breakpoints are specifIEd,delete them all. disable -- disable the specifIEd breakpoint(s) without removing them. If none are specifIEd,disable all breakpoints. enable -- Enable the specifIEd Disabled breakpoint(s). If no breakpoints are specifIEd,enable all of them. List -- List some or all breakpoints at configurable levels of detail. modify -- Modify the options on a breakpoint or set of breakpoints in the executable. If no breakpoint is specifIEd,acts on the last created breakpoint. With the exception of -e,-d and -i,passing an empty argument clears the modification. name -- A set of commands to manage name Tags for breakpoints set -- Sets a breakpoint or set of breakpoints in the executable.

breakpoint set -E language
breakpoint s -E swift -O ErrorType

列出断点

(lldb) br liCurrent breakpoints:1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/VIEwController.swift',line = 27,locations = 1,resolved = 1,hit count = 1  1.1: where = SWTest`SWTest.VIEwController.vIEwDIDLoad (SWTest.VIEwController)() -> () + 75 at VIEwController.swift:27,address = 0x000000010ef8556b,resolved,hit count = 1

禁用断点

(lldb) br dis 11 breakpoints Disabled.

删除断点

(lldb) br del 11 breakpoints deleted; 0 breakpoint locations Disabled.(lldb) br liNo breakpoints currently set.

添加断点

(lldb) br set -f VIEwController.swift -l 28Breakpoint 2: where = SWTest`SWTest.VIEwController.vIEwDIDLoad (SWTest.VIEwController)() -> () + 139 at VIEwController.swift:29,address = 0x000000010ef855ab

也可以简写为

(lldb) b VIEwController.swift:28Breakpoint 3: where = SWTest`SWTest.VIEwController.vIEwDIDLoad (SWTest.VIEwController)() -> () + 139 at VIEwController.swift:29,address = 0x000000010ef855ab(lldb) br liCurrent breakpoints:2: file = 'VIEwController.swift',line = 28,hit count = 0  2.1: where = SWTest`SWTest.VIEwController.vIEwDIDLoad (SWTest.VIEwController)() -> () + 139 at VIEwController.swift:29,address = 0x000000010ef855ab,hit count = 0 3: file = 'VIEwController.swift',hit count = 0  3.1: where = SWTest`SWTest.VIEwController.vIEwDIDLoad (SWTest.VIEwController)() -> () + 139 at VIEwController.swift:29,hit count = 0
断点name

断点名称是用来管理一组断点的,通过name可以启用或者禁用一组断点,一个断点可以有多个name,很像tag。

br set -f VIEwController.swift -l 28 -N leo
(lldb) br set -f VIEwController.swift -l 28 -N leoBreakpoint 2: 3 locations.(lldb) br liCurrent breakpoints:1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/VIEwController.swift',line = 34,hit count = 1  1.1: where = SWTest`SWTest.VIEwController.vIEwDIDLoad (SWTest.VIEwController)() -> () + 75 at VIEwController.swift:34,address = 0x00000001070d51fb,hit count = 1 2: file = 'VIEwController.swift',locations = 3,resolved = 3,hit count = 0  names:    leo  2.1: where = SWTest`SWTest.VIEwController.__deallocating_deinit + 12 at VIEwController.swift,address = 0x00000001070d538c,hit count = 0   2.2: where = SWTest`SWTest.VIEwController.init (SWTest.VIEwController.Type)(nibname : Swift.Optional<Swift.String>,bundle : Swift.Optional<__ObjC.NSBundle>) -> SWTest.VIEwController + 57 at VIEwController.swift,address = 0x00000001070d53f9,hit count = 0   2.3: where = SWTest`SWTest.VIEwController.init (SWTest.VIEwController.Type)(coder : __ObjC.NSCoder) -> Swift.Optional<SWTest.VIEwController> + 16 at VIEwController.swift,address = 0x00000001070d56d0,hit count = 0

在加上名字以后,我们就可以通过名字来 *** 作断点了

(lldb) br disable -N leo1 breakpoints Disabled.
在某一个函数上加断点

例如,在准备Person的函数中personLoop添加断点

(lldb) br s -F personLoopBreakpoint 2: 2 locations.(lldb) br liCurrent breakpoints:1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/VIEwController.swift',line = 40,hit count = 1  1.1: where = SWTest`SWTest.VIEwController.vIEwDIDLoad (SWTest.VIEwController)() -> () + 75 at VIEwController.swift:40,address = 0x000000010f6d51bb,hit count = 1 2: name = 'personLoop',locations = 2,resolved = 2,hit count = 0  2.1: where = SWTest`SWTest.Person.personLoop (SWTest.Person)() -> () + 12 at VIEwController.swift:25,address = 0x000000010f6d45cc,hit count = 0   2.2: where = SWTest`@objc SWTest.Person.personLoop (SWTest.Person)() -> () + 4 at VIEwController.swift,address = 0x000000010f6d4664,hit count = 0
条件断点

先在这里加一个断点

当某种条件产生的时候触发的断点,例如停在1000次循环的第800次

然后添加条件,停在i == 80

(lldb) br liCurrent breakpoints:1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/VIEwController.swift',address = 0x00000001094d81bb,hit count = 1 2: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/VIEwController.swift',hit count = 1  2.1: where = SWTest`SWTest.Person.personLoop (SWTest.Person)() -> () + 111 at VIEwController.swift:27,address = 0x00000001094d762f,hit count = 1 (lldb) br modify -c 'i == 80'(lldb) po i80
断点行为

当断点触发的时候,执行的LLDB代码

例如,当i==80的时候,输出sum

(lldb) br liCurrent breakpoints:1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/VIEwController.swift',line = 40,hit count = 1  1.1: where = SWTest`SWTest.VIEwController.vIEwDIDLoad (SWTest.VIEwController)() -> () + 75 at VIEwController.swift:40,address = 0x00000001057391bb,hit count = 1 3: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/VIEwController.swift',line = 27,hit count = 0  3.1: where = SWTest`SWTest.Person.personLoop (SWTest.Person)() -> () + 111 at VIEwController.swift:27,address = 0x000000010573862f,hit count = 0 (lldb) br modify -c 'i == 80' 3(lldb) br command add 3Enter your deBUGger command(s). Type 'DONE' to end.> po sum> DONE po sum3160
其他断点相关

lldb中输入

(lldb) help br set

篇幅限制,不列出help的结果了

类型查找Type

抛出一个异常,不知道是啥的时候怎么办?

(lldb) type lookup CustomErrorenum CustomError : ErrorType {  case LeoError1  case LeoError2  var hashValue: Swift.Int {    get {}  }  var _code: Swift.Int {    get {}  }}

可以简写

(lldb) ty l CustomErrorenum CustomError : ErrorType {  case LeoError1  case LeoError2  var hashValue: Swift.Int {    get {}  }  var _code: Swift.Int {    get {}  }}
LLDB中的异常处理

执行一个抛出异常的方法

(lldb) e person.personException()(SWTest.CustomError) $E0 = LeoError1
流程控制

frame info 查看当前所在的位置

(lldb) frame infoframe #0: 0x000000010573862f SWTest`SWTest.Person.personLoop (self=0x00007fbaf1d054d0)() -> () + 111 at VIEwController.swift:27
c 继续运行 n next 下一行 s step in finish step out 函数提前返回
thread return

通过这个命令,可以很好的隔离函数,通常用在函数的最开始位置,避免ARC引用计数问题

最后

欢饮关注我的CSDN博客,很长一段时间内,我会持续的更新iOS/Swift/Objective C相关的文章

LLDB调试的文章应该还有一篇进阶使用的,近期会更新

总结

以上是内存溢出为你收集整理的Swift 代码调试核武-LLDB调试基础全部内容,希望文章能够帮你解决Swift 代码调试核武-LLDB调试基础所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1080950.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-27
下一篇 2022-05-27

发表评论

登录后才能评论

评论列表(0条)

保存