LLDB 调试小结

一、概述

LLDB全称 [ Low Level Debugger ], 默认内置于Xcode中的动态调试工具。标准的 LLDB 提供了一组广泛的命令,旨在与熟悉的 GDB 命令兼容。 除了使用标准配置外,还可以很容易地自定义 LLDB 以满足实际需要。

语法结构

<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]

乍一看,有点懵,其实是这样的:

<command>(命令)和<subcommand>(子命令):LLDB调试命令的名称。
命令和子命令按层级结构来排列:一个命令对象为跟随其的子命令对象创建一个上下文,子命令又为其子命令创建一个上下文,依此类推。

<action>:执行命令的操作

<options>:命令选项

<arguement>:命令的参数

[]:表示命令是可选的,可以有也可以没有

例如:
breakpoint set -n viewDidLoad

这个命令对应到上面就是:

command: breakpoint 表示断点命令
action: set 表示设置断点
option: -n 表示根据方法name设置断点
arguement: viewDidLoad 表示方法名为mian

二、LLDB调试命令

调试时,添加断点,暂停运行时,此时就可以在 Xcode 下方的控制台使用 lldb 调试:

常用调试命令:

    1. 打印某个变量或对象:
      po / print / p / call / e 变量名/ 对象
      po 命令只是打印数值,同于 NSLog 打印对象,而 print、p、call 命令还打印了变量的类型。
      如图:
image.png

在打印变量的值的时候,我们还可以使用 print/<fmt> 或者简化的 p/<fmt>指定打印格式,例如打印十六进制:


image.png

p/x 变量名

x 代表十六进制格式、t 代表二进制格式,其他格式类型请点击这里查看。

如果需查看内存数据:可以在输出窗口采用gdb命令:x /nfu <addr>

n表示要显示的内存单元的个数
-----------------------------------------
f表示显示方式, 可取如下值:
x 按十六进制格式显示变量
d 按十进制格式显示变量
u 按十进制格式显示无符号整型
o 按八进制格式显示变量
t 按二进制格式显示变量
a 按十六进制格式显示变量
i 指令地址格式
c 按字符格式显示变量
f 按浮点数格式显示变量
-----------------------------------------
u表示一个地址单元的长度:
b表示单字节
h表示双字节
w表示四字节
g表示八字节
-------------------------------------------
例如x/16xb self
会显示self指针地址内容,16个字节,16进制

    1. expression 命令(简写 expr/e/p)

从前面的命令列表可以看到 print、p、po、call 都是 expression 命令的简写,而 expression命令的作用是执行一个表达式,并将表达式返回的结果输出。 常用于调试时修改当前线程上变量的值,也就是说我们可以利用它们更改变量的值,而不需要修改代码再重新编译就可以看到效果,简写为 expr

例如我们将 number 的值修改为100:

image.png

也可以用于修改某属性的值,例如:

// 修改颜色
expression self.view.backgroundColor = [UIColor purpleColor]
// 刷新界面
expression -- (void)[CATransaction flush]

也可作为打印命令:

expression -- self.view

image.png

我们知道,OC里所有的对象都是用指针表示的,所以一般打印的时候,打印出来的是对象的指针,而不是对象本身。如果我们想打印对象。我们需要使用命令选项:-O。为了更方便的使用,LLDB为expression -O --定义了一个别名:po

image.png

p (expression)也可用于调试时,动态注入代码,像正常写代码一样,比较强大的。

    1. call 命令 调用某个方法
      相当于在 lldb 中实时执行所添加的代码
      例如: 调试界面时,查看某个控件的位置等,可以直接设置一下背景,而不用重新运行才能看到。
      call self.topIV.backgroundColor = [UIColor orangeColor]
    1. d 反汇编当前目标中的指定指令。
      默认为当前线程和当前函数
      堆栈框架。可以查看当前方法的汇编代码
      ,包括:内存地址、所占字节、汇编指令等,无意间发现的。(应该是 dis 命令的简写)
      如图:
image.png
    1. image 命令

由于LLDB给 target modules 取了个别名 image,所以 target modules lookup 这个命令我们又可以写成 image lookup

  • (1)image lookup --address/a 寻址,定位异常代码位置

当我们有一个地址,想查找这个地址具体对应的文件位置,可以使用 image lookup --address ,简写为 image lookup -a

image.png

当程序崩溃的时候,可以通过 image lookup --address 内存地址,来精确定位崩溃的具体位置,很实用。
例如:

    NSString *testStr = @"12345";
    NSString *subString = [testStr substringToIndex:10];
代码截图

运行越界崩溃:

崩溃信息

具体的调用堆栈信息居然没有,很神奇吧?但是不同非凡的 Me 两次居然就找到了,呵呵

崩溃具体位置
  • (2)image lookup –name
    当我们想查找一个方法或者符号的信息,比如所在文件位置等。我们可以使用image lookup --name,简写为image lookup -n。

适用于查找同名方法,不只是自己写的方法, 系统的和第三方的 .a 都可以搜索得到,而工程中的搜索是办不到的,

例如,随便找的:


image.png
  • (3)image lookup --type查看类型

当我们想查看一个类型的时候,可以使用image lookup --type,简写为image lookup -t:
定义代码如下:

@interface ViewController ()
{
    NSString *address;
    float height;
}

/** Description */
@property (nonatomic, copy) NSString *name;
/** Description */
@property (nonatomic, assign) int age;

@end

打印信息如下:

image.png

可以看到,LLDB把 ViewController 这个class的所有属性和成员变量都打印了出来,当我们想了解某个类的时候,直接使用image lookup -t即可

image list 查看项目所调用的库,第一个为Mach-o 其余为相关的库,相当于 Windows 的镜像。

    1. thread 查看线程堆栈信息
    • thread backtrace & bt 查看堆栈调用,效果是一样的,如下:
image.png
  • up 查看上一步的堆栈调用信息,如下:
image.png
  • down 查看下一步的堆栈调用信息,类似 up

  • frame select 编号,跳转至指定堆栈查看,源码和汇编(系统的或打包的),定位某个方法的具体实现。

image.png

堆栈信息的编号,指定查看:

image.png
  • frame variable 查看方法的所有参数。
image.png

注:三个参数因为 OC 中每个方法默认都有的两个隐式参数,第三个才为我们传的参数,此时也可以通过 p 修改相关的数据。

修改,上面的 up 和 down 只是查看,thread return 则是让代码回滚到上一步返回,也不会执行,相当于代码中的 return。

    1. breakpoint 断点(代码断点)
      断点可能是在我们调试过程中用的最多的功能了,但是我们不一定都了解断点的各种用法。

手动打断点时:

  • 断点的编辑,如:
    1.设置触发条件
image.png

这个功能也比较实用,调试过程中,可以跟踪数据或界面等的变化,自动触发。

    1. 设置触发事件,可以看到有以下几种:


      image.png

可以试一下,探索一下。

断点 lldb 调试命令:

  • breakpoint set 设置断点
  • 使用-n根据方法名给当前类设置断点:

breakpoint set -n viewWillAppear:
给 viewWillAppear 方法设置一个断点:

set 是子命令
-n 是选项 是--name 的缩写!

  • 使用-n根据方法名给指定类多个方法设置断点:

breakpoint set -n "-[ViewController save:]" -n "-[ViewController continueGame:]" -n "-[ViewController pauseGame:]"

注意:"" 和参数的 :,简写 b -n 方法名,或 b 方法名

b -n "-[ViewController touchesBegan:withEvent:]"
b pauseGame:

  • 给整个项目某个指定方法设置断点:

breakpoint set --selector 方法名

如:给 touchesBegan:withEvent: 设置断点

breakpoint set --selector touchesBegan:withEvent:

包含系统的方法,

  1. 使用-f指定文件和方法

breakpoint set -f ViewController.m -n viewDidAppear:

给ViewController.m文件中的viewDidAppear 方法设置断点:
注意方法后面的 :冒号,不添加无效果。

shift +Command + j 调转至当前类文件处

  1. 使用-l指定文件某一行设置断点

breakpoint set -f ViewController.m -l 33

在 ViewController.m 的 33 行设置一个断点。

breakpoint set --file ViewController.m --selector touchesBegan:withEvent:

给 ViewController.m 的 touchesBegan:withEvent: 方法添加断点。

这些都可以通过上面手动来添加,只不过是两种方式罢了。

给某个内存地址设置断点

b -a 地址

  • 查看断点列表
    $breakpoint list

  • 删除
    breakpoint delete 删除所有断点
    $breakpoint delete 组号(一组的断点)
    breakpoint delete 组分号
    breakpoint delete 1.1 不会删除该断点,会禁用该断点

  • 禁用/启用

breakpoint disable 禁用
简写:break dis
breakpoint enable 启用
简写:break en

禁用某一个断点

breakpoint disable 4.1

  • 遍历整个项目中的所有方法包含 Game: 这个字符的所有方法

breakpoint set -r Game:

流程控制

  • 继续执行
    $continue c

  • 单步运行,将子函数当做整体一步执行
    $n next

  • 单步运行,遇到子函数会进去
    $s

    • lldb 调试时,按住 control 进入汇编指令,流程控制。

watchpoint 内存断点

  • watchpoint 内存断点,查看某个值的变化。
image.png
  • watchpoint delete 删除内存断点
    同 breakpoint 用法。

  • break command add 断点编号,执行至该断点时做相应操作。
    如下:

image.png

执行结果:

image.png
  • break command delete 4
  • break command list
    同 breakpoint 用法。

stop-hook

让你在每次stop的时候去执行一些命令,(除了Debug 控制台中的暂停和 Debug View hierarchy 查看)只对breadpoint,watchpoint 有效。

  • 添加一条断点指令,打印变量,只要程序停止就会执行。

target stop-hook add -o "frame variable"
-o one line 一行 感觉像输出 -output 简写

  • 查看方法实现,仅限于在源码中调试

target stop-hook add -o "frame select"

"" 中可以添加任意想要查看的 指令,eg: p ...

每次 stop 时,结果如下:

image.png
  • 查看所有的 stop-hook 指令

target stop-hook list

image.png

删除 stop-hook 指令

删除指定标号的
target stop-hook delete 1
删除所有的
target stop-hook delete

有一点特殊的:

undisplay 3
移除指定标号的 stop-hook 指令同 delete

同 breakpoint 用法,help target stop-hook 查看相关的命令。

.lldbinit

以上都是在 lldb 调试时,手动添加配置指令。

  • 自动配置
    在用户目录下找到 .lldbinit 文件,没有的话就新建一个,可以添加一条指令测试一下,如下:

target stop-hook add -o "frame variable"

注:用 Mac 的文本编辑工具创建编辑后保存不要使用任何格式,多信息的会有很多附加的设置信息,如:


image.png
image.png

这样就可以实现断点无须手动输入指令查看,但是 .lldbinit 一般用于导入配置文件,更能方便的使用 LLDB 的功能。

image.png

常用命令

  • p
  • b -[xxx xxx]
  • x memory read 的缩写
  • register read
  • po
  • image list

注:其实上面的所有命令,都可以通过 help 命令查看其相关的所有指令及用法,
如:thread help 就可以查看 thread 相关的所有命令
直接在 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.
  disassemble       -- Disassemble specified instructions in the current
                       target.  Defaults to the current function for the
                       current thread and stack frame.
  expression        -- Evaluate an expression on the current thread.  Displays
                       any returned value with LLDB's default formatting.
  frame             -- Commands for selecting and examing the current thread's
                       stack frames.
  gdb-remote        -- Connect to a process via remote GDB server.  If no host
                       is specifed, localhost is assumed.
  gui               -- Switch into the curses based GUI mode.
  help              -- Show a list of all debugger commands, or give details
                       about a specific command.
  kdp-remote        -- Connect to a process via remote KDP server.  If no UDP
                       port is specified, port 41139 is assumed.
  language          -- Commands specific to a source language.
  log               -- Commands controlling LLDB internal logging.
  memory            -- Commands for operating on memory in the current target
                       process.
  platform          -- Commands to manage and create platforms.
  plugin            -- Commands for managing LLDB plugins.
  process           -- Commands for interacting with processes on the current
                       platform.
  quit              -- Quit the LLDB debugger.
  register          -- Commands to access registers for the current thread and
                       stack frame.
  script            -- Invoke the script interpreter with provided code and
                       display any results.  Start the interactive interpreter
                       if no code is supplied.
  settings          -- Commands for managing LLDB settings.
  source            -- Commands for examining source code described by debug
                       information for the current target process.
  target            -- Commands for operating on debugger targets.
  thread            -- Commands for operating on one or more threads in the
                       current process.
  type              -- Commands for operating on the type system.
  version           -- Show the LLDB debugger version.
  watchpoint        -- Commands for operating on watchpoints.
Current command abbreviations (type 'help command alias' for more info):
  add-dsym  -- Add a debug symbol file to one of the target's current modules
               by specifying a path to a debug symbols file, or using the
               options to specify a module to download symbols for.
  attach    -- Attach to process by ID or name.
  b         -- Set a breakpoint using one of several shorthand formats.
  bt        -- Show the current thread's call stack.  Any numeric argument
               displays at most that many frames.  The argument 'all' displays
               all threads.
  c         -- Continue execution of all threads in the current process.
  call      -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  continue  -- Continue execution of all threads in the current process.
  detach    -- Detach from the current target process.
  di        -- Disassemble specified instructions in the current target. 
               Defaults to the current function for the current thread and
               stack frame.
  dis       -- Disassemble specified instructions in the current target. 
               Defaults to the current function for the current thread and
               stack frame.
  display   -- Evaluate an expression at every stop (see 'help target
               stop-hook'.)
  down      -- Select a newer stack frame.  Defaults to moving one frame, a
               numeric argument can specify an arbitrary number.
  env       -- Shorthand for viewing and setting environment variables.
  exit      -- Quit the LLDB debugger.
  f         -- Select the current stack frame by index from within the current
               thread (see 'thread backtrace'.)
  file      -- Create a target using the argument as the main executable.
  finish    -- Finish executing the current stack frame and stop after
               returning.  Defaults to current thread unless specified.
  image     -- Commands for accessing information for one or more target
               modules.
  j         -- Set the program counter to a new address.
  jump      -- Set the program counter to a new address.
  kill      -- Terminate the current target process.
  l         -- List relevant source code using one of several shorthand formats.
  list      -- List relevant source code using one of several shorthand formats.
  n         -- Source level single step, stepping over calls.  Defaults to
               current thread unless specified.
  next      -- Source level single step, stepping over calls.  Defaults to
               current thread unless specified.
  nexti     -- Instruction level single step, stepping over calls.  Defaults to
               current thread unless specified.
  ni        -- Instruction level single step, stepping over calls.  Defaults to
               current thread unless specified.
  p         -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  parray    -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  po        -- Evaluate an expression on the current thread.  Displays any
               returned value with formatting controlled by the type's author.
  poarray   -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  print     -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  q         -- Quit the LLDB debugger.
  r         -- Launch the executable in the debugger.
  rbreak    -- Sets a breakpoint or set of breakpoints in the executable.
  repl      -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  run       -- Launch the executable in the debugger.
  s         -- Source level single step, stepping into calls.  Defaults to
               current thread unless specified.
  si        -- Instruction level single step, stepping into calls.  Defaults to
               current thread unless specified.
  sif       -- Step through the current block, stopping if you step directly
               into a function whose name matches the TargetFunctionName.
  step      -- Source level single step, stepping into calls.  Defaults to
               current thread unless specified.
  stepi     -- Instruction level single step, stepping into calls.  Defaults to
               current thread unless specified.
  t         -- Change the currently selected thread.
  tbreak    -- Set a one-shot breakpoint using one of several shorthand
               formats.
  undisplay -- Stop displaying expression at every stop (specified by stop-hook
               index.)
  up        -- Select an older stack frame.  Defaults to moving one frame, a
               numeric argument can specify an arbitrary number.
  x         -- Read from the memory of the current target process.
For more information on any command, type 'help <command-name>'.

命令很多,要查看某一个相关,可以继续 help , 熟悉熟悉,就会发现新大陆。

不常用调试命令:

apropos -- 列出与单词或主题相关的调试器命令
breakpoint -- 在断点上操作的命令 (详情使用'help b'查看)
bugreport -- 用于创建指定域的错误报告
command -- 用于管理自定义LLDB命令的命令
disassemble -- 拆分当前目标中的特定说明。 默认为当前线程和堆栈帧的当前函数
expression -- 求当前线程上的表达式的值。 以LLDB默认格式显示返回的值
frame -- 用于选择和检查当前线程的堆栈帧的命令
gdb-remote -- 通过远程GDB服务器连接到进程。 如果未指定主机,则假定为localhost
gui -- 切换到基于curses的GUI模式
help -- 显示所有调试器命令的列表,或提供指定命令的详细信息
kdp-remote -- 通过远程KDP服务器连接到进程。 如果没有指定UDP端口,则假定端口41139
language -- 指定源语言
log -- 控制LLDB内部日志记录的命令
memory -- 用于在当前目标进程的内存上操作的命令
platform -- 用于管理和创建平台的命令
plugin -- 用于管理LLDB插件的命令
process -- 用于与当前平台上的进程交互的命令
quit -- 退出LLDB调试器
register -- 命令访问当前线程和堆栈帧的寄存器
script -- 使用提供的代码调用脚本解释器并显示任何结果。 如果没有提供代码,启动交互式解释器。
settings -- 用于管理LLDB设置的命令
source -- 检查当前目标进程的调试信息所描述的源代码的命令
target -- 用于在调试器目标上操作的命令
thread -- 用于在当前进程中的一个或多个线程上操作的命令
type -- 在类型系统上操作的命令
version -- 显示LLDB调试器版本
watchpoint -- 在观察点上操作的命令

add-dsym -- ('target symbols add') 通过指定调试符号文件的路径,或使用选项指定下载符号的模块,将调试符号文件添加到目标的当前模块中的一个
attach -- ('_regexp-attach') 通过ID或名称附加到进程
b -- ('_regexp-break') 使用几种简写格式之一设置断点
bt -- ('_regexp-bt') 显示当前线程的调用堆栈。通过数字参数设置最多显示帧数。参数“all”显示所有线程
c -- ('process continue') 继续执行当前进程中的所有线程
call -- ('expression --') 计算当前线程上的表达式,使用LLDB的默认格式显示返回的值
continue -- ('process continue') 继续执行当前进程中的所有线程
detach -- ('process detach') 脱离当前目标进程
di -- ('disassemble') 拆分当前目标中的特定说明。 默认为当前线程和堆栈帧的当前函数
dis -- ('disassemble') 同上
display -- ('_regexp-display') 在每次停止时计算表达式(请参阅'help target stop-hook')
down -- ('_regexp-down') 选择一个新的堆栈帧。默认为移动一个帧,数字参数可以指定值
env -- ('_regexp-env') 查看和设置环境变量的简写
exit -- ('quit') 退出LLDB调试器
f -- ('frame select') 从当前线程中通过索引选择当前堆栈帧(参见'thread backtrace')
file -- ('target create') 使用参数作为主要可执行文件创建目标
finish -- ('thread step-out') 完成当前堆栈帧的执行并返回后停止。 默认为当前线程
image -- ('target modules') 用于访问一个或多个目标模块的信息的命令
j -- ('_regexp-jump') 将程序计数器设置为新地址
jump -- ('_regexp-jump') 同上
kill -- ('process kill') 终止当前目标进程
l -- ('_regexp-list') 使用几种简写格式之一列出相关的源代码
list -- ('_regexp-list') 同上
n -- ('thread step-over') 源级单步执行、步进调用,默认当前线程
next -- ('thread step-over') 同上
nexti -- ('thread step-inst-over') 指令级单步执行、步进调用,默认当前线程
ni -- ('thread step-inst-over') 同上
p -- ('expression --') 计算当前线程上表达式的值,以LLDB默认格式显示返回值
parray -- ('expression -Z %1 --') 同上
po -- 计算当前线程上的表达式。显示由类型作者控制的格式的返回值。
poarray -- ('expression -O -Z %1 --') 计算当前线程上表达式的值,以LLDB默认格式显示返回值
print -- ('expression --') 同上
q -- ('quit') 退出LLDB调试器
r -- ('process launch -X true --') 在调试器中启动可执行文件
rbreak -- ('breakpoint set -r %1') 在可执行文件中设置断点或断点集
repl -- ('expression -r -- ') E计算当前线程上表达式的值,以LLDB默认格式显示返回值
run -- ('process launch -X true --') 在调试器中启动可执行文件
s -- ('thread step-in') 源级单步执行、步进调用,默认当前线程
si -- ('thread step-inst') 指令级单步执行、步进调用,默认当前线程
sif -- 遍历当前块,如果直接步入名称与TargetFunctionName匹配的函数,则停止
step -- ('thread step-in') 源级单步执行、步进调用,默认当前线程
stepi -- ('thread step-inst') 指令级单步执行、步进调用,默认当前线程
t -- ('thread select') 更改当前选择的线程
tbreak -- ('_regexp-tbreak') 使用几种简写格式之一设置单次断点
undisplay -- ('_regexp-undisplay') 每次停止时停止显示表达式(由stop-hook索引指定)
up -- ('_regexp-up') 选择较早的堆栈帧。 默认为移动一个帧,数值参数可以指定任意数字
x -- ('memory read') 从当前目标进程的内存中读取

写这个小结也参考了大牛一些优秀的文章, 非常感谢,共同学习。
这是一位曾经供职于百度的技术大牛伯乐在线的个人主页,文章受益匪浅。

http://www.jobbole.com/members/hsdyg/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • [转]浅谈LLDB调试器文章来源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc阅读 2,487评论 2 6
  •   LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用...
    Thinkdifferents阅读 1,529评论 1 4
  • LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用Xc...
    小笨狼阅读 20,444评论 31 187
  • 转载 与调试器共舞 - LLDB 的华尔兹: https://objccn.io/issue-19-2/ 推荐:i...
    F麦子阅读 3,331评论 0 10
  • iOS调试之LLDB Xcode内嵌了LLDB控制台,在Xcode代码编辑区的下方。shift + cmd + y...
    comst阅读 1,465评论 0 3