llvm学习(十六):lldb脚本API和整体设计

从零开始的 lldb 脚本开发。系列第二篇,讲API和整体设计。

lldb python API简介

首先需要明确一点,swig 是连接 cpp 和 python 的桥梁,脚本最终调用到 cpp 的 API,因此可以将 python 对象理解为一个 cpp 里的指针,指向一个 cpp 的对象。还有一种不直接返回指针,而是返回一个 accessor,例如 modules_access,使用起来区别不大,开发时稍微注意一下就行。

根据官方文档和日常的经验,下面几个对象最为常见,这里强烈建议阅读 https://lldb.llvm.org/use/python-reference.htmlEmbedded Python Interpreter 这一章节,本文也简单谈谈自己的理解。

这里我用简易的图来描述它们之间的关系,本质上就是层级关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|--------------------------------|
|SBDebugger |
| |
| |-------------------------|
| |SBTarget |
| | |
| | |-------------------|
| | |SBProcess |
| | | |
| | | |------------|
| | | |SBThread |
| | | | \-SBFrame |
| | | | \-SBFrame |
| | | | \-SBFrame |
|--------------------------------|

lldb对象

在 lldb.py 的最后几行,有如下的代码:

1
2
3
4
5
debugger = None
target = None
process = None
thread = None
frame = None

根据 python 的语法,我们可以使用 lldb.debuggerlldb.target 这样的方式来获取到这些 “全局变量”,实际上,这种使用方式是不完全可靠的。

When running under the script command, lldb sets some convenience variables that give you quick access to the currently selected entities that characterize the program and debugger state.
In each case, if there is no currently selected entity of the appropriate type, the variable’s IsValid method will return false. These variables are:

个人推荐两种写法:

  1. 使用 script 命令执行代码时,这些变量都是可用的
  2. 开发自定义插件时,只有 lldb.debugger 是可靠的,其他的变量经常为空或者不可用

class SBDebugger

SBDebugger类表示 lldb 本身,通过它可以做到:执行命令、找到 SBTarget。

根据开发经验,在绝大部分场景下,lldb.debugger 这个全局变量都可以找到这个实例。

class SBTarget

SBTarget 表示当前加载的文件,它表示的是文件本身,例如有文件的格式、节信息、启动参数等,通过它可以做到启动进程、找到正在运行的 SBProcess。

class SBProcess

SBProcess 表示单个进程,例如有进程运行状态、线程数量、是否停止等,通过它可以杀死进程、发送信号、查看内存、找到某个线程,例如找到触发了断点的那个 SBThread。

class SBThread

SBThread 表示单个线程,在断点触发时,可以找到断点对应的栈回溯,可以获得每一层的栈帧,即 SBFrame。

class SBFrame

SBFrame 表示一个栈帧,包括寄存器信息、栈上的变量信息等,是调试时最直接接触到的部分,包含很多调试时关注的信息。

class SBExecutionContext

它是一个比较特殊的类,在 stop-hook 回调时提供,包含我们最关心的四个对象,target、process、thread、frame。

整体设计

由此看来,lldb 设计非常条例,将运行状态层层展开,和开发者的思维过程基本一致,提供丰富的回调,为插件开发提供了便利。

emmmmm 这里编不下去了,只是觉得很优雅,还是有深刻理解再讨论它吧。