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 internal class SourceFile : ISymbolDocumentWriter
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 public string FileName {
44 public SourceMethod[] Methods {
46 SourceMethod[] retval = new SourceMethod [_methods.Count];
47 _methods.CopyTo (retval);
52 public void AddMethod (SourceMethod method)
54 _methods.Add (method);
57 void ISymbolDocumentWriter.SetCheckSum (Guid algorithmId, byte[] checkSum)
59 throw new NotSupportedException ();
62 void ISymbolDocumentWriter.SetSource (byte[] source)
64 throw new NotSupportedException ();
68 internal class SourceBlock
70 static private int next_index;
71 private readonly int _index;
73 public SourceBlock (SourceMethod method, LineNumberEntry start, LineNumberEntry end)
75 this._method = method;
78 this._index = ++next_index;
81 internal SourceBlock (SourceMethod method, int startOffset)
83 this._method = method;
84 this._start_offset = startOffset;
85 this._index = ++next_index;
88 public override string ToString ()
90 return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
93 private readonly SourceMethod _method;
94 private ArrayList _blocks = new ArrayList ();
95 internal LineNumberEntry _start = LineNumberEntry.Null;
96 internal LineNumberEntry _end = LineNumberEntry.Null;
97 internal int _start_offset, _end_offset;
100 internal void SetSourceRange (int startLine, int endLine)
102 _start = new LineNumberEntry (startLine, _start_offset);
103 _end = new LineNumberEntry (endLine, _end_offset);
107 private ArrayList _locals = new ArrayList ();
109 public SourceMethod SourceMethod {
115 public SourceBlock[] Blocks {
117 SourceBlock[] retval = new SourceBlock [_blocks.Count];
118 _blocks.CopyTo (retval);
123 public void AddBlock (SourceBlock block)
128 public bool HasSource {
134 public LineNumberEntry Start {
140 public LineNumberEntry End {
152 public LocalVariableEntry[] Locals {
154 LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
155 _locals.CopyTo (retval);
160 public void AddLocal (LocalVariableEntry local)
166 internal class SourceMethod
168 private ArrayList _lines = new ArrayList ();
169 private ArrayList _blocks = new ArrayList ();
170 private Hashtable _block_hash = new Hashtable ();
171 private Stack _block_stack = new Stack ();
173 internal readonly MethodBase _method_base;
174 internal SourceFile _source_file;
177 private SourceBlock _implicit_block;
179 public SourceMethod (MethodBase method_base, SourceFile source_file)
182 this._source_file = source_file;
185 internal SourceMethod (MethodBase method_base)
187 this._method_base = method_base;
189 this._implicit_block = new SourceBlock (this, 0);
192 public void SetSourceRange (SourceFile sourceFile,
193 int startLine, int startColumn,
194 int endLine, int endColumn)
196 _source_file = sourceFile;
197 _implicit_block.SetSourceRange (startLine, endLine);
200 public void StartBlock (SourceBlock block)
202 _block_stack.Push (block);
205 public void EndBlock (int endOffset) {
206 SourceBlock block = (SourceBlock) _block_stack.Pop ();
208 block._end_offset = endOffset;
210 if (_block_stack.Count > 0) {
211 SourceBlock parent = (SourceBlock) _block_stack.Peek ();
213 parent.AddBlock (block);
217 _block_hash.Add (block.ID, block);
220 public void SetBlockRange (int BlockID, int startOffset, int endOffset)
222 SourceBlock block = (SourceBlock) _block_hash [BlockID];
223 block._start_offset = startOffset;
224 block._end_offset = endOffset;
227 public SourceBlock CurrentBlock {
229 if (_block_stack.Count > 0)
230 return (SourceBlock) _block_stack.Peek ();
232 return _implicit_block;
236 public LineNumberEntry[] Lines {
238 LineNumberEntry[] retval = new LineNumberEntry [_lines.Count];
239 _lines.CopyTo (retval);
244 public void AddLine (LineNumberEntry line)
249 public SourceBlock[] Blocks {
251 SourceBlock[] retval = new SourceBlock [_blocks.Count];
252 _blocks.CopyTo (retval);
257 public LocalVariableEntry[] Locals {
259 return _implicit_block.Locals;
263 public void AddLocal (LocalVariableEntry local)
265 _implicit_block.AddLocal (local);
268 public MethodBase MethodBase {
274 public string FullName {
276 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
280 public Type ReturnType {
282 if (_method_base is MethodInfo)
283 return ((MethodInfo)_method_base).ReturnType;
284 else if (_method_base is ConstructorInfo)
285 return _method_base.DeclaringType;
287 throw new NotSupportedException ();
291 public ParameterInfo[] Parameters {
293 if (_method_base == null)
294 return new ParameterInfo [0];
296 ParameterInfo [] retval = _method_base.GetParameters ();
298 return new ParameterInfo [0];
304 public SourceFile SourceFile {
315 throw new NotSupportedException ();
319 public bool HasSource {
321 return _implicit_block.HasSource && (_source_file != null);
325 public LineNumberEntry Start {
327 return _implicit_block.Start;
331 public LineNumberEntry End {
333 return _implicit_block.End;
338 public class MonoSymbolWriter : IMonoSymbolWriter
340 protected ModuleBuilder module_builder;
341 protected ArrayList locals = null;
342 protected ArrayList orphant_methods = null;
343 protected ArrayList methods = null;
344 protected Hashtable sources = null;
345 private ArrayList mbuilder_array = null;
347 internal SourceMethod[] Methods {
349 SourceMethod[] retval = new SourceMethod [methods.Count];
350 methods.CopyTo (retval);
355 internal SourceFile[] Sources {
357 SourceFile[] retval = new SourceFile [sources.Count];
358 sources.Values.CopyTo (retval, 0);
363 private SourceMethod current_method = null;
366 // Interface IMonoSymbolWriter
369 public MonoSymbolWriter (ModuleBuilder mb, ArrayList mbuilder_array)
371 this.module_builder = mb;
372 this.methods = new ArrayList ();
373 this.sources = new Hashtable ();
374 this.orphant_methods = new ArrayList ();
375 this.locals = new ArrayList ();
376 this.mbuilder_array = mbuilder_array;
381 throw new InvalidOperationException ();
384 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
386 DoFixups (assembly_builder);
388 return CreateOutput (assembly_builder);
391 public void CloseNamespace () {
394 // Create and return a new IMonoSymbolDocumentWriter.
395 public ISymbolDocumentWriter DefineDocument (string url,
400 SourceFile source_info = new SourceFile (url);
401 sources.Add (url, source_info);
405 public void DefineField (
408 FieldAttributes attributes,
410 SymAddressKind addrKind,
415 throw new NotSupportedException ();
418 public void DefineGlobalVariable (
420 FieldAttributes attributes,
422 SymAddressKind addrKind,
427 throw new NotSupportedException ();
430 public void DefineLocalVariable (string name,
431 FieldAttributes attributes,
433 SymAddressKind addrKind,
440 if (current_method == null)
443 current_method.AddLocal (new LocalVariableEntry (name, attributes, signature));
446 public void DefineParameter (string name,
447 ParameterAttributes attributes,
449 SymAddressKind addrKind,
454 throw new NotSupportedException ();
457 public void DefineSequencePoints (ISymbolDocumentWriter document,
464 throw new NotSupportedException ();
467 public void MarkSequencePoint (int offset, int line, int column)
469 if (current_method == null)
472 LineNumberEntry source_line = new LineNumberEntry (line, offset);
473 current_method.AddLine (source_line);
476 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
478 throw new NotSupportedException ();
481 public void OpenMethod (SymbolToken symbol_token)
483 int token = symbol_token.GetToken ();
485 if ((token & 0xff000000) != 0x06000000)
486 throw new ArgumentException ();
488 int index = (token & 0xffffff) - 1;
490 MethodBase mb = (MethodBase) mbuilder_array [index];
492 current_method = new SourceMethod (mb);
494 methods.Add (current_method);
497 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
498 int startLine, int startColumn,
499 ISymbolDocumentWriter endDoc,
500 int endLine, int endColumn)
502 if (current_method == null)
504 if ((startDoc == null) || (endDoc == null))
505 throw new NullReferenceException ();
506 if (!(startDoc is SourceFile) || !(endDoc is SourceFile))
507 throw new ArgumentException ("both startDoc and endDoc must be created " +
508 "with DefineDocument()");
509 if (!startDoc.Equals (endDoc))
510 throw new ArgumentException ("startDoc and endDoc must be the same");
512 SourceFile source_info = (SourceFile) startDoc;
514 current_method.SetSourceRange (source_info, startLine, startColumn,
517 source_info.AddMethod (current_method);
520 public void CloseMethod () {
521 current_method = null;
524 public void OpenNamespace (string name)
526 throw new NotSupportedException ();
529 public int OpenScope (int startOffset)
531 if (current_method == null)
534 SourceBlock block = new SourceBlock (current_method, startOffset);
535 current_method.StartBlock (block);
540 public void CloseScope (int endOffset) {
541 if (current_method == null)
544 current_method.EndBlock (endOffset);
547 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
549 if (current_method == null)
552 current_method.SetBlockRange (scopeID, startOffset, endOffset);
555 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
557 throw new NotSupportedException ();
560 public void SetUnderlyingWriter (IntPtr underlyingWriter)
562 throw new NotSupportedException ();
565 public void SetUserEntryPoint (SymbolToken entryMethod)
567 throw new NotSupportedException ();
570 public void UsingNamespace (string fullName)
572 throw new NotSupportedException ();
576 // MonoSymbolWriter implementation
578 protected void DoFixups (Assembly assembly)
580 foreach (SourceMethod method in methods) {
581 if (method._method_base is MethodBuilder) {
582 MethodBuilder mb = (MethodBuilder) method._method_base;
583 method._token = mb.GetToken ().Token;
584 } else if (method._method_base is ConstructorBuilder) {
585 ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
586 method._token = cb.GetToken ().Token;
588 throw new NotSupportedException ();
590 if (method.SourceFile == null)
591 orphant_methods.Add (method);
595 protected byte[] CreateOutput (Assembly assembly)
597 MonoSymbolFile file = new MonoSymbolFile ();
599 foreach (SourceMethod method in Methods) {
600 if (!method.HasSource) {
601 Console.WriteLine ("INGORING METHOD: {0}", method);
605 SourceFileEntry source = file.DefineSource (method.SourceFile.FileName);
607 source.DefineMethod (method.MethodBase, method.Token, method.Locals,
608 method.Lines, method.Start.Row, method.End.Row);
611 return file.CreateSymbolFile ();