2 // Mono.CSharp.Debugger/MonoSymbolTable.cs
5 // Martin Baulig (martin@ximian.com)
7 // (C) 2002 Ximian, Inc. http://www.ximian.com
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
32 using System
.Security
.Cryptography
;
33 using System
.Collections
;
38 // Parts which are actually written into the symbol file are marked with
40 // #region This is actually written to the symbol file
43 // Please do not modify these regions without previously talking to me.
45 // All changes to the file format must be synchronized in several places:
47 // a) The fields in these regions (and their order) must match the actual
48 // contents of the symbol file.
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.
54 // It is also required to help me enforce b).
56 // b) The regions must be kept in sync with the unmanaged code in
57 // mono/metadata/debug-mono-symfile.h
59 // When making changes to the file format, you must also increase two version
62 // i) OffsetTable.Version in this file.
63 // ii) MONO_SYMBOL_FILE_VERSION in mono/metadata/debug-mono-symfile.h
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.
71 namespace Mono
.CompilerServices
.SymbolWriter
73 public class OffsetTable
75 public const int MajorVersion
= 50;
76 public const int MinorVersion
= 0;
77 public const long Magic
= 0x45e82623fd7fa614;
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
;
93 public int AnonymousScopeCount
;
94 public int AnonymousScopeTableOffset
;
95 public int AnonymousScopeTableSize
;
104 public Flags FileFlags
;
106 public int LineNumberTable_LineBase
= LineNumberTable
.Default_LineBase
;
107 public int LineNumberTable_LineRange
= LineNumberTable
.Default_LineRange
;
108 public int LineNumberTable_OpcodeBase
= LineNumberTable
.Default_OpcodeBase
;
111 internal OffsetTable ()
113 int platform
= (int) Environment
.OSVersion
.Platform
;
114 if ((platform
!= 4) && (platform
!= 128))
115 FileFlags
|= Flags
.WindowsFileNames
;
118 internal OffsetTable (BinaryReader reader
, int major_version
, int minor_version
)
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 ();
134 AnonymousScopeCount
= reader
.ReadInt32 ();
135 AnonymousScopeTableOffset
= reader
.ReadInt32 ();
136 AnonymousScopeTableSize
= reader
.ReadInt32 ();
138 LineNumberTable_LineBase
= reader
.ReadInt32 ();
139 LineNumberTable_LineRange
= reader
.ReadInt32 ();
140 LineNumberTable_OpcodeBase
= reader
.ReadInt32 ();
142 FileFlags
= (Flags
) reader
.ReadInt32 ();
145 internal void Write (BinaryWriter bw
, int major_version
, int minor_version
)
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
);
161 bw
.Write (AnonymousScopeCount
);
162 bw
.Write (AnonymousScopeTableOffset
);
163 bw
.Write (AnonymousScopeTableSize
);
165 bw
.Write (LineNumberTable_LineBase
);
166 bw
.Write (LineNumberTable_LineRange
);
167 bw
.Write (LineNumberTable_OpcodeBase
);
169 bw
.Write ((int) FileFlags
);
172 public override string ToString ()
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
);
182 public class LineNumberEntry
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
;
191 public LineNumberEntry (int file
, int row
, int offset
)
192 : this (file
, row
, offset
, false)
195 public LineNumberEntry (int file
, int row
, int offset
, bool is_hidden
)
199 this.Offset
= offset
;
200 this.IsHidden
= is_hidden
;
203 public static LineNumberEntry Null
= new LineNumberEntry (0, 0, 0);
205 private class OffsetComparerClass
: IComparer
207 public int Compare (object a
, object b
)
209 LineNumberEntry l1
= (LineNumberEntry
) a
;
210 LineNumberEntry l2
= (LineNumberEntry
) b
;
212 if (l1
.Offset
< l2
.Offset
)
214 else if (l1
.Offset
> l2
.Offset
)
221 private class RowComparerClass
: IComparer
223 public int Compare (object a
, object b
)
225 LineNumberEntry l1
= (LineNumberEntry
) a
;
226 LineNumberEntry l2
= (LineNumberEntry
) b
;
230 else if (l1
.Row
> l2
.Row
)
237 public static readonly IComparer OffsetComparer
= new OffsetComparerClass ();
238 public static readonly IComparer RowComparer
= new RowComparerClass ();
240 public override string ToString ()
242 return String
.Format ("[Line {0}:{1}:{2}]", File
, Row
, Offset
);
246 public class CodeBlockEntry
249 #region This is actually written to the symbol file
251 public Type BlockType
;
252 public int StartOffset
;
253 public int EndOffset
;
258 CompilerGenerated
= 2,
260 IteratorDispatcher
= 4
263 public CodeBlockEntry (int index
, int parent
, Type type
, int start_offset
)
266 this.Parent
= parent
;
267 this.BlockType
= type
;
268 this.StartOffset
= start_offset
;
271 internal CodeBlockEntry (int index
, MyBinaryReader reader
)
274 int type_flag
= reader
.ReadLeb128 ();
275 BlockType
= (Type
) (type_flag
& 0x3f);
276 this.Parent
= reader
.ReadLeb128 ();
277 this.StartOffset
= reader
.ReadLeb128 ();
278 this.EndOffset
= reader
.ReadLeb128 ();
280 /* Reserved for future extensions. */
281 if ((type_flag
& 0x40) != 0) {
282 int data_size
= reader
.ReadInt16 ();
283 reader
.BaseStream
.Position
+= data_size
;
287 public void Close (int end_offset
)
289 this.EndOffset
= end_offset
;
292 internal void Write (MyBinaryWriter bw
)
294 bw
.WriteLeb128 ((int) BlockType
);
295 bw
.WriteLeb128 (Parent
);
296 bw
.WriteLeb128 (StartOffset
);
297 bw
.WriteLeb128 (EndOffset
);
300 public override string ToString ()
302 return String
.Format ("[CodeBlock {0}:{1}:{2}:{3}:{4}]",
303 Index
, Parent
, BlockType
, StartOffset
, EndOffset
);
307 public struct LocalVariableEntry
309 #region This is actually written to the symbol file
310 public readonly int Index
;
311 public readonly string Name
;
312 public readonly int BlockIndex
;
315 public LocalVariableEntry (int index
, string name
, int block
)
319 this.BlockIndex
= block
;
322 internal LocalVariableEntry (MonoSymbolFile file
, MyBinaryReader reader
)
324 Index
= reader
.ReadLeb128 ();
325 Name
= reader
.ReadString ();
326 BlockIndex
= reader
.ReadLeb128 ();
329 internal void Write (MonoSymbolFile file
, MyBinaryWriter bw
)
331 bw
.WriteLeb128 (Index
);
333 bw
.WriteLeb128 (BlockIndex
);
336 public override string ToString ()
338 return String
.Format ("[LocalVariable {0}:{1}:{2}]",
339 Name
, Index
, BlockIndex
);
343 public struct CapturedVariable
345 #region This is actually written to the symbol file
346 public readonly string Name
;
347 public readonly string CapturedName
;
348 public readonly CapturedKind Kind
;
351 public enum CapturedKind
: byte
358 public CapturedVariable (string name
, string captured_name
,
362 this.CapturedName
= captured_name
;
366 internal CapturedVariable (MyBinaryReader reader
)
368 Name
= reader
.ReadString ();
369 CapturedName
= reader
.ReadString ();
370 Kind
= (CapturedKind
) reader
.ReadByte ();
373 internal void Write (MyBinaryWriter bw
)
376 bw
.Write (CapturedName
);
377 bw
.Write ((byte) Kind
);
380 public override string ToString ()
382 return String
.Format ("[CapturedVariable {0}:{1}:{2}]",
383 Name
, CapturedName
, Kind
);
387 public struct CapturedScope
389 #region This is actually written to the symbol file
390 public readonly int Scope
;
391 public readonly string CapturedName
;
394 public CapturedScope (int scope
, string captured_name
)
397 this.CapturedName
= captured_name
;
400 internal CapturedScope (MyBinaryReader reader
)
402 Scope
= reader
.ReadLeb128 ();
403 CapturedName
= reader
.ReadString ();
406 internal void Write (MyBinaryWriter bw
)
408 bw
.WriteLeb128 (Scope
);
409 bw
.Write (CapturedName
);
412 public override string ToString ()
414 return String
.Format ("[CapturedScope {0}:{1}]",
415 Scope
, CapturedName
);
419 public struct ScopeVariable
421 #region This is actually written to the symbol file
422 public readonly int Scope
;
423 public readonly int Index
;
426 public ScopeVariable (int scope
, int index
)
432 internal ScopeVariable (MyBinaryReader reader
)
434 Scope
= reader
.ReadLeb128 ();
435 Index
= reader
.ReadLeb128 ();
438 internal void Write (MyBinaryWriter bw
)
440 bw
.WriteLeb128 (Scope
);
441 bw
.WriteLeb128 (Index
);
444 public override string ToString ()
446 return String
.Format ("[ScopeVariable {0}:{1}]", Scope
, Index
);
450 public class AnonymousScopeEntry
452 #region This is actually written to the symbol file
453 public readonly int ID
;
456 ArrayList captured_vars
= new ArrayList ();
457 ArrayList captured_scopes
= new ArrayList ();
459 public AnonymousScopeEntry (int id
)
464 internal AnonymousScopeEntry (MyBinaryReader reader
)
466 ID
= reader
.ReadLeb128 ();
468 int num_captured_vars
= reader
.ReadLeb128 ();
469 for (int i
= 0; i
< num_captured_vars
; i
++)
470 captured_vars
.Add (new CapturedVariable (reader
));
472 int num_captured_scopes
= reader
.ReadLeb128 ();
473 for (int i
= 0; i
< num_captured_scopes
; i
++)
474 captured_scopes
.Add (new CapturedScope (reader
));
477 internal void AddCapturedVariable (string name
, string captured_name
,
478 CapturedVariable
.CapturedKind kind
)
480 captured_vars
.Add (new CapturedVariable (name
, captured_name
, kind
));
483 public CapturedVariable
[] CapturedVariables
{
485 CapturedVariable
[] retval
= new CapturedVariable
[captured_vars
.Count
];
486 captured_vars
.CopyTo (retval
, 0);
491 internal void AddCapturedScope (int scope
, string captured_name
)
493 captured_scopes
.Add (new CapturedScope (scope
, captured_name
));
496 public CapturedScope
[] CapturedScopes
{
498 CapturedScope
[] retval
= new CapturedScope
[captured_scopes
.Count
];
499 captured_scopes
.CopyTo (retval
, 0);
504 internal void Write (MyBinaryWriter bw
)
508 bw
.WriteLeb128 (captured_vars
.Count
);
509 foreach (CapturedVariable cv
in captured_vars
)
512 bw
.WriteLeb128 (captured_scopes
.Count
);
513 foreach (CapturedScope cs
in captured_scopes
)
517 public override string ToString ()
519 return String
.Format ("[AnonymousScope {0}]", ID
);
523 public class CompileUnitEntry
: ICompileUnit
525 #region This is actually written to the symbol file
526 public readonly int Index
;
531 SourceFileEntry source
;
532 ArrayList include_files
;
533 ArrayList namespaces
;
537 public static int Size
{
541 CompileUnitEntry ICompileUnit
.Entry
{
545 public CompileUnitEntry (MonoSymbolFile file
, SourceFileEntry source
)
548 this.source
= source
;
550 this.Index
= file
.AddCompileUnit (this);
553 namespaces
= new ArrayList ();
556 public void AddFile (SourceFileEntry file
)
559 throw new InvalidOperationException ();
561 if (include_files
== null)
562 include_files
= new ArrayList ();
564 include_files
.Add (file
);
567 public SourceFileEntry SourceFile
{
577 public int DefineNamespace (string name
, string[] using_clauses
, int parent
)
580 throw new InvalidOperationException ();
582 int index
= file
.GetNextNamespaceIndex ();
583 NamespaceEntry ns
= new NamespaceEntry (name
, index
, using_clauses
, parent
);
588 internal void WriteData (MyBinaryWriter bw
)
590 DataOffset
= (int) bw
.BaseStream
.Position
;
591 bw
.WriteLeb128 (source
.Index
);
593 int count_includes
= include_files
!= null ? include_files
.Count
: 0;
594 bw
.WriteLeb128 (count_includes
);
595 if (include_files
!= null) {
596 foreach (SourceFileEntry entry
in include_files
)
597 bw
.WriteLeb128 (entry
.Index
);
600 bw
.WriteLeb128 (namespaces
.Count
);
601 foreach (NamespaceEntry ns
in namespaces
)
605 internal void Write (BinaryWriter bw
)
608 bw
.Write (DataOffset
);
611 internal CompileUnitEntry (MonoSymbolFile file
, MyBinaryReader reader
)
615 Index
= reader
.ReadInt32 ();
616 DataOffset
= reader
.ReadInt32 ();
622 throw new InvalidOperationException ();
625 if (namespaces
!= null)
628 MyBinaryReader reader
= file
.BinaryReader
;
629 int old_pos
= (int) reader
.BaseStream
.Position
;
631 reader
.BaseStream
.Position
= DataOffset
;
633 int source_idx
= reader
.ReadLeb128 ();
634 source
= file
.GetSourceFile (source_idx
);
636 int count_includes
= reader
.ReadLeb128 ();
637 if (count_includes
> 0) {
638 include_files
= new ArrayList ();
639 for (int i
= 0; i
< count_includes
; i
++) {
640 // FIXME: The debugger will need this later on.
641 reader
.ReadLeb128 ();
645 int count_ns
= reader
.ReadLeb128 ();
646 namespaces
= new ArrayList ();
647 for (int i
= 0; i
< count_ns
; i
++)
648 namespaces
.Add (new NamespaceEntry (file
, reader
));
650 reader
.BaseStream
.Position
= old_pos
;
654 public NamespaceEntry
[] Namespaces
{
657 NamespaceEntry
[] retval
= new NamespaceEntry
[namespaces
.Count
];
658 namespaces
.CopyTo (retval
, 0);
664 public class SourceFileEntry
666 #region This is actually written to the symbol file
667 public readonly int Index
;
678 public static int Size
{
682 public SourceFileEntry (MonoSymbolFile file
, string file_name
)
685 this.file_name
= file_name
;
686 this.Index
= file
.AddSource (this);
691 public SourceFileEntry (MonoSymbolFile file
, string file_name
,
692 byte[] guid
, byte[] checksum
)
693 : this (file
, file_name
)
696 this.hash
= checksum
;
699 internal void WriteData (MyBinaryWriter bw
)
701 DataOffset
= (int) bw
.BaseStream
.Position
;
702 bw
.Write (file_name
);
705 guid
= Guid
.NewGuid ().ToByteArray ();
707 using (FileStream fs
= new FileStream (file_name
, FileMode
.Open
, FileAccess
.Read
)) {
708 MD5 md5
= MD5
.Create ();
709 hash
= md5
.ComputeHash (fs
);
712 hash
= new byte [16];
718 bw
.Write ((byte) (auto_generated
? 1 : 0));
721 internal void Write (BinaryWriter bw
)
724 bw
.Write (DataOffset
);
727 internal SourceFileEntry (MonoSymbolFile file
, MyBinaryReader reader
)
731 Index
= reader
.ReadInt32 ();
732 DataOffset
= reader
.ReadInt32 ();
734 int old_pos
= (int) reader
.BaseStream
.Position
;
735 reader
.BaseStream
.Position
= DataOffset
;
737 file_name
= reader
.ReadString ();
738 guid
= reader
.ReadBytes (16);
739 hash
= reader
.ReadBytes (16);
740 auto_generated
= reader
.ReadByte () == 1;
742 reader
.BaseStream
.Position
= old_pos
;
745 public string FileName
{
746 get { return file_name; }
749 public bool AutoGenerated
{
750 get { return auto_generated; }
753 public void SetAutoGenerated ()
756 throw new InvalidOperationException ();
758 auto_generated
= true;
759 file
.OffsetTable
.FileFlags
|= OffsetTable
.Flags
.IsAspxSource
;
762 public bool CheckChecksum ()
765 using (FileStream fs
= new FileStream (file_name
, FileMode
.Open
)) {
766 MD5 md5
= MD5
.Create ();
767 byte[] data
= md5
.ComputeHash (fs
);
768 for (int i
= 0; i
< 16; i
++)
769 if (data
[i
] != hash
[i
])
778 public override string ToString ()
780 return String
.Format ("SourceFileEntry ({0}:{1})", Index
, DataOffset
);
784 public class LineNumberTable
786 protected LineNumberEntry
[] _line_numbers
;
787 public LineNumberEntry
[] LineNumbers
{
788 get { return _line_numbers; }
791 public readonly int LineBase
;
792 public readonly int LineRange
;
793 public readonly byte OpcodeBase
;
794 public readonly int MaxAddressIncrement
;
796 #region Configurable constants
797 public const int Default_LineBase
= -1;
798 public const int Default_LineRange
= 8;
799 public const byte Default_OpcodeBase
= 9;
801 public const bool SuppressDuplicates
= true;
804 public const byte DW_LNS_copy
= 1;
805 public const byte DW_LNS_advance_pc
= 2;
806 public const byte DW_LNS_advance_line
= 3;
807 public const byte DW_LNS_set_file
= 4;
808 public const byte DW_LNS_const_add_pc
= 8;
810 public const byte DW_LNE_end_sequence
= 1;
813 public const byte DW_LNE_MONO_negate_is_hidden
= 0x40;
815 protected LineNumberTable (MonoSymbolFile file
)
817 this.LineBase
= file
.OffsetTable
.LineNumberTable_LineBase
;
818 this.LineRange
= file
.OffsetTable
.LineNumberTable_LineRange
;
819 this.OpcodeBase
= (byte) file
.OffsetTable
.LineNumberTable_OpcodeBase
;
820 this.MaxAddressIncrement
= (255 - OpcodeBase
) / LineRange
;
823 internal LineNumberTable (MonoSymbolFile file
, LineNumberEntry
[] lines
)
826 this._line_numbers
= lines
;
829 internal void Write (MonoSymbolFile file
, MyBinaryWriter bw
)
831 int start
= (int) bw
.BaseStream
.Position
;
833 bool last_is_hidden
= false;
834 int last_line
= 1, last_offset
= 0, last_file
= 1;
835 for (int i
= 0; i
< LineNumbers
.Length
; i
++) {
836 int line_inc
= LineNumbers
[i
].Row
- last_line
;
837 int offset_inc
= LineNumbers
[i
].Offset
- last_offset
;
839 if (SuppressDuplicates
&& (i
+1 < LineNumbers
.Length
)) {
840 if (LineNumbers
[i
+1].Equals (LineNumbers
[i
]))
844 if (LineNumbers
[i
].File
!= last_file
) {
845 bw
.Write (DW_LNS_set_file
);
846 bw
.WriteLeb128 (LineNumbers
[i
].File
);
847 last_file
= LineNumbers
[i
].File
;
850 if (LineNumbers
[i
].IsHidden
!= last_is_hidden
) {
853 bw
.Write (DW_LNE_MONO_negate_is_hidden
);
854 last_is_hidden
= LineNumbers
[i
].IsHidden
;
857 if (offset_inc
>= MaxAddressIncrement
) {
858 if (offset_inc
< 2 * MaxAddressIncrement
) {
859 bw
.Write (DW_LNS_const_add_pc
);
860 offset_inc
-= MaxAddressIncrement
;
862 bw
.Write (DW_LNS_advance_pc
);
863 bw
.WriteLeb128 (offset_inc
);
868 if ((line_inc
< LineBase
) || (line_inc
>= LineBase
+ LineRange
)) {
869 bw
.Write (DW_LNS_advance_line
);
870 bw
.WriteLeb128 (line_inc
);
871 if (offset_inc
!= 0) {
872 bw
.Write (DW_LNS_advance_pc
);
873 bw
.WriteLeb128 (offset_inc
);
875 bw
.Write (DW_LNS_copy
);
878 opcode
= (byte) (line_inc
- LineBase
+ (LineRange
* offset_inc
) +
883 last_line
= LineNumbers
[i
].Row
;
884 last_offset
= LineNumbers
[i
].Offset
;
889 bw
.Write (DW_LNE_end_sequence
);
891 file
.ExtendedLineNumberSize
+= (int) bw
.BaseStream
.Position
- start
;
894 internal static LineNumberTable
Read (MonoSymbolFile file
, MyBinaryReader br
)
896 LineNumberTable lnt
= new LineNumberTable (file
);
897 lnt
.DoRead (file
, br
);
901 void DoRead (MonoSymbolFile file
, MyBinaryReader br
)
903 ArrayList lines
= new ArrayList ();
905 bool is_hidden
= false, modified
= false;
906 int stm_line
= 1, stm_offset
= 0, stm_file
= 1;
908 byte opcode
= br
.ReadByte ();
911 byte size
= br
.ReadByte ();
912 long end_pos
= br
.BaseStream
.Position
+ size
;
913 opcode
= br
.ReadByte ();
915 if (opcode
== DW_LNE_end_sequence
) {
917 lines
.Add (new LineNumberEntry (
918 stm_file
, stm_line
, stm_offset
, is_hidden
));
920 } else if (opcode
== DW_LNE_MONO_negate_is_hidden
) {
921 is_hidden
= !is_hidden
;
924 throw new MonoSymbolFileException (
925 "Unknown extended opcode {0:x} in LNT ({1})",
926 opcode
, file
.FileName
);
928 br
.BaseStream
.Position
= end_pos
;
930 } else if (opcode
< OpcodeBase
) {
933 lines
.Add (new LineNumberEntry (
934 stm_file
, stm_line
, stm_offset
, is_hidden
));
937 case DW_LNS_advance_pc
:
938 stm_offset
+= br
.ReadLeb128 ();
941 case DW_LNS_advance_line
:
942 stm_line
+= br
.ReadLeb128 ();
945 case DW_LNS_set_file
:
946 stm_file
= br
.ReadLeb128 ();
949 case DW_LNS_const_add_pc
:
950 stm_offset
+= MaxAddressIncrement
;
954 throw new MonoSymbolFileException (
955 "Unknown standard opcode {0:x} in LNT",
959 opcode
-= OpcodeBase
;
961 stm_offset
+= opcode
/ LineRange
;
962 stm_line
+= LineBase
+ (opcode
% LineRange
);
963 lines
.Add (new LineNumberEntry (
964 stm_file
, stm_line
, stm_offset
, is_hidden
));
969 _line_numbers
= new LineNumberEntry
[lines
.Count
];
970 lines
.CopyTo (_line_numbers
, 0);
973 public bool GetMethodBounds (out LineNumberEntry start
, out LineNumberEntry end
)
975 if (_line_numbers
.Length
> 1) {
976 start
= _line_numbers
[0];
977 end
= _line_numbers
[_line_numbers
.Length
- 1];
981 start
= LineNumberEntry
.Null
;
982 end
= LineNumberEntry
.Null
;
987 public class MethodEntry
: IComparable
989 #region This is actually written to the symbol file
990 public readonly int CompileUnitIndex
;
991 public readonly int Token
;
992 public readonly int NamespaceID
;
995 int LocalVariableTableOffset
;
996 int LineNumberTableOffset
;
997 int CodeBlockTableOffset
;
998 int ScopeVariableTableOffset
;
1005 public Flags MethodFlags
{
1006 get { return flags; }
1009 public readonly CompileUnitEntry CompileUnit
;
1011 LocalVariableEntry
[] locals
;
1012 CodeBlockEntry
[] code_blocks
;
1013 ScopeVariable
[] scope_vars
;
1014 LineNumberTable lnt
;
1017 public readonly MonoSymbolFile SymbolFile
;
1020 get { return index; }
1021 set { index = value; }
1027 LocalNamesAmbiguous
= 1
1030 public const int Size
= 12;
1032 internal MethodEntry (MonoSymbolFile file
, MyBinaryReader reader
, int index
)
1034 this.SymbolFile
= file
;
1037 Token
= reader
.ReadInt32 ();
1038 DataOffset
= reader
.ReadInt32 ();
1039 LineNumberTableOffset
= reader
.ReadInt32 ();
1041 long old_pos
= reader
.BaseStream
.Position
;
1042 reader
.BaseStream
.Position
= DataOffset
;
1044 CompileUnitIndex
= reader
.ReadLeb128 ();
1045 LocalVariableTableOffset
= reader
.ReadLeb128 ();
1046 NamespaceID
= reader
.ReadLeb128 ();
1048 CodeBlockTableOffset
= reader
.ReadLeb128 ();
1049 ScopeVariableTableOffset
= reader
.ReadLeb128 ();
1051 RealNameOffset
= reader
.ReadLeb128 ();
1053 flags
= (Flags
) reader
.ReadLeb128 ();
1055 reader
.BaseStream
.Position
= old_pos
;
1057 CompileUnit
= file
.GetCompileUnit (CompileUnitIndex
);
1060 internal MethodEntry (MonoSymbolFile file
, CompileUnitEntry comp_unit
,
1061 int token
, ScopeVariable
[] scope_vars
,
1062 LocalVariableEntry
[] locals
, LineNumberEntry
[] lines
,
1063 CodeBlockEntry
[] code_blocks
, string real_name
,
1064 Flags flags
, int namespace_id
)
1066 this.SymbolFile
= file
;
1067 this.real_name
= real_name
;
1068 this.locals
= locals
;
1069 this.code_blocks
= code_blocks
;
1070 this.scope_vars
= scope_vars
;
1076 CompileUnitIndex
= comp_unit
.Index
;
1077 CompileUnit
= comp_unit
;
1078 NamespaceID
= namespace_id
;
1080 CheckLineNumberTable (lines
);
1081 lnt
= new LineNumberTable (file
, lines
);
1082 file
.NumLineNumbers
+= lines
.Length
;
1084 int num_locals
= locals
!= null ? locals
.Length
: 0;
1086 if (num_locals
<= 32) {
1087 // Most of the time, the O(n^2) factor is actually
1088 // less than the cost of allocating the hash table,
1089 // 32 is a rough number obtained through some testing.
1091 for (int i
= 0; i
< num_locals
; i
++) {
1092 string nm
= locals
[i
].Name
;
1094 for (int j
= i
+ 1; j
< num_locals
; j
++) {
1095 if (locals
[j
].Name
== nm
) {
1096 flags
|= Flags
.LocalNamesAmbiguous
;
1097 goto locals_check_done
;
1104 Hashtable local_names
= new Hashtable ();
1105 foreach (LocalVariableEntry local
in locals
) {
1106 if (local_names
.Contains (local
.Name
)) {
1107 flags
|= Flags
.LocalNamesAmbiguous
;
1110 local_names
.Add (local
.Name
, local
);
1115 void CheckLineNumberTable (LineNumberEntry
[] line_numbers
)
1117 int last_offset
= -1;
1120 if (line_numbers
== null)
1123 for (int i
= 0; i
< line_numbers
.Length
; i
++) {
1124 LineNumberEntry line
= line_numbers
[i
];
1126 if (line
.Equals (LineNumberEntry
.Null
))
1127 throw new MonoSymbolFileException ();
1129 if (line
.Offset
< last_offset
)
1130 throw new MonoSymbolFileException ();
1132 if (line
.Offset
> last_offset
) {
1133 last_row
= line
.Row
;
1134 last_offset
= line
.Offset
;
1135 } else if (line
.Row
> last_row
) {
1136 last_row
= line
.Row
;
1141 internal void Write (MyBinaryWriter bw
)
1143 if ((index
<= 0) || (DataOffset
== 0))
1144 throw new InvalidOperationException ();
1147 bw
.Write (DataOffset
);
1148 bw
.Write (LineNumberTableOffset
);
1151 internal void WriteData (MonoSymbolFile file
, MyBinaryWriter bw
)
1154 throw new InvalidOperationException ();
1156 LocalVariableTableOffset
= (int) bw
.BaseStream
.Position
;
1157 int num_locals
= locals
!= null ? locals
.Length
: 0;
1158 bw
.WriteLeb128 (num_locals
);
1159 for (int i
= 0; i
< num_locals
; i
++)
1160 locals
[i
].Write (file
, bw
);
1161 file
.LocalCount
+= num_locals
;
1163 CodeBlockTableOffset
= (int) bw
.BaseStream
.Position
;
1164 int num_code_blocks
= code_blocks
!= null ? code_blocks
.Length
: 0;
1165 bw
.WriteLeb128 (num_code_blocks
);
1166 for (int i
= 0; i
< num_code_blocks
; i
++)
1167 code_blocks
[i
].Write (bw
);
1169 ScopeVariableTableOffset
= (int) bw
.BaseStream
.Position
;
1170 int num_scope_vars
= scope_vars
!= null ? scope_vars
.Length
: 0;
1171 bw
.WriteLeb128 (num_scope_vars
);
1172 for (int i
= 0; i
< num_scope_vars
; i
++)
1173 scope_vars
[i
].Write (bw
);
1175 if (real_name
!= null) {
1176 RealNameOffset
= (int) bw
.BaseStream
.Position
;
1177 bw
.Write (real_name
);
1180 LineNumberTableOffset
= (int) bw
.BaseStream
.Position
;
1181 lnt
.Write (file
, bw
);
1183 DataOffset
= (int) bw
.BaseStream
.Position
;
1185 bw
.WriteLeb128 (CompileUnitIndex
);
1186 bw
.WriteLeb128 (LocalVariableTableOffset
);
1187 bw
.WriteLeb128 (NamespaceID
);
1189 bw
.WriteLeb128 (CodeBlockTableOffset
);
1190 bw
.WriteLeb128 (ScopeVariableTableOffset
);
1192 bw
.WriteLeb128 (RealNameOffset
);
1193 bw
.WriteLeb128 ((int) flags
);
1196 public LineNumberTable
GetLineNumberTable ()
1202 if (LineNumberTableOffset
== 0)
1205 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1206 long old_pos
= reader
.BaseStream
.Position
;
1207 reader
.BaseStream
.Position
= LineNumberTableOffset
;
1209 lnt
= LineNumberTable
.Read (SymbolFile
, reader
);
1211 reader
.BaseStream
.Position
= old_pos
;
1216 public LocalVariableEntry
[] GetLocals ()
1222 if (LocalVariableTableOffset
== 0)
1225 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1226 long old_pos
= reader
.BaseStream
.Position
;
1227 reader
.BaseStream
.Position
= LocalVariableTableOffset
;
1229 int num_locals
= reader
.ReadLeb128 ();
1230 locals
= new LocalVariableEntry
[num_locals
];
1232 for (int i
= 0; i
< num_locals
; i
++)
1233 locals
[i
] = new LocalVariableEntry (SymbolFile
, reader
);
1235 reader
.BaseStream
.Position
= old_pos
;
1240 public CodeBlockEntry
[] GetCodeBlocks ()
1243 if (code_blocks
!= null)
1246 if (CodeBlockTableOffset
== 0)
1249 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1250 long old_pos
= reader
.BaseStream
.Position
;
1251 reader
.BaseStream
.Position
= CodeBlockTableOffset
;
1253 int num_code_blocks
= reader
.ReadLeb128 ();
1254 code_blocks
= new CodeBlockEntry
[num_code_blocks
];
1256 for (int i
= 0; i
< num_code_blocks
; i
++)
1257 code_blocks
[i
] = new CodeBlockEntry (i
, reader
);
1259 reader
.BaseStream
.Position
= old_pos
;
1264 public ScopeVariable
[] GetScopeVariables ()
1267 if (scope_vars
!= null)
1270 if (ScopeVariableTableOffset
== 0)
1273 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1274 long old_pos
= reader
.BaseStream
.Position
;
1275 reader
.BaseStream
.Position
= ScopeVariableTableOffset
;
1277 int num_scope_vars
= reader
.ReadLeb128 ();
1278 scope_vars
= new ScopeVariable
[num_scope_vars
];
1280 for (int i
= 0; i
< num_scope_vars
; i
++)
1281 scope_vars
[i
] = new ScopeVariable (reader
);
1283 reader
.BaseStream
.Position
= old_pos
;
1288 public string GetRealName ()
1291 if (real_name
!= null)
1294 if (RealNameOffset
== 0)
1297 real_name
= SymbolFile
.BinaryReader
.ReadString (RealNameOffset
);
1302 public int CompareTo (object obj
)
1304 MethodEntry method
= (MethodEntry
) obj
;
1306 if (method
.Token
< Token
)
1308 else if (method
.Token
> Token
)
1314 public override string ToString ()
1316 return String
.Format ("[Method {0}:{1:x}:{2}:{3}]",
1317 index
, Token
, CompileUnitIndex
, CompileUnit
);
1321 public struct NamespaceEntry
1323 #region This is actually written to the symbol file
1324 public readonly string Name
;
1325 public readonly int Index
;
1326 public readonly int Parent
;
1327 public readonly string[] UsingClauses
;
1330 public NamespaceEntry (string name
, int index
, string[] using_clauses
, int parent
)
1334 this.Parent
= parent
;
1335 this.UsingClauses
= using_clauses
!= null ? using_clauses
: new string [0];
1338 internal NamespaceEntry (MonoSymbolFile file
, MyBinaryReader reader
)
1340 Name
= reader
.ReadString ();
1341 Index
= reader
.ReadLeb128 ();
1342 Parent
= reader
.ReadLeb128 ();
1344 int count
= reader
.ReadLeb128 ();
1345 UsingClauses
= new string [count
];
1346 for (int i
= 0; i
< count
; i
++)
1347 UsingClauses
[i
] = reader
.ReadString ();
1350 internal void Write (MonoSymbolFile file
, MyBinaryWriter bw
)
1353 bw
.WriteLeb128 (Index
);
1354 bw
.WriteLeb128 (Parent
);
1355 bw
.WriteLeb128 (UsingClauses
.Length
);
1356 foreach (string uc
in UsingClauses
)
1360 public override string ToString ()
1362 return String
.Format ("[Namespace {0}:{1}:{2}]", Name
, Index
, Parent
);