[build] Add System.Text.Encoding.CodePages dependency used for non-ascii files in...
[mono-project.git] / mcs / class / Mono.CompilerServices.SymbolWriter / MonoSymbolTable.cs
blobacd269f5c4e3dcec29a7524fc9fecfa536c17d41
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.Generic;
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 int Column;
187 public int EndRow, EndColumn;
188 public readonly int File;
189 public readonly int Offset;
190 public readonly bool IsHidden; // Obsolete is never used
191 #endregion
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)
224 this.File = file;
225 this.Row = row;
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
241 public int Index;
242 #region This is actually written to the symbol file
243 public int Parent;
244 public Type BlockType;
245 public int StartOffset;
246 public int EndOffset;
247 #endregion
249 public enum Type {
250 Lexical = 1,
251 CompilerGenerated = 2,
252 IteratorBody = 3,
253 IteratorDispatcher = 4
256 public CodeBlockEntry (int index, int parent, Type type, int start_offset)
258 this.Index = index;
259 this.Parent = parent;
260 this.BlockType = type;
261 this.StartOffset = start_offset;
264 internal CodeBlockEntry (int index, MyBinaryReader reader)
266 this.Index = index;
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;
306 #endregion
308 public LocalVariableEntry (int index, string name, int block)
310 this.Index = index;
311 this.Name = name;
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);
325 bw.Write (Name);
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;
342 #endregion
344 public enum CapturedKind : byte
346 Local,
347 Parameter,
348 This
351 public CapturedVariable (string name, string captured_name,
352 CapturedKind kind)
354 this.Name = name;
355 this.CapturedName = captured_name;
356 this.Kind = kind;
359 internal CapturedVariable (MyBinaryReader reader)
361 Name = reader.ReadString ();
362 CapturedName = reader.ReadString ();
363 Kind = (CapturedKind) reader.ReadByte ();
366 internal void Write (MyBinaryWriter bw)
368 bw.Write (Name);
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;
385 #endregion
387 public CapturedScope (int scope, string captured_name)
389 this.Scope = scope;
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;
417 #endregion
419 public ScopeVariable (int scope, int index)
421 this.Scope = scope;
422 this.Index = 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;
447 #endregion
449 List<CapturedVariable> captured_vars = new List<CapturedVariable> ();
450 List<CapturedScope> captured_scopes = new List<CapturedScope> ();
452 public AnonymousScopeEntry (int id)
454 this.ID = 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 {
477 get {
478 CapturedVariable[] retval = new CapturedVariable [captured_vars.Count];
479 captured_vars.CopyTo (retval, 0);
480 return retval;
484 internal void AddCapturedScope (int scope, string captured_name)
486 captured_scopes.Add (new CapturedScope (scope, captured_name));
489 public CapturedScope[] CapturedScopes {
490 get {
491 CapturedScope[] retval = new CapturedScope [captured_scopes.Count];
492 captured_scopes.CopyTo (retval, 0);
493 return retval;
497 internal void Write (MyBinaryWriter bw)
499 bw.WriteLeb128 (ID);
501 bw.WriteLeb128 (captured_vars.Count);
502 foreach (CapturedVariable cv in captured_vars)
503 cv.Write (bw);
505 bw.WriteLeb128 (captured_scopes.Count);
506 foreach (CapturedScope cs in captured_scopes)
507 cs.Write (bw);
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;
520 int DataOffset;
521 #endregion
523 MonoSymbolFile file;
524 SourceFileEntry source;
525 List<SourceFileEntry> include_files;
526 List<NamespaceEntry> namespaces;
528 bool creating;
530 public static int Size {
531 get { return 8; }
534 CompileUnitEntry ICompileUnit.Entry {
535 get { return this; }
538 public CompileUnitEntry (MonoSymbolFile file, SourceFileEntry source)
540 this.file = file;
541 this.source = source;
543 this.Index = file.AddCompileUnit (this);
545 creating = true;
546 namespaces = new List<NamespaceEntry> ();
549 public void AddFile (SourceFileEntry file)
551 if (!creating)
552 throw new InvalidOperationException ();
554 if (include_files == null)
555 include_files = new List<SourceFileEntry> ();
557 include_files.Add (file);
560 public SourceFileEntry SourceFile {
561 get {
562 if (creating)
563 return source;
565 ReadData ();
566 return source;
570 public int DefineNamespace (string name, string[] using_clauses, int parent)
572 if (!creating)
573 throw new InvalidOperationException ();
575 int index = file.GetNextNamespaceIndex ();
576 NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
577 namespaces.Add (ns);
578 return index;
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)
595 ns.Write (file, bw);
598 internal void Write (BinaryWriter bw)
600 bw.Write (Index);
601 bw.Write (DataOffset);
604 internal CompileUnitEntry (MonoSymbolFile file, MyBinaryReader reader)
606 this.file = file;
608 Index = reader.ReadInt32 ();
609 DataOffset = reader.ReadInt32 ();
612 public void ReadAll ()
614 ReadData ();
617 void ReadData ()
619 if (creating)
620 throw new InvalidOperationException ();
622 lock (file) {
623 if (namespaces != null)
624 return;
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 {
651 get {
652 ReadData ();
653 NamespaceEntry[] retval = new NamespaceEntry [namespaces.Count];
654 namespaces.CopyTo (retval, 0);
655 return retval;
659 public SourceFileEntry[] IncludeFiles {
660 get {
661 ReadData ();
662 if (include_files == null)
663 return new SourceFileEntry [0];
665 SourceFileEntry[] retval = new SourceFileEntry [include_files.Count];
666 include_files.CopyTo (retval, 0);
667 return retval;
672 public class SourceFileEntry
674 #region This is actually written to the symbol file
675 public readonly int Index;
676 int DataOffset;
677 #endregion
679 MonoSymbolFile file;
680 string file_name;
681 byte[] guid;
682 byte[] hash;
683 bool creating;
684 bool auto_generated;
685 readonly string sourceFile;
687 public static int Size {
688 get { return 8; }
691 public SourceFileEntry (MonoSymbolFile file, string file_name)
693 this.file = file;
694 this.file_name = file_name;
695 this.Index = file.AddSource (this);
697 creating = true;
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)
708 this.guid = guid;
709 this.hash = checksum;
710 this.sourceFile = sourceFile;
713 public byte[] Checksum {
714 get {
715 return hash;
719 internal void WriteData (MyBinaryWriter bw)
721 DataOffset = (int) bw.BaseStream.Position;
722 bw.Write (file_name);
724 if (guid == null)
725 guid = new byte[16];
727 if (hash == null) {
728 try {
729 using (FileStream fs = new FileStream (sourceFile, FileMode.Open, FileAccess.Read)) {
730 MD5 md5 = MD5.Create ();
731 hash = md5.ComputeHash (fs);
733 } catch {
734 hash = new byte [16];
738 bw.Write (guid);
739 bw.Write (hash);
740 bw.Write ((byte) (auto_generated ? 1 : 0));
743 internal void Write (BinaryWriter bw)
745 bw.Write (Index);
746 bw.Write (DataOffset);
749 internal SourceFileEntry (MonoSymbolFile file, MyBinaryReader reader)
751 this.file = file;
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 ()
778 if (!creating)
779 throw new InvalidOperationException ();
781 auto_generated = true;
782 file.OffsetTable.FileFlags |= OffsetTable.Flags.IsAspxSource;
785 public bool CheckChecksum ()
787 try {
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])
793 return false;
794 return true;
796 } catch {
797 return false;
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;
824 #endregion
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;
834 // MONO extensions.
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)
849 : this (file)
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) {
871 bw.Write ((byte) 0);
872 bw.Write ((byte) 1);
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;
881 } else {
882 bw.Write (DW_LNS_advance_pc);
883 bw.WriteLeb128 (offset_inc);
884 offset_inc = 0;
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);
896 } else {
897 byte opcode;
898 opcode = (byte) (line_inc - LineBase + (LineRange * offset_inc) +
899 OpcodeBase);
900 bw.Write (opcode);
903 last_line = LineNumbers [i].Row;
904 last_offset = LineNumbers [i].Offset;
907 bw.Write ((byte) 0);
908 bw.Write ((byte) 1);
909 bw.Write (DW_LNE_end_sequence);
911 if (hasColumnsInfo) {
912 for (int i = 0; i < LineNumbers.Length; i++) {
913 var ln = LineNumbers [i];
914 if (ln.Row >= 0)
915 bw.WriteLeb128 (ln.Column);
919 if (hasEndInfo) {
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);
924 } else {
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);
938 return lnt;
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;
947 while (true) {
948 byte opcode = br.ReadByte ();
950 if (opcode == 0) {
951 byte size = br.ReadByte ();
952 long end_pos = br.BaseStream.Position + size;
953 opcode = br.ReadByte ();
955 if (opcode == DW_LNE_end_sequence) {
956 if (modified)
957 lines.Add (new LineNumberEntry (
958 stm_file, stm_line, -1, stm_offset, is_hidden));
959 break;
960 } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
961 is_hidden = !is_hidden;
962 modified = true;
963 } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
964 (opcode <= DW_LNE_MONO__extensions_end)) {
965 ; // reserved for future extensions
966 } else {
967 throw new MonoSymbolFileException ("Unknown extended opcode {0:x}", opcode);
970 br.BaseStream.Position = end_pos;
971 continue;
972 } else if (opcode < OpcodeBase) {
973 switch (opcode) {
974 case DW_LNS_copy:
975 lines.Add (new LineNumberEntry (
976 stm_file, stm_line, -1, stm_offset, is_hidden));
977 modified = false;
978 break;
979 case DW_LNS_advance_pc:
980 stm_offset += br.ReadLeb128 ();
981 modified = true;
982 break;
983 case DW_LNS_advance_line:
984 stm_line += br.ReadLeb128 ();
985 modified = true;
986 break;
987 case DW_LNS_set_file:
988 stm_file = br.ReadLeb128 ();
989 modified = true;
990 break;
991 case DW_LNS_const_add_pc:
992 stm_offset += MaxAddressIncrement;
993 modified = true;
994 break;
995 default:
996 throw new MonoSymbolFileException (
997 "Unknown standard opcode {0:x} in LNT",
998 opcode);
1000 } else {
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));
1007 modified = false;
1011 _line_numbers = lines.ToArray ();
1013 if (includesColumns) {
1014 for (int i = 0; i < _line_numbers.Length; ++i) {
1015 var ln = _line_numbers[i];
1016 if (ln.Row >= 0)
1017 ln.Column = br.ReadLeb128 ();
1020 if (includesEnds) {
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) {
1026 ln.EndRow = -1;
1027 ln.EndColumn = -1;
1028 } else {
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];
1041 return true;
1044 start = LineNumberEntry.Null;
1045 end = LineNumberEntry.Null;
1046 return false;
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;
1057 int DataOffset;
1058 int LocalVariableTableOffset;
1059 int LineNumberTableOffset;
1060 int CodeBlockTableOffset;
1061 int ScopeVariableTableOffset;
1062 int RealNameOffset;
1063 Flags flags;
1064 #endregion
1066 int index;
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;
1078 string real_name;
1080 public readonly MonoSymbolFile SymbolFile;
1082 public int Index {
1083 get { return index; }
1084 set { index = value; }
1087 [Flags]
1088 public enum Flags
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;
1100 this.index = index;
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;
1136 this.flags = flags;
1138 index = -1;
1140 Token = token;
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;
1166 locals_check_done :
1168 } else {
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;
1173 break;
1175 local_names.Add (local.Name, local);
1180 static void CheckLineNumberTable (LineNumberEntry[] line_numbers)
1182 int last_offset = -1;
1183 int last_row = -1;
1185 if (line_numbers == null)
1186 return;
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 ();
1211 bw.Write (Token);
1212 bw.Write (DataOffset);
1213 bw.Write (LineNumberTableOffset);
1216 internal void WriteData (MonoSymbolFile file, MyBinaryWriter bw)
1218 if (index <= 0)
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 ();
1269 GetLocals ();
1270 GetCodeBlocks ();
1271 GetScopeVariables ();
1272 GetRealName ();
1275 public LineNumberTable GetLineNumberTable ()
1277 lock (SymbolFile) {
1278 if (lnt != null)
1279 return lnt;
1281 if (LineNumberTableOffset == 0)
1282 return null;
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;
1291 return lnt;
1295 public LocalVariableEntry[] GetLocals ()
1297 lock (SymbolFile) {
1298 if (locals != null)
1299 return locals;
1301 if (LocalVariableTableOffset == 0)
1302 return null;
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;
1315 return locals;
1319 public CodeBlockEntry[] GetCodeBlocks ()
1321 lock (SymbolFile) {
1322 if (code_blocks != null)
1323 return code_blocks;
1325 if (CodeBlockTableOffset == 0)
1326 return null;
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;
1339 return code_blocks;
1343 public ScopeVariable[] GetScopeVariables ()
1345 lock (SymbolFile) {
1346 if (scope_vars != null)
1347 return scope_vars;
1349 if (ScopeVariableTableOffset == 0)
1350 return null;
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;
1363 return scope_vars;
1367 public string GetRealName ()
1369 lock (SymbolFile) {
1370 if (real_name != null)
1371 return real_name;
1373 if (RealNameOffset == 0)
1374 return null;
1376 real_name = SymbolFile.BinaryReader.ReadString (RealNameOffset);
1377 return real_name;
1381 public int CompareTo (object obj)
1383 MethodEntry method = (MethodEntry) obj;
1385 if (method.Token < Token)
1386 return 1;
1387 else if (method.Token > Token)
1388 return -1;
1389 else
1390 return 0;
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;
1407 #endregion
1409 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
1411 this.Name = name;
1412 this.Index = index;
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)
1431 bw.Write (Name);
1432 bw.WriteLeb128 (Index);
1433 bw.WriteLeb128 (Parent);
1434 bw.WriteLeb128 (UsingClauses.Length);
1435 foreach (string uc in UsingClauses)
1436 bw.Write (uc);
1439 public override string ToString ()
1441 return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);