2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / Mono.CompilerServices.SymbolWriter / MonoSymbolTable.cs
bloba044a60a2d13fb4a4ba8cb78e8aecb9fe97cb7af
1 //
2 // Mono.CSharp.Debugger/MonoSymbolTable.cs
3 //
4 // Author:
5 // Martin Baulig (martin@ximian.com)
6 //
7 // (C) 2002 Ximian, Inc. http://www.ximian.com
8 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System;
32 using System.Security.Cryptography;
33 using System.Collections;
34 using System.Text;
35 using System.IO;
38 // Parts which are actually written into the symbol file are marked with
40 // #region This is actually written to the symbol file
41 // #endregion
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
60 // numbers:
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;
92 public int TypeCount;
93 public int AnonymousScopeCount;
94 public int AnonymousScopeTableOffset;
95 public int AnonymousScopeTableSize;
97 [Flags]
98 public enum Flags
100 IsAspxSource = 1,
101 WindowsFileNames = 2
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;
109 #endregion
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;
189 #endregion
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)
197 this.File = file;
198 this.Row = row;
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)
213 return -1;
214 else if (l1.Offset > l2.Offset)
215 return 1;
216 else
217 return 0;
221 private class RowComparerClass : IComparer
223 public int Compare (object a, object b)
225 LineNumberEntry l1 = (LineNumberEntry) a;
226 LineNumberEntry l2 = (LineNumberEntry) b;
228 if (l1.Row < l2.Row)
229 return -1;
230 else if (l1.Row > l2.Row)
231 return 1;
232 else
233 return 0;
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
248 public int Index;
249 #region This is actually written to the symbol file
250 public int Parent;
251 public Type BlockType;
252 public int StartOffset;
253 public int EndOffset;
254 #endregion
256 public enum Type {
257 Lexical = 1,
258 CompilerGenerated = 2,
259 IteratorBody = 3,
260 IteratorDispatcher = 4
263 public CodeBlockEntry (int index, int parent, Type type, int start_offset)
265 this.Index = index;
266 this.Parent = parent;
267 this.BlockType = type;
268 this.StartOffset = start_offset;
271 internal CodeBlockEntry (int index, MyBinaryReader reader)
273 this.Index = index;
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;
313 #endregion
315 public LocalVariableEntry (int index, string name, int block)
317 this.Index = index;
318 this.Name = name;
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);
332 bw.Write (Name);
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;
349 #endregion
351 public enum CapturedKind : byte
353 Local,
354 Parameter,
355 This
358 public CapturedVariable (string name, string captured_name,
359 CapturedKind kind)
361 this.Name = name;
362 this.CapturedName = captured_name;
363 this.Kind = kind;
366 internal CapturedVariable (MyBinaryReader reader)
368 Name = reader.ReadString ();
369 CapturedName = reader.ReadString ();
370 Kind = (CapturedKind) reader.ReadByte ();
373 internal void Write (MyBinaryWriter bw)
375 bw.Write (Name);
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;
392 #endregion
394 public CapturedScope (int scope, string captured_name)
396 this.Scope = scope;
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;
424 #endregion
426 public ScopeVariable (int scope, int index)
428 this.Scope = scope;
429 this.Index = 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;
454 #endregion
456 ArrayList captured_vars = new ArrayList ();
457 ArrayList captured_scopes = new ArrayList ();
459 public AnonymousScopeEntry (int id)
461 this.ID = 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 {
484 get {
485 CapturedVariable[] retval = new CapturedVariable [captured_vars.Count];
486 captured_vars.CopyTo (retval, 0);
487 return retval;
491 internal void AddCapturedScope (int scope, string captured_name)
493 captured_scopes.Add (new CapturedScope (scope, captured_name));
496 public CapturedScope[] CapturedScopes {
497 get {
498 CapturedScope[] retval = new CapturedScope [captured_scopes.Count];
499 captured_scopes.CopyTo (retval, 0);
500 return retval;
504 internal void Write (MyBinaryWriter bw)
506 bw.WriteLeb128 (ID);
508 bw.WriteLeb128 (captured_vars.Count);
509 foreach (CapturedVariable cv in captured_vars)
510 cv.Write (bw);
512 bw.WriteLeb128 (captured_scopes.Count);
513 foreach (CapturedScope cs in captured_scopes)
514 cs.Write (bw);
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;
527 int DataOffset;
528 #endregion
530 MonoSymbolFile file;
531 SourceFileEntry source;
532 ArrayList include_files;
533 ArrayList namespaces;
535 bool creating;
537 public static int Size {
538 get { return 8; }
541 CompileUnitEntry ICompileUnit.Entry {
542 get { return this; }
545 public CompileUnitEntry (MonoSymbolFile file, SourceFileEntry source)
547 this.file = file;
548 this.source = source;
550 this.Index = file.AddCompileUnit (this);
552 creating = true;
553 namespaces = new ArrayList ();
556 public void AddFile (SourceFileEntry file)
558 if (!creating)
559 throw new InvalidOperationException ();
561 if (include_files == null)
562 include_files = new ArrayList ();
564 include_files.Add (file);
567 public SourceFileEntry SourceFile {
568 get {
569 if (creating)
570 return source;
572 ReadData ();
573 return source;
577 public int DefineNamespace (string name, string[] using_clauses, int parent)
579 if (!creating)
580 throw new InvalidOperationException ();
582 int index = file.GetNextNamespaceIndex ();
583 NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
584 namespaces.Add (ns);
585 return index;
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)
602 ns.Write (file, bw);
605 internal void Write (BinaryWriter bw)
607 bw.Write (Index);
608 bw.Write (DataOffset);
611 internal CompileUnitEntry (MonoSymbolFile file, MyBinaryReader reader)
613 this.file = file;
615 Index = reader.ReadInt32 ();
616 DataOffset = reader.ReadInt32 ();
619 void ReadData ()
621 if (creating)
622 throw new InvalidOperationException ();
624 lock (file) {
625 if (namespaces != null)
626 return;
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 {
653 get {
654 ReadData ();
655 NamespaceEntry[] retval = new NamespaceEntry [namespaces.Count];
656 namespaces.CopyTo (retval, 0);
657 return retval;
661 public SourceFileEntry[] IncludeFiles {
662 get {
663 ReadData ();
664 if (include_files == null)
665 return new SourceFileEntry [0];
667 SourceFileEntry[] retval = new SourceFileEntry [include_files.Count];
668 include_files.CopyTo (retval, 0);
669 return retval;
674 public class SourceFileEntry
676 #region This is actually written to the symbol file
677 public readonly int Index;
678 int DataOffset;
679 #endregion
681 MonoSymbolFile file;
682 string file_name;
683 byte[] guid;
684 byte[] hash;
685 bool creating;
686 bool auto_generated;
688 public static int Size {
689 get { return 8; }
692 public SourceFileEntry (MonoSymbolFile file, string file_name)
694 this.file = file;
695 this.file_name = file_name;
696 this.Index = file.AddSource (this);
698 creating = true;
701 public SourceFileEntry (MonoSymbolFile file, string file_name,
702 byte[] guid, byte[] checksum)
703 : this (file, file_name)
705 this.guid = guid;
706 this.hash = checksum;
709 internal void WriteData (MyBinaryWriter bw)
711 DataOffset = (int) bw.BaseStream.Position;
712 bw.Write (file_name);
714 if (guid == null) {
715 guid = Guid.NewGuid ().ToByteArray ();
716 try {
717 using (FileStream fs = new FileStream (file_name, FileMode.Open, FileAccess.Read)) {
718 MD5 md5 = MD5.Create ();
719 hash = md5.ComputeHash (fs);
721 } catch {
722 hash = new byte [16];
726 bw.Write (guid);
727 bw.Write (hash);
728 bw.Write ((byte) (auto_generated ? 1 : 0));
731 internal void Write (BinaryWriter bw)
733 bw.Write (Index);
734 bw.Write (DataOffset);
737 internal SourceFileEntry (MonoSymbolFile file, MyBinaryReader reader)
739 this.file = file;
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 ()
765 if (!creating)
766 throw new InvalidOperationException ();
768 auto_generated = true;
769 file.OffsetTable.FileFlags |= OffsetTable.Flags.IsAspxSource;
772 public bool CheckChecksum ()
774 try {
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])
780 return false;
781 return true;
783 } catch {
784 return false;
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;
812 #endregion
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;
822 // MONO extensions.
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)
837 : this (file)
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]))
854 continue;
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) {
864 bw.Write ((byte) 0);
865 bw.Write ((byte) 1);
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;
874 } else {
875 bw.Write (DW_LNS_advance_pc);
876 bw.WriteLeb128 (offset_inc);
877 offset_inc = 0;
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);
889 } else {
890 byte opcode;
891 opcode = (byte) (line_inc - LineBase + (LineRange * offset_inc) +
892 OpcodeBase);
893 bw.Write (opcode);
896 last_line = LineNumbers [i].Row;
897 last_offset = LineNumbers [i].Offset;
900 bw.Write ((byte) 0);
901 bw.Write ((byte) 1);
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);
911 return lnt;
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;
920 while (true) {
921 byte opcode = br.ReadByte ();
923 if (opcode == 0) {
924 byte size = br.ReadByte ();
925 long end_pos = br.BaseStream.Position + size;
926 opcode = br.ReadByte ();
928 if (opcode == DW_LNE_end_sequence) {
929 if (modified)
930 lines.Add (new LineNumberEntry (
931 stm_file, stm_line, stm_offset, is_hidden));
932 break;
933 } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
934 is_hidden = !is_hidden;
935 modified = true;
936 } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
937 (opcode <= DW_LNE_MONO__extensions_end)) {
938 ; // reserved for future extensions
939 } else {
940 throw new MonoSymbolFileException (
941 "Unknown extended opcode {0:x} in LNT ({1})",
942 opcode, file.FileName);
945 br.BaseStream.Position = end_pos;
946 continue;
947 } else if (opcode < OpcodeBase) {
948 switch (opcode) {
949 case DW_LNS_copy:
950 lines.Add (new LineNumberEntry (
951 stm_file, stm_line, stm_offset, is_hidden));
952 modified = false;
953 break;
954 case DW_LNS_advance_pc:
955 stm_offset += br.ReadLeb128 ();
956 modified = true;
957 break;
958 case DW_LNS_advance_line:
959 stm_line += br.ReadLeb128 ();
960 modified = true;
961 break;
962 case DW_LNS_set_file:
963 stm_file = br.ReadLeb128 ();
964 modified = true;
965 break;
966 case DW_LNS_const_add_pc:
967 stm_offset += MaxAddressIncrement;
968 modified = true;
969 break;
970 default:
971 throw new MonoSymbolFileException (
972 "Unknown standard opcode {0:x} in LNT",
973 opcode);
975 } else {
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));
982 modified = false;
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];
995 return true;
998 start = LineNumberEntry.Null;
999 end = LineNumberEntry.Null;
1000 return false;
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;
1011 int DataOffset;
1012 int LocalVariableTableOffset;
1013 int LineNumberTableOffset;
1014 int CodeBlockTableOffset;
1015 int ScopeVariableTableOffset;
1016 int RealNameOffset;
1017 Flags flags;
1018 #endregion
1020 int index;
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;
1032 string real_name;
1034 public readonly MonoSymbolFile SymbolFile;
1036 public int Index {
1037 get { return index; }
1038 set { index = value; }
1041 [Flags]
1042 public enum Flags
1044 LocalNamesAmbiguous = 1
1047 public const int Size = 12;
1049 internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index)
1051 this.SymbolFile = file;
1052 this.index = index;
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;
1088 this.flags = flags;
1090 index = -1;
1092 Token = token;
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;
1118 locals_check_done :
1120 } else {
1121 Hashtable local_names = new Hashtable ();
1122 foreach (LocalVariableEntry local in locals) {
1123 if (local_names.Contains (local.Name)) {
1124 flags |= Flags.LocalNamesAmbiguous;
1125 break;
1127 local_names.Add (local.Name, local);
1132 void CheckLineNumberTable (LineNumberEntry[] line_numbers)
1134 int last_offset = -1;
1135 int last_row = -1;
1137 if (line_numbers == null)
1138 return;
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 ();
1163 bw.Write (Token);
1164 bw.Write (DataOffset);
1165 bw.Write (LineNumberTableOffset);
1168 internal void WriteData (MonoSymbolFile file, MyBinaryWriter bw)
1170 if (index <= 0)
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 ()
1215 lock (SymbolFile) {
1216 if (lnt != null)
1217 return lnt;
1219 if (LineNumberTableOffset == 0)
1220 return null;
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;
1229 return lnt;
1233 public LocalVariableEntry[] GetLocals ()
1235 lock (SymbolFile) {
1236 if (locals != null)
1237 return locals;
1239 if (LocalVariableTableOffset == 0)
1240 return null;
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;
1253 return locals;
1257 public CodeBlockEntry[] GetCodeBlocks ()
1259 lock (SymbolFile) {
1260 if (code_blocks != null)
1261 return code_blocks;
1263 if (CodeBlockTableOffset == 0)
1264 return null;
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;
1277 return code_blocks;
1281 public ScopeVariable[] GetScopeVariables ()
1283 lock (SymbolFile) {
1284 if (scope_vars != null)
1285 return scope_vars;
1287 if (ScopeVariableTableOffset == 0)
1288 return null;
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;
1301 return scope_vars;
1305 public string GetRealName ()
1307 lock (SymbolFile) {
1308 if (real_name != null)
1309 return real_name;
1311 if (RealNameOffset == 0)
1312 return null;
1314 real_name = SymbolFile.BinaryReader.ReadString (RealNameOffset);
1315 return real_name;
1319 public int CompareTo (object obj)
1321 MethodEntry method = (MethodEntry) obj;
1323 if (method.Token < Token)
1324 return 1;
1325 else if (method.Token > Token)
1326 return -1;
1327 else
1328 return 0;
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;
1345 #endregion
1347 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
1349 this.Name = name;
1350 this.Index = index;
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)
1369 bw.Write (Name);
1370 bw.WriteLeb128 (Index);
1371 bw.WriteLeb128 (Parent);
1372 bw.WriteLeb128 (UsingClauses.Length);
1373 foreach (string uc in UsingClauses)
1374 bw.Write (uc);
1377 public override string ToString ()
1379 return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);