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 ISourceMethod
63 public class MonoSymbolWriter
65 protected ArrayList locals
= null;
66 protected ArrayList methods
= null;
67 protected ArrayList sources
= null;
68 protected readonly MonoSymbolFile file
;
69 private string filename
= null;
71 LineNumberEntry
[] current_method_lines
;
72 int current_method_lines_pos
= 0;
74 internal ISourceFile
[] Sources
{
76 ISourceFile
[] retval
= new ISourceFile
[sources
.Count
];
77 sources
.CopyTo (retval
, 0);
82 private SourceMethod current_method
= null;
85 // Interface IMonoSymbolWriter
88 public MonoSymbolWriter (string filename
)
90 this.methods
= new ArrayList ();
91 this.sources
= new ArrayList ();
92 this.locals
= new ArrayList ();
93 this.file
= new MonoSymbolFile ();
95 this.filename
= filename
+ ".mdb";
97 this.current_method_lines
= new LineNumberEntry
[50];
100 public void CloseNamespace ()
103 public void DefineLocalVariable (string name
, byte[] signature
)
105 if (current_method
== null)
108 current_method
.AddLocal (name
, signature
);
111 public void MarkSequencePoint (int offset
, int line
, int column
)
113 if (current_method
== null)
116 if (current_method_lines_pos
== current_method_lines
.Length
) {
117 LineNumberEntry
[] tmp
= current_method_lines
;
118 current_method_lines
= new LineNumberEntry
[current_method_lines
.Length
* 2];
119 Array
.Copy (tmp
, current_method_lines
, current_method_lines_pos
);
122 current_method_lines
[current_method_lines_pos
++] = new LineNumberEntry (line
, offset
);
125 public void OpenMethod (ISourceFile file
, ISourceMethod method
,
126 int startRow
, int startColumn
,
127 int endRow
, int endColumn
)
129 SourceMethod source
= new SourceMethod (
130 file
, method
, startRow
, startColumn
, endRow
, endColumn
);
132 current_method
= source
;
133 methods
.Add (current_method
);
136 public void CloseMethod ()
138 current_method
.SetLineNumbers (
139 current_method_lines
, current_method_lines_pos
);
140 current_method_lines_pos
= 0;
142 current_method
= null;
145 public SourceFileEntry
DefineDocument (string url
)
147 SourceFileEntry entry
= new SourceFileEntry (file
, url
);
152 public int DefineNamespace (string name
, SourceFileEntry source
,
153 string[] using_clauses
, int parent
)
155 if ((source
== null) || (using_clauses
== null))
156 throw new NullReferenceException ();
158 return source
.DefineNamespace (name
, using_clauses
, parent
);
161 public int OpenScope (int startOffset
)
163 if (current_method
== null)
166 current_method
.StartBlock (startOffset
);
170 public void CloseScope (int endOffset
)
172 if (current_method
== null)
175 current_method
.EndBlock (endOffset
);
178 protected byte[] CreateOutput (Guid guid
)
180 foreach (SourceMethod method
in methods
) {
181 method
.SourceFile
.Entry
.DefineMethod (
182 method
.Method
.Name
, method
.Method
.Token
,
183 method
.Locals
, method
.Lines
, method
.Blocks
,
184 method
.Start
.Row
, method
.End
.Row
,
185 method
.Method
.NamespaceID
);
188 return file
.CreateSymbolFile (guid
);
191 public void WriteSymbolFile (Guid guid
)
193 using (FileStream stream
= new FileStream (
194 filename
, FileMode
.Create
, FileAccess
.Write
)) {
195 byte[] data
= CreateOutput (guid
);
196 stream
.Write (data
, 0, data
.Length
);
200 protected class SourceMethod
202 LineNumberEntry
[] lines
;
203 private ArrayList _locals
;
204 private ArrayList _blocks
;
205 private Stack _block_stack
;
206 private int next_block_id
= 0;
207 private ISourceMethod _method
;
208 private ISourceFile _file
;
209 private LineNumberEntry _start
, _end
;
211 private LexicalBlockEntry _implicit_block
;
213 public SourceMethod (ISourceFile file
, ISourceMethod method
,
214 int startLine
, int startColumn
,
215 int endLine
, int endColumn
)
218 this._method
= method
;
220 this._start
= new LineNumberEntry (startLine
, 0);
221 this._end
= new LineNumberEntry (endLine
, 0);
223 this._implicit_block
= new LexicalBlockEntry (0, 0);
226 public void StartBlock (int startOffset
)
228 LexicalBlockEntry block
= new LexicalBlockEntry (
229 ++next_block_id
, startOffset
);
230 if (_block_stack
== null)
231 _block_stack
= new Stack ();
232 _block_stack
.Push (block
);
234 _blocks
= new ArrayList ();
238 public void EndBlock (int endOffset
)
240 LexicalBlockEntry block
=
241 (LexicalBlockEntry
) _block_stack
.Pop ();
243 block
.Close (endOffset
);
246 public LexicalBlockEntry
[] Blocks
{
249 return new LexicalBlockEntry
[0];
251 LexicalBlockEntry
[] retval
=
252 new LexicalBlockEntry
[_blocks
.Count
];
253 _blocks
.CopyTo (retval
, 0);
259 public LexicalBlockEntry CurrentBlock
{
261 if ((_block_stack
!= null) && (_block_stack
.Count
> 0))
262 return (LexicalBlockEntry
) _block_stack
.Peek ();
264 return _implicit_block
;
268 public LineNumberEntry
[] Lines
{
274 public LocalVariableEntry
[] Locals
{
277 return new LocalVariableEntry
[0];
279 LocalVariableEntry
[] retval
=
280 new LocalVariableEntry
[_locals
.Count
];
281 _locals
.CopyTo (retval
, 0);
287 public void AddLocal (string name
, byte[] signature
)
290 _locals
= new ArrayList ();
291 _locals
.Add (new LocalVariableEntry (
292 name
, signature
, CurrentBlock
.Index
));
295 public ISourceFile SourceFile
{
296 get { return _file; }
299 public ISourceMethod Method
{
300 get { return _method; }
303 public LineNumberEntry Start
{
304 get { return _start; }
307 public LineNumberEntry End
{
312 // Passes on the lines from the MonoSymbolWriter. This method is
313 // free to mutate the lns array, and it does.
315 internal void SetLineNumbers (LineNumberEntry
[] lns
, int count
)
319 int last_offset
= -1;
321 for (int i
= 0; i
< count
; i
++) {
322 LineNumberEntry line
= lns
[i
];
324 if (line
.Offset
> last_offset
) {
326 lns
[pos
++] = new LineNumberEntry (
327 last_row
, last_offset
);
330 last_offset
= line
.Offset
;
331 } else if (line
.Row
> last_row
) {
336 lines
= new LineNumberEntry
[count
+ ((last_row
>= 0) ? 1 : 0)];
337 Array
.Copy (lns
, lines
, pos
);
339 lines
[pos
] = new LineNumberEntry (
340 last_row
, last_offset
);