mcpField
D
dwarf-expert

dwarf-expert

github.com/trailofbits开发7.9k5.3k 次安装今天更新
代码仓库

关于 dwarf-expert

dwarf-expert 是处理 DWARF 调试信息的技术技能,面向需要搜索、验证调试数据或编写解析器的开发者。它提供标准资料参考与工具使用指导,不涵盖运行时调试。

主要功能

  1. 01按名称或地址搜索 DIE
  2. 02验证 DWARF 结构与质量
  3. 03解释 DWARF 格式细节
  4. 04推荐解析库
  5. 05提示解析器边界情况

适用场景

  1. 01在调试数据中查找符号或条目
  2. 02检查编译后的调试信息
  3. 03调查二进制文件的调试器问题
  4. 04编写或审查 DWARF 解析代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trailofbits/skills --skill dwarf-expert

安装后在 Claude Code 中输入/dwarf-expert确认已加载。

附带文件agents/openai.yamlassets/trail-of-bits-mark.svg

详细介绍

DWARF 专家

精通 DWARF 调试信息:解析和搜索、验证其完整性、回答有关标准的问题,以及编写使用这些信息的代码。不包括:运行时调试(请使用 gdb/lldb)、超出 DWARF 段范围的逆向工程(请使用 Ghidra/IDA),以及特定编译器生成 DWARF 时出现的问题。

权威来源

需要精确答案时,请查阅标准详情,而不要凭记忆作答:

  1. dwarfstd.org — 官方规范。使用网页搜索查找特定章节,例如“DWARF5 DW_TAG_subprogram attributes site:dwarfstd.org”。
  2. LLVM — llvm/lib/DebugInfo/DWARF/ 是可靠的参考实现: DWARFDie.cpp(DIE 和属性访问)、DWARFUnit.cpp(编译单元)、 DWARFDebugLine.cpp(行表)、DWARFVerifier.cpp(验证)。
  3. libdwarf — github.com/davea42/libdwarf-code 上的参考 C 实现。

使用 dwarfdump 解析和搜索

处理 DWARF 相关工作时,优先使用 dwarfdump,而不是 readelf。有两个实现——libdwarf 的 dwarfdump 和 LLVM 的 llvm-dwarfdump——它们的选项不同;直接运行 dwarfdump 时可能调用其中任意一个:请先检查 dwarfdump --version。以下选项适用于 LLVM 版本。

在 macOS 上,已链接的 Mach-O 可执行文件不包含 DWARF:DWARF 会保留在 .o 文件中,直到 dsymutil 将其收集到 .dSYM bundle 中。请将 dSYM(或目标文件)而非可执行文件传给 dwarfdump。pyelftools 仅支持 ELF——对于以脚本处理 Mach-O 的工作,请使用 LLVM 工具。

  • --all:转储所有 DWARF 段;--debug-info、--debug-line 等则转储单个段
  • --show-children [--recurse-depth=<n>]:打印所选条目时包含子 DIE——参数、局部变量和结构体成员都是函数和类型 DIE 的子项
  • --show-parents [--parent-recurse-depth=<n>]:包含父 DIE
  • --show-form:打印属性的形式类型,适用于需要关注编码细节的情况
  • --find=<name>:通过加速表进行精确名称查找——速度快但不全面;未找到时请改用 --name
  • --name=<pattern> [--ignore-case] [--regex]:全面搜索 DIE 名称
  • --lookup=<address>:查找覆盖某个地址的 DIE
  • --verbose:打印底层编码细节

搜索 DIE

随着查询变复杂,逐步采用以下策略:

  1. 名称或地址匹配:先用 --find,再用 --name;地址查询使用 --lookup。
  2. 属性或类型查询(例如所有类型为 float * 的参数):转储并筛选。grep -B 会提取包含每个 DIE 偏移量的标题行: llvm-dwarfdump file | grep -B 5 "float \*" | grep DW_TAG_formal_parameter, 然后使用 --debug-info=<offset> --show-children 在各自的偏移量处打印 DIE (--lookup 接受的是程序地址,而非 DIE 偏移量)。
  3. 多属性或结构查询:当 grep 管道变得脆弱时,请改用 pyelftools 编写 Python 脚本。

验证 DWARF 完整性

  • llvm-dwarfdump --verify <binary>:执行结构检查(单元链、DIE 关系、地址范围)。--error-display=<quiet|summary|details|full> 控制详细程度;--verify-json=<path> 将错误摘要写入机器可读文件;使用 --quiet 仅检查退出代码。
  • llvm-dwarfdump --statistics <binary>:以 JSON 格式输出调试信息质量指标,可跨编译器版本或优化级别进行比较,以发现回归。

在生成 DWARF 后(例如使用编译器、二进制重写工具后)、调试器在某个二进制文件上表现异常时,以及基于已知正常文件开发 DWARF 工具时,都应进行验证。

如果当前一代的编译器生成了旧版 DWARF,说明构建时明确传入了 -gdwarf-N——现代 gcc 和 clang 默认使用 v4/v5,因此应检查构建系统,而不要想当然地认为是工具链默认值。GCC 会将其标志嵌入 DW_AT_producer,因此通常能直接从中读出指定版本;clang 的 producer 字符串则不包含标志。旧版本在实际使用中仍很常见,除表面形式外,读取方式相同:在 v2 输出中,成员偏移量以位置表达式(DW_OP_plus_uconst)表示,链接名称则使用 DW_AT_MIPS_linkage_name。

readelf

查看常规 ELF 结构,或在无法使用 dwarfdump 时:

  • --debug-dump=<section>:转储 DWARF 节(info、line……)
  • --dwarf-depth=<n> / --dwarf-start=<n>:限制 DIE 深度/起始偏移量

编写解析 DWARF 的代码

优先使用现有库,而不是手动解析:

库语言说明
libdwarfC/C++github.com/davea42/libdwarf-code — 底层库;用于实现 dwarfdump
pyelftoolsPythongithub.com/eliben/pyelftools — 也可解析通用 ELF
gimliRustgithub.com/gimli-rs/gimli — 搭配 object 加载容器文件
debug/dwarfGo标准库
LibObjectFile.NETgithub.com/xoofx/LibObjectFile — 也可处理 ELF/PE 对象文件

除非任务另有要求,临时脚本默认使用 Python 和 pyelftools。

DWARF 特有的陷阱需要处理,也应在审查 DWARF 代码时检查:

  • 属性是可选的:DIE 可能省略 DW_AT_name、DW_AT_type、范围等属性。
  • 属性间接引用:DIE 的属性可能位于其 DW_AT_abstract_origin(内联实例)或 DW_AT_specification(非内联定义)所引用的 DIE 上——在断定数据缺失前,先解析完整引用链。
  • 类型链:限定符和修饰符(DW_TAG_const_type、DW_TAG_pointer_type……)会包装底层类型;沿 DW_AT_type 链遍历,直到到达基本类型。

评论

支持 Markdown