普通视图

发现新文章,点击刷新页面。
昨天以前Casa Taloyum

使用LLDB调试程序(二)

作者 Casa Taloyum
2014年12月6日 00:00




简述


这篇文章主要讲了如何使用lldb来处理以下三种场景:

  • 死循环
  • 异常断点
  • 多线程

之所以挑选这3个场景,主要还是因为他们比较常见,有些不常见的其实用基础命令也能hold住。




死循环


死循环的场景发生得不太多,即便有,大部分也都能立刻发现并且改掉。但有时候发生的死循环比较难解,主要是因为程序定在一个地方不动,不确定死循环出没的地方。lldb调试的时候去重现死循环,然后ctrl+c,你就会停在一个地方,比如这样:


Enter a number (0 to quit): 2 is not prime
Enter a number (0 to quit): 2 is not prime
Enter a number (0 to quit): 2 is not prime
Enter a number (0 to quit): 2 is not prime
EnteProcess 2650 stopped        # 按了ctrl+c之后就停下来了。
* thread #1: tid = 0x6957c, 0x00007fff8fe81976 libsystem_kernel.dylib`__write_nocancel + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x00007fff8fe81976 libsystem_kernel.dylib`__write_nocancel + 10
libsystem_kernel.dylib`__write_nocancel + 10:
-> 0x7fff8fe81976:  jae    0x7fff8fe81980            ; __write_nocancel + 20
   0x7fff8fe81978:  movq   %rax, %rdi
   0x7fff8fe8197b:  jmp    0x7fff8fe7cca3            ; cerror_nocancel
   0x7fff8fe81980:  retq


你会落到程序暂停的地方,大部分情况是一个莫名奇妙的地方,这时候就要用finish命令啦。finish命令可能要按很多次,于是你就会跳到你熟悉的地方了:


(lldb) finish
Process 2650 stopped
* thread #1: tid = 0x6957c, 0x0000000100000ef0 a.out`main(argc=1, argv=0x00007fff5fbffa40) + 272 at a.c:23, queue = 'com.apple.main-thread', stop reason = step out
    frame #0: 0x0000000100000ef0 a.out`main(argc=1, argv=0x00007fff5fbffa40) + 272 at a.c:23
   20           if (count == 2)
   21              printf("%d is prime\n",n);
   22           else
-> 23              printf("%d is not prime\n",n);
   24       }
   25   }


到了这里你就可以结合上下文,找到死循环出没的点了




异常断点


开发的时候经常会遇到一个程序抛了异常然后没有人catch就挂了,我们使用XCode调试的时候都会采用异常断点的方法来确定在哪儿抛出的异常。在XCode里面轻松点两下鼠标就能下异常断点了,那么在命令行lldb的情况下,我们是这么做的:


    (lldb) breakpoint set -E objc       # 这里也可以是breakpoint set -E c++或者breakpoint set -E c
    Breakpoint 2: where = libobjc.A.dylib`objc_exception_throw, address = 0x000000010b444b8a

    (lldb) continue
    Process 3772 resuming
    2014-12-06 21:52:23.066 TownShipHelper[3772:232356] -[UITableView crash]: unrecognized selector sent to instance 0x7fe98c03f400


这个时候我们发现程序停住了,我们看一下调用栈:


(lldb) bt
* thread #1: tid = 0x38ba4, 0x000000010b444b8a libobjc.A.dylib`objc_exception_throw, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
  * frame #0: 0x000000010b444b8a libobjc.A.dylib`objc_exception_throw
    frame #1: 0x000000010bb5b50d CoreFoundation`-[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    frame #2: 0x000000010bab37fc CoreFoundation`___forwarding___ + 988
    frame #3: 0x000000010bab3398 CoreFoundation`__forwarding_prep_0___ + 120
    frame #4: 0x000000010af011e3 TownShipHelper`-[TSMenuViewController tableView](self=0x00007fe9896092b0, _cmd=0x000000010c76fd26) + 355 at TSMenuViewController.m:34
    frame #5: 0x000000010af0138a TownShipHelper`-[TSMenuViewController viewDidLoad](self=0x00007fe9896092b0, _cmd=0x000000010c746c6f) + 138 at TSMenuViewController.m:52


看一下0-3号栈帧都是系统runtime的,4号栈帧我们切过去看一下:


(lldb) frame select 4
frame #4: 0x000000010af011e3 TownShipHelper`-[TSMenuViewController tableView](self=0x00007fe9896092b0, _cmd=0x000000010c76fd26) + 355 at TSMenuViewController.m:34
   31           _tableView.delegate = self;
   32           _tableView.dataSource = self;
   33           [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"TableViewCell"];
-> 34           [_tableView performSelector:@selector(crash) withObject:nil];
   35       }
   36       return _tableView;
   37   }


果然,在34行这里发现_tableView这个实例调用了一个不存在的selector,导致runtime抛出异常。 关于异常断点还有一个细节要讲,我们可以使用-w <boolean>-h <boolean>参数来指定这个异常断点具体停下的位置。-w表示是否在异常被throW的时候停下,-h表示是否在异常被catcH的时候停下,具体使用的时候要跟-E language一起使用,例如:


    breakpoint set -E objc -w true -h true      # 表示异常在throw的时候和在catch的时候都停下。




多线程


调试多线程程序绝对是个揪心的问题,GDB在这方面做的也不是很好,LLDB在多线程调试方面做得是非常棒的。主要是通过thread指令做一些多线程相关的操作,具体到后面查看变量呀什么的就跟这篇文章里面讲得一样了。

一般情况下我们会在一个地方下断点:


(lldb) l TSDispatchViewControllerFactory.m:43
   43       dispatch_once(&onceToken, ^{
   44           factory = [[TSDispatchViewControllerFactory alloc] init];
   45       });
   46       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   47           NSLog(@"this is another thread");   # 断点下在这儿这儿是一个异步调用
   48       });
   49       return factory;
   50   }


跑起来之后断点就会停住:


frame #0: 0x0000000108084ee7 TownShipHelper`__49+[TSDispatchViewControllerFactory sharedInstance]_block_invoke_2(.block_descriptor=0x0000000108094140) + 23 at TSDispatchViewControllerFactory.m:47
   44           factory = [[TSDispatchViewControllerFactory alloc] init];
   45       });
   46       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-> 47           NSLog(@"this is another thread");
   48       });
   49       return factory;
   50   }


此时我们看一下当前都有哪些线程:


(lldb) thread backtrace all
  thread #1: tid = 0x4d8a7, 0x00000001085d15d4 libobjc.A.dylib`lookUpImpOrForward + 82, queue = 'com.apple.main-thread'
    frame #0: 0x00000001085d15d4 libobjc.A.dylib`lookUpImpOrForward + 82
    frame #1: 0x00000001085de0d3 libobjc.A.dylib`objc_msgSend + 211
    frame #2: 0x0000000108084ce6 TownShipHelper`-[TSDispatchViewControllerFactory viewContorllerList](self=0x00007ff352e0ed80, _cmd=0x0000000108091454) + 294 at TSDispatchViewControllerFactory.m:28

  thread #2: tid = 0x4d8bf, 0x000000010b56c22e libsystem_kernel.dylib`kevent64 + 10, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x000000010b56c22e libsystem_kernel.dylib`kevent64 + 10
    frame #1: 0x000000010b20a252 libdispatch.dylib`_dispatch_mgr_invoke + 247
    frame #2: 0x000000010b209ff7 libdispatch.dylib`_dispatch_mgr_thread + 54

* thread #3: tid = 0x4d8c0, 0x0000000108084ee7 TownShipHelper`__49+[TSDispatchViewControllerFactory sharedInstance]_block_invoke_2(.block_descriptor=0x0000000108094140) + 23 at TSDispatchViewControllerFactory.m:47, queue = 'com.apple.root.default-qos', stop reason = breakpoint 1.1
  * frame #0: 0x0000000108084ee7 TownShipHelper`__49+[TSDispatchViewControllerFactory sharedInstance]_block_invoke_2(.block_descriptor=0x0000000108094140) + 23 at TSDispatchViewControllerFactory.m:47
    frame #1: 0x000000010b1fccc6 libdispatch.dylib`_dispatch_call_block_and_release + 12
    frame #2: 0x000000010b21a7f4 libdispatch.dylib`_dispatch_client_callout + 8

  thread #4: tid = 0x4d8c1, 0x000000010b56b946 libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x000000010b56b946 libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010b59c757 libsystem_pthread.dylib`_pthread_wqthread + 869
    frame #2: 0x000000010b59a4a1 libsystem_pthread.dylib`start_wqthread + 13

  thread #5: tid = 0x4d8c2, 0x000000010b56b946 libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x000000010b56b946 libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010b59c757 libsystem_pthread.dylib`_pthread_wqthread + 869
    frame #2: 0x000000010b59a4a1 libsystem_pthread.dylib`start_wqthread + 13

  thread #6: tid = 0x4d8c3, 0x000000010b56b946 libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x000000010b56b946 libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010b59c757 libsystem_pthread.dylib`_pthread_wqthread + 869
    frame #2: 0x000000010b59a4a1 libsystem_pthread.dylib`start_wqthread + 13


前面打*的线程就是我们当前所处的线程,我们当前处在3号线程0号栈帧上。那么我们现在切换一下线程,使用thread select:


(lldb) thread select 1
(lldb) bt
* thread #1: tid = 0x4d8a7, 0x00000001085d15d4 libobjc.A.dylib`lookUpImpOrForward + 82, queue = 'com.apple.main-thread'
  * frame #0: 0x00000001085d15d4 libobjc.A.dylib`lookUpImpOrForward + 82
    frame #1: 0x00000001085de0d3 libobjc.A.dylib`objc_msgSend + 211
    frame #2: 0x0000000108084ce6 TownShipHelper`-[TSDispatchViewControllerFactory viewContorllerList](self=0x00007ff352e0ed80, _cmd=0x0000000108091454) + 294 at TSDispatchViewControllerFactory.m:28


我们可以看到,现在我们已经切换到1号线程了,就是这么简单。后面跳帧,看变量,都跟这篇文章里介绍的一样了。更复杂的指令可以在lldb命令行中输入help thread查看文档。




结尾

本来这篇文章应当是紧跟着这一篇的,但是因为一个异常断点的问题一直没解决给耽搁了,其实也是我的疏忽,在看help文档的时候没有注意看开头的命令描述,后来才发现原来有些参数是要跟别的参数搭配一起才能使用的。另外,我在查文档的时候发现lldb官方网站上只有tutorial还算是个文档,但是tutorial写得非常简单,然而在lldb中使用help能够找到的文档则非常详细,建议大家在后续的学习中,尽量多使用help指令。

关于lldb的使用方面我就先写到这里了,我们可以在评论区里讨论关于lldb更深层次的问题。


使用LLDB调试程序

作者 Casa Taloyum
2014年11月19日 00:00




简述


LLDB是XCode下默认的调试工具,苹果向来都会把界面做得很好,XCode中的lldb也不例外:无缝集成,方便简单。 嗯,casa是命令行控,也不喜欢简单玩法,所以这篇文章要讲的是用命令行LLDB来调试C程序。 LLDB和GDB有很多相似之处,如果你GDB玩得比较熟,那么相信你LLDB一会儿就能上手了。阅读这篇文章不需要有GDB的基础。 系好安全带,打起精神,我们开始了。

如果你是因为不知道怎么退出lldb才搜到这篇文章的, 直接告诉你退出命令就是quit, 你可以关网页去愉快地玩耍啦。




准备工作


1. 安装lldb



Ubuntu用户:

    sudo apt-get install lldb-3.5

    # 然后去`~/.bashrc`里面添加一句话:
    alias lldb="lldb-3.5"
    #你安装好lldb之后,要跑lldb-3.5才能调用到lldb这个程序,所以上面这句话做了一个别名,以后直接lldb就可以了。


Mac用户:

去装个xcode,然后再装个toolchain


Windows用户:

呵呵



2. 写一段C程序,记得编译成可执行文件


程序自己随便写一个就好了,来个if-else判断, 然后有一个随便你做什么的子函数,然后输出个helloworld就好。编译时记得带-g参数,这样编译器就能在编译时候提供调试时所需要的一些信息。




lldb调试之旅


进入调试状态


1. 调试可执行文件

    lldb DebugDemo.run
    # DebugDemo.run 是编译出来的可执行文件


2. 调试运行时带参数的可执行文件

如果运行这个程序时是要带参数的,那么就这样:

    lldb -- DebugDemo.run 1 2 3
    # 等价于你在终端运行 DebugDemo.run 1 2 3


3. 调试某个正在运行中的进程

    # 先启动lldb

      ~  lldb
    (lldb)

    #---------------------------------------------------------------------------

    # 然后你找一个进程的pid出来,我找的是QQ音乐
    # 你可以ps aux | grep casa (casa是我的用户名) 在这个列表里面挑一个程序的pid
    # 输入process attach --pid 你找到的pid,来把调试器挂到这个进程上去调试

    (lldb) process attach --pid 9939        # 简写命令: attach -p 9939
                                                        pro att -p 9939
    Process 9939 stopped
    Executable module set to "/Applications/QQMusic.app/Contents/MacOS/QQMusic".
    Architecture set to: x86_64h-apple-macosx.
    (lldb)

    #---------------------------------------------------------------------------

    # 你也可以告诉lldb你要挂在那个进程名下

      ~  lldb
    (lldb) process attach --name Safari     # 简写命令: attach -n Safari
                                                        pro att -n Safari
    Process 8362 stopped
    Executable module set to "/Applications/Safari.app/Contents/MacOS/Safari".
    Architecture set to: x86_64h-apple-macosx.
    (lldb)

    #---------------------------------------------------------------------------

    # 此时你就可以使用调试器命令了
    # 这个命令后面我会解释的
    (lldb) bt
    * thread #1: tid = 0x17d6e4, 0x00007fff9105152e libsystem_kernel.dylib`mach_msg_trap + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
      * frame #0: 0x00007fff9105152e libsystem_kernel.dylib`mach_msg_trap + 10
        frame #1: 0x00007fff9105069f libsystem_kernel.dylib`mach_msg + 55
        frame #2: 0x00007fff8d9ffb14 CoreFoundation`__CFRunLoopServiceMachPort + 212
        frame #3: 0x00007fff8d9fefdb CoreFoundation`__CFRunLoopRun + 1371
        frame #4: 0x00007fff8d9fe838 CoreFoundation`CFRunLoopRunSpecific + 296
        frame #5: 0x00007fff8d45443f HIToolbox`RunCurrentEventLoopInMode + 235
        frame #6: 0x00007fff8d4541ba HIToolbox`ReceiveNextEventCommon + 431
        frame #7: 0x00007fff8d453ffb HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 71
        frame #8: 0x00007fff97b0d6d1 AppKit`_DPSNextEvent + 964
        frame #9: 0x00007fff97b0ce80 AppKit`-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194
        frame #10: 0x00007fff97b00e23 AppKit`-[NSApplication run] + 594
        frame #11: 0x00007fff97aec2d4 AppKit`NSApplicationMain + 1832
        frame #12: 0x000000010ff2b1d2 QQMusic`main + 34
        frame #13: 0x000000010ff2b1a4 QQMusic`start + 52

    #---------------------------------------------------------------------------




看代码


进入到调试状态之后, lldb和gdb一样,也给了你看代码的命令: listl, 但只有在编译时候带-g才能看哦


1. 使用list看代码

  DebugDemo git:(master) lldb DebugDemo.run
(lldb) target create "DebugDemo.run"
Current executable set to 'DebugDemo.run' (x86_64).
(lldb) l
   7    int main () {
   8        size_t result_array[2] = {0, 0};
   9    
   10       FILE *file_handler = fopen("TestData", "r");
   11       json_error_t error;
   12   
   13       json_t *root = json_loadf(file_handler, JSON_DECODE_ANY, &error);
   14       if (!root) {
   15           printf("there is an error on line:%d, test:%s\n", error.line, error.text);
   16       } else {
(lldb)

tips:

  1. 不输入命令的时候直接按回车,就会执行上一次执行的命令。
  2. 一直list到底了之后再list就没有了,这时候怎么办?list 1就回到第一行了。l 13就是从第13行开始往下看10行。


2. 看其他文件的代码

如果你的这个程序编译的时候是由很多文件组成的,那么就可以使用list 文件名看其他文件的代码, 以后再执行list 3的时候,看的就是你前面设置的文件名的第三行

(lldb) list ArrayUtils.c
   1    #include "ArrayUtils.h"
   2    
   3    int
   4    array_count(void *array) {
   5        return 10;
   6    }

(lldb) l 3
   3    int
   4    array_count(void *array) {
   5        return 10;
   6    }


3. 看某个函数的代码

# 直接输入函数名字即可
(lldb) list main
File: /Users/casa/playground/algorithm/leetcode/DebugDemo/src/DebugDemo.c
    2    #include "ArrayUtils.h"
    3    #include <jansson.h>
    4    
    5    void yell(void);
    6    
    7    int main () {
    8        size_t result_array[2] = {0, 0};
    9    
    10       FILE *file_handler = fopen("TestData", "r");
    11       json_error_t error;



下断点


我们把调试器挂上程序了,也看到代码了,接下来就是找一个地方下断点,然后让程序跑起来,看看这里面到底发生了些什么~o


1. 根据文件名和行号下断点

    (lldb) breakpoint set --file DebugDemo.c --line 10
    Breakpoint 1: where = DebugDemo.run`main + 92 at DebugDemo.c:10, address = 0x0000000100000a7c


2. 根据函数名下断点

    # C函数
    (lldb) breakpoint set --name main

    # C++类方法
    (lldb) breakpoint set --method foo

    # Objective-C选择器
    kpoint set --selector alignLeftEdges:


3. 根据某个函数调用语句下断点(Objective-C比较有用)

    # lldb有一个最小子串匹配算法,会知道应该在哪个函数那里下断点
    breakpoint set -n "-[SKTGraphicView alignLeftEdges:]"


4. 一个小技巧

你可以通过设置命令的别名来简化上面的命令

    # 比如下面的这条命令
    (lldb) breakpoint set --file DebugDemo.c --line 10

    # 你就可以写这样的别名
    (lldb) command alias bfl breakpoint set -f %1 -l %2

    # 使用的时候就像这样就好了
    (lldb) bfl DebugDemo.c 10


5. 查看断点列表、启用/禁用断点、删除断点

    #---------------------------------------------------------------------------

    # 查看断点列表

    (lldb) breakpoint list

    Current breakpoints:
    1: file = 'DebugDemo.c', line = 10, locations = 1
      1.1: where = DebugDemo.run`main + 92 at DebugDemo.c:10, address = DebugDemo.run[0x0000000100000a7c], unresolved, hit count = 0

    2: name = 'main', locations = 1
      2.1: where = DebugDemo.run`main + 68 at DebugDemo.c:8, address = DebugDemo.run[0x0000000100000a64], unresolved, hit count = 0

    #---------------------------------------------------------------------------

    # 禁用断点
    # 根据上面查看断点列表的时候的序号来操作断点
    (lldb) breakpoint disable 2
    1 breakpoints disabled.
    (lldb) breakpoint list
    Current breakpoints:
    1: file = 'DebugDemo.c', line = 10, locations = 1
      1.1: where = DebugDemo.run`main + 92 at DebugDemo.c:10, address = DebugDemo.run[0x0000000100000a7c], unresolved, hit count = 0

    2: name = 'main', locations = 1 Options: disabled 
      2.1: where = DebugDemo.run`main + 68 at DebugDemo.c:8, address = DebugDemo.run[0x0000000100000a64], unresolved, hit count = 0

    #---------------------------------------------------------------------------

    # 启用断点
    (lldb) breakpoint enable 2
    1 breakpoints enabled.
    (lldb) breakpoint list
    Current breakpoints:
    1: file = 'DebugDemo.c', line = 10, locations = 1
      1.1: where = DebugDemo.run`main + 92 at DebugDemo.c:10, address = DebugDemo.run[0x0000000100000a7c], unresolved, hit count = 0

    2: name = 'main', locations = 1
      2.1: where = DebugDemo.run`main + 68 at DebugDemo.c:8, address = DebugDemo.run[0x0000000100000a64], unresolved, hit count = 0

    #---------------------------------------------------------------------------

    # 删除断点
    (lldb) breakpoint delete 1
    1 breakpoints deleted; 0 breakpoint locations disabled.
    (lldb) breakpoint list
    Current breakpoints:
    2: name = 'main', locations = 1
      2.1: where = DebugDemo.run`main + 68 at DebugDemo.c:8, address = DebugDemo.run[0x0000000100000a64], unresolved, hit count = 0

    #---------------------------------------------------------------------------



运行环境操作



1. 启动

OK, 我们前面已经下好断点了,现在就要启动这个程序了!前面留了一个断点是断在main函数的哈。

    # run命令就是启动程序
    (lldb) run
    Process 11500 launched: '/Users/casa/Playground/algorithm/leetcode/DebugDemo/DebugDemo.run' (x86_64)
    Process 11500 stopped   # 这里执行到断点了
    * thread #1: tid = 0x1af357, 0x0000000100000a64 DebugDemo.run`main + 68 at DebugDemo.c:8, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
        frame #0: 0x0000000100000a64 DebugDemo.run`main + 68 at DebugDemo.c:8
       5    void yell(void);
       6    
       7    int main () {
    -> 8        size_t result_array[2] = {0, 0};  # 这一行前面的箭头表示调试器在这里停住了
       9    
       10       FILE *file_handler = fopen("TestData", "r");
       11       json_error_t error;


2. 下一步、步入、步出、继续执行

    # 下一步 (next 或 n)
    (lldb) next
    Process 11500 stopped
    * thread #1: tid = 0x1af357, 0x0000000100000a7c DebugDemo.run`main + 92 at DebugDemo.c:10, queue = 'com.apple.main-thread', stop reason = step over
        frame #0: 0x0000000100000a7c DebugDemo.run`main + 92 at DebugDemo.c:10
       7    int main () {
       8        size_t result_array[2] = {0, 0};
       9    
    -> 10       FILE *file_handler = fopen("TestData", "r");
       11       json_error_t error;
       12   
       13       json_t *root = json_loadf(file_handler, JSON_DECODE_ANY, &error);

    #---------------------------------------------------------------------------

    # 步入(step 或 s)
    Process 11668 stopped
    * thread #1: tid = 0x1b4e9d, 0x0000000100000c06 DebugDemo.run`main + 486 at DebugDemo.c:29, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
        frame #0: 0x0000000100000c06 DebugDemo.run`main + 486 at DebugDemo.c:29
       26               printf("input array is %"JSON_INTEGER_FORMAT"\n", json_integer_value(item));
       27           }
       28   
    -> 29           yell();
       30   
       31           json_array_foreach(input_array, index, item) {
       32

    (lldb) step
    Process 11668 stopped
    * thread #1: tid = 0x1b4e9d, 0x0000000100000e1f DebugDemo.run`yell + 15 at DebugDemo.c:57, queue = 'com.apple.main-thread', stop reason = step in
        frame #0: 0x0000000100000e1f DebugDemo.run`yell + 15 at DebugDemo.c:57
       54   
       55   void yell()
       56   {
    -> 57       printf("here i am yelling\n");
       58   }

    #---------------------------------------------------------------------------

    # 步出(finish)
    (lldb) finish
    here i am yelling
    Process 11668 stopped
    * thread #1: tid = 0x1b4e9d, 0x0000000100000c0b DebugDemo.run`main + 491 at DebugDemo.c:31, queue = 'com.apple.main-thread', stop reason = step out
        frame #0: 0x0000000100000c0b DebugDemo.run`main + 491 at DebugDemo.c:31
       28   
       29           yell();
       30   
    -> 31           json_array_foreach(input_array, index, item) {
       32   
       33               result_array[0] = index;
       34               json_int_t value = json_integer_value(item);

    #---------------------------------------------------------------------------

    # 继续执行到下一个断点停, 后面没有断点的话就跑完了(continue 或 c)
    (lldb) continue
    Process 11668 resuming
    result is 2, 3
    Process 11668 exited with status = 0 (0x00000000)

    #---------------------------------------------------------------------------


3. 查看变量、跳帧查看变量

    # 使用po或p,po一般用来输出指针指向的那个对象,p一般用来输出基础变量。普通数组两者都可用
    Process 11717 stopped
    * thread #1: tid = 0x1b7afc, 0x0000000100000a7c DebugDemo.run`main + 92 at DebugDemo.c:10, queue = 'com.apple.main-thread', stop reason = step over
        frame #0: 0x0000000100000a7c DebugDemo.run`main + 92 at DebugDemo.c:10
       7    int main () {
       8        size_t result_array[2] = {0, 0};
       9    
    -> 10       FILE *file_handler = fopen("TestData", "r");
       11       json_error_t error;
       12   
       13       json_t *root = json_loadf(file_handler, JSON_DECODE_ANY, &error);

    (lldb) po result_array
     ([0] = 0, [1] = 0)

    (lldb) p result_array
    (size_t [2]) $2 = ([0] = 0, [1] = 0)

    #---------------------------------------------------------------------------

    # 查看所有帧(bt)
    (lldb) bt
    * thread #1: tid = 0x1bb7dc, 0x0000000100000e1f DebugDemo.run`yell + 15 at DebugDemo.c:57, queue = 'com.apple.main-thread', stop reason = step in
      * frame #0: 0x0000000100000e1f DebugDemo.run`yell + 15 at DebugDemo.c:57
        frame #1: 0x0000000100000c0b DebugDemo.run`main + 491 at DebugDemo.c:29
        frame #2: 0x00007fff99d175c9 libdyld.dylib`start + 1

    #---------------------------------------------------------------------------

    # 跳帧(frame select)
    (lldb) frame select 1
    frame #1: 0x0000000100000c0b DebugDemo.run`main + 491 at DebugDemo.c:29
       26               printf("input array is %"JSON_INTEGER_FORMAT"\n", json_integer_value(item));
       27           }
       28   
    -> 29           yell();
       30   
       31           json_array_foreach(input_array, index, item) {
       32

    #---------------------------------------------------------------------------

    # 查看当前帧中所有变量的值(frame variable)
    (lldb) frame variable

    (size_t [2]) result_array = ([0] = 0, [1] = 0)
    (FILE *) file_handler = 0x00007fff7cfdd070
    (json_error_t) error = (line = 0, column = 0, position = 0, source = "", text = "?)
    (json_t *) root = 0x0000000000000000

    #---------------------------------------------------------------------------




结束


这只是这篇文章结束了,还有watchpoints这一门没有写。不过这篇文章里面的东西知道了以后,调试个程序问题就不大。 想要进阶的同学可以去看官方tutorial




❌
❌