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