LLDB

官网:The LLDB DebuggerJoySeeDog/iOS开发断点调试高级技巧Xcode 常用 LLDB 指令

 

一、breakpoint

1、给某个文件的某一行设置断点

(lldb) breakpoint set --file ViewController.m --line 123
Breakpoint 14: where = Demo`-[ViewController viewDidLoad] + 87 at ViewController.m:139, address = 0x00000001029b1de7

ViewController.m 文件的 123 行设置断点,出现提示则说明设置断点成功。

也可以使用简写的形式:

(lldb) breakpoint set -f ViewController.m -l 145
Breakpoint 15: where = Demo`-[ViewController viewDidLoad] + 125 at ViewController.m:146, address = 0x00000001029b1e0d

 

2、给某个函数设置断点

(lldb) breakpoint set --name MyDesignRetain
Breakpoint 16: where = Demo`MyDesignRetain + 16 at ViewController.m:94, address = 0x00000001029b2080

简写形式:

(lldb) breakpoint set -n MyDesignRelease
Breakpoint 18: where = Demo`MyDesignRelease + 16 at ViewController.m:99, address = 0x00000001029b20a0

也可以在一次命令中为多个函数设置断点:

(lldb) breakpoint set --name MyDesignRetain --name MyDesignRelease
Breakpoint 19: 2 locations.

如果是 C 的方法,可以使用如下两种的方法打断点,第二种 M 需要大写。

/**
 *  自定义的 c 方法没有设置成功
 */
void cfunc(int i) {
    printf("%d", i);
}


(lldb) breakpoint set --method cfunc
Breakpoint 10: no locations (pending).
WARNING:  Unable to resolve breakpoint to any actual locations.
(lldb) breakpoint set -M cfunc
Breakpoint 11: no locations (pending).
WARNING:  Unable to resolve breakpoint to any actual locations.
(lldb) breakpoint set -M main
Breakpoint 12: where = JavaScriptCore`WTF::RunLoop::main(), address = 0x000000011e18b060
(lldb) breakpoint set --method main Breakpoint 17: where = JavaScriptCore`WTF::RunLoop::main(), address = 0x000000011e18b060

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

- (UIImage *)drawImage:(UIImage *)image
{
    return nil;
}

(lldb) breakpoint set --selector drawImage 
Breakpoint 20: no locations (pending). 
WARNING: Unable to resolve breakpoint to any actual locations.
(lldb) breakpoint set --selector drawImage:
Breakpoint 21: where = Demo`-[ViewController drawImage:] + 23 at ViewController.m:65, address = 0x000000010d6cba97
(lldb) breakpoint set -S drawImage:
Breakpoint 22: where = Demo`-[ViewController drawImage:] + 23 at ViewController.m:65, address = 0x000000010d6cba97

(lldb) breakpoint set --selector viewDidLoad
Breakpoint 23: 104 locations.
(lldb) breakpoint set -S viewDidLoad
Breakpoint 24: 104 locations.

如果是 C 语言,还是只能使用上面介绍的 --name 的方式,不能直接指定对应的方法。

(lldb) breakpoint set --name cfunc
Breakpoint 27: where = Demo`cfunc + 18 at ViewController.m:118, address = 0x000000010d6cbd72

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

(lldb) breakpoint set -r cfunc
Breakpoint 28: where = Demo`cfunc + 18 at ViewController.m:118, address = 0x000000010d6cbd72
(lldb) breakpoint set -r drawImage
Breakpoint 29: 43 locations.

 

3、指定加载的动态库

(lldb) breakpoint set --shlib libobjc.A.dylib --name alloc
Breakpoint 12: where = libobjc.A.dylib`+[NSObject alloc], address = 0x000000010de6c179
(lldb) breakpoint set -s libobjc.A.dylib --name alloc
Breakpoint 13: where = libobjc.A.dylib`+[NSObject alloc], address = 0x000000010de6c179

简写形式:

(lldb) breakpoint set -n "[RACStream zipWith:]"
Breakpoint 33: where = Demo`-[RACStream zipWith:] + 47 at RACStream.m:46, address = 0x000000010d73088f
(lldb) br s -n "[RACStream zipWith:]" 
Breakpoint 34: where = Demo`-[RACStream zipWith:] + 47 at RACStream.m:46, address = 0x000000010d73088f

 

4、查看有多少断点可以使用

(lldb) breakpoint list
Current breakpoints:
1: file = '/Users/cykj/Desktop/Demo/Demo/ImageSource/HookTool.m', line = 172, exact_match = 0, locations = 0 (pending)


2: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m', line = 205, exact_match = 0, locations = 4, resolved = 4, hit count = 0

  2.1: where = Demo`-[SDWebImageDownloaderOperation start] + 218 at SDWebImageDownloaderOperation.m:205, address = 0x000000010d75771a, resolved, hit count = 0 
  2.2: where = Demo`-[SDWebImageDownloaderOperation start] + 761 at SDWebImageDownloaderOperation.m:205, address = 0x000000010d757939, resolved, hit count = 0 
  2.3: where = Demo`-[SDWebImageDownloaderOperation start] + 1797 at SDWebImageDownloaderOperation.m:205, address = 0x000000010d757d45, resolved, hit count = 0 
  2.4: where = Demo`-[SDWebImageDownloaderOperation start] + 3999 at SDWebImageDownloaderOperation.m:205, address = 0x000000010d7585df, resolved, hit count = 0 

3: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m', line = 400, exact_match = 0, locations = 1, resolved = 1, hit count = 0

  3.1: where = Demo`-[SDWebImageDownloaderOperation URLSession:task:didCompleteWithError:] + 660 at SDWebImageDownloaderOperation.m:400, address = 0x000000010d75ad04, resolved, hit count = 0 

4: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m', line = 444, exact_match = 0, locations = 2, resolved = 2, hit count = 0

  4.1: where = Demo`-[SDWebImageDownloaderOperation URLSession:task:didCompleteWithError:] + 1345 at SDWebImageDownloaderOperation.m:445, address = 0x000000010d75afb1, resolved, hit count = 0 
  4.2: where = Demo`-[SDWebImageDownloaderOperation URLSession:task:didCompleteWithError:] + 1986 at SDWebImageDownloaderOperation.m:445, address = 0x000000010d75b232, resolved, hit count = 0 

5: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageManager.m', line = 176, exact_match = 0, locations = 1, resolved = 1, hit count = 0

  5.1: where = Demo`__65-[SDWebImageManager loadImageWithURL:options:progress:completed:]_block_invoke + 615 at SDWebImageManager.m:176, address = 0x000000010d761d67, resolved, hit count = 0 

6: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageManager.m', line = 342, exact_match = 0, locations = 1, resolved = 1, hit count = 0

  6.1: where = Demo`-[SDWebImageManager callCompletionBlockForOperation:completion:image:data:error:cacheType:finished:url:] + 283 at SDWebImageManager.m:344, address = 0x000000010d76447b, resolved, hit count = 0 

7: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageManager.m', line = 201, exact_match = 0, locations = 1, resolved = 1, hit count = 0

  7.1: where = Demo`__65-[SDWebImageManager loadImageWithURL:options:progress:completed:]_block_invoke_2 + 168 at SDWebImageManager.m:201, address = 0x000000010d762548, resolved, hit count = 0 

8: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageManager.m', line = 243, exact_match = 0, locations = 1, resolved = 1, hit count = 0

  8.1: where = Demo`__65-[SDWebImageManager loadImageWithURL:options:progress:completed:]_block_invoke_2 + 1855 at SDWebImageManager.m:244, address = 0x000000010d762bdf, resolved, hit count = 0 

9: file = '/Users/cykj/Desktop/Demo/Demo/ViewController.m', line = 123, exact_match = 0, locations = 1, resolved = 1, hit count = 1

  9.1: where = Demo`-[ViewController viewDidLoad] + 23 at ViewController.m:123, address = 0x000000010d6cbda7, resolved, hit count = 1 

10: name = 'cfunc', locations = 0 (pending)

11: name = 'cfunc', locations = 0 (pending)

12: name = 'main', locations = 1, resolved = 1, hit count = 0
  12.1: where = JavaScriptCore`WTF::RunLoop::main(), address = 0x000000011e18b060, resolved, hit count = 0 
...

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

(lldb) breakpoint command add 2.1
Enter your debugger command(s).  Type 'DONE' to end.
> bt
> DONE

除了 add,还要 delete 等命令,使用 help 命令查找这些命令。

(lldb) help break command
     Commands for adding, removing and listing LLDB commands executed when a
     breakpoint is hit.

Syntax: command <sub-command> [<sub-command-options>] <breakpoint-id>

The following subcommands are supported:

      add    -- Add LLDB commands to a breakpoint, to be executed whenever the
                breakpoint is hit.  If no breakpoint is specified, adds the
                commands to the last created breakpoint.
      delete -- Delete the set of commands from a breakpoint.
      list   -- List the script or set of commands to be executed when the
                breakpoint is hit.

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

要查看更详细的命令用途,使用 help <command> <subcommand>。比如查看 add 命令用法

help break command add
     Add LLDB commands to a breakpoint, to be executed whenever the breakpoint
     is hit.  If no breakpoint is specified, adds the commands to the last
     created breakpoint.

Syntax: breakpoint command add <cmd-options> [<breakpt-id>]

Command Options Usage:
  breakpoint command add [-D] [-o <one-line-command>] [-e <boolean>] [-s <none>] [<breakpt-id>]
  breakpoint command add [-D] [-e <boolean>] [-s <none>] [-F <python-function>] [<breakpt-id>]

       -D ( --dummy-breakpoints )
            Sets Dummy breakpoints - i.e. breakpoints set before a file is
            provided, which prime new targets.

       -F <python-function> ( --python-function <python-function> )
            Give the name of a Python function to run as command for this
            breakpoint. Be sure to give a module name if appropriate.

       -e <boolean> ( --stop-on-error <boolean> )
            Specify whether breakpoint command execution should terminate on
            error.

       -o <one-line-command> ( --one-liner <one-line-command> )
            Specify a one-line breakpoint command inline. Be sure to surround
            it with quotes.

       -s <none> ( --script-type <none> )
            Specify the language for the commands - if none is specified, the
            lldb command interpreter will be used.
            Values: command | python | default-script

General information about entering breakpoint commands
------------------------------------------------------

This command will prompt for commands to be executed when the specified
breakpoint is hit.  Each command is typed on its own line following the '> '
prompt until 'DONE' is entered.

Syntactic errors may not be detected when initially entered, and many malformed
commands can silently fail when executed.  If your breakpoint commands do not
appear to be executing, double-check the command syntax.

Note: You may enter any debugger command exactly as you would at the debugger
prompt.  There is no limit to the number of commands supplied, but do NOT enter
more than one command per line.

Special information about PYTHON breakpoint commands
----------------------------------------------------

You may enter either one or more lines of Python, including function
definitions or calls to functions that will have been imported by the time the
code executes.  Single line breakpoint commands will be interpreted 'as is'
when the breakpoint is hit.  Multiple lines of Python will be wrapped in a
generated function, and a call to the function will be attached to the
breakpoint.

This auto-generated function is passed in three arguments:

    frame:  an lldb.SBFrame object for the frame which hit breakpoint.

    bp_loc: an lldb.SBBreakpointLocation object that represents the breakpoint
    location that was hit.

    dict:   the python session dictionary hit.

When specifying a python function with the --python-function option, you need
to supply the function name prepended by the module name:

    --python-function myutils.breakpoint_callback

The function itself must have the following prototype:

def breakpoint_callback(frame, bp_loc, dict):
  # Your code goes here

The arguments are the same as the arguments passed to generated functions as
described above.  Note that the global variable 'lldb.frame' will NOT be
updated when this function is called, so be sure to use the 'frame' argument.
The 'frame' argument can get you to the thread via frame.GetThread(), the
thread can get you to the process via thread.GetProcess(), and the process can
get you back to the target via process.GetTarget().

Important Note: As Python code gets collected into functions, access to global
variables requires explicit scoping using the 'global' keyword.  Be sure to use
correct Python syntax, including indentation, when entering Python breakpoint
commands.

Example Python one-line breakpoint command:

(lldb) breakpoint command add -s python 1
Enter your Python command(s). Type 'DONE' to end.
> print "Hit this breakpoint!"
> DONE

As a convenience, this also works for a short Python one-liner:

(lldb) breakpoint command add -s python 1 -o 'import time; print time.asctime()'
(lldb) run
Launching '.../a.out'  (x86_64)
(lldb) Fri Sep 10 12:17:45 2010
Process 21778 Stopped
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop
reason = breakpoint 1.1, queue = com.apple.main-thread
  36
  37   	int c(int val)
  38   	{
  39 ->	    return val + 3;
  40   	}
  41
  42   	int main (int argc, char const *argv[])

Example multiple line Python breakpoint command:

(lldb) breakpoint command add -s p 1
Enter your Python command(s). Type 'DONE' to end.
> global bp_count
> bp_count = bp_count + 1
> print "Hit this breakpoint " + repr(bp_count) + " times!"
> DONE

Example multiple line Python breakpoint command, using function definition:

(lldb) breakpoint command add -s python 1
Enter your Python command(s). Type 'DONE' to end.
> def breakpoint_output (bp_no):
>     out_string = "Hit breakpoint number " + repr (bp_no)
>     print out_string
>     return True
> breakpoint_output (1)
> DONE

In this case, since there is a reference to a global variable, 'bp_count', you
will also need to make sure 'bp_count' exists and is initialized:

(lldb) script
>>> bp_count = 0
>>> quit()

Your Python code, however organized, can optionally return a value.  If the
returned value is False, that tells LLDB not to stop at the breakpoint to which
the code is associated. Returning anything other than False, or even returning
None, or even omitting a return statement entirely, will cause LLDB to stop.

Final Note: A warning that no breakpoint command was generated when there are
no syntax errors may indicate that a function was declared but never called.
     
     This command takes options and free-form arguments.  If your arguments
     resemble option specifiers (i.e., they start with a - or --), you must use
     ' -- ' between the end of the command options and the beginning of the
     arguments.

这里面的命令大部分是 Python 脚本。

 

5、删除断点

breakpoint delete [-Df] [<breakpt-id | breakpt-id-list>]

用 breakpoint list 查进程中所有的断点。

(lldb) breakpoint list
Current breakpoints:
1: file = '/Users/cykj/Desktop/Demo/Demo/ImageSource/HookTool.m', line = 172, exact_match = 0, locations = 0 (pending)


2: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m', line = 205, exact_match = 0, locations = 4, resolved = 4, hit count = 0

  2.1: where = SDWebImage`-[SDWebImageDownloaderOperation start] + 218 at SDWebImageDownloaderOperation.m:205, address = 0x000000010293d44a, resolved, hit count = 0 
  2.2: where = SDWebImage`-[SDWebImageDownloaderOperation start] + 761 at SDWebImageDownloaderOperation.m:205, address = 0x000000010293d669, resolved, hit count = 0 
  2.3: where = SDWebImage`-[SDWebImageDownloaderOperation start] + 1797 at SDWebImageDownloaderOperation.m:205, address = 0x000000010293da75, resolved, hit count = 0 
  2.4: where = SDWebImage`-[SDWebImageDownloaderOperation start] + 3999 at SDWebImageDownloaderOperation.m:205, address = 0x000000010293e30f, resolved, hit count = 0 

3: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m', line = 400, exact_match = 0, locations = 1, resolved = 1, hit count = 0

  3.1: where = SDWebImage`-[SDWebImageDownloaderOperation URLSession:task:didCompleteWithError:] + 660 at SDWebImageDownloaderOperation.m:400, address = 0x0000000102940a34, resolved, hit count = 0 

4: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m', line = 444, exact_match = 0, locations = 2, resolved = 2, hit count = 0

  4.1: where = SDWebImage`-[SDWebImageDownloaderOperation URLSession:task:didCompleteWithError:] + 1345 at SDWebImageDownloaderOperation.m:445, address = 0x0000000102940ce1, resolved, hit count = 0 
  4.2: where = SDWebImage`-[SDWebImageDownloaderOperation URLSession:task:didCompleteWithError:] + 1986 at SDWebImageDownloaderOperation.m:445, address = 0x0000000102940f62, resolved, hit count = 0 

5: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageManager.m', line = 176, exact_match = 0, locations = 1, resolved = 1, hit count = 0

  5.1: where = SDWebImage`__65-[SDWebImageManager loadImageWithURL:options:progress:completed:]_block_invoke + 615 at SDWebImageManager.m:176, address = 0x0000000102947a97, resolved, hit count = 0 

6: file = '/Users/cykj/Desktop/Demo/Pods/SDWebImage/SDWebImage/SDWebImageManager.m', line = 342, exact_match = 0, locations = 1, resolved = 1, hit count = 0

  6.1: where = SDWebImage`-[SDWebImageManager callCompletionBlockForOperation:completion:image:data:error:cacheType:finished:url:] + 283 at SDWebImageManager.m:344, address = 0x000000010294a1ab, resolved, hit count = 0 

...

11: name = 'alloc', locations = 113, resolved = 113, hit count = 0 11.1: where = Foundation`+[NSHashTable alloc], address = 0x00000001029ef758, resolved, hit count = 0 11.2: where = Foundation`+[NSMapTable alloc], address = 0x0000000102a2a8cc, resolved, hit count = 0 11.3: where = Foundation`+[NSProxy alloc], address = 0x0000000102a579d6, resolved, hit count = 0 

...

若要删除 11.1 断点(无法删除?):

(lldb) breakpoint delete 11.1
0 breakpoints deleted; 1 breakpoint locations disabled.

删除 11 下面所有的断点,这样 11.1 和 11.2 都会删除。

(lldb) breakpoint delete 11
1 breakpoints deleted; 0 breakpoint locations disabled.

删除所有的断点:

(lldb) breakpoint delete
About to delete all breakpoints, do you want to do that?: [Y/n] y
All breakpoints removed. (10 breakpoints)

 

二、watchpoint

1、观察变量值的具体变化。

@interface ViewController ()
{
    NSInteger _num;  // 观察的对象
}

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

也可以在这里添加:

1

当执行到修改 _num 值的代码时,会输出:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    _num = 10;
}

Watchpoint 1 hit:
old value: 0
new value: 10

我们可以设置在 _num 的值变化为某个特定值之后触发:

- (void)viewDidLoad
{
    // xcode 左侧设置断点 p1
    [super viewDidLoad];
    
    _num = 10;
    
    _num = 20;
    
    // xcode 左侧设置断点 p2
    
    _num = 200;

    _num = 100;
}

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

Watchpoint 1 hit:
old value: 0
new value: 10

Watchpoint 1 hit:
old value: 10
new value: 20
(lldb) watchpoint modify -c '(_num==100)'

Watchpoint 1 hit:
old value: 20
new value: 100

2

断点 p1 时在 lldb 执行 watchpoint set variable _num,继续向下执行,此时没有条件限制,每次设置 _num 都会触发观察;到达断点 p2lldb 执行 watchpoint modify -c '(_num==100)',向下执行,此时有了条件 _num == 100 才会触发,所以跳过了 _num = 200 的控制输出。

 

2、查看具体断点的参数

(lldb) watchpoint list
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 1: addr = 0x7f87c103d428 size = 8 state = enabled type = w
    watchpoint spec = '_num'
    old value: 20
    new value: 100
    condition = '(_num==100)'

可以看到我们观察的变量的地址,声明变量的代码在第几行,以及具体的变量名是 _num,当前的值是 100,触发的条件是 '(_num==100)'。

然后我们执行如下命令,就可以看到断点到 _num 的值变为 100 的地方。

(lldb) c
Process 95917 resuming

Watchpoint 1 hit:
old value: 0
new value: 100

可以看到这个地方 _num 的值已经发生改变。我们可以再使用 watchpoint list 命令看看具体值的变化

(lldb) watchpoint list
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 1: addr = 0x7f9d4884b628 size = 8 state = enabled type = w
    watchpoint spec = '_num'
    old value: 0
    new value: 100
    condition = '(_num = 100)'

注意这里用的 _num = 100,不是上面的 _num==100,两个条件不同。

watchpoint list 命令包括了三个可选参数,我们可以使用 help 命令查看具体的值。

(lldb) help watchpoint list
     List all watchpoints at configurable levels of detail.

Syntax: watchpoint list <cmd-options> [<watchpt-id | watchpt-id-list>]

Command Options Usage:
  watchpoint list [-b] [<watchpt-id | watchpt-id-list>]
  watchpoint list [-f] [<watchpt-id | watchpt-id-list>]
  watchpoint list [-v] [<watchpt-id | watchpt-id-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).
     
     This command takes options and free-form arguments.  If your arguments
     resemble option specifiers (i.e., they start with a - or --), you must use
     ' -- ' between the end of the command options and the beginning of the
     arguments.

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

 

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

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1
  * frame #0: 0x0000000106cc43fd Demo`-[ViewController viewDidLoad](self=0x00007f9d4884b200, _cmd="viewDidLoad") at ViewController.m:0
    frame #1: 0x00000001153d24e1 UIKitCore`-[UIViewController loadViewIfRequired] + 1186
    frame #2: 0x0000000115332104 UIKitCore`-[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68
    frame #3: 0x00000001153323f8 UIKitCore`-[UINavigationController _startTransition:fromViewController:toViewController:] + 147
    frame #4: 0x000000011533348b UIKitCore`-[UINavigationController _startDeferredTransitionIfNeeded:] + 896
    frame #5: 0x00000001153347e0 UIKitCore`-[UINavigationController __viewWillLayoutSubviews] + 150
    frame #6: 0x0000000115314600 UIKitCore`-[UILayoutContainerView layoutSubviews] + 217
    frame #7: 0x0000000115edb795 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1441
    frame #8: 0x000000010ecc7b19 QuartzCore`-[CALayer layoutSublayers] + 175
    frame #9: 0x000000010eccc9d3 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 395
    frame #10: 0x000000010ec457ca QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 342
    frame #11: 0x000000010ec7c97e QuartzCore`CA::Transaction::commit() + 576
    frame #12: 0x0000000115a0c2d0 UIKitCore`__34-[UIApplication _firstCommitBlock]_block_invoke_2 + 139
    frame #13: 0x000000010813f62c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame #14: 0x000000010813ede0 CoreFoundation`__CFRunLoopDoBlocks + 336
    frame #15: 0x0000000108139654 CoreFoundation`__CFRunLoopRun + 1284
    frame #16: 0x0000000108138e11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #17: 0x000000010eb4a1dd GraphicsServices`GSEventRunModal + 62
    frame #18: 0x00000001159f181d UIKitCore`UIApplicationMain + 140
    frame #19: 0x0000000106cc4c70 Demo`main(argc=1, argv=0x00007ffee8f3c068) at main.m:17
    frame #20: 0x000000010a7a3575 libdyld.dylib`start + 1
    frame #21: 0x000000010a7a3575 libdyld.dylib`start + 1

 

4、使用 frame 命令查看变量 _num 的具体值

(lldb) frame variable _num
(NSInteger) _num = 100

 

三、process

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

(lldb) help process
     Commands for interacting with processes on the current platform.

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

The following subcommands are supported:

      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
                   process.  Defaults to showing current policy.
      interrupt -- Interrupt the current target process.
      kill      -- Terminate the current target process.
      launch    -- Launch the executable in the debugger.
      load      -- Load a shared library into the current process.
      plugin    -- Send a custom command to the current target process plug-in.
      save-core -- Save the current process as a core file using an appropriate
                   file type.
      signal    -- Send a UNIX signal to the current target process.
      status    -- Show status and stop location for the current target process.
      unload    -- Unload a shared library from the current process using the
                   index returned by a previous call to "process load".

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

查看更详细的命令使用 help <command> <subcommand>。比如

(lldb) help process attach
     Attach to a process.

Syntax: process attach <cmd-options>

Command Options Usage:
  process attach [-c] [-P <plugin>] [-p <pid>]
  process attach [-ciw] [-P <plugin>] [-n <process-name>]

       -P <plugin> ( --plugin <plugin> )
            Name of the process plugin you want to use.

       -c ( --continue )
            Immediately continue the process once attached.

       -i ( --include-existing )
            Include existing processes when doing attach -w.

       -n <process-name> ( --name <process-name> )
            The name of the process to attach to.

       -p <pid> ( --pid <pid> )
            The process ID of an existing process to attach to.

       -w ( --waitfor )
            Wait for the process with <process-name> to launch.

 

四、thread

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

3

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

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

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

The following subcommands are supported:

      backtrace      -- Show thread call stacks.  Defaults to the current
                        thread, thread indexes can be specified as
                        arguments.
                        Use the thread-index "all" to see all threads.
                        Use the thread-index "unique" to see threads grouped by
                        unique call stacks.
      continue       -- Continue execution of the current target process.  One
                        or more threads may be specified, by default all
                        threads continue.
      info           -- Show an extended summary of one or more threads. 
                        Defaults to the current thread.
      jump           -- Sets the program counter to a new address.
      list           -- Show a summary of each thread in the current target
                        process.
      plan           -- Commands for managing thread plans that control
                        execution.
      return         -- Prematurely return from a stack frame, short-circuiting
                        execution of newer frames and optionally yielding a
                        specified value.  Defaults to the exiting the current
                        stack frame.  Expects 'raw' input (see 'help
                        raw-input'.)
      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.  The
                        target line number(s) are given as arguments, and if
                        more than one is provided, stepping will stop when the
                        first one is hit.

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

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

 

EXAMINING THREAD STATE

这个使用的也主要还是 thread 命令,主要是使用以下几个命令。

1、检查当前进程的状态

(lldb) thread list
Process 97464 stopped
* thread #1: tid = 0x788f30, 0x000000010016a3c8 Demo`-[ViewController viewDidLoad](self=0x00007fde09024c00, _cmd="viewDidLoad") at ViewController.m:125, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  thread #2: tid = 0x788f6c, 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #3: tid = 0x788f6d, 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #4: tid = 0x788f6e, 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #5: tid = 0x788f6f, 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #6: tid = 0x788f76, 0x000000010401d20a libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread'
  thread #7: tid = 0x788f79, 0x000000010405cbdc libsystem_pthread.dylib`start_wqthread

*表明的就是当前的线程

 

2、当前线程的堆栈(回溯、追踪)

(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x000000010016a3c8 Demo`-[ViewController viewDidLoad](self=0x00007fde09024c00, _cmd="viewDidLoad") at ViewController.m:125
    frame #1: 0x000000010e8764e1 UIKitCore`-[UIViewController loadViewIfRequired] + 1186
    frame #2: 0x000000010e7d6104 UIKitCore`-[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68
    frame #3: 0x000000010e7d63f8 UIKitCore`-[UINavigationController _startTransition:fromViewController:toViewController:] + 147
    frame #4: 0x000000010e7d748b UIKitCore`-[UINavigationController _startDeferredTransitionIfNeeded:] + 896
    frame #5: 0x000000010e7d87e0 UIKitCore`-[UINavigationController __viewWillLayoutSubviews] + 150
    frame #6: 0x000000010e7b8600 UIKitCore`-[UILayoutContainerView layoutSubviews] + 217
    frame #7: 0x000000010f37f795 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1441
    frame #8: 0x000000010820bb19 QuartzCore`-[CALayer layoutSublayers] + 175
    frame #9: 0x00000001082109d3 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 395
    frame #10: 0x00000001081897ca QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 342
    frame #11: 0x00000001081c097e QuartzCore`CA::Transaction::commit() + 576
    frame #12: 0x000000010eeb02d0 UIKitCore`__34-[UIApplication _firstCommitBlock]_block_invoke_2 + 139
    frame #13: 0x00000001015e562c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame #14: 0x00000001015e4de0 CoreFoundation`__CFRunLoopDoBlocks + 336
    frame #15: 0x00000001015df654 CoreFoundation`__CFRunLoopRun + 1284
    frame #16: 0x00000001015dee11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #17: 0x000000010808e1dd GraphicsServices`GSEventRunModal + 62
    frame #18: 0x000000010ee9581d UIKitCore`UIApplicationMain + 140
    frame #19: 0x000000010016ac70 Demo`main(argc=1, argv=0x00007ffeefa96068) at main.m:17
    frame #20: 0x0000000103cec575 libdyld.dylib`start + 1
    frame #21: 0x0000000103cec575 libdyld.dylib`start + 1

 

3、查看所有线程的 backtrace

(lldb) thread backtrace all
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x000000010016a3c8 Demo`-[ViewController viewDidLoad](self=0x00007fde09024c00, _cmd="viewDidLoad") at ViewController.m:125
    frame #1: 0x000000010e8764e1 UIKitCore`-[UIViewController loadViewIfRequired] + 1186
    frame #2: 0x000000010e7d6104 UIKitCore`-[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68
    frame #3: 0x000000010e7d63f8 UIKitCore`-[UINavigationController _startTransition:fromViewController:toViewController:] + 147
    frame #4: 0x000000010e7d748b UIKitCore`-[UINavigationController _startDeferredTransitionIfNeeded:] + 896
    frame #5: 0x000000010e7d87e0 UIKitCore`-[UINavigationController __viewWillLayoutSubviews] + 150
    frame #6: 0x000000010e7b8600 UIKitCore`-[UILayoutContainerView layoutSubviews] + 217
    frame #7: 0x000000010f37f795 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1441
    frame #8: 0x000000010820bb19 QuartzCore`-[CALayer layoutSublayers] + 175
    frame #9: 0x00000001082109d3 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 395
    frame #10: 0x00000001081897ca QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 342
    frame #11: 0x00000001081c097e QuartzCore`CA::Transaction::commit() + 576
    frame #12: 0x000000010eeb02d0 UIKitCore`__34-[UIApplication _firstCommitBlock]_block_invoke_2 + 139
    frame #13: 0x00000001015e562c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame #14: 0x00000001015e4de0 CoreFoundation`__CFRunLoopDoBlocks + 336
    frame #15: 0x00000001015df654 CoreFoundation`__CFRunLoopRun + 1284
    frame #16: 0x00000001015dee11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #17: 0x000000010808e1dd GraphicsServices`GSEventRunModal + 62
    frame #18: 0x000000010ee9581d UIKitCore`UIApplicationMain + 140
    frame #19: 0x000000010016ac70 Demo`main(argc=1, argv=0x00007ffeefa96068) at main.m:17
    frame #20: 0x0000000103cec575 libdyld.dylib`start + 1
    frame #21: 0x0000000103cec575 libdyld.dylib`start + 1
  thread #2
    frame #0: 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010405d009 libsystem_pthread.dylib`_pthread_wqthread + 1035
    frame #2: 0x000000010405cbe9 libsystem_pthread.dylib`start_wqthread + 13
  thread #3
    frame #0: 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010405d009 libsystem_pthread.dylib`_pthread_wqthread + 1035
    frame #2: 0x000000010405cbe9 libsystem_pthread.dylib`start_wqthread + 13
  thread #4
    frame #0: 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010405d009 libsystem_pthread.dylib`_pthread_wqthread + 1035
    frame #2: 0x000000010405cbe9 libsystem_pthread.dylib`start_wqthread + 13
  thread #5
    frame #0: 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010405d009 libsystem_pthread.dylib`_pthread_wqthread + 1035
    frame #2: 0x000000010405cbe9 libsystem_pthread.dylib`start_wqthread + 13
  thread #6, name = 'com.apple.uikit.eventfetch-thread'
    frame #0: 0x000000010401d20a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x000000010401c724 libsystem_kernel.dylib`mach_msg + 60
    frame #2: 0x00000001015e51b4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x00000001015df7e9 CoreFoundation`__CFRunLoopRun + 1689
    frame #4: 0x00000001015dee11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #5: 0x00000001006a2322 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 277
    frame #6: 0x00000001006a24f4 Foundation`-[NSRunLoop(NSRunLoop) runUntilDate:] + 79
    frame #7: 0x000000010ef8cbcb UIKitCore`-[UIEventFetcher threadMain] + 118
    frame #8: 0x00000001006b7732 Foundation`__NSThread__start__ + 1221
    frame #9: 0x000000010405d661 libsystem_pthread.dylib`_pthread_body + 340
    frame #10: 0x000000010405d50d libsystem_pthread.dylib`_pthread_start + 377
    frame #11: 0x000000010405cbf9 libsystem_pthread.dylib`thread_start + 13
  thread #7
    frame #0: 0x000000010405cbdc libsystem_pthread.dylib`start_wqthread

 

4、单独查看某个线程

(lldb) thread select 3
(lldb) thread backtrace
* thread #3
  * frame #0: 0x000000010402728a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010405d009 libsystem_pthread.dylib`_pthread_wqthread + 1035
    frame #2: 0x000000010405cbe9 libsystem_pthread.dylib`start_wqthread + 13

 

五、Frame

EXAMINING STACK FRAME STATE

1、观测架构参数和本地变量

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

(lldb) thread select 1
(lldb) frame variable
(ViewController *) self = 0x00007fde09024c00
(SEL) _cmd = "viewDidLoad"
(CFBinaryHeapCallBacks) callBacks = {
  version = 0
  retain = 0x0000000000000000
  release = 0x4084d80000000000 (0x4084d80000000000)
  copyDescription = 0x0000000000000000
  compare = 0x4090480000000000 (0x4090480000000000)
}
(__NSTaggedDate *) p1 = 0x8000000000000000
(NSTaggedPointerString *) p2 = 0xc145315880000000 @"pgrI0tf031"
(Person *) p3 = nil
(Person *) p4 = nil
(NSInteger) count = 0
(const void **) list = 0x0000000000000000
(CFArrayRef) objects = 0x8000000000000000
(NSArray *) arr = 0x0000000000000001

注意:如果之前执行了 thread select x,那么是在 x 线程执行 frame 命令。

 

2、打印某个变量及它的子元素

(lldb) frame variable
(ViewController *) self = 0x00007fde09024c00
(SEL) _cmd = "viewDidLoad"
(CFBinaryHeapCallBacks) callBacks = {
  version = 0
  retain = 0x0000000000000000
  release = 0x4084d80000000000 (0x4084d80000000000)
  copyDescription = 0x0000000000000000
  compare = 0x4090480000000000 (0x4090480000000000)
}
(__NSTaggedDate *) p1 = 0x8000000000000000
(NSTaggedPointerString *) p2 = 0xc145315880000000 @"pgrI0tf031"
(Person *) p3 = nil
(Person *) p4 = nil
(NSInteger) count = 0
(const void **) list = 0x0000000000000000
(CFArrayRef) objects = 0x8000000000000000
(NSArray *) arr = 0x0000000000000001
(lldb) frame variable self
(ViewController *) self = 0x00007fde09024c00
(lldb) frame variable self->isa
(Class) self->isa = ViewController

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

(lldb) frame variable *self
(ViewController) *self = {
  UIViewController = {
    UIResponder = {
      NSObject = {
        isa = ViewController
      }
    }
    _overrideTransitioningDelegate = nil
    _view = 0x00007fde0740c230
    _tabBarItem = 0x00007fde0750a530
    _navigationItem = 0x00007fde0770f8e0
    _toolbarItems = nil
    _title = nil
    _nibName = 0x000060000101aee0 @"BYZ-38-t0r-view-8bC-Xf-vdC"
    _nibBundle = 0x0000600003d40b90 @"/Users/cykj/Library/Developer/CoreSimulator/Devices/5EA7E32E-0543-406C-A9D1-1917DEB0F3A3/data/Containers/Bundle/Application/0FF04E7A-851D-4E4D-970F-F6D775E759FF/Demo.app"
    _parentViewController = 0x00007fde09043000
    _childModalViewController = nil
    _parentModalViewController = nil
    _previousRootViewController = nil
    _modalTransitionView = nil
    _modalPreservedFirstResponder = nil
    _dimmingView = nil
    _dropShadowView = nil
    _currentAction = nil
    _storyboard = 0x0000600000b01980
    _externalObjectsTableForViewLoading = 0x0000600001c54080
    _topLevelObjectsToKeepAliveFromStoryboard = nil
    _savedHeaderSuperview = nil
    _savedFooterSuperview = nil
    _editButtonItem = nil
    _searchDisplayController = nil
    _strongSearchDisplayController = nil
    _modalTransitionStyle = 0
    _modalPresentationStyle = 0
    _lastKnownInterfaceOrientation = 0
    _popoverController = nil
    _containerViewInSheet = nil
    _recordedContentScrollView = nil
    _afterAppearance = nil
    _explicitAppearanceTransitionLevel = 0
    _interfaceBuilderKeyCommands = nil
    _addedKeyCommands = nil
    _overrideTraitCollectionsForChildren = nil
    _previewSourceViews = nil
    _retainCount = 10
    _ignoreAppSupportedOrientations = false
    _viewHostsLayoutEngine = false
    _storyboardIdentifier = 0x0000600001e15540 @"ViewController"
    _transitioningDelegate = nil
    _frozenTraitCollection = nil
    _overrideTraitCollection = nil
    _accessibilityHUD = nil
    overrideUseCustomPresentation = false
    _modalPresentationCapturesStatusBarAppearance = false
    _ignoresParentMargins = false
    _childViewControllers = nil
    _customNavigationInteractiveTransitionDuration = 0
    _customNavigationInteractiveTransitionPercentComplete = 0
    _customTransitioningView = nil
    _lastNotifiedTraitCollection = nil
    _presentationController = nil
    _navigationControllerContentOffsetAdjustment = 0
    _leftContentMargin = 0
    _rightContentMargin = 0
    _contentMargin = 16
    _topLayoutGuide = 0x00007fde07408bb0
    _bottomLayoutGuide = 0x00007fde07404080
    _topBarInsetGuideConstraint = 0x0000600003d76800
    _bottomBarInsetGuideConstraint = 0x0000600003d75130
    _storyboardSegueTemplates = nil
    _segueResponsibleForModalPresentation = nil
    _sourceViewControllerIfPresentedViaPopoverSegue = nil
    _modalSourceViewController = nil
    _expectedWindow = nil
    _presentedStatusBarViewController = nil
    _presentedUserInterfaceStyleViewController = nil
    _edgesForExtendedLayout = 15
    __childControllerToIgnoreWhileLookingForTransitionCoordinator = nil
    _presentingFocusedItem = nil
    _navigationInsetAdjustment = nil
    _storyboardPreviewSegueTemplates = nil
    _storyboardCommitSegueTemplates = nil
    _storyboardPreviewingRegistrants = nil
    __embeddedView = nil
    __embeddingView = nil
    __embeddedDelegate = nil
    _originalPresentationController = nil
    _temporaryPresentationController = nil
    _preferredFocusedItem = nil
  }
  _heap = 0x0000000000000000
  _dict = nil
  _rwlock = (__sig = 0, __opaque = "")
  _num = 0
  _needRegister = NO
  _data = nil
  _thread = nil
}

 

3、选择另外的一个 frame

(lldb) frame select 9
frame #9: 0x00000001082109d3 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 395
QuartzCore`CA::Layer::layout_if_needed:
    0x1082109d3 <+395>: movq   0x8(%rbx), %rbx
    0x1082109d7 <+399>: testq  %rbx, %rbx
    0x1082109da <+402>: jne    0x1082109b0               ; <+360>
    0x1082109dc <+404>: testq  %r14, %r14

 

六、expression

看更复杂的数据

(lldb) frame select 0
frame #0: 0x000000010016a3c8 Demo`-[ViewController viewDidLoad](self=0x00007fde09024c00, _cmd="viewDidLoad") at ViewController.m:125
   122 	
   123 	- (void)viewDidLoad
   124 	{
-> 125 	    [super viewDidLoad];
   126 	    
   127 	    _num = 10;
   128 	    
(lldb) expression self
(ViewController *) $0 = 0x00007fde09024c00

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

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

继续以之前的命令来操作:

(lldb) expr self = $0
(ViewController *) $2 = 0x00007fde09024c00

 

七、call

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

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

原本没有设置颜色的视图,会被设置成颜色。

5 4

 

八、image

这是一个比较重要也比较实用的命令。命令可用于寻址。比较实用的用法是用于寻找栈地址对应的代码位置

NSArray * arr = [[NSArray alloc] initWithObjects:@"1", @"2", nil];

NSLog(@"%@", arr[2]);

可以很明显的看到数组越界了。运行程序,程序崩溃报如下错误:

2019-04-03 14:10:13.975574+0800 Demo[97853:7915627] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndexedSubscript:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
	0   CoreFoundation                      0x000000010e1b31bb __exceptionPreprocess + 331
	1   libobjc.A.dylib                     0x000000010d751735 objc_exception_throw + 48
	2   CoreFoundation                      0x000000010e0ff4ec _CFThrowFormattedException + 194
	3   CoreFoundation                      0x000000010e235b00 +[__NSArrayI allocWithZone:] + 0
	4   Demo                                0x000000010cc9d4c5 -[ViewController viewDidLoad] + 181
	5   UIKitCore                           0x000000011b3aa4e1 -[UIViewController loadViewIfRequired] + 1186
	6   UIKitCore                           0x000000011b30a104 -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68
	7   UIKitCore                           0x000000011b30a3f8 -[UINavigationController _startTransition:fromViewController:toViewController:] + 147
	8   UIKitCore                           0x000000011b30b48b -[UINavigationController _startDeferredTransitionIfNeeded:] + 896
	9   UIKitCore                           0x000000011b30c7e0 -[UINavigationController __viewWillLayoutSubviews] + 150
	10  UIKitCore                           0x000000011b2ec600 -[UILayoutContainerView layoutSubviews] + 217
	11  UIKitCore                           0x000000011beb3795 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1441
	12  QuartzCore                          0x0000000114de9b19 -[CALayer layoutSublayers] + 175
	13  QuartzCore                          0x0000000114dee9d3 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 395
	14  QuartzCore                          0x0000000114d677ca _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 342
	15  QuartzCore                          0x0000000114d9e97e _ZN2CA11Transaction6commitEv + 576
	16  UIKitCore                           0x000000011b9e42d0 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 139
	17  CoreFoundation                      0x000000010e11862c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
	18  CoreFoundation                      0x000000010e117de0 __CFRunLoopDoBlocks + 336
	19  CoreFoundation                      0x000000010e112654 __CFRunLoopRun + 1284
	20  CoreFoundation                      0x000000010e111e11 CFRunLoopRunSpecific + 625
	21  GraphicsServices                    0x000000011394d1dd GSEventRunModal + 62
	22  UIKitCore                           0x000000011b9c981d UIApplicationMain + 140
	23  Demo                                0x000000010cc9dc80 main + 112
	24  libdyld.dylib                       0x000000011077c575 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

我们大概可以猜测程序是崩溃在第四行 log,也就是地址为 0x000000010cc9d4c5的地方。因为工程名叫 Demo,其他的名字很明显是系统的库。虽然 log 的 23 行也有 Demo,但它是 main 函数,不在考虑范围之内。

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

(lldb) image lookup --address 0x000000010cc9d4c5
      Address: Demo[0x00000001000024c5] (Demo.__TEXT.__text + 2661)
      Summary: Demo`-[ViewController viewDidLoad] + 181 at ViewController.m:128

6

当然还有很多的命令我们可以探索,使用 image help 可以查看。

(lldb) image help
     Commands for accessing information for one or more target modules.

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

The following subcommands are supported:

      add          -- Add a new module to the current target's modules.
      dump         -- Commands for dumping information about one or more target
                      modules.
      list         -- List current executable and dependent shared library
                      images.
      load         -- Set the load addresses for one or more sections in a
                      target module.
      lookup       -- Look up information within executable and dependent
                      shared library images.
      search-paths -- Commands for managing module search paths for a target.
      show-unwind  -- Show synthesized unwind instructions for a function.

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

 

九、为命令设置别名

比如 p 是 frame variable 的别名,p view 实际上是 frame variable view。除了系统自建的 LLDB 别名,你也可以自定义别名。

掌握了规律之后,任何的命令我们都可以自己设置别名。

1、设置别名

(lldb) command alias bfl breakpoint set -f %1 -l %2
(lldb) bfl ViewController.m 128
Breakpoint 1: where = Demo`-[ViewController viewDidLoad] + 161 at ViewController.m:128, address = 0x000000010cc9d4b1

 

2、撤销别名

(lldb) command unalias bfl
(lldb) bfl ViewController.m 128
error: 'bfl' is not a valid command.
error: Unrecognized command 'bfl'.

 

十、memory

内存操作,无非就是读写操作。

1、修改内存内的值

memory write [内存地址] [数值]

 

2、读取内存的操作

memory read/[数量_格式_字节数] [内存地址]

或者

x/[数量_格式_字节数] [内存地址]

 

3、格式

  • x :代表 16 进制
  • f :代表浮点数
  • d :代表 10 进制

 

4、字节大小

  • bbyte 代表 1 个字节
  • hhalf word 代表 2 个字节
  • wword 代表 4 个字节

如:

memory read/1wx 0x7ffee14a5ba8
memory read/1wd 0x7ffee14a5ba8

寓意是:读取 0x7ffee14a5ba84 个字节的内容。

(lldb) expr NSLog(@"%p", &_num)
2019-04-03 14:39:41.334140+0800 Demo[98334:7932911] 0x7fef6484cc30
(lldb) memory write 0x7fef6484cc30 18
(lldb) p _num
(NSInteger) $0 = 24
(lldb) memory read/1wd 0x7fef6484cc30
0x7fef6484cc30: 24
(lldb) memory read/1wx 0x7fef6484cc30
0x7fef6484cc30: 0x00000018
(lldb) x/1wx 0x7fef6484cc30
0x7fef6484cc30: 0x00000018

 

十一、打印指令 p、po
p 通常用于打印基本数据类型的值。这个指令会默认生出一个临时变量,如 $1po 打印变量的内容,如果是对象,它打印的内容由 -debugDescription 决定。

(lldb) p self
(ViewController *) $0 = 0x00007fe85f858600
(lldb) po self
<ViewController: 0x7fe85f858600>

使用:

Class cls = NSClassFromString(@"ViewController");
id obj = [[cls alloc] init];
NSLog(@"%@, %@", cls, obj);

7

运行代码发现:

  • cls 没有显示具体的地址值。
  • obj 没有看到 isa 这个成员变量。

使用简单的 p 或者 po 指令都是不可以的。需要借助上面说的操作内存的指令。

(lldb) p/x cls
(Class) $2 = 0x000000010c258098 ViewController
(lldb) p/x obj->isa
(Class) $3 = 0x000000010c258098 ViewController

 

 

十二、bt

bt 返回所有的调用栈。

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x000000010282e4e2 Demo`-[ViewController viewDidLoad](self=0x00007fef6484c800, _cmd="viewDidLoad") at ViewController.m:131
    frame #1: 0x0000000110f3b4e1 UIKitCore`-[UIViewController loadViewIfRequired] + 1186
    frame #2: 0x0000000110e9b104 UIKitCore`-[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68
    frame #3: 0x0000000110e9b3f8 UIKitCore`-[UINavigationController _startTransition:fromViewController:toViewController:] + 147
    frame #4: 0x0000000110e9c48b UIKitCore`-[UINavigationController _startDeferredTransitionIfNeeded:] + 896
    frame #5: 0x0000000110e9d7e0 UIKitCore`-[UINavigationController __viewWillLayoutSubviews] + 150
    frame #6: 0x0000000110e7d600 UIKitCore`-[UILayoutContainerView layoutSubviews] + 217
    frame #7: 0x0000000111a44795 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1441
    frame #8: 0x000000010a8d0b19 QuartzCore`-[CALayer layoutSublayers] + 175
    frame #9: 0x000000010a8d59d3 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 395
    frame #10: 0x000000010a84e7ca QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 342
    frame #11: 0x000000010a88597e QuartzCore`CA::Transaction::commit() + 576
    frame #12: 0x00000001115752d0 UIKitCore`__34-[UIApplication _firstCommitBlock]_block_invoke_2 + 139
    frame #13: 0x0000000103ca962c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame #14: 0x0000000103ca8de0 CoreFoundation`__CFRunLoopDoBlocks + 336
    frame #15: 0x0000000103ca3654 CoreFoundation`__CFRunLoopRun + 1284
    frame #16: 0x0000000103ca2e11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #17: 0x000000010a7531dd GraphicsServices`GSEventRunModal + 62
    frame #18: 0x000000011155a81d UIKitCore`UIApplicationMain + 140
    frame #19: 0x000000010282eca0 Demo`main(argc=1, argv=0x00007ffeed3d2068) at main.m:17
    frame #20: 0x00000001063b1575 libdyld.dylib`start + 1
    frame #21: 0x00000001063b1575 libdyld.dylib`start + 1

You may also like...