2002-09-14 Martin Baulig <martin@gnome.org>
[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 : ISourceFile
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                 // interface ISourceFile
39
40                 public string FileName {
41                         get {
42                                 return _file_name;
43                         }
44                 }
45
46                 public ISourceMethod[] Methods {
47                         get {
48                                 ISourceMethod[] retval = new ISourceMethod [_methods.Count];
49                                 _methods.CopyTo (retval);
50                                 return retval;
51                         }
52                 }
53
54                 public void AddMethod (ISourceMethod method)
55                 {
56                         _methods.Add (method);
57                 }
58         }
59
60         internal class SourceBlock : ISourceBlock
61         {
62                 static private int next_index;
63                 private readonly int _index;
64
65                 public SourceBlock (ISourceMethod method, ISourceLine start, ISourceLine end)
66                 {
67                         this._method = method;
68                         this._start = start;
69                         this._end = end;
70                         this._index = ++next_index;
71                 }
72
73                 internal SourceBlock (ISourceMethod method, int startOffset)
74                 {
75                         this._method = method;
76                         this._start = new SourceLine (startOffset);
77                         this._index = ++next_index;
78                 }
79
80                 public override string ToString ()
81                 {
82                         return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
83                 }
84
85                 private readonly ISourceMethod _method;
86                 private ArrayList _blocks = new ArrayList ();
87                 internal ISourceLine _start;
88                 internal ISourceLine _end;
89
90                 private ArrayList _locals = new ArrayList ();
91
92                 public ISourceMethod SourceMethod {
93                         get {
94                                 return _method;
95                         }
96                 }
97
98                 public ISourceBlock[] Blocks {
99                         get {
100                                 ISourceBlock[] retval = new ISourceBlock [_blocks.Count];
101                                 _blocks.CopyTo (retval);
102                                 return retval;
103                         }
104                 }
105
106                 public void AddBlock (ISourceBlock block)
107                 {
108                         _blocks.Add (block);
109                 }
110
111                 public ISourceLine Start {
112                         get {
113                                 return _start;
114                         }
115                 }
116
117                 public ISourceLine End {
118                         get {
119                                 return _end;
120                         }
121                 }
122
123                 public int ID {
124                         get {
125                                 return _index;
126                         }
127                 }
128
129                 public ILocalVariable[] Locals {
130                         get {
131                                 ILocalVariable[] retval = new ILocalVariable [_locals.Count];
132                                 _locals.CopyTo (retval);
133                                 return retval;
134                         }
135                 }
136
137                 public void AddLocal (ILocalVariable local)
138                 {
139                         _locals.Add (local);
140                 }
141         }
142
143         internal class SourceLine : ISourceLine
144         {
145                 public SourceLine (int row, int column)
146                         : this (0, row, column)
147                 {
148                         this._type = SourceOffsetType.OFFSET_NONE;
149                 }
150
151                 public SourceLine (int offset, int row, int column)
152                 {
153                         this._offset = offset;
154                         this._row = row;
155                         this._column = column;
156                         this._type = SourceOffsetType.OFFSET_IL;
157                 }
158
159                 internal SourceLine (int offset)
160                         : this (offset, 0, 0)
161                 { }
162
163                 public override string ToString ()
164                 {
165                         return "SourceLine (" + _offset + "@" + _row + ":" + _column + ")";
166                 }
167
168                 internal SourceOffsetType _type;
169                 internal int _offset;
170                 internal int _row;
171                 internal int _column;
172
173                 // interface ISourceLine
174
175                 public SourceOffsetType OffsetType {
176                         get {
177                                 return _type;
178                         }
179                 }
180
181                 public int Offset {
182                         get {
183                                 return _offset;
184                         }
185                 }
186
187                 public int Row {
188                         get {
189                                 return _row;
190                         }
191                 }
192
193                 public int Column {
194                         get {
195                                 return _column;
196                         }
197                 }
198         }
199
200         internal class Variable : IVariable
201         {
202                 public Variable (string name, ITypeHandle handle, ISourceMethod method, int index)
203                         : this (name, handle, method, index, null)
204                 { }
205
206                 public Variable (string name, ITypeHandle handle, ISourceMethod method,
207                                  int index, ISourceLine line)
208                 {
209                         this._name = name;
210                         this._handle = handle;
211                         this._method = method;
212                         this._line = line;
213                         this._index = index;
214                 }
215
216                 private readonly string _name;
217                 private readonly ITypeHandle _handle;
218                 private readonly ISourceMethod _method;
219                 private readonly ISourceLine _line;
220                 private readonly int _index;
221
222                 // interface IVariable
223
224                 public string Name {
225                         get {
226                                 return _name;
227                         }
228                 }
229
230                 public ISourceMethod Method {
231                         get {
232                                 return _method;
233                         }
234                 }
235
236                 public int Index {
237                         get {
238                                 return _index;
239                         }
240                 }
241
242                 public ITypeHandle TypeHandle {
243                         get {
244                                 return _handle;
245                         }
246                 }
247
248                 public ISourceLine Line {
249                         get {
250                                 return _line;
251                         }
252                 }
253         }
254
255         internal class LocalVariable : Variable, ILocalVariable
256         {
257                 public LocalVariable (string name, ITypeHandle handle, ISourceMethod method,
258                                       int index, ISourceLine line)
259                         : base (name, handle, method, index, line)
260                 { }
261
262                 public override string ToString ()
263                 {
264                         return "LocalVariable (" + Index + "," + Name + ")";
265                 }
266         }
267
268         internal class SourceMethod : ISourceMethod
269         {
270                 private ArrayList _lines = new ArrayList ();
271                 private ArrayList _blocks = new ArrayList ();
272                 private Hashtable _block_hash = new Hashtable ();
273                 private Stack _block_stack = new Stack ();
274
275                 internal readonly MethodBase _method_base;
276                 internal ISourceFile _source_file;
277                 internal int _token;
278
279                 private SourceBlock _implicit_block;
280
281                 public SourceMethod (MethodBase method_base, ISourceFile source_file)
282                         : this (method_base)
283                 {
284                         this._source_file = source_file;
285                 }
286
287                 internal SourceMethod (MethodBase method_base)
288                 {
289                         this._method_base = method_base;
290
291                         this._implicit_block = new SourceBlock (this, 0);
292                 }
293
294                 public void SetSourceRange (ISourceFile sourceFile,
295                                             int startLine, int startColumn,
296                                             int endLine, int endColumn)
297                 {
298                         _source_file = sourceFile;
299                         _implicit_block._start = new SourceLine (startLine, startColumn);
300                         _implicit_block._end = new SourceLine (endLine, endColumn);
301                 }
302
303
304                 public void StartBlock (ISourceBlock block)
305                 {
306                         _block_stack.Push (block);
307                 }
308
309                 public void EndBlock (int endOffset) {
310                         SourceBlock block = (SourceBlock) _block_stack.Pop ();
311
312                         block._end = new SourceLine (endOffset);
313
314                         if (_block_stack.Count > 0) {
315                                 ISourceBlock parent = (ISourceBlock) _block_stack.Peek ();
316
317                                 parent.AddBlock (block);
318                         } else
319                                 _blocks.Add (block);
320
321                         _block_hash.Add (block.ID, block);
322                 }
323
324                 public void SetBlockRange (int BlockID, int startOffset, int endOffset)
325                 {
326                         SourceBlock block = (SourceBlock) _block_hash [BlockID];
327                         ((SourceLine) block.Start)._offset = startOffset;
328                         ((SourceLine) block.End)._offset = endOffset;
329                 }
330
331                 public ISourceBlock CurrentBlock {
332                         get {
333                                 if (_block_stack.Count > 0)
334                                         return (ISourceBlock) _block_stack.Peek ();
335                                 else
336                                         return _implicit_block;
337                         }
338                 }
339
340                 // interface ISourceMethod
341
342                 public ISourceLine[] Lines {
343                         get {
344                                 ISourceLine[] retval = new ISourceLine [_lines.Count];
345                                 _lines.CopyTo (retval);
346                                 return retval;
347                         }
348                 }
349
350                 public void AddLine (ISourceLine line)
351                 {
352                         _lines.Add (line);
353                 }
354
355                 public ISourceBlock[] Blocks {
356                         get {
357                                 ISourceBlock[] retval = new ISourceBlock [_blocks.Count];
358                                 _blocks.CopyTo (retval);
359                                 return retval;
360                         }
361                 }
362
363                 public ILocalVariable[] Locals {
364                         get {
365                                 return _implicit_block.Locals;
366                         }
367                 }
368
369                 public void AddLocal (ILocalVariable local)
370                 {
371                         _implicit_block.AddLocal (local);
372                 }
373
374                 public MethodBase MethodBase {
375                         get {
376                                 return _method_base;
377                         }
378                 }
379
380                 public string FullName {
381                         get {
382                                 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
383                         }
384                 }
385
386                 public Type ReturnType {
387                         get {
388                                 if (_method_base is MethodInfo)
389                                         return ((MethodInfo)_method_base).ReturnType;
390                                 else if (_method_base is ConstructorInfo)
391                                         return _method_base.DeclaringType;
392                                 else
393                                         throw new NotSupportedException ();
394                         }
395                 }
396
397                 public ParameterInfo[] Parameters {
398                         get {
399                                 if (_method_base == null)
400                                         return new ParameterInfo [0];
401
402                                 ParameterInfo [] retval = _method_base.GetParameters ();
403                                 if (retval == null)
404                                         return new ParameterInfo [0];
405                                 else
406                                         return retval;
407                         }
408                 }
409
410                 public ISourceFile SourceFile {
411                         get {
412                                 return _source_file;
413                         }
414                 }
415
416                 public int Token {
417                         get {
418                                 if (_token != 0)
419                                         return _token;
420                                 else
421                                         throw new NotSupportedException ();
422                         }
423                 }
424
425                 public ISourceLine Start {
426                         get {
427                                 return _implicit_block.Start;
428                         }
429                 }
430
431                 public ISourceLine End {
432                         get {
433                                 return _implicit_block.End;
434                         }
435                 }
436         }
437
438         public class MonoSymbolWriter : IMonoSymbolWriter
439         {
440                 protected Assembly assembly;
441                 protected ModuleBuilder module_builder;
442                 protected ArrayList locals = null;
443                 protected ArrayList orphant_methods = null;
444                 protected ArrayList methods = null;
445                 protected Hashtable sources = null;
446                 private ArrayList mbuilder_array = null;
447
448                 internal ISourceMethod[] Methods {
449                         get {
450                                 ISourceMethod[] retval = new ISourceMethod [methods.Count];
451                                 methods.CopyTo (retval);
452                                 return retval;
453                         }
454                 }
455
456                 internal ISourceFile[] Sources {
457                         get {
458                                 ISourceFile[] retval = new ISourceFile [sources.Count];
459                                 sources.Values.CopyTo (retval, 0);
460                                 return retval;
461                         }
462                 }
463
464                 protected SourceMethod current_method = null;
465                 private string assembly_filename = null;
466                 private string output_filename = null;
467
468                 //
469                 // Interface IMonoSymbolWriter
470                 //
471
472                 public MonoSymbolWriter (ModuleBuilder mb, string filename, ArrayList mbuilder_array)
473                 {
474                         this.assembly_filename = filename;
475                         this.module_builder = mb;
476                         this.methods = new ArrayList ();
477                         this.sources = new Hashtable ();
478                         this.orphant_methods = new ArrayList ();
479                         this.locals = new ArrayList ();
480                         this.mbuilder_array = mbuilder_array;
481                 }
482
483                 public void Close () {
484                         if (assembly == null)
485                                 assembly = Assembly.LoadFrom (assembly_filename);
486
487                         DoFixups (assembly);
488
489                         CreateOutput (assembly);
490                 }
491
492                 public void CloseNamespace () {
493                 }
494
495                 // Create and return a new IMonoSymbolDocumentWriter.
496                 public ISymbolDocumentWriter DefineDocument (string url,
497                                                              Guid language,
498                                                              Guid languageVendor,
499                                                              Guid documentType)
500                 {
501                         return new MonoSymbolDocumentWriter (url);
502                 }
503
504                 public void DefineField (
505                         SymbolToken parent,
506                         string name,
507                         FieldAttributes attributes,
508                         byte[] signature,
509                         SymAddressKind addrKind,
510                         int addr1,
511                         int addr2,
512                         int addr3)
513                 {
514                 }
515
516                 public void DefineGlobalVariable (
517                         string name,
518                         FieldAttributes attributes,
519                         byte[] signature,
520                         SymAddressKind addrKind,
521                         int addr1,
522                         int addr2,
523                         int addr3)
524                 {
525                 }
526
527                 public void DefineLocalVariable (string name,
528                                                  FieldAttributes attributes,
529                                                  byte[] signature,
530                                                  SymAddressKind addrKind,
531                                                  int addr1,
532                                                  int addr2,
533                                                  int addr3,
534                                                  int startOffset,
535                                                  int endOffset)
536                 {
537                         throw new NotSupportedException ();
538                 }
539
540                 public void DefineLocalVariable (string name,
541                                                  LocalBuilder local,
542                                                  FieldAttributes attributes,
543                                                  int position,
544                                                  int startOffset,
545                                                  int endOffset)
546                 {
547                 }
548
549
550                 public void DefineParameter (string name,
551                                              ParameterAttributes attributes,
552                                              int sequence,
553                                              SymAddressKind addrKind,
554                                              int addr1,
555                                              int addr2,
556                                              int addr3)
557                 {
558                         throw new NotSupportedException ();
559                 }
560
561                 public void DefineSequencePoints (ISymbolDocumentWriter document,
562                                                   int[] offsets,
563                                                   int[] lines,
564                                                   int[] columns,
565                                                   int[] endLines,
566                                                   int[] endColumns)
567                 {
568                         SourceLine source_line = new SourceLine (offsets [0], lines [0], columns [0]);
569
570                         if (current_method != null)
571                                 current_method.AddLine (source_line);
572                 }
573
574                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
575                 {
576                         throw new NotSupportedException ();
577                 }
578
579                 public void Initialize (string assembly_filename, string filename, string[] args)
580                 {
581                         this.output_filename = filename;
582                         this.assembly_filename = assembly_filename;
583                 }
584
585                 public void OpenMethod (SymbolToken symbol_token)
586                 {
587                         int token = symbol_token.GetToken ();
588
589                         if ((token & 0xff000000) != 0x06000000)
590                                 throw new ArgumentException ();
591
592                         int index = (token & 0xffffff) - 1;
593
594                         MethodBuilder mb = (MethodBuilder) mbuilder_array [index];
595
596                         current_method = new SourceMethod (mb);
597
598                         methods.Add (current_method);
599                 }
600
601                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
602                                                   int startLine, int startColumn,
603                                                   ISymbolDocumentWriter endDoc,
604                                                   int endLine, int endColumn)
605                 {
606                         if (current_method == null)
607                                 return;
608
609                         if ((startDoc == null) || (endDoc == null))
610                                 throw new NullReferenceException ();
611
612                         if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
613                                 throw new NotSupportedException ("both startDoc and endDoc must be of type "
614                                                                  + "MonoSymbolDocumentWriter");
615
616                         if (!startDoc.Equals (endDoc))
617                                 throw new NotSupportedException ("startDoc and endDoc must be the same");
618
619                         string source_file = ((MonoSymbolDocumentWriter) startDoc).FileName;
620                         SourceFile source_info;
621
622                         if (sources.ContainsKey (source_file))
623                                 source_info = (SourceFile) sources [source_file];
624                         else {
625                                 source_info = new SourceFile (source_file);
626                                 sources.Add (source_file, source_info);
627                         }
628
629                         current_method.SetSourceRange (source_info, startLine, startColumn,
630                                                        endLine, endColumn);
631
632                         source_info.AddMethod (current_method);
633                 }
634
635                 public void CloseMethod () {
636                         current_method = null;
637                 }
638
639                 public void OpenNamespace (string name)
640                 {
641                 }
642
643                 public int OpenScope (int startOffset)
644                 {
645                         if (current_method == null)
646                                 return 0;
647
648                         ISourceBlock block = new SourceBlock (current_method, startOffset);
649                         current_method.StartBlock (block);
650
651                         return block.ID;
652                 }
653
654                 public void CloseScope (int endOffset) {
655                         if (current_method == null)
656                                 return;
657
658                         current_method.EndBlock (endOffset);
659                 }
660
661                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
662                 {
663                         if (current_method == null)
664                                 return;
665
666                         current_method.SetBlockRange (scopeID, startOffset, endOffset);
667                 }
668
669                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
670                 {
671                 }
672
673                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
674                 {
675                         throw new NotSupportedException ();
676                 }
677
678                 public void SetUserEntryPoint (SymbolToken entryMethod)
679                 {
680                 }
681
682                 public void UsingNamespace (string fullName)
683                 {
684                 }
685
686                 //
687                 // MonoSymbolWriter implementation
688                 //
689                 protected void DoFixups (Assembly assembly)
690                 {
691                         foreach (SourceMethod method in methods) {
692                                 if (method._method_base is MethodBuilder) {
693                                         MethodBuilder mb = (MethodBuilder) method._method_base;
694                                         method._token = mb.GetToken ().Token;
695                                 } else if (method._method_base is ConstructorBuilder) {
696                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
697                                         method._token = cb.GetToken ().Token;
698                                 } else
699                                         throw new NotSupportedException ();
700
701                                 if (method.SourceFile == null)
702                                         orphant_methods.Add (method);
703                         }
704                 }
705
706                 protected void CreateOutput (Assembly assembly)
707                 {
708                         using (MonoSymbolTableWriter writer = new MonoSymbolTableWriter (output_filename))
709                                 writer.WriteSymbolTable (this);
710                 }
711         }
712 }
713