Xcode的使用中总是离不开调试这个环境,在一年多的iOS开发时间中,我更多地依赖于XCode本身提供的GUI工具来进行调试,而对LLDB敬而远之,这段时间好好学习了LLDB的使用,发觉我错过了太多东西了……因此做一个比较完备的总结,也希望在写这篇文章的过程中进一步学习LLDB调试的各种实践方法。

LLDB阐述

LLDB 是一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器。LLDB 绑定在 Xcode 内部,存在于主窗口底部的控制台中。调试器允许你在程序运行的特定时暂停它,你可以查看变量的值,执行自定的指令,并且按照你所认为合适的步骤来操作程序的进展。

lldb下,相信大家用的较多的是po,或者使用条件断点。但是面对复杂的问题时,比如.a静态库,就需要其他调试方法了。

breakpoint

给某个文件的某一行下断点。可以使用如下两种方法,比如我想给Person.m文件的10行下一个断点。可以使用如下的方法。

(lldb) breakpoint set --file Person.m --line 10

如果出现如下提示则说明设置断点成功

Breakpoint 2: where = BreakPointDemo`-[Person foo] + 23 at Foo.m:10, address = 0x000000010b22e687

也可以使用简写的形式如下。

(lldb) breakpoint set -f Foo.m -l 10

给一个函数下断点

(lldb) breakpoint set --name foo

(lldb) breakpoint set -n foo

一次性给多个函数下断点

(lldb) breakpoint set --name foo --name bar

OC的方法,可以使用以下两种方式打断点,第二种S需要大写

(lldb) breakpoint set --selector foo

(lldb) breakpoint set -S foo

使用 正则匹配 你要打断点的函数。这个不限语言

(lldb) breakpoint set -r cFoo

(lldb) breakpoint set -r foo

也可以指定加载的动态库

(lldb) breakpoint set --shlib foo.dylib --name foo

(lldb) breakpoint set -s foo.dylib -n foo

我们同样可以对命令进行简写。下面两个命令的效果是一样的

(lldb) breakpoint set -n "-[Foo foo]"

(lldb) br s -n "-[Foo foo]"

查看有多少断点可以使用

(lldb) breakpoint list

打印结果如下:

Current breakpoints:

1: file = '/Users/jianquan/Xcode/BreakPointDemo/BreakPointDemo/ViewCo ntroller.m', line = 20, exact_match = 0, locations = 0 (pending)

2: file = '/Users/jianquan/Xcode/BreakPointDemo/BreakPointDemo/ViewController.mm', line = 33, exact_match = 0, locations = 1, resolved = 1, hit count = 0

2.1: where = BreakPointDemo`::-[ViewController viewDidLoad]() + 186 at ViewController.mm:34, address = 0x0000000105f8362a, resolved, hit count = 0

......

我们可以对断点进行相关的操作,比如在执行到2.1断点的时候打印追踪轨迹。bt是

(lldb) breakpoint command add 2.1

Enter your debugger command(s). Type 'DONE' to end.

> bt

> DONE

删除所有断点

(lldb) breakpoint delete

watchpoint

观察变量值的具体变化

比如我需要观察某个变量a的值变化,我可以使用如下命令

(lldb) watchpoint set variable a

bt命令用来追踪程序的运行过程

(lldb) bt

* thread #1: tid = 0x5c52c2, 0x000000010ff465fe BreakPointDemo`::-[ViewController viewDidLoad](self=0x00007f932cc07c50, _cmd="viewDidLoad") + 158 at ViewController.mm:36, queue = 'com.apple.main-thread', stop reason = watchpoint 1

* frame #0: 0x000000010ff465fe BreakPointDemo`::-[ViewController viewDidLoad](self=0x00007f932cc07c50, _cmd="viewDidLoad") + 158 at ViewController.mm:36

frame #1: 0x000000011112ba3d UIKit`-[UIViewController loadViewIfRequired] + 1258

......

我们可以使用frame命令查看变量a的具体值。

(lldb) frame variable a

(int) a = 100

补充一点watchpoint list的东西。这个命令包括了三个可选参数,我们可以使用help命令查看具体的值

(lldb) help watchpoint list

-b ( --brief )

Give a brief description of the watchpoint (no location info).

-f ( --full )

Give a full description of the watchpoint and its locations.

-v ( --verbose )

Explain everything we know about the watchpoint (for debugging

debugger bugs).

-b是比较简略的信息,-f是比较全面的信息,-v是完整的信息。经过我的实验,如果使用watchpoint list,默认的是 watchpoint list -f。

process

使用process命令也可以做很多有趣的操作。具体能做什么,我们也可使用help命令查看

(lldb) process help

attach -- Attach to a process.

connect -- Connect to a remote debug service.

continue -- Continue execution of all threads in the current process.

detach -- Detach from the current target process.

handle -- Manage LLDB handling of OS signals for the current target

......

查看更详细的命令使用help 。比如

(lldb) help process attach

thread

其实这个功能主要就是断点调试里面的如下这个功能。

1654054-8d533324eaa728a8.png

我们可以使用thread命令来做一些断点的操作,具体有那些命令我们可以使用thread help进行查看

(lldb) thread help

......

select -- Change the currently selected thread.

step-in -- Source level single step, stepping into calls.

Defaults to current thread unless specified.

step-inst -- Instruction level single step, stepping into calls.

Defaults to current thread unless specified.

step-inst-over -- Instruction level single step, stepping over calls.

Defaults to current thread unless specified.

step-out -- Finish executing the current stack frame and stop after

returning. Defaults to current thread unless

specified.

step-over -- Source level single step, stepping over calls.

Defaults to current thread unless specified.

step-scripted -- Step as instructed by the script class passed in the -C

option.

until -- Continue until a line number or address is reached by

the current or specified thread. Stops when returning

from the current function as a safety measure.

用得比较多的应该是 step-开头的这几个命令,使用起来很容易。我个人感觉比用鼠标点击断点好用多了~

检查当前进程的状态,可以使用如下命令

lldb) thread list

Process 22323 stopped

* thread #1: tid = 0x62d0d7, 0x00000001082185fe BreakPointDemo`::-[ViewController viewDidLoad](self=0x00007ff81b60ab20, _cmd="viewDidLoad") + 158 at ViewController.mm:36, queue = 'com.apple.main-thread', stop reason = step until

......

*表明的就是当前的线程,可以使用如下的命令得到线程的回溯,这个词我也不确定怎么表达好,backtrace,也可以说是追踪。

(lldb) thread backtrace

* thread #1: tid = 0x354e72, 0x0000000103ce94bc RunTimeUse`-[ViewController viewDidLoad](self=0x00007ffea04050e0, _cmd="viewDidLoad") + 140 at ViewController.m:24, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1

* frame #0: 0x0000000103ce94bc RunTimeUse`-[ViewController viewDidLoad](self=0x00007ffea04050e0, _cmd="viewDidLoad") + 140 at ViewController.m:24

frame #1: 0x0000000104e21c99 UIKit`-[UIViewController loadViewIfRequired] + 1258

frame #2: 0x0000000104e220cc UIKit`-[UIViewController view] + 27

frame #3: 0x0000000104cebc51 UIKit`-[UIWindow addRootViewControllerViewIfPossible] + 71

frame #4: 0x0000000104cec3a2 UIKit`-[UIWindow _setHidden:forced:] + 293

frame #5: 0x0000000104cffcb5 UIKit`-[UIWindow makeKeyAndVisible] + 42

frame #6: 0x0000000104c78c89 UIKit`-[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4818

frame #7: 0x0000000104c7ede9 UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 1731

frame #8: 0x0000000104c7bf69 UIKit`-[UIApplication workspaceDidEndTransaction:] + 188

frame #9: 0x0000000107dd4723 FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24

frame #10: 0x0000000107dd459c FrontBoardServices`-[FBSSerialQueue _performNext] + 189

frame #11: 0x0000000107dd4925 FrontBoardServices`-[FBSSerialQueue _performNextFromRunLoopSource] + 45

frame #12: 0x0000000104802311 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17

frame #13: 0x00000001047e759c CoreFoundation`__CFRunLoopDoSources0 + 556

frame #14: 0x00000001047e6a86 CoreFoundation`__CFRunLoopRun + 918

frame #15: 0x00000001047e6494 CoreFoundation`CFRunLoopRunSpecific + 420

frame #16: 0x0000000104c7a7e6 UIKit`-[UIApplication _run] + 434

frame #17: 0x0000000104c80964 UIKit`UIApplicationMain + 159

frame #18: 0x0000000103ce9b1f RunTimeUse`main(argc=1, argv=0x00007fff5bf165e8) + 111 at main.m:14

frame #19: 0x000000010763d68d libdyld.dylib`start + 1

frame #20: 0x000000010763d68d libdyld.dylib`start + 1

当然我们如果想看所有线程的backtrace,可以使用thread backtrace all命令。内容太多,我这里就不演示log输出了。

如果我们想单独查看某个线程,我们可以先使用thread select 2跳到某个具体的线程,然后再进行其他操作,比如thread backtrace

为了方便的观测架构参数和本地变量,我们可以使用 frame variable 命令

如果我什么参数也不加,将会把所有的参数和本地变量到打印出来。

(lldb) frame variable

(ViewController *) self = 0x00007ffea04050e0

(SEL) _cmd = "viewDidLoad"

(Person *) p = 0x0000610000001940

要打印某个变量需要在参数里面指定,这个命令我们在前面也使用过,比如要查看self

(lldb) frame variable self

(ViewController *) self = 0x00007ff81b60ab20

更进一步,我们可以查看一些子元素

(lldb) frame variable self->isa

(Class) self->isa = ViewController

命令虽然不是完整的表达式解释器,当时可以识别一些基本的操作 比如 &, *, ->, [],不是重载运算符,数组也可以使用,因为数组本身也是指针。

(lldb) frame variable *self

(ViewController) *self = {

UIViewController = {

UIResponder = {

NSObject = {

isa = ViewController

}

......

}

和之前thread命令很类似,我可以使用frame select去选择另外的一个frame

(lldb) frame select 9

如果想看更复杂的数据,我们可以使用expression命令

(lldb) expression self

(ViewController *) $0 = 0x00007fefa4705110

更复杂一些,我们可以用来输出一个表达式

(lldb) expr (int) printf ("I have a pointer 0x%llx.\n", self)

I have a pointer 0x7fefa4705110.

(int) $1 = 33

call

其实这个命令完全可以使用po进行替代,call一般可以用来调用不需要返回值的调试命令,比如更改View的背景颜色,以下两个命令都可以达到相似的作用,更改当前View的背景颜色值。

(lldb) po [self.view setBackgroundColor:[UIColor redColor]]

(lldb) call [self.view setBackgroundColor:[UIColor redColor]]

image

这个比较实用,可用于寻找栈地址对应的代码位置。

//测试image命令使用

NSArray *a = @[@"1"];

NSLog(@"%@",a[1]);

很显然,数组越界了,以下显示崩溃信息

RunTimeUse[46698:3510999] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

*** First throw call stack:

(

0 CoreFoundation 0x000000010934d34b __exceptionPreprocess + 171

1 libobjc.A.dylib 0x0000000108dae21e objc_exception_throw + 48

2 CoreFoundation 0x00000001093a5bdf -[__NSSingleObjectArrayI objectAtIndex:] + 111

3 RunTimeUse 0x00000001087d9480 -[ViewController viewDidLoad] + 320

4 UIKit 0x0000000109911c99 -[UIViewController loadViewIfRequired] + 1258

5 UIKit 0x00000001099120cc -[UIViewController view] + 27

6 UIKit 0x00000001097dbc51 -[UIWindow addRootViewControllerViewIfPossible] + 71

7 UIKit 0x00000001097dc3a2 -[UIWindow _setHidden:forced:] + 293

8 UIKit 0x00000001097efcb5 -[UIWindow makeKeyAndVisible] + 42

9 UIKit 0x0000000109768c89 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4818

10 UIKit 0x000000010976ede9 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1731

11 UIKit 0x000000010976bf69 -[UIApplication workspaceDidEndTransaction:] + 188

12 FrontBoardServices 0x000000010c8c4723 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24

13 FrontBoardServices 0x000000010c8c459c -[FBSSerialQueue _performNext] + 189

14 FrontBoardServices 0x000000010c8c4925 -[FBSSerialQueue _performNextFromRunLoopSource] + 45

15 CoreFoundation 0x00000001092f2311 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17

16 CoreFoundation 0x00000001092d759c __CFRunLoopDoSources0 + 556

17 CoreFoundation 0x00000001092d6a86 __CFRunLoopRun + 918

18 CoreFoundation 0x00000001092d6494 CFRunLoopRunSpecific + 420

19 UIKit 0x000000010976a7e6 -[UIApplication _run] + 434

20 UIKit 0x0000000109770964 UIApplicationMain + 159

21 RunTimeUse 0x00000001087d9acf main + 111

22 libdyld.dylib 0x000000010c12d68d start + 1

)

libc++abi.dylib: terminating with uncaught exception of type NSException

(lldb)

程序奔溃在3,地址为:0x00000001087d9480,

因为我的Demo名字叫RunTimeUse。其他的名字很明显是系统的库。虽然log的21行也有RunTimeUse,但是经过观察应该是main函数,不在考虑范围之内。

我们使用image的 lookup命令,可以很快的定位到具体的代码行。

(lldb) image lookup --address 0x00000001087d9480

Address: RunTimeUse[0x0000000100001480] (RunTimeUse.__TEXT.__text + 320)

Summary: RunTimeUse`-[ViewController viewDidLoad] + 320 at ViewController.m:28

1654054-7dd117c55d5e5772.png

可以看出,奔溃在ViewController.m中的第28行。

android lldb断点,iOS lldb断点调试相关推荐

  1. 用debugserver+lldb代替gdb进行iOS远程动态调试

    转载自:http://aigudao.net/archives/244.html 以下部分内容摘自<iOS应用逆向工程>第二版,以iOS 8为环境编写,应该也支持iOS 7,请大家注意. ...

  2. android studil打断点_Android Studio你不知道的调试技巧

    写代码不可避免有Bug,通常情况下除了日志最直接的调试手段就是debug;那么你的调试技术停留在哪一阶段呢?仅仅是下个断点单步执行吗?或者你知道 Evaluate Expression,知道条件断点; ...

  3. 一步一步用debugserver + lldb代替gdb进行动态调试(整理与补充)

    原文章出处:http://bbs.iosre.com/t/debugserver-lldb-gdb/65/12 *** 以下部分内容摘自<iOS应用逆向工程>第二版,以iOS 8为环境编写 ...

  4. [系统安全] 二十四.逆向分析之OllyDbg调试INT3断点、反调试、硬件断点与内存断点

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  5. Eclipse 答疑:如何使用 Eclipse 进行断点(Breakpoints)调试?

    文章目录 前言 一.打开需要调试的程序 二.设置断点 三.进行代码调试 3.1.在上方标签栏,点击"Debug As→Java Application" 3.2.进入调试页面并查看 ...

  6. 微信开发者工具模拟器、IOS真机调试、Android真机调试中Editor效果不一致问题

    问题环境: 1.微信开发者工具1.05.2110290(以下简称"工具") 2.真机调试1.0版本(不区分IOS与Android) 3.微信的editor component,用于 ...

  7. 【Android】Android Studio 1.5+ 中混合调试Native和Java代码

    [Android]Android Studio 1.5+ 中调试Native和Java代码 Android Studio 1.5+表示Android Studio 1.5版本以及以上. 网上大部分中文 ...

  8. 快手,快影 iOS App反调试

    Python实战社群 Java实战社群 长按识别下方二维码,按需求添加 扫码关注添加客服 进Python社群▲ 扫码关注添加客服 进Java社群▲ 作者 | 倒影cc  来源 | 掘金 https:/ ...

  9. 【Win7下Android native code的编译和调试】

    光为这编译及调试环境就前后折腾了两三天,墙外找了很多教程,bill以为以下教程最为贴切 Using eclipse for android - cc Development Using eclipse ...

最新文章

  1. 【备忘】bounce ease
  2. java 手动编译打包_Maven 手动添加第三方依赖包及编译打包和java命令行编译JAVA文件并使用jar命令打包...
  3. ar路由器 pppoe下发ipv6 dns_移动宽带如何获取IPV6地址
  4. SpaceEmacs Rock Day7 学习笔记
  5. mybatis Caused by: java.io.IOException: Could not find resource xxx.xml
  6. 利用 Python 写一个颜值测试小工具
  7. 《openstack-nova》use-novaclient 创建虚拟机(createvms.py)
  8. Java从0开始之Java环境搭建
  9. php.ini中设置session过期时间
  10. servlet容器_Tomcat是一个Servlet容器?
  11. java 注释器_注释和注释处理器入门指南
  12. (转)听赌徒谈风险:没犯任何错误照样输个精光
  13. python下载手机app视频教程_Python实例教学
  14. Python-科比投篮预测
  15. 基于java在线问卷调查系统
  16. 市场调研—2021-2027全球与中国肌酸激酶试剂市场现状及未来发展趋势
  17. SQL Server 按间隔时间查询记录
  18. 教育行业网络安全等级保护法律法规参考
  19. ORAN专题系列-21:主要的玩家(设备商)以及他们各自的态度、擅长领域
  20. Oracle快速复制一张表

热门文章

  1. 惊,苹果FB相继故障
  2. Recast编译方式
  3. win7怎么设置开机不用密码登陆?
  4. 建模杂谈系列226 流程与对象
  5. 中国无车承运人行业需求前景与投资战略研究报告2022-2027年
  6. Linux中的ko怎么玩?:进阶版
  7. PC端诉前案件管理系统功能介绍
  8. 基于DCT变换和PN序列的数字水印嵌入和提取matlab仿真
  9. orangePI Lite 安装ubuntu desktop image以及配置
  10. 39 解决全志h3 linux内核源码里的关于script.fex的bug