2004-01-15 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolTable.cs
1 //
2 // System.Diagnostics.SymbolStore/MonoSymbolTable.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@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 = 35;
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 FullNameOffset;
453                 public readonly int Token;
454                 #endregion
455
456                 public static int Size {
457                         get { return 12; }
458                 }
459
460                 public MethodIndexEntry (int offset, int name_offset, int token)
461                 {
462                         this.FileOffset = offset;
463                         this.FullNameOffset = name_offset;
464                         this.Token = token;
465                 }
466
467                 internal MethodIndexEntry (BinaryReader reader)
468                 {
469                         FileOffset = reader.ReadInt32 ();
470                         FullNameOffset = reader.ReadInt32 ();
471                         Token = reader.ReadInt32 ();
472                 }
473
474                 internal void Write (BinaryWriter bw)
475                 {
476                         bw.Write (FileOffset);
477                         bw.Write (FullNameOffset);
478                         bw.Write (Token);
479                 }
480
481                 public override string ToString ()
482                 {
483                         return String.Format ("MethodIndexEntry ({0}:{1}:{2:x})",
484                                               FileOffset, FullNameOffset, Token);
485                 }
486         }
487
488         public class MethodEntry
489         {
490                 #region This is actually written to the symbol file
491                 public readonly int SourceFileIndex;
492                 public readonly int Token;
493                 public readonly int StartRow;
494                 public readonly int EndRow;
495                 public readonly int ClassTypeIndex;
496                 public readonly int NumParameters;
497                 public readonly int NumLocals;
498                 public readonly int NumLineNumbers;
499                 public readonly int NamespaceID;
500                 public readonly bool LocalNamesAmbiguous;
501
502                 int NameOffset;
503                 int FullNameOffset;
504                 int TypeIndexTableOffset;
505                 int LocalVariableTableOffset;
506                 int LineNumberTableOffset;
507                 int NumLexicalBlocks;
508                 int LexicalBlockTableOffset;
509                 #endregion
510
511                 int file_offset;
512                 string name;
513                 string full_name;
514
515                 public readonly int Index;
516                 public readonly SourceFileEntry SourceFile;
517                 public readonly LineNumberEntry[] LineNumbers;
518                 public readonly int[] ParamTypeIndices;
519                 public readonly int[] LocalTypeIndices;
520                 public readonly LocalVariableEntry[] Locals;
521                 public readonly Type[] LocalTypes;
522                 public readonly LexicalBlockEntry[] LexicalBlocks;
523
524                 public readonly MonoSymbolFile SymbolFile;
525
526                 public static int Size {
527                         get { return 52; }
528                 }
529
530                 public string Name {
531                         get { return name; }
532                 }
533
534                 public string FullName {
535                         get { return full_name; }
536                 }
537
538                 public MethodBase MethodBase {
539                         get { return MonoDebuggerSupport.GetMethod (SymbolFile.Assembly, Token); }
540                 }
541
542                 internal MethodEntry (MonoSymbolFile file, BinaryReader reader, int index)
543                 {
544                         this.SymbolFile = file;
545                         this.Index = index;
546                         SourceFileIndex = reader.ReadInt32 ();
547                         Token = reader.ReadInt32 ();
548                         StartRow = reader.ReadInt32 ();
549                         EndRow = reader.ReadInt32 ();
550                         ClassTypeIndex = reader.ReadInt32 ();
551                         NumParameters = reader.ReadInt32 ();
552                         NumLocals = reader.ReadInt32 ();
553                         NumLineNumbers = reader.ReadInt32 ();
554                         NameOffset = reader.ReadInt32 ();
555                         FullNameOffset = reader.ReadInt32 ();
556                         TypeIndexTableOffset = reader.ReadInt32 ();
557                         LocalVariableTableOffset = reader.ReadInt32 ();
558                         LineNumberTableOffset = reader.ReadInt32 ();
559                         NumLexicalBlocks = reader.ReadInt32 ();
560                         LexicalBlockTableOffset = reader.ReadInt32 ();
561                         NamespaceID = reader.ReadInt32 ();
562                         LocalNamesAmbiguous = reader.ReadInt32 () != 0;
563
564                         name = file.ReadString (NameOffset);
565                         full_name = file.ReadString (FullNameOffset);
566
567                         SourceFile = file.GetSourceFile (SourceFileIndex);
568
569                         if (LineNumberTableOffset != 0) {
570                                 long old_pos = reader.BaseStream.Position;
571                                 reader.BaseStream.Position = LineNumberTableOffset;
572
573                                 LineNumbers = new LineNumberEntry [NumLineNumbers];
574
575                                 for (int i = 0; i < NumLineNumbers; i++)
576                                         LineNumbers [i] = new LineNumberEntry (reader);
577
578                                 reader.BaseStream.Position = old_pos;
579                         }
580
581                         if (LocalVariableTableOffset != 0) {
582                                 long old_pos = reader.BaseStream.Position;
583                                 reader.BaseStream.Position = LocalVariableTableOffset;
584
585                                 Locals = new LocalVariableEntry [NumLocals];
586                                 LocalTypes = new Type [NumLocals];
587
588                                 Assembly ass = file.Assembly;
589
590                                 for (int i = 0; i < NumLocals; i++) {
591                                         Locals [i] = new LocalVariableEntry (reader);
592                                         LocalTypes [i] = MonoDebuggerSupport.GetLocalTypeFromSignature (
593                                                 ass, Locals [i].Signature);
594                                 }
595
596                                 reader.BaseStream.Position = old_pos;
597                         }
598
599                         if (TypeIndexTableOffset != 0) {
600                                 long old_pos = reader.BaseStream.Position;
601                                 reader.BaseStream.Position = TypeIndexTableOffset;
602
603                                 ParamTypeIndices = new int [NumParameters];
604                                 LocalTypeIndices = new int [NumLocals];
605
606                                 for (int i = 0; i < NumParameters; i++)
607                                         ParamTypeIndices [i] = reader.ReadInt32 ();
608                                 for (int i = 0; i < NumLocals; i++)
609                                         LocalTypeIndices [i] = reader.ReadInt32 ();
610
611                                 reader.BaseStream.Position = old_pos;
612                         }
613
614                         if (LexicalBlockTableOffset != 0) {
615                                 long old_pos = reader.BaseStream.Position;
616                                 reader.BaseStream.Position = LexicalBlockTableOffset;
617
618                                 LexicalBlocks = new LexicalBlockEntry [NumLexicalBlocks];
619                                 for (int i = 0; i < NumLexicalBlocks; i++)
620                                         LexicalBlocks [i] = new LexicalBlockEntry (i, reader);
621
622                                 reader.BaseStream.Position = old_pos;
623                         }
624                 }
625
626                 internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, MethodBase method,
627                                       int token, LocalVariableEntry[] locals, LineNumberEntry[] lines,
628                                       LexicalBlockEntry[] blocks, int start_row, int end_row,
629                                       int namespace_id)
630                 {
631                         this.SymbolFile = file;
632                         Index = file.GetNextMethodIndex ();
633
634                         Token = token;
635                         SourceFileIndex = source.Index;
636                         SourceFile = source;
637                         StartRow = start_row;
638                         EndRow = end_row;
639                         NamespaceID = namespace_id;
640                         LexicalBlocks = blocks;
641                         NumLexicalBlocks = LexicalBlocks.Length;
642
643                         LineNumbers = BuildLineNumberTable (lines);
644                         NumLineNumbers = LineNumbers.Length;
645
646                         ParameterInfo[] parameters = method.GetParameters ();
647                         if (parameters == null)
648                                 parameters = new ParameterInfo [0];
649                         
650                         if (parameters.Length == 0)
651                                 full_name = method.DeclaringType.FullName + "." + method.Name + "()";
652                         else if (parameters.Length == 1)
653                                 full_name = method.DeclaringType.FullName + "." + method.Name + "(" + parameters [0].ParameterType.FullName +  ")";
654                         else if (parameters.Length == 2)
655                                 full_name = method.DeclaringType.FullName + "." + method.Name + "(" + parameters [0].ParameterType.FullName + "," + parameters [1].ParameterType.FullName + ")";
656                         else {
657                                 StringBuilder sb = new StringBuilder ();
658                                 sb.Append (method.DeclaringType.FullName);
659                                 sb.Append (".");
660                                 sb.Append (method.Name);
661                                 sb.Append ("(");
662                                 for (int i = 0; i < parameters.Length; i++) {
663                                         if (i > 0)
664                                                 sb.Append (",");
665                                         sb.Append (parameters [i].ParameterType.FullName);
666                                 }
667                                 sb.Append (")");
668                                 full_name = sb.ToString ();
669                         }
670
671                         name = method.Name;
672                         
673                         NumParameters = parameters.Length;
674                         ParamTypeIndices = new int [NumParameters];
675                         for (int i = 0; i < NumParameters; i++)
676                                 ParamTypeIndices [i] = file.DefineType (parameters [i].ParameterType);
677
678                         NumLocals = locals.Length;
679                         Locals = locals;
680
681                         if (NumLocals <= 32) {
682                                 // Most of the time, the O(n^2) factor is actually
683                                 // less than the cost of allocating the hash table,
684                                 // 32 is a rough number obtained through some testing.
685                                 
686                                 for (int i = 0; i < NumLocals; i ++) {
687                                         string nm = locals [i].Name;
688                                         
689                                         for (int j = i + 1; j < NumLocals; j ++) {
690                                                 if (locals [j].Name == nm) {
691                                                         LocalNamesAmbiguous = true;
692                                                         goto locals_check_done;
693                                                 }
694                                         }
695                                 }
696                         locals_check_done :
697                                 ;
698                         } else {
699                                 Hashtable local_names = new Hashtable ();
700                                 foreach (LocalVariableEntry local in locals) {
701                                         if (local_names.Contains (local.Name)) {
702                                                 LocalNamesAmbiguous = true;
703                                                 break;
704                                         }
705                                         local_names.Add (local.Name, local);
706                                 }
707                         }
708
709                         LocalTypeIndices = new int [NumLocals];
710                         for (int i = 0; i < NumLocals; i++)
711                                 LocalTypeIndices [i] = file.GetNextTypeIndex ();
712
713                         ClassTypeIndex = file.DefineType (method.ReflectedType);
714                 }
715
716                 // BuildLineNumberTable() eliminates duplicate line numbers and ensures
717                 // we aren't going "backwards" since this would counfuse the runtime's
718                 // debugging code (and the debugger).
719                 //
720                 // In the line number table, the "offset" field most be strictly
721                 // monotonic increasing; that is, the next entry must not have an offset
722                 // which is equal to or less than the current one.
723                 //
724                 // The most common case is that our input (ie. the line number table as
725                 // we get it from mcs) contains several entries with the same offset
726                 // (and different line numbers) - but it may also happen that the offset
727                 // is decreasing (this can be considered as an exception, such lines will
728                 // simply be discarded).
729                 LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
730                 {
731                         ArrayList list = new ArrayList ();
732                         int last_offset = -1;
733                         int last_row = -1;
734
735                         for (int i = 0; i < line_numbers.Length; i++) {
736                                 LineNumberEntry line = (LineNumberEntry) line_numbers [i];
737
738                                 if (line.Offset > last_offset) {
739                                         if (last_row >= 0)
740                                                 list.Add (new LineNumberEntry (last_row, last_offset));
741                                         last_row = line.Row;
742                                         last_offset = line.Offset;
743                                 } else if (line.Row > last_row) {
744                                         last_row = line.Row;
745                                 }
746                         }
747
748                         if (last_row >= 0)
749                                 list.Add (new LineNumberEntry (last_row, last_offset));
750
751                         LineNumberEntry[] retval = new LineNumberEntry [list.Count];
752                         list.CopyTo (retval, 0);
753                         return retval;
754                 }
755
756                 internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
757                 {
758                         NameOffset = (int) bw.BaseStream.Position;
759                         file.WriteString (bw, name);
760
761                         FullNameOffset = (int) bw.BaseStream.Position;
762                         file.WriteString (bw, full_name);
763
764                         TypeIndexTableOffset = (int) bw.BaseStream.Position;
765
766                         for (int i = 0; i < NumParameters; i++)
767                                 bw.Write (ParamTypeIndices [i]);
768                         for (int i = 0; i < NumLocals; i++)
769                                 bw.Write (LocalTypeIndices [i]);
770
771                         LocalVariableTableOffset = (int) bw.BaseStream.Position;
772                         for (int i = 0; i < NumLocals; i++)
773                                 Locals [i].Write (file, bw);
774                         file.LocalCount += NumLocals;
775
776                         LineNumberTableOffset = (int) bw.BaseStream.Position;
777                         for (int i = 0; i < NumLineNumbers; i++)
778                                 LineNumbers [i].Write (bw);
779                         file.LineNumberCount += NumLineNumbers;
780
781                         LexicalBlockTableOffset = (int) bw.BaseStream.Position;
782                         for (int i = 0; i < NumLexicalBlocks; i++)
783                                 LexicalBlocks [i].Write (bw);
784                         file_offset = (int) bw.BaseStream.Position;
785
786                         bw.Write (SourceFileIndex);
787                         bw.Write (Token);
788                         bw.Write (StartRow);
789                         bw.Write (EndRow);
790                         bw.Write (ClassTypeIndex);
791                         bw.Write (NumParameters);
792                         bw.Write (NumLocals);
793                         bw.Write (NumLineNumbers);
794                         bw.Write (NameOffset);
795                         bw.Write (FullNameOffset);
796                         bw.Write (TypeIndexTableOffset);
797                         bw.Write (LocalVariableTableOffset);
798                         bw.Write (LineNumberTableOffset);
799                         bw.Write (NumLexicalBlocks);
800                         bw.Write (LexicalBlockTableOffset);
801                         bw.Write (NamespaceID);
802                         bw.Write (LocalNamesAmbiguous ? 1 : 0);
803
804                         return new MethodSourceEntry (Index, file_offset, StartRow, EndRow);
805                 }
806
807                 internal void WriteIndex (BinaryWriter bw)
808                 {
809                         new MethodIndexEntry (file_offset, FullNameOffset, Token).Write (bw);
810                 }
811
812                 public override string ToString ()
813                 {
814                         return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {7}:{8}:{9}:{10} - {5} - {6}]",
815                                               Index, Token, SourceFileIndex, StartRow, EndRow,
816                                               SourceFile, FullName, ClassTypeIndex, NumParameters,
817                                               NumLocals, NumLineNumbers);
818                 }
819         }
820
821         public struct NamespaceEntry
822         {
823                 #region This is actually written to the symbol file
824                 public readonly string Name;
825                 public readonly int Index;
826                 public readonly int Parent;
827                 public readonly string[] UsingClauses;
828                 #endregion
829
830                 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
831                 {
832                         this.Name = name;
833                         this.Index = index;
834                         this.Parent = parent;
835                         this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
836                 }
837
838                 internal void Write (MonoSymbolFile file, BinaryWriter bw)
839                 {
840                         file.WriteString (bw, Name);
841                         bw.Write (Index);
842                         bw.Write (Parent);
843                         bw.Write (UsingClauses.Length);
844                         foreach (string uc in UsingClauses)
845                                 file.WriteString (bw, uc);
846                 }
847
848                 public override string ToString ()
849                 {
850                         return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);
851                 }
852         }
853 }