From 11aa99476bb844d36dcbd7278423b1b96db39fb3 Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Wed, 2 Mar 2016 10:29:05 +0000 Subject: [PATCH] [mono-symbolicate] Created SeqPointInfo.cs SeqPointInfo is a c# implementation of the debug data decoding process that is done natively by the runtime. --- .../mono-symbolicate/LocationProvider.cs | 16 +- mcs/tools/mono-symbolicate/Makefile | 11 ++ mcs/tools/mono-symbolicate/SeqPointInfo.cs | 156 ++++++++++++++++++ .../mono-symbolicate.exe.sources | 1 + mono/metadata/seq-points-data.h | 2 +- 5 files changed, 176 insertions(+), 10 deletions(-) create mode 100644 mcs/tools/mono-symbolicate/SeqPointInfo.cs diff --git a/mcs/tools/mono-symbolicate/LocationProvider.cs b/mcs/tools/mono-symbolicate/LocationProvider.cs index ffe3c14206f..cad20ae8e16 100644 --- a/mcs/tools/mono-symbolicate/LocationProvider.cs +++ b/mcs/tools/mono-symbolicate/LocationProvider.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Collections.Generic; using Mono.Cecil; using Mono.CompilerServices.SymbolWriter; +using System.Runtime.InteropServices; namespace Symbolicate { @@ -57,19 +58,16 @@ namespace Symbolicate return true; } + [DllImport("mono-symbolicate-native.dll")] + private static extern bool mono_seq_point_data_get_il_offset (string path, uint method_token, uint method_index, uint native_offset, out uint il_offset); + static MethodInfo methodGetIL; private int GetILOffsetFromFile (int methodToken, uint methodIndex, int nativeOffset) { - if (string.IsNullOrEmpty (seqPointDataPath)) - return -1; - - if (methodGetIL == null) - methodGetIL = typeof (StackFrame).GetMethod ("GetILOffsetFromFile", BindingFlags.NonPublic | BindingFlags.Static); - - if (methodGetIL == null) - throw new Exception ("System.Diagnostics.StackFrame.GetILOffsetFromFile could not be found, make sure you have an updated mono installed."); + uint ilOffset; + mono_seq_point_data_get_il_offset (seqPointDataPath, (uint) methodToken, methodIndex, (uint) nativeOffset, out ilOffset); - return (int) methodGetIL.Invoke (null, new object[] {seqPointDataPath, methodToken, methodIndex, nativeOffset}); + return (int) ilOffset; } private string GetMethodFullName (MethodBase m) diff --git a/mcs/tools/mono-symbolicate/Makefile b/mcs/tools/mono-symbolicate/Makefile index 35cdfd88a39..daa92225a3d 100644 --- a/mcs/tools/mono-symbolicate/Makefile +++ b/mcs/tools/mono-symbolicate/Makefile @@ -11,6 +11,8 @@ LOCAL_MCS_FLAGS = \ /r:System.Core.dll \ /r:System.dll +EXTRA_DISTFILES="mono-symbolicate-native.dll" + include ../../build/executable.make LIB_PATH = $(topdir)/class/lib/$(PROFILE) @@ -58,3 +60,12 @@ ifeq ($(AOT_SUPPORTED), 1) @MONO_DEBUG=gen-compact-seq-points $(MONO) --aot=gen-seq-points-file $(TEST_EXE) > /dev/null $(CHECK_DIFF) endif + +all: mono-symbolicate-native.dll + +mono-symbolicate-native.dll: + cp ../../../mono/mini/mono-sgen mono-symbolicate-native.dll + +clean: + rm -rf mono-symbolicate-native.dll + diff --git a/mcs/tools/mono-symbolicate/SeqPointInfo.cs b/mcs/tools/mono-symbolicate/SeqPointInfo.cs new file mode 100644 index 00000000000..606e4fb3f17 --- /dev/null +++ b/mcs/tools/mono-symbolicate/SeqPointInfo.cs @@ -0,0 +1,156 @@ +using System; +using System.IO; +using System.Collections.Generic; + +namespace Symbolicate +{ + static class BinaryReaderExtensions + { + public static int ReadVariableInt (this BinaryReader reader) + { + int val = 0; + for (var i = 0; i < 4; i++) { + var b = reader.ReadByte (); + val |= (b & 0x7f) << (7 * i); + if ((b & 0x80) == 0) + return val; + } + + throw new Exception ("Invalid variable int"); + } + + public static int ReadVariableZigZagInt (this BinaryReader reader) + { + int enc = ReadVariableInt (reader); + int val = enc >> 1; + return ((enc & 1) == 0)? val : -val; + } + } + + class SeqPointInfo + { + class MethodData + { + List seqPoints; + + public static MethodData Read (BinaryReader reader) + { + var hasDebugData = reader.ReadVariableInt () != 0; + var dataSize = reader.ReadVariableInt (); + var dataEnd = reader.BaseStream.Position + dataSize; + + var seqPoints = new List (); + SeqPoint prev = null; + while (reader.BaseStream.Position < dataEnd) { + var seqPoint = SeqPoint.Read (reader, prev, hasDebugData); + seqPoints.Add (seqPoint); + prev = seqPoint; + } + + if (reader.BaseStream.Position != dataEnd) + throw new Exception ("Read more seq point than expected."); + + return new MethodData () { seqPoints = seqPoints }; + } + + public bool TryGetILOffset (int nativeOffset, out int ilOffset) + { + ilOffset = 0; + SeqPoint prev = null; + foreach (var seqPoint in seqPoints) { + if (seqPoint.NativeOffset > nativeOffset) + break; + prev = seqPoint; + } + + if (prev == null) + return false; + + ilOffset = prev.ILOffset; + return true; + } + } + + class SeqPoint + { + public readonly int ILOffset; + public readonly int NativeOffset; + + public SeqPoint (int ilOffset, int nativeOffset) + { + ILOffset = ilOffset; + NativeOffset = nativeOffset; + } + + public static SeqPoint Read (BinaryReader reader, SeqPoint prev, bool hasDebug) + { + var ilOffset = reader.ReadVariableZigZagInt (); + var nativeOffset = reader.ReadVariableZigZagInt (); + + // Respect delta encoding + if (prev != null) { + ilOffset += prev.ILOffset; + nativeOffset += prev.NativeOffset; + } + + //Read everything to ensure the buffer position is at the end of the seq point data. + if (hasDebug) { + reader.ReadVariableInt (); // flags + + var next_length = reader.ReadVariableInt (); + for (var i = 0; i < next_length; ++i) + reader.ReadVariableInt (); + } + + return new SeqPoint (ilOffset, nativeOffset); + } + }; + + Dictionary, MethodData> dataByIds; + Dictionary dataByTokens; + + public static SeqPointInfo Read (string path) + { + using (var reader = new BinaryReader (File.Open (path, FileMode.Open))) + { + var dataByIds = new Dictionary, MethodData> (); + var dataByTokens = new Dictionary (); + + var methodCount = reader.ReadVariableInt (); + + for (var i = 0; i < methodCount; ++i) { + var methodToken = reader.ReadVariableInt (); + var methodIndex = reader.ReadVariableInt (); + var methodId = new Tuple (methodToken, methodIndex); + + var methodData = MethodData.Read (reader); + + dataByIds.Add (methodId, methodData); + if (!dataByTokens.ContainsKey (methodToken)) + dataByTokens.Add (methodToken, methodData); + } + + return new SeqPointInfo { dataByIds = dataByIds, dataByTokens = dataByTokens }; + } + } + + public int GetILOffset (int methodToken, uint methodIndex, int nativeOffset) + { + MethodData methodData; + if (methodIndex == 0xffffff) { + if (!dataByTokens.TryGetValue (methodToken, out methodData)) + throw new Exception (string.Format ("Could not find data for method token {0:X}", methodToken)); + } else { + var methodId = new Tuple (methodToken, (int)methodIndex); + if (!dataByIds.TryGetValue (methodId, out methodData)) + throw new Exception (string.Format ("Could not find data for method token {0:X} with index {1:X}", methodToken, methodIndex)); + } + + int ilOffset; + if (!methodData.TryGetILOffset (nativeOffset, out ilOffset)) + throw new Exception ("Could not retrieve IL offset"); + + return ilOffset; + } + } +} diff --git a/mcs/tools/mono-symbolicate/mono-symbolicate.exe.sources b/mcs/tools/mono-symbolicate/mono-symbolicate.exe.sources index e3e3b588bda..7f50e887c20 100644 --- a/mcs/tools/mono-symbolicate/mono-symbolicate.exe.sources +++ b/mcs/tools/mono-symbolicate/mono-symbolicate.exe.sources @@ -1,3 +1,4 @@ symbolicate.cs LocationProvider.cs +SeqPointInfo.cs ../../class/corlib/System.Diagnostics/StackTraceHelper.cs diff --git a/mono/metadata/seq-points-data.h b/mono/metadata/seq-points-data.h index 3f72f3f338a..280a148caac 100644 --- a/mono/metadata/seq-points-data.h +++ b/mono/metadata/seq-points-data.h @@ -111,7 +111,7 @@ mono_seq_point_data_add (SeqPointData *data, guint32 methodToken, guint32 method gboolean mono_seq_point_data_get (SeqPointData *data, guint32 methodToken, guint32 methodIndex, MonoSeqPointInfo** info); -gboolean +MONO_API gboolean mono_seq_point_data_get_il_offset (char *path, guint32 methodToken, guint32 methodIndex, guint32 native_offset, guint32 *il_offset); #endif /* __MONO_SEQ_POINTS_DATA_H__ */ -- 2.25.1