X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FMono.CompilerServices.SymbolWriter%2FMonoSymbolFile.cs;h=8431c70a4548e27b9ea3c6be7b7a0ddd667ac42f;hb=253b743dca0baabe199188871237993cd3c7e2e8;hp=efc36a8f8a791a461b3b28343804865d88d7f09a;hpb=5d9434fcb3acc1ed7d3d30603faae797d672fe65;p=mono.git diff --git a/mcs/class/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs b/mcs/class/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs index efc36a8f8a7..8431c70a454 100644 --- a/mcs/class/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs +++ b/mcs/class/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs @@ -1,12 +1,13 @@ // -// Mono.CSharp.Debugger/MonoSymbolFile.cs +// MonoSymbolFile.cs // -// Author: +// Authors: // Martin Baulig (martin@ximian.com) +// Marek Safar (marek.safar@gmail.com) // // (C) 2003 Ximian, Inc. http://www.ximian.com +// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com) // - // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -30,10 +31,7 @@ using System; using System.Reflection; -using SRE = System.Reflection.Emit; -using System.Collections; -using System.Text; -using System.Threading; +using System.Collections.Generic; using System.IO; namespace Mono.CompilerServices.SymbolWriter @@ -46,10 +44,16 @@ namespace Mono.CompilerServices.SymbolWriter public MonoSymbolFileException (string message, params object[] args) : base (String.Format (message, args)) - { } + { + } + + public MonoSymbolFileException (string message, Exception innerException) + : base (message, innerException) + { + } } - internal class MyBinaryWriter : BinaryWriter + sealed class MyBinaryWriter : BinaryWriter { public MyBinaryWriter (Stream stream) : base (stream) @@ -71,97 +75,129 @@ namespace Mono.CompilerServices.SymbolWriter { return base.Read7BitEncodedInt (); } - } - - internal class MonoDebuggerSupport - { - static GetMethodTokenFunc get_method_token; - static GetGuidFunc get_guid; - static GetLocalIndexFunc get_local_index; - - delegate int GetMethodTokenFunc (MethodBase method); - delegate Guid GetGuidFunc (Module module); - delegate int GetLocalIndexFunc (SRE.LocalBuilder local); - static Delegate create_delegate (Type type, Type delegate_type, string name) + public string ReadString (int offset) { - MethodInfo mi = type.GetMethod (name, BindingFlags.Static | - BindingFlags.NonPublic); - if (mi == null) - throw new Exception ("Can't find " + name); + long old_pos = BaseStream.Position; + BaseStream.Position = offset; - return Delegate.CreateDelegate (delegate_type, mi); - } - - static MonoDebuggerSupport () - { - get_method_token = (GetMethodTokenFunc) create_delegate ( - typeof (Assembly), typeof (GetMethodTokenFunc), - "MonoDebugger_GetMethodToken"); + string text = ReadString (); - get_guid = (GetGuidFunc) create_delegate ( - typeof (Module), typeof (GetGuidFunc), "Mono_GetGuid"); + BaseStream.Position = old_pos; + return text; + } + } - get_local_index = (GetLocalIndexFunc) create_delegate ( - typeof (SRE.LocalBuilder), typeof (GetLocalIndexFunc), - "Mono_GetLocalIndex"); + public interface ISourceFile + { + SourceFileEntry Entry { + get; } + } - public static int GetMethodToken (MethodBase method) - { - return get_method_token (method); + public interface ICompileUnit + { + CompileUnitEntry Entry { + get; } + } - public static Guid GetGuid (Module module) - { - return get_guid (module); + public interface IMethodDef + { + string Name { + get; } - public static int GetLocalIndex (SRE.LocalBuilder local) - { - return get_local_index (local); + int Token { + get; } } public class MonoSymbolFile : IDisposable { - ArrayList methods = new ArrayList (); - ArrayList sources = new ArrayList (); - Hashtable method_source_hash = new Hashtable (); - Hashtable type_hash = new Hashtable (); + List methods = new List (); + List sources = new List (); + List comp_units = new List (); + Dictionary anonymous_scopes; OffsetTable ot; int last_type_index; int last_method_index; - int last_source_index; int last_namespace_index; + public readonly int MajorVersion = OffsetTable.MajorVersion; + public readonly int MinorVersion = OffsetTable.MinorVersion; + public int NumLineNumbers; public MonoSymbolFile () - { } + { + ot = new OffsetTable (); + } - internal int AddSource (SourceFileEntry source) + public int AddSource (SourceFileEntry source) { sources.Add (source); - return ++last_source_index; + return sources.Count; } - internal int DefineType (Type type) + public int AddCompileUnit (CompileUnitEntry entry) { - if (type_hash.Contains (type)) - return (int) type_hash [type]; - - int index = ++last_type_index; - type_hash.Add (type, index); - return index; + comp_units.Add (entry); + return comp_units.Count; } - internal void AddMethod (MethodEntry entry) + public void AddMethod (MethodEntry entry) { methods.Add (entry); } + public MethodEntry DefineMethod (CompileUnitEntry comp_unit, int token, + ScopeVariable[] scope_vars, LocalVariableEntry[] locals, + LineNumberEntry[] lines, CodeBlockEntry[] code_blocks, + string real_name, MethodEntry.Flags flags, + int namespace_id) + { + if (reader != null) + throw new InvalidOperationException (); + + MethodEntry method = new MethodEntry ( + this, comp_unit, token, scope_vars, locals, lines, code_blocks, + real_name, flags, namespace_id); + AddMethod (method); + return method; + } + + internal void DefineAnonymousScope (int id) + { + if (reader != null) + throw new InvalidOperationException (); + + if (anonymous_scopes == null) + anonymous_scopes = new Dictionary (); + + anonymous_scopes.Add (id, new AnonymousScopeEntry (id)); + } + + internal void DefineCapturedVariable (int scope_id, string name, string captured_name, + CapturedVariable.CapturedKind kind) + { + if (reader != null) + throw new InvalidOperationException (); + + AnonymousScopeEntry scope = anonymous_scopes [scope_id]; + scope.AddCapturedVariable (name, captured_name, kind); + } + + internal void DefineCapturedScope (int scope_id, int id, string captured_name) + { + if (reader != null) + throw new InvalidOperationException (); + + AnonymousScopeEntry scope = anonymous_scopes [scope_id]; + scope.AddCapturedScope (id, captured_name); + } + internal int GetNextTypeIndex () { return ++last_type_index; @@ -177,22 +213,12 @@ namespace Mono.CompilerServices.SymbolWriter return ++last_namespace_index; } - internal string ReadString (int offset) - { - int old_pos = (int) reader.BaseStream.Position; - reader.BaseStream.Position = offset; - - string text = reader.ReadString (); - - reader.BaseStream.Position = old_pos; - return text; - } - void Write (MyBinaryWriter bw, Guid guid) { // Magic number and file version. bw.Write (OffsetTable.Magic); - bw.Write (OffsetTable.Version); + bw.Write (MajorVersion); + bw.Write (MinorVersion); bw.Write (guid.ToByteArray ()); @@ -201,14 +227,14 @@ namespace Mono.CompilerServices.SymbolWriter // writing the whole file, so we just reserve the space for it here. // long offset_table_offset = bw.BaseStream.Position; - ot.Write (bw); + ot.Write (bw, MajorVersion, MinorVersion); // // Sort the methods according to their tokens and update their index. // methods.Sort (); for (int i = 0; i < methods.Count; i++) - ((MethodEntry) methods [i]).Index = i + 1; + methods [i].Index = i + 1; // // Write data sections. @@ -216,6 +242,10 @@ namespace Mono.CompilerServices.SymbolWriter ot.DataSectionOffset = (int) bw.BaseStream.Position; foreach (SourceFileEntry source in sources) source.WriteData (bw); + foreach (CompileUnitEntry comp_unit in comp_units) + comp_unit.WriteData (bw); + foreach (MethodEntry method in methods) + method.WriteData (this, bw); ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset; // @@ -223,8 +253,8 @@ namespace Mono.CompilerServices.SymbolWriter // ot.MethodTableOffset = (int) bw.BaseStream.Position; for (int i = 0; i < methods.Count; i++) { - MethodEntry entry = (MethodEntry) methods [i]; - entry.WriteIndex (bw); + MethodEntry entry = methods [i]; + entry.Write (bw); } ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset; @@ -233,88 +263,103 @@ namespace Mono.CompilerServices.SymbolWriter // ot.SourceTableOffset = (int) bw.BaseStream.Position; for (int i = 0; i < sources.Count; i++) { - SourceFileEntry source = (SourceFileEntry) sources [i]; + SourceFileEntry source = sources [i]; source.Write (bw); } ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset; + // + // Write compilation unit table. + // + ot.CompileUnitTableOffset = (int) bw.BaseStream.Position; + for (int i = 0; i < comp_units.Count; i++) { + CompileUnitEntry unit = comp_units [i]; + unit.Write (bw); + } + ot.CompileUnitTableSize = (int) bw.BaseStream.Position - ot.CompileUnitTableOffset; + + // + // Write anonymous scope table. + // + ot.AnonymousScopeCount = anonymous_scopes != null ? anonymous_scopes.Count : 0; + ot.AnonymousScopeTableOffset = (int) bw.BaseStream.Position; + if (anonymous_scopes != null) { + foreach (AnonymousScopeEntry scope in anonymous_scopes.Values) + scope.Write (bw); + } + ot.AnonymousScopeTableSize = (int) bw.BaseStream.Position - ot.AnonymousScopeTableOffset; + // // Fixup offset table. // ot.TypeCount = last_type_index; ot.MethodCount = methods.Count; ot.SourceCount = sources.Count; + ot.CompileUnitCount = comp_units.Count; // // Write offset table. // ot.TotalFileSize = (int) bw.BaseStream.Position; bw.Seek ((int) offset_table_offset, SeekOrigin.Begin); - ot.Write (bw); + ot.Write (bw, MajorVersion, MinorVersion); bw.Seek (0, SeekOrigin.End); + +#if false + Console.WriteLine ("TOTAL: {0} line numbes, {1} bytes, extended {2} bytes, " + + "{3} methods.", NumLineNumbers, LineNumberSize, + ExtendedLineNumberSize, methods.Count); +#endif } public void CreateSymbolFile (Guid guid, FileStream fs) { if (reader != null) throw new InvalidOperationException (); - + Write (new MyBinaryWriter (fs), guid); } - Assembly assembly; MyBinaryReader reader; - Hashtable method_hash; - Hashtable source_file_hash; + Dictionary source_file_hash; + Dictionary compile_unit_hash; - Hashtable method_token_hash; - Hashtable source_name_hash; + List method_list; + Dictionary method_token_hash; + Dictionary source_name_hash; - protected MonoSymbolFile (string filename, Assembly assembly) - { - this.assembly = assembly; + Guid guid; - FileStream stream = new FileStream (filename, FileMode.Open, FileAccess.Read); + MonoSymbolFile (Stream stream) + { reader = new MyBinaryReader (stream); - Guid guid; - try { long magic = reader.ReadInt64 (); - long version = reader.ReadInt32 (); + int major_version = reader.ReadInt32 (); + int minor_version = reader.ReadInt32 (); + if (magic != OffsetTable.Magic) + throw new MonoSymbolFileException ("Symbol file is not a valid"); + if (major_version != OffsetTable.MajorVersion) throw new MonoSymbolFileException ( - "Symbol file `{0}' is not a valid " + - "Mono symbol file", filename); - if (version != OffsetTable.Version) - throw new MonoSymbolFileException ( - "Symbol file `{0}' has version {1}, " + - "but expected {2}", filename, version, - OffsetTable.Version); - + "Symbol file has version {0} but expected {1}", major_version, OffsetTable.MajorVersion); + if (minor_version != OffsetTable.MinorVersion) + throw new MonoSymbolFileException ("Symbol file has version {0}.{1} but expected {2}.{3}", + major_version, minor_version, + OffsetTable.MajorVersion, OffsetTable.MinorVersion); + + MajorVersion = major_version; + MinorVersion = minor_version; guid = new Guid (reader.ReadBytes (16)); - ot = new OffsetTable (reader); - } catch { - throw new MonoSymbolFileException ( - "Cannot read symbol file `{0}'", filename); + ot = new OffsetTable (reader, major_version, minor_version); + } catch (Exception e) { + throw new MonoSymbolFileException ("Cannot read symbol file", e); } - if (assembly != null) { - // Check that the MDB file matches the assembly, if we have been - // passed an assembly. - - Module[] modules = assembly.GetModules (); - Guid assembly_guid = MonoDebuggerSupport.GetGuid (modules [0]); - - if (guid != assembly_guid) - throw new MonoSymbolFileException ( - "Symbol file `{0}' does not match assembly `{1}'", - filename, assembly.Location); - } - - method_hash = new Hashtable (); - source_file_hash = new Hashtable (); + source_file_hash = new Dictionary (); + compile_unit_hash = new Dictionary (); } public static MonoSymbolFile ReadSymbolFile (Assembly assembly) @@ -322,16 +367,33 @@ namespace Mono.CompilerServices.SymbolWriter string filename = assembly.Location; string name = filename + ".mdb"; - return new MonoSymbolFile (name, assembly); + Module[] modules = assembly.GetModules (); + Guid assembly_guid = modules[0].ModuleVersionId; + + return ReadSymbolFile (name, assembly_guid); } public static MonoSymbolFile ReadSymbolFile (string mdbFilename) { - return new MonoSymbolFile (mdbFilename, null); + return ReadSymbolFile (new FileStream (mdbFilename, FileMode.Open, FileAccess.Read)); } - public Assembly Assembly { - get { return assembly; } + public static MonoSymbolFile ReadSymbolFile (string mdbFilename, Guid assemblyGuid) + { + var sf = ReadSymbolFile (mdbFilename); + if (assemblyGuid != sf.guid) + throw new MonoSymbolFileException ("Symbol file `{0}' does not match assembly", mdbFilename); + + return sf; + } + + public static MonoSymbolFile ReadSymbolFile (Stream stream) + { + return new MonoSymbolFile (stream); + } + + public int CompileUnitCount { + get { return ot.CompileUnitCount; } } public int SourceCount { @@ -346,14 +408,29 @@ namespace Mono.CompilerServices.SymbolWriter get { return ot.TypeCount; } } + public int AnonymousScopeCount { + get { return ot.AnonymousScopeCount; } + } + public int NamespaceCount { get { return last_namespace_index; } } + public Guid Guid { + get { return guid; } + } + + public OffsetTable OffsetTable { + get { return ot; } + } + internal int LineNumberCount = 0; internal int LocalCount = 0; internal int StringSize = 0; + internal int LineNumberSize = 0; + internal int ExtendedLineNumberSize = 0; + public SourceFileEntry GetSourceFile (int index) { if ((index < 1) || (index > ot.SourceCount)) @@ -361,15 +438,21 @@ namespace Mono.CompilerServices.SymbolWriter if (reader == null) throw new InvalidOperationException (); - SourceFileEntry source = (SourceFileEntry) source_file_hash [index]; - if (source != null) - return source; + lock (this) { + SourceFileEntry source; + if (source_file_hash.TryGetValue (index, out source)) + return source; + + long old_pos = reader.BaseStream.Position; + + reader.BaseStream.Position = ot.SourceTableOffset + + SourceFileEntry.Size * (index - 1); + source = new SourceFileEntry (this, reader); + source_file_hash.Add (index, source); - reader.BaseStream.Position = ot.SourceTableOffset + - SourceFileEntry.Size * (index - 1); - source = new SourceFileEntry (this, reader); - source_file_hash.Add (index, source); - return source; + reader.BaseStream.Position = old_pos; + return source; + } } public SourceFileEntry[] Sources { @@ -384,44 +467,75 @@ namespace Mono.CompilerServices.SymbolWriter } } - public MethodIndexEntry GetMethodIndexEntry (int index) - { - int old_pos = (int) reader.BaseStream.Position; - reader.BaseStream.Position = ot.MethodTableOffset + - MethodIndexEntry.Size * (index - 1); - MethodIndexEntry ie = new MethodIndexEntry (reader); - reader.BaseStream.Position = old_pos; - return ie; - } - - public MethodEntry GetMethodByToken (int token) + public CompileUnitEntry GetCompileUnit (int index) { + if ((index < 1) || (index > ot.CompileUnitCount)) + throw new ArgumentException (); if (reader == null) throw new InvalidOperationException (); - if (method_token_hash == null) { - method_token_hash = new Hashtable (); + lock (this) { + CompileUnitEntry unit; + if (compile_unit_hash.TryGetValue (index, out unit)) + return unit; - for (int i = 0; i < MethodCount; i++) { - MethodIndexEntry ie = GetMethodIndexEntry (i + 1); + long old_pos = reader.BaseStream.Position; - method_token_hash.Add (ie.Token, i + 1); - } + reader.BaseStream.Position = ot.CompileUnitTableOffset + + CompileUnitEntry.Size * (index - 1); + unit = new CompileUnitEntry (this, reader); + compile_unit_hash.Add (index, unit); + + reader.BaseStream.Position = old_pos; + return unit; + } + } + + public CompileUnitEntry[] CompileUnits { + get { + if (reader == null) + throw new InvalidOperationException (); + + CompileUnitEntry[] retval = new CompileUnitEntry [CompileUnitCount]; + for (int i = 0; i < CompileUnitCount; i++) + retval [i] = GetCompileUnit (i + 1); + return retval; } + } + + void read_methods () + { + lock (this) { + if (method_token_hash != null) + return; - object value = method_token_hash [token]; - if (value == null) - return null; + method_token_hash = new Dictionary (); + method_list = new List (); - return GetMethod ((int) value); + long old_pos = reader.BaseStream.Position; + reader.BaseStream.Position = ot.MethodTableOffset; + + for (int i = 0; i < MethodCount; i++) { + MethodEntry entry = new MethodEntry (this, reader, i + 1); + method_token_hash.Add (entry.Token, entry); + method_list.Add (entry); + } + + reader.BaseStream.Position = old_pos; + } } - public MethodEntry GetMethod (MethodBase method) + public MethodEntry GetMethodByToken (int token) { if (reader == null) throw new InvalidOperationException (); - int token = MonoDebuggerSupport.GetMethodToken (method); - return GetMethodByToken (token); + + lock (this) { + read_methods (); + MethodEntry me; + method_token_hash.TryGetValue (token, out me); + return me; + } } public MethodEntry GetMethod (int index) @@ -431,16 +545,10 @@ namespace Mono.CompilerServices.SymbolWriter if (reader == null) throw new InvalidOperationException (); - MethodEntry entry = (MethodEntry) method_hash [index]; - if (entry != null) - return entry; - - MethodIndexEntry ie = GetMethodIndexEntry (index); - reader.BaseStream.Position = ie.FileOffset; - - entry = new MethodEntry (this, reader, index); - method_hash.Add (index, entry); - return entry; + lock (this) { + read_methods (); + return method_list [index - 1]; + } } public MethodEntry[] Methods { @@ -448,54 +556,58 @@ namespace Mono.CompilerServices.SymbolWriter if (reader == null) throw new InvalidOperationException (); - MethodEntry[] retval = new MethodEntry [MethodCount]; - for (int i = 0; i < MethodCount; i++) - retval [i] = GetMethod (i + 1); - return retval; + lock (this) { + read_methods (); + MethodEntry[] retval = new MethodEntry [MethodCount]; + method_list.CopyTo (retval, 0); + return retval; + } } } - public MethodSourceEntry GetMethodSource (int index) + public int FindSource (string file_name) { - if ((index < 1) || (index > ot.MethodCount)) - throw new ArgumentException (); if (reader == null) throw new InvalidOperationException (); - object entry = method_source_hash [index]; - if (entry != null) - return (MethodSourceEntry) entry; + lock (this) { + if (source_name_hash == null) { + source_name_hash = new Dictionary (); - MethodEntry method = GetMethod (index); - foreach (MethodSourceEntry source in method.SourceFile.Methods) { - if (source.Index == index) { - method_source_hash.Add (index, source); - return source; + for (int i = 0; i < ot.SourceCount; i++) { + SourceFileEntry source = GetSourceFile (i + 1); + source_name_hash.Add (source.FileName, i); + } } - } - throw new MonoSymbolFileException ("Internal error."); + int value; + if (!source_name_hash.TryGetValue (file_name, out value)) + return -1; + return value; + } } - public int FindSource (string file_name) + public AnonymousScopeEntry GetAnonymousScope (int id) { if (reader == null) throw new InvalidOperationException (); - if (source_name_hash == null) { - source_name_hash = new Hashtable (); - - for (int i = 0; i < ot.SourceCount; i++) { - SourceFileEntry source = GetSourceFile (i + 1); + AnonymousScopeEntry scope; + lock (this) { + if (anonymous_scopes != null) { + anonymous_scopes.TryGetValue (id, out scope); + return scope; + } - source_name_hash.Add (source.FileName, i); + anonymous_scopes = new Dictionary (); + reader.BaseStream.Position = ot.AnonymousScopeTableOffset; + for (int i = 0; i < ot.AnonymousScopeCount; i++) { + scope = new AnonymousScopeEntry (reader); + anonymous_scopes.Add (scope.ID, scope); } - } - object value = source_name_hash [file_name]; - if (value == null) - return -1; - return (int) value; + return anonymous_scopes [id]; + } } internal MyBinaryReader BinaryReader {