Merge pull request #2819 from BrzVlad/fix-major-log
[mono.git] / mcs / tools / mono-symbolicate / SeqPointInfo.cs
1 using System;
2 using System.IO;
3 using System.Collections.Generic;
4
5 namespace Symbolicate
6 {
7         static class BinaryReaderExtensions
8         {
9                 public static int ReadVariableInt (this BinaryReader reader)
10                 {
11                         int val = 0;
12                         for (var i = 0; i < 4; i++) {
13                                 var b = reader.ReadByte ();
14                                 val |= (b & 0x7f) << (7 * i);
15                                 if ((b & 0x80) == 0)
16                                         return val;
17                         }
18
19                         throw new Exception ("Invalid variable int");
20                 }
21
22                 public static int ReadVariableZigZagInt (this BinaryReader reader)
23                 {
24                         int enc = ReadVariableInt (reader);
25                         int val = enc >> 1;
26                         return ((enc & 1) == 0)? val : -val;
27                 }
28         }
29
30         class SeqPointInfo
31         {
32                 class MethodData
33                 {
34                         List<SeqPoint> seqPoints;
35
36                         public static MethodData Read (BinaryReader reader)
37                         {
38                                 var hasDebugData = reader.ReadVariableInt () != 0;
39                                 var dataSize = reader.ReadVariableInt ();
40                                 var dataEnd = reader.BaseStream.Position + dataSize;
41
42                                 var seqPoints = new List<SeqPoint> ();
43                                 SeqPoint prev = null;
44                                 while (reader.BaseStream.Position < dataEnd) {
45                                         var seqPoint = SeqPoint.Read (reader, prev, hasDebugData);
46                                         seqPoints.Add (seqPoint);
47                                         prev = seqPoint;
48                                 }
49
50                                 if (reader.BaseStream.Position != dataEnd)
51                                         throw new Exception ("Read more seq point than expected.");
52
53                                 return new MethodData () { seqPoints = seqPoints };
54                         }
55
56                         public bool TryGetILOffset (int nativeOffset, out int ilOffset)
57                         {
58                                 ilOffset = 0;
59                                 SeqPoint prev = null;
60                                 foreach (var seqPoint in seqPoints) {
61                                         if (seqPoint.NativeOffset > nativeOffset)
62                                                 break;
63                                         prev = seqPoint;
64                                 }
65
66                                 if (prev == null)
67                                         return false;
68
69                                 ilOffset = prev.ILOffset;
70                                 return true;
71                         }
72                 }
73
74                 class SeqPoint
75                 {
76                         public readonly int ILOffset;
77                         public readonly int NativeOffset;
78
79                         public SeqPoint (int ilOffset, int nativeOffset)
80                         {
81                                 ILOffset = ilOffset;
82                                 NativeOffset = nativeOffset;
83                         }
84
85                         public static SeqPoint Read (BinaryReader reader, SeqPoint prev, bool hasDebug)
86                         {
87                                 var ilOffset = reader.ReadVariableZigZagInt ();
88                                 var nativeOffset = reader.ReadVariableZigZagInt ();
89
90                                 // Respect delta encoding
91                                 if (prev != null) {
92                                         ilOffset += prev.ILOffset;
93                                         nativeOffset += prev.NativeOffset;
94                                 }
95
96                                 //Read everything to ensure the buffer position is at the end of the seq point data.
97                                 if (hasDebug) {
98                                         reader.ReadVariableInt (); // flags
99
100                                         var next_length = reader.ReadVariableInt ();
101                                         for (var i = 0; i < next_length; ++i)
102                                                 reader.ReadVariableInt ();
103                                 }
104
105                                 return new SeqPoint (ilOffset, nativeOffset);
106                         }
107                 };
108
109                 Dictionary<Tuple<int,int>, MethodData> dataByIds;
110                 Dictionary<int, MethodData> dataByTokens;
111
112                 public static SeqPointInfo Read (string path)
113                 {
114                         using (var reader = new BinaryReader (File.Open (path, FileMode.Open)))
115                         {
116                                 var dataByIds = new Dictionary<Tuple<int,int>, MethodData> ();
117                                 var dataByTokens = new Dictionary<int, MethodData> ();
118
119                                 var methodCount = reader.ReadVariableInt ();
120
121                                 for (var i = 0; i < methodCount; ++i) {
122                                         var methodToken = reader.ReadVariableInt ();
123                                         var methodIndex = reader.ReadVariableInt ();
124                                         var methodId = new Tuple<int, int> (methodToken, methodIndex);
125
126                                         var methodData = MethodData.Read (reader);
127
128                                         dataByIds.Add (methodId, methodData);
129                                         if (!dataByTokens.ContainsKey (methodToken))
130                                                 dataByTokens.Add (methodToken, methodData);
131                                 }
132
133                                 return new SeqPointInfo { dataByIds  = dataByIds, dataByTokens = dataByTokens };
134                         }
135                 }
136
137                 public int GetILOffset (int methodToken, uint methodIndex, int nativeOffset)
138                 {
139                         MethodData methodData;
140                         if (methodIndex == 0xffffff) {
141                            if (!dataByTokens.TryGetValue (methodToken, out methodData))
142                                         throw new Exception (string.Format ("Could not find data for method token {0:X}", methodToken));
143                         } else {
144                                 var methodId = new Tuple<int, int> (methodToken, (int)methodIndex);
145                                 if (!dataByIds.TryGetValue (methodId, out methodData))
146                                         throw new Exception (string.Format ("Could not find data for method token {0:X} with index {1:X}", methodToken, methodIndex));
147                         }
148
149                         int ilOffset;
150                         if (!methodData.TryGetILOffset (nativeOffset, out ilOffset))
151                                 throw new Exception ("Could not retrieve IL offset");
152
153                         return ilOffset;
154                 }
155         }
156 }