mcpField
A
android-tombstone-symbolication

android-tombstone-symbolication

github.com/dotnet開発5.8k3.4k 回インストール1 日前に更新
リポジトリ

android-tombstone-symbolication について

.NET Android アプリのネイティブクラッシュのバックトレースを、関数名やソース位置に解決するスキルです。シンボルの取得手順と、解析・シンボリケーションを自動化する PowerShell スクリプトを備えています。

主な機能

  1. 01tombstone と logcat 出力の解析
  2. 02.NET ランタイムフレームと BuildId の特定
  3. 03ランタイムデバッグシンボルの取得
  4. 04llvm-symbolizer によるフレーム解決
  5. 05BuildId によるランタイムバージョン特定

活用シーン

  1. 01MAUI または Xamarin アプリのネイティブクラッシュ調査
  2. 02Mono または CoreCLR フレームのソース位置特定
  3. 03付属の PowerShell スクリプトによる tombstone 処理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dotnet/skills --skill android-tombstone-symbolication

インストール後、Claude Code で/android-tombstone-symbolicationを入力して読み込まれたか確認します。

同梱ファイルscripts/Symbolicate-Tombstone.ps1

詳細

Android Tombstone .NET シンボリケーション

ELF BuildId と Microsoft のシンボルサーバーを使用して、.NET Android アプリ(MAUI、Xamarin、Mono)のクラッシュ時に出力されるネイティブバックトレースのフレームを、関数名、ソースファイル、行番号に解決します。

入力: Tombstone ファイルまたは logcat のクラッシュ出力、llvm-symbolizer(Android NDK または LLVM 14 以降の任意のツールチェーンに含まれています)、シンボルのダウンロードに必要なインターネット接続。

使用しないケース: クラッシュがマネージド .NET 例外の場合(マネージドスタックトレースとともに logcat に表示されます)、クラッシュしたライブラリが .NET コンポーネントではない場合(例:libart.so)、または Tombstone が iOS のものである場合。


ワークフロー

ステップ 1:Tombstone のバックトレースを解析する

各バックトレースフレームの形式は次のとおりです。

#NN pc OFFSET  /path/to/library.so (optional_symbol+0xNN) (BuildId: HEXSTRING)

フレーム番号、PC オフセット(16 進数、すでにライブラリ相対)、ライブラリ名、BuildId(16 進数で 32~40 文字)を抽出します。

デフォルトでは、すべてのスレッドをシンボリケーションします(GC/ファイナライザーなどのバックグラウンドスレッドに、有用な .NET フレームが含まれていることがよくあります)。クラッシュしたスレッドのバックトレースが最初に記載され、追加のスレッドは --- --- --- マーカーの後に続きます。

形式に関する注意:

  • スクリプトは、backtrace: ヘッダーの有無にかかわらず #NN pc フレーム行を自動検出し、logcat のタイムスタンプ/タグのプレフィックスも自動的に削除します。
  • logcat で取得した Tombstone では、BuildId が省略されていることがよくあります。adb shell readelf -n、CI のビルド成果物、または .NET ランタイムの NuGet パッケージから取得してください。
  • GitHub の Issue に貼り付けられた内容では、#1 pc が Issue へのリンクに変換されることがあります。ファイルに保存する前に、org/repo#N pc を #N pc に置き換えてください。
  • スクリプトで形式を解析できない場合は、#NN pc OFFSET library.so (BuildId: HEX) の組を手動で抽出してください。
ステップ 2:.NET ランタイムライブラリを特定する

フレームを .NET ランタイムライブラリで絞り込みます。

ライブラリランタイム
libmonosgen-2.0.soMono(MAUI、Xamarin、インタープリター)
libcoreclr.soCoreCLR(JIT モード)
libSystem.*.so.NET BCL のネイティブコンポーネント(Native、Globalization.Native、IO.Compression.Native、Security.Cryptography.Native.OpenSsl、Net.Security.Native)

NativeAOT: libcoreclr.so と libmonosgen-2.0.so はありません。ランタイムはアプリのバイナリ(例:libMyApp.so)に静的にリンクされています。libSystem.*.so の BCL ライブラリは分離されたままなので、シンボルサーバーを通じてシンボリケーションできます。アプリのバイナリ自体には、アプリ独自のデバッグシンボルが必要です。

ユーザーから特に依頼がない限り、libc.so、libart.so、その他の Android システムライブラリはスキップします。

ステップ 3:デバッグシンボルをダウンロードする

.NET の一意な BuildId ごとに、デバッグシンボルをダウンロードします。

https://msdl.microsoft.com/download/symbols/_.debug/elf-buildid-sym-<BUILDID>/_.debug
curl -sL "https://msdl.microsoft.com/download/symbols/_.debug/elf-buildid-sym-1eb39fc72918c7c6c0c610b79eb3d3d47b2f81be/_.debug" \
  -o libmonosgen-2.0.so.debug

file libmonosgen-2.0.so.debug で確認します。ELF 64-bit ... with debug_info, not stripped と表示されるはずです。ダウンロード結果が 404 または HTML の場合、そのビルドのシンボルは公開されていません。ライブラリのベースアドレスを加算または減算しないでください。Tombstone のオフセットはすでにライブラリ相対です。

ステップ 4:各フレームをシンボリケーションする
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:6244

/__w/1/s/ プレフィックスは CI のワークスペースルートです。意味のあるパスは src/runtime/ から始まり、dotnet/dotnet VMR に対応します。

ステップ 5:シンボリケーションしたバックトレースを提示する

元のフレーム番号と、解決された関数名およびソース位置を組み合わせます。

#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 オフセットを含む元の行を保持します。

自動化スクリプト

scripts/Symbolicate-Tombstone.ps1 は、ワークフロー全体を自動化します。

pwsh scripts/Symbolicate-Tombstone.ps1 -TombstoneFile tombstone_01.txt -LlvmSymbolizer llvm-symbolizer

フラグ:-CrashingThreadOnly(クラッシュしたスレッドのみに制限)、-OutputFile path(ファイルに出力)、-ParseOnly(ダウンロードせず、ライブラリ/BuildId/URL を報告)、-SkipVersionLookup(ランタイムのバージョン識別をスキップ)。


llvm-symbolizer の検索

まず Android NDK を確認してください。$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/*/bin/llvm-symbolizer または $ANDROID_HOME/ndk/*/toolchains/llvm/prebuilt/*/bin/llvm-symbolizer にあります。また、macOS では brew install llvm、apt install llvm、または xcrun --find llvm-symbolizer でも利用できます。

見つからない場合は、手順 1~3 を完了し、ユーザーが実行するダウンロードコマンドと llvm-symbolizer コマンドを提示してください。LLVM のインストールに時間をかけないでください。


出力の理解

CI のソースパスには、次のプレフィックスが使われます。

パスのプレフィックス対応先
/__w/1/s/src/runtime/dotnet/dotnet VMR の src/runtime/
/__w/1/s/src/mono/VMR の src/mono/(古いビルド)
/__w/1/s/VMR のルート
ランタイムバージョンの特定

このスクリプトは、BuildId をローカルにインストールされたランタイムパックと照合し、正確な .NET ランタイムバージョンを特定します。検索先は SDK パック($DOTNET_ROOT/packs/)、NuGet キャッシュ(~/.nuget/packages/)、オンラインでのフォールバックとして NuGet.org です。見つかった場合は、.nuspec の <repository commit="..." /> 要素からバージョンとソースコミットを抽出します。無効にするには -SkipVersionLookup を指定してください。llvm-readelf が必要です(NDK から自動検出されます)。


検証

  1. file <debug-file> の結果に ELF ... with debug_info, not stripped と表示される
  2. 少なくとも 1 つの .NET フレームが関数名(?? 以外)に解決される
  3. 解決されたパスに、認識できる .NET ランタイムの構造(例:mono/metadata/、mono/mini/)が含まれる

停止条件

  • .NET フレームが見つからない:解析されたフレームを報告して停止します。
  • すべてのフレームが解決された:シンボリケーション済みのバックトレースを提示します。ソースをたどったり、ランタイムのビルドやデバッグを試みたりしないでください。
  • シンボルが利用できない(404):BuildId ごとに 1 回だけ試行し、その後停止します。シンボリケーションされていないフレームを BuildId とオフセットとともに報告してください。
  • llvm-symbolizer が利用できない:-ParseOnly を使用し、手動実行用のコマンドを提示してください。LLVM をインストールしないでください。

よくある落とし穴

  • BuildId がない:Logcat の tombstone には BuildId が含まれないことがよくあります。次の方法で取得してください:adb shell readelf -n /path/to/lib.so、CI のビルド成果物、またはランタイムの NuGet パッケージ(~/.dotnet/packs/Microsoft.NETCore.App.Runtime.Mono.android-arm64/<version>/)。BuildId が必ず含まれる、生の tombstone ファイル(adb shell cat /data/tombstones/tombstone_XX)を取得する方法を優先してください。
  • シンボルが見つからない(404):プレリリースビルドや内部ビルドでは、シンボルが公開されていないことがあります。ビルド成果物または NuGet ランタイムパックに、ストリップされていない .so/.so.dbg がないか確認してください。
  • NativeAOT:tombstone にランタイムの .so がありません。ランタイムはアプリのバイナリに含まれています。libSystem.*.so の BCL ライブラリは引き続きシンボルサーバーを利用できますが、アプリのバイナリには独自のデバッグシンボルが必要です。
  • llvm-symbolizer のバージョンが不適切:DWARF との互換性を高めるには、LLVM 14 以降を使用してください。
  • BuildId が複数ある:.NET ライブラリごとに異なる BuildId があるため、それぞれ個別にシンボルをダウンロードしてください。

コメント