10

LLDB命令速查手册

 3 years ago
source link: https://easeapi.com/blog/blog/156-lldb.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

LLDB是Xcode上默认的调试器,支持C/C++、Objective-C 和 Swift 程序的调试,也是LLVM项目的一个可重用的高性能调试器。在LLVM项目的lldb子目录可以查看LLDB的源码:llvm-project

LLDB命令格式

<command> [<subcommand> [<subcommand>...]] <action> [-options [optionvalue]] [argument [argument...]]
//命令 + 子命令 + 命令选项 + 命令参数

LLDB命令参数、选项和选项值都用空格分隔的,双引号用于保护参数中的空格。如果需要在参数中放置反斜杠或双引号字符,请在使用反斜杠。对于是二进制数据的参数,可以使用' -- '作为参数结束标记。

获取帮助信息

(lldb) help

help命令将列出所有支持的命令列表。如果需要继续查看某一个命令的帮助信息,后面直接跟上命令的名字即可:

(lldb) help memory

LLDB常用命令

expression

执行表达式并将表达式的执行结果输出打印。开发中常用po来打印对象,po实际上就是expression -O的别名。

breakpoint:代码调试断点

指定文件和行号设置断点:

breakpoint set --file easeapi.c --line 12
breakpoint set -f ViewController.m -l 12

指定函数名称设置断点:

//对于C函数,填写完整的函数名称。
breakpoint set --name easeapi_func
breakpoint set -n easeapi_func

//对于Objective-C函数,填写完整的方法签名Selector字符串。
breakpoint set -n viewDidAppear:
breakpoint set -n tableView:cellForRowAtIndexPath:

//对于Swift方法,填写函数名称,参数省略。
breakpoint set -n easeapi_func

指定对象方法设置断点:

breakpoint set -n "-[ViewController viewDidAppear:]"
breakpoint set -n "+[ViewController classFunc]"
//Swift函数
breakpoint set -n "ViewController.easeapi_func"

指定代码地址设置断点:

breakpoint set --address 0x1021744bb
breakpoint set -a 0x1021744bb

查看已经设置的断点:

(lldb) breakpoint list
Current breakpoints:
1: file = '/Users/easeapi/Desktop/Job/ViewController.m', line = 163, exact_match = 0, locations = 1, resolved = 1, hit count = 1

  1.1: where = Project`-[ViewController viewDidLoad] + 3461 at ViewController.m:163:10, address = 0x0000000102174355, resolved, hit count = 1 

2: file = '/Users/easeapi/Desktop/Job/ViewController.m', line = 66, exact_match = 0, locations = 1, resolved = 1, hit count = 1

  2.1: where = Project `-[ViewController viewDidLoad] + 68 at ViewController.m:66:41, address = 0x0000000102173614, resolved, hit count = 1 

3: address = Project[0x00000001000044bb], locations = 1, resolved = 1, hit count = 1
  3.1: where = Project `-[ViewController viewDidLoad] + 3819 at ViewController.m:171:14, address = 0x00000001021744bb, resolved, hit count = 1 

每一次设置的断点都是逻辑断点(对应编号1、2、3等),一个逻辑断点可以解析为多个断点位置(对应编号1.1等)。比如仅对viewDidLoad方法做一个逻辑断点,则每一个加载类的viewDidLoad方法都会被标记为断点位置。

取消断点:

//breakpoint delete [断点编号]
breakpoint delete 1

删除所有断点:

breakpoint delete

watchpoint:内存调试断点

与breakpoint不同,watchpoint允许开发者对内存中的变量或指定内存的数据进行监控。当该地址有数据写入时,会命中断点。

设置观察变量:

watchpoint set variable value
watchpoint set variable self->_dataArray//不能使用点语法

设置观察内存地址:

watchpoint set expression 0x000000016f47fc70

查看所有内存断点:

(lldb) watchpoint list
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 7: addr = 0x13dd10618 size = 8 state = enabled type = w
    watchpoint spec = 'self->_dataArray'
    new value: 0x000000028279d380
Watchpoint 8: addr = 0x16f47fc70 size = 8 state = enabled type = w
    new value: 1024

删除内存断点:

watchpoint delete index
watchpoint delete

register:寄存器操作

读取所有寄存器信息:

(lldb) register read
General Purpose Registers:
        x0 = 0x0000000100b4a0ec  "/Users/easeapi/Desktop/Job/"
        x1 = 0x000000016f47fc70
        x2 = 0x0000000000000002
        x3 = 0x0000000197b59f30  libsystem_malloc.dylib`nanov2_free_definite_size$VARIANT$mp
        x4 = 0x0000000000000402
        x5 = 0x000000016f47ea88
        x6 = 0x0000000000000001
        x7 = 0x0000000000000002
        x8 = 0x0000000000000000
        x9 = 0x0000000000000000
       x10 = 0x000001a1d17d01c1 (0x00000001d17d01c1) (void *)0xb0000001a1d17d03
       x11 = 0x00000000000007fb
       x12 = 0x00000000000007fd
       x13 = 0x0000000000000000
       x14 = 0x00000000c0c45000
       x15 = 0x000000000000008a
       x16 = 0x0000000197177c90  libobjc.A.dylib`objc_release
       x17 = 0x0000000040c00000
       x18 = 0x0000000000000000
       x19 = 0x00000001d1807364  UIKitCore`_UIApplicationLinkedOnVersion
       x20 = 0x000000013dd102c0
       x21 = 0x0000000000000018
       x22 = 0x00000001c4e93601  "count"
       x23 = 0x0000000000000000
       x24 = 0x0000000000000000
       x25 = 0x000000013e010e00
       x26 = 0x0000000000000400
       x27 = 0x000000028209d4a0
       x28 = 0x0000000000000000
        fp = 0x000000016f47fe20
        lr = 0x0000000100983770  Project`-[ViewController viewDidLoad] + 2608 at ViewController.m:166:9
        sp = 0x000000016f47fa60
        pc = 0x0000000100983790  Project`-[ViewController viewDidLoad] + 2640 at ViewController.m:171:14
      cpsr = 0x20000000

ARM64架构中共有34个寄存器,包括31个通用寄存器、SP、PC、CPSR。

  • 通用寄存器

r0 - r30是31个通用寄存器。每个寄存器可以存取一个64位大小的数。 当使用x0 - x30访问时,它就是一个64位的数。当使用w0 - w30访问时,访问的是这些寄存器的低32位。 r29又称FP寄存器(frame point),主要用来保存栈帧(栈底)指针。 r30又称LR寄存器(link register),主要用来保存函数返回地址。

  • SP:stack pointer,栈顶指针;
  • PC:用来记录当前执行的指令地址;
  • CPSR:状态寄存器。

参考:iOS crash log分析实践

读取指定寄存器的值:

register read x1

写入寄存器:

register write x0 1

memory:内存操作

查看内存数据。命令格式:

memory read/个数+格式+每一个的字节数 内存地址
格式:x-16进制、f-浮点数,d-10进制;
字节数:b-1个字节,h-2个字节,w-4个字节,g-8个字节。
默认为:16xb
(lldb) memory read/8xg 0x000000016f08fc70
0x16f08fc70: 0x0000000000000400 0x0000000100f5fe28
0x16f08fc80: 0x0000000000000001 0x0000000000000000
0x16f08fc90: 0x0000000100f678b8 0x00000001c4e9ee67
0x16f08fca0: 0x00000001015051e0 0x00000001d17baf18

也可以使用x查看内存,和memory read的效果一样:

x/8xg 0x000000016f08fc70

向指定内存写入数据:

//写入1个字节
memory write 0x000000016f08fc70 9
//以8字节对齐,写入两个数据
memory write 0x000000016f08fc70 -s 8 0x01 0x02

image:image操作

列出当前进程空间加载的image:

image list

查找信息:

//查找类信息
image lookup --type UIViewController
image lookup -t UIViewController

//查找符号
image lookup --name viewDidLoad
image lookup -n viewDidLoad

//查找地址
image lookup --address 0x000000018ff60490
image lookup -a 0x000000018ff60490

导出image信息:

//导出所有sections信息
image dump sections
//导出所有符号信息
image dump symtab

thread:线程

查看线程列表

(lldb) thread list
Process 17177 stopped
  thread #1: tid = 0x285da2e, 0x00007fff603032ba libsystem_kernel.dylib`mach_msg_trap + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
* thread #2: tid = 0x285dc0c, 0x00007fff60305cde libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #3: tid = 0x285dc0d, 0x00007fff60305cde libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #4: tid = 0x285dc0e, 0x00007fff60305cde libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #6: tid = 0x285dc10, 0x00007fff6033f420 libsystem_pthread.dylib`start_wqthread
  thread #8: tid = 0x285dc18, 0x00007fff6033f420 libsystem_pthread.dylib`start_wqthread
  thread #10: tid = 0x285dc1b, 0x00007fff6030495e libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #11: tid = 0x285dc1c, 0x00007fff603032ba libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread'
  thread #13: tid = 0x285dec2, 0x00007fff6033f420 libsystem_pthread.dylib`start_wqthread
  thread #14: tid = 0x285dec1, 0x00007fff6030495e libsystem_kernel.dylib`__workq_kernreturn + 10

其中,使用*标记当前线程;使用#标记线程编号。

获取线程调用栈:

//获取当前线程调用栈
thread backtrace
bt
//获取所有线程调用栈
thread backtrace all

在Xcode中,有四个控制Debug的按钮:

  • Continue:程序继续运行
thread continue/continue/c
  • Step over:单步指定,遇到子函数时断点不会进入子函数。
thread step-over/next/n
  • Step into:单步运行,遇到子函数时断点会进入子函数。
thread step-into/step/s
  • Step out:执行完当前函数剩余的代码,返回上一层函数。
thread step-out/finish

修改函数返回:

thread return 10

当需要修改一个函数返回值时,可以在函数开始位置加以上断点并修改到需要的返回值。

frame:栈帧信息

查看当前栈帧变量:

frame variable

iOS启动优化之二进制重排
iOS crash log分析实践
iOS Crash log符号化
iOS Link Map
iOS Method Swizzling使用陷阱


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK