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 移植版本,以便能够稳健地使用大页进行构建。 以下是链接器性能的基准测试结果: ![AMD Ryzen Threadripper PRO 3995WX 64-Cores, 256 GiB RAM (Windows x64)](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/e43e95c889193659.svg) ## 项目开发设置说明 **注意:目前仅支持 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调试, 云资产清单, 内存分析, 单步执行, 原生调试器, 图形化调试, 堆栈跟踪, 多进程调试, 安全意识培训, 客户端加密, 开发工具, 断点调试, 源码级调试, 用户模式调试, 符号解析, 调试协议, 调试器工具链, 跨平台调试, 软件调试, 逆向工程