2003-02-18 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 = 31;
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                 public override string ToString ()
64                 {
65                         return String.Format (
66                                 "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]",
67                                 TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount,
68                                 SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset,
69                                 MethodTableSize, TypeCount);
70                 }
71         }
72
73         public struct LineNumberEntry
74         {
75                 public readonly int Row;
76                 public readonly int Offset;
77
78                 public LineNumberEntry (int row, int offset)
79                 {
80                         this.Row = row;
81                         this.Offset = offset;
82                 }
83
84                 public static LineNumberEntry Null = new LineNumberEntry (0, 0);
85
86                 internal LineNumberEntry (BinaryReader reader)
87                 {
88                         Row = reader.ReadInt32 ();
89                         Offset = reader.ReadInt32 ();
90                 }
91
92                 internal void Write (BinaryWriter bw)
93                 {
94                         bw.Write (Row);
95                         bw.Write (Offset);
96                 }
97
98                 private class OffsetComparerClass : IComparer
99                 {
100                         public int Compare (object a, object b)
101                         {
102                                 LineNumberEntry l1 = (LineNumberEntry) a;
103                                 LineNumberEntry l2 = (LineNumberEntry) b;
104
105                                 if (l1.Offset < l2.Offset)
106                                         return -1;
107                                 else if (l1.Offset > l2.Offset)
108                                         return 1;
109                                 else
110                                         return 0;
111                         }
112                 }
113
114                 private class RowComparerClass : IComparer
115                 {
116                         public int Compare (object a, object b)
117                         {
118                                 LineNumberEntry l1 = (LineNumberEntry) a;
119                                 LineNumberEntry l2 = (LineNumberEntry) b;
120
121                                 if (l1.Row < l2.Row)
122                                         return -1;
123                                 else if (l1.Row > l2.Row)
124                                         return 1;
125                                 else
126                                         return 0;
127                         }
128                 }
129
130                 public static readonly IComparer OffsetComparer = new OffsetComparerClass ();
131                 public static readonly IComparer RowComparer = new RowComparerClass ();
132
133                 public override string ToString ()
134                 {
135                         return String.Format ("[Line {0}:{1}]", Row, Offset);
136                 }
137         }
138
139         public struct LocalVariableEntry
140         {
141                 public readonly string Name;
142                 public readonly FieldAttributes Attributes;
143                 public readonly byte[] Signature;
144
145                 public LocalVariableEntry (string Name, FieldAttributes Attributes, byte[] Signature)
146                 {
147                         this.Name = Name;
148                         this.Attributes = Attributes;
149                         this.Signature = Signature;
150                 }
151
152                 internal LocalVariableEntry (BinaryReader reader)
153                 {
154                         int name_length = reader.ReadInt32 ();
155                         byte[] name = reader.ReadBytes (name_length);
156                         Name = Encoding.UTF8.GetString (name);
157                         Attributes = (FieldAttributes) reader.ReadInt32 ();
158                         int sig_length = reader.ReadInt32 ();
159                         Signature = reader.ReadBytes (sig_length);
160                 }
161
162                 internal void Write (MonoSymbolFile file, BinaryWriter bw)
163                 {
164                         file.WriteString (bw, Name);
165                         bw.Write ((int) Attributes);
166                         bw.Write ((int) Signature.Length);
167                         bw.Write (Signature);
168                 }
169
170                 public override string ToString ()
171                 {
172                         return String.Format ("[LocalVariable {0}:{1}]", Name, Attributes);
173                 }
174         }
175
176         public class SourceFileEntry
177         {
178                 MonoSymbolFile file;
179                 string file_name;
180                 ArrayList methods;
181                 ArrayList namespaces;
182                 int index, count, name_offset, method_offset;
183                 int namespace_count, nstable_offset;
184                 bool creating;
185
186                 internal static int Size {
187                         get { return 24; }
188                 }
189
190                 internal SourceFileEntry (MonoSymbolFile file, string file_name)
191                 {
192                         this.file = file;
193                         this.file_name = file_name;
194                         this.index = file.AddSource (this);
195
196                         creating = true;
197                         methods = new ArrayList ();
198                         namespaces = new ArrayList ();
199                 }
200
201                 public void DefineMethod (MethodBase method, int token, LocalVariableEntry[] locals,
202                                           LineNumberEntry[] lines, int start, int end, int namespace_id)
203                 {
204                         if (!creating)
205                                 throw new InvalidOperationException ();
206
207                         MethodEntry entry = new MethodEntry (
208                                 file, this, method, token, locals, lines, start, end, namespace_id);
209
210                         methods.Add (entry);
211                         file.AddMethod (entry);
212                 }
213
214                 public int DefineNamespace (string name, string[] using_clauses, int parent)
215                 {
216                         if (!creating)
217                                 throw new InvalidOperationException ();
218
219                         int index = file.GetNextNamespaceIndex ();
220                         NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
221                         namespaces.Add (ns);
222                         return index;
223                 }
224
225                 internal void WriteData (BinaryWriter bw)
226                 {
227                         name_offset = (int) bw.BaseStream.Position;
228                         file.WriteString (bw, file_name);
229
230                         ArrayList list = new ArrayList ();
231                         foreach (MethodEntry entry in methods)
232                                 list.Add (entry.Write (file, bw));
233                         list.Sort ();
234                         count = list.Count;
235
236                         method_offset = (int) bw.BaseStream.Position;
237                         foreach (MethodSourceEntry method in list)
238                                 method.Write (bw);
239
240                         namespace_count = namespaces.Count;
241                         nstable_offset = (int) bw.BaseStream.Position;
242                         foreach (NamespaceEntry ns in namespaces)
243                                 ns.Write (file, bw);
244                 }
245
246                 internal void Write (BinaryWriter bw)
247                 {
248                         bw.Write (index);
249                         bw.Write (count);
250                         bw.Write (namespace_count);
251                         bw.Write (name_offset);
252                         bw.Write (method_offset);
253                         bw.Write (nstable_offset);
254                 }
255
256                 internal SourceFileEntry (MonoSymbolFile file, BinaryReader reader)
257                 {
258                         this.file = file;
259
260                         index = reader.ReadInt32 ();
261                         count = reader.ReadInt32 ();
262                         namespace_count = reader.ReadInt32 ();
263                         name_offset = reader.ReadInt32 ();
264                         method_offset = reader.ReadInt32 ();
265                         nstable_offset = reader.ReadInt32 ();
266
267                         file_name = file.ReadString (name_offset);
268                 }
269
270                 public int Index {
271                         get { return index; }
272                 }
273
274                 public string FileName {
275                         get { return file_name; }
276                 }
277
278                 public MethodSourceEntry[] Methods {
279                         get {
280                                 if (creating)
281                                         throw new InvalidOperationException ();
282
283                                 BinaryReader reader = file.BinaryReader;
284                                 int old_pos = (int) reader.BaseStream.Position;
285
286                                 reader.BaseStream.Position = method_offset;
287                                 ArrayList list = new ArrayList ();
288                                 for (int i = 0; i < count; i ++)
289                                         list.Add (new MethodSourceEntry (reader));
290                                 reader.BaseStream.Position = old_pos;
291
292                                 MethodSourceEntry[] retval = new MethodSourceEntry [count];
293                                 list.CopyTo (retval, 0);
294                                 return retval;
295                         }
296                 }
297
298                 public override string ToString ()
299                 {
300                         return String.Format ("SourceFileEntry ({0}:{1}:{2})", index, file_name, count);
301                 }
302         }
303
304         public struct MethodSourceEntry : IComparable
305         {
306                 public readonly int Index;
307                 public readonly int FileOffset;
308                 public readonly int StartRow;
309                 public readonly int EndRow;
310
311                 public MethodSourceEntry (int index, int file_offset, int start, int end)
312                 {
313                         this.Index = index;
314                         this.FileOffset = file_offset;
315                         this.StartRow = start;
316                         this.EndRow = end;
317                 }
318
319                 internal MethodSourceEntry (BinaryReader reader)
320                 {
321                         Index = reader.ReadInt32 ();
322                         FileOffset = reader.ReadInt32 ();
323                         StartRow = reader.ReadInt32 ();
324                         EndRow = reader.ReadInt32 ();
325                 }
326
327                 public static int Size
328                 {
329                         get {
330                                 return 16;
331                         }
332                 }
333
334                 internal void Write (BinaryWriter bw)
335                 {
336                         bw.Write (Index);
337                         bw.Write (FileOffset);
338                         bw.Write (StartRow);
339                         bw.Write (EndRow);
340                 }
341
342                 public int CompareTo (object obj)
343                 {
344                         MethodSourceEntry method = (MethodSourceEntry) obj;
345
346                         if (method.StartRow < StartRow)
347                                 return -1;
348                         else if (method.StartRow > StartRow)
349                                 return 1;
350                         else
351                                 return 0;
352                 }
353
354                 public override string ToString ()
355                 {
356                         return String.Format ("MethodSourceEntry ({0}:{1}:{2}:{3})",
357                                               Index, FileOffset, StartRow, EndRow);
358                 }
359         }
360
361         public class MethodEntry
362         {
363                 #region This is actually written to the symbol file
364                 public readonly int SourceFileIndex;
365                 public readonly int Token;
366                 public readonly int StartRow;
367                 public readonly int EndRow;
368                 public readonly int ClassTypeIndex;
369                 public readonly int NumParameters;
370                 public readonly int NumLocals;
371                 public readonly int NumLineNumbers;
372                 public readonly int NamespaceID;
373
374                 int NameOffset;
375                 int FullNameOffset;
376                 int TypeIndexTableOffset;
377                 int LocalVariableTableOffset;
378                 int LineNumberTableOffset;
379                 #endregion
380
381                 int index;
382                 int file_offset;
383                 string name;
384                 string full_name;
385
386                 public readonly SourceFileEntry SourceFile;
387                 public readonly LineNumberEntry[] LineNumbers;
388                 public readonly int[] ParamTypeIndices;
389                 public readonly int[] LocalTypeIndices;
390                 public readonly LocalVariableEntry[] Locals;
391
392                 public static int Size
393                 {
394                         get {
395                                 return 52;
396                         }
397                 }
398
399                 public string Name {
400                         get { return name; }
401                 }
402
403                 public string FullName {
404                         get { return full_name; }
405                 }
406
407                 internal MethodEntry (MonoSymbolFile file, BinaryReader reader, int index)
408                 {
409                         this.index = index;
410                         SourceFileIndex = reader.ReadInt32 ();
411                         Token = reader.ReadInt32 ();
412                         StartRow = reader.ReadInt32 ();
413                         EndRow = reader.ReadInt32 ();
414                         ClassTypeIndex = reader.ReadInt32 ();
415                         NumParameters = reader.ReadInt32 ();
416                         NumLocals = reader.ReadInt32 ();
417                         NumLineNumbers = reader.ReadInt32 ();
418                         NameOffset = reader.ReadInt32 ();
419                         FullNameOffset = reader.ReadInt32 ();
420                         TypeIndexTableOffset = reader.ReadInt32 ();
421                         LocalVariableTableOffset = reader.ReadInt32 ();
422                         LineNumberTableOffset = reader.ReadInt32 ();
423                         NamespaceID = reader.ReadInt32 ();
424
425                         name = file.ReadString (NameOffset);
426                         full_name = file.ReadString (FullNameOffset);
427
428                         SourceFile = file.GetSourceFile (SourceFileIndex);
429
430                         if (LineNumberTableOffset != 0) {
431                                 long old_pos = reader.BaseStream.Position;
432                                 reader.BaseStream.Position = LineNumberTableOffset;
433
434                                 LineNumbers = new LineNumberEntry [NumLineNumbers];
435
436                                 for (int i = 0; i < NumLineNumbers; i++)
437                                         LineNumbers [i] = new LineNumberEntry (reader);
438
439                                 reader.BaseStream.Position = old_pos;
440                         }
441
442                         if (LocalVariableTableOffset != 0) {
443                                 long old_pos = reader.BaseStream.Position;
444                                 reader.BaseStream.Position = LocalVariableTableOffset;
445
446                                 Locals = new LocalVariableEntry [NumLocals];
447
448                                 for (int i = 0; i < NumLocals; i++)
449                                         Locals [i] = new LocalVariableEntry (reader);
450
451                                 reader.BaseStream.Position = old_pos;
452                         }
453
454                         if (TypeIndexTableOffset != 0) {
455                                 long old_pos = reader.BaseStream.Position;
456                                 reader.BaseStream.Position = TypeIndexTableOffset;
457
458                                 ParamTypeIndices = new int [NumParameters];
459                                 LocalTypeIndices = new int [NumLocals];
460
461                                 for (int i = 0; i < NumParameters; i++)
462                                         ParamTypeIndices [i] = reader.ReadInt32 ();
463                                 for (int i = 0; i < NumLocals; i++)
464                                         LocalTypeIndices [i] = reader.ReadInt32 ();
465
466                                 reader.BaseStream.Position = old_pos;
467                         }
468                 }
469
470                 internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, MethodBase method,
471                                       int token, LocalVariableEntry[] locals, LineNumberEntry[] lines,
472                                       int start_row, int end_row, int namespace_id)
473                 {
474                         index = file.GetNextMethodIndex ();
475
476                         Token = token;
477                         SourceFileIndex = source.Index;
478                         SourceFile = source;
479                         StartRow = start_row;
480                         EndRow = end_row;
481                         NamespaceID = namespace_id;
482
483                         LineNumbers = BuildLineNumberTable (lines);
484                         NumLineNumbers = LineNumbers.Length;
485
486                         ParameterInfo[] parameters = method.GetParameters ();
487                         if (parameters == null)
488                                 parameters = new ParameterInfo [0];
489
490                         StringBuilder sb = new StringBuilder ();
491                         sb.Append (method.DeclaringType.FullName);
492                         sb.Append (".");
493                         sb.Append (method.Name);
494                         sb.Append ("(");
495                         for (int i = 0; i < parameters.Length; i++) {
496                                 if (i > 0)
497                                         sb.Append (",");
498                                 sb.Append (parameters [i].ParameterType.FullName);
499                         }
500                         sb.Append (")");
501
502                         name = method.Name;
503                         full_name = sb.ToString ();
504
505                         NumParameters = parameters.Length;
506                         ParamTypeIndices = new int [NumParameters];
507                         for (int i = 0; i < NumParameters; i++)
508                                 ParamTypeIndices [i] = file.DefineType (parameters [i].ParameterType);
509
510                         NumLocals = locals.Length;
511                         Locals = locals;
512
513                         LocalTypeIndices = new int [NumLocals];
514                         for (int i = 0; i < NumLocals; i++)
515                                 LocalTypeIndices [i] = file.GetNextTypeIndex ();
516
517                         ClassTypeIndex = file.DefineType (method.ReflectedType);
518                 }
519
520                 LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
521                 {
522                         ArrayList list = new ArrayList ();
523                         int last_offset = -1;
524                         int last_row = -1;
525
526                         for (int i = 0; i < line_numbers.Length; i++) {
527                                 LineNumberEntry line = (LineNumberEntry) line_numbers [i];
528
529                                 if (line.Offset > last_offset) {
530                                         if (last_row >= 0)
531                                                 list.Add (new LineNumberEntry (last_row, last_offset));
532                                         last_row = line.Row;
533                                         last_offset = line.Offset;
534                                 } else if (line.Row > last_row) {
535                                         last_row = line.Row;
536                                 }
537                         }
538
539                         if (last_row >= 0)
540                                 list.Add (new LineNumberEntry (last_row, last_offset));
541
542                         LineNumberEntry[] retval = new LineNumberEntry [list.Count];
543                         list.CopyTo (retval, 0);
544                         return retval;
545                 }
546
547                 internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
548                 {
549                         NameOffset = (int) bw.BaseStream.Position;
550                         file.WriteString (bw, name);
551
552                         FullNameOffset = (int) bw.BaseStream.Position;
553                         file.WriteString (bw, full_name);
554
555                         TypeIndexTableOffset = (int) bw.BaseStream.Position;
556
557                         for (int i = 0; i < NumParameters; i++)
558                                 bw.Write (ParamTypeIndices [i]);
559                         for (int i = 0; i < NumLocals; i++)
560                                 bw.Write (LocalTypeIndices [i]);
561
562                         LocalVariableTableOffset = (int) bw.BaseStream.Position;
563
564                         for (int i = 0; i < NumLocals; i++)
565                                 Locals [i].Write (file, bw);
566
567                         LineNumberTableOffset = (int) bw.BaseStream.Position;
568
569                         for (int i = 0; i < NumLineNumbers; i++)
570                                 LineNumbers [i].Write (bw);
571
572                         file.LineNumberCount += NumLineNumbers;
573                         file.LocalCount += NumLocals;
574
575                         file_offset = (int) bw.BaseStream.Position;
576
577                         bw.Write (SourceFileIndex);
578                         bw.Write (Token);
579                         bw.Write (StartRow);
580                         bw.Write (EndRow);
581                         bw.Write (ClassTypeIndex);
582                         bw.Write (NumParameters);
583                         bw.Write (NumLocals);
584                         bw.Write (NumLineNumbers);
585                         bw.Write (NameOffset);
586                         bw.Write (FullNameOffset);
587                         bw.Write (TypeIndexTableOffset);
588                         bw.Write (LocalVariableTableOffset);
589                         bw.Write (LineNumberTableOffset);
590                         bw.Write (NamespaceID);
591
592                         return new MethodSourceEntry (index, file_offset, StartRow, EndRow);
593                 }
594
595                 internal void WriteIndex (BinaryWriter bw)
596                 {
597                         bw.Write (file_offset);
598                         bw.Write (FullNameOffset);
599                 }
600
601                 public override string ToString ()
602                 {
603                         return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {7}:{8}:{9}:{10} - {5} - {6}]",
604                                               index, Token, SourceFileIndex, StartRow, EndRow,
605                                               SourceFile, FullName, ClassTypeIndex, NumParameters,
606                                               NumLocals, NumLineNumbers);
607                 }
608         }
609
610         public struct NamespaceEntry
611         {
612                 public readonly string Name;
613                 public readonly int Index;
614                 public readonly int Parent;
615                 public readonly string[] UsingClauses;
616
617                 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
618                 {
619                         this.Name = name;
620                         this.Index = index;
621                         this.Parent = parent;
622                         this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
623                 }
624
625                 internal void Write (MonoSymbolFile file, BinaryWriter bw)
626                 {
627                         file.WriteString (bw, Name);
628                         bw.Write (Index);
629                         bw.Write (Parent);
630                         bw.Write (UsingClauses.Length);
631                         foreach (string uc in UsingClauses)
632                                 file.WriteString (bw, uc);
633                 }
634
635                 public override string ToString ()
636                 {
637                         return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);
638                 }
639         }
640 }