Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/mcs
diff options
context:
space:
mode:
authorAlexander Kyte <alexmkyte@gmail.com>2018-10-19 01:59:38 +0300
committerAlexander Köplinger <alex.koeplinger@outlook.com>2018-10-19 01:59:38 +0300
commit5ed4143b4f460d0a7a7d4ab745297bd9ab3c0cc9 (patch)
tree1e8c390b42e1725b0cfc07ccb27db8ae8d4f5914 /mcs
parentf0db92c2b6d3e6690cdc1069237f034570950e62 (diff)
[2018-06] Crash Reporter V2 (#11162)
* [runtime] Add icall to format crashes to disk in uniform way * [crash] More gentle error handling around stack walking * [crash] Make self-summarizier not need managed thread state * [crash] Remove reliance on sgen/gchandles * [crash] Refactor dumper mechanism * [crash] Make threads not die during thread dump * [crash] Add silent option to dumper * [crash] Print error when unable to dump thread * [crash] Add icalls to directly trigger telemetry-style walks * [crash] Increase maximum frame depth * [crash] Add support for concurrent global dump requests * [crash] Switch from CAS+Sleep to semaphore for dumper Locks and GC-Safe regions are both unsafe in a signal handler context. CAS primitives and the sleep syscall was used before. Semaphores appear to be safe, enabling the following cleanup. * [runtime] Make find_method use stack memory for dumper-facing entry point * [crash] Enable install_state_summarizer on all platforms * [crash] Dump managed stacks from controlling thread * [crash] Fix string races with DumpTotal icall * [crash] Fix space in crash file name * [crash] Fix lifetime and size checks on mono-state memory * [runtime] Make sequence point lookup lockless * [crash] Fix managed exception dumper icall format * [crash] Add tests for concurrent dumping * [crash] Print half-completed dump when space runs out * [crash] Bump static memory for crash string to 500k Note: - This memory isn't accessed until we're crashing - On any modern machine, unused static memory is lazily allocated. When we access it, the fault will trigger the MMU to map memory for us. - This is guaranteed to be reentrant and safe. mmap (the alternative) is surely fairly stable on many systems, but this is not guaranteed. The documentation pages for mmap specifically claim it as not safe in these async contexts. * [crash] Make whitelist lookup lockless * [crash] Split unmanaged ptrs into method ip + offset * [crash] Copy safer strings with crash privacy disabled * [crash] Fix BindingFlags undefined with mcs+linux x64 * [crash] Fix icall declarations for new style * [crash] Squashed support for RegisterReportingForNativeLib * [crash] Disable tests on linux / non-osx platforms
Diffstat (limited to 'mcs')
-rw-r--r--mcs/build/platforms/linux.make2
-rw-r--r--mcs/class/corlib/Mono/Runtime.cs55
-rw-r--r--mcs/class/corlib/Test/System/ExceptionTest.cs180
3 files changed, 235 insertions, 2 deletions
diff --git a/mcs/build/platforms/linux.make b/mcs/build/platforms/linux.make
index 02348318afe..b0a7ebb9af0 100644
--- a/mcs/build/platforms/linux.make
+++ b/mcs/build/platforms/linux.make
@@ -6,7 +6,7 @@
PLATFORM_MCS_FLAGS =
PLATFORM_RUNTIME = $(RUNTIME)
PLATFORM_CORLIB = mscorlib.dll
-PLATFORM_TEST_HARNESS_EXCLUDES =
+PLATFORM_TEST_HARNESS_EXCLUDES = NotOnLinux,
EXTERNAL_MCS = mcs
EXTERNAL_MBAS = mbas
diff --git a/mcs/class/corlib/Mono/Runtime.cs b/mcs/class/corlib/Mono/Runtime.cs
index 1addbac49ac..1c8cdc4a1ab 100644
--- a/mcs/class/corlib/Mono/Runtime.cs
+++ b/mcs/class/corlib/Mono/Runtime.cs
@@ -63,7 +63,7 @@ namespace Mono {
// Should not be removed intended for external use
// Safe to be called using reflection
- // Format is undefined only for use as a string for reporting
+ // Format is undefined only for use as a string for
[MethodImplAttribute (MethodImplOptions.InternalCall)]
#if MOBILE || XAMMAC_4_5
public
@@ -105,6 +105,21 @@ namespace Mono {
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern void SendMicrosoftTelemetry_internal (IntPtr payload, ulong portable_hash, ulong unportable_hash);
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ static extern void WriteStateToFile_internal (IntPtr payload, ulong portable_hash, ulong unportable_hash);
+
+ static void
+ WriteStateToFile (Exception exc)
+ {
+ ulong portable_hash;
+ ulong unportable_hash;
+ string payload_str = ExceptionToState_internal (exc, out portable_hash, out unportable_hash);
+ using (var payload_chars = RuntimeMarshal.MarshalString (payload_str))
+ {
+ WriteStateToFile_internal (payload_chars.Value, portable_hash, unportable_hash);
+ }
+ }
+
static void SendMicrosoftTelemetry (string payload_str, ulong portable_hash, ulong unportable_hash)
{
if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
@@ -150,5 +165,43 @@ namespace Mono {
}
#endif
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ static extern string DumpStateSingle_internal (out ulong portable_hash, out ulong unportable_hash);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ static extern string DumpStateTotal_internal (out ulong portable_hash, out ulong unportable_hash);
+
+ static Tuple<String, ulong, ulong>
+ DumpStateSingle ()
+ {
+ ulong portable_hash;
+ ulong unportable_hash;
+ string payload_str = DumpStateSingle_internal (out portable_hash, out unportable_hash);
+
+ return new Tuple<String, ulong, ulong> (payload_str, portable_hash, unportable_hash);
+ }
+
+ static Tuple<String, ulong, ulong>
+ DumpStateTotal ()
+ {
+ ulong portable_hash;
+ ulong unportable_hash;
+ string payload_str = DumpStateTotal_internal (out portable_hash, out unportable_hash);
+
+ return new Tuple<String, ulong, ulong> (payload_str, portable_hash, unportable_hash);
+ }
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ static extern void RegisterReportingForNativeLib_internal (IntPtr modulePathSuffix, IntPtr moduleName);
+
+ static void RegisterReportingForNativeLib (string modulePathSuffix_str, string moduleName_str)
+ {
+ using (var modulePathSuffix_chars = RuntimeMarshal.MarshalString (modulePathSuffix_str))
+ using (var moduleName_chars = RuntimeMarshal.MarshalString (moduleName_str))
+ {
+ RegisterReportingForNativeLib_internal (modulePathSuffix_chars.Value, moduleName_chars.Value);
+ }
+ }
+
}
}
diff --git a/mcs/class/corlib/Test/System/ExceptionTest.cs b/mcs/class/corlib/Test/System/ExceptionTest.cs
index 36f37e9c66b..68a550b51eb 100644
--- a/mcs/class/corlib/Test/System/ExceptionTest.cs
+++ b/mcs/class/corlib/Test/System/ExceptionTest.cs
@@ -15,6 +15,9 @@ using System.Runtime.Serialization;
using NUnit.Framework;
+using System.Threading.Tasks;
+using System.Reflection;
+
namespace MonoTests.System
{
[TestFixture]
@@ -400,6 +403,183 @@ namespace MonoTests.System
Assert.IsNull (a.InnerException.Source);
}
+#if !MOBILE
+ // Ensure that we can convert a stacktrace to a
+ // telemetry message
+ //
+ [Test]
+ [Category("NotOnWindows")]
+ [Category("NotOnLinux")]
+ public void StacktraceToState ()
+ {
+ try {
+ throw new Exception ("#0");
+ } catch (Exception exc) {
+ var monoType = Type.GetType ("Mono.Runtime", false);
+ var convert = monoType.GetMethod("ExceptionToState", BindingFlags.NonPublic | BindingFlags.Static);
+ object [] convert_params = new object[] {exc};
+ var output = (Tuple<String, ulong, ulong>) convert.Invoke(null, convert_params);
+
+ var dump = output.Item1;
+ var portable_hash = output.Item2;
+ var unportable_hash = output.Item3;
+
+ Assert.IsTrue (portable_hash != 0, "#1");
+ Assert.IsTrue (unportable_hash != 0, "#2");
+ Assert.IsTrue (dump.Length > 0, "#3");
+
+ // Console.WriteLine (dump);
+ // dump should look something like:
+ // {
+ // "protocol_version" : "0.0.1",
+ // "configuration" : {
+ // "version" : "5.19.0 (managed_telemetry_pipeline/d342c73e320 Wed Aug 15 14:40:40 EDT 2018)",
+ // "tlc" : "normal",
+ // "sigsgev" : "altstack",
+ // "notifications" : "kqueue",
+ // "architecture" : "amd64",
+ // "disabled_features" : "none",
+ // "smallconfig" : "disabled",
+ // "bigarrays" : "disabled",
+ // "softdebug" : "enabled",
+ // "interpreter" : "enabled",
+ // "llvm_support" : "disabled",
+ // "suspend" : "hybrid"
+ // },
+ // "memory" : {
+ // "Resident Size" : "40693760",
+ // "Virtual Size" : "4521312256",
+ // "minor_gc_time" : "216992",
+ // "major_gc_time" : "0",
+ // "minor_gc_count" : "6",
+ // "major_gc_count" : "0",
+ // "major_gc_time_concurrent" : "0"
+ // },
+ // "threads" : [
+ // {
+ // "is_managed" : false,
+ // "managed_thread_ptr" : "0x0",
+ // "thread_info_addr" : "0x0",
+ // "native_thread_id" : "0x0",
+ // "managed_frames" : [
+ // {
+ // "is_managed" : "true",
+ // "guid" : "43A03618-E657-44B0-B9FA-F63314A3C1B2",
+ // "token" : "0x60008da",
+ // "native_offset" : "0xb2",
+ // "il_offset" : "0x00000"
+ // }
+ // ]
+ // }
+ // ]
+ // }
+ }
+ }
+
+ void DumpSingle ()
+ {
+ var monoType = Type.GetType ("Mono.Runtime", false);
+ var convert = monoType.GetMethod("DumpStateSingle", BindingFlags.NonPublic | BindingFlags.Static);
+ var output = (Tuple<String, ulong, ulong>) convert.Invoke(null, Array.Empty<object> ());
+
+ var dump = output.Item1;
+ var portable_hash = output.Item2;
+ var unportable_hash = output.Item3;
+
+ Assert.IsTrue (portable_hash != 0, "#1");
+ Assert.IsTrue (unportable_hash != 0, "#2");
+ Assert.IsTrue (dump.Length > 0, "#3");
+ }
+
+ void DumpTotal ()
+ {
+ var monoType = Type.GetType ("Mono.Runtime", false);
+ var convert = monoType.GetMethod("DumpStateTotal", BindingFlags.NonPublic | BindingFlags.Static);
+ var output = (Tuple<String, ulong, ulong>) convert.Invoke(null, Array.Empty<object> ());
+
+ var dump = output.Item1;
+ var portable_hash = output.Item2;
+ var unportable_hash = output.Item3;
+
+ Assert.IsTrue (portable_hash != 0, "#1");
+ Assert.IsTrue (unportable_hash != 0, "#2");
+ Assert.IsTrue (dump.Length > 0, "#3");
+ }
+
+ [Test]
+ [Category("NotOnWindows")]
+ [Category("NotOnLinux")]
+ public void DumpICallSingleOnce ()
+ {
+ DumpSingle ();
+ }
+
+ [Test]
+ [Category("NotOnWindows")]
+ [Category("NotOnLinux")]
+ public void DumpICallSingleConcurrent ()
+ {
+ // checks that self-dumping works in parallel, locklessly
+ int amt = 20;
+ var tasks = new Task [amt];
+ for (int i=0; i < amt; i++)
+ tasks [i] = Task.Run(() => DumpSingle ());
+ Task.WaitAll (tasks);
+ }
+
+ [Test]
+ [Category("NotOnWindows")]
+ [Category("NotOnLinux")]
+ public void DumpICallSingleAsync ()
+ {
+ // checks that dumping works in an async context
+ var t = Task.Run(() => DumpSingle ());
+ t.Wait ();
+ }
+
+ [Test]
+ [Category("NotOnWindows")]
+ [Category("NotOnLinux")]
+ public void DumpICallTotalOnce ()
+ {
+ DumpTotal ();
+ }
+
+ [Test]
+ [Category("NotOnWindows")]
+ [Category("NotOnLinux")]
+ public void DumpICallTotalRepeated ()
+ {
+ // checks that the state doesn't get broken with repeated use
+ DumpTotal ();
+ DumpTotal ();
+ DumpTotal ();
+ }
+
+ [Test]
+ [Category("NotOnWindows")]
+ [Category("NotOnLinux")]
+ public void DumpICallTotalAsync ()
+ {
+ // checks that dumping works in an async context
+ var t = Task.Run(() => DumpTotal ());
+ t.Wait ();
+ }
+
+ [Test]
+ [Category("NotOnWindows")]
+ [Category("NotOnLinux")]
+ public void DumpICallTotalConcurrent ()
+ {
+ int amt = 3;
+ var tasks = new Task [amt];
+ for (int i=0; i < amt; i++)
+ tasks [i] = Task.Run(() => DumpTotal ());
+ Task.WaitAll (tasks);
+ }
+
+#endif
+
[Test]
public void StackTrace ()
{