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.Runtime.CompilerServices;
36 using System.Collections;
39 namespace Mono.CompilerServices.SymbolWriter
41 public interface ISourceFile
43 SourceFileEntry Entry {
48 public interface ICompileUnit
50 CompileUnitEntry Entry {
55 public interface ISourceMethod
70 public class MonoSymbolWriter
72 ArrayList methods = null;
73 ArrayList sources = null;
74 ArrayList comp_units = null;
75 protected readonly MonoSymbolFile file;
76 string filename = null;
78 LineNumberEntry [] current_method_lines;
79 int current_method_lines_pos = 0;
81 private SourceMethod current_method = null;
83 public MonoSymbolWriter (string filename)
85 this.methods = new ArrayList ();
86 this.sources = new ArrayList ();
87 this.comp_units = new ArrayList ();
88 this.file = new MonoSymbolFile ();
90 this.filename = filename + ".mdb";
92 this.current_method_lines = new LineNumberEntry [50];
95 public MonoSymbolFile SymbolFile {
99 public void CloseNamespace ()
102 public void DefineLocalVariable (int index, string name)
104 if (current_method == null)
107 current_method.AddLocal (index, name);
110 public void DefineCapturedLocal (int scope_id, string name, string captured_name)
112 file.DefineCapturedVariable (scope_id, name, captured_name,
113 CapturedVariable.CapturedKind.Local);
116 public void DefineCapturedParameter (int scope_id, string name, string captured_name)
118 file.DefineCapturedVariable (scope_id, name, captured_name,
119 CapturedVariable.CapturedKind.Parameter);
122 public void DefineCapturedThis (int scope_id, string captured_name)
124 file.DefineCapturedVariable (scope_id, "this", captured_name,
125 CapturedVariable.CapturedKind.This);
128 public void DefineCapturedScope (int scope_id, int id, string captured_name)
130 file.DefineCapturedScope (scope_id, id, captured_name);
133 public void DefineScopeVariable (int scope, int index)
135 if (current_method == null)
138 current_method.AddScopeVariable (scope, index);
141 public void MarkSequencePoint (int offset, int file, int line, int column)
143 if (current_method == null)
144 throw new ArgumentNullException ();
146 if (current_method_lines_pos == current_method_lines.Length) {
147 LineNumberEntry [] tmp = current_method_lines;
148 current_method_lines = new LineNumberEntry [current_method_lines.Length * 2];
149 Array.Copy (tmp, current_method_lines, current_method_lines_pos);
152 current_method_lines [current_method_lines_pos++] = new LineNumberEntry (file, line, offset);
155 public void MarkSequencePoint (int offset, int file, int line, int column, bool is_hidden)
157 if (current_method == null)
160 if (current_method_lines_pos == current_method_lines.Length) {
161 LineNumberEntry [] tmp = current_method_lines;
162 current_method_lines = new LineNumberEntry [current_method_lines.Length * 2];
163 Array.Copy (tmp, current_method_lines, current_method_lines_pos);
166 current_method_lines [current_method_lines_pos++] = new LineNumberEntry (
167 file, line, offset, is_hidden);
170 public void OpenMethod (ICompileUnit file, ISourceMethod method)
172 SourceMethod source = new SourceMethod (file, method);
174 current_method = source;
175 methods.Add (current_method);
178 public void SetRealMethodName (string name)
180 current_method.RealMethodName = name;
183 public void SetCompilerGenerated ()
185 current_method.SetCompilerGenerated ();
188 public void CloseMethod ()
190 if (current_method == null) {
191 Console.WriteLine ("Some clown is calling CloseMethod() while " +
192 "current_method == null: {0}", Environment.StackTrace);
196 current_method.SetLineNumbers (
197 current_method_lines, current_method_lines_pos);
198 current_method_lines_pos = 0;
200 current_method = null;
203 public SourceFileEntry DefineDocument (string url)
205 SourceFileEntry entry = new SourceFileEntry (file, url);
210 public SourceFileEntry DefineDocument (string url, byte[] guid, byte[] checksum)
212 SourceFileEntry entry = new SourceFileEntry (file, url, guid, checksum);
217 public CompileUnitEntry DefineCompilationUnit (SourceFileEntry source)
219 CompileUnitEntry entry = new CompileUnitEntry (file, source);
220 comp_units.Add (entry);
224 public int DefineNamespace (string name, CompileUnitEntry unit,
225 string[] using_clauses, int parent)
227 if ((unit == null) || (using_clauses == null))
228 throw new NullReferenceException ();
230 return unit.DefineNamespace (name, using_clauses, parent);
233 public int OpenScope (int start_offset)
235 if (current_method == null)
238 current_method.StartBlock (CodeBlockEntry.Type.Lexical, start_offset);
242 public void CloseScope (int end_offset)
244 if (current_method == null)
247 current_method.EndBlock (end_offset);
250 public void OpenCompilerGeneratedBlock (int start_offset)
252 if (current_method == null)
255 current_method.StartBlock (CodeBlockEntry.Type.CompilerGenerated,
259 public void CloseCompilerGeneratedBlock (int end_offset)
261 if (current_method == null)
264 current_method.EndBlock (end_offset);
267 public void StartIteratorBody (int start_offset)
269 current_method.StartBlock (CodeBlockEntry.Type.IteratorBody,
273 public void EndIteratorBody (int end_offset)
275 current_method.EndBlock (end_offset);
278 public void StartIteratorDispatcher (int start_offset)
280 current_method.StartBlock (CodeBlockEntry.Type.IteratorDispatcher,
284 public void EndIteratorDispatcher (int end_offset)
286 current_method.EndBlock (end_offset);
289 public void DefineAnonymousScope (int id)
291 file.DefineAnonymousScope (id);
294 public void WriteSymbolFile (Guid guid)
296 foreach (SourceMethod method in methods)
297 method.DefineMethod (file);
300 // We mmap the file, so unlink the previous version since it may be in use
301 File.Delete (filename);
303 // We can safely ignore
305 using (FileStream fs = new FileStream (filename, FileMode.Create, FileAccess.Write)) {
306 file.CreateSymbolFile (guid, fs);
310 protected class SourceMethod
312 LineNumberEntry [] lines;
313 private ArrayList _locals;
314 private ArrayList _blocks;
315 private ArrayList _scope_vars;
316 private Stack _block_stack;
317 private string _real_name;
318 private ISourceMethod _method;
319 private ICompileUnit _comp_unit;
320 private MethodEntry.Flags _method_flags;
322 public SourceMethod (ICompileUnit comp_unit, ISourceMethod method)
324 this._comp_unit = comp_unit;
325 this._method = method;
328 public void StartBlock (CodeBlockEntry.Type type, int start_offset)
330 if (_block_stack == null)
331 _block_stack = new Stack ();
333 _blocks = new ArrayList ();
335 int parent = CurrentBlock != null ? CurrentBlock.Index : -1;
337 CodeBlockEntry block = new CodeBlockEntry (
338 _blocks.Count + 1, parent, type, start_offset);
340 _block_stack.Push (block);
344 public void EndBlock (int end_offset)
346 CodeBlockEntry block = (CodeBlockEntry) _block_stack.Pop ();
347 block.Close (end_offset);
350 public CodeBlockEntry[] Blocks {
353 return new CodeBlockEntry [0];
355 CodeBlockEntry[] retval = new CodeBlockEntry [_blocks.Count];
356 _blocks.CopyTo (retval, 0);
361 public CodeBlockEntry CurrentBlock {
363 if ((_block_stack != null) && (_block_stack.Count > 0))
364 return (CodeBlockEntry) _block_stack.Peek ();
370 public LineNumberEntry[] Lines {
376 public LocalVariableEntry[] Locals {
379 return new LocalVariableEntry [0];
381 LocalVariableEntry[] retval =
382 new LocalVariableEntry [_locals.Count];
383 _locals.CopyTo (retval, 0);
389 public void AddLocal (int index, string name)
392 _locals = new ArrayList ();
393 int block_idx = CurrentBlock != null ? CurrentBlock.Index : 0;
394 _locals.Add (new LocalVariableEntry (index, name, block_idx));
397 public ScopeVariable[] ScopeVariables {
399 if (_scope_vars == null)
400 return new ScopeVariable [0];
402 ScopeVariable[] retval = new ScopeVariable [_scope_vars.Count];
403 _scope_vars.CopyTo (retval);
408 public void AddScopeVariable (int scope, int index)
410 if (_scope_vars == null)
411 _scope_vars = new ArrayList ();
413 new ScopeVariable (scope, index));
416 public string RealMethodName {
417 get { return _real_name; }
418 set { _real_name = value; }
421 public void SetCompilerGenerated ()
423 _method_flags |= MethodEntry.Flags.IsCompilerGenerated;
426 public ICompileUnit SourceFile {
427 get { return _comp_unit; }
430 public ISourceMethod Method {
431 get { return _method; }
434 internal void SetLineNumbers (LineNumberEntry [] lns, int count)
436 lines = new LineNumberEntry [count];
437 Array.Copy (lns, lines, count);
440 public void DefineMethod (MonoSymbolFile file)
442 MethodEntry entry = new MethodEntry (
443 file, _comp_unit.Entry, _method.Token, ScopeVariables,
444 Locals, Lines, Blocks, RealMethodName, _method_flags,
445 _method.NamespaceID);
447 file.AddMethod (entry);