调试技巧有用网站编译原理

iOS_LLDB

2018-08-17  本文已影响34人  Lin__Chuan

LLVM 是一个模块化和可重用的编译器和工具链技术的集合,创始人是 Chris Lattner,也是Swift之父
LLDB 是 LLVM 的子项目,基于LLVM提供的库和Clang构建的优秀的本地调试器。

在命令行中调试程序

在终端中使用LLDB调试器, 需要了解以下内容.

  1. 加载程序以备调试
  2. 将一个运行的程序绑定到LLDB
$ lldb /Projects/Sketch/build/Debug/Sketch.app 
Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64).
  1. 设置断点和观察点

给main.m文件中的12行设置断点

(lldb) breakpoint set --file main.m --line 12

设置观察点
作为断点的补充, LLDB支持观察点以在不中断程序运行的情况下监测一些变量。例如,我们可以使用以下命令来监测名为global的变量的写操作,并在(global==5)为真时停止监测

(lldb) watch set var global
Watchpoint created: Watchpoint 1: addr = 0x100001018 size = 4 state = enabled type = w
   declare @ '/Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp:12'
(lldb) watch modify -c '(global==5)'
(lldb) watch list
  1. 控制程序的执行

启动程序

(lldb) process launch
(lldb) run
(lldb) r
  1. 在调试的程序中导航
(lldb) thread continue
Resuming thread 0x2c03 in process 46915
Resuming process 46915
  1. 检查状态和值的变量

查看线程状态

(lldb) thread list

查看调用栈状态

(lldb) frame variable self
(SKTGraphicView *) self = 0x0000000100208b40

  1. 执行替代代码

expression命令不仅会改变调试器中的值,还改变了程序中的实际值

(lldb) exp a = 10
(NSInteger) $0 = 10
(lldb) exp b = 100
(NSInteger) $1 = 100
2015-01-25 14:00:41.313 test[18064:71466] a + b = 110, abc

在Xcode中使用LLDB调试器本质上和在命令行中调试程序一样(Xcode只是一个GUI, 图形操作界面), 以上的步骤完全一样, 相关的指令可以参考苹果官方文档.


在Xcode中调试程序

help命令可以列出能使用的命令列表

(lldb) help

这里介绍一些常用命令的用法

1. print指令

Swift中的打印

(lldb) print a
(Int) $R1 = 10
(lldb) print p
(LCCustomTools_Swift.Person) $R2 = (name = "lucy", age = 12)
(lldb) prin a
(Int) $R3 = 10
(lldb) pri a
(Int) $R4 = 10
(lldb) p a
(Int) $R5 = 10

// 结构体
(lldb) po p
▿ Person
  - name : "lucy"
  - age : 12

// class
(lldb) po p2
<PersonClass: 0x60000044a830>

(lldb) 

OC中的打印

(lldb) p a
(int) $0 = 10
(lldb) p person
(Person *) $1 = 0x0000608000010780

(lldb) po person
<Person: 0x608000010780>
2. 打印视图的层级结构

OC

(lldb) po [self.view recursiveDescription]

Swift

(lldb) po view. recursiveDescription
<UIView: 0x7fec9152ce10; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x600000032120>>
   | <UIButton: 0x7fec9152b0b0; frame = (114 76; 92 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x600000031520>>
   | <UIButton: 0x7fec9152b570; frame = (130 152; 60 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x600000031a20>>
   | <UIButton: 0x7fec9152c7d0; frame = (177.583 229; 86.3333 60); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x600000031f00>>
   |    | <UIImageView: 0x7fec9152e240; frame = (10.6667 15; 30 30); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x600000033920>>
   |    | <UIButtonLabel: 0x7fec91530d20; frame = (41 20; 34.6667 20.3333); text = '撸串'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x60000008ce90>>
   |    |    | <_UILabelContentLayer: 0x600000035140> (layer)
3. 打印视图控制器的层级结构

OC

(lldb) po [UIWindow valueForKeyPath:@"keyWindow.rootViewController._printHierarchy"]

Swift

(lldb) po UIWindow.valueForKeyPath("keyWindow.rootViewController._printHierarchy")
<NavigationController 0x7fcf83807a00>, state: appeared, view: <UILayoutContainerView 0x7fcf82c09900>
   | <ViewController 0x7fcf82d09900>, state: appeared, view: <UIView 0x7fcf82c0c420>
   | <Button_ViewController 0x7fcf82e02320>, state: disappeared, view: <UIView 0x7fcf82d223a0> not in the window
4. 格式化输出
// 16进制
(lldb) p/x p2.age
(Int) $R2 = 0x000000000000000c
// 10进制
(lldb) p/d p2.age
(Int) $R3 = 12
// 8进制
(lldb) p/o p2.age
(Int) $R4 = 014

(lldb) p/x 0x7fcf83807a00
(Int) $R5 = 0x00007fcf83807a00
5. expression命令

expression的简写有exp, e。可以用expression来声明新的变量,也可以改变已有变量的值。我们看到e声明的都是$开头的变量。我们在使用时也需要加上$符号。

(lldb) e let $arr = ["a", "b", "c"] 
(lldb) p $arr
([String]) $R0 = 3 values {
  [0] = "a"
  [1] = "b"
  [2] = "c"
}
(lldb) po $arr[0]
"a"

6. image命令

image命令可以用来寻找栈地址对应的代码位置

NSArray *arr = @[@"a", @"b"];
NSLog(@"%@", arr[2]);
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndexedSubscript:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000011045d12b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010faf1f41 objc_exception_throw + 48
    2   CoreFoundation                      0x000000011049d0cc _CFThrowFormattedException + 194
    3   CoreFoundation                      0x0000000110510890 +[__NSArrayI allocWithZone:] + 0
    4   LCCustomTools_OC                    0x000000010f1cf878 -[AppDelegate application:didFinishLaunchingWithOptions:] + 184
    5   UIKit                               0x0000000110fe5bca -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 299
    6   UIKit                               0x0000000110fe7648 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4113
    7   UIKit                               0x0000000110fecaeb -[UIApplication _runWithMainScene:transitionContext:completion:] + 1720
...

根据以上信息, 可以知道问题出在[AppDelegate application:didFinishLaunchingWithOptions:], 但是不知道具体在哪一行.
通过以下命令找到出错位置

(lldb) image lookup --address 0x000000010f1cf878
      Address: LCCustomTools_OC[0x0000000100009878] (LCCustomTools_OC.__TEXT.__text + 32824)
      Summary: LCCustomTools_OC`-[AppDelegate application:didFinishLaunchingWithOptions:] + 184 at AppDelegate.m:30

问题出在30行

参考自
深入了解GDB和LLDB
LLDB调试器使用简介
LLDB之基本命令使用(Swift)

上一篇下一篇

猜你喜欢

热点阅读