android-tombstone-symbolication
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAndroid Tombstone .NET Symbolication
Android Tombstone .NET符号化
Resolves native backtrace frames from .NET Android app crashes (MAUI, Xamarin, Mono) to function names, source files, and line numbers using ELF BuildIds and Microsoft's symbol server.
Inputs: Tombstone file or logcat crash output, (from Android NDK or any LLVM 14+ toolchain), internet access for symbol downloads.
llvm-symbolizerDo not use when: The crash is a managed .NET exception (visible in logcat with a managed stack trace), the crashing library is not a .NET component (e.g., ), or the tombstone is from iOS.
libart.so通过ELF BuildIds和微软符号服务器,将.NET Android应用崩溃(MAUI、Xamarin、Mono)产生的原生回溯栈帧解析为函数名、源文件路径和行号。
输入要求: Tombstone文件或logcat崩溃输出、(来自Android NDK或任意LLVM 14+工具链)、可访问互联网用于下载符号。
llvm-symbolizer不适用场景: 崩溃为托管.NET异常(可在logcat中看到托管栈轨迹)、崩溃的库不是.NET组件(例如)、tombstone来自iOS系统。
libart.soWorkflow
工作流
Step 1: Parse the Tombstone Backtrace
第一步:解析Tombstone回溯
Each backtrace frame has this format:
#NN pc OFFSET /path/to/library.so (optional_symbol+0xNN) (BuildId: HEXSTRING)Extract: frame number, PC offset (hex, already library-relative), library name, and BuildId (32–40 hex chars).
Symbolicate all threads by default (background threads like GC/finalizer often have useful .NET frames). The crashing thread's backtrace is listed first; additional threads appear after markers.
--- --- ---Format notes:
- The script auto-detects frame lines with or without a
#NN pcheader, and strips logcat timestamp/tag prefixes automatically.backtrace: - Logcat-captured tombstones often omit BuildIds. Recover via , CI build artifacts, or the .NET runtime NuGet package.
adb shell readelf -n - GitHub issue pastes may mangle into issue links — replace
#1 pcwithorg/repo#N pcbefore saving to a file.#N pc - If the script fails to parse a format, fall back to manual extraction of tuples.
#NN pc OFFSET library.so (BuildId: HEX)
每个回溯栈帧格式如下:
#NN pc OFFSET /path/to/library.so (optional_symbol+0xNN) (BuildId: HEXSTRING)提取信息:栈帧编号、PC偏移量(十六进制,已为库相对偏移)、库名称、BuildId(32-40个十六进制字符)。
默认符号化所有线程的栈帧(GC/终结器等后台线程通常包含有用的.NET栈帧)。崩溃线程的回溯会排在最前面,其余线程出现在标记之后。
--- --- ---格式说明:
- 脚本可自动识别带或不带头部的
backtrace:栈帧行,自动去除logcat的时间戳/标签前缀。#NN pc - logcat捕获的tombstone通常会缺失BuildIds,可通过、CI构建产物或.NET runtime NuGet包恢复。
adb shell readelf -n - GitHub issue粘贴的内容可能会将误转换为issue链接——保存到文件前请将
#1 pc替换为org/repo#N pc。#N pc - 如果脚本无法解析格式,请手动提取元组。
#NN pc OFFSET library.so (BuildId: HEX)
Step 2: Identify .NET Runtime Libraries
第二步:识别.NET Runtime库
Filter frames to .NET runtime libraries:
| Library | Runtime |
|---|---|
| Mono (MAUI, Xamarin, interpreter) |
| CoreCLR (JIT mode) |
| .NET BCL native components ( |
NativeAOT: No or — the runtime is statically linked into the app binary (e.g., ). The BCL libraries remain separate and can be symbolicated via the symbol server. For the app binary itself, you need the app's own debug symbols.
libcoreclr.solibmonosgen-2.0.solibMyApp.solibSystem.*.soSkip , , and other Android system libraries unless the user specifically asks.
libc.solibart.so筛选出属于.NET runtime库的栈帧:
| 库名称 | 运行时类型 |
|---|---|
| Mono(MAUI、Xamarin、解释器模式) |
| CoreCLR(JIT模式) |
| .NET BCL原生组件( |
NativeAOT: 不存在或,运行时被静态链接到应用二进制中(例如)。 BCL库仍为独立文件,可通过符号服务器进行符号化。应用二进制本身需要自行提供对应的调试符号。
libcoreclr.solibmonosgen-2.0.solibMyApp.solibSystem.*.so除非用户明确要求,否则跳过、和其他Android系统库。
libc.solibart.soStep 3: Download Debug Symbols
第三步:下载调试符号
For each unique .NET BuildId, download debug symbols:
https://msdl.microsoft.com/download/symbols/_.debug/elf-buildid-sym-<BUILDID>/_.debugbash
curl -sL "https://msdl.microsoft.com/download/symbols/_.debug/elf-buildid-sym-1eb39fc72918c7c6c0c610b79eb3d3d47b2f81be/_.debug" \
-o libmonosgen-2.0.so.debugVerify with — should show . If the download returns 404 or HTML, symbols are not published for that build. Do not add or subtract library base addresses — offsets in tombstones are already library-relative.
file libmonosgen-2.0.so.debugELF 64-bit ... with debug_info, not stripped为每个唯一的.NET BuildId下载调试符号:
https://msdl.microsoft.com/download/symbols/_.debug/elf-buildid-sym-<BUILDID>/_.debugbash
curl -sL "https://msdl.microsoft.com/download/symbols/_.debug/elf-buildid-sym-1eb39fc72918c7c6c0c610b79eb3d3d47b2f81be/_.debug" \
-o libmonosgen-2.0.so.debug使用验证,输出应显示。如果下载返回404或HTML内容,说明该构建版本未发布符号。不要调整库基地址——tombstone中的偏移量已经是库相对偏移。
file libmonosgen-2.0.so.debugELF 64-bit ... with debug_info, not strippedStep 4: Symbolicate Each Frame
第四步:符号化每个栈帧
bash
llvm-symbolizer --obj=libmonosgen-2.0.so.debug -f -C 0x222098Output:
ves_icall_System_Environment_FailFast
/__w/1/s/src/runtime/src/mono/mono/metadata/icall.c:6244The prefix is the CI workspace root — the meaningful path starts at , mapping to dotnet/dotnet VMR.
/__w/1/s/src/runtime/bash
llvm-symbolizer --obj=libmonosgen-2.0.so.debug -f -C 0x222098输出示例:
ves_icall_System_Environment_FailFast
/__w/1/s/src/runtime/src/mono/mono/metadata/icall.c:6244Step 5: Present the Symbolicated Backtrace
第五步:展示符号化后的回溯
Combine original frame numbers with resolved function names and source locations:
#00 libc.so abort+164
#01 libmonosgen-2.0.so ves_icall_System_Environment_FailFast (mono/metadata/icall.c:6244)
#02 libmonosgen-2.0.so do_icall (mono/mini/interp.c:2457)
#03 libmonosgen-2.0.so mono_interp_exec_method (mono/mini/interp.c)For unresolved frames (), keep the original line with BuildId and PC offset.
??将原始栈帧编号与解析后的函数名、源码位置合并展示:
#00 libc.so abort+164
#01 libmonosgen-2.0.so ves_icall_System_Environment_FailFast (mono/metadata/icall.c:6244)
#02 libmonosgen-2.0.so do_icall (mono/mini/interp.c:2457)
#03 libmonosgen-2.0.so mono_interp_exec_method (mono/mini/interp.c)对于未解析的栈帧(显示),保留包含BuildId和PC偏移量的原始行。
??Automation Script
自动化脚本
scripts/Symbolicate-Tombstone.ps1 automates the full workflow:
powershell
pwsh scripts/Symbolicate-Tombstone.ps1 -TombstoneFile tombstone_01.txt -LlvmSymbolizer llvm-symbolizerFlags: (limit to crashing thread), (write to file), (report libraries/BuildIds/URLs without downloading), (skip runtime version identification).
-CrashingThreadOnly-OutputFile path-ParseOnly-SkipVersionLookupscripts/Symbolicate-Tombstone.ps1可自动化完成全流程:
powershell
pwsh scripts/Symbolicate-Tombstone.ps1 -TombstoneFile tombstone_01.txt -LlvmSymbolizer llvm-symbolizer可用参数:(仅处理崩溃线程)、(输出到指定文件)、(仅输出库/BuildId/下载链接,不执行下载)、(跳过运行时版本识别)。
-CrashingThreadOnly-OutputFile path-ParseOnly-SkipVersionLookupFinding llvm-symbolizer
查找llvm-symbolizer
Check the Android NDK first: or . Also available via , , or on macOS.
$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/*/bin/llvm-symbolizer$ANDROID_HOME/ndk/*/toolchains/llvm/prebuilt/*/bin/llvm-symbolizerbrew install llvmapt install llvmxcrun --find llvm-symbolizerIf unavailable, complete steps 1–3 and present the download commands and commands for the user to run. Do not spend time installing LLVM.
llvm-symbolizer优先从Android NDK中查找:路径为或。也可通过包管理器安装:macOS上执行、Debian/Ubuntu上执行,或在macOS上通过查找。
$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/*/bin/llvm-symbolizer$ANDROID_HOME/ndk/*/toolchains/llvm/prebuilt/*/bin/llvm-symbolizerbrew install llvmapt install llvmxcrun --find llvm-symbolizer如果无法获取llvm-symbolizer,完成步骤1-3后向用户提供下载命令和执行命令即可,无需花费时间安装LLVM。
llvm-symbolizerUnderstanding the Output
理解输出内容
CI source paths use these prefixes:
| Path prefix | Maps to |
|---|---|
| |
| |
| VMR root |
CI源码路径的前缀对应关系如下:
| 路径前缀 | 对应路径 |
|---|---|
| dotnet/dotnet VMR仓库中的 |
| VMR仓库中的 |
| VMR仓库根目录 |
Runtime Version Identification
运行时版本识别
The script identifies the exact .NET runtime version by matching BuildIds against locally-installed runtime packs. It searches: SDK packs (), NuGet cache (), and NuGet.org as an online fallback. When found, it extracts the version and source commit from the element. Pass to disable. Requires (auto-discovered from the NDK).
$DOTNET_ROOT/packs/~/.nuget/packages/.nuspec<repository commit="..." />-SkipVersionLookupllvm-readelf脚本可通过将BuildId与本地安装的运行时包匹配,识别准确的.NET runtime版本。搜索范围包括:SDK包()、NuGet缓存(),以及NuGet.org作为在线 fallback。找到匹配后会从文件的元素中提取版本和源码提交哈希。可传入参数禁用该功能,该功能需要(会从NDK中自动查找)。
$DOTNET_ROOT/packs/~/.nuget/packages/.nuspec<repository commit="..." />-SkipVersionLookupllvm-readelfValidation
验证标准
- shows
file <debug-file>ELF ... with debug_info, not stripped - At least one .NET frame resolves to a function name (not )
?? - Resolved paths contain recognizable .NET runtime structure (e.g., ,
mono/metadata/)mono/mini/
- 输出显示
file <debug-file>ELF ... with debug_info, not stripped - 至少有一个.NET栈帧解析为有效函数名(不是)
?? - 解析后的路径包含可识别的.NET runtime结构(例如、
mono/metadata/)mono/mini/
Stop Signals
停止信号
- No .NET frames found: Report parsed frames and stop.
- All frames resolved: Present symbolicated backtrace. Do not trace into source or attempt to build/debug the runtime.
- Symbols not available (404): One attempt per BuildId, then stop. Report unsymbolicated frames with BuildIds and offsets.
- llvm-symbolizer not available: Use , present manual commands. Do not install LLVM.
-ParseOnly
- 未找到.NET栈帧:报告已解析的栈帧后终止流程。
- 所有栈帧已解析:展示符号化后的回溯即可,无需深入追踪源码或尝试构建/调试运行时。
- 符号不存在(返回404):每个BuildId尝试一次下载后终止,报告未符号化的栈帧及对应的BuildId和偏移量。
- 无可用llvm-symbolizer:使用参数输出手动执行命令即可,无需安装LLVM。
-ParseOnly
Common Pitfalls
常见问题
- Missing BuildIds: Logcat tombstones often omit BuildIds. Recover via: , CI build artifacts, or the runtime NuGet package (
adb shell readelf -n /path/to/lib.so). Prefer pulling raw tombstone files (~/.dotnet/packs/Microsoft.NETCore.App.Runtime.Mono.android-arm64/<version>/) which always include BuildIds.adb shell cat /data/tombstones/tombstone_XX - Symbols not found (404): Pre-release/internal builds may not publish symbols. Check for local unstripped /
.soin build artifacts or the NuGet runtime pack..so.dbg - NativeAOT: No runtime in the tombstone — runtime is in the app binary.
.soBCL libraries still work with the symbol server; the app binary needs its own debug symbols.libSystem.*.so - Wrong llvm-symbolizer version: Use LLVM 14+ for best DWARF compatibility.
- Multiple BuildIds: Each .NET library has its own BuildId — download symbols for each separately.
- 缺失BuildIds:logcat输出的tombstone通常会缺失BuildIds,可通过以下方式恢复:、CI构建产物、运行时NuGet包(
adb shell readelf -n /path/to/lib.so)。优先拉取原始tombstone文件(~/.dotnet/packs/Microsoft.NETCore.App.Runtime.Mono.android-arm64/<version>/),这类文件始终包含BuildIds。adb shell cat /data/tombstones/tombstone_XX - 找不到符号(404):预发布/内部构建版本可能不会发布符号,可检查构建产物或NuGet运行时包中是否存在未剥离的/
.so文件。.so.dbg - NativeAOT场景:tombstone中不存在独立的运行时文件,运行时被打包到应用二进制中。
.soBCL库仍可通过符号服务器符号化,应用二进制需要自行提供调试符号。libSystem.*.so - llvm-symbolizer版本错误:建议使用LLVM 14+版本以获得最佳DWARF兼容性。
- 多个BuildIds:每个.NET库都有独立的BuildId,需要分别下载对应的符号。