[mono-symbolicate] Created SeqPointInfo.cs
authorMarcos Henrich <marcos.henrich@xamarin.com>
Wed, 2 Mar 2016 10:29:05 +0000 (10:29 +0000)
committerMarcos Henrich <marcos.henrich@xamarin.com>
Tue, 22 Mar 2016 14:22:49 +0000 (14:22 +0000)
SeqPointInfo is a c# implementation of the debug data decoding process
that is done natively by the runtime.

mcs/tools/mono-symbolicate/LocationProvider.cs
mcs/tools/mono-symbolicate/Makefile
mcs/tools/mono-symbolicate/SeqPointInfo.cs [new file with mode: 0644]
mcs/tools/mono-symbolicate/mono-symbolicate.exe.sources
mono/metadata/seq-points-data.h

index ffe3c14206f36fca484c6515ae5fad3475fd4cd1..cad20ae8e16f6bdb6e073e1a10ef447851605493 100644 (file)
@@ -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)
index 35cdfd88a39e21ee4d503c0316bbc2c31577d1a7..daa92225a3d6423a9f09a9abc688960765af7bd5 100644 (file)
@@ -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 (file)
index 0000000..606e4fb
--- /dev/null
@@ -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<SeqPoint> 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> ();
+                               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<Tuple<int,int>, MethodData> dataByIds;
+               Dictionary<int, MethodData> dataByTokens;
+
+               public static SeqPointInfo Read (string path)
+               {
+                       using (var reader = new BinaryReader (File.Open (path, FileMode.Open)))
+                       {
+                               var dataByIds = new Dictionary<Tuple<int,int>, MethodData> ();
+                               var dataByTokens = new Dictionary<int, MethodData> ();
+
+                               var methodCount = reader.ReadVariableInt ();
+
+                               for (var i = 0; i < methodCount; ++i) {
+                                       var methodToken = reader.ReadVariableInt ();
+                                       var methodIndex = reader.ReadVariableInt ();
+                                       var methodId = new Tuple<int, int> (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<int, int> (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;
+               }
+       }
+}
index e3e3b588bdad8322a1eaa5ebfdf4c2ea67fff5b7..7f50e887c2032b2fde8f5f62f689241af91c5237 100644 (file)
@@ -1,3 +1,4 @@
 symbolicate.cs
 LocationProvider.cs
+SeqPointInfo.cs
 ../../class/corlib/System.Diagnostics/StackTraceHelper.cs
index 3f72f3f338a59069bf0323c4d7f47e035d394e4c..280a148caac3ccb8004f7fe1863d22a0ff9b2395 100644 (file)
@@ -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__ */