Wed May 15 16:02:56 CEST 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / dis / main.c
1 /*
2  * main.c: Sample disassembler
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  *
9  * TODO:
10  *   Investigate how interface inheritance works and how it should be dumped.
11  *   Structs are not being labeled as `valuetype' classes
12  *   
13  *   How are fields with literals mapped to constants?
14  */
15 #include <config.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <glib.h>
19 #include <stdlib.h>
20 #include "meta.h"
21 #include "util.h"
22 #include "dump.h"
23 #include "get.h"
24 #include "dis-cil.h"
25 #include <mono/metadata/loader.h>
26 #include <mono/metadata/assembly.h>
27 #include <mono/metadata/appdomain.h>
28
29 FILE *output;
30
31 /* True if you want to get a dump of the header data */
32 gboolean dump_header_data_p = FALSE;
33
34 gboolean substitute_with_mscorlib_p = FALSE;
35
36 int dump_table = -1;
37
38 static void
39 dump_header_data (MonoImage *img)
40 {
41         if (!dump_header_data_p)
42                 return;
43
44         fprintf (output,
45                  "// Ximian's CIL disassembler, version 1.0\n"
46                  "// Copyright (C) 2001 Ximian, Inc.\n\n");
47 }
48
49 static void
50 dis_directive_assembly (MonoImage *m)
51 {
52         MonoTableInfo *t  = &m->tables [MONO_TABLE_ASSEMBLY];
53         guint32 cols [MONO_ASSEMBLY_SIZE];
54         
55         if (t->base == NULL)
56                 return;
57
58         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
59         
60         fprintf (output,
61                  ".assembly '%s'\n"
62                  "{\n"
63                  "  .hash algorithm 0x%08x\n"
64                  "  .ver  %d:%d:%d:%d"
65                  "%s %s"
66                  "%s"
67                  "\n"
68                  "}\n",
69                  mono_metadata_string_heap (m, cols [MONO_ASSEMBLY_NAME]),
70                  cols [MONO_ASSEMBLY_HASH_ALG],
71                  cols [MONO_ASSEMBLY_MAJOR_VERSION], cols [MONO_ASSEMBLY_MINOR_VERSION], 
72                  cols [MONO_ASSEMBLY_BUILD_NUMBER], cols [MONO_ASSEMBLY_REV_NUMBER],
73                  cols [MONO_ASSEMBLY_CULTURE] ? "\n  .locale" : "",
74                  cols [MONO_ASSEMBLY_CULTURE] ? mono_metadata_string_heap (m, cols [MONO_ASSEMBLY_CULTURE]) : "",
75                  cols [MONO_ASSEMBLY_PUBLIC_KEY] ? "\n  .publickey" : ""
76                 );
77 }
78
79 static void
80 dis_directive_assemblyref (MonoImage *m)
81 {
82         MonoTableInfo *t = &m->tables [MONO_TABLE_ASSEMBLYREF];
83         guint32 cols [MONO_ASSEMBLYREF_SIZE];
84         int i;
85         
86         if (t->base == NULL)
87                 return;
88
89         for (i = 0; i < t->rows; i++){
90                 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
91
92                 fprintf (output,
93                          ".assembly extern %s\n"
94                          "{\n"
95                          "  .ver %d:%d:%d:%d\n"
96                          "}\n",
97                          mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_NAME]),
98                          cols [MONO_ASSEMBLYREF_MAJOR_VERSION], cols [MONO_ASSEMBLYREF_MINOR_VERSION], 
99                          cols [MONO_ASSEMBLYREF_BUILD_NUMBER], cols [MONO_ASSEMBLYREF_REV_NUMBER]
100                         );
101         }
102 }
103
104 static map_t visibility_map [] = {
105         { TYPE_ATTRIBUTE_NOT_PUBLIC,           "private " },
106         { TYPE_ATTRIBUTE_PUBLIC,               "public " },
107         { TYPE_ATTRIBUTE_NESTED_PUBLIC,        "nested-public " },
108         { TYPE_ATTRIBUTE_NESTED_PRIVATE,       "nested-private " },
109         { TYPE_ATTRIBUTE_NESTED_FAMILY,        "family " },
110         { TYPE_ATTRIBUTE_NESTED_ASSEMBLY,      "nested-assembly" },
111         { TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM, "nested-fam-and-assembly" },
112         { TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM,  "nested-fam-or-assembly" },
113         { 0, NULL }
114 };
115
116 static map_t layout_map [] = {
117         { TYPE_ATTRIBUTE_AUTO_LAYOUT,          "auto " },
118         { TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT,    "sequential " },
119         { TYPE_ATTRIBUTE_EXPLICIT_LAYOUT,      "explicit " },
120         { 0, NULL }
121 };
122
123 static map_t format_map [] = {
124         { TYPE_ATTRIBUTE_ANSI_CLASS,           "ansi " },
125         { TYPE_ATTRIBUTE_UNICODE_CLASS,        "unicode " },
126         { TYPE_ATTRIBUTE_AUTO_CLASS,           "auto " },
127         { 0, NULL }
128 };
129
130 static char *
131 typedef_flags (guint32 flags)
132 {
133         static char buffer [1024];
134         int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
135         int layout = flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
136         int format = flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK;
137         
138         buffer [0] = 0;
139
140         strcat (buffer, map (visibility, visibility_map));
141         strcat (buffer, map (layout, layout_map));
142         strcat (buffer, map (format, format_map));
143         
144         if (flags & TYPE_ATTRIBUTE_ABSTRACT)
145                 strcat (buffer, "abstract ");
146         if (flags & TYPE_ATTRIBUTE_SEALED)
147                 strcat (buffer, "sealed ");
148         if (flags & TYPE_ATTRIBUTE_SPECIAL_NAME)
149                 strcat (buffer, "special-name ");
150         if (flags & TYPE_ATTRIBUTE_IMPORT)
151                 strcat (buffer, "import ");
152         if (flags & TYPE_ATTRIBUTE_SERIALIZABLE)
153                 strcat (buffer, "serializable ");
154         if (flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
155                 strcat (buffer, "beforefieldinit ");
156
157         return buffer;
158 }
159
160 /**
161  * dis_field_list:
162  * @m: metadata context
163  * @start: starting index into the Field Table.
164  * @end: ending index into Field table.
165  *
166  * This routine displays all the decoded fields from @start to @end
167  */
168 static void
169 dis_field_list (MonoImage *m, guint32 start, guint32 end)
170 {
171         MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
172         guint32 cols [MONO_FIELD_SIZE];
173         char rva_desc [32];
174         guint32 rva;
175         int i;
176
177         if (end > t->rows + 1) {
178                 g_warning ("ERROR index out of range in fields");
179                 end = t->rows;
180         }
181                         
182         for (i = start; i < end; i++){
183                 char *sig, *flags, *attrs = NULL;
184                 guint32 field_offset = -1;
185                 
186                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
187                 sig = get_field_signature (m, cols [MONO_FIELD_SIGNATURE]);
188                 flags = field_flags (cols [MONO_FIELD_FLAGS]);
189
190                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
191                         mono_metadata_field_info (m, i, NULL, &rva, NULL);
192                         g_snprintf (rva_desc, sizeof (rva_desc), " at D_%08x", rva);
193                 } else {
194                         rva_desc [0] = 0;
195                 }
196                 
197                 mono_metadata_field_info (m, i, &field_offset, NULL, NULL);
198                 if (field_offset != -1)
199                         attrs = g_strdup_printf ("[%d]", field_offset);
200                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_LITERAL){
201                         char *lit;
202                         guint32 const_cols [MONO_CONSTANT_SIZE];
203                         guint32 crow;
204                         
205                         if ((crow = mono_metadata_get_constant_index (m, MONO_TOKEN_FIELD_DEF | (i+1)))) {
206                                 mono_metadata_decode_row (&m->tables [MONO_TABLE_CONSTANT], crow-1, const_cols, MONO_CONSTANT_SIZE);
207                                 lit = get_constant (m, const_cols [MONO_CONSTANT_TYPE], const_cols [MONO_CONSTANT_VALUE]);
208                         } else {
209                                 lit = g_strdup ("not found");
210                         }
211                         
212                         fprintf (output, "    .field %s %s %s = ",
213                                  flags, sig,
214                                  mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
215                         fprintf (output, "%s\n", lit);
216                         g_free (lit);
217                 } else
218                         fprintf (output, "    .field %s %s %s %s%s\n",
219                                  attrs? attrs: "", flags, sig,
220                                  mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]), rva_desc);
221                 g_free (attrs);
222                 g_free (flags);
223                 g_free (sig);
224         }
225 }
226
227 static map_t method_access_map [] = {
228         { METHOD_ATTRIBUTE_COMPILER_CONTROLLED, "compilercontrolled " },
229         { METHOD_ATTRIBUTE_PRIVATE,             "private" },
230         { METHOD_ATTRIBUTE_FAM_AND_ASSEM,       "famandassem" },
231         { METHOD_ATTRIBUTE_ASSEM,               "assembly " },
232         { METHOD_ATTRIBUTE_FAMILY,              "family " },
233         { METHOD_ATTRIBUTE_FAM_OR_ASSEM,        "famorassem " },
234         { METHOD_ATTRIBUTE_PUBLIC,              "public " },
235         { 0, NULL }
236 };
237
238 static map_t method_flags_map [] = {
239         { METHOD_ATTRIBUTE_STATIC,              "static " },
240         { METHOD_ATTRIBUTE_FINAL,               "final " },
241         { METHOD_ATTRIBUTE_VIRTUAL,             "virtual " },
242         { METHOD_ATTRIBUTE_HIDE_BY_SIG,         "hidebysig " },
243         { METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK,  "newslot " },
244         { METHOD_ATTRIBUTE_ABSTRACT,            "abstract " },
245         { METHOD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
246         { METHOD_ATTRIBUTE_RT_SPECIAL_NAME,     "rtspecialname " },
247         { METHOD_ATTRIBUTE_UNMANAGED_EXPORT,    "export " },
248         { METHOD_ATTRIBUTE_HAS_SECURITY,        "hassecurity" },
249         { METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT,  "requiresecobj" },
250         { METHOD_ATTRIBUTE_PINVOKE_IMPL,        "pinvokeimpl " }, 
251         { 0, NULL }
252 };
253
254 /**
255  * method_flags:
256  *
257  * Returns a stringified version of the Method's flags
258  */
259 static char *
260 method_flags (guint32 f)
261 {
262         GString *str = g_string_new ("");
263         int access = f & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
264         char *s;
265         
266         g_string_append (str, map (access, method_access_map));
267         g_string_append (str, flags (f, method_flags_map));
268
269         s = str->str;
270         g_string_free (str, FALSE);
271
272         return s;
273 }
274
275 static map_t pinvoke_flags_map [] = {
276         { PINVOKE_ATTRIBUTE_NO_MANGLE ,            "nomangle " },
277         { PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR,   "lasterr " },
278         { 0, NULL }
279 };
280
281 static map_t pinvoke_call_conv_map [] = {
282         { PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI,      "winapi " },
283         { PINVOKE_ATTRIBUTE_CALL_CONV_CDECL,       "cdecl " },
284         { PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL,     "stdcall " },
285         { PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL,    "thiscall " },
286         { PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL,    "fastcall " },
287         { 0, NULL }
288 };
289
290 static map_t pinvoke_char_set_map [] = {
291         { PINVOKE_ATTRIBUTE_CHAR_SET_NOT_SPEC,     "" },
292         { PINVOKE_ATTRIBUTE_CHAR_SET_ANSI,         "ansi " },
293         { PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE ,     "unicode " },
294         { PINVOKE_ATTRIBUTE_CHAR_SET_AUTO,         "autochar " },
295         { 0, NULL }
296 };
297
298 /**
299  * pinvoke_flags:
300  *
301  * Returns a stringified version of the Method's pinvoke flags
302  */
303 static char *
304 pinvoke_flags (guint32 f)
305 {
306         GString *str = g_string_new ("");
307         int cset = f & PINVOKE_ATTRIBUTE_CHAR_SET_MASK;
308         int cconv = f & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
309         char *s;
310         
311         g_string_append (str, map (cset, pinvoke_char_set_map));
312         g_string_append (str, map (cconv, pinvoke_call_conv_map));
313         g_string_append (str, flags (f, pinvoke_flags_map));
314
315         s = g_strdup(str->str);
316         g_string_free (str, FALSE);
317
318         return s;
319 }
320
321 static map_t method_impl_map [] = {
322         { METHOD_IMPL_ATTRIBUTE_IL,              "cil " },
323         { METHOD_IMPL_ATTRIBUTE_NATIVE,          "native " },
324         { METHOD_IMPL_ATTRIBUTE_OPTIL,           "optil " },
325         { METHOD_IMPL_ATTRIBUTE_RUNTIME,         "runtime " },
326         { 0, NULL }
327 };
328
329 static map_t managed_type_map [] = {
330         { METHOD_IMPL_ATTRIBUTE_UNMANAGED,       "unmanaged " },
331         { METHOD_IMPL_ATTRIBUTE_MANAGED,         "managed " },
332         { 0, NULL }
333 };
334
335 static map_t managed_impl_flags [] = {
336         { METHOD_IMPL_ATTRIBUTE_FORWARD_REF,     "fwdref " },
337         { METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG,    "preservesig " },
338         { METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL,   "internalcall " },
339         { METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED,    "synchronized " },
340         { METHOD_IMPL_ATTRIBUTE_NOINLINING,      "noinline " },
341         { 0, NULL }
342 };
343
344 static char *
345 method_impl_flags (guint32 f)
346 {
347         GString *str = g_string_new ("");
348         char *s;
349         int code_type = f & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
350         int managed_type = f & METHOD_IMPL_ATTRIBUTE_MANAGED_MASK;
351
352         g_string_append (str, map (code_type, method_impl_map));
353         g_string_append (str, map (managed_type, managed_type_map));
354         g_string_append (str, flags (f, managed_impl_flags));
355         
356         s = str->str;
357         g_string_free (str, FALSE);
358         return s;
359 }
360
361 static void
362 dis_locals (MonoImage *m, MonoMethodHeader *mh) 
363 {
364         int i;
365
366         fprintf(output, "\t.locals %s(\n", mh->init_locals ? "init " : "");
367         for (i=0; i < mh->num_locals; ++i) {
368                 char * desc;
369                 if (i)
370                         fprintf(output, ",\n");
371                 /* print also byref and pinned attributes */
372                 desc = dis_stringify_type (m, mh->locals[i]);
373                 fprintf(output, "\t\t%s\tV_%d", desc, i);
374                 g_free(desc);
375         }
376         fprintf(output, ")\n");
377 }
378
379 static void
380 dis_code (MonoImage *m, guint32 rva)
381 {
382         MonoMethodHeader *mh;
383         MonoCLIImageInfo *ii = m->image_info;
384         const char *ptr = mono_cli_rva_map (ii, rva);
385         const char *loc;
386
387         if (rva == 0)
388                 return;
389
390         mh = mono_metadata_parse_mh (m, ptr);
391         if (ii->cli_cli_header.ch_entry_point){
392                 loc = mono_metadata_locate_token (m, ii->cli_cli_header.ch_entry_point);
393                 if (rva == read32 (loc))
394                         fprintf (output, "\t.entrypoint\n");
395         }
396         
397         fprintf (output, "\t// Code size %d (0x%x)\n", mh->code_size, mh->code_size);
398         fprintf (output, "\t.maxstack %d\n", mh->max_stack);
399         if (mh->num_locals)
400                 dis_locals (m, mh);
401         dissasemble_cil (m, mh);
402         
403 /*
404   hex_dump (mh->code, 0, mh->code_size);
405   printf ("\nAfter the code\n");
406   hex_dump (mh->code + mh->code_size, 0, 64);
407 */
408         mono_metadata_free_mh (mh);
409 }
410
411 static char *
412 pinvoke_info (MonoImage *m, guint32 mindex)
413 {
414         MonoTableInfo *im = &m->tables [MONO_TABLE_IMPLMAP];
415         MonoTableInfo *mr = &m->tables [MONO_TABLE_MODULEREF];
416         guint32 im_cols [MONO_IMPLMAP_SIZE];
417         guint32 mr_cols [MONO_MODULEREF_SIZE];
418         const char *import, *scope;
419         char *flags;
420         int i;
421
422         for (i = 0; i < im->rows; i++) {
423
424                 mono_metadata_decode_row (im, i, im_cols, MONO_IMPLMAP_SIZE);
425
426                 if ((im_cols [MONO_IMPLMAP_MEMBER] >> 1) == mindex + 1) {
427
428                         flags = pinvoke_flags (im_cols [MONO_IMPLMAP_FLAGS]);
429
430                         import = mono_metadata_string_heap (m, im_cols [MONO_IMPLMAP_NAME]);
431
432                         mono_metadata_decode_row (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, 
433                                                   mr_cols, MONO_MODULEREF_SIZE);
434
435                         scope = mono_metadata_string_heap (m, mr_cols [MONO_MODULEREF_NAME]);
436                                 
437                         return g_strdup_printf ("(%s as %s %s)", scope, import,
438                                                 flags);
439                         g_free (flags);
440                 }
441         }
442
443         return NULL;
444 }
445
446 /**
447  * dis_method_list:
448  * @m: metadata context
449  * @start: starting index into the Method Table.
450  * @end: ending index into Method table.
451  *
452  * This routine displays the methods in the Method Table from @start to @end
453  */
454 static void
455 dis_method_list (MonoImage *m, guint32 start, guint32 end)
456 {
457         MonoTableInfo *t = &m->tables [MONO_TABLE_METHOD];
458         guint32 cols [MONO_METHOD_SIZE];
459         int i;
460
461         if (end > t->rows){
462                 fprintf (output, "ERROR index out of range in methods");
463                 /*exit (1);*/
464                 end = t->rows;
465         }
466
467         for (i = start; i < end; i++){
468                 MonoMethodSignature *ms;
469                 char *flags, *impl_flags;
470                 const char *sig;
471                 char *sig_str;
472                 
473                 mono_metadata_decode_row (t, i, cols, MONO_METHOD_SIZE);
474
475                 flags = method_flags (cols [MONO_METHOD_FLAGS]);
476                 impl_flags = method_impl_flags (cols [MONO_METHOD_IMPLFLAGS]);
477
478                 sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
479                 mono_metadata_decode_blob_size (sig, &sig);
480                 ms = mono_metadata_parse_method_signature (m, 1, sig, &sig);
481                 sig_str = dis_stringify_method_signature (m, ms, i + 1);
482                         
483                 fprintf (output, "    // method line %d\n", i + 1);
484                 fprintf (output, "    .method %s", flags);
485
486                 if (cols [MONO_METHOD_FLAGS] & METHOD_ATTRIBUTE_PINVOKE_IMPL)
487                         fprintf (output, "%s", pinvoke_info (m, i));
488
489                 fprintf (output, "\n           %s", sig_str);
490                 fprintf (output, " %s\n", impl_flags);
491                 g_free (flags);
492                 g_free (impl_flags);
493                 
494                 fprintf (output, "    {\n");
495                 fprintf (output, "        // Method begins at RVA 0x%x\n", cols [MONO_METHOD_RVA]);
496                 dis_code (m, cols [MONO_METHOD_RVA]);
497                 fprintf (output, "    } // end of method %s\n\n", sig_str);
498                 mono_metadata_free_method_signature (ms);
499                 g_free (sig_str);
500         }
501 }
502
503 typedef struct {
504         MonoTableInfo *t;
505         guint32 col_idx;
506         guint32 idx;
507         guint32 result;
508 } plocator_t;
509
510 static int
511 table_locator (const void *a, const void *b)
512 {
513         plocator_t *loc = (plocator_t *) a;
514         const char *bb = (const char *) b;
515         guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
516         guint32 col;
517         
518         col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
519
520         if (loc->idx == col) {
521                 loc->result = table_index;
522                 return 0;
523         }
524         if (loc->idx < col)
525                 return -1;
526         else 
527                 return 1;
528 }
529
530 static void
531 dis_property_methods (MonoImage *m, guint32 prop)
532 {
533         guint start, end;
534         MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
535         guint32 cols [MONO_METHOD_SEMA_SIZE];
536         char *sig;
537         const char *type[] = {NULL, ".set", ".get", NULL, ".other"};
538
539         start = mono_metadata_methods_from_property (m, prop, &end);
540         while (start < end) {
541                 mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
542                 sig = dis_stringify_method_signature (m, NULL, cols [MONO_METHOD_SEMA_METHOD]);
543                 fprintf (output, "\t\t%s %s\n", type [cols [MONO_METHOD_SEMA_SEMANTICS]], sig);
544                 g_free (sig);
545                 ++start;
546         }
547 }
548
549 static char*
550 dis_property_signature (MonoImage *m, guint32 prop_idx)
551 {
552         MonoTableInfo *propt = &m->tables [MONO_TABLE_PROPERTY];
553         const char *ptr;
554         guint32 pcount, i;
555         guint32 cols [MONO_PROPERTY_SIZE];
556         MonoType *type;
557         MonoType *param;
558         char *blurb;
559         const char *name;
560         int prop_flags;
561         GString *res = g_string_new ("");
562
563         mono_metadata_decode_row (propt, prop_idx, cols, MONO_PROPERTY_SIZE);
564         name = mono_metadata_string_heap (m, cols [MONO_PROPERTY_NAME]);
565         prop_flags = cols [MONO_PROPERTY_FLAGS];
566         ptr = mono_metadata_blob_heap (m, cols [MONO_PROPERTY_TYPE]);
567         mono_metadata_decode_blob_size (ptr, &ptr);
568         /* ECMA claims 0x08 ... */
569         if (*ptr != 0x28 && *ptr != 0x08)
570                 g_warning("incorrect signature in propert blob: 0x%x", *ptr);
571         ptr++;
572         pcount = mono_metadata_decode_value (ptr, &ptr);
573         type = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
574         blurb = dis_stringify_type (m, type);
575         if (prop_flags & 0x0200)
576                 g_string_append (res, "special ");
577         if (prop_flags & 0x0400)
578                 g_string_append (res, "runtime ");
579         if (prop_flags & 0x1000)
580                 g_string_append (res, "hasdefault ");
581         g_string_sprintfa (res, "%s %s (", blurb, name);
582         g_free (blurb);
583         mono_metadata_free_type (type);
584         for (i = 0; i < pcount; i++) {
585                 if (i)
586                         g_string_append (res, ", ");
587                 param = mono_metadata_parse_param (m, ptr, &ptr);
588                 blurb = dis_stringify_param (m, param);
589                 g_string_append (res, blurb);
590                 mono_metadata_free_type (param);
591                 g_free (blurb);
592         }
593         g_string_append_c (res, ')');
594         blurb = res->str;
595         g_string_free (res, FALSE);
596         return blurb;
597
598 }
599
600 static void
601 dis_property_list (MonoImage *m, guint32 typedef_row)
602 {
603         guint start, end, i;
604         start = mono_metadata_properties_from_typedef (m, typedef_row, &end);
605
606         for (i = start; i < end; ++i) {
607                 char *sig = dis_property_signature (m, i);
608                 fprintf (output, "\t.property %s\n\t{\n", sig);
609                 dis_property_methods (m, i);
610                 fprintf (output, "\t}\n");
611                 g_free (sig);
612         }
613 }
614
615 static char*
616 dis_event_signature (MonoImage *m, guint32 event_idx)
617 {
618         MonoTableInfo *et = &m->tables [MONO_TABLE_EVENT];
619         const char *name;
620         char *type, *res;
621         guint32 cols [MONO_EVENT_SIZE];
622         
623         mono_metadata_decode_row (et, event_idx, cols, MONO_EVENT_SIZE);
624         name = mono_metadata_string_heap (m, cols [MONO_EVENT_NAME]);
625         type = get_typedef_or_ref (m, cols [MONO_EVENT_TYPE]);
626
627         res = g_strdup_printf ("%s %s", type, name);
628         g_free (type);
629         return res;
630 }
631
632 static void
633 dis_event_methods (MonoImage *m, guint32 event)
634 {
635         guint start, end;
636         MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
637         guint32 cols [MONO_METHOD_SEMA_SIZE];
638         char *sig;
639         const char *type;
640
641         start = mono_metadata_methods_from_event (m, event, &end);
642         while (start < end) {
643                 mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
644                 sig = dis_stringify_method_signature (m, NULL, cols [MONO_METHOD_SEMA_METHOD]);
645                 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
646                 case METHOD_SEMANTIC_OTHER:
647                         type = ".other"; break;
648                 case METHOD_SEMANTIC_ADD_ON:
649                         type = ".addon"; break;
650                 case METHOD_SEMANTIC_REMOVE_ON:
651                         type = ".removeon"; break;
652                 case METHOD_SEMANTIC_FIRE:
653                         type = ".fire"; break;
654                 default:
655                         break;
656                 }
657                 fprintf (output, "\t\t%s %s\n", type, sig);
658                 g_free (sig);
659                 ++start;
660         }
661 }
662
663 static void
664 dis_event_list (MonoImage *m, guint32 typedef_row)
665 {
666         guint start, end, i;
667         start = mono_metadata_events_from_typedef (m, typedef_row, &end);
668
669         for (i = start; i < end; ++i) {
670                 char *sig = dis_event_signature (m, i);
671                 fprintf (output, "\t.event %s\n\t{\n", sig);
672                 dis_event_methods (m, i);
673                 fprintf (output, "\t}\n");
674                 g_free (sig);
675         }
676 }
677
678 static void
679 dis_interfaces (MonoImage *m, guint32 typedef_row)
680 {
681         plocator_t loc;
682         guint start;
683         guint32 cols [MONO_INTERFACEIMPL_SIZE];
684         char *intf;
685         MonoTableInfo *table = &m->tables [MONO_TABLE_INTERFACEIMPL];
686
687         if (!table->base)
688                 return;
689
690         loc.t = table;
691         loc.col_idx = MONO_INTERFACEIMPL_CLASS;
692         loc.idx = typedef_row;
693
694         if (!bsearch (&loc, table->base, table->rows, table->row_size, table_locator))
695                 return;
696
697         start = loc.result;
698         /*
699          * We may end up in the middle of the rows... 
700          */
701         while (start > 0) {
702                 if (loc.idx == mono_metadata_decode_row_col (table, start - 1, MONO_INTERFACEIMPL_CLASS))
703                         start--;
704                 else
705                         break;
706         }
707         while (start < table->rows) {
708                 mono_metadata_decode_row (table, start, cols, MONO_INTERFACEIMPL_SIZE);
709                 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
710                         break;
711                 intf = get_typedef_or_ref (m, cols [MONO_INTERFACEIMPL_INTERFACE]);
712                 fprintf (output, "  \timplements %s\n", intf);
713                 g_free (intf);
714                 ++start;
715         }
716 }
717
718 /**
719  * dis_type:
720  * @m: metadata context
721  * @n: index of type to disassemble
722  *
723  * Disassembles the type whose index in the TypeDef table is @n.
724  */
725 static void
726 dis_type (MonoImage *m, int n)
727 {
728         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
729         guint32 cols [MONO_TYPEDEF_SIZE];
730         guint32 cols_next [MONO_TYPEDEF_SIZE];
731         const char *name, *nspace;
732         guint32 packing_size, class_size;
733         gboolean next_is_valid, last;
734         
735         mono_metadata_decode_row (t, n, cols, MONO_TYPEDEF_SIZE);
736
737         if (t->rows > n + 1) {
738                 mono_metadata_decode_row (t, n + 1, cols_next, MONO_TYPEDEF_SIZE);
739                 next_is_valid = 1;
740         } else
741                 next_is_valid = 0;
742
743         nspace = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE]);
744         if (*nspace)
745                 fprintf (output, ".namespace %s\n{\n", nspace);
746         name = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME]);
747
748         if ((cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
749                 char *base = get_typedef_or_ref (m, cols [MONO_TYPEDEF_EXTENDS]);
750                 fprintf (output, "  .class %s%s\n", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), name);
751                 fprintf (output, "  \textends %s\n", base);
752                 g_free (base);
753         } else
754                 fprintf (output, "  .class interface %s%s\n", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), name);
755         
756         dis_interfaces (m, n + 1);
757         fprintf (output, "  {\n");
758
759         if (mono_metadata_packing_from_typedef (m, n + 1, &packing_size, &class_size)) {
760                 fprintf (output, "    .pack %d\n", packing_size);
761                 fprintf (output, "    .size %d\n", class_size);
762         }
763         /*
764          * The value in the table is always valid, we know we have fields
765          * if the value stored is different than the next record.
766          */
767
768         if (next_is_valid)
769                 last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
770         else
771                 last = m->tables [MONO_TABLE_FIELD].rows;
772                         
773         if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= m->tables [MONO_TABLE_FIELD].rows)
774                 dis_field_list (m, cols [MONO_TYPEDEF_FIELD_LIST] - 1, last);
775         fprintf (output, "\n");
776
777         if (next_is_valid)
778                 last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
779         else
780                 last = m->tables [MONO_TABLE_METHOD].rows;
781         
782         if (cols [MONO_TYPEDEF_METHOD_LIST] && cols [MONO_TYPEDEF_METHOD_LIST] <= m->tables [MONO_TABLE_METHOD].rows)
783                 dis_method_list (m, cols [MONO_TYPEDEF_METHOD_LIST] - 1, last);
784
785         dis_property_list (m, n);
786         dis_event_list (m, n);
787
788         fprintf (output, "  } // end of type %s%s%s\n", nspace, *nspace? ".": "", name);
789         if (*nspace)
790                 fprintf (output, "}\n");
791         fprintf (output, "\n");
792 }
793
794 /**
795  * dis_types:
796  * @m: metadata context
797  *
798  * disassembles all types in the @m context
799  */
800 static void
801 dis_types (MonoImage *m)
802 {
803         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
804         int i;
805
806         for (i = 1; i < t->rows; i++)
807                 dis_type (m, i);
808 }
809
810 /**
811  * dis_data:
812  * @m: metadata context
813  *
814  * disassembles all data blobs references in the FieldRVA table in the @m context
815  */
816 static void
817 dis_data (MonoImage *m)
818 {
819         MonoTableInfo *t = &m->tables [MONO_TABLE_FIELDRVA];
820         MonoTableInfo *ft = &m->tables [MONO_TABLE_FIELD];
821         int i, b;
822         const char *rva, *sig;
823         guint32 align, size;
824         guint32 cols [MONO_FIELD_RVA_SIZE];
825         MonoType *type;
826
827         for (i = 0; i < t->rows; i++) {
828                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_RVA_SIZE);
829                 rva = mono_cli_rva_map (m->image_info, cols [MONO_FIELD_RVA_RVA]);
830                 sig = mono_metadata_blob_heap (m, mono_metadata_decode_row_col (ft, cols [MONO_FIELD_RVA_FIELD] -1, MONO_FIELD_SIGNATURE));
831                 mono_metadata_decode_value (sig, &sig);
832                 /* FIELD signature == 0x06 */
833                 g_assert (*sig == 0x06);
834                 type = mono_metadata_parse_field_type (m, 0, sig + 1, &sig);
835                 mono_class_init (mono_class_from_mono_type (type));
836                 size = mono_class_value_size (mono_class_from_mono_type (type), &align);
837                 fprintf (output, ".data D_%08x = bytearray (", cols [MONO_FIELD_RVA_RVA]);
838                 for (b = 0; b < size; ++b) {
839                         if (!(b % 16))
840                                 fprintf (output, "\n\t");
841                         fprintf (output, " %02x", rva [b]);
842                 }
843                 fprintf (output, ") // size: %d\n", size);
844         }
845 }
846
847 struct {
848         const char *name;
849         int table;
850         void (*dumper) (MonoImage *m);
851 } table_list [] = {
852         { "--assembly",    MONO_TABLE_ASSEMBLY,    dump_table_assembly },
853         { "--assemblyref", MONO_TABLE_ASSEMBLYREF, dump_table_assemblyref },
854         { "--fields",      MONO_TABLE_FIELD,       dump_table_field },
855         { "--memberref",   MONO_TABLE_MEMBERREF,   dump_table_memberref },
856         { "--param",       MONO_TABLE_PARAM,       dump_table_param },
857         { "--typedef",     MONO_TABLE_TYPEDEF,     dump_table_typedef },
858         { "--typeref",     MONO_TABLE_TYPEREF,     dump_table_typeref },
859         { "--exported",    MONO_TABLE_EXPORTEDTYPE,     dump_table_exported },
860         { "--nested",      MONO_TABLE_NESTEDCLASS, dump_table_nestedclass },
861         { "--interface",   MONO_TABLE_INTERFACEIMPL,     dump_table_interfaceimpl },
862         { "--classlayout", MONO_TABLE_CLASSLAYOUT, dump_table_class_layout },
863         { "--constant",    MONO_TABLE_CONSTANT,    dump_table_constant },
864         { "--customattr",  MONO_TABLE_CUSTOMATTRIBUTE,    dump_table_customattr },
865         { "--property",    MONO_TABLE_PROPERTY,    dump_table_property },
866         { "--propertymap", MONO_TABLE_PROPERTYMAP, dump_table_property_map },
867         { "--event",       MONO_TABLE_EVENT,       dump_table_event },
868         { "--file",        MONO_TABLE_FILE,        dump_table_file },
869         { "--moduleref",   MONO_TABLE_MODULEREF,   dump_table_moduleref },
870         { "--module",      MONO_TABLE_MODULE,      dump_table_module },
871         { "--method",      MONO_TABLE_METHOD,      dump_table_method },
872         { "--methodsem",   MONO_TABLE_METHODSEMANTICS,      dump_table_methodsem },
873         { "--manifest",    MONO_TABLE_MANIFESTRESOURCE,     dump_table_manifest },
874         { NULL, -1 }
875 };
876
877 /**
878  * disassemble_file:
879  * @file: file containing CIL code.
880  *
881  * Disassembles the @file file.
882  */
883 static void
884 disassemble_file (const char *file)
885 {
886         MonoAssembly *ass;
887         MonoImageOpenStatus status;
888         MonoImage *img;
889
890         ass = mono_assembly_open (file, &status);
891         if (ass == NULL){
892                 fprintf (stderr, "Error while trying to process %s\n", file);
893                 return;
894         }
895
896         img = ass->image;
897
898         if (dump_table != -1){
899                 (*table_list [dump_table].dumper) (img);
900         } else {
901                 dump_header_data (img);
902                 
903                 dis_directive_assemblyref (img);
904                 dis_directive_assembly (img);
905                 dis_types (img);
906                 dis_data (img);
907         }
908         
909         mono_image_close (img);
910 }
911
912 static void
913 usage (void)
914 {
915         GString *args = g_string_new ("[--help] [--mscorlib] ");
916         int i;
917         
918         for (i = 0; table_list [i].name != NULL; i++){
919                 g_string_append (args, "[");
920                 g_string_append (args, table_list [i].name);
921                 g_string_append (args, "] ");
922                 if (((i-2) % 5) == 0)
923                         g_string_append_c (args, '\n');
924         }
925         fprintf (stderr,
926                  "Usage is: monodis %s file ..\n", args->str);
927         exit (1);
928 }
929
930 int
931 main (int argc, char *argv [])
932 {
933         GList *input_files = NULL, *l;
934         int i, j;
935
936         output = stdout;
937         for (i = 1; i < argc; i++){
938                 if (argv [i][0] == '-'){
939                         if (argv [i][1] == 'h')
940                                 usage ();
941                         else if (argv [i][1] == 'd')
942                                 dump_header_data_p = TRUE;
943                         else if (strcmp (argv [i], "--mscorlib") == 0) {
944                                 substitute_with_mscorlib_p = TRUE;
945                                 i++;
946                         }
947                         else if (strcmp (argv [i], "--help") == 0)
948                                 usage ();
949                         for (j = 0; table_list [j].name != NULL; j++) {
950                                 if (strcmp (argv [i], table_list [j].name) == 0)
951                                         dump_table = j;
952                         }
953                         if (dump_table < 0)
954                                 usage ();
955                 } else
956                         input_files = g_list_append (input_files, argv [i]);
957         }
958
959         if (input_files == NULL)
960                 usage ();
961         
962         mono_init (argv [0]);
963
964         for (l = input_files; l; l = l->next)
965                 disassemble_file (l->data);
966
967         return 0;
968 }