[csdoc-patches] csdoc/src/mcsdoc/class/Mono.CSharp.Debugger MonoSymbolFile.cs,NONE,1.1 MonoSymbolTab
Status: Planning
Brought to you by:
mastergaurav
From: <mas...@us...> - 2004-10-29 14:18:39
|
Update of /cvsroot/csdoc/csdoc/src/mcsdoc/class/Mono.CSharp.Debugger In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24165/Mono.CSharp.Debugger Added Files: MonoSymbolFile.cs MonoSymbolTable.cs MonoSymbolWriter.cs Log Message: 2004-10-28 Gaurav Vaish * **/* : Getting the latest sync from mono repository. Will resume work pretty soon. Moving final work from csdoc to mcsdoc. --- NEW FILE: MonoSymbolFile.cs --- // // Mono.CSharp.Debugger/MonoSymbolFile.cs // // Author: // Martin Baulig (ma...@xi...) // // (C) 2003 Ximian, Inc. http://www.ximian.com // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Reflection; using System.Collections; using System.Text; using System.Threading; using System.IO; namespace Mono.CompilerServices.SymbolWriter { public class MonoSymbolFileException : Exception { public MonoSymbolFileException () : base () { } public MonoSymbolFileException (string message, params object[] args) : base (String.Format (message, args)) { } } internal class MyMemoryStream : Stream { int length; int real_length; int position; int chunk_size = 4096; ArrayList chunks = new ArrayList (); private struct Chunk { public readonly int Offset; public readonly int Length; public byte[] Buffer; public Chunk (int offset, int length) { this.Offset = offset; this.Length = length; this.Buffer = new Byte [length]; } } public override long Position { get { return position; } set { if (value > length) throw new ArgumentOutOfRangeException (); position = (int) value; } } public override long Length { get { return length; } } public override bool CanRead { get { return true; } } public override bool CanWrite { get { return true; } } public override bool CanSeek { get { return true; } } public override void SetLength (long new_length) { if (new_length < length) throw new ArgumentException (); while (new_length >= real_length) { Chunk new_chunk = new Chunk (real_length, chunk_size); chunks.Add (new_chunk); real_length += chunk_size; } length = (int) new_length; } public override void Flush () { } public override long Seek (long offset, SeekOrigin origin) { int ref_point; switch (origin) { case SeekOrigin.Begin: ref_point = 0; break; case SeekOrigin.Current: ref_point = position; break; case SeekOrigin.End: ref_point = length; break; default: throw new ArgumentException ("Invalid SeekOrigin"); } if ((ref_point + offset < 0) || (offset > real_length)) throw new ArgumentOutOfRangeException (); position = ref_point + (int) offset; return position; } Chunk FindChunk (int offset) { return (Chunk) chunks [offset / chunk_size]; } public override int Read (byte[] buffer, int offset, int count) { int old_count = count; while (count > 0) { Chunk chunk = FindChunk (position); int coffset = position - chunk.Offset; int rest = chunk.Length - coffset; int size = System.Math.Min (count, rest); Array.Copy (chunk.Buffer, coffset, buffer, offset, size); position += size; offset += size; count -= size; } return old_count; } public override void Write (byte[] buffer, int offset, int count) { if (position + count > length) SetLength (position + count); while (count > 0) { Chunk chunk = FindChunk (position); int coffset = position - chunk.Offset; int rest = chunk.Length - coffset; int size = System.Math.Min (count, rest); Array.Copy (buffer, offset, chunk.Buffer, coffset, size); position += size; offset += size; count -= size; } } public byte[] GetContents () { byte[] retval = new byte [length]; position = 0; Read (retval, 0, length); return retval; } } internal class MyBinaryWriter : BinaryWriter { public MyBinaryWriter (Stream stream) : base (stream) { } public void WriteLeb128 (int value) { base.Write7BitEncodedInt (value); } } internal class MyBinaryReader : BinaryReader { public MyBinaryReader (Stream stream) : base (stream) { } public int ReadLeb128 () { return base.Read7BitEncodedInt (); } } public class MonoDebuggerSupport { static GetTypeFunc get_type; static GetMethodTokenFunc get_method_token; static GetMethodFunc get_method; static GetLocalTypeFromSignatureFunc local_type_from_sig; static GetGuidFunc get_guid; static CheckRuntimeVersionFunc check_runtime_version; delegate Type GetTypeFunc (Assembly assembly, int token); delegate int GetMethodTokenFunc (Assembly assembly, MethodBase method); delegate MethodBase GetMethodFunc (Assembly assembly, int token); delegate Type GetLocalTypeFromSignatureFunc (Assembly assembly, byte[] sig); delegate Guid GetGuidFunc (Module module); delegate string CheckRuntimeVersionFunc (string filename); static Delegate create_delegate (Type type, Type delegate_type, string name) { MethodInfo mi = type.GetMethod (name, BindingFlags.Static | BindingFlags.NonPublic); if (mi == null) throw new Exception ("Can't find " + name); return Delegate.CreateDelegate (delegate_type, mi); } static MonoDebuggerSupport () { get_type = (GetTypeFunc) create_delegate ( typeof (Assembly), typeof (GetTypeFunc), "MonoDebugger_GetType"); get_method_token = (GetMethodTokenFunc) create_delegate ( typeof (Assembly), typeof (GetMethodTokenFunc), "MonoDebugger_GetMethodToken"); get_method = (GetMethodFunc) create_delegate ( typeof (Assembly), typeof (GetMethodFunc), "MonoDebugger_GetMethod"); local_type_from_sig = (GetLocalTypeFromSignatureFunc) create_delegate ( typeof (Assembly), typeof (GetLocalTypeFromSignatureFunc), "MonoDebugger_GetLocalTypeFromSignature"); get_guid = (GetGuidFunc) create_delegate ( typeof (Module), typeof (GetGuidFunc), "Mono_GetGuid"); check_runtime_version = (CheckRuntimeVersionFunc) create_delegate ( typeof (Assembly), typeof (CheckRuntimeVersionFunc), "MonoDebugger_CheckRuntimeVersion"); } public static Type GetType (Assembly assembly, int token) { return get_type (assembly, token); } public static int GetMethodToken (MethodBase method) { return get_method_token (method.ReflectedType.Assembly, method); } public static MethodBase GetMethod (Assembly assembly, int token) { return get_method (assembly, token); } public static Type GetLocalTypeFromSignature (Assembly assembly, byte[] sig) { return local_type_from_sig (assembly, sig); } public static string CheckRuntimeVersion (string filename) { return check_runtime_version (filename); } public static Guid GetGuid (Module module) { return get_guid (module); } } public class MonoSymbolFile : IDisposable { ArrayList methods = new ArrayList (); ArrayList sources = new ArrayList (); Hashtable method_source_hash = new Hashtable (); Hashtable type_hash = new Hashtable (); OffsetTable ot; int last_type_index; int last_method_index; int last_source_index; int last_namespace_index; public int NumLineNumbers; public MonoSymbolFile () { } internal int AddSource (SourceFileEntry source) { sources.Add (source); return ++last_source_index; } internal int DefineType (Type type) { if (type_hash.Contains (type)) return (int) type_hash [type]; int index = ++last_type_index; type_hash.Add (type, index); return index; } internal void AddMethod (MethodEntry entry) { methods.Add (entry); } internal int GetNextTypeIndex () { return ++last_type_index; } internal int GetNextMethodIndex () { return ++last_method_index; } internal int GetNextNamespaceIndex () { return ++last_namespace_index; } byte [] stringBuffer; int maxCharsPerRound; static Encoding enc = Encoding.UTF8; 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 (guid.ToByteArray ()); // // Offsets of file sections; we must write this after we're done // writing the whole file, so we just reserve the space for it here. // long offset_table_offset = bw.BaseStream.Position; ot.Write (bw); // // Write data sections. // ot.DataSectionOffset = (int) bw.BaseStream.Position; foreach (SourceFileEntry source in sources) source.WriteData (bw); ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset; // // Write out the method index // ot.MethodTableOffset = (int) bw.BaseStream.Position; for (int i = 0; i < methods.Count; i++) { MethodEntry entry = (MethodEntry) methods [i]; entry.WriteIndex (bw); } ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset; // // Write source table. // ot.SourceTableOffset = (int) bw.BaseStream.Position; for (int i = 0; i < sources.Count; i++) { SourceFileEntry source = (SourceFileEntry) sources [i]; source.Write (bw); } ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset; // // Fixup offset table. // ot.TypeCount = last_type_index; ot.MethodCount = methods.Count; ot.SourceCount = sources.Count; // // Write offset table. // ot.TotalFileSize = (int) bw.BaseStream.Position; bw.Seek ((int) offset_table_offset, SeekOrigin.Begin); ot.Write (bw); bw.Seek (0, SeekOrigin.End); } public byte[] CreateSymbolFile (Guid guid) { if (reader != null) throw new InvalidOperationException (); using (MyMemoryStream stream = new MyMemoryStream ()) { Write (new MyBinaryWriter (stream), guid); return stream.GetContents (); } } Assembly assembly; MyBinaryReader reader; Hashtable method_hash; Hashtable source_file_hash; Hashtable method_token_hash; Hashtable source_name_hash; protected MonoSymbolFile (string filename, Assembly assembly) { this.assembly = assembly; FileStream stream = new FileStream (filename, FileMode.Open, FileAccess.Read); reader = new MyBinaryReader (stream); Guid guid; try { long magic = reader.ReadInt64 (); long version = reader.ReadInt32 (); if (magic != OffsetTable.Magic) 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); guid = new Guid (reader.ReadBytes (16)); ot = new OffsetTable (reader); } catch { throw new MonoSymbolFileException ( "Cannot read symbol file `{0}'", filename); } 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 (); } public static MonoSymbolFile ReadSymbolFile (Assembly assembly) { string filename = assembly.Location; string name = filename + ".mdb"; return new MonoSymbolFile (name, assembly); } public Assembly Assembly { get { return assembly; } } public int SourceCount { get { return ot.SourceCount; } } public int MethodCount { get { return ot.MethodCount; } } public int TypeCount { get { return ot.TypeCount; } } public int NamespaceCount { get { return last_namespace_index; } } internal int LineNumberCount = 0; internal int LocalCount = 0; internal int StringSize = 0; public SourceFileEntry GetSourceFile (int index) { if ((index < 1) || (index > ot.SourceCount)) throw new ArgumentException (); if (reader == null) throw new InvalidOperationException (); SourceFileEntry source = (SourceFileEntry) source_file_hash [index]; if (source != null) return source; reader.BaseStream.Position = ot.SourceTableOffset + SourceFileEntry.Size * (index - 1); source = new SourceFileEntry (this, reader); source_file_hash.Add (index, source); return source; } public SourceFileEntry[] Sources { get { if (reader == null) throw new InvalidOperationException (); SourceFileEntry[] retval = new SourceFileEntry [SourceCount]; for (int i = 0; i < SourceCount; i++) retval [i] = GetSourceFile (i + 1); return retval; } } 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) { if (reader == null) throw new InvalidOperationException (); if (method_token_hash == null) { method_token_hash = new Hashtable (); for (int i = 0; i < MethodCount; i++) { MethodIndexEntry ie = GetMethodIndexEntry (i + 1); method_token_hash.Add (ie.Token, i + 1); } } object value = method_token_hash [token]; if (value == null) return null; return GetMethod ((int) value); } public MethodEntry GetMethod (MethodBase method) { if (reader == null) throw new InvalidOperationException (); int token = MonoDebuggerSupport.GetMethodToken (method); return GetMethodByToken (token); } public MethodEntry GetMethod (int index) { if ((index < 1) || (index > ot.MethodCount)) throw new ArgumentException (); 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; } public MethodEntry[] Methods { get { 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; } } public MethodSourceEntry GetMethodSource (int index) { 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; MethodEntry method = GetMethod (index); foreach (MethodSourceEntry source in method.SourceFile.Methods) { if (source.Index == index) { method_source_hash.Add (index, source); return source; } } throw new MonoSymbolFileException ("Internal error."); } public int FindSource (string file_name) { 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); source_name_hash.Add (source.FileName, i); } } object value = source_name_hash [file_name]; if (value == null) return -1; return (int) value; } internal MyBinaryReader BinaryReader { get { if (reader == null) throw new InvalidOperationException (); return reader; } } void IDisposable.Dispose () { Dispose (true); } protected virtual void Dispose (bool disposing) { if (disposing) { if (reader != null) { reader.Close (); reader = null; } } } } } --- NEW FILE: MonoSymbolTable.cs --- // // Mono.CSharp.Debugger/MonoSymbolTable.cs // // Author: // Martin Baulig (ma...@xi...) // // (C) 2002 Ximian, Inc. http://www.ximian.com // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.Text; using System.IO; // // Parts which are actually written into the symbol file are marked with // // #region This is actually written to the symbol file // #endregion // // Please do not modify these regions without previously talking to me. // // All changes to the file format must be synchronized in several places: // // a) The fields in these regions (and their order) must match the actual // contents of the symbol file. // // This helps people to understand the symbol file format without reading // too much source code, ie. you look at the appropriate region and then // you know what's actually in the file. // // It is also required to help me enforce b). // // b) The regions must be kept in sync with the unmanaged code in // mono/metadata/debug-mono-symfile.h // // When making changes to the file format, you must also increase two version // numbers: // // i) OffsetTable.Version in this file. // ii) MONO_SYMBOL_FILE_VERSION in mono/metadata/debug-mono-symfile.h // // After doing so, recompile everything, including the debugger. Symbol files // with different versions are incompatible to each other and the debugger and // the runtime enfore this, so you need to recompile all your assemblies after // changing the file format. // namespace Mono.CompilerServices.SymbolWriter { public struct OffsetTable { public const int Version = 38; 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 SourceCount; public int SourceTableOffset; public int SourceTableSize; public int MethodCount; public int MethodTableOffset; public int MethodTableSize; public int TypeCount; #endregion internal OffsetTable (BinaryReader reader) { TotalFileSize = reader.ReadInt32 (); DataSectionOffset = reader.ReadInt32 (); DataSectionSize = reader.ReadInt32 (); SourceCount = reader.ReadInt32 (); SourceTableOffset = reader.ReadInt32 (); SourceTableSize = reader.ReadInt32 (); MethodCount = reader.ReadInt32 (); MethodTableOffset = reader.ReadInt32 (); MethodTableSize = reader.ReadInt32 (); TypeCount = reader.ReadInt32 (); } internal void Write (BinaryWriter bw) { bw.Write (TotalFileSize); bw.Write (DataSectionOffset); bw.Write (DataSectionSize); bw.Write (SourceCount); bw.Write (SourceTableOffset); bw.Write (SourceTableSize); bw.Write (MethodCount); bw.Write (MethodTableOffset); bw.Write (MethodTableSize); bw.Write (TypeCount); } public override string ToString () { return String.Format ( "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]", TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount, SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset, MethodTableSize, TypeCount); } } public struct LineNumberEntry { #region This is actually written to the symbol file public readonly int Row; public readonly int Offset; #endregion public LineNumberEntry (int row, int offset) { this.Row = row; this.Offset = offset; } 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); } private class OffsetComparerClass : IComparer { public int Compare (object a, object b) { LineNumberEntry l1 = (LineNumberEntry) a; LineNumberEntry l2 = (LineNumberEntry) b; if (l1.Offset < l2.Offset) return -1; else if (l1.Offset > l2.Offset) return 1; else return 0; } } private class RowComparerClass : IComparer { public int Compare (object a, object b) { LineNumberEntry l1 = (LineNumberEntry) a; LineNumberEntry l2 = (LineNumberEntry) b; if (l1.Row < l2.Row) return -1; else if (l1.Row > l2.Row) return 1; else return 0; } } 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); } } public class LexicalBlockEntry { public int Index; #region This is actually written to the symbol file public int StartOffset; public int EndOffset; #endregion public LexicalBlockEntry (int index, int start_offset) { this.Index = index; this.StartOffset = start_offset; } internal LexicalBlockEntry (int index, MyBinaryReader reader) { this.Index = index; this.StartOffset = reader.ReadInt32 (); this.EndOffset = reader.ReadInt32 (); } public void Close (int end_offset) { this.EndOffset = end_offset; } internal void Write (MyBinaryWriter bw) { bw.Write (StartOffset); bw.Write (EndOffset); } public override string ToString () { return String.Format ("[LexicalBlock {0}:{1}]", StartOffset, EndOffset); } } public struct LocalVariableEntry { #region This is actually written to the symbol file public readonly string Name; public readonly byte[] Signature; public readonly int BlockIndex; #endregion public LocalVariableEntry (string Name, byte[] Signature, int BlockIndex) { this.Name = Name; this.Signature = Signature; this.BlockIndex = BlockIndex; } internal LocalVariableEntry (MyBinaryReader reader) { Name = reader.ReadString (); int sig_length = reader.ReadLeb128 (); Signature = reader.ReadBytes (sig_length); BlockIndex = reader.ReadLeb128 (); } internal void Write (MonoSymbolFile file, MyBinaryWriter bw) { bw.Write (Name); bw.WriteLeb128 ((int) Signature.Length); bw.Write (Signature); bw.WriteLeb128 (BlockIndex); } public override string ToString () { return String.Format ("[LocalVariable {0}]", Name); } } public class SourceFileEntry { #region This is actually written to the symbol file public readonly int Index; int Count; int NamespaceCount; int NameOffset; int MethodOffset; int NamespaceTableOffset; #endregion MonoSymbolFile file; string file_name; ArrayList methods; ArrayList namespaces; bool creating; public static int Size { get { return 24; } } public SourceFileEntry (MonoSymbolFile file, string file_name) { this.file = file; this.file_name = file_name; this.Index = file.AddSource (this); creating = true; methods = new ArrayList (); namespaces = new ArrayList (); } public void DefineMethod (string name, int token, LocalVariableEntry[] locals, LineNumberEntry[] lines, LexicalBlockEntry[] blocks, int start, int end, int namespace_id) { if (!creating) throw new InvalidOperationException (); MethodEntry entry = new MethodEntry ( file, this, name, (int) token, locals, lines, blocks, start, end, namespace_id); methods.Add (entry); file.AddMethod (entry); } public int DefineNamespace (string name, string[] using_clauses, int parent) { if (!creating) throw new InvalidOperationException (); int index = file.GetNextNamespaceIndex (); NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent); namespaces.Add (ns); return index; } 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); NamespaceCount = namespaces.Count; NamespaceTableOffset = (int) bw.BaseStream.Position; foreach (NamespaceEntry ns in namespaces) ns.Write (file, bw); } internal void Write (BinaryWriter bw) { bw.Write (Index); bw.Write (Count); bw.Write (NamespaceCount); bw.Write (NameOffset); bw.Write (MethodOffset); bw.Write (NamespaceTableOffset); } internal SourceFileEntry (MonoSymbolFile file, BinaryReader 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); } public string FileName { get { return file_name; } } public MethodSourceEntry[] Methods { get { if (creating) throw new InvalidOperationException (); BinaryReader 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; MethodSourceEntry[] retval = new MethodSourceEntry [Count]; list.CopyTo (retval, 0); return retval; } } public NamespaceEntry[] Namespaces { get { if (creating) throw new InvalidOperationException (); MyBinaryReader reader = file.BinaryReader; int old_pos = (int) reader.BaseStream.Position; 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); return retval; } } public override string ToString () { return String.Format ("SourceFileEntry ({0}:{1}:{2})", Index, file_name, Count); } } public struct MethodSourceEntry : IComparable { #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; #endregion public MethodSourceEntry (int index, int file_offset, int start, int end) { this.Index = index; this.FileOffset = file_offset; this.StartRow = start; this.EndRow = end; } internal MethodSourceEntry (BinaryReader reader) { Index = reader.ReadInt32 (); FileOffset = reader.ReadInt32 (); StartRow = reader.ReadInt32 (); EndRow = reader.ReadInt32 (); } public static int Size { get { return 16; } } internal void Write (BinaryWriter bw) { bw.Write (Index); bw.Write (FileOffset); bw.Write (StartRow); bw.Write (EndRow); } public int CompareTo (object obj) { MethodSourceEntry method = (MethodSourceEntry) obj; if (method.StartRow < StartRow) return -1; else if (method.StartRow > StartRow) return 1; else return 0; } public override string ToString () { return String.Format ("MethodSourceEntry ({0}:{1}:{2}:{3})", Index, FileOffset, StartRow, EndRow); } } public struct MethodIndexEntry { #region This is actually written to the symbol file public readonly int FileOffset; public readonly int Token; #endregion public static int Size { get { return 8; } } public MethodIndexEntry (int offset, int token) { this.FileOffset = offset; this.Token = token; } internal MethodIndexEntry (BinaryReader reader) { FileOffset = reader.ReadInt32 (); Token = reader.ReadInt32 (); } internal void Write (BinaryWriter bw) { bw.Write (FileOffset); bw.Write (Token); } public override string ToString () { return String.Format ("MethodIndexEntry ({0}:{1:x})", FileOffset, Token); } } public class MethodEntry : IComparable { #region This is actually written to the symbol file public readonly int SourceFileIndex; 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 LocalVariableTableOffset; int LineNumberTableOffset; int NumLexicalBlocks; int LexicalBlockTableOffset; #endregion int file_offset; public readonly int Index; public readonly SourceFileEntry SourceFile; public readonly LineNumberEntry[] LineNumbers; public readonly int[] LocalTypeIndices; public readonly LocalVariableEntry[] Locals; public readonly LexicalBlockEntry[] LexicalBlocks; public readonly MonoSymbolFile SymbolFile; public static int Size { get { return 52; } } 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 (); 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; LineNumbers = new LineNumberEntry [NumLineNumbers]; for (int i = 0; i < NumLineNumbers; i++) LineNumbers [i] = new LineNumberEntry (reader); 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; LocalTypeIndices = new int [NumLocals]; for (int i = 0; i < NumLocals; i++) LocalTypeIndices [i] = reader.ReadInt32 (); 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; } } 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) { this.SymbolFile = file; Index = file.GetNextMethodIndex (); Token = token; SourceFileIndex = source.Index; SourceFile = source; StartRow = start_row; EndRow = end_row; NamespaceID = namespace_id; LexicalBlocks = blocks; NumLexicalBlocks = LexicalBlocks != null ? LexicalBlocks.Length : 0; LineNumbers = BuildLineNumberTable (lines); NumLineNumbers = LineNumbers.Length; file.NumLineNumbers += NumLineNumbers; NumLocals = locals != null ? locals.Length : 0; Locals = locals; if (NumLocals <= 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 ++) { string nm = locals [i].Name; for (int j = i + 1; j < NumLocals; j ++) { if (locals [j].Name == nm) { LocalNamesAmbiguous = true; goto locals_check_done; } } } locals_check_done : ; } else { Hashtable local_names = new Hashtable (); foreach (LocalVariableEntry local in locals) { if (local_names.Contains (local.Name)) { LocalNamesAmbiguous = true; 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; int last_offset = -1; int last_row = -1; if (line_numbers == null) return new LineNumberEntry [0]; 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.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); LineNumberEntry [] retval = new LineNumberEntry [pos]; Array.Copy (tmp_buff, retval, pos); return retval; } internal MethodSourceEntry Write (MonoSymbolFile file, MyBinaryWriter bw) { NameOffset = (int) bw.BaseStream.Position; TypeIndexTableOffset = (int) bw.BaseStream.Position; for (int i = 0; i < NumLocals; i++) bw.Write (LocalTypeIndices [i]); LocalVariableTableOffset = (int) bw.BaseStream.Position; for (int i = 0; i < NumLocals; i++) Locals [i].Write (file, bw); file.LocalCount += NumLocals; LineNumberTableOffset = (int) bw.BaseStream.Position; for (int i = 0; i < NumLineNumbers; i++) LineNumbers [i].Write (bw); file.LineNumberCount += NumLineNumbers; LexicalBlockTableOffset = (int) bw.BaseStream.Position; for (int i = 0; i < NumLexicalBlocks; i++) LexicalBlocks [i].Write (bw); file_offset = (int) bw.BaseStream.Position; 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); return new MethodSourceEntry (Index, file_offset, StartRow, EndRow); } internal void WriteIndex (BinaryWriter bw) { new MethodIndexEntry (file_offset, Token).Write (bw); } public int CompareTo (object obj) { MethodEntry method = (MethodEntry) obj; if (method.Token < Token) return 1; else if (method.Token > Token) return -1; else return 0; } public override string ToString () { return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {6}:{7} - {5}]", Index, Token, SourceFileIndex, StartRow, EndRow, SourceFile, NumLocals, NumLineNumbers); } } public struct NamespaceEntry { #region This is actually written to the symbol file public readonly string Name; public readonly int Index; public readonly int Parent; public readonly string[] UsingClauses; #endregion public NamespaceEntry (string name, int index, string[] using_clauses, int parent) { this.Name = name; this.Index = index; this.Parent = parent; this.UsingClauses = using_clauses != null ? using_clauses : new string [0]; } internal NamespaceEntry (MonoSymbolFile file, MyBinaryReader reader) { Name = reader.ReadString (); Index = reader.ReadLeb128 (); Parent = reader.ReadLeb128 (); int count = reader.ReadLeb128 (); UsingClauses = new string [count]; for (int i = 0; i < count; i++) UsingClauses [i] = reader.ReadString (); } internal void Write (MonoSymbolFile file, MyBinaryWriter bw) { bw.Write (Name); bw.WriteLeb128 (Index); bw.WriteLeb128 (Parent); bw.WriteLeb128 (UsingClauses.Length); foreach (string uc in UsingClauses) bw.Write (uc); } public override string ToString () { return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent); } } } --- NEW FILE: MonoSymbolWriter.cs --- // // Mono.CSharp.Debugger/MonoSymbolWriter.cs // // Author: // Martin Baulig (ma...@xi...) // // This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter // interface. // // (C) 2002 Ximian, Inc. http://www.ximian.com // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Runtime.CompilerServices; using System.Collections; using System.IO; namespace Mono.CompilerServices.SymbolWriter { public interface ISourceFile { SourceFileEntry Entry { get; } } public interface ISourceMethod { string Name { get; } int NamespaceID { get; } int Token { get; } } public class MonoSymbolWriter { protected ArrayList locals = null; protected ArrayList methods = null; protected ArrayList sources = null; protected readonly MonoSymbolFile file; private string filename = null; LineNumberEntry [] current_method_lines; int current_method_lines_pos = 0; internal ISourceFile[] Sources { get { ISourceFile[] retval = new ISourceFile [sources.Count]; sources.CopyTo (retval, 0); return retval; } } private SourceMethod current_method = null; // // Interface IMonoSymbolWriter // public MonoSymbolWriter (string filename) { this.methods = new ArrayList (); this.sources = new ArrayList (); this.locals = new ArrayList (); this.file = new MonoSymbolFile (); this.filename = filename + ".mdb"; this.current_method_lines = new LineNumberEntry [50]; } public void CloseNamespace () { } public void DefineLocalVariable (string name, byte[] signature) { if (current_method == null) return; current_method.AddLocal (name, signature); } public void MarkSequencePoint (int offset, int line, int column) { if (current_method == null) return; if (current_method_lines_pos == current_method_lines.Length) { LineNumberEntry [] tmp = current_method_lines; current_method_lines = new LineNumberEntry [current_method_lines.Length * 2]; Array.Copy (tmp, current_method_lines, current_method_lines_pos); } current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset); } public void OpenMethod (ISourceFile file, ISourceMethod method, int startRow, int startColumn, int endRow, int endColumn) { SourceMethod source = new SourceMethod ( file, method, startRow, startColumn, endRow, endColumn); current_method = source; methods.Add (current_method); } public void CloseMethod () { current_method.SetLineNumbers ( current_method_lines, current_method_lines_pos); current_method_lines_pos = 0; current_method = null; } public SourceFileEntry DefineDocument (string url) { SourceFileEntry entry = new SourceFileEntry (file, url); sources.Add (entry); return entry; } public int DefineNamespace (string name, SourceFileEntry source, string[] using_clauses, int parent) { if ((source == null) || (using_clauses == null)) throw new NullReferenceException (); return source.DefineNamespace (name, using_clauses, parent); } public int OpenScope (int startOffset) { if (current_method == null) return 0; current_method.StartBlock (startOffset); return 0; } public void CloseScope (int endOffset) { if (current_method == null) return; current_method.EndBlock (endOffset); } protected byte[] CreateOutput (Guid guid) { foreach (SourceMethod method in methods) { method.SourceFile.Entry.DefineMethod ( method.Method.Name, method.Method.Token, method.Locals, method.Lines, method.Blocks, method.Start.Row, method.End.Row, method.Method.NamespaceID); } return file.CreateSymbolFile (guid); } public void WriteSymbolFile (Guid guid) { using (FileStream stream = new FileStream ( filename, FileMode.Create, FileAccess.Write)) { byte[] data = CreateOutput (guid); stream.Write (data, 0, data.Length); } } protected class SourceMethod { LineNumberEntry [] lines; private ArrayList _locals; private ArrayList _blocks; private Stack _block_stack; private int next_block_id = 0; private ISourceMethod _method; private ISourceFile _file; private LineNumberEntry _start, _end; private LexicalBlockEntry _implicit_block; public SourceMethod (ISourceFile file, ISourceMethod method, int startLine, int startColumn, int endLine, int endColumn) { this._file = file; this._method = method; this._start = new LineNumberEntry (startLine, 0); this._end = new LineNumberEntry (endLine, 0); this._implicit_block = new LexicalBlockEntry (0, 0); } public void StartBlock (int startOffset) { LexicalBlockEntry block = new LexicalBlockEntry ( ++next_block_id, startOffset); if (_block_stack == null) _block_stack = new Stack (); _block_stack.Push (block); if (_blocks == null) _blocks = new ArrayList (); _blocks.Add (block); } public void EndBlock (int endOffset) { LexicalBlockEntry block = (LexicalBlockEntry) _block_stack.Pop (); block.Close (endOffset); } public LexicalBlockEntry[] Blocks { get { if (_blocks == null) return new LexicalBlockEntry [0]; else { LexicalBlockEntry[] retval = new LexicalBlockEntry [_blocks.Count]; _blocks.CopyTo (retval, 0); return retval; } } } public LexicalBlockEntry CurrentBlock { get { if ((_block_stack != null) && (_block_stack.Count > 0)) return (LexicalBlockEntry) _block_stack.Peek (); else return _implicit_block; } } public LineNumberEntry[] Lines { get { return lines; } } public LocalVariableEntry[] Locals { get { if (_locals == null) return new LocalVariableEntry [0]; else { LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count]; _locals.CopyTo (retval, 0); return retval; } } } public void AddLocal (string name, byte[] signature) { if (_locals == null) _locals = new ArrayList (); _locals.Add (new LocalVariableEntry ( name, signature, CurrentBlock.Index)); } public ISourceFile SourceFile { get { return _file; } } public ISourceMethod Method { get { return _method; } } public LineNumberEntry Start { get { return _start; } } public LineNumberEntry End { get { return _end; } } // // Passes on the lines from the MonoSymbolWriter. This method is // free to mutate the lns array, and it does. // internal void SetLineNumbers (LineNumberEntry [] lns, int count) { int pos = 0; int last_offset = -1; int last_row = -1; for (int i = 0; i < count; i++) { LineNumberEntry line = lns [i]; if (line.Offset > last_offset) { if (last_row >= 0) lns [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; } } lines = new LineNumberEntry [count + ((last_row >= 0) ? 1 : 0)]; Array.Copy (lns, lines, pos); if (last_row >= 0) lines [pos] = new LineNumberEntry ( last_row, last_offset); } } } } |