Quick answer: Make a development IL2CPP build with managed stack traces enabled, capture the device log over adb/Xcode, map the native crash back through the generated C++ symbols, and check the link.xml against what stripping removed.
An IL2CPP build that runs fine in the editor but crashes on a phone is a different beast: there is no managed runtime stepping in to catch your exception. You debug it by making the build talk (managed traces on) and by reading what the device itself logged.
How to debug it
1. Build with managed stack traces
Set the build to Development with Full stack traces and IL2CPP, so a managed exception prints a C# stack instead of a bare native address. This alone often names the line.
2. Capture the device log
Run adb logcat on Android or read the Xcode device console on iOS while reproducing. The fatal signal and the Unity exception both land here in real time.
3. Symbolicate the native frames
If it is a true native crash, resolve the addresses against the build's libil2cpp.so symbols or dSYM. Keep those symbol files archived per build or the addresses are unreadable.
4. Check stripping with link.xml
An ExecutionEngineException or missing method in release but not editor usually means managed stripping removed code reached via reflection. Preserve it in link.xml so the method survives the build.
Catching the ones you can't reproduce
The hardest version of this to fix is the one you can't reproduce — it only happens on a player's hardware, OS, driver, or save state, under conditions that simply aren't present on your machine. A report that says “it crashed” or “it froze” gives you nothing to act on, so the bug survives release after release while quietly costing you players.
Automatic error capture closes that gap. Each failure arrives with its full stack trace, the device and OS, the build number, and a breadcrumb trail of what the player did right before it broke, so even a failure you have never seen becomes a specific, reproducible issue. Fold identical failures into one signature ranked by how many players each hits, and your worklist sorts itself worst-first instead of arriving as a stream of vague complaints.
This is where a tool like Bugnet earns its place. Its SDK captures every mobile error automatically with the full stack trace plus device, OS, memory, build, and game-state context, folds duplicates into one grouped issue with an occurrence count, and ties each to the build it first appeared on — so you fix the problem that hurts the most players first and confirm it is gone when its signature disappears from the next release.
Reproduce it once with full context and the fix writes itself. The hunt is the expensive part.