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