EpicGamesExt/raddebugger
GitHub: EpicGamesExt/raddebugger
一款原生用户态多进程图形化调试器,专注于 Windows 调试信息转换与大型项目的高效链接与调试。
Stars: 6832 | Forks: 303
# RAD Debugger 项目
_**注意:** 本 README 并不包含调试器的使用说明和技巧,而是对项目的技术概述。调试器的使用说明和技巧包含在随调试器发布的文档中,或者在本地构建完成后的 `build` 文件夹内。您可以在[这里](https://github.com/EpicGamesExt/raddebugger/releases)找到预编译的发布版本二进制文件。_
RAD Debugger 是一款原生、用户模式、多进程、图形化调试器。
目前仅支持本地机器的 Windows x64 调试(使用 PDB),未来计划扩展并移植以支持原生 Linux 调试和 DWARF 调试信息。
调试器目前处于 **ALPHA** 阶段。为了让调试器足够稳定,如果发现了问题,
请[在此处](https://github.com/EpicGamesExt/raddebugger/issues)提交您发现的问题,以及您能收集到的任何信息,
例如转储文件(连同您使用的构建版本)、重现步骤、测试可执行文件等。
除了调试器本身,我们还致力于通过两项相关技术进一步改进工具链:**(1)** RAD 调试信息(RDI)格式,以及 **(2)** RAD 链接器。
## RAD 调试信息(RDI)格式
RAD 调试信息(RDI)格式是我们自定义的调试信息格式,
调试器会解析并使用它,而不是直接使用工具链原生生成的调试信息(如 PDB 或 DWARF)。
为了兼容现有的工具链,我们会按需将 PDB(以及未来的 PE/ELF 文件中嵌入的 DWARF)转换为 RDI 格式。
RDI 格式目前在代码中定义,位于 `src/lib_rdi` 文件夹内。
在 [`rdi.h`](src/lib_rdi/rdi.h) 和
[`rdi.c`](src/lib_rdi/rdi.c) 中,定义了格式本身的类型和函数。
在 [`rdi_parse.h`](src/lib_rdi/rdi_parse.h) 和
[`rdi_parse.c`](src/lib_rdi/rdi_parse.c) 中,包含了用于解析格式的辅助函数。
我们还在 `src/lib_rdi_make` 文件夹中提供了一个正在开发中的库,用于构建和序列化 RDI 数据。
我们的 `radbin` 工具(也可通过调试器的 `--bin` 命令行参数访问)能够将原生调试信息格式转换为 RDI,
并生成 RDI 文件内容的可文本化转储。
## RAD 链接器
RAD 链接器是一款用于生成 x64 PE/COFF 二进制文件的新性能链接器。
它被设计为在创建巨型可执行文件时速度极快。它会生成标准的 PDB 文件用于调试,
但也可以(可选)原生创建 RAD 调试信息,这在调试时能消除即时转换的开销,
同时也适用于那些否则会产生损坏 PDB(溢出内部 32 位表)的巨型可执行文件。
RAD 链接器主要针对大型链接项目进行了优化。在我们的测试用例(调试信息达数 GB)中,
链接时间比以往快了 50%。
命令行语法与 MSVC 完全兼容,您可以通过 `/help` 获取已实现的开关完整列表。
我们为链接器设计的当前用例是帮助大型项目的编译-调试循环。
我们尚未支持链接时优化(LTO),但这已在路线图中。
默认情况下,链接器会启动与核心数相同数量的线程,因此如果您计划并行运行多个链接器,
可以通过 `/rad_workers` 限制工作线程数量。
我们还支持大内存页,开启后可进一步提升 25% 的链接速度。
要链接时启用大页,需要显式通过 `/rad_large_pages` 请求。
大页默认关闭,因为 Windows 对大页的支持存在一些问题;
我们建议仅在 Docker 或 VM 镜像中使用这些环境(每次链接后环境会被重置)。
在标准 Windows 环境下,不当使用大页会迅速导致内存碎片化,迫使重启。
我们正在开发链接器的 Linux 移植版本,以便能够稳健地使用大页进行构建。
以下是链接器性能的基准测试结果:

## 项目开发设置说明
**注意:目前仅支持 x64 Windows 开发。**
## 1. 安装所需工具(MSVC 与 Windows SDK)
为了使用代码库,您需要安装 [Microsoft C/C++ 构建工具
v15(2017)或更高版本](https://aka.ms/vs/17/release/vs_BuildTools.exe),其中包含
Windows SDK 以及 MSVC 编译器和链接器。
如果已安装 Windows SDK(例如通过安装 Microsoft C/C++ 构建工具),
您也可以使用 [Clang](https://releases.llvm.org/) 进行构建。
## 2. 构建环境设置
构建代码库可以在一个具备以下能力的终端中进行:
能够通过命令行调用 MSVC 或 Clang。
这通常通过运行 `vcvarsall.bat x64` 来实现,该脚本包含在
Microsoft C/C++ 构建工具中。该脚本会自动被 `x64
原生工具命令提示符(VS <年份>)` 变体调用。如果您已安装构建工具,
可以通过在 Windows 开始菜单搜索 `Native` 来轻松找到该命令提示符。
您可以通过运行以下命令来确认 MSVC 编译器是否可从命令行访问:
```
cl
```
如果一切设置正确,您应该会看到类似以下的输出:
```
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
usage: cl [ option... ] filename... [ /link linkoption... ]
```
### 3. 构建
在该终端中,`cd` 到代码库的根目录,然后运行
`build.bat` 脚本:
```
build
```
您应该会看到如下输出:
```
[debug mode]
[msvc compile]
[default mode, assuming `raddbg` build]
metagen_main.c
searching C:\devel\raddebugger/src... 458 files found
parsing metadesk... 16 metadesk files parsed
gathering tables... 97 tables found
generating layer code...
raddbg_main.c
```
如果一切正常,代码库根目录下会生成一个 `build` 文件夹,
其中包含新构建的 `raddbg.exe`。
此 `raddbg.exe` 是在 **调试模式** 下构建的,未开启优化,因此性能可能较低。
若要生成 **发布模式** 可执行文件,请使用 `release` 参数运行 `build.bat`:
```
build release
```
此构建过程会花费更长时间。
默认情况下,`build.bat` 在未传递参数(或仅传递 `release`)时仅构建调试器,
但可以通过传递额外参数来构建 RAD 链接器或 `radbin` CLI 工具:
```
build radlink release
build radbin release
```
## 项目路线图
### 初始 Alpha 阶段(压力测试)
项目的首要任务是确保最核心的组件在本地 x64 Windows 开发中运行极其可靠。
对于调试器,这包括调试信息转换、调试信息加载、进程控制、单步执行、表达式求值(正确使用位置信息与类型信息),
以及确保前端稳健以支撑底层功能。对于链接器,则是可靠性和与现有链接器行为的收敛。
我们认为已在这些方面取得了长足进步,但考虑到语言、构建设置、工具链和生成代码模式的庞大组合,
仍可能遇到一些问题,并将优先解决这些问题。
我们也希望在此阶段持续提升性能。对调试器而言,
主要包括前端性能、引入合理的缓存机制,以及优化现有系统。
对链接器而言,目前主要针对巨型项目进行了优化,
因此我们也希望提升中小型项目的链接速度。
对于链接器,未来还将引入一些新功能,例如
死代码消除(`/opt:ref`)以及借助 `clang` 的链接时优化(LTO)(
我们不会支持 MSVC 的 LTCG,因为它是未记录的)。
### 本地 x64 Linux 调试阶段
接下来的优先级是为项目提供完整的本地 x64 Linux 调试支持,
将 Windows 上的稳定调试体验移植到 Linux。
调试器已被设计为可抽象出需要不同的平台相关部分,
这主要是一个为这些抽象层实现不同后端的任务。
该阶段的主要工作包括:
- 将 `src/demon` 层移植以实现 Demon 本地进程控制抽象 API。
- 在 `src/ctrl` 层中实现 x64 ELF Linux 解绕器(unwinder)。
- 创建一个 DWARF 到 RDI 转换器(类似于我们已有的 PDB 到 RDI 转换器),
部分实现位于 `src/rdi_from_dwarf`。
- 将 `src/render` 层移植以实现在 Linux 上运行前端所需的渲染功能(
Windows 上使用的后端是 D3D11)。
- 将 `src/font_provider` 层移植为 Linux 兼容的字体光栅化后端,
例如 FreeType(Windows 上使用的是 DirectWrite)。
- 将 `src/os` 层移植到 Linux。这包括核心操作系统抽象
(虚拟内存分配、线程与同步原语等),以及图形操作系统抽象
(窗口、输入事件等)。
完成上述列表后,并确保各部分足够稳定,
我们将在 Linux 机器上提供与 Windows 同等的调试体验。
### 后续方向
在此之后,我们可能会探索其他方向,
例如远程调试、移植到不同架构、进一步改进调试器可视化引擎等。
但目前,我们主要聚焦于上述两个阶段。
## 代码库简介
### 顶层目录说明
- `data`:小型二进制文件,用于构建过程中嵌入到构建产物中,或与它们一起打包。
- `src`:所有源代码。
在设置并构建代码库后,还会生成以下目录:
- `build`:所有构建产物,不会提交到版本控制。
- `local`:本地文件,用于本地构建配置输入文件,不会提交到版本控制。
### 层(Layer)说明
代码库被组织为多个 *层*。层被分离出来是为了隔离特定问题,
并允许在不需要引入整个代码库的情况下将其包含在不同的构建中。
层对应于 `src` 目录下的文件夹。
有时,一个 `src` 文件夹下会包含多个子层,但整体结构力求扁平。
层之间大致按 1:1 对应 *命名空间*。
在此上下文中,“命名空间”并不指代具体的语言命名空间特性,
而是指采用短前缀(通常为 1-3 个字符)加下划线的 C 风格命名约定。
这些命名空间用于快速识别代码所属的层,
在代码中通过查看命名前缀即可了解其归属。
命名空间通常较短,以避免书写负担。
有时多个子层会共享同一命名空间。
部分层没有命名空间,但大多数都有。
命名空间的大小写取决于使用场景:
类型、枚举值和部分宏使用大写;
函数和全局变量使用小写。
层之间存在依赖关系,但为避免破坏分离性和隔离性,
不会形成循环依赖(即形成有向无环图)。
部分层被设计为可完全独立于代码库其余部分使用,
作为其他代码库和项目中的库。
这些层通常以 `lib_` 前缀命名,例如 `lib_rdi`。
以下是代码库中各层及其命名空间的列表:
- `artifact_cache` (`AC_`):实现异步填充的缓存,用于存储计算产物,
在未访问时自动逐出。用于异步流式处理和缓存进程内存及文件系统内容,
以及异步准备可视化数据。
- `base`(无命名空间):跨代码库通用的基础构造。字符串、数学、内存分配器、
辅助宏、命令行解析等。不依赖其他代码库层。
- `codeview` (`CV_`):用于解析和写入 CodeView 格式的代码。
- `coff` (`COFF_`):用于解析和写入 COFF(通用对象文件格式)的代码。
- `content` (`C_`):实现基于 128 位哈希键的内容缓存,
用于存储通用数据块。还实现了一个键系统,键指向对应 128 位哈希的历史记录。
作为其他层的数据存储。
- `ctrl` (`CTRL_`):调试器的“控制层”。实现异步进程控制、单步执行和断点,
适用于所有附加进程。运行时会与附加进程保持同步。
由另一个线程上的前端驱动。
- `dbg_engine` (`D_`):实现核心调试系统(不含图形组件)。
包含单步执行、启动、冻结线程、运行时断点添加等顶层逻辑,以及部分缓存。
- `dbg_info` (`DI_`):实现异步调试信息转换和加载。
维护已加载调试信息的缓存。加载 RDI 文件。
启动独立进程进行按需转换(如将 PDB 转换为 RDI)。
还提供用于使用调试信息的异步操作,例如模糊搜索所有已加载记录。
- `demon` (`DMN_`):本地机器底层进程控制的抽象层。
提供跨平台的统一接口,用于进程控制。
被 `ctrl` 层使用。
- `disasm` (`DASM_`):实现反汇编生成,包括异步计算和缓存反汇编结果的能力。
- `draw` (`DR_`):实现调试器使用的高级图形绘制 API,
基于底层的 `render` 抽象层。提供高级绘图命令 API,同时负责批处理等操作。
- `dwarf` (`DW_`):用于解析 DWARF 格式的代码。
- `eh` (`EH_`):用于解析 EH 帧格式的代码。
- `elf` (`ELF_`):用于解析 ELF 格式的代码。
- `eval` (`E_`):为表达式语言设计的编译器,
用于从已附加进程、调试信息、调试器状态和文件中求值变量、寄存器、类型等。
分为多个阶段,大致对应传统编译器阶段:词法分析、解析、类型检查、IR 生成和 IR 求值。
- `eval_visualization` (`EV_`):实现核心的非图形化求值可视化引擎,
可用于以多种方式可视化求值结果(通过 `eval` 层)。
实现核心数据结构和用于观察表的转换。
- `file_stream` (`FS_`):实现异步文件流,
将产物存储在 `content` 和 `artifact_cache` 层中,
并在文件变更时热重载内容。允许调用者将文件路径映射到数据哈希,
然后用于获取文件数据。
- `font_cache` (`FNT_`):实现字体数据缓存,
包含 CPU 侧的文本整形数据以及 GPU 纹理图集中的光栅化字形。
所有缓存数据均来源于 `font_provider` 抽象层。
- `font_provider` (`FP_`):为多种字体文件解码和字体光栅化提供抽象层,
支持不同的后端。
- `lib_raddbg_markup` (`RADDBG_`):独立库,用于为调试器功能标记用户程序,
不依赖 `base`,可独立迁移到其他代码库。
- `lib_rdi` (`RDI_`):独立库,定义核心 RDI 类型和读写 RDI 调试信息文件的辅助函数,
不依赖 `base`,可独立迁移到其他代码库。
- `lib_rdi_make` (`RDIM_`):独立库,用于构建和序列化 RDI 调试信息数据,
不依赖 `base`,可独立迁移到其他代码库。
- `linker` (`LNK_`):实现 RAD 链接器可执行文件本身的层。
- `mdesk` (`MD_`):用于解析 `.mdesk` 文件(JSON 类似语法,实际上是 JSON 超集)的代码,
这些文件用于调试器的用户和项目配置,以及通过 `metagen` 层生成代码。
- `metagen` (`MG_`):用于生成代码和数据表的主要元编程工具。
消费 `.mdesk` 文件并生成 C 代码,随后手动包含。
目前不分析代码库的手写 C 代码,但原则上这是可行的。
这使得管理大型数据表更加简单且不易出错,
并用于生成例如 C 枚举及大量关联数据表。
还具备嵌入二进制文件或复杂多行字符串等其他生成功能。
- `msf` (`MSF_`):用于解析和写入 MSF 文件格式的代码。
- `msvc_crt` (`MSCRT_`):用于解析 MSVC CRT 相关的代码。
- `mule`(无命名空间):用于调试器功能测试的战斗测试可执行文件。
- `mutable_text` (`MTX_`):实现异步填充和变更的文本缓冲区缓存,
在调试器中用于实现 `Output` 日志。
- `natvis`(无命名空间):用于类型可视化的 NatVis 文件。
- `os/core` (`OS_`):提供核心操作系统抽象的非图形化功能,
针对目标操作系统分别实现。
- `os/gfx` (`OS_`):基于 `os/core` 构建的图形化操作系统抽象层,
针对目标操作系统分别实现。
- `pdb` (`PDB_`):用于解析和写入 PDB 文件格式的代码。
- `pe` (`PE_`):用于解析和写入 PE(可移植可执行文件)格式的代码。
- `radbin` (`RB_`):实现 `radbin` 二进制工具可执行文件的层。
- `raddbg` (`RD_`):将各层整合的主调试器可执行文件层。
实现调试器的图形前端、所有调试器特定 UI、调试器可执行文件的命令行接口以及内置的可视化器。
- `rdi` (`RDI_`):包含 `lib_rdi` 层并为其添加代码库特定辅助功能,
便于在代码库程序中包含该库并与代码库结构集成。
- `rdi_from_coff` (`C2R_`):用于将 COFF 文件中的信息转换为等效 RDI 数据的代码。
- `rdi_from_dwarf` (`D2R_`):正在开发中的将 DWARF 转换为等效 RDI 数据的代码。
- `rdi_from_elf` (`E2R_`):用于将 ELF 数据转换为等效 RDI 数据的代码。
- `rdi_from_pdb` (`P2R_`):用于将 PDB 数据转换为等效 RDI 数据的代码。
- `rdi_make` (`RDIM_`):包含 `lib_rdi_make` 层并为其添加代码库特定辅助功能,
便于在代码库程序中包含该库并与代码库结构集成。
- `regs` (`REGS_`):用于目标架构的寄存器类型、辅助函数和元数据,
在 `demon`、读取/写入寄存器或查找寄存器元数据时使用。
- `render` (`R_`):提供用于各种 GPU API 的抽象渲染 API,
不实现高级绘图功能——该层严格用于在需要时进行最小化抽象。
更高级别的绘图功能实现在 `draw` 层。
- `scratch`(无命名空间):用于小型临时测试程序的临时空间。
- `tester`(无命名空间):用于自动化测试的程序。
- `text` (`TXT_`):实现文本处理功能,如解析换行、词法分析和解析源代码。
同时提供用于异步执行此操作的 API。
- `third_party`(无命名空间):来自其他项目的第三方代码,
所有外部代码均被包含并直接构建在代码库中。
- `ui` (`UI_`):用于构建图形用户界面的机制。
提供核心的即时模式分层用户界面数据结构构建 API,
并包含用于构建更高级别小部件的辅助层。
标签:Alpha版本, DWARF调试信息, EpicGamesExt, GitHub开源, JARM, Linux调试, PDB解析, RAD调试信息格式, RAD链接器, RDI格式, SOC Prime, Windows, Windows调试, 云资产清单, 内存分析, 单步执行, 原生调试器, 图形化调试, 堆栈跟踪, 多进程调试, 安全意识培训, 客户端加密, 开发工具, 断点调试, 源码级调试, 用户模式调试, 符号解析, 调试协议, 调试器工具链, 跨平台调试, 软件调试, 逆向工程