X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FMono.CompilerServices.SymbolWriter%2FMonoSymbolTable.cs;h=5f30818ff626bf3ec23d046c9ee4e7f09cb5dc3b;hb=eae45fd7044c04b0ebc1ad900e00ef0b79aa7ed8;hp=4fadaf1e18b467e5411801c0d61b7bc920e55401;hpb=bd9f9ee7cb81823608edc76ef9d0b6416783fe71;p=mono.git diff --git a/mcs/class/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs b/mcs/class/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs index 4fadaf1e18b..5f30818ff62 100644 --- a/mcs/class/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs +++ b/mcs/class/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs @@ -29,7 +29,8 @@ // using System; -using System.Collections; +using System.Security.Cryptography; +using System.Collections.Generic; using System.Text; using System.IO; @@ -69,15 +70,19 @@ using System.IO; namespace Mono.CompilerServices.SymbolWriter { - public struct OffsetTable + public class OffsetTable { - public const int Version = 38; - public const long Magic = 0x45e82623fd7fa614; + public const int MajorVersion = 50; + public const int MinorVersion = 0; + public const long Magic = 0x45e82623fd7fa614; #region This is actually written to the symbol file public int TotalFileSize; public int DataSectionOffset; public int DataSectionSize; + public int CompileUnitCount; + public int CompileUnitTableOffset; + public int CompileUnitTableSize; public int SourceCount; public int SourceTableOffset; public int SourceTableSize; @@ -85,13 +90,39 @@ namespace Mono.CompilerServices.SymbolWriter public int MethodTableOffset; public int MethodTableSize; public int TypeCount; + public int AnonymousScopeCount; + public int AnonymousScopeTableOffset; + public int AnonymousScopeTableSize; + + [Flags] + public enum Flags + { + IsAspxSource = 1, + WindowsFileNames = 2 + } + + public Flags FileFlags; + + public int LineNumberTable_LineBase = LineNumberTable.Default_LineBase; + public int LineNumberTable_LineRange = LineNumberTable.Default_LineRange; + public int LineNumberTable_OpcodeBase = LineNumberTable.Default_OpcodeBase; #endregion - internal OffsetTable (BinaryReader reader) + internal OffsetTable () + { + int platform = (int) Environment.OSVersion.Platform; + if ((platform != 4) && (platform != 128)) + FileFlags |= Flags.WindowsFileNames; + } + + internal OffsetTable (BinaryReader reader, int major_version, int minor_version) { TotalFileSize = reader.ReadInt32 (); DataSectionOffset = reader.ReadInt32 (); DataSectionSize = reader.ReadInt32 (); + CompileUnitCount = reader.ReadInt32 (); + CompileUnitTableOffset = reader.ReadInt32 (); + CompileUnitTableSize = reader.ReadInt32 (); SourceCount = reader.ReadInt32 (); SourceTableOffset = reader.ReadInt32 (); SourceTableSize = reader.ReadInt32 (); @@ -99,13 +130,26 @@ namespace Mono.CompilerServices.SymbolWriter MethodTableOffset = reader.ReadInt32 (); MethodTableSize = reader.ReadInt32 (); TypeCount = reader.ReadInt32 (); + + AnonymousScopeCount = reader.ReadInt32 (); + AnonymousScopeTableOffset = reader.ReadInt32 (); + AnonymousScopeTableSize = reader.ReadInt32 (); + + LineNumberTable_LineBase = reader.ReadInt32 (); + LineNumberTable_LineRange = reader.ReadInt32 (); + LineNumberTable_OpcodeBase = reader.ReadInt32 (); + + FileFlags = (Flags) reader.ReadInt32 (); } - internal void Write (BinaryWriter bw) + internal void Write (BinaryWriter bw, int major_version, int minor_version) { bw.Write (TotalFileSize); bw.Write (DataSectionOffset); bw.Write (DataSectionSize); + bw.Write (CompileUnitCount); + bw.Write (CompileUnitTableOffset); + bw.Write (CompileUnitTableSize); bw.Write (SourceCount); bw.Write (SourceTableOffset); bw.Write (SourceTableSize); @@ -113,6 +157,16 @@ namespace Mono.CompilerServices.SymbolWriter bw.Write (MethodTableOffset); bw.Write (MethodTableSize); bw.Write (TypeCount); + + bw.Write (AnonymousScopeCount); + bw.Write (AnonymousScopeTableOffset); + bw.Write (AnonymousScopeTableSize); + + bw.Write (LineNumberTable_LineBase); + bw.Write (LineNumberTable_LineRange); + bw.Write (LineNumberTable_OpcodeBase); + + bw.Write ((int) FileFlags); } public override string ToString () @@ -125,40 +179,33 @@ namespace Mono.CompilerServices.SymbolWriter } } - public struct LineNumberEntry + public class LineNumberEntry { #region This is actually written to the symbol file public readonly int Row; + public readonly int File; public readonly int Offset; + public readonly bool IsHidden; #endregion - public LineNumberEntry (int row, int offset) + public LineNumberEntry (int file, int row, int offset) + : this (file, row, offset, false) + { } + + public LineNumberEntry (int file, int row, int offset, bool is_hidden) { + this.File = file; this.Row = row; this.Offset = offset; + this.IsHidden = is_hidden; } - public static LineNumberEntry Null = new LineNumberEntry (0, 0); - - internal LineNumberEntry (BinaryReader reader) - { - Row = reader.ReadInt32 (); - Offset = reader.ReadInt32 (); - } - - internal void Write (BinaryWriter bw) - { - bw.Write (Row); - bw.Write (Offset); - } + public static LineNumberEntry Null = new LineNumberEntry (0, 0, 0); - private class OffsetComparerClass : IComparer + private class OffsetComparerClass : IComparer { - public int Compare (object a, object b) + public int Compare (LineNumberEntry l1, LineNumberEntry l2) { - LineNumberEntry l1 = (LineNumberEntry) a; - LineNumberEntry l2 = (LineNumberEntry) b; - if (l1.Offset < l2.Offset) return -1; else if (l1.Offset > l2.Offset) @@ -168,13 +215,10 @@ namespace Mono.CompilerServices.SymbolWriter } } - private class RowComparerClass : IComparer + private class RowComparerClass : IComparer { - public int Compare (object a, object b) + public int Compare (LineNumberEntry l1, LineNumberEntry l2) { - LineNumberEntry l1 = (LineNumberEntry) a; - LineNumberEntry l2 = (LineNumberEntry) b; - if (l1.Row < l2.Row) return -1; else if (l1.Row > l2.Row) @@ -184,34 +228,54 @@ namespace Mono.CompilerServices.SymbolWriter } } - public static readonly IComparer OffsetComparer = new OffsetComparerClass (); - public static readonly IComparer RowComparer = new RowComparerClass (); + public static readonly IComparer OffsetComparer = new OffsetComparerClass (); + public static readonly IComparer RowComparer = new RowComparerClass (); public override string ToString () { - return String.Format ("[Line {0}:{1}]", Row, Offset); + return String.Format ("[Line {0}:{1}:{2}]", File, Row, Offset); } } - public class LexicalBlockEntry + public class CodeBlockEntry { public int Index; #region This is actually written to the symbol file + public int Parent; + public Type BlockType; public int StartOffset; public int EndOffset; #endregion - public LexicalBlockEntry (int index, int start_offset) + public enum Type { + Lexical = 1, + CompilerGenerated = 2, + IteratorBody = 3, + IteratorDispatcher = 4 + } + + public CodeBlockEntry (int index, int parent, Type type, int start_offset) { this.Index = index; + this.Parent = parent; + this.BlockType = type; this.StartOffset = start_offset; } - internal LexicalBlockEntry (int index, MyBinaryReader reader) + internal CodeBlockEntry (int index, MyBinaryReader reader) { this.Index = index; - this.StartOffset = reader.ReadInt32 (); - this.EndOffset = reader.ReadInt32 (); + int type_flag = reader.ReadLeb128 (); + BlockType = (Type) (type_flag & 0x3f); + this.Parent = reader.ReadLeb128 (); + this.StartOffset = reader.ReadLeb128 (); + this.EndOffset = reader.ReadLeb128 (); + + /* Reserved for future extensions. */ + if ((type_flag & 0x40) != 0) { + int data_size = reader.ReadInt16 (); + reader.BaseStream.Position += data_size; + } } public void Close (int end_offset) @@ -221,98 +285,287 @@ namespace Mono.CompilerServices.SymbolWriter internal void Write (MyBinaryWriter bw) { - bw.Write (StartOffset); - bw.Write (EndOffset); + bw.WriteLeb128 ((int) BlockType); + bw.WriteLeb128 (Parent); + bw.WriteLeb128 (StartOffset); + bw.WriteLeb128 (EndOffset); } public override string ToString () { - return String.Format ("[LexicalBlock {0}:{1}]", StartOffset, EndOffset); + return String.Format ("[CodeBlock {0}:{1}:{2}:{3}:{4}]", + Index, Parent, BlockType, StartOffset, EndOffset); } } public struct LocalVariableEntry { #region This is actually written to the symbol file + public readonly int Index; public readonly string Name; - public readonly byte[] Signature; public readonly int BlockIndex; #endregion - public LocalVariableEntry (string Name, byte[] Signature, int BlockIndex) + public LocalVariableEntry (int index, string name, int block) { - this.Name = Name; - this.Signature = Signature; - this.BlockIndex = BlockIndex; + this.Index = index; + this.Name = name; + this.BlockIndex = block; } - internal LocalVariableEntry (MyBinaryReader reader) + internal LocalVariableEntry (MonoSymbolFile file, MyBinaryReader reader) { + Index = reader.ReadLeb128 (); Name = reader.ReadString (); - int sig_length = reader.ReadLeb128 (); - Signature = reader.ReadBytes (sig_length); BlockIndex = reader.ReadLeb128 (); } internal void Write (MonoSymbolFile file, MyBinaryWriter bw) { + bw.WriteLeb128 (Index); bw.Write (Name); - bw.WriteLeb128 ((int) Signature.Length); - bw.Write (Signature); bw.WriteLeb128 (BlockIndex); } public override string ToString () { - return String.Format ("[LocalVariable {0}]", Name); + return String.Format ("[LocalVariable {0}:{1}:{2}]", + Name, Index, BlockIndex - 1); } } - public class SourceFileEntry + public struct CapturedVariable + { + #region This is actually written to the symbol file + public readonly string Name; + public readonly string CapturedName; + public readonly CapturedKind Kind; + #endregion + + public enum CapturedKind : byte + { + Local, + Parameter, + This + } + + public CapturedVariable (string name, string captured_name, + CapturedKind kind) + { + this.Name = name; + this.CapturedName = captured_name; + this.Kind = kind; + } + + internal CapturedVariable (MyBinaryReader reader) + { + Name = reader.ReadString (); + CapturedName = reader.ReadString (); + Kind = (CapturedKind) reader.ReadByte (); + } + + internal void Write (MyBinaryWriter bw) + { + bw.Write (Name); + bw.Write (CapturedName); + bw.Write ((byte) Kind); + } + + public override string ToString () + { + return String.Format ("[CapturedVariable {0}:{1}:{2}]", + Name, CapturedName, Kind); + } + } + + public struct CapturedScope + { + #region This is actually written to the symbol file + public readonly int Scope; + public readonly string CapturedName; + #endregion + + public CapturedScope (int scope, string captured_name) + { + this.Scope = scope; + this.CapturedName = captured_name; + } + + internal CapturedScope (MyBinaryReader reader) + { + Scope = reader.ReadLeb128 (); + CapturedName = reader.ReadString (); + } + + internal void Write (MyBinaryWriter bw) + { + bw.WriteLeb128 (Scope); + bw.Write (CapturedName); + } + + public override string ToString () + { + return String.Format ("[CapturedScope {0}:{1}]", + Scope, CapturedName); + } + } + + public struct ScopeVariable + { + #region This is actually written to the symbol file + public readonly int Scope; + public readonly int Index; + #endregion + + public ScopeVariable (int scope, int index) + { + this.Scope = scope; + this.Index = index; + } + + internal ScopeVariable (MyBinaryReader reader) + { + Scope = reader.ReadLeb128 (); + Index = reader.ReadLeb128 (); + } + + internal void Write (MyBinaryWriter bw) + { + bw.WriteLeb128 (Scope); + bw.WriteLeb128 (Index); + } + + public override string ToString () + { + return String.Format ("[ScopeVariable {0}:{1}]", Scope, Index); + } + } + + public class AnonymousScopeEntry + { + #region This is actually written to the symbol file + public readonly int ID; + #endregion + + List captured_vars = new List (); + List captured_scopes = new List (); + + public AnonymousScopeEntry (int id) + { + this.ID = id; + } + + internal AnonymousScopeEntry (MyBinaryReader reader) + { + ID = reader.ReadLeb128 (); + + int num_captured_vars = reader.ReadLeb128 (); + for (int i = 0; i < num_captured_vars; i++) + captured_vars.Add (new CapturedVariable (reader)); + + int num_captured_scopes = reader.ReadLeb128 (); + for (int i = 0; i < num_captured_scopes; i++) + captured_scopes.Add (new CapturedScope (reader)); + } + + internal void AddCapturedVariable (string name, string captured_name, + CapturedVariable.CapturedKind kind) + { + captured_vars.Add (new CapturedVariable (name, captured_name, kind)); + } + + public CapturedVariable[] CapturedVariables { + get { + CapturedVariable[] retval = new CapturedVariable [captured_vars.Count]; + captured_vars.CopyTo (retval, 0); + return retval; + } + } + + internal void AddCapturedScope (int scope, string captured_name) + { + captured_scopes.Add (new CapturedScope (scope, captured_name)); + } + + public CapturedScope[] CapturedScopes { + get { + CapturedScope[] retval = new CapturedScope [captured_scopes.Count]; + captured_scopes.CopyTo (retval, 0); + return retval; + } + } + + internal void Write (MyBinaryWriter bw) + { + bw.WriteLeb128 (ID); + + bw.WriteLeb128 (captured_vars.Count); + foreach (CapturedVariable cv in captured_vars) + cv.Write (bw); + + bw.WriteLeb128 (captured_scopes.Count); + foreach (CapturedScope cs in captured_scopes) + cs.Write (bw); + } + + public override string ToString () + { + return String.Format ("[AnonymousScope {0}]", ID); + } + } + + public class CompileUnitEntry : ICompileUnit { #region This is actually written to the symbol file public readonly int Index; - int Count; - int NamespaceCount; - int NameOffset; - int MethodOffset; - int NamespaceTableOffset; + int DataOffset; #endregion MonoSymbolFile file; - string file_name; - ArrayList methods; - ArrayList namespaces; + SourceFileEntry source; + List include_files; + List namespaces; + bool creating; public static int Size { - get { return 24; } + get { return 8; } } - public SourceFileEntry (MonoSymbolFile file, string file_name) + CompileUnitEntry ICompileUnit.Entry { + get { return this; } + } + + public CompileUnitEntry (MonoSymbolFile file, SourceFileEntry source) { this.file = file; - this.file_name = file_name; - this.Index = file.AddSource (this); + this.source = source; + + this.Index = file.AddCompileUnit (this); creating = true; - methods = new ArrayList (); - namespaces = new ArrayList (); + namespaces = new List (); } - public void DefineMethod (string name, int token, LocalVariableEntry[] locals, - LineNumberEntry[] lines, LexicalBlockEntry[] blocks, - int start, int end, int namespace_id) + public void AddFile (SourceFileEntry file) { if (!creating) throw new InvalidOperationException (); - MethodEntry entry = new MethodEntry ( - file, this, name, (int) token, locals, lines, blocks, - start, end, namespace_id); + if (include_files == null) + include_files = new List (); - methods.Add (entry); - file.AddMethod (entry); + include_files.Add (file); + } + + public SourceFileEntry SourceFile { + get { + if (creating) + return source; + + ReadData (); + return source; + } } public int DefineNamespace (string name, string[] using_clauses, int parent) @@ -328,21 +581,17 @@ namespace Mono.CompilerServices.SymbolWriter internal void WriteData (MyBinaryWriter bw) { - NameOffset = (int) bw.BaseStream.Position; - bw.Write (file_name); - - ArrayList list = new ArrayList (); - foreach (MethodEntry entry in methods) - list.Add (entry.Write (file, bw)); - list.Sort (); - Count = list.Count; - - MethodOffset = (int) bw.BaseStream.Position; - foreach (MethodSourceEntry method in list) - method.Write (bw); + DataOffset = (int) bw.BaseStream.Position; + bw.WriteLeb128 (source.Index); + + int count_includes = include_files != null ? include_files.Count : 0; + bw.WriteLeb128 (count_includes); + if (include_files != null) { + foreach (SourceFileEntry entry in include_files) + bw.WriteLeb128 (entry.Index); + } - NamespaceCount = namespaces.Count; - NamespaceTableOffset = (int) bw.BaseStream.Position; + bw.WriteLeb128 (namespaces.Count); foreach (NamespaceEntry ns in namespaces) ns.Write (file, bw); } @@ -350,198 +599,431 @@ namespace Mono.CompilerServices.SymbolWriter internal void Write (BinaryWriter bw) { bw.Write (Index); - bw.Write (Count); - bw.Write (NamespaceCount); - bw.Write (NameOffset); - bw.Write (MethodOffset); - bw.Write (NamespaceTableOffset); + bw.Write (DataOffset); } - internal SourceFileEntry (MonoSymbolFile file, BinaryReader reader) + internal CompileUnitEntry (MonoSymbolFile file, MyBinaryReader reader) { this.file = file; Index = reader.ReadInt32 (); - Count = reader.ReadInt32 (); - NamespaceCount = reader.ReadInt32 (); - NameOffset = reader.ReadInt32 (); - MethodOffset = reader.ReadInt32 (); - NamespaceTableOffset = reader.ReadInt32 (); - - file_name = file.ReadString (NameOffset); + DataOffset = reader.ReadInt32 (); } - public string FileName { - get { return file_name; } - } + void ReadData () + { + if (creating) + throw new InvalidOperationException (); - public MethodSourceEntry[] Methods { - get { - if (creating) - throw new InvalidOperationException (); + lock (file) { + if (namespaces != null) + return; - BinaryReader reader = file.BinaryReader; + MyBinaryReader reader = file.BinaryReader; int old_pos = (int) reader.BaseStream.Position; - reader.BaseStream.Position = MethodOffset; - ArrayList list = new ArrayList (); - for (int i = 0; i < Count; i ++) - list.Add (new MethodSourceEntry (reader)); - reader.BaseStream.Position = old_pos; + reader.BaseStream.Position = DataOffset; - MethodSourceEntry[] retval = new MethodSourceEntry [Count]; - list.CopyTo (retval, 0); - return retval; - } - } + int source_idx = reader.ReadLeb128 (); + source = file.GetSourceFile (source_idx); - public NamespaceEntry[] Namespaces { - get { - if (creating) - throw new InvalidOperationException (); + int count_includes = reader.ReadLeb128 (); + if (count_includes > 0) { + include_files = new List (); + for (int i = 0; i < count_includes; i++) + include_files.Add (file.GetSourceFile (reader.ReadLeb128 ())); + } - MyBinaryReader reader = file.BinaryReader; - int old_pos = (int) reader.BaseStream.Position; + int count_ns = reader.ReadLeb128 (); + namespaces = new List (); + for (int i = 0; i < count_ns; i ++) + namespaces.Add (new NamespaceEntry (file, reader)); - reader.BaseStream.Position = NamespaceTableOffset; - ArrayList list = new ArrayList (); - for (int i = 0; i < NamespaceCount; i ++) - list.Add (new NamespaceEntry (file, reader)); reader.BaseStream.Position = old_pos; + } + } - NamespaceEntry[] retval = new NamespaceEntry [list.Count]; - list.CopyTo (retval, 0); + public NamespaceEntry[] Namespaces { + get { + ReadData (); + NamespaceEntry[] retval = new NamespaceEntry [namespaces.Count]; + namespaces.CopyTo (retval, 0); return retval; } } - public override string ToString () - { - return String.Format ("SourceFileEntry ({0}:{1}:{2})", - Index, file_name, Count); + public SourceFileEntry[] IncludeFiles { + get { + ReadData (); + if (include_files == null) + return new SourceFileEntry [0]; + + SourceFileEntry[] retval = new SourceFileEntry [include_files.Count]; + include_files.CopyTo (retval, 0); + return retval; + } } } - public struct MethodSourceEntry : IComparable + public class SourceFileEntry { #region This is actually written to the symbol file public readonly int Index; - public readonly int FileOffset; - public readonly int StartRow; - public readonly int EndRow; + int DataOffset; #endregion - public MethodSourceEntry (int index, int file_offset, int start, int end) + MonoSymbolFile file; + string file_name; + byte[] guid; + byte[] hash; + bool creating; + bool auto_generated; + + public static int Size { + get { return 8; } + } + + public SourceFileEntry (MonoSymbolFile file, string file_name) { - this.Index = index; - this.FileOffset = file_offset; - this.StartRow = start; - this.EndRow = end; + this.file = file; + this.file_name = file_name; + this.Index = file.AddSource (this); + + creating = true; } - internal MethodSourceEntry (BinaryReader reader) + public SourceFileEntry (MonoSymbolFile file, string file_name, + byte[] guid, byte[] checksum) + : this (file, file_name) { - Index = reader.ReadInt32 (); - FileOffset = reader.ReadInt32 (); - StartRow = reader.ReadInt32 (); - EndRow = reader.ReadInt32 (); + this.guid = guid; + this.hash = checksum; } - public static int Size { - get { return 16; } + internal void WriteData (MyBinaryWriter bw) + { + DataOffset = (int) bw.BaseStream.Position; + bw.Write (file_name); + + if (guid == null) { + guid = Guid.NewGuid ().ToByteArray (); + try { + using (FileStream fs = new FileStream (file_name, FileMode.Open, FileAccess.Read)) { + MD5 md5 = MD5.Create (); + hash = md5.ComputeHash (fs); + } + } catch { + hash = new byte [16]; + } + } + + bw.Write (guid); + bw.Write (hash); + bw.Write ((byte) (auto_generated ? 1 : 0)); } internal void Write (BinaryWriter bw) { bw.Write (Index); - bw.Write (FileOffset); - bw.Write (StartRow); - bw.Write (EndRow); + bw.Write (DataOffset); } - public int CompareTo (object obj) + internal SourceFileEntry (MonoSymbolFile file, MyBinaryReader reader) { - MethodSourceEntry method = (MethodSourceEntry) obj; + this.file = file; - if (method.StartRow < StartRow) - return -1; - else if (method.StartRow > StartRow) - return 1; - else - return 0; + Index = reader.ReadInt32 (); + DataOffset = reader.ReadInt32 (); + + int old_pos = (int) reader.BaseStream.Position; + reader.BaseStream.Position = DataOffset; + + file_name = reader.ReadString (); + guid = reader.ReadBytes (16); + hash = reader.ReadBytes (16); + auto_generated = reader.ReadByte () == 1; + + reader.BaseStream.Position = old_pos; + } + + public string FileName { + get { return file_name; } + } + + public bool AutoGenerated { + get { return auto_generated; } + } + + public void SetAutoGenerated () + { + if (!creating) + throw new InvalidOperationException (); + + auto_generated = true; + file.OffsetTable.FileFlags |= OffsetTable.Flags.IsAspxSource; + } + + public bool CheckChecksum () + { + try { + using (FileStream fs = new FileStream (file_name, FileMode.Open)) { + MD5 md5 = MD5.Create (); + byte[] data = md5.ComputeHash (fs); + for (int i = 0; i < 16; i++) + if (data [i] != hash [i]) + return false; + return true; + } + } catch { + return false; + } } public override string ToString () { - return String.Format ("MethodSourceEntry ({0}:{1}:{2}:{3})", - Index, FileOffset, StartRow, EndRow); + return String.Format ("SourceFileEntry ({0}:{1})", Index, DataOffset); } } - public struct MethodIndexEntry + public class LineNumberTable { - #region This is actually written to the symbol file - public readonly int FileOffset; - public readonly int Token; - #endregion + protected LineNumberEntry[] _line_numbers; + public LineNumberEntry[] LineNumbers { + get { return _line_numbers; } + } - public static int Size { - get { return 8; } + public readonly int LineBase; + public readonly int LineRange; + public readonly byte OpcodeBase; + public readonly int MaxAddressIncrement; + +#region Configurable constants + public const int Default_LineBase = -1; + public const int Default_LineRange = 8; + public const byte Default_OpcodeBase = 9; + + public const bool SuppressDuplicates = true; +#endregion + + public const byte DW_LNS_copy = 1; + public const byte DW_LNS_advance_pc = 2; + public const byte DW_LNS_advance_line = 3; + public const byte DW_LNS_set_file = 4; + public const byte DW_LNS_const_add_pc = 8; + + public const byte DW_LNE_end_sequence = 1; + + // MONO extensions. + public const byte DW_LNE_MONO_negate_is_hidden = 0x40; + + internal const byte DW_LNE_MONO__extensions_start = 0x40; + internal const byte DW_LNE_MONO__extensions_end = 0x7f; + + protected LineNumberTable (MonoSymbolFile file) + { + this.LineBase = file.OffsetTable.LineNumberTable_LineBase; + this.LineRange = file.OffsetTable.LineNumberTable_LineRange; + this.OpcodeBase = (byte) file.OffsetTable.LineNumberTable_OpcodeBase; + this.MaxAddressIncrement = (255 - OpcodeBase) / LineRange; } - public MethodIndexEntry (int offset, int token) + internal LineNumberTable (MonoSymbolFile file, LineNumberEntry[] lines) + : this (file) { - this.FileOffset = offset; - this.Token = token; + this._line_numbers = lines; } - internal MethodIndexEntry (BinaryReader reader) + internal void Write (MonoSymbolFile file, MyBinaryWriter bw) { - FileOffset = reader.ReadInt32 (); - Token = reader.ReadInt32 (); + int start = (int) bw.BaseStream.Position; + + bool last_is_hidden = false; + int last_line = 1, last_offset = 0, last_file = 1; + for (int i = 0; i < LineNumbers.Length; i++) { + int line_inc = LineNumbers [i].Row - last_line; + int offset_inc = LineNumbers [i].Offset - last_offset; + + if (SuppressDuplicates && (i+1 < LineNumbers.Length)) { + if (LineNumbers [i+1].Equals (LineNumbers [i])) + continue; + } + + if (LineNumbers [i].File != last_file) { + bw.Write (DW_LNS_set_file); + bw.WriteLeb128 (LineNumbers [i].File); + last_file = LineNumbers [i].File; + } + + if (LineNumbers [i].IsHidden != last_is_hidden) { + bw.Write ((byte) 0); + bw.Write ((byte) 1); + bw.Write (DW_LNE_MONO_negate_is_hidden); + last_is_hidden = LineNumbers [i].IsHidden; + } + + if (offset_inc >= MaxAddressIncrement) { + if (offset_inc < 2 * MaxAddressIncrement) { + bw.Write (DW_LNS_const_add_pc); + offset_inc -= MaxAddressIncrement; + } else { + bw.Write (DW_LNS_advance_pc); + bw.WriteLeb128 (offset_inc); + offset_inc = 0; + } + } + + if ((line_inc < LineBase) || (line_inc >= LineBase + LineRange)) { + bw.Write (DW_LNS_advance_line); + bw.WriteLeb128 (line_inc); + if (offset_inc != 0) { + bw.Write (DW_LNS_advance_pc); + bw.WriteLeb128 (offset_inc); + } + bw.Write (DW_LNS_copy); + } else { + byte opcode; + opcode = (byte) (line_inc - LineBase + (LineRange * offset_inc) + + OpcodeBase); + bw.Write (opcode); + } + + last_line = LineNumbers [i].Row; + last_offset = LineNumbers [i].Offset; + } + + bw.Write ((byte) 0); + bw.Write ((byte) 1); + bw.Write (DW_LNE_end_sequence); + + file.ExtendedLineNumberSize += (int) bw.BaseStream.Position - start; } - internal void Write (BinaryWriter bw) + internal static LineNumberTable Read (MonoSymbolFile file, MyBinaryReader br) { - bw.Write (FileOffset); - bw.Write (Token); + LineNumberTable lnt = new LineNumberTable (file); + lnt.DoRead (file, br); + return lnt; } - public override string ToString () + void DoRead (MonoSymbolFile file, MyBinaryReader br) + { + var lines = new List (); + + bool is_hidden = false, modified = false; + int stm_line = 1, stm_offset = 0, stm_file = 1; + while (true) { + byte opcode = br.ReadByte (); + + if (opcode == 0) { + byte size = br.ReadByte (); + long end_pos = br.BaseStream.Position + size; + opcode = br.ReadByte (); + + if (opcode == DW_LNE_end_sequence) { + if (modified) + lines.Add (new LineNumberEntry ( + stm_file, stm_line, stm_offset, is_hidden)); + break; + } else if (opcode == DW_LNE_MONO_negate_is_hidden) { + is_hidden = !is_hidden; + modified = true; + } else if ((opcode >= DW_LNE_MONO__extensions_start) && + (opcode <= DW_LNE_MONO__extensions_end)) { + ; // reserved for future extensions + } else { + throw new MonoSymbolFileException ( + "Unknown extended opcode {0:x} in LNT ({1})", + opcode, file.FileName); + } + + br.BaseStream.Position = end_pos; + continue; + } else if (opcode < OpcodeBase) { + switch (opcode) { + case DW_LNS_copy: + lines.Add (new LineNumberEntry ( + stm_file, stm_line, stm_offset, is_hidden)); + modified = false; + break; + case DW_LNS_advance_pc: + stm_offset += br.ReadLeb128 (); + modified = true; + break; + case DW_LNS_advance_line: + stm_line += br.ReadLeb128 (); + modified = true; + break; + case DW_LNS_set_file: + stm_file = br.ReadLeb128 (); + modified = true; + break; + case DW_LNS_const_add_pc: + stm_offset += MaxAddressIncrement; + modified = true; + break; + default: + throw new MonoSymbolFileException ( + "Unknown standard opcode {0:x} in LNT", + opcode); + } + } else { + opcode -= OpcodeBase; + + stm_offset += opcode / LineRange; + stm_line += LineBase + (opcode % LineRange); + lines.Add (new LineNumberEntry ( + stm_file, stm_line, stm_offset, is_hidden)); + modified = false; + } + } + + _line_numbers = new LineNumberEntry [lines.Count]; + lines.CopyTo (_line_numbers, 0); + } + + public bool GetMethodBounds (out LineNumberEntry start, out LineNumberEntry end) { - return String.Format ("MethodIndexEntry ({0}:{1:x})", - FileOffset, Token); + if (_line_numbers.Length > 1) { + start = _line_numbers [0]; + end = _line_numbers [_line_numbers.Length - 1]; + return true; + } + + start = LineNumberEntry.Null; + end = LineNumberEntry.Null; + return false; } } public class MethodEntry : IComparable { #region This is actually written to the symbol file - public readonly int SourceFileIndex; + public readonly int CompileUnitIndex; public readonly int Token; - public readonly int StartRow; - public readonly int EndRow; - public readonly int NumLocals; - public readonly int NumLineNumbers; public readonly int NamespaceID; - public readonly bool LocalNamesAmbiguous; - int NameOffset; - int TypeIndexTableOffset; + int DataOffset; int LocalVariableTableOffset; int LineNumberTableOffset; - int NumLexicalBlocks; - int LexicalBlockTableOffset; + int CodeBlockTableOffset; + int ScopeVariableTableOffset; + int RealNameOffset; + Flags flags; #endregion int index; - int file_offset; - public readonly SourceFileEntry SourceFile; - public readonly LineNumberEntry[] LineNumbers; - public readonly int[] LocalTypeIndices; - public readonly LocalVariableEntry[] Locals; - public readonly LexicalBlockEntry[] LexicalBlocks; + public Flags MethodFlags { + get { return flags; } + } + + public readonly CompileUnitEntry CompileUnit; + + LocalVariableEntry[] locals; + CodeBlockEntry[] code_blocks; + ScopeVariable[] scope_vars; + LineNumberTable lnt; + string real_name; public readonly MonoSymbolFile SymbolFile; @@ -550,116 +1032,79 @@ namespace Mono.CompilerServices.SymbolWriter set { index = value; } } - public static int Size { - get { return 52; } + [Flags] + public enum Flags + { + LocalNamesAmbiguous = 1 } + public const int Size = 12; + internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index) { this.SymbolFile = file; this.index = index; - SourceFileIndex = reader.ReadInt32 (); + Token = reader.ReadInt32 (); - StartRow = reader.ReadInt32 (); - EndRow = reader.ReadInt32 (); - NumLocals = reader.ReadInt32 (); - NumLineNumbers = reader.ReadInt32 (); - NameOffset = reader.ReadInt32 (); - TypeIndexTableOffset = reader.ReadInt32 (); - LocalVariableTableOffset = reader.ReadInt32 (); + DataOffset = reader.ReadInt32 (); LineNumberTableOffset = reader.ReadInt32 (); - NumLexicalBlocks = reader.ReadInt32 (); - LexicalBlockTableOffset = reader.ReadInt32 (); - NamespaceID = reader.ReadInt32 (); - LocalNamesAmbiguous = reader.ReadInt32 () != 0; - SourceFile = file.GetSourceFile (SourceFileIndex); - - if (LineNumberTableOffset != 0) { - long old_pos = reader.BaseStream.Position; - reader.BaseStream.Position = LineNumberTableOffset; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = DataOffset; - LineNumbers = new LineNumberEntry [NumLineNumbers]; + CompileUnitIndex = reader.ReadLeb128 (); + LocalVariableTableOffset = reader.ReadLeb128 (); + NamespaceID = reader.ReadLeb128 (); - for (int i = 0; i < NumLineNumbers; i++) - LineNumbers [i] = new LineNumberEntry (reader); + CodeBlockTableOffset = reader.ReadLeb128 (); + ScopeVariableTableOffset = reader.ReadLeb128 (); - reader.BaseStream.Position = old_pos; - } - - if (LocalVariableTableOffset != 0) { - long old_pos = reader.BaseStream.Position; - reader.BaseStream.Position = LocalVariableTableOffset; - - Locals = new LocalVariableEntry [NumLocals]; - - for (int i = 0; i < NumLocals; i++) - Locals [i] = new LocalVariableEntry (reader); - - reader.BaseStream.Position = old_pos; - } - - if (TypeIndexTableOffset != 0) { - long old_pos = reader.BaseStream.Position; - reader.BaseStream.Position = TypeIndexTableOffset; + RealNameOffset = reader.ReadLeb128 (); - LocalTypeIndices = new int [NumLocals]; + flags = (Flags) reader.ReadLeb128 (); - for (int i = 0; i < NumLocals; i++) - LocalTypeIndices [i] = reader.ReadInt32 (); + reader.BaseStream.Position = old_pos; - reader.BaseStream.Position = old_pos; - } - - if (LexicalBlockTableOffset != 0) { - long old_pos = reader.BaseStream.Position; - reader.BaseStream.Position = LexicalBlockTableOffset; - - LexicalBlocks = new LexicalBlockEntry [NumLexicalBlocks]; - for (int i = 0; i < NumLexicalBlocks; i++) - LexicalBlocks [i] = new LexicalBlockEntry (i, reader); - - reader.BaseStream.Position = old_pos; - } + CompileUnit = file.GetCompileUnit (CompileUnitIndex); } - internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, - string name, int token, LocalVariableEntry[] locals, - LineNumberEntry[] lines, LexicalBlockEntry[] blocks, - int start_row, int end_row, int namespace_id) + internal MethodEntry (MonoSymbolFile file, CompileUnitEntry comp_unit, + int token, ScopeVariable[] scope_vars, + LocalVariableEntry[] locals, LineNumberEntry[] lines, + CodeBlockEntry[] code_blocks, string real_name, + Flags flags, int namespace_id) { this.SymbolFile = file; + this.real_name = real_name; + this.locals = locals; + this.code_blocks = code_blocks; + this.scope_vars = scope_vars; + this.flags = flags; index = -1; Token = token; - SourceFileIndex = source.Index; - SourceFile = source; - StartRow = start_row; - EndRow = end_row; + CompileUnitIndex = comp_unit.Index; + CompileUnit = comp_unit; NamespaceID = namespace_id; - LexicalBlocks = blocks; - NumLexicalBlocks = LexicalBlocks != null ? LexicalBlocks.Length : 0; - - LineNumbers = BuildLineNumberTable (lines); - NumLineNumbers = LineNumbers.Length; - file.NumLineNumbers += NumLineNumbers; + CheckLineNumberTable (lines); + lnt = new LineNumberTable (file, lines); + file.NumLineNumbers += lines.Length; - NumLocals = locals != null ? locals.Length : 0; - Locals = locals; + int num_locals = locals != null ? locals.Length : 0; - if (NumLocals <= 32) { + if (num_locals <= 32) { // Most of the time, the O(n^2) factor is actually // less than the cost of allocating the hash table, // 32 is a rough number obtained through some testing. - for (int i = 0; i < NumLocals; i ++) { + for (int i = 0; i < num_locals; i ++) { string nm = locals [i].Name; - for (int j = i + 1; j < NumLocals; j ++) { + for (int j = i + 1; j < num_locals; j ++) { if (locals [j].Name == nm) { - LocalNamesAmbiguous = true; + flags |= Flags.LocalNamesAmbiguous; goto locals_check_done; } } @@ -667,117 +1112,202 @@ namespace Mono.CompilerServices.SymbolWriter locals_check_done : ; } else { - Hashtable local_names = new Hashtable (); + var local_names = new Dictionary (); foreach (LocalVariableEntry local in locals) { - if (local_names.Contains (local.Name)) { - LocalNamesAmbiguous = true; + if (local_names.ContainsKey (local.Name)) { + flags |= Flags.LocalNamesAmbiguous; break; } local_names.Add (local.Name, local); } } - - LocalTypeIndices = new int [NumLocals]; - for (int i = 0; i < NumLocals; i++) - LocalTypeIndices [i] = file.GetNextTypeIndex (); } - static LineNumberEntry [] tmp_buff = new LineNumberEntry [20]; - - // BuildLineNumberTable() eliminates duplicate line numbers and ensures - // we aren't going "backwards" since this would counfuse the runtime's - // debugging code (and the debugger). - // - // In the line number table, the "offset" field most be strictly - // monotonic increasing; that is, the next entry must not have an offset - // which is equal to or less than the current one. - // - // The most common case is that our input (ie. the line number table as - // we get it from mcs) contains several entries with the same offset - // (and different line numbers) - but it may also happen that the offset - // is decreasing (this can be considered as an exception, such lines will - // simply be discarded). - LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers) - { - int pos = 0; + void CheckLineNumberTable (LineNumberEntry[] line_numbers) + { int last_offset = -1; int last_row = -1; if (line_numbers == null) - return new LineNumberEntry [0]; + return; - if (tmp_buff.Length < (line_numbers.Length + 1)) - tmp_buff = new LineNumberEntry [(line_numbers.Length + 1) * 2]; - for (int i = 0; i < line_numbers.Length; i++) { LineNumberEntry line = line_numbers [i]; + if (line.Equals (LineNumberEntry.Null)) + throw new MonoSymbolFileException (); + + if (line.Offset < last_offset) + throw new MonoSymbolFileException (); + if (line.Offset > last_offset) { - if (last_row >= 0) - tmp_buff [pos ++] = new LineNumberEntry (last_row, last_offset); last_row = line.Row; last_offset = line.Offset; } else if (line.Row > last_row) { last_row = line.Row; } } + } - if (last_row >= 0) - tmp_buff [pos ++] = new LineNumberEntry (last_row, last_offset); + internal void Write (MyBinaryWriter bw) + { + if ((index <= 0) || (DataOffset == 0)) + throw new InvalidOperationException (); - LineNumberEntry [] retval = new LineNumberEntry [pos]; - Array.Copy (tmp_buff, retval, pos); - return retval; + bw.Write (Token); + bw.Write (DataOffset); + bw.Write (LineNumberTableOffset); } - internal MethodSourceEntry Write (MonoSymbolFile file, MyBinaryWriter bw) + internal void WriteData (MonoSymbolFile file, MyBinaryWriter bw) { if (index <= 0) throw new InvalidOperationException (); - NameOffset = (int) bw.BaseStream.Position; + LocalVariableTableOffset = (int) bw.BaseStream.Position; + int num_locals = locals != null ? locals.Length : 0; + bw.WriteLeb128 (num_locals); + for (int i = 0; i < num_locals; i++) + locals [i].Write (file, bw); + file.LocalCount += num_locals; + + CodeBlockTableOffset = (int) bw.BaseStream.Position; + int num_code_blocks = code_blocks != null ? code_blocks.Length : 0; + bw.WriteLeb128 (num_code_blocks); + for (int i = 0; i < num_code_blocks; i++) + code_blocks [i].Write (bw); + + ScopeVariableTableOffset = (int) bw.BaseStream.Position; + int num_scope_vars = scope_vars != null ? scope_vars.Length : 0; + bw.WriteLeb128 (num_scope_vars); + for (int i = 0; i < num_scope_vars; i++) + scope_vars [i].Write (bw); + + if (real_name != null) { + RealNameOffset = (int) bw.BaseStream.Position; + bw.Write (real_name); + } - TypeIndexTableOffset = (int) bw.BaseStream.Position; + LineNumberTableOffset = (int) bw.BaseStream.Position; + lnt.Write (file, bw); - for (int i = 0; i < NumLocals; i++) - bw.Write (LocalTypeIndices [i]); + DataOffset = (int) bw.BaseStream.Position; - LocalVariableTableOffset = (int) bw.BaseStream.Position; - for (int i = 0; i < NumLocals; i++) - Locals [i].Write (file, bw); - file.LocalCount += NumLocals; + bw.WriteLeb128 (CompileUnitIndex); + bw.WriteLeb128 (LocalVariableTableOffset); + bw.WriteLeb128 (NamespaceID); - LineNumberTableOffset = (int) bw.BaseStream.Position; - for (int i = 0; i < NumLineNumbers; i++) - LineNumbers [i].Write (bw); - file.LineNumberCount += NumLineNumbers; + bw.WriteLeb128 (CodeBlockTableOffset); + bw.WriteLeb128 (ScopeVariableTableOffset); - LexicalBlockTableOffset = (int) bw.BaseStream.Position; - for (int i = 0; i < NumLexicalBlocks; i++) - LexicalBlocks [i].Write (bw); - file_offset = (int) bw.BaseStream.Position; + bw.WriteLeb128 (RealNameOffset); + bw.WriteLeb128 ((int) flags); + } - bw.Write (SourceFileIndex); - bw.Write (Token); - bw.Write (StartRow); - bw.Write (EndRow); - bw.Write (NumLocals); - bw.Write (NumLineNumbers); - bw.Write (NameOffset); - bw.Write (TypeIndexTableOffset); - bw.Write (LocalVariableTableOffset); - bw.Write (LineNumberTableOffset); - bw.Write (NumLexicalBlocks); - bw.Write (LexicalBlockTableOffset); - bw.Write (NamespaceID); - bw.Write (LocalNamesAmbiguous ? 1 : 0); + public LineNumberTable GetLineNumberTable () + { + lock (SymbolFile) { + if (lnt != null) + return lnt; + + if (LineNumberTableOffset == 0) + return null; - return new MethodSourceEntry (index, file_offset, StartRow, EndRow); + MyBinaryReader reader = SymbolFile.BinaryReader; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = LineNumberTableOffset; + + lnt = LineNumberTable.Read (SymbolFile, reader); + + reader.BaseStream.Position = old_pos; + return lnt; + } } - internal void WriteIndex (BinaryWriter bw) + public LocalVariableEntry[] GetLocals () { - new MethodIndexEntry (file_offset, Token).Write (bw); + lock (SymbolFile) { + if (locals != null) + return locals; + + if (LocalVariableTableOffset == 0) + return null; + + MyBinaryReader reader = SymbolFile.BinaryReader; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = LocalVariableTableOffset; + + int num_locals = reader.ReadLeb128 (); + locals = new LocalVariableEntry [num_locals]; + + for (int i = 0; i < num_locals; i++) + locals [i] = new LocalVariableEntry (SymbolFile, reader); + + reader.BaseStream.Position = old_pos; + return locals; + } + } + + public CodeBlockEntry[] GetCodeBlocks () + { + lock (SymbolFile) { + if (code_blocks != null) + return code_blocks; + + if (CodeBlockTableOffset == 0) + return null; + + MyBinaryReader reader = SymbolFile.BinaryReader; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = CodeBlockTableOffset; + + int num_code_blocks = reader.ReadLeb128 (); + code_blocks = new CodeBlockEntry [num_code_blocks]; + + for (int i = 0; i < num_code_blocks; i++) + code_blocks [i] = new CodeBlockEntry (i, reader); + + reader.BaseStream.Position = old_pos; + return code_blocks; + } + } + + public ScopeVariable[] GetScopeVariables () + { + lock (SymbolFile) { + if (scope_vars != null) + return scope_vars; + + if (ScopeVariableTableOffset == 0) + return null; + + MyBinaryReader reader = SymbolFile.BinaryReader; + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = ScopeVariableTableOffset; + + int num_scope_vars = reader.ReadLeb128 (); + scope_vars = new ScopeVariable [num_scope_vars]; + + for (int i = 0; i < num_scope_vars; i++) + scope_vars [i] = new ScopeVariable (reader); + + reader.BaseStream.Position = old_pos; + return scope_vars; + } + } + + public string GetRealName () + { + lock (SymbolFile) { + if (real_name != null) + return real_name; + + if (RealNameOffset == 0) + return null; + + real_name = SymbolFile.BinaryReader.ReadString (RealNameOffset); + return real_name; + } } public int CompareTo (object obj) @@ -794,9 +1324,8 @@ namespace Mono.CompilerServices.SymbolWriter public override string ToString () { - return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {6}:{7} - {5}]", - index, Token, SourceFileIndex, StartRow, EndRow, - SourceFile, NumLocals, NumLineNumbers); + return String.Format ("[Method {0}:{1:x}:{2}:{3}]", + index, Token, CompileUnitIndex, CompileUnit); } }