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
- 1);
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 include_files
.Add (file
.GetSourceFile (reader
.ReadLeb128 ()));
643 int count_ns
= reader
.ReadLeb128 ();
644 namespaces
= new ArrayList ();
645 for (int i
= 0; i
< count_ns
; i
++)
646 namespaces
.Add (new NamespaceEntry (file
, reader
));
648 reader
.BaseStream
.Position
= old_pos
;
652 public NamespaceEntry
[] Namespaces
{
655 NamespaceEntry
[] retval
= new NamespaceEntry
[namespaces
.Count
];
656 namespaces
.CopyTo (retval
, 0);
661 public SourceFileEntry
[] IncludeFiles
{
664 if (include_files
== null)
665 return new SourceFileEntry
[0];
667 SourceFileEntry
[] retval
= new SourceFileEntry
[include_files
.Count
];
668 include_files
.CopyTo (retval
, 0);
674 public class SourceFileEntry
676 #region This is actually written to the symbol file
677 public readonly int Index
;
688 public static int Size
{
692 public SourceFileEntry (MonoSymbolFile file
, string file_name
)
695 this.file_name
= file_name
;
696 this.Index
= file
.AddSource (this);
701 public SourceFileEntry (MonoSymbolFile file
, string file_name
,
702 byte[] guid
, byte[] checksum
)
703 : this (file
, file_name
)
706 this.hash
= checksum
;
709 internal void WriteData (MyBinaryWriter bw
)
711 DataOffset
= (int) bw
.BaseStream
.Position
;
712 bw
.Write (file_name
);
715 guid
= Guid
.NewGuid ().ToByteArray ();
717 using (FileStream fs
= new FileStream (file_name
, FileMode
.Open
, FileAccess
.Read
)) {
718 MD5 md5
= MD5
.Create ();
719 hash
= md5
.ComputeHash (fs
);
722 hash
= new byte [16];
728 bw
.Write ((byte) (auto_generated
? 1 : 0));
731 internal void Write (BinaryWriter bw
)
734 bw
.Write (DataOffset
);
737 internal SourceFileEntry (MonoSymbolFile file
, MyBinaryReader reader
)
741 Index
= reader
.ReadInt32 ();
742 DataOffset
= reader
.ReadInt32 ();
744 int old_pos
= (int) reader
.BaseStream
.Position
;
745 reader
.BaseStream
.Position
= DataOffset
;
747 file_name
= reader
.ReadString ();
748 guid
= reader
.ReadBytes (16);
749 hash
= reader
.ReadBytes (16);
750 auto_generated
= reader
.ReadByte () == 1;
752 reader
.BaseStream
.Position
= old_pos
;
755 public string FileName
{
756 get { return file_name; }
759 public bool AutoGenerated
{
760 get { return auto_generated; }
763 public void SetAutoGenerated ()
766 throw new InvalidOperationException ();
768 auto_generated
= true;
769 file
.OffsetTable
.FileFlags
|= OffsetTable
.Flags
.IsAspxSource
;
772 public bool CheckChecksum ()
775 using (FileStream fs
= new FileStream (file_name
, FileMode
.Open
)) {
776 MD5 md5
= MD5
.Create ();
777 byte[] data
= md5
.ComputeHash (fs
);
778 for (int i
= 0; i
< 16; i
++)
779 if (data
[i
] != hash
[i
])
788 public override string ToString ()
790 return String
.Format ("SourceFileEntry ({0}:{1})", Index
, DataOffset
);
794 public class LineNumberTable
796 protected LineNumberEntry
[] _line_numbers
;
797 public LineNumberEntry
[] LineNumbers
{
798 get { return _line_numbers; }
801 public readonly int LineBase
;
802 public readonly int LineRange
;
803 public readonly byte OpcodeBase
;
804 public readonly int MaxAddressIncrement
;
806 #region Configurable constants
807 public const int Default_LineBase
= -1;
808 public const int Default_LineRange
= 8;
809 public const byte Default_OpcodeBase
= 9;
811 public const bool SuppressDuplicates
= true;
814 public const byte DW_LNS_copy
= 1;
815 public const byte DW_LNS_advance_pc
= 2;
816 public const byte DW_LNS_advance_line
= 3;
817 public const byte DW_LNS_set_file
= 4;
818 public const byte DW_LNS_const_add_pc
= 8;
820 public const byte DW_LNE_end_sequence
= 1;
823 public const byte DW_LNE_MONO_negate_is_hidden
= 0x40;
825 internal const byte DW_LNE_MONO__extensions_start
= 0x40;
826 internal const byte DW_LNE_MONO__extensions_end
= 0x7f;
828 protected LineNumberTable (MonoSymbolFile file
)
830 this.LineBase
= file
.OffsetTable
.LineNumberTable_LineBase
;
831 this.LineRange
= file
.OffsetTable
.LineNumberTable_LineRange
;
832 this.OpcodeBase
= (byte) file
.OffsetTable
.LineNumberTable_OpcodeBase
;
833 this.MaxAddressIncrement
= (255 - OpcodeBase
) / LineRange
;
836 internal LineNumberTable (MonoSymbolFile file
, LineNumberEntry
[] lines
)
839 this._line_numbers
= lines
;
842 internal void Write (MonoSymbolFile file
, MyBinaryWriter bw
)
844 int start
= (int) bw
.BaseStream
.Position
;
846 bool last_is_hidden
= false;
847 int last_line
= 1, last_offset
= 0, last_file
= 1;
848 for (int i
= 0; i
< LineNumbers
.Length
; i
++) {
849 int line_inc
= LineNumbers
[i
].Row
- last_line
;
850 int offset_inc
= LineNumbers
[i
].Offset
- last_offset
;
852 if (SuppressDuplicates
&& (i
+1 < LineNumbers
.Length
)) {
853 if (LineNumbers
[i
+1].Equals (LineNumbers
[i
]))
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
;
863 if (LineNumbers
[i
].IsHidden
!= last_is_hidden
) {
866 bw
.Write (DW_LNE_MONO_negate_is_hidden
);
867 last_is_hidden
= LineNumbers
[i
].IsHidden
;
870 if (offset_inc
>= MaxAddressIncrement
) {
871 if (offset_inc
< 2 * MaxAddressIncrement
) {
872 bw
.Write (DW_LNS_const_add_pc
);
873 offset_inc
-= MaxAddressIncrement
;
875 bw
.Write (DW_LNS_advance_pc
);
876 bw
.WriteLeb128 (offset_inc
);
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
);
888 bw
.Write (DW_LNS_copy
);
891 opcode
= (byte) (line_inc
- LineBase
+ (LineRange
* offset_inc
) +
896 last_line
= LineNumbers
[i
].Row
;
897 last_offset
= LineNumbers
[i
].Offset
;
902 bw
.Write (DW_LNE_end_sequence
);
904 file
.ExtendedLineNumberSize
+= (int) bw
.BaseStream
.Position
- start
;
907 internal static LineNumberTable
Read (MonoSymbolFile file
, MyBinaryReader br
)
909 LineNumberTable lnt
= new LineNumberTable (file
);
910 lnt
.DoRead (file
, br
);
914 void DoRead (MonoSymbolFile file
, MyBinaryReader br
)
916 ArrayList lines
= new ArrayList ();
918 bool is_hidden
= false, modified
= false;
919 int stm_line
= 1, stm_offset
= 0, stm_file
= 1;
921 byte opcode
= br
.ReadByte ();
924 byte size
= br
.ReadByte ();
925 long end_pos
= br
.BaseStream
.Position
+ size
;
926 opcode
= br
.ReadByte ();
928 if (opcode
== DW_LNE_end_sequence
) {
930 lines
.Add (new LineNumberEntry (
931 stm_file
, stm_line
, stm_offset
, is_hidden
));
933 } else if (opcode
== DW_LNE_MONO_negate_is_hidden
) {
934 is_hidden
= !is_hidden
;
936 } else if ((opcode
>= DW_LNE_MONO__extensions_start
) &&
937 (opcode
<= DW_LNE_MONO__extensions_end
)) {
938 ; // reserved for future extensions
940 throw new MonoSymbolFileException (
941 "Unknown extended opcode {0:x} in LNT ({1})",
942 opcode
, file
.FileName
);
945 br
.BaseStream
.Position
= end_pos
;
947 } else if (opcode
< OpcodeBase
) {
950 lines
.Add (new LineNumberEntry (
951 stm_file
, stm_line
, stm_offset
, is_hidden
));
954 case DW_LNS_advance_pc
:
955 stm_offset
+= br
.ReadLeb128 ();
958 case DW_LNS_advance_line
:
959 stm_line
+= br
.ReadLeb128 ();
962 case DW_LNS_set_file
:
963 stm_file
= br
.ReadLeb128 ();
966 case DW_LNS_const_add_pc
:
967 stm_offset
+= MaxAddressIncrement
;
971 throw new MonoSymbolFileException (
972 "Unknown standard opcode {0:x} in LNT",
976 opcode
-= OpcodeBase
;
978 stm_offset
+= opcode
/ LineRange
;
979 stm_line
+= LineBase
+ (opcode
% LineRange
);
980 lines
.Add (new LineNumberEntry (
981 stm_file
, stm_line
, stm_offset
, is_hidden
));
986 _line_numbers
= new LineNumberEntry
[lines
.Count
];
987 lines
.CopyTo (_line_numbers
, 0);
990 public bool GetMethodBounds (out LineNumberEntry start
, out LineNumberEntry end
)
992 if (_line_numbers
.Length
> 1) {
993 start
= _line_numbers
[0];
994 end
= _line_numbers
[_line_numbers
.Length
- 1];
998 start
= LineNumberEntry
.Null
;
999 end
= LineNumberEntry
.Null
;
1004 public class MethodEntry
: IComparable
1006 #region This is actually written to the symbol file
1007 public readonly int CompileUnitIndex
;
1008 public readonly int Token
;
1009 public readonly int NamespaceID
;
1012 int LocalVariableTableOffset
;
1013 int LineNumberTableOffset
;
1014 int CodeBlockTableOffset
;
1015 int ScopeVariableTableOffset
;
1022 public Flags MethodFlags
{
1023 get { return flags; }
1026 public readonly CompileUnitEntry CompileUnit
;
1028 LocalVariableEntry
[] locals
;
1029 CodeBlockEntry
[] code_blocks
;
1030 ScopeVariable
[] scope_vars
;
1031 LineNumberTable lnt
;
1034 public readonly MonoSymbolFile SymbolFile
;
1037 get { return index; }
1038 set { index = value; }
1044 LocalNamesAmbiguous
= 1
1047 public const int Size
= 12;
1049 internal MethodEntry (MonoSymbolFile file
, MyBinaryReader reader
, int index
)
1051 this.SymbolFile
= file
;
1054 Token
= reader
.ReadInt32 ();
1055 DataOffset
= reader
.ReadInt32 ();
1056 LineNumberTableOffset
= reader
.ReadInt32 ();
1058 long old_pos
= reader
.BaseStream
.Position
;
1059 reader
.BaseStream
.Position
= DataOffset
;
1061 CompileUnitIndex
= reader
.ReadLeb128 ();
1062 LocalVariableTableOffset
= reader
.ReadLeb128 ();
1063 NamespaceID
= reader
.ReadLeb128 ();
1065 CodeBlockTableOffset
= reader
.ReadLeb128 ();
1066 ScopeVariableTableOffset
= reader
.ReadLeb128 ();
1068 RealNameOffset
= reader
.ReadLeb128 ();
1070 flags
= (Flags
) reader
.ReadLeb128 ();
1072 reader
.BaseStream
.Position
= old_pos
;
1074 CompileUnit
= file
.GetCompileUnit (CompileUnitIndex
);
1077 internal MethodEntry (MonoSymbolFile file
, CompileUnitEntry comp_unit
,
1078 int token
, ScopeVariable
[] scope_vars
,
1079 LocalVariableEntry
[] locals
, LineNumberEntry
[] lines
,
1080 CodeBlockEntry
[] code_blocks
, string real_name
,
1081 Flags flags
, int namespace_id
)
1083 this.SymbolFile
= file
;
1084 this.real_name
= real_name
;
1085 this.locals
= locals
;
1086 this.code_blocks
= code_blocks
;
1087 this.scope_vars
= scope_vars
;
1093 CompileUnitIndex
= comp_unit
.Index
;
1094 CompileUnit
= comp_unit
;
1095 NamespaceID
= namespace_id
;
1097 CheckLineNumberTable (lines
);
1098 lnt
= new LineNumberTable (file
, lines
);
1099 file
.NumLineNumbers
+= lines
.Length
;
1101 int num_locals
= locals
!= null ? locals
.Length
: 0;
1103 if (num_locals
<= 32) {
1104 // Most of the time, the O(n^2) factor is actually
1105 // less than the cost of allocating the hash table,
1106 // 32 is a rough number obtained through some testing.
1108 for (int i
= 0; i
< num_locals
; i
++) {
1109 string nm
= locals
[i
].Name
;
1111 for (int j
= i
+ 1; j
< num_locals
; j
++) {
1112 if (locals
[j
].Name
== nm
) {
1113 flags
|= Flags
.LocalNamesAmbiguous
;
1114 goto locals_check_done
;
1121 Hashtable local_names
= new Hashtable ();
1122 foreach (LocalVariableEntry local
in locals
) {
1123 if (local_names
.Contains (local
.Name
)) {
1124 flags
|= Flags
.LocalNamesAmbiguous
;
1127 local_names
.Add (local
.Name
, local
);
1132 void CheckLineNumberTable (LineNumberEntry
[] line_numbers
)
1134 int last_offset
= -1;
1137 if (line_numbers
== null)
1140 for (int i
= 0; i
< line_numbers
.Length
; i
++) {
1141 LineNumberEntry line
= line_numbers
[i
];
1143 if (line
.Equals (LineNumberEntry
.Null
))
1144 throw new MonoSymbolFileException ();
1146 if (line
.Offset
< last_offset
)
1147 throw new MonoSymbolFileException ();
1149 if (line
.Offset
> last_offset
) {
1150 last_row
= line
.Row
;
1151 last_offset
= line
.Offset
;
1152 } else if (line
.Row
> last_row
) {
1153 last_row
= line
.Row
;
1158 internal void Write (MyBinaryWriter bw
)
1160 if ((index
<= 0) || (DataOffset
== 0))
1161 throw new InvalidOperationException ();
1164 bw
.Write (DataOffset
);
1165 bw
.Write (LineNumberTableOffset
);
1168 internal void WriteData (MonoSymbolFile file
, MyBinaryWriter bw
)
1171 throw new InvalidOperationException ();
1173 LocalVariableTableOffset
= (int) bw
.BaseStream
.Position
;
1174 int num_locals
= locals
!= null ? locals
.Length
: 0;
1175 bw
.WriteLeb128 (num_locals
);
1176 for (int i
= 0; i
< num_locals
; i
++)
1177 locals
[i
].Write (file
, bw
);
1178 file
.LocalCount
+= num_locals
;
1180 CodeBlockTableOffset
= (int) bw
.BaseStream
.Position
;
1181 int num_code_blocks
= code_blocks
!= null ? code_blocks
.Length
: 0;
1182 bw
.WriteLeb128 (num_code_blocks
);
1183 for (int i
= 0; i
< num_code_blocks
; i
++)
1184 code_blocks
[i
].Write (bw
);
1186 ScopeVariableTableOffset
= (int) bw
.BaseStream
.Position
;
1187 int num_scope_vars
= scope_vars
!= null ? scope_vars
.Length
: 0;
1188 bw
.WriteLeb128 (num_scope_vars
);
1189 for (int i
= 0; i
< num_scope_vars
; i
++)
1190 scope_vars
[i
].Write (bw
);
1192 if (real_name
!= null) {
1193 RealNameOffset
= (int) bw
.BaseStream
.Position
;
1194 bw
.Write (real_name
);
1197 LineNumberTableOffset
= (int) bw
.BaseStream
.Position
;
1198 lnt
.Write (file
, bw
);
1200 DataOffset
= (int) bw
.BaseStream
.Position
;
1202 bw
.WriteLeb128 (CompileUnitIndex
);
1203 bw
.WriteLeb128 (LocalVariableTableOffset
);
1204 bw
.WriteLeb128 (NamespaceID
);
1206 bw
.WriteLeb128 (CodeBlockTableOffset
);
1207 bw
.WriteLeb128 (ScopeVariableTableOffset
);
1209 bw
.WriteLeb128 (RealNameOffset
);
1210 bw
.WriteLeb128 ((int) flags
);
1213 public LineNumberTable
GetLineNumberTable ()
1219 if (LineNumberTableOffset
== 0)
1222 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1223 long old_pos
= reader
.BaseStream
.Position
;
1224 reader
.BaseStream
.Position
= LineNumberTableOffset
;
1226 lnt
= LineNumberTable
.Read (SymbolFile
, reader
);
1228 reader
.BaseStream
.Position
= old_pos
;
1233 public LocalVariableEntry
[] GetLocals ()
1239 if (LocalVariableTableOffset
== 0)
1242 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1243 long old_pos
= reader
.BaseStream
.Position
;
1244 reader
.BaseStream
.Position
= LocalVariableTableOffset
;
1246 int num_locals
= reader
.ReadLeb128 ();
1247 locals
= new LocalVariableEntry
[num_locals
];
1249 for (int i
= 0; i
< num_locals
; i
++)
1250 locals
[i
] = new LocalVariableEntry (SymbolFile
, reader
);
1252 reader
.BaseStream
.Position
= old_pos
;
1257 public CodeBlockEntry
[] GetCodeBlocks ()
1260 if (code_blocks
!= null)
1263 if (CodeBlockTableOffset
== 0)
1266 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1267 long old_pos
= reader
.BaseStream
.Position
;
1268 reader
.BaseStream
.Position
= CodeBlockTableOffset
;
1270 int num_code_blocks
= reader
.ReadLeb128 ();
1271 code_blocks
= new CodeBlockEntry
[num_code_blocks
];
1273 for (int i
= 0; i
< num_code_blocks
; i
++)
1274 code_blocks
[i
] = new CodeBlockEntry (i
, reader
);
1276 reader
.BaseStream
.Position
= old_pos
;
1281 public ScopeVariable
[] GetScopeVariables ()
1284 if (scope_vars
!= null)
1287 if (ScopeVariableTableOffset
== 0)
1290 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1291 long old_pos
= reader
.BaseStream
.Position
;
1292 reader
.BaseStream
.Position
= ScopeVariableTableOffset
;
1294 int num_scope_vars
= reader
.ReadLeb128 ();
1295 scope_vars
= new ScopeVariable
[num_scope_vars
];
1297 for (int i
= 0; i
< num_scope_vars
; i
++)
1298 scope_vars
[i
] = new ScopeVariable (reader
);
1300 reader
.BaseStream
.Position
= old_pos
;
1305 public string GetRealName ()
1308 if (real_name
!= null)
1311 if (RealNameOffset
== 0)
1314 real_name
= SymbolFile
.BinaryReader
.ReadString (RealNameOffset
);
1319 public int CompareTo (object obj
)
1321 MethodEntry method
= (MethodEntry
) obj
;
1323 if (method
.Token
< Token
)
1325 else if (method
.Token
> Token
)
1331 public override string ToString ()
1333 return String
.Format ("[Method {0}:{1:x}:{2}:{3}]",
1334 index
, Token
, CompileUnitIndex
, CompileUnit
);
1338 public struct NamespaceEntry
1340 #region This is actually written to the symbol file
1341 public readonly string Name
;
1342 public readonly int Index
;
1343 public readonly int Parent
;
1344 public readonly string[] UsingClauses
;
1347 public NamespaceEntry (string name
, int index
, string[] using_clauses
, int parent
)
1351 this.Parent
= parent
;
1352 this.UsingClauses
= using_clauses
!= null ? using_clauses
: new string [0];
1355 internal NamespaceEntry (MonoSymbolFile file
, MyBinaryReader reader
)
1357 Name
= reader
.ReadString ();
1358 Index
= reader
.ReadLeb128 ();
1359 Parent
= reader
.ReadLeb128 ();
1361 int count
= reader
.ReadLeb128 ();
1362 UsingClauses
= new string [count
];
1363 for (int i
= 0; i
< count
; i
++)
1364 UsingClauses
[i
] = reader
.ReadString ();
1367 internal void Write (MonoSymbolFile file
, MyBinaryWriter bw
)
1370 bw
.WriteLeb128 (Index
);
1371 bw
.WriteLeb128 (Parent
);
1372 bw
.WriteLeb128 (UsingClauses
.Length
);
1373 foreach (string uc
in UsingClauses
)
1377 public override string ToString ()
1379 return String
.Format ("[Namespace {0}:{1}:{2}]", Name
, Index
, Parent
);