Browse Source

feat: Run csharp/il2cpp events through symbolicator (#35615)

Arpad Borsos 2 years ago
parent
commit
3bb7dc56dd

+ 5 - 2
src/sentry/lang/native/processing.py

@@ -36,7 +36,9 @@ APPLECRASHREPORT_ATTACHMENT_TYPE = "event.applecrashreport"
 
 
 def _merge_frame(new_frame, symbolicated, platform="native"):
-    if symbolicated.get("function"):
+    # il2cpp events which have the "csharp" platform have good (C#) names
+    # coming from the SDK, we do not want to override those with bad (mangled) C++ names.
+    if platform != "csharp" and symbolicated.get("function"):
         raw_func = trim(symbolicated["function"], 256)
         func = trim(trim_function_name(symbolicated["function"], platform), 256)
 
@@ -61,7 +63,8 @@ def _merge_frame(new_frame, symbolicated, platform="native"):
         new_frame["lineno"] = symbolicated["lineno"]
     if symbolicated.get("colno"):
         new_frame["colno"] = symbolicated["colno"]
-    if symbolicated.get("package"):
+    # similarly as with `function` above, we do want to retain the original "package".
+    if platform != "csharp" and symbolicated.get("package"):
         new_frame["package"] = symbolicated["package"]
     if symbolicated.get("trust"):
         new_frame["trust"] = symbolicated["trust"]

+ 3 - 1
src/sentry/lang/native/utils.py

@@ -12,7 +12,9 @@ logger = logging.getLogger(__name__)
 WINDOWS_PATH_RE = re.compile(r"^([a-z]:\\|\\\\)", re.IGNORECASE)
 
 # Event platforms that could contain native stacktraces
-NATIVE_PLATFORMS = ("cocoa", "native")
+# il2cpp events have the "csharp" platform, and we do need to run those
+# through symbolicator to correctly symbolicate il2cpp stack frames.
+NATIVE_PLATFORMS = ("cocoa", "native", "csharp")
 
 # Debug image types that can be handled by the symbolicator
 NATIVE_IMAGE_TYPES = (

+ 1 - 1
static/app/utils/displayReprocessEventAction.tsx

@@ -56,7 +56,7 @@ function getStackTracePlatforms(event: Event, exceptionEntry: EntryException) {
   ]);
 }
 
-// Checks whether an event indicates that it has an apple crash report.
+// Checks whether an event indicates that it is a native event.
 function isNativeEvent(event: Event, exceptionEntry: EntryException) {
   const {platform} = event;
 

+ 148 - 0
tests/sentry/lang/native/test_processing.py

@@ -176,3 +176,151 @@ def test_filter_frames():
     filtered_frames = get_frames_for_symbolication(frames, {"platform": "native"}, {})
 
     assert len(filtered_frames) == 0
+
+
+@pytest.mark.django_db
+@mock.patch("sentry.lang.native.processing.Symbolicator")
+def test_il2cpp_symbolication(mock_symbolicator, default_project):
+
+    data = {
+        "event_id": "c87700da71534177b92bd912f21a062f",
+        "timestamp": "2022-06-15T10:13:46.963575+00:00",
+        "platform": "csharp",
+        "project": default_project.id,
+        "exception": {
+            "values": [
+                {
+                    "type": "System.InvalidOperationException",
+                    "value": "Exception from a lady beetle \uD83D\uDC1E",
+                    "module": "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
+                    "thread_id": 1,
+                    "stacktrace": {
+                        "frames": [
+                            {
+                                "function": "Process",
+                                "module": "UnityEngine.EventSystems.StandaloneInputModule",
+                                "in_app": True,
+                                "package": "UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
+                                "instruction_addr": "0x0095013A",
+                            },
+                            {
+                                "function": "StackTraceExampleA",
+                                "module": "BugFarmButtons",
+                                "in_app": True,
+                                "package": "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
+                                "instruction_addr": "0x004820C8",
+                            },
+                            {
+                                "function": "StackTraceExampleB",
+                                "module": "BugFarmButtons",
+                                "in_app": True,
+                                "package": "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
+                                "instruction_addr": "0x004820B4",
+                            },
+                        ]
+                    },
+                    "mechanism": {"type": "Unity.LogException", "handled": False},
+                }
+            ]
+        },
+        "level": "error",
+        "debug_meta": {
+            "images": [
+                {
+                    "type": "macho",
+                    "image_addr": "0x00001000",
+                    "debug_id": "a9669c0c72b33d2c952bd9096f65bc4f",
+                    "code_file": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Builds/MacOS.app/Contents/Frameworks/GameAssembly.dylib",
+                }
+            ]
+        },
+    }
+
+    mock_symbolicator.return_value = mock_symbolicator
+    mock_symbolicator.process_payload.return_value = {
+        "status": "completed",
+        "stacktraces": [
+            {
+                "frames": [
+                    {
+                        "status": "symbolicated",
+                        "original_index": 0,
+                        "instruction_addr": "0x4820b4",
+                        "package": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Builds/MacOS.app/Contents/Frameworks/GameAssembly.dylib",
+                        "lang": "cpp",
+                        "symbol": "BugFarmButtons_StackTraceExampleB_m2A05E98E60BAA84184F3674F339A2E47B7E09318",
+                        "sym_addr": "0x482060",
+                        "function": "BugFarmButtons_StackTraceExampleB_m2A05E98E60BAA84184F3674F339A2E47B7E09318",
+                        "filename": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Assets/Scripts/BugFarmButtons.cs",
+                        "lineno": 51,
+                    },
+                    {
+                        "status": "symbolicated",
+                        "original_index": 1,
+                        "instruction_addr": "0x4820c7",
+                        "package": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Builds/MacOS.app/Contents/Frameworks/GameAssembly.dylib",
+                        "lang": "cpp",
+                        "symbol": "BugFarmButtons_StackTraceExampleA_m3A729DCA84695DB390C9B590F7973541BE497553",
+                        "sym_addr": "0x4820c0",
+                        "function": "BugFarmButtons_StackTraceExampleA_m3A729DCA84695DB390C9B590F7973541BE497553",
+                        "filename": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Assets/Scripts/BugFarmButtons.cs",
+                        "lineno": 55,
+                    },
+                    {
+                        "status": "symbolicated",
+                        "original_index": 2,
+                        "instruction_addr": "0x950139",
+                        "package": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Builds/MacOS.app/Contents/Frameworks/GameAssembly.dylib",
+                        "lang": "cpp",
+                        "symbol": "StandaloneInputModule_ProcessMouseEvent_mCE1BA96E47D9A4448614CB9DAF5A406754F655DD",
+                        "function": "StandaloneInputModule_ProcessMouseEvent_mCE1BA96E47D9A4448614CB9DAF5A406754F655DD",
+                        "filename": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/InputModules/StandaloneInputModule.cs",
+                        "lineno": 526,
+                    },
+                    {
+                        "status": "symbolicated",
+                        "original_index": 2,
+                        "instruction_addr": "0x950139",
+                        "package": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Builds/MacOS.app/Contents/Frameworks/GameAssembly.dylib",
+                        "lang": "cpp",
+                        "symbol": "StandaloneInputModule_Process_mBD949CC45BBCAB5A0FAF5E24F3BB4C3B22FF3E81",
+                        "sym_addr": "0x9500e0",
+                        "function": "StandaloneInputModule_Process_mBD949CC45BBCAB5A0FAF5E24F3BB4C3B22FF3E81",
+                        "filename": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/InputModules/StandaloneInputModule.cs",
+                        "lineno": 280,
+                    },
+                ]
+            }
+        ],
+        "modules": [
+            {
+                "debug_status": "found",
+                "arch": "x86_64",
+                "type": "macho",
+                "code_file": "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Builds/MacOS.app/Contents/Frameworks/GameAssembly.dylib",
+                "debug_id": "a9669c0c-72b3-3d2c-952b-d9096f65bc4f",
+                "image_addr": "0x1000",
+            }
+        ],
+    }
+
+    process_payload(data)
+
+    frame = get_path(data, "exception", "values", 0, "stacktrace", "frames", 3)
+
+    # For il2cpp frames, we want to retain the original `function` and `package`
+    # that are coming from the Unity/C# SDK. But we want to have the underlying
+    # C++ symbol, and the re-mapped files/lines.
+    assert frame["function"] == "StackTraceExampleB"
+    assert (
+        frame["package"] == "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
+    )
+    assert (
+        frame["symbol"]
+        == "BugFarmButtons_StackTraceExampleB_m2A05E98E60BAA84184F3674F339A2E47B7E09318"
+    )
+    assert (
+        frame["filename"]
+        == "/Users/swatinem/Coding/sentry-unity/samples/unity-of-bugs/Assets/Scripts/BugFarmButtons.cs"
+    )
+    assert frame["lineno"] == 51