apple-crash-symbolication

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Apple Platform Crash Log .NET Symbolication

苹果平台崩溃日志的.NET符号化解析

Resolves native backtrace frames from .NET MAUI and Mono app crashes on Apple platforms (iOS, tvOS, Mac Catalyst, macOS) to function names, source files, and line numbers using Mach-O UUIDs and dSYM debug symbol bundles.
Inputs: Crash log file (
.ips
JSON format, iOS 15+ / macOS 12+),
atos
(from Xcode), optionally a connected iOS device to pull crash logs from.
Do not use when: The crashing library is not a .NET component (e.g., pure Swift/UIKit), or the crash log is an Android tombstone.

通过Mach-O UUID和dSYM调试符号包,将苹果平台(iOS、tvOS、Mac Catalyst、macOS)上.NET MAUI和Mono应用崩溃的原生回溯帧解析为函数名、源文件及行号。
输入:崩溃日志文件(
.ips
JSON格式,iOS 15+ / macOS 12+)、
atos
(来自Xcode),可选已连接的iOS设备用于拉取崩溃日志。
不适用场景:崩溃库并非.NET组件(如纯Swift/UIKit),或崩溃日志为Android tombstone文件。

Workflow

工作流程

Step 1: Parse the .ips Crash Log

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

Format check: Before proceeding, verify the file is
.ips
JSON format. The first line must be valid JSON. If the file is plain text (e.g., Android tombstone with
#NN pc
frame lines, or legacy Apple
.crash
text format), stop immediately — this workflow does not apply. Report the format mismatch to the user and do not attempt any symbolication.
The
.ips
file is two-part JSON: line 1 is a metadata header; the remaining lines are a separate JSON crash body. Parse them separately:
python
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
Key fields in the crash body:
  • usedImages[N]
    has
    name
    ,
    base
    (load address),
    uuid
    ,
    arch
    for each loaded binary
  • threads[N].frames[M]
    has
    imageOffset
    ,
    imageIndex
    ; frame address =
    usedImages[imageIndex].base + imageOffset
  • exception.type
    ,
    exception.signal
    (e.g.,
    EXC_CRASH
    /
    SIGABRT
    )
  • asi
    (Application Specific Information) often contains the managed exception message
  • lastExceptionBacktrace
    has frames from the exception that triggered the crash
  • faultingThread
    is the index into the
    threads
    array
Parsing gotcha: Some .ips files have case-conflicting duplicate keys (
vmRegionInfo
/
vmregioninfo
). Pre-process the raw JSON to rename the lowercase duplicate before parsing. The
asi
field may be absent.
格式检查:在开始前,验证文件为
.ips
JSON格式。第一行必须是有效的JSON。如果文件是纯文本格式(例如带有
#NN pc
帧行的Android tombstone,或旧版苹果
.crash
文本格式),请立即停止——本工作流程不适用。向用户报告格式不匹配问题,不要尝试任何符号化解析操作。
.ips
文件是两部分JSON结构:第一行是元数据头;剩余行是独立的崩溃主体JSON。需分别解析:
python
lines = open('crash.ips').readlines()
metadata = json.loads(lines[0])           # app_name, bundleID, os_version, slice_uuid
crash    = json.loads(''.join(lines[1:])) # 完整崩溃报告
崩溃主体中的关键字段:
  • 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
字段可能不存在。

Step 2: Identify .NET Runtime Libraries

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

Filter
usedImages
to .NET runtime libraries:
LibraryRuntime
libcoreclr
CoreCLR runtime
libmonosgen-2.0
Mono runtime
libSystem.Native
.NET BCL native component
libSystem.Globalization.Native
.NET BCL globalization
libSystem.Security.Cryptography.Native.Apple
.NET BCL crypto
libSystem.IO.Compression.Native
.NET BCL compression
libSystem.Net.Security.Native
.NET BCL net security
On Apple platforms these ship as
.framework
bundles, so image names may omit
.dylib
. Match using substring (e.g.,
libcoreclr
not
libcoreclr.dylib
). The app binary may appear twice in
usedImages
with different UUIDs.
Key bridge functions in the app binary:
xamarin_process_managed_exception
(managed exception bridged to ObjC NSException),
xamarin_main
,
mono_jit_exec
,
coreclr_execute_assembly
.
NativeAOT: Runtime is statically linked into the app binary.
libSystem.*
BCL libraries remain separate. The app binary needs its own dSYM from the build output.
Skip
libsystem_kernel.dylib
,
UIKitCore
, and other Apple system frameworks unless specifically asked.
usedImages
中筛选出.NET运行时库:
库名称运行时环境
libcoreclr
CoreCLR运行时
libmonosgen-2.0
Mono运行时
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网络安全组件
在苹果平台上,这些库以
.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
及其他苹果系统框架。

Step 3: Interpret the Crash

步骤3:分析崩溃原因

Start with
asi
(Application Specific Information) — for .NET crashes, it often contains the managed exception type and message (e.g.,
XamlParseException
,
NullReferenceException
). The root cause may already be visible here.
Then examine the faulting thread (
threads[faultingThread]
). Explain what frames #0 and #1 mean before examining other threads. Cross-thread context (GC state, thread pool) is useful for validation but not evidence of causation.
Also check
lastExceptionBacktrace
for the managed exception path through bridge functions like
xamarin_process_managed_exception
.
Sometimes the .NET runtime version is visible in image paths in
usedImages
, particularly on macOS when using shared-framework installs or NuGet-pack-style layouts (e.g.,
.../Microsoft.NETCore.App/10.0.4/libcoreclr.dylib
). On iOS, however, image paths are typically inside the app bundle (for example,
.../Frameworks/libcoreclr.framework/libcoreclr
) and do not embed the runtime version, so you usually need to infer it via the Mach-O UUID by matching against SDK packs or symbol-server downloads rather than relying on the path alone.
首先查看
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包或符号服务器下载内容匹配来推断版本,而非依赖路径。

Step 4: Locate dSYMs

步骤4:定位dSYM

For each .NET library needing symbolication, locate a UUID-matched dSYM:
  1. Microsoft symbol server (automatic): Download
    .dwarf
    via
    https://msdl.microsoft.com/download/symbols/_.dwarf/mach-uuid-sym-{UUID}/_.dwarf
    (UUID lowercase, no dashes). Convert to
    .dSYM
    bundle (use the image name from
    usedImages[].name
    , e.g.,
    libcoreclr
    ):
    bash
    mkdir -p libcoreclr.dSYM/Contents/Resources/DWARF
    cp _.dwarf libcoreclr.dSYM/Contents/Resources/DWARF/libcoreclr
  2. Build output:
    bin/Debug/net*-ios/ios-arm64/<App>.app.dSYM/
  3. SDK packs:
    $DOTNET_ROOT/packs/Microsoft.NETCore.App.Runtime.<rid>/<version>/runtimes/<rid>/native/
  4. NuGet cache:
    ~/.nuget/packages/microsoft.netcore.app.runtime.<rid>/<version>/runtimes/<rid>/native/
  5. dotnet-symbol
    :
    dotnet-symbol --symbols -o symbols-out <path-to-binary.dylib>
Always verify:
dwarfdump --uuid <dsym>
must match the UUID from the crash log exactly.
对于每个需要符号化解析的.NET库,找到匹配UUID的dSYM:
  1. Microsoft符号服务器(自动):通过
    https://msdl.microsoft.com/download/symbols/_.dwarf/mach-uuid-sym-{UUID}/_.dwarf
    下载
    .dwarf
    文件(UUID需小写,无连字符)。转换为
    .dSYM
    包(使用
    usedImages[].name
    中的镜像名称,例如
    libcoreclr
    ):
    bash
    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完全匹配。

Step 5: Symbolicate with atos

步骤5:使用atos进行符号化解析

bash
atos -arch arm64 -o <path.dSYM/Contents/Resources/DWARF/binary_name> -l <load_address> <frame_addresses...>
  • -o
    points to the DWARF binary inside the
    .dSYM
    bundle (
    Contents/Resources/DWARF/
    ), not the bundle itself
  • -l
    is the load address from
    usedImages[N].base
  • Use the
    arch
    from
    usedImages[N].arch
    (usually
    arm64
    , may be
    arm64e
    )
  • Pass multiple addresses per invocation for batch symbolication
bash
undefined
bash
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
    中的架构(通常为
    arm64
    ,可能为
    arm64e
  • 一次调用可传入多个地址进行批量符号化解析
bash
undefined

Example: symbolicate libcoreclr frames

示例:对libcoreclr帧进行符号化解析

atos -arch arm64 -o libcoreclr.dSYM/Contents/Resources/DWARF/libcoreclr -l 0x104000000 0x104522098 0x1043c0014

Strip the `/__w/1/s/` CI workspace prefix from output — meaningful paths start at `src/runtime/`, mapping to the [dotnet/dotnet](https://github.com/dotnet/dotnet) VMR.
atos -arch arm64 -o libcoreclr.dSYM/Contents/Resources/DWARF/libcoreclr -l 0x104000000 0x104522098 0x1043c0014

从输出中去除`/__w/1/s/` CI工作区前缀——有意义的路径从`src/runtime/`开始,对应[dotnet/dotnet](https://github.com/dotnet/dotnet) VMR。

Automation Script

自动化脚本

scripts/Symbolicate-Crash.ps1 automates the full workflow (parsing, dSYM lookup, symbol download, and symbolication). Resolve the path relative to this SKILL.md file.
powershell
undefined
scripts/Symbolicate-Crash.ps1可自动化完成整个工作流程(解析、dSYM查找、符号下载、符号化解析)。请相对于本SKILL.md文件解析路径。
powershell
undefined

$SKILL_DIR is the directory containing this SKILL.md

$SKILL_DIR是包含本SKILL.md的目录

pwsh "$SKILL_DIR/scripts/Symbolicate-Crash.ps1" -CrashFile MyApp-2026-02-25.ips

Start with `-ParseOnly` for a fast overview without requiring `atos`. The script automatically downloads symbols from the Microsoft symbol server when local dSYMs are missing.

Flags: `-CrashingThreadOnly`, `-OutputFile path`, `-ParseOnly`, `-SkipVersionLookup`, `-SkipSymbolDownload`, `-SymbolCacheDir path`, `-DsymSearchPaths path1,path2`.

---
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`。

---

Retrieving Crash Logs

获取崩溃日志

Pull crash logs from a connected iOS device using
idevicecrashreport
(from libimobiledevice):
bash
idevicecrashreport -e /tmp/crashlogs/
find /tmp/crashlogs/ -iname '*MyApp*' -name '*.ips'
Also available in Xcode > Window > Devices and Simulators > View Device Logs, or at
~/Library/Logs/CrashReporter/
(Mac Catalyst),
~/Library/Logs/DiagnosticReports/
(macOS).

使用
idevicecrashreport
(来自libimobiledevice)从已连接的iOS设备拉取崩溃日志:
bash
idevicecrashreport -e /tmp/crashlogs/
find /tmp/crashlogs/ -iname '*MyApp*' -name '*.ips'
也可通过Xcode > 窗口 > 设备与模拟器 > 查看设备日志获取,或在以下路径查找:
~/Library/Logs/CrashReporter/
(Mac Catalyst)、
~/Library/Logs/DiagnosticReports/
(macOS)。

Validation

验证

  1. dwarfdump --uuid <dsym>
    matches UUID from the crash log
  2. At least one .NET frame resolves to a function name (not a raw address)
  3. Resolved paths contain recognizable .NET runtime structure (e.g.,
    src/coreclr/
    ,
    mono/metadata/
    ,
    mono/mini/
    )
  1. dwarfdump --uuid <dsym>
    与崩溃日志中的UUID匹配
  2. 至少有一个.NET帧解析为函数名(而非原始地址)
  3. 解析后的路径包含可识别的.NET运行时结构(例如
    src/coreclr/
    ,
    mono/metadata/
    ,
    mono/mini/

Stop Signals

终止信号

  • Wrong file format: If the file is not
    .ips
    JSON (e.g., Android tombstone with
    #NN pc
    stack frames, legacy
    .crash
    text format), stop immediately — report the format mismatch to the user and do not proceed with any symbolication. Do not attempt to symbolicate using other tools or workflows.
  • No .NET frames found: Report parsed frames and stop.
  • All frames resolved: Present symbolicated backtrace with brief crash analysis (faulting thread, exception type, likely area). If the user asks for deeper investigation, proceed.
  • dSYM not available / UUID mismatch: Report unsymbolicated frames with UUIDs and addresses. Suggest locating the original build artifacts.
  • atos not available: Present the manual
    atos
    commands for the user to run. Do not install Xcode.
    atos
    ships with Xcode Command Line Tools (
    xcode-select --install
    ).
  • 文件格式错误:如果文件不是
    .ips
    JSON格式(例如带有
    #NN pc
    调用栈帧的Android tombstone、旧版
    .crash
    文本格式),请立即停止——向用户报告格式不匹配问题,不要继续任何符号化解析操作。不要尝试使用其他工具或工作流程进行符号化解析。
  • 未找到.NET帧:报告解析后的帧并停止。
  • 所有帧已解析:展示符号化后的回溯信息及简要崩溃分析(故障线程、异常类型、可能的问题区域)。如果用户要求深入调查,再继续。
  • dSYM不可用/UUID不匹配:报告未符号化的帧及其UUID和地址。建议用户定位原始构建产物。
  • atos不可用:提供手动运行的
    atos
    命令供用户执行。不要安装Xcode。
    atos
    随Xcode命令行工具一起发布(
    xcode-select --install
    )。

References

参考资料

  • IPS format details: See references/ips-crash-format.md for additional .ips parsing details and macOS symbol package differences.
  • IPS格式详情:查看references/ips-crash-format.md获取更多.ips解析细节及macOS符号包差异。