2 // System.Diagnostics.SymbolStore/MonoSymbolWriter.cs
5 // Martin Baulig (martin@gnome.org)
7 // This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter
10 // (C) 2002 Ximian, Inc. http://www.ximian.com
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Runtime.CompilerServices;
17 using System.Diagnostics.SymbolStore;
18 using System.Collections;
21 namespace Mono.CSharp.Debugger
24 public class MonoSymbolWriter : IMonoSymbolWriter
26 protected Assembly assembly;
27 protected ModuleBuilder module_builder;
28 protected string output_filename = null;
29 protected ArrayList locals = null;
30 protected ArrayList orphant_methods = null;
31 protected ArrayList methods = null;
32 protected Hashtable sources = null;
34 protected class SourceFile : ISourceFile
36 private ArrayList _methods = new ArrayList ();
37 private string _file_name;
39 public SourceFile (string filename)
41 this._file_name = filename;
44 public override string ToString ()
49 // interface ISourceFile
51 public string FileName {
57 public ISourceMethod[] Methods {
59 ISourceMethod[] retval = new ISourceMethod [_methods.Count];
60 _methods.CopyTo (retval);
65 public void AddMethod (ISourceMethod method)
67 _methods.Add (method);
71 protected class SourceBlock : ISourceBlock
73 static private int next_index;
74 private readonly int _index;
76 public SourceBlock (ISourceMethod method, ISourceLine start, ISourceLine end)
78 this._method = method;
81 this._index = ++next_index;
84 internal SourceBlock (ISourceMethod method, int startOffset)
86 this._method = method;
87 this._start = new SourceLine (startOffset);
88 this._index = ++next_index;
91 public override string ToString ()
93 return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
96 private readonly ISourceMethod _method;
97 private ArrayList _blocks = new ArrayList ();
98 internal ISourceLine _start;
99 internal ISourceLine _end;
101 private ArrayList _locals = new ArrayList ();
103 public ISourceMethod SourceMethod {
109 public ISourceBlock[] Blocks {
111 ISourceBlock[] retval = new ISourceBlock [_blocks.Count];
112 _blocks.CopyTo (retval);
117 public void AddBlock (ISourceBlock block)
122 public ISourceLine Start {
128 public ISourceLine End {
140 public ILocalVariable[] Locals {
142 ILocalVariable[] retval = new ILocalVariable [_locals.Count];
143 _locals.CopyTo (retval);
148 public void AddLocal (ILocalVariable local)
154 protected class SourceLine : ISourceLine
156 public SourceLine (int row, int column)
157 : this (0, row, column)
159 this._type = SourceOffsetType.OFFSET_NONE;
162 public SourceLine (int offset, int row, int column)
164 this._offset = offset;
166 this._column = column;
167 this._type = SourceOffsetType.OFFSET_IL;
170 internal SourceLine (int offset)
171 : this (offset, 0, 0)
174 public override string ToString ()
176 return "SourceLine (" + _offset + "@" + _row + ":" + _column + ")";
179 internal SourceOffsetType _type;
180 internal int _offset;
182 internal int _column;
184 // interface ISourceLine
186 public SourceOffsetType OffsetType {
211 protected class LocalVariable : ILocalVariable
213 public LocalVariable (string name, byte[] signature, ISourceMethod method,
215 : this (name, signature, method, index, null)
218 public LocalVariable (string name, byte[] signature, ISourceMethod method,
219 int index, ISourceLine line)
222 this._signature = signature;
223 this._method = method;
228 private readonly string _name;
230 private readonly byte[] _signature;
231 private readonly ISourceMethod _method;
232 private readonly int _index;
233 private readonly ISourceLine _line;
235 public override string ToString ()
237 return "LocalVariable (" + _index + "," + _name + ")";
240 // interface ILocalVariable
248 public ISourceMethod Method {
266 public byte[] Signature {
272 public ISourceLine Line {
279 protected class SourceMethod : ISourceMethod
281 private ArrayList _lines = new ArrayList ();
282 private ArrayList _blocks = new ArrayList ();
283 private Hashtable _block_hash = new Hashtable ();
284 private Stack _block_stack = new Stack ();
286 internal readonly MethodBase _method_base;
287 internal ISourceFile _source_file;
290 private SourceBlock _implicit_block;
292 public SourceMethod (MethodBase method_base, ISourceFile source_file)
295 this._source_file = source_file;
298 internal SourceMethod (MethodBase method_base)
300 this._method_base = method_base;
302 this._implicit_block = new SourceBlock (this, 0);
305 public void SetSourceRange (ISourceFile sourceFile,
306 int startLine, int startColumn,
307 int endLine, int endColumn)
309 _source_file = sourceFile;
310 _implicit_block._start = new SourceLine (startLine, startColumn);
311 _implicit_block._end = new SourceLine (endLine, endColumn);
315 public void StartBlock (ISourceBlock block)
317 _block_stack.Push (block);
320 public void EndBlock (int endOffset) {
321 SourceBlock block = (SourceBlock) _block_stack.Pop ();
323 block._end = new SourceLine (endOffset);
325 if (_block_stack.Count > 0) {
326 ISourceBlock parent = (ISourceBlock) _block_stack.Peek ();
328 parent.AddBlock (block);
332 _block_hash.Add (block.ID, block);
335 public void SetBlockRange (int BlockID, int startOffset, int endOffset)
337 SourceBlock block = (SourceBlock) _block_hash [BlockID];
338 ((SourceLine) block.Start)._offset = startOffset;
339 ((SourceLine) block.End)._offset = endOffset;
342 public ISourceBlock CurrentBlock {
344 if (_block_stack.Count > 0)
345 return (ISourceBlock) _block_stack.Peek ();
347 return _implicit_block;
351 // interface ISourceMethod
353 public ISourceLine[] Lines {
355 ISourceLine[] retval = new ISourceLine [_lines.Count];
356 _lines.CopyTo (retval);
361 public void AddLine (ISourceLine line)
366 public ISourceBlock[] Blocks {
368 ISourceBlock[] retval = new ISourceBlock [_blocks.Count];
369 _blocks.CopyTo (retval);
374 public ILocalVariable[] Locals {
376 return _implicit_block.Locals;
380 public void AddLocal (ILocalVariable local)
382 _implicit_block.AddLocal (local);
385 public MethodBase MethodBase {
391 public Type ReturnType {
393 if (_method_base is MethodInfo)
394 return ((MethodInfo)_method_base).ReturnType;
395 else if (_method_base is ConstructorInfo)
396 return _method_base.DeclaringType;
398 throw new NotSupportedException ();
402 public ISourceFile SourceFile {
413 throw new NotSupportedException ();
417 public ISourceLine Start {
419 return _implicit_block.Start;
423 public ISourceLine End {
425 return _implicit_block.End;
430 public ISourceMethod[] Methods {
432 ISourceMethod[] retval = new ISourceMethod [methods.Count];
433 methods.CopyTo (retval);
438 public ISourceFile[] Sources {
440 ISourceFile[] retval = new ISourceFile [sources.Count];
441 sources.Values.CopyTo (retval, 0);
446 protected SourceMethod current_method = null;
447 private readonly string assembly_filename = null;
450 // Interface IMonoSymbolWriter
453 public MonoSymbolWriter (ModuleBuilder mb, string filename)
455 this.assembly_filename = filename;
456 this.module_builder = mb;
458 this.methods = new ArrayList ();
459 this.sources = new Hashtable ();
460 this.orphant_methods = new ArrayList ();
461 this.locals = new ArrayList ();
464 public void Close () {
465 if (assembly == null)
466 assembly = Assembly.LoadFrom (assembly_filename);
470 CreateDwarfFile (output_filename);
473 public void CloseNamespace () {
476 // Create and return a new IMonoSymbolDocumentWriter.
477 public ISymbolDocumentWriter DefineDocument (string url,
482 return new MonoSymbolDocumentWriter (url);
485 public void DefineField (
488 FieldAttributes attributes,
490 SymAddressKind addrKind,
497 public void DefineGlobalVariable (
499 FieldAttributes attributes,
501 SymAddressKind addrKind,
508 public void DefineLocalVariable (string name,
509 FieldAttributes attributes,
511 SymAddressKind addrKind,
518 if (current_method == null)
521 LocalVariable local_info = new LocalVariable (name, signature,
522 current_method, addr1);
524 current_method.CurrentBlock.AddLocal (local_info);
525 locals.Add (local_info);
528 public void DefineParameter (string name,
529 ParameterAttributes attributes,
531 SymAddressKind addrKind,
536 throw new NotSupportedException ();
539 public void DefineSequencePoints (ISymbolDocumentWriter document,
546 SourceLine source_line = new SourceLine (offsets [0], lines [0], columns [0]);
548 if (current_method != null)
549 current_method.AddLine (source_line);
552 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
554 this.output_filename = filename;
557 public void OpenMethod (SymbolToken symbol_token)
559 int token = symbol_token.GetToken ();
561 MethodBuilder mb = get_method (module_builder, token);
563 current_method = new SourceMethod (mb);
565 methods.Add (current_method);
568 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
569 int startLine, int startColumn,
570 ISymbolDocumentWriter endDoc,
571 int endLine, int endColumn)
573 if (current_method == null)
576 if ((startDoc == null) || (endDoc == null))
577 throw new NullReferenceException ();
579 if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
580 throw new NotSupportedException ("both startDoc and endDoc must be of type "
581 + "MonoSymbolDocumentWriter");
583 if (!startDoc.Equals (endDoc))
584 throw new NotSupportedException ("startDoc and endDoc must be the same");
586 string source_file = ((MonoSymbolDocumentWriter) startDoc).FileName;
587 SourceFile source_info;
589 if (sources.ContainsKey (source_file))
590 source_info = (SourceFile) sources [source_file];
592 source_info = new SourceFile (source_file);
593 sources.Add (source_file, source_info);
596 current_method.SetSourceRange (source_info, startLine, startColumn,
599 source_info.AddMethod (current_method);
602 public void CloseMethod () {
603 current_method = null;
606 public void OpenNamespace (string name)
610 public int OpenScope (int startOffset)
612 if (current_method == null)
615 ISourceBlock block = new SourceBlock (current_method, startOffset);
616 current_method.StartBlock (block);
621 public void CloseScope (int endOffset) {
622 if (current_method == null)
625 current_method.EndBlock (endOffset);
628 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
630 if (current_method == null)
633 current_method.SetBlockRange (scopeID, startOffset, endOffset);
636 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
640 public void SetUnderlyingWriter (IntPtr underlyingWriter)
642 throw new NotSupportedException ();
645 public void SetUserEntryPoint (SymbolToken entryMethod)
649 public void UsingNamespace (string fullName)
654 // MonoSymbolWriter implementation
656 protected void WriteLocal (DwarfFileWriter.Die parent_die, ILocalVariable local)
658 DwarfFileWriter.DieMethodVariable die;
660 die = new DwarfFileWriter.DieMethodVariable (parent_die, local);
663 protected void WriteBlock (DwarfFileWriter.Die parent_die, ISourceBlock block)
665 DwarfFileWriter.DieLexicalBlock die;
667 die = new DwarfFileWriter.DieLexicalBlock (parent_die, block);
669 foreach (ILocalVariable local in block.Locals)
670 WriteLocal (die, local);
672 foreach (ISourceBlock subblock in block.Blocks)
673 WriteBlock (die, subblock);
676 protected void WriteMethod (DwarfFileWriter.DieCompileUnit parent_die, ISourceMethod method)
678 DwarfFileWriter.DieSubProgram die;
680 die = new DwarfFileWriter.DieSubProgram (parent_die, method);
682 foreach (ILocalVariable local in method.Locals)
683 WriteLocal (die, local);
685 foreach (ISourceBlock block in method.Blocks)
686 WriteBlock (die, block);
689 protected void WriteSource (DwarfFileWriter writer, ISourceFile source)
691 DwarfFileWriter.CompileUnit compile_unit = new DwarfFileWriter.CompileUnit (
692 writer, source.FileName);
694 DwarfFileWriter.DieCompileUnit die = new DwarfFileWriter.DieCompileUnit (compile_unit);
696 foreach (ISourceMethod method in source.Methods)
697 WriteMethod (die, method);
701 [MethodImplAttribute(MethodImplOptions.InternalCall)]
702 internal extern static Type get_local_type_from_sig (Assembly assembly, byte[] sig);
704 [MethodImplAttribute(MethodImplOptions.InternalCall)]
705 internal extern static MethodBuilder get_method (ModuleBuilder mb, int token);
707 protected void DoFixups (Assembly assembly)
709 foreach (SourceMethod method in methods) {
710 if (method._method_base is MethodBuilder) {
711 MethodBuilder mb = (MethodBuilder) method._method_base;
712 method._token = mb.GetToken ().Token;
713 } else if (method._method_base is ConstructorBuilder) {
714 ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
715 method._token = cb.GetToken ().Token;
717 throw new NotSupportedException ();
719 if (method.SourceFile == null)
720 orphant_methods.Add (method);
723 foreach (LocalVariable local in locals) {
724 byte[] signature = local.Signature;
726 Type type = get_local_type_from_sig (assembly, signature);
728 ((LocalVariable) local)._type = type;
732 protected void CreateDwarfFile (string filename)
734 DwarfFileWriter writer = new DwarfFileWriter (filename);
736 foreach (ISourceFile source in sources.Values)
737 WriteSource (writer, source);
739 if (orphant_methods.Count > 0) {
740 SourceFile source = new SourceFile ("<unknown>");
742 foreach (SourceMethod orphant in orphant_methods) {
743 orphant._source_file = source;
744 source.AddMethod (orphant);
747 WriteSource (writer, source);
750 writer.WriteSymbolTable (this);