关于 symbolicate-crash-dump
symbolicate-crash-dump 介绍如何使用 `electron-minidump` 将 VS Code 原生 `.dmp` 文件转换为可读回溯。该指南面向 VS Code 团队成员,涵盖符号匹配、崩溃归因及远程 Linux 扩展主机崩溃分析。
主要功能
- 01符号化原生崩溃转储
- 02按构建版本和调试 ID 匹配符号
- 03判断崩溃模块与进程
- 04比较重复崩溃特征
- 05使用 gdb 分析远程 Linux 核心转储
适用场景
- 01分析 VS Code 原生崩溃
- 02定位缺失的符号文件
- 03判断崩溃所属模块
- 04调查远程扩展主机崩溃
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ vscode --skill symbolicate-crash-dump安装后在 Claude Code 中输入/symbolicate-crash-dump确认已加载。
详细介绍
符号化崩溃转储文件
使用 electron-minidump,将原生 VS Code 崩溃转储文件(.dmp)转换为包含方法名称的可读回溯信息。
仅限 VS Code 团队成员。 内部 Electron、Insiders 和 Stable 版本的符号文件存放在一个相邻的私有发布仓库中。必须使用 macOS 或 Linux 设备——electron-minidump 无法在 Windows 上运行。
前提条件
- 崩溃转储文件(
*.dmp)。如果还没有,请参阅下方的创建崩溃报告。 - 全局安装
electron-minidump:npm install -g electron-minidump - 对于 Insiders/Stable 符号,需要经过身份验证且有权访问私有
microsoft/vscode-electron-prebuilt仓库的 GitHub CLI(gh auth status)。
操作步骤
1. 运行初步符号化
此操作会生成或刷新 electron-minidump 缓存,并告知你仍缺少哪些符号。
electron-minidump crash-file.dmp > symbolicated-output.log
检查 symbolicated-output.log。查看回溯信息顶部的栈帧:如果某个栈帧列出了模块(例如 Electron Framework),但后面没有方法名称,则需要该模块的符号。
临时下载错误时请重试。 electron-minidump 会从公共符号服务器下载符号,因此运行时可能会遇到临时网络错误(例如
failed to download ... (code 56)或(code 28))。已成功下载的符号会缓存,因此只需重新运行相同命令,就能从中断处继续。预期需要重试几次:for i in 1 2 3 4 5; do electron-minidump crash-file.dmp > symbolicated-output.log && break sleep 3 done
2. 获取相应的符号文件
根据导致崩溃的版本,选择符号来源:
| 发生崩溃的版本 | 符号文件来源 |
|---|---|
| Insiders / Stable(内部 Electron) | microsoft/vscode-electron-prebuilt releases |
| Code - OSS(OSS Electron) | electron/electron releases |
microsoft/vscode-electron-prebuilt 是一个私有仓库——因此此流程仅限团队成员使用。未通过身份验证时,普通浏览器或 curl 链接会返回 404;请改用经过身份验证的 GitHub CLI 下载资源(gh auth status 应显示你已登录):
# List releases (tagged by Electron version) to find the right tag:
gh release list --repo microsoft/vscode-electron-prebuilt
# Download just the symbol zip you need:
gh release download v42.5.0-14525058 \
--repo microsoft/vscode-electron-prebuilt \
--pattern "stable-symbols-v42.5.0-win32-x64.zip"
发布版本使用 Electron 版本标记,而非 VS Code 版本,因此请先找出发生崩溃的 VS Code 版本所使用的 Electron 版本。该版本 .npmrc 中的 target= 就是所需信息(例如 git show 1.128.0:.npmrc),它与 package.json 中的 electron 开发依赖项一致。然后根据质量、平台和架构选择匹配的符号 zip 文件——例如,Electron 42.5.0 上发生崩溃的 Stable Windows x64 版本需要 stable-symbols-v42.5.0-win32-x64.zip(Insiders 版本请使用 insiders-symbols-…)。Code - OSS 符号来自公开的 electron/electron releases,无需特殊权限即可下载。
这些 zip 文件较小,且仅包含部分符号。
*-symbols-*.zip通常只包含少数几个第一方模块——Windows 上的electron.exe.sym、libEGL.dll.sym、libGLESv2.dll.sym(其他平台上则包含对应文件)。回溯信息中出现的许多模块——尤其是runtime.node和任何操作系统或第三方 DLL——都不在这些 zip 文件中。通常无法使用公开符号为runtime.node栈帧进行符号化;如果崩溃发生在第三方模块中,应根据模块名称判断,而不要期待每个栈帧都有方法名称(请参阅阅读结果)。
3. 将 .sym 文件复制到 electron-minidump 缓存
缓存位于:
"$(npm root -g)/electron-minidump/cache/breakpad_symbols"
Breakpad 使用 <module>.pdb/<debug-id>/<module>.sym 作为符号键,其中 <debug-id> 必须与转储文件和符号压缩包中的值完全一致——即使是同一版本,只要压缩包来自不同的流水线运行,其 ID 就会不同,因此不会被使用。完成初步检查后,缓存中已经为每个所需模块创建了一个(空)目录,你必须匹配其名称和哈希值:
CACHE="$(npm root -g)/electron-minidump/cache/breakpad_symbols"
# The debug-id electron-minidump wants for a given module:
ls "$CACHE/electron.exe.pdb" # e.g. DD081533CD7E33A44C4C44205044422E1
解压下载的符号文件,并确认压缩包中存在相同模块和哈希值,然后再将其复制到缓存中。压缩包内部的布局同样是 <module>.pdb/<debug-id>/<module>.sym。
示例(Windows:随附的主二进制文件是 Code.exe,但其符号来自 electron.exe.sym):
# Unzip somewhere, e.g. ~/stable-symbols/
unzip stable-symbols-v42.5.0-win32-x64.zip -d ~/stable-symbols
# Only copy if the debug-id matches what the cache expects.
# Keep the tilde outside quotes so it expands to your home directory:
HASH=DD081533CD7E33A44C4C44205044422E1
cp ~/stable-symbols/symbols/electron.exe.pdb/"$HASH"/electron.exe.sym \
"$CACHE/electron.exe.pdb/$HASH/"
在 macOS 上,对应的模块是 Electron Framework(Electron Framework/<hash>/Electron Framework.sym)。对于初步检查报告缺少方法名的其他模块,也重复此操作——但前提是压缩包中确实包含与其哈希值匹配的 .sym 文件。
如果不存在哈希值匹配的符号文件,就无法获取该模块的方法名——这在官方发布的 Stable/Insiders 版本中很常见,因为公开的预构建压缩包里可能没有其准确的
electron.exe/Code.exe哈希值;runtime.node也常见这种情况。请改为根据模块和进程判断崩溃原因(见阅读结果);这通常足以找出第三方责任方。
4. 重新运行符号化
electron-minidump crash-file.dmp > symbolicated-output.log
symbolicated-output.log 中的回溯现在应该已附带方法名。如果仍有一些栈帧没有方法名,请返回步骤 2,为仍缺少符号的模块重复操作。
阅读结果
获得符号化的回溯后,请回答两个问题,以确定根本原因:
哪个模块导致了崩溃?
查看崩溃线程的顶层栈帧(标记为 (crashed))及其模块名称:
- 如果是 VS Code / Electron 模块——
Code.exe、runtime.node、Electron Framework、libnode、libffmpeg、V8 栈帧——故障很可能出在产品或 Electron 内部。 - 如果是第三方 / 操作系统模块——注入进程的杀毒软件、VPN、代理或 shell 扩展 DLL——崩溃几乎肯定由该软件而非 VS Code 导致。注入的 DLL 通常会与
runtime.node/V8 栈帧交错出现,因为它们会挂钩运行时。
请在磁盘上找到该模块的加载位置,以确认它属于第三方。在 Windows 上,转储文件中的 strings 通常会显示完整路径,例如 DLL 位于 C:\WINDOWS\system32\ 或供应商目录下,而非 VS Code 安装目录:
strings -a crash-file.dmp | grep -i "<SuspectModule>" | sort -u
哪个进程发生了崩溃?
进程类型可以告诉你崩溃的是主进程、渲染器/窗口,还是扩展宿主。在较新的 Electron 中,扩展宿主运行在 Node 实用程序进程内,因此此类崩溃会显示为 node.mojom.NodeService 实用程序进程,而不是名称真的叫“扩展宿主”的进程:
strings -a crash-file.dmp | grep -oiE "utility-sub-type=[a-zA-Z0-9._-]+|node\.mojom\.[A-Za-z]+|--type=[a-z-]+" | sort -u
| 标记 | 进程 |
|---|---|
node.mojom.NodeService / utility-sub-type=node.mojom.NodeService | 扩展宿主(Node 实用程序进程) |
--type=renderer | 工作台窗口(渲染器) |
--type=gpu-process | GPU 进程 |
(no --type) | 主进程 |
请将此信息与报告中的症状进行对照(例如,“扩展宿主崩溃循环”应对应 NodeService 实用程序进程崩溃)。
如果有多个转储文件,请分别对其进行符号化,并比较崩溃原因和顶层栈帧——多个转储文件中出现相同的特征,表明原因一致且可复现。
创建崩溃报告
如果你还没有 .dmp 文件,可以使用 --crash-reporter-directory 选项生成一个:
- 关闭所有 VS Code 实例。
- 在命令行中运行
code --crash-reporter-directory <absolute-path>(Insiders 版本请使用code-insiders)。 - 执行导致崩溃的操作。
- 在该文件夹中查找
*.dmp文件。
只有当你拥有与构建版本匹配的符号文件时,才能对崩溃进行符号化。Insiders/Stable 版本的崩溃需要内部 Electron 符号文件;本地源代码构建版本(Code - OSS)的崩溃需要 OSS Electron 符号文件。
远程扩展宿主崩溃(Linux,gdb)
远程服务的扩展宿主发生原生崩溃时,会使用核心转储和 gdb,而非 electron-minidump:
- 启动服务前,允许生成核心转储:
ulimit -c unlimited。 - 重现崩溃。通过
coredumpctl获取核心转储,或从/proc/sys/kernel/core_pattern中指定的路径获取。 - 在 gdb 中加载核心转储并捕获输出:
然后运行以下命令并收集输出:gdb -se <path-to-vscode-server>/node -c <path-to-core-file>set pagination off info sharedlibrary info registers bt full disassemble
提示
- 请勿将
crash-file.dmp和symbolicated-output.log放入仓库——它们是临时产物。 - 缓存路径是动态的;请始终使用
$(npm root -g)解析路径,而不要硬编码主目录。 - Breakpad 根据精确的 debug-id 匹配符号,而非版本名称。如果添加符号后仍缺少方法名,请确认复制的
.sym与缓存目录所需的哈希完全一致,并再次检查符号 zip 的质量(stable/insiders)、平台(win32/darwin/linux)和架构(x64/arm64)。 - 并非所有帧都能进行符号化。
runtime.node和第三方/OS 模块通常没有公开符号;通常只需识别发生崩溃的模块和进程,就足以找到根本原因。