Merge pull request #260 from pcc/topmost
[mono.git] / mcs / class / Mono.CompilerServices.SymbolWriter / MonoSymbolTable.cs
1 //
2 // Mono.CSharp.Debugger/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.Security.Cryptography;
33 using System.Collections.Generic;
34 using System.Text;
35 using System.IO;
36
37 //
38 // Parts which are actually written into the symbol file are marked with
39 //
40 //         #region This is actually written to the symbol file
41 //         #endregion
42 //
43 // Please do not modify these regions without previously talking to me.
44 //
45 // All changes to the file format must be synchronized in several places:
46 //
47 // a) The fields in these regions (and their order) must match the actual
48 //    contents of the symbol file.
49 //
50 //    This helps people to understand the symbol file format without reading
51 //    too much source code, ie. you look at the appropriate region and then
52 //    you know what's actually in the file.
53 //
54 //    It is also required to help me enforce b).
55 //
56 // b) The regions must be kept in sync with the unmanaged code in
57 //    mono/metadata/debug-mono-symfile.h
58 //
59 // When making changes to the file format, you must also increase two version
60 // numbers:
61 //
62 // i)  OffsetTable.Version in this file.
63 // ii) MONO_SYMBOL_FILE_VERSION in mono/metadata/debug-mono-symfile.h
64 //
65 // After doing so, recompile everything, including the debugger.  Symbol files
66 // with different versions are incompatible to each other and the debugger and
67 // the runtime enfore this, so you need to recompile all your assemblies after
68 // changing the file format.
69 //
70
71 namespace Mono.CompilerServices.SymbolWriter
72 {
73         public class OffsetTable
74         {
75                 public const int  MajorVersion = 50;
76                 public const int  MinorVersion = 0;
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 CompileUnitCount;
84                 public int CompileUnitTableOffset;
85                 public int CompileUnitTableSize;
86                 public int SourceCount;
87                 public int SourceTableOffset;
88                 public int SourceTableSize;
89                 public int MethodCount;
90                 public int MethodTableOffset;
91                 public int MethodTableSize;
92                 public int TypeCount;
93                 public int AnonymousScopeCount;
94                 public int AnonymousScopeTableOffset;
95                 public int AnonymousScopeTableSize;
96
97                 [Flags]
98                 public enum Flags
99                 {
100                         IsAspxSource            = 1,
101                         WindowsFileNames        = 2
102                 }
103
104                 public Flags FileFlags;
105
106                 public int LineNumberTable_LineBase = LineNumberTable.Default_LineBase;
107                 public int LineNumberTable_LineRange = LineNumberTable.Default_LineRange;
108                 public int LineNumberTable_OpcodeBase = LineNumberTable.Default_OpcodeBase;
109                 #endregion
110
111                 internal OffsetTable ()
112                 {
113                         int platform = (int) Environment.OSVersion.Platform;
114                         if ((platform != 4) && (platform != 128))
115                                 FileFlags |= Flags.WindowsFileNames;
116                 }
117
118                 internal OffsetTable (BinaryReader reader, int major_version, int minor_version)
119                 {
120                         TotalFileSize = reader.ReadInt32 ();
121                         DataSectionOffset = reader.ReadInt32 ();
122                         DataSectionSize = reader.ReadInt32 ();
123                         CompileUnitCount = reader.ReadInt32 ();
124                         CompileUnitTableOffset = reader.ReadInt32 ();
125                         CompileUnitTableSize = reader.ReadInt32 ();
126                         SourceCount = reader.ReadInt32 ();
127                         SourceTableOffset = reader.ReadInt32 ();
128                         SourceTableSize = reader.ReadInt32 ();
129                         MethodCount = reader.ReadInt32 ();
130                         MethodTableOffset = reader.ReadInt32 ();
131                         MethodTableSize = reader.ReadInt32 ();
132                         TypeCount = reader.ReadInt32 ();
133
134                         AnonymousScopeCount = reader.ReadInt32 ();
135                         AnonymousScopeTableOffset = reader.ReadInt32 ();
136                         AnonymousScopeTableSize = reader.ReadInt32 ();
137
138                         LineNumberTable_LineBase = reader.ReadInt32 ();
139                         LineNumberTable_LineRange = reader.ReadInt32 ();
140                         LineNumberTable_OpcodeBase = reader.ReadInt32 ();
141
142                         FileFlags = (Flags) reader.ReadInt32 ();
143                 }
144
145                 internal void Write (BinaryWriter bw, int major_version, int minor_version)
146                 {
147                         bw.Write (TotalFileSize);
148                         bw.Write (DataSectionOffset);
149                         bw.Write (DataSectionSize);
150                         bw.Write (CompileUnitCount);
151                         bw.Write (CompileUnitTableOffset);
152                         bw.Write (CompileUnitTableSize);
153                         bw.Write (SourceCount);
154                         bw.Write (SourceTableOffset);
155                         bw.Write (SourceTableSize);
156                         bw.Write (MethodCount);
157                         bw.Write (MethodTableOffset);
158                         bw.Write (MethodTableSize);
159                         bw.Write (TypeCount);
160
161                         bw.Write (AnonymousScopeCount);
162                         bw.Write (AnonymousScopeTableOffset);
163                         bw.Write (AnonymousScopeTableSize);
164
165                         bw.Write (LineNumberTable_LineBase);
166                         bw.Write (LineNumberTable_LineRange);
167                         bw.Write (LineNumberTable_OpcodeBase);
168
169                         bw.Write ((int) FileFlags);
170                 }
171
172                 public override string ToString ()
173                 {
174                         return String.Format (
175                                 "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]",
176                                 TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount,
177                                 SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset,
178                                 MethodTableSize, TypeCount);
179                 }
180         }
181
182         public class LineNumberEntry
183         {
184                 #region This is actually written to the symbol file
185                 public readonly int Row;
186                 public int Column;
187                 public readonly int File;
188                 public readonly int Offset;
189                 public readonly bool IsHidden;  // Obsolete is never used
190                 #endregion
191
192                 public sealed class LocationComparer : IComparer<LineNumberEntry>
193                 {
194                         public static readonly LocationComparer Default = new LocationComparer ();
195
196                         public int Compare (LineNumberEntry l1, LineNumberEntry l2)
197                         {
198                                 return l1.Row == l2.Row ?
199                                         l1.Column.CompareTo (l2.Column) :
200                                         l1.Row.CompareTo (l2.Row);
201                         }
202                 }
203
204                 public static readonly LineNumberEntry Null = new LineNumberEntry (0, 0, 0, 0);
205
206                 public LineNumberEntry (int file, int row, int column, int offset)
207                         : this (file, row, offset, column, false)
208                 {
209                 }
210
211                 public LineNumberEntry (int file, int row, int offset)
212                         : this (file, row, -1, offset, false)
213                 {
214                 }
215
216                 public LineNumberEntry (int file, int row, int column, int offset, bool is_hidden)
217                 {
218                         this.File = file;
219                         this.Row = row;
220                         this.Column = column;
221                         this.Offset = offset;
222                         this.IsHidden = is_hidden;
223                 }
224
225                 public override string ToString ()
226                 {
227                         return String.Format ("[Line {0}:{1,2}:{3}]", File, Row, Column, Offset);
228                 }
229         }
230
231         public class CodeBlockEntry
232         {
233                 public int Index;
234                 #region This is actually written to the symbol file
235                 public int Parent;
236                 public Type BlockType;
237                 public int StartOffset;
238                 public int EndOffset;
239                 #endregion
240
241                 public enum Type {
242                         Lexical                 = 1,
243                         CompilerGenerated       = 2,
244                         IteratorBody            = 3,
245                         IteratorDispatcher      = 4
246                 }
247
248                 public CodeBlockEntry (int index, int parent, Type type, int start_offset)
249                 {
250                         this.Index = index;
251                         this.Parent = parent;
252                         this.BlockType = type;
253                         this.StartOffset = start_offset;
254                 }
255
256                 internal CodeBlockEntry (int index, MyBinaryReader reader)
257                 {
258                         this.Index = index;
259                         int type_flag = reader.ReadLeb128 ();
260                         BlockType = (Type) (type_flag & 0x3f);
261                         this.Parent = reader.ReadLeb128 ();
262                         this.StartOffset = reader.ReadLeb128 ();
263                         this.EndOffset = reader.ReadLeb128 ();
264
265                         /* Reserved for future extensions. */
266                         if ((type_flag & 0x40) != 0) {
267                                 int data_size = reader.ReadInt16 ();
268                                 reader.BaseStream.Position += data_size;
269                         }                               
270                 }
271
272                 public void Close (int end_offset)
273                 {
274                         this.EndOffset = end_offset;
275                 }
276
277                 internal void Write (MyBinaryWriter bw)
278                 {
279                         bw.WriteLeb128 ((int) BlockType);
280                         bw.WriteLeb128 (Parent);
281                         bw.WriteLeb128 (StartOffset);
282                         bw.WriteLeb128 (EndOffset);
283                 }
284
285                 public override string ToString ()
286                 {
287                         return String.Format ("[CodeBlock {0}:{1}:{2}:{3}:{4}]",
288                                               Index, Parent, BlockType, StartOffset, EndOffset);
289                 }
290         }
291
292         public struct LocalVariableEntry
293         {
294                 #region This is actually written to the symbol file
295                 public readonly int Index;
296                 public readonly string Name;
297                 public readonly int BlockIndex;
298                 #endregion
299
300                 public LocalVariableEntry (int index, string name, int block)
301                 {
302                         this.Index = index;
303                         this.Name = name;
304                         this.BlockIndex = block;
305                 }
306
307                 internal LocalVariableEntry (MonoSymbolFile file, MyBinaryReader reader)
308                 {
309                         Index = reader.ReadLeb128 ();
310                         Name = reader.ReadString ();
311                         BlockIndex = reader.ReadLeb128 ();
312                 }
313
314                 internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
315                 {
316                         bw.WriteLeb128 (Index);
317                         bw.Write (Name);
318                         bw.WriteLeb128 (BlockIndex);
319                 }
320
321                 public override string ToString ()
322                 {
323                         return String.Format ("[LocalVariable {0}:{1}:{2}]",
324                                               Name, Index, BlockIndex - 1);
325                 }
326         }
327
328         public struct CapturedVariable
329         {
330                 #region This is actually written to the symbol file
331                 public readonly string Name;
332                 public readonly string CapturedName;
333                 public readonly CapturedKind Kind;
334                 #endregion
335
336                 public enum CapturedKind : byte
337                 {
338                         Local,
339                         Parameter,
340                         This
341                 }
342
343                 public CapturedVariable (string name, string captured_name,
344                                          CapturedKind kind)
345                 {
346                         this.Name = name;
347                         this.CapturedName = captured_name;
348                         this.Kind = kind;
349                 }
350
351                 internal CapturedVariable (MyBinaryReader reader)
352                 {
353                         Name = reader.ReadString ();
354                         CapturedName = reader.ReadString ();
355                         Kind = (CapturedKind) reader.ReadByte ();
356                 }
357
358                 internal void Write (MyBinaryWriter bw)
359                 {
360                         bw.Write (Name);
361                         bw.Write (CapturedName);
362                         bw.Write ((byte) Kind);
363                 }
364
365                 public override string ToString ()
366                 {
367                         return String.Format ("[CapturedVariable {0}:{1}:{2}]",
368                                               Name, CapturedName, Kind);
369                 }
370         }
371
372         public struct CapturedScope
373         {
374                 #region This is actually written to the symbol file
375                 public readonly int Scope;
376                 public readonly string CapturedName;
377                 #endregion
378
379                 public CapturedScope (int scope, string captured_name)
380                 {
381                         this.Scope = scope;
382                         this.CapturedName = captured_name;
383                 }
384
385                 internal CapturedScope (MyBinaryReader reader)
386                 {
387                         Scope = reader.ReadLeb128 ();
388                         CapturedName = reader.ReadString ();
389                 }
390
391                 internal void Write (MyBinaryWriter bw)
392                 {
393                         bw.WriteLeb128 (Scope);
394                         bw.Write (CapturedName);
395                 }
396
397                 public override string ToString ()
398                 {
399                         return String.Format ("[CapturedScope {0}:{1}]",
400                                               Scope, CapturedName);
401                 }
402         }
403
404         public struct ScopeVariable
405         {
406                 #region This is actually written to the symbol file
407                 public readonly int Scope;
408                 public readonly int Index;
409                 #endregion
410
411                 public ScopeVariable (int scope, int index)
412                 {
413                         this.Scope = scope;
414                         this.Index = index;
415                 }
416
417                 internal ScopeVariable (MyBinaryReader reader)
418                 {
419                         Scope = reader.ReadLeb128 ();
420                         Index = reader.ReadLeb128 ();
421                 }
422
423                 internal void Write (MyBinaryWriter bw)
424                 {
425                         bw.WriteLeb128 (Scope);
426                         bw.WriteLeb128 (Index);
427                 }
428
429                 public override string ToString ()
430                 {
431                         return String.Format ("[ScopeVariable {0}:{1}]", Scope, Index);
432                 }
433         }
434
435         public class AnonymousScopeEntry
436         {
437                 #region This is actually written to the symbol file
438                 public readonly int ID;
439                 #endregion
440
441                 List<CapturedVariable> captured_vars = new List<CapturedVariable> ();
442                 List<CapturedScope> captured_scopes = new List<CapturedScope> ();
443
444                 public AnonymousScopeEntry (int id)
445                 {
446                         this.ID = id;
447                 }
448
449                 internal AnonymousScopeEntry (MyBinaryReader reader)
450                 {
451                         ID = reader.ReadLeb128 ();
452
453                         int num_captured_vars = reader.ReadLeb128 ();
454                         for (int i = 0; i < num_captured_vars; i++)
455                                 captured_vars.Add (new CapturedVariable (reader));
456
457                         int num_captured_scopes = reader.ReadLeb128 ();
458                         for (int i = 0; i < num_captured_scopes; i++)
459                                 captured_scopes.Add (new CapturedScope (reader));
460                 }
461
462                 internal void AddCapturedVariable (string name, string captured_name,
463                                                    CapturedVariable.CapturedKind kind)
464                 {
465                         captured_vars.Add (new CapturedVariable (name, captured_name, kind));
466                 }
467
468                 public CapturedVariable[] CapturedVariables {
469                         get {
470                                 CapturedVariable[] retval = new CapturedVariable [captured_vars.Count];
471                                 captured_vars.CopyTo (retval, 0);
472                                 return retval;
473                         }
474                 }
475
476                 internal void AddCapturedScope (int scope, string captured_name)
477                 {
478                         captured_scopes.Add (new CapturedScope (scope, captured_name));
479                 }
480
481                 public CapturedScope[] CapturedScopes {
482                         get {
483                                 CapturedScope[] retval = new CapturedScope [captured_scopes.Count];
484                                 captured_scopes.CopyTo (retval, 0);
485                                 return retval;
486                         }
487                 }
488
489                 internal void Write (MyBinaryWriter bw)
490                 {
491                         bw.WriteLeb128 (ID);
492
493                         bw.WriteLeb128 (captured_vars.Count);
494                         foreach (CapturedVariable cv in captured_vars)
495                                 cv.Write (bw);
496
497                         bw.WriteLeb128 (captured_scopes.Count);
498                         foreach (CapturedScope cs in captured_scopes)
499                                 cs.Write (bw);
500                 }
501
502                 public override string ToString ()
503                 {
504                         return String.Format ("[AnonymousScope {0}]", ID);
505                 }
506         }
507
508         public class CompileUnitEntry : ICompileUnit
509         {
510                 #region This is actually written to the symbol file
511                 public readonly int Index;
512                 int DataOffset;
513                 #endregion
514
515                 MonoSymbolFile file;
516                 SourceFileEntry source;
517                 List<SourceFileEntry> include_files;
518                 List<NamespaceEntry> namespaces;
519
520                 bool creating;
521
522                 public static int Size {
523                         get { return 8; }
524                 }
525
526                 CompileUnitEntry ICompileUnit.Entry {
527                         get { return this; }
528                 }
529
530                 public CompileUnitEntry (MonoSymbolFile file, SourceFileEntry source)
531                 {
532                         this.file = file;
533                         this.source = source;
534
535                         this.Index = file.AddCompileUnit (this);
536
537                         creating = true;
538                         namespaces = new List<NamespaceEntry> ();
539                 }
540
541                 public void AddFile (SourceFileEntry file)
542                 {
543                         if (!creating)
544                                 throw new InvalidOperationException ();
545
546                         if (include_files == null)
547                                 include_files = new List<SourceFileEntry> ();
548
549                         include_files.Add (file);
550                 }
551
552                 public SourceFileEntry SourceFile {
553                         get {
554                                 if (creating)
555                                         return source;
556
557                                 ReadData ();
558                                 return source;
559                         }
560                 }
561
562                 public int DefineNamespace (string name, string[] using_clauses, int parent)
563                 {
564                         if (!creating)
565                                 throw new InvalidOperationException ();
566
567                         int index = file.GetNextNamespaceIndex ();
568                         NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
569                         namespaces.Add (ns);
570                         return index;
571                 }
572
573                 internal void WriteData (MyBinaryWriter bw)
574                 {
575                         DataOffset = (int) bw.BaseStream.Position;
576                         bw.WriteLeb128 (source.Index);
577
578                         int count_includes = include_files != null ? include_files.Count : 0;
579                         bw.WriteLeb128 (count_includes);
580                         if (include_files != null) {
581                                 foreach (SourceFileEntry entry in include_files)
582                                         bw.WriteLeb128 (entry.Index);
583                         }
584
585                         bw.WriteLeb128 (namespaces.Count);
586                         foreach (NamespaceEntry ns in namespaces)
587                                 ns.Write (file, bw);
588                 }
589
590                 internal void Write (BinaryWriter bw)
591                 {
592                         bw.Write (Index);
593                         bw.Write (DataOffset);
594                 }
595
596                 internal CompileUnitEntry (MonoSymbolFile file, MyBinaryReader reader)
597                 {
598                         this.file = file;
599
600                         Index = reader.ReadInt32 ();
601                         DataOffset = reader.ReadInt32 ();
602                 }
603
604                 public void ReadAll ()
605                 {
606                         ReadData ();
607                 }
608
609                 void ReadData ()
610                 {
611                         if (creating)
612                                 throw new InvalidOperationException ();
613
614                         lock (file) {
615                                 if (namespaces != null)
616                                         return;
617
618                                 MyBinaryReader reader = file.BinaryReader;
619                                 int old_pos = (int) reader.BaseStream.Position;
620
621                                 reader.BaseStream.Position = DataOffset;
622
623                                 int source_idx = reader.ReadLeb128 ();
624                                 source = file.GetSourceFile (source_idx);
625
626                                 int count_includes = reader.ReadLeb128 ();
627                                 if (count_includes > 0) {
628                                         include_files = new List<SourceFileEntry> ();
629                                         for (int i = 0; i < count_includes; i++)
630                                                 include_files.Add (file.GetSourceFile (reader.ReadLeb128 ()));
631                                 }
632
633                                 int count_ns = reader.ReadLeb128 ();
634                                 namespaces = new List<NamespaceEntry> ();
635                                 for (int i = 0; i < count_ns; i ++)
636                                         namespaces.Add (new NamespaceEntry (file, reader));
637
638                                 reader.BaseStream.Position = old_pos;
639                         }
640                 }
641
642                 public NamespaceEntry[] Namespaces {
643                         get {
644                                 ReadData ();
645                                 NamespaceEntry[] retval = new NamespaceEntry [namespaces.Count];
646                                 namespaces.CopyTo (retval, 0);
647                                 return retval;
648                         }
649                 }
650
651                 public SourceFileEntry[] IncludeFiles {
652                         get {
653                                 ReadData ();
654                                 if (include_files == null)
655                                         return new SourceFileEntry [0];
656
657                                 SourceFileEntry[] retval = new SourceFileEntry [include_files.Count];
658                                 include_files.CopyTo (retval, 0);
659                                 return retval;
660                         }
661                 }
662         }
663
664         public class SourceFileEntry
665         {
666                 #region This is actually written to the symbol file
667                 public readonly int Index;
668                 int DataOffset;
669                 #endregion
670
671                 MonoSymbolFile file;
672                 string file_name;
673                 byte[] guid;
674                 byte[] hash;
675                 bool creating;
676                 bool auto_generated;
677
678                 public static int Size {
679                         get { return 8; }
680                 }
681
682                 public SourceFileEntry (MonoSymbolFile file, string file_name)
683                 {
684                         this.file = file;
685                         this.file_name = file_name;
686                         this.Index = file.AddSource (this);
687
688                         creating = true;
689                 }
690
691                 public SourceFileEntry (MonoSymbolFile file, string file_name, byte[] guid, byte[] checksum)
692                         : this (file, file_name)
693                 {
694                         this.guid = guid;
695                         this.hash = checksum;
696                 }
697
698                 public byte[] Checksum {
699                         get {
700                                 return hash;
701                         }
702                 }
703
704                 internal void WriteData (MyBinaryWriter bw)
705                 {
706                         DataOffset = (int) bw.BaseStream.Position;
707                         bw.Write (file_name);
708
709                         if (guid == null)
710                                 guid = new byte[16];
711
712                         if (hash == null) {
713                                 try {
714                                     using (FileStream fs = new FileStream (file_name, FileMode.Open, FileAccess.Read)) {
715                                         MD5 md5 = MD5.Create ();
716                                         hash = md5.ComputeHash (fs);
717                                     }
718                                 } catch {
719                                         hash = new byte [16];
720                                 }
721                         }
722
723                         bw.Write (guid);
724                         bw.Write (hash);
725                         bw.Write ((byte) (auto_generated ? 1 : 0));
726                 }
727
728                 internal void Write (BinaryWriter bw)
729                 {
730                         bw.Write (Index);
731                         bw.Write (DataOffset);
732                 }
733
734                 internal SourceFileEntry (MonoSymbolFile file, MyBinaryReader reader)
735                 {
736                         this.file = file;
737
738                         Index = reader.ReadInt32 ();
739                         DataOffset = reader.ReadInt32 ();
740
741                         int old_pos = (int) reader.BaseStream.Position;
742                         reader.BaseStream.Position = DataOffset;
743
744                         file_name = reader.ReadString ();
745                         guid = reader.ReadBytes (16);
746                         hash = reader.ReadBytes (16);
747                         auto_generated = reader.ReadByte () == 1;
748
749                         reader.BaseStream.Position = old_pos;
750                 }
751
752                 public string FileName {
753                         get { return file_name; }
754                         set { file_name = value; }
755                 }
756
757                 public bool AutoGenerated {
758                         get { return auto_generated; }
759                 }
760
761                 public void SetAutoGenerated ()
762                 {
763                         if (!creating)
764                                 throw new InvalidOperationException ();
765
766                         auto_generated = true;
767                         file.OffsetTable.FileFlags |= OffsetTable.Flags.IsAspxSource;
768                 }
769
770                 public bool CheckChecksum ()
771                 {
772                         try {
773                                 using (FileStream fs = new FileStream (file_name, FileMode.Open)) {
774                                         MD5 md5 = MD5.Create ();
775                                         byte[] data = md5.ComputeHash (fs);
776                                         for (int i = 0; i < 16; i++)
777                                                 if (data [i] != hash [i])
778                                                         return false;
779                                         return true;
780                                 }
781                         } catch {
782                                 return false;
783                         }
784                 }
785
786                 public override string ToString ()
787                 {
788                         return String.Format ("SourceFileEntry ({0}:{1})", Index, DataOffset);
789                 }
790         }
791
792         public class LineNumberTable
793         {
794                 protected LineNumberEntry[] _line_numbers;
795                 public LineNumberEntry[] LineNumbers {
796                         get { return _line_numbers; }
797                 }
798
799                 public readonly int LineBase;
800                 public readonly int LineRange;
801                 public readonly byte OpcodeBase;
802                 public readonly int MaxAddressIncrement;
803
804 #region Configurable constants
805                 public const int Default_LineBase = -1;
806                 public const int Default_LineRange = 8;
807                 public const byte Default_OpcodeBase = 9;
808
809 #endregion
810
811                 public const byte DW_LNS_copy = 1;
812                 public const byte DW_LNS_advance_pc = 2;
813                 public const byte DW_LNS_advance_line = 3;
814                 public const byte DW_LNS_set_file = 4;
815                 public const byte DW_LNS_const_add_pc = 8;
816
817                 public const byte DW_LNE_end_sequence = 1;
818
819                 // MONO extensions.
820                 public const byte DW_LNE_MONO_negate_is_hidden = 0x40;
821
822                 internal const byte DW_LNE_MONO__extensions_start = 0x40;
823                 internal const byte DW_LNE_MONO__extensions_end   = 0x7f;
824
825                 protected LineNumberTable (MonoSymbolFile file)
826                 {
827                         this.LineBase = file.OffsetTable.LineNumberTable_LineBase;
828                         this.LineRange = file.OffsetTable.LineNumberTable_LineRange;
829                         this.OpcodeBase = (byte) file.OffsetTable.LineNumberTable_OpcodeBase;
830                         this.MaxAddressIncrement = (255 - OpcodeBase) / LineRange;
831                 }
832
833                 internal LineNumberTable (MonoSymbolFile file, LineNumberEntry[] lines)
834                         : this (file)
835                 {
836                         this._line_numbers = lines;
837                 }
838
839                 internal void Write (MonoSymbolFile file, MyBinaryWriter bw, bool readColumnsInfo)
840                 {
841                         int start = (int) bw.BaseStream.Position;
842
843                         bool last_is_hidden = false;
844                         int last_line = 1, last_offset = 0, last_file = 1;
845                         for (int i = 0; i < LineNumbers.Length; i++) {
846                                 int line_inc = LineNumbers [i].Row - last_line;
847                                 int offset_inc = LineNumbers [i].Offset - last_offset;
848
849                                 if (LineNumbers [i].File != last_file) {
850                                         bw.Write (DW_LNS_set_file);
851                                         bw.WriteLeb128 (LineNumbers [i].File);
852                                         last_file = LineNumbers [i].File;
853                                 }
854
855                                 if (LineNumbers [i].IsHidden != last_is_hidden) {
856                                         bw.Write ((byte) 0);
857                                         bw.Write ((byte) 1);
858                                         bw.Write (DW_LNE_MONO_negate_is_hidden);
859                                         last_is_hidden = LineNumbers [i].IsHidden;
860                                 }
861
862                                 if (offset_inc >= MaxAddressIncrement) {
863                                         if (offset_inc < 2 * MaxAddressIncrement) {
864                                                 bw.Write (DW_LNS_const_add_pc);
865                                                 offset_inc -= MaxAddressIncrement;
866                                         } else {
867                                                 bw.Write (DW_LNS_advance_pc);
868                                                 bw.WriteLeb128 (offset_inc);
869                                                 offset_inc = 0;
870                                         }
871                                 }
872
873                                 if ((line_inc < LineBase) || (line_inc >= LineBase + LineRange)) {
874                                         bw.Write (DW_LNS_advance_line);
875                                         bw.WriteLeb128 (line_inc);
876                                         if (offset_inc != 0) {
877                                                 bw.Write (DW_LNS_advance_pc);
878                                                 bw.WriteLeb128 (offset_inc);
879                                         }
880                                         bw.Write (DW_LNS_copy);
881                                 } else {
882                                         byte opcode;
883                                         opcode = (byte) (line_inc - LineBase + (LineRange * offset_inc) +
884                                                          OpcodeBase);
885                                         bw.Write (opcode);
886                                 }
887
888                                 last_line = LineNumbers [i].Row;
889                                 last_offset = LineNumbers [i].Offset;
890                         }
891
892                         bw.Write ((byte) 0);
893                         bw.Write ((byte) 1);
894                         bw.Write (DW_LNE_end_sequence);
895
896                         for (int i = 0; i < LineNumbers.Length; i++) {
897                                 var ln = LineNumbers [i];
898                                 if (ln.Row >= 0)
899                                         bw.WriteLeb128 (ln.Column);
900                         }
901
902                         file.ExtendedLineNumberSize += (int) bw.BaseStream.Position - start;
903                 }
904
905                 internal static LineNumberTable Read (MonoSymbolFile file, MyBinaryReader br, bool readColumnsInfo)
906                 {
907                         LineNumberTable lnt = new LineNumberTable (file);
908                         lnt.DoRead (file, br, readColumnsInfo);
909                         return lnt;
910                 }
911
912                 void DoRead (MonoSymbolFile file, MyBinaryReader br, bool includesColumns)
913                 {
914                         var lines = new List<LineNumberEntry> ();
915
916                         bool is_hidden = false, modified = false;
917                         int stm_line = 1, stm_offset = 0, stm_file = 1;
918                         while (true) {
919                                 byte opcode = br.ReadByte ();
920
921                                 if (opcode == 0) {
922                                         byte size = br.ReadByte ();
923                                         long end_pos = br.BaseStream.Position + size;
924                                         opcode = br.ReadByte ();
925
926                                         if (opcode == DW_LNE_end_sequence) {
927                                                 if (modified)
928                                                         lines.Add (new LineNumberEntry (
929                                                                 stm_file, stm_line, -1, stm_offset, is_hidden));
930                                                 break;
931                                         } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
932                                                 is_hidden = !is_hidden;
933                                                 modified = true;
934                                         } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
935                                                    (opcode <= DW_LNE_MONO__extensions_end)) {
936                                                 ; // reserved for future extensions
937                                         } else {
938                                                 throw new MonoSymbolFileException ("Unknown extended opcode {0:x}", opcode);
939                                         }
940
941                                         br.BaseStream.Position = end_pos;
942                                         continue;
943                                 } else if (opcode < OpcodeBase) {
944                                         switch (opcode) {
945                                         case DW_LNS_copy:
946                                                 lines.Add (new LineNumberEntry (
947                                                         stm_file, stm_line, -1, stm_offset, is_hidden));
948                                                 modified = false;
949                                                 break;
950                                         case DW_LNS_advance_pc:
951                                                 stm_offset += br.ReadLeb128 ();
952                                                 modified = true;
953                                                 break;
954                                         case DW_LNS_advance_line:
955                                                 stm_line += br.ReadLeb128 ();
956                                                 modified = true;
957                                                 break;
958                                         case DW_LNS_set_file:
959                                                 stm_file = br.ReadLeb128 ();
960                                                 modified = true;
961                                                 break;
962                                         case DW_LNS_const_add_pc:
963                                                 stm_offset += MaxAddressIncrement;
964                                                 modified = true;
965                                                 break;
966                                         default:
967                                                 throw new MonoSymbolFileException (
968                                                         "Unknown standard opcode {0:x} in LNT",
969                                                         opcode);
970                                         }
971                                 } else {
972                                         opcode -= OpcodeBase;
973
974                                         stm_offset += opcode / LineRange;
975                                         stm_line += LineBase + (opcode % LineRange);
976                                         lines.Add (new LineNumberEntry (
977                                                 stm_file, stm_line, -1, stm_offset, is_hidden));
978                                         modified = false;
979                                 }
980                         }
981
982                         _line_numbers = lines.ToArray ();
983
984                         if (includesColumns) {
985                                 for (int i = 0; i < _line_numbers.Length; ++i) {
986                                         var ln = _line_numbers[i];
987                                         if (ln.Row >= 0)
988                                                 ln.Column = br.ReadLeb128 ();
989                                 }
990                         }
991                 }
992
993                 public bool GetMethodBounds (out LineNumberEntry start, out LineNumberEntry end)
994                 {
995                         if (_line_numbers.Length > 1) {
996                                 start = _line_numbers [0];
997                                 end = _line_numbers [_line_numbers.Length - 1];
998                                 return true;
999                         }
1000
1001                         start = LineNumberEntry.Null;
1002                         end = LineNumberEntry.Null;
1003                         return false;
1004                 }
1005         }
1006
1007         public class MethodEntry : IComparable
1008         {
1009                 #region This is actually written to the symbol file
1010                 public readonly int CompileUnitIndex;
1011                 public readonly int Token;
1012                 public readonly int NamespaceID;
1013
1014                 int DataOffset;
1015                 int LocalVariableTableOffset;
1016                 int LineNumberTableOffset;
1017                 int CodeBlockTableOffset;
1018                 int ScopeVariableTableOffset;
1019                 int RealNameOffset;
1020                 Flags flags;
1021                 #endregion
1022
1023                 int index;
1024
1025                 public Flags MethodFlags {
1026                         get { return flags; }
1027                 }
1028
1029                 public readonly CompileUnitEntry CompileUnit;
1030
1031                 LocalVariableEntry[] locals;
1032                 CodeBlockEntry[] code_blocks;
1033                 ScopeVariable[] scope_vars;
1034                 LineNumberTable lnt;
1035                 string real_name;
1036
1037                 public readonly MonoSymbolFile SymbolFile;
1038
1039                 public int Index {
1040                         get { return index; }
1041                         set { index = value; }
1042                 }
1043
1044                 [Flags]
1045                 public enum Flags
1046                 {
1047                         LocalNamesAmbiguous     = 1,
1048                         ColumnsInfoIncluded = 1 << 1
1049                 }
1050
1051                 public const int Size = 12;
1052
1053                 internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index)
1054                 {
1055                         this.SymbolFile = file;
1056                         this.index = index;
1057
1058                         Token = reader.ReadInt32 ();
1059                         DataOffset = reader.ReadInt32 ();
1060                         LineNumberTableOffset = reader.ReadInt32 ();
1061
1062                         long old_pos = reader.BaseStream.Position;
1063                         reader.BaseStream.Position = DataOffset;
1064
1065                         CompileUnitIndex = reader.ReadLeb128 ();
1066                         LocalVariableTableOffset = reader.ReadLeb128 ();
1067                         NamespaceID = reader.ReadLeb128 ();
1068
1069                         CodeBlockTableOffset = reader.ReadLeb128 ();
1070                         ScopeVariableTableOffset = reader.ReadLeb128 ();
1071
1072                         RealNameOffset = reader.ReadLeb128 ();
1073
1074                         flags = (Flags) reader.ReadLeb128 ();
1075
1076                         reader.BaseStream.Position = old_pos;
1077
1078                         CompileUnit = file.GetCompileUnit (CompileUnitIndex);
1079                 }
1080
1081                 internal MethodEntry (MonoSymbolFile file, CompileUnitEntry comp_unit,
1082                                       int token, ScopeVariable[] scope_vars,
1083                                       LocalVariableEntry[] locals, LineNumberEntry[] lines,
1084                                       CodeBlockEntry[] code_blocks, string real_name,
1085                                       Flags flags, int namespace_id)
1086                 {
1087                         this.SymbolFile = file;
1088                         this.real_name = real_name;
1089                         this.locals = locals;
1090                         this.code_blocks = code_blocks;
1091                         this.scope_vars = scope_vars;
1092                         this.flags = flags;
1093
1094                         index = -1;
1095
1096                         Token = token;
1097                         CompileUnitIndex = comp_unit.Index;
1098                         CompileUnit = comp_unit;
1099                         NamespaceID = namespace_id;
1100
1101                         CheckLineNumberTable (lines);
1102                         lnt = new LineNumberTable (file, lines);
1103                         file.NumLineNumbers += lines.Length;
1104
1105                         int num_locals = locals != null ? locals.Length : 0;
1106
1107                         if (num_locals <= 32) {
1108                                 // Most of the time, the O(n^2) factor is actually
1109                                 // less than the cost of allocating the hash table,
1110                                 // 32 is a rough number obtained through some testing.
1111                                 
1112                                 for (int i = 0; i < num_locals; i ++) {
1113                                         string nm = locals [i].Name;
1114                                         
1115                                         for (int j = i + 1; j < num_locals; j ++) {
1116                                                 if (locals [j].Name == nm) {
1117                                                         flags |= Flags.LocalNamesAmbiguous;
1118                                                         goto locals_check_done;
1119                                                 }
1120                                         }
1121                                 }
1122                         locals_check_done :
1123                                 ;
1124                         } else {
1125                                 var local_names = new Dictionary<string, LocalVariableEntry> ();
1126                                 foreach (LocalVariableEntry local in locals) {
1127                                         if (local_names.ContainsKey (local.Name)) {
1128                                                 flags |= Flags.LocalNamesAmbiguous;
1129                                                 break;
1130                                         }
1131                                         local_names.Add (local.Name, local);
1132                                 }
1133                         }
1134                 }
1135                 
1136                 static void CheckLineNumberTable (LineNumberEntry[] line_numbers)
1137                 {
1138                         int last_offset = -1;
1139                         int last_row = -1;
1140
1141                         if (line_numbers == null)
1142                                 return;
1143                         
1144                         for (int i = 0; i < line_numbers.Length; i++) {
1145                                 LineNumberEntry line = line_numbers [i];
1146
1147                                 if (line.Equals (LineNumberEntry.Null))
1148                                         throw new MonoSymbolFileException ();
1149
1150                                 if (line.Offset < last_offset)
1151                                         throw new MonoSymbolFileException ();
1152
1153                                 if (line.Offset > last_offset) {
1154                                         last_row = line.Row;
1155                                         last_offset = line.Offset;
1156                                 } else if (line.Row > last_row) {
1157                                         last_row = line.Row;
1158                                 }
1159                         }
1160                 }
1161
1162                 internal void Write (MyBinaryWriter bw)
1163                 {
1164                         if ((index <= 0) || (DataOffset == 0))
1165                                 throw new InvalidOperationException ();
1166
1167                         bw.Write (Token);
1168                         bw.Write (DataOffset);
1169                         bw.Write (LineNumberTableOffset);
1170                 }
1171
1172                 internal void WriteData (MonoSymbolFile file, MyBinaryWriter bw)
1173                 {
1174                         if (index <= 0)
1175                                 throw new InvalidOperationException ();
1176
1177                         LocalVariableTableOffset = (int) bw.BaseStream.Position;
1178                         int num_locals = locals != null ? locals.Length : 0;
1179                         bw.WriteLeb128 (num_locals);
1180                         for (int i = 0; i < num_locals; i++)
1181                                 locals [i].Write (file, bw);
1182                         file.LocalCount += num_locals;
1183
1184                         CodeBlockTableOffset = (int) bw.BaseStream.Position;
1185                         int num_code_blocks = code_blocks != null ? code_blocks.Length : 0;
1186                         bw.WriteLeb128 (num_code_blocks);
1187                         for (int i = 0; i < num_code_blocks; i++)
1188                                 code_blocks [i].Write (bw);
1189
1190                         ScopeVariableTableOffset = (int) bw.BaseStream.Position;
1191                         int num_scope_vars = scope_vars != null ? scope_vars.Length : 0;
1192                         bw.WriteLeb128 (num_scope_vars);
1193                         for (int i = 0; i < num_scope_vars; i++)
1194                                 scope_vars [i].Write (bw);
1195
1196                         if (real_name != null) {
1197                                 RealNameOffset = (int) bw.BaseStream.Position;
1198                                 bw.Write (real_name);
1199                         }
1200
1201                         LineNumberTableOffset = (int) bw.BaseStream.Position;
1202                         lnt.Write (file, bw, (flags & Flags.ColumnsInfoIncluded) != 0);
1203
1204                         DataOffset = (int) bw.BaseStream.Position;
1205
1206                         bw.WriteLeb128 (CompileUnitIndex);
1207                         bw.WriteLeb128 (LocalVariableTableOffset);
1208                         bw.WriteLeb128 (NamespaceID);
1209
1210                         bw.WriteLeb128 (CodeBlockTableOffset);
1211                         bw.WriteLeb128 (ScopeVariableTableOffset);
1212
1213                         bw.WriteLeb128 (RealNameOffset);
1214                         bw.WriteLeb128 ((int) flags);
1215                 }
1216
1217                 public void ReadAll ()
1218                 {
1219                         GetLineNumberTable ();
1220                         GetLocals ();
1221                         GetCodeBlocks ();
1222                         GetScopeVariables ();
1223                         GetRealName ();
1224                 }
1225
1226                 public LineNumberTable GetLineNumberTable ()
1227                 {
1228                         lock (SymbolFile) {
1229                                 if (lnt != null)
1230                                         return lnt;
1231
1232                                 if (LineNumberTableOffset == 0)
1233                                         return null;
1234
1235                                 MyBinaryReader reader = SymbolFile.BinaryReader;
1236                                 long old_pos = reader.BaseStream.Position;
1237                                 reader.BaseStream.Position = LineNumberTableOffset;
1238
1239                                 lnt = LineNumberTable.Read (SymbolFile, reader, (flags & Flags.ColumnsInfoIncluded) != 0);
1240
1241                                 reader.BaseStream.Position = old_pos;
1242                                 return lnt;
1243                         }
1244                 }
1245
1246                 public LocalVariableEntry[] GetLocals ()
1247                 {
1248                         lock (SymbolFile) {
1249                                 if (locals != null)
1250                                         return locals;
1251
1252                                 if (LocalVariableTableOffset == 0)
1253                                         return null;
1254
1255                                 MyBinaryReader reader = SymbolFile.BinaryReader;
1256                                 long old_pos = reader.BaseStream.Position;
1257                                 reader.BaseStream.Position = LocalVariableTableOffset;
1258
1259                                 int num_locals = reader.ReadLeb128 ();
1260                                 locals = new LocalVariableEntry [num_locals];
1261
1262                                 for (int i = 0; i < num_locals; i++)
1263                                         locals [i] = new LocalVariableEntry (SymbolFile, reader);
1264
1265                                 reader.BaseStream.Position = old_pos;
1266                                 return locals;
1267                         }
1268                 }
1269
1270                 public CodeBlockEntry[] GetCodeBlocks ()
1271                 {
1272                         lock (SymbolFile) {
1273                                 if (code_blocks != null)
1274                                         return code_blocks;
1275
1276                                 if (CodeBlockTableOffset == 0)
1277                                         return null;
1278
1279                                 MyBinaryReader reader = SymbolFile.BinaryReader;
1280                                 long old_pos = reader.BaseStream.Position;
1281                                 reader.BaseStream.Position = CodeBlockTableOffset;
1282
1283                                 int num_code_blocks = reader.ReadLeb128 ();
1284                                 code_blocks = new CodeBlockEntry [num_code_blocks];
1285
1286                                 for (int i = 0; i < num_code_blocks; i++)
1287                                         code_blocks [i] = new CodeBlockEntry (i, reader);
1288
1289                                 reader.BaseStream.Position = old_pos;
1290                                 return code_blocks;
1291                         }
1292                 }
1293
1294                 public ScopeVariable[] GetScopeVariables ()
1295                 {
1296                         lock (SymbolFile) {
1297                                 if (scope_vars != null)
1298                                         return scope_vars;
1299
1300                                 if (ScopeVariableTableOffset == 0)
1301                                         return null;
1302
1303                                 MyBinaryReader reader = SymbolFile.BinaryReader;
1304                                 long old_pos = reader.BaseStream.Position;
1305                                 reader.BaseStream.Position = ScopeVariableTableOffset;
1306
1307                                 int num_scope_vars = reader.ReadLeb128 ();
1308                                 scope_vars = new ScopeVariable [num_scope_vars];
1309
1310                                 for (int i = 0; i < num_scope_vars; i++)
1311                                         scope_vars [i] = new ScopeVariable (reader);
1312
1313                                 reader.BaseStream.Position = old_pos;
1314                                 return scope_vars;
1315                         }
1316                 }
1317
1318                 public string GetRealName ()
1319                 {
1320                         lock (SymbolFile) {
1321                                 if (real_name != null)
1322                                         return real_name;
1323
1324                                 if (RealNameOffset == 0)
1325                                         return null;
1326
1327                                 real_name = SymbolFile.BinaryReader.ReadString (RealNameOffset);
1328                                 return real_name;
1329                         }
1330                 }
1331
1332                 public int CompareTo (object obj)
1333                 {
1334                         MethodEntry method = (MethodEntry) obj;
1335
1336                         if (method.Token < Token)
1337                                 return 1;
1338                         else if (method.Token > Token)
1339                                 return -1;
1340                         else
1341                                 return 0;
1342                 }
1343
1344                 public override string ToString ()
1345                 {
1346                         return String.Format ("[Method {0}:{1:x}:{2}:{3}]",
1347                                               index, Token, CompileUnitIndex, CompileUnit);
1348                 }
1349         }
1350
1351         public struct NamespaceEntry
1352         {
1353                 #region This is actually written to the symbol file
1354                 public readonly string Name;
1355                 public readonly int Index;
1356                 public readonly int Parent;
1357                 public readonly string[] UsingClauses;
1358                 #endregion
1359
1360                 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
1361                 {
1362                         this.Name = name;
1363                         this.Index = index;
1364                         this.Parent = parent;
1365                         this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
1366                 }
1367
1368                 internal NamespaceEntry (MonoSymbolFile file, MyBinaryReader reader)
1369                 {
1370                         Name = reader.ReadString ();
1371                         Index = reader.ReadLeb128 ();
1372                         Parent = reader.ReadLeb128 ();
1373
1374                         int count = reader.ReadLeb128 ();
1375                         UsingClauses = new string [count];
1376                         for (int i = 0; i < count; i++)
1377                                 UsingClauses [i] = reader.ReadString ();
1378                 }
1379
1380                 internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
1381                 {
1382                         bw.Write (Name);
1383                         bw.WriteLeb128 (Index);
1384                         bw.WriteLeb128 (Parent);
1385                         bw.WriteLeb128 (UsingClauses.Length);
1386                         foreach (string uc in UsingClauses)
1387                                 bw.Write (uc);
1388                 }
1389
1390                 public override string ToString ()
1391                 {
1392                         return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);
1393                 }
1394         }
1395 }