2 // Mono.CSharp.Debugger/MonoSymbolWriter.cs
5 // Martin Baulig (martin@ximian.com)
7 // This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter
10 // (C) 2002 Ximian, Inc. http://www.ximian.com
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Reflection;
36 using System.Reflection.Emit;
37 using System.Runtime.CompilerServices;
38 using System.Diagnostics.SymbolStore;
39 using System.Collections;
42 namespace Mono.CSharp.Debugger
44 internal class SourceFile : SourceFileEntry, ISymbolDocumentWriter
46 private ArrayList _methods = new ArrayList ();
48 public SourceFile (MonoSymbolFile file, string filename)
49 : base (file, filename)
52 public new SourceMethod[] Methods {
54 SourceMethod[] retval = new SourceMethod [_methods.Count];
55 _methods.CopyTo (retval);
60 public void AddMethod (SourceMethod method)
62 _methods.Add (method);
65 void ISymbolDocumentWriter.SetCheckSum (Guid algorithmId, byte[] checkSum)
67 throw new NotSupportedException ();
70 void ISymbolDocumentWriter.SetSource (byte[] source)
72 throw new NotSupportedException ();
76 internal class SourceMethod
78 LineNumberEntry [] lines;
79 private ArrayList _locals;
80 private ArrayList _blocks;
81 private Stack _block_stack;
82 private int next_block_id = 0;
84 internal readonly MethodBase _method_base;
85 internal SourceFile _source_file;
87 private int _namespace_id;
88 private LineNumberEntry _start, _end;
89 private MonoSymbolFile _file;
91 private LexicalBlockEntry _implicit_block;
93 internal SourceMethod (MonoSymbolFile file, SourceFile source_file,
94 int startLine, int startColumn, int endLine, int endColumn,
95 MethodBase method_base, int namespace_id)
98 this._method_base = method_base;
99 this._source_file = source_file;
100 this._namespace_id = namespace_id;
102 this._start = new LineNumberEntry (startLine, 0);
103 this._end = new LineNumberEntry (endLine, 0);
105 this._implicit_block = new LexicalBlockEntry (0, 0);
108 public void StartBlock (int startOffset)
110 LexicalBlockEntry block = new LexicalBlockEntry (++next_block_id, startOffset);
111 if (_block_stack == null)
112 _block_stack = new Stack ();
113 _block_stack.Push (block);
115 _blocks = new ArrayList ();
119 public void EndBlock (int endOffset)
121 LexicalBlockEntry block = (LexicalBlockEntry) _block_stack.Pop ();
123 block.Close (endOffset);
126 public LexicalBlockEntry[] Blocks {
129 return new LexicalBlockEntry [0];
131 LexicalBlockEntry[] retval = new LexicalBlockEntry [_blocks.Count];
132 _blocks.CopyTo (retval, 0);
138 public LexicalBlockEntry CurrentBlock {
140 if ((_block_stack != null) && (_block_stack.Count > 0))
141 return (LexicalBlockEntry) _block_stack.Peek ();
143 return _implicit_block;
147 public LineNumberEntry[] Lines {
153 public LocalVariableEntry[] Locals {
156 return new LocalVariableEntry [0];
158 LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
159 _locals.CopyTo (retval, 0);
165 public void AddLocal (string name, FieldAttributes attributes, byte[] signature)
168 _locals = new ArrayList ();
169 _locals.Add (new LocalVariableEntry (name, attributes, signature, CurrentBlock.Index));
172 public MethodBase MethodBase {
178 public string FullName {
180 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
184 public Type ReturnType {
186 if (_method_base is MethodInfo)
187 return ((MethodInfo)_method_base).ReturnType;
188 else if (_method_base is ConstructorInfo)
189 return _method_base.DeclaringType;
191 throw new NotSupportedException ();
195 public ParameterInfo[] Parameters {
197 if (_method_base == null)
198 return new ParameterInfo [0];
200 ParameterInfo [] retval = _method_base.GetParameters ();
202 return new ParameterInfo [0];
208 public SourceFile SourceFile {
219 throw new NotSupportedException ();
223 public bool HasSource {
225 return _source_file != null;
229 public LineNumberEntry Start {
235 public LineNumberEntry End {
241 public int NamespaceID {
243 return _namespace_id;
248 // Passes on the lines from the MonoSymbolWriter. This method is
249 // free to mutate the lns array, and it does.
251 internal void SetLineNumbers (LineNumberEntry [] lns, int count)
255 int last_offset = -1;
257 for (int i = 0; i < count; i++) {
258 LineNumberEntry line = lns [i];
260 if (line.Offset > last_offset) {
262 lns [pos++] = new LineNumberEntry (last_row, last_offset);
265 last_offset = line.Offset;
266 } else if (line.Row > last_row) {
271 lines = new LineNumberEntry [count + ((last_row >= 0) ? 1 : 0)];
272 Array.Copy (lns, lines, pos);
274 lines [pos] = new LineNumberEntry (last_row, last_offset);
278 public class MonoSymbolWriter : IMonoSymbolWriter
280 protected ModuleBuilder module_builder;
281 protected ArrayList locals = null;
282 protected ArrayList orphant_methods = null;
283 protected ArrayList methods = null;
284 protected Hashtable sources = null;
285 private MonoSymbolFile file = null;
287 LineNumberEntry [] current_method_lines;
288 int current_method_lines_pos = 0;
290 internal SourceMethod[] Methods {
292 SourceMethod[] retval = new SourceMethod [methods.Count];
293 methods.CopyTo (retval);
298 internal SourceFile[] Sources {
300 SourceFile[] retval = new SourceFile [sources.Count];
301 sources.Values.CopyTo (retval, 0);
306 private SourceMethod current_method = null;
309 // Interface IMonoSymbolWriter
312 public MonoSymbolWriter (ModuleBuilder mb)
314 this.module_builder = mb;
315 this.methods = new ArrayList ();
316 this.sources = new Hashtable ();
317 this.orphant_methods = new ArrayList ();
318 this.locals = new ArrayList ();
319 this.file = new MonoSymbolFile ();
321 this.current_method_lines = new LineNumberEntry [50];
326 throw new InvalidOperationException ();
329 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
331 DoFixups (assembly_builder);
333 return CreateOutput (assembly_builder);
336 public void CloseNamespace () {
339 // Create and return a new IMonoSymbolDocumentWriter.
340 public ISymbolDocumentWriter DefineDocument (string url,
345 if (sources.ContainsKey (url))
346 return (ISymbolDocumentWriter)sources [url];
347 SourceFile source_info = new SourceFile (file, url);
348 sources.Add (url, source_info);
352 public void DefineField (
355 FieldAttributes attributes,
357 SymAddressKind addrKind,
362 throw new NotSupportedException ();
365 public void DefineGlobalVariable (
367 FieldAttributes attributes,
369 SymAddressKind addrKind,
374 throw new NotSupportedException ();
377 public void DefineLocalVariable (string name,
378 FieldAttributes attributes,
380 SymAddressKind addrKind,
387 if (current_method == null)
390 current_method.AddLocal (name, attributes, signature);
393 public void DefineParameter (string name,
394 ParameterAttributes attributes,
396 SymAddressKind addrKind,
401 throw new NotSupportedException ();
404 public void DefineSequencePoints (ISymbolDocumentWriter document,
411 throw new NotSupportedException ();
414 public void MarkSequencePoint (int offset, int line, int column)
416 if (current_method == null)
419 if (current_method_lines_pos == current_method_lines.Length) {
420 LineNumberEntry [] tmp = current_method_lines;
421 current_method_lines = new LineNumberEntry [current_method_lines.Length * 2];
422 Array.Copy (tmp, current_method_lines, current_method_lines_pos);
425 current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset);
428 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
430 throw new NotSupportedException ();
433 public void OpenMethod (SymbolToken symbol_token)
435 throw new NotSupportedException ();
438 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
439 int startLine, int startColumn,
440 ISymbolDocumentWriter endDoc,
441 int endLine, int endColumn)
443 throw new NotSupportedException ();
446 public void OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
447 int endLine, int endColumn, MethodBase method, int namespace_id)
449 SourceFile source_info = document as SourceFile;
451 if ((source_info == null) || (method == null))
452 throw new NullReferenceException ();
454 current_method = new SourceMethod (file, source_info, startLine, startColumn,
455 endLine, endColumn, method, namespace_id);
457 methods.Add (current_method);
458 source_info.AddMethod (current_method);
461 public void CloseMethod ()
463 current_method.SetLineNumbers (current_method_lines, current_method_lines_pos);
464 current_method_lines_pos = 0;
466 current_method = null;
469 public int DefineNamespace (string name, ISymbolDocumentWriter document,
470 string[] using_clauses, int parent)
472 if ((document == null) || (using_clauses == null))
473 throw new NullReferenceException ();
474 if (!(document is SourceFile))
475 throw new ArgumentException ();
477 SourceFile source_info = (SourceFile) document;
479 return source_info.DefineNamespace (name, using_clauses, parent);
482 public void OpenNamespace (string name)
484 throw new NotSupportedException ();
487 public int OpenScope (int startOffset)
489 if (current_method == null)
492 current_method.StartBlock (startOffset);
496 public void CloseScope (int endOffset)
498 if (current_method == null)
501 current_method.EndBlock (endOffset);
504 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
506 throw new NotSupportedException ();
509 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
511 throw new NotSupportedException ();
514 public void SetUnderlyingWriter (IntPtr underlyingWriter)
516 throw new NotSupportedException ();
519 public void SetUserEntryPoint (SymbolToken entryMethod)
521 throw new NotSupportedException ();
524 public void UsingNamespace (string fullName)
526 throw new NotSupportedException ();
530 // MonoSymbolWriter implementation
532 protected void DoFixups (Assembly assembly)
534 foreach (SourceMethod method in methods) {
535 if (method._method_base is MethodBuilder) {
536 MethodBuilder mb = (MethodBuilder) method._method_base;
537 method._token = mb.GetToken ().Token;
538 } else if (method._method_base is ConstructorBuilder) {
539 ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
540 method._token = cb.GetToken ().Token;
542 throw new NotSupportedException ();
544 if (method.SourceFile == null)
545 orphant_methods.Add (method);
549 protected byte[] CreateOutput (Assembly assembly)
551 foreach (SourceMethod method in Methods) {
552 if (!method.HasSource) {
553 Console.WriteLine ("INGORING METHOD: {0}", method);
557 method.SourceFile.DefineMethod (
558 method.MethodBase, method.Token, method.Locals,
559 method.Lines, method.Blocks, method.Start.Row, method.End.Row,
563 return file.CreateSymbolFile ();