From 9aab5273dd8f1a516c4f072b350487a50cc0bced Mon Sep 17 00:00:00 2001 From: Alexander Kyte Date: Thu, 18 Oct 2018 20:39:03 -0400 Subject: [PATCH] Add crash reporting debugger event (#10628) This should help get information on native crashes that happen in hard-to-debug environments. To quote https://github.com/mono/mono/issues/10157 : When a mono runtime is attached to a managed debugger and the debugged runtime is induced to cause a crash, the state of that crash is not communicated to the managed debugger. This, combined with the difficulty in having the debugged runtime both attached to the managed debugger and lldb, makes this type of crash difficult to interactively debug. When the managed debugger is the only connection someone has with the runtime because it is embedded in a way that is resistant to unmanaged debugging (watchOS application on-device, for instance), this is an even more difficult problem. By adding an SDB protocol event that sends a type of "runtime death" and a blob of opaque json (version dependent, no protocol guarantees), people can report these crashes without having to assist a mono runtime engineer in observing a crash on device. In the case that spurious bugs in this manner are submitted, it will require less effort as well to spot stack frames that indicate misuse of mixed managed-unmanaged APIs (which offer the ability to drive a segfault or g_assert --- bcl.sln | 46 +++++++-------- external/api-snapshot | 2 +- .../Mono.Debugger.Soft/Mono.Debugger.Soft.csproj | 3 +- .../Mono.Debugger.Soft.dll.sources | 1 + .../Mono.Debugger.Soft/Connection.cs | 40 ++++++++++--- .../Mono.Debugger.Soft/CrashEvent.cs | 25 +++++++++ .../Mono.Debugger.Soft/EventType.cs | 2 + .../Mono.Debugger.Soft/VMDisconnectedException.cs | 10 ++++ .../Mono.Debugger.Soft/VirtualMachine.cs | 3 + mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs | 9 +++ mcs/class/Mono.Debugger.Soft/Test/dtest.cs | 33 +++++++++++ mono/mini/debugger-agent-stubs.c | 6 ++ mono/mini/debugger-agent.c | 65 +++++++++++++++++++++- mono/mini/debugger-agent.h | 1 + mono/mini/debugger-engine.h | 3 +- mono/mini/mini-posix.c | 12 +++- 16 files changed, 224 insertions(+), 37 deletions(-) create mode 100644 mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/CrashEvent.cs diff --git a/bcl.sln b/bcl.sln index c09e7445c88..2ac8f3f986a 100644 --- a/bcl.sln +++ b/bcl.sln @@ -188,7 +188,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Mdb", "mcs/class EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.CSharp", "mcs/class/Mono.CSharp/Mono.CSharp.csproj", "{817CE046-07E8-409D-84BF-A6EA4F2879DE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugger.Soft", "mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj", "{8787A3B7-8A19-4586-8DCF-6F5914FD48D5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugger.Soft", "mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj", "{767CAD15-F8B5-4EAC-8B3D-4EF75F768015}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.C5", "mcs/class/Mono.C5/Mono.C5.csproj", "{A9F5A575-3725-4691-A7A6-0ABDEA3994CE}" EndProject @@ -3368,28 +3368,28 @@ Global {817CE046-07E8-409D-84BF-A6EA4F2879DE}.Release|winaot.ActiveCfg = Release|net_4_x {817CE046-07E8-409D-84BF-A6EA4F2879DE}.Debug|xammac.ActiveCfg = Debug|net_4_x {817CE046-07E8-409D-84BF-A6EA4F2879DE}.Release|xammac.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|net_4_x.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|net_4_x.Build.0 = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|net_4_x.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|net_4_x.Build.0 = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|monodroid.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|monodroid.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|monotouch.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|monotouch.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|monotouch_tv.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|monotouch_tv.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|monotouch_watch.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|monotouch_watch.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|orbis.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|orbis.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|unreal.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|unreal.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|wasm.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|wasm.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|winaot.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|winaot.ActiveCfg = Release|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Debug|xammac.ActiveCfg = Debug|net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5}.Release|xammac.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|net_4_x.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|net_4_x.Build.0 = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|net_4_x.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|net_4_x.Build.0 = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|monodroid.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|monodroid.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|monotouch.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|monotouch.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|monotouch_tv.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|monotouch_tv.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|monotouch_watch.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|monotouch_watch.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|orbis.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|orbis.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|unreal.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|unreal.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|wasm.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|wasm.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|winaot.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|winaot.ActiveCfg = Release|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Debug|xammac.ActiveCfg = Debug|net_4_x + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015}.Release|xammac.ActiveCfg = Release|net_4_x {A9F5A575-3725-4691-A7A6-0ABDEA3994CE}.Debug|net_4_x.ActiveCfg = Debug|net_4_x {A9F5A575-3725-4691-A7A6-0ABDEA3994CE}.Debug|net_4_x.Build.0 = Debug|net_4_x {A9F5A575-3725-4691-A7A6-0ABDEA3994CE}.Release|net_4_x.ActiveCfg = Release|net_4_x diff --git a/external/api-snapshot b/external/api-snapshot index 1e1d58fb726..95462f9c5fc 160000 --- a/external/api-snapshot +++ b/external/api-snapshot @@ -1 +1 @@ -Subproject commit 1e1d58fb72622559cc73f7693bdf1856aa4247c0 +Subproject commit 95462f9c5fc78a57bb5598ffca6cc82b03e67cb3 diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj index b73e91c40a2..af6eba5272a 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj @@ -4,7 +4,7 @@ Debug net_4_x - {8787A3B7-8A19-4586-8DCF-6F5914FD48D5} + {767CAD15-F8B5-4EAC-8B3D-4EF75F768015} Library 1699 latest @@ -62,6 +62,7 @@ + diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.dll.sources b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.dll.sources index 3ea9e744843..65ebbf5e7c0 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.dll.sources +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft.dll.sources @@ -74,4 +74,5 @@ Mono.Debugger.Soft/ITargetProcess.cs Mono.Debugger.Soft/AbsentInformationException.cs Mono.Debugger.Soft/UserBreakEvent.cs Mono.Debugger.Soft/UserLogEvent.cs +Mono.Debugger.Soft/CrashEvent.cs Mono.Debugger.Soft/ILInterpreter.cs diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs index 99db87ed34d..1553096b5f8 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs @@ -367,6 +367,14 @@ namespace Mono.Debugger.Soft get; set; } + public string Dump { + get; set; + } + + public ulong Hash { + get; set; + } + public EventInfo (EventType type, int req_id) { EventType = type; ReqId = req_id; @@ -420,7 +428,7 @@ namespace Mono.Debugger.Soft * with newer runtimes, and vice versa. */ internal const int MAJOR_VERSION = 2; - internal const int MINOR_VERSION = 48; + internal const int MINOR_VERSION = 49; enum WPSuspendPolicy { NONE = 0, @@ -463,7 +471,8 @@ namespace Mono.Debugger.Soft EXCEPTION = 13, KEEPALIVE = 14, USER_BREAK = 15, - USER_LOG = 16 + USER_LOG = 16, + CRASH = 17 } enum ModifierKind { @@ -1272,6 +1281,7 @@ namespace Mono.Debugger.Soft } bool disconnected; + VMCrashException crashed; internal ManualResetEvent DisconnectedEvent = new ManualResetEvent (false); @@ -1279,10 +1289,14 @@ namespace Mono.Debugger.Soft while (!closed) { try { bool res = ReceivePacket (); - if (!res) + if (!res) { break; + } } catch (ThreadAbortException) { break; + } catch (VMCrashException ex) { + crashed = ex; + break; } catch (Exception ex) { if (!closed) { Console.WriteLine (ex); @@ -1300,6 +1314,15 @@ namespace Mono.Debugger.Soft EventHandler.VMDisconnect (0, 0, null); } + void disconnected_check () { + if (!disconnected) + return; + else if (crashed != null) + throw crashed; + else + throw new VMDisconnectedException (); + } + bool ReceivePacket () { byte[] packet = ReadPacket (); @@ -1354,6 +1377,11 @@ namespace Mono.Debugger.Soft exit_code = r.ReadInt (); //EventHandler.VMDeath (req_id, 0, null); events [i] = new EventInfo (etype, req_id) { ExitCode = exit_code }; + } else if (kind == EventKind.CRASH) { + ulong hash = (ulong) r.ReadLong (); + string dump = r.ReadString (); + + events [i] = new EventInfo (etype, req_id) { Dump = dump, Hash = hash}; } else if (kind == EventKind.THREAD_START) { events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = thread_id }; //EventHandler.ThreadStart (req_id, thread_id, thread_id); @@ -1571,8 +1599,7 @@ namespace Mono.Debugger.Soft int id = IdGenerator; Stopwatch watch = null; - if (disconnected) - throw new VMDisconnectedException (); + disconnected_check (); if (EnableConnectionLogging) watch = Stopwatch.StartNew (); @@ -1606,8 +1633,7 @@ namespace Mono.Debugger.Soft return r; } } else { - if (disconnected) - throw new VMDisconnectedException (); + disconnected_check (); Monitor.Wait (reply_packets_monitor); } } diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/CrashEvent.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/CrashEvent.cs new file mode 100644 index 00000000000..35daf5d396c --- /dev/null +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/CrashEvent.cs @@ -0,0 +1,25 @@ +namespace Mono.Debugger.Soft +{ + public class CrashEvent : Event { + + ulong hash; + string dump; + + internal CrashEvent (VirtualMachine vm, int req_id, long thread_id, string dump, ulong hash) : base (EventType.Crash, vm, req_id, thread_id) { + this.dump = dump; + this.hash = hash; + } + + public ulong Hash { + get { + return hash; + } + } + + public string Dump { + get { + return dump; + } + } + } +} diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/EventType.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/EventType.cs index 802a4ad7d0e..9fd82bd1aac 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/EventType.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/EventType.cs @@ -26,6 +26,8 @@ namespace Mono.Debugger.Soft // System.Diagnostics.Debugger.Log () // UserLog = 16, + // Fatal error handling + Crash = 17, // Not part of the wire protocol VMDisconnect = 99 } diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectedException.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectedException.cs index d26b1be202f..6c3425e4fa5 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectedException.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectedException.cs @@ -7,4 +7,14 @@ namespace Mono.Debugger.Soft public VMDisconnectedException () : base () { } } + + public class VMCrashException : VMDisconnectedException { + public readonly string Dump; + public readonly ulong Hash; + + public VMCrashException (string dump, ulong hash) : base () { + this.Dump = dump; + this.Hash = hash; + } + } } diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs index c72c17a443c..aff5d94d9a1 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs @@ -808,6 +808,9 @@ namespace Mono.Debugger.Soft case EventType.UserLog: l.Add (new UserLogEvent (vm, req_id, thread_id, ei.Level, ei.Category, ei.Message)); break; + case EventType.Crash: + l.Add (new CrashEvent (vm, req_id, thread_id, ei.Dump, ei.Hash)); + break; } } diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs index 98cf550d047..c617107cafe 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs @@ -319,6 +319,10 @@ public class Tests : TestsBase, ITest2 unhandled_exception_endinvoke (); return 0; } + if (args.Length >0 && args [0] == "crash-vm") { + crash (); + return 0; + } if (args.Length >0 && args [0] == "unhandled-exception-user") { unhandled_exception_user (); return 0; @@ -1331,6 +1335,11 @@ public class Tests : TestsBase, ITest2 } [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static void crash () { + unsafe { Console.WriteLine("{0}", *(int*) -1); } + } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] public static void unhandled_exception_user () { System.Threading.Tasks.Task.Factory.StartNew (() => { Throw (); diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs index b5a544a6f7e..d6c76b435e9 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs @@ -2455,6 +2455,39 @@ public class DebuggerTests } [Test] + [Category("NotOnWindows")] + public void Crash () { + bool success = false; + + try { + vm.Detach (); + Start (new string [] { dtest_app_path, "crash-vm" }); + Event e = run_until ("crash"); + while (!success) { + vm.Resume (); + e = GetNextEvent (); + var crash = e as CrashEvent; + if (crash == null) + continue; + + success = true; + Assert.AreNotEqual (0, crash.Dump.Length); + + break; + } + } finally { + try { + vm.Detach (); + } finally { + vm = null; + } + } + + if (!success) + Assert.Fail ("Didn't get crash event"); + } + + [Test] public void Dispose () { run_until ("Main"); diff --git a/mono/mini/debugger-agent-stubs.c b/mono/mini/debugger-agent-stubs.c index 755a78d7ae6..43173ba4e99 100644 --- a/mono/mini/debugger-agent-stubs.c +++ b/mono/mini/debugger-agent-stubs.c @@ -91,6 +91,11 @@ stub_debugger_agent_breakpoint_from_context (MonoContext *ctx) g_assert_not_reached (); } +static void +stub_debugger_agent_send_crash (char *json_dump, MonoStackHash *hashes, int pause) +{ +} + void mono_debugger_agent_stub_init (void) { @@ -112,6 +117,7 @@ mono_debugger_agent_stub_init (void) cbs.user_break = stub_debugger_agent_user_break; cbs.debug_log = stub_debugger_agent_debug_log; cbs.debug_log_is_enabled = stub_debugger_agent_debug_log_is_enabled; + cbs.send_crash = stub_debugger_agent_send_crash; mini_install_dbg_callbacks (&cbs); } diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index 3cbbb1ca680..c379b5388fd 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -273,7 +273,7 @@ typedef struct { #define HEADER_LENGTH 11 #define MAJOR_VERSION 2 -#define MINOR_VERSION 48 +#define MINOR_VERSION 49 typedef enum { CMD_SET_VM = 1, @@ -500,6 +500,9 @@ typedef struct { char *category, *message; /* For EVENT_KIND_TYPE_LOAD */ MonoClass *klass; + /* For EVENT_KIND_CRASH */ + char *dump; + MonoStackHash *hashes; } EventInfo; typedef struct { @@ -3627,6 +3630,7 @@ event_to_string (EventKind event) case EVENT_KIND_KEEPALIVE: return "KEEPALIVE"; case EVENT_KIND_USER_BREAK: return "USER_BREAK"; case EVENT_KIND_USER_LOG: return "USER_LOG"; + case EVENT_KIND_CRASH: return "CRASH"; default: g_assert_not_reached (); return ""; @@ -3764,6 +3768,12 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx if (CHECK_PROTOCOL_VERSION (2, 27)) buffer_add_int (&buf, mono_environment_exitcode_get ()); break; + case EVENT_KIND_CRASH: { + EventInfo *ei = (EventInfo *)arg; + buffer_add_long (&buf, ei->hashes->offset_free_hash); + buffer_add_string (&buf, ei->dump); + break; + } case EVENT_KIND_EXCEPTION: { EventInfo *ei = (EventInfo *)arg; buffer_add_objid (&buf, ei->exc); @@ -4848,6 +4858,58 @@ ss_clear_for_assembly (SingleStepReq *req, MonoAssembly *assembly) } /* + * This takes a lot of locks and stuff. Do this at the end, after + * other things have dumped us, so that getting stuck here won't + * prevent seeing other crash information + */ +static void +mono_debugger_agent_send_crash (char *json_dump, MonoStackHash *hashes, int pause) +{ +#ifndef DISABLE_CRASH_REPORTING + int suspend_policy; + GSList *events; + EventInfo ei; + + if (!agent_config.enabled) + return; + + // Don't send the event if the client doesn't expect it + if (!CHECK_PROTOCOL_VERSION (2, 49)) + return; + + // It doesn't make sense to wait for lldb/gdb to finish if we're not + // actually enabled. Therefore we do the wait here. + sleep (pause); + + // Don't heap allocate when we can avoid it + EventRequest request; + memset (&request, 0, sizeof (request)); + request.event_kind = EVENT_KIND_CRASH; + + gpointer pdata [1]; + pdata [0] = &request; + GPtrArray array; + memset (&array, 0, sizeof (array)); + array.pdata = pdata; + array.len = 1; + + mono_loader_lock (); + events = create_event_list (EVENT_KIND_CRASH, &array, NULL, NULL, &suspend_policy); + mono_loader_unlock (); + + ei.dump = json_dump; + ei.hashes = hashes; + + g_assert (events != NULL); + + process_event (EVENT_KIND_CRASH, &ei, 0, NULL, events, suspend_policy); + + // Don't die before it is sent. + sleep (4); +#endif +} + +/* * Called from metadata by the icall for System.Diagnostics.Debugger:Log (). */ static void @@ -9685,6 +9747,7 @@ mono_debugger_agent_init (void) cbs.user_break = debugger_agent_user_break; cbs.debug_log = debugger_agent_debug_log; cbs.debug_log_is_enabled = debugger_agent_debug_log_is_enabled; + cbs.send_crash = mono_debugger_agent_send_crash; mini_install_dbg_callbacks (&cbs); } diff --git a/mono/mini/debugger-agent.h b/mono/mini/debugger-agent.h index f1d455c5d2b..1b2d8affd8a 100644 --- a/mono/mini/debugger-agent.h +++ b/mono/mini/debugger-agent.h @@ -28,6 +28,7 @@ struct _MonoDebuggerCallbacks { void (*user_break) (void); void (*debug_log) (int level, MonoStringHandle category, MonoStringHandle message); gboolean (*debug_log_is_enabled) (void); + void (*send_crash) (char *json_dump, MonoStackHash *hashes, int pause); }; typedef struct _DebuggerTlsData DebuggerTlsData; diff --git a/mono/mini/debugger-engine.h b/mono/mini/debugger-engine.h index 5b2434aad0a..4b9a8f44209 100644 --- a/mono/mini/debugger-engine.h +++ b/mono/mini/debugger-engine.h @@ -33,7 +33,8 @@ typedef enum { EVENT_KIND_EXCEPTION = 13, EVENT_KIND_KEEPALIVE = 14, EVENT_KIND_USER_BREAK = 15, - EVENT_KIND_USER_LOG = 16 + EVENT_KIND_USER_LOG = 16, + EVENT_KIND_CRASH = 17 } EventKind; typedef enum { diff --git a/mono/mini/mini-posix.c b/mono/mini/mini-posix.c index 132163d478d..44de03809a0 100644 --- a/mono/mini/mini-posix.c +++ b/mono/mini/mini-posix.c @@ -1001,10 +1001,10 @@ dump_native_stacktrace (const char *signal, void *ctx) pid_t pid; int status; pid_t crashed_pid = getpid (); + gchar *output = NULL; + MonoStackHash hashes; #ifndef DISABLE_CRASH_REPORTING - MonoStackHash hashes; - gchar *output = NULL; MonoContext mctx; if (ctx) { gboolean leave = FALSE; @@ -1084,12 +1084,18 @@ dump_native_stacktrace (const char *signal, void *ctx) if (pid == 0) { dup2 (STDERR_FILENO, STDOUT_FILENO); + mono_runtime_printf_err ("\nDebug info from gdb:\n"); mono_gdb_render_native_backtraces (crashed_pid); exit (1); } - mono_runtime_printf_err ("\nDebug info from gdb:\n"); waitpid (pid, &status, 0); + + // We've already done our gdb dump and our telemetry steps. Before exiting, + // see if we can notify any attached debugger instances. + // + // At this point we are accepting that the below step might end in a crash + mini_get_dbg_callbacks ()->send_crash (output, &hashes, 0 /* wait # seconds */); } #endif #else -- 2.11.4.GIT