2003-02-08 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolWriter.cs
1 //
2 // System.Diagnostics.SymbolStore/MonoSymbolWriter.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@gnome.org)
6 //
7 // This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter
8 // interface.
9 //
10 // (C) 2002 Ximian, Inc.  http://www.ximian.com
11 //
12
13 using System;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Runtime.CompilerServices;
17 using System.Diagnostics.SymbolStore;
18 using System.Collections;
19 using System.IO;
20         
21 namespace Mono.CSharp.Debugger
22 {
23         internal class SourceFile : ISymbolDocumentWriter
24         {
25                 private ArrayList _methods = new ArrayList ();
26                 private string _file_name;
27
28                 public SourceFile (string filename)
29                 {
30                         this._file_name = filename;
31                 }
32
33                 public override string ToString ()
34                 {
35                         return _file_name;
36                 }
37
38                 public string FileName {
39                         get {
40                                 return _file_name;
41                         }
42                 }
43
44                 public SourceMethod[] Methods {
45                         get {
46                                 SourceMethod[] retval = new SourceMethod [_methods.Count];
47                                 _methods.CopyTo (retval);
48                                 return retval;
49                         }
50                 }
51
52                 public void AddMethod (SourceMethod method)
53                 {
54                         _methods.Add (method);
55                 }
56
57                 void ISymbolDocumentWriter.SetCheckSum (Guid algorithmId, byte[] checkSum)
58                 {
59                         throw new NotSupportedException ();
60                 }
61
62                 void ISymbolDocumentWriter.SetSource (byte[] source)
63                 {
64                         throw new NotSupportedException ();
65                 }
66         }
67
68         internal class SourceBlock
69         {
70                 static private int next_index;
71                 private readonly int _index;
72
73                 public SourceBlock (SourceMethod method, LineNumberEntry start, LineNumberEntry end)
74                 {
75                         this._method = method;
76                         this._start = start;
77                         this._end = end;
78                         this._index = ++next_index;
79                 }
80
81                 internal SourceBlock (SourceMethod method, int startOffset)
82                 {
83                         this._method = method;
84                         this._start_offset = startOffset;
85                         this._index = ++next_index;
86                 }
87
88                 public override string ToString ()
89                 {
90                         return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
91                 }
92
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;
98                 bool _has_source;
99
100                 internal void SetSourceRange (int startLine, int endLine)
101                 {
102                         _start = new LineNumberEntry (startLine, _start_offset);
103                         _end = new LineNumberEntry (endLine, _end_offset);
104                         _has_source = true;
105                 }
106
107                 private ArrayList _locals = new ArrayList ();
108
109                 public SourceMethod SourceMethod {
110                         get {
111                                 return _method;
112                         }
113                 }
114
115                 public SourceBlock[] Blocks {
116                         get {
117                                 SourceBlock[] retval = new SourceBlock [_blocks.Count];
118                                 _blocks.CopyTo (retval);
119                                 return retval;
120                         }
121                 }
122
123                 public void AddBlock (SourceBlock block)
124                 {
125                         _blocks.Add (block);
126                 }
127
128                 public bool HasSource {
129                         get {
130                                 return _has_source;
131                         }
132                 }
133
134                 public LineNumberEntry Start {
135                         get {
136                                 return _start;
137                         }
138                 }
139
140                 public LineNumberEntry End {
141                         get {
142                                 return _end;
143                         }
144                 }
145
146                 public int ID {
147                         get {
148                                 return _index;
149                         }
150                 }
151
152                 public LocalVariableEntry[] Locals {
153                         get {
154                                 LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
155                                 _locals.CopyTo (retval);
156                                 return retval;
157                         }
158                 }
159
160                 public void AddLocal (LocalVariableEntry local)
161                 {
162                         _locals.Add (local);
163                 }
164         }
165
166         internal class SourceMethod
167         {
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 ();
172
173                 internal readonly MethodBase _method_base;
174                 internal SourceFile _source_file;
175                 internal int _token;
176
177                 private SourceBlock _implicit_block;
178
179                 public SourceMethod (MethodBase method_base, SourceFile source_file)
180                         : this (method_base)
181                 {
182                         this._source_file = source_file;
183                 }
184
185                 internal SourceMethod (MethodBase method_base)
186                 {
187                         this._method_base = method_base;
188
189                         this._implicit_block = new SourceBlock (this, 0);
190                 }
191
192                 public void SetSourceRange (SourceFile sourceFile,
193                                             int startLine, int startColumn,
194                                             int endLine, int endColumn)
195                 {
196                         _source_file = sourceFile;
197                         _implicit_block.SetSourceRange (startLine, endLine);
198                 }
199
200                 public void StartBlock (SourceBlock block)
201                 {
202                         _block_stack.Push (block);
203                 }
204
205                 public void EndBlock (int endOffset) {
206                         SourceBlock block = (SourceBlock) _block_stack.Pop ();
207
208                         block._end_offset = endOffset;
209
210                         if (_block_stack.Count > 0) {
211                                 SourceBlock parent = (SourceBlock) _block_stack.Peek ();
212
213                                 parent.AddBlock (block);
214                         } else
215                                 _blocks.Add (block);
216
217                         _block_hash.Add (block.ID, block);
218                 }
219
220                 public void SetBlockRange (int BlockID, int startOffset, int endOffset)
221                 {
222                         SourceBlock block = (SourceBlock) _block_hash [BlockID];
223                         block._start_offset = startOffset;
224                         block._end_offset = endOffset;
225                 }
226
227                 public SourceBlock CurrentBlock {
228                         get {
229                                 if (_block_stack.Count > 0)
230                                         return (SourceBlock) _block_stack.Peek ();
231                                 else
232                                         return _implicit_block;
233                         }
234                 }
235
236                 public LineNumberEntry[] Lines {
237                         get {
238                                 LineNumberEntry[] retval = new LineNumberEntry [_lines.Count];
239                                 _lines.CopyTo (retval);
240                                 return retval;
241                         }
242                 }
243
244                 public void AddLine (LineNumberEntry line)
245                 {
246                         _lines.Add (line);
247                 }
248
249                 public SourceBlock[] Blocks {
250                         get {
251                                 SourceBlock[] retval = new SourceBlock [_blocks.Count];
252                                 _blocks.CopyTo (retval);
253                                 return retval;
254                         }
255                 }
256
257                 public LocalVariableEntry[] Locals {
258                         get {
259                                 return _implicit_block.Locals;
260                         }
261                 }
262
263                 public void AddLocal (LocalVariableEntry local)
264                 {
265                         _implicit_block.AddLocal (local);
266                 }
267
268                 public MethodBase MethodBase {
269                         get {
270                                 return _method_base;
271                         }
272                 }
273
274                 public string FullName {
275                         get {
276                                 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
277                         }
278                 }
279
280                 public Type ReturnType {
281                         get {
282                                 if (_method_base is MethodInfo)
283                                         return ((MethodInfo)_method_base).ReturnType;
284                                 else if (_method_base is ConstructorInfo)
285                                         return _method_base.DeclaringType;
286                                 else
287                                         throw new NotSupportedException ();
288                         }
289                 }
290
291                 public ParameterInfo[] Parameters {
292                         get {
293                                 if (_method_base == null)
294                                         return new ParameterInfo [0];
295
296                                 ParameterInfo [] retval = _method_base.GetParameters ();
297                                 if (retval == null)
298                                         return new ParameterInfo [0];
299                                 else
300                                         return retval;
301                         }
302                 }
303
304                 public SourceFile SourceFile {
305                         get {
306                                 return _source_file;
307                         }
308                 }
309
310                 public int Token {
311                         get {
312                                 if (_token != 0)
313                                         return _token;
314                                 else
315                                         throw new NotSupportedException ();
316                         }
317                 }
318
319                 public bool HasSource {
320                         get {
321                                 return _implicit_block.HasSource && (_source_file != null);
322                         }
323                 }
324
325                 public LineNumberEntry Start {
326                         get {
327                                 return _implicit_block.Start;
328                         }
329                 }
330
331                 public LineNumberEntry End {
332                         get {
333                                 return _implicit_block.End;
334                         }
335                 }
336         }
337
338         public class MonoSymbolWriter : IMonoSymbolWriter
339         {
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;
346
347                 internal SourceMethod[] Methods {
348                         get {
349                                 SourceMethod[] retval = new SourceMethod [methods.Count];
350                                 methods.CopyTo (retval);
351                                 return retval;
352                         }
353                 }
354
355                 internal SourceFile[] Sources {
356                         get {
357                                 SourceFile[] retval = new SourceFile [sources.Count];
358                                 sources.Values.CopyTo (retval, 0);
359                                 return retval;
360                         }
361                 }
362
363                 private SourceMethod current_method = null;
364
365                 //
366                 // Interface IMonoSymbolWriter
367                 //
368
369                 public MonoSymbolWriter (ModuleBuilder mb, ArrayList mbuilder_array)
370                 {
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;
377                 }
378
379                 public void Close ()
380                 {
381                         throw new InvalidOperationException ();
382                 }
383
384                 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
385                 {
386                         DoFixups (assembly_builder);
387
388                         return CreateOutput (assembly_builder);
389                 }
390
391                 public void CloseNamespace () {
392                 }
393
394                 // Create and return a new IMonoSymbolDocumentWriter.
395                 public ISymbolDocumentWriter DefineDocument (string url,
396                                                              Guid language,
397                                                              Guid languageVendor,
398                                                              Guid documentType)
399                 {
400                         SourceFile source_info = new SourceFile (url);
401                         sources.Add (url, source_info);
402                         return source_info;
403                 }
404
405                 public void DefineField (
406                         SymbolToken parent,
407                         string name,
408                         FieldAttributes attributes,
409                         byte[] signature,
410                         SymAddressKind addrKind,
411                         int addr1,
412                         int addr2,
413                         int addr3)
414                 {
415                         throw new NotSupportedException ();
416                 }
417
418                 public void DefineGlobalVariable (
419                         string name,
420                         FieldAttributes attributes,
421                         byte[] signature,
422                         SymAddressKind addrKind,
423                         int addr1,
424                         int addr2,
425                         int addr3)
426                 {
427                         throw new NotSupportedException ();
428                 }
429
430                 public void DefineLocalVariable (string name,
431                                                  FieldAttributes attributes,
432                                                  byte[] signature,
433                                                  SymAddressKind addrKind,
434                                                  int addr1,
435                                                  int addr2,
436                                                  int addr3,
437                                                  int startOffset,
438                                                  int endOffset)
439                 {
440                         if (current_method == null)
441                                 return;
442
443                         current_method.AddLocal (new LocalVariableEntry (name, attributes, signature));
444                 }
445
446                 public void DefineParameter (string name,
447                                              ParameterAttributes attributes,
448                                              int sequence,
449                                              SymAddressKind addrKind,
450                                              int addr1,
451                                              int addr2,
452                                              int addr3)
453                 {
454                         throw new NotSupportedException ();
455                 }
456
457                 public void DefineSequencePoints (ISymbolDocumentWriter document,
458                                                   int[] offsets,
459                                                   int[] lines,
460                                                   int[] columns,
461                                                   int[] endLines,
462                                                   int[] endColumns)
463                 {
464                         if (current_method == null)
465                                 return;
466
467                         LineNumberEntry source_line = new LineNumberEntry (lines [0], offsets [0]);
468
469                         if (current_method != null)
470                                 current_method.AddLine (source_line);
471                 }
472
473                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
474                 {
475                         throw new NotSupportedException ();
476                 }
477
478                 public void Initialize (string blah, string filename, string[] blah2)
479                 {
480                         throw new NotSupportedException ();
481                 }
482
483                 public void OpenMethod (SymbolToken symbol_token)
484                 {
485                         int token = symbol_token.GetToken ();
486
487                         if ((token & 0xff000000) != 0x06000000)
488                                 throw new ArgumentException ();
489
490                         int index = (token & 0xffffff) - 1;
491
492                         MethodBase mb = (MethodBase) mbuilder_array [index];
493
494                         current_method = new SourceMethod (mb);
495
496                         methods.Add (current_method);
497                 }
498
499                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
500                                                   int startLine, int startColumn,
501                                                   ISymbolDocumentWriter endDoc,
502                                                   int endLine, int endColumn)
503                 {
504                         if (current_method == null)
505                                 return;
506                         if ((startDoc == null) || (endDoc == null))
507                                 throw new NullReferenceException ();
508                         if (!(startDoc is SourceFile) || !(endDoc is SourceFile))
509                                 throw new ArgumentException ("both startDoc and endDoc must be created " +
510                                                              "with DefineDocument()");
511                         if (!startDoc.Equals (endDoc))
512                                 throw new ArgumentException ("startDoc and endDoc must be the same");
513
514                         SourceFile source_info = (SourceFile) startDoc;
515
516                         current_method.SetSourceRange (source_info, startLine, startColumn,
517                                                        endLine, endColumn);
518
519                         source_info.AddMethod (current_method);
520                 }
521
522                 public void CloseMethod () {
523                         current_method = null;
524                 }
525
526                 public void OpenNamespace (string name)
527                 {
528                         throw new NotSupportedException ();
529                 }
530
531                 public int OpenScope (int startOffset)
532                 {
533                         if (current_method == null)
534                                 return 0;
535
536                         SourceBlock block = new SourceBlock (current_method, startOffset);
537                         current_method.StartBlock (block);
538
539                         return block.ID;
540                 }
541
542                 public void CloseScope (int endOffset) {
543                         if (current_method == null)
544                                 return;
545
546                         current_method.EndBlock (endOffset);
547                 }
548
549                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
550                 {
551                         if (current_method == null)
552                                 return;
553
554                         current_method.SetBlockRange (scopeID, startOffset, endOffset);
555                 }
556
557                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
558                 {
559                         throw new NotSupportedException ();
560                 }
561
562                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
563                 {
564                         throw new NotSupportedException ();
565                 }
566
567                 public void SetUserEntryPoint (SymbolToken entryMethod)
568                 {
569                         throw new NotSupportedException ();
570                 }
571
572                 public void UsingNamespace (string fullName)
573                 {
574                         throw new NotSupportedException ();
575                 }
576
577                 //
578                 // MonoSymbolWriter implementation
579                 //
580                 protected void DoFixups (Assembly assembly)
581                 {
582                         foreach (SourceMethod method in methods) {
583                                 if (method._method_base is MethodBuilder) {
584                                         MethodBuilder mb = (MethodBuilder) method._method_base;
585                                         method._token = mb.GetToken ().Token;
586                                 } else if (method._method_base is ConstructorBuilder) {
587                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
588                                         method._token = cb.GetToken ().Token;
589                                 } else
590                                         throw new NotSupportedException ();
591
592                                 if (method.SourceFile == null)
593                                         orphant_methods.Add (method);
594                         }
595                 }
596
597                 protected byte[] CreateOutput (Assembly assembly)
598                 {
599                         MonoSymbolFile file = new MonoSymbolFile ();
600
601                         foreach (SourceMethod method in Methods) {
602                                 if (!method.HasSource) {
603                                         Console.WriteLine ("INGORING METHOD: {0}", method);
604                                         continue;
605                                 }
606
607                                 SourceFileEntry source = file.DefineSource (method.SourceFile.FileName);
608
609                                 source.DefineMethod (method.MethodBase, method.Token, method.Locals,
610                                                      method.Lines, method.Start.Row, method.End.Row);
611                         }
612
613                         return file.CreateSymbolFile ();
614                 }
615         }
616 }
617