Chisel-LLDB命令插件,让调试更Easy

chisel是facebook开源的LLDB插件,方便开发者在开发过程中提升开发效率,或是方便从新接手的一个旧项目中快速熟悉起来。

以下内容多来自博客:https://blog.cnbluebox.com/ 因为有些东西都是一样的,就直接拷过来了,有部分是我后来补充的。

LLDB 是一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器。LLDB 绑定在 Xcode 内部,存在于主窗口底部的控制台中。调试器允许你在程序运行的特定时暂停它,你可以查看变量的值,执行自定的指令,并且按照你所认为合适的步骤来操作程序的进展。(这里有一个关于调试器如何工作的总体的解释。)

相信每个人或多或少都在用LLDB来调试,比如po一个对象。LLDB的是非常强大的,且有内建的,完整的 Python 支持。今天我们主要介绍一个 facebook 开源的 lldb 插件 Chisel。可以让你的调试更Easy.

1.安装Chisel

源码地址: Chisel

Chisel 使用 homebrew 来安装,如果你没有安装homebrew, 参考 homebrew

1
2
brew update
brew install chisel

安装完成按照安装日志上的提示,在~/.lldbinit文件中添加一行,没有则新建。 提示类似如下:

1
2
3
==> Caveats
Add the following line to ~/.lldbinit to load chisel when Xcode launches:
  command script import /usr/local/opt/chisel/libexec/fblldb.py

做好上面的步骤,然后重启Xcode就可以尝试下了。

注:使用命令行“ls -a”查看是否有“.lldbinit”的文件,如果没有该文件,我们可以利用“touch ~/.lldbinit”创建该文件。然后将如下图中的地址复制到文件中,保存退出。重启Xcode,暂停后在控制台输入“help”,如果出现如图二的显示则表示安装成功。(“brew uninstall”可以卸载已安装的chisel)

图一

图二

2.内置命令

Chisel 为lldb提供了新增的便捷命令,是非常实用的命令

2.1 pviews

这个命令可以递归打印所有的view,并能标示层级,相当于 UIView 的私有辅助方法 [view recursiveDescription] 。 善用使用这个功能会让你在调试定位问题时省去很多麻烦。

使用示例:

1
2
3
4
5
6
7
8
9
(lldb) pviews view
<TestView: 0x18df8070; baseClass = UIControl; frame = (144 9; 126 167); layer = <CALayer: 0x18df8150>>
   | <UIView: 0x18df81d0; frame = (0 0; 126 126); userInteractionEnabled = NO; layer = <CALayer: 0x18df8240>>
   | <UIImageView: 0x18df8330; frame = (0 0; 126 126); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x18df83b0>>
   | <UILabel: 0x18df8460; frame = (0 135; 126 14); text = 'haha'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x18df7fb0>>
   |    | <_UILabelContentLayer: 0x131a3d50> (layer)
   | <UILabel: 0x18df8670; frame = (0 155; 126 12); text = 'hahaha'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x18df8730>>
   |    | <_UILabelContentLayer: 0x131bea10> (layer)
   | <UIImageView: 0x18df88d0; frame = (0 9; 28 27); hidden = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x18df8ba0>>

2.2 pvc

这个命令也是递归打印层级,但是不是view,而是viewController。利用它我们可以对viewController的结构一目了然。 其实苹果在IOS8也默默的添加了 UIViewController 的一个私有辅助方法[UIViewController _printHierarchy] 同样的效果。(注:配合符号断点,也可以定位ViewController。在符号断点中输入“viewDidLoad”,便会在所有初始化ViewController时都会断一下。cmd+shift+o是快速定位)

预览效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(lldb) pvc
<TabBarController: 0x13772fd0; view = <UILayoutContainerView; 0x151b3a30>; frame = (0, 0; 414, 736)>
   | <UINavigationController: 0x1602b800; view = <UILayoutContainerView; 0x1b00aca0>; frame = (0, 0; 414, 736)>
   |   | <FirstViewController: 0x16029c00; view = <UIView; 0x1b01e1c0>; frame = (0, 0; 414, 736)>
   | <UINavigationController: 0x138c5200; view = <UILayoutContainerView; 0x1316a080>; frame = (0, 0; 414, 736)>
   |   | <SecondViewController: 0x16030400; view = <UIView; 0x2094b370>; frame = (0, 0; 414, 736)>
   |   |   | <SecondChildViewController: 0x15af6000; view = <UIView; 0x18d4e650>; frame = (0, 64; 414, 628)>
   | <UINavigationController: 0x1383ca00; view = <UILayoutContainerView; 0x13180070>; frame = (0, 0; 414, 736)>
   |   | <ThirdViewController: 0x138ddc00; view = <UIView; 0x18df6650>; frame = (0, 0; 414, 736)>
   |   |   | <ThirdChild1ViewController: 0x1393fe00; view = <UIView; 0x131ec000>; frame = (0, 0; 414, 672)>
   |   |   | <ThirdChild2ViewController: 0x138dce00; view = <UIView; 0x204075a0>; frame = (414, 0; 414, 672)>
   |   |   | <ThirdChild3ViewController: 0x138a8e00; view = <UIView; 0x20426250>; frame = (828, 0; 414, 672)>
   | <UINavigationController: 0x160eca00; view = <UILayoutContainerView; 0x152f7d90>; frame = (0, 0; 414, 736)>
   |   | <FourViewController: 0x13157cc0; view not loaded>

是不是方便很多呢,而且还可以看到 viewController 是否已经 viewDidLoad .

2.3 visualize

这是个很有意思的功能,它可以让你使用Mac的预览打开一个 UIImage, CGImageRef, UIView, 或 CALayer。 这个功能或许可以帮我们用来截图、用来定位一个view的具体内容。 但是在我试用了一下,发现暂时还是只能在模拟器时使用,真机还不行。(注:visualize可以用在已打印出的对象的地址(地址也可以通过viewdebuger获取)预览该对象,例如“visualize0x7f82617107f0”)

使用简单:

1
(lldb) visualize imageView

2.4 fv & fvc

fvfvc 这两个命令是用来通过类名搜索当前内存中存在的view和viewController实例的命令,支持正则搜索。

如:

1
2
3
4
5
6
7
8
9
(lldb) fv scrollView
0x18d3b8c0 UIScrollView
0x137d0c50 UIScrollView
0x131b1580 UIScrollView
0x131b2070 UIScrollView
(lldb) fvc Home
0x1393fe00 HomeFeedsViewController
0x138a8e00 HomeFeedsViewController
(lldb)

2.5 show & hide

这两个命令用来显示和隐藏一个指定的 UIView . 你甚至不需要Continue Progress. 就可以看到效果。

2.6 mask/umask border/unborder

这两组命令用来标识一个view或layer的位置时用, mask用来在view上覆盖一个半透明的矩形, border可以给view添加边框。但是在我实际使用的过程中mask总是会报错,估计是有bug, 那么mask/unmask 一般不要用好了,用border命令是一样的效果,反正二者的用途都是找到一个对应的view.

2.7 caflush

这个命令会重新渲染,即可以重新绘制界面, 相当于执行了 [CATransaction flush] 方法,要注意如果在动画过程中执行这个命令,就直接渲染出动画结束的效果。

当你想在调试界面颜色、坐标之类的时候,可以直接在控制台修改属性,然后caflush就可以看到效果啦,是不是要比改代码,然后重新build省事多了呢。

例, 其中 $122 即是目标UIView:

1
2
3
4
(lldb) p view
(long) $122 = 140718754142192
(lldb) e (void)[$122 setBackgroundColor:[UIColor greenColor]]
(lldb) caflush

2.8 bmessage

这个命令就是用来打断点用的了,虽然大家断点可能都喜欢在图形界面里面打,但是考虑一种情况:我们想在 [MyViewController viewWillAppear:] 里面打断点,但是 MyViewController并没有实现viewWillAppear: 方法, 以往的作法可能就是在子类中实现下viewWillAppear:,然后打断点,然后rebuild。

那么幸好有了 bmessage命令。我们可以不用这样就可以打这个效果的断点: (lldb) bmessage -[MyViewController viewWillAppear:] 上面命令会在其父类的viewWillAppear: 方法中打断点,并添加上了条件:[self isKindOfClass:[MyViewController class]]

2.9 border

这个命令是用来给某个对象加边框,方便与其他的视图对象有所区别。

border -c red -w 2 0x7f82617107f0(对象地址),此时模拟器会自动刷新界面并对该对象加上边框宽度为2的红色边框。

unborder 0x7f82617107f0,这条命令是去掉刚才加的边框属性

2.10 caflush补充

这个命令是在你做了修改view的外观之后,可以让屏幕立刻刷新成你修改的外观样式。因为在一些chisel命令中是默认刷新的,但是有些命令是需要我们自己去手动刷新的。

在控制台输入“po [0x7f82617107f0 setBackgroundColor:[UIColor redColor]]”后,需要在输入“caflush”模拟器的界面才会有变化。但是不建议我们去手动改变对象的背景色,因为我们必须去改过来或者重新启动工程才能还原。通常建议是加边框来区别。

2.11 presponder

这个命令是输出对象的响应者链。

presponder 0x7f82617107f0,在控制器中从APPDelegate到当前对象的响应者链,不会显示同级的对象,方便我们梳理一些层级关系和响应事件的执行。

2.12 taplog

这个命令是在你程序中断时,你敲击模拟器屏幕的任何地方,控制器会打印到你触摸的view。方便我们快速查找获取触摸的view地址,以便利用其它的命令来做其它的操作。注意:我们需要 先输入“taplog”,再去点击屏幕。

2.13 pcalss

这个命令可以打印当前对象的类的继承关系。

pclass 0x7f82617107f0
结果:

UITableViewLabel
   | UILabel
   |    | UIView
   |    |    | UIResponder
   |    |    |    | NSObject

2.14 pinternals

这个命令是打印对象的继承关系、对象属性、实例方法等详细信息,其中包括我们自定义的属性和方法。

输入: pinternals 0x7fde6681dc00
结果:(UITableViewCell) $5 = {
  UIView = {
    UIResponder = {
      NSObject = {
        isa = UITableViewCell
      }
      _hasOverrideClient = false
      _hasOverrideHost = false
      _hasInputAssistantItem = false
    }

    _constraintsExceptingSubviewAutoresizingConstraints = nil
    _cachedTraitCollection = 0x00006000000dc9a0
    _layer = 0x0000608000029be0
    _layerRetained = nil
    _gestureInfo = nil
    _gestureRecognizers = nil
    _window = 0x00007fde66006a90
    _subviewCache = 0x000060000005c920 @"2 elements"
    _templateLayoutView = nil
    _charge = 0
    _tag = 0
    _viewDelegate = nil
    _backgroundColorSystemColorName = 0x000060800005c110 @"tableCellPlainBackgroundColor"
    _countOfMotionEffectsInSubtree = 0
    _countOfTraitChangeRespondersInDirectSubtree = 3
    _cachedScreenScale = 3
    _layoutSubviewsCount = 0
    _retainCount = 4
    _tintAdjustmentDimmingCount = 0
    _shouldArchiveUIAppearanceTags = false
    _wantsDeepColorDrawing = true
    _interactionTintColor = nil
    _layoutMarginsGuide = nil
    _minXVariable = nil
    _minYVariable = nil
    _boundsWidthVariable = nil
    _boundsHeightVariable = nil
    _layoutEngine = nil
    _layoutDebuggingIdentifier = nil
    _stashedLayoutVariableObservations = nil
    _internalConstraints = nil
    _continuousCornerRadius = 0
    _countOfFocusedAncestorTrackingViewsInSubtree = 0
    _semanticContentAttribute = 0
    _contentSizeNotificationToken = 0x000060800005c2f0
    _readableContentGuide = nil
    __preferedContentsFormat = 0
    _previewingSegueTemplateStorage = nil
    __presentationControllerToNotifyOnLayoutSubviews = nil
  }
  _tableView = nil
  _layoutManager = 0x0000608000002520
  _target = nil
  _editAction = <no value available>
  _accessoryAction = <no value available>
  _oldEditingData = nil
  _editingData = nil
  _rightMargin = 0
  _indentationLevel = 0
  _indentationWidth = 10
  _reuseIdentifier = 0x0000000107074b10 @"Cell"
  _floatingContentView = nil
  _lineBreakModeBeforeFocus = 0
  _contentView = 0x00007fde66002050
  _imageView = nil
  _textLabel = 0x00007fde6600e3e0
  _detailTextLabel = nil
  _backgroundView = nil
  _selectedBackgroundView = nil
  _multipleSelectionBackgroundView = nil
  _selectedOverlayView = nil
  _selectionFadeDuration = 0.5
  _backgroundColor = 0x000060800007d5c0
  _separatorColor = 0x0000600000077640
  _separatorEffect = nil
  _topShadowColor = 0x000060800005c170
  _bottomShadowColor = 0x000060800005c1a0
  _sectionBorderColor = 0x0000600000077640
  _floatingSeparatorView = nil
  _topShadowAnimationView = nil
  _bottomShadowAnimationView = nil
  _badge = nil
  _unhighlightedStates = 0x0000000000000000
  _highlightingSupport = nil
  _selectionSegueTemplate = nil
  _accessoryActionSegueTemplate = nil
  _accessoryActionPreviewingSegueTemplateStorage = nil
  _accessoryView = nil
  _editingAccessoryView = nil
  _customAccessoryView = nil
  _customEditingAccessoryView = nil
  _separatorView = 0x00007fde63f089a0
  _topSeparatorView = nil
  _topShadowView = nil
  _editableTextField = nil
  _lastSelectionTime = 0
  _deselectTimer = nil
  _textFieldOffset = 114
  _indexBarWidth = 0
  _returnAction = <no value available>
  _selectionTintColor = 0x0000608000055cf0
  _accessoryTintColor = nil
  _reorderControlImage = nil
  _menuGesture = 0x00007fde6600e070
  _representedIndexPath = nil
  _focusable = false
  _swipeToDeleteConfirmationView = nil
  _swipeToDeleteCancelationGesture = nil
  _clearBlendingView = nil
  _swipeToDeleteDistancePulled = 0
  _sectionCornerRadius = 0
  _sectionBorderWidth = 0
  _defaultMarginWidth = 20
  _editControlFocusGuide = nil
  _reorderControlFocusGuide = nil
  _constants = 0x0000600000002410
  _isLayoutEngineSuspended = false
}

3. 自定义命令

我们也可以自定义插件,不过前提是要懂一些 python。 比如设计一个打印keyWindow的windowLevel的命令:

创建python脚本文件 /magical/commands/example.py :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/python
# Example file with custom commands, located at /magical/commands/example.py

import lldb
import fblldbbase as fb

def lldbcommands():
  return [ PrintKeyWindowLevel() ]

class PrintKeyWindowLevel(fb.FBCommand):
  def name(self):
    return 'pkeywinlevel'

  def description(self):
    return 'An incredibly contrived command that prints the window level of the key window.'

  def run(self, arguments, options):
    # It's a good habit to explicitly cast the type of all return
    # values and arguments. LLDB can't always find them on its own.
    lldb.debugger.HandleCommand('p (CGFloat)[(id)[(id)[UIApplication sharedApplication] keyWindow] windowLevel]')

其中定义了PrintKeyWindowLevel的类,需要实现 name descriptionrun 方法来分别告诉名称、描述、和执行实体。

创建好脚本后,然后在前面安装时创建的 ~/.lldbinit文件中添加一行:

1
script fblldb.loadCommandsInDirectory('/magical/commands/')

然后重启Xcode之后就可以使用自定义的命令啦。

参考文献:

Chisel官方说明

与调试器共舞 – LLDB 的华尔兹


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Chisel是一种用于硬件描述语言(HDL)的工具,可用于设计和验证硬件电路。要安装Chisel,首先需要在计算机上安装Scala编程语言和SBT构建工具。 首先,我们需要安装Scala。打开终端或命令提示符,并输入以下命令: ``` sudo apt-get update sudo apt-get install scala ``` 这将新软件包列表并安装Scala。 接下来,我们需要安装SBT。继续在终端或命令提示符中输入以下命令: ``` echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | sudo tee /etc/apt/sources.list.d/sbt_old.list sudo apt-get update sudo apt-get install sbt ``` 这将添加SBT存储库并安装SBT。 一旦Scala和SBT安装完成,我们就可以开始安装Chisel了。打开终端或命令提示符,进入您希望安装Chisel的目录,并输入以下命令: ``` sbt new freechipsproject/chisel-template.g8 ``` 这将从Github下载Chisel模板。下载完成后,进入新创建的目录,并输入以下命令: ``` sbt run ``` 这将编译并运行Chisel项目。现在您已成功安装Chisel并可以开始使用它来设计和验证硬件电路了。 总结起来,安装Chisel需要先安装Scala和SBT,然后使用SBT下载Chisel模板并编译运行项目。 ### 回答2: Chisel是一种用于硬件描述语言(HDL)的开源工具,它允许我们使用高级别语言编写硬件电路并生成相应的Verilog代码。安装Chisel可以帮助我们方便地进行硬件设计和开发。 首先,我们需要确保我们的计算机上已经安装了几个必要的软件和工具。这些包括Java Development Kit(JDK)、Scala和sbt(一个构建工具)。 然后,我们可以从Chisel的官方GitHub存储库中下载代码。我们可以通过克隆存储库或直接下载ZIP文件来获取它。 接下来,我们需要设置环境变量来引用下载的Chisel代码。我们可以通过在终端中执行以下命令来设置环境变量: export CHISEL_HOME=/path/to/chisel 确保将"/path/to/chisel"替换为实际存储Chisel代码的文件夹的路径。 然后,我们需要进入Chisel代码文件夹并构建工具链。我们可以在终端中执行以下命令: cd $CHISEL_HOME sbt compile 这将编译Chisel并生成运行所需的工具。 最后,我们可以通过运行一个示例项目来验证Chisel是否成功安装。我们可以在终端中执行以下命令: sbt "runMain edu.chisel.example.<ExampleClassName>" 确保将"<ExampleClassName>"替换为实际示例项目的类名。 如果一切顺利,我们将在终端中看到示例项目的输出。 总结来说,Chisel的安装过程涉及下载代码、设置环境变量、构建工具链,并验证安装是否成功。这样,我们就可以开始使用Chisel进行硬件设计和开发了。 ### 回答3: Chisel 安装指的是在计算机上安装并配置 Chisel 编程语言的过程。以下是关于 Chisel 安装的一些说明。 首先,要安装 Chisel,你需要确保你的计算机上已经安装了 Java Development Kit(JDK),因为 Chisel 是基于 Java 开发的。你可以从 Oracle 官方网站下载并安装最新版本的 JDK。 一旦你完成了 JDK 的安装,你可以开始安装 Chisel。Chisel 最简单的安装方法是通过 sbt(Simple Build Tool)进行。sbt 是用于构建和管理 Scala 项目的工具。你可以从 sbt 的官方网站下载并安装最新版本的 sbt。 当你完成了 sbt 的安装后,你可以创建一个 Chisel 项目。首先,你需要使用 sbt 命令行工具进入项目保存的目录。然后,你可以使用 "sbt new freechipsproject/chisel-template.g8" 命令来创建一个新的 Chisel 项目。 一旦项目创建成功,你可以进入项目文件夹并编辑 src/main/scala 目录下的 .scala 文件来编写 Chisel 代码。Chisel 提供了许多工具和库来帮助你创建硬件描述。 编写完代码后,你可以使用 sbt 命令来编译和运行你的 Chisel 项目。你可以使用 "sbt compile" 命令来编译项目,使用 "sbt run" 命令来运行项目。 总结来说,Chisel 的安装过程包括安装 JDK、安装 sbt、创建 Chisel 项目、编写 Chisel 代码以及使用 sbt 编译和运行项目。安装完成后,你就可以开始使用 Chisel 编程语言来创建硬件描述和进行硬件设计了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值