0e2ca5b9746af8418990a923ddfacef7d7fe56ae
[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         int i;
174
175         if (end > t->rows + 1) {
176                 g_warning ("ERROR index out of range in fields");
177                 end = t->rows;
178         }
179                         
180         for (i = start; i < end; i++){
181                 char *sig, *flags, *attrs = NULL;
182                 guint32 field_offset = -1;
183                 
184                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
185                 sig = get_field_signature (m, cols [MONO_FIELD_SIGNATURE]);
186                 flags = field_flags (cols [MONO_FIELD_FLAGS]);
187                 
188                 mono_metadata_field_info (m, i, &field_offset, NULL, NULL);
189                 if (field_offset != -1)
190                         attrs = g_strdup_printf ("[%d]", field_offset);
191                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_LITERAL){
192                         char *lit;
193                         guint32 const_cols [MONO_CONSTANT_SIZE];
194                         guint32 crow;
195                         
196                         if ((crow = mono_metadata_get_constant_index (m, MONO_TOKEN_FIELD_DEF | (i+1)))) {
197                                 mono_metadata_decode_row (&m->tables [MONO_TABLE_CONSTANT], crow-1, const_cols, MONO_CONSTANT_SIZE);
198                                 lit = get_constant (m, const_cols [MONO_CONSTANT_TYPE], const_cols [MONO_CONSTANT_VALUE]);
199                         } else {
200                                 lit = g_strdup ("not found");
201                         }
202                         
203                         fprintf (output, "    .field %s %s %s = ",
204                                  flags, sig,
205                                  mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
206                         fprintf (output, "%s\n", lit);
207                         g_free (lit);
208                 } else 
209                         fprintf (output, "    .field %s %s %s %s\n",
210                                  attrs? attrs: "", flags, sig,
211                                  mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
212                 g_free (attrs);
213                 g_free (flags);
214                 g_free (sig);
215         }
216 }
217
218 static map_t method_access_map [] = {
219         { METHOD_ATTRIBUTE_COMPILER_CONTROLLED, "compilercontrolled " },
220         { METHOD_ATTRIBUTE_PRIVATE,             "private" },
221         { METHOD_ATTRIBUTE_FAM_AND_ASSEM,       "famandassem" },
222         { METHOD_ATTRIBUTE_ASSEM,               "assembly " },
223         { METHOD_ATTRIBUTE_FAMILY,              "family " },
224         { METHOD_ATTRIBUTE_FAM_OR_ASSEM,        "famorassem " },
225         { METHOD_ATTRIBUTE_PUBLIC,              "public " },
226         { 0, NULL }
227 };
228
229 static map_t method_flags_map [] = {
230         { METHOD_ATTRIBUTE_STATIC,              "static " },
231         { METHOD_ATTRIBUTE_FINAL,               "final " },
232         { METHOD_ATTRIBUTE_VIRTUAL,             "virtual " },
233         { METHOD_ATTRIBUTE_HIDE_BY_SIG,         "hidebysig " },
234         { METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK,  "newslot " },
235         { METHOD_ATTRIBUTE_ABSTRACT,            "abstract " },
236         { METHOD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
237         { METHOD_ATTRIBUTE_RT_SPECIAL_NAME,     "rtspecialname " },
238         { METHOD_ATTRIBUTE_UNMANAGED_EXPORT,    "export " },
239         { METHOD_ATTRIBUTE_HAS_SECURITY,        "hassecurity" },
240         { METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT,  "requiresecobj" },
241         { METHOD_ATTRIBUTE_PINVOKE_IMPL,        "pinvokeimpl " }, 
242         { 0, NULL }
243 };
244
245 /**
246  * method_flags:
247  *
248  * Returns a stringified version of the Method's flags
249  */
250 static char *
251 method_flags (guint32 f)
252 {
253         GString *str = g_string_new ("");
254         int access = f & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
255         char *s;
256         
257         g_string_append (str, map (access, method_access_map));
258         g_string_append (str, flags (f, method_flags_map));
259
260         s = str->str;
261         g_string_free (str, FALSE);
262
263         return s;
264 }
265
266 static map_t pinvoke_flags_map [] = {
267         { PINVOKE_ATTRIBUTE_NO_MANGLE ,            "nomangle " },
268         { PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR,   "lasterr " },
269         { 0, NULL }
270 };
271
272 static map_t pinvoke_call_conv_map [] = {
273         { PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI,      "winapi " },
274         { PINVOKE_ATTRIBUTE_CALL_CONV_CDECL,       "cdecl " },
275         { PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL,     "stdcall " },
276         { PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL,    "thiscall " },
277         { PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL,    "fastcall " },
278         { 0, NULL }
279 };
280
281 static map_t pinvoke_char_set_map [] = {
282         { PINVOKE_ATTRIBUTE_CHAR_SET_NOT_SPEC,     "" },
283         { PINVOKE_ATTRIBUTE_CHAR_SET_ANSI,         "ansi " },
284         { PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE ,     "unicode " },
285         { PINVOKE_ATTRIBUTE_CHAR_SET_AUTO,         "autochar " },
286         { 0, NULL }
287 };
288
289 /**
290  * pinvoke_flags:
291  *
292  * Returns a stringified version of the Method's pinvoke flags
293  */
294 static char *
295 pinvoke_flags (guint32 f)
296 {
297         GString *str = g_string_new ("");
298         int cset = f & PINVOKE_ATTRIBUTE_CHAR_SET_MASK;
299         int cconv = f & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
300         char *s;
301         
302         g_string_append (str, map (cset, pinvoke_char_set_map));
303         g_string_append (str, map (cconv, pinvoke_call_conv_map));
304         g_string_append (str, flags (f, pinvoke_flags_map));
305
306         s = g_strdup(str->str);
307         g_string_free (str, FALSE);
308
309         return s;
310 }
311
312 static map_t method_impl_map [] = {
313         { METHOD_IMPL_ATTRIBUTE_IL,              "cil " },
314         { METHOD_IMPL_ATTRIBUTE_NATIVE,          "native " },
315         { METHOD_IMPL_ATTRIBUTE_OPTIL,           "optil " },
316         { METHOD_IMPL_ATTRIBUTE_RUNTIME,         "runtime " },
317         { 0, NULL }
318 };
319
320 static map_t managed_type_map [] = {
321         { METHOD_IMPL_ATTRIBUTE_UNMANAGED,       "unmanaged " },
322         { METHOD_IMPL_ATTRIBUTE_MANAGED,         "managed " },
323         { 0, NULL }
324 };
325
326 static map_t managed_impl_flags [] = {
327         { METHOD_IMPL_ATTRIBUTE_FORWARD_REF,     "fwdref " },
328         { METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG,    "preservesig " },
329         { METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL,   "internalcall " },
330         { METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED,    "synchronized " },
331         { METHOD_IMPL_ATTRIBUTE_NOINLINING,      "noinline " },
332         { 0, NULL }
333 };
334
335 static char *
336 method_impl_flags (guint32 f)
337 {
338         GString *str = g_string_new ("");
339         char *s;
340         int code_type = f & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
341         int managed_type = f & METHOD_IMPL_ATTRIBUTE_MANAGED_MASK;
342
343         g_string_append (str, map (code_type, method_impl_map));
344         g_string_append (str, map (managed_type, managed_type_map));
345         g_string_append (str, flags (f, managed_impl_flags));
346         
347         s = str->str;
348         g_string_free (str, FALSE);
349         return s;
350 }
351
352 static void
353 dis_locals (MonoImage *m, MonoMethodHeader *mh) 
354 {
355         int i;
356
357         fprintf(output, "\t.locals %s(\n", mh->init_locals ? "init " : "");
358         for (i=0; i < mh->num_locals; ++i) {
359                 char * desc;
360                 if (i)
361                         fprintf(output, ",\n");
362                 /* print also byref and pinned attributes */
363                 desc = dis_stringify_type (m, mh->locals[i]);
364                 fprintf(output, "\t\t%s\tV_%d", desc, i);
365                 g_free(desc);
366         }
367         fprintf(output, ")\n");
368 }
369
370 static void
371 dis_code (MonoImage *m, guint32 rva)
372 {
373         MonoMethodHeader *mh;
374         MonoCLIImageInfo *ii = m->image_info;
375         const char *ptr = mono_cli_rva_map (ii, rva);
376         const char *loc;
377
378         if (rva == 0)
379                 return;
380
381         mh = mono_metadata_parse_mh (m, ptr);
382         if (ii->cli_cli_header.ch_entry_point){
383                 loc = mono_metadata_locate_token (m, ii->cli_cli_header.ch_entry_point);
384                 if (rva == read32 (loc))
385                         fprintf (output, "\t.entrypoint\n");
386         }
387         
388         fprintf (output, "\t// Code size %d (0x%x)\n", mh->code_size, mh->code_size);
389         fprintf (output, "\t.maxstack %d\n", mh->max_stack);
390         if (mh->num_locals)
391                 dis_locals (m, mh);
392         dissasemble_cil (m, mh);
393         
394 /*
395   hex_dump (mh->code, 0, mh->code_size);
396   printf ("\nAfter the code\n");
397   hex_dump (mh->code + mh->code_size, 0, 64);
398 */
399         mono_metadata_free_mh (mh);
400 }
401
402 static char *
403 pinvoke_info (MonoImage *m, guint32 mindex)
404 {
405         MonoTableInfo *im = &m->tables [MONO_TABLE_IMPLMAP];
406         MonoTableInfo *mr = &m->tables [MONO_TABLE_MODULEREF];
407         guint32 im_cols [MONO_IMPLMAP_SIZE];
408         guint32 mr_cols [MONO_MODULEREF_SIZE];
409         const char *import, *scope;
410         char *flags;
411         int i;
412
413         for (i = 0; i < im->rows; i++) {
414
415                 mono_metadata_decode_row (im, i, im_cols, MONO_IMPLMAP_SIZE);
416
417                 if ((im_cols [MONO_IMPLMAP_MEMBER] >> 1) == mindex + 1) {
418
419                         flags = pinvoke_flags (im_cols [MONO_IMPLMAP_FLAGS]);
420
421                         import = mono_metadata_string_heap (m, im_cols [MONO_IMPLMAP_NAME]);
422
423                         mono_metadata_decode_row (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, 
424                                                   mr_cols, MONO_MODULEREF_SIZE);
425
426                         scope = mono_metadata_string_heap (m, mr_cols [MONO_MODULEREF_NAME]);
427                                 
428                         return g_strdup_printf ("(%s as %s %s)", scope, import,
429                                                 flags);
430                         g_free (flags);
431                 }
432         }
433
434         return NULL;
435 }
436
437 /**
438  * dis_method_list:
439  * @m: metadata context
440  * @start: starting index into the Method Table.
441  * @end: ending index into Method table.
442  *
443  * This routine displays the methods in the Method Table from @start to @end
444  */
445 static void
446 dis_method_list (MonoImage *m, guint32 start, guint32 end)
447 {
448         MonoTableInfo *t = &m->tables [MONO_TABLE_METHOD];
449         guint32 cols [MONO_METHOD_SIZE];
450         int i;
451
452         if (end > t->rows){
453                 fprintf (output, "ERROR index out of range in methods");
454                 /*exit (1);*/
455                 end = t->rows;
456         }
457
458         for (i = start; i < end; i++){
459                 MonoMethodSignature *ms;
460                 char *flags, *impl_flags;
461                 const char *sig;
462                 char *sig_str;
463                 
464                 mono_metadata_decode_row (t, i, cols, MONO_METHOD_SIZE);
465
466                 flags = method_flags (cols [MONO_METHOD_FLAGS]);
467                 impl_flags = method_impl_flags (cols [MONO_METHOD_IMPLFLAGS]);
468
469                 sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
470                 mono_metadata_decode_blob_size (sig, &sig);
471                 ms = mono_metadata_parse_method_signature (m, 1, sig, &sig);
472                 sig_str = dis_stringify_method_signature (m, ms, i + 1);
473                         
474                 fprintf (output, "    // method line %d\n", i + 1);
475                 fprintf (output, "    .method %s", flags);
476
477                 if (cols [MONO_METHOD_FLAGS] & METHOD_ATTRIBUTE_PINVOKE_IMPL)
478                         fprintf (output, "%s", pinvoke_info (m, i));
479
480                 fprintf (output, "\n           %s", sig_str);
481                 fprintf (output, " %s\n", impl_flags);
482                 g_free (flags);
483                 g_free (impl_flags);
484                 
485                 fprintf (output, "    {\n");
486                 fprintf (output, "        // Method begins at RVA 0x%x\n", cols [MONO_METHOD_RVA]);
487                 dis_code (m, cols [MONO_METHOD_RVA]);
488                 fprintf (output, "    }\n\n");
489                 mono_metadata_free_method_signature (ms);
490                 g_free (sig_str);
491         }
492 }
493
494 typedef struct {
495         MonoTableInfo *t;
496         guint32 col_idx;
497         guint32 idx;
498         guint32 result;
499 } plocator_t;
500
501 static int
502 table_locator (const void *a, const void *b)
503 {
504         plocator_t *loc = (plocator_t *) a;
505         const char *bb = (const char *) b;
506         guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
507         guint32 col;
508         
509         col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
510
511         if (loc->idx == col) {
512                 loc->result = table_index;
513                 return 0;
514         }
515         if (loc->idx < col)
516                 return -1;
517         else 
518                 return 1;
519 }
520
521 static void
522 dis_property_methods (MonoImage *m, guint32 prop)
523 {
524         guint start, end;
525         MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
526         guint32 cols [MONO_METHOD_SEMA_SIZE];
527         char *sig;
528         const char *type[] = {NULL, ".set", ".get", NULL, ".other"};
529
530         start = mono_metadata_methods_from_property (m, prop, &end);
531         while (start < end) {
532                 mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
533                 sig = dis_stringify_method_signature (m, NULL, cols [MONO_METHOD_SEMA_METHOD]);
534                 fprintf (output, "\t\t%s %s\n", type [cols [MONO_METHOD_SEMA_SEMANTICS]], sig);
535                 g_free (sig);
536                 ++start;
537         }
538 }
539
540 static char*
541 dis_property_signature (MonoImage *m, guint32 prop_idx)
542 {
543         MonoTableInfo *propt = &m->tables [MONO_TABLE_PROPERTY];
544         const char *ptr;
545         guint32 pcount, i;
546         guint32 cols [MONO_PROPERTY_SIZE];
547         MonoType *type;
548         MonoType *param;
549         char *blurb;
550         const char *name;
551         int prop_flags;
552         GString *res = g_string_new ("");
553
554         mono_metadata_decode_row (propt, prop_idx, cols, MONO_PROPERTY_SIZE);
555         name = mono_metadata_string_heap (m, cols [MONO_PROPERTY_NAME]);
556         prop_flags = cols [MONO_PROPERTY_FLAGS];
557         ptr = mono_metadata_blob_heap (m, cols [MONO_PROPERTY_TYPE]);
558         mono_metadata_decode_blob_size (ptr, &ptr);
559         /* ECMA claims 0x08 ... */
560         if (*ptr != 0x28 && *ptr != 0x08)
561                 g_warning("incorrect signature in propert blob: 0x%x", *ptr);
562         ptr++;
563         pcount = mono_metadata_decode_value (ptr, &ptr);
564         type = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
565         blurb = dis_stringify_type (m, type);
566         if (prop_flags & 0x0200)
567                 g_string_append (res, "special ");
568         if (prop_flags & 0x0400)
569                 g_string_append (res, "runtime ");
570         if (prop_flags & 0x1000)
571                 g_string_append (res, "hasdefault ");
572         g_string_sprintfa (res, "%s %s (", blurb, name);
573         g_free (blurb);
574         mono_metadata_free_type (type);
575         for (i = 0; i < pcount; i++) {
576                 if (i)
577                         g_string_append (res, ", ");
578                 param = mono_metadata_parse_param (m, ptr, &ptr);
579                 blurb = dis_stringify_param (m, param);
580                 g_string_append (res, blurb);
581                 mono_metadata_free_type (param);
582                 g_free (blurb);
583         }
584         g_string_append_c (res, ')');
585         blurb = res->str;
586         g_string_free (res, FALSE);
587         return blurb;
588
589 }
590
591 static void
592 dis_property_list (MonoImage *m, guint32 typedef_row)
593 {
594         guint start, end, i;
595         start = mono_metadata_properties_from_typedef (m, typedef_row, &end);
596
597         for (i = start; i < end; ++i) {
598                 char *sig = dis_property_signature (m, i);
599                 fprintf (output, "\t.property %s\n\t{\n", sig);
600                 dis_property_methods (m, i);
601                 fprintf (output, "\t}\n");
602                 g_free (sig);
603         }
604 }
605
606 static char*
607 dis_event_signature (MonoImage *m, guint32 event_idx)
608 {
609         MonoTableInfo *et = &m->tables [MONO_TABLE_EVENT];
610         const char *name;
611         char *type, *res;
612         guint32 cols [MONO_EVENT_SIZE];
613         
614         mono_metadata_decode_row (et, event_idx, cols, MONO_EVENT_SIZE);
615         name = mono_metadata_string_heap (m, cols [MONO_EVENT_NAME]);
616         type = get_typedef_or_ref (m, cols [MONO_EVENT_TYPE]);
617
618         res = g_strdup_printf ("%s %s", type, name);
619         g_free (type);
620         return res;
621 }
622
623 static void
624 dis_event_methods (MonoImage *m, guint32 event)
625 {
626         guint start, end;
627         MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
628         guint32 cols [MONO_METHOD_SEMA_SIZE];
629         char *sig;
630         const char *type;
631
632         start = mono_metadata_methods_from_event (m, event, &end);
633         while (start < end) {
634                 mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
635                 sig = dis_stringify_method_signature (m, NULL, cols [MONO_METHOD_SEMA_METHOD]);
636                 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
637                 case METHOD_SEMANTIC_OTHER:
638                         type = ".other"; break;
639                 case METHOD_SEMANTIC_ADD_ON:
640                         type = ".addon"; break;
641                 case METHOD_SEMANTIC_REMOVE_ON:
642                         type = ".removeon"; break;
643                 case METHOD_SEMANTIC_FIRE:
644                         type = ".fire"; break;
645                 default:
646                         break;
647                 }
648                 fprintf (output, "\t\t%s %s\n", type, sig);
649                 g_free (sig);
650                 ++start;
651         }
652 }
653
654 static void
655 dis_event_list (MonoImage *m, guint32 typedef_row)
656 {
657         guint start, end, i;
658         start = mono_metadata_events_from_typedef (m, typedef_row, &end);
659
660         for (i = start; i < end; ++i) {
661                 char *sig = dis_event_signature (m, i);
662                 fprintf (output, "\t.event %s\n\t{\n", sig);
663                 dis_event_methods (m, i);
664                 fprintf (output, "\t}\n");
665                 g_free (sig);
666         }
667 }
668
669 static void
670 dis_interfaces (MonoImage *m, guint32 typedef_row)
671 {
672         plocator_t loc;
673         guint start;
674         guint32 cols [MONO_INTERFACEIMPL_SIZE];
675         char *intf;
676         MonoTableInfo *table = &m->tables [MONO_TABLE_INTERFACEIMPL];
677
678         if (!table->base)
679                 return;
680
681         loc.t = table;
682         loc.col_idx = MONO_INTERFACEIMPL_CLASS;
683         loc.idx = typedef_row;
684
685         if (!bsearch (&loc, table->base, table->rows, table->row_size, table_locator))
686                 return;
687
688         start = loc.result;
689         /*
690          * We may end up in the middle of the rows... 
691          */
692         while (start > 0) {
693                 if (loc.idx == mono_metadata_decode_row_col (table, start - 1, MONO_INTERFACEIMPL_CLASS))
694                         start--;
695                 else
696                         break;
697         }
698         while (start < table->rows) {
699                 mono_metadata_decode_row (table, start, cols, MONO_INTERFACEIMPL_SIZE);
700                 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
701                         break;
702                 intf = get_typedef_or_ref (m, cols [MONO_INTERFACEIMPL_INTERFACE]);
703                 fprintf (output, "  \timplements %s\n", intf);
704                 g_free (intf);
705                 ++start;
706         }
707 }
708
709 /**
710  * dis_type:
711  * @m: metadata context
712  * @n: index of type to disassemble
713  *
714  * Disassembles the type whose index in the TypeDef table is @n.
715  */
716 static void
717 dis_type (MonoImage *m, int n)
718 {
719         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
720         guint32 cols [MONO_TYPEDEF_SIZE];
721         guint32 cols_next [MONO_TYPEDEF_SIZE];
722         const char *name, *nspace;
723         guint32 packing_size, class_size;
724         gboolean next_is_valid, last;
725         
726         mono_metadata_decode_row (t, n, cols, MONO_TYPEDEF_SIZE);
727
728         if (t->rows > n + 1) {
729                 mono_metadata_decode_row (t, n + 1, cols_next, MONO_TYPEDEF_SIZE);
730                 next_is_valid = 1;
731         } else
732                 next_is_valid = 0;
733
734         nspace = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE]);
735         if (*nspace)
736                 fprintf (output, ".namespace %s\n{\n", nspace);
737         name = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME]);
738
739         if ((cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
740                 char *base = get_typedef_or_ref (m, cols [MONO_TYPEDEF_EXTENDS]);
741                 fprintf (output, "  .class %s%s\n", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), name);
742                 fprintf (output, "  \textends %s\n", base);
743                 g_free (base);
744         } else
745                 fprintf (output, "  .class interface %s%s\n", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), name);
746         
747         dis_interfaces (m, n + 1);
748         fprintf (output, "  {\n");
749
750         if (mono_metadata_packing_from_typedef (m, n + 1, &packing_size, &class_size)) {
751                 fprintf (output, "    .pack %d\n", packing_size);
752                 fprintf (output, "    .size %d\n", class_size);
753         }
754         /*
755          * The value in the table is always valid, we know we have fields
756          * if the value stored is different than the next record.
757          */
758
759         if (next_is_valid)
760                 last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
761         else
762                 last = m->tables [MONO_TABLE_FIELD].rows;
763                         
764         if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= m->tables [MONO_TABLE_FIELD].rows)
765                 dis_field_list (m, cols [MONO_TYPEDEF_FIELD_LIST] - 1, last);
766         fprintf (output, "\n");
767
768         if (next_is_valid)
769                 last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
770         else
771                 last = m->tables [MONO_TABLE_METHOD].rows;
772         
773         if (cols [MONO_TYPEDEF_METHOD_LIST] && cols [MONO_TYPEDEF_METHOD_LIST] <= m->tables [MONO_TABLE_METHOD].rows)
774                 dis_method_list (m, cols [MONO_TYPEDEF_METHOD_LIST] - 1, last);
775
776         dis_property_list (m, n);
777         dis_event_list (m, n);
778
779         fprintf (output, "  }\n");
780         if (*nspace)
781                 fprintf (output, "}\n");
782         fprintf (output, "\n");
783 }
784
785 /**
786  * dis_types:
787  * @m: metadata context
788  *
789  * disassembles all types in the @m context
790  */
791 static void
792 dis_types (MonoImage *m)
793 {
794         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
795         int i;
796
797         for (i = 1; i < t->rows; i++)
798                 dis_type (m, i);
799 }
800
801 struct {
802         const char *name;
803         int table;
804         void (*dumper) (MonoImage *m);
805 } table_list [] = {
806         { "--assembly",    MONO_TABLE_ASSEMBLY,    dump_table_assembly },
807         { "--assemblyref", MONO_TABLE_ASSEMBLYREF, dump_table_assemblyref },
808         { "--fields",      MONO_TABLE_FIELD,       dump_table_field },
809         { "--memberref",   MONO_TABLE_MEMBERREF,   dump_table_memberref },
810         { "--param",       MONO_TABLE_PARAM,       dump_table_param },
811         { "--typedef",     MONO_TABLE_TYPEDEF,     dump_table_typedef },
812         { "--typeref",     MONO_TABLE_TYPEREF,     dump_table_typeref },
813         { "--exported",    MONO_TABLE_EXPORTEDTYPE,     dump_table_exported },
814         { "--nested",      MONO_TABLE_NESTEDCLASS, dump_table_nestedclass },
815         { "--interface",   MONO_TABLE_INTERFACEIMPL,     dump_table_interfaceimpl },
816         { "--classlayout", MONO_TABLE_CLASSLAYOUT, dump_table_class_layout },
817         { "--constant",    MONO_TABLE_CONSTANT,    dump_table_constant },
818         { "--customattr",  MONO_TABLE_CUSTOMATTRIBUTE,    dump_table_customattr },
819         { "--property",    MONO_TABLE_PROPERTY,    dump_table_property },
820         { "--propertymap", MONO_TABLE_PROPERTYMAP, dump_table_property_map },
821         { "--event",       MONO_TABLE_EVENT,       dump_table_event },
822         { "--file",        MONO_TABLE_FILE,        dump_table_file },
823         { "--moduleref",   MONO_TABLE_MODULEREF,   dump_table_moduleref },
824         { "--module",      MONO_TABLE_MODULE,      dump_table_module },
825         { "--method",      MONO_TABLE_METHOD,      dump_table_method },
826         { "--methodsem",   MONO_TABLE_METHODSEMANTICS,      dump_table_methodsem },
827         { "--manifest",    MONO_TABLE_MANIFESTRESOURCE,     dump_table_manifest },
828         { NULL, -1 }
829 };
830
831 /**
832  * disassemble_file:
833  * @file: file containing CIL code.
834  *
835  * Disassembles the @file file.
836  */
837 static void
838 disassemble_file (const char *file)
839 {
840         MonoAssembly *ass;
841         MonoImageOpenStatus status;
842         MonoImage *img;
843
844         ass = mono_assembly_open (file, &status);
845         if (ass == NULL){
846                 fprintf (stderr, "Error while trying to process %s\n", file);
847                 return;
848         }
849
850         img = ass->image;
851
852         if (dump_table != -1){
853                 (*table_list [dump_table].dumper) (img);
854         } else {
855                 dump_header_data (img);
856                 
857                 dis_directive_assemblyref (img);
858                 dis_directive_assembly (img);
859                 dis_types (img);
860         }
861         
862         mono_image_close (img);
863 }
864
865 static void
866 usage (void)
867 {
868         GString *args = g_string_new ("[--help] [--mscorlib] ");
869         int i;
870         
871         for (i = 0; table_list [i].name != NULL; i++){
872                 g_string_append (args, "[");
873                 g_string_append (args, table_list [i].name);
874                 g_string_append (args, "] ");
875                 if (((i-2) % 5) == 0)
876                         g_string_append_c (args, '\n');
877         }
878         fprintf (stderr,
879                  "Usage is: monodis %s file ..\n", args->str);
880         exit (1);
881 }
882
883 int
884 main (int argc, char *argv [])
885 {
886         GList *input_files = NULL, *l;
887         int i, j;
888
889         output = stdout;
890         for (i = 1; i < argc; i++){
891                 if (argv [i][0] == '-'){
892                         if (argv [i][1] == 'h')
893                                 usage ();
894                         else if (argv [i][1] == 'd')
895                                 dump_header_data_p = TRUE;
896                         else if (strcmp (argv [i], "--mscorlib") == 0) {
897                                 substitute_with_mscorlib_p = TRUE;
898                                 i++;
899                         }
900                         else if (strcmp (argv [i], "--help") == 0)
901                                 usage ();
902                         for (j = 0; table_list [j].name != NULL; j++) {
903                                 if (strcmp (argv [i], table_list [j].name) == 0)
904                                         dump_table = j;
905                         }
906                         if (dump_table < 0)
907                                 usage ();
908                 } else
909                         input_files = g_list_append (input_files, argv [i]);
910         }
911
912         if (input_files == NULL)
913                 usage ();
914         
915         mono_init (argv [0]);
916
917         for (l = input_files; l; l = l->next)
918                 disassemble_file (l->data);
919
920         return 0;
921 }