2002-09-21 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
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                                 return _implicit_block.Start;
356                         }
357                 }
358
359                 public SourceLine End {
360                         get {
361                                 return _implicit_block.End;
362                         }
363                 }
364         }
365
366         public class MonoSymbolWriter : IMonoSymbolWriter
367         {
368                 protected Assembly assembly;
369                 protected ModuleBuilder module_builder;
370                 protected ArrayList locals = null;
371                 protected ArrayList orphant_methods = null;
372                 protected ArrayList methods = null;
373                 protected Hashtable sources = null;
374                 private ArrayList mbuilder_array = null;
375
376                 internal SourceMethod[] Methods {
377                         get {
378                                 SourceMethod[] retval = new SourceMethod [methods.Count];
379                                 methods.CopyTo (retval);
380                                 return retval;
381                         }
382                 }
383
384                 internal SourceFile[] Sources {
385                         get {
386                                 SourceFile[] retval = new SourceFile [sources.Count];
387                                 sources.Values.CopyTo (retval, 0);
388                                 return retval;
389                         }
390                 }
391
392                 private SourceMethod current_method = null;
393                 private string assembly_filename = null;
394                 private string output_filename = null;
395
396                 //
397                 // Interface IMonoSymbolWriter
398                 //
399
400                 public MonoSymbolWriter (ModuleBuilder mb, string filename, ArrayList mbuilder_array)
401                 {
402                         this.assembly_filename = filename;
403                         this.module_builder = mb;
404                         this.methods = new ArrayList ();
405                         this.sources = new Hashtable ();
406                         this.orphant_methods = new ArrayList ();
407                         this.locals = new ArrayList ();
408                         this.mbuilder_array = mbuilder_array;
409                 }
410
411                 public void Close () {
412                         if (assembly == null)
413                                 assembly = Assembly.LoadFrom (assembly_filename);
414
415                         DoFixups (assembly);
416
417                         CreateOutput (assembly);
418                 }
419
420                 public void CloseNamespace () {
421                 }
422
423                 // Create and return a new IMonoSymbolDocumentWriter.
424                 public ISymbolDocumentWriter DefineDocument (string url,
425                                                              Guid language,
426                                                              Guid languageVendor,
427                                                              Guid documentType)
428                 {
429                         return new MonoSymbolDocumentWriter (url);
430                 }
431
432                 public void DefineField (
433                         SymbolToken parent,
434                         string name,
435                         FieldAttributes attributes,
436                         byte[] signature,
437                         SymAddressKind addrKind,
438                         int addr1,
439                         int addr2,
440                         int addr3)
441                 {
442                         throw new NotSupportedException ();
443                 }
444
445                 public void DefineGlobalVariable (
446                         string name,
447                         FieldAttributes attributes,
448                         byte[] signature,
449                         SymAddressKind addrKind,
450                         int addr1,
451                         int addr2,
452                         int addr3)
453                 {
454                         throw new NotSupportedException ();
455                 }
456
457                 public void DefineLocalVariable (string name,
458                                                  FieldAttributes attributes,
459                                                  byte[] signature,
460                                                  SymAddressKind addrKind,
461                                                  int addr1,
462                                                  int addr2,
463                                                  int addr3,
464                                                  int startOffset,
465                                                  int endOffset)
466                 {
467                         if (current_method == null)
468                                 return;
469
470                         current_method.AddLocal (new LocalVariableEntry (name, attributes, signature));
471                 }
472
473                 public void DefineParameter (string name,
474                                              ParameterAttributes attributes,
475                                              int sequence,
476                                              SymAddressKind addrKind,
477                                              int addr1,
478                                              int addr2,
479                                              int addr3)
480                 {
481                         throw new NotSupportedException ();
482                 }
483
484                 public void DefineSequencePoints (ISymbolDocumentWriter document,
485                                                   int[] offsets,
486                                                   int[] lines,
487                                                   int[] columns,
488                                                   int[] endLines,
489                                                   int[] endColumns)
490                 {
491                         if (current_method == null)
492                                 return;
493
494                         SourceLine source_line = new SourceLine (offsets [0], lines [0], columns [0]);
495
496                         if (current_method != null)
497                                 current_method.AddLine (source_line);
498                 }
499
500                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
501                 {
502                         throw new NotSupportedException ();
503                 }
504
505                 public void Initialize (string assembly_filename, string filename, string[] args)
506                 {
507                         this.output_filename = filename;
508                         this.assembly_filename = assembly_filename;
509                 }
510
511                 public void OpenMethod (SymbolToken symbol_token)
512                 {
513                         int token = symbol_token.GetToken ();
514
515                         if ((token & 0xff000000) != 0x06000000)
516                                 throw new ArgumentException ();
517
518                         int index = (token & 0xffffff) - 1;
519
520                         MethodBuilder mb = (MethodBuilder) mbuilder_array [index];
521
522                         current_method = new SourceMethod (mb);
523
524                         methods.Add (current_method);
525                 }
526
527                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
528                                                   int startLine, int startColumn,
529                                                   ISymbolDocumentWriter endDoc,
530                                                   int endLine, int endColumn)
531                 {
532                         if (current_method == null)
533                                 return;
534
535                         if ((startDoc == null) || (endDoc == null))
536                                 throw new NullReferenceException ();
537
538                         if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
539                                 throw new NotSupportedException ("both startDoc and endDoc must be of type "
540                                                                  + "MonoSymbolDocumentWriter");
541
542                         if (!startDoc.Equals (endDoc))
543                                 throw new NotSupportedException ("startDoc and endDoc must be the same");
544
545                         string source_file = ((MonoSymbolDocumentWriter) startDoc).FileName;
546                         SourceFile source_info;
547
548                         if (sources.ContainsKey (source_file))
549                                 source_info = (SourceFile) sources [source_file];
550                         else {
551                                 source_info = new SourceFile (source_file);
552                                 sources.Add (source_file, source_info);
553                         }
554
555                         current_method.SetSourceRange (source_info, startLine, startColumn,
556                                                        endLine, endColumn);
557
558                         source_info.AddMethod (current_method);
559                 }
560
561                 public void CloseMethod () {
562                         current_method = null;
563                 }
564
565                 public void OpenNamespace (string name)
566                 {
567                         throw new NotSupportedException ();
568                 }
569
570                 public int OpenScope (int startOffset)
571                 {
572                         if (current_method == null)
573                                 return 0;
574
575                         SourceBlock block = new SourceBlock (current_method, startOffset);
576                         current_method.StartBlock (block);
577
578                         return block.ID;
579                 }
580
581                 public void CloseScope (int endOffset) {
582                         if (current_method == null)
583                                 return;
584
585                         current_method.EndBlock (endOffset);
586                 }
587
588                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
589                 {
590                         if (current_method == null)
591                                 return;
592
593                         current_method.SetBlockRange (scopeID, startOffset, endOffset);
594                 }
595
596                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
597                 {
598                         throw new NotSupportedException ();
599                 }
600
601                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
602                 {
603                         throw new NotSupportedException ();
604                 }
605
606                 public void SetUserEntryPoint (SymbolToken entryMethod)
607                 {
608                         throw new NotSupportedException ();
609                 }
610
611                 public void UsingNamespace (string fullName)
612                 {
613                         throw new NotSupportedException ();
614                 }
615
616                 //
617                 // MonoSymbolWriter implementation
618                 //
619                 protected void DoFixups (Assembly assembly)
620                 {
621                         foreach (SourceMethod method in methods) {
622                                 if (method._method_base is MethodBuilder) {
623                                         MethodBuilder mb = (MethodBuilder) method._method_base;
624                                         method._token = mb.GetToken ().Token;
625                                 } else if (method._method_base is ConstructorBuilder) {
626                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
627                                         method._token = cb.GetToken ().Token;
628                                 } else
629                                         throw new NotSupportedException ();
630
631                                 if (method.SourceFile == null)
632                                         orphant_methods.Add (method);
633                         }
634                 }
635
636                 protected void CreateOutput (Assembly assembly)
637                 {
638                         using (MonoSymbolTableWriter writer = new MonoSymbolTableWriter (output_filename))
639                                 writer.WriteSymbolTable (this);
640                 }
641         }
642 }
643