iOS开发iOS相关技术实现工具

LLDB 调试小结

2018-06-13  本文已影响3人  Superman168

一、概述

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 调试:

常用调试命令:

image.png

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


image.png

p/x 变量名

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

从前面的命令列表可以看到 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)也可用于调试时,动态注入代码,像正常写代码一样,比较强大的。

image.png

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

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

image.png

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

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

运行越界崩溃:

崩溃信息

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

崩溃具体位置

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

例如,随便找的:


image.png

当我们想查看一个类型的时候,可以使用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 的镜像。

image.png image.png image.png

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

image.png image.png

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

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

手动打断点时:

image.png

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

可以试一下,探索一下。

断点 lldb 调试命令:

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

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

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 disable 禁用
简写:break dis
breakpoint enable 启用
简写:break en

禁用某一个断点

breakpoint disable 4.1

breakpoint set -r Game:

流程控制

watchpoint 内存断点

image.png image.png

执行结果:

image.png

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

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 调试时,手动添加配置指令。

target stop-hook add -o "frame variable"

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


image.png image.png

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

image.png

常用命令

注:其实上面的所有命令,都可以通过 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/

上一篇下一篇

猜你喜欢

热点阅读