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