首页
社区
课程
招聘
[原创] QBDI 源码阅读笔记
发表于: 2025-7-21 00:58 7849

[原创] QBDI 源码阅读笔记

2025-7-21 00:58
7849

用的 Ubuntu 编译的 Linux 版本, android 版本也编译了, 不过为了方便调试还是用的 Linux, 两者编译有些许不同, 原理和代码一样.

长文预警! 长文预警! 长文预警!

感觉前后文联系很强, 写的比较细, 几乎是每个地方都刨根问底, 如果跳着看, 注意回看前文, 有些前面写了, 我就没在后面重复.

建议一个屏幕打开源码, 一个屏幕读文章. 这样可以自己亲身体会一下.

作者也是小白, 难免疏忽, 如有错误还请您指出.

94bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6c8b7V1c8u0i4K6u0r3f1f1u0p5d9b7`.`.

QBDI 实现了一个自己的 ir, 然后将要插桩的二进制指令与插桩代码统一翻译成自己的 ir, 然后借助 llvm 的组件转成对应架构二进制指令, 天才的构思. 接下来让我们一点点揭开它神秘的面纱.

跑一下 build/examples/ 中的可执行程序, 看看效果

可以正常跑, 好了现在开始阅读 example 目录下的代码, 首先看下 CMakeLists.txt, examples/CMakeLists.txt:

添加了 mnemonicFilter modules_c modules_cpp thedude_c thedude_cpp cryptolock_cpp cryptolock_c 可执行文件, 然后再看 examples/c/CMakeLists.txt:

创建 fibonacci_c 可执行文件和 tracer_preload_c 共享库. 斐波那契数列真是老演员了, 我们从这里开始看起, 上边的 c 语言示例同样讲解的这个代码, 我觉得官方文档写的真好, 我无论怎么讲都显得冗余, 但为了完整性, 我还是简单概括下:

进入 src/Engine/VM_C.cpp 中查看代码:

可以看到代码很简单, 就是处理参数, 返回了一个 VM 类的实例, 跟进去 VM 类看一下, 来到了 include/QBDI/VM.h 下, 整个文件都是这个类的定义, 支持了很多的方法, 因为太长所以只截了几张图:

我们看一下它的构造函数:

将参数传入到了 Engine 类中, 我们同样找一下 Engine 类初始化函数:

可以看到, 很复杂, 初始化了很多类, 我们暂时不分析, 继续往下看.

可以看到是在调用 VM 类中的 getGPRState 方法, 再跟入 engine->getGPRState 来到 src/Engine/Engine.cpp 中:

返回了 Engine 类 中的 curGPRState 属性, 让我们跟踪一下 curGPRState:

include/QBDI/arch/X86_64/State.h 中找到了 GPRState 结构体的定义:

可以看到在 include/QBDI/arch/ 下同样有其他架构的一些支持, 根据我们编译时运行的脚本 GPRState 等有不同的实现.

src/Engine/Engine.cppsrc/Engine/Engine.h 中实现了 Engine 类, 而 VM 类中的 engine 属性就是 Engine 类的实例. 我们不着急分析这些类, 而是分析这个斐波那契示例实现的过程, 慢慢的就明白这些类扮演了什么样的角色.

我按执行顺序从上往下贴的, 可以看到这段是为虚拟栈分配了内存空间, 并且再内存大小上做了对齐处理, 然后将虚拟寄存器中的栈指针, 帧指针赋值. (虚拟栈存在堆上, 虚拟寄存器存在寄存器中)

然后来到 src/Engine/VM_C.cpp 文件来看实现:

与上边的 qbdi_getGPRState 类似, 还是调用 VM 类中的方法, 我们接着往下看, 跟入 addCodeCB 方法:

一点点看, 首先是 True::unique(), 跟进去:

发现就是一个模板工具类, 用来快速创建 unique_ptr 只能指针(这个指针的使用与 rust 中的所有权转移类似, 一个 std::unique_ptr 对象在任何时刻只能拥有一个指向动态分配对象的指针. 它不允许拷贝构造或赋值, 但可以通过 std::move 将所有权从一个 std::unique_ptr 转移到另一个), 现在我们疑惑的是 AutoUnique 这个模板类在 True::unique 调用时 typename T, typename U 是什么, 为此我们还要跟入 True 类一探究竟:

在跟入 AutoClone<PatchCondition, True>:

看到这, 我们可以知道 T 类型是 PatchCondition, U 类型是 True, 而 AutoClone AutoUnique 模板类相当于插入继承链, 本来是 True 类继承 PatchCondition 类变为了 True 继承 AutoClone 继承 AutoUnique 继承 PatchCondition. 而 True::unique(address) 创建的也就是一个类型为 True 的智能指针, 而翻回头来 InstrRuleBasicCBK::unique 也是类似的实现:

好了现在我们可以回过头来跟入 engine->addInstrRule 函数了:

把插桩规则的个数 instrRulesCounter 作为 id 返回, 并规定了最大个数 id < EVENTID_VM_MASK, 再看 this->clearCache(rule->affectedRange()), 先跟入 rule->affectedRange(如果跳转错误, 也可以搜索 InstrRuleBasicCBK::affectedRange):

InstrRuleBasicCBK 的 condition 属性就是 True::unique(), 而 True 类继承自 PatchCondition, 在跟入 condition->affectedRange, 就到了 PatchCondition 类中:

RangeRangeSet 太长了, 说下作用, 不在贴出代码, 感兴趣可以到 include/QBDI/Range.h 中自行查看:

回到 Engine::addInstrRule 函数中来看剩余这部分:

std::make_pair 创建了一个 std::pair 对象, 将 id 和 rule 组合在一起. std::upper_bound 是一个标准库函数, 用于在有序范围内找到第一个不满足给定条件的元素. 而 instrRulesstd::vector<std::pair<uint32_t, std::unique_ptr<InstrRule>>> 类型, 所以这段代码就是将 rule 插入到 instrRules 中第一个优先级小于或等于 rule 的优先级的位置. 使得 instrRules 中的规则始终按照优先级从高到低.

总结一下 qbdi_addCodeCB 函数就是创建插桩规则然后按输入的优先级存起来. 其中插桩规则保存了回调函数, 插桩位置, 用户参数...具体可以看 InstrRuleBasicCBK 类的构造函数.

二话不说跟进 addMnemonicCB:

可以看到和 qbdi_addCodeCB 函数实现唯一的差别就是 True::unique() 变为了 MnemonicIs::unique(mnemonic). mnemonic 就是咱们传进来的出发回调的特定指令, 在斐波那契这个示例中就是 "CALL*". 而 MnemonicIs 类与 True 类似:

看到这结合上面不难猜测 TrueMnemonicIs 类都是用来判断回调条件的, 而这个 test 虚函数就是判断的统一调用. 所以我们在来看看 MnemonicIs::test:

我们先来看看第一个参数的类型 Patch 类, 跟入来到了 src/Patch/Patch.h 中, 代码不长, 将头文件注释:

在跟进 llvmcpu.getInstOpcodeName 看一眼:

看样子是在返回反汇编指令, 行, 这里先打住, 乱猜也是浪费时间, 接下往下看.

从上到下一步步跟入, execBroker 是 Engine 类的一个属性 ExecBroker *execBroker, 也是 ExecBroker 类的实例, 我们继续跟入 execBroker->addInstrumentedModuleFromAddr 函数:

看函数的名字就很容易知道在做什么, 写出注释. 首先先看看 getCurrentProcessMaps 函数, 来到了 src/Utility/Memory_linux.cpp 中, 还是会根据你编译的架构确定函数实现, 在同级目录下同样有其他架构的实现:

闲话少说来看看 getCurrentProcessMaps 函数的实现:

也就是通过 Linux 系统调用 getpid() 获取当前进程的 pid, 然后通过读取 /proc/[pid]/maps 文件获取内存映射, 然后将每条映射存进 std::vector<MemoryMap> maps 中.

在来看 addInstrumentedModule(回看一下上面的 ExecBroker::addInstrumentedModuleFromAddr 函数):

代码很简单就是将找到 name 对应的内存映射, 然后将映射的地址 保存到 ExecBroker 类的 instrumented 属性中. (我真要控制你了, 又调用 getCurrentProcessMaps() 遍历一遍)

好了, 现在再看这个函数感觉一切都明了了(再自己回顾一遍):

头文件的注释:

再来看具体实现:

va_start(ap, argNum) 处理可变参数, 参数存在 ap 中(随机提问, 在汇编层是如何实现可变参数的? 事实上只要知道可变参数的起始地址, 知道参数个数, 调用约定就可以顺藤摸瓜一点点找过去), 跟进 callV 函数:

将可变参数传入列表中在调用 callA, 继续跟入 callA:

首先检测栈指针, 然后调用 simulateCallA(看注释的意思是处理参数, QBDI_GPR_GET 在上边贴过源码, 忘记的话可以自己看一下), 跟进去:

根据目标架构的调用约定, 将参数加载到寄存器或栈中, 不同的架构有不同的处理方式, FRAME_LENGTH 决定了栈帧可以容纳的最大参数数量(一般来说, 在各个架构的调用约定中, 参数先通过寄存器传参, 然后再通过栈传参). 回过头再来看看 run:

首先看看设置的回调函数 stopCallback:

再跟入 addCodeAddrCB 中:

似曾相识的感觉有没有, 注册回调函数?!(忘记的朋友可以翻一翻上边). 有了上边的经验, 我们直接看 AddressIs:

如果我没记错的话 AddressIs::unique(address) 中的 address 应该是 42, 上边 #define FAKE_RET_ADDR 42 定义的. 带着疑问, 我们回到 VM::run, 跟入 bool ret = engine->run(start, stop)(等下, 我要再帮你回忆一下, start 是我们要插桩的函数的地址, stop 是注册回调返回的回调 id):

一个很长的函数, 让我们一点点看吧, 首先是 QBDI_REQUIRE_ABORT(not running, "Cannot run an already running Engine") 确保引擎当前没有在运行. 然后是 rword currentPC = start, 将 PC 指向了目标函数地址. 然后 curGPRState = gprState.get() 获取当前通用寄存器, curFPRState = fprState.get() 获取当前浮点寄存器, gprStatefprState 都是 Engine 类的属性:

GPRState 结构体的定义可以在前面找到, FPRStateGPRState 类似, 同样在 include/QBDI/arch/X86_64/State.h 中, 每个架构有不同的实现:

接着往下看:

还记得 execBroker, Engine 中存的 ExecBroker 实例, 我们用这个 ExecBroker 类记录了插桩的作用范围, 这里就是在检查目标函数地址是否在指定范围中, 不在的话直接返回. 再接着:

running 属性设置 true, 表示正在运行, 然后进入一个 do-while 大循环, 直到当前 PC 指针 currentPC 为 传进来的回调函数 id stop. 好了, 是时候进入主逻辑, 也就是这个 do-while 大循环, 先是 VMAction action = CONTINUE, 哦, 状态机? 我们跟进这个枚举看一看:

接着往下看, 一个大的 if-else:

看注释很容易理解, if 中处理了 currentPC 不在插桩范围内的情况, else 是执行, 我们先看 else 掌握执行的主要逻辑, 再来看 if 中的逻辑. 首先是 VMEvent event = VMEvent::SEQUENCE_ENTRY, 还是跟入枚举对象:

再回过头来看这段:

在 ARM 架构时, 区分 ARM 模式(32 位指令集)和 Thumb 模式(16 位指令集). 在往下看:

检查是否有待处理的缓存刷新操作, 更新缓存的 gprStatefprState 为当前值. 首先明确 blockManager 属性是 std::unique_ptr<ExecBlockManager> 类型, 也就是 ExecBlockManager 类的智能指针. 再看一下 isFlushPending:

没什么好说的, 再看一下 flushCommit:

我们需要关注两个属性 regionscodeBlockMap, 首先是 std::vector<ExecRegion> regions, 看 ExecRegion 类(比较短就贴出了):

再来看 std::map<rword, ExecBlock *> codeBlockMap, 也就是 ExecBlock 类, 非常的长, 在 src/ExecBlock/ExecBlock.h 文件中, 可以自行查看完整的实现:

它通过两块连续内存(代码块 codeBlock + 数据块 dataBlock)存储和运行插桩后的基本块, 同时提供执行控制、内存管理、记录等功能.

我们同样再找一下 ExecBlockManager 类的构造:

有个印象就行, 直到大概初始化了什么.

在回过来往下看:

看注释像是在检查能不能用缓存, 我们第一次执行到这, 肯定没有, 不过我们还是分析一下, 首先让我们先看看参数 currentPC 现在的值是 strat 也就是目标函数的地址, 然后 curCPUModeEngine 类的 CPUMode curCPUMode 属性, 让我们看一下 CPUMode 是什么:

还是在 include/QBDI/arch/X86_64/State.h 中的一个枚举, 代表了 cpu 状态

在看看 currentSequence 的类型 SeqLoc:

看样子是一个表示位置的结构体, 好了现在跟入 blockManager->getProgrammedExecBlock:

又是一个很长的函数, 先跟入 searchRegion:

一个二分查找, 找到 address 所在的块的下标返回(regions 类型上面有讲过, 可以回看), 这样的话 regions 这个 vector 中存储的块的执行地址就是按循序排列的.

再回到 getProgrammedExecBlock, 往下看, 如果找到了就进入 if 逻辑, 否则返回一个 nullptr, 我们看一下 if 逻辑:

根据注释, 我们大概知道它的逻辑, 但是为了弄清楚还是关注几个点. 首先跟入 getExecRegionKey:

将地址在 arm 结构时做特殊处理, 不再赘述. 再看一眼 region.sequenceCache 的类型: std::map<rword, SeqLoc> sequenceCache, 一个地址与 SeqLoc 结构体(前面贴出过代码)的映射.

往下看, 看到 region.blocks[seqLoc->second.blockIdx]->selectSeq(seqLoc->second.seqID) 我们就大概明白 SeqLoc 结构体了, 它记录了指令序列的起始 seqStart 与结束 seqEnd 的地址, 以及所在 blocks 的索引 blockIdx, 自身的 id seqID, 所在块结束的地址 bbEnd. (还是贴出来, 方便你看):

可以再看下 selectSeq 函数:

看一下 seqRegistry 的类型: std::vector<SeqInfo> seqRegistry, 也就是说 seqID 实际上是 seqRegistry 中的下标, 看一下 SeqInfo:

再看一下 instRegistry 的类型: std::vector<InstInfo>, 还是一个 vector, 看 InstInfo:

好了, 现在可以理一理了, SeqLoc 记录了指令序列的位置以及 seqID, 根据 seqID 可以作为 seqRegistry 的下标找到 SeqInfo, 姑且称之为序列详情(根据这句代码 currentInst = seqRegistry[currentSeq].startInstID), 而用 SeqInfo 中的 startInstIDendInstID, 可以作为 instRegistry 属性的下标找到 InstInfo, 姑且称之为指令详情(根据这句代码 static_cast<rword>(instRegistry[currentInst].offset). 每个结构体还额外记录了很多信息. 而 ExecBlock::selectSeq 函数就是将当前块(ExecBlock 的实例)的一些属性设置成 seqID 对应的, 包括 currentSeq 当前序列, currentInst 当前指令, context->hostState.selector 上下文中的选择子, context->hostState.executeFlags 上下文中的执行标志.

回到 if 逻辑, 继续看 const auto instLoc = region.instCache.find(target), 找到 instCache 属性的类型 std::map<rword, InstLoc>, 看 InstLoc:

简直就是 sequenceCache 的翻版, 不在多说, 来看 block->getSeqID 函数:

多少有点循环链表的意思了, block->getSeqStart 也是类似:

再看 block->getInstMetadata:

使用了 instMetadata 属性, 我们来看看它的类型 std::vector<InstMetadata> instMetadata, 跟入 InstMetadata 类:

InstMetadata 存储了指令的很多信息.

再来看看 block->splitSequence:

构造 SeqInfo 实例, 存入 seqRegistry 中. 到此我们弄清楚了 getProgrammedExecBlock 的全部流程, 在回看一遍, 自己理一理.

回到 Engine::run 接着往下看:

这里就是处理缓存中没有时的逻辑, 整体看一下, 从名字也大概知道, handleNewBasicBlock(currentPC) 是生成新块, event |= BASIC_BLOCK_NEW 记录事件, blockManager->getProgrammedExecBlock 是刚刚看过的读取当前块. 所以我们重点看 handleNewBasicBlock:

先进入 patch:

通读一遍后, 我们可能已经知道它在做什么了, 还是补充说明几个点. llvm 部分我们不在刨根问底, 因为这篇写的已经够多了, llvm 的源码阅读放在别的文章.

先从 execBroker->getInstrumentedRange().getElementRange(start) 开始, execBroker 是我们的老朋友了(在上面获取内存 map, 设置插桩范围时就是它), execBroker->getInstrumentedRange:

instrumented 这个属性就存储了插桩的范围, 不记得的回看一下之前的分析, 在看 getElementRange:

返回了当前的 Range 用于计算块大小等, 再来看 llvmcpu.getInstruction:

LLVMCPU 这个类对 QBDI 需要的 llvm 中的功能做了封装, 在 src/Engine/LLVMCPU.h 中:

disassembler 属性类型为 std::unique_ptr<llvm::MCDisassembler>, 让我介绍一下:

disassembler->getInstruction 是 llvm api, 我们简单看一下头文件的注释:

再来看看 showInst:

asmPrinter 属性的类型是 std::unique_ptr<llvm::MCInstPrinter>, 让我介绍一下:

MSTI 属性类型是 std::unique_ptr<llvm::MCSubtargetInfo>, 让我介绍一下:

看看 asmPrinter->printInst 的注释:

回到 Engine::patch 我们接着看, patchRuleAssemblyEngine 类的属性, 是 PatchRuleAssembly 类的实例, 在上面 Engine 类构造函数中有: patchRuleAssembly = std::make_unique<PatchRuleAssembly>(options), 再来看 patchRuleAssembly->generate:

还记得这个函数的参数是什么吗? instllvm::MCInst 的实例, 存储解析出的机械指令, address 是指令地址, instSize 指令大小, llvmcpu llvm 方法封装, patchList 储存返回的地址.

看上去逻辑很明了. 用传进来的参数构建 Patch 实例, 然后用已有的 patch 规则处理这个实例, 然后处理可以合并的 patch. 但是已有的补丁规则 patchRules 是哪来的, 顶着头顶上的问号, 我们找一找, patchRulesPatchRuleAssembly 的属性, 我们找到 PatchRuleAssembly 的构造函数:

跟入 getDefaultPatchRules, 一个巨无霸函数:

这个函数位于 src/Patch/X86_64/PatchRuleAssembly_X86_64.cpp 中, 对于不同的架构有不同的实现:

这个函数我们要仔细分析一下, 先来看 PatchRule 类, 在 src/Patch/PatchRule.h 中:

我们看看 canBeApplied 方法实现:

和前面对上了, 还记得前面的注册回调函数的 TrueMnemonicIs 类吗, 由各种子类实现 test 虚函数, 然后由 canBeApplied 调用.

apply 有些复杂, 留在后再调用时在分析. 回到 getDefaultPatchRules, 再来看 conv_unique 方法:

模板处理可变参数, 这个应该很经典, 那么 conv_unique 函数就是将传入的未知格式参数压入 vector, 然后返回 vector(随机提问: 模板处理可变参数在汇编层的实现?)

再往下看, 我们看到了各种 GetPCOffset::unique SubstituteWithTemp::unique ModifyInstruction::unique SetOpcode::unique.......他们就是 QBDI 的 ir. 我们随便找一个规则解读一下:

这是对 JMP *[RIP + IMM] 的转换, 用 QBDI 的 ir 去实现. rulesstd::vector<PatchRule> 类型, 也就是说 emplace_back 进去的会被用来构造 PatchRule, 还记 PatchRule 的构造吗:

第一个是判断知否执行的条件, 第二个是执行的 ir. 先看条件:

从名字上也很容易看出来: 指令是 llvm::X86::JMP64m 并且使用 PC 寄存器. 我们直接看 OpIs 类:

patch.metadata.inst.getOpcode() 是 llvm 的 api, 一看就懂, 不在赘述. OpIs 类就是用来判断汇编指令的, 也就是操作码. 再看 UseReg:

UseReg 类检查指令是否使用了指定的寄存器. 再看 And 类:

就是将传入的条件们包装起来, 然后在 test 实现中, 使用 std::all_of 要所有的条件都返回 true 才是 true,

条件实现都在 src/Patch/PatchCondition.h src/Patch/PatchCondition.cpp 中. 条件判断的类都继承了 PatchCondition 类, 包括上面回调函数的也是, PatchCondition 类在上面贴出了, 不在重复, 子类都要实现 test 这个核心的虚函数.

然后是生成 QBDI 的 ir, 围绕着这个注释讲:

首先是 Temp(0) := RIP + Constant(0) 对应 GetPCOffset::unique(Temp(0), Constant(0)), 先看看 Temp:

可以看到就是包装了一层, 像 Constant, Operand 等也是类似, 都是包装一层赋予一定含义, 我们不在意义查看, Reg 类略有不同, 贴出注释:

再跟进 GetPCOffset:

首先我们关注的是它的父类 PatchGenerator 类:

不出意外, 应该是每个 QBDI ir 生成类都是 PatchGenerator 的子类, 并且都位于 src/Patch/PatchGenerator.h src/Patch/PatchGenerator.cpp 中, generate 应该是生成 ir 的核心虚方法.

接下来看一下 GetPCOffset::generate 的实现:

根据是传入的是常量还是操作数, 由不一样的调用:

可以看到最终都是调用 LoadImm::unique, 我们先不着急跟进去, 先看看 patch.metadata.endAddress:

获取指令结束地址, patch.metadata.instllvm::MCInst 的实例, 还记得吗, 咱们之前调用 llvm api 解析出来的. op 是操作数索引, patch.metadata.inst.getOperand(op).getImm() 就是调用 llvm api 获取索引对应的 操作数.

现在跟进 LoadImm, 来到 src/Patch/RelocatableInst.h 中:

同样先看看父类 RelocatableInst:

看名字是用来构建重定位指令.

现在看看 LoadImm 的两个虚方法, 在 src/Patch/X86_64/RelocatableInst_X86_64.cpp 文件中, 同样是根据架构改变:

看到着我们大概就知道了, 这个就是用来赋值的, mov 指令, 也就是组成了 Temp(0) := RIP + Constant(0), 即如下伪代码:

我们跟入 mov64ri, mov64ri32, mov32ri:

可以看到是在构造对应的 llvm::MCInst 实例返回. 好了这里我们全部理清了.

接下来看看下一条的实现 JMP *[RIP + IMM] --> MOV Temp(1), [Temp(0) + IMM]:

首先是 ModifyInstruction:

来看看 generate 方法:

And 类似, 调用传入的 transforms 中每个实例的 transform 方法, 将当前汇编指令的信息传入.

然后看看传入的 transformsSubstituteWithTemp开始, 在 src/Patch/InstTransform.h中:

它的父类 InstTransform:

与之前的类似. 让我们来看看 SubstituteWithTemp::transform

放到我们这个例子中, 也就是将 JMP *[RIP + IMM] 中的 RIP 换成 Temp(0) 成了 JMP *[Temp(0) + IMM].

也就是说为之前这个 Temp(0) 临时对象分配一个真实的寄存器, TempManager 类也就是用来管理临时寄存器的以及这种映射关系的, 篇幅原因, 我们不在细看, 并不复杂, 感兴趣的朋友可以自行查看.

再回头看:

跟入 SetOpcode 类:

这个简单粗暴, 直接将汇编指令种类替换, 即由 JMP *[Temp(0) + IMM] 变为 MOV *[Temp(0) + IMM].

再来看:

跟进 AddOperand:

猜也猜到它的作用了, 向指令中插入新的操作数, 来看 transform 的实现:

即将 MOV *[Temp(0) + IMM] 变为 MOV Temp(1), [Temp(0) + IMM].

最后是 DataBlock[Offset(RIP)] := Temp(1):

我们跟进 WriteTemp:

查看 generate 方法的实现:

生成可重定位指令, 将临时值写入指定位置, 因为我们是 OffsetType, 所以跟进 StoreDataBlock, 其他的感兴趣可以自行查看:

来看看 reloc 方法, 来到了 src/Patch/X86_64/RelocatableInst_X86_64.cpp 中, 不同的架构实现不同:

mov64mrmov32mr 位于 src/Patch/X86_64/Layer2_X86_64.cpp, 同样因架构而异:

这个 StoreDataBlock 类的作用是: 生成将寄存器值存储到数据块的 llvm::MCInst 指令​​. 这里就是将 Temp(1) 寄存器的值覆盖原 PC 值.

ok, 回到 getDefaultPatchRules 函数, 其他的规则也是类似, 不在一一分析. 我们走了太远, 已经快要忘记来时的路, 现在让我们回到 Engine::patch 方法. 在它的 do-while 循环中, 不断调用 patchRuleAssembly->generate, 用的规则将汇编指令转成 QBDI 自己的 ir, 然后, QBDI 的 ir 再到 llvm::MCInst. 在根据是否改变 PC 分割出基本块, 如果改变了那就是一个基本块, 这样我们将结果存入 basicBlock 中返回, 反之继续. 回到了 Engine::handleNewBasicBlock 方法(再贴一遍):

然后进入 blockManager->preWriteBasicBlock:

就是在找一个大小合适缓冲区位置, 然后返回要存的 patch 数量. 进入 instrument 方法:

代码也很好懂, 就是从刚刚生成好的基本块中取出每个指令 patch, 然后调用我们设置的插桩规则 instrRules (在设置回调函数那里写入的, 可以搜索 InstrRuleBasicCBK::unique). 在我们这个例子中 rule 的类型为 InstrRuleBasicCBK, 取出每条插桩规则看看能不能插桩 rule->tryInstrument. 我们看一下 InstrRuleBasicCBK 类中的 tryInstrument 方法:

先调用 canBeApplied 判断是否可以插桩:

调用 condition->test. 上面已经讲过不在赘述. 然后看 instrument(patch, patchGen, breakToHost, position, priority, tag) 的参数, patch 是汇编指令对应的 ir, patchGen, breakToHost, position, priority, tag 都是 InstrRuleBasicCBK 类属性, InstrRuleBasicCBK 类在上面贴出来过, 不在重复, 让我们去看看 InstrRuleBasicCBK 的构造函数:

patchGen 看样子是将我们传入的回调函数和自定义参数的 patch, position 是插桩位置(指令前或者指令后), breakToHost 传入的固定值 true, priority 传入的优先级, tagposition 相关.

看看 getCallbackGenerator 方法的实现:

看一眼 GetConstant:

好吧, 这些代码应该比较熟悉了, 概括一下就是 MOV REG64 temp, IMM64 cst, 这个注释.

再看 GetInstId:

再来看看 InstId:

也就是将执行块的 id execBlock->getNextInstID() 当作立即数, 用 mov 放入 Temp(0) 寄存器中.

回来再来看 instrument 函数:

还是整体浏览一遍, 然后找不懂得点查看实现, 首先是 RelocatableInst::UniquePtrVec instru, 这个是最终插桩代码, 我们看看它的属性 using UniquePtrVec = std::vector<std::unique_ptr<RelocatableInst>> 可重定位的指令集合, 将 patchGen 中的先放进来:

看看 append 函数:

让我们理一理: generate 方法会对应一条或者多条指令, 以 RelocatableInst 数组的形式返回, RelocatableInst 类的 reloc 会返回 llvm::MCInst 实例.

然后看这里:

根据 position 处理插桩位置, 是在指令前还是指令后.

然后是这里:

GetConstant(Temp(0), Constant(address)).generate(patch, tempManager) 在前面讲过, mov Temp(0), address, 将插桩地址赋给 Temp(0) 寄存器, 再看后面这个 append: tempManager.getRegForTemp(0) 前面讲过, 为临时寄存器配分一个实际寄存器. 看看 SaveReg:

这个 StoreDataBlock 咱们再前面也讲过, 概括就是这个注释 MOV MEM64 DataBlock[offset], REG64 reg, 看完这段咱们应该懂了 SaveReg(tempManager.getRegForTemp(0), Offset(Reg(REG_PC))) 就是将 MOV MEM64 DataBlock[PC], Temp(0), 将寄存器 Temp(0) 中的值写入数据块偏移为 Reg(REG_PC) 的值. 也就是将寄存器 Temp(0) 中的值写入 PC.

再回到 InstrRule::instrument, 往下看 tempManager.generateSaveRestoreInstructions:

LoadRegSaveReg 相反, 代码非常相似, 从数据块加载值到对应寄存器, 而这个函数是用来生成寄存器的保存和恢复的指令, 它根据指定的数量 unrestoredRegNum, 决定哪些寄存器需要保存但不需要恢复, 哪些寄存器需要保存和恢复. 生成的指令分别存储在 saveInstrestoreInst 列表中, 未恢复的寄存器存储在 unrestoredReg 列表中.

再看 prepend 函数:

没什么好说的, 最后看 patch.addInstsPatch 函数:

按优先级存入 instsPatchs 属性中. 好了 InstrRule::instrument 函数就是将我回调函数与自定义参数处理好, 记录到 patch 的属性中.

现在回到 Engine::instrument 函数(在贴一次):

看最后的 patch.finalizeInstsPatch:

看一下 RelocTag 类:

在看一下 TargetPrologue 类:

RelocTagTargetPrologue 类不在多说.

Patch::finalizeInstsPatch 方法是将插桩代码的指令从 instsPatchs 属性中读取真的插入到 patch 中, patch 对应了一条汇编指令, 由多指令实现.

回到 Engine::handleNewBasicBlock(再贴一次):

看最后的 blockManager->writeBasicBlock(std::move(basicBlock), patchEnd) 将指令写入缓存(这里我们插入到指令是插到 patch, 而 blockManager->preWriteBasicBlock 预分配的空间是按 patch 个数, 所以预分配的空间不会因为插入插桩代码和不足):

浏览器一遍函数. 这里构建了指令序列 SeqLoc, 对应了一条 patch 中包含的一条或者多条指令的范围. 存入 sequenceCache instCache 缓存, 和前面串起来了. 我们也理一理, region 中包含很多 block, 然后 block 包含很多 seq, seq 中包含很多 inst.

然后看这里:

跟入 writeSequence:

代码也很读, 根据注释, 我们大体懂了做什么, 我们跟入 writePatch

先判断是否已经填满一个块, 然后调用 applyRelocatedInst:

读完后, 让我们关注 llvmcpu.writeInstruction(inst->reloc(this, llvmcpu), stream, getCurrentPC()), 这里调用了 reloc 返回 llvm::MCInst 实例, 跟入 writeInstruction:

这里调用了 llvm 的 api assembler->getEmitter().encodeInstructionllvm::MCValue 转为机器码, 存入 CB. 回头看一下 writeCodeByte:

将机器码写如 codeBlock 中.

好了, 终于读完了 Engine::handleNewBasicBlock 方法, 我们回到 Engine::run 方法, 走了太远了, 我们再贴一下它的代码, 并且注释一下, 帮你恢复死去的记忆:

有没有感觉已经很明了了, 我们再看几个函数 signalEvent:

再来看 curExecBlock->execute 执行函数:

先看 run 函数中的 qbdi_runCodeBlock 如何执行的:

找到 src/ExecBlock/X86_64/linux_X86_64.s 中的 __qbdi_runCodeBlock, 还是不同架构实现不同:

这里调用汇编进入我们之前用 llvm 写的机器码.

还记得上边我们如何插入插桩指令的吗? 我们有三条步, 回调函数地址赋值给 hostState.callback, 将用户自定义参数赋值给 hostState.data, 将执行块 id 赋值给 hostState.origin. 然后执行完一段后, 会跳回来检查是不是填好了回调 hostState.callback, 如果有就执行:

好了, 差不多就写到这, 自己再回顾一遍 Engine::run 函数. 想一想都做了什么...

整体看下来, QBDI 的代码写的非常好, 规范, 工整, 像一个艺术品.

我们的 QBDI 之旅告一段落, 等等, 我们是不是还忘了什么: 收尾, 某个被跳过的 if...好吧, 已经写了足够多了, 大行不顾细谨, 不在纠结了.

mkdir build
cd build
../cmake/config/config-linux-X86_64.sh
# cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
# ln -s compile_commands.json ..
# 要安装到系统目录, 这样头文件可以直接导入
sudo ninja install
mkdir build
cd build
../cmake/config/config-linux-X86_64.sh
# cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
# ln -s compile_commands.json ..
# 要安装到系统目录, 这样头文件可以直接导入
sudo ninja install
# 编译 examples/ 程序
cd build
# 编译 debug 版可以配合 gdb 调试
cmake -DQBDI_EXAMPLES=ON -DCMAKE_BUILD_TYPE=Debug -DQBDI_LOG_DEBUG=ON ..
ninja
# 编译 examples/ 程序
cd build
# 编译 debug 版可以配合 gdb 调试
cmake -DQBDI_EXAMPLES=ON -DCMAKE_BUILD_TYPE=Debug -DQBDI_LOG_DEBUG=ON ..
ninja
mkdir QBDIPreload && cd QBDIPreload
# build/package/qbdi-preload-template 脚本中的命令, 要在编译时执行 sudo ninja install 才能复制过来
cp /usr/local/share/qbdipreloadX86_64/qbdi_preload_template/* .
mkdir build && cd build
cmake ..
make
mkdir QBDIPreload && cd QBDIPreload
# build/package/qbdi-preload-template 脚本中的命令, 要在编译时执行 sudo ninja install 才能复制过来
cp /usr/local/share/qbdipreloadX86_64/qbdi_preload_template/* .
mkdir build && cd build
cmake ..
make
// 斐波那契数列
int fibonacci(int n) {
    if(n <= 2)
        return 1;
    return fibonacci(n-1) + fibonacci(n-2);
}
// 斐波那契数列
int fibonacci(int n) {
    if(n <= 2)
        return 1;
    return fibonacci(n-1) + fibonacci(n-2);
}
#include "QBDI.h"
 
// 初始化虚拟机
VMInstanceRef vm;
qbdi_initVM(&vm, NULL, NULL, 0);
 
// 虚拟机状态的指针
GPRState *state;
state = qbdi_getGPRState(vm);
assert(state != NULL);
 
// 请求一个虚拟堆栈, 虚拟机不使用你进程中的常规堆栈, QBDI 需要自己的堆栈
uint8_t *fakestack;
static const uint32_t STACK_SIZE = 0x100000; // 1MB
bool res = qbdi_allocateVirtualStack(state, STACK_SIZE, &fakestack);
assert(res == true);
#include "QBDI.h"
 
// 初始化虚拟机
VMInstanceRef vm;
qbdi_initVM(&vm, NULL, NULL, 0);
 
// 虚拟机状态的指针
GPRState *state;
state = qbdi_getGPRState(vm);
assert(state != NULL);
 
// 请求一个虚拟堆栈, 虚拟机不使用你进程中的常规堆栈, QBDI 需要自己的堆栈
uint8_t *fakestack;
static const uint32_t STACK_SIZE = 0x100000; // 1MB
bool res = qbdi_allocateVirtualStack(state, STACK_SIZE, &fakestack);
assert(res == true);
// 获取当前指令的地址和反汇编, 并将其打印出来,
 
// 回调函数遵循 InstCallback 的函数签名
VMAction showInstruction(VMInstanceRef vm, GPRState *gprState,
                        FPRState *fprState, void *data) {
// 获取指令的分析信息, 包括指令地址和反汇编代码
const InstAnalysis *instAnalysis = qbdi_getInstAnalysis(
    vm, QBDI_ANALYSIS_INSTRUCTION | QBDI_ANALYSIS_DISASSEMBLY);
 
// 打印指令的地址和反汇编代码
printf("0x%" PRIRWORD ": %s\n", instAnalysis->address,
        instAnalysis->disassembly);
 
return QBDI_CONTINUE;
}
// 通过传参控制回调是在指令前(QBDI_PREINST)或指令后(QBDI_POSTINST)被调用.
uint32_t cid = qbdi_addCodeCB(vm, QBDI_PREINST, showInstruction, NULL, 0);
assert(cid != QBDI_INVALID_EVENTID);
 
// 计算递归调用次数
 
// QBDI 回调函数都允许用户传递一个自定义参数 data, 其类型为 void *
VMAction countIteration(VMInstanceRef vm, GPRState *gprState,
                        FPRState *fprState, void *data) {
(*((int *)data))++;
 
return QBDI_CONTINUE;
}
int iterationCount = 0;
// qbdi_addMnemonicCB 可以用于注册一个回调函数, 该回调函数仅在遇到特定指令时被调用
qbdi_addMnemonicCB(vm, "CALL*", QBDI_PREINST, countIteration, &iterationCount, 0);
// 获取当前指令的地址和反汇编, 并将其打印出来,
 
// 回调函数遵循 InstCallback 的函数签名
VMAction showInstruction(VMInstanceRef vm, GPRState *gprState,
                        FPRState *fprState, void *data) {
// 获取指令的分析信息, 包括指令地址和反汇编代码
const InstAnalysis *instAnalysis = qbdi_getInstAnalysis(
    vm, QBDI_ANALYSIS_INSTRUCTION | QBDI_ANALYSIS_DISASSEMBLY);
 
// 打印指令的地址和反汇编代码
printf("0x%" PRIRWORD ": %s\n", instAnalysis->address,
        instAnalysis->disassembly);
 
return QBDI_CONTINUE;
}
// 通过传参控制回调是在指令前(QBDI_PREINST)或指令后(QBDI_POSTINST)被调用.
uint32_t cid = qbdi_addCodeCB(vm, QBDI_PREINST, showInstruction, NULL, 0);
assert(cid != QBDI_INVALID_EVENTID);
 
// 计算递归调用次数
 
// QBDI 回调函数都允许用户传递一个自定义参数 data, 其类型为 void *
VMAction countIteration(VMInstanceRef vm, GPRState *gprState,
                        FPRState *fprState, void *data) {
(*((int *)data))++;
 
return QBDI_CONTINUE;
}
int iterationCount = 0;
// qbdi_addMnemonicCB 可以用于注册一个回调函数, 该回调函数仅在遇到特定指令时被调用
qbdi_addMnemonicCB(vm, "CALL*", QBDI_PREINST, countIteration, &iterationCount, 0);
// QBDI 的插桩代码需要一个生效的地址范围, 如果超出此范围, QBDI 不再处理, 即插桩代码不再发生作用.
bool res = qbdi_addInstrumentedModuleFromAddr(vm, (rword)&fibonacci);
assert(res == true);
 
// qbdi_call() 函数最终运行插桩, 用 retvalue 接收返回值, 并通过 QBDI 调用目标函数, 1 是参数个数, n 是要传入参数
rword retvalue;
res = qbdi_call(vm, &retvalue, (rword)fibonacci, 1, n);
assert(res == true);
// QBDI 的插桩代码需要一个生效的地址范围, 如果超出此范围, QBDI 不再处理, 即插桩代码不再发生作用.
bool res = qbdi_addInstrumentedModuleFromAddr(vm, (rword)&fibonacci);
assert(res == true);
 
// qbdi_call() 函数最终运行插桩, 用 retvalue 接收返回值, 并通过 QBDI 调用目标函数, 1 是参数个数, n 是要传入参数
rword retvalue;
res = qbdi_call(vm, &retvalue, (rword)fibonacci, 1, n);
assert(res == true);
/*! 创建并初始化一个虚拟机实例.
 *
 * @param[out] instance 创建的虚拟机实例.
 * @param[in]  cpu      一个 C 字符串, 指定要使用的 CPU 模型名称.
 *                      如果为 NULL, 则使用默认架构的 CPU 模型
 *                      (更多细节请参考 LLVM 文档).
 * @param[in]  mattrs   一个以 NULL 结尾的 C 字符串数组, 指定 CPU 模型的属性.
 *                      如果为 NULL, 则不指定额外的特性.
 * @param[in]  opts     要在虚拟机中启用的选项.
 */
QBDI_EXPORT void qbdi_initVM(VMInstanceRef *instance, const char *cpu,
                             const char **mattrs, Options opts);
/*! 创建并初始化一个虚拟机实例.
 *
 * @param[out] instance 创建的虚拟机实例.
 * @param[in]  cpu      一个 C 字符串, 指定要使用的 CPU 模型名称.
 *                      如果为 NULL, 则使用默认架构的 CPU 模型
 *                      (更多细节请参考 LLVM 文档).
 * @param[in]  mattrs   一个以 NULL 结尾的 C 字符串数组, 指定 CPU 模型的属性.
 *                      如果为 NULL, 则不指定额外的特性.
 * @param[in]  opts     要在虚拟机中启用的选项.
 */
QBDI_EXPORT void qbdi_initVM(VMInstanceRef *instance, const char *cpu,
                             const char **mattrs, Options opts);
#define QBDI_REQUIRE_ACTION(req, ac)           \
  if (!(req)) {                                \
    QBDI_ERROR("Assertion Failed : {}", #req); \
    ac;                                        \
  }
 
void qbdi_initVM(VMInstanceRef *instance, const char *cpu, const char **mattrs,
                 Options opts) {
  QBDI_REQUIRE_ACTION(instance, return);
 
  *instance = nullptr;
  std::string cpuStr = "";
  std::vector<std::string> mattrsStr;
 
  if (cpu != nullptr) {
    cpuStr += cpu;
  }
 
  if (mattrs != nullptr) {
    for (unsigned i = 0; mattrs[i] != nullptr; i++) {
      mattrsStr.emplace_back(mattrs[i]);
    }
  }
 
  *instance = static_cast<VMInstanceRef>(new VM(cpuStr, mattrsStr, opts));
}
#define QBDI_REQUIRE_ACTION(req, ac)           \
  if (!(req)) {                                \
    QBDI_ERROR("Assertion Failed : {}", #req); \
    ac;                                        \
  }
 
void qbdi_initVM(VMInstanceRef *instance, const char *cpu, const char **mattrs,
                 Options opts) {
  QBDI_REQUIRE_ACTION(instance, return);
 
  *instance = nullptr;
  std::string cpuStr = "";
  std::vector<std::string> mattrsStr;
 
  if (cpu != nullptr) {
    cpuStr += cpu;
  }
 
  if (mattrs != nullptr) {
    for (unsigned i = 0; mattrs[i] != nullptr; i++) {
      mattrsStr.emplace_back(mattrs[i]);
    }
  }
 
  *instance = static_cast<VMInstanceRef>(new VM(cpuStr, mattrsStr, opts));
}
VM::VM(const std::string &cpu, const std::vector<std::string> &mattrs,
       Options opts)
    : memoryLoggingLevel(0), memCBID(0),
      memReadGateCBID(VMError::INVALID_EVENTID),
      memWriteGateCBID(VMError::INVALID_EVENTID) {
#if defined(_QBDI_ASAN_ENABLED_)
  opts |= Options::OPT_DISABLE_FPR;
#endif
  engine = std::make_unique<Engine>(cpu, mattrs, opts, this);
  memCBInfos = std::make_unique<std::vector<std::pair<uint32_t, MemCBInfo>>>();
  instrCBInfos = std::make_unique<
      std::vector<std::pair<uint32_t, std::unique_ptr<InstrCBInfo>>>>();
}
VM::VM(const std::string &cpu, const std::vector<std::string> &mattrs,
       Options opts)
    : memoryLoggingLevel(0), memCBID(0),
      memReadGateCBID(VMError::INVALID_EVENTID),
      memWriteGateCBID(VMError::INVALID_EVENTID) {
#if defined(_QBDI_ASAN_ENABLED_)
  opts |= Options::OPT_DISABLE_FPR;
#endif
  engine = std::make_unique<Engine>(cpu, mattrs, opts, this);
  memCBInfos = std::make_unique<std::vector<std::pair<uint32_t, MemCBInfo>>>();
  instrCBInfos = std::make_unique<
      std::vector<std::pair<uint32_t, std::unique_ptr<InstrCBInfo>>>>();
}
Engine::Engine(const std::string &_cpu, const std::vector<std::string> &_mattrs,
               Options opts, VMInstanceRef vminstance)
    : vminstance(vminstance), instrRulesCounter(0), vmCallbacksCounter(0),
      curCPUMode(CPUMode::DEFAULT), options(opts), eventMask(VMEvent::NO_EVENT),
      running(false) {
 
  llvmCPUs = std::make_unique<LLVMCPUs>(_cpu, _mattrs, opts);
  blockManager = std::make_unique<ExecBlockManager>(*llvmCPUs, vminstance);
  execBroker = blockManager->getExecBroker();
 
  // Get Patch rules Assembly for this architecture
  patchRuleAssembly = std::make_unique<PatchRuleAssembly>(options);
 
  gprState = std::make_unique<GPRState>();
  fprState = std::make_unique<FPRState>();
  curGPRState = gprState.get();
  curFPRState = fprState.get();
 
  initGPRState();
  initFPRState();
 
  curExecBlock = nullptr;
}
Engine::Engine(const std::string &_cpu, const std::vector<std::string> &_mattrs,
               Options opts, VMInstanceRef vminstance)
    : vminstance(vminstance), instrRulesCounter(0), vmCallbacksCounter(0),
      curCPUMode(CPUMode::DEFAULT), options(opts), eventMask(VMEvent::NO_EVENT),
      running(false) {
 
  llvmCPUs = std::make_unique<LLVMCPUs>(_cpu, _mattrs, opts);
  blockManager = std::make_unique<ExecBlockManager>(*llvmCPUs, vminstance);
  execBroker = blockManager->getExecBroker();
 
  // Get Patch rules Assembly for this architecture
  patchRuleAssembly = std::make_unique<PatchRuleAssembly>(options);
 
  gprState = std::make_unique<GPRState>();
  fprState = std::make_unique<FPRState>();
  curGPRState = gprState.get();
  curFPRState = fprState.get();
 
  initGPRState();
  initFPRState();
 
  curExecBlock = nullptr;
}
GPRState *qbdi_getGPRState(VMInstanceRef instance) {
  QBDI_REQUIRE_ACTION(instance, return nullptr);
  return static_cast<VM *>(instance)->getGPRState();
}
 
GPRState *VM::getGPRState() const { return engine->getGPRState(); }
GPRState *qbdi_getGPRState(VMInstanceRef instance) {
  QBDI_REQUIRE_ACTION(instance, return nullptr);
  return static_cast<VM *>(instance)->getGPRState();
}
 
GPRState *VM::getGPRState() const { return engine->getGPRState(); }
GPRState *Engine::getGPRState() const { return curGPRState; }
GPRState *Engine::getGPRState() const { return curGPRState; }
GPRState *curGPRState;
 
/*! X86_64 General Purpose Register context.
 */ // SPHINX_X86_64_GPRSTATE_BEGIN
typedef struct QBDI_ALIGNED(8) {
  rword rax;
  rword rbx;
  rword rcx;
  rword rdx;
  rword rsi;
  rword rdi;
  rword r8;
  rword r9;
  rword r10;
  rword r11;
  rword r12;
  rword r13;
  rword r14;
  rword r15;
  rword rbp;
  rword rsp;
  rword rip;
  rword eflags;
  // Only backup and restore with OPT_ENABLE_FS_GS
  rword fs;
  rword gs;
} GPRState;
// SPHINX_X86_64_GPRSTATE_END
GPRState *curGPRState;
 
/*! X86_64 General Purpose Register context.
 */ // SPHINX_X86_64_GPRSTATE_BEGIN
typedef struct QBDI_ALIGNED(8) {
  rword rax;
  rword rbx;
  rword rcx;
  rword rdx;
  rword rsi;
  rword rdi;
  rword r8;
  rword r9;
  rword r10;
  rword r11;
  rword r12;
  rword r13;
  rword r14;
  rword r15;
  rword rbp;
  rword rsp;
  rword rip;
  rword eflags;
  // Only backup and restore with OPT_ENABLE_FS_GS
  rword fs;
  rword gs;
} GPRState;
// SPHINX_X86_64_GPRSTATE_END
bool qbdi_allocateVirtualStack(GPRState *ctx, uint32_t stackSize,
                               uint8_t **stack) {
  return allocateVirtualStack(ctx, stackSize, stack);
}
 
bool allocateVirtualStack(GPRState *ctx, uint32_t stackSize, uint8_t **stack) {
  (*stack) = static_cast<uint8_t *>(alignedAlloc(stackSize, 16));
  if (*stack == nullptr) {
    return false;
  }
 
  QBDI_GPR_SET(ctx, REG_SP, reinterpret_cast<QBDI::rword>(*stack) + stackSize);
  QBDI_GPR_SET(ctx, REG_BP, QBDI_GPR_GET(ctx, REG_SP));
 
  return true;
}
 
// 分配对齐的内存
void *alignedAlloc(size_t size, size_t align) {
  void *allocated = nullptr;  // 初始化分配的内存指针为 nullptr
  // 对齐大小必须是 2 的幂
  if ((align == 0) || ((align & (align - 1)) != 0)) {
    return nullptr;  // 如果对齐大小不是 2 的幂, 返回 nullptr
  }
#if defined(QBDI_PLATFORM_LINUX) || defined(QBDI_PLATFORM_ANDROID) || \
    defined(QBDI_PLATFORM_OSX)
  // 在 Linux、Android 和 macOS 上使用 posix_memalign 分配对齐内存
  int ret = posix_memalign(&allocated, align, size);  // 尝试分配对齐内存
  if (ret != 0) {
    return nullptr;  // 如果分配失败, 返回 nullptr
  }
#elif defined(QBDI_PLATFORM_WINDOWS)
  // 在 Windows 上使用 _aligned_malloc 分配对齐内存
  allocated = _aligned_malloc(size, align);  // 尝试分配对齐内存
#endif
  return allocated;  // 返回分配的内存指针
}
 
#ifdef __cplusplus
#define QBDI_GPR_GET(state, i) (reinterpret_cast<const QBDI::rword *>(state)[i])
#define QBDI_GPR_SET(state, i, v) \
  (reinterpret_cast<QBDI::rword *>(state)[i] = v)
#else
#define QBDI_GPR_GET(state, i) (((rword *)state)[i])
#define QBDI_GPR_SET(state, i, v) (((rword *)state)[i] = v)
#endif
bool qbdi_allocateVirtualStack(GPRState *ctx, uint32_t stackSize,
                               uint8_t **stack) {
  return allocateVirtualStack(ctx, stackSize, stack);
}
 
bool allocateVirtualStack(GPRState *ctx, uint32_t stackSize, uint8_t **stack) {
  (*stack) = static_cast<uint8_t *>(alignedAlloc(stackSize, 16));
  if (*stack == nullptr) {
    return false;
  }
 
  QBDI_GPR_SET(ctx, REG_SP, reinterpret_cast<QBDI::rword>(*stack) + stackSize);
  QBDI_GPR_SET(ctx, REG_BP, QBDI_GPR_GET(ctx, REG_SP));
 
  return true;
}
 
// 分配对齐的内存
void *alignedAlloc(size_t size, size_t align) {
  void *allocated = nullptr;  // 初始化分配的内存指针为 nullptr
  // 对齐大小必须是 2 的幂
  if ((align == 0) || ((align & (align - 1)) != 0)) {
    return nullptr;  // 如果对齐大小不是 2 的幂, 返回 nullptr
  }
#if defined(QBDI_PLATFORM_LINUX) || defined(QBDI_PLATFORM_ANDROID) || \
    defined(QBDI_PLATFORM_OSX)
  // 在 Linux、Android 和 macOS 上使用 posix_memalign 分配对齐内存
  int ret = posix_memalign(&allocated, align, size);  // 尝试分配对齐内存
  if (ret != 0) {
    return nullptr;  // 如果分配失败, 返回 nullptr
  }
#elif defined(QBDI_PLATFORM_WINDOWS)
  // 在 Windows 上使用 _aligned_malloc 分配对齐内存
  allocated = _aligned_malloc(size, align);  // 尝试分配对齐内存
#endif
  return allocated;  // 返回分配的内存指针
}
 
#ifdef __cplusplus
#define QBDI_GPR_GET(state, i) (reinterpret_cast<const QBDI::rword *>(state)[i])
#define QBDI_GPR_SET(state, i, v) \
  (reinterpret_cast<QBDI::rword *>(state)[i] = v)
#else
#define QBDI_GPR_GET(state, i) (((rword *)state)[i])
#define QBDI_GPR_SET(state, i, v) (((rword *)state)[i] = v)
#endif
/*! 注册特定指令事件的回调事件.
 
 * @param[in] instance  虚拟机实例.
 * @param[in] pos       事件回调的相对位置
 *                      (QBDI_PREINST / QBDI_POSTINST).
 * @param[in] cbk       回调函数的指针.
 * @param[in] data      传递给回调函数的用户自定义数据.
 * @param[in] priority  回调的优先级.
 
 * @return 注册的插桩的 ID(如果失败则返回 QBDI_INVALID_EVENTID).
 */
QBDI_EXPORT uint32_t qbdi_addCodeCB(VMInstanceRef instance, InstPosition pos,
                                    InstCallback cbk, void *data, int priority);
/*! 注册特定指令事件的回调事件.
 
 * @param[in] instance  虚拟机实例.
 * @param[in] pos       事件回调的相对位置
 *                      (QBDI_PREINST / QBDI_POSTINST).
 * @param[in] cbk       回调函数的指针.
 * @param[in] data      传递给回调函数的用户自定义数据.
 * @param[in] priority  回调的优先级.
 
 * @return 注册的插桩的 ID(如果失败则返回 QBDI_INVALID_EVENTID).
 */
QBDI_EXPORT uint32_t qbdi_addCodeCB(VMInstanceRef instance, InstPosition pos,
                                    InstCallback cbk, void *data, int priority);
uint32_t qbdi_addCodeCB(VMInstanceRef instance, InstPosition pos,
                        InstCallback cbk, void *data, int priority) {
  QBDI_REQUIRE_ACTION(instance, return VMError::INVALID_EVENTID);
  return static_cast<VM *>(instance)->addCodeCB(pos, cbk, data, priority);
}
uint32_t qbdi_addCodeCB(VMInstanceRef instance, InstPosition pos,
                        InstCallback cbk, void *data, int priority) {
  QBDI_REQUIRE_ACTION(instance, return VMError::INVALID_EVENTID);
  return static_cast<VM *>(instance)->addCodeCB(pos, cbk, data, priority);
}
uint32_t VM::addCodeCB(InstPosition pos, InstCallback cbk, void *data,
                       int priority) {
  QBDI_REQUIRE_ACTION(cbk != nullptr, return VMError::INVALID_EVENTID);
  return engine->addInstrRule(InstrRuleBasicCBK::unique(
      True::unique(), cbk, data, pos, true, priority,
      (pos == PREINST) ? RelocTagPreInstStdCBK : RelocTagPostInstStdCBK));
}
uint32_t VM::addCodeCB(InstPosition pos, InstCallback cbk, void *data,
                       int priority) {
  QBDI_REQUIRE_ACTION(cbk != nullptr, return VMError::INVALID_EVENTID);
  return engine->addInstrRule(InstrRuleBasicCBK::unique(
      True::unique(), cbk, data, pos, true, priority,
      (pos == PREINST) ? RelocTagPreInstStdCBK : RelocTagPostInstStdCBK));
}
// helper to create a object as a unique_ptr
template <typename T, typename U>
class AutoUnique : public T {
public:
  template <typename... Args>
  AutoUnique(Args &&...args) : T(std::forward<Args>(args)...) {}
 
  template <typename... Args>
  inline static std::unique_ptr<T> unique(Args &&...args) {
    return std::make_unique<U>(std::forward<Args>(args)...);
  };
};
// helper to create a object as a unique_ptr
template <typename T, typename U>
class AutoUnique : public T {
public:
  template <typename... Args>
  AutoUnique(Args &&...args) : T(std::forward<Args>(args)...) {}
 
  template <typename... Args>
  inline static std::unique_ptr<T> unique(Args &&...args) {
    return std::make_unique<U>(std::forward<Args>(args)...);
  };
};
class True : public AutoClone<PatchCondition, True> {
public:
  /*! Return true.
   */
  True() {}
 
  bool test(const Patch &patch, const LLVMCPU &llvmcpu) const override {
    return true;
  }
};
class True : public AutoClone<PatchCondition, True> {
public:
  /*! Return true.
   */
  True() {}
 
  bool test(const Patch &patch, const LLVMCPU &llvmcpu) const override {
    return true;
  }
};
// helper to clone object, when the copy is possible
template <typename T, typename U>
class AutoClone : public AutoUnique<T, U> {
public:
  template <typename... Args>
  AutoClone(Args &&...args) : AutoUnique<T, U>(std::forward<Args>(args)...) {}
 
  inline std::unique_ptr<T> clone() const override {
    return std::make_unique<U>(*static_cast<const U *>(this));
  };
};
// helper to clone object, when the copy is possible
template <typename T, typename U>
class AutoClone : public AutoUnique<T, U> {
public:
  template <typename... Args>
  AutoClone(Args &&...args) : AutoUnique<T, U>(std::forward<Args>(args)...) {}
 
  inline std::unique_ptr<T> clone() const override {
    return std::make_unique<U>(*static_cast<const U *>(this));
  };
};
class InstrRuleBasicCBK : public AutoUnique<InstrRule, InstrRuleBasicCBK> {
 
  PatchConditionUniquePtr condition;
  PatchGeneratorUniquePtrVec patchGen;
  InstPosition position;
  bool breakToHost;
  RelocatableInstTag tag;
  InstCallback cbk;
  void *data;
 
public:
  /*! 创建新的插桩规则, 包含条件判断、生成器列表、插桩位置和主机中断请求.
   *
   * @param[in] condition    用于判断该PatchRule是否适用的PatchCondition条件
   * @param[in] cbk          待执行的回调函数
   * @param[in] data         传递给回调函数的数据指针
   * @param[in] position     枚举值, 指示插桩应位于指令之前还是之后
   * @param[in] breakToHost  布尔值, 决定该插桩是否应以主机中断结束(例如在回调场景)
   * @param[in] priority     回调函数的优先级
   * @param[in] tag          回调函数的标签
   */
  InstrRuleBasicCBK(PatchConditionUniquePtr &&condition, InstCallback cbk,
                    void *data, InstPosition position, bool breakToHost,
                    int priority = PRIORITY_DEFAULT,
                    RelocatableInstTag tag = RelocTagInvalid);
 
  ~InstrRuleBasicCBK() override;
 
  std::unique_ptr<InstrRule> clone() const override;
 
  inline InstPosition getPosition() const { return position; }
 
  RangeSet<rword> affectedRange() const override;
 
  /*! 通过评估当前上下文中的规则条件, 确定本规则是否适用.
   *
   * @param[in] patch    包含当前上下文的补丁对象
   * @param[in] llvmcpu  LLVMCPU对象
   *
   * @return 若插桩条件在当前补丁上评估为真, 则返回true
   */
  bool canBeApplied(const Patch &patch, const LLVMCPU &llvmcpu) const;
 
  bool changeDataPtr(void *data) override;
 
  inline bool tryInstrument(Patch &patch,
                            const LLVMCPU &llvmcpu) const override {
    if (canBeApplied(patch, llvmcpu)) {
      instrument(patch, patchGen, breakToHost, position, priority, tag);
      return true;
    }
    return false;
  }
};
class InstrRuleBasicCBK : public AutoUnique<InstrRule, InstrRuleBasicCBK> {
 
  PatchConditionUniquePtr condition;
  PatchGeneratorUniquePtrVec patchGen;
  InstPosition position;
  bool breakToHost;
  RelocatableInstTag tag;
  InstCallback cbk;
  void *data;
 
public:
  /*! 创建新的插桩规则, 包含条件判断、生成器列表、插桩位置和主机中断请求.
   *
   * @param[in] condition    用于判断该PatchRule是否适用的PatchCondition条件
   * @param[in] cbk          待执行的回调函数
   * @param[in] data         传递给回调函数的数据指针
   * @param[in] position     枚举值, 指示插桩应位于指令之前还是之后
   * @param[in] breakToHost  布尔值, 决定该插桩是否应以主机中断结束(例如在回调场景)
   * @param[in] priority     回调函数的优先级
   * @param[in] tag          回调函数的标签
   */
  InstrRuleBasicCBK(PatchConditionUniquePtr &&condition, InstCallback cbk,
                    void *data, InstPosition position, bool breakToHost,
                    int priority = PRIORITY_DEFAULT,
                    RelocatableInstTag tag = RelocTagInvalid);
 
  ~InstrRuleBasicCBK() override;
 
  std::unique_ptr<InstrRule> clone() const override;
 
  inline InstPosition getPosition() const { return position; }
 
  RangeSet<rword> affectedRange() const override;
 
  /*! 通过评估当前上下文中的规则条件, 确定本规则是否适用.
   *
   * @param[in] patch    包含当前上下文的补丁对象
   * @param[in] llvmcpu  LLVMCPU对象
   *
   * @return 若插桩条件在当前补丁上评估为真, 则返回true
   */
  bool canBeApplied(const Patch &patch, const LLVMCPU &llvmcpu) const;
 
  bool changeDataPtr(void *data) override;
 
  inline bool tryInstrument(Patch &patch,
                            const LLVMCPU &llvmcpu) const override {
    if (canBeApplied(patch, llvmcpu)) {
      instrument(patch, patchGen, breakToHost, position, priority, tag);
      return true;
    }
    return false;
  }
};
uint32_t Engine::addInstrRule(std::unique_ptr<InstrRule> &&rule) {
  uint32_t id = instrRulesCounter++;
  QBDI_REQUIRE_ACTION(id < EVENTID_VM_MASK, return VMError::INVALID_EVENTID);
 
  this->clearCache(rule->affectedRange());
 
  auto v = std::make_pair(id, std::move(rule));
 
  // insert rule in instrRules and keep the priority order
  auto it = std::upper_bound(instrRules.begin(), instrRules.end(), v,
                             [](const decltype(instrRules)::value_type &a,
                                const decltype(instrRules)::value_type &b) {
                               return a.second->getPriority() >
                                      b.second->getPriority();
                             });
  instrRules.insert(it, std::move(v));
 
  return id;
}
uint32_t Engine::addInstrRule(std::unique_ptr<InstrRule> &&rule) {
  uint32_t id = instrRulesCounter++;
  QBDI_REQUIRE_ACTION(id < EVENTID_VM_MASK, return VMError::INVALID_EVENTID);
 
  this->clearCache(rule->affectedRange());
 
  auto v = std::make_pair(id, std::move(rule));
 
  // insert rule in instrRules and keep the priority order
  auto it = std::upper_bound(instrRules.begin(), instrRules.end(), v,
                             [](const decltype(instrRules)::value_type &a,
                                const decltype(instrRules)::value_type &b) {
                               return a.second->getPriority() >
                                      b.second->getPriority();
                             });
  instrRules.insert(it, std::move(v));
 
  return id;
}
RangeSet<rword> InstrRuleBasicCBK::affectedRange() const {
  return condition->affectedRange();
}
RangeSet<rword> InstrRuleBasicCBK::affectedRange() const {
  return condition->affectedRange();
}
class PatchCondition {
public:
  using UniquePtr = std::unique_ptr<PatchCondition>;
  using UniquePtrVec = std::vector<std::unique_ptr<PatchCondition>>;
 
  virtual UniquePtr clone() const = 0;
 
  virtual bool test(const Patch &patch, const LLVMCPU &llvmcpu) const = 0;
 
  virtual RangeSet<rword> affectedRange() const {
    RangeSet<rword> r;
    r.add(Range<rword>(0, (rword)-1));
    return r;
  }
 
  virtual ~PatchCondition() = default;
};
class PatchCondition {
public:
  using UniquePtr = std::unique_ptr<PatchCondition>;
  using UniquePtrVec = std::vector<std::unique_ptr<PatchCondition>>;
 
  virtual UniquePtr clone() const = 0;
 
  virtual bool test(const Patch &patch, const LLVMCPU &llvmcpu) const = 0;
 
  virtual RangeSet<rword> affectedRange() const {
    RangeSet<rword> r;
    r.add(Range<rword>(0, (rword)-1));
    return r;
  }
 
  virtual ~PatchCondition() = default;
};
auto v = std::make_pair(id, std::move(rule));
 
// insert rule in instrRules and keep the priority order
auto it = std::upper_bound(instrRules.begin(), instrRules.end(), v,
                            [](const decltype(instrRules)::value_type &a,
                            const decltype(instrRules)::value_type &b) {
                            return a.second->getPriority() >
                                    b.second->getPriority();
                            });
instrRules.insert(it, std::move(v));
auto v = std::make_pair(id, std::move(rule));
 
// insert rule in instrRules and keep the priority order
auto it = std::upper_bound(instrRules.begin(), instrRules.end(), v,
                            [](const decltype(instrRules)::value_type &a,
                            const decltype(instrRules)::value_type &b) {
                            return a.second->getPriority() >
                                    b.second->getPriority();
                            });
instrRules.insert(it, std::move(v));
uint32_t qbdi_addMnemonicCB(VMInstanceRef instance, const char *mnemonic,
                            InstPosition pos, InstCallback cbk, void *data,
                            int priority) {
  QBDI_REQUIRE_ACTION(instance, return VMError::INVALID_EVENTID);
  return static_cast<VM *>(instance)->addMnemonicCB(mnemonic, pos, cbk, data,
                                                    priority);
}
uint32_t qbdi_addMnemonicCB(VMInstanceRef instance, const char *mnemonic,
                            InstPosition pos, InstCallback cbk, void *data,
                            int priority) {
  QBDI_REQUIRE_ACTION(instance, return VMError::INVALID_EVENTID);
  return static_cast<VM *>(instance)->addMnemonicCB(mnemonic, pos, cbk, data,
                                                    priority);
}
uint32_t VM::addMnemonicCB(const char *mnemonic, InstPosition pos,
                           InstCallback cbk, void *data, int priority) {
  QBDI_REQUIRE_ACTION(mnemonic != nullptr, return VMError::INVALID_EVENTID);
  QBDI_REQUIRE_ACTION(cbk != nullptr, return VMError::INVALID_EVENTID);
  return engine->addInstrRule(InstrRuleBasicCBK::unique(
      MnemonicIs::unique(mnemonic), cbk, data, pos, true, priority,
      (pos == PREINST) ? RelocTagPreInstStdCBK : RelocTagPostInstStdCBK));
}
uint32_t VM::addMnemonicCB(const char *mnemonic, InstPosition pos,
                           InstCallback cbk, void *data, int priority) {
  QBDI_REQUIRE_ACTION(mnemonic != nullptr, return VMError::INVALID_EVENTID);
  QBDI_REQUIRE_ACTION(cbk != nullptr, return VMError::INVALID_EVENTID);
  return engine->addInstrRule(InstrRuleBasicCBK::unique(
      MnemonicIs::unique(mnemonic), cbk, data, pos, true, priority,
      (pos == PREINST) ? RelocTagPreInstStdCBK : RelocTagPostInstStdCBK));
}
class MnemonicIs : public AutoClone<PatchCondition, MnemonicIs> {
  std::string mnemonic;
 
public:
  /*! Return true if the mnemonic of the current instruction is equal to
   * Mnemonic.
   *
   * @param[in] mnemonic   A null terminated instruction mnemonic (using LLVM
   * style)
   */
  MnemonicIs(const char *mnemonic) : mnemonic(mnemonic) {}
 
  bool test(const Patch &patch, const LLVMCPU &llvmcpu) const override;
};
class MnemonicIs : public AutoClone<PatchCondition, MnemonicIs> {
  std::string mnemonic;
 
public:
  /*! Return true if the mnemonic of the current instruction is equal to
   * Mnemonic.
   *
   * @param[in] mnemonic   A null terminated instruction mnemonic (using LLVM
   * style)
   */
  MnemonicIs(const char *mnemonic) : mnemonic(mnemonic) {}
 
  bool test(const Patch &patch, const LLVMCPU &llvmcpu) const override;
};
bool MnemonicIs::test(const Patch &patch, const LLVMCPU &llvmcpu) const {
  return QBDI::String::startsWith(
      mnemonic.c_str(), llvmcpu.getInstOpcodeName(patch.metadata.inst));
}
 
bool startsWith(const char *prefix, const char *str) {
  // 确保prefix和str都不是nullptr
  QBDI_REQUIRE_ACTION(prefix != nullptr, return false);
  QBDI_REQUIRE_ACTION(str != nullptr, return false);
 
  // 遍历prefix和str, 逐字符比较
  while (*prefix && *str) {
    // 通配符匹配: 如果prefix中的当前字符是'*', 则跳过直到str中的字符与prefix中的下一个字符匹配
    if (*prefix == '*') {
      // 如果prefix的下一个字符(忽略大小写)与str的当前字符匹配, 则移动prefix和str的指针
      if (toupper(*(prefix + 1)) == toupper(*str++)) {
        prefix++;
      }
      // 继续检查下一个字符
      continue;
    }
    // 比较当前字符(忽略大小写)
    if (toupper(*prefix++) != toupper(*str++)) {
      // 如果字符不匹配, 返回false
      return false;
    }
  }
  // 检查prefix是否还有未匹配的字符(除了通配符'*'之外)
  if (*prefix && *(prefix + 1)) {
    // 如果prefix还有未匹配的字符, 则返回false
    return false;
  }
  // 检查str的下一个字符是否是数字、下划线或字符串结束符
  // 如果不是, 则返回false
  if (!((*str >= '0' && *str <= '9') || *str == '_' || !*str)) {
    return false;
  }
  // 如果所有检查都通过, 则返回true
  return true;
}
bool MnemonicIs::test(const Patch &patch, const LLVMCPU &llvmcpu) const {
  return QBDI::String::startsWith(
      mnemonic.c_str(), llvmcpu.getInstOpcodeName(patch.metadata.inst));
}
 
bool startsWith(const char *prefix, const char *str) {
  // 确保prefix和str都不是nullptr
  QBDI_REQUIRE_ACTION(prefix != nullptr, return false);
  QBDI_REQUIRE_ACTION(str != nullptr, return false);
 
  // 遍历prefix和str, 逐字符比较
  while (*prefix && *str) {
    // 通配符匹配: 如果prefix中的当前字符是'*', 则跳过直到str中的字符与prefix中的下一个字符匹配
    if (*prefix == '*') {
      // 如果prefix的下一个字符(忽略大小写)与str的当前字符匹配, 则移动prefix和str的指针
      if (toupper(*(prefix + 1)) == toupper(*str++)) {
        prefix++;
      }
      // 继续检查下一个字符
      continue;
    }
    // 比较当前字符(忽略大小写)
    if (toupper(*prefix++) != toupper(*str++)) {
      // 如果字符不匹配, 返回false
      return false;
    }
  }
  // 检查prefix是否还有未匹配的字符(除了通配符'*'之外)
  if (*prefix && *(prefix + 1)) {
    // 如果prefix还有未匹配的字符, 则返回false
    return false;
  }
  // 检查str的下一个字符是否是数字、下划线或字符串结束符
  // 如果不是, 则返回false
  if (!((*str >= '0' && *str <= '9') || *str == '_' || !*str)) {
    return false;
  }
  // 如果所有检查都通过, 则返回true
  return true;
}
namespace llvm {
class MCInst;
}
 
namespace QBDI {
class LLVMCPU;
class RelocatableInst;
 
// 指令补丁结构
struct InstrPatch {
  InstPosition position;
  int priority;
  std::vector<std::unique_ptr<RelocatableInst>> insts;
};
 
// 指令补丁的类
class Patch {
private:
  std::vector<InstrPatch> instsPatchs;
 
public:
  InstMetadata metadata;
  std::vector<std::unique_ptr<RelocatableInst>> insts;
  // 由 PatchRule 生成的标志
  std::vector<std::pair<unsigned int, int>> patchGenFlags;
  int patchGenFlagsOffset = 0;
  // 用于在 ExecBlockManager 中注册的指令回调
  std::vector<std::unique_ptr<InstCbLambda>> userInstCB;
  // 指令使用的寄存器
  std::array<RegisterUsage, NUM_GPR> regUsage;
  std::map<RegLLVM, RegisterUsage> regUsageExtra;
  // 本补丁使用的临时寄存器
  std::set<RegLLVM> tempReg;
  const LLVMCPU *llvmcpu;
  bool finalize = false;
 
  using Vec = std::vector<Patch>;
 
  Patch(const llvm::MCInst &inst, rword address, uint32_t instSize,
        const LLVMCPU &llvmcpu);
 
  Patch(Patch &&);
  Patch &operator=(Patch &&);
 
  ~Patch();
 
  void setModifyPC(bool modifyPC);
 
  // 在指令列表的末尾追加一个可重定位指令
  void append(std::unique_ptr<RelocatableInst> &&r);
  // 在指令列表的末尾追加多个可重定位指令
  void append(std::vector<std::unique_ptr<RelocatableInst>> v);
 
  // 在指令列表的开头插入一个可重定位指令
  void prepend(std::unique_ptr<RelocatableInst> &&r);
  // 在指令列表的开头插入多个可重定位指令
  void prepend(std::vector<std::unique_ptr<RelocatableInst>> v);
 
  // 在指定位置插入多个可重定位指令
  void insertAt(unsigned position,
                std::vector<std::unique_ptr<RelocatableInst>> v);
 
  void addInstsPatch(InstPosition position, int priority,
                     std::vector<std::unique_ptr<RelocatableInst>> v);
 
  void finalizeInstsPatch();
};
 
} // namespace QBDI
namespace llvm {
class MCInst;
}
 
namespace QBDI {
class LLVMCPU;
class RelocatableInst;
 
// 指令补丁结构
struct InstrPatch {
  InstPosition position;
  int priority;
  std::vector<std::unique_ptr<RelocatableInst>> insts;
};
 
// 指令补丁的类
class Patch {
private:
  std::vector<InstrPatch> instsPatchs;
 
public:
  InstMetadata metadata;
  std::vector<std::unique_ptr<RelocatableInst>> insts;
  // 由 PatchRule 生成的标志
  std::vector<std::pair<unsigned int, int>> patchGenFlags;
  int patchGenFlagsOffset = 0;
  // 用于在 ExecBlockManager 中注册的指令回调
  std::vector<std::unique_ptr<InstCbLambda>> userInstCB;
  // 指令使用的寄存器
  std::array<RegisterUsage, NUM_GPR> regUsage;
  std::map<RegLLVM, RegisterUsage> regUsageExtra;
  // 本补丁使用的临时寄存器
  std::set<RegLLVM> tempReg;
  const LLVMCPU *llvmcpu;
  bool finalize = false;
 
  using Vec = std::vector<Patch>;
 
  Patch(const llvm::MCInst &inst, rword address, uint32_t instSize,
        const LLVMCPU &llvmcpu);
 
  Patch(Patch &&);
  Patch &operator=(Patch &&);
 
  ~Patch();
 
  void setModifyPC(bool modifyPC);
 
  // 在指令列表的末尾追加一个可重定位指令
  void append(std::unique_ptr<RelocatableInst> &&r);
  // 在指令列表的末尾追加多个可重定位指令
  void append(std::vector<std::unique_ptr<RelocatableInst>> v);
 
  // 在指令列表的开头插入一个可重定位指令
  void prepend(std::unique_ptr<RelocatableInst> &&r);
  // 在指令列表的开头插入多个可重定位指令
  void prepend(std::vector<std::unique_ptr<RelocatableInst>> v);
 
  // 在指定位置插入多个可重定位指令
  void insertAt(unsigned position,
                std::vector<std::unique_ptr<RelocatableInst>> v);
 
  void addInstsPatch(InstPosition position, int priority,
                     std::vector<std::unique_ptr<RelocatableInst>> v);
 
  void finalizeInstsPatch();
};
 
} // namespace QBDI
const char *LLVMCPU::getInstOpcodeName(const llvm::MCInst &inst) const {
  return getInstOpcodeName(inst.getOpcode());
}
 
const char *LLVMCPU::getInstOpcodeName(unsigned opcode) const {
  /* llvm::StringRef can return a no null terminate pointer
   * However, in the case of opcode name, that seems to be always the case
   * see <ARM|AArch64|X86>InstrNameData
   */
  return MCII->getName(opcode).data();
}
const char *LLVMCPU::getInstOpcodeName(const llvm::MCInst &inst) const {
  return getInstOpcodeName(inst.getOpcode());
}
 
const char *LLVMCPU::getInstOpcodeName(unsigned opcode) const {
  /* llvm::StringRef can return a no null terminate pointer
   * However, in the case of opcode name, that seems to be always the case
   * see <ARM|AArch64|X86>InstrNameData
   */
  return MCII->getName(opcode).data();
}
bool qbdi_addInstrumentedModuleFromAddr(VMInstanceRef instance, rword addr) {
  QBDI_REQUIRE_ACTION(instance, return false);
  return static_cast<VM *>(instance)->addInstrumentedModuleFromAddr(addr);
}
 
bool VM::addInstrumentedModuleFromAddr(rword addr) {
  return engine->addInstrumentedModuleFromAddr(addr);
}
 
bool Engine::addInstrumentedModuleFromAddr(rword addr) {
  return execBroker->addInstrumentedModuleFromAddr(addr);
}
bool qbdi_addInstrumentedModuleFromAddr(VMInstanceRef instance, rword addr) {
  QBDI_REQUIRE_ACTION(instance, return false);
  return static_cast<VM *>(instance)->addInstrumentedModuleFromAddr(addr);
}
 
bool VM::addInstrumentedModuleFromAddr(rword addr) {
  return engine->addInstrumentedModuleFromAddr(addr);
}
 
bool Engine::addInstrumentedModuleFromAddr(rword addr) {
  return execBroker->addInstrumentedModuleFromAddr(addr);
}
bool ExecBroker::addInstrumentedModuleFromAddr(rword addr) {
  // 遍历当前进程的内存映射
  for (const MemoryMap &m : getCurrentProcessMaps()) {
    // 检查当前内存映射是否包含指定地址
    if (m.range.contains(addr)) {
      // 如果内存映射有名称(即是一个已知的模块)
      if (not m.name.empty()) {
        // 尝试将该模块添加到已监控的模块列表中
        return addInstrumentedModule(m.name);
      } else if (m.permission & QBDI::PF_EXEC) {
        // 如果内存映射没有名称, 但具有执行权限
        // 则将该内存范围添加到已监控的范围中
        addInstrumentedRange(m.range);
        return true;
      } else {
        // 如果内存映射没有名称且没有执行权限, 则返回false
        return false;
      }
    }
  }
  // 如果没有找到包含指定地址的内存映射, 返回false
  return false;
}
bool ExecBroker::addInstrumentedModuleFromAddr(rword addr) {
  // 遍历当前进程的内存映射
  for (const MemoryMap &m : getCurrentProcessMaps()) {
    // 检查当前内存映射是否包含指定地址
    if (m.range.contains(addr)) {
      // 如果内存映射有名称(即是一个已知的模块)
      if (not m.name.empty()) {
        // 尝试将该模块添加到已监控的模块列表中
        return addInstrumentedModule(m.name);
      } else if (m.permission & QBDI::PF_EXEC) {
        // 如果内存映射没有名称, 但具有执行权限
        // 则将该内存范围添加到已监控的范围中
        addInstrumentedRange(m.range);
        return true;
      } else {
        // 如果内存映射没有名称且没有执行权限, 则返回false
        return false;
      }
    }
  }
  // 如果没有找到包含指定地址的内存映射, 返回false
  return false;
}
QBDI_EXPORT std::vector<MemoryMap>
getCurrentProcessMaps(bool full_path = false);
 
std::vector<MemoryMap> getCurrentProcessMaps(bool full_path) {
  return getRemoteProcessMaps(getpid(), full_path);
}
 
// 获取指定进程的内存映射
std::vector<MemoryMap> getRemoteProcessMaps(QBDI::rword pid, bool full_path) {
  static const int BUFFER_SIZE = 256; // 定义缓冲区大小
  char line[BUFFER_SIZE] = {0}; // 用于存储读取的每一行数据
  FILE *mapfile = nullptr; // 文件指针, 用于打开 /proc/[pid]/maps 文件
  std::vector<MemoryMap> maps; // 用于存储解析后的内存映射信息
 
  // 构造 /proc/[pid]/maps 文件的路径
  snprintf(line, BUFFER_SIZE, "/proc/%llu/maps", (unsigned long long)pid);
  // 打开文件
  mapfile = fopen(line, "r");
  // 打印调试信息
  QBDI_DEBUG("Querying memory maps from {}", line);
  // 确保文件打开成功
  QBDI_REQUIRE_ACTION(mapfile != nullptr, return maps);
 
  // 处理 /proc/[pid]/maps 文件中的每一行
  while (fgets(line, BUFFER_SIZE, mapfile) != nullptr) {
    char *ptr = nullptr; // 用于指向当前解析的位置
    MemoryMap m; // 创建一个 MemoryMap 对象, 用于存储当前行的解析结果
 
    // 去掉行尾的换行符
    if ((ptr = strchr(line, '\n')) != nullptr) {
      *ptr = '\0';
    }
    ptr = line; // 从行首开始解析
    QBDI_DEBUG("Parsing line: {}", line);
 
    // 解析内存范围
    m.range.setStart(strtoul(ptr, &ptr, 16)); // 解析起始地址
    ptr++; // 跳过 '-'
    m.range.setEnd(strtoul(ptr, &ptr, 16)); // 解析结束地址
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 解析权限标志
    m.permission = QBDI::PF_NONE; // 初始化权限标志
    if (*ptr == 'r') // 读权限
      m.permission |= QBDI::PF_READ;
    ptr++;
    if (*ptr == 'w') // 写权限
      m.permission |= QBDI::PF_WRITE;
    ptr++;
    if (*ptr == 'x') // 执行权限
      m.permission |= QBDI::PF_EXEC;
    ptr++;
    ptr++; // 跳过保护标志
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 跳过文件偏移量
    strtoul(ptr, &ptr, 16);
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 跳过设备 ID
    strtoul(ptr, &ptr, 16);
    ptr++; // 跳过 ':'
    strtoul(ptr, &ptr, 16);
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 跳过 inode
    strtoul(ptr, &ptr, 10);
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 获取文件名
    if (full_path) {
      m.name = ptr; // 如果需要完整路径, 则直接使用文件名
    } else {
      if ((ptr = strrchr(ptr, '/')) != nullptr) {
        m.name = ptr + 1; // 如果不需要完整路径, 则只保留文件名
      } else {
        m.name.clear(); // 如果没有路径分隔符, 则清空文件名
      }
    }
 
    // 打印调试信息
    QBDI_DEBUG("Read new map [0x{:x}, 0x{:x}] {} {}{}{}", m.range.start(),
               m.range.end(), m.name.c_str(),
               (m.permission & QBDI::PF_READ) ? "r" : "-",
               (m.permission & QBDI::PF_WRITE) ? "w" : "-",
               (m.permission & QBDI::PF_EXEC) ? "x" : "-");
    maps.push_back(m); // 将解析后的内存映射信息添加到列表中
  }
  fclose(mapfile); // 关闭文件
  return maps; // 返回内存映射列表
}
QBDI_EXPORT std::vector<MemoryMap>
getCurrentProcessMaps(bool full_path = false);
 
std::vector<MemoryMap> getCurrentProcessMaps(bool full_path) {
  return getRemoteProcessMaps(getpid(), full_path);
}
 
// 获取指定进程的内存映射
std::vector<MemoryMap> getRemoteProcessMaps(QBDI::rword pid, bool full_path) {
  static const int BUFFER_SIZE = 256; // 定义缓冲区大小
  char line[BUFFER_SIZE] = {0}; // 用于存储读取的每一行数据
  FILE *mapfile = nullptr; // 文件指针, 用于打开 /proc/[pid]/maps 文件
  std::vector<MemoryMap> maps; // 用于存储解析后的内存映射信息
 
  // 构造 /proc/[pid]/maps 文件的路径
  snprintf(line, BUFFER_SIZE, "/proc/%llu/maps", (unsigned long long)pid);
  // 打开文件
  mapfile = fopen(line, "r");
  // 打印调试信息
  QBDI_DEBUG("Querying memory maps from {}", line);
  // 确保文件打开成功
  QBDI_REQUIRE_ACTION(mapfile != nullptr, return maps);
 
  // 处理 /proc/[pid]/maps 文件中的每一行
  while (fgets(line, BUFFER_SIZE, mapfile) != nullptr) {
    char *ptr = nullptr; // 用于指向当前解析的位置
    MemoryMap m; // 创建一个 MemoryMap 对象, 用于存储当前行的解析结果
 
    // 去掉行尾的换行符
    if ((ptr = strchr(line, '\n')) != nullptr) {
      *ptr = '\0';
    }
    ptr = line; // 从行首开始解析
    QBDI_DEBUG("Parsing line: {}", line);
 
    // 解析内存范围
    m.range.setStart(strtoul(ptr, &ptr, 16)); // 解析起始地址
    ptr++; // 跳过 '-'
    m.range.setEnd(strtoul(ptr, &ptr, 16)); // 解析结束地址
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 解析权限标志
    m.permission = QBDI::PF_NONE; // 初始化权限标志
    if (*ptr == 'r') // 读权限
      m.permission |= QBDI::PF_READ;
    ptr++;
    if (*ptr == 'w') // 写权限
      m.permission |= QBDI::PF_WRITE;
    ptr++;
    if (*ptr == 'x') // 执行权限
      m.permission |= QBDI::PF_EXEC;
    ptr++;
    ptr++; // 跳过保护标志
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 跳过文件偏移量
    strtoul(ptr, &ptr, 16);
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 跳过设备 ID
    strtoul(ptr, &ptr, 16);
    ptr++; // 跳过 ':'
    strtoul(ptr, &ptr, 16);
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 跳过 inode
    strtoul(ptr, &ptr, 10);
 
    // 跳过空格
    while (isspace(*ptr))
      ptr++;
 
    // 获取文件名
    if (full_path) {
      m.name = ptr; // 如果需要完整路径, 则直接使用文件名
    } else {
      if ((ptr = strrchr(ptr, '/')) != nullptr) {
        m.name = ptr + 1; // 如果不需要完整路径, 则只保留文件名
      } else {
        m.name.clear(); // 如果没有路径分隔符, 则清空文件名
      }
    }
 
    // 打印调试信息
    QBDI_DEBUG("Read new map [0x{:x}, 0x{:x}] {} {}{}{}", m.range.start(),
               m.range.end(), m.name.c_str(),
               (m.permission & QBDI::PF_READ) ? "r" : "-",
               (m.permission & QBDI::PF_WRITE) ? "w" : "-",
               (m.permission & QBDI::PF_EXEC) ? "x" : "-");
    maps.push_back(m); // 将解析后的内存映射信息添加到列表中
  }
  fclose(mapfile); // 关闭文件
  return maps; // 返回内存映射列表
}
bool ExecBroker::addInstrumentedModule(const std::string &name) {
  bool instrumented = false;
  if (name.empty()) {
    return false;
  }
 
  for (const MemoryMap &m : getCurrentProcessMaps()) {
    if ((m.name == name) && (m.permission & QBDI::PF_EXEC)) {
      addInstrumentedRange(m.range);
      instrumented = true;
    }
  }
  return instrumented;
}
 
void ExecBroker::addInstrumentedRange(const Range<rword> &r) {
  QBDI_DEBUG("Adding instrumented range [0x{:x}, 0x{:x}]", r.start(), r.end());
  instrumented.add(r);
}
bool ExecBroker::addInstrumentedModule(const std::string &name) {
  bool instrumented = false;
  if (name.empty()) {
    return false;
  }
 
  for (const MemoryMap &m : getCurrentProcessMaps()) {
    if ((m.name == name) && (m.permission & QBDI::PF_EXEC)) {
      addInstrumentedRange(m.range);
      instrumented = true;
    }
  }
  return instrumented;
}
 
void ExecBroker::addInstrumentedRange(const Range<rword> &r) {
  QBDI_DEBUG("Adding instrumented range [0x{:x}, 0x{:x}]", r.start(), r.end());
  instrumented.add(r);
}
bool ExecBroker::addInstrumentedModuleFromAddr(rword addr) {
  for (const MemoryMap &m : getCurrentProcessMaps()) {
    if (m.range.contains(addr)) {
      if (not m.name.empty()) {
        return addInstrumentedModule(m.name);
      } else if (m.permission & QBDI::PF_EXEC) {
        addInstrumentedRange(m.range);
        return true;
      } else {
        return false;
      }
    }
  }
  return false;
}
bool ExecBroker::addInstrumentedModuleFromAddr(rword addr) {
  for (const MemoryMap &m : getCurrentProcessMaps()) {
    if (m.range.contains(addr)) {
      if (not m.name.empty()) {
        return addInstrumentedModule(m.name);
      } else if (m.permission & QBDI::PF_EXEC) {
        addInstrumentedRange(m.range);
        return true;
      } else {
        return false;
      }
    }
  }
  return false;
}
/*! 使用 DBI(及其当前状态)调用一个函数.
 *  当 VM 已经运行时, 不能调用此方法.
 *
 * @param[in] instance   VM 实例.
 * @param[in] [retval]   指向返回值的指针(可选).
 * @param[in] function   函数起始指令的地址.
 * @param[in] argNum     可变参数列表中的参数数量.
 * @param[in] ...        可变参数列表.
 *
 * @return  如果至少执行了一个块, 则返回 True.
 *
 * @details 示例:
 *
 *     // 使用 QBDI 执行类似于 (*funcPtr)(42) 的调用
 *     uint8_t *fakestack = NULL;
 *     VMInstanceRef vm;
 *     qbdi_initVM(&vm, NULL, NULL);
 *     GPRState* gprState = qbdi_getGPRState(vm);
 *     qbdi_allocateVirtualStack(gprState, 0x1000000, &fakestack);
 *     qbdi_addInstrumentedModuleFromAddr(vm, funcPtr);
 *     rword retVal;
 *     qbdi_call(vm, &retVal, funcPtr, 1, 42);
 *     qbdi_alignedFree(fakestack);
 *
 */
QBDI_EXPORT bool qbdi_call(VMInstanceRef instance, rword *retval,
                           rword function, uint32_t argNum, ...);
/*! 使用 DBI(及其当前状态)调用一个函数.
 *  当 VM 已经运行时, 不能调用此方法.
 *
 * @param[in] instance   VM 实例.
 * @param[in] [retval]   指向返回值的指针(可选).
 * @param[in] function   函数起始指令的地址.
 * @param[in] argNum     可变参数列表中的参数数量.
 * @param[in] ...        可变参数列表.
 *
 * @return  如果至少执行了一个块, 则返回 True.
 *
 * @details 示例:
 *
 *     // 使用 QBDI 执行类似于 (*funcPtr)(42) 的调用
 *     uint8_t *fakestack = NULL;
 *     VMInstanceRef vm;
 *     qbdi_initVM(&vm, NULL, NULL);
 *     GPRState* gprState = qbdi_getGPRState(vm);
 *     qbdi_allocateVirtualStack(gprState, 0x1000000, &fakestack);
 *     qbdi_addInstrumentedModuleFromAddr(vm, funcPtr);
 *     rword retVal;
 *     qbdi_call(vm, &retVal, funcPtr, 1, 42);
 *     qbdi_alignedFree(fakestack);
 *
 */
QBDI_EXPORT bool qbdi_call(VMInstanceRef instance, rword *retval,
                           rword function, uint32_t argNum, ...);
bool qbdi_call(VMInstanceRef instance, rword *retval, rword function,
               uint32_t argNum, ...) {
  QBDI_REQUIRE_ACTION(instance, return false);
  va_list ap;
  va_start(ap, argNum);
  bool res = static_cast<VM *>(instance)->callV(retval, function, argNum, ap);
  va_end(ap);
  return res;
}
bool qbdi_call(VMInstanceRef instance, rword *retval, rword function,
               uint32_t argNum, ...) {
  QBDI_REQUIRE_ACTION(instance, return false);
  va_list ap;
  va_start(ap, argNum);
  bool res = static_cast<VM *>(instance)->callV(retval, function, argNum, ap);
  va_end(ap);
  return res;
}
bool VM::callV(rword *retval, rword function, uint32_t argNum, va_list ap) {
  std::vector<rword> args(argNum);
  for (uint32_t i = 0; i < argNum; i++) {
    args[i] = va_arg(ap, rword);
  }
 
  bool res = this->callA(retval, function, argNum, args.data());
 
  return res;
}
bool VM::callV(rword *retval, rword function, uint32_t argNum, va_list ap) {
  std::vector<rword> args(argNum);
  for (uint32_t i = 0; i < argNum; i++) {
    args[i] = va_arg(ap, rword);
  }
 
  bool res = this->callA(retval, function, argNum, args.data());
 
  return res;
}
#define FAKE_RET_ADDR 42
 
bool VM::callA(rword *retval, rword function, uint32_t argNum,
               const rword *args) {
  GPRState *state = getGPRState();
  QBDI_REQUIRE_ABORT(state != nullptr, "Fail to get VM GPRState");
 
  // a stack pointer must be set in state
  if (QBDI_GPR_GET(state, REG_SP) == 0) {
    return false;
  }
  // push arguments in current context
  simulateCallA(state, FAKE_RET_ADDR, argNum, args);
  // call function
  bool res = run(function, FAKE_RET_ADDR);
  // get return value from current state
  if (retval != nullptr) {
    *retval = QBDI_GPR_GET(state, REG_RETURN);
  }
  return res;
}
#define FAKE_RET_ADDR 42
 
bool VM::callA(rword *retval, rword function, uint32_t argNum,
               const rword *args) {
  GPRState *state = getGPRState();
  QBDI_REQUIRE_ABORT(state != nullptr, "Fail to get VM GPRState");
 
  // a stack pointer must be set in state
  if (QBDI_GPR_GET(state, REG_SP) == 0) {
    return false;
  }
  // push arguments in current context
  simulateCallA(state, FAKE_RET_ADDR, argNum, args);
  // call function
  bool res = run(function, FAKE_RET_ADDR);
  // get return value from current state
  if (retval != nullptr) {
    *retval = QBDI_GPR_GET(state, REG_RETURN);
  }
  return res;
}
#define FRAME_LENGTH 16
 
void simulateCallA(GPRState *ctx, rword returnAddress, uint32_t argNum,
                   const rword *args) {
  uint32_t i = 0; // 用于遍历参数的索引
  uint32_t argsoff = 0; // 用于计算栈帧偏移
  uint32_t limit = FRAME_LENGTH; // 栈帧的最大长度
 
  // 为参数分配栈帧
  QBDI_GPR_SET(ctx, REG_SP,
               QBDI_GPR_GET(ctx, REG_SP) - FRAME_LENGTH * sizeof(rword));
 
  // 处理返回地址
#if defined(QBDI_ARCH_X86_64) || defined(QBDI_ARCH_X86)
  // 在 x86 和 x86_64 架构上, 返回地址存储在栈上
  QBDI_GPR_SET(ctx, REG_SP, QBDI_GPR_GET(ctx, REG_SP) - sizeof(rword));
  *(rword *)(QBDI_GPR_GET(ctx, REG_SP)) = returnAddress; // 将返回地址压入栈
  argsoff++;
#elif defined(QBDI_ARCH_ARM) || defined(QBDI_ARCH_AARCH64)
  // 在 ARM 和 AArch64 架构上, 返回地址存储在链接寄存器中
  QBDI_DEBUG("Set LR to: 0x{:x}", returnAddress);
  ctx->lr = returnAddress; // 设置链接寄存器
#endif
 
#define UNSTACK_ARG(REG)  \
  if (i < argNum) {       \
    ctx->REG = args[i++]; \
  }
  // 根据架构不同, 将参数加载到寄存器中
#if defined(QBDI_ARCH_X86_64)
#if defined(QBDI_PLATFORM_WINDOWS)
  // Windows 平台的 x86_64 架构有影子空间, 在Windows平台的x86_64架构中, 为了确保栈对齐和兼容性, 调用者需要在栈上预留一个固定大小的空间, 这个空间被称为影子空间
  argsoff += 4;
  // 寄存器参数
  UNSTACK_ARG(rcx);
  UNSTACK_ARG(rdx);
  UNSTACK_ARG(r8);
  UNSTACK_ARG(r9);
#else
  // 非 Windows 平台的 x86_64 架构
  // 寄存器参数
  UNSTACK_ARG(rdi);
  UNSTACK_ARG(rsi);
  UNSTACK_ARG(rdx);
  UNSTACK_ARG(rcx);
  UNSTACK_ARG(r8);
  UNSTACK_ARG(r9);
#endif // OS
#elif defined(QBDI_ARCH_X86)
  // x86 架构不使用寄存器传递参数
#elif defined(QBDI_ARCH_ARM)
  // ARM 架构的寄存器参数
  UNSTACK_ARG(r0);
  UNSTACK_ARG(r1);
  UNSTACK_ARG(r2);
  UNSTACK_ARG(r3);
#elif defined(QBDI_ARCH_AARCH64)
  // AArch64 架构的寄存器参数
  UNSTACK_ARG(x0);
  UNSTACK_ARG(x1);
  UNSTACK_ARG(x2);
  UNSTACK_ARG(x3);
  UNSTACK_ARG(x4);
  UNSTACK_ARG(x5);
  UNSTACK_ARG(x6);
  UNSTACK_ARG(x7);
#endif // ARCH
#undef UNSTACK_ARG
  limit -= argsoff;
 
  // 将剩余的参数压入栈
  rword *frame = (rword *)QBDI_GPR_GET(ctx, REG_SP);
  for (uint32_t j = 0; (i + j) < argNum && j < limit; j++) {
    frame[argsoff + j] = args[i + j];
  }
}
#define FRAME_LENGTH 16
 
void simulateCallA(GPRState *ctx, rword returnAddress, uint32_t argNum,
                   const rword *args) {
  uint32_t i = 0; // 用于遍历参数的索引
  uint32_t argsoff = 0; // 用于计算栈帧偏移
  uint32_t limit = FRAME_LENGTH; // 栈帧的最大长度
 
  // 为参数分配栈帧
  QBDI_GPR_SET(ctx, REG_SP,
               QBDI_GPR_GET(ctx, REG_SP) - FRAME_LENGTH * sizeof(rword));
 
  // 处理返回地址
#if defined(QBDI_ARCH_X86_64) || defined(QBDI_ARCH_X86)
  // 在 x86 和 x86_64 架构上, 返回地址存储在栈上
  QBDI_GPR_SET(ctx, REG_SP, QBDI_GPR_GET(ctx, REG_SP) - sizeof(rword));
  *(rword *)(QBDI_GPR_GET(ctx, REG_SP)) = returnAddress; // 将返回地址压入栈
  argsoff++;
#elif defined(QBDI_ARCH_ARM) || defined(QBDI_ARCH_AARCH64)
  // 在 ARM 和 AArch64 架构上, 返回地址存储在链接寄存器中
  QBDI_DEBUG("Set LR to: 0x{:x}", returnAddress);
  ctx->lr = returnAddress; // 设置链接寄存器
#endif
 
#define UNSTACK_ARG(REG)  \
  if (i < argNum) {       \
    ctx->REG = args[i++]; \
  }
  // 根据架构不同, 将参数加载到寄存器中
#if defined(QBDI_ARCH_X86_64)
#if defined(QBDI_PLATFORM_WINDOWS)
  // Windows 平台的 x86_64 架构有影子空间, 在Windows平台的x86_64架构中, 为了确保栈对齐和兼容性, 调用者需要在栈上预留一个固定大小的空间, 这个空间被称为影子空间
  argsoff += 4;
  // 寄存器参数
  UNSTACK_ARG(rcx);
  UNSTACK_ARG(rdx);
  UNSTACK_ARG(r8);
  UNSTACK_ARG(r9);
#else
  // 非 Windows 平台的 x86_64 架构
  // 寄存器参数
  UNSTACK_ARG(rdi);
  UNSTACK_ARG(rsi);
  UNSTACK_ARG(rdx);
  UNSTACK_ARG(rcx);
  UNSTACK_ARG(r8);
  UNSTACK_ARG(r9);
#endif // OS
#elif defined(QBDI_ARCH_X86)
  // x86 架构不使用寄存器传递参数
#elif defined(QBDI_ARCH_ARM)
  // ARM 架构的寄存器参数
  UNSTACK_ARG(r0);
  UNSTACK_ARG(r1);
  UNSTACK_ARG(r2);
  UNSTACK_ARG(r3);
#elif defined(QBDI_ARCH_AARCH64)
  // AArch64 架构的寄存器参数
  UNSTACK_ARG(x0);
  UNSTACK_ARG(x1);
  UNSTACK_ARG(x2);
  UNSTACK_ARG(x3);
  UNSTACK_ARG(x4);
  UNSTACK_ARG(x5);
  UNSTACK_ARG(x6);
  UNSTACK_ARG(x7);
#endif // ARCH
#undef UNSTACK_ARG
  limit -= argsoff;
 
  // 将剩余的参数压入栈
  rword *frame = (rword *)QBDI_GPR_GET(ctx, REG_SP);
  for (uint32_t j = 0; (i + j) < argNum && j < limit; j++) {
    frame[argsoff + j] = args[i + j];
  }
}
bool VM::run(rword start, rword stop) {
  uint32_t stopCB =
      addCodeAddrCB(stop, InstPosition::PREINST, stopCallback, nullptr);
  bool ret = engine->run(start, stop);
  deleteInstrumentation(stopCB);
  return ret;
}
bool VM::run(rword start, rword stop) {
  uint32_t stopCB =
      addCodeAddrCB(stop, InstPosition::PREINST, stopCallback, nullptr);
  bool ret = engine->run(start, stop);
  deleteInstrumentation(stopCB);
  return ret;
}
VMAction stopCallback(VMInstanceRef vm, GPRState *gprState, FPRState *fprState,
                      void *data) {
  return VMAction::STOP;
}
VMAction stopCallback(VMInstanceRef vm, GPRState *gprState, FPRState *fprState,
                      void *data) {
  return VMAction::STOP;
}
uint32_t VM::addCodeAddrCB(rword address, InstPosition pos, InstCallback cbk,
                           void *data, int priority) {
  QBDI_REQUIRE_ACTION(cbk != nullptr, return VMError::INVALID_EVENTID);
  return engine->addInstrRule(InstrRuleBasicCBK::unique(
      AddressIs::unique(address), cbk, data, pos, true, priority,
      (pos == PREINST) ? RelocTagPreInstStdCBK : RelocTagPostInstStdCBK));
}
uint32_t VM::addCodeAddrCB(rword address, InstPosition pos, InstCallback cbk,
                           void *data, int priority) {
  QBDI_REQUIRE_ACTION(cbk != nullptr, return VMError::INVALID_EVENTID);
  return engine->addInstrRule(InstrRuleBasicCBK::unique(
      AddressIs::unique(address), cbk, data, pos, true, priority,
      (pos == PREINST) ? RelocTagPreInstStdCBK : RelocTagPostInstStdCBK));
}
class AddressIs : public AutoClone<PatchCondition, AddressIs> {
  rword breakpoint;
 
public:
  /*! Return true if on specified address
   */
  AddressIs(rword breakpoint_) : breakpoint(breakpoint_) {
    // for ARM, remove the LSB
    if constexpr (is_arm) {
      breakpoint &= (~1);
    }
  }
 
  bool test(const Patch &patch, const LLVMCPU &llvmcpu) const override {
    return patch.metadata.address == breakpoint;
  }
 
  RangeSet<rword> affectedRange() const override {
    RangeSet<rword> r;
    r.add(Range<rword>(breakpoint, breakpoint + 1));
    return r;
  }
};
class AddressIs : public AutoClone<PatchCondition, AddressIs> {
  rword breakpoint;
 
public:
  /*! Return true if on specified address
   */
  AddressIs(rword breakpoint_) : breakpoint(breakpoint_) {
    // for ARM, remove the LSB
    if constexpr (is_arm) {
      breakpoint &= (~1);
    }
  }
 
  bool test(const Patch &patch, const LLVMCPU &llvmcpu) const override {
    return patch.metadata.address == breakpoint;
  }
 
  RangeSet<rword> affectedRange() const override {
    RangeSet<rword> r;
    r.add(Range<rword>(breakpoint, breakpoint + 1));
    return r;
  }
};
bool Engine::run(rword start, rword stop) {
  QBDI_REQUIRE_ABORT(not running, "Cannot run an already running Engine");
 
  rword currentPC = start;
  bool hasRan = false;
  curGPRState = gprState.get();
  curFPRState = fprState.get();
 
  rword basicBlockBeginAddr = 0;
  rword basicBlockEndAddr = 0;
 
  // Start address is out of range
  if (!execBroker->isInstrumented(start)) {
    return false;
  }
 
  running = true;
 
  // Execute basic block per basic block
  do {
    VMAction action = CONTINUE;
 
    // If this PC is not instrumented try to transfer execution
    if (execBroker->isInstrumented(currentPC) == false and
        execBroker->canTransferExecution(curGPRState)) {
 
#if defined(QBDI_ARCH_ARM)
      // Handle ARM mode
      // If we switch to the execbroker without an exchange, keep the current
      // mode
      bool changeCPUMode = curExecBlock == nullptr ||
                           curExecBlock->getContext()->hostState.exchange == 1;
      if (not changeCPUMode) {
        if (curCPUMode == CPUMode::Thumb) {
          currentPC = currentPC | 1;
        } else {
          currentPC = currentPC & (~1);
        }
      }
#endif
 
      curExecBlock = nullptr;
      basicBlockBeginAddr = 0;
      basicBlockEndAddr = 0;
 
      QBDI_DEBUG("Executing 0x{:x} through execBroker", currentPC);
      action = signalEvent(EXEC_TRANSFER_CALL, currentPC, nullptr, 0,
                           curGPRState, curFPRState);
      // transfer execution
      if (action == CONTINUE) {
        execBroker->transferExecution(currentPC, curGPRState, curFPRState);
        action = signalEvent(EXEC_TRANSFER_RETURN, currentPC, nullptr, 0,
                             curGPRState, curFPRState);
      }
    }
    // Else execute through DBI
    else {
      VMEvent event = VMEvent::SEQUENCE_ENTRY;
 
#if defined(QBDI_ARCH_ARM)
      // Handle ARM mode switching, only at the start of an execution or when
      // the guest signal an exchange.
      bool changeCPUMode = curExecBlock == nullptr ||
                           curExecBlock->getContext()->hostState.exchange == 1;
      if (changeCPUMode) {
        curCPUMode = currentPC & 1 ? CPUMode::Thumb : CPUMode::ARM;
        QBDI_DEBUG("CPUMode set to {}",
                   curCPUMode == CPUMode::ARM ? "ARM" : "Thumb");
      } else if (curCPUMode == CPUMode::ARM) {
        QBDI_REQUIRE_ABORT((currentPC & 1) == 0,
                           "Unexpected address in ARM mode");
      } else {
        QBDI_REQUIRE_ABORT((currentPC & 1) == 1,
                           "Unexpected address in Thumb mode");
      }
      currentPC = currentPC & (~1);
#endif
 
      QBDI_DEBUG("Executing 0x{:x} through DBI in mode {}", currentPC,
                 curCPUMode);
 
      // Is cache flush pending?
      if (blockManager->isFlushPending()) {
        // Backup fprState and gprState
        *gprState = *curGPRState;
        *fprState = *curFPRState;
        curGPRState = gprState.get();
        curFPRState = fprState.get();
        // Commit the flush
        blockManager->flushCommit();
      }
 
      // Test if we have it in cache
      SeqLoc currentSequence;
      curExecBlock = blockManager->getProgrammedExecBlock(currentPC, curCPUMode,
                                                          &currentSequence);
      if (curExecBlock == nullptr) {
        QBDI_DEBUG(
            "Cache miss for 0x{:x}, patching & instrumenting new basic block",
            currentPC);
        handleNewBasicBlock(currentPC);
        // Signal a new basic block
        event |= BASIC_BLOCK_NEW;
        // Set new basic block as current
        curExecBlock = blockManager->getProgrammedExecBlock(
            currentPC, curCPUMode, &currentSequence);
        QBDI_REQUIRE_ABORT(curExecBlock != nullptr,
                           "Fail to instrument the next basic block");
      }
 
      if (basicBlockEndAddr == 0) {
        event |= BASIC_BLOCK_ENTRY;
        basicBlockEndAddr = currentSequence.bbEnd;
        basicBlockBeginAddr = currentPC;
      }
 
      // Set context if necessary
      if (&(curExecBlock->getContext()->gprState) != curGPRState ||
          &(curExecBlock->getContext()->fprState) != curFPRState) {
        curExecBlock->getContext()->gprState = *curGPRState;
        curExecBlock->getContext()->fprState = *curFPRState;
      }
      curGPRState = &(curExecBlock->getContext()->gprState);
      curFPRState = &(curExecBlock->getContext()->fprState);
 
      action = signalEvent(event, currentPC, &currentSequence,
                           basicBlockBeginAddr, curGPRState, curFPRState);
 
      if (action == CONTINUE) {
        hasRan = true;
        action = curExecBlock->execute();
        // Signal events if normal exit
        if (action == CONTINUE) {
          if (basicBlockEndAddr == currentSequence.seqEnd) {
            action = signalEvent(SEQUENCE_EXIT | BASIC_BLOCK_EXIT, currentPC,
                                 &currentSequence, basicBlockBeginAddr,
                                 curGPRState, curFPRState);
            basicBlockBeginAddr = 0;
            basicBlockEndAddr = 0;
          } else {
            action = signalEvent(SEQUENCE_EXIT, currentPC, &currentSequence,
                                 basicBlockBeginAddr, curGPRState, curFPRState);
          }
        }
      }
    }
    if (action == STOP) {
      QBDI_DEBUG("Receive STOP Action");
      break;
    }
    if (action != CONTINUE) {
      basicBlockBeginAddr = 0;
      basicBlockEndAddr = 0;
      curExecBlock = nullptr;
    }
    // Get next block PC
    currentPC = QBDI_GPR_GET(curGPRState, REG_PC);
    QBDI_DEBUG("Next address to execute is 0x{:x}", currentPC);
  } while (currentPC != stop);
 
  // Copy final context
  *gprState = *curGPRState;
  *fprState = *curFPRState;
  curGPRState = gprState.get();
  curFPRState = fprState.get();
  curExecBlock = nullptr;
  running = false;
 
  if (blockManager->isFlushPending()) {
    blockManager->flushCommit();
  }
 
  return hasRan;
}
bool Engine::run(rword start, rword stop) {
  QBDI_REQUIRE_ABORT(not running, "Cannot run an already running Engine");
 
  rword currentPC = start;
  bool hasRan = false;
  curGPRState = gprState.get();
  curFPRState = fprState.get();
 
  rword basicBlockBeginAddr = 0;
  rword basicBlockEndAddr = 0;
 
  // Start address is out of range
  if (!execBroker->isInstrumented(start)) {
    return false;
  }
 
  running = true;
 
  // Execute basic block per basic block
  do {
    VMAction action = CONTINUE;
 
    // If this PC is not instrumented try to transfer execution
    if (execBroker->isInstrumented(currentPC) == false and
        execBroker->canTransferExecution(curGPRState)) {
 
#if defined(QBDI_ARCH_ARM)
      // Handle ARM mode
      // If we switch to the execbroker without an exchange, keep the current
      // mode
      bool changeCPUMode = curExecBlock == nullptr ||
                           curExecBlock->getContext()->hostState.exchange == 1;
      if (not changeCPUMode) {
        if (curCPUMode == CPUMode::Thumb) {
          currentPC = currentPC | 1;
        } else {
          currentPC = currentPC & (~1);
        }
      }
#endif
 
      curExecBlock = nullptr;
      basicBlockBeginAddr = 0;
      basicBlockEndAddr = 0;
 
      QBDI_DEBUG("Executing 0x{:x} through execBroker", currentPC);
      action = signalEvent(EXEC_TRANSFER_CALL, currentPC, nullptr, 0,
                           curGPRState, curFPRState);
      // transfer execution
      if (action == CONTINUE) {
        execBroker->transferExecution(currentPC, curGPRState, curFPRState);
        action = signalEvent(EXEC_TRANSFER_RETURN, currentPC, nullptr, 0,
                             curGPRState, curFPRState);
      }
    }
    // Else execute through DBI
    else {
      VMEvent event = VMEvent::SEQUENCE_ENTRY;
 
#if defined(QBDI_ARCH_ARM)
      // Handle ARM mode switching, only at the start of an execution or when
      // the guest signal an exchange.
      bool changeCPUMode = curExecBlock == nullptr ||
                           curExecBlock->getContext()->hostState.exchange == 1;
      if (changeCPUMode) {
        curCPUMode = currentPC & 1 ? CPUMode::Thumb : CPUMode::ARM;
        QBDI_DEBUG("CPUMode set to {}",
                   curCPUMode == CPUMode::ARM ? "ARM" : "Thumb");
      } else if (curCPUMode == CPUMode::ARM) {
        QBDI_REQUIRE_ABORT((currentPC & 1) == 0,
                           "Unexpected address in ARM mode");
      } else {
        QBDI_REQUIRE_ABORT((currentPC & 1) == 1,
                           "Unexpected address in Thumb mode");
      }
      currentPC = currentPC & (~1);
#endif
 
      QBDI_DEBUG("Executing 0x{:x} through DBI in mode {}", currentPC,
                 curCPUMode);
 
      // Is cache flush pending?
      if (blockManager->isFlushPending()) {
        // Backup fprState and gprState
        *gprState = *curGPRState;
        *fprState = *curFPRState;
        curGPRState = gprState.get();
        curFPRState = fprState.get();
        // Commit the flush
        blockManager->flushCommit();
      }
 
      // Test if we have it in cache
      SeqLoc currentSequence;
      curExecBlock = blockManager->getProgrammedExecBlock(currentPC, curCPUMode,
                                                          &currentSequence);
      if (curExecBlock == nullptr) {
        QBDI_DEBUG(
            "Cache miss for 0x{:x}, patching & instrumenting new basic block",
            currentPC);
        handleNewBasicBlock(currentPC);
        // Signal a new basic block
        event |= BASIC_BLOCK_NEW;
        // Set new basic block as current
        curExecBlock = blockManager->getProgrammedExecBlock(
            currentPC, curCPUMode, &currentSequence);
        QBDI_REQUIRE_ABORT(curExecBlock != nullptr,
                           "Fail to instrument the next basic block");
      }
 
      if (basicBlockEndAddr == 0) {
        event |= BASIC_BLOCK_ENTRY;
        basicBlockEndAddr = currentSequence.bbEnd;
        basicBlockBeginAddr = currentPC;
      }
 
      // Set context if necessary
      if (&(curExecBlock->getContext()->gprState) != curGPRState ||
          &(curExecBlock->getContext()->fprState) != curFPRState) {
        curExecBlock->getContext()->gprState = *curGPRState;
        curExecBlock->getContext()->fprState = *curFPRState;
      }
      curGPRState = &(curExecBlock->getContext()->gprState);
      curFPRState = &(curExecBlock->getContext()->fprState);
 
      action = signalEvent(event, currentPC, &currentSequence,
                           basicBlockBeginAddr, curGPRState, curFPRState);
 
      if (action == CONTINUE) {
        hasRan = true;
        action = curExecBlock->execute();
        // Signal events if normal exit
        if (action == CONTINUE) {
          if (basicBlockEndAddr == currentSequence.seqEnd) {
            action = signalEvent(SEQUENCE_EXIT | BASIC_BLOCK_EXIT, currentPC,
                                 &currentSequence, basicBlockBeginAddr,
                                 curGPRState, curFPRState);
            basicBlockBeginAddr = 0;
            basicBlockEndAddr = 0;
          } else {
            action = signalEvent(SEQUENCE_EXIT, currentPC, &currentSequence,
                                 basicBlockBeginAddr, curGPRState, curFPRState);
          }
        }
      }
    }
    if (action == STOP) {
      QBDI_DEBUG("Receive STOP Action");
      break;
    }
    if (action != CONTINUE) {
      basicBlockBeginAddr = 0;
      basicBlockEndAddr = 0;
      curExecBlock = nullptr;
    }
    // Get next block PC
    currentPC = QBDI_GPR_GET(curGPRState, REG_PC);
    QBDI_DEBUG("Next address to execute is 0x{:x}", currentPC);
  } while (currentPC != stop);
 
  // Copy final context
  *gprState = *curGPRState;
  *fprState = *curFPRState;
  curGPRState = gprState.get();
  curFPRState = fprState.get();
  curExecBlock = nullptr;
  running = false;
 
  if (blockManager->isFlushPending()) {
    blockManager->flushCommit();
  }
 
  return hasRan;
}
std::unique_ptr<GPRState> gprState;
std::unique_ptr<FPRState> fprState;
std::unique_ptr<GPRState> gprState;
std::unique_ptr<FPRState> fprState;
/*! X86_64 Floating Point Register context.
 */ // SPHINX_X86_64_FPRSTATE_BEGIN
typedef struct QBDI_ALIGNED(16) {
  union {
    FPControl fcw; /* x87 FPU control word */
    uint16_t rfcw;
  };
  union {
    FPStatus fsw; /* x87 FPU status word */
    uint16_t rfsw;
  };
  uint8_t ftw;        /* x87 FPU tag word */
  uint8_t rsrv1;      /* reserved */
  uint16_t fop;       /* x87 FPU Opcode */
  uint32_t ip;        /* x87 FPU Instruction Pointer offset */
  uint16_t cs;        /* x87 FPU Instruction Pointer Selector */
  uint16_t rsrv2;     /* reserved */
  uint32_t dp;        /* x87 FPU Instruction Operand(Data) Pointer offset */
  uint16_t ds;        /* x87 FPU Instruction Operand(Data) Pointer Selector */
  uint16_t rsrv3;     /* reserved */
  uint32_t mxcsr;     /* MXCSR Register state */
  uint32_t mxcsrmask; /* MXCSR mask */
  MMSTReg stmm0;      /* ST0/MM0   */
  MMSTReg stmm1;      /* ST1/MM1  */
  MMSTReg stmm2;      /* ST2/MM2  */
  MMSTReg stmm3;      /* ST3/MM3  */
  MMSTReg stmm4;      /* ST4/MM4  */
  MMSTReg stmm5;      /* ST5/MM5  */
  MMSTReg stmm6;      /* ST6/MM6  */
  MMSTReg stmm7;      /* ST7/MM7  */
  char xmm0[16];      /* XMM 0  */
  char xmm1[16];      /* XMM 1  */
  char xmm2[16];      /* XMM 2  */
  char xmm3[16];      /* XMM 3  */
  char xmm4[16];      /* XMM 4  */
  char xmm5[16];      /* XMM 5  */
  char xmm6[16];      /* XMM 6  */
  char xmm7[16];      /* XMM 7  */
  char xmm8[16];      /* XMM 8  */
  char xmm9[16];      /* XMM 9  */
  char xmm10[16];     /* XMM 10  */
  char xmm11[16];     /* XMM 11  */
  char xmm12[16];     /* XMM 12  */
  char xmm13[16];     /* XMM 13  */
  char xmm14[16];     /* XMM 14  */
  char xmm15[16];     /* XMM 15  */
  char reserved[6 * 16];
  char ymm0[16];  /* YMM0[255:128] */
  char ymm1[16];  /* YMM1[255:128] */
  char ymm2[16];  /* YMM2[255:128] */
  char ymm3[16];  /* YMM3[255:128] */
  char ymm4[16];  /* YMM4[255:128] */
  char ymm5[16];  /* YMM5[255:128] */
  char ymm6[16];  /* YMM6[255:128] */
  char ymm7[16];  /* YMM7[255:128] */
  char ymm8[16];  /* YMM8[255:128] */
  char ymm9[16];  /* YMM9[255:128] */
  char ymm10[16]; /* YMM10[255:128] */
  char ymm11[16]; /* YMM11[255:128] */
  char ymm12[16]; /* YMM12[255:128] */
  char ymm13[16]; /* YMM13[255:128] */
  char ymm14[16]; /* YMM14[255:128] */
  char ymm15[16]; /* YMM15[255:128] */
} FPRState;
/*! X86_64 Floating Point Register context.
 */ // SPHINX_X86_64_FPRSTATE_BEGIN
typedef struct QBDI_ALIGNED(16) {
  union {
    FPControl fcw; /* x87 FPU control word */
    uint16_t rfcw;
  };
  union {
    FPStatus fsw; /* x87 FPU status word */
    uint16_t rfsw;
  };
  uint8_t ftw;        /* x87 FPU tag word */
  uint8_t rsrv1;      /* reserved */
  uint16_t fop;       /* x87 FPU Opcode */
  uint32_t ip;        /* x87 FPU Instruction Pointer offset */
  uint16_t cs;        /* x87 FPU Instruction Pointer Selector */
  uint16_t rsrv2;     /* reserved */
  uint32_t dp;        /* x87 FPU Instruction Operand(Data) Pointer offset */
  uint16_t ds;        /* x87 FPU Instruction Operand(Data) Pointer Selector */
  uint16_t rsrv3;     /* reserved */
  uint32_t mxcsr;     /* MXCSR Register state */
  uint32_t mxcsrmask; /* MXCSR mask */
  MMSTReg stmm0;      /* ST0/MM0   */
  MMSTReg stmm1;      /* ST1/MM1  */
  MMSTReg stmm2;      /* ST2/MM2  */
  MMSTReg stmm3;      /* ST3/MM3  */
  MMSTReg stmm4;      /* ST4/MM4  */
  MMSTReg stmm5;      /* ST5/MM5  */
  MMSTReg stmm6;      /* ST6/MM6  */
  MMSTReg stmm7;      /* ST7/MM7  */
  char xmm0[16];      /* XMM 0  */
  char xmm1[16];      /* XMM 1  */
  char xmm2[16];      /* XMM 2  */
  char xmm3[16];      /* XMM 3  */
  char xmm4[16];      /* XMM 4  */
  char xmm5[16];      /* XMM 5  */
  char xmm6[16];      /* XMM 6  */
  char xmm7[16];      /* XMM 7  */
  char xmm8[16];      /* XMM 8  */
  char xmm9[16];      /* XMM 9  */
  char xmm10[16];     /* XMM 10  */
  char xmm11[16];     /* XMM 11  */
  char xmm12[16];     /* XMM 12  */
  char xmm13[16];     /* XMM 13  */
  char xmm14[16];     /* XMM 14  */
  char xmm15[16];     /* XMM 15  */
  char reserved[6 * 16];
  char ymm0[16];  /* YMM0[255:128] */
  char ymm1[16];  /* YMM1[255:128] */
  char ymm2[16];  /* YMM2[255:128] */
  char ymm3[16];  /* YMM3[255:128] */
  char ymm4[16];  /* YMM4[255:128] */
  char ymm5[16];  /* YMM5[255:128] */
  char ymm6[16];  /* YMM6[255:128] */
  char ymm7[16];  /* YMM7[255:128] */
  char ymm8[16];  /* YMM8[255:128] */
  char ymm9[16];  /* YMM9[255:128] */
  char ymm10[16]; /* YMM10[255:128] */
  char ymm11[16]; /* YMM11[255:128] */
  char ymm12[16]; /* YMM12[255:128] */
  char ymm13[16]; /* YMM13[255:128] */
  char ymm14[16]; /* YMM14[255:128] */
  char ymm15[16]; /* YMM15[255:128] */
} FPRState;
// Start address is out of range
if (!execBroker->isInstrumented(start)) {
    return false;
}
// Start address is out of range
if (!execBroker->isInstrumented(start)) {
    return false;
}
running = true;
 
do {
    // ...
} while (currentPC != stop);
running = true;
 
do {
    // ...
} while (currentPC != stop);
/*! 回调函数执行结果.  */
typedef enum {
  _QBDI_EI(CONTINUE) = 0,    /*!< 基本块继续执行.  */
  _QBDI_EI(SKIP_INST) = 1,   /*!< 仅适用于PREINST(指令执行前)回调.
                              *   跳过当前指令及后续的PREINST回调,
                              *   直接执行POSTINST(指令执行后)回调.
                              *
                              *   建议将此结果用于低优先级的PREINST回调,
                              *   以便在跳过指令时仍保留POSTINST回调功能.
                              */
  _QBDI_EI(SKIP_PATCH) = 2,  /*!< 仅适用于InstCallback(指令回调).
                              *   跳过当前指令及剩余的PRE/POST回调,
                              *   继续执行下一条指令.
                              *
                              *   注意: 修改指令指针的指令(跳转/调用/返回)
                              *   必须使用BREAK_TO_VM而非SKIP.
                              *
                              *   SKIP可能中断当前指令的内存访问记录.
                              */
  _QBDI_EI(BREAK_TO_VM) = 3, /*!< 中断执行并返回虚拟机(VM),
                              *   触发执行状态的完整重新评估.
                              *   需BREAK_TO_VM以确保程序计数器(PC)
                              *   或程序代码的修改生效.
                              */
  _QBDI_EI(STOP) = 4,        /*!< 终止程序执行,
                              *   导致run函数提前返回.
                              */
} VMAction;
/*! 回调函数执行结果.  */
typedef enum {
  _QBDI_EI(CONTINUE) = 0,    /*!< 基本块继续执行.  */
  _QBDI_EI(SKIP_INST) = 1,   /*!< 仅适用于PREINST(指令执行前)回调.
                              *   跳过当前指令及后续的PREINST回调,
                              *   直接执行POSTINST(指令执行后)回调.
                              *
                              *   建议将此结果用于低优先级的PREINST回调,
                              *   以便在跳过指令时仍保留POSTINST回调功能.
                              */
  _QBDI_EI(SKIP_PATCH) = 2,  /*!< 仅适用于InstCallback(指令回调).
                              *   跳过当前指令及剩余的PRE/POST回调,
                              *   继续执行下一条指令.
                              *
                              *   注意: 修改指令指针的指令(跳转/调用/返回)
                              *   必须使用BREAK_TO_VM而非SKIP.
                              *
                              *   SKIP可能中断当前指令的内存访问记录.
                              */
  _QBDI_EI(BREAK_TO_VM) = 3, /*!< 中断执行并返回虚拟机(VM),
                              *   触发执行状态的完整重新评估.
                              *   需BREAK_TO_VM以确保程序计数器(PC)
                              *   或程序代码的修改生效.
                              */
  _QBDI_EI(STOP) = 4,        /*!< 终止程序执行,
                              *   导致run函数提前返回.
                              */
} VMAction;
// If this PC is not instrumented try to transfer execution
if (execBroker->isInstrumented(currentPC) == false and
    execBroker->canTransferExecution(curGPRState)){
 
} // Else execute through DBI
else {
 
}
// If this PC is not instrumented try to transfer execution
if (execBroker->isInstrumented(currentPC) == false and
    execBroker->canTransferExecution(curGPRState)){
 
} // Else execute through DBI
else {
 
}
typedef enum {
  _QBDI_EI(NO_EVENT) = 0,                /*!< 无事件 */
  _QBDI_EI(SEQUENCE_ENTRY) = 1,          /*!< 当执行进入一个序列时触发 */
  _QBDI_EI(SEQUENCE_EXIT) = 1 << 1,      /*!< 当执行退出当前序列时触发 */
  _QBDI_EI(BASIC_BLOCK_ENTRY) = 1 << 2,  /*!< 当执行进入一个基本块时触发 */
  _QBDI_EI(BASIC_BLOCK_EXIT) = 1 << 3,   /*!< 当执行退出当前基本块时触发 */
  _QBDI_EI(BASIC_BLOCK_NEW) = 1 << 4,    /*!< 当执行进入新(未知)基本块时触发 */
  _QBDI_EI(EXEC_TRANSFER_CALL) = 1 << 5, /*!< 当ExecBroker执行控制权转移时触发 */
  _QBDI_EI(EXEC_TRANSFER_RETURN) = 1 << 6, /*!< 当ExecBroker从控制权转移返回时触发 */
  _QBDI_EI(SYSCALL_ENTRY) = 1 << 7,      /*!< 未实现 */
  _QBDI_EI(SYSCALL_EXIT) = 1 << 8,       /*!< 未实现 */
  _QBDI_EI(SIGNAL) = 1 << 9,             /*!< 未实现 */
} VMEvent;
typedef enum {
  _QBDI_EI(NO_EVENT) = 0,                /*!< 无事件 */
  _QBDI_EI(SEQUENCE_ENTRY) = 1,          /*!< 当执行进入一个序列时触发 */
  _QBDI_EI(SEQUENCE_EXIT) = 1 << 1,      /*!< 当执行退出当前序列时触发 */
  _QBDI_EI(BASIC_BLOCK_ENTRY) = 1 << 2,  /*!< 当执行进入一个基本块时触发 */
  _QBDI_EI(BASIC_BLOCK_EXIT) = 1 << 3,   /*!< 当执行退出当前基本块时触发 */
  _QBDI_EI(BASIC_BLOCK_NEW) = 1 << 4,    /*!< 当执行进入新(未知)基本块时触发 */
  _QBDI_EI(EXEC_TRANSFER_CALL) = 1 << 5, /*!< 当ExecBroker执行控制权转移时触发 */
  _QBDI_EI(EXEC_TRANSFER_RETURN) = 1 << 6, /*!< 当ExecBroker从控制权转移返回时触发 */
  _QBDI_EI(SYSCALL_ENTRY) = 1 << 7,      /*!< 未实现 */
  _QBDI_EI(SYSCALL_EXIT) = 1 << 8,       /*!< 未实现 */
  _QBDI_EI(SIGNAL) = 1 << 9,             /*!< 未实现 */
} VMEvent;
#if defined(QBDI_ARCH_ARM)
      // Handle ARM mode switching, only at the start of an execution or when
      // the guest signal an exchange.
      bool changeCPUMode = curExecBlock == nullptr ||
                           curExecBlock->getContext()->hostState.exchange == 1;
      if (changeCPUMode) {
        curCPUMode = currentPC & 1 ? CPUMode::Thumb : CPUMode::ARM;
        QBDI_DEBUG("CPUMode set to {}",
                   curCPUMode == CPUMode::ARM ? "ARM" : "Thumb");
      } else if (curCPUMode == CPUMode::ARM) {
        QBDI_REQUIRE_ABORT((currentPC & 1) == 0,
                           "Unexpected address in ARM mode");
      } else {
        QBDI_REQUIRE_ABORT((currentPC & 1) == 1,
                           "Unexpected address in Thumb mode");
      }
      currentPC = currentPC & (~1);
#endif
#if defined(QBDI_ARCH_ARM)
      // Handle ARM mode switching, only at the start of an execution or when
      // the guest signal an exchange.
      bool changeCPUMode = curExecBlock == nullptr ||
                           curExecBlock->getContext()->hostState.exchange == 1;
      if (changeCPUMode) {
        curCPUMode = currentPC & 1 ? CPUMode::Thumb : CPUMode::ARM;
        QBDI_DEBUG("CPUMode set to {}",
                   curCPUMode == CPUMode::ARM ? "ARM" : "Thumb");
      } else if (curCPUMode == CPUMode::ARM) {
        QBDI_REQUIRE_ABORT((currentPC & 1) == 0,
                           "Unexpected address in ARM mode");
      } else {
        QBDI_REQUIRE_ABORT((currentPC & 1) == 1,
                           "Unexpected address in Thumb mode");
      }
      currentPC = currentPC & (~1);
#endif
// Is cache flush pending?
if (blockManager->isFlushPending()) {
    // Backup fprState and gprState
    *gprState = *curGPRState;
    *fprState = *curFPRState;
    curGPRState = gprState.get();
    curFPRState = fprState.get();
    // Commit the flush
    blockManager->flushCommit();
}
// Is cache flush pending?
if (blockManager->isFlushPending()) {
    // Backup fprState and gprState
    *gprState = *curGPRState;
    *fprState = *curFPRState;
    curGPRState = gprState.get();
    curFPRState = fprState.get();
    // Commit the flush
    blockManager->flushCommit();
}
bool isFlushPending() { return needFlush; }
bool isFlushPending() { return needFlush; }
void ExecBlockManager::flushCommit() {
  // 如果有需要刷新的区域
  if (needFlush) {
    QBDI_DEBUG("Flushing analysis caches"); // 打印调试信息
    // 定义一个删除函数, 用于检查区域是否需要刷新
    auto delFunc = [&](const ExecRegion &r) -> bool {
      // 如果区域需要刷新
      if (r.toFlush) {
        // 打印调试信息, 显示正在移除的区域
        QBDI_DEBUG("Erasing region [0x{:x}, 0x{:x}]", r.covered.start(),
                   r.covered.end());
        // 遍历区域中的所有代码块, 并从代码块映射中移除
        for (const auto &block : r.blocks) {
          codeBlockMap.erase(block->getBaseCodeBlock());
        }
      }
      // 返回是否需要移除该区域
      return r.toFlush;
    };
 
    // 使用 std::remove_if 移除所有需要刷新的区域
    regions.erase(std::remove_if(regions.begin(), regions.end(), delFunc),
                  regions.end());
    // 设置刷新标志为 false, 表示已经完成刷新
    needFlush = false;
  }
}
void ExecBlockManager::flushCommit() {
  // 如果有需要刷新的区域
  if (needFlush) {
    QBDI_DEBUG("Flushing analysis caches"); // 打印调试信息
    // 定义一个删除函数, 用于检查区域是否需要刷新
    auto delFunc = [&](const ExecRegion &r) -> bool {
      // 如果区域需要刷新
      if (r.toFlush) {
        // 打印调试信息, 显示正在移除的区域
        QBDI_DEBUG("Erasing region [0x{:x}, 0x{:x}]", r.covered.start(),
                   r.covered.end());
        // 遍历区域中的所有代码块, 并从代码块映射中移除
        for (const auto &block : r.blocks) {
          codeBlockMap.erase(block->getBaseCodeBlock());
        }
      }
      // 返回是否需要移除该区域
      return r.toFlush;
    };
 
    // 使用 std::remove_if 移除所有需要刷新的区域
    regions.erase(std::remove_if(regions.begin(), regions.end(), delFunc),
                  regions.end());
    // 设置刷新标志为 false, 表示已经完成刷新
    needFlush = false;
  }
}
class ExecRegion : public MovableDoubleLinkedListElement<ExecRegion> {
public:
  Range<rword> covered; // 覆盖的地址范围
  unsigned translated = 0; // 已翻译的指令数量
  unsigned available = 0; // 可用的指令数量
  std::vector<std::unique_ptr<ExecBlock>> blocks; // 存储执行块的数组
  // 用于序列缓存和指令缓存的映射
  // 键必须通过 getExecRegionKey 生成
  std::map<rword, SeqLoc> sequenceCache; // 序列缓存
  std::map<rword, InstLoc> instCache; // 指令缓存
  bool toFlush = false; // 是否需要刷新
 
  // 用于用户回调的 lambda 指针, 通过 addInstrRule 设置
  // 这些指针应该在区域被移除时同时移除
  std::vector<std::unique_ptr<InstCbLambda>> userInstCB;
 
  // 构造函数
  ExecRegion(const Range<rword> &c)
      : MovableDoubleLinkedListElement<ExecRegion>(), covered(c) {}
};
class ExecRegion : public MovableDoubleLinkedListElement<ExecRegion> {
public:
  Range<rword> covered; // 覆盖的地址范围
  unsigned translated = 0; // 已翻译的指令数量
  unsigned available = 0; // 可用的指令数量
  std::vector<std::unique_ptr<ExecBlock>> blocks; // 存储执行块的数组
  // 用于序列缓存和指令缓存的映射
  // 键必须通过 getExecRegionKey 生成
  std::map<rword, SeqLoc> sequenceCache; // 序列缓存
  std::map<rword, InstLoc> instCache; // 指令缓存
  bool toFlush = false; // 是否需要刷新
 
  // 用于用户回调的 lambda 指针, 通过 addInstrRule 设置
  // 这些指针应该在区域被移除时同时移除
  std::vector<std::unique_ptr<InstCbLambda>> userInstCB;
 
  // 构造函数
  ExecRegion(const Range<rword> &c)
      : MovableDoubleLinkedListElement<ExecRegion>(), covered(c) {}
};
class ExecBlock {
private:
  using PF = llvm::sys::Memory::ProtectionFlags;
 
  enum PageState { RX, RW }; // 页面状态: 只读可执行(RX)或读写(RW)
 
  VMInstanceRef vminstance; // 指向虚拟机实例的引用
  llvm::sys::MemoryBlock codeBlock; // 代码块
  llvm::sys::MemoryBlock dataBlock; // 数据块
  unsigned codeBlockPosition; // 当前代码块的位置
  unsigned codeBlockMaxSize; // 代码块的最大大小
  const LLVMCPUs &llvmCPUs; // 用于在执行块中组装指令的 LLVMCPU
  Context *context;
  rword *shadows;
  std::vector<ShadowInfo> shadowRegistry;
  std::vector<TagInfo> tagRegistry; // 标签信息注册表
  uint16_t shadowIdx;
  std::vector<InstMetadata> instMetadata; // 指令元数据
  std::vector<InstInfo> instRegistry; // 指令信息注册表
  std::vector<SeqInfo> seqRegistry; // 序列信息注册表
  PageState pageState; // 当前页面状态
  uint16_t currentSeq;
  uint16_t currentInst;
  uint32_t epilogueSize;
  bool isFull; // 执行块是否已满
  ScratchRegisterInfo srInfo; // 暂存寄存器信息
 
  // 检查代码块是否处于只读可执行模式
  inline bool isRX() const { return pageState == RX; }
 
  // 检查代码块是否处于读写模式
  inline bool isRW() const { return pageState == RW; }
 
  // 将代码块权限更改为只读可执行
  void makeRX();
 
  // 将代码块权限更改为读写
  void makeRW();
 
  // 为补丁初始化暂存寄存器
  void initScratchRegisterForPatch(std::vector<Patch>::const_iterator seqStart,
                                   std::vector<Patch>::const_iterator seqEnd);
 
  // 写入补丁
  bool writePatch(std::vector<Patch>::const_iterator seqCurrent,
                  std::vector<Patch>::const_iterator seqEnd,
                  const LLVMCPU &llvmcpu);
 
  // 写入代码字节
  bool writeCodeByte(const llvm::ArrayRef<char> &);
 
  // .......
}
class ExecBlock {
private:
  using PF = llvm::sys::Memory::ProtectionFlags;
 
  enum PageState { RX, RW }; // 页面状态: 只读可执行(RX)或读写(RW)
 
  VMInstanceRef vminstance; // 指向虚拟机实例的引用
  llvm::sys::MemoryBlock codeBlock; // 代码块
  llvm::sys::MemoryBlock dataBlock; // 数据块
  unsigned codeBlockPosition; // 当前代码块的位置
  unsigned codeBlockMaxSize; // 代码块的最大大小
  const LLVMCPUs &llvmCPUs; // 用于在执行块中组装指令的 LLVMCPU
  Context *context;
  rword *shadows;
  std::vector<ShadowInfo> shadowRegistry;
  std::vector<TagInfo> tagRegistry; // 标签信息注册表
  uint16_t shadowIdx;
  std::vector<InstMetadata> instMetadata; // 指令元数据
  std::vector<InstInfo> instRegistry; // 指令信息注册表
  std::vector<SeqInfo> seqRegistry; // 序列信息注册表
  PageState pageState; // 当前页面状态
  uint16_t currentSeq;
  uint16_t currentInst;
  uint32_t epilogueSize;
  bool isFull; // 执行块是否已满
  ScratchRegisterInfo srInfo; // 暂存寄存器信息
 
  // 检查代码块是否处于只读可执行模式
  inline bool isRX() const { return pageState == RX; }
 
  // 检查代码块是否处于读写模式
  inline bool isRW() const { return pageState == RW; }
 
  // 将代码块权限更改为只读可执行
  void makeRX();
 
  // 将代码块权限更改为读写
  void makeRW();
 
  // 为补丁初始化暂存寄存器
  void initScratchRegisterForPatch(std::vector<Patch>::const_iterator seqStart,
                                   std::vector<Patch>::const_iterator seqEnd);
 
  // 写入补丁
  bool writePatch(std::vector<Patch>::const_iterator seqCurrent,
                  std::vector<Patch>::const_iterator seqEnd,
                  const LLVMCPU &llvmcpu);
 
  // 写入代码字节
  bool writeCodeByte(const llvm::ArrayRef<char> &);
 
  // .......
}
ExecBlockManager::ExecBlockManager(const LLVMCPUs &llvmCPUs,
                                   VMInstanceRef vminstance)
    : total_translated_size(1), total_translation_size(1),
      vminstance(vminstance), llvmCPUs(llvmCPUs),
      execBlockPrologue(
          getExecBlockPrologue(llvmCPUs.getCPU(CPUMode::DEFAULT))),
      execBlockEpilogue(
          getExecBlockEpilogue(llvmCPUs.getCPU(CPUMode::DEFAULT))) {
 
  auto execBrokerBlock = std::make_unique<ExecBlock>(
      llvmCPUs, vminstance, &execBlockPrologue, &execBlockEpilogue, 0);
  epilogueSize = execBrokerBlock->getEpilogueSize();
  execBroker = std::make_unique<ExecBroker>(std::move(execBrokerBlock),
                                            llvmCPUs, vminstance);
}
ExecBlockManager::ExecBlockManager(const LLVMCPUs &llvmCPUs,
                                   VMInstanceRef vminstance)
    : total_translated_size(1), total_translation_size(1),
      vminstance(vminstance), llvmCPUs(llvmCPUs),
      execBlockPrologue(
          getExecBlockPrologue(llvmCPUs.getCPU(CPUMode::DEFAULT))),
      execBlockEpilogue(
          getExecBlockEpilogue(llvmCPUs.getCPU(CPUMode::DEFAULT))) {
 
  auto execBrokerBlock = std::make_unique<ExecBlock>(
      llvmCPUs, vminstance, &execBlockPrologue, &execBlockEpilogue, 0);
  epilogueSize = execBrokerBlock->getEpilogueSize();
  execBroker = std::make_unique<ExecBroker>(std::move(execBrokerBlock),
                                            llvmCPUs, vminstance);
}
// Test if we have it in cache
SeqLoc currentSequence;
curExecBlock = blockManager->getProgrammedExecBlock(currentPC, curCPUMode,
                                                    &currentSequence);
// Test if we have it in cache
SeqLoc currentSequence;
curExecBlock = blockManager->getProgrammedExecBlock(currentPC, curCPUMode,
                                                    &currentSequence);
/*! X86_64 CPU modes.
 */
typedef enum { X86_64 = 0, DEFAULT = 0, COUNT } CPUMode;
/*! X86_64 CPU modes.
 */
typedef enum { X86_64 = 0, DEFAULT = 0, COUNT } CPUMode;
struct SeqLoc {
  uint16_t blockIdx;
  uint16_t seqID;
  rword bbEnd;
  rword seqStart;
  rword seqEnd;
};
struct SeqLoc {
  uint16_t blockIdx;
  uint16_t seqID;
  rword bbEnd;
  rword seqStart;
  rword seqEnd;
};
ExecBlock *ExecBlockManager::getProgrammedExecBlock(rword address,
                                                    CPUMode cpumode,
                                                    SeqLoc *programmedSeqLock) {
  QBDI_DEBUG("Looking up sequence at address {:x} mode {}", address, cpumode);
 
  size_t r = searchRegion(address);
 
  if (r < regions.size() && regions[r].covered.contains(address)) {
    ExecRegion &region = regions[r];
    const auto target = getExecRegionKey(address, cpumode);
 
    // Attempting sequenceCache resolution
    const auto seqLoc = region.sequenceCache.find(target);
    if (seqLoc != region.sequenceCache.end()) {
      QBDI_DEBUG("Found sequence 0x{:x} ({}) in ExecBlock 0x{:x} as seqID {:x}",
                 address, cpumode,
                 reinterpret_cast<uintptr_t>(
                     region.blocks[seqLoc->second.blockIdx].get()),
                 seqLoc->second.seqID);
      // copy current sequence info
      if (programmedSeqLock != nullptr) {
        *programmedSeqLock = seqLoc->second;
      }
      // Select sequence and return execBlock
      region.blocks[seqLoc->second.blockIdx]->selectSeq(seqLoc->second.seqID);
      return region.blocks[seqLoc->second.blockIdx].get();
    }
 
    // Attempting instCache resolution
    const auto instLoc = region.instCache.find(target);
    if (instLoc != region.instCache.end()) {
      // Retrieving corresponding block and seqLoc
      ExecBlock *block = region.blocks[instLoc->second.blockIdx].get();
      uint16_t existingSeqId = block->getSeqID(instLoc->second.instID);
      const SeqLoc &existingSeqLoc = region.sequenceCache[getExecRegionKey(
          block->getInstMetadata(block->getSeqStart(existingSeqId)).address,
          cpumode)];
      // Creating a new sequence at that instruction and
      // saving it in the sequenceCache
      uint16_t newSeqID = block->splitSequence(instLoc->second.instID);
      region.sequenceCache[target] = SeqLoc{
          instLoc->second.blockIdx, newSeqID, existingSeqLoc.bbEnd, address,
          existingSeqLoc.seqEnd,
      };
      QBDI_DEBUG(
          "Splitted seqID {:x} at instID {:x} in ExecBlock 0x{:x} as new "
          "sequence with seqID {:x}",
          existingSeqId, instLoc->second.instID,
          reinterpret_cast<uintptr_t>(block), newSeqID);
      // copy current sequence info
      if (programmedSeqLock != nullptr) {
        *programmedSeqLock = regions[r].sequenceCache[target];
      }
      block->selectSeq(newSeqID);
      return block;
    }
  }
  QBDI_DEBUG("Cache miss for sequence 0x{:x} ({})", address, cpumode);
  return nullptr;
}
ExecBlock *ExecBlockManager::getProgrammedExecBlock(rword address,
                                                    CPUMode cpumode,
                                                    SeqLoc *programmedSeqLock) {
  QBDI_DEBUG("Looking up sequence at address {:x} mode {}", address, cpumode);
 
  size_t r = searchRegion(address);
 
  if (r < regions.size() && regions[r].covered.contains(address)) {
    ExecRegion &region = regions[r];
    const auto target = getExecRegionKey(address, cpumode);
 
    // Attempting sequenceCache resolution
    const auto seqLoc = region.sequenceCache.find(target);
    if (seqLoc != region.sequenceCache.end()) {
      QBDI_DEBUG("Found sequence 0x{:x} ({}) in ExecBlock 0x{:x} as seqID {:x}",
                 address, cpumode,
                 reinterpret_cast<uintptr_t>(
                     region.blocks[seqLoc->second.blockIdx].get()),
                 seqLoc->second.seqID);
      // copy current sequence info
      if (programmedSeqLock != nullptr) {
        *programmedSeqLock = seqLoc->second;
      }
      // Select sequence and return execBlock
      region.blocks[seqLoc->second.blockIdx]->selectSeq(seqLoc->second.seqID);
      return region.blocks[seqLoc->second.blockIdx].get();
    }
 
    // Attempting instCache resolution
    const auto instLoc = region.instCache.find(target);
    if (instLoc != region.instCache.end()) {
      // Retrieving corresponding block and seqLoc
      ExecBlock *block = region.blocks[instLoc->second.blockIdx].get();
      uint16_t existingSeqId = block->getSeqID(instLoc->second.instID);
      const SeqLoc &existingSeqLoc = region.sequenceCache[getExecRegionKey(
          block->getInstMetadata(block->getSeqStart(existingSeqId)).address,
          cpumode)];
      // Creating a new sequence at that instruction and
      // saving it in the sequenceCache
      uint16_t newSeqID = block->splitSequence(instLoc->second.instID);
      region.sequenceCache[target] = SeqLoc{
          instLoc->second.blockIdx, newSeqID, existingSeqLoc.bbEnd, address,
          existingSeqLoc.seqEnd,
      };
      QBDI_DEBUG(
          "Splitted seqID {:x} at instID {:x} in ExecBlock 0x{:x} as new "
          "sequence with seqID {:x}",
          existingSeqId, instLoc->second.instID,
          reinterpret_cast<uintptr_t>(block), newSeqID);
      // copy current sequence info
      if (programmedSeqLock != nullptr) {
        *programmedSeqLock = regions[r].sequenceCache[target];
      }
      block->selectSeq(newSeqID);
      return block;
    }
  }
  QBDI_DEBUG("Cache miss for sequence 0x{:x} ({})", address, cpumode);
  return nullptr;
}
size_t ExecBlockManager::searchRegion(rword address) const {
  size_t low = 0;
  size_t high = regions.size();
  if (regions.size() == 0) {
    return 0;
  }
  QBDI_DEBUG("Searching for address 0x{:x}", address);
  // Binary search of the first region to look at
  while (low + 1 != high) {
    size_t idx = (low + high) / 2;
    if (regions[idx].covered.start() > address) {
      high = idx;
    } else if (regions[idx].covered.end() <= address) {
      low = idx;
    } else {
      QBDI_DEBUG("Exact match for region {} [0x{:x}, 0x{:x}]", idx,
                 regions[idx].covered.start(), regions[idx].covered.end());
      return idx;
    }
  }
  QBDI_DEBUG("Low match for region {} [0x{:x}, 0x{:x}]", low,
             regions[low].covered.start(), regions[low].covered.end());
  return low;
}
size_t ExecBlockManager::searchRegion(rword address) const {
  size_t low = 0;
  size_t high = regions.size();
  if (regions.size() == 0) {
    return 0;
  }
  QBDI_DEBUG("Searching for address 0x{:x}", address);
  // Binary search of the first region to look at
  while (low + 1 != high) {
    size_t idx = (low + high) / 2;
    if (regions[idx].covered.start() > address) {
      high = idx;
    } else if (regions[idx].covered.end() <= address) {
      low = idx;
    } else {
      QBDI_DEBUG("Exact match for region {} [0x{:x}, 0x{:x}]", idx,
                 regions[idx].covered.start(), regions[idx].covered.end());
      return idx;
    }
  }
  QBDI_DEBUG("Low match for region {} [0x{:x}, 0x{:x}]", low,
             regions[low].covered.start(), regions[low].covered.end());
  return low;
}
if (r < regions.size() && regions[r].covered.contains(address)) {
  ExecRegion &region = regions[r]; // 获取对应的区域
  const auto target = getExecRegionKey(address, cpumode);
 
  // 尝试从 sequenceCache 中查找目标地址所在序列
  const auto seqLoc = region.sequenceCache.find(target);
  if (seqLoc != region.sequenceCache.end()) {
    // 如果找到了对应的序列
    QBDI_DEBUG("Found sequence 0x{:x} ({}) in ExecBlock 0x{:x} as seqID {:x}",
                address, cpumode,
                reinterpret_cast<uintptr_t>(region.blocks[seqLoc->second.blockIdx].get()),
                seqLoc->second.seqID);
    // 如果提供了 programmedSeqLock 参数, 则将当前序列信息复制到其中
    if (programmedSeqLock != nullptr) {
      *programmedSeqLock = seqLoc->second;
    }
    // 选择对应的序列并返回对应的 ExecBlock
    region.blocks[seqLoc->second.blockIdx]->selectSeq(seqLoc->second.seqID);
    return region.blocks[seqLoc->second.blockIdx].get();
  }
 
  // 如果 sequenceCache 中没有找到, 尝试从 instCache 中查找目标地址所在指令
  const auto instLoc = region.instCache.find(target);
  if (instLoc != region.instCache.end()) {
    // 获取对应的块和序列位置
    ExecBlock *block = region.blocks[instLoc->second.blockIdx].get();
    uint16_t existingSeqId = block->getSeqID(instLoc->second.instID);
    const SeqLoc &existingSeqLoc = region.sequenceCache[getExecRegionKey(
        block->getInstMetadata(block->getSeqStart(existingSeqId)).address,
        cpumode)];
    // 在该指令处创建一个新的序列, 并将其保存到 sequenceCache 中
    uint16_t newSeqID = block->splitSequence(instLoc->second.instID);
    region.sequenceCache[target] = SeqLoc{
        instLoc->second.blockIdx, newSeqID, existingSeqLoc.bbEnd, address,
        existingSeqLoc.seqEnd,
    };
    QBDI_DEBUG(
        "Splitted seqID {:x} at instID {:x} in ExecBlock 0x{:x} as new "
        "sequence with seqID {:x}",
        existingSeqId, instLoc->second.instID,
        reinterpret_cast<uintptr_t>(block), newSeqID);
    // 如果提供了 programmedSeqLock 参数, 则将当前序列信息复制到其中
    if (programmedSeqLock != nullptr) {
      *programmedSeqLock = regions[r].sequenceCache[target];
    }
    block->selectSeq(newSeqID);
    return block;
  }
}
if (r < regions.size() && regions[r].covered.contains(address)) {
  ExecRegion &region = regions[r]; // 获取对应的区域
  const auto target = getExecRegionKey(address, cpumode);
 
  // 尝试从 sequenceCache 中查找目标地址所在序列
  const auto seqLoc = region.sequenceCache.find(target);
  if (seqLoc != region.sequenceCache.end()) {
    // 如果找到了对应的序列
    QBDI_DEBUG("Found sequence 0x{:x} ({}) in ExecBlock 0x{:x} as seqID {:x}",
                address, cpumode,
                reinterpret_cast<uintptr_t>(region.blocks[seqLoc->second.blockIdx].get()),
                seqLoc->second.seqID);
    // 如果提供了 programmedSeqLock 参数, 则将当前序列信息复制到其中
    if (programmedSeqLock != nullptr) {
      *programmedSeqLock = seqLoc->second;
    }
    // 选择对应的序列并返回对应的 ExecBlock
    region.blocks[seqLoc->second.blockIdx]->selectSeq(seqLoc->second.seqID);
    return region.blocks[seqLoc->second.blockIdx].get();
  }
 
  // 如果 sequenceCache 中没有找到, 尝试从 instCache 中查找目标地址所在指令
  const auto instLoc = region.instCache.find(target);
  if (instLoc != region.instCache.end()) {
    // 获取对应的块和序列位置
    ExecBlock *block = region.blocks[instLoc->second.blockIdx].get();
    uint16_t existingSeqId = block->getSeqID(instLoc->second.instID);
    const SeqLoc &existingSeqLoc = region.sequenceCache[getExecRegionKey(
        block->getInstMetadata(block->getSeqStart(existingSeqId)).address,
        cpumode)];
    // 在该指令处创建一个新的序列, 并将其保存到 sequenceCache 中
    uint16_t newSeqID = block->splitSequence(instLoc->second.instID);
    region.sequenceCache[target] = SeqLoc{
        instLoc->second.blockIdx, newSeqID, existingSeqLoc.bbEnd, address,
        existingSeqLoc.seqEnd,
    };
    QBDI_DEBUG(
        "Splitted seqID {:x} at instID {:x} in ExecBlock 0x{:x} as new "
        "sequence with seqID {:x}",
        existingSeqId, instLoc->second.instID,
        reinterpret_cast<uintptr_t>(block), newSeqID);
    // 如果提供了 programmedSeqLock 参数, 则将当前序列信息复制到其中
    if (programmedSeqLock != nullptr) {
      *programmedSeqLock = regions[r].sequenceCache[target];
    }
    block->selectSeq(newSeqID);
    return block;
  }
}
inline rword getExecRegionKey(rword address, CPUMode cpumode) {
  if constexpr (is_arm) {
    if (cpumode != CPUMode::DEFAULT) {
      address |= 1;
    } else {
      address &= (~1);
    }
  }
  return address;
}
inline rword getExecRegionKey(rword address, CPUMode cpumode) {
  if constexpr (is_arm) {
    if (cpumode != CPUMode::DEFAULT) {
      address |= 1;
    } else {
      address &= (~1);
    }
  }
  return address;
}
struct SeqLoc {
  uint16_t blockIdx;
  uint16_t seqID;
  rword bbEnd;
  rword seqStart;
  rword seqEnd;
};
struct SeqLoc {
  uint16_t blockIdx;
  uint16_t seqID;
  rword bbEnd;
  rword seqStart;
  rword seqEnd;
};
void ExecBlock::selectSeq(uint16_t seqID) {
  QBDI_REQUIRE(seqID < seqRegistry.size());
  currentSeq = seqID;
  currentInst = seqRegistry[currentSeq].startInstID;
  context->hostState.selector =
      reinterpret_cast<rword>(codeBlock.base()) +
      static_cast<rword>(instRegistry[currentInst].offset);
  context->hostState.executeFlags = seqRegistry[currentSeq].executeFlags;
}
void ExecBlock::selectSeq(uint16_t seqID) {
  QBDI_REQUIRE(seqID < seqRegistry.size());
  currentSeq = seqID;
  currentInst = seqRegistry[currentSeq].startInstID;
  context->hostState.selector =
      reinterpret_cast<rword>(codeBlock.base()) +
      static_cast<rword>(instRegistry[currentInst].offset);
  context->hostState.executeFlags = seqRegistry[currentSeq].executeFlags;
}
struct SeqInfo {
  uint16_t startInstID;
  uint16_t endInstID;
  uint8_t executeFlags;
  CPUMode cpuMode;
  ScratchRegisterSeqInfo sr;
};
struct SeqInfo {
  uint16_t startInstID;
  uint16_t endInstID;
  uint8_t executeFlags;
  CPUMode cpuMode;
  ScratchRegisterSeqInfo sr;
};
struct InstInfo {
  uint16_t seqID;
  uint16_t offset;
  uint16_t offsetSkip;
  uint16_t shadowOffset;
  uint16_t shadowSize;
  uint16_t tagOffset;
  uint16_t tagSize;
  ScratchRegisterSeqInfo sr;
};
struct InstInfo {
  uint16_t seqID;
  uint16_t offset;
  uint16_t offsetSkip;
  uint16_t shadowOffset;
  uint16_t shadowSize;
  uint16_t tagOffset;
  uint16_t tagSize;
  ScratchRegisterSeqInfo sr;
};
struct InstLoc {
  uint16_t blockIdx;
  uint16_t instID;
};
struct InstLoc {
  uint16_t blockIdx;
  uint16_t instID;
};
uint16_t ExecBlock::getSeqID(uint16_t instID) const {
  QBDI_REQUIRE(instID < instRegistry.size());
  return instRegistry[instID].seqID;
}
uint16_t ExecBlock::getSeqID(uint16_t instID) const {
  QBDI_REQUIRE(instID < instRegistry.size());
  return instRegistry[instID].seqID;
}
uint16_t ExecBlock::getSeqStart(uint16_t seqID) const {
  QBDI_REQUIRE(seqID < seqRegistry.size());
  return seqRegistry[seqID].startInstID;
}
uint16_t ExecBlock::getSeqStart(uint16_t seqID) const {
  QBDI_REQUIRE(seqID < seqRegistry.size());
  return seqRegistry[seqID].startInstID;
}
const InstMetadata &ExecBlock::getInstMetadata(uint16_t instID) const {
  QBDI_REQUIRE(instID < instMetadata.size());
  return instMetadata[instID];
}
const InstMetadata &ExecBlock::getInstMetadata(uint16_t instID) const {
  QBDI_REQUIRE(instID < instMetadata.size());
  return instMetadata[instID];
}
class InstMetadata {
public:
  llvm::MCInst inst;                 // LLVM 的机器指令对象
  rword address;                     // 指令的地址
  uint32_t instSize;                 // 指令的大小(字节)
  uint32_t patchSize;                // 指令的补丁大小(字节)
  CPUMode cpuMode;                   // 指令对应的 CPU 模式
  bool modifyPC;                     // 指令是否修改程序计数器(PC)
  uint8_t execblockFlags;            // 执行块的标志
  mutable InstAnalysisPtr analysis;  // 指令的分析结果指针
  InstMetadataArch archMetadata;     // 架构相关的元数据
 
#if defined(QBDI_ARCH_X86_64) || defined(QBDI_ARCH_X86)
  // 对于 X86_64 指令, 存储前缀(如 ``lock``)
  std::vector<llvm::MCInst> prefix;
#endif
 
  // 构造函数
  InstMetadata(const llvm::MCInst &inst, rword address, uint32_t instSize,
               uint32_t patchSize, CPUMode cpuMode, bool modifyPC,
               uint8_t execblockFlags, InstAnalysisPtr analysis)
      : inst(inst), address(address), instSize(instSize), patchSize(patchSize),
        cpuMode(cpuMode), modifyPC(modifyPC), execblockFlags(execblockFlags),
        analysis(std::move(analysis)) {}
 
  // 简化版构造函数
  InstMetadata(const llvm::MCInst &inst, rword address, uint32_t instSize,
               CPUMode cpuMode, uint8_t execblockFlags)
      : inst(inst), address(address), instSize(instSize), patchSize(0),
        cpuMode(cpuMode), modifyPC(false), execblockFlags(execblockFlags),
        analysis(nullptr) {}
 
  // 计算指令的结束地址
  inline rword endAddress() const { return address + instSize; }
 
  // 创建一个副本
  inline InstMetadata lightCopy() const {
    InstMetadata cpy{inst,    address,  instSize,       patchSize,
                     cpuMode, modifyPC, execblockFlags, nullptr};
#if defined(QBDI_ARCH_X86_64) || defined(QBDI_ARCH_X86)
    cpy.prefix = prefix; // 如果是 X86 架构, 复制前缀
#endif
    cpy.archMetadata = archMetadata; // 复制架构相关的元数据
    return cpy;
  }
};
class InstMetadata {
public:
  llvm::MCInst inst;                 // LLVM 的机器指令对象
  rword address;                     // 指令的地址
  uint32_t instSize;                 // 指令的大小(字节)
  uint32_t patchSize;                // 指令的补丁大小(字节)
  CPUMode cpuMode;                   // 指令对应的 CPU 模式
  bool modifyPC;                     // 指令是否修改程序计数器(PC)
  uint8_t execblockFlags;            // 执行块的标志
  mutable InstAnalysisPtr analysis;  // 指令的分析结果指针
  InstMetadataArch archMetadata;     // 架构相关的元数据
 
#if defined(QBDI_ARCH_X86_64) || defined(QBDI_ARCH_X86)
  // 对于 X86_64 指令, 存储前缀(如 ``lock``)
  std::vector<llvm::MCInst> prefix;
#endif
 
  // 构造函数
  InstMetadata(const llvm::MCInst &inst, rword address, uint32_t instSize,
               uint32_t patchSize, CPUMode cpuMode, bool modifyPC,
               uint8_t execblockFlags, InstAnalysisPtr analysis)
      : inst(inst), address(address), instSize(instSize), patchSize(patchSize),
        cpuMode(cpuMode), modifyPC(modifyPC), execblockFlags(execblockFlags),
        analysis(std::move(analysis)) {}
 
  // 简化版构造函数
  InstMetadata(const llvm::MCInst &inst, rword address, uint32_t instSize,
               CPUMode cpuMode, uint8_t execblockFlags)
      : inst(inst), address(address), instSize(instSize), patchSize(0),
        cpuMode(cpuMode), modifyPC(false), execblockFlags(execblockFlags),
        analysis(nullptr) {}
 
  // 计算指令的结束地址
  inline rword endAddress() const { return address + instSize; }
 
  // 创建一个副本
  inline InstMetadata lightCopy() const {
    InstMetadata cpy{inst,    address,  instSize,       patchSize,
                     cpuMode, modifyPC, execblockFlags, nullptr};
#if defined(QBDI_ARCH_X86_64) || defined(QBDI_ARCH_X86)
    cpy.prefix = prefix; // 如果是 X86 架构, 复制前缀
#endif
    cpy.archMetadata = archMetadata; // 复制架构相关的元数据
    return cpy;
  }
};
uint16_t ExecBlock::splitSequence(uint16_t instID) {
  QBDI_REQUIRE(instID < instRegistry.size());
  uint16_t seqID = instRegistry[instID].seqID;
  seqRegistry.push_back(SeqInfo{
      instID, seqRegistry[seqID].endInstID, seqRegistry[seqID].executeFlags,
      seqRegistry[seqID].cpuMode, instRegistry[instID].sr});
  return getNextSeqID() - 1;
}
uint16_t ExecBlock::splitSequence(uint16_t instID) {
  QBDI_REQUIRE(instID < instRegistry.size());
  uint16_t seqID = instRegistry[instID].seqID;
  seqRegistry.push_back(SeqInfo{
      instID, seqRegistry[seqID].endInstID, seqRegistry[seqID].executeFlags,
      seqRegistry[seqID].cpuMode, instRegistry[instID].sr});
  return getNextSeqID() - 1;
}
if (curExecBlock == nullptr) {
  QBDI_DEBUG(
      "Cache miss for 0x{:x}, patching & instrumenting new basic block",
      currentPC);
  handleNewBasicBlock(currentPC);
  // Signal a new basic block
  event |= BASIC_BLOCK_NEW;
  // Set new basic block as current
  curExecBlock = blockManager->getProgrammedExecBlock(
      currentPC, curCPUMode, &currentSequence);
  QBDI_REQUIRE_ABORT(curExecBlock != nullptr,
                      "Fail to instrument the next basic block");
}
if (curExecBlock == nullptr) {
  QBDI_DEBUG(
      "Cache miss for 0x{:x}, patching & instrumenting new basic block",
      currentPC);
  handleNewBasicBlock(currentPC);
  // Signal a new basic block
  event |= BASIC_BLOCK_NEW;
  // Set new basic block as current
  curExecBlock = blockManager->getProgrammedExecBlock(
      currentPC, curCPUMode, &currentSequence);
  QBDI_REQUIRE_ABORT(curExecBlock != nullptr,
                      "Fail to instrument the next basic block");
}
void Engine::handleNewBasicBlock(rword pc) {
  // disassemble and patch new basic block
  Patch::Vec basicBlock = patch(pc);
  // Reserve cache and get uncached instruction
  size_t patchEnd = blockManager->preWriteBasicBlock(basicBlock);
  // instrument uncached instruction
  instrument(basicBlock, patchEnd);
  // Write in the cache
  blockManager->writeBasicBlock(std::move(basicBlock), patchEnd);
}
void Engine::handleNewBasicBlock(rword pc) {
  // disassemble and patch new basic block
  Patch::Vec basicBlock = patch(pc);
  // Reserve cache and get uncached instruction
  size_t patchEnd = blockManager->preWriteBasicBlock(basicBlock);
  // instrument uncached instruction
  instrument(basicBlock, patchEnd);
  // Write in the cache
  blockManager->writeBasicBlock(std::move(basicBlock), patchEnd);
}
std::vector<Patch> Engine::patch(rword start) {
  std::vector<Patch> basicBlock; // 用于存储生成的补丁
  const LLVMCPU &llvmcpu = llvmCPUs->getCPU(curCPUMode);
 
  // 如果起始地址在执行范围内, 则确定基本块的最大大小
  size_t sizeCode = (size_t)-1; // 初始化为最大值
  const Range<rword> *curRange =
      execBroker->getInstrumentedRange().getElementRange(start);
  if (curRange != nullptr) {
    sizeCode = curRange->end() - start; // 计算范围内的代码大小
  }
 
  // 创建一个代码片段, 从起始地址开始, 大小为 sizeCode
  const llvm::ArrayRef<uint8_t> code((uint8_t *)start, sizeCode);
  rword address = start;
  QBDI_DEBUG("Patching basic block at address 0x{:x}", start);
 
  bool endLoop = false;
  do {
    llvm::MCInst inst; // llvm 中中一个低级的、与目标架构无关的指令表示.
    uint64_t instSize; // 指令的大小
    // 反汇编指令
    bool dstatus = llvmcpu.getInstruction(inst, instSize,
                                          code.slice(address - start), address);
 
    // 处理反汇编错误
    if (not dstatus) {
      QBDI_DEBUG("Bump into invalid instruction at address {:x}", address);
 
      // 当前指令无效, 立即停止基本块的生成
      bool rollbackOK = patchRuleAssembly->earlyEnd(llvmcpu, basicBlock);
 
      // 如果回滚失败或未生成任何补丁, 则失败
      if ((not rollbackOK) or (basicBlock.size() == 0)) {
        size_t sizeDump = start + sizeCode - address;
        if (sizeDump > 16) {
          sizeDump = 16;
        }
        QBDI_ABORT(
            "Disassembly error : fail to parse address 0x{:x} (CPUMode {}) "
            "({:n})",
            address, curCPUMode,
            spdlog::to_hex(reinterpret_cast<uint8_t *>(address),
                           reinterpret_cast<uint8_t *>(address + sizeDump)));
      } else {
        endLoop = true;
        break;
      }
    }
    QBDI_DEBUG("Disassembly address 0x{:x} ({:n})", address,
               spdlog::to_hex(reinterpret_cast<uint8_t *>(address),
                              reinterpret_cast<uint8_t *>(address + instSize)));
 
    // 为当前指令生成补丁
    QBDI_REQUIRE_ABORT(dstatus, "Unexpected disassembly status");
    QBDI_DEBUG_BLOCK({
      std::string disass = llvmcpu.showInst(inst, address);
      QBDI_DEBUG("Patching 0x{:x} {}", address, disass.c_str());
    });
    endLoop = not patchRuleAssembly->generate(inst, address, instSize, llvmcpu,
                                              basicBlock);
    address += instSize; // 更新当前地址
  } while (endLoop);
 
  QBDI_REQUIRE_ABORT(basicBlock.size() > 0,
                     "No instruction to disassemble found");
 
  QBDI_DEBUG("Basic block starting at address 0x{:x} ended at address 0x{:x}",
             start, basicBlock.back().metadata.endAddress());
 
  return basicBlock; // 返回生成的补丁
}
std::vector<Patch> Engine::patch(rword start) {
  std::vector<Patch> basicBlock; // 用于存储生成的补丁
  const LLVMCPU &llvmcpu = llvmCPUs->getCPU(curCPUMode);
 
  // 如果起始地址在执行范围内, 则确定基本块的最大大小
  size_t sizeCode = (size_t)-1; // 初始化为最大值
  const Range<rword> *curRange =
      execBroker->getInstrumentedRange().getElementRange(start);
  if (curRange != nullptr) {
    sizeCode = curRange->end() - start; // 计算范围内的代码大小
  }
 
  // 创建一个代码片段, 从起始地址开始, 大小为 sizeCode
  const llvm::ArrayRef<uint8_t> code((uint8_t *)start, sizeCode);
  rword address = start;
  QBDI_DEBUG("Patching basic block at address 0x{:x}", start);
 
  bool endLoop = false;
  do {
    llvm::MCInst inst; // llvm 中中一个低级的、与目标架构无关的指令表示.
    uint64_t instSize; // 指令的大小
    // 反汇编指令
    bool dstatus = llvmcpu.getInstruction(inst, instSize,
                                          code.slice(address - start), address);
 
    // 处理反汇编错误
    if (not dstatus) {
      QBDI_DEBUG("Bump into invalid instruction at address {:x}", address);
 
      // 当前指令无效, 立即停止基本块的生成
      bool rollbackOK = patchRuleAssembly->earlyEnd(llvmcpu, basicBlock);
 
      // 如果回滚失败或未生成任何补丁, 则失败
      if ((not rollbackOK) or (basicBlock.size() == 0)) {
        size_t sizeDump = start + sizeCode - address;
        if (sizeDump > 16) {
          sizeDump = 16;
        }
        QBDI_ABORT(
            "Disassembly error : fail to parse address 0x{:x} (CPUMode {}) "
            "({:n})",
            address, curCPUMode,
            spdlog::to_hex(reinterpret_cast<uint8_t *>(address),
                           reinterpret_cast<uint8_t *>(address + sizeDump)));
      } else {
        endLoop = true;
        break;
      }
    }
    QBDI_DEBUG("Disassembly address 0x{:x} ({:n})", address,
               spdlog::to_hex(reinterpret_cast<uint8_t *>(address),
                              reinterpret_cast<uint8_t *>(address + instSize)));
 
    // 为当前指令生成补丁
    QBDI_REQUIRE_ABORT(dstatus, "Unexpected disassembly status");
    QBDI_DEBUG_BLOCK({
      std::string disass = llvmcpu.showInst(inst, address);
      QBDI_DEBUG("Patching 0x{:x} {}", address, disass.c_str());
    });
    endLoop = not patchRuleAssembly->generate(inst, address, instSize, llvmcpu,
                                              basicBlock);
    address += instSize; // 更新当前地址
  } while (endLoop);
 
  QBDI_REQUIRE_ABORT(basicBlock.size() > 0,
                     "No instruction to disassemble found");
 
  QBDI_DEBUG("Basic block starting at address 0x{:x} ended at address 0x{:x}",
             start, basicBlock.back().metadata.endAddress());
 
  return basicBlock; // 返回生成的补丁
}
const RangeSet<rword> &getInstrumentedRange() const { return instrumented; }
const RangeSet<rword> &getInstrumentedRange() const { return instrumented; }
const Range<T> *getElementRange(const T &t) const {
  // 使用 std::lower_bound 查找第一个满足条件的范围
  // 条件是范围的结束地址大于或等于 t
  auto lower = std::lower_bound(
      ranges.cbegin(), ranges.cend(), t,
      [](const Range<T> &r, const T &value) { return r.end() <= value; });
 
  // 如果找到的范围是最后一个范围(即超出范围)或者该范围不包含 t
  if (lower == ranges.cend() || (!lower->contains(t))) {
    return nullptr; // 返回 nullptr, 表示没有找到包含 t 的范围
  } else {
    return &*lower; // 返回找到的范围的指针
  }
}
const Range<T> *getElementRange(const T &t) const {
  // 使用 std::lower_bound 查找第一个满足条件的范围
  // 条件是范围的结束地址大于或等于 t
  auto lower = std::lower_bound(
      ranges.cbegin(), ranges.cend(), t,
      [](const Range<T> &r, const T &value) { return r.end() <= value; });
 
  // 如果找到的范围是最后一个范围(即超出范围)或者该范围不包含 t
  if (lower == ranges.cend() || (!lower->contains(t))) {
    return nullptr; // 返回 nullptr, 表示没有找到包含 t 的范围
  } else {
    return &*lower; // 返回找到的范围的指针
  }
}
bool LLVMCPU::getInstruction(llvm::MCInst &instr, uint64_t &size,
                             llvm::ArrayRef<uint8_t> bytes,
                             uint64_t address) const {
  // 调用 LLVM 的反汇编器, 尝试反汇编指令
  auto status =
      disassembler->getInstruction(instr, size, bytes, address, llvm::nulls());
 
  // 如果反汇编状态为 SoftFail(软失败), 记录警告信息
  if (status == llvm::MCDisassembler::SoftFail) {
    // 生成指令的汇编代码字符串
    std::string dissas = showInst(instr, address);
    QBDI_WARN("Disassembly softfail on 0x{:x} : {} (CPUMode {}) ({:n})",
              address, dissas, getCPUMode(),
              spdlog::to_hex(bytes.data(), bytes.data() + size));
  }
  // 返回是否成功反汇编, 如果状态不是 Fail(失败), 则返回 true
  return status != llvm::MCDisassembler::Fail;
}
bool LLVMCPU::getInstruction(llvm::MCInst &instr, uint64_t &size,
                             llvm::ArrayRef<uint8_t> bytes,
                             uint64_t address) const {
  // 调用 LLVM 的反汇编器, 尝试反汇编指令
  auto status =
      disassembler->getInstruction(instr, size, bytes, address, llvm::nulls());
 
  // 如果反汇编状态为 SoftFail(软失败), 记录警告信息
  if (status == llvm::MCDisassembler::SoftFail) {
    // 生成指令的汇编代码字符串
    std::string dissas = showInst(instr, address);
    QBDI_WARN("Disassembly softfail on 0x{:x} : {} (CPUMode {}) ({:n})",
              address, dissas, getCPUMode(),
              spdlog::to_hex(bytes.data(), bytes.data() + size));
  }
  // 返回是否成功反汇编, 如果状态不是 Fail(失败), 则返回 true
  return status != llvm::MCDisassembler::Fail;
}
class LLVMCPU {
 
private:
  std::string tripleName;
  std::string cpu;
  std::string arch;
  std::vector<std::string> mattrs;
  const llvm::Target *target;
  Options options;
  CPUMode cpumode;
 
  std::unique_ptr<llvm::MCAsmInfo> MAI;
  std::unique_ptr<llvm::MCContext> MCTX;
  std::unique_ptr<llvm::MCInstrInfo> MCII;
  std::unique_ptr<llvm::MCObjectFileInfo> MOFI;
  std::unique_ptr<llvm::MCRegisterInfo> MRI;
  std::unique_ptr<llvm::MCSubtargetInfo> MSTI;
 
  std::unique_ptr<llvm::MCAssembler> assembler;
  std::unique_ptr<llvm::MCDisassembler> disassembler;
  std::unique_ptr<llvm::MCInstPrinter> asmPrinter;
  std::unique_ptr<llvm::raw_pwrite_stream> null_ostream;
 
  // ......
}
class LLVMCPU {
 
private:
  std::string tripleName;
  std::string cpu;
  std::string arch;
  std::vector<std::string> mattrs;
  const llvm::Target *target;
  Options options;
  CPUMode cpumode;
 
  std::unique_ptr<llvm::MCAsmInfo> MAI;
  std::unique_ptr<llvm::MCContext> MCTX;
  std::unique_ptr<llvm::MCInstrInfo> MCII;
  std::unique_ptr<llvm::MCObjectFileInfo> MOFI;
  std::unique_ptr<llvm::MCRegisterInfo> MRI;
  std::unique_ptr<llvm::MCSubtargetInfo> MSTI;
 
  std::unique_ptr<llvm::MCAssembler> assembler;
  std::unique_ptr<llvm::MCDisassembler> disassembler;
  std::unique_ptr<llvm::MCInstPrinter> asmPrinter;
  std::unique_ptr<llvm::raw_pwrite_stream> null_ostream;
 
  // ......
}
/// 返回单条指令的反汇编结果.
///
/// \param Instr    - 将被填入指令内容的 MCInst 对象.
/// \param Size     - 将被填入指令大小的值;若试图解码无效指令, 则为实际消耗的字节数.
/// \param Address  - 指令第一个字节在其所属内存区域中的地址.
/// \param Bytes    - 指令实际字节数据的引用.
/// \param CStream  - 用于输出反汇编注释和标注信息的流.
/// \return         - 返回解码状态:
///                   MCDisassembler::Success  -> 指令有效
///                   MCDisassembler::SoftFail -> 指令可被反汇编但无效
///                   MCDisassembler::Fail     -> 指令无效
virtual DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
                                    ArrayRef<uint8_t> Bytes, uint64_t Address,
                                    raw_ostream &CStream) const = 0;
/// 返回单条指令的反汇编结果.
///
/// \param Instr    - 将被填入指令内容的 MCInst 对象.
/// \param Size     - 将被填入指令大小的值;若试图解码无效指令, 则为实际消耗的字节数.
/// \param Address  - 指令第一个字节在其所属内存区域中的地址.
/// \param Bytes    - 指令实际字节数据的引用.
/// \param CStream  - 用于输出反汇编注释和标注信息的流.
/// \return         - 返回解码状态:
///                   MCDisassembler::Success  -> 指令有效
///                   MCDisassembler::SoftFail -> 指令可被反汇编但无效
///                   MCDisassembler::Fail     -> 指令无效
virtual DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
                                    ArrayRef<uint8_t> Bytes, uint64_t Address,
                                    raw_ostream &CStream) const = 0;
std::string LLVMCPU::showInst(const llvm::MCInst &inst, rword address) const {
  std::string out;
  llvm::raw_string_ostream rso(out);
 
  llvm::StringRef unusedAnnotations;
  asmPrinter->printInst(&inst, address, unusedAnnotations, *MSTI, rso);
 
  rso.flush();
  return out;
}
std::string LLVMCPU::showInst(const llvm::MCInst &inst, rword address) const {
  std::string out;
  llvm::raw_string_ostream rso(out);
 
  llvm::StringRef unusedAnnotations;
  asmPrinter->printInst(&inst, address, unusedAnnotations, *MSTI, rso);
 
  rso.flush();
  return out;
}
/// 将指定的 MCInst 对象打印到指定的原始输出流(raw_ostream).
///
/// \p Address 在多数目标平台上表示当前指令的地址, 用于将 PC 相对立即数打印为目标地址.
/// 在 PC 相对立即数基于下一条指令地址的目标平台(如 x86)或 MCInst 长度难以测量的情况下,
/// 此参数需传入下一条指令的地址. 若 Address 为 0, 则直接打印立即数值.
virtual void printInst(const MCInst *MI, uint64_t Address, StringRef Annot,
                       const MCSubtargetInfo &STI, raw_ostream &OS) = 0;
/// 将指定的 MCInst 对象打印到指定的原始输出流(raw_ostream).
///
/// \p Address 在多数目标平台上表示当前指令的地址, 用于将 PC 相对立即数打印为目标地址.
/// 在 PC 相对立即数基于下一条指令地址的目标平台(如 x86)或 MCInst 长度难以测量的情况下,
/// 此参数需传入下一条指令的地址. 若 Address 为 0, 则直接打印立即数值.
virtual void printInst(const MCInst *MI, uint64_t Address, StringRef Annot,
                       const MCSubtargetInfo &STI, raw_ostream &OS) = 0;
bool PatchRuleAssembly::generate(const llvm::MCInst &inst, rword address,
                                 uint32_t instSize, const LLVMCPU &llvmcpu,
                                 std::vector<Patch> &patchList) {
    // 创建一个 Patch 对象, 用于存储当前指令的补丁信息
    Patch instPatch{inst, address, instSize, llvmcpu};
    // 设置当前指令的寄存器保存信息
    setRegisterSaved(instPatch);
 
    // 遍历所有补丁规则
    for (uint32_t j = 0; j < patchRules.size(); j++) {
        // 检查当前补丁规则是否适用于当前指令
        if (patchRules[j].canBeApplied(instPatch, llvmcpu)) {
            QBDI_DEBUG("Patch rule {} applied", j);
            // 如果存在待合并的补丁
            if (mergePending) {
                QBDI_REQUIRE_ABORT(patchList.size() > 0, "No previous patch to merge");
                QBDI_DEBUG("Previous instruction merged");
 
                // 1. 为当前指令生成补丁
                patchRules[j].apply(instPatch, llvmcpu);
 
                // 2. 获取插入位置
                int position = -1;
                for (auto &p : instPatch.patchGenFlags) {
                    if (p.second == PatchGeneratorFlags::ModifyInstructionBeginFlags) {
                        position = p.first;
                        break;
                    }
                }
                QBDI_REQUIRE_ABORT(
                    position != -1,
                    "Fail to get the position to insert the new patch {}", instPatch);
 
                // 3. 在指定位置插入指令以合并
                Patch &mergePatch = patchList.back();
                instPatch.insertAt(position, std::move(mergePatch.insts));
 
                // 4. 保留一些元数据
                instPatch.metadata.address = mergePatch.metadata.address;
                instPatch.metadata.instSize += mergePatch.metadata.instSize;
                instPatch.metadata.execblockFlags |= mergePatch.metadata.execblockFlags;
                instPatch.metadata.prefix = mergePatch.metadata.prefix;
                instPatch.metadata.prefix.push_back(mergePatch.metadata.inst);
 
                // 5. 替换补丁
                mergePatch = std::move(instPatch);
 
            } else {
                // 如果没有待合并的补丁, 直接应用补丁规则并添加到补丁列表中
                patchRules[j].apply(instPatch, llvmcpu);
                patchList.push_back(std::move(instPatch));
            }
            // 获取最后一个补丁的引用
            Patch &patch = patchList.back();
            // 重置合并标志
            mergePending = false;
            // 检查是否有待合并的补丁
            for (auto &p : patch.patchGenFlags) {
                mergePending |= (p.second == PatchGeneratorFlagsX86_64::MergeFlag);
            }
 
            // 如果有待合并的补丁, 返回 false 表示继续处理
            if (mergePending) {
                return false;
            } else if (patch.metadata.modifyPC) {
                // 如果补丁修改了程序计数器(PC), 重置状态并返回 true
                reset();
                return true;
            } else {
                // 如果补丁没有修改 PC, 返回 false 表示继续处理
                return false;
            }
        }
    }
    // 如果没有找到适用的补丁规则, 终止程序并报错
    QBDI_ABORT("Not PatchRule found for: {}", instPatch);
}
 
static void setRegisterSaved(Patch &patch) {
 
  if constexpr (is_x86) {
    // 根据指令的操作码设置寄存器的保存状态
    switch (patch.metadata.inst.getOpcode()) {
      // 对于 x86 架构中的 PUSHA 和 POPA 指令
      case llvm::X86::PUSHA16: // 16 位保存所有通用寄存器
      case llvm::X86::PUSHA32: // 32 位保存所有通用寄存器
      case llvm::X86::POPA16:  // 16 位恢复所有通用寄存器
      case llvm::X86::POPA32:  // 32 位恢复所有通用寄存器
        // 允许 TmpManager 重用这些寄存器
        for (unsigned i = 0; i < AVAILABLE_GPR; i++) {
          patch.regUsage[i] |= RegisterUsage::RegisterSaved;
        }
        break;
      default:
        break;
    }
  }
 
  return;
}
bool PatchRuleAssembly::generate(const llvm::MCInst &inst, rword address,
                                 uint32_t instSize, const LLVMCPU &llvmcpu,
                                 std::vector<Patch> &patchList) {
    // 创建一个 Patch 对象, 用于存储当前指令的补丁信息
    Patch instPatch{inst, address, instSize, llvmcpu};
    // 设置当前指令的寄存器保存信息
    setRegisterSaved(instPatch);
 
    // 遍历所有补丁规则
    for (uint32_t j = 0; j < patchRules.size(); j++) {
        // 检查当前补丁规则是否适用于当前指令
        if (patchRules[j].canBeApplied(instPatch, llvmcpu)) {
            QBDI_DEBUG("Patch rule {} applied", j);
            // 如果存在待合并的补丁
            if (mergePending) {
                QBDI_REQUIRE_ABORT(patchList.size() > 0, "No previous patch to merge");
                QBDI_DEBUG("Previous instruction merged");
 
                // 1. 为当前指令生成补丁
                patchRules[j].apply(instPatch, llvmcpu);
 
                // 2. 获取插入位置
                int position = -1;
                for (auto &p : instPatch.patchGenFlags) {
                    if (p.second == PatchGeneratorFlags::ModifyInstructionBeginFlags) {
                        position = p.first;
                        break;
                    }
                }
                QBDI_REQUIRE_ABORT(
                    position != -1,
                    "Fail to get the position to insert the new patch {}", instPatch);
 
                // 3. 在指定位置插入指令以合并
                Patch &mergePatch = patchList.back();
                instPatch.insertAt(position, std::move(mergePatch.insts));
 
                // 4. 保留一些元数据
                instPatch.metadata.address = mergePatch.metadata.address;
                instPatch.metadata.instSize += mergePatch.metadata.instSize;
                instPatch.metadata.execblockFlags |= mergePatch.metadata.execblockFlags;
                instPatch.metadata.prefix = mergePatch.metadata.prefix;
                instPatch.metadata.prefix.push_back(mergePatch.metadata.inst);
 
                // 5. 替换补丁
                mergePatch = std::move(instPatch);
 
            } else {
                // 如果没有待合并的补丁, 直接应用补丁规则并添加到补丁列表中
                patchRules[j].apply(instPatch, llvmcpu);
                patchList.push_back(std::move(instPatch));
            }
            // 获取最后一个补丁的引用
            Patch &patch = patchList.back();
            // 重置合并标志
            mergePending = false;
            // 检查是否有待合并的补丁
            for (auto &p : patch.patchGenFlags) {
                mergePending |= (p.second == PatchGeneratorFlagsX86_64::MergeFlag);
            }
 
            // 如果有待合并的补丁, 返回 false 表示继续处理
            if (mergePending) {
                return false;
            } else if (patch.metadata.modifyPC) {
                // 如果补丁修改了程序计数器(PC), 重置状态并返回 true
                reset();
                return true;
            } else {
                // 如果补丁没有修改 PC, 返回 false 表示继续处理
                return false;
            }
        }
    }
    // 如果没有找到适用的补丁规则, 终止程序并报错
    QBDI_ABORT("Not PatchRule found for: {}", instPatch);
}
 
static void setRegisterSaved(Patch &patch) {
 
  if constexpr (is_x86) {
    // 根据指令的操作码设置寄存器的保存状态
    switch (patch.metadata.inst.getOpcode()) {
      // 对于 x86 架构中的 PUSHA 和 POPA 指令
      case llvm::X86::PUSHA16: // 16 位保存所有通用寄存器
      case llvm::X86::PUSHA32: // 32 位保存所有通用寄存器
      case llvm::X86::POPA16:  // 16 位恢复所有通用寄存器
      case llvm::X86::POPA32:  // 32 位恢复所有通用寄存器
        // 允许 TmpManager 重用这些寄存器
        for (unsigned i = 0; i < AVAILABLE_GPR; i++) {
          patch.regUsage[i] |= RegisterUsage::RegisterSaved;
        }
        break;
      default:
        break;
    }
  }
 
  return;
}
PatchRuleAssembly::PatchRuleAssembly(Options opts)
    : patchRules(getDefaultPatchRules(opts)), options(opts),
      mergePending(false) {}
PatchRuleAssembly::PatchRuleAssembly(Options opts)
    : patchRules(getDefaultPatchRules(opts)), options(opts),
      mergePending(false) {}
std::vector<PatchRule> getDefaultPatchRules(Options opts) {
  std::vector<PatchRule> rules;
 
  /* Rule #0: Avoid instrumenting instruction prefixes.
   * Target:  X86 prefixes (LOCK, REP and other REX prefixes).
   * Patch:   Output the unmodified MCInst but flag the patch as "do not
   * instrument".
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(
          OpIs::unique(llvm::X86::LOCK_PREFIX),
          OpIs::unique(llvm::X86::REX64_PREFIX),
          OpIs::unique(llvm::X86::REP_PREFIX),
          OpIs::unique(llvm::X86::REPNE_PREFIX),
          OpIs::unique(llvm::X86::DATA16_PREFIX),
          OpIs::unique(llvm::X86::CS_PREFIX),
          OpIs::unique(llvm::X86::SS_PREFIX),
          OpIs::unique(llvm::X86::DS_PREFIX),
          OpIs::unique(llvm::X86::ES_PREFIX),
          OpIs::unique(llvm::X86::FS_PREFIX),
          OpIs::unique(llvm::X86::GS_PREFIX),
          OpIs::unique(llvm::X86::XACQUIRE_PREFIX),
          OpIs::unique(llvm::X86::XRELEASE_PREFIX))),
      conv_unique<PatchGenerator>(
          PatchGenFlags::unique(PatchGeneratorFlagsX86_64::MergeFlag),
          ModifyInstruction::unique(InstTransform::UniquePtrVec())));
 
  /* Rule #1: Simulate jmp to memory value using RIP addressing.
   * Target:  JMP *[RIP + IMM]
   * Patch:   Temp(0) := RIP + Constant(0)
   *          JMP *[RIP + IMM] --> MOV Temp(1), [Temp(0) + IMM]
   *          DataBlock[Offset(RIP)] := Temp(1)
   */
  rules.emplace_back(
      And::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::JMP64m),
                                              UseReg::unique(Reg(REG_PC)))),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Constant(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SubstituteWithTemp::unique(Reg(REG_PC), Temp(0)),
              SetOpcode::unique(llvm::X86::MOV64rm),
              AddOperand::unique(Operand(0), Temp(1)))),
          WriteTemp::unique(Temp(1), Offset(Reg(REG_PC)))));
 
  /* Rule #2: Simulate call to memory value using RIP addressing.
   * Target:  CALL *[RIP + IMM]
   * Patch:   Temp(0) := RIP + Constant(0)
   *          CALL *[RIP + IMM] --> MOV Temp(1), [Temp(0) + IMM]
   *          SimulateCall(Temp(1))
   */
  rules.emplace_back(
      And::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::CALL64m),
                                              UseReg::unique(Reg(REG_PC)))),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Constant(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SubstituteWithTemp::unique(Reg(REG_PC), Temp(0)),
              SetOpcode::unique(llvm::X86::MOV64rm),
              AddOperand::unique(Operand(0), Temp(1)))),
          SimulateCall::unique(Temp(1))));
 
  /* Rule #3: Generic RIP patching.
   * Target:  Any instruction with RIP as operand, e.g. LEA RAX, [RIP + 1]
   * Patch:   Temp(0) := rip
   *          LEA RAX, [RIP + IMM] --> LEA RAX, [Temp(0) + IMM]
   */
  rules.emplace_back(
      UseReg::unique(Reg(REG_PC)),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Constant(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SubstituteWithTemp::unique(Reg(REG_PC), Temp(0))))));
 
  /* Rule #4: Simulate JMP to memory value.
   * Target:  JMP *MEM
   * Patch:   JMP *MEM --> MOV Temp(0), MEM
   *          DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::JMP32m),
                                             OpIs::unique(llvm::X86::JMP64m))),
      conv_unique<PatchGenerator>(
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SetOpcode::unique(is_x86 ? llvm::X86::MOV32rm
                                       : llvm::X86::MOV64rm),
              AddOperand::unique(Operand(0), Temp(0)))),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #5: Simulate CALL to memory value.
   * Target:  CALL MEM
   * Patch:   CALL MEM --> MOV Temp(0), MEM
   *          SimulateCall(Temp(1))
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::CALL32m),
                                             OpIs::unique(llvm::X86::CALL64m))),
      conv_unique<PatchGenerator>(
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SetOpcode::unique(is_x86 ? llvm::X86::MOV32rm
                                       : llvm::X86::MOV64rm),
              AddOperand::unique(Operand(0), Temp(0)))),
          SimulateCall::unique(Temp(0))));
 
  /* Rule #6: Simulate JMP to constant value.
   * Target:  JMP IMM
   * Patch:   Temp(0) := RIP + Operand(0)
   *          DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::JMP_1),
                                             OpIs::unique(llvm::X86::JMP_2),
                                             OpIs::unique(llvm::X86::JMP_4))),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Operand(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #7: Simulate JMP to register value.
   * Target:  JMP REG
   * Patch:   Temp(0) := Operand(0)
   *          DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::JMP32r),
                                             OpIs::unique(llvm::X86::JMP64r))),
      conv_unique<PatchGenerator>(
          GetOperand::unique(Temp(0), Operand(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #8: Simulate CALL to register value.
   * Target:  CALL REG
   * Patch:   Temp(0) := Operand(0)
   *          SimulateCall(Temp(0))
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::CALL32r),
                                             OpIs::unique(llvm::X86::CALL64r))),
      conv_unique<PatchGenerator>(GetOperand::unique(Temp(0), Operand(0)),
                                  SimulateCall::unique(Temp(0))));
 
  /* Rule #9: Simulate Jcc IMM8.
   * Target:  Jcc IMM8
   * Patch:     Temp(0) := RIP + Operand(0)
   *         ---Jcc IMM8 --> Jcc END
   *         |  Temp(0) := RIP + Constant(0)
   *         -->END: DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(
          OpIs::unique(llvm::X86::JCC_1), OpIs::unique(llvm::X86::LOOP),
          OpIs::unique(llvm::X86::LOOPE), OpIs::unique(llvm::X86::LOOPNE),
          OpIs::unique(llvm::X86::JRCXZ), OpIs::unique(llvm::X86::JECXZ),
          OpIs::unique(llvm::X86::JCXZ))),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Operand(0)),
          ModifyInstruction::unique(
              conv_unique<InstTransform>(SetOperand::unique(
                  Operand(0),
                  Constant(is_x86 ? 6 : 11)) // Offset to jump the next load.
                                         )),
          GetPCOffset::unique(Temp(0), Constant(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #10: Simulate Jcc IMM16.
   * Target:  Jcc IMM16
   * Patch:     Temp(0) := RIP + Operand(0)
   *         ---Jcc IMM16 --> Jcc END
   *         |  Temp(0) := RIP + Constant(0)
   *         -->END: DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      OpIs::unique(llvm::X86::JCC_2),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Operand(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SetOperand::unique(Operand(0), Constant(is_x86 ? 7 : 12)))),
          GetPCOffset::unique(Temp(0), Constant(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #11: Simulate Jcc IMM32.
   * Target:  Jcc IMM32
   * Patch:     Temp(0) := RIP + Operand(0)
   *         ---Jcc IMM32 --> Jcc END
   *         |  Temp(0) := RIP + Constant(0)
   *         -->END: DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      OpIs::unique(llvm::X86::JCC_4),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Operand(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SetOperand::unique(Operand(0), Constant(is_x86 ? 9 : 14)))),
          GetPCOffset::unique(Temp(0), Constant(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #12: Simulate CALL to constant offset.
   * Target:   CALL IMM
   * Patch:    Temp(0) := RIP + Operand(0)
   *           SimulateCall(Temp(0))
   */
  rules.emplace_back(
      Or::unique(
          conv_unique<PatchCondition>(OpIs::unique(llvm::X86::CALL64pcrel32),
                                      OpIs::unique(llvm::X86::CALLpcrel16),
                                      OpIs::unique(llvm::X86::CALLpcrel32))),
      conv_unique<PatchGenerator>(GetPCOffset::unique(Temp(0), Operand(0)),
                                  SimulateCall::unique(Temp(0))));
 
  /* Rule #13: Simulate return.
   * Target:   RET
   * Patch:    SimulateRet(Temp(0))
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(
          OpIs::unique(llvm::X86::RET32), OpIs::unique(llvm::X86::RET64),
          OpIs::unique(llvm::X86::RET16), OpIs::unique(llvm::X86::RETI32),
          OpIs::unique(llvm::X86::RETI64), OpIs::unique(llvm::X86::RETI16))),
      conv_unique<PatchGenerator>(SimulateRet::unique(Temp(0))));
 
  /* Rule #14: Default rule for every other instructions.
   * Target:   *
   * Patch:    Output original unmodified instructions.
   */
  rules.emplace_back(True::unique(),
                     conv_unique<PatchGenerator>(ModifyInstruction::unique(
                         InstTransform::UniquePtrVec())));
 
  return rules;
}
std::vector<PatchRule> getDefaultPatchRules(Options opts) {
  std::vector<PatchRule> rules;
 
  /* Rule #0: Avoid instrumenting instruction prefixes.
   * Target:  X86 prefixes (LOCK, REP and other REX prefixes).
   * Patch:   Output the unmodified MCInst but flag the patch as "do not
   * instrument".
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(
          OpIs::unique(llvm::X86::LOCK_PREFIX),
          OpIs::unique(llvm::X86::REX64_PREFIX),
          OpIs::unique(llvm::X86::REP_PREFIX),
          OpIs::unique(llvm::X86::REPNE_PREFIX),
          OpIs::unique(llvm::X86::DATA16_PREFIX),
          OpIs::unique(llvm::X86::CS_PREFIX),
          OpIs::unique(llvm::X86::SS_PREFIX),
          OpIs::unique(llvm::X86::DS_PREFIX),
          OpIs::unique(llvm::X86::ES_PREFIX),
          OpIs::unique(llvm::X86::FS_PREFIX),
          OpIs::unique(llvm::X86::GS_PREFIX),
          OpIs::unique(llvm::X86::XACQUIRE_PREFIX),
          OpIs::unique(llvm::X86::XRELEASE_PREFIX))),
      conv_unique<PatchGenerator>(
          PatchGenFlags::unique(PatchGeneratorFlagsX86_64::MergeFlag),
          ModifyInstruction::unique(InstTransform::UniquePtrVec())));
 
  /* Rule #1: Simulate jmp to memory value using RIP addressing.
   * Target:  JMP *[RIP + IMM]
   * Patch:   Temp(0) := RIP + Constant(0)
   *          JMP *[RIP + IMM] --> MOV Temp(1), [Temp(0) + IMM]
   *          DataBlock[Offset(RIP)] := Temp(1)
   */
  rules.emplace_back(
      And::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::JMP64m),
                                              UseReg::unique(Reg(REG_PC)))),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Constant(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SubstituteWithTemp::unique(Reg(REG_PC), Temp(0)),
              SetOpcode::unique(llvm::X86::MOV64rm),
              AddOperand::unique(Operand(0), Temp(1)))),
          WriteTemp::unique(Temp(1), Offset(Reg(REG_PC)))));
 
  /* Rule #2: Simulate call to memory value using RIP addressing.
   * Target:  CALL *[RIP + IMM]
   * Patch:   Temp(0) := RIP + Constant(0)
   *          CALL *[RIP + IMM] --> MOV Temp(1), [Temp(0) + IMM]
   *          SimulateCall(Temp(1))
   */
  rules.emplace_back(
      And::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::CALL64m),
                                              UseReg::unique(Reg(REG_PC)))),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Constant(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SubstituteWithTemp::unique(Reg(REG_PC), Temp(0)),
              SetOpcode::unique(llvm::X86::MOV64rm),
              AddOperand::unique(Operand(0), Temp(1)))),
          SimulateCall::unique(Temp(1))));
 
  /* Rule #3: Generic RIP patching.
   * Target:  Any instruction with RIP as operand, e.g. LEA RAX, [RIP + 1]
   * Patch:   Temp(0) := rip
   *          LEA RAX, [RIP + IMM] --> LEA RAX, [Temp(0) + IMM]
   */
  rules.emplace_back(
      UseReg::unique(Reg(REG_PC)),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Constant(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SubstituteWithTemp::unique(Reg(REG_PC), Temp(0))))));
 
  /* Rule #4: Simulate JMP to memory value.
   * Target:  JMP *MEM
   * Patch:   JMP *MEM --> MOV Temp(0), MEM
   *          DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::JMP32m),
                                             OpIs::unique(llvm::X86::JMP64m))),
      conv_unique<PatchGenerator>(
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SetOpcode::unique(is_x86 ? llvm::X86::MOV32rm
                                       : llvm::X86::MOV64rm),
              AddOperand::unique(Operand(0), Temp(0)))),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #5: Simulate CALL to memory value.
   * Target:  CALL MEM
   * Patch:   CALL MEM --> MOV Temp(0), MEM
   *          SimulateCall(Temp(1))
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::CALL32m),
                                             OpIs::unique(llvm::X86::CALL64m))),
      conv_unique<PatchGenerator>(
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SetOpcode::unique(is_x86 ? llvm::X86::MOV32rm
                                       : llvm::X86::MOV64rm),
              AddOperand::unique(Operand(0), Temp(0)))),
          SimulateCall::unique(Temp(0))));
 
  /* Rule #6: Simulate JMP to constant value.
   * Target:  JMP IMM
   * Patch:   Temp(0) := RIP + Operand(0)
   *          DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::JMP_1),
                                             OpIs::unique(llvm::X86::JMP_2),
                                             OpIs::unique(llvm::X86::JMP_4))),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Operand(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #7: Simulate JMP to register value.
   * Target:  JMP REG
   * Patch:   Temp(0) := Operand(0)
   *          DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::JMP32r),
                                             OpIs::unique(llvm::X86::JMP64r))),
      conv_unique<PatchGenerator>(
          GetOperand::unique(Temp(0), Operand(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #8: Simulate CALL to register value.
   * Target:  CALL REG
   * Patch:   Temp(0) := Operand(0)
   *          SimulateCall(Temp(0))
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(OpIs::unique(llvm::X86::CALL32r),
                                             OpIs::unique(llvm::X86::CALL64r))),
      conv_unique<PatchGenerator>(GetOperand::unique(Temp(0), Operand(0)),
                                  SimulateCall::unique(Temp(0))));
 
  /* Rule #9: Simulate Jcc IMM8.
   * Target:  Jcc IMM8
   * Patch:     Temp(0) := RIP + Operand(0)
   *         ---Jcc IMM8 --> Jcc END
   *         |  Temp(0) := RIP + Constant(0)
   *         -->END: DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(
          OpIs::unique(llvm::X86::JCC_1), OpIs::unique(llvm::X86::LOOP),
          OpIs::unique(llvm::X86::LOOPE), OpIs::unique(llvm::X86::LOOPNE),
          OpIs::unique(llvm::X86::JRCXZ), OpIs::unique(llvm::X86::JECXZ),
          OpIs::unique(llvm::X86::JCXZ))),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Operand(0)),
          ModifyInstruction::unique(
              conv_unique<InstTransform>(SetOperand::unique(
                  Operand(0),
                  Constant(is_x86 ? 6 : 11)) // Offset to jump the next load.
                                         )),
          GetPCOffset::unique(Temp(0), Constant(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #10: Simulate Jcc IMM16.
   * Target:  Jcc IMM16
   * Patch:     Temp(0) := RIP + Operand(0)
   *         ---Jcc IMM16 --> Jcc END
   *         |  Temp(0) := RIP + Constant(0)
   *         -->END: DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      OpIs::unique(llvm::X86::JCC_2),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Operand(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SetOperand::unique(Operand(0), Constant(is_x86 ? 7 : 12)))),
          GetPCOffset::unique(Temp(0), Constant(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #11: Simulate Jcc IMM32.
   * Target:  Jcc IMM32
   * Patch:     Temp(0) := RIP + Operand(0)
   *         ---Jcc IMM32 --> Jcc END
   *         |  Temp(0) := RIP + Constant(0)
   *         -->END: DataBlock[Offset(RIP)] := Temp(0)
   */
  rules.emplace_back(
      OpIs::unique(llvm::X86::JCC_4),
      conv_unique<PatchGenerator>(
          GetPCOffset::unique(Temp(0), Operand(0)),
          ModifyInstruction::unique(conv_unique<InstTransform>(
              SetOperand::unique(Operand(0), Constant(is_x86 ? 9 : 14)))),
          GetPCOffset::unique(Temp(0), Constant(0)),
          WriteTemp::unique(Temp(0), Offset(Reg(REG_PC)))));
 
  /* Rule #12: Simulate CALL to constant offset.
   * Target:   CALL IMM
   * Patch:    Temp(0) := RIP + Operand(0)
   *           SimulateCall(Temp(0))
   */
  rules.emplace_back(
      Or::unique(
          conv_unique<PatchCondition>(OpIs::unique(llvm::X86::CALL64pcrel32),
                                      OpIs::unique(llvm::X86::CALLpcrel16),
                                      OpIs::unique(llvm::X86::CALLpcrel32))),
      conv_unique<PatchGenerator>(GetPCOffset::unique(Temp(0), Operand(0)),
                                  SimulateCall::unique(Temp(0))));
 
  /* Rule #13: Simulate return.
   * Target:   RET
   * Patch:    SimulateRet(Temp(0))
   */
  rules.emplace_back(
      Or::unique(conv_unique<PatchCondition>(
          OpIs::unique(llvm::X86::RET32), OpIs::unique(llvm::X86::RET64),
          OpIs::unique(llvm::X86::RET16), OpIs::unique(llvm::X86::RETI32),
          OpIs::unique(llvm::X86::RETI64), OpIs::unique(llvm::X86::RETI16))),
      conv_unique<PatchGenerator>(SimulateRet::unique(Temp(0))));
 
  /* Rule #14: Default rule for every other instructions.
   * Target:   *
   * Patch:    Output original unmodified instructions.
   */
  rules.emplace_back(True::unique(),
                     conv_unique<PatchGenerator>(ModifyInstruction::unique(
                         InstTransform::UniquePtrVec())));
 
  return rules;
}
/*! 一个使用 PatchDSL 编写的补丁规则.
 */
class PatchRule {
  std::unique_ptr<PatchCondition> condition;
  std::vector<std::unique_ptr<PatchGenerator>> generators;
 
public:
  /*! 分配新补丁规则对象(含条件与生成器集合)
   *
   * @param[in] condition   用于判定当前规则是否适用的 PatchCondition 条件对象
   * @param[in] generators  生成补丁指令的 PatchGenerator 向量
   */
  PatchRule(std::unique_ptr<PatchCondition> &&condition,
            std::vector<std::unique_ptr<PatchGenerator>> &&generators);
 
  PatchRule(PatchRule &&);
  ~PatchRule();       
 
  /*! 通过评估当前上下文的条件, 判定规则是否适用
   *
   * @param[in] patch    待检查的 Patch 对象
   * @param[in] llvmcpu  LLVMCPU 上下文对象
   *
   * @return 若当前上下文满足条件则返回 true
   */
  bool canBeApplied(const Patch &patch, const LLVMCPU &llvmcpu) const;
 
  /*! 通过在当前上下文执行生成器来生成补丁输出
   *   同时管理补丁的临时寄存器分配
   *
   * @param[in] patch    待应用规则的 Patch 对象
   * @param[in] llvmcpu  LLVMCPU 上下文对象
   */
  void apply(Patch &patch, const LLVMCPU &llvmcpu) const;
};
/*! 一个使用 PatchDSL 编写的补丁规则.
 */
class PatchRule {
  std::unique_ptr<PatchCondition> condition;
  std::vector<std::unique_ptr<PatchGenerator>> generators;
 
public:
  /*! 分配新补丁规则对象(含条件与生成器集合)
   *
   * @param[in] condition   用于判定当前规则是否适用的 PatchCondition 条件对象
   * @param[in] generators  生成补丁指令的 PatchGenerator 向量
   */
  PatchRule(std::unique_ptr<PatchCondition> &&condition,
            std::vector<std::unique_ptr<PatchGenerator>> &&generators);
 
  PatchRule(PatchRule &&);
  ~PatchRule();       
 
  /*! 通过评估当前上下文的条件, 判定规则是否适用
   *
   * @param[in] patch    待检查的 Patch 对象
   * @param[in] llvmcpu  LLVMCPU 上下文对象
   *
   * @return 若当前上下文满足条件则返回 true
   */
  bool canBeApplied(const Patch &patch, const LLVMCPU &llvmcpu) const;
 
  /*! 通过在当前上下文执行生成器来生成补丁输出
   *   同时管理补丁的临时寄存器分配
   *
   * @param[in] patch    待应用规则的 Patch 对象
   * @param[in] llvmcpu  LLVMCPU 上下文对象
   */
  void apply(Patch &patch, const LLVMCPU &llvmcpu) const;
};
bool PatchRule::canBeApplied(const Patch &patch, const LLVMCPU &llvmcpu) const {
  return condition->test(patch, llvmcpu);
}
bool PatchRule::canBeApplied(const Patch &patch, const LLVMCPU &llvmcpu) const {
  return condition->test(patch, llvmcpu);
}
template <class T, class... Args>
inline std::vector<std::unique_ptr<T>> conv_unique(Args... args) {
  std::vector<std::unique_ptr<T>> vec;
  _conv_unique<T>(vec, std::forward<Args>(args)...);
  return vec;
}
 
template <class T>
inline void _conv_unique(std::vector<std::unique_ptr<T>> &vec,
                         std::unique_ptr<T> &&u) {
  vec.push_back(std::forward<std::unique_ptr<T>>(u));
}
 
template <class T, class... Args>
inline void _conv_unique(std::vector<std::unique_ptr<T>> &vec,
                         std::unique_ptr<T> &&u, Args... args) {
  vec.push_back(std::forward<std::unique_ptr<T>>(u));
  _conv_unique<T>(vec, std::forward<Args>(args)...);
}
template <class T, class... Args>
inline std::vector<std::unique_ptr<T>> conv_unique(Args... args) {
  std::vector<std::unique_ptr<T>> vec;
  _conv_unique<T>(vec, std::forward<Args>(args)...);
  return vec;
}
 
template <class T>
inline void _conv_unique(std::vector<std::unique_ptr<T>> &vec,
                         std::unique_ptr<T> &&u) {
  vec.push_back(std::forward<std::unique_ptr<T>>(u));
}
 
template <class T, class... Args>
inline void _conv_unique(std::vector<std::unique_ptr<T>> &vec,
                         std::unique_ptr<T> &&u, Args... args) {
  vec.push_back(std::forward<std::unique_ptr<T>>(u));

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 2025-7-22 09:48 被nothing233编辑 ,原因:
收藏
免费 111
支持
分享
最新回复 (49)
雪    币: 2307
活跃值: (3950)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
你是真的卷~
2025-7-21 01:10
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2025-7-21 06:12
0
雪    币: 2308
活跃值: (1587)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
hacker521 你是真的卷~
呃, 感觉探索一些未知的领域, 实现一些有创意的想法比较有意思, 做出来也很有成就感, 不是在卷, hh
2025-7-21 08:55
0
雪    币: 1398
活跃值: (6853)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
5
1
2025-7-21 09:18
0
雪    币: 11
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
666
2025-7-21 09:26
0
雪    币: 528
活跃值: (4269)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
tql
2025-7-21 09:35
0
雪    币: 3654
活跃值: (5797)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
感谢分享
2025-7-21 09:41
0
雪    币: 0
活跃值: (1540)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
6666
2025-7-21 10:38
0
雪    币: 343
活跃值: (1751)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
77777
2025-7-21 10:54
0
雪    币: 342
活跃值: (145)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
66
2025-7-21 11:20
0
雪    币: 156
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
能不能教一下手把手写trace
2025-7-21 13:39
0
雪    币: 2308
活跃值: (1587)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
13
mb_cfjwplfo 能不能教一下手把手写trace[em_006]
等后面放假会实战写一写
2025-7-21 13:54
0
雪    币: 104
活跃值: (7134)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
牛逼
2025-7-21 14:28
0
雪    币: 190
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
2025-7-21 17:32
0
雪    币: 107
活跃值: (918)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
666
2025-7-22 17:51
0
雪    币: 213
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
666666666
2025-7-22 22:01
0
雪    币: 2815
活跃值: (12067)
能力值: (RANK:385 )
在线值:
发帖
回帖
粉丝
18
牛 学到了.
2025-7-23 09:51
0
雪    币: 293
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
19
66666
2025-7-24 16:26
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
感谢分享
2025-7-25 03:52
0
雪    币: 117
活跃值: (2081)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
666
2025-7-25 09:12
0
雪    币: 1116
活跃值: (1301)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
22
666学习一下
2025-7-25 09:13
0
雪    币: 1495
活跃值: (3698)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
23
牛逼
2025-7-27 22:55
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
1
2025-7-27 23:20
0
雪    币: 7
活跃值: (1656)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
321321213
2025-8-5 00:28
0
游客
登录 | 注册 方可回帖
返回