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
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);
58 internal class SourceBlock
60 static private int next_index;
61 private readonly int _index;
63 public SourceBlock (SourceMethod method, LineNumberEntry start, LineNumberEntry end)
65 this._method = method;
68 this._index = ++next_index;
71 internal SourceBlock (SourceMethod method, int startOffset)
73 this._method = method;
74 this._start_offset = startOffset;
75 this._index = ++next_index;
78 public override string ToString ()
80 return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
83 private readonly SourceMethod _method;
84 private ArrayList _blocks = new ArrayList ();
85 internal LineNumberEntry _start = LineNumberEntry.Null;
86 internal LineNumberEntry _end = LineNumberEntry.Null;
87 internal int _start_offset, _end_offset;
90 internal void SetSourceRange (int startLine, int endLine)
92 _start = new LineNumberEntry (startLine, _start_offset);
93 _end = new LineNumberEntry (endLine, _end_offset);
97 private ArrayList _locals = new ArrayList ();
99 public SourceMethod SourceMethod {
105 public SourceBlock[] Blocks {
107 SourceBlock[] retval = new SourceBlock [_blocks.Count];
108 _blocks.CopyTo (retval);
113 public void AddBlock (SourceBlock block)
118 public bool HasSource {
124 public LineNumberEntry Start {
130 public LineNumberEntry End {
142 public LocalVariableEntry[] Locals {
144 LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
145 _locals.CopyTo (retval);
150 public void AddLocal (LocalVariableEntry local)
156 internal class SourceMethod
158 private ArrayList _lines = new ArrayList ();
159 private ArrayList _blocks = new ArrayList ();
160 private Hashtable _block_hash = new Hashtable ();
161 private Stack _block_stack = new Stack ();
163 internal readonly MethodBase _method_base;
164 internal SourceFile _source_file;
167 private SourceBlock _implicit_block;
169 public SourceMethod (MethodBase method_base, SourceFile source_file)
172 this._source_file = source_file;
175 internal SourceMethod (MethodBase method_base)
177 this._method_base = method_base;
179 this._implicit_block = new SourceBlock (this, 0);
182 public void SetSourceRange (SourceFile sourceFile,
183 int startLine, int startColumn,
184 int endLine, int endColumn)
186 _source_file = sourceFile;
187 _implicit_block.SetSourceRange (startLine, endLine);
190 public void StartBlock (SourceBlock block)
192 _block_stack.Push (block);
195 public void EndBlock (int endOffset) {
196 SourceBlock block = (SourceBlock) _block_stack.Pop ();
198 block._end_offset = endOffset;
200 if (_block_stack.Count > 0) {
201 SourceBlock parent = (SourceBlock) _block_stack.Peek ();
203 parent.AddBlock (block);
207 _block_hash.Add (block.ID, block);
210 public void SetBlockRange (int BlockID, int startOffset, int endOffset)
212 SourceBlock block = (SourceBlock) _block_hash [BlockID];
213 block._start_offset = startOffset;
214 block._end_offset = endOffset;
217 public SourceBlock CurrentBlock {
219 if (_block_stack.Count > 0)
220 return (SourceBlock) _block_stack.Peek ();
222 return _implicit_block;
226 public LineNumberEntry[] Lines {
228 LineNumberEntry[] retval = new LineNumberEntry [_lines.Count];
229 _lines.CopyTo (retval);
234 public void AddLine (LineNumberEntry line)
239 public SourceBlock[] Blocks {
241 SourceBlock[] retval = new SourceBlock [_blocks.Count];
242 _blocks.CopyTo (retval);
247 public LocalVariableEntry[] Locals {
249 return _implicit_block.Locals;
253 public void AddLocal (LocalVariableEntry local)
255 _implicit_block.AddLocal (local);
258 public MethodBase MethodBase {
264 public string FullName {
266 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
270 public Type ReturnType {
272 if (_method_base is MethodInfo)
273 return ((MethodInfo)_method_base).ReturnType;
274 else if (_method_base is ConstructorInfo)
275 return _method_base.DeclaringType;
277 throw new NotSupportedException ();
281 public ParameterInfo[] Parameters {
283 if (_method_base == null)
284 return new ParameterInfo [0];
286 ParameterInfo [] retval = _method_base.GetParameters ();
288 return new ParameterInfo [0];
294 public SourceFile SourceFile {
305 throw new NotSupportedException ();
309 public bool HasSource {
311 return _implicit_block.HasSource && (_source_file != null);
315 public LineNumberEntry Start {
317 return _implicit_block.Start;
321 public LineNumberEntry End {
323 return _implicit_block.End;
328 public class MonoSymbolWriter : IMonoSymbolWriter
330 protected ModuleBuilder module_builder;
331 protected ArrayList locals = null;
332 protected ArrayList orphant_methods = null;
333 protected ArrayList methods = null;
334 protected Hashtable sources = null;
335 private ArrayList mbuilder_array = null;
337 internal SourceMethod[] Methods {
339 SourceMethod[] retval = new SourceMethod [methods.Count];
340 methods.CopyTo (retval);
345 internal SourceFile[] Sources {
347 SourceFile[] retval = new SourceFile [sources.Count];
348 sources.Values.CopyTo (retval, 0);
353 private SourceMethod current_method = null;
356 // Interface IMonoSymbolWriter
359 public MonoSymbolWriter (ModuleBuilder mb, ArrayList mbuilder_array)
361 this.module_builder = mb;
362 this.methods = new ArrayList ();
363 this.sources = new Hashtable ();
364 this.orphant_methods = new ArrayList ();
365 this.locals = new ArrayList ();
366 this.mbuilder_array = mbuilder_array;
371 throw new InvalidOperationException ();
374 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
376 DoFixups (assembly_builder);
378 return CreateOutput (assembly_builder);
381 public void CloseNamespace () {
384 // Create and return a new IMonoSymbolDocumentWriter.
385 public ISymbolDocumentWriter DefineDocument (string url,
390 return new MonoSymbolDocumentWriter (url);
393 public void DefineField (
396 FieldAttributes attributes,
398 SymAddressKind addrKind,
403 throw new NotSupportedException ();
406 public void DefineGlobalVariable (
408 FieldAttributes attributes,
410 SymAddressKind addrKind,
415 throw new NotSupportedException ();
418 public void DefineLocalVariable (string name,
419 FieldAttributes attributes,
421 SymAddressKind addrKind,
428 if (current_method == null)
431 current_method.AddLocal (new LocalVariableEntry (name, attributes, signature));
434 public void DefineParameter (string name,
435 ParameterAttributes attributes,
437 SymAddressKind addrKind,
442 throw new NotSupportedException ();
445 public void DefineSequencePoints (ISymbolDocumentWriter document,
452 if (current_method == null)
455 LineNumberEntry source_line = new LineNumberEntry (lines [0], offsets [0]);
457 if (current_method != null)
458 current_method.AddLine (source_line);
461 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
463 throw new NotSupportedException ();
466 public void OpenMethod (SymbolToken symbol_token)
468 int token = symbol_token.GetToken ();
470 if ((token & 0xff000000) != 0x06000000)
471 throw new ArgumentException ();
473 int index = (token & 0xffffff) - 1;
475 MethodBase mb = (MethodBase) mbuilder_array [index];
477 current_method = new SourceMethod (mb);
479 methods.Add (current_method);
482 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
483 int startLine, int startColumn,
484 ISymbolDocumentWriter endDoc,
485 int endLine, int endColumn)
487 if (current_method == null)
490 if ((startDoc == null) || (endDoc == null))
491 throw new NullReferenceException ();
493 if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
494 throw new NotSupportedException ("both startDoc and endDoc must be of type "
495 + "MonoSymbolDocumentWriter");
497 if (!startDoc.Equals (endDoc))
498 throw new NotSupportedException ("startDoc and endDoc must be the same");
500 string source_file = ((MonoSymbolDocumentWriter) startDoc).FileName;
501 SourceFile source_info;
503 if (sources.ContainsKey (source_file))
504 source_info = (SourceFile) sources [source_file];
506 source_info = new SourceFile (source_file);
507 sources.Add (source_file, source_info);
510 current_method.SetSourceRange (source_info, startLine, startColumn,
513 source_info.AddMethod (current_method);
516 public void CloseMethod () {
517 current_method = null;
520 public void OpenNamespace (string name)
522 throw new NotSupportedException ();
525 public int OpenScope (int startOffset)
527 if (current_method == null)
530 SourceBlock block = new SourceBlock (current_method, startOffset);
531 current_method.StartBlock (block);
536 public void CloseScope (int endOffset) {
537 if (current_method == null)
540 current_method.EndBlock (endOffset);
543 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
545 if (current_method == null)
548 current_method.SetBlockRange (scopeID, startOffset, endOffset);
551 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
553 throw new NotSupportedException ();
556 public void SetUnderlyingWriter (IntPtr underlyingWriter)
558 throw new NotSupportedException ();
561 public void SetUserEntryPoint (SymbolToken entryMethod)
563 throw new NotSupportedException ();
566 public void UsingNamespace (string fullName)
568 throw new NotSupportedException ();
572 // MonoSymbolWriter implementation
574 protected void DoFixups (Assembly assembly)
576 foreach (SourceMethod method in methods) {
577 if (method._method_base is MethodBuilder) {
578 MethodBuilder mb = (MethodBuilder) method._method_base;
579 method._token = mb.GetToken ().Token;
580 } else if (method._method_base is ConstructorBuilder) {
581 ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
582 method._token = cb.GetToken ().Token;
584 throw new NotSupportedException ();
586 if (method.SourceFile == null)
587 orphant_methods.Add (method);
591 protected byte[] CreateOutput (Assembly assembly)
593 MonoSymbolFile file = new MonoSymbolFile ();
595 foreach (SourceMethod method in Methods) {
596 if (!method.HasSource) {
597 Console.WriteLine ("INGORING METHOD: {0}", method);
601 SourceFileEntry source = file.DefineSource (method.SourceFile.FileName);
603 source.DefineMethod (method.MethodBase, method.Token, method.Locals,
604 method.Lines, method.Start.Row, method.End.Row);
607 return file.CreateSymbolFile ();