apple-crash-symbolication について
Apple プラットフォーム上の .NET MAUI と Mono アプリを分析するスキルです。.ips レポートを解析し、UUID が一致する dSYM を探して、atos でネイティブフレームを関数やソース位置に解決します。
主な機能
- 012 部構成の .ips クラッシュレポート解析
- 02.NET ランタイムフレームの識別
- 03UUID が一致する dSYM の検索
- 04atos によるフレーム解決
- 05PowerShell によるシンボリケーション自動化
活用シーン
- 01iOS 上の .NET MAUI クラッシュ追跡
- 02macOS 上の Mono クラッシュレポート調査
- 03ネイティブフレームをソース位置に解決
- 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 シンボリケーション
Apple プラットフォーム(iOS、tvOS、Mac Catalyst、macOS)で発生した .NET MAUI および Mono アプリのクラッシュについて、Mach-O UUID と dSYM デバッグシンボルバンドルを使って、ネイティブのバックトレースフレームを関数名、ソースファイル名、行番号に解決します。
入力: クラッシュログファイル(.ips JSON 形式、iOS 15 以降/macOS 12 以降)、atos(Xcode に付属)、必要に応じてクラッシュログの取得に使用する接続済み iOS デバイス。
使用しない場合: クラッシュしたライブラリが .NET コンポーネントではない場合(例:Swift/UIKit のみ)、またはクラッシュログが Android の tombstone の場合。
ワークフロー
ステップ 1:.ips クラッシュログを解析する
形式の確認: 作業を進める前に、ファイルが .ips JSON 形式であることを確認します。1 行目は有効な JSON である必要があります。ファイルがプレーンテキスト(例:#NN pc 形式のフレーム行を含む Android tombstone、または従来の Apple .crash テキスト形式)の場合は、直ちに中止してください。このワークフローは適用できません。形式が一致しないことをユーザーに伝え、シンボリケーションを試みないでください。
.ips ファイルは 2 部構成の 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 + imageOffsetexception.type、exception.signal(例:EXC_CRASH/SIGABRT)asi(アプリケーション固有情報)には、管理例外のメッセージが含まれることがよくありますlastExceptionBacktraceには、クラッシュの原因となった例外のフレームが含まれますfaultingThreadはthreads配列内のインデックスです
解析時の注意点: 一部の .ips ファイルには、大文字と小文字が異なる重複キー(vmRegionInfo/vmregioninfo)があります。解析前に、生の JSON を前処理して小文字の重複キーの名前を変更してください。asi フィールドが存在しない場合もあります。
ステップ 2:.NET ランタイムライブラリを特定する
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 ネットワークセキュリティ |
Apple プラットフォームでは、これらは .framework バンドルとして提供されるため、イメージ名に .dylib が含まれないことがあります。部分文字列で照合してください(例:libcoreclr.dylib ではなく libcoreclr)。アプリのバイナリが、UUID の異なる 2 つの項目として usedImages に現れることがあります。
アプリのバイナリに含まれる主なブリッジ関数: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 を特定します。
- 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 - ビルド出力:
bin/Debug/net*-ios/ios-arm64/<App>.app.dSYM/ - SDK パック:
$DOTNET_ROOT/packs/Microsoft.NETCore.App.Runtime.<rid>/<version>/runtimes/<rid>/native/ - NuGet キャッシュ:
~/.nuget/packages/microsoft.netcore.app.runtime.<rid>/<version>/runtimes/<rid>/native/ dotnet-symbol:dotnet-symbol --symbols -o symbols-out <path-to-binary.dylib>
必ず検証してください:dwarfdump --uuid <dsym> の UUID がクラッシュログの 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の場合もあります)- バッチでシンボル化するには、1 回の実行で複数のアドレスを渡します
# 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
atos を使わずに概要をすばやく確認するには、-ParseOnly から始めてください。ローカルに dSYM がない場合、スクリプトは Microsoft シンボルサーバーからシンボルを自動的にダウンロードします。
フラグ:-CrashingThreadOnly、-OutputFile path、-ParseOnly、-SkipVersionLookup、-SkipSymbolDownload、-SymbolCacheDir path、-DsymSearchPaths path1,path2。
クラッシュログの取得
libimobiledevice の idevicecrashreport を使い、接続中の 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)にもあります。
検証
dwarfdump --uuid <dsym>の UUID がクラッシュログの UUID と一致する- 少なくとも 1 つの .NET フレームが、未解決のアドレスではなく関数名に解決される
- 解決されたパスに、認識可能な .NET ランタイムの構造(例:
src/coreclr/、mono/metadata/、mono/mini/)が含まれている
停止条件
- ファイル形式が不正:ファイルが
.ipsJSON ではない場合(例:#NN pcのスタックフレームを含む Android tombstone、従来の.crashテキスト形式)、直ちに停止し、形式の不一致をユーザーに報告して、シンボル化を進めないでください。他のツールやワークフローを使ってシンボル化しようとしないでください。 - .NET フレームが見つからない:解析したフレームを報告して停止してください。
- すべてのフレームを解決できた:シンボル化したバックトレースと、簡潔なクラッシュ分析(障害が発生したスレッド、例外の種類、可能性の高い領域)を提示してください。ユーザーがさらに詳しい調査を求めた場合は、続行してください。
- dSYM がない/UUID が一致しない:シンボル化されていないフレームと UUID、アドレスを報告してください。元のビルド成果物を探すよう提案してください。
atosを利用できない:ユーザーが実行できるよう、手動で実行するatosコマンドを提示してください。Xcode をインストールしないでください。atosは Xcode Command Line Tools(xcode-select --install)に含まれています。
参考資料
- IPS 形式の詳細:追加の .ips 解析の詳細と macOS のシンボルパッケージの違いについては、references/ips-crash-format.md を参照してください。