Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/MonoSymbolTable.cs @ 16240

Last change on this file since 16240 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

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