2002-03-20 Martin Baulig <martin@gnome.org>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoDwarfFileWriter.cs
1 //
2 // System.Diagnostics.SymbolStore/MonoDwarfWriter.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 DwarfFileWriter
24         {
25                 protected const string producer_id = "Mono C# Compiler 0.01 03-18-2002";
26
27                 protected ArrayList compile_units = new ArrayList ();
28                 protected ArrayList line_number_engines = new ArrayList ();
29                 protected StreamWriter writer = null;
30                 protected string symbol_file = null;
31
32                 // Write a generic file which contains no machine dependant stuff but
33                 // only function and type declarations.
34                 protected readonly bool DoGeneric = false;
35
36                 //
37                 // DwarfFileWriter public interface
38                 //
39                 public DwarfFileWriter (string symbol_file)
40                 {
41                         this.symbol_file = symbol_file;
42                         this.writer = new StreamWriter (symbol_file);
43                 }
44
45                 // Writes the final dwarf file.
46                 public void Close ()
47                 {
48                         foreach (CompileUnit compile_unit in compile_units)
49                                 compile_unit.Emit ();
50
51                         foreach (LineNumberEngine line_number_engine in line_number_engines)
52                                 line_number_engine.Emit ();
53
54                         WriteAbbrevDeclarations ();
55                         WriteRelocEntries ();
56
57                         writer.Close ();
58                 }
59
60                 // Adds a new compile unit to this dwarf file
61                 public void AddCompileUnit (CompileUnit compile_unit)
62                 {
63                         compile_units.Add (compile_unit);
64                 }
65
66                 // Adds a new line number engine to this dwarf file
67                 public void AddLineNumberEngine (LineNumberEngine line_number_engine)
68                 {
69                         line_number_engines.Add (line_number_engine);
70                 }
71
72                 // This string is written into the generated dwarf file to identify the
73                 // producer and version number.
74                 public string ProducerID {
75                         get {
76                                 return producer_id;
77                         }
78                 }
79
80                 //
81                 // Create a debugging information entry for the given type.
82                 //
83                 public Die CreateType (DieCompileUnit die_compile_unit, Type type)
84                 {
85                         if (type.IsPrimitive)
86                                 return new DieBaseType (die_compile_unit, type);
87                         else if (type.IsPointer)
88                                 return new DiePointerType (die_compile_unit, type.GetElementType ());
89
90                         throw new NotSupportedException ("Type " + type + " is not yet supported.");
91                 }
92
93                 //
94                 // A compile unit refers to a single C# source file.
95                 //
96                 public class CompileUnit
97                 {
98                         protected DwarfFileWriter dw;
99                         protected string source_file;
100                         protected ArrayList dies = new ArrayList ();
101
102                         private static int next_ref_index = 0;
103
104                         public readonly int ReferenceIndex;
105                         public readonly string ReferenceLabel;
106
107                         public CompileUnit (DwarfFileWriter dw, string source_file, Die[] dies)
108                         {
109                                 this.dw = dw;
110                                 this.source_file = source_file;
111                                 if (dies != null)
112                                         this.dies.AddRange (dies);
113
114                                 this.ReferenceIndex = ++next_ref_index;
115                                 this.ReferenceLabel = ".L_COMPILE_UNIT_" + this.ReferenceIndex;
116
117                                 dw.AddCompileUnit (this);
118                         }
119
120                         //
121                         // Construct a new compile unit for source file @source_file.
122                         //
123                         // This constructor automatically adds the newly created compile
124                         // unit to the DwarfFileWriter's list of compile units.
125                         //
126                         public CompileUnit (DwarfFileWriter dw, string source_file)
127                                 : this (dw, source_file, null)
128                         { }
129
130                         public string SourceFile {
131                                 get {
132                                         return source_file;
133                                 }
134                         }
135
136                         public string ProducerID {
137                                 get {
138                                         return dw.ProducerID;
139                                 }
140                         }
141
142                         public DwarfFileWriter DwarfFileWriter
143                         {
144                                 get {
145                                         return dw;
146                                 }
147                         }
148
149                         // Add a new debugging information entry to this compile unit.
150                         public void AddDie (Die die)
151                         {
152                                 dies.Add (die);
153                         }
154
155                         // Write the whole compile unit to the dwarf file.
156                         public void Emit ()
157                         {
158                                 int start_index, end_index;
159
160                                 dw.WriteSectionStart (Section.DEBUG_INFO);
161
162                                 dw.WriteLabel (ReferenceLabel);
163
164                                 start_index = dw.WriteAnonLabel ();
165
166                                 end_index = dw.WriteSectionSize ();
167                                 dw.WriteUInt16 (2);
168                                 dw.WriteOffset ("debug_abbrev_b");
169                                 if (dw.DoGeneric)
170                                         dw.WriteUInt8 (4);
171                                 else {
172                                         dw.AddRelocEntry (RelocEntryType.TARGET_ADDRESS_SIZE);
173                                         dw.WriteUInt8 (4);
174                                 }
175
176                                 if (dies != null)
177                                         foreach (Die die in dies)
178                                                 die.Emit ();
179
180                                 dw.WriteAnonLabel (end_index);
181
182                                 dw.WriteSectionEnd ();
183                         }
184                 }
185
186                 public class LineNumberEngine
187                 {
188                         public readonly int ReferenceIndex;
189                         public readonly string ReferenceLabel;
190
191                         public readonly int LineBase = 1;
192                         public readonly int LineRange = 8;
193
194                         protected DwarfFileWriter dw;
195
196                         public readonly int[] StandardOpcodeSizes = {
197                                 0, 0, 1, 1, 1, 1, 0, 0, 0, 0
198                         };
199
200                         public readonly int OpcodeBase;
201
202                         private Hashtable _sources = new Hashtable ();
203                         private Hashtable _directories = new Hashtable ();
204                         private Hashtable _methods = new Hashtable ();
205
206                         private int next_source_id;
207                         private int next_directory_id;
208
209                         private static int next_ref_index;
210                         private static int next_method_id;
211
212                         private enum DW_LNS {
213                                 LNS_extended_op         = 0,
214                                 LNS_copy                = 1,
215                                 LNS_advance_pc          = 2,
216                                 LNS_advance_line        = 3,
217                                 LNS_set_file            = 4,
218                                 LNS_set_column          = 5,
219                                 LNS_negate_stmt         = 6,
220                                 LNS_set_basic_block     = 7,
221                                 LNS_const_add_pc        = 8,
222                                 LNS_fixed_advance_pc    = 9
223                         };
224
225                         private enum DW_LNE {
226                                 LNE_end_sequence        = 1,
227                                 LNE_set_address         = 2,
228                                 LNE_define_file         = 3
229                         };
230
231
232                         public ISourceFile[] Sources {
233                                 get {
234                                         ISourceFile[] retval = new ISourceFile [_sources.Count];
235
236                                         foreach (ISourceFile source in _sources.Keys)
237                                                 retval [(int) _sources [source] - 1] = source;
238
239                                         return retval;
240                                 }
241                         }
242
243                         public string[] Directories {
244                                 get {
245                                         string[] retval = new string [_directories.Count];
246
247                                         foreach (string directory in _directories.Keys)
248                                                 retval [(int) _directories [directory] - 1] = directory;
249
250                                         return retval;
251                                 }
252                         }
253
254                         public ISourceMethod[] Methods {
255                                 get {
256                                         ISourceMethod[] retval = new ISourceMethod [_methods.Count];
257
258                                         foreach (ISourceMethod method in _methods.Keys)
259                                                 retval [(int) _methods [method] - 1] = method;
260
261                                         return retval;
262                                 }
263                         }
264                         
265                         public LineNumberEngine (DwarfFileWriter writer)
266                         {
267                                 this.dw = writer;
268                                 this.ReferenceIndex = ++next_ref_index;
269                                 this.ReferenceLabel = ".L_DEBUG_LINE_" + this.ReferenceIndex;
270
271                                 dw.AddLineNumberEngine (this);
272                         }
273
274                         public int LookupSource (ISourceFile source)
275                         {
276                                 if (_sources.ContainsKey (source))
277                                         return (int) _sources [source];
278
279                                 int index = ++next_source_id;
280                                 _sources.Add (source, index);
281                                 return index;
282                         }
283
284                         public int LookupDirectory (string directory)
285                         {
286                                 if (_directories.ContainsKey (directory))
287                                         return (int) _directories [directory];
288
289                                 int index = ++next_directory_id;
290                                 _directories.Add (directory, index);
291                                 return index;
292                         }
293
294                         public void AddMethod (ISourceMethod method)
295                         {
296                                 LookupSource (method.SourceFile);
297
298                                 int index = ++next_method_id;
299                                 _methods.Add (method, index);
300                         }
301
302                         private void SetFile (ISourceFile source)
303                         {
304                                 dw.WriteInt8 ((int) DW_LNS.LNS_set_file);
305                                 dw.WriteULeb128 (LookupSource (source));
306                         }
307
308                         private int st_line = 1;
309                         private int st_address = 0;
310
311                         private void SetLine (int line)
312                         {
313                                 dw.WriteInt8 ((int) DW_LNS.LNS_advance_line);
314                                 dw.WriteSLeb128 (line - st_line);
315                                 st_line = line;
316                         }
317
318                         private void SetAddress (int token, int address)
319                         {
320                                 dw.WriteUInt8 (0);
321                                 int end_index = dw.WriteShortSectionSize ();
322                                 dw.WriteUInt8 ((int) DW_LNE.LNE_set_address);
323                                 dw.AddRelocEntry (RelocEntryType.IL_OFFSET, token);
324                                 dw.WriteAddress (address);
325                                 dw.WriteAnonLabel (end_index);
326                                 st_address = address;
327                         }
328
329                         private void EndSequence ()
330                         {
331                                 dw.WriteUInt8 (0);
332                                 dw.WriteUInt8 (1);
333                                 dw.WriteUInt8 ((int) DW_LNE.LNE_end_sequence);
334                         }
335
336                         private void Commit ()
337                         {
338                                 dw.WriteUInt8 ((int) DW_LNS.LNS_copy);
339                         }
340
341                         public void Emit ()
342                         {
343                                 dw.WriteSectionStart (Section.DEBUG_LINE);
344                                 dw.WriteLabel (ReferenceLabel);
345                                 int end_index = dw.WriteSectionSize ();
346
347                                 dw.WriteUInt16 (2);
348                                 int start_index = dw.WriteSectionSize ();
349                                 dw.WriteUInt8 (1);
350                                 dw.WriteUInt8 (1);
351                                 dw.WriteInt8 (LineBase);
352                                 dw.WriteUInt8 (LineRange);
353                                 dw.WriteUInt8 (StandardOpcodeSizes.Length);
354                                 for (int i = 1; i < StandardOpcodeSizes.Length; i++)
355                                         dw.WriteUInt8 (StandardOpcodeSizes [i]);
356
357                                 foreach (string directory in Directories)
358                                         dw.WriteString (directory);
359                                 dw.WriteUInt8 (0);                                      
360
361                                 foreach (ISourceFile source in Sources) {
362                                         dw.WriteString (source.FileName);
363                                         dw.WriteULeb128 (0);
364                                         dw.WriteULeb128 (0);
365                                         dw.WriteULeb128 (0);
366                                 }
367
368                                 dw.WriteUInt8 (0);
369
370                                 dw.WriteAnonLabel (start_index);
371
372                                 foreach (ISourceMethod method in Methods) {
373                                         SetFile (method.SourceFile);
374                                         SetLine (method.FirstLine);
375                                         SetAddress (method.Token, 0);
376                                         Commit ();
377
378                                         foreach (ISourceLine line in method.Lines) {
379                                                 SetLine (line.Line);
380                                                 SetAddress (method.Token, line.Offset);
381                                                 Commit ();
382                                         }
383
384                                         SetLine (method.LastLine);
385                                         if (method.CodeSize >= 0)
386                                                 SetAddress (method.Token, method.CodeSize);
387                                         Commit ();
388
389                                         EndSequence ();
390                                 }
391
392                                 dw.WriteAnonLabel (end_index);
393                                 dw.WriteSectionEnd ();
394                         }
395                 }
396
397                 // DWARF tag from the DWARF 2 specification.
398                 public enum DW_TAG {
399                         TAG_pointer_type        = 0x0f,
400                         TAG_compile_unit        = 0x11,
401                         TAG_base_type           = 0x24,
402                         TAG_subprogram          = 0x2e
403                 }
404
405                 // DWARF attribute from the DWARF 2 specification.
406                 public enum DW_AT {
407                         AT_name                 = 0x03,
408                         AT_byte_size            = 0x0b,
409                         AT_stmt_list            = 0x10,
410                         AT_low_pc               = 0x11,
411                         AT_high_pc              = 0x12,
412                         AT_language             = 0x13,
413                         AT_producer             = 0x25,
414                         AT_declaration          = 0x3c,
415                         AT_encoding             = 0x3e,
416                         AT_external             = 0x3f,
417                         AT_type                 = 0x49
418                 }
419
420                 // DWARF form from the DWARF 2 specification.
421                 public enum DW_FORM {
422                         FORM_addr               = 0x01,
423                         FORM_string             = 0x08,
424                         FORM_data1              = 0x0b,
425                         FORM_flag               = 0x0c,
426                         FORM_ref4               = 0x13
427
428                 }
429
430                 public enum DW_LANG {
431                         LANG_C_plus_plus        = 0x04,
432                         LANG_C_sharp            = LANG_C_plus_plus
433                 }
434
435                 // Abstract base class for a "debugging information entry" (die).
436                 public abstract class Die
437                 {
438                         protected DwarfFileWriter dw;
439                         protected ArrayList child_dies = new ArrayList ();
440                         public readonly Die Parent;
441
442                         private static int next_ref_index = 0;
443
444                         protected readonly int abbrev_id;
445                         protected readonly AbbrevDeclaration abbrev_decl;
446
447                         public readonly int ReferenceIndex;
448                         public readonly string ReferenceLabel;
449
450                         //
451                         // Create a new die If @parent is not null, add the newly
452                         // created die to the parent's list of child dies.
453                         //
454                         // @abbrev_id is the abbreviation id for this die class.
455                         // Derived classes should call the DwarfFileWriter's static
456                         // RegisterAbbrevDeclaration function in their static constructor
457                         // to get an abbrev id. Once you registered an abbrev entry, it'll
458                         // be automatically written to the debug_abbrev section.
459                         //
460                         public Die (DwarfFileWriter dw, Die parent, int abbrev_id)
461                         {
462                                 this.dw = dw;
463                                 this.Parent = parent;
464                                 this.abbrev_id = abbrev_id;
465                                 this.abbrev_decl = GetAbbrevDeclaration (abbrev_id);
466                                 this.ReferenceIndex = ++next_ref_index;
467                                 this.ReferenceLabel = ".L_DIE_" + this.ReferenceIndex;
468
469                                 if (parent != null)
470                                         parent.AddChildDie (this);
471                         }
472
473                         public Die (DwarfFileWriter dw, int abbrev_id)
474                                 : this (dw, null, abbrev_id)
475                         { }
476
477                         public Die (Die parent, int abbrev_id)
478                                 : this (parent.dw, parent, abbrev_id)
479                         { }
480
481                         protected void AddChildDie (Die die)
482                         {
483                                 child_dies.Add (die);
484                         }
485
486                         public override bool Equals (object o)
487                         {
488                                 if (!(o is Die))
489                                         return false;
490
491                                 return ((Die) o).ReferenceIndex == ReferenceIndex;
492                         }
493
494                         public override int GetHashCode ()
495                         {
496                                 return ReferenceIndex;
497                         }
498
499                         //
500                         // Write this die and all its children to the dwarf file.
501                         //
502                         public virtual void Emit ()
503                         {
504                                 dw.WriteLabel (ReferenceLabel);
505
506                                 dw.WriteULeb128 (abbrev_id);
507                                 DoEmit ();
508
509                                 if (abbrev_decl.HasChildren) {
510                                         foreach (Die child in child_dies)
511                                                 child.Emit ();
512
513                                         dw.WriteUInt8 (0);
514                                 }
515                         }
516
517                         //
518                         // Derived classes must implement this function to actually
519                         // write themselves to the dwarf file.
520                         //
521                         // Note that the abbrev id has already been written in Emit() -
522                         // if you don't like this, you must override Emit() as well.
523                         //
524                         public abstract void DoEmit ();
525
526                         //
527                         // Gets the compile unit of this die.
528                         //
529                         public virtual DieCompileUnit GetCompileUnit ()
530                         {
531                                 Die die = this;
532
533                                 while (die.Parent != null)
534                                         die = die.Parent;
535
536                                 if (die is DieCompileUnit)
537                                         return (DieCompileUnit) die;
538                                 else
539                                         return null;
540                         }
541
542                         public DieCompileUnit DieCompileUnit {
543                                 get {
544                                         return GetCompileUnit ();
545                                 }
546                         }
547                 }
548
549                 // DW_TAG_compile_unit
550                 public class DieCompileUnit : Die
551                 {
552                         private static int my_abbrev_id;
553
554                         protected Hashtable types = new Hashtable ();
555
556                         static DieCompileUnit ()
557                         {
558                                 AbbrevEntry[] entries = {
559                                         new AbbrevEntry (DW_AT.AT_name, DW_FORM.FORM_string),
560                                         new AbbrevEntry (DW_AT.AT_producer, DW_FORM.FORM_string),
561                                         new AbbrevEntry (DW_AT.AT_language, DW_FORM.FORM_data1),
562                                         new AbbrevEntry (DW_AT.AT_stmt_list, DW_FORM.FORM_ref4)
563                                 };
564                                 AbbrevDeclaration decl = new AbbrevDeclaration (
565                                         DW_TAG.TAG_compile_unit, true, entries);
566
567                                 my_abbrev_id = RegisterAbbrevDeclaration (decl);
568                         }
569
570                         public readonly CompileUnit CompileUnit;
571                         public readonly bool DoGeneric;
572                         public readonly LineNumberEngine LineNumberEngine;
573
574                         //
575                         // Create a new DW_TAG_compile_unit debugging information entry
576                         // and add it to the @compile_unit.
577                         //
578                         public DieCompileUnit (CompileUnit compile_unit)
579                                 : base (compile_unit.DwarfFileWriter, my_abbrev_id)
580                         {
581                                 this.CompileUnit = compile_unit;
582                                 this.DoGeneric = dw.DoGeneric;
583                                 compile_unit.AddDie (this);
584
585                                 // GDB doesn't support DW_TAG_base_types yet, so we need to
586                                 // include the types in each compile unit.
587                                 RegisterType (typeof (bool));
588                                 RegisterType (typeof (char));
589                                 RegisterType (typeof (SByte));
590                                 RegisterType (typeof (Byte));
591                                 RegisterType (typeof (Int16));
592                                 RegisterType (typeof (UInt16));
593                                 RegisterType (typeof (Int32));
594                                 RegisterType (typeof (UInt32));
595                                 RegisterType (typeof (Int64));
596                                 RegisterType (typeof (UInt64));
597                                 RegisterType (typeof (Single));
598                                 RegisterType (typeof (Double));
599
600                                 LineNumberEngine = new LineNumberEngine (dw);
601                         }
602
603                         // Registers a new type
604                         public Die RegisterType (Type type)
605                         {
606                                 if (types.Contains (type))
607                                         return (Die) types [type];
608
609                                 Die die = dw.CreateType (this, type);
610
611                                 types.Add (type, die);
612                                 return die;
613                         }
614
615                         public void WriteRelativeDieReference (Die target_die)
616                         {
617                                 if (!this.Equals (target_die.GetCompileUnit ()))
618                                         throw new ArgumentException ("Target die must be in the same "
619                                                                      + "compile unit");
620
621                                 dw.WriteRelativeReference (CompileUnit.ReferenceLabel,
622                                                            target_die.ReferenceLabel);
623                         }
624
625                         public override void DoEmit ()
626                         {
627                                 dw.WriteString (CompileUnit.SourceFile);
628                                 dw.WriteString (CompileUnit.ProducerID);
629                                 dw.WriteUInt8 ((int) DW_LANG.LANG_C_sharp);
630                                 dw.WriteAbsoluteReference (LineNumberEngine.ReferenceLabel);
631                         }
632                 }
633
634                 // DW_TAG_subprogram
635                 public class DieSubProgram : Die
636                 {
637                         private static int my_abbrev_id_1;
638                         private static int my_abbrev_id_2;
639                         private static int my_abbrev_id_3;
640                         private static int my_abbrev_id_4;
641
642                         static DieSubProgram ()
643                         {
644                                 // Method without return value
645                                 AbbrevEntry[] entries_1 = {
646                                         new AbbrevEntry (DW_AT.AT_name, DW_FORM.FORM_string),
647                                         new AbbrevEntry (DW_AT.AT_external, DW_FORM.FORM_flag),
648                                         new AbbrevEntry (DW_AT.AT_low_pc, DW_FORM.FORM_addr),
649                                         new AbbrevEntry (DW_AT.AT_high_pc, DW_FORM.FORM_addr)
650                                 };
651                                 // Method with return value
652                                 AbbrevEntry[] entries_2 = {
653                                         new AbbrevEntry (DW_AT.AT_name, DW_FORM.FORM_string),
654                                         new AbbrevEntry (DW_AT.AT_external, DW_FORM.FORM_flag),
655                                         new AbbrevEntry (DW_AT.AT_low_pc, DW_FORM.FORM_addr),
656                                         new AbbrevEntry (DW_AT.AT_high_pc, DW_FORM.FORM_addr),
657                                         new AbbrevEntry (DW_AT.AT_type, DW_FORM.FORM_ref4)
658                                 };
659                                 // Method declaration without return value
660                                 AbbrevEntry[] entries_3 = {
661                                         new AbbrevEntry (DW_AT.AT_name, DW_FORM.FORM_string),
662                                         new AbbrevEntry (DW_AT.AT_external, DW_FORM.FORM_flag),
663                                         new AbbrevEntry (DW_AT.AT_declaration, DW_FORM.FORM_flag)
664                                 };
665                                 // Method declaration with return value
666                                 AbbrevEntry[] entries_4 = {
667                                         new AbbrevEntry (DW_AT.AT_name, DW_FORM.FORM_string),
668                                         new AbbrevEntry (DW_AT.AT_external, DW_FORM.FORM_flag),
669                                         new AbbrevEntry (DW_AT.AT_declaration, DW_FORM.FORM_flag),
670                                         new AbbrevEntry (DW_AT.AT_type, DW_FORM.FORM_ref4)
671                                 };
672
673
674                                 AbbrevDeclaration decl_1 = new AbbrevDeclaration (
675                                         DW_TAG.TAG_subprogram, true, entries_1);
676                                 AbbrevDeclaration decl_2 = new AbbrevDeclaration (
677                                         DW_TAG.TAG_subprogram, true, entries_2);
678                                 AbbrevDeclaration decl_3 = new AbbrevDeclaration (
679                                         DW_TAG.TAG_subprogram, true, entries_3);
680                                 AbbrevDeclaration decl_4 = new AbbrevDeclaration (
681                                         DW_TAG.TAG_subprogram, true, entries_4);
682
683                                 my_abbrev_id_1 = RegisterAbbrevDeclaration (decl_1);
684                                 my_abbrev_id_2 = RegisterAbbrevDeclaration (decl_2);
685                                 my_abbrev_id_3 = RegisterAbbrevDeclaration (decl_3);
686                                 my_abbrev_id_4 = RegisterAbbrevDeclaration (decl_4);
687                         }
688
689                         private static int get_abbrev_id (DieCompileUnit parent_die, ISourceMethod method)
690                         {
691                                 if (parent_die.DoGeneric)
692                                         if (method.MethodInfo.ReturnType == typeof (void))
693                                                 return my_abbrev_id_3;
694                                         else
695                                                 return my_abbrev_id_4;
696                                 else
697                                         if (method.MethodInfo.ReturnType == typeof (void))
698                                                 return my_abbrev_id_1;
699                                         else
700                                                 return my_abbrev_id_2;
701                         }
702
703                         protected ISourceMethod method;
704                         protected Die retval_die;
705
706                         //
707                         // Create a new DW_TAG_subprogram debugging information entry
708                         // for method @name (which has a void return value) and add it
709                         // to the @parent_die
710                         //
711                         public DieSubProgram (DieCompileUnit parent_die, ISourceMethod method)
712                                 : base (parent_die, get_abbrev_id (parent_die, method))
713                         {
714                                 this.method = method;
715
716                                 if (method.MethodInfo.ReturnType != typeof (void))
717                                         retval_die = DieCompileUnit.RegisterType (
718                                                 method.MethodInfo.ReturnType);
719
720                                 DieCompileUnit.LineNumberEngine.AddMethod (method);
721                         }
722
723                         public override void DoEmit ()
724                         {
725                                 dw.WriteString (method.MethodInfo.Name);
726                                 dw.WriteFlag (true);
727                                 if (dw.DoGeneric)
728                                         dw.WriteFlag (true);
729                                 else {
730                                         dw.AddRelocEntry (RelocEntryType.IL_OFFSET, method.Token);
731                                         dw.WriteAddress (0);
732                                         dw.AddRelocEntry (RelocEntryType.IL_OFFSET, method.Token);
733                                         dw.WriteAddress (0);
734                                 }
735                                 if (method.MethodInfo.ReturnType != typeof (void))
736                                         DieCompileUnit.WriteRelativeDieReference (retval_die);
737                         }
738                 }
739
740                 // DW_TAG_base_type
741                 public class DieBaseType : Die
742                 {
743                         private static int my_abbrev_id;
744
745                         static DieBaseType ()
746                         {
747                                 AbbrevEntry[] entries = {
748                                         new AbbrevEntry (DW_AT.AT_name, DW_FORM.FORM_string),
749                                         new AbbrevEntry (DW_AT.AT_encoding, DW_FORM.FORM_data1),
750                                         new AbbrevEntry (DW_AT.AT_byte_size, DW_FORM.FORM_data1)
751                                 };
752
753                                 AbbrevDeclaration decl = new AbbrevDeclaration (
754                                         DW_TAG.TAG_base_type, false, entries);
755
756                                 my_abbrev_id = RegisterAbbrevDeclaration (decl);
757                         }
758
759                         protected Type type;
760
761                         //
762                         // Create a new DW_TAG_base_type debugging information entry
763                         //
764                         public DieBaseType (DieCompileUnit parent_die, Type type)
765                                 : base (parent_die, my_abbrev_id)
766                         {
767                                 this.type = type;
768                         }
769
770                         protected enum DW_ATE {
771                                 ATE_void                = 0x00,
772                                 ATE_address             = 0x01,
773                                 ATE_boolean             = 0x02,
774                                 ATE_complex_float       = 0x03,
775                                 ATE_float               = 0x04,
776                                 ATE_signed              = 0x05,
777                                 ATE_signed_char         = 0x06,
778                                 ATE_unsigned            = 0x07,
779                                 ATE_unsigned_char       = 0x08
780                         }
781
782                         public override void DoEmit ()
783                         {
784                                 string name = type.Name;
785
786                                 dw.WriteString (name);
787                                 switch (name) {
788                                 case "Void":
789                                         dw.WriteUInt8 ((int) DW_ATE.ATE_address);
790                                         dw.WriteUInt8 (0);
791                                         break;
792                                 case "Boolean":
793                                         dw.WriteUInt8 ((int) DW_ATE.ATE_boolean);
794                                         dw.WriteUInt8 (1);
795                                         break;
796                                 case "Char":
797                                         dw.WriteUInt8 ((int) DW_ATE.ATE_unsigned_char);
798                                         dw.WriteUInt8 (2);
799                                         break;
800                                 case "SByte":
801                                         dw.WriteUInt8 ((int) DW_ATE.ATE_signed);
802                                         dw.WriteUInt8 (1);
803                                         break;
804                                 case "Byte":
805                                         dw.WriteUInt8 ((int) DW_ATE.ATE_unsigned);
806                                         dw.WriteUInt8 (1);
807                                         break;
808                                 case "Int16":
809                                         dw.WriteUInt8 ((int) DW_ATE.ATE_signed);
810                                         dw.WriteUInt8 (2);
811                                         break;
812                                 case "UInt16":
813                                         dw.WriteUInt8 ((int) DW_ATE.ATE_unsigned);
814                                         dw.WriteUInt8 (2);
815                                         break;
816                                 case "Int32":
817                                         dw.WriteUInt8 ((int) DW_ATE.ATE_signed);
818                                         dw.WriteUInt8 (4);
819                                         break;
820                                 case "UInt32":
821                                         dw.WriteUInt8 ((int) DW_ATE.ATE_unsigned);
822                                         dw.WriteUInt8 (4);
823                                         break;
824                                 case "Int64":
825                                         dw.WriteUInt8 ((int) DW_ATE.ATE_signed);
826                                         dw.WriteUInt8 (8);
827                                         break;
828                                 case "UInt64":
829                                         dw.WriteUInt8 ((int) DW_ATE.ATE_unsigned);
830                                         dw.WriteUInt8 (8);
831                                         break;
832                                 case "Single":
833                                         dw.WriteUInt8 ((int) DW_ATE.ATE_float);
834                                         dw.WriteUInt8 (4);
835                                         break;
836                                 case "Double":
837                                         dw.WriteUInt8 ((int) DW_ATE.ATE_float);
838                                         dw.WriteUInt8 (8);
839                                         break;
840                                 default:
841                                         throw new ArgumentException ("Not a base type: " + type);
842                                 }
843                         }
844                 }
845
846                 // DW_TAG_pointer_type
847                 public class DiePointerType : Die
848                 {
849                         private static int my_abbrev_id;
850
851                         static DiePointerType ()
852                         {
853                                 AbbrevEntry[] entries = {
854                                         new AbbrevEntry (DW_AT.AT_type, DW_FORM.FORM_ref4)
855                                 };
856
857                                 AbbrevDeclaration decl = new AbbrevDeclaration (
858                                         DW_TAG.TAG_pointer_type, false, entries);
859
860                                 my_abbrev_id = RegisterAbbrevDeclaration (decl);
861                         }
862
863                         protected Type type;
864                         protected Die type_die;
865
866                         //
867                         // Create a new type DIE describing a pointer to @type.
868                         //
869                         public DiePointerType (DieCompileUnit parent_die, Type type)
870                                 : base (parent_die, my_abbrev_id)
871                         {
872                                 this.type = type;
873                                 type_die = DieCompileUnit.RegisterType (type);
874                         }
875
876                         public override void DoEmit ()
877                         {
878                                 DieCompileUnit.WriteRelativeDieReference (type_die);
879                         }
880                 }
881
882                 protected const int reloc_table_version = 2;
883
884                 protected enum Section {
885                         DEBUG_INFO,
886                         DEBUG_ABBREV,
887                         DEBUG_LINE,
888                         MONO_RELOC_TABLE
889                 }
890
891                 public struct AbbrevEntry {
892                         public AbbrevEntry (DW_AT attribute, DW_FORM form)
893                         {
894                                 this._attribute = attribute;
895                                 this._form = form;
896                         }
897
898                         private DW_AT _attribute;
899                         private DW_FORM _form;
900
901                         public DW_AT Attribute {
902                                 get {
903                                         return _attribute;
904                                 }
905                         }
906
907                         public DW_FORM Form {
908                                 get {
909                                         return _form;
910                                 }
911                         }
912                 }
913
914                 public struct AbbrevDeclaration {
915                         public AbbrevDeclaration (DW_TAG tag, bool has_children, AbbrevEntry[] entries)
916                         {
917                                 this._tag = tag;
918                                 this._has_children = has_children;
919                                 this._entries = entries;
920                         }
921
922                         private DW_TAG _tag;
923                         private bool _has_children;
924                         private AbbrevEntry[] _entries;
925
926                         public DW_TAG Tag {
927                                 get {
928                                         return _tag;
929                                 }
930                         }
931
932                         public bool HasChildren {
933                                 get {
934                                         return _has_children;
935                                 }
936                         }
937
938                         public AbbrevEntry[] Entries {
939                                 get {
940                                         return _entries;
941                                 }
942                         }
943                 }
944             
945                 protected enum RelocEntryType {
946                         NONE,
947                         // Size of an address on the target machine
948                         TARGET_ADDRESS_SIZE     = 0x01,
949                         // Map an IL offset to a machine address
950                         IL_OFFSET               = 0x02
951                 }
952
953                 protected class RelocEntry {
954                         public RelocEntry (RelocEntryType type, int token, Section section, int index)
955                         {
956                                 _type = type;
957                                 _section = section;
958                                 _token = token;
959                                 _index = index;
960                         }
961
962                         public RelocEntryType RelocType {
963                                 get {
964                                         return _type;
965                                 }
966                         }
967
968                         public Section Section {
969                                 get {
970                                         return _section;
971                                 }
972                         }
973
974                         public int Index {
975                                 get {
976                                         return _index;
977                                 }
978                         }
979
980                         public int Token {
981                                 get {
982                                         return _token;
983                                 }
984                         }
985
986                         private RelocEntryType _type;
987                         private Section _section;
988                         private int _token;
989                         private int _index;
990                 }
991
992                 private int next_anon_label_idx = 0;
993                 private Section current_section;
994                 private ArrayList reloc_entries = new ArrayList ();
995
996                 private static ArrayList abbrev_declarations = new ArrayList ();
997
998                 protected string GetSectionName (Section section)
999                 {
1000                         switch (section) {
1001                         case Section.DEBUG_INFO:
1002                                 return "debug_info";
1003                         case Section.DEBUG_ABBREV:
1004                                 return "debug_abbrev";
1005                         case Section.DEBUG_LINE:
1006                                 return "debug_line";
1007                         case Section.MONO_RELOC_TABLE:
1008                                 return "mono_reloc_table";
1009                         default:
1010                                 throw new ArgumentException ();
1011                         }
1012                 }
1013
1014                 protected int WriteAnonLabel ()
1015                 {
1016                         int index = ++next_anon_label_idx;
1017
1018                         WriteAnonLabel (index);
1019
1020                         return index;
1021                 }
1022
1023                 protected void AddRelocEntry (RelocEntry entry)
1024                 {
1025                         reloc_entries.Add (entry);
1026                 }
1027
1028                 protected void AddRelocEntry (RelocEntryType type, int token, Section section, int index)
1029                 {
1030                         AddRelocEntry (new RelocEntry (type, token, section, index));
1031                 }
1032
1033                 protected void AddRelocEntry (RelocEntryType type, int token)
1034                 {
1035                         AddRelocEntry (type, token, current_section, WriteAnonLabel ());
1036                 }
1037
1038                 protected void AddRelocEntry (RelocEntryType type)
1039                 {
1040                         AddRelocEntry (type, 0);
1041                 }
1042
1043                 //
1044                 // Mono relocation table. See the README.relocation-table file in this
1045                 // directory for a detailed description of the file format.
1046                 //
1047                 protected void WriteRelocEntries ()
1048                 {
1049                         WriteSectionStart (Section.MONO_RELOC_TABLE);
1050                         WriteUInt16 (reloc_table_version);
1051                         WriteUInt8 (0);
1052                         int end_index = WriteSectionSize ();
1053
1054                         foreach (RelocEntry entry in reloc_entries) {
1055                                 WriteUInt8 ((int) entry.RelocType);
1056                                 int tmp_index = WriteSectionSize ();
1057
1058                                 WriteUInt8 ((int) entry.Section);
1059                                 WriteUInt16 (entry.Index);
1060
1061                                 switch (entry.RelocType) {
1062                                 case RelocEntryType.IL_OFFSET:
1063                                         WriteUInt32 (entry.Token);
1064                                         break;
1065                                 }
1066
1067                                 WriteAnonLabel (tmp_index);
1068                         }
1069
1070                         WriteAnonLabel (end_index);
1071                         WriteSectionEnd ();
1072                 }
1073
1074                 //
1075                 // Registers a new abbreviation declaration.
1076                 //
1077                 // This function should be called by a static constructor in one of
1078                 // Die's subclasses.
1079                 //
1080                 protected static int RegisterAbbrevDeclaration (AbbrevDeclaration decl)
1081                 {
1082                         return abbrev_declarations.Add (decl) + 1;
1083                 }
1084
1085                 protected static AbbrevDeclaration GetAbbrevDeclaration (int index)
1086                 {
1087                         return (AbbrevDeclaration) abbrev_declarations [index - 1];
1088                 }
1089
1090                 protected void WriteAbbrevDeclarations ()
1091                 {
1092                         WriteSectionStart (Section.DEBUG_ABBREV);
1093                         WriteLabel ("debug_abbrev_b");
1094
1095                         for (int index = 0; index < abbrev_declarations.Count; index++) {
1096                                 AbbrevDeclaration decl = (AbbrevDeclaration) abbrev_declarations [index];
1097
1098                                 WriteULeb128 (index + 1);
1099                                 WriteULeb128 ((int) decl.Tag);
1100                                 WriteFlag (decl.HasChildren);
1101
1102                                 foreach (AbbrevEntry entry in decl.Entries)
1103                                         WritePair ((int) entry.Attribute, (int) entry.Form);
1104
1105                                 WritePair (0, 0);
1106                         }
1107
1108                         WriteSectionEnd ();
1109                 }
1110
1111                 protected void WriteAnonLabel (int index)
1112                 {
1113                         writer.WriteLine (".L_" + index + ":");
1114                 }
1115
1116                 protected void WriteLabel (string label)
1117                 {
1118                         writer.WriteLine (label + ":");
1119                 }
1120
1121                 protected int WriteSectionSize ()
1122                 {
1123                         int start_index = ++next_anon_label_idx;
1124                         int end_index = ++next_anon_label_idx;
1125
1126                         writer.WriteLine ("\t.long\t\t.L_" + end_index + " - .L_" + start_index);
1127                         WriteAnonLabel (start_index);
1128
1129                         return end_index;
1130                 }
1131
1132                 protected int WriteShortSectionSize ()
1133                 {
1134                         int start_index = ++next_anon_label_idx;
1135                         int end_index = ++next_anon_label_idx;
1136
1137                         writer.WriteLine ("\t.byte\t\t.L_" + end_index + " - .L_" + start_index);
1138                         WriteAnonLabel (start_index);
1139
1140                         return end_index;
1141                 }
1142
1143                 protected void WriteRelativeReference (string start_label, string end_label)
1144                 {
1145                         writer.WriteLine ("\t.long\t\t" + end_label + " - " + start_label);
1146                 }
1147
1148                 protected void WriteAbsoluteReference (string label)
1149                 {
1150                         writer.WriteLine ("\t.long\t\t" + label);
1151                 }
1152
1153                 protected void WriteSectionStart (Section section)
1154                 {
1155                         writer.WriteLine ("\t.section\t." + GetSectionName (section));
1156                         current_section = section;
1157                 }
1158
1159                 protected void WriteSectionEnd ()
1160                 {
1161                         writer.WriteLine ("\t.previous\n");
1162                 }
1163
1164                 protected void WriteFlag (bool value)
1165                 {
1166                         writer.WriteLine ("\t.byte\t\t" + (value ? 1 : 0));
1167                 }
1168
1169                 protected void WritePair (int key, int value)
1170                 {
1171                         writer.WriteLine ("\t.byte\t\t" + key + ", " + value);
1172                 }
1173
1174                 protected void WriteUInt8 (int value)
1175                 {
1176                         writer.WriteLine ("\t.byte\t\t" + value);
1177                 }
1178
1179                 protected void WriteInt8 (int value)
1180                 {
1181                         writer.WriteLine ("\t.byte\t\t" + value);
1182                 }
1183
1184                 protected void WriteUInt16 (int value)
1185                 {
1186                         writer.WriteLine ("\t.2byte\t\t" + value);
1187                 }
1188
1189                 protected void WriteUInt32 (int value)
1190                 {
1191                         writer.WriteLine ("\t.long\t\t" + value);
1192                 }
1193
1194                 protected void WriteSLeb128 (int value)
1195                 {
1196                         writer.WriteLine ("\t.sleb128\t" + value);
1197                 }
1198
1199                 protected void WriteULeb128 (int value)
1200                 {
1201                         writer.WriteLine ("\t.uleb128\t" + value);
1202                 }
1203
1204                 protected void WriteOffset (string section)
1205                 {
1206                         writer.WriteLine ("\t.long\t\t" + section);
1207                 }
1208
1209                 protected void WriteAddress (int value)
1210                 {
1211                         writer.WriteLine ("\t.long\t\t" + value);
1212                 }
1213
1214                 protected void WriteString (string value)
1215                 {
1216                         writer.WriteLine ("\t.string\t\t\"" + value + "\"");
1217                 }
1218         }
1219 }