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