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. 012 部構成の .ips クラッシュレポート解析
  2. 02.NET ランタイムフレームの識別
  3. 03UUID が一致する dSYM の検索
  4. 04atos によるフレーム解決
  5. 05PowerShell によるシンボリケーション自動化

活用シーン

  1. 01iOS 上の .NET MAUI クラッシュ追跡
  2. 02macOS 上の 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 シンボリケーション

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 + 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.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 を特定します。

  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 がクラッシュログの 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)にもあります。


検証

  1. dwarfdump --uuid <dsym> の UUID がクラッシュログの UUID と一致する
  2. 少なくとも 1 つの .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)に含まれています。

参考資料

  • IPS 形式の詳細:追加の .ips 解析の詳細と macOS のシンボルパッケージの違いについては、references/ips-crash-format.md を参照してください。

コメント