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;
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<LineNumberEntry>
207 public int Compare (LineNumberEntry l1, LineNumberEntry l2)
209 if (l1.Offset < l2.Offset)
211 else if (l1.Offset > l2.Offset)
218 private class RowComparerClass : IComparer<LineNumberEntry>
220 public int Compare (LineNumberEntry l1, LineNumberEntry l2)
224 else if (l1.Row > l2.Row)
231 public static readonly IComparer<LineNumberEntry> OffsetComparer = new OffsetComparerClass ();
232 public static readonly IComparer<LineNumberEntry> RowComparer = new RowComparerClass ();
234 public override string ToString ()
236 return String.Format ("[Line {0}:{1}:{2}]", File, Row, Offset);
240 public class CodeBlockEntry
243 #region This is actually written to the symbol file
245 public Type BlockType;
246 public int StartOffset;
247 public int EndOffset;
252 CompilerGenerated = 2,
254 IteratorDispatcher = 4
257 public CodeBlockEntry (int index, int parent, Type type, int start_offset)
260 this.Parent = parent;
261 this.BlockType = type;
262 this.StartOffset = start_offset;
265 internal CodeBlockEntry (int index, MyBinaryReader reader)
268 int type_flag = reader.ReadLeb128 ();
269 BlockType = (Type) (type_flag & 0x3f);
270 this.Parent = reader.ReadLeb128 ();
271 this.StartOffset = reader.ReadLeb128 ();
272 this.EndOffset = reader.ReadLeb128 ();
274 /* Reserved for future extensions. */
275 if ((type_flag & 0x40) != 0) {
276 int data_size = reader.ReadInt16 ();
277 reader.BaseStream.Position += data_size;
281 public void Close (int end_offset)
283 this.EndOffset = end_offset;
286 internal void Write (MyBinaryWriter bw)
288 bw.WriteLeb128 ((int) BlockType);
289 bw.WriteLeb128 (Parent);
290 bw.WriteLeb128 (StartOffset);
291 bw.WriteLeb128 (EndOffset);
294 public override string ToString ()
296 return String.Format ("[CodeBlock {0}:{1}:{2}:{3}:{4}]",
297 Index, Parent, BlockType, StartOffset, EndOffset);
301 public struct LocalVariableEntry
303 #region This is actually written to the symbol file
304 public readonly int Index;
305 public readonly string Name;
306 public readonly int BlockIndex;
309 public LocalVariableEntry (int index, string name, int block)
313 this.BlockIndex = block;
316 internal LocalVariableEntry (MonoSymbolFile file, MyBinaryReader reader)
318 Index = reader.ReadLeb128 ();
319 Name = reader.ReadString ();
320 BlockIndex = reader.ReadLeb128 ();
323 internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
325 bw.WriteLeb128 (Index);
327 bw.WriteLeb128 (BlockIndex);
330 public override string ToString ()
332 return String.Format ("[LocalVariable {0}:{1}:{2}]",
333 Name, Index, BlockIndex - 1);
337 public struct CapturedVariable
339 #region This is actually written to the symbol file
340 public readonly string Name;
341 public readonly string CapturedName;
342 public readonly CapturedKind Kind;
345 public enum CapturedKind : byte
352 public CapturedVariable (string name, string captured_name,
356 this.CapturedName = captured_name;
360 internal CapturedVariable (MyBinaryReader reader)
362 Name = reader.ReadString ();
363 CapturedName = reader.ReadString ();
364 Kind = (CapturedKind) reader.ReadByte ();
367 internal void Write (MyBinaryWriter bw)
370 bw.Write (CapturedName);
371 bw.Write ((byte) Kind);
374 public override string ToString ()
376 return String.Format ("[CapturedVariable {0}:{1}:{2}]",
377 Name, CapturedName, Kind);
381 public struct CapturedScope
383 #region This is actually written to the symbol file
384 public readonly int Scope;
385 public readonly string CapturedName;
388 public CapturedScope (int scope, string captured_name)
391 this.CapturedName = captured_name;
394 internal CapturedScope (MyBinaryReader reader)
396 Scope = reader.ReadLeb128 ();
397 CapturedName = reader.ReadString ();
400 internal void Write (MyBinaryWriter bw)
402 bw.WriteLeb128 (Scope);
403 bw.Write (CapturedName);
406 public override string ToString ()
408 return String.Format ("[CapturedScope {0}:{1}]",
409 Scope, CapturedName);
413 public struct ScopeVariable
415 #region This is actually written to the symbol file
416 public readonly int Scope;
417 public readonly int Index;
420 public ScopeVariable (int scope, int index)
426 internal ScopeVariable (MyBinaryReader reader)
428 Scope = reader.ReadLeb128 ();
429 Index = reader.ReadLeb128 ();
432 internal void Write (MyBinaryWriter bw)
434 bw.WriteLeb128 (Scope);
435 bw.WriteLeb128 (Index);
438 public override string ToString ()
440 return String.Format ("[ScopeVariable {0}:{1}]", Scope, Index);
444 public class AnonymousScopeEntry
446 #region This is actually written to the symbol file
447 public readonly int ID;
450 List<CapturedVariable> captured_vars = new List<CapturedVariable> ();
451 List<CapturedScope> captured_scopes = new List<CapturedScope> ();
453 public AnonymousScopeEntry (int id)
458 internal AnonymousScopeEntry (MyBinaryReader reader)
460 ID = reader.ReadLeb128 ();
462 int num_captured_vars = reader.ReadLeb128 ();
463 for (int i = 0; i < num_captured_vars; i++)
464 captured_vars.Add (new CapturedVariable (reader));
466 int num_captured_scopes = reader.ReadLeb128 ();
467 for (int i = 0; i < num_captured_scopes; i++)
468 captured_scopes.Add (new CapturedScope (reader));
471 internal void AddCapturedVariable (string name, string captured_name,
472 CapturedVariable.CapturedKind kind)
474 captured_vars.Add (new CapturedVariable (name, captured_name, kind));
477 public CapturedVariable[] CapturedVariables {
479 CapturedVariable[] retval = new CapturedVariable [captured_vars.Count];
480 captured_vars.CopyTo (retval, 0);
485 internal void AddCapturedScope (int scope, string captured_name)
487 captured_scopes.Add (new CapturedScope (scope, captured_name));
490 public CapturedScope[] CapturedScopes {
492 CapturedScope[] retval = new CapturedScope [captured_scopes.Count];
493 captured_scopes.CopyTo (retval, 0);
498 internal void Write (MyBinaryWriter bw)
502 bw.WriteLeb128 (captured_vars.Count);
503 foreach (CapturedVariable cv in captured_vars)
506 bw.WriteLeb128 (captured_scopes.Count);
507 foreach (CapturedScope cs in captured_scopes)
511 public override string ToString ()
513 return String.Format ("[AnonymousScope {0}]", ID);
517 public class CompileUnitEntry : ICompileUnit
519 #region This is actually written to the symbol file
520 public readonly int Index;
525 SourceFileEntry source;
526 List<SourceFileEntry> include_files;
527 List<NamespaceEntry> namespaces;
531 public static int Size {
535 CompileUnitEntry ICompileUnit.Entry {
539 public CompileUnitEntry (MonoSymbolFile file, SourceFileEntry source)
542 this.source = source;
544 this.Index = file.AddCompileUnit (this);
547 namespaces = new List<NamespaceEntry> ();
550 public void AddFile (SourceFileEntry file)
553 throw new InvalidOperationException ();
555 if (include_files == null)
556 include_files = new List<SourceFileEntry> ();
558 include_files.Add (file);
561 public SourceFileEntry SourceFile {
571 public int DefineNamespace (string name, string[] using_clauses, int parent)
574 throw new InvalidOperationException ();
576 int index = file.GetNextNamespaceIndex ();
577 NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
582 internal void WriteData (MyBinaryWriter bw)
584 DataOffset = (int) bw.BaseStream.Position;
585 bw.WriteLeb128 (source.Index);
587 int count_includes = include_files != null ? include_files.Count : 0;
588 bw.WriteLeb128 (count_includes);
589 if (include_files != null) {
590 foreach (SourceFileEntry entry in include_files)
591 bw.WriteLeb128 (entry.Index);
594 bw.WriteLeb128 (namespaces.Count);
595 foreach (NamespaceEntry ns in namespaces)
599 internal void Write (BinaryWriter bw)
602 bw.Write (DataOffset);
605 internal CompileUnitEntry (MonoSymbolFile file, MyBinaryReader reader)
609 Index = reader.ReadInt32 ();
610 DataOffset = reader.ReadInt32 ();
616 throw new InvalidOperationException ();
619 if (namespaces != null)
622 MyBinaryReader reader = file.BinaryReader;
623 int old_pos = (int) reader.BaseStream.Position;
625 reader.BaseStream.Position = DataOffset;
627 int source_idx = reader.ReadLeb128 ();
628 source = file.GetSourceFile (source_idx);
630 int count_includes = reader.ReadLeb128 ();
631 if (count_includes > 0) {
632 include_files = new List<SourceFileEntry> ();
633 for (int i = 0; i < count_includes; i++)
634 include_files.Add (file.GetSourceFile (reader.ReadLeb128 ()));
637 int count_ns = reader.ReadLeb128 ();
638 namespaces = new List<NamespaceEntry> ();
639 for (int i = 0; i < count_ns; i ++)
640 namespaces.Add (new NamespaceEntry (file, reader));
642 reader.BaseStream.Position = old_pos;
646 public NamespaceEntry[] Namespaces {
649 NamespaceEntry[] retval = new NamespaceEntry [namespaces.Count];
650 namespaces.CopyTo (retval, 0);
655 public SourceFileEntry[] IncludeFiles {
658 if (include_files == null)
659 return new SourceFileEntry [0];
661 SourceFileEntry[] retval = new SourceFileEntry [include_files.Count];
662 include_files.CopyTo (retval, 0);
668 public class SourceFileEntry
670 #region This is actually written to the symbol file
671 public readonly int Index;
682 public static int Size {
686 public SourceFileEntry (MonoSymbolFile file, string file_name)
689 this.file_name = file_name;
690 this.Index = file.AddSource (this);
695 public SourceFileEntry (MonoSymbolFile file, string file_name,
696 byte[] guid, byte[] checksum)
697 : this (file, file_name)
700 this.hash = checksum;
703 internal void WriteData (MyBinaryWriter bw)
705 DataOffset = (int) bw.BaseStream.Position;
706 bw.Write (file_name);
709 guid = Guid.NewGuid ().ToByteArray ();
711 using (FileStream fs = new FileStream (file_name, FileMode.Open, FileAccess.Read)) {
712 MD5 md5 = MD5.Create ();
713 hash = md5.ComputeHash (fs);
716 hash = new byte [16];
722 bw.Write ((byte) (auto_generated ? 1 : 0));
725 internal void Write (BinaryWriter bw)
728 bw.Write (DataOffset);
731 internal SourceFileEntry (MonoSymbolFile file, MyBinaryReader reader)
735 Index = reader.ReadInt32 ();
736 DataOffset = reader.ReadInt32 ();
738 int old_pos = (int) reader.BaseStream.Position;
739 reader.BaseStream.Position = DataOffset;
741 file_name = reader.ReadString ();
742 guid = reader.ReadBytes (16);
743 hash = reader.ReadBytes (16);
744 auto_generated = reader.ReadByte () == 1;
746 reader.BaseStream.Position = old_pos;
749 public string FileName {
750 get { return file_name; }
753 public bool AutoGenerated {
754 get { return auto_generated; }
757 public void SetAutoGenerated ()
760 throw new InvalidOperationException ();
762 auto_generated = true;
763 file.OffsetTable.FileFlags |= OffsetTable.Flags.IsAspxSource;
766 public bool CheckChecksum ()
769 using (FileStream fs = new FileStream (file_name, FileMode.Open)) {
770 MD5 md5 = MD5.Create ();
771 byte[] data = md5.ComputeHash (fs);
772 for (int i = 0; i < 16; i++)
773 if (data [i] != hash [i])
782 public override string ToString ()
784 return String.Format ("SourceFileEntry ({0}:{1})", Index, DataOffset);
788 public class LineNumberTable
790 protected LineNumberEntry[] _line_numbers;
791 public LineNumberEntry[] LineNumbers {
792 get { return _line_numbers; }
795 public readonly int LineBase;
796 public readonly int LineRange;
797 public readonly byte OpcodeBase;
798 public readonly int MaxAddressIncrement;
800 #region Configurable constants
801 public const int Default_LineBase = -1;
802 public const int Default_LineRange = 8;
803 public const byte Default_OpcodeBase = 9;
805 public const bool SuppressDuplicates = true;
808 public const byte DW_LNS_copy = 1;
809 public const byte DW_LNS_advance_pc = 2;
810 public const byte DW_LNS_advance_line = 3;
811 public const byte DW_LNS_set_file = 4;
812 public const byte DW_LNS_const_add_pc = 8;
814 public const byte DW_LNE_end_sequence = 1;
817 public const byte DW_LNE_MONO_negate_is_hidden = 0x40;
819 internal const byte DW_LNE_MONO__extensions_start = 0x40;
820 internal const byte DW_LNE_MONO__extensions_end = 0x7f;
822 protected LineNumberTable (MonoSymbolFile file)
824 this.LineBase = file.OffsetTable.LineNumberTable_LineBase;
825 this.LineRange = file.OffsetTable.LineNumberTable_LineRange;
826 this.OpcodeBase = (byte) file.OffsetTable.LineNumberTable_OpcodeBase;
827 this.MaxAddressIncrement = (255 - OpcodeBase) / LineRange;
830 internal LineNumberTable (MonoSymbolFile file, LineNumberEntry[] lines)
833 this._line_numbers = lines;
836 internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
838 int start = (int) bw.BaseStream.Position;
840 bool last_is_hidden = false;
841 int last_line = 1, last_offset = 0, last_file = 1;
842 for (int i = 0; i < LineNumbers.Length; i++) {
843 int line_inc = LineNumbers [i].Row - last_line;
844 int offset_inc = LineNumbers [i].Offset - last_offset;
846 if (SuppressDuplicates && (i+1 < LineNumbers.Length)) {
847 if (LineNumbers [i+1].Equals (LineNumbers [i]))
851 if (LineNumbers [i].File != last_file) {
852 bw.Write (DW_LNS_set_file);
853 bw.WriteLeb128 (LineNumbers [i].File);
854 last_file = LineNumbers [i].File;
857 if (LineNumbers [i].IsHidden != last_is_hidden) {
860 bw.Write (DW_LNE_MONO_negate_is_hidden);
861 last_is_hidden = LineNumbers [i].IsHidden;
864 if (offset_inc >= MaxAddressIncrement) {
865 if (offset_inc < 2 * MaxAddressIncrement) {
866 bw.Write (DW_LNS_const_add_pc);
867 offset_inc -= MaxAddressIncrement;
869 bw.Write (DW_LNS_advance_pc);
870 bw.WriteLeb128 (offset_inc);
875 if ((line_inc < LineBase) || (line_inc >= LineBase + LineRange)) {
876 bw.Write (DW_LNS_advance_line);
877 bw.WriteLeb128 (line_inc);
878 if (offset_inc != 0) {
879 bw.Write (DW_LNS_advance_pc);
880 bw.WriteLeb128 (offset_inc);
882 bw.Write (DW_LNS_copy);
885 opcode = (byte) (line_inc - LineBase + (LineRange * offset_inc) +
890 last_line = LineNumbers [i].Row;
891 last_offset = LineNumbers [i].Offset;
896 bw.Write (DW_LNE_end_sequence);
898 file.ExtendedLineNumberSize += (int) bw.BaseStream.Position - start;
901 internal static LineNumberTable Read (MonoSymbolFile file, MyBinaryReader br)
903 LineNumberTable lnt = new LineNumberTable (file);
904 lnt.DoRead (file, br);
908 void DoRead (MonoSymbolFile file, MyBinaryReader br)
910 var lines = new List<LineNumberEntry> ();
912 bool is_hidden = false, modified = false;
913 int stm_line = 1, stm_offset = 0, stm_file = 1;
915 byte opcode = br.ReadByte ();
918 byte size = br.ReadByte ();
919 long end_pos = br.BaseStream.Position + size;
920 opcode = br.ReadByte ();
922 if (opcode == DW_LNE_end_sequence) {
924 lines.Add (new LineNumberEntry (
925 stm_file, stm_line, stm_offset, is_hidden));
927 } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
928 is_hidden = !is_hidden;
930 } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
931 (opcode <= DW_LNE_MONO__extensions_end)) {
932 ; // reserved for future extensions
934 throw new MonoSymbolFileException (
935 "Unknown extended opcode {0:x} in LNT ({1})",
936 opcode, file.FileName);
939 br.BaseStream.Position = end_pos;
941 } else if (opcode < OpcodeBase) {
944 lines.Add (new LineNumberEntry (
945 stm_file, stm_line, stm_offset, is_hidden));
948 case DW_LNS_advance_pc:
949 stm_offset += br.ReadLeb128 ();
952 case DW_LNS_advance_line:
953 stm_line += br.ReadLeb128 ();
956 case DW_LNS_set_file:
957 stm_file = br.ReadLeb128 ();
960 case DW_LNS_const_add_pc:
961 stm_offset += MaxAddressIncrement;
965 throw new MonoSymbolFileException (
966 "Unknown standard opcode {0:x} in LNT",
970 opcode -= OpcodeBase;
972 stm_offset += opcode / LineRange;
973 stm_line += LineBase + (opcode % LineRange);
974 lines.Add (new LineNumberEntry (
975 stm_file, stm_line, stm_offset, is_hidden));
980 _line_numbers = new LineNumberEntry [lines.Count];
981 lines.CopyTo (_line_numbers, 0);
984 public bool GetMethodBounds (out LineNumberEntry start, out LineNumberEntry end)
986 if (_line_numbers.Length > 1) {
987 start = _line_numbers [0];
988 end = _line_numbers [_line_numbers.Length - 1];
992 start = LineNumberEntry.Null;
993 end = LineNumberEntry.Null;
998 public class MethodEntry : IComparable
1000 #region This is actually written to the symbol file
1001 public readonly int CompileUnitIndex;
1002 public readonly int Token;
1003 public readonly int NamespaceID;
1006 int LocalVariableTableOffset;
1007 int LineNumberTableOffset;
1008 int CodeBlockTableOffset;
1009 int ScopeVariableTableOffset;
1016 public Flags MethodFlags {
1017 get { return flags; }
1020 public readonly CompileUnitEntry CompileUnit;
1022 LocalVariableEntry[] locals;
1023 CodeBlockEntry[] code_blocks;
1024 ScopeVariable[] scope_vars;
1025 LineNumberTable lnt;
1028 public readonly MonoSymbolFile SymbolFile;
1031 get { return index; }
1032 set { index = value; }
1038 LocalNamesAmbiguous = 1
1041 public const int Size = 12;
1043 internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index)
1045 this.SymbolFile = file;
1048 Token = reader.ReadInt32 ();
1049 DataOffset = reader.ReadInt32 ();
1050 LineNumberTableOffset = reader.ReadInt32 ();
1052 long old_pos = reader.BaseStream.Position;
1053 reader.BaseStream.Position = DataOffset;
1055 CompileUnitIndex = reader.ReadLeb128 ();
1056 LocalVariableTableOffset = reader.ReadLeb128 ();
1057 NamespaceID = reader.ReadLeb128 ();
1059 CodeBlockTableOffset = reader.ReadLeb128 ();
1060 ScopeVariableTableOffset = reader.ReadLeb128 ();
1062 RealNameOffset = reader.ReadLeb128 ();
1064 flags = (Flags) reader.ReadLeb128 ();
1066 reader.BaseStream.Position = old_pos;
1068 CompileUnit = file.GetCompileUnit (CompileUnitIndex);
1071 internal MethodEntry (MonoSymbolFile file, CompileUnitEntry comp_unit,
1072 int token, ScopeVariable[] scope_vars,
1073 LocalVariableEntry[] locals, LineNumberEntry[] lines,
1074 CodeBlockEntry[] code_blocks, string real_name,
1075 Flags flags, int namespace_id)
1077 this.SymbolFile = file;
1078 this.real_name = real_name;
1079 this.locals = locals;
1080 this.code_blocks = code_blocks;
1081 this.scope_vars = scope_vars;
1087 CompileUnitIndex = comp_unit.Index;
1088 CompileUnit = comp_unit;
1089 NamespaceID = namespace_id;
1091 CheckLineNumberTable (lines);
1092 lnt = new LineNumberTable (file, lines);
1093 file.NumLineNumbers += lines.Length;
1095 int num_locals = locals != null ? locals.Length : 0;
1097 if (num_locals <= 32) {
1098 // Most of the time, the O(n^2) factor is actually
1099 // less than the cost of allocating the hash table,
1100 // 32 is a rough number obtained through some testing.
1102 for (int i = 0; i < num_locals; i ++) {
1103 string nm = locals [i].Name;
1105 for (int j = i + 1; j < num_locals; j ++) {
1106 if (locals [j].Name == nm) {
1107 flags |= Flags.LocalNamesAmbiguous;
1108 goto locals_check_done;
1115 var local_names = new Dictionary<string, LocalVariableEntry> ();
1116 foreach (LocalVariableEntry local in locals) {
1117 if (local_names.ContainsKey (local.Name)) {
1118 flags |= Flags.LocalNamesAmbiguous;
1121 local_names.Add (local.Name, local);
1126 void CheckLineNumberTable (LineNumberEntry[] line_numbers)
1128 int last_offset = -1;
1131 if (line_numbers == null)
1134 for (int i = 0; i < line_numbers.Length; i++) {
1135 LineNumberEntry line = line_numbers [i];
1137 if (line.Equals (LineNumberEntry.Null))
1138 throw new MonoSymbolFileException ();
1140 if (line.Offset < last_offset)
1141 throw new MonoSymbolFileException ();
1143 if (line.Offset > last_offset) {
1144 last_row = line.Row;
1145 last_offset = line.Offset;
1146 } else if (line.Row > last_row) {
1147 last_row = line.Row;
1152 internal void Write (MyBinaryWriter bw)
1154 if ((index <= 0) || (DataOffset == 0))
1155 throw new InvalidOperationException ();
1158 bw.Write (DataOffset);
1159 bw.Write (LineNumberTableOffset);
1162 internal void WriteData (MonoSymbolFile file, MyBinaryWriter bw)
1165 throw new InvalidOperationException ();
1167 LocalVariableTableOffset = (int) bw.BaseStream.Position;
1168 int num_locals = locals != null ? locals.Length : 0;
1169 bw.WriteLeb128 (num_locals);
1170 for (int i = 0; i < num_locals; i++)
1171 locals [i].Write (file, bw);
1172 file.LocalCount += num_locals;
1174 CodeBlockTableOffset = (int) bw.BaseStream.Position;
1175 int num_code_blocks = code_blocks != null ? code_blocks.Length : 0;
1176 bw.WriteLeb128 (num_code_blocks);
1177 for (int i = 0; i < num_code_blocks; i++)
1178 code_blocks [i].Write (bw);
1180 ScopeVariableTableOffset = (int) bw.BaseStream.Position;
1181 int num_scope_vars = scope_vars != null ? scope_vars.Length : 0;
1182 bw.WriteLeb128 (num_scope_vars);
1183 for (int i = 0; i < num_scope_vars; i++)
1184 scope_vars [i].Write (bw);
1186 if (real_name != null) {
1187 RealNameOffset = (int) bw.BaseStream.Position;
1188 bw.Write (real_name);
1191 LineNumberTableOffset = (int) bw.BaseStream.Position;
1192 lnt.Write (file, bw);
1194 DataOffset = (int) bw.BaseStream.Position;
1196 bw.WriteLeb128 (CompileUnitIndex);
1197 bw.WriteLeb128 (LocalVariableTableOffset);
1198 bw.WriteLeb128 (NamespaceID);
1200 bw.WriteLeb128 (CodeBlockTableOffset);
1201 bw.WriteLeb128 (ScopeVariableTableOffset);
1203 bw.WriteLeb128 (RealNameOffset);
1204 bw.WriteLeb128 ((int) flags);
1207 public LineNumberTable GetLineNumberTable ()
1213 if (LineNumberTableOffset == 0)
1216 MyBinaryReader reader = SymbolFile.BinaryReader;
1217 long old_pos = reader.BaseStream.Position;
1218 reader.BaseStream.Position = LineNumberTableOffset;
1220 lnt = LineNumberTable.Read (SymbolFile, reader);
1222 reader.BaseStream.Position = old_pos;
1227 public LocalVariableEntry[] GetLocals ()
1233 if (LocalVariableTableOffset == 0)
1236 MyBinaryReader reader = SymbolFile.BinaryReader;
1237 long old_pos = reader.BaseStream.Position;
1238 reader.BaseStream.Position = LocalVariableTableOffset;
1240 int num_locals = reader.ReadLeb128 ();
1241 locals = new LocalVariableEntry [num_locals];
1243 for (int i = 0; i < num_locals; i++)
1244 locals [i] = new LocalVariableEntry (SymbolFile, reader);
1246 reader.BaseStream.Position = old_pos;
1251 public CodeBlockEntry[] GetCodeBlocks ()
1254 if (code_blocks != null)
1257 if (CodeBlockTableOffset == 0)
1260 MyBinaryReader reader = SymbolFile.BinaryReader;
1261 long old_pos = reader.BaseStream.Position;
1262 reader.BaseStream.Position = CodeBlockTableOffset;
1264 int num_code_blocks = reader.ReadLeb128 ();
1265 code_blocks = new CodeBlockEntry [num_code_blocks];
1267 for (int i = 0; i < num_code_blocks; i++)
1268 code_blocks [i] = new CodeBlockEntry (i, reader);
1270 reader.BaseStream.Position = old_pos;
1275 public ScopeVariable[] GetScopeVariables ()
1278 if (scope_vars != null)
1281 if (ScopeVariableTableOffset == 0)
1284 MyBinaryReader reader = SymbolFile.BinaryReader;
1285 long old_pos = reader.BaseStream.Position;
1286 reader.BaseStream.Position = ScopeVariableTableOffset;
1288 int num_scope_vars = reader.ReadLeb128 ();
1289 scope_vars = new ScopeVariable [num_scope_vars];
1291 for (int i = 0; i < num_scope_vars; i++)
1292 scope_vars [i] = new ScopeVariable (reader);
1294 reader.BaseStream.Position = old_pos;
1299 public string GetRealName ()
1302 if (real_name != null)
1305 if (RealNameOffset == 0)
1308 real_name = SymbolFile.BinaryReader.ReadString (RealNameOffset);
1313 public int CompareTo (object obj)
1315 MethodEntry method = (MethodEntry) obj;
1317 if (method.Token < Token)
1319 else if (method.Token > Token)
1325 public override string ToString ()
1327 return String.Format ("[Method {0}:{1:x}:{2}:{3}]",
1328 index, Token, CompileUnitIndex, CompileUnit);
1332 public struct NamespaceEntry
1334 #region This is actually written to the symbol file
1335 public readonly string Name;
1336 public readonly int Index;
1337 public readonly int Parent;
1338 public readonly string[] UsingClauses;
1341 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
1345 this.Parent = parent;
1346 this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
1349 internal NamespaceEntry (MonoSymbolFile file, MyBinaryReader reader)
1351 Name = reader.ReadString ();
1352 Index = reader.ReadLeb128 ();
1353 Parent = reader.ReadLeb128 ();
1355 int count = reader.ReadLeb128 ();
1356 UsingClauses = new string [count];
1357 for (int i = 0; i < count; i++)
1358 UsingClauses [i] = reader.ReadString ();
1361 internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
1364 bw.WriteLeb128 (Index);
1365 bw.WriteLeb128 (Parent);
1366 bw.WriteLeb128 (UsingClauses.Length);
1367 foreach (string uc in UsingClauses)
1371 public override string ToString ()
1373 return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);