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;
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;
464 MethodIndexEntry index_entry;
466 public readonly int Index;
467 public readonly SourceFileEntry SourceFile;
468 public readonly LineNumberEntry[] LineNumbers;
469 public readonly int[] ParamTypeIndices;
470 public readonly int[] LocalTypeIndices;
471 public readonly LocalVariableEntry[] Locals;
472 public readonly Type[] LocalTypes;
473 public readonly LexicalBlockEntry[] LexicalBlocks;
475 public readonly MonoSymbolFile SymbolFile;
477 public static int Size {
485 public string FullName {
486 get { return full_name; }
489 public MethodBase MethodBase {
490 get { return SymbolFile.Assembly.MonoDebugger_GetMethod (Token); }
493 internal MethodEntry (MonoSymbolFile file, BinaryReader reader, int index)
495 this.SymbolFile = file;
497 SourceFileIndex = reader.ReadInt32 ();
498 Token = reader.ReadInt32 ();
499 StartRow = reader.ReadInt32 ();
500 EndRow = reader.ReadInt32 ();
501 ClassTypeIndex = reader.ReadInt32 ();
502 NumParameters = reader.ReadInt32 ();
503 NumLocals = reader.ReadInt32 ();
504 NumLineNumbers = reader.ReadInt32 ();
505 NameOffset = reader.ReadInt32 ();
506 FullNameOffset = reader.ReadInt32 ();
507 TypeIndexTableOffset = reader.ReadInt32 ();
508 LocalVariableTableOffset = reader.ReadInt32 ();
509 LineNumberTableOffset = reader.ReadInt32 ();
510 NumLexicalBlocks = reader.ReadInt32 ();
511 LexicalBlockTableOffset = reader.ReadInt32 ();
512 NamespaceID = reader.ReadInt32 ();
513 LocalNamesAmbiguous = reader.ReadInt32 () != 0;
515 name = file.ReadString (NameOffset);
516 full_name = file.ReadString (FullNameOffset);
518 SourceFile = file.GetSourceFile (SourceFileIndex);
520 if (LineNumberTableOffset != 0) {
521 long old_pos = reader.BaseStream.Position;
522 reader.BaseStream.Position = LineNumberTableOffset;
524 LineNumbers = new LineNumberEntry [NumLineNumbers];
526 for (int i = 0; i < NumLineNumbers; i++)
527 LineNumbers [i] = new LineNumberEntry (reader);
529 reader.BaseStream.Position = old_pos;
532 if (LocalVariableTableOffset != 0) {
533 long old_pos = reader.BaseStream.Position;
534 reader.BaseStream.Position = LocalVariableTableOffset;
536 Locals = new LocalVariableEntry [NumLocals];
537 LocalTypes = new Type [NumLocals];
539 Assembly ass = file.Assembly;
541 for (int i = 0; i < NumLocals; i++) {
542 Locals [i] = new LocalVariableEntry (reader);
543 LocalTypes [i] = ass.MonoDebugger_GetLocalTypeFromSignature (
544 Locals [i].Signature);
547 reader.BaseStream.Position = old_pos;
550 if (TypeIndexTableOffset != 0) {
551 long old_pos = reader.BaseStream.Position;
552 reader.BaseStream.Position = TypeIndexTableOffset;
554 ParamTypeIndices = new int [NumParameters];
555 LocalTypeIndices = new int [NumLocals];
557 for (int i = 0; i < NumParameters; i++)
558 ParamTypeIndices [i] = reader.ReadInt32 ();
559 for (int i = 0; i < NumLocals; i++)
560 LocalTypeIndices [i] = reader.ReadInt32 ();
562 reader.BaseStream.Position = old_pos;
565 if (LexicalBlockTableOffset != 0) {
566 long old_pos = reader.BaseStream.Position;
567 reader.BaseStream.Position = LexicalBlockTableOffset;
569 LexicalBlocks = new LexicalBlockEntry [NumLexicalBlocks];
570 for (int i = 0; i < NumLexicalBlocks; i++)
571 LexicalBlocks [i] = new LexicalBlockEntry (i, reader);
573 reader.BaseStream.Position = old_pos;
577 internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, MethodBase method,
578 int token, LocalVariableEntry[] locals, LineNumberEntry[] lines,
579 LexicalBlockEntry[] blocks, int start_row, int end_row,
582 this.SymbolFile = file;
583 Index = file.GetNextMethodIndex ();
586 SourceFileIndex = source.Index;
588 StartRow = start_row;
590 NamespaceID = namespace_id;
591 LexicalBlocks = blocks;
592 NumLexicalBlocks = LexicalBlocks.Length;
594 LineNumbers = BuildLineNumberTable (lines);
595 NumLineNumbers = LineNumbers.Length;
597 ParameterInfo[] parameters = method.GetParameters ();
598 if (parameters == null)
599 parameters = new ParameterInfo [0];
601 StringBuilder sb = new StringBuilder ();
602 sb.Append (method.DeclaringType.FullName);
604 sb.Append (method.Name);
606 for (int i = 0; i < parameters.Length; i++) {
609 sb.Append (parameters [i].ParameterType.FullName);
614 full_name = sb.ToString ();
616 NumParameters = parameters.Length;
617 ParamTypeIndices = new int [NumParameters];
618 for (int i = 0; i < NumParameters; i++)
619 ParamTypeIndices [i] = file.DefineType (parameters [i].ParameterType);
621 NumLocals = locals.Length;
624 if (NumLocals <= 32) {
625 // Most of the time, the O(n^2) factor is actually
626 // less than the cost of allocating the hash table,
627 // 32 is a rough number obtained through some testing.
629 for (int i = 0; i < NumLocals; i ++) {
630 string nm = locals [i].Name;
632 for (int j = i + 1; j < NumLocals; j ++) {
633 if (locals [j].Name == nm) {
634 LocalNamesAmbiguous = true;
635 goto locals_check_done;
642 Hashtable local_names = new Hashtable ();
643 foreach (LocalVariableEntry local in locals) {
644 if (local_names.Contains (local.Name)) {
645 LocalNamesAmbiguous = true;
648 local_names.Add (local.Name, local);
652 LocalTypeIndices = new int [NumLocals];
653 for (int i = 0; i < NumLocals; i++)
654 LocalTypeIndices [i] = file.GetNextTypeIndex ();
656 ClassTypeIndex = file.DefineType (method.ReflectedType);
659 LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
661 ArrayList list = new ArrayList ();
662 int last_offset = -1;
665 for (int i = 0; i < line_numbers.Length; i++) {
666 LineNumberEntry line = (LineNumberEntry) line_numbers [i];
668 if (line.Offset > last_offset) {
670 list.Add (new LineNumberEntry (last_row, last_offset));
672 last_offset = line.Offset;
673 } else if (line.Row > last_row) {
679 list.Add (new LineNumberEntry (last_row, last_offset));
681 LineNumberEntry[] retval = new LineNumberEntry [list.Count];
682 list.CopyTo (retval, 0);
686 internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
688 NameOffset = (int) bw.BaseStream.Position;
689 file.WriteString (bw, name);
691 FullNameOffset = (int) bw.BaseStream.Position;
692 file.WriteString (bw, full_name);
694 TypeIndexTableOffset = (int) bw.BaseStream.Position;
696 for (int i = 0; i < NumParameters; i++)
697 bw.Write (ParamTypeIndices [i]);
698 for (int i = 0; i < NumLocals; i++)
699 bw.Write (LocalTypeIndices [i]);
701 LocalVariableTableOffset = (int) bw.BaseStream.Position;
702 for (int i = 0; i < NumLocals; i++)
703 Locals [i].Write (file, bw);
704 file.LocalCount += NumLocals;
706 LineNumberTableOffset = (int) bw.BaseStream.Position;
707 for (int i = 0; i < NumLineNumbers; i++)
708 LineNumbers [i].Write (bw);
709 file.LineNumberCount += NumLineNumbers;
711 LexicalBlockTableOffset = (int) bw.BaseStream.Position;
712 for (int i = 0; i < NumLexicalBlocks; i++)
713 LexicalBlocks [i].Write (bw);
714 file_offset = (int) bw.BaseStream.Position;
716 index_entry = new MethodIndexEntry (file_offset, FullNameOffset, Token);
718 bw.Write (SourceFileIndex);
722 bw.Write (ClassTypeIndex);
723 bw.Write (NumParameters);
724 bw.Write (NumLocals);
725 bw.Write (NumLineNumbers);
726 bw.Write (NameOffset);
727 bw.Write (FullNameOffset);
728 bw.Write (TypeIndexTableOffset);
729 bw.Write (LocalVariableTableOffset);
730 bw.Write (LineNumberTableOffset);
731 bw.Write (NumLexicalBlocks);
732 bw.Write (LexicalBlockTableOffset);
733 bw.Write (NamespaceID);
734 bw.Write (LocalNamesAmbiguous ? 1 : 0);
736 return new MethodSourceEntry (Index, file_offset, StartRow, EndRow);
739 internal void WriteIndex (BinaryWriter bw)
741 index_entry.Write (bw);
744 public override string ToString ()
746 return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {7}:{8}:{9}:{10} - {5} - {6}]",
747 Index, Token, SourceFileIndex, StartRow, EndRow,
748 SourceFile, FullName, ClassTypeIndex, NumParameters,
749 NumLocals, NumLineNumbers);
753 public struct NamespaceEntry
755 public readonly string Name;
756 public readonly int Index;
757 public readonly int Parent;
758 public readonly string[] UsingClauses;
760 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
764 this.Parent = parent;
765 this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
768 internal void Write (MonoSymbolFile file, BinaryWriter bw)
770 file.WriteString (bw, Name);
773 bw.Write (UsingClauses.Length);
774 foreach (string uc in UsingClauses)
775 file.WriteString (bw, uc);
778 public override string ToString ()
780 return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);