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 string output_filename = null;
28 protected ArrayList locals = null;
29 protected ArrayList orphant_methods = null;
30 protected Hashtable methods = null;
31 protected Hashtable sources = null;
33 protected class SourceFile : ISourceFile
35 private ArrayList _methods = new ArrayList ();
36 private string _file_name;
38 public SourceFile (string filename)
40 this._file_name = filename;
43 public override string ToString ()
48 // interface ISourceFile
50 public string FileName {
56 public ISourceMethod[] Methods {
58 ISourceMethod[] retval = new ISourceMethod [_methods.Count];
59 _methods.CopyTo (retval);
64 public void AddMethod (ISourceMethod method)
66 _methods.Add (method);
70 protected class SourceBlock : ISourceBlock
72 static private int next_index;
73 private readonly int _index;
75 public SourceBlock (ISourceMethod method, ISourceLine start, ISourceLine end)
77 this._method = method;
80 this._index = ++next_index;
83 internal SourceBlock (ISourceMethod method, int startOffset)
85 this._method = method;
86 this._start = new SourceLine (startOffset);
87 this._index = ++next_index;
90 public override string ToString ()
92 return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
95 private readonly ISourceMethod _method;
96 private ArrayList _blocks = new ArrayList ();
97 internal ISourceLine _start;
98 internal ISourceLine _end;
100 private ArrayList _locals = new ArrayList ();
102 public ISourceMethod SourceMethod {
108 public ISourceBlock[] Blocks {
110 ISourceBlock[] retval = new ISourceBlock [_blocks.Count];
111 _blocks.CopyTo (retval);
116 public void AddBlock (ISourceBlock block)
121 public ISourceLine Start {
127 public ISourceLine End {
139 public ILocalVariable[] Locals {
141 ILocalVariable[] retval = new ILocalVariable [_locals.Count];
142 _locals.CopyTo (retval);
147 public void AddLocal (ILocalVariable local)
153 protected class SourceLine : ISourceLine
155 public SourceLine (int row, int column)
156 : this (0, row, column)
158 this._type = SourceOffsetType.OFFSET_NONE;
161 public SourceLine (int offset, int row, int column)
163 this._offset = offset;
165 this._column = column;
166 this._type = SourceOffsetType.OFFSET_IL;
169 internal SourceLine (int offset)
170 : this (offset, 0, 0)
173 public override string ToString ()
175 return "SourceLine (" + _offset + "@" + _row + ":" + _column + ")";
178 internal SourceOffsetType _type;
179 internal int _offset;
181 internal int _column;
183 // interface ISourceLine
185 public SourceOffsetType OffsetType {
210 protected class LocalVariable : ILocalVariable
212 public LocalVariable (string name, byte[] signature, int token, int index)
213 : this (name, signature, token, index, null)
216 public LocalVariable (string name, byte[] signature, int token, int index,
220 this._signature = signature;
226 private readonly string _name;
228 private readonly byte[] _signature;
229 private readonly int _token;
230 private readonly int _index;
231 private readonly ISourceLine _line;
233 public override string ToString ()
235 return "LocalVariable (" + _index + "," + _name + ")";
238 // interface ILocalVariable
264 public byte[] Signature {
270 public ISourceLine Line {
277 protected class SourceMethod : ISourceMethod
279 private ArrayList _lines = new ArrayList ();
280 private ArrayList _blocks = new ArrayList ();
281 private Hashtable _block_hash = new Hashtable ();
282 private Stack _block_stack = new Stack ();
284 internal MethodInfo _method_info;
285 internal ISourceFile _source_file;
286 private readonly int _token;
288 private SourceBlock _implicit_block;
290 public SourceMethod (int token, MethodInfo method_info, ISourceFile source_file)
293 this._method_info = method_info;
294 this._source_file = source_file;
297 internal SourceMethod (int token)
301 this._implicit_block = new SourceBlock (this, 0);
304 public void SetSourceRange (ISourceFile sourceFile,
305 int startLine, int startColumn,
306 int endLine, int endColumn)
308 _source_file = sourceFile;
309 _implicit_block._start = new SourceLine (startLine, startColumn);
310 _implicit_block._end = new SourceLine (endLine, endColumn);
314 public void StartBlock (ISourceBlock block)
316 _block_stack.Push (block);
319 public void EndBlock (int endOffset) {
320 SourceBlock block = (SourceBlock) _block_stack.Pop ();
322 block._end = new SourceLine (endOffset);
324 if (_block_stack.Count > 0) {
325 ISourceBlock parent = (ISourceBlock) _block_stack.Peek ();
327 parent.AddBlock (block);
331 _block_hash.Add (block.ID, block);
334 public void SetBlockRange (int BlockID, int startOffset, int endOffset)
336 SourceBlock block = (SourceBlock) _block_hash [BlockID];
337 ((SourceLine) block.Start)._offset = startOffset;
338 ((SourceLine) block.End)._offset = endOffset;
341 public ISourceBlock CurrentBlock {
343 if (_block_stack.Count > 0)
344 return (ISourceBlock) _block_stack.Peek ();
346 return _implicit_block;
350 // interface ISourceMethod
352 public ISourceLine[] Lines {
354 ISourceLine[] retval = new ISourceLine [_lines.Count];
355 _lines.CopyTo (retval);
360 public void AddLine (ISourceLine line)
365 public ISourceBlock[] Blocks {
367 ISourceBlock[] retval = new ISourceBlock [_blocks.Count];
368 _blocks.CopyTo (retval);
373 public ILocalVariable[] Locals {
375 return _implicit_block.Locals;
379 public void AddLocal (ILocalVariable local)
381 _implicit_block.AddLocal (local);
384 public MethodInfo MethodInfo {
390 public ISourceFile SourceFile {
402 public ISourceLine Start {
404 return _implicit_block.Start;
408 public ISourceLine End {
410 return _implicit_block.End;
415 protected SourceMethod current_method = null;
416 private readonly string assembly_filename = null;
419 // Interface IMonoSymbolWriter
422 public MonoSymbolWriter (string filename)
424 this.assembly_filename = filename;
426 this.methods = new Hashtable ();
427 this.sources = new Hashtable ();
428 this.orphant_methods = new ArrayList ();
429 this.locals = new ArrayList ();
432 public void Close () {
433 if (assembly == null)
434 assembly = Assembly.LoadFrom (assembly_filename);
438 CreateDwarfFile (output_filename);
441 public void CloseNamespace () {
444 // Create and return a new IMonoSymbolDocumentWriter.
445 public ISymbolDocumentWriter DefineDocument (string url,
450 return new MonoSymbolDocumentWriter (url);
453 public void DefineField (
456 FieldAttributes attributes,
458 SymAddressKind addrKind,
465 public void DefineGlobalVariable (
467 FieldAttributes attributes,
469 SymAddressKind addrKind,
476 public void DefineLocalVariable (string name,
477 FieldAttributes attributes,
479 SymAddressKind addrKind,
486 if (current_method == null)
489 int token = current_method.Token;
491 LocalVariable local_info = new LocalVariable (name, signature, token, addr1);
493 current_method.CurrentBlock.AddLocal (local_info);
494 locals.Add (local_info);
497 public void DefineParameter (string name,
498 ParameterAttributes attributes,
500 SymAddressKind addrKind,
505 throw new NotSupportedException ();
508 public void DefineSequencePoints (ISymbolDocumentWriter document,
515 SourceLine source_line = new SourceLine (offsets [0], lines [0], columns [0]);
517 if (current_method != null)
518 current_method.AddLine (source_line);
521 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
523 this.output_filename = filename;
526 public void OpenMethod (SymbolToken symbol_token)
528 int token = symbol_token.GetToken ();
530 if (methods.ContainsKey (token))
531 methods.Remove (token);
533 current_method = new SourceMethod (token);
535 methods.Add (token, current_method);
538 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
539 int startLine, int startColumn,
540 ISymbolDocumentWriter endDoc,
541 int endLine, int endColumn)
543 if (current_method == null)
546 if ((startDoc == null) || (endDoc == null))
547 throw new NullReferenceException ();
549 if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
550 throw new NotSupportedException ("both startDoc and endDoc must be of type "
551 + "MonoSymbolDocumentWriter");
553 if (!startDoc.Equals (endDoc))
554 throw new NotSupportedException ("startDoc and endDoc must be the same");
556 string source_file = ((MonoSymbolDocumentWriter) startDoc).FileName;
557 SourceFile source_info;
559 if (sources.ContainsKey (source_file))
560 source_info = (SourceFile) sources [source_file];
562 source_info = new SourceFile (source_file);
563 sources.Add (source_file, source_info);
566 current_method.SetSourceRange (source_info, startLine, startColumn,
569 source_info.AddMethod (current_method);
572 public void CloseMethod () {
573 current_method = null;
576 public void OpenNamespace (string name)
580 public int OpenScope (int startOffset)
582 if (current_method == null)
585 ISourceBlock block = new SourceBlock (current_method, startOffset);
586 current_method.StartBlock (block);
591 public void CloseScope (int endOffset) {
592 if (current_method == null)
595 current_method.EndBlock (endOffset);
598 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
600 if (current_method == null)
603 current_method.SetBlockRange (scopeID, startOffset, endOffset);
606 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
610 public void SetUnderlyingWriter (IntPtr underlyingWriter)
612 throw new NotSupportedException ();
615 public void SetUserEntryPoint (SymbolToken entryMethod)
619 public void UsingNamespace (string fullName)
624 // MonoSymbolWriter implementation
626 protected void WriteLocal (DwarfFileWriter.Die parent_die, ILocalVariable local)
628 DwarfFileWriter.DieMethodVariable die;
630 die = new DwarfFileWriter.DieMethodVariable (parent_die, local);
633 protected void WriteBlock (DwarfFileWriter.Die parent_die, ISourceBlock block)
635 DwarfFileWriter.DieLexicalBlock die;
637 die = new DwarfFileWriter.DieLexicalBlock (parent_die, block);
639 foreach (ILocalVariable local in block.Locals)
640 WriteLocal (die, local);
642 foreach (ISourceBlock subblock in block.Blocks)
643 WriteBlock (die, subblock);
646 protected void WriteMethod (DwarfFileWriter.DieCompileUnit parent_die, ISourceMethod method)
648 DwarfFileWriter.DieSubProgram die;
650 die = new DwarfFileWriter.DieSubProgram (parent_die, method);
652 foreach (ILocalVariable local in method.Locals)
653 WriteLocal (die, local);
655 foreach (ISourceBlock block in method.Blocks)
656 WriteBlock (die, block);
659 protected void WriteSource (DwarfFileWriter writer, ISourceFile source)
661 DwarfFileWriter.CompileUnit compile_unit = new DwarfFileWriter.CompileUnit (
662 writer, source.FileName);
664 DwarfFileWriter.DieCompileUnit die = new DwarfFileWriter.DieCompileUnit (compile_unit);
666 foreach (ISourceMethod method in source.Methods)
667 WriteMethod (die, method);
671 [MethodImplAttribute(MethodImplOptions.InternalCall)]
672 internal extern static Type get_local_type_from_sig (Assembly module, byte[] sig);
674 [MethodImplAttribute(MethodImplOptions.InternalCall)]
675 internal extern static MethodInfo get_method (Assembly module, int token);
677 protected void DoFixups (Assembly assembly)
679 foreach (SourceMethod method in methods.Values) {
680 method._method_info = get_method (assembly, method.Token);
682 if (method.SourceFile == null)
683 orphant_methods.Add (method);
686 foreach (LocalVariable local in locals) {
687 byte[] signature = local.Signature;
689 Type type = get_local_type_from_sig (assembly, signature);
691 ((LocalVariable) local)._type = type;
695 protected void CreateDwarfFile (string filename)
697 DwarfFileWriter writer = new DwarfFileWriter (filename);
699 foreach (ISourceFile source in sources.Values)
700 WriteSource (writer, source);
702 if (orphant_methods.Count > 0) {
703 SourceFile source = new SourceFile ("<unknown>");
705 foreach (SourceMethod orphant in orphant_methods) {
706 orphant._source_file = source;
707 source.AddMethod (orphant);
710 WriteSource (writer, source);