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