2 // System.Diagnostics.SymbolStore/MonoSymbolTable.cs
5 // Martin Baulig (martin@gnome.org)
7 // (C) 2002 Ximian, Inc. http://www.ximian.com
11 using System.Reflection;
12 using System.Reflection.Emit;
13 using System.Collections;
17 namespace Mono.CSharp.Debugger
19 public struct OffsetTable
21 public const int Version = 35;
22 public const long Magic = 0x45e82623fd7fa614;
24 public int TotalFileSize;
25 public int DataSectionOffset;
26 public int DataSectionSize;
27 public int SourceCount;
28 public int SourceTableOffset;
29 public int SourceTableSize;
30 public int MethodCount;
31 public int MethodTableOffset;
32 public int MethodTableSize;
35 internal OffsetTable (BinaryReader reader)
37 TotalFileSize = reader.ReadInt32 ();
38 DataSectionOffset = reader.ReadInt32 ();
39 DataSectionSize = reader.ReadInt32 ();
40 SourceCount = reader.ReadInt32 ();
41 SourceTableOffset = reader.ReadInt32 ();
42 SourceTableSize = reader.ReadInt32 ();
43 MethodCount = reader.ReadInt32 ();
44 MethodTableOffset = reader.ReadInt32 ();
45 MethodTableSize = reader.ReadInt32 ();
46 TypeCount = reader.ReadInt32 ();
49 internal void Write (BinaryWriter bw)
51 bw.Write (TotalFileSize);
52 bw.Write (DataSectionOffset);
53 bw.Write (DataSectionSize);
54 bw.Write (SourceCount);
55 bw.Write (SourceTableOffset);
56 bw.Write (SourceTableSize);
57 bw.Write (MethodCount);
58 bw.Write (MethodTableOffset);
59 bw.Write (MethodTableSize);
63 public override string ToString ()
65 return String.Format (
66 "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]",
67 TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount,
68 SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset,
69 MethodTableSize, TypeCount);
73 public struct LineNumberEntry
75 public readonly int Row;
76 public readonly int Offset;
78 public LineNumberEntry (int row, int offset)
84 public static LineNumberEntry Null = new LineNumberEntry (0, 0);
86 internal LineNumberEntry (BinaryReader reader)
88 Row = reader.ReadInt32 ();
89 Offset = reader.ReadInt32 ();
92 internal void Write (BinaryWriter bw)
98 private class OffsetComparerClass : IComparer
100 public int Compare (object a, object b)
102 LineNumberEntry l1 = (LineNumberEntry) a;
103 LineNumberEntry l2 = (LineNumberEntry) b;
105 if (l1.Offset < l2.Offset)
107 else if (l1.Offset > l2.Offset)
114 private class RowComparerClass : IComparer
116 public int Compare (object a, object b)
118 LineNumberEntry l1 = (LineNumberEntry) a;
119 LineNumberEntry l2 = (LineNumberEntry) b;
123 else if (l1.Row > l2.Row)
130 public static readonly IComparer OffsetComparer = new OffsetComparerClass ();
131 public static readonly IComparer RowComparer = new RowComparerClass ();
133 public override string ToString ()
135 return String.Format ("[Line {0}:{1}]", Row, Offset);
139 public class LexicalBlockEntry
142 public int StartOffset;
143 public int EndOffset;
145 public LexicalBlockEntry (int index, int start_offset)
148 this.StartOffset = start_offset;
151 internal LexicalBlockEntry (int index, BinaryReader reader)
154 this.StartOffset = reader.ReadInt32 ();
155 this.EndOffset = reader.ReadInt32 ();
158 public void Close (int end_offset)
160 this.EndOffset = end_offset;
163 internal void Write (BinaryWriter bw)
165 bw.Write (StartOffset);
166 bw.Write (EndOffset);
169 public override string ToString ()
171 return String.Format ("[LexicalBlock {0}:{1}]", StartOffset, EndOffset);
175 public struct LocalVariableEntry
177 public readonly string Name;
178 public readonly FieldAttributes Attributes;
179 public readonly byte[] Signature;
180 public readonly int BlockIndex;
182 public LocalVariableEntry (string Name, FieldAttributes Attributes, byte[] Signature,
186 this.Attributes = Attributes;
187 this.Signature = Signature;
188 this.BlockIndex = BlockIndex;
191 internal LocalVariableEntry (BinaryReader reader)
193 int name_length = reader.ReadInt32 ();
194 byte[] name = reader.ReadBytes (name_length);
195 Name = Encoding.UTF8.GetString (name);
196 Attributes = (FieldAttributes) reader.ReadInt32 ();
197 int sig_length = reader.ReadInt32 ();
198 Signature = reader.ReadBytes (sig_length);
199 BlockIndex = reader.ReadInt32 ();
202 internal void Write (MonoSymbolFile file, BinaryWriter bw)
204 file.WriteString (bw, Name);
205 bw.Write ((int) Attributes);
206 bw.Write ((int) Signature.Length);
207 bw.Write (Signature);
208 bw.Write (BlockIndex);
211 public override string ToString ()
213 return String.Format ("[LocalVariable {0}:{1}]", Name, Attributes);
217 public class SourceFileEntry
222 ArrayList namespaces;
223 int index, count, name_offset, method_offset;
224 int namespace_count, nstable_offset;
227 public static int Size {
231 internal SourceFileEntry (MonoSymbolFile file, string file_name)
234 this.file_name = file_name;
235 this.index = file.AddSource (this);
238 methods = new ArrayList ();
239 namespaces = new ArrayList ();
242 public void DefineMethod (MethodBase method, int token, LocalVariableEntry[] locals,
243 LineNumberEntry[] lines, LexicalBlockEntry[] blocks,
244 int start, int end, int namespace_id)
247 throw new InvalidOperationException ();
249 MethodEntry entry = new MethodEntry (
250 file, this, method, token, locals, lines, blocks, start, end, namespace_id);
253 file.AddMethod (entry);
256 public int DefineNamespace (string name, string[] using_clauses, int parent)
259 throw new InvalidOperationException ();
261 int index = file.GetNextNamespaceIndex ();
262 NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
267 internal void WriteData (BinaryWriter bw)
269 name_offset = (int) bw.BaseStream.Position;
270 file.WriteString (bw, file_name);
272 ArrayList list = new ArrayList ();
273 foreach (MethodEntry entry in methods)
274 list.Add (entry.Write (file, bw));
278 method_offset = (int) bw.BaseStream.Position;
279 foreach (MethodSourceEntry method in list)
282 namespace_count = namespaces.Count;
283 nstable_offset = (int) bw.BaseStream.Position;
284 foreach (NamespaceEntry ns in namespaces)
288 internal void Write (BinaryWriter bw)
292 bw.Write (namespace_count);
293 bw.Write (name_offset);
294 bw.Write (method_offset);
295 bw.Write (nstable_offset);
298 internal SourceFileEntry (MonoSymbolFile file, BinaryReader reader)
302 index = reader.ReadInt32 ();
303 count = reader.ReadInt32 ();
304 namespace_count = reader.ReadInt32 ();
305 name_offset = reader.ReadInt32 ();
306 method_offset = reader.ReadInt32 ();
307 nstable_offset = reader.ReadInt32 ();
309 file_name = file.ReadString (name_offset);
313 get { return index; }
316 public string FileName {
317 get { return file_name; }
320 public MethodSourceEntry[] Methods {
323 throw new InvalidOperationException ();
325 BinaryReader reader = file.BinaryReader;
326 int old_pos = (int) reader.BaseStream.Position;
328 reader.BaseStream.Position = method_offset;
329 ArrayList list = new ArrayList ();
330 for (int i = 0; i < count; i ++)
331 list.Add (new MethodSourceEntry (reader));
332 reader.BaseStream.Position = old_pos;
334 MethodSourceEntry[] retval = new MethodSourceEntry [count];
335 list.CopyTo (retval, 0);
340 public override string ToString ()
342 return String.Format ("SourceFileEntry ({0}:{1}:{2})", index, file_name, count);
346 public struct MethodSourceEntry : IComparable
348 public readonly int Index;
349 public readonly int FileOffset;
350 public readonly int StartRow;
351 public readonly int EndRow;
353 public MethodSourceEntry (int index, int file_offset, int start, int end)
356 this.FileOffset = file_offset;
357 this.StartRow = start;
361 internal MethodSourceEntry (BinaryReader reader)
363 Index = reader.ReadInt32 ();
364 FileOffset = reader.ReadInt32 ();
365 StartRow = reader.ReadInt32 ();
366 EndRow = reader.ReadInt32 ();
369 public static int Size {
373 internal void Write (BinaryWriter bw)
376 bw.Write (FileOffset);
381 public int CompareTo (object obj)
383 MethodSourceEntry method = (MethodSourceEntry) obj;
385 if (method.StartRow < StartRow)
387 else if (method.StartRow > StartRow)
393 public override string ToString ()
395 return String.Format ("MethodSourceEntry ({0}:{1}:{2}:{3})",
396 Index, FileOffset, StartRow, EndRow);
400 public struct MethodIndexEntry
402 public readonly int FileOffset;
403 public readonly int FullNameOffset;
404 public readonly int Token;
406 public static int Size {
410 public MethodIndexEntry (int offset, int name_offset, int token)
412 this.FileOffset = offset;
413 this.FullNameOffset = name_offset;
417 internal MethodIndexEntry (BinaryReader reader)
419 FileOffset = reader.ReadInt32 ();
420 FullNameOffset = reader.ReadInt32 ();
421 Token = reader.ReadInt32 ();
424 internal void Write (BinaryWriter bw)
426 bw.Write (FileOffset);
427 bw.Write (FullNameOffset);
431 public override string ToString ()
433 return String.Format ("MethodIndexEntry ({0}:{1}:{2:x})",
434 FileOffset, FullNameOffset, Token);
438 public class MethodEntry
440 #region This is actually written to the symbol file
441 //public readonly int SourceFileIndex; (we take this from the SourceFile)
442 public readonly int Token;
443 public readonly int StartRow;
444 public readonly int EndRow;
445 public readonly int ClassTypeIndex;
446 public readonly int NumParameters;
447 public readonly int NumLocals;
448 public readonly int NumLineNumbers;
449 public readonly int NamespaceID;
450 public readonly bool LocalNamesAmbiguous;
454 int TypeIndexTableOffset;
455 int LocalVariableTableOffset;
456 int LineNumberTableOffset;
457 int NumLexicalBlocks;
458 int LexicalBlockTableOffset;
465 public readonly int Index;
466 public readonly SourceFileEntry SourceFile;
467 public readonly LineNumberEntry[] LineNumbers;
468 public readonly int[] ParamTypeIndices;
469 public readonly int[] LocalTypeIndices;
470 public readonly LocalVariableEntry[] Locals;
471 public readonly Type[] LocalTypes;
472 public readonly LexicalBlockEntry[] LexicalBlocks;
474 public readonly MonoSymbolFile SymbolFile;
476 public static int Size {
484 public string FullName {
485 get { return full_name; }
488 public MethodBase MethodBase {
489 get { return SymbolFile.Assembly.MonoDebugger_GetMethod (Token); }
492 internal MethodEntry (MonoSymbolFile file, BinaryReader reader, int index)
494 this.SymbolFile = file;
496 int SourceFileIndex = reader.ReadInt32 ();
497 Token = reader.ReadInt32 ();
498 StartRow = reader.ReadInt32 ();
499 EndRow = reader.ReadInt32 ();
500 ClassTypeIndex = reader.ReadInt32 ();
501 NumParameters = reader.ReadInt32 ();
502 NumLocals = reader.ReadInt32 ();
503 NumLineNumbers = reader.ReadInt32 ();
504 NameOffset = reader.ReadInt32 ();
505 FullNameOffset = reader.ReadInt32 ();
506 TypeIndexTableOffset = reader.ReadInt32 ();
507 LocalVariableTableOffset = reader.ReadInt32 ();
508 LineNumberTableOffset = reader.ReadInt32 ();
509 NumLexicalBlocks = reader.ReadInt32 ();
510 LexicalBlockTableOffset = reader.ReadInt32 ();
511 NamespaceID = reader.ReadInt32 ();
512 LocalNamesAmbiguous = reader.ReadInt32 () != 0;
514 name = file.ReadString (NameOffset);
515 full_name = file.ReadString (FullNameOffset);
517 SourceFile = file.GetSourceFile (SourceFileIndex);
519 if (LineNumberTableOffset != 0) {
520 long old_pos = reader.BaseStream.Position;
521 reader.BaseStream.Position = LineNumberTableOffset;
523 LineNumbers = new LineNumberEntry [NumLineNumbers];
525 for (int i = 0; i < NumLineNumbers; i++)
526 LineNumbers [i] = new LineNumberEntry (reader);
528 reader.BaseStream.Position = old_pos;
531 if (LocalVariableTableOffset != 0) {
532 long old_pos = reader.BaseStream.Position;
533 reader.BaseStream.Position = LocalVariableTableOffset;
535 Locals = new LocalVariableEntry [NumLocals];
536 LocalTypes = new Type [NumLocals];
538 Assembly ass = file.Assembly;
540 for (int i = 0; i < NumLocals; i++) {
541 Locals [i] = new LocalVariableEntry (reader);
542 LocalTypes [i] = ass.MonoDebugger_GetLocalTypeFromSignature (
543 Locals [i].Signature);
546 reader.BaseStream.Position = old_pos;
549 if (TypeIndexTableOffset != 0) {
550 long old_pos = reader.BaseStream.Position;
551 reader.BaseStream.Position = TypeIndexTableOffset;
553 ParamTypeIndices = new int [NumParameters];
554 LocalTypeIndices = new int [NumLocals];
556 for (int i = 0; i < NumParameters; i++)
557 ParamTypeIndices [i] = reader.ReadInt32 ();
558 for (int i = 0; i < NumLocals; i++)
559 LocalTypeIndices [i] = reader.ReadInt32 ();
561 reader.BaseStream.Position = old_pos;
564 if (LexicalBlockTableOffset != 0) {
565 long old_pos = reader.BaseStream.Position;
566 reader.BaseStream.Position = LexicalBlockTableOffset;
568 LexicalBlocks = new LexicalBlockEntry [NumLexicalBlocks];
569 for (int i = 0; i < NumLexicalBlocks; i++)
570 LexicalBlocks [i] = new LexicalBlockEntry (i, reader);
572 reader.BaseStream.Position = old_pos;
576 internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, MethodBase method,
577 int token, LocalVariableEntry[] locals, LineNumberEntry[] lines,
578 LexicalBlockEntry[] blocks, int start_row, int end_row,
581 this.SymbolFile = file;
582 Index = file.GetNextMethodIndex ();
586 StartRow = start_row;
588 NamespaceID = namespace_id;
589 LexicalBlocks = blocks;
590 NumLexicalBlocks = LexicalBlocks.Length;
593 NumLineNumbers = LineNumbers.Length;
595 ParameterInfo[] parameters = method.GetParameters ();
596 if (parameters == null)
597 parameters = new ParameterInfo [0];
599 if (parameters.Length == 0)
600 full_name = method.DeclaringType.FullName + "." + method.Name + "()";
601 else if (parameters.Length == 1)
602 full_name = method.DeclaringType.FullName + "." + method.Name + "(" + parameters [0].ParameterType.FullName + ")";
603 else if (parameters.Length == 2)
604 full_name = method.DeclaringType.FullName + "." + method.Name + "(" + parameters [0].ParameterType.FullName + "," + parameters [1].ParameterType.FullName + ")";
606 StringBuilder sb = new StringBuilder ();
607 sb.Append (method.DeclaringType.FullName);
609 sb.Append (method.Name);
611 for (int i = 0; i < parameters.Length; i++) {
614 sb.Append (parameters [i].ParameterType.FullName);
617 full_name = sb.ToString ();
622 NumParameters = parameters.Length;
623 ParamTypeIndices = new int [NumParameters];
624 for (int i = 0; i < NumParameters; i++)
625 ParamTypeIndices [i] = file.DefineType (parameters [i].ParameterType);
627 NumLocals = locals.Length;
630 if (NumLocals <= 32) {
631 // Most of the time, the O(n^2) factor is actually
632 // less than the cost of allocating the hash table,
633 // 32 is a rough number obtained through some testing.
635 for (int i = 0; i < NumLocals; i ++) {
636 string nm = locals [i].Name;
638 for (int j = i + 1; j < NumLocals; j ++) {
639 if (locals [j].Name == nm) {
640 LocalNamesAmbiguous = true;
641 goto locals_check_done;
648 Hashtable local_names = new Hashtable ();
649 foreach (LocalVariableEntry local in locals) {
650 if (local_names.Contains (local.Name)) {
651 LocalNamesAmbiguous = true;
654 local_names.Add (local.Name, local);
658 LocalTypeIndices = new int [NumLocals];
659 for (int i = 0; i < NumLocals; i++)
660 LocalTypeIndices [i] = file.GetNextTypeIndex ();
662 ClassTypeIndex = file.DefineType (method.ReflectedType);
665 internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
667 NameOffset = (int) bw.BaseStream.Position;
668 file.WriteString (bw, name);
670 FullNameOffset = (int) bw.BaseStream.Position;
671 file.WriteString (bw, full_name);
673 TypeIndexTableOffset = (int) bw.BaseStream.Position;
675 for (int i = 0; i < NumParameters; i++)
676 bw.Write (ParamTypeIndices [i]);
677 for (int i = 0; i < NumLocals; i++)
678 bw.Write (LocalTypeIndices [i]);
680 LocalVariableTableOffset = (int) bw.BaseStream.Position;
681 for (int i = 0; i < NumLocals; i++)
682 Locals [i].Write (file, bw);
683 file.LocalCount += NumLocals;
685 LineNumberTableOffset = (int) bw.BaseStream.Position;
686 for (int i = 0; i < NumLineNumbers; i++)
687 LineNumbers [i].Write (bw);
688 file.LineNumberCount += NumLineNumbers;
690 LexicalBlockTableOffset = (int) bw.BaseStream.Position;
691 for (int i = 0; i < NumLexicalBlocks; i++)
692 LexicalBlocks [i].Write (bw);
693 file_offset = (int) bw.BaseStream.Position;
695 bw.Write (SourceFile.Index);
699 bw.Write (ClassTypeIndex);
700 bw.Write (NumParameters);
701 bw.Write (NumLocals);
702 bw.Write (NumLineNumbers);
703 bw.Write (NameOffset);
704 bw.Write (FullNameOffset);
705 bw.Write (TypeIndexTableOffset);
706 bw.Write (LocalVariableTableOffset);
707 bw.Write (LineNumberTableOffset);
708 bw.Write (NumLexicalBlocks);
709 bw.Write (LexicalBlockTableOffset);
710 bw.Write (NamespaceID);
711 bw.Write (LocalNamesAmbiguous ? 1 : 0);
713 return new MethodSourceEntry (Index, file_offset, StartRow, EndRow);
716 internal void WriteIndex (BinaryWriter bw)
718 new MethodIndexEntry (file_offset, FullNameOffset, Token).Write (bw);
721 public override string ToString ()
723 return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {7}:{8}:{9}:{10} - {5} - {6}]",
724 Index, Token, SourceFile.Index, StartRow, EndRow,
725 SourceFile, FullName, ClassTypeIndex, NumParameters,
726 NumLocals, NumLineNumbers);
730 public struct NamespaceEntry
732 public readonly string Name;
733 public readonly int Index;
734 public readonly int Parent;
735 public readonly string[] UsingClauses;
737 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
741 this.Parent = parent;
742 this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
745 internal void Write (MonoSymbolFile file, BinaryWriter bw)
747 file.WriteString (bw, Name);
750 bw.Write (UsingClauses.Length);
751 foreach (string uc in UsingClauses)
752 file.WriteString (bw, uc);
755 public override string ToString ()
757 return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);