2004-05-05 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolTable.cs
1 //
2 // System.Diagnostics.SymbolStore/MonoSymbolTable.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@ximian.com)
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 //
18 // Parts which are actually written into the symbol file are marked with
19 //
20 //         #region This is actually written to the symbol file
21 //         #endregion
22 //
23 // Please do not modify these regions without previously talking to me.
24 //
25 // All changes to the file format must be synchronized in several places:
26 //
27 // a) The fields in these regions (and their order) must match the actual
28 //    contents of the symbol file.
29 //
30 //    This helps people to understand the symbol file format without reading
31 //    too much source code, ie. you look at the appropriate region and then
32 //    you know what's actually in the file.
33 //
34 //    It is also required to help me enforce b).
35 //
36 // b) The regions must be kept in sync with the unmanaged code in
37 //    mono/metadata/debug-mono-symfile.h
38 //
39 // When making changes to the file format, you must also increase two version
40 // numbers:
41 //
42 // i)  OffsetTable.Version in this file.
43 // ii) MONO_SYMBOL_FILE_VERSION in mono/metadata/debug-mono-symfile.h
44 //
45 // After doing so, recompile everything, including the debugger.  Symbol files
46 // with different versions are incompatible to each other and the debugger and
47 // the runtime enfore this, so you need to recompile all your assemblies after
48 // changing the file format.
49 //
50
51 namespace Mono.CSharp.Debugger
52 {
53         public struct OffsetTable
54         {
55                 public const int  Version = 36;
56                 public const long Magic   = 0x45e82623fd7fa614;
57
58                 #region This is actually written to the symbol file
59                 public int TotalFileSize;
60                 public int DataSectionOffset;
61                 public int DataSectionSize;
62                 public int SourceCount;
63                 public int SourceTableOffset;
64                 public int SourceTableSize;
65                 public int MethodCount;
66                 public int MethodTableOffset;
67                 public int MethodTableSize;
68                 public int TypeCount;
69                 #endregion
70
71                 internal OffsetTable (BinaryReader reader)
72                 {
73                         TotalFileSize = reader.ReadInt32 ();
74                         DataSectionOffset = reader.ReadInt32 ();
75                         DataSectionSize = reader.ReadInt32 ();
76                         SourceCount = reader.ReadInt32 ();
77                         SourceTableOffset = reader.ReadInt32 ();
78                         SourceTableSize = reader.ReadInt32 ();
79                         MethodCount = reader.ReadInt32 ();
80                         MethodTableOffset = reader.ReadInt32 ();
81                         MethodTableSize = reader.ReadInt32 ();
82                         TypeCount = reader.ReadInt32 ();
83                 }
84
85                 internal void Write (BinaryWriter bw)
86                 {
87                         bw.Write (TotalFileSize);
88                         bw.Write (DataSectionOffset);
89                         bw.Write (DataSectionSize);
90                         bw.Write (SourceCount);
91                         bw.Write (SourceTableOffset);
92                         bw.Write (SourceTableSize);
93                         bw.Write (MethodCount);
94                         bw.Write (MethodTableOffset);
95                         bw.Write (MethodTableSize);
96                         bw.Write (TypeCount);
97                 }
98
99                 public override string ToString ()
100                 {
101                         return String.Format (
102                                 "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]",
103                                 TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount,
104                                 SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset,
105                                 MethodTableSize, TypeCount);
106                 }
107         }
108
109         public struct LineNumberEntry
110         {
111                 #region This is actually written to the symbol file
112                 public readonly int Row;
113                 public readonly int Offset;
114                 #endregion
115
116                 public LineNumberEntry (int row, int offset)
117                 {
118                         this.Row = row;
119                         this.Offset = offset;
120                 }
121
122                 public static LineNumberEntry Null = new LineNumberEntry (0, 0);
123
124                 internal LineNumberEntry (BinaryReader reader)
125                 {
126                         Row = reader.ReadInt32 ();
127                         Offset = reader.ReadInt32 ();
128                 }
129
130                 internal void Write (BinaryWriter bw)
131                 {
132                         bw.Write (Row);
133                         bw.Write (Offset);
134                 }
135
136                 private class OffsetComparerClass : IComparer
137                 {
138                         public int Compare (object a, object b)
139                         {
140                                 LineNumberEntry l1 = (LineNumberEntry) a;
141                                 LineNumberEntry l2 = (LineNumberEntry) b;
142
143                                 if (l1.Offset < l2.Offset)
144                                         return -1;
145                                 else if (l1.Offset > l2.Offset)
146                                         return 1;
147                                 else
148                                         return 0;
149                         }
150                 }
151
152                 private class RowComparerClass : IComparer
153                 {
154                         public int Compare (object a, object b)
155                         {
156                                 LineNumberEntry l1 = (LineNumberEntry) a;
157                                 LineNumberEntry l2 = (LineNumberEntry) b;
158
159                                 if (l1.Row < l2.Row)
160                                         return -1;
161                                 else if (l1.Row > l2.Row)
162                                         return 1;
163                                 else
164                                         return 0;
165                         }
166                 }
167
168                 public static readonly IComparer OffsetComparer = new OffsetComparerClass ();
169                 public static readonly IComparer RowComparer = new RowComparerClass ();
170
171                 public override string ToString ()
172                 {
173                         return String.Format ("[Line {0}:{1}]", Row, Offset);
174                 }
175         }
176
177         public class LexicalBlockEntry
178         {
179                 public int Index;
180                 #region This is actually written to the symbol file
181                 public int StartOffset;
182                 public int EndOffset;
183                 #endregion
184
185                 public LexicalBlockEntry (int index, int start_offset)
186                 {
187                         this.Index = index;
188                         this.StartOffset = start_offset;
189                 }
190
191                 internal LexicalBlockEntry (int index, BinaryReader reader)
192                 {
193                         this.Index = index;
194                         this.StartOffset = reader.ReadInt32 ();
195                         this.EndOffset = reader.ReadInt32 ();
196                 }
197
198                 public void Close (int end_offset)
199                 {
200                         this.EndOffset = end_offset;
201                 }
202
203                 internal void Write (BinaryWriter bw)
204                 {
205                         bw.Write (StartOffset);
206                         bw.Write (EndOffset);
207                 }
208
209                 public override string ToString ()
210                 {
211                         return String.Format ("[LexicalBlock {0}:{1}]", StartOffset, EndOffset);
212                 }
213         }
214
215         public struct LocalVariableEntry
216         {
217                 #region This is actually written to the symbol file
218                 public readonly string Name;
219                 public readonly FieldAttributes Attributes;
220                 public readonly byte[] Signature;
221                 public readonly int BlockIndex;
222                 #endregion
223
224                 public LocalVariableEntry (string Name, FieldAttributes Attributes, byte[] Signature,
225                                            int BlockIndex)
226                 {
227                         this.Name = Name;
228                         this.Attributes = Attributes;
229                         this.Signature = Signature;
230                         this.BlockIndex = BlockIndex;
231                 }
232
233                 internal LocalVariableEntry (BinaryReader reader)
234                 {
235                         int name_length = reader.ReadInt32 ();
236                         byte[] name = reader.ReadBytes (name_length);
237                         Name = Encoding.UTF8.GetString (name);
238                         Attributes = (FieldAttributes) reader.ReadInt32 ();
239                         int sig_length = reader.ReadInt32 ();
240                         Signature = reader.ReadBytes (sig_length);
241                         BlockIndex = reader.ReadInt32 ();
242                 }
243
244                 internal void Write (MonoSymbolFile file, BinaryWriter bw)
245                 {
246                         file.WriteString (bw, Name);
247                         bw.Write ((int) Attributes);
248                         bw.Write ((int) Signature.Length);
249                         bw.Write (Signature);
250                         bw.Write (BlockIndex);
251                 }
252
253                 public override string ToString ()
254                 {
255                         return String.Format ("[LocalVariable {0}:{1}]", Name, Attributes);
256                 }
257         }
258
259         public class SourceFileEntry
260         {
261                 #region This is actually written to the symbol file
262                 public readonly int Index;
263                 int Count;
264                 int NamespaceCount;
265                 int NameOffset;
266                 int MethodOffset;
267                 int NamespaceTableOffset;
268                 #endregion
269
270                 MonoSymbolFile file;
271                 string file_name;
272                 ArrayList methods;
273                 ArrayList namespaces;
274                 bool creating;
275
276                 public static int Size {
277                         get { return 24; }
278                 }
279
280                 internal SourceFileEntry (MonoSymbolFile file, string file_name)
281                 {
282                         this.file = file;
283                         this.file_name = file_name;
284                         this.Index = file.AddSource (this);
285
286                         creating = true;
287                         methods = new ArrayList ();
288                         namespaces = new ArrayList ();
289                 }
290
291                 public void DefineMethod (MethodBase method, int token, LocalVariableEntry[] locals,
292                                           LineNumberEntry[] lines, LexicalBlockEntry[] blocks,
293                                           int start, int end, int namespace_id)
294                 {
295                         if (!creating)
296                                 throw new InvalidOperationException ();
297
298                         MethodEntry entry = new MethodEntry (
299                                 file, this, method, token, locals, lines, blocks, start, end, namespace_id);
300
301                         methods.Add (entry);
302                         file.AddMethod (entry);
303                 }
304
305                 public int DefineNamespace (string name, string[] using_clauses, int parent)
306                 {
307                         if (!creating)
308                                 throw new InvalidOperationException ();
309
310                         int index = file.GetNextNamespaceIndex ();
311                         NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
312                         namespaces.Add (ns);
313                         return index;
314                 }
315
316                 internal void WriteData (BinaryWriter bw)
317                 {
318                         NameOffset = (int) bw.BaseStream.Position;
319                         file.WriteString (bw, file_name);
320
321                         ArrayList list = new ArrayList ();
322                         foreach (MethodEntry entry in methods)
323                                 list.Add (entry.Write (file, bw));
324                         list.Sort ();
325                         Count = list.Count;
326
327                         MethodOffset = (int) bw.BaseStream.Position;
328                         foreach (MethodSourceEntry method in list)
329                                 method.Write (bw);
330
331                         NamespaceCount = namespaces.Count;
332                         NamespaceTableOffset = (int) bw.BaseStream.Position;
333                         foreach (NamespaceEntry ns in namespaces)
334                                 ns.Write (file, bw);
335                 }
336
337                 internal void Write (BinaryWriter bw)
338                 {
339                         bw.Write (Index);
340                         bw.Write (Count);
341                         bw.Write (NamespaceCount);
342                         bw.Write (NameOffset);
343                         bw.Write (MethodOffset);
344                         bw.Write (NamespaceTableOffset);
345                 }
346
347                 internal SourceFileEntry (MonoSymbolFile file, BinaryReader reader)
348                 {
349                         this.file = file;
350
351                         Index = reader.ReadInt32 ();
352                         Count = reader.ReadInt32 ();
353                         NamespaceCount = reader.ReadInt32 ();
354                         NameOffset = reader.ReadInt32 ();
355                         MethodOffset = reader.ReadInt32 ();
356                         NamespaceTableOffset = reader.ReadInt32 ();
357
358                         file_name = file.ReadString (NameOffset);
359                 }
360
361                 public string FileName {
362                         get { return file_name; }
363                 }
364
365                 public MethodSourceEntry[] Methods {
366                         get {
367                                 if (creating)
368                                         throw new InvalidOperationException ();
369
370                                 BinaryReader reader = file.BinaryReader;
371                                 int old_pos = (int) reader.BaseStream.Position;
372
373                                 reader.BaseStream.Position = MethodOffset;
374                                 ArrayList list = new ArrayList ();
375                                 for (int i = 0; i < Count; i ++)
376                                         list.Add (new MethodSourceEntry (reader));
377                                 reader.BaseStream.Position = old_pos;
378
379                                 MethodSourceEntry[] retval = new MethodSourceEntry [Count];
380                                 list.CopyTo (retval, 0);
381                                 return retval;
382                         }
383                 }
384
385                 public override string ToString ()
386                 {
387                         return String.Format ("SourceFileEntry ({0}:{1}:{2})",
388                                               Index, file_name, Count);
389                 }
390         }
391
392         public struct MethodSourceEntry : IComparable
393         {
394                 #region This is actually written to the symbol file
395                 public readonly int Index;
396                 public readonly int FileOffset;
397                 public readonly int StartRow;
398                 public readonly int EndRow;
399                 #endregion
400
401                 public MethodSourceEntry (int index, int file_offset, int start, int end)
402                 {
403                         this.Index = index;
404                         this.FileOffset = file_offset;
405                         this.StartRow = start;
406                         this.EndRow = end;
407                 }
408
409                 internal MethodSourceEntry (BinaryReader reader)
410                 {
411                         Index = reader.ReadInt32 ();
412                         FileOffset = reader.ReadInt32 ();
413                         StartRow = reader.ReadInt32 ();
414                         EndRow = reader.ReadInt32 ();
415                 }
416
417                 public static int Size {
418                         get { return 16; }
419                 }
420
421                 internal void Write (BinaryWriter bw)
422                 {
423                         bw.Write (Index);
424                         bw.Write (FileOffset);
425                         bw.Write (StartRow);
426                         bw.Write (EndRow);
427                 }
428
429                 public int CompareTo (object obj)
430                 {
431                         MethodSourceEntry method = (MethodSourceEntry) obj;
432
433                         if (method.StartRow < StartRow)
434                                 return -1;
435                         else if (method.StartRow > StartRow)
436                                 return 1;
437                         else
438                                 return 0;
439                 }
440
441                 public override string ToString ()
442                 {
443                         return String.Format ("MethodSourceEntry ({0}:{1}:{2}:{3})",
444                                               Index, FileOffset, StartRow, EndRow);
445                 }
446         }
447
448         public struct MethodIndexEntry
449         {
450                 #region This is actually written to the symbol file
451                 public readonly int FileOffset;
452                 public readonly int Token;
453                 #endregion
454
455                 public static int Size {
456                         get { return 8; }
457                 }
458
459                 public MethodIndexEntry (int offset, int token)
460                 {
461                         this.FileOffset = offset;
462                         this.Token = token;
463                 }
464
465                 internal MethodIndexEntry (BinaryReader reader)
466                 {
467                         FileOffset = reader.ReadInt32 ();
468                         Token = reader.ReadInt32 ();
469                 }
470
471                 internal void Write (BinaryWriter bw)
472                 {
473                         bw.Write (FileOffset);
474                         bw.Write (Token);
475                 }
476
477                 public override string ToString ()
478                 {
479                         return String.Format ("MethodIndexEntry ({0}:{1:x})",
480                                               FileOffset, Token);
481                 }
482         }
483
484         public class MethodEntry
485         {
486                 #region This is actually written to the symbol file
487                 public readonly int SourceFileIndex;
488                 public readonly int Token;
489                 public readonly int StartRow;
490                 public readonly int EndRow;
491                 public readonly int ClassTypeIndex;
492                 public readonly int NumParameters;
493                 public readonly int NumLocals;
494                 public readonly int NumLineNumbers;
495                 public readonly int NamespaceID;
496                 public readonly bool LocalNamesAmbiguous;
497
498                 int NameOffset;
499                 int TypeIndexTableOffset;
500                 int LocalVariableTableOffset;
501                 int LineNumberTableOffset;
502                 int NumLexicalBlocks;
503                 int LexicalBlockTableOffset;
504                 #endregion
505
506                 int file_offset;
507                 string name;
508
509                 public readonly int Index;
510                 public readonly SourceFileEntry SourceFile;
511                 public readonly LineNumberEntry[] LineNumbers;
512                 public readonly int[] ParamTypeIndices;
513                 public readonly int[] LocalTypeIndices;
514                 public readonly LocalVariableEntry[] Locals;
515                 public readonly Type[] LocalTypes;
516                 public readonly LexicalBlockEntry[] LexicalBlocks;
517
518                 public readonly MonoSymbolFile SymbolFile;
519
520                 public static int Size {
521                         get { return 52; }
522                 }
523
524                 public string Name {
525                         get { return name; }
526                 }
527
528                 public MethodBase MethodBase {
529                         get { return MonoDebuggerSupport.GetMethod (SymbolFile.Assembly, Token); }
530                 }
531
532                 internal MethodEntry (MonoSymbolFile file, BinaryReader reader, int index)
533                 {
534                         this.SymbolFile = file;
535                         this.Index = index;
536                         SourceFileIndex = reader.ReadInt32 ();
537                         Token = reader.ReadInt32 ();
538                         StartRow = reader.ReadInt32 ();
539                         EndRow = reader.ReadInt32 ();
540                         ClassTypeIndex = reader.ReadInt32 ();
541                         NumParameters = reader.ReadInt32 ();
542                         NumLocals = reader.ReadInt32 ();
543                         NumLineNumbers = reader.ReadInt32 ();
544                         NameOffset = reader.ReadInt32 ();
545                         TypeIndexTableOffset = reader.ReadInt32 ();
546                         LocalVariableTableOffset = reader.ReadInt32 ();
547                         LineNumberTableOffset = reader.ReadInt32 ();
548                         NumLexicalBlocks = reader.ReadInt32 ();
549                         LexicalBlockTableOffset = reader.ReadInt32 ();
550                         NamespaceID = reader.ReadInt32 ();
551                         LocalNamesAmbiguous = reader.ReadInt32 () != 0;
552
553                         name = file.ReadString (NameOffset);
554
555                         SourceFile = file.GetSourceFile (SourceFileIndex);
556
557                         if (LineNumberTableOffset != 0) {
558                                 long old_pos = reader.BaseStream.Position;
559                                 reader.BaseStream.Position = LineNumberTableOffset;
560
561                                 LineNumbers = new LineNumberEntry [NumLineNumbers];
562
563                                 for (int i = 0; i < NumLineNumbers; i++)
564                                         LineNumbers [i] = new LineNumberEntry (reader);
565
566                                 reader.BaseStream.Position = old_pos;
567                         }
568
569                         if (LocalVariableTableOffset != 0) {
570                                 long old_pos = reader.BaseStream.Position;
571                                 reader.BaseStream.Position = LocalVariableTableOffset;
572
573                                 Locals = new LocalVariableEntry [NumLocals];
574                                 LocalTypes = new Type [NumLocals];
575
576                                 Assembly ass = file.Assembly;
577
578                                 for (int i = 0; i < NumLocals; i++) {
579                                         Locals [i] = new LocalVariableEntry (reader);
580                                         LocalTypes [i] = MonoDebuggerSupport.GetLocalTypeFromSignature (
581                                                 ass, Locals [i].Signature);
582                                 }
583
584                                 reader.BaseStream.Position = old_pos;
585                         }
586
587                         if (TypeIndexTableOffset != 0) {
588                                 long old_pos = reader.BaseStream.Position;
589                                 reader.BaseStream.Position = TypeIndexTableOffset;
590
591                                 ParamTypeIndices = new int [NumParameters];
592                                 LocalTypeIndices = new int [NumLocals];
593
594                                 for (int i = 0; i < NumParameters; i++)
595                                         ParamTypeIndices [i] = reader.ReadInt32 ();
596                                 for (int i = 0; i < NumLocals; i++)
597                                         LocalTypeIndices [i] = reader.ReadInt32 ();
598
599                                 reader.BaseStream.Position = old_pos;
600                         }
601
602                         if (LexicalBlockTableOffset != 0) {
603                                 long old_pos = reader.BaseStream.Position;
604                                 reader.BaseStream.Position = LexicalBlockTableOffset;
605
606                                 LexicalBlocks = new LexicalBlockEntry [NumLexicalBlocks];
607                                 for (int i = 0; i < NumLexicalBlocks; i++)
608                                         LexicalBlocks [i] = new LexicalBlockEntry (i, reader);
609
610                                 reader.BaseStream.Position = old_pos;
611                         }
612                 }
613
614                 internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, MethodBase method,
615                                       int token, LocalVariableEntry[] locals, LineNumberEntry[] lines,
616                                       LexicalBlockEntry[] blocks, int start_row, int end_row,
617                                       int namespace_id)
618                 {
619                         this.SymbolFile = file;
620                         Index = file.GetNextMethodIndex ();
621
622                         Token = token;
623                         SourceFileIndex = source.Index;
624                         SourceFile = source;
625                         StartRow = start_row;
626                         EndRow = end_row;
627                         NamespaceID = namespace_id;
628                         LexicalBlocks = blocks;
629                         NumLexicalBlocks = LexicalBlocks.Length;
630
631                         LineNumbers = BuildLineNumberTable (lines);
632                         NumLineNumbers = LineNumbers.Length;
633
634                         ParameterInfo[] parameters = method.GetParameters ();
635                         if (parameters == null)
636                                 parameters = new ParameterInfo [0];
637                         
638                         name = method.Name;
639                         
640                         NumParameters = parameters.Length;
641                         ParamTypeIndices = new int [NumParameters];
642                         for (int i = 0; i < NumParameters; i++)
643                                 ParamTypeIndices [i] = file.DefineType (parameters [i].ParameterType);
644
645                         NumLocals = locals.Length;
646                         Locals = locals;
647
648                         if (NumLocals <= 32) {
649                                 // Most of the time, the O(n^2) factor is actually
650                                 // less than the cost of allocating the hash table,
651                                 // 32 is a rough number obtained through some testing.
652                                 
653                                 for (int i = 0; i < NumLocals; i ++) {
654                                         string nm = locals [i].Name;
655                                         
656                                         for (int j = i + 1; j < NumLocals; j ++) {
657                                                 if (locals [j].Name == nm) {
658                                                         LocalNamesAmbiguous = true;
659                                                         goto locals_check_done;
660                                                 }
661                                         }
662                                 }
663                         locals_check_done :
664                                 ;
665                         } else {
666                                 Hashtable local_names = new Hashtable ();
667                                 foreach (LocalVariableEntry local in locals) {
668                                         if (local_names.Contains (local.Name)) {
669                                                 LocalNamesAmbiguous = true;
670                                                 break;
671                                         }
672                                         local_names.Add (local.Name, local);
673                                 }
674                         }
675
676                         LocalTypeIndices = new int [NumLocals];
677                         for (int i = 0; i < NumLocals; i++)
678                                 LocalTypeIndices [i] = file.GetNextTypeIndex ();
679
680                         ClassTypeIndex = file.DefineType (method.ReflectedType);
681                 }
682
683                 // BuildLineNumberTable() eliminates duplicate line numbers and ensures
684                 // we aren't going "backwards" since this would counfuse the runtime's
685                 // debugging code (and the debugger).
686                 //
687                 // In the line number table, the "offset" field most be strictly
688                 // monotonic increasing; that is, the next entry must not have an offset
689                 // which is equal to or less than the current one.
690                 //
691                 // The most common case is that our input (ie. the line number table as
692                 // we get it from mcs) contains several entries with the same offset
693                 // (and different line numbers) - but it may also happen that the offset
694                 // is decreasing (this can be considered as an exception, such lines will
695                 // simply be discarded).
696                 LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
697                 {
698                         ArrayList list = new ArrayList ();
699                         int last_offset = -1;
700                         int last_row = -1;
701
702                         for (int i = 0; i < line_numbers.Length; i++) {
703                                 LineNumberEntry line = (LineNumberEntry) line_numbers [i];
704
705                                 if (line.Offset > last_offset) {
706                                         if (last_row >= 0)
707                                                 list.Add (new LineNumberEntry (last_row, last_offset));
708                                         last_row = line.Row;
709                                         last_offset = line.Offset;
710                                 } else if (line.Row > last_row) {
711                                         last_row = line.Row;
712                                 }
713                         }
714
715                         if (last_row >= 0)
716                                 list.Add (new LineNumberEntry (last_row, last_offset));
717
718                         LineNumberEntry[] retval = new LineNumberEntry [list.Count];
719                         list.CopyTo (retval, 0);
720                         return retval;
721                 }
722
723                 internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
724                 {
725                         NameOffset = (int) bw.BaseStream.Position;
726                         file.WriteString (bw, name);
727
728                         TypeIndexTableOffset = (int) bw.BaseStream.Position;
729
730                         for (int i = 0; i < NumParameters; i++)
731                                 bw.Write (ParamTypeIndices [i]);
732                         for (int i = 0; i < NumLocals; i++)
733                                 bw.Write (LocalTypeIndices [i]);
734
735                         LocalVariableTableOffset = (int) bw.BaseStream.Position;
736                         for (int i = 0; i < NumLocals; i++)
737                                 Locals [i].Write (file, bw);
738                         file.LocalCount += NumLocals;
739
740                         LineNumberTableOffset = (int) bw.BaseStream.Position;
741                         for (int i = 0; i < NumLineNumbers; i++)
742                                 LineNumbers [i].Write (bw);
743                         file.LineNumberCount += NumLineNumbers;
744
745                         LexicalBlockTableOffset = (int) bw.BaseStream.Position;
746                         for (int i = 0; i < NumLexicalBlocks; i++)
747                                 LexicalBlocks [i].Write (bw);
748                         file_offset = (int) bw.BaseStream.Position;
749
750                         bw.Write (SourceFileIndex);
751                         bw.Write (Token);
752                         bw.Write (StartRow);
753                         bw.Write (EndRow);
754                         bw.Write (ClassTypeIndex);
755                         bw.Write (NumParameters);
756                         bw.Write (NumLocals);
757                         bw.Write (NumLineNumbers);
758                         bw.Write (NameOffset);
759                         bw.Write (TypeIndexTableOffset);
760                         bw.Write (LocalVariableTableOffset);
761                         bw.Write (LineNumberTableOffset);
762                         bw.Write (NumLexicalBlocks);
763                         bw.Write (LexicalBlockTableOffset);
764                         bw.Write (NamespaceID);
765                         bw.Write (LocalNamesAmbiguous ? 1 : 0);
766
767                         return new MethodSourceEntry (Index, file_offset, StartRow, EndRow);
768                 }
769
770                 internal void WriteIndex (BinaryWriter bw)
771                 {
772                         new MethodIndexEntry (file_offset, Token).Write (bw);
773                 }
774
775                 public override string ToString ()
776                 {
777                         return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {6}:{7}:{8}:{9} - {5}]",
778                                               Index, Token, SourceFileIndex, StartRow, EndRow,
779                                               SourceFile, ClassTypeIndex, NumParameters,
780                                               NumLocals, NumLineNumbers);
781                 }
782         }
783
784         public struct NamespaceEntry
785         {
786                 #region This is actually written to the symbol file
787                 public readonly string Name;
788                 public readonly int Index;
789                 public readonly int Parent;
790                 public readonly string[] UsingClauses;
791                 #endregion
792
793                 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
794                 {
795                         this.Name = name;
796                         this.Index = index;
797                         this.Parent = parent;
798                         this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
799                 }
800
801                 internal void Write (MonoSymbolFile file, BinaryWriter bw)
802                 {
803                         file.WriteString (bw, Name);
804                         bw.Write (Index);
805                         bw.Write (Parent);
806                         bw.Write (UsingClauses.Length);
807                         foreach (string uc in UsingClauses)
808                                 file.WriteString (bw, uc);
809                 }
810
811                 public override string ToString ()
812                 {
813                         return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);
814                 }
815         }
816 }