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
23 public class SourceFile : ISourceFile
25 private ArrayList _methods = new ArrayList ();
26 private string _file_name;
28 public SourceFile (string filename)
30 this._file_name = filename;
33 public override string ToString ()
38 // interface ISourceFile
40 public string FileName {
46 public ISourceMethod[] Methods {
48 ISourceMethod[] retval = new ISourceMethod [_methods.Count];
49 _methods.CopyTo (retval);
54 public void AddMethod (ISourceMethod method)
56 _methods.Add (method);
60 public class SourceBlock : ISourceBlock
62 static private int next_index;
63 private readonly int _index;
65 public SourceBlock (ISourceMethod method, ISourceLine start, ISourceLine end)
67 this._method = method;
70 this._index = ++next_index;
73 internal SourceBlock (ISourceMethod method, int startOffset)
75 this._method = method;
76 this._start = new SourceLine (startOffset);
77 this._index = ++next_index;
80 public override string ToString ()
82 return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
85 private readonly ISourceMethod _method;
86 private ArrayList _blocks = new ArrayList ();
87 internal ISourceLine _start;
88 internal ISourceLine _end;
90 private ArrayList _locals = new ArrayList ();
92 public ISourceMethod SourceMethod {
98 public ISourceBlock[] Blocks {
100 ISourceBlock[] retval = new ISourceBlock [_blocks.Count];
101 _blocks.CopyTo (retval);
106 public void AddBlock (ISourceBlock block)
111 public ISourceLine Start {
117 public ISourceLine End {
129 public ILocalVariable[] Locals {
131 ILocalVariable[] retval = new ILocalVariable [_locals.Count];
132 _locals.CopyTo (retval);
137 public void AddLocal (ILocalVariable local)
143 public class SourceLine : ISourceLine
145 public SourceLine (int row, int column)
146 : this (0, row, column)
148 this._type = SourceOffsetType.OFFSET_NONE;
151 public SourceLine (int offset, int row, int column)
153 this._offset = offset;
155 this._column = column;
156 this._type = SourceOffsetType.OFFSET_IL;
159 internal SourceLine (int offset)
160 : this (offset, 0, 0)
163 public override string ToString ()
165 return "SourceLine (" + _offset + "@" + _row + ":" + _column + ")";
168 internal SourceOffsetType _type;
169 internal int _offset;
171 internal int _column;
173 // interface ISourceLine
175 public SourceOffsetType OffsetType {
200 public class Variable : IVariable
202 public Variable (string name, ITypeHandle handle, ISourceMethod method, int index)
203 : this (name, handle, method, index, null)
206 public Variable (string name, ITypeHandle handle, ISourceMethod method,
207 int index, ISourceLine line)
210 this._handle = handle;
211 this._method = method;
216 private readonly string _name;
217 private readonly ITypeHandle _handle;
218 private readonly ISourceMethod _method;
219 private readonly ISourceLine _line;
220 private readonly int _index;
222 // interface IVariable
230 public ISourceMethod Method {
242 public ITypeHandle TypeHandle {
248 public ISourceLine Line {
255 public class LocalVariable : Variable, ILocalVariable
257 public LocalVariable (string name, ITypeHandle handle, ISourceMethod method,
258 int index, ISourceLine line)
259 : base (name, handle, method, index, line)
262 public override string ToString ()
264 return "LocalVariable (" + Index + "," + Name + ")";
268 public class MethodParameter : Variable, IMethodParameter
270 private static int get_index (ISourceMethod method, ParameterInfo param)
272 return method.MethodBase.IsStatic ? param.Position - 1 :
276 public MethodParameter (DwarfFileWriter writer, ISourceMethod method,
278 : base (param.Name, writer.RegisterType (param.ParameterType),
279 method, get_index (method, param))
281 this._method = method;
285 private readonly ISourceMethod _method;
286 private readonly ParameterInfo _param;
289 public class SourceMethod : ISourceMethod
291 private ArrayList _lines = new ArrayList ();
292 private ArrayList _blocks = new ArrayList ();
293 private Hashtable _block_hash = new Hashtable ();
294 private Stack _block_stack = new Stack ();
296 internal readonly MethodBase _method_base;
297 internal ISourceFile _source_file;
300 private SourceBlock _implicit_block;
302 public SourceMethod (MethodBase method_base, ISourceFile source_file)
305 this._source_file = source_file;
308 internal SourceMethod (MethodBase method_base)
310 this._method_base = method_base;
312 this._implicit_block = new SourceBlock (this, 0);
315 public void SetSourceRange (ISourceFile sourceFile,
316 int startLine, int startColumn,
317 int endLine, int endColumn)
319 _source_file = sourceFile;
320 _implicit_block._start = new SourceLine (startLine, startColumn);
321 _implicit_block._end = new SourceLine (endLine, endColumn);
325 public void StartBlock (ISourceBlock block)
327 _block_stack.Push (block);
330 public void EndBlock (int endOffset) {
331 SourceBlock block = (SourceBlock) _block_stack.Pop ();
333 block._end = new SourceLine (endOffset);
335 if (_block_stack.Count > 0) {
336 ISourceBlock parent = (ISourceBlock) _block_stack.Peek ();
338 parent.AddBlock (block);
342 _block_hash.Add (block.ID, block);
345 public void SetBlockRange (int BlockID, int startOffset, int endOffset)
347 SourceBlock block = (SourceBlock) _block_hash [BlockID];
348 ((SourceLine) block.Start)._offset = startOffset;
349 ((SourceLine) block.End)._offset = endOffset;
352 public ISourceBlock CurrentBlock {
354 if (_block_stack.Count > 0)
355 return (ISourceBlock) _block_stack.Peek ();
357 return _implicit_block;
361 // interface ISourceMethod
363 public ISourceLine[] Lines {
365 ISourceLine[] retval = new ISourceLine [_lines.Count];
366 _lines.CopyTo (retval);
371 public void AddLine (ISourceLine line)
376 public ISourceBlock[] Blocks {
378 ISourceBlock[] retval = new ISourceBlock [_blocks.Count];
379 _blocks.CopyTo (retval);
384 public ILocalVariable[] Locals {
386 return _implicit_block.Locals;
390 public void AddLocal (ILocalVariable local)
392 _implicit_block.AddLocal (local);
395 public MethodBase MethodBase {
401 public string FullName {
403 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
407 public Type ReturnType {
409 if (_method_base is MethodInfo)
410 return ((MethodInfo)_method_base).ReturnType;
411 else if (_method_base is ConstructorInfo)
412 return _method_base.DeclaringType;
414 throw new NotSupportedException ();
418 public ParameterInfo[] Parameters {
420 if (_method_base == null)
421 return new ParameterInfo [0];
423 ParameterInfo [] retval = _method_base.GetParameters ();
425 return new ParameterInfo [0];
431 public ISourceFile SourceFile {
442 throw new NotSupportedException ();
446 public ISourceLine Start {
448 return _implicit_block.Start;
452 public ISourceLine End {
454 return _implicit_block.End;
459 public class MonoSymbolWriter : IMonoSymbolWriter
461 protected Assembly assembly;
462 protected ModuleBuilder module_builder;
463 protected ArrayList locals = null;
464 protected ArrayList orphant_methods = null;
465 protected ArrayList methods = null;
466 protected Hashtable sources = null;
467 protected DwarfFileWriter writer = null;
468 private ArrayList mbuilder_array = null;
470 public ISourceMethod[] Methods {
472 ISourceMethod[] retval = new ISourceMethod [methods.Count];
473 methods.CopyTo (retval);
478 public ISourceFile[] Sources {
480 ISourceFile[] retval = new ISourceFile [sources.Count];
481 sources.Values.CopyTo (retval, 0);
486 public DwarfFileWriter DwarfFileWriter {
492 protected SourceMethod current_method = null;
493 private readonly string assembly_filename = null;
496 // Interface IMonoSymbolWriter
499 public MonoSymbolWriter (ModuleBuilder mb, string filename, ArrayList mbuilder_array)
501 this.assembly_filename = filename;
502 this.module_builder = mb;
503 this.methods = new ArrayList ();
504 this.sources = new Hashtable ();
505 this.orphant_methods = new ArrayList ();
506 this.locals = new ArrayList ();
507 this.mbuilder_array = mbuilder_array;
510 public void Close () {
511 if (assembly == null)
512 assembly = Assembly.LoadFrom (assembly_filename);
516 CreateDwarfFile (assembly);
519 public void CloseNamespace () {
522 // Create and return a new IMonoSymbolDocumentWriter.
523 public ISymbolDocumentWriter DefineDocument (string url,
528 return new MonoSymbolDocumentWriter (url);
531 public void DefineField (
534 FieldAttributes attributes,
536 SymAddressKind addrKind,
543 public void DefineGlobalVariable (
545 FieldAttributes attributes,
547 SymAddressKind addrKind,
554 public void DefineLocalVariable (string name,
555 FieldAttributes attributes,
557 SymAddressKind addrKind,
564 throw new NotSupportedException ();
567 public void DefineLocalVariable (string name,
569 FieldAttributes attributes,
574 if (current_method == null)
577 ITypeHandle type = writer.RegisterType (local.LocalType);
579 LocalVariable local_info = new LocalVariable (name, type, current_method,
582 current_method.CurrentBlock.AddLocal (local_info);
583 locals.Add (local_info);
587 public void DefineParameter (string name,
588 ParameterAttributes attributes,
590 SymAddressKind addrKind,
595 throw new NotSupportedException ();
598 public void DefineSequencePoints (ISymbolDocumentWriter document,
605 SourceLine source_line = new SourceLine (offsets [0], lines [0], columns [0]);
607 if (current_method != null)
608 current_method.AddLine (source_line);
611 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
613 throw new NotSupportedException ();
616 public void Initialize (string filename, string[] args)
618 this.writer = new DwarfFileWriter (filename, args);
621 public void OpenMethod (SymbolToken symbol_token)
623 int token = symbol_token.GetToken ();
625 if ((token & 0xff000000) != 0x06000000)
626 throw new ArgumentException ();
628 int index = (token & 0xffffff) - 1;
630 MethodBuilder mb = (MethodBuilder) mbuilder_array [index];
632 current_method = new SourceMethod (mb);
634 methods.Add (current_method);
637 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
638 int startLine, int startColumn,
639 ISymbolDocumentWriter endDoc,
640 int endLine, int endColumn)
642 if (current_method == null)
645 if ((startDoc == null) || (endDoc == null))
646 throw new NullReferenceException ();
648 if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
649 throw new NotSupportedException ("both startDoc and endDoc must be of type "
650 + "MonoSymbolDocumentWriter");
652 if (!startDoc.Equals (endDoc))
653 throw new NotSupportedException ("startDoc and endDoc must be the same");
655 string source_file = ((MonoSymbolDocumentWriter) startDoc).FileName;
656 SourceFile source_info;
658 if (sources.ContainsKey (source_file))
659 source_info = (SourceFile) sources [source_file];
661 source_info = new SourceFile (source_file);
662 sources.Add (source_file, source_info);
665 current_method.SetSourceRange (source_info, startLine, startColumn,
668 source_info.AddMethod (current_method);
671 public void CloseMethod () {
672 current_method = null;
675 public void OpenNamespace (string name)
679 public int OpenScope (int startOffset)
681 if (current_method == null)
684 ISourceBlock block = new SourceBlock (current_method, startOffset);
685 current_method.StartBlock (block);
690 public void CloseScope (int endOffset) {
691 if (current_method == null)
694 current_method.EndBlock (endOffset);
697 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
699 if (current_method == null)
702 current_method.SetBlockRange (scopeID, startOffset, endOffset);
705 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
709 public void SetUnderlyingWriter (IntPtr underlyingWriter)
711 throw new NotSupportedException ();
714 public void SetUserEntryPoint (SymbolToken entryMethod)
718 public void UsingNamespace (string fullName)
723 // MonoSymbolWriter implementation
725 protected void WriteLocal (DwarfFileWriter.Die parent_die, ILocalVariable local)
727 DwarfFileWriter.DieMethodVariable die;
729 die = new DwarfFileWriter.DieMethodVariable (parent_die, local);
732 protected void WriteBlock (DwarfFileWriter.Die parent_die, ISourceBlock block)
734 DwarfFileWriter.DieLexicalBlock die;
736 die = new DwarfFileWriter.DieLexicalBlock (parent_die, block);
738 foreach (ILocalVariable local in block.Locals)
739 WriteLocal (die, local);
741 foreach (ISourceBlock subblock in block.Blocks)
742 WriteBlock (die, subblock);
745 protected void WriteMethod (ISourceMethod method)
747 DwarfFileWriter.DieCompileUnit parent_die = writer.DieGlobalCompileUnit;
748 DwarfFileWriter.DieSubProgram die;
750 die = new DwarfFileWriter.DieSubProgram (parent_die, method);
752 foreach (ILocalVariable local in method.Locals)
753 WriteLocal (die, local);
755 foreach (ISourceBlock block in method.Blocks)
756 WriteBlock (die, block);
759 protected void WriteSource (DwarfFileWriter writer, ISourceFile source)
761 foreach (ISourceMethod method in source.Methods)
762 WriteMethod (method);
765 protected void DoFixups (Assembly assembly)
767 foreach (SourceMethod method in methods) {
768 if (method._method_base is MethodBuilder) {
769 MethodBuilder mb = (MethodBuilder) method._method_base;
770 method._token = mb.GetToken ().Token;
771 } else if (method._method_base is ConstructorBuilder) {
772 ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
773 method._token = cb.GetToken ().Token;
775 throw new NotSupportedException ();
777 if (method.SourceFile == null)
778 orphant_methods.Add (method);
782 protected void CreateDwarfFile (Assembly assembly)
784 foreach (ISourceFile source in sources.Values)
785 WriteSource (writer, source);
787 if (orphant_methods.Count > 0) {
788 SourceFile source = new SourceFile ("<unknown>");
790 foreach (SourceMethod orphant in orphant_methods) {
791 orphant._source_file = source;
792 source.AddMethod (orphant);
795 WriteSource (writer, source);
798 writer.WriteSymbolTable (this);