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:
authorAlexander Kyte <alexmkyte@gmail.com>2018-10-23 18:24:26 +0300
committerAlexander Köplinger <alex.koeplinger@outlook.com>2018-10-23 18:24:26 +0300
commit109563930d6559e3ade2c8f652f21574ea43ad1d (patch)
tree083bdc5d74f542d081438fbd520f05050eb385aa
parent5de2976c1168f402567380e77536482d58ae68c9 (diff)
[crash] Add mono_crash uploader for Sentry (#10840)
* [crash] Report which thread was crashing * [crash] Added upload-to-sentry tool * [crash] Add sentry uploader step to telemetry
-rw-r--r--mcs/tools/Makefile2
-rw-r--r--mcs/tools/upload-to-sentry/Makefile31
-rw-r--r--mcs/tools/upload-to-sentry/UploadToSentry.cs423
-rw-r--r--mcs/tools/upload-to-sentry/upload-to-sentry.exe.sources156
-rw-r--r--mono/metadata/icall.c4
-rw-r--r--mono/metadata/threads.c6
-rw-r--r--mono/utils/mono-state.c11
-rw-r--r--mono/utils/mono-state.h6
-rwxr-xr-xscripts/ci/run-jenkins.sh2
-rwxr-xr-xscripts/ci/run-upload-sentry.sh15
10 files changed, 643 insertions, 13 deletions
diff --git a/mcs/tools/Makefile b/mcs/tools/Makefile
index 891d8c32c4c..3056f53a1d2 100644
--- a/mcs/tools/Makefile
+++ b/mcs/tools/Makefile
@@ -51,7 +51,7 @@ net_4_5_dirs := \
gacutil
build_SUBDIRS =
-build_PARALLEL_SUBDIRS := resgen gacutil security culevel commoncryptogenerator resx2sr linker cil-strip corcompare mono-api-diff mono-api-html
+build_PARALLEL_SUBDIRS := resgen gacutil security culevel upload-to-sentry commoncryptogenerator resx2sr linker cil-strip corcompare mono-api-diff mono-api-html
monodroid_tools_SUBDIRS =
monodroid_tools_PARALLEL_SUBDIRS = cil-strip linker-analyzer mkbundle mdoc mono-symbolicate
monodroid_SUBDIRS = nunit-lite
diff --git a/mcs/tools/upload-to-sentry/Makefile b/mcs/tools/upload-to-sentry/Makefile
new file mode 100644
index 00000000000..6605744cc29
--- /dev/null
+++ b/mcs/tools/upload-to-sentry/Makefile
@@ -0,0 +1,31 @@
+thisdir = tools/upload-to-sentry
+SUBDIRS =
+include ../../build/rules.make
+
+PROGRAM = upload-to-sentry.exe
+LIB_REFS = \
+ System \
+ System.Core \
+ System.Data \
+ System.Runtime.Serialization \
+ System.Xml \
+ System.Xml.Linq \
+ Mono.Posix \
+ System Mono.Cecil
+
+NO_INSTALL = yes
+
+upload-crashes:
+ MONO_PATH="$(topdir)/class/lib/$(BUILD_TOOLS_PROFILE)$(PLATFORM_PATH_SEPARATOR)$$MONO_PATH" $(RUNTIME) $(topdir)/class/lib/build-$(HOST_PLATFORM)/upload-to-sentry.exe
+
+# It can be run using system .net during boostrap
+TARGET_NET_REFERENCE = v4.6
+# Trick to make it work during boostrap where it has to run with system
+# assemblies not the ones in lib/basic folder
+PROGRAM_USE_INTERMEDIATE_FILE = 1
+
+ifdef MCS_MODE
+LIB_REFS += Mono.Cecil.Mdb
+endif
+
+include ../../build/executable.make
diff --git a/mcs/tools/upload-to-sentry/UploadToSentry.cs b/mcs/tools/upload-to-sentry/UploadToSentry.cs
new file mode 100644
index 00000000000..2a1309d0661
--- /dev/null
+++ b/mcs/tools/upload-to-sentry/UploadToSentry.cs
@@ -0,0 +1,423 @@
+/**
+ * \file UploadToSentry.cs
+ * Support for reading verbose unmanaged crash dumps
+ *
+ * Author:
+ * Alexander Kyte (alkyte@microsoft.com)
+ *
+ * (C) 2018 Microsoft, Inc.
+ *
+ */
+
+using System;
+
+using System.IO;
+using System.Linq;
+using System.Collections.Generic;
+using Mono.Collections.Generic;
+
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Newtonsoft.Json.Linq;
+
+using System.Reflection;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using System.Net;
+
+namespace UploadToSentry
+{
+ // Modeled after https://github.com/getsentry/raven-csharp/blob/develop/src/app/SharpRaven/Dsn.cs
+ class Dsn {
+ public readonly string PrivateKey;
+ public readonly string PublicKey;
+ public readonly string ProjectID;
+
+ private readonly string path;
+ private readonly int port;
+ private readonly string sentryUriString;
+ private readonly Uri uri;
+
+ public Dsn (string dsn) {
+ this.uri = new Uri(dsn);
+ this.PrivateKey = GetPrivateKey(this.uri);
+ this.PublicKey = GetPublicKey(this.uri) ?? throw new ArgumentException("A publicKey is required.", nameof(dsn));
+ this.port = this.uri.Port;
+ this.ProjectID = GetProjectID(this.uri);
+ this.path = GetPath(this.uri);
+ this.sentryUriString = String.Format("{0}://{1}:{2}{3}/api/{4}/store/", this.uri.Scheme, this.uri.DnsSafeHost, this.port, this.path, this.ProjectID);
+ }
+
+ private static string GetPath(Uri uri)
+ {
+ int lastSlash = uri.AbsolutePath.LastIndexOf("/", StringComparison.Ordinal);
+ return uri.AbsolutePath.Substring(0, lastSlash);
+ }
+
+ private static string GetProjectID(Uri uri)
+ {
+ int lastSlash = uri.AbsoluteUri.LastIndexOf("/", StringComparison.Ordinal);
+ return uri.AbsoluteUri.Substring(lastSlash + 1);
+ }
+
+ public Uri SentryUri {
+ get {
+ return new Uri (sentryUriString);
+ }
+ }
+
+ private static string GetPrivateKey(Uri uri)
+ {
+ var parts = uri.UserInfo.Split(':');
+ return parts.Length == 2 ? parts[1] : null;
+ }
+
+ private static string GetPublicKey(Uri uri)
+ {
+ var publicKey = uri.UserInfo.Split(':')[0];
+ return publicKey != string.Empty ? publicKey : null;
+ }
+ }
+
+ class CodeCollection
+ {
+ Dictionary<Tuple<string, uint>, Collection<SequencePoint>> Lookup;
+ Dictionary<Tuple<string, uint>, Tuple<string, string, string>> Types;
+
+ public void Add (string assembly, string klass, string function, string mvid, uint token, Collection<SequencePoint> seqs)
+ {
+ var key = new Tuple<string, uint>(mvid, token);
+ Lookup[key] = seqs;
+ Types[key] = new Tuple<string, string, string>(assembly, klass, function);
+ }
+
+ public CodeCollection(string [] assemblies)
+ {
+ Lookup = new Dictionary<Tuple<string, uint>, Collection<SequencePoint>>();
+ Types = new Dictionary<Tuple<string, uint>, Tuple<string, string, string>>();
+
+ foreach (string assembly in assemblies)
+ {
+ if (assembly.EndsWith(".dll") || assembly.EndsWith(".exe"))
+ {
+ // Console.WriteLine("Reading {0}", assembly);
+ var readerParameters = new ReaderParameters { ReadSymbols = true };
+ AssemblyDefinition myLibrary = null;
+ try
+ {
+ myLibrary = AssemblyDefinition.ReadAssembly(assembly, readerParameters);
+ string mvid = myLibrary.MainModule.Mvid.ToString().ToUpper();
+ Console.WriteLine("\t-- Success Parsing {0}: {1}", assembly, mvid);
+
+ foreach (var ty in myLibrary.MainModule.Types)
+ {
+ for (int i = 0; i < ty.Methods.Count; i++)
+ {
+ string klass = ty.FullName;
+ string function = ty.Methods[i].FullName;
+ uint token = Convert.ToUInt32(ty.Methods[i].MetadataToken.ToInt32());
+ this.Add(assembly, klass, function, mvid, token, ty.Methods[i].DebugInformation.SequencePoints);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("\t-- Error Parsing {0}: {1}", assembly, e.Message);
+ }
+ }
+ }
+ }
+
+ public JObject Find (string mvid, uint token, uint goal)
+ {
+ var method_idx = new Tuple<string, uint>(mvid, token);
+ if (!Lookup.ContainsKey(method_idx))
+ return null;
+
+ var seqs = Lookup[method_idx];
+
+ var accum = new JObject();
+ foreach (var seq in seqs)
+ {
+ if (goal != seq.Offset)
+ continue;
+
+ accum.Add (new JProperty("lineno", seq.StartLine));
+ accum.Add (new JProperty("filename", seq.Document.Url));
+ break;
+ }
+
+ var typ = Types[method_idx];
+ var assembly = typ.Item1;
+ var klass = typ.Item2;
+ accum.Add (new JProperty("module", String.Format("{0} {1}", assembly, klass)));
+ accum.Add (new JProperty("function", typ.Item3));
+
+ return accum;
+ }
+ }
+
+
+ class Uploader
+ {
+ CodeCollection codebase;
+
+ public JObject Format_0_0_2 (string fileName, JObject payload, string hash)
+ {
+ var event_id = new JProperty("event_id", Guid.NewGuid().ToString("n"));
+ var timestamp = new JProperty("timestamp", DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture));
+ var exc_objs = new List<JObject> ();
+ var thread_objs = new List<JObject> ();
+
+ var stackTraces = payload["threads"] as JArray;
+
+ var path = Path.GetDirectoryName (fileName); // Best differentiator in-tree for files is where they are run from
+
+ for (int i=0; i < stackTraces.Count; i++){
+ var thread_id = stackTraces[i]["native_thread_id"].ToString();
+
+ var unmanaged_frames = new List<JObject>();
+ var managed_frames = new List<JObject>();
+
+ var thread_name = stackTraces [i]["thread_name"].ToString ();
+ if (thread_name == null || thread_name.Length == 0)
+ thread_name = "Unnamed thread";
+
+ var payload_unmanaged_frames = stackTraces[i]["unmanaged_frames"] as JArray;
+ for (int fr=0; payload_unmanaged_frames != null && fr < payload_unmanaged_frames.Count; fr++)
+ {
+ var frame = payload_unmanaged_frames [fr] as JObject;
+ var native_address = frame["native_address"];
+ var unmanaged_name = frame["unmanaged_name"] != null ? frame["unmanaged_name"].ToString() : "";
+
+ var fn_filename = new JProperty("filename", "");
+ var function = new JProperty("function", unmanaged_name);
+ var module = new JProperty("module", "mono-sgen");
+ var vars = new JProperty("vars", new JObject(new JProperty ("native_address", native_address)));
+ var blob = new JObject(fn_filename, function, module, vars);
+
+ unmanaged_frames.Add (blob);
+ }
+
+ var payload_managed_frames = stackTraces[i]["managed_frames"] as JArray;
+ for (int fr = 0; payload_managed_frames != null && fr < payload_managed_frames.Count; fr++)
+ {
+ var frame = payload_managed_frames [fr] as JObject;
+ if (frame["is_managed"] != null && frame["is_managed"].ToString ().ToUpper () == "TRUE")
+ {
+ var guid_val = frame["guid"].ToString ();
+ var token_val = Convert.ToUInt32(frame["token"].ToString (), 16);
+ var offset_val = Convert.ToUInt32(frame["il_offset"].ToString (), 16);
+
+ var output_frame = codebase.Find (guid_val, token_val, offset_val);
+ if (output_frame == null)
+ continue;
+
+ var guid = new JProperty("guid", guid_val);
+ var token = new JProperty("token", token_val);
+ var il_offset = new JProperty("il_offset", offset_val);
+
+ output_frame.Add (new JProperty("vars", new JObject(guid, token, il_offset)));
+
+ managed_frames.Add(output_frame);
+ } else {
+ var native_address = frame["native_address"];
+ var unmanaged_name = frame["unmanaged_name"] != null ? frame["unmanaged_name"].ToString() : "";
+
+ var fn_filename = new JProperty("filename", "mono-sgen");
+ var function = new JProperty("function", unmanaged_name);
+ var module = new JProperty("module", "");
+ var vars = new JProperty("vars", frame);
+ var blob = new JObject(fn_filename, function, module, vars);
+
+ managed_frames.Add (blob);
+ }
+ }
+
+ if (unmanaged_frames.Count > 0) {
+ var unmanaged_st = new JObject(new JProperty("frames", new JArray(unmanaged_frames.ToArray ())));
+ var id = String.Format ("{0}_unmanaged", stackTraces[i]["native_thread_id"]);
+ var active = new JProperty ("active", "true");
+
+ if (stackTraces[i]["crashed"].ToString ().ToUpper () == "TRUE") {
+ var unmanaged_thread = new JObject (active, new JProperty ("crashed", "true"), new JProperty ("name", String.Format ("{0} unmanaged", thread_name)), new JProperty ("id", id));
+ var unmanaged_exc = new JObject(new JProperty("module", String.Format("{0}_managed_frames", thread_id)),
+ new JProperty("type", path),
+ new JProperty("value", ""),
+ new JProperty("stacktrace", unmanaged_st), new JProperty("thread_id", id));
+
+ thread_objs.Add(unmanaged_thread);
+ exc_objs.Add (unmanaged_exc);
+ } else {
+ var unmanaged_thread = new JObject (active, new JProperty ("name", String.Format ("{0} Unmanaged", thread_name)),
+ new JProperty ("id", id), new JProperty ("stacktrace", unmanaged_st));
+ thread_objs.Add(unmanaged_thread);
+ }
+ }
+
+ if (managed_frames.Count > 0) {
+ var managed_st = new JObject(new JProperty("frames", new JArray(managed_frames.ToArray())));
+ // If we are the crashing thread, set the exception object to the
+ // managed stacktrace and the thread object to the managed thread
+ //
+ // If we aren't, add the thread + st to
+ var id = String.Format ("{0}_managed", stackTraces[i]["native_thread_id"]);
+ var active = new JProperty ("active", "true");
+
+ if (unmanaged_frames.Count == 0 && stackTraces[i]["crashed"].ToString ().ToUpper () == "TRUE") {
+ var managed_thread = new JObject (active, new JProperty ("crashed", "true"), new JProperty ("name", String.Format ("{0} managed", thread_name)), new JProperty ("id", id));
+ var managed_exc = new JObject(new JProperty("module", String.Format("{0}_managed_frames", thread_id)),
+ new JProperty("type", path),
+ new JProperty("value", ""),
+ new JProperty("stacktrace", managed_st), new JProperty("thread_id", id));
+
+ thread_objs.Add(managed_thread);
+ exc_objs.Add (managed_exc);
+ } else {
+ var managed_thread = new JObject (active, new JProperty ("name", String.Format ("{0} managed", thread_name)),
+ new JProperty ("id", id), new JProperty ("stacktrace", managed_st));
+ thread_objs.Add(managed_thread);
+ }
+ }
+ }
+
+ var exception = new JProperty("exception", new JObject (new JProperty ("values", new JArray(exc_objs.ToArray ()))));
+ var threads = new JProperty("threads", new JObject (new JProperty ("values", new JArray(thread_objs.ToArray ()))));
+ // Bake in the whole blob
+ var embedded = new JProperty("extra", payload);
+ var fingerprint = new JProperty ("fingerprint", new JArray (new JValue (hash)));
+
+ var sentry_message = new JObject (timestamp, event_id, exception, embedded, threads, fingerprint);
+
+ return sentry_message;
+ }
+
+ public void SendMessage (JObject sentry_message, Dsn url)
+ {
+ // Console.WriteLine ("Sending {0}", sentry_message.ToString ());
+
+ var request = (HttpWebRequest) WebRequest.Create (url.SentryUri);
+ request.Method = "POST";
+ request.ContentType = "application/json";
+ request.UserAgent = "SharpRaven/2.4.0.0";
+
+ var sentryVersion = 7;
+ var time = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
+ var key = url.PrivateKey != null ? ", sentry_secret=" + url.PrivateKey : null;
+ var header = String.Format("Sentry sentry_version={0}" +
+ ", sentry_client={1}, sentry_timestamp={2}, sentry_key={3}{4}",
+ sentryVersion, request.UserAgent, time, url.PublicKey, key);
+ request.Headers ["X-Sentry-Auth"] = header;
+
+ byte[] byteArray = Encoding.UTF8.GetBytes(sentry_message.ToString ());
+ request.ContentLength = byteArray.Length;
+
+ Stream dataStream = request.GetRequestStream();
+ dataStream.Write(byteArray, 0, byteArray.Length);
+ dataStream.Close();
+
+ try {
+ WebResponse response = request.GetResponse ();
+ // Display the status.
+ // Console.WriteLine(((HttpWebResponse)response).StatusDescription);
+
+ StreamReader reader = new StreamReader(response.GetResponseStream());
+ // Read the content.
+ string responseFromServer = reader.ReadToEnd();
+ // Display the content.
+ Console.WriteLine("\t-- HTTP POST Success {0}", responseFromServer);
+ // Clean up the streams.
+ } catch (WebException ex) {
+ Console.WriteLine("\t-- HTTP POST Error {0}", ex.Response.Headers [""]);
+ }
+ }
+
+ public void Upload (string filePath, string os_tag, Dsn url)
+ {
+ if (!File.Exists(filePath))
+ throw new Exception(String.Format("Json file not found {0}", filePath));
+
+ var dump = File.ReadAllText(filePath);
+ //var message = new SentryMessage(dump);
+ // var blob = new SentryEvent(message);
+ var payload = JObject.Parse(dump);
+
+ // Try to extract a test name
+ var fileName = Path.GetFileName (filePath);
+ var extract = Regex.Match(fileName, @"mono_crash\.([A-Za-z0-9]+)\.(\d)\.json");
+ if (!extract.Success)
+ throw new Exception ("File name does not match correct format");
+
+ var groups = extract.Groups;
+ var hash = groups[1].Value;
+ // var increment = groups[2].Value;
+
+ var version_string = payload["protocol_version"].ToString();
+ JObject sentry_message = null;
+ if (version_string == "0.0.2")
+ sentry_message = Format_0_0_2 (filePath, payload, hash);
+ else
+ throw new Exception ("Crash reporting version mismatch");
+
+ // sent to url via post?
+ // Console.WriteLine (sentry_message);
+
+ SendMessage (sentry_message, url);
+ }
+
+ public Uploader (CodeCollection assemblies)
+ {
+ this.codebase = assemblies;
+ }
+
+ static bool IsAssembly (string fileName) {
+ var extension = Path.GetExtension(fileName).ToUpper ();
+ return (extension == ".EXE" || extension == ".DLL");
+ }
+
+ static IEnumerable<string> GetAssemblies (string fileRoot) {
+ return Directory.GetFiles (fileRoot, "*.*", SearchOption.AllDirectories).Where(path => IsAssembly (path));
+ }
+
+ static IEnumerable<string> GetFiles (string fileRoot) {
+ var file_regex = @".*mono_crash.*json";
+ return Directory.GetFiles (fileRoot, "*.*", SearchOption.AllDirectories).Where (path =>
+ Regex.Match(Path.GetFileName(path), file_regex).Success);
+ }
+
+ public static void Main (string[] args)
+ {
+ var url = System.Environment.GetEnvironmentVariable ("MONO_SENTRY_URL");
+ if (url == null) {
+ Console.WriteLine ("MONO_SENTRY_URL missing");
+ return;
+ }
+
+ var fileRoot = System.Environment.GetEnvironmentVariable ("MONO_SENTRY_ROOT");
+ if (fileRoot == null) {
+ Console.WriteLine ("MONO_SENTRY_ROOT missing");
+ return;
+ }
+
+ var os_tag = System.Environment.GetEnvironmentVariable ("MONO_SENTRY_OS");
+ if (os_tag == null) {
+ Console.WriteLine ("MONO_SENTRY_OS missing");
+ return;
+ }
+
+ var dsn = new Dsn(url);
+
+ // Find all of the assemblies in tree that could have made the crash dump
+ var assemblies = GetAssemblies (fileRoot);
+ var codebase = new CodeCollection (assemblies.ToArray ());
+
+ var files = GetFiles (fileRoot);
+ foreach (var file in files) {
+ var state = new Uploader (codebase);
+ state.Upload (file, os_tag, dsn);
+ }
+ }
+ }
+}
diff --git a/mcs/tools/upload-to-sentry/upload-to-sentry.exe.sources b/mcs/tools/upload-to-sentry/upload-to-sentry.exe.sources
new file mode 100644
index 00000000000..e069eacc6f3
--- /dev/null
+++ b/mcs/tools/upload-to-sentry/upload-to-sentry.exe.sources
@@ -0,0 +1,156 @@
+UploadToSentry.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Bson/BsonBinaryType.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Bson/BsonReader.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Bson/BsonToken.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Bson/BsonType.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Bson/BsonWriter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Bson/BsonObjectId.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/BinaryConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/DataSetConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/DataTableConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/DateTimeConverterBase.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/RegexConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/ConstructorHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/VersionConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/DateFormatHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/DateTimeZoneHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Formatting.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonConstructorAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonPosition.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JPath.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JRaw.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Required.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonDynamicContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonFormatterConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonISerializableContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonLinqContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/ErrorEventArgs.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/PreserveReferencesHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/IJsonLineInfo.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonArrayAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonContainerAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/DefaultValueHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonConverterAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonObjectAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonSerializerSettings.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonValidatingReader.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/IJEnumerable.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/MemberSerialization.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/ObjectCreationHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonTextReader.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonPropertyAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonIgnoreAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonTextWriter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonWriterException.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonReaderException.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonConverter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonConverterCollection.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonReader.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonConvert.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonSerializationException.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonSerializer.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/Extensions.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JConstructor.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JContainer.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JEnumerable.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JObject.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JArray.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JTokenReader.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JTokenWriter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JToken.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JProperty.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JTokenType.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JValue.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/Extensions.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaNodeCollection.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaResolver.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/UndefinedSchemaIdHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/ValidationEventArgs.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/ValidationEventHandler.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/DefaultSerializationBinder.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/ErrorContext.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/IContractResolver.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/IValueProvider.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonProperty.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/MissingMemberHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/NullValueHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/ReferenceLoopHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchema.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/IReferenceResolver.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Schema/JsonSchemaType.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonStringContract.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/LateBoundMetadataTypeAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/ReflectionValueProvider.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/OnErrorAttribute.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/Base64Encoder.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/DynamicWrapper.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/ObjectConstructor.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/ILGeneratorExtensions.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/MethodCall.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/StringReference.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/TypeNameHandling.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/CollectionWrapper.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/EnumUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/EnumValue.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/EnumValues.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonToken.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonWriter.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/StringBuffer.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/ListWrapper.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/MathUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/StringUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs
+../../../external/Newtonsoft.Json/Src/Newtonsoft.Json/WriteState.cs
diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c
index 904cc9efc6d..8d41869399b 100644
--- a/mono/metadata/icall.c
+++ b/mono/metadata/icall.c
@@ -5803,7 +5803,7 @@ ves_icall_Mono_Runtime_ExceptionToState (MonoExceptionHandle exc_handle, guint64
mono_json_writer_init (&writer);
mono_native_state_init (&writer);
gboolean first_thread_added = TRUE;
- mono_native_state_add_thread (&writer, &out, NULL, first_thread_added);
+ mono_native_state_add_thread (&writer, &out, NULL, first_thread_added, TRUE);
char *output = mono_native_state_free (&writer, FALSE);
result = mono_string_new_handle (mono_domain_get (), output, error);
g_free (output);
@@ -5875,7 +5875,7 @@ ves_icall_Mono_Runtime_DumpStateSingle (guint64 *portable_hash, guint64 *unporta
mono_json_writer_init (&writer);
mono_native_state_init (&writer);
gboolean first_thread_added = TRUE;
- mono_native_state_add_thread (&writer, &this_thread, NULL, first_thread_added);
+ mono_native_state_add_thread (&writer, &this_thread, NULL, first_thread_added, TRUE);
char *output = mono_native_state_free (&writer, FALSE);
result = mono_string_new_handle (mono_domain_get (), output, error);
g_free (output);
diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c
index 2e4ab8e3c46..9afb96778b8 100644
--- a/mono/metadata/threads.c
+++ b/mono/metadata/threads.c
@@ -6218,7 +6218,7 @@ summary_timedwait (SummarizerGlobalState *state, int timeout_seconds)
}
static void
-summarizer_state_term (SummarizerGlobalState *state, gchar **out, gchar *mem, size_t provided_size)
+summarizer_state_term (SummarizerGlobalState *state, gchar **out, gchar *mem, size_t provided_size, MonoThreadSummary *controlling)
{
// See the array writes
mono_memory_barrier ();
@@ -6246,7 +6246,7 @@ summarizer_state_term (SummarizerGlobalState *state, gchar **out, gchar *mem, si
// much more stable to do it all from the controlling thread.
mono_get_eh_callbacks ()->mono_summarize_managed_stack (thread);
- mono_summarize_native_state_add_thread (thread, thread->ctx);
+ mono_summarize_native_state_add_thread (thread, thread->ctx, thread == controlling);
// Set non-shared state to notify the waiting thread to clean up
// without having to keep our shared state alive
@@ -6313,7 +6313,7 @@ mono_threads_summarize_execute (MonoContext *ctx, gchar **out, MonoStackHash *ha
MOSTLY_ASYNC_SAFE_PRINTF("Finished thread summarizer pause from 0x%zx.\n", current);
// Dump and cleanup all the stack memory
- summarizer_state_term (&state, out, mem, provided_size);
+ summarizer_state_term (&state, out, mem, provided_size, &this_thread);
} else {
// Wait here, keeping our stack memory alive
// for the dumper
diff --git a/mono/utils/mono-state.c b/mono/utils/mono-state.c
index adb2440db4b..4515a8cd5a5 100644
--- a/mono/utils/mono-state.c
+++ b/mono/utils/mono-state.c
@@ -213,7 +213,7 @@ mono_native_state_add_frames (JsonWriter *writer, int num_frames, MonoFrameSumma
}
void
-mono_native_state_add_thread (JsonWriter *writer, MonoThreadSummary *thread, MonoContext *ctx, gboolean first_thread)
+mono_native_state_add_thread (JsonWriter *writer, MonoThreadSummary *thread, MonoContext *ctx, gboolean first_thread, gboolean crashing_thread)
{
assert_has_space ();
@@ -231,6 +231,10 @@ mono_native_state_add_thread (JsonWriter *writer, MonoThreadSummary *thread, Mon
assert_has_space ();
mono_json_writer_indent (writer);
+ mono_json_writer_object_key(writer, "crashed");
+ mono_json_writer_printf (writer, "%s,\n", crashing_thread ? "true" : "false");
+
+ mono_json_writer_indent (writer);
mono_json_writer_object_key(writer, "managed_thread_ptr");
mono_json_writer_printf (writer, "\"0x%x\",\n", (gpointer) thread->managed_thread_ptr);
@@ -615,11 +619,10 @@ mono_summarize_native_state_end (void)
}
void
-mono_summarize_native_state_add_thread (MonoThreadSummary *thread, MonoContext *ctx)
+mono_summarize_native_state_add_thread (MonoThreadSummary *thread, MonoContext *ctx, gboolean crashing_thread)
{
-
static gboolean not_first_thread = FALSE;
- mono_native_state_add_thread (&writer, thread, ctx, !not_first_thread);
+ mono_native_state_add_thread (&writer, thread, ctx, !not_first_thread, crashing_thread);
not_first_thread = TRUE;
}
diff --git a/mono/utils/mono-state.h b/mono/utils/mono-state.h
index d69dbf4ab3f..8c64ada6ac0 100644
--- a/mono/utils/mono-state.h
+++ b/mono/utils/mono-state.h
@@ -18,7 +18,7 @@
#include <mono/metadata/threads-types.h>
#include <mono/utils/json.h>
-#define MONO_NATIVE_STATE_PROTOCOL_VERSION "0.0.1"
+#define MONO_NATIVE_STATE_PROTOCOL_VERSION "0.0.2"
MONO_BEGIN_DECLS
@@ -33,7 +33,7 @@ char *
mono_summarize_native_state_end (void);
void
-mono_summarize_native_state_add_thread (MonoThreadSummary *thread, MonoContext *ctx);
+mono_summarize_native_state_add_thread (MonoThreadSummary *thread, MonoContext *ctx, gboolean crashing_thread);
/*
* These use memory from the caller
@@ -49,7 +49,7 @@ char *
mono_native_state_free (JsonWriter *writer, gboolean free_data);
void
-mono_native_state_add_thread (JsonWriter *writer, MonoThreadSummary *thread, MonoContext *ctx, gboolean first_thread);
+mono_native_state_add_thread (JsonWriter *writer, MonoThreadSummary *thread, MonoContext *ctx, gboolean first_thread, gboolean crashing_thread);
void
mono_crash_dump (const char *jsonFile, MonoStackHash *hashes);
diff --git a/scripts/ci/run-jenkins.sh b/scripts/ci/run-jenkins.sh
index a12c9820a45..22e0bf67b06 100755
--- a/scripts/ci/run-jenkins.sh
+++ b/scripts/ci/run-jenkins.sh
@@ -270,3 +270,5 @@ elif [[ ${CI_TAGS} == *'mac-sdk'* ]]; then ${MONO_REPO_ROOT}/sc
elif [[ ${CI_TAGS} == *'no-tests'* ]]; then exit 0;
else make check-ci;
fi
+
+${MONO_REPO_ROOT}/scripts/ci/run-upload-sentry.sh
diff --git a/scripts/ci/run-upload-sentry.sh b/scripts/ci/run-upload-sentry.sh
new file mode 100755
index 00000000000..2527b53a34d
--- /dev/null
+++ b/scripts/ci/run-upload-sentry.sh
@@ -0,0 +1,15 @@
+#!/bin/bash -e
+export TESTCMD=`dirname "${BASH_SOURCE[0]}"`/run-step.sh
+
+export MONO_SENTRY_ROOT=`dirname "${BASH_SOURCE[0]}/../../"`
+
+if [[ ${CI_TAGS} == *'win-'* ]];
+then
+ echo "Skipping telemetry phase due to arch"
+elif [[ -n "${MONO_SENTRY_URL}" ]]
+then
+ # Define MONO_SENTRY_URL and MONO_SENTRY_OS in environment
+ ${TESTCMD} --label=sentry-telemetry-upload --timeout=10m make -C mcs/tools/upload-to-sentry upload-crashes MONO_SENTRY_ROOT="$MONO_REPO_ROOT"
+else
+ echo "Skipping telemetry phase because URL missing"
+fi