Status: decisions locked (epic il2cpp_linenumbermaps). Implementation lands across
bugsee-cli, appserver, worker, and (last) cross/bugsee-unity.
Related: Unity SDK crash/symbols plan (unity_symbols_and_crashes); UPM
cross/bugsee-unity; worker crash/managed/unity.py.
IL2CPP turns C# → C++ → native code. Crashes surface as native addresses in
libil2cpp.so / UnityFramework, mangled Type_Method_mHASH names, and/or
managed-looking strings without reliable file/line in Release.
Unity emits build-time mapping files that are not shipped in the player. Bugsee already uploads dSYM / ELF / ProGuard / PDB / sourcemaps; this epic adds first-class support for IL2CPP line maps.
| Role | Maps generated IL2CPP C++ file/line → C# file/line. |
| Typical path | Il2CppOutputProject/Source/il2cppOutput/Symbols/LineNumberMappings.json |
| Sibling | il2cppFileRoot.txt — root prefix for paths in the mapping. |
| Schema | Nested JSON: cpp_path → { cs_path → { cpp_line: cs_line } } (Sentry symbolic-il2cpp semantics). Optional __debug-id__ sentinel is ignored by parsers. |
| Scope | One file per platform IL2CPP build (whole managed codegen). Not shared Android↔iOS. Not one file per plugin .so. |
| Must match binary | Wrong map identity must never be applied. |
Maps mangled C++ symbol names → C# method signatures
(Namespace.Type::Method(args)). Required for the string/mangled fallback path.
| Artifact | CLI | Notes |
|---|---|---|
iOS .dSYM |
--type dsym |
Archive-time upload |
| Android ELF / symbols.zip | --type elf |
Needs line-program / Breakpad line records for primary apply |
| ProGuard/R8 | --type proguard |
Separate from linemap |
Engine libs (libunity.so, etc.) are not covered by LineNumberMappings.
- Primary: native address → dSYM/ELF/Breakpad → C++ file + line →
LineNumberMappings.json→ C# file/line. - Fallback: mangled / managed string →
MethodMap.tsv(line map only when a C++ location exists). Existingunity.pystring parse remains last resort.
- Separate
SymbolFilewithformat: il2cpp-linemap— not packed inside ELF/dSYM zips. - Bundle ZIP:
LineNumberMappings.json+MethodMap.tsv+il2cppFileRoot.txtmanifest.json.
- Crash lookup starts from module UUID(s) on the frame.
- One linemap document may list multiple
images[].uuid(all Android ABI build-ids forlibil2cpp, or relevant iOS slice UUIDs). version/build/ platform = metadata only (not the apply key).- Mobile v1 modules: Android
libil2cpp.so; iOSUnityFramework.GameAssemblydeferred (desktop).
Not “like mapping vs breakpad” (those UUIDs diverge after processing). Requires:
- Dedup / overwrite scoped by
(uuid, format). - Crash symbol batch must return native symbols and
il2cpp-linemapfor the same UUID (multiplicity), not last-wins collapse.
- Worker must preserve full cpp paths for IL2CPP modules and normalize with
il2cppFileRoot.txtbefore LNM lookup (iOS basename-stripping is incompatible). - Primary path needs DWARF / Breakpad line records. SYMBOL_TABLE-only / PUBLIC-only → native names only; LNM skipped (observable in diagnostics).
| Event class | Required payload | Apply path | Dependency |
|---|---|---|---|
| Native fatal (iOS) | module UUID + PC | primary | dSYM with line info + linemap |
| Native fatal (Android) | module UUID + PC | primary | NDK re-enabled + ELF/Breakpad line info + linemap |
| Managed fatal (IL2CPP) | Prefer addresses; else mangled/managed strings | primary if addrs; else MethodMap | ExceptionPipeline / bridge |
| String-only / Phase A stacks | strings | fallback / partial | unity.py |
| Situation | Behavior |
|---|---|
| Map not found during auto-discovery | Warn + continue dSYM/ELF/ProGuard; skip linemap |
--no-il2cpp-mapping |
Skip discovery; no warn |
--il2cpp-mapping PATH but file missing |
Fail that upload |
| UUID(s) unresolved for the bundle | Fail il2cpp-linemap upload |
| Wrong map identity at apply time | Never apply; leave native symbolication intact |
- Bugsnag: CLI
unity-android/unity-ios; uploadsLineNumberMappings.jsonwith native symbols; fail unless--no-upload-il2cpp-mapping. - Sentry: Capture-time
il2cpp_native_stack_traceIPs + server apply viasymbolic-il2cpp; upload with debug files.CaptureException(e)required for Release Method-only file/line; Unity 6 MethodFileLineNumber is an alternate path. - Firebase: NDK / symbols.zip focus; managed lines lean on Unity stack settings.
- Backtrace: Prefer real
Exceptionobject; symbols.zip; WebGL no C# lines.
Bugsee matches Bugsnag for thin CLI orchestration and Sentry for the primary
address→map apply model (managed Mode B via Il2CppNativeStack + worker LNM).
Worker host: GitHub bugsee/bugsee-background-worker.
| Layer | Status |
|---|---|
bugsee-cli |
Shipped — --type il2cpp-linemap (1540fe7 on main); siblings auto-discovered; fixtures under tests/fixtures/il2cpp-linemap/ |
| Appserver | Shipped — format: il2cpp-linemap, UUID(s) required, format-scoped uniqueness, multi-format batch lookup (2ecf6c26 on master) |
| Worker | Shipped on GitHub main — PR #19 → 32230b9; apply in crash/il2cpp_apply.py; detect/parse under symbolfiles/il2cpp_linemap.py |
| Unity SDK | WIP — uncommitted Editor/BugseeIl2CppLinemapUpload.cs + BugseeIl2CppModuleIdentity.cs; ExceptionPipeline / NDK / iOS bridge still open |
Do not reuse mapping / sourcemap / BMF/BSF processors.
Backend epic complete. Remaining: Unity Editor collect + SDK crash capture so maps and address frames reach the worker in the field.
B0 Fixtures— done.B1a Worker offline spike— done.B2 Appserver format + format-aware dedup + multi-format lookup— done onmaster.B1b Worker production apply— merged to GitHubmain(#19).B3— done onbugsee-cli --type il2cpp-linemapmain.- B4 Unity Editor/CI collect — WIP uncommitted in
cross/bugsee-unity.
bugsee-cli debug-files upload PATH/TO/LineNumberMappings.json \
--type il2cpp-linemap \
--version … --build … \
[--uuid UUID…] # IL2CPP module UUID(s); repeatable / comma-separated
[--il2cpp-root PATH] # optional override for il2cppFileRoot.txt
Siblings (MethodMap.tsv, il2cppFileRoot.txt) are auto-discovered next to the
JSON when present. Optional later: unity-android / unity-ios multi-artifact
orchestrators (not MVP).
Crash report (Unity / IL2CPP)
→ native symbolicate (dSYM/ELF/Breakpad) where addresses exist
(preserve full cpp path for IL2CPP modules)
→ if format il2cpp-linemap present for module UUID:
→ stash pre-remap frames on thread/exception `original_frames`
(same pattern as ProGuard deobfuscate / managed mono+dart)
→ overwrite existing display fields with C# file / line / method
(`data.source`, `data.line`, `data.member*`, `trace-sym`)
→ MethodMap demangle when mangled names present
→ existing unity.py string parse as last resort
Do not invent parallel fields (csharp_*, il2cpp_cpp_*). Natives live under
original_frames; remapped values occupy the normal display fields.
- Native-address frames gain C# file/line when map + line info match.
- Mangled
Type_Method_mHASHdemangles when MethodMap present. - Wrong map identity is not applied.
- Missing map leaves native symbolication intact.
- Multi-ABI UUID on the same linemap document applies.
- Scripting Backend = IL2CPP
- Android: Create symbols.zip = Debugging (line info, not SYMBOL_TABLE-only)
- iOS: dSYM enabled for Release; Script Debugging off if dSYM must succeed
- Emit IL2CPP line mapping files (confirm Player Setting / IL2CPP args)
- Archive
LineNumberMappings.json,il2cppFileRoot.txt,MethodMap.tsv - Upload with IL2CPP module UUID(s); version/build as metadata
- Do not ship mapping folders in the player
- Android native primary apply requires Bugsee NDK enabled
- Epic plan: Cursor
il2cpp_linenumbermaps_epic - Unity symbols plan: Cursor
unity_symbols_and_crashes bugsee-clidebug-files uploadtypes;src/cli/debug_files.rs- Appserver
symbolFormats/formatBatch/(uuid, transform)Android create - Worker
crash/symbolicator.py,crash/helpers/android_ndk.py,crash/managed/unity.py - Sentry
symbolic-il2cppLineMapping - Bugsnag Unity stacktraces /
unity-android/unity-iosCLI