2003-02-10 Nick Drochak <ndrochak@gol.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 = 30;
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 16; }
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 ThisTypeIndex;
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                         ThisTypeIndex = 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                         if (method.IsStatic)
518                                 ThisTypeIndex = 0;
519                         else
520                                 ThisTypeIndex = file.DefineType (method.ReflectedType);
521                 }
522
523                 LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
524                 {
525                         ArrayList list = new ArrayList ();
526                         int last_offset = -1;
527                         int last_row = -1;
528
529                         for (int i = 0; i < line_numbers.Length; i++) {
530                                 LineNumberEntry line = (LineNumberEntry) line_numbers [i];
531
532                                 if (line.Offset > last_offset) {
533                                         if (last_row >= 0)
534                                                 list.Add (new LineNumberEntry (last_row, last_offset));
535                                         last_row = line.Row;
536                                         last_offset = line.Offset;
537                                 } else if (line.Row > last_row) {
538                                         last_row = line.Row;
539                                 }
540                         }
541
542                         if (last_row >= 0)
543                                 list.Add (new LineNumberEntry (last_row, last_offset));
544
545                         LineNumberEntry[] retval = new LineNumberEntry [list.Count];
546                         list.CopyTo (retval, 0);
547                         return retval;
548                 }
549
550                 internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
551                 {
552                         NameOffset = (int) bw.BaseStream.Position;
553                         file.WriteString (bw, name);
554
555                         FullNameOffset = (int) bw.BaseStream.Position;
556                         file.WriteString (bw, full_name);
557
558                         TypeIndexTableOffset = (int) bw.BaseStream.Position;
559
560                         for (int i = 0; i < NumParameters; i++)
561                                 bw.Write (ParamTypeIndices [i]);
562                         for (int i = 0; i < NumLocals; i++)
563                                 bw.Write (LocalTypeIndices [i]);
564
565                         LocalVariableTableOffset = (int) bw.BaseStream.Position;
566
567                         for (int i = 0; i < NumLocals; i++)
568                                 Locals [i].Write (file, bw);
569
570                         LineNumberTableOffset = (int) bw.BaseStream.Position;
571
572                         for (int i = 0; i < NumLineNumbers; i++)
573                                 LineNumbers [i].Write (bw);
574
575                         file.LineNumberCount += NumLineNumbers;
576                         file.LocalCount += NumLocals;
577
578                         file_offset = (int) bw.BaseStream.Position;
579
580                         bw.Write (SourceFileIndex);
581                         bw.Write (Token);
582                         bw.Write (StartRow);
583                         bw.Write (EndRow);
584                         bw.Write (ThisTypeIndex);
585                         bw.Write (NumParameters);
586                         bw.Write (NumLocals);
587                         bw.Write (NumLineNumbers);
588                         bw.Write (NameOffset);
589                         bw.Write (FullNameOffset);
590                         bw.Write (TypeIndexTableOffset);
591                         bw.Write (LocalVariableTableOffset);
592                         bw.Write (LineNumberTableOffset);
593                         bw.Write (NamespaceID);
594
595                         return new MethodSourceEntry (index, file_offset, StartRow, EndRow);
596                 }
597
598                 internal void WriteIndex (BinaryWriter bw)
599                 {
600                         bw.Write (file_offset);
601                         bw.Write (FullNameOffset);
602                 }
603
604                 public override string ToString ()
605                 {
606                         return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {7}:{8}:{9}:{10} - {5} - {6}]",
607                                               index, Token, SourceFileIndex, StartRow, EndRow,
608                                               SourceFile, FullName, ThisTypeIndex, NumParameters,
609                                               NumLocals, NumLineNumbers);
610                 }
611         }
612
613         public struct NamespaceEntry
614         {
615                 public readonly string Name;
616                 public readonly int Index;
617                 public readonly int Parent;
618                 public readonly string[] UsingClauses;
619
620                 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
621                 {
622                         this.Name = name;
623                         this.Index = index;
624                         this.Parent = parent;
625                         this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
626                 }
627
628                 internal void Write (MonoSymbolFile file, BinaryWriter bw)
629                 {
630                         file.WriteString (bw, Name);
631                         bw.Write (Index);
632                         bw.Write (Parent);
633                         bw.Write (UsingClauses.Length);
634                         foreach (string uc in UsingClauses)
635                                 file.WriteString (bw, uc);
636                 }
637
638                 public override string ToString ()
639                 {
640                         return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);
641                 }
642         }
643 }