Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.ExtLibs/HeuristicLab.Cecil/0.9.5/Mono.Cecil-0.9.5/Symbols/Mono.Cecil.Mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs @ 12931

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

#2077: created branch and added first version

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