{
  "schema": "https://ai-atoms.com/schemas/skill-v1.json",
  "type": "skill",
  "id": "skill/android-tombstone-symbolication",
  "version": "1.0.0",
  "name": "android-tombstone-symbolication",
  "description": "Symbolicate the .NET runtime frames in an Android tombstone file. Extracts BuildIds and PC offsets from the native backtrace, downloads debug symbols from the Microsoft symbol server, and runs llvm-symbolizer to produce function names with source file and line numbers. USE FOR triaging a .NET MAUI or Mono Android app crash from a tombstone, resolving native backtrace frames in libmonosgen-2.0.so or libcoreclr.so to .NET runtime source code, or investigating SIGABRT, SIGSEGV, or other native signals originating from the .NET runtime on Android. DO NOT USE FOR pure Java/Kotlin crashes, managed .NET exceptions that are already captured in logcat, or iOS crash logs. INVOKES Symbolicate-Tombstone.ps1 script, llvm-symbolizer, Microsoft symbol server.",
  "system_prompt_fragment": "# Android Tombstone .NET Symbolication\n\nResolves native backtrace frames from .NET Android app crashes (MAUI, Xamarin, Mono) to function names, source files, and line numbers using ELF BuildIds and Microsoft's symbol server.\n\n**Inputs:** Tombstone file or logcat crash output, `llvm-symbolizer` (from Android NDK or any LLVM 14+ toolchain), internet access for symbol downloads.\n\n**Do not use when:** The crash is a managed .NET exception (visible in logcat with a managed stack trace), the crashing library is not a .NET component (e.g., `libart.so`), or the tombstone is from iOS.\n\n---\n\n## Workflow\n\n### Step 1: Parse the Tombstone Backtrace\n\nEach backtrace frame has this format:\n\n```\n#NN pc OFFSET  /path/to/library.so (optional_symbol+0xNN) (BuildId: HEXSTRING)\n```\n\nExtract: **frame number**, **PC offset** (hex, already library-relative), **library name**, and **BuildId** (32–40 hex chars).\n\nSymbolicate all threads by default (background threads like GC/finalizer often have useful .NET frames). The crashing thread's backtrace is listed first; additional threads appear after `--- --- ---` markers.\n\n**Format notes:**\n- The script auto-detects `#NN pc` frame lines with or without a `backtrace:` header, and strips logcat timestamp/tag prefixes automatically.\n- Logcat-captured tombstones often omit BuildIds. Recover via `adb shell readelf -n`, CI build artifacts, or the .NET runtime NuGet package.\n- GitHub issue pastes may mangle `#1 pc` into issue links — replace `org/repo#N pc` with `#N pc` before saving to a file.\n- If the script fails to parse a format, fall back to manual extraction of `#NN pc OFFSET library.so (BuildId: HEX)` tuples.\n\n### Step 2: Identify .NET Runtime Libraries\n\nFilter frames to .NET runtime libraries:\n\n| Library | Runtime |\n|---------|---------|\n| `libmonosgen-2.0.so` | Mono (MAUI, Xamarin, interpreter) |\n| `libcoreclr.so` | CoreCLR (JIT mode) |\n| `libSystem.*.so` | .NET BCL native components (`Native`, `Globalization.Native`, `IO.Compression.Native`, `Security.Cryptography.Native.OpenSsl`, `Net.Security.Native`) |\n\n**NativeAOT:** No `libcoreclr.so` or `libmonosgen-2.0.so` — the runtime is statically linked into the app binary (e.g., `libMyApp.so`). The `libSystem.*.so` BCL libraries remain separate and can be symbolicated via the symbol server. For the app binary itself, you need the app's own debug symbols.\n\nSkip `libc.so`, `libart.so`, and other Android system libraries unless the user specifically asks.\n\n### Step 3: Download Debug Symbols\n\nFor each unique .NET BuildId, download debug symbols:\n\n```\nhttps://msdl.microsoft.com/download/symbols/_.debug/elf-buildid-sym-<BUILDID>/_.debug\n```\n\n```bash\ncurl -sL \"https://msdl.microsoft.com/download/symbols/_.debug/elf-buildid-sym-1eb39fc72918c7c6c0c610b79eb3d3d47b2f81be/_.debug\" \\\n  -o libmonosgen-2.0.so.debug\n```\n\nVerify with `file libmonosgen-2.0.so.debug` — should show `ELF 64-bit ... with debug_info, not stripped`. If the download returns 404 or HTML, symbols are not published for that build. Do not add or subtract library base addresses — offsets in tombstones are already library-relative.\n\n### Step 4: Symbolicate Each Frame\n\n```bash\nllvm-symbolizer --obj=libmonosgen-2.0.so.debug -f -C 0x222098\n```\n\nOutput:\n```\nves_icall_System_Environment_FailFast\n/__w/1/s/src/runtime/src/mono/mono/metadata/icall.c:6244\n```\n\nThe `/__w/1/s/` prefix is the CI workspace root — the meaningful path starts at `src/runtime/`, mapping to [dotnet/dotnet](https://github.com/dotnet/dotnet) VMR.\n\n### Step 5: Present the Symbolicated Backtrace\n\nCombine original frame numbers with resolved function names and source locations:\n\n```\n#00  libc.so              abort+164\n#01  libmonosgen-2.0.so   ves_icall_System_Environment_FailFast        (mono/metadata/icall.c:6244)\n#02  libmonosgen-2.0.so   do_icall                                     (mono/mini/interp.c:2457)\n#03  libmonosgen-2.0.so   mono_interp_exec_method                      (mono/mini/interp.c)\n```\n\nFor unresolved frames (`??`), keep the original line with BuildId and PC offset.\n\n### Automation Script\n\n[scripts/Symbolicate-Tombstone.ps1](scripts/Symbolicate-Tombstone.ps1) automates the full workflow:\n\n```powershell\npwsh scripts/Symbolicate-Tombstone.ps1 -TombstoneFile tombstone_01.txt -LlvmSymbolizer llvm-symbolizer\n```\n\nFlags: `-CrashingThreadOnly` (limit to crashing thread), `-OutputFile path` (write to file), `-ParseOnly` (report libraries/BuildIds/URLs without downloading), `-SkipVersionLookup` (skip runtime version identification).\n\n---\n\n## Finding llvm-symbolizer\n\nCheck the **Android NDK** first: `$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/*/bin/llvm-symbolizer` or `$ANDROID_HOME/ndk/*/toolchains/llvm/prebuilt/*/bin/llvm-symbolizer`. Also available via `brew install llvm`, `apt install llvm`, or `xcrun --find llvm-symbolizer` on macOS.\n\nIf unavailable, complete steps 1–3 and present the download commands and `llvm-symbolizer` commands for the user to run. Do not spend time installing LLVM.\n\n---\n\n## Understanding the Output\n\nCI source paths use these prefixes:\n\n| Path prefix | Maps to |\n|---|---|\n| `/__w/1/s/src/runtime/` | `src/runtime/` in [dotnet/dotnet](https://github.com/dotnet/dotnet) VMR |\n| `/__w/1/s/src/mono/` | `src/mono/` in the VMR (older builds) |\n| `/__w/1/s/` | VMR root |\n\n### Runtime Version Identification\n\nThe script identifies the exact .NET runtime version by matching BuildIds against locally-installed runtime packs. It searches: SDK packs (`$DOTNET_ROOT/packs/`), NuGet cache (`~/.nuget/packages/`), and NuGet.org as an online fallback. When found, it extracts the version and source commit from the `.nuspec` `<repository commit=\"...\" />` element. Pass `-SkipVersionLookup` to disable. Requires `llvm-readelf` (auto-discovered from the NDK).\n\n---\n\n## Validation\n\n1. `file <debug-file>` shows `ELF ... with debug_info, not stripped`\n2. At least one .NET frame resolves to a function name (not `??`)\n3. Resolved paths contain recognizable .NET runtime structure (e.g., `mono/metadata/`, `mono/mini/`)\n\n## Stop Signals\n\n- **No .NET frames found**: Report parsed frames and stop.\n- **All frames resolved**: Present symbolicated backtrace. Do not trace into source or attempt to build/debug the runtime.\n- **Symbols not available (404)**: One attempt per BuildId, then stop. Report unsymbolicated frames with BuildIds and offsets.\n- **llvm-symbolizer not available**: Use `-ParseOnly`, present manual commands. Do not install LLVM.\n\n## Common Pitfalls\n\n- **Missing BuildIds**: Logcat tombstones often omit BuildIds. Recover via: `adb shell readelf -n /path/to/lib.so`, CI build artifacts, or the runtime NuGet package (`~/.dotnet/packs/Microsoft.NETCore.App.Runtime.Mono.android-arm64/<version>/`). Prefer pulling raw tombstone files (`adb shell cat /data/tombstones/tombstone_XX`) which always include BuildIds.\n- **Symbols not found (404)**: Pre-release/internal builds may not publish symbols. Check for local unstripped `.so`/`.so.dbg` in build artifacts or the NuGet runtime pack.\n- **NativeAOT**: No runtime `.so` in the tombstone — runtime is in the app binary. `libSystem.*.so` BCL libraries still work with the symbol server; the app binary needs its own debug symbols.\n- **Wrong llvm-symbolizer version**: Use LLVM 14+ for best DWARF compatibility.\n- **Multiple BuildIds**: Each .NET library has its own BuildId — download symbols for each separately.",
  "applicable_domains": [
    "code",
    "dotnet",
    "engineering"
  ],
  "invocation": [
    "/android-tombstone-symbolication"
  ],
  "tags": [
    "dotnet-diag",
    "dotnet",
    "csharp",
    "microsoft"
  ],
  "authored_by": "anthropics",
  "source_url": "https://github.com/dotnet/skills/blob/main/plugins/dotnet-diag/skills/android-tombstone-symbolication/SKILL.md",
  "lifecycle": "stable",
  "category": "dotnet",
  "provenance": {
    "source": "dotnet/skills",
    "source_url": "https://github.com/dotnet/skills/blob/main/plugins/dotnet-diag/skills/android-tombstone-symbolication/SKILL.md",
    "author": "Microsoft / .NET Foundation",
    "license": "MIT",
    "notes": "Imported by scripts/import-anthropic-skills.py."
  }
}