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