diff options
author | Alexander Kyte <alexmkyte@gmail.com> | 2018-10-19 03:39:03 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2018-10-19 03:39:03 +0300 |
commit | 9aab5273dd8f1a516c4f072b350487a50cc0bced (patch) | |
tree | f538100ae4e9f7d06421595970be7f9a40cceb37 /mcs/class/Mono.Debugger.Soft | |
parent | 4844ab019dc4c04eb5b96dceca32a84a6256dff5 (diff) |
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
Diffstat (limited to 'mcs/class/Mono.Debugger.Soft')
9 files changed, 118 insertions, 8 deletions
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 @@ <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">net_4_x</Platform>
- <ProjectGuid>{8787A3B7-8A19-4586-8DCF-6F5914FD48D5}</ProjectGuid>
+ <ProjectGuid>{767CAD15-F8B5-4EAC-8B3D-4EF75F768015}</ProjectGuid>
<OutputType>Library</OutputType>
<NoWarn>1699</NoWarn>
<LangVersion>latest</LangVersion>
@@ -62,6 +62,7 @@ <Compile Include="Mono.Debugger.Soft\BreakpointEvent.cs" />
<Compile Include="Mono.Debugger.Soft\BreakpointEventRequest.cs" />
<Compile Include="Mono.Debugger.Soft\Connection.cs" />
+ <Compile Include="Mono.Debugger.Soft\CrashEvent.cs" />
<Compile Include="Mono.Debugger.Soft\CustomAttributeDataMirror.cs" />
<Compile Include="Mono.Debugger.Soft\CustomAttributeNamedArgumentMirror.cs" />
<Compile Include="Mono.Debugger.Soft\CustomAttributeTypedArgumentMirror.cs" />
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"); |