mcpField
A
apple-crash-symbolication

apple-crash-symbolication

github.com/dotnet开发5.8k3.3k 次安装1 天前更新
代码仓库

关于 apple-crash-symbolication

用于分析 Apple 平台上 .NET MAUI 和 Mono 应用崩溃的技能。它解析 .ips 报告、查找 UUID 匹配的 dSYM 符号,并通过 atos 将原生栈帧解析为函数及源码位置。

主要功能

  1. 01解析双段式 .ips 崩溃报告
  2. 02识别 .NET 运行时栈帧
  3. 03查找 UUID 匹配的 dSYM 符号
  4. 04使用 atos 解析栈帧
  5. 05通过 PowerShell 自动符号化

适用场景

  1. 01追踪 iOS 上的 .NET MAUI 崩溃
  2. 02检查 macOS 上的 Mono 崩溃报告
  3. 03将原生栈帧解析到源码位置
  4. 04在符号化前快速检查崩溃报告

安装

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

$npx skills add https://github.com/dotnet/skills --skill apple-crash-symbolication

安装后在 Claude Code 中输入/apple-crash-symbolication确认已加载。

附带文件references/ips-crash-format.mdscripts/Symbolicate-Crash.ps1

详细介绍

Apple 平台崩溃日志 .NET 符号化

使用 Mach-O UUID 和 dSYM 调试符号包,将 Apple 平台(iOS、tvOS、Mac Catalyst、macOS)上 .NET MAUI 和 Mono 应用崩溃的原生回溯帧解析为函数名称、源文件和行号。

输入: 崩溃日志文件(.ips JSON 格式,iOS 15+ / macOS 12+)、atos(来自 Xcode),以及可选的已连接 iOS 设备(用于提取崩溃日志)。

不适用情形: 崩溃库不是 .NET 组件(例如纯 Swift/UIKit),或崩溃日志是 Android tombstone。


工作流

步骤 1:解析 .ips 崩溃日志

格式检查: 继续之前,请确认文件是 .ips JSON 格式。第一行必须是有效的 JSON。如果文件是纯文本(例如带有 #NN pc 帧行的 Android tombstone,或旧版 Apple .crash 文本格式),请立即停止——此工作流不适用。请向用户说明格式不匹配,不要尝试进行符号化。

.ips 文件是由两部分组成的 JSON:第 1 行是元数据头;其余行是独立的 JSON 崩溃正文。请分别解析:

lines = open('crash.ips').readlines()
metadata = json.loads(lines[0])           # app_name, bundleID, os_version, slice_uuid
crash    = json.loads(''.join(lines[1:])) # Full crash report

崩溃正文中的关键字段:

  • usedImages[N] 包含每个已加载二进制文件的 name、base(加载地址)、uuid 和 arch
  • threads[N].frames[M] 包含 imageOffset 和 imageIndex;帧地址 = usedImages[imageIndex].base + imageOffset
  • exception.type、exception.signal(例如 EXC_CRASH / SIGABRT)
  • asi(应用专属信息)通常包含托管异常消息
  • lastExceptionBacktrace 包含触发崩溃的异常帧
  • faultingThread 是 threads 数组中的索引

解析注意事项: 部分 .ips 文件中存在大小写冲突的重复键(vmRegionInfo / vmregioninfo)。解析前,请预处理原始 JSON,将小写的重复键重命名。asi 字段可能不存在。

步骤 2:识别 .NET 运行时库

筛选 usedImages 中的 .NET 运行时库:

库运行时
libcoreclrCoreCLR 运行时
libmonosgen-2.0Mono 运行时
libSystem.Native.NET BCL 原生组件
libSystem.Globalization.Native.NET BCL 全球化
libSystem.Security.Cryptography.Native.Apple.NET BCL 加密
libSystem.IO.Compression.Native.NET BCL 压缩
libSystem.Net.Security.Native.NET BCL 网络安全

在 Apple 平台上,这些库以 .framework 包的形式提供,因此映像名称可能不包含 .dylib。请使用子字符串匹配(例如匹配 libcoreclr,而非 libcoreclr.dylib)。应用二进制文件可能会在 usedImages 中出现两次,且 UUID 不同。

应用二进制文件中的关键桥接函数:xamarin_process_managed_exception(将托管异常桥接为 ObjC NSException)、xamarin_main、mono_jit_exec、coreclr_execute_assembly。

NativeAOT: 运行时静态链接到应用二进制文件中。libSystem.* BCL 库仍是独立的。应用二进制文件需要使用构建输出中的专属 dSYM。

除非有特别要求,否则请跳过 libsystem_kernel.dylib、UIKitCore 及其他 Apple 系统框架。

第 3 步:解读崩溃

从 asi(特定于应用的信息)开始查看——对于 .NET 崩溃,其中通常包含托管异常类型和消息(例如 XamlParseException、NullReferenceException)。根本原因可能已在此处显现。

然后检查故障线程(threads[faultingThread])。在查看其他线程之前,先说明帧 #0 和 #1 的含义。跨线程上下文(GC 状态、线程池)有助于验证,但不能作为因果关系的证据。

还要检查 lastExceptionBacktrace,查看托管异常经过 xamarin_process_managed_exception 等桥接函数的路径。

有时可以从 usedImages 中的映像路径看出 .NET 运行时版本,尤其是在 macOS 上使用共享框架安装或 NuGet 包布局时(例如 .../Microsoft.NETCore.App/10.0.4/libcoreclr.dylib)。不过,在 iOS 上,映像路径通常位于应用包内(例如 .../Frameworks/libcoreclr.framework/libcoreclr),不会包含运行时版本,因此通常需要通过 Mach-O UUID 与 SDK 包或符号服务器下载的文件进行匹配来推断版本,而不能只依赖路径。

第 4 步:查找 dSYM

对于每个需要符号化的 .NET 库,查找 UUID 匹配的 dSYM:

  1. Microsoft 符号服务器(自动):通过 https://msdl.microsoft.com/download/symbols/_.dwarf/mach-uuid-sym-{UUID}/_.dwarf 下载 .dwarf(UUID 使用小写,不带连字符)。将其转换为 .dSYM 包(使用 usedImages[].name 中的映像名称,例如 libcoreclr):
    mkdir -p libcoreclr.dSYM/Contents/Resources/DWARF
    cp _.dwarf libcoreclr.dSYM/Contents/Resources/DWARF/libcoreclr
    
  2. 构建输出:bin/Debug/net*-ios/ios-arm64/<App>.app.dSYM/
  3. SDK 包:$DOTNET_ROOT/packs/Microsoft.NETCore.App.Runtime.<rid>/<version>/runtimes/<rid>/native/
  4. NuGet 缓存:~/.nuget/packages/microsoft.netcore.app.runtime.<rid>/<version>/runtimes/<rid>/native/
  5. dotnet-symbol:dotnet-symbol --symbols -o symbols-out <path-to-binary.dylib>

务必验证:dwarfdump --uuid <dsym> 必须与崩溃日志中的 UUID 完全匹配。

第 5 步:使用 atos 进行符号化
atos -arch arm64 -o <path.dSYM/Contents/Resources/DWARF/binary_name> -l <load_address> <frame_addresses...>
  • -o 指向 .dSYM 包内部的 DWARF 二进制文件(Contents/Resources/DWARF/),而不是包本身
  • -l 是 usedImages[N].base 中的加载地址
  • 使用 usedImages[N].arch 中的 arch(通常为 arm64,也可能是 arm64e)
  • 每次调用可传入多个地址,以批量进行符号化
# Example: symbolicate libcoreclr frames
atos -arch arm64 -o libcoreclr.dSYM/Contents/Resources/DWARF/libcoreclr -l 0x104000000 0x104522098 0x1043c0014

从输出中去掉 /__w/1/s/ CI 工作区前缀——有意义的路径从 src/runtime/ 开始,对应 dotnet/dotnet VMR。

自动化脚本

scripts/Symbolicate-Crash.ps1 可自动执行完整工作流(解析、查找 dSYM、下载符号和符号化)。请根据此 SKILL.md 文件的位置解析路径。

# $SKILL_DIR is the directory containing this SKILL.md
pwsh "$SKILL_DIR/scripts/Symbolicate-Crash.ps1" -CrashFile MyApp-2026-02-25.ips

使用 -ParseOnly 快速查看概览,无需 atos。如果本地缺少 dSYM,脚本会自动从 Microsoft 符号服务器下载符号。

标志:-CrashingThreadOnly、-OutputFile path、-ParseOnly、-SkipVersionLookup、-SkipSymbolDownload、-SymbolCacheDir path、-DsymSearchPaths path1,path2。


获取崩溃日志

使用 idevicecrashreport(来自 libimobiledevice)从已连接的 iOS 设备提取崩溃日志:

idevicecrashreport -e /tmp/crashlogs/
find /tmp/crashlogs/ -iname '*MyApp*' -name '*.ips'

也可在 Xcode > Window > Devices and Simulators > View Device Logs 中查看,或者在 ~/Library/Logs/CrashReporter/(Mac Catalyst)、~/Library/Logs/DiagnosticReports/(macOS)中查找。


验证

  1. dwarfdump --uuid <dsym> 与崩溃日志中的 UUID 匹配
  2. 至少有一个 .NET 帧解析出函数名称(而非原始地址)
  3. 解析出的路径包含可识别的 .NET 运行时结构(例如 src/coreclr/、mono/metadata/、mono/mini/)

停止信号

  • 文件格式错误:如果文件不是 .ips JSON(例如带有 #NN pc 堆栈帧的 Android tombstone,或旧版 .crash 文本格式),请立即停止——向用户报告格式不匹配,不要继续进行任何符号化。不要尝试使用其他工具或工作流进行符号化。
  • 未找到 .NET 帧:报告已解析的帧并停止。
  • 所有帧均已解析:提供符号化后的回溯,并简要分析崩溃情况(故障线程、异常类型、可能的问题区域)。如果用户要求进一步调查,则继续处理。
  • dSYM 不可用 / UUID 不匹配:报告未符号化的帧及其 UUID 和地址。建议查找原始构建产物。
  • atos 不可用:提供供用户运行的手动 atos 命令。不要安装 Xcode。atos 随 Xcode Command Line Tools 提供(xcode-select --install)。

参考资料

评论

支持 Markdown