相关文章推荐
叛逆的山楂  ·  调试 JavaScript 或 ...·  2 月前    · 
憨厚的小马驹  ·  about_Debuggers - ...·  2 月前    · 
面冷心慈的保温杯  ·  招远市政府公示公告关于2024年度招远市拟推 ...·  11 月前    · 
年轻有为的楼房  ·  Arduino IDE 搭建ESP8266 ...·  1 年前    · 
讲道义的闹钟  ·  2021年北京城市学院招生章程-北京城市学院招生网·  1 年前    · 
独立的饺子  ·  我们的身体-当当网·  1 年前    · 
霸气的大蒜  ·  房产家居室内设计公众号推文排版素材(家装设计 ...·  1 年前    · 
Code  ›  lldb 入坑指北(1) - 给Xcode批量添加启用&禁用断点功能开发者社区
命令模式 python函数 xcode 断点
https://cloud.tencent.com/developer/article/1796756
火星上的蚂蚁
1 年前
作者头像
酷酷的哀殿
0 篇文章

lldb 入坑指北(1) - 给Xcode批量添加启用&禁用断点功能

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > 酷酷的哀殿 > lldb 入坑指北(1) - 给Xcode批量添加启用&禁用断点功能

lldb 入坑指北(1) - 给Xcode批量添加启用&禁用断点功能

作者头像
酷酷的哀殿
发布 于 2021-03-03 15:34:35
622 0
发布 于 2021-03-03 15:34:35
举报

前言

为了避免浪费你的时间,在阅读本文前,请先思考以下问题:

  • 你是否经常使用 Xcode 的断点功能?
  • Xcode 的断点功能好用吗?
  • 如果给 Xcode 批量添加启用&禁用断点功能,是否会提高你的工作效率?

如果都是 NO ,那么,请先阅读 与调试器共舞 - LLDB 的华尔兹[1] 后再回来阅读本文章。相信我,掌握甚至精通 lldb 能够快速的提供你的生产力。

如果以上问题都是 YES ,那么,欢迎继续阅读以下内容。

阅读本文需要以下技能:

  • 对 Python 有基本的了解
  • 对 Xcode 的断点功能有基本的了解(相关的文档可以参考 Xcode 断点文档[2] )

通过本文,希望大家可以了解以下内容:

  • 了解 lldb 的 API 架构
  • 通过 lldb 相关 API,构建自己的效率工具(Python 脚本)

入门

LLDB

LLDB 是一个开源调试器,它已经被内置在 Xcode 程序中。如下图所示,位于主窗口的底部,名为 Conseole 的窗口就是用于和 lldb 交互的区域。

x

断点

首先,我们先通过以下步骤对 lldb 进行初步的了解。

  • 创建一个程序
  • 在 viewDidLoad 处添加添加断点
  • 运行程序,并使程序停在断点处
  • 在 Console 区域输入 po self 并回车
  • 观察输出结果

当程序暂停后(通过断点或者手动点击暂停按钮),Console 区域就会进入 lldb 模式。 po self 是指把 self 当做一个对象进行打印,类似的还有 p self 等命令。

ps. 通过 help 命令,可以打印所有的可用命令。pss. 通过 help po 命令,可以打印该命令的用法。

Chisel

Chisel 是一个 Python 脚本集合,建议读者先阅读 与调试器共舞 - LLDB 的华尔兹 后再看下面的部分

进阶

再看 LLDB

LLDB 的调试接口本质上是一个 C++ 共享库,在 Mac 系统上,它被打包为 LLDB.framework(正常情况下,我们可以 /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework 路径看到它),在类 unix 系统上,它是 lldb.so。这些调试接口可以在 lldb 的脚本解释器内直接使用,或者可以被引入 lldb.py 模块的 Python 脚本使用。

LLDB 本身支持用户自定义命令,比如通过脚本可以自定义一个 pviews 命令,该命令可以打印 APP 所有的视图。

该命令已经在 Chisel 中实现。

lldb 脚本入门

首先,我们先通过一个非常简单的脚本,构造一个自定义命令。

创建脚本

在~/ls.py 位置创建一个脚本,内容如下:

import lldb
import subprocess
def ls(debugger, command, result, internal_dict):
    print(command)
    ret = subprocess.getstatusoutput('ls ' + command)
    for i in ret[1].split("\n"):
        print(i)
def __lldb_init_module(debugger, internal_dict):
    debugger.HandleCommand('command script add -f ls.ls ls')
    print ('The "ls" python command has been installed and is ready for use.')

在 lldb 中载入脚本

(lldb) command script import ~/ls.py

执行命令

    (lldb) ls ./
  Applications
    Users

到此为止,我们已经成功的实现了一个自定义的命令。

OK,让我们重新解释一下上面的代码。

    command script import ~/ls.py

command 是 lldb 用于管理自定义命令的一个入口。

command script import 可以导入一个自定义的脚本文件。

    def __lldb_init_module(debugger, internal_dict):
        debugger.HandleCommand('command script add -f ls.ls ls')
        print 'The "ls" python command has been installed and is ready for use.'

脚本文件被导入时,并且 def __lldb_init_module(debugger, internal_dict): 方法会被检测到时,它会被自动调用。我们可以在这里一次性实现多个自定义命令。

debugger 是 lldb.SBDebugger lldb.SBDebugger-class[3] 的一个实例,代表了当前的调试器对象。

internal_dict 包含了当前脚本会话的变量和方法。

HandleCommand 是一个实例方法,通过它,我们可以在 Python 脚本里面,调用 lldb 的方法。比如,这里的 command script add -f ls.ls ls

command script add -f ls.ls ls 的含义是“声明一个自定义的命令 ls ,这个命令的实现是 ls.ls ”。 command script add -f 函数名 自定义命令名 -f 代表后面跟着一个函数名,类似还有 -c ,代表一个 Python 类。

import lldb
import subprocess
def ls(debugger, command, result, internal_dict):
    print(command)
    ret = subprocess.getstatusoutput('ls ' + command)
    for i in ret[1].split("\n"):
        print(i)

debugger 上面已经讲过,不再赘述。

command 是一个字符串,是我们命令的参数。以我们在 lldb 输入 ls -l var 为例, command 是 -l var 。

result 是 lldb.SBCommandReturnObject 的实例。

internal_dict 上面已经讲过,不再赘述。

这个函数是我们自定义命令的核心,它通过调用 Python 模块 subprocess 的 getstatusoutput 方法,获取 ls 命令的输出结果,并打印到结果中。

批量管理断点

通过上面的介绍,相信我们很容易实现一个批量管理断点的自定义命令。

这里简单分享一下思路。

  • 注册两个自定义命令作为入口, benable & bdisable
  • 通过一个函数实现状态的控制 def switchBreakpointState(expression,on):
  • 遍历断点和 location,当 location 符合要求时,切换断点和 location 的状态。

完整源码

#!/usr/bin/python
import lldb
import optparse
import shlex
import re
def switchBreakpointState(expression, on):
    expression_pattern = re.compile(r"{}".format(expression), re.I)
    target = lldb.debugger.GetSelectedTarget()
    for breakpoint in target.breakpoint_iter():
        if breakpoint.IsEnabled() != on and (
            expression_pattern.search(str(breakpoint))
            print(str(breakpoint))
            breakpoint.SetEnabled(on)
        for location in breakpoint:
            if location.IsEnabled() != on and (
                expression_pattern.search(str(location))
                or expression == hex(location.GetLoadAddress())
                print(str(location))
                location.SetEnabled(on)
def benable(debugger, command, result, internal_dict):
    switchBreakpointState(str(command),True)
def bdisable(debugger, command, result, internal_dict):
    switchBreakpointState(str(command),False)
 
推荐文章
叛逆的山楂  ·  调试 JavaScript 或 TypeScript 应用 - Visual Studio (Windows) | Microsoft Learn
2 月前
憨厚的小马驹  ·  about_Debuggers - PowerShell | Microsoft Learn
2 月前
面冷心慈的保温杯  ·  招远市政府公示公告关于2024年度招远市拟推荐参加烟台市事业单位 ...
11 月前
年轻有为的楼房  ·  Arduino IDE 搭建ESP8266 开发环境及项目演示- rollingstarky - 简书
1 年前
讲道义的闹钟  ·  2021年北京城市学院招生章程-北京城市学院招生网
1 年前
独立的饺子  ·  我们的身体-当当网
1 年前
霸气的大蒜  ·  房产家居室内设计公众号推文排版素材(家装设计文案宣传模版 ...
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号