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
.Generic
;
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
;
187 public int EndRow
, EndColumn
;
188 public readonly int File
;
189 public readonly int Offset
;
190 public readonly bool IsHidden
; // Obsolete is never used
193 public sealed class LocationComparer
: IComparer
<LineNumberEntry
>
195 public static readonly LocationComparer Default
= new LocationComparer ();
197 public int Compare (LineNumberEntry l1
, LineNumberEntry l2
)
199 return l1
.Row
== l2
.Row
?
200 l1
.Column
.CompareTo (l2
.Column
) :
201 l1
.Row
.CompareTo (l2
.Row
);
205 public static readonly LineNumberEntry Null
= new LineNumberEntry (0, 0, 0, 0);
207 public LineNumberEntry (int file
, int row
, int column
, int offset
)
208 : this (file
, row
, column
, offset
, false)
212 public LineNumberEntry (int file
, int row
, int offset
)
213 : this (file
, row
, -1, offset
, false)
217 public LineNumberEntry (int file
, int row
, int column
, int offset
, bool is_hidden
)
218 : this (file
, row
, column
, -1, -1, offset
, is_hidden
)
222 public LineNumberEntry (int file
, int row
, int column
, int end_row
, int end_column
, int offset
, bool is_hidden
)
226 this.Column
= column
;
227 this.EndRow
= end_row
;
228 this.EndColumn
= end_column
;
229 this.Offset
= offset
;
230 this.IsHidden
= is_hidden
;
233 public override string ToString ()
235 return String
.Format ("[Line {0}:{1,2}-{3,4}:{5}]", File
, Row
, Column
, EndRow
, EndColumn
, Offset
);
239 public class CodeBlockEntry
242 #region This is actually written to the symbol file
244 public Type BlockType
;
245 public int StartOffset
;
246 public int EndOffset
;
251 CompilerGenerated
= 2,
253 IteratorDispatcher
= 4
256 public CodeBlockEntry (int index
, int parent
, Type type
, int start_offset
)
259 this.Parent
= parent
;
260 this.BlockType
= type
;
261 this.StartOffset
= start_offset
;
264 internal CodeBlockEntry (int index
, MyBinaryReader reader
)
267 int type_flag
= reader
.ReadLeb128 ();
268 BlockType
= (Type
) (type_flag
& 0x3f);
269 this.Parent
= reader
.ReadLeb128 ();
270 this.StartOffset
= reader
.ReadLeb128 ();
271 this.EndOffset
= reader
.ReadLeb128 ();
273 /* Reserved for future extensions. */
274 if ((type_flag
& 0x40) != 0) {
275 int data_size
= reader
.ReadInt16 ();
276 reader
.BaseStream
.Position
+= data_size
;
280 public void Close (int end_offset
)
282 this.EndOffset
= end_offset
;
285 internal void Write (MyBinaryWriter bw
)
287 bw
.WriteLeb128 ((int) BlockType
);
288 bw
.WriteLeb128 (Parent
);
289 bw
.WriteLeb128 (StartOffset
);
290 bw
.WriteLeb128 (EndOffset
);
293 public override string ToString ()
295 return String
.Format ("[CodeBlock {0}:{1}:{2}:{3}:{4}]",
296 Index
, Parent
, BlockType
, StartOffset
, EndOffset
);
300 public struct LocalVariableEntry
302 #region This is actually written to the symbol file
303 public readonly int Index
;
304 public readonly string Name
;
305 public readonly int BlockIndex
;
308 public LocalVariableEntry (int index
, string name
, int block
)
312 this.BlockIndex
= block
;
315 internal LocalVariableEntry (MonoSymbolFile file
, MyBinaryReader reader
)
317 Index
= reader
.ReadLeb128 ();
318 Name
= reader
.ReadString ();
319 BlockIndex
= reader
.ReadLeb128 ();
322 internal void Write (MonoSymbolFile file
, MyBinaryWriter bw
)
324 bw
.WriteLeb128 (Index
);
326 bw
.WriteLeb128 (BlockIndex
);
329 public override string ToString ()
331 return String
.Format ("[LocalVariable {0}:{1}:{2}]",
332 Name
, Index
, BlockIndex
- 1);
336 public struct CapturedVariable
338 #region This is actually written to the symbol file
339 public readonly string Name
;
340 public readonly string CapturedName
;
341 public readonly CapturedKind Kind
;
344 public enum CapturedKind
: byte
351 public CapturedVariable (string name
, string captured_name
,
355 this.CapturedName
= captured_name
;
359 internal CapturedVariable (MyBinaryReader reader
)
361 Name
= reader
.ReadString ();
362 CapturedName
= reader
.ReadString ();
363 Kind
= (CapturedKind
) reader
.ReadByte ();
366 internal void Write (MyBinaryWriter bw
)
369 bw
.Write (CapturedName
);
370 bw
.Write ((byte) Kind
);
373 public override string ToString ()
375 return String
.Format ("[CapturedVariable {0}:{1}:{2}]",
376 Name
, CapturedName
, Kind
);
380 public struct CapturedScope
382 #region This is actually written to the symbol file
383 public readonly int Scope
;
384 public readonly string CapturedName
;
387 public CapturedScope (int scope
, string captured_name
)
390 this.CapturedName
= captured_name
;
393 internal CapturedScope (MyBinaryReader reader
)
395 Scope
= reader
.ReadLeb128 ();
396 CapturedName
= reader
.ReadString ();
399 internal void Write (MyBinaryWriter bw
)
401 bw
.WriteLeb128 (Scope
);
402 bw
.Write (CapturedName
);
405 public override string ToString ()
407 return String
.Format ("[CapturedScope {0}:{1}]",
408 Scope
, CapturedName
);
412 public struct ScopeVariable
414 #region This is actually written to the symbol file
415 public readonly int Scope
;
416 public readonly int Index
;
419 public ScopeVariable (int scope
, int index
)
425 internal ScopeVariable (MyBinaryReader reader
)
427 Scope
= reader
.ReadLeb128 ();
428 Index
= reader
.ReadLeb128 ();
431 internal void Write (MyBinaryWriter bw
)
433 bw
.WriteLeb128 (Scope
);
434 bw
.WriteLeb128 (Index
);
437 public override string ToString ()
439 return String
.Format ("[ScopeVariable {0}:{1}]", Scope
, Index
);
443 public class AnonymousScopeEntry
445 #region This is actually written to the symbol file
446 public readonly int ID
;
449 List
<CapturedVariable
> captured_vars
= new List
<CapturedVariable
> ();
450 List
<CapturedScope
> captured_scopes
= new List
<CapturedScope
> ();
452 public AnonymousScopeEntry (int id
)
457 internal AnonymousScopeEntry (MyBinaryReader reader
)
459 ID
= reader
.ReadLeb128 ();
461 int num_captured_vars
= reader
.ReadLeb128 ();
462 for (int i
= 0; i
< num_captured_vars
; i
++)
463 captured_vars
.Add (new CapturedVariable (reader
));
465 int num_captured_scopes
= reader
.ReadLeb128 ();
466 for (int i
= 0; i
< num_captured_scopes
; i
++)
467 captured_scopes
.Add (new CapturedScope (reader
));
470 internal void AddCapturedVariable (string name
, string captured_name
,
471 CapturedVariable
.CapturedKind kind
)
473 captured_vars
.Add (new CapturedVariable (name
, captured_name
, kind
));
476 public CapturedVariable
[] CapturedVariables
{
478 CapturedVariable
[] retval
= new CapturedVariable
[captured_vars
.Count
];
479 captured_vars
.CopyTo (retval
, 0);
484 internal void AddCapturedScope (int scope
, string captured_name
)
486 captured_scopes
.Add (new CapturedScope (scope
, captured_name
));
489 public CapturedScope
[] CapturedScopes
{
491 CapturedScope
[] retval
= new CapturedScope
[captured_scopes
.Count
];
492 captured_scopes
.CopyTo (retval
, 0);
497 internal void Write (MyBinaryWriter bw
)
501 bw
.WriteLeb128 (captured_vars
.Count
);
502 foreach (CapturedVariable cv
in captured_vars
)
505 bw
.WriteLeb128 (captured_scopes
.Count
);
506 foreach (CapturedScope cs
in captured_scopes
)
510 public override string ToString ()
512 return String
.Format ("[AnonymousScope {0}]", ID
);
516 public class CompileUnitEntry
: ICompileUnit
518 #region This is actually written to the symbol file
519 public readonly int Index
;
524 SourceFileEntry source
;
525 List
<SourceFileEntry
> include_files
;
526 List
<NamespaceEntry
> namespaces
;
530 public static int Size
{
534 CompileUnitEntry ICompileUnit
.Entry
{
538 public CompileUnitEntry (MonoSymbolFile file
, SourceFileEntry source
)
541 this.source
= source
;
543 this.Index
= file
.AddCompileUnit (this);
546 namespaces
= new List
<NamespaceEntry
> ();
549 public void AddFile (SourceFileEntry file
)
552 throw new InvalidOperationException ();
554 if (include_files
== null)
555 include_files
= new List
<SourceFileEntry
> ();
557 include_files
.Add (file
);
560 public SourceFileEntry SourceFile
{
570 public int DefineNamespace (string name
, string[] using_clauses
, int parent
)
573 throw new InvalidOperationException ();
575 int index
= file
.GetNextNamespaceIndex ();
576 NamespaceEntry ns
= new NamespaceEntry (name
, index
, using_clauses
, parent
);
581 internal void WriteData (MyBinaryWriter bw
)
583 DataOffset
= (int) bw
.BaseStream
.Position
;
584 bw
.WriteLeb128 (source
.Index
);
586 int count_includes
= include_files
!= null ? include_files
.Count
: 0;
587 bw
.WriteLeb128 (count_includes
);
588 if (include_files
!= null) {
589 foreach (SourceFileEntry entry
in include_files
)
590 bw
.WriteLeb128 (entry
.Index
);
593 bw
.WriteLeb128 (namespaces
.Count
);
594 foreach (NamespaceEntry ns
in namespaces
)
598 internal void Write (BinaryWriter bw
)
601 bw
.Write (DataOffset
);
604 internal CompileUnitEntry (MonoSymbolFile file
, MyBinaryReader reader
)
608 Index
= reader
.ReadInt32 ();
609 DataOffset
= reader
.ReadInt32 ();
612 public void ReadAll ()
620 throw new InvalidOperationException ();
623 if (namespaces
!= null)
626 MyBinaryReader reader
= file
.BinaryReader
;
627 int old_pos
= (int) reader
.BaseStream
.Position
;
629 reader
.BaseStream
.Position
= DataOffset
;
631 int source_idx
= reader
.ReadLeb128 ();
632 source
= file
.GetSourceFile (source_idx
);
634 int count_includes
= reader
.ReadLeb128 ();
635 if (count_includes
> 0) {
636 include_files
= new List
<SourceFileEntry
> ();
637 for (int i
= 0; i
< count_includes
; i
++)
638 include_files
.Add (file
.GetSourceFile (reader
.ReadLeb128 ()));
641 int count_ns
= reader
.ReadLeb128 ();
642 namespaces
= new List
<NamespaceEntry
> ();
643 for (int i
= 0; i
< count_ns
; i
++)
644 namespaces
.Add (new NamespaceEntry (file
, reader
));
646 reader
.BaseStream
.Position
= old_pos
;
650 public NamespaceEntry
[] Namespaces
{
653 NamespaceEntry
[] retval
= new NamespaceEntry
[namespaces
.Count
];
654 namespaces
.CopyTo (retval
, 0);
659 public SourceFileEntry
[] IncludeFiles
{
662 if (include_files
== null)
663 return new SourceFileEntry
[0];
665 SourceFileEntry
[] retval
= new SourceFileEntry
[include_files
.Count
];
666 include_files
.CopyTo (retval
, 0);
672 public class SourceFileEntry
674 #region This is actually written to the symbol file
675 public readonly int Index
;
685 readonly string sourceFile
;
687 public static int Size
{
691 public SourceFileEntry (MonoSymbolFile file
, string file_name
)
694 this.file_name
= file_name
;
695 this.Index
= file
.AddSource (this);
700 public SourceFileEntry (MonoSymbolFile file
, string sourceFile
, byte [] guid
, byte [] checksum
)
701 : this (file
, sourceFile
, sourceFile
, guid
, checksum
)
705 public SourceFileEntry (MonoSymbolFile file
, string fileName
, string sourceFile
, byte[] guid
, byte[] checksum
)
706 : this (file
, fileName
)
709 this.hash
= checksum
;
710 this.sourceFile
= sourceFile
;
713 public byte[] Checksum
{
719 internal void WriteData (MyBinaryWriter bw
)
721 DataOffset
= (int) bw
.BaseStream
.Position
;
722 bw
.Write (file_name
);
729 using (FileStream fs
= new FileStream (sourceFile
, FileMode
.Open
, FileAccess
.Read
)) {
730 MD5 md5
= MD5
.Create ();
731 hash
= md5
.ComputeHash (fs
);
734 hash
= new byte [16];
740 bw
.Write ((byte) (auto_generated
? 1 : 0));
743 internal void Write (BinaryWriter bw
)
746 bw
.Write (DataOffset
);
749 internal SourceFileEntry (MonoSymbolFile file
, MyBinaryReader reader
)
753 Index
= reader
.ReadInt32 ();
754 DataOffset
= reader
.ReadInt32 ();
756 int old_pos
= (int) reader
.BaseStream
.Position
;
757 reader
.BaseStream
.Position
= DataOffset
;
759 sourceFile
= file_name
= reader
.ReadString ();
760 guid
= reader
.ReadBytes (16);
761 hash
= reader
.ReadBytes (16);
762 auto_generated
= reader
.ReadByte () == 1;
764 reader
.BaseStream
.Position
= old_pos
;
767 public string FileName
{
768 get { return file_name; }
769 set { file_name = value; }
772 public bool AutoGenerated
{
773 get { return auto_generated; }
776 public void SetAutoGenerated ()
779 throw new InvalidOperationException ();
781 auto_generated
= true;
782 file
.OffsetTable
.FileFlags
|= OffsetTable
.Flags
.IsAspxSource
;
785 public bool CheckChecksum ()
788 using (FileStream fs
= new FileStream (sourceFile
, FileMode
.Open
)) {
789 MD5 md5
= MD5
.Create ();
790 byte[] data
= md5
.ComputeHash (fs
);
791 for (int i
= 0; i
< 16; i
++)
792 if (data
[i
] != hash
[i
])
801 public override string ToString ()
803 return String
.Format ("SourceFileEntry ({0}:{1})", Index
, DataOffset
);
807 public class LineNumberTable
809 protected LineNumberEntry
[] _line_numbers
;
810 public LineNumberEntry
[] LineNumbers
{
811 get { return _line_numbers; }
814 public readonly int LineBase
;
815 public readonly int LineRange
;
816 public readonly byte OpcodeBase
;
817 public readonly int MaxAddressIncrement
;
819 #region Configurable constants
820 public const int Default_LineBase
= -1;
821 public const int Default_LineRange
= 8;
822 public const byte Default_OpcodeBase
= 9;
826 public const byte DW_LNS_copy
= 1;
827 public const byte DW_LNS_advance_pc
= 2;
828 public const byte DW_LNS_advance_line
= 3;
829 public const byte DW_LNS_set_file
= 4;
830 public const byte DW_LNS_const_add_pc
= 8;
832 public const byte DW_LNE_end_sequence
= 1;
835 public const byte DW_LNE_MONO_negate_is_hidden
= 0x40;
837 internal const byte DW_LNE_MONO__extensions_start
= 0x40;
838 internal const byte DW_LNE_MONO__extensions_end
= 0x7f;
840 protected LineNumberTable (MonoSymbolFile file
)
842 this.LineBase
= file
.OffsetTable
.LineNumberTable_LineBase
;
843 this.LineRange
= file
.OffsetTable
.LineNumberTable_LineRange
;
844 this.OpcodeBase
= (byte) file
.OffsetTable
.LineNumberTable_OpcodeBase
;
845 this.MaxAddressIncrement
= (255 - OpcodeBase
) / LineRange
;
848 internal LineNumberTable (MonoSymbolFile file
, LineNumberEntry
[] lines
)
851 this._line_numbers
= lines
;
854 internal void Write (MonoSymbolFile file
, MyBinaryWriter bw
, bool hasColumnsInfo
, bool hasEndInfo
)
856 int start
= (int) bw
.BaseStream
.Position
;
858 bool last_is_hidden
= false;
859 int last_line
= 1, last_offset
= 0, last_file
= 1;
860 for (int i
= 0; i
< LineNumbers
.Length
; i
++) {
861 int line_inc
= LineNumbers
[i
].Row
- last_line
;
862 int offset_inc
= LineNumbers
[i
].Offset
- last_offset
;
864 if (LineNumbers
[i
].File
!= last_file
) {
865 bw
.Write (DW_LNS_set_file
);
866 bw
.WriteLeb128 (LineNumbers
[i
].File
);
867 last_file
= LineNumbers
[i
].File
;
870 if (LineNumbers
[i
].IsHidden
!= last_is_hidden
) {
873 bw
.Write (DW_LNE_MONO_negate_is_hidden
);
874 last_is_hidden
= LineNumbers
[i
].IsHidden
;
877 if (offset_inc
>= MaxAddressIncrement
) {
878 if (offset_inc
< 2 * MaxAddressIncrement
) {
879 bw
.Write (DW_LNS_const_add_pc
);
880 offset_inc
-= MaxAddressIncrement
;
882 bw
.Write (DW_LNS_advance_pc
);
883 bw
.WriteLeb128 (offset_inc
);
888 if ((line_inc
< LineBase
) || (line_inc
>= LineBase
+ LineRange
)) {
889 bw
.Write (DW_LNS_advance_line
);
890 bw
.WriteLeb128 (line_inc
);
891 if (offset_inc
!= 0) {
892 bw
.Write (DW_LNS_advance_pc
);
893 bw
.WriteLeb128 (offset_inc
);
895 bw
.Write (DW_LNS_copy
);
898 opcode
= (byte) (line_inc
- LineBase
+ (LineRange
* offset_inc
) +
903 last_line
= LineNumbers
[i
].Row
;
904 last_offset
= LineNumbers
[i
].Offset
;
909 bw
.Write (DW_LNE_end_sequence
);
911 if (hasColumnsInfo
) {
912 for (int i
= 0; i
< LineNumbers
.Length
; i
++) {
913 var ln
= LineNumbers
[i
];
915 bw
.WriteLeb128 (ln
.Column
);
920 for (int i
= 0; i
< LineNumbers
.Length
; i
++) {
921 var ln
= LineNumbers
[i
];
922 if (ln
.EndRow
== -1 || ln
.EndColumn
== -1 || ln
.Row
> ln
.EndRow
) {
923 bw
.WriteLeb128 (0xffffff);
925 bw
.WriteLeb128 (ln
.EndRow
- ln
.Row
);
926 bw
.WriteLeb128 (ln
.EndColumn
);
931 file
.ExtendedLineNumberSize
+= (int) bw
.BaseStream
.Position
- start
;
934 internal static LineNumberTable
Read (MonoSymbolFile file
, MyBinaryReader br
, bool readColumnsInfo
, bool readEndInfo
)
936 LineNumberTable lnt
= new LineNumberTable (file
);
937 lnt
.DoRead (file
, br
, readColumnsInfo
, readEndInfo
);
941 void DoRead (MonoSymbolFile file
, MyBinaryReader br
, bool includesColumns
, bool includesEnds
)
943 var lines
= new List
<LineNumberEntry
> ();
945 bool is_hidden
= false, modified
= false;
946 int stm_line
= 1, stm_offset
= 0, stm_file
= 1;
948 byte opcode
= br
.ReadByte ();
951 byte size
= br
.ReadByte ();
952 long end_pos
= br
.BaseStream
.Position
+ size
;
953 opcode
= br
.ReadByte ();
955 if (opcode
== DW_LNE_end_sequence
) {
957 lines
.Add (new LineNumberEntry (
958 stm_file
, stm_line
, -1, stm_offset
, is_hidden
));
960 } else if (opcode
== DW_LNE_MONO_negate_is_hidden
) {
961 is_hidden
= !is_hidden
;
963 } else if ((opcode
>= DW_LNE_MONO__extensions_start
) &&
964 (opcode
<= DW_LNE_MONO__extensions_end
)) {
965 ; // reserved for future extensions
967 throw new MonoSymbolFileException ("Unknown extended opcode {0:x}", opcode
);
970 br
.BaseStream
.Position
= end_pos
;
972 } else if (opcode
< OpcodeBase
) {
975 lines
.Add (new LineNumberEntry (
976 stm_file
, stm_line
, -1, stm_offset
, is_hidden
));
979 case DW_LNS_advance_pc
:
980 stm_offset
+= br
.ReadLeb128 ();
983 case DW_LNS_advance_line
:
984 stm_line
+= br
.ReadLeb128 ();
987 case DW_LNS_set_file
:
988 stm_file
= br
.ReadLeb128 ();
991 case DW_LNS_const_add_pc
:
992 stm_offset
+= MaxAddressIncrement
;
996 throw new MonoSymbolFileException (
997 "Unknown standard opcode {0:x} in LNT",
1001 opcode
-= OpcodeBase
;
1003 stm_offset
+= opcode
/ LineRange
;
1004 stm_line
+= LineBase
+ (opcode
% LineRange
);
1005 lines
.Add (new LineNumberEntry (
1006 stm_file
, stm_line
, -1, stm_offset
, is_hidden
));
1011 _line_numbers
= lines
.ToArray ();
1013 if (includesColumns
) {
1014 for (int i
= 0; i
< _line_numbers
.Length
; ++i
) {
1015 var ln
= _line_numbers
[i
];
1017 ln
.Column
= br
.ReadLeb128 ();
1021 for (int i
= 0; i
< _line_numbers
.Length
; ++i
) {
1022 var ln
= _line_numbers
[i
];
1024 int row
= br
.ReadLeb128 ();
1025 if (row
== 0xffffff) {
1029 ln
.EndRow
= ln
.Row
+ row
;
1030 ln
.EndColumn
= br
.ReadLeb128 ();
1036 public bool GetMethodBounds (out LineNumberEntry start
, out LineNumberEntry end
)
1038 if (_line_numbers
.Length
> 1) {
1039 start
= _line_numbers
[0];
1040 end
= _line_numbers
[_line_numbers
.Length
- 1];
1044 start
= LineNumberEntry
.Null
;
1045 end
= LineNumberEntry
.Null
;
1050 public class MethodEntry
: IComparable
1052 #region This is actually written to the symbol file
1053 public readonly int CompileUnitIndex
;
1054 public readonly int Token
;
1055 public readonly int NamespaceID
;
1058 int LocalVariableTableOffset
;
1059 int LineNumberTableOffset
;
1060 int CodeBlockTableOffset
;
1061 int ScopeVariableTableOffset
;
1068 public Flags MethodFlags
{
1069 get { return flags; }
1072 public readonly CompileUnitEntry CompileUnit
;
1074 LocalVariableEntry
[] locals
;
1075 CodeBlockEntry
[] code_blocks
;
1076 ScopeVariable
[] scope_vars
;
1077 LineNumberTable lnt
;
1080 public readonly MonoSymbolFile SymbolFile
;
1083 get { return index; }
1084 set { index = value; }
1090 LocalNamesAmbiguous
= 1,
1091 ColumnsInfoIncluded
= 1 << 1,
1092 EndInfoIncluded
= 1 << 2
1095 public const int Size
= 12;
1097 internal MethodEntry (MonoSymbolFile file
, MyBinaryReader reader
, int index
)
1099 this.SymbolFile
= file
;
1102 Token
= reader
.ReadInt32 ();
1103 DataOffset
= reader
.ReadInt32 ();
1104 LineNumberTableOffset
= reader
.ReadInt32 ();
1106 long old_pos
= reader
.BaseStream
.Position
;
1107 reader
.BaseStream
.Position
= DataOffset
;
1109 CompileUnitIndex
= reader
.ReadLeb128 ();
1110 LocalVariableTableOffset
= reader
.ReadLeb128 ();
1111 NamespaceID
= reader
.ReadLeb128 ();
1113 CodeBlockTableOffset
= reader
.ReadLeb128 ();
1114 ScopeVariableTableOffset
= reader
.ReadLeb128 ();
1116 RealNameOffset
= reader
.ReadLeb128 ();
1118 flags
= (Flags
) reader
.ReadLeb128 ();
1120 reader
.BaseStream
.Position
= old_pos
;
1122 CompileUnit
= file
.GetCompileUnit (CompileUnitIndex
);
1125 internal MethodEntry (MonoSymbolFile file
, CompileUnitEntry comp_unit
,
1126 int token
, ScopeVariable
[] scope_vars
,
1127 LocalVariableEntry
[] locals
, LineNumberEntry
[] lines
,
1128 CodeBlockEntry
[] code_blocks
, string real_name
,
1129 Flags flags
, int namespace_id
)
1131 this.SymbolFile
= file
;
1132 this.real_name
= real_name
;
1133 this.locals
= locals
;
1134 this.code_blocks
= code_blocks
;
1135 this.scope_vars
= scope_vars
;
1141 CompileUnitIndex
= comp_unit
.Index
;
1142 CompileUnit
= comp_unit
;
1143 NamespaceID
= namespace_id
;
1145 CheckLineNumberTable (lines
);
1146 lnt
= new LineNumberTable (file
, lines
);
1147 file
.NumLineNumbers
+= lines
.Length
;
1149 int num_locals
= locals
!= null ? locals
.Length
: 0;
1151 if (num_locals
<= 32) {
1152 // Most of the time, the O(n^2) factor is actually
1153 // less than the cost of allocating the hash table,
1154 // 32 is a rough number obtained through some testing.
1156 for (int i
= 0; i
< num_locals
; i
++) {
1157 string nm
= locals
[i
].Name
;
1159 for (int j
= i
+ 1; j
< num_locals
; j
++) {
1160 if (locals
[j
].Name
== nm
) {
1161 flags
|= Flags
.LocalNamesAmbiguous
;
1162 goto locals_check_done
;
1169 var local_names
= new Dictionary
<string, LocalVariableEntry
> ();
1170 foreach (LocalVariableEntry local
in locals
) {
1171 if (local_names
.ContainsKey (local
.Name
)) {
1172 flags
|= Flags
.LocalNamesAmbiguous
;
1175 local_names
.Add (local
.Name
, local
);
1180 static void CheckLineNumberTable (LineNumberEntry
[] line_numbers
)
1182 int last_offset
= -1;
1185 if (line_numbers
== null)
1188 for (int i
= 0; i
< line_numbers
.Length
; i
++) {
1189 LineNumberEntry line
= line_numbers
[i
];
1191 if (line
.Equals (LineNumberEntry
.Null
))
1192 throw new MonoSymbolFileException ();
1194 if (line
.Offset
< last_offset
)
1195 throw new MonoSymbolFileException ();
1197 if (line
.Offset
> last_offset
) {
1198 last_row
= line
.Row
;
1199 last_offset
= line
.Offset
;
1200 } else if (line
.Row
> last_row
) {
1201 last_row
= line
.Row
;
1206 internal void Write (MyBinaryWriter bw
)
1208 if ((index
<= 0) || (DataOffset
== 0))
1209 throw new InvalidOperationException ();
1212 bw
.Write (DataOffset
);
1213 bw
.Write (LineNumberTableOffset
);
1216 internal void WriteData (MonoSymbolFile file
, MyBinaryWriter bw
)
1219 throw new InvalidOperationException ();
1221 LocalVariableTableOffset
= (int) bw
.BaseStream
.Position
;
1222 int num_locals
= locals
!= null ? locals
.Length
: 0;
1223 bw
.WriteLeb128 (num_locals
);
1224 for (int i
= 0; i
< num_locals
; i
++)
1225 locals
[i
].Write (file
, bw
);
1226 file
.LocalCount
+= num_locals
;
1228 CodeBlockTableOffset
= (int) bw
.BaseStream
.Position
;
1229 int num_code_blocks
= code_blocks
!= null ? code_blocks
.Length
: 0;
1230 bw
.WriteLeb128 (num_code_blocks
);
1231 for (int i
= 0; i
< num_code_blocks
; i
++)
1232 code_blocks
[i
].Write (bw
);
1234 ScopeVariableTableOffset
= (int) bw
.BaseStream
.Position
;
1235 int num_scope_vars
= scope_vars
!= null ? scope_vars
.Length
: 0;
1236 bw
.WriteLeb128 (num_scope_vars
);
1237 for (int i
= 0; i
< num_scope_vars
; i
++)
1238 scope_vars
[i
].Write (bw
);
1240 if (real_name
!= null) {
1241 RealNameOffset
= (int) bw
.BaseStream
.Position
;
1242 bw
.Write (real_name
);
1245 foreach (var lne
in lnt
.LineNumbers
) {
1246 if (lne
.EndRow
!= -1 || lne
.EndColumn
!= -1)
1247 flags
|= Flags
.EndInfoIncluded
;
1250 LineNumberTableOffset
= (int) bw
.BaseStream
.Position
;
1251 lnt
.Write (file
, bw
, (flags
& Flags
.ColumnsInfoIncluded
) != 0, (flags
& Flags
.EndInfoIncluded
) != 0);
1253 DataOffset
= (int) bw
.BaseStream
.Position
;
1255 bw
.WriteLeb128 (CompileUnitIndex
);
1256 bw
.WriteLeb128 (LocalVariableTableOffset
);
1257 bw
.WriteLeb128 (NamespaceID
);
1259 bw
.WriteLeb128 (CodeBlockTableOffset
);
1260 bw
.WriteLeb128 (ScopeVariableTableOffset
);
1262 bw
.WriteLeb128 (RealNameOffset
);
1263 bw
.WriteLeb128 ((int) flags
);
1266 public void ReadAll ()
1268 GetLineNumberTable ();
1271 GetScopeVariables ();
1275 public LineNumberTable
GetLineNumberTable ()
1281 if (LineNumberTableOffset
== 0)
1284 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1285 long old_pos
= reader
.BaseStream
.Position
;
1286 reader
.BaseStream
.Position
= LineNumberTableOffset
;
1288 lnt
= LineNumberTable
.Read (SymbolFile
, reader
, (flags
& Flags
.ColumnsInfoIncluded
) != 0, (flags
& Flags
.EndInfoIncluded
) != 0);
1290 reader
.BaseStream
.Position
= old_pos
;
1295 public LocalVariableEntry
[] GetLocals ()
1301 if (LocalVariableTableOffset
== 0)
1304 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1305 long old_pos
= reader
.BaseStream
.Position
;
1306 reader
.BaseStream
.Position
= LocalVariableTableOffset
;
1308 int num_locals
= reader
.ReadLeb128 ();
1309 locals
= new LocalVariableEntry
[num_locals
];
1311 for (int i
= 0; i
< num_locals
; i
++)
1312 locals
[i
] = new LocalVariableEntry (SymbolFile
, reader
);
1314 reader
.BaseStream
.Position
= old_pos
;
1319 public CodeBlockEntry
[] GetCodeBlocks ()
1322 if (code_blocks
!= null)
1325 if (CodeBlockTableOffset
== 0)
1328 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1329 long old_pos
= reader
.BaseStream
.Position
;
1330 reader
.BaseStream
.Position
= CodeBlockTableOffset
;
1332 int num_code_blocks
= reader
.ReadLeb128 ();
1333 code_blocks
= new CodeBlockEntry
[num_code_blocks
];
1335 for (int i
= 0; i
< num_code_blocks
; i
++)
1336 code_blocks
[i
] = new CodeBlockEntry (i
, reader
);
1338 reader
.BaseStream
.Position
= old_pos
;
1343 public ScopeVariable
[] GetScopeVariables ()
1346 if (scope_vars
!= null)
1349 if (ScopeVariableTableOffset
== 0)
1352 MyBinaryReader reader
= SymbolFile
.BinaryReader
;
1353 long old_pos
= reader
.BaseStream
.Position
;
1354 reader
.BaseStream
.Position
= ScopeVariableTableOffset
;
1356 int num_scope_vars
= reader
.ReadLeb128 ();
1357 scope_vars
= new ScopeVariable
[num_scope_vars
];
1359 for (int i
= 0; i
< num_scope_vars
; i
++)
1360 scope_vars
[i
] = new ScopeVariable (reader
);
1362 reader
.BaseStream
.Position
= old_pos
;
1367 public string GetRealName ()
1370 if (real_name
!= null)
1373 if (RealNameOffset
== 0)
1376 real_name
= SymbolFile
.BinaryReader
.ReadString (RealNameOffset
);
1381 public int CompareTo (object obj
)
1383 MethodEntry method
= (MethodEntry
) obj
;
1385 if (method
.Token
< Token
)
1387 else if (method
.Token
> Token
)
1393 public override string ToString ()
1395 return String
.Format ("[Method {0}:{1:x}:{2}:{3}]",
1396 index
, Token
, CompileUnitIndex
, CompileUnit
);
1400 public struct NamespaceEntry
1402 #region This is actually written to the symbol file
1403 public readonly string Name
;
1404 public readonly int Index
;
1405 public readonly int Parent
;
1406 public readonly string[] UsingClauses
;
1409 public NamespaceEntry (string name
, int index
, string[] using_clauses
, int parent
)
1413 this.Parent
= parent
;
1414 this.UsingClauses
= using_clauses
!= null ? using_clauses
: new string [0];
1417 internal NamespaceEntry (MonoSymbolFile file
, MyBinaryReader reader
)
1419 Name
= reader
.ReadString ();
1420 Index
= reader
.ReadLeb128 ();
1421 Parent
= reader
.ReadLeb128 ();
1423 int count
= reader
.ReadLeb128 ();
1424 UsingClauses
= new string [count
];
1425 for (int i
= 0; i
< count
; i
++)
1426 UsingClauses
[i
] = reader
.ReadString ();
1429 internal void Write (MonoSymbolFile file
, MyBinaryWriter bw
)
1432 bw
.WriteLeb128 (Index
);
1433 bw
.WriteLeb128 (Parent
);
1434 bw
.WriteLeb128 (UsingClauses
.Length
);
1435 foreach (string uc
in UsingClauses
)
1439 public override string ToString ()
1441 return String
.Format ("[Namespace {0}:{1}:{2}]", Name
, Index
, Parent
);