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
diff options
context:
space:
mode:
authormonojenkins <jo.shields+jenkins@xamarin.com>2020-06-18 00:46:44 +0300
committerGitHub <noreply@github.com>2020-06-18 00:46:44 +0300
commit6ea4cbcee040956cceaa53058cdb7de6529d2db0 (patch)
treeb174ed3a08e81552b179e4a74ecb018badbb44f3
parentd45ff3af75b1fa9098004a73869edde06dfc4f2a (diff)
[2020-02] [merp] Add API methods for getting hashcode/reason of last crash (#19978)
* [merp] Add API methods for getting hashcode/reason of last crash * Add test * Review feedback and cleanup Co-authored-by: Alexis Christoforides <alexis@thenull.net>
-rw-r--r--mcs/class/corlib/Mono/Runtime.cs38
-rw-r--r--mono/tests/merp-crash-test.cs38
2 files changed, 73 insertions, 3 deletions
diff --git a/mcs/class/corlib/Mono/Runtime.cs b/mcs/class/corlib/Mono/Runtime.cs
index f59a7e93891..c85a3a3b1f5 100644
--- a/mcs/class/corlib/Mono/Runtime.cs
+++ b/mcs/class/corlib/Mono/Runtime.cs
@@ -27,6 +27,7 @@
//
using System;
+using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -255,6 +256,43 @@ namespace Mono {
}
}
+ static string get_breadcrumb_value (string file_prefix, string directory_str, bool clear)
+ {
+ var allfiles = Directory.GetFiles (directory_str, $"{file_prefix}_*" );
+ if (allfiles.Length == 0)
+ return string.Empty;
+
+ if (allfiles.Length > 1) {
+ // it's impossible to tell which breadcrumb is the last one (let's not trust filesystem timestamps)
+ // delete the multiple files so at least next crash can make sense
+ try {
+ Array.ForEach (allfiles, f => File.Delete (f) );
+ } catch (Exception) { }
+
+ return string.Empty;
+ }
+
+ if (clear)
+ File.Delete (allfiles [0]);
+
+ var filename = Path.GetFileName (allfiles [0]);
+ return filename.Substring (file_prefix.Length + 1);
+ }
+
+ static long CheckCrashReportHash (string directory_str, bool clear)
+ {
+ var value = get_breadcrumb_value ("crash_hash", directory_str, clear);
+ if (value == string.Empty)
+ return 0;
+ else
+ return Convert.ToInt64 (value, 16);
+ }
+
+ static string CheckCrashReportReason (string directory_str, bool clear)
+ {
+ return get_breadcrumb_value ("crash_reason", directory_str, clear);
+ }
+
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern void AnnotateMicrosoftTelemetry_internal (IntPtr key, IntPtr val);
diff --git a/mono/tests/merp-crash-test.cs b/mono/tests/merp-crash-test.cs
index a33010e59cf..d534a64fae5 100644
--- a/mono/tests/merp-crash-test.cs
+++ b/mono/tests/merp-crash-test.cs
@@ -65,6 +65,7 @@ class C
Crashers.Add(new Crasher ("MerpCrashSignalKill", MerpCrashSignalBus));
Crashers.Add(new Crasher ("MerpCrashSignalSegv", MerpCrashSignalSegv));
Crashers.Add(new Crasher ("MerpCrashSignalIll", MerpCrashSignalIll));
+ Crashers.Add(new Crasher ("MerpCrashTestBreadcrumbs", MerpCrashTestBreadcrumbs, validator: ValidateBreadcrumbs));
}
public static void
@@ -88,6 +89,22 @@ class C
throw new ValidationException (String.Format ("incorrect fail fast message (expected: {0}, got: {1})", failfastMsg, s));
}
+ public static void ValidateBreadcrumbs (object json)
+ {
+ var monoType = Type.GetType ("Mono.Runtime", false);
+ var m = monoType.GetMethod ("CheckCrashReportReason", BindingFlags.NonPublic | BindingFlags.Static);
+ var m_params = new object [] { "./", false };
+ string o = (string)m.Invoke(null, m_params);
+ if (o != "segv")
+ throw new Exception ("Crash report reason should be 'segv'");
+
+ m = monoType.GetMethod ("CheckCrashReportHash", BindingFlags.NonPublic | BindingFlags.Static);
+ long hash = (long)m.Invoke (null, m_params);
+
+ if (hash == 0)
+ throw new Exception ("Crash hash should not be zero");
+ }
+
[DllImport("libtest")]
public static extern void mono_test_MerpCrashSnprintf ();
@@ -222,6 +239,12 @@ class C
mono_test_MerpCrashUnhandledExceptionHook ();
}
+ public static void
+ MerpCrashTestBreadcrumbs ()
+ {
+ mono_test_MerpCrashSignalSegv ();
+ }
+
private static object jsonGetKey (object o, string key) => (o as Dictionary<string,object>)[key];
private static object jsonGetKeys (object o, params string[] keys) {
@@ -273,8 +296,6 @@ class C
public static void
TestValidate (string configDir, bool silent, Action<object> validator = null)
{
- DumpLogCheck (expected_level: "MerpInvoke"); // we are expecting merp invoke to fail
-
var xmlFilePath = String.Format("{0}CustomLogsMetadata.xml", configDir);
var paramsFilePath = String.Format("{0}MERP.uploadparams.txt", configDir);
var crashFilePath = String.Format("{0}lastcrashlog.txt", configDir);
@@ -319,7 +340,7 @@ class C
} catch (CrasherClass.ValidationException e) {
throw new Exception (String.Format ("Validation failed '{0}', json: {1}", e.Message, crashFile));
} catch (Exception e) {
- throw new Exception (String.Format ("Invalid json: {0}", crashFile));
+ throw new Exception (String.Format ("Invalid json ({0}:{1}): {2}", e.GetType(), e.Message, crashFile));
}
File.Delete (crashFilePath);
@@ -328,6 +349,8 @@ class C
Console.WriteLine ("Crash file {0} missing", crashFilePath);
}
+ DumpLogCheck (expected_level: "MerpInvoke"); // we are expecting merp invoke to fail
+
if (!xmlFileExists)
throw new Exception (String.Format ("Did not produce {0}", xmlFilePath));
@@ -368,6 +391,15 @@ class C
if (expected_level != levels [result])
throw new Exception (String.Format ("Crash level {0} does not match expected {1}", levels [result], expected_level));
+
+ // also clear hash and reason breadcrumbs
+ convert = monoType.GetMethod("CheckCrashReportHash", BindingFlags.NonPublic | BindingFlags.Static);
+ var hash_result = (long) convert.Invoke(null, new object[] { "./", true });
+ convert = monoType.GetMethod("CheckCrashReportReason", BindingFlags.NonPublic | BindingFlags.Static);
+ var reason_result = (string) convert.Invoke(null, new object[] { "./", true });
+
+ if (reason_result == string.Empty)
+ throw new Exception("Crash reason should not be an empty string");
}