//
-// System.Diagnostics.SymbolStore/MonoSymbolTable.cs
+// Mono.CSharp.Debugger/MonoSymbolTable.cs
//
// Author:
-// Martin Baulig (martin@gnome.org)
+// Martin Baulig (martin@ximian.com)
//
// (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.Reflection;
-using System.Reflection.Emit;
using System.Collections;
using System.Text;
using System.IO;
-
-namespace Mono.CSharp.Debugger
+
+//
+// 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 = 35;
+ 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 MethodTableOffset;
public int MethodTableSize;
public int TypeCount;
+ #endregion
internal OffsetTable (BinaryReader reader)
{
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)
{
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.StartOffset = start_offset;
}
- internal LexicalBlockEntry (int index, BinaryReader reader)
+ internal LexicalBlockEntry (int index, MyBinaryReader reader)
{
this.Index = index;
this.StartOffset = reader.ReadInt32 ();
this.EndOffset = end_offset;
}
- internal void Write (BinaryWriter bw)
+ internal void Write (MyBinaryWriter bw)
{
bw.Write (StartOffset);
bw.Write (EndOffset);
public struct LocalVariableEntry
{
+ #region This is actually written to the symbol file
public readonly string Name;
- public readonly FieldAttributes Attributes;
public readonly byte[] Signature;
public readonly int BlockIndex;
+ #endregion
- public LocalVariableEntry (string Name, FieldAttributes Attributes, byte[] Signature,
- int BlockIndex)
+ public LocalVariableEntry (string Name, byte[] Signature, int BlockIndex)
{
this.Name = Name;
- this.Attributes = Attributes;
this.Signature = Signature;
this.BlockIndex = BlockIndex;
}
- internal LocalVariableEntry (BinaryReader reader)
+ internal LocalVariableEntry (MyBinaryReader reader)
{
- int name_length = reader.ReadInt32 ();
- byte[] name = reader.ReadBytes (name_length);
- Name = Encoding.UTF8.GetString (name);
- Attributes = (FieldAttributes) reader.ReadInt32 ();
- int sig_length = reader.ReadInt32 ();
+ Name = reader.ReadString ();
+ int sig_length = reader.ReadLeb128 ();
Signature = reader.ReadBytes (sig_length);
- BlockIndex = reader.ReadInt32 ();
+ BlockIndex = reader.ReadLeb128 ();
}
- internal void Write (MonoSymbolFile file, BinaryWriter bw)
+ internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
{
- file.WriteString (bw, Name);
- bw.Write ((int) Attributes);
- bw.Write ((int) Signature.Length);
+ bw.Write (Name);
+ bw.WriteLeb128 ((int) Signature.Length);
bw.Write (Signature);
- bw.Write (BlockIndex);
+ bw.WriteLeb128 (BlockIndex);
}
public override string ToString ()
{
- return String.Format ("[LocalVariable {0}:{1}]", Name, Attributes);
+ 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;
- int index, count, name_offset, method_offset;
- int namespace_count, nstable_offset;
bool creating;
public static int Size {
get { return 24; }
}
- internal SourceFileEntry (MonoSymbolFile file, string file_name)
+ public SourceFileEntry (MonoSymbolFile file, string file_name)
{
this.file = file;
this.file_name = file_name;
- this.index = file.AddSource (this);
+ this.Index = file.AddSource (this);
creating = true;
methods = new ArrayList ();
namespaces = new ArrayList ();
}
- public void DefineMethod (MethodBase method, int token, LocalVariableEntry[] locals,
+ public void DefineMethod (string name, int token, LocalVariableEntry[] locals,
LineNumberEntry[] lines, LexicalBlockEntry[] blocks,
int start, int end, int namespace_id)
{
throw new InvalidOperationException ();
MethodEntry entry = new MethodEntry (
- file, this, method, token, locals, lines, blocks, start, end, namespace_id);
+ file, this, name, (int) token, locals, lines, blocks,
+ start, end, namespace_id);
methods.Add (entry);
file.AddMethod (entry);
return index;
}
- internal void WriteData (BinaryWriter bw)
+ internal void WriteData (MyBinaryWriter bw)
{
- name_offset = (int) bw.BaseStream.Position;
- file.WriteString (bw, file_name);
+ 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;
+ Count = list.Count;
- method_offset = (int) bw.BaseStream.Position;
+ MethodOffset = (int) bw.BaseStream.Position;
foreach (MethodSourceEntry method in list)
method.Write (bw);
- namespace_count = namespaces.Count;
- nstable_offset = (int) bw.BaseStream.Position;
+ 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 (namespace_count);
- bw.Write (name_offset);
- bw.Write (method_offset);
- bw.Write (nstable_offset);
+ 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 ();
- namespace_count = reader.ReadInt32 ();
- name_offset = reader.ReadInt32 ();
- method_offset = reader.ReadInt32 ();
- nstable_offset = reader.ReadInt32 ();
-
- file_name = file.ReadString (name_offset);
- }
+ Index = reader.ReadInt32 ();
+ Count = reader.ReadInt32 ();
+ NamespaceCount = reader.ReadInt32 ();
+ NameOffset = reader.ReadInt32 ();
+ MethodOffset = reader.ReadInt32 ();
+ NamespaceTableOffset = reader.ReadInt32 ();
- public int Index {
- get { return index; }
+ file_name = file.ReadString (NameOffset);
}
public string FileName {
BinaryReader reader = file.BinaryReader;
int old_pos = (int) reader.BaseStream.Position;
- reader.BaseStream.Position = method_offset;
+ reader.BaseStream.Position = MethodOffset;
ArrayList list = new ArrayList ();
- for (int i = 0; i < count; i ++)
+ for (int i = 0; i < Count; i ++)
list.Add (new MethodSourceEntry (reader));
reader.BaseStream.Position = old_pos;
- MethodSourceEntry[] retval = new MethodSourceEntry [count];
+ 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);
+ 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)
{
public struct MethodIndexEntry
{
+ #region This is actually written to the symbol file
public readonly int FileOffset;
- public readonly int FullNameOffset;
public readonly int Token;
+ #endregion
public static int Size {
- get { return 12; }
+ get { return 8; }
}
- public MethodIndexEntry (int offset, int name_offset, int token)
+ public MethodIndexEntry (int offset, int token)
{
this.FileOffset = offset;
- this.FullNameOffset = name_offset;
this.Token = token;
}
internal MethodIndexEntry (BinaryReader reader)
{
FileOffset = reader.ReadInt32 ();
- FullNameOffset = reader.ReadInt32 ();
Token = reader.ReadInt32 ();
}
internal void Write (BinaryWriter bw)
{
bw.Write (FileOffset);
- bw.Write (FullNameOffset);
bw.Write (Token);
}
public override string ToString ()
{
- return String.Format ("MethodIndexEntry ({0}:{1}:{2:x})",
- FileOffset, FullNameOffset, Token);
+ return String.Format ("MethodIndexEntry ({0}:{1:x})",
+ FileOffset, Token);
}
}
- public class MethodEntry
+ 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 ClassTypeIndex;
- public readonly int NumParameters;
public readonly int NumLocals;
public readonly int NumLineNumbers;
public readonly int NamespaceID;
public readonly bool LocalNamesAmbiguous;
int NameOffset;
- int FullNameOffset;
int TypeIndexTableOffset;
int LocalVariableTableOffset;
int LineNumberTableOffset;
int LexicalBlockTableOffset;
#endregion
+ int index;
int file_offset;
- string name;
- string full_name;
- public readonly int Index;
public readonly SourceFileEntry SourceFile;
public readonly LineNumberEntry[] LineNumbers;
- public readonly int[] ParamTypeIndices;
public readonly int[] LocalTypeIndices;
public readonly LocalVariableEntry[] Locals;
- public readonly Type[] LocalTypes;
public readonly LexicalBlockEntry[] LexicalBlocks;
public readonly MonoSymbolFile SymbolFile;
- public static int Size {
- get { return 52; }
- }
-
- public string Name {
- get { return name; }
- }
-
- public string FullName {
- get { return full_name; }
+ public int Index {
+ get { return index; }
+ set { index = value; }
}
- public MethodBase MethodBase {
- get { return SymbolFile.Assembly.MonoDebugger_GetMethod (Token); }
+ public static int Size {
+ get { return 52; }
}
- internal MethodEntry (MonoSymbolFile file, BinaryReader reader, int index)
+ internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index)
{
this.SymbolFile = file;
- this.Index = index;
+ this.index = index;
SourceFileIndex = reader.ReadInt32 ();
Token = reader.ReadInt32 ();
StartRow = reader.ReadInt32 ();
EndRow = reader.ReadInt32 ();
- ClassTypeIndex = reader.ReadInt32 ();
- NumParameters = reader.ReadInt32 ();
NumLocals = reader.ReadInt32 ();
NumLineNumbers = reader.ReadInt32 ();
NameOffset = reader.ReadInt32 ();
- FullNameOffset = reader.ReadInt32 ();
TypeIndexTableOffset = reader.ReadInt32 ();
LocalVariableTableOffset = reader.ReadInt32 ();
LineNumberTableOffset = reader.ReadInt32 ();
NamespaceID = reader.ReadInt32 ();
LocalNamesAmbiguous = reader.ReadInt32 () != 0;
- name = file.ReadString (NameOffset);
- full_name = file.ReadString (FullNameOffset);
-
SourceFile = file.GetSourceFile (SourceFileIndex);
if (LineNumberTableOffset != 0) {
reader.BaseStream.Position = LocalVariableTableOffset;
Locals = new LocalVariableEntry [NumLocals];
- LocalTypes = new Type [NumLocals];
-
- Assembly ass = file.Assembly;
- for (int i = 0; i < NumLocals; i++) {
+ for (int i = 0; i < NumLocals; i++)
Locals [i] = new LocalVariableEntry (reader);
- LocalTypes [i] = ass.MonoDebugger_GetLocalTypeFromSignature (
- Locals [i].Signature);
- }
reader.BaseStream.Position = old_pos;
}
long old_pos = reader.BaseStream.Position;
reader.BaseStream.Position = TypeIndexTableOffset;
- ParamTypeIndices = new int [NumParameters];
LocalTypeIndices = new int [NumLocals];
- for (int i = 0; i < NumParameters; i++)
- ParamTypeIndices [i] = reader.ReadInt32 ();
for (int i = 0; i < NumLocals; i++)
LocalTypeIndices [i] = reader.ReadInt32 ();
}
}
- internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, MethodBase method,
- int token, LocalVariableEntry[] locals, LineNumberEntry[] lines,
- LexicalBlockEntry[] blocks, int start_row, int end_row,
- int namespace_id)
+ 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 ();
+
+ index = -1;
Token = token;
SourceFileIndex = source.Index;
EndRow = end_row;
NamespaceID = namespace_id;
LexicalBlocks = blocks;
- NumLexicalBlocks = LexicalBlocks.Length;
+ NumLexicalBlocks = LexicalBlocks != null ? LexicalBlocks.Length : 0;
LineNumbers = BuildLineNumberTable (lines);
NumLineNumbers = LineNumbers.Length;
- ParameterInfo[] parameters = method.GetParameters ();
- if (parameters == null)
- parameters = new ParameterInfo [0];
-
- if (parameters.Length == 0)
- full_name = method.DeclaringType.FullName + "." + method.Name + "()";
- else if (parameters.Length == 1)
- full_name = method.DeclaringType.FullName + "." + method.Name + "(" + parameters [0].ParameterType.FullName + ")";
- else if (parameters.Length == 2)
- full_name = method.DeclaringType.FullName + "." + method.Name + "(" + parameters [0].ParameterType.FullName + "," + parameters [1].ParameterType.FullName + ")";
- else {
- StringBuilder sb = new StringBuilder ();
- sb.Append (method.DeclaringType.FullName);
- sb.Append (".");
- sb.Append (method.Name);
- sb.Append ("(");
- for (int i = 0; i < parameters.Length; i++) {
- if (i > 0)
- sb.Append (",");
- sb.Append (parameters [i].ParameterType.FullName);
- }
- sb.Append (")");
- full_name = sb.ToString ();
- }
+ file.NumLineNumbers += NumLineNumbers;
- name = method.Name;
-
- NumParameters = parameters.Length;
- ParamTypeIndices = new int [NumParameters];
- for (int i = 0; i < NumParameters; i++)
- ParamTypeIndices [i] = file.DefineType (parameters [i].ParameterType);
-
- NumLocals = locals.Length;
+ NumLocals = locals != null ? locals.Length : 0;
Locals = locals;
if (NumLocals <= 32) {
LocalTypeIndices = new int [NumLocals];
for (int i = 0; i < NumLocals; i++)
LocalTypeIndices [i] = file.GetNextTypeIndex ();
-
- ClassTypeIndex = file.DefineType (method.ReflectedType);
}
+
+ 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
// simply be discarded).
LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
{
- ArrayList list = new ArrayList ();
+ 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 = (LineNumberEntry) line_numbers [i];
+ LineNumberEntry line = line_numbers [i];
if (line.Offset > last_offset) {
if (last_row >= 0)
- list.Add (new LineNumberEntry (last_row, last_offset));
+ tmp_buff [pos ++] = new LineNumberEntry (last_row, last_offset);
last_row = line.Row;
last_offset = line.Offset;
} else if (line.Row > last_row) {
}
if (last_row >= 0)
- list.Add (new LineNumberEntry (last_row, last_offset));
+ tmp_buff [pos ++] = new LineNumberEntry (last_row, last_offset);
- LineNumberEntry[] retval = new LineNumberEntry [list.Count];
- list.CopyTo (retval, 0);
+ LineNumberEntry [] retval = new LineNumberEntry [pos];
+ Array.Copy (tmp_buff, retval, pos);
return retval;
}
- internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
+ internal MethodSourceEntry Write (MonoSymbolFile file, MyBinaryWriter bw)
{
- NameOffset = (int) bw.BaseStream.Position;
- file.WriteString (bw, name);
+ if (index <= 0)
+ throw new InvalidOperationException ();
- FullNameOffset = (int) bw.BaseStream.Position;
- file.WriteString (bw, full_name);
+ NameOffset = (int) bw.BaseStream.Position;
TypeIndexTableOffset = (int) bw.BaseStream.Position;
- for (int i = 0; i < NumParameters; i++)
- bw.Write (ParamTypeIndices [i]);
for (int i = 0; i < NumLocals; i++)
bw.Write (LocalTypeIndices [i]);
bw.Write (Token);
bw.Write (StartRow);
bw.Write (EndRow);
- bw.Write (ClassTypeIndex);
- bw.Write (NumParameters);
bw.Write (NumLocals);
bw.Write (NumLineNumbers);
bw.Write (NameOffset);
- bw.Write (FullNameOffset);
bw.Write (TypeIndexTableOffset);
bw.Write (LocalVariableTableOffset);
bw.Write (LineNumberTableOffset);
bw.Write (NamespaceID);
bw.Write (LocalNamesAmbiguous ? 1 : 0);
- return new MethodSourceEntry (Index, file_offset, StartRow, EndRow);
+ return new MethodSourceEntry (index, file_offset, StartRow, EndRow);
}
internal void WriteIndex (BinaryWriter bw)
{
- new MethodIndexEntry (file_offset, FullNameOffset, Token).Write (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} - {7}:{8}:{9}:{10} - {5} - {6}]",
- Index, Token, SourceFileIndex, StartRow, EndRow,
- SourceFile, FullName, ClassTypeIndex, NumParameters,
- NumLocals, NumLineNumbers);
+ 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.UsingClauses = using_clauses != null ? using_clauses : new string [0];
}
- internal void Write (MonoSymbolFile file, BinaryWriter bw)
+ internal NamespaceEntry (MonoSymbolFile file, MyBinaryReader reader)
{
- file.WriteString (bw, Name);
- bw.Write (Index);
- bw.Write (Parent);
- bw.Write (UsingClauses.Length);
+ 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)
- file.WriteString (bw, uc);
+ bw.Write (uc);
}
public override string ToString ()