iOS之lldb 调试技巧

2017/05/26 blog

前言

在程序员的路上,bug 总是伴随而行,遇到bug 怎么办?当然是解决啦,解决bug 调试必不可少,。工欲善其事,必先利其器,今天来说说iOS的额调试:lldb

自己开发的,有源码,直接使用xcode 进入调试模式即可,没什么好讲的。当看到别人开发的APP,我们想学习学习,想一探究竟怎么办呢。今天讲讲怎么调试别人的APP。

废话不多说,开始

准备工作

MacPro$ ls /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/
硌,你会看到以下结果
10.0/         10.2 (14C89)/ 8.1/          8.3/          9.0/          9.2/         
10.1/         8.0/          8.2/          8.4/          9.1/          9.3/

选择一个版本,适合你的iOS系统的,

$ hdiutil attach /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/10.3\ \(14E269\)/DeveloperDiskImage.dmg
Checksumming whole disk (Apple_HFS : 0)…
.....................................................................................................................................
          whole disk (Apple_HFS : 0): verified   CRC32 $2C5704DD
verified   CRC32 $3E5D9CC2
/dev/disk2          	                               	/Volumes/DeveloperDiskImage
$ ls /Volumes/DeveloperDiskImage/usr/bin/
DTDeviceArbitration	XcodeDeviceMonitor	debugserver		xctest
ScreenShotr		axauditd		iprofiler

这时在/Volumes/DeveloperDiskImage/usr/bin/ 看到debugserver 了

MacPro$ codesign -s - --entitlements entitlements.plist -f debugserver

entilements.plist 的内容如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/ PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.springboard.debugapplications</key> <true/>
    <key>run-unsigned-code</key> <true/>
    <key>get-task-allow</key> <true/>
    <key>task_for_pid-allow</key> <true/>
</dict> 
</plist>

然后把debugserver 拷贝到手机上

MacPro$ scp ./debugserver root@192.168.0.101:/usr/bin/

慢着,记得看看debugserver 的权限

#chmod +x /usr/bin/debugserver
# debugserver *:6666 -a Preferences

嗯,等个1分钟就可以了

$ lldb
(lldb) platform select remote-ios
(lldb) process connect connect://192.168.0.101:6666

debugserver-310.2 for armv7.
Attaching to process Preferences...
Listening to port 6666 for a connection from *...

嗯,这里等了几分钟终于看到结果了。

几分钟,小编,你搞事情啊,有没有能快点的方法

下面来介绍一种快速的方法:通过USB来调试

*下载usbmuxd :https://github.com/libimobiledevice/usbmuxd 或者 :http://iphonedevwiki.net/index.php/SSH_Over_USB#Using_python 安装好。

打开终端

$ iproxy 6666 6666
(lldb) process connect connect://localhost:6666
$ ssh root@localhost -p 2222
root@localhost's password: 

Starting debuging

如果你想调试的APP 正在运行

# ps -ax 
  PID TTY           TIME CMD
    ...
 2953 ??         0:02.27 /Applications/MobileSMS.app/MobileSMS
    ...

通过pid attach

# debugserver *:6666 -a 2953

或者

# debugserver *:6666 -a MobileSMS

在你mac上

(lldb) platform select remote-ios
(lldb) process connect connect://192.168.0.101:6666

或者USB的方式

(lldb) platform select remote-ios
(lldb) process connect connect://localhost:6666

如果APP还没有运行

# debugserver *:6666 -waitfor MobileSMS
(lldb) platform select remote-ios
(lldb) process connect connect://192.168.0.101:6666

或者

(lldb) platform select remote-ios
(lldb) process connect connect://localhost:6666

还有一种情况,我们想调试APP的启动过程

# debugserver *:6666 -x backboard /Applications/MobileSMS.app/MobileSMS

或者

# find /private/var/mobile/Containers/Bundle/Application  -name "QQMusic"
/private/var/mobile/Containers/Bundle/Application/49737E0A-343F-447B-B863-4866E7BE7727/QQMusic.app/QQMusic

# debugserver *:1234 -x backboard /private/var/mobile/Containers/Bundle/Application/49737E0A-343F-447B-B863-4866E7BE7727/QQMusic.app/QQMusic
debugserver-@(#)PROGRAM:debugserver  PROJECT:debugserver-320.2.89
 for arm64.
Listening to port 1234 for a connection from *…
The -x parameter can be one of:

auto: Auto-detect the best launch method to use.
fork: Launch program using fork() and exec().
posix: Launch program using posix_spawn().
backboard: Launch program via BackBoard Services.
Note! Always use backboard to start iOS GUI applications! 

同样在你的mac上启动lldb

(lldb) platform select remote-ios
(lldb) process connect connect://192.168.0.101:6666

或者

(lldb) platform select remote-ios
(lldb) process connect connect://localhost:6666

*有可能你在连接的时候报

(lldb) process connect connect://localhost:6666
error: failed to get reply to handshake packet

把你的程序手动杀死一遍或者kill -9 WeChat

(lldb) image list
[  0] D4078742-B857-3661-B9FE-465518CAED3C 0x0000000120080000 /Users/uusafe/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/usr/lib/dyld

你没看错,我的qq 音乐就只加载了这么个东西 其他的怎么加载呢

Use the following commands to load all images:

(lldb) settings set target.process.stop-on-sharedlibrary-events 1
(lldb) c
(lldb) settings set target.process.stop-on-sharedlibrary-events 0
(lldb) image list
[  0] 813351AD-C374-3903-B832-DED6E23E7D62 0x0000000100010000 /var/mobile/Containers/Bundle/Application/49737E0A-343F-447B-B863-4866E7BE7727/QQMusic.app/WeChat (0x0000000100010000)
[  1] D4078742-B857-3661-B9FE-465518CAED3C 0x0000000120080000 /Users/uusafe/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/usr/lib/dyld

接下来我们看看lldb 的命令

# debugserver *:6666 -a WeChat
debugserver-@(#)PROGRAM:debugserver  PROJECT:debugserver-340.3.124
 for arm64.
Attaching to process WeChat...
Listening to port 6666 for a connection from *...
Waiting for debugger instructions for process 0.
$ lldb
(lldb) process connect connect://localhost:6666
Process 690 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x00000001983dca40 libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
->  0x1983dca40 <+8>: ret    

libsystem_kernel.dylib`mach_msg_overwrite_trap:
    0x1983dca44 <+0>: mov    x16, #-0x20
    0x1983dca48 <+4>: svc    #0x80
    0x1983dca4c <+8>: ret
(lldb) thread backtrace 
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00000001983dca40 libsystem_kernel.dylib`mach_msg_trap + 8
    frame #1: 0x00000001983dc8bc libsystem_kernel.dylib`mach_msg + 72
    frame #2: 0x0000000182f80108 CoreFoundation`__CFRunLoopServiceMachPort + 196
    frame #3: 0x0000000182f7de0c CoreFoundation`__CFRunLoopRun + 1032
    frame #4: 0x0000000182eacca0 CoreFoundation`CFRunLoopRunSpecific + 384
    frame #5: 0x000000018e0e8088 GraphicsServices`GSEventRunModal + 180
    frame #6: 0x00000001885c4ffc UIKit`UIApplicationMain + 204
    frame #7: 0x00000001000dbea4 WeChat`-[WATemplateMsgMngSwitchCell .cxx_destruct] + 372
    frame #8: 0x00000001982da8b8 libdyld.dylib`start + 4

看到当前主线程中,还有各个frame的状态

我们再看看微信当前的UI结构:

(lldb) po [[UIApplication sharedApplication] keyWindow]
<iConsoleWindow: 0x15e797a10; baseClass = UIWindow; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x15e7999b0>; layer = <UIWindowLayer: 0x15e794520>>

(lldb) po [[[UIApplication sharedApplication] keyWindow] rootViewController]
<MMTabBarController: 0x15f0c4600>

我们从上面的结果来看,知道微信的大致结构了(你这不废话吗,我不用调试我也知道)。

breakpoint 命令

可以根据函数名设置断点:

(lldb) breakpoint set --name main
(lldb) br s -n main
(lldb) b main
(lldb) breakpoint set --method main
(lldb) br s -M main
(lldb)breakpoint set --shlib libsystem_kernel.dylib --name open

可以根据文件名,代码行数设置断点:

(lldb) breakpoint set --file test.c --line 12
(lldb) br s -f test.c -l 12
(lldb) b test.c:12

对于OC:

(lldb) breakpoint set --name "-[NSString stringWithFormat:]"
(lldb) b -[NSString stringWithFormat:]

也可以

(lldb) breakpoint set --selector count
(lldb) br s -S count

单步进入

(lldb) thread step-in
(lldb) step
(lldb) s

单步跳过

(lldb) thread step-over
(lldb) next
(lldb) n

查看所有断点:

(lldb) breakpoint set -name sendAction:to:from:forEvent:
Breakpoint 1: where = UIKit`-[UIApplication sendAction:to:from:forEvent:], address = 0x0000000188593c98
(lldb) br list 
Current breakpoints:
1: name = 'sendAction:to:from:forEvent:', locations = 1, resolved = 1, hit count = 0
  1.1: where = UIKit`-[UIApplication sendAction:to:from:forEvent:], address = 0x0000000188593c98, resolved, hit count = 0 

(lldb) br l
Current breakpoints:
1: name = 'sendAction:to:from:forEvent:', locations = 1, resolved = 1, hit count = 0
  1.1: where = UIKit`-[UIApplication sendAction:to:from:forEvent:], address = 0x0000000188593c98, resolved, hit count = 0

删除断点:

(lldb) breakpoint delete 1
(lldb) br del 1

print 命令

可能print 命令是我们在平时开发中使用频率最高的了. 输入help print

'print' is an abbreviation for 'expression --'

我们平时打印对象时会使用po(print object) 其实就是expression -o –的缩写

(lldb) po @[@"1",@"2"]
<__NSArrayI 0x12795b4d0>(
1,
2
)


(lldb) expression -o -- @[@"1",@"2"]
<__NSArrayI 0x127bc7de0>(
1,
2
)

会得到同样的结果。

同样我们要打印一个对象。我们更喜欢直接使用po 而不是expression -o –

(lldb) po [[UIApplication sharedApplication] delegate]
<MicroMessengerAppDelegate: 0x126798290>

另外,可以给 print 指定不同的打印格式。它们都是以 print/ 或者简化的 p/ 格式书写。下面是一些例子:

(lldb) p 16
(int) $7 = 16
(lldb) p/x 16
(int) $8 = 0x00000010
(lldb) p/t 16
(int) $9 = 0b00000000000000000000000000010000

expression 命令

expression 的作用当然不只是打印一个对象,比如说

(lldb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] class]
MMTabBarController

(lldb) expression id $ret = (id)[[[UIApplication sharedApplication] keyWindow] rootViewController]
(lldb) po [$ret class]
MMTabBarController

嗯,就是有这种操作。

再来个神级的操作:

(lldb) po [$ret _shortMethodDescription]
<MMTabBarController: 0x126883000>:
in MMTabBarController:
	Properties:
		@property (weak, nonatomic) <MMTabBarControllerDelegate>* delegate;
	Instance Methods:
		- (id) currentViewController; (0x101c38bb4)
		- (id) getViewControllerAtIndex:(unsigned int)arg1; (0x101c38bc0)
.....

嗯,是的,所有方法和属性都打印出来了。

当然你也可以像写程序一样来:

(lldb) expression char* $str = (char*)malloc(sizeof(char)*8)
(lldb) expression (void*)memset($str,0,8)
(void *) $11 = 0x00000001267ab9b0
(lldb) expression (void*)memcpy((void*)$str,(void*)"1234567",7)
(void *) $12 = 0x00000001267ab9b0
(lldb) p (char*)$str
(char *) $13 = 0x00000001267ab9b0 "1234567"
(lldb) expression (void)free((void*)$str)

当然还有很多其他的操作,可以使用

(lldb) help expression

来查看,讲的非常详细

thread 命令

有时候,我们想了解线程堆栈信息,可以使用thread backtrace,thread backtrace 的作用是将线程的堆栈信息打印出来

(lldb) help thread
     Commands for operating on one or more threads in the current process.

Syntax: thread <subcommand> [<subcommand-options>]

当发生crash的时候,我们可以使用thread backtrace 查看堆栈调用信息

(lldb) thread backtrace 
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
  * frame #0: 0x00000001983dc8c8 libsystem_kernel.dylib`mach_msg + 84
    frame #1: 0x0000000182f80108 CoreFoundation`__CFRunLoopServiceMachPort + 196
    frame #2: 0x0000000182f7de0c CoreFoundation`__CFRunLoopRun + 1032
    frame #3: 0x0000000182eacca0 CoreFoundation`CFRunLoopRunSpecific + 384
    frame #4: 0x000000018e0e8088 GraphicsServices`GSEventRunModal + 180
    frame #5: 0x00000001885c4ffc UIKit`UIApplicationMain + 204
    frame #6: 0x0000000100157ea4 WeChat`-[WATemplateMsgMngSwitchCell .cxx_destruct] + 372
    frame #7: 0x00000001982da8b8 libdyld.dylib`start + 4

有时候,我们并不想让代码执行,只需要返回一个结果就好了,比如:

(lldb) thread return NO

具体的看help thread 吧,很详细.

frame 命令

有时候,我们想查看线程中的调用栈是什么样的,有时候我们经常查看变量的值

查看当前堆栈帧的所有本地变量

(lldb) frame variable
(ViewController *) self = 0x00007f84fed03df0
(SEL) _cmd = "viewDidLoad"
(NSArray *) array = 0x3ff0000000000000

查看某个具体变量

(lldb) frame variable bar

(lldb) fr v bar

(lldb) p bar //print bar的缩写

查看当前frame的信息:

(lldb) frame info
frame #0: 0x0000000104938b51 DemoSandbox`::-[ViewController viewDidLoad](self=0x00007f84fed03df0, _cmd="viewDidLoad") at ViewController.mm:38

有时候,由于某种原因,我们想观察的变量或者返回值过了,但是再来调试又麻烦,怎么办, 这时就有一个非常好的命令

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
  * frame #0: 0x0000000104938b9e DemoSandbox`::-[ViewController viewDidLoad](self=0x00007f84fed03df0, _cmd="viewDidLoad") at ViewController.mm:40
    frame #1: 0x0000000105ecbcca UIKit`-[UIViewController loadViewIfRequired] + 1235
    ......
(lldb) frame select 1
frame #1: 0x000000010a00fcca UIKit`-[UIViewController loadViewIfRequired] + 1235
UIKit`-[UIViewController loadViewIfRequired]:
    0x10a00fcca <+1235>: mov    eax, dword ptr [r14]
    0x10a00fccd <+1238>: test   eax, eax
    0x10a00fccf <+1240>: je     0x10a00fcdd               ; <+1254>
    0x10a00fcd1 <+1242>: cmp    eax, 0x70000

把程序状态倒回去,方便我们查看。

(lldb) frame info
frame #1: 0x000000010a00fcca UIKit`-[UIViewController loadViewIfRequired] + 1235

当然还有很多其他方法,等用到的时候再去看,大多数时候是用不到的。

breakpoint command

breadkpoint command add 命令就是给断点添加命令的命令

假设我们需要在sendAction:to:from:forEvent: 查看action 是什么,我们首先给sendAction:to:from:forEvent: 添加一个断点。

(lldb) breakpoint set -name sendAction:to:from:forEvent:
Breakpoint 1: where = UIKit`-[UIApplication sendAction:to:from:forEvent:], address = 0x0000000188593c98
(lldb) breakpoint list 
Current breakpoints:
1: name = 'sendAction:to:from:forEvent:', locations = 1, resolved = 1, hit count = 9
  1.1: where = UIKit`-[UIApplication sendAction:to:from:forEvent:], address = 0x0000000188593c98, resolved, hit count = 9 

可以看到添加成功之后,这个breakpoint的id为1,然后我们给他增加一个命令:po self.view

(lldb) breakpoint command add -o "po self.view" 1

输入breakpoint command add 3对断点3增加命令。他会让你输入增加哪些命令,输入’DONE’表示结束。这时候你就可以输入多条命令了

(lldb) breakpoint command add 1
Enter your debugger command(s).  Type 'DONE' to end.
> p (char*)$x2 
> continue  
> DONE
(lldb) breakpoint command list 1
Breakpoint 1:
    Breakpoint commands:
      p (char*)$x2
      continue 
(lldb) c
Process 809 resuming
(lldb)  p (char*)$x2
(char *) $2 = 0x0000000188fa5257 "_buttonUp:"
(lldb)  continue 
Process 809 resuming
Command #2 'continue ' continued the target.
.....

多次对同一个断点添加命令,后面命令会将前面命令覆盖

有add 就有delete

(lldb) breakpoint command delete 1
(lldb) breakpoint command list 1
Breakpoint 1 does not have an associated command.

watchpoint

breakpoint有一个孪生兄弟watchpoint。如果说breakpoint是对方法生效的断点,watchpoint就是对地址生效的断点

如果我们想知道某个属性什么时候被篡改了,我们如何有效监测了。这时候最好的办法就是用watchpoint。我们可以用他观察这个属性的地址,如果地址里面的东西改了,就让程序中断

(lldb) watchpoint set variable _objcProperty
Watchpoint created: Watchpoint 1: addr = 0x7fa34e007898 size = 8 state = enabled type = w
    watchpoint spec = '_objcProperty'
    new value: 0x0000000000000000

当属性被篡改的时候,程序中断

Watchpoint 1 hit:
old value: 0x0000000000000000
new value: 0x000000010101e3b8

还有很多其他的命令,使用help watchpoint 查看

(lldb) watchpoint help
     Commands for operating on watchpoints.

Syntax: watchpoint <subcommand> [<command-options>]

The following subcommands are supported:

      command -- Commands for adding, removing and examining LLDB commands executed when the watchpoint is hit (watchpoint
                 'commmands').
      delete  -- Delete the specified watchpoint(s).  If no watchpoints are specified, delete them all.
      disable -- Disable the specified watchpoint(s) without removing it/them.  If no watchpoints are specified, disable them all.
      enable  -- Enable the specified disabled watchpoint(s). If no watchpoints are specified, enable all of them.
      ignore  -- Set ignore count on the specified watchpoint(s).  If no watchpoints are specified, set them all.
      list    -- List all watchpoints at configurable levels of detail.
      modify  -- Modify the options on a watchpoint or set of watchpoints in the executable.  If no watchpoint is specified, act on
                 the last created watchpoint.  Passing an empty argument clears the modification.
      set     -- Commands for setting a watchpoint.

For more help on any particular subcommand, type 'help <command> <subcommand>'.

而且帮助中还有更加详细的。根据自己需要吧,太多了

target

对于target这个命令,我们用得最多的可能就是target modules lookup。由于LLDB给target modules取了个别名image,所以这个命令我们又可以写成image lookup。

(lldb) target modules list 
[  0] D4078742-B857-3661-B9FE-465518CAED3C 0x00000001200b8000 /Users/heyonly/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/usr/lib/dyld 
[  1] 8B7A2113-6F44-34DF-B277-1B8A4218A0F1 0x000000010003c000 /var/mobile/Containers/Bundle/Application/864A552D-40ED-4C24-994E-E23AE8A86122/WeChat.app/WeChat (0x000000010003c000)
......

或者

(lldb) image list 
[  0] D4078742-B857-3661-B9FE-465518CAED3C 0x00000001200b8000 /Users/heyonly/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/usr/lib/dyld 
[  1] 8B7A2113-6F44-34DF-B277-1B8A4218A0F1 0x000000010003c000 /var/mobile/Containers/Bundle/Application/864A552D-40ED-4C24-994E-E23AE8A86122/WeChat.app/WeChat (0x000000010003c000)
image lookup --address

当我们的工程已经很大了。当程序crash的时候,可能一下子找不到地方,这时我们可以使用image lookup –address 查找crash的文件位置。e.g:

2017-05-29 10:04:49.576 DemoSandbox[3283:299768] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 3 beyond bounds [0 .. 1]'
*** First throw call stack:
(
	0   CoreFoundation                      0x0000000105e7ab0b __exceptionPreprocess + 171
	1   libobjc.A.dylib                     0x00000001058df141 objc_exception_throw + 48
	2   CoreFoundation                      0x0000000105db83eb -[__NSArrayI objectAtIndex:] + 155
	3   DemoSandbox                         0x0000000104eadaed -[ViewController viewDidLoad] + 381
	4   UIKit                               0x0000000106440cca -[UIViewController loadViewIfRequired] + 1235
	5   UIKit                               0x000000010644110a -[UIViewController view] + 27
	6   UIKit                               0x000000010630963a -[UIWindow addRootViewControllerViewIfPossible] + 65
	7   UIKit                               0x0000000106309d20 -[UIWindow _setHidden:forced:] + 294
	8   UIKit                               0x000000010631cb6e -[UIWindow makeKeyAndVisible] + 42
	9   UIKit                               0x000000010629631f -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4346
	10  UIKit                               0x000000010629c584 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1709
	11  UIKit                               0x0000000106299793 -[UIApplication workspaceDidEndTransaction:] + 182
	12  FrontBoardServices                  0x000000010e4805f6 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24
	13  FrontBoardServices                  0x000000010e48046d -[FBSSerialQueue _performNext] + 186
	14  FrontBoardServices                  0x000000010e4807f6 -[FBSSerialQueue _performNextFromRunLoopSource] + 45
	15  CoreFoundation                      0x0000000105e20c01 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
	16  CoreFoundation                      0x0000000105e060cf __CFRunLoopDoSources0 + 527
	17  CoreFoundation                      0x0000000105e055ff __CFRunLoopRun + 911
	18  CoreFoundation                      0x0000000105e05016 CFRunLoopRunSpecific + 406
	19  UIKit                               0x000000010629802f -[UIApplication _run] + 468
	20  UIKit                               0x000000010629e0d4 UIApplicationMain + 159
	21  DemoSandbox                         0x0000000104eaf5df main + 111
	22  libdyld.dylib                       0x0000000107c8065d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) image lookup --address 0x0000000104eadaed
      Address: DemoSandbox[0x0000000100001aed] (DemoSandbox.__TEXT.__text + 381)
      Summary: DemoSandbox`::-[ViewController viewDidLoad]() + 381 at ViewController.mm:48

通过image lookup –address 可以知道,在ViewController.mm 文件的48行。

image lookup --name

当我们想查找一个方法或者符号的信息,比如文件的位置等等,我们可以使用image lookup –name,简写为image lookup -n,e.g:

(lldb) image lookup -n stringWithFormat:
1 match found in /Users/heyonly/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/System/Library/Frameworks/Foundation.framework/Foundation:
        Address: Foundation[0x0000000182fb676c] (Foundation.__TEXT.__text + 1068)
        Summary: Foundation`+[NSString stringWithFormat:]
(lldb) help target modules 
     Commands for accessing information for one or more target modules.

Syntax: target modules <sub-command> ...

比如我们输入:

(lldb) image lookup -rn . WeChat

结果,就自己去看了。。。

(lldb) help image dump sections 
     Dump the sections from one or more target modules.

Syntax: target modules dump sections [<filename> [<filename> [...]]]
(lldb) image dump sections WeChat
Sections for '/var/mobile/Containers/Bundle/Application/864A552D-40ED-4C24-994E-E23AE8A86122/WeChat.app/WeChat(0x000000010003c000)' (arm64):
  SectID     Type             Load Address                             Perm File Off.  File Size  Flags      Section Name
  ---------- ---------------- ---------------------------------------  ---- ---------- ---------- ---------- ----------------------------
  0x00000100 container        [0x0000000000000000-0x0000000100000000)* ---  0x00000000 0x00000000 0x00000000 WeChat.__PAGEZERO
  0x00000200 container        [0x000000010003c000-0x00000001033a8000)  r-x  0x00000000 0x0336c000 0x00000000 WeChat.__TEXT
  0x00000001 code             [0x0000000100043000-0x0000000102c5bfc8)  r-x  0x00007000 0x02c18fc8 0x80000400 WeChat.__TEXT.__text
  0x00000002 code             [0x0000000102c5bfc8-0x0000000102c5f5f8)  r-x  0x02c1ffc8 0x00003630 0x80000408 WeChat.__TEXT.__stubs
  0x00000003 code             [0x0000000102c5f5f8-0x0000000102c62bec)  r-x  0x02c235f8 0x000035f4 0x80000400 WeChat.__TEXT.__stub_helper
  0x00000004 data-cstr        [0x0000000102c62bec-0x0000000102e0db1f)  r-x  0x02c26bec 0x001aaf33 0x00000002 WeChat.__TEXT.__objc_methname
  ......

(lldb) p/x 0x000000010003c000-0x0000000100000000
(long) $47 = 0x000000000003c000

这个 0x000000000003c000 就是ALSR 偏移了。

target stop-hook

当我们调试程序的时候,有时候我们只是想知道这个函数或方法的参数或者返回值,而不需要我们手动去获取,这时我们就可以在这个断点上添加一些行为,同样我们先help,养成好习惯

(lldb) help target stop-hook 
     Commands for operating on debugger target stop-hooks.

Syntax: target stop-hook <subcommand> [<subcommand-options>]

The following subcommands are supported:

      add     -- Add a hook to be executed when the target stops.
      delete  -- Delete a stop-hook.
      disable -- Disable a stop-hook.
      enable  -- Enable a stop-hook.
      list    -- List all stop-hooks.

For more help on any particular subcommand, type 'help <command> <subcommand>'.

e.g:我们在某个断点上,我们只需要知道这个类和对象就可以了,不需要暂停,我们既可以这样:

(lldb) target stop-hook add -o "po $x0"
Stop hook #3 added.
(lldb) target stop-hook add -o "continue"
Stop hook #4 added.
(lldb) target stop-hook list
Hook: 3
  State: enabled
  Commands: 
    po $x0

Hook: 4
  State: enabled
  Commands: 
    continue

接下来,我们执行continue ,lldb 就会打印$x0 的值,并继续向下走,并没有停下来

当然有add 就有delete ,有enable 就有disable啦,

script

同样我们先help

(lldb) help script 
     Invoke the script interpreter with provided code and display any results.  Start the interactive interpreter if no code is
     supplied.  Expects 'raw' input (see 'help raw-input'.)

Syntax: script [<script-code>]
(lldb) script 
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
>>> print "hello world"
hello world

进入Python 环境了,你可以使用Python一些命令了,Python 正在学,就不举栗子了。

lldb 的命令还有很多,具体的可以查看help命令,非常详细

当然,我们大脑的内存有限,但是还有两个命令一定会记得

help & apropos

help

直接在lldb 中输入help命令

(lldb) help
Debugger commands:

  apropos           -- List debugger commands related to a word or subject.
  breakpoint        -- Commands for operating on breakpoints (see 'help b' for shorthand.)
  bugreport         -- Commands for creating domain-specific bug reports.
  command           -- Commands for managing custom LLDB commands.
  ......

太多。。。

apropos

有时候,脑子短路,一个经常用的命令可能记不全了,只记得某些一部分,或者某个关键字,这时候我们可以使用apropos 来搜索相关命令信息。

(lldb) apropos setting
The following commands may relate to 'setting':
  _regexp-env               -- Shorthand for viewing and setting environment variables.
  platform settings         -- Set settings for the current target's platform, or for a platform by name.
  settings                  -- Commands for managing LLDB settings.
  ......

最后

最后再介绍一下DerekSelander ( https://github.com/DerekSelander/LLDB ) 这位Facebook 大神,lldb用的太六,在GitHub 上有他的源码,有兴趣的可以自己去看看。

还有一位 https://github.com/facebook/chisel

这两个都是用Python写的

搭个梯子出去看看,会有很多新鲜玩意儿☺

参考: [1]:https://developer.apple.com/library/content/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-command-examples.html#//apple_ref/doc/uid/TP40012917-CH3-SW1 [2]:http://codedigging.com/blog/2016-04-27-debugging-ios-binaries-with-lldb/ [3]:http://blog.csdn.net/woaizijiheni/article/details/49181295

[4]:http://ios.jobbole.com/83393/

Search

    Post Directory