2003-02-05 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolTable.cs
1 //
2 // System.Diagnostics.SymbolStore/MonoSymbolTable.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@gnome.org)
6 //
7 // (C) 2002 Ximian, Inc.  http://www.ximian.com
8 //
9
10 using System;
11 using System.Reflection;
12 using System.Reflection.Emit;
13 using System.Collections;
14 using System.Text;
15 using System.IO;
16         
17 namespace Mono.CSharp.Debugger
18 {
19         public struct OffsetTable
20         {
21                 public const int  Version = 29;
22                 public const long Magic   = 0x45e82623fd7fa614;
23
24                 public int TotalFileSize;
25                 public int DataSectionOffset;
26                 public int DataSectionSize;
27                 public int SourceCount;
28                 public int SourceTableOffset;
29                 public int SourceTableSize;
30                 public int MethodCount;
31                 public int MethodTableOffset;
32                 public int MethodTableSize;
33                 public int TypeCount;
34
35                 internal OffsetTable (BinaryReader reader)
36                 {
37                         TotalFileSize = reader.ReadInt32 ();
38                         DataSectionOffset = reader.ReadInt32 ();
39                         DataSectionSize = reader.ReadInt32 ();
40                         SourceCount = reader.ReadInt32 ();
41                         SourceTableOffset = reader.ReadInt32 ();
42                         SourceTableSize = reader.ReadInt32 ();
43                         MethodCount = reader.ReadInt32 ();
44                         MethodTableOffset = reader.ReadInt32 ();
45                         MethodTableSize = reader.ReadInt32 ();
46                         TypeCount = reader.ReadInt32 ();
47                 }
48
49                 internal void Write (BinaryWriter bw)
50                 {
51                         bw.Write (TotalFileSize);
52                         bw.Write (DataSectionOffset);
53                         bw.Write (DataSectionSize);
54                         bw.Write (SourceCount);
55                         bw.Write (SourceTableOffset);
56                         bw.Write (SourceTableSize);
57                         bw.Write (MethodCount);
58                         bw.Write (MethodTableOffset);
59                         bw.Write (MethodTableSize);
60                         bw.Write (TypeCount);
61                 }
62         }
63
64         public struct LineNumberEntry
65         {
66                 public readonly int Row;
67                 public readonly int Offset;
68
69                 public LineNumberEntry (int row, int offset)
70                 {
71                         this.Row = row;
72                         this.Offset = offset;
73                 }
74
75                 internal LineNumberEntry (SourceLine line)
76                         : this (line.Row, line.Offset)
77                 { }
78
79                 internal LineNumberEntry (BinaryReader reader)
80                 {
81                         Row = reader.ReadInt32 ();
82                         Offset = reader.ReadInt32 ();
83                 }
84
85                 internal void Write (BinaryWriter bw)
86                 {
87                         bw.Write (Row);
88                         bw.Write (Offset);
89                 }
90
91                 public override string ToString ()
92                 {
93                         return String.Format ("[Line {0}:{1}]", Row, Offset);
94                 }
95         }
96
97         public struct LocalVariableEntry
98         {
99                 public readonly string Name;
100                 public readonly FieldAttributes Attributes;
101                 public readonly byte[] Signature;
102
103                 public LocalVariableEntry (string Name, FieldAttributes Attributes, byte[] Signature)
104                 {
105                         this.Name = Name;
106                         this.Attributes = Attributes;
107                         this.Signature = Signature;
108                 }
109
110                 internal LocalVariableEntry (BinaryReader reader)
111                 {
112                         int name_length = reader.ReadInt32 ();
113                         byte[] name = reader.ReadBytes (name_length);
114                         Name = Encoding.UTF8.GetString (name);
115                         Attributes = (FieldAttributes) reader.ReadInt32 ();
116                         int sig_length = reader.ReadInt32 ();
117                         Signature = reader.ReadBytes (sig_length);
118                 }
119
120                 internal void Write (MonoSymbolFile file, BinaryWriter bw)
121                 {
122                         file.WriteString (bw, Name);
123                         bw.Write ((int) Attributes);
124                         bw.Write ((int) Signature.Length);
125                         bw.Write (Signature);
126                 }
127
128                 public override string ToString ()
129                 {
130                         return String.Format ("[LocalVariable {0}:{1}]", Name, Attributes);
131                 }
132         }
133
134         public class SourceFileEntry
135         {
136                 MonoSymbolFile file;
137                 string file_name;
138                 ArrayList methods;
139                 int index, count, name_offset, method_offset;
140                 bool creating;
141
142                 internal static int Size {
143                         get { return 16; }
144                 }
145
146                 internal SourceFileEntry (MonoSymbolFile file, string file_name, int index)
147                 {
148                         this.file = file;
149                         this.file_name = file_name;
150                         this.index = index;
151
152                         creating = true;
153                         methods = new ArrayList ();
154                 }
155
156                 public void DefineMethod (MethodBase method, int token, LocalVariableEntry[] locals,
157                                           LineNumberEntry[] lines, int start, int end)
158                 {
159                         if (!creating)
160                                 throw new InvalidOperationException ();
161
162                         MethodEntry entry = new MethodEntry (
163                                 file, this, method, token, locals, lines, start, end);
164
165                         methods.Add (entry);
166                         file.AddMethod (entry);
167                 }
168
169                 internal void WriteData (BinaryWriter bw)
170                 {
171                         name_offset = (int) bw.BaseStream.Position;
172                         file.WriteString (bw, file_name);
173
174                         ArrayList list = new ArrayList ();
175                         foreach (MethodEntry entry in methods)
176                                 list.Add (entry.Write (file, bw));
177                         list.Sort ();
178                         count = list.Count;
179
180                         method_offset = (int) bw.BaseStream.Position;
181                         foreach (MethodSourceEntry method in list)
182                                 method.Write (bw);
183                 }
184
185                 internal void Write (BinaryWriter bw)
186                 {
187                         bw.Write (index);
188                         bw.Write (count);
189                         bw.Write (name_offset);
190                         bw.Write (method_offset);
191                 }
192
193                 internal SourceFileEntry (MonoSymbolFile file, BinaryReader reader)
194                 {
195                         this.file = file;
196
197                         index = reader.ReadInt32 ();
198                         count = reader.ReadInt32 ();
199                         name_offset = reader.ReadInt32 ();
200                         method_offset = reader.ReadInt32 ();
201
202                         file_name = file.ReadString (name_offset);
203                 }
204
205                 public int Index {
206                         get { return index; }
207                 }
208
209                 public string FileName {
210                         get { return file_name; }
211                 }
212
213                 public MethodSourceEntry[] Methods {
214                         get {
215                                 if (creating)
216                                         throw new InvalidOperationException ();
217
218                                 BinaryReader reader = file.BinaryReader;
219                                 int old_pos = (int) reader.BaseStream.Position;
220
221                                 reader.BaseStream.Position = method_offset;
222                                 ArrayList list = new ArrayList ();
223                                 for (int i = 0; i < count; i ++)
224                                         list.Add (new MethodSourceEntry (reader));
225                                 reader.BaseStream.Position = old_pos;
226
227                                 MethodSourceEntry[] retval = new MethodSourceEntry [count];
228                                 list.CopyTo (retval, 0);
229                                 return retval;
230                         }
231                 }
232
233                 public override string ToString ()
234                 {
235                         return String.Format ("SourceFileEntry ({0}:{1}:{2})", index, file_name, count);
236                 }
237         }
238
239         public struct MethodSourceEntry : IComparable
240         {
241                 public readonly int Index;
242                 public readonly int FileOffset;
243                 public readonly int StartRow;
244                 public readonly int EndRow;
245
246                 public MethodSourceEntry (int index, int file_offset, int start, int end)
247                 {
248                         this.Index = index;
249                         this.FileOffset = file_offset;
250                         this.StartRow = start;
251                         this.EndRow = end;
252                 }
253
254                 internal MethodSourceEntry (BinaryReader reader)
255                 {
256                         Index = reader.ReadInt32 ();
257                         FileOffset = reader.ReadInt32 ();
258                         StartRow = reader.ReadInt32 ();
259                         EndRow = reader.ReadInt32 ();
260                 }
261
262                 public static int Size
263                 {
264                         get {
265                                 return 16;
266                         }
267                 }
268
269                 internal void Write (BinaryWriter bw)
270                 {
271                         bw.Write (Index);
272                         bw.Write (FileOffset);
273                         bw.Write (StartRow);
274                         bw.Write (EndRow);
275                 }
276
277                 public int CompareTo (object obj)
278                 {
279                         MethodSourceEntry method = (MethodSourceEntry) obj;
280
281                         if (method.StartRow < StartRow)
282                                 return -1;
283                         else if (method.StartRow > StartRow)
284                                 return 1;
285                         else
286                                 return 0;
287                 }
288
289                 public override string ToString ()
290                 {
291                         return String.Format ("MethodSourceEntry ({0}:{1}:{2}:{3})",
292                                               Index, FileOffset, StartRow, EndRow);
293                 }
294         }
295
296         public class MethodEntry
297         {
298                 #region This is actually written to the symbol file
299                 public readonly int SourceFileIndex;
300                 public readonly int Token;
301                 public readonly int StartRow;
302                 public readonly int EndRow;
303                 public readonly int ThisTypeIndex;
304                 public readonly int NumParameters;
305                 public readonly int NumLocals;
306                 public readonly int NumLineNumbers;
307
308                 int NameOffset;
309                 int FullNameOffset;
310                 int TypeIndexTableOffset;
311                 int LocalVariableTableOffset;
312                 int LineNumberTableOffset;
313                 #endregion
314
315                 int index;
316                 int file_offset;
317                 string name;
318                 string full_name;
319
320                 public readonly SourceFileEntry SourceFile;
321                 public readonly LineNumberEntry[] LineNumbers;
322                 public readonly int[] ParamTypeIndices;
323                 public readonly int[] LocalTypeIndices;
324                 public readonly LocalVariableEntry[] Locals;
325
326                 public static int Size
327                 {
328                         get {
329                                 return 48;
330                         }
331                 }
332
333                 public string Name {
334                         get { return name; }
335                 }
336
337                 public string FullName {
338                         get { return full_name; }
339                 }
340
341                 internal MethodEntry (MonoSymbolFile file, BinaryReader reader)
342                 {
343                         SourceFileIndex = reader.ReadInt32 ();
344                         Token = reader.ReadInt32 ();
345                         StartRow = reader.ReadInt32 ();
346                         EndRow = reader.ReadInt32 ();
347                         ThisTypeIndex = reader.ReadInt32 ();
348                         NumParameters = reader.ReadInt32 ();
349                         NumLocals = reader.ReadInt32 ();
350                         NumLineNumbers = reader.ReadInt32 ();
351                         NameOffset = reader.ReadInt32 ();
352                         FullNameOffset = reader.ReadInt32 ();
353                         TypeIndexTableOffset = reader.ReadInt32 ();
354                         LocalVariableTableOffset = reader.ReadInt32 ();
355                         LineNumberTableOffset = reader.ReadInt32 ();
356
357                         name = file.ReadString (NameOffset);
358                         full_name = file.ReadString (FullNameOffset);
359
360                         SourceFile = file.GetSourceFile (SourceFileIndex);
361
362                         if (LineNumberTableOffset != 0) {
363                                 long old_pos = reader.BaseStream.Position;
364                                 reader.BaseStream.Position = LineNumberTableOffset;
365
366                                 LineNumbers = new LineNumberEntry [NumLineNumbers];
367
368                                 for (int i = 0; i < NumLineNumbers; i++)
369                                         LineNumbers [i] = new LineNumberEntry (reader);
370
371                                 reader.BaseStream.Position = old_pos;
372                         }
373
374                         if (LocalVariableTableOffset != 0) {
375                                 long old_pos = reader.BaseStream.Position;
376                                 reader.BaseStream.Position = LocalVariableTableOffset;
377
378                                 Locals = new LocalVariableEntry [NumLocals];
379
380                                 for (int i = 0; i < NumLocals; i++)
381                                         Locals [i] = new LocalVariableEntry (reader);
382
383                                 reader.BaseStream.Position = old_pos;
384                         }
385
386                         if (TypeIndexTableOffset != 0) {
387                                 long old_pos = reader.BaseStream.Position;
388                                 reader.BaseStream.Position = TypeIndexTableOffset;
389
390                                 ParamTypeIndices = new int [NumParameters];
391                                 LocalTypeIndices = new int [NumLocals];
392
393                                 for (int i = 0; i < NumParameters; i++)
394                                         ParamTypeIndices [i] = reader.ReadInt32 ();
395                                 for (int i = 0; i < NumLocals; i++)
396                                         LocalTypeIndices [i] = reader.ReadInt32 ();
397
398                                 reader.BaseStream.Position = old_pos;
399                         }
400                 }
401
402                 internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, MethodBase method,
403                                       int token, LocalVariableEntry[] locals, LineNumberEntry[] lines,
404                                       int start_row, int end_row)
405                 {
406                         index = file.GetNextMethodIndex ();
407
408                         Token = token;
409                         SourceFileIndex = source.Index;
410                         SourceFile = source;
411                         StartRow = start_row;
412                         EndRow = end_row;
413
414                         NumLineNumbers = lines.Length;
415                         LineNumbers = lines;
416
417                         ParameterInfo[] parameters = method.GetParameters ();
418                         if (parameters == null)
419                                 parameters = new ParameterInfo [0];
420
421                         StringBuilder sb = new StringBuilder ();
422                         sb.Append (method.DeclaringType.FullName);
423                         sb.Append (".");
424                         sb.Append (method.Name);
425                         sb.Append ("(");
426                         for (int i = 0; i < parameters.Length; i++) {
427                                 if (i > 0)
428                                         sb.Append (",");
429                                 sb.Append (parameters [i].ParameterType.FullName);
430                         }
431                         sb.Append (")");
432
433                         name = method.Name;
434                         full_name = sb.ToString ();
435
436                         NumParameters = parameters.Length;
437                         ParamTypeIndices = new int [NumParameters];
438                         for (int i = 0; i < NumParameters; i++)
439                                 ParamTypeIndices [i] = file.DefineType (parameters [i].ParameterType);
440
441                         NumLocals = locals.Length;
442                         Locals = locals;
443
444                         LocalTypeIndices = new int [NumLocals];
445                         for (int i = 0; i < NumLocals; i++)
446                                 LocalTypeIndices [i] = file.GetNextTypeIndex ();
447
448                         if (method.IsStatic)
449                                 ThisTypeIndex = 0;
450                         else
451                                 ThisTypeIndex = file.DefineType (method.ReflectedType);
452                 }
453
454                 internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
455                 {
456                         NameOffset = (int) bw.BaseStream.Position;
457                         file.WriteString (bw, name);
458
459                         FullNameOffset = (int) bw.BaseStream.Position;
460                         file.WriteString (bw, full_name);
461
462                         TypeIndexTableOffset = (int) bw.BaseStream.Position;
463
464                         for (int i = 0; i < NumParameters; i++)
465                                 bw.Write (ParamTypeIndices [i]);
466                         for (int i = 0; i < NumLocals; i++)
467                                 bw.Write (LocalTypeIndices [i]);
468
469                         LocalVariableTableOffset = (int) bw.BaseStream.Position;
470
471                         for (int i = 0; i < NumLocals; i++)
472                                 Locals [i].Write (file, bw);
473
474                         LineNumberTableOffset = (int) bw.BaseStream.Position;
475
476                         for (int i = 0; i < NumLineNumbers; i++)
477                                 LineNumbers [i].Write (bw);
478
479                         file_offset = (int) bw.BaseStream.Position;
480
481                         bw.Write (SourceFileIndex);
482                         bw.Write (Token);
483                         bw.Write (StartRow);
484                         bw.Write (EndRow);
485                         bw.Write (ThisTypeIndex);
486                         bw.Write (NumParameters);
487                         bw.Write (NumLocals);
488                         bw.Write (NumLineNumbers);
489                         bw.Write (NameOffset);
490                         bw.Write (FullNameOffset);
491                         bw.Write (TypeIndexTableOffset);
492                         bw.Write (LocalVariableTableOffset);
493                         bw.Write (LineNumberTableOffset);
494
495                         return new MethodSourceEntry (index, file_offset, StartRow, EndRow);
496                 }
497
498                 internal void WriteIndex (BinaryWriter bw)
499                 {
500                         bw.Write (file_offset);
501                         bw.Write (FullNameOffset);
502                 }
503
504                 public override string ToString ()
505                 {
506                         return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {5} - {6}]",
507                                               SourceFileIndex, index, Token, StartRow, EndRow,
508                                               SourceFile, FullName);
509                 }
510         }
511 }