d8f6f8558fa8d30927b50760ab82e6715e09d60c
[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 <fcntl.h>
22 #include "meta.h"
23 #include "util.h"
24 #include "dump.h"
25 #include "get.h"
26 #include "dis-cil.h"
27 #include "declsec.h"
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/object-internals.h>
30 #include <mono/metadata/loader.h>
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/appdomain.h>
33 #include <mono/utils/bsearch.h>
34
35 static void     setup_filter          (MonoImage *image);
36 static gboolean should_include_type   (int idx);
37 static gboolean should_include_method (int idx);
38 static gboolean should_include_field  (int idx);
39
40 FILE *output;
41
42 /* True if you want to get a dump of the header data */
43 gboolean dump_header_data_p = FALSE;
44
45 /* True if you want to get forward declarations */
46 gboolean dump_forward_decls = FALSE;
47
48 /* True if you want to dump managed resources as files */
49 gboolean dump_managed_resources = FALSE;
50
51 gboolean substitute_with_mscorlib_p = FALSE;
52
53 int dump_table = -1;
54
55 static void
56 dump_header_data (MonoImage *img)
57 {
58         if (!dump_header_data_p)
59                 return;
60
61         fprintf (output,
62                  "// Ximian's CIL disassembler, version 1.0\n"
63                  "// Copyright (C) 2001 Ximian, Inc.\n\n");
64 }
65
66 static void
67 dump_cattrs_list (GList *list,  const char *indent)
68 {
69         GList *tmp;
70
71         for (tmp = list; tmp; tmp = tmp->next) {
72                 fprintf (output, "%s%s\n", indent, (char*)tmp->data);
73                 g_free (tmp->data);
74         }
75         g_list_free (list);
76 }
77
78 static void
79 dump_cattrs (MonoImage *m, guint32 token, const char *indent)
80 {
81         GList *list;
82
83         list = dis_get_custom_attrs (m, token);
84         dump_cattrs_list (list, indent);
85 }
86
87 static const char*
88 get_il_security_action (int val) 
89 {
90         static char buf [32];
91
92         switch (val) {
93         case SECURITY_ACTION_DEMAND:
94                 return "demand";
95         case SECURITY_ACTION_ASSERT:
96                 return "assert";
97         case SECURITY_ACTION_DENY:
98                 return "deny";
99         case SECURITY_ACTION_PERMITONLY:
100                 return "permitonly";
101         case SECURITY_ACTION_LINKDEMAND:
102                 return "linkcheck";
103         case SECURITY_ACTION_INHERITDEMAND:
104                 return "inheritcheck";
105         case SECURITY_ACTION_REQMIN:
106                 return "reqmin";
107         case SECURITY_ACTION_REQOPT:
108                 return "reqopt";
109         case SECURITY_ACTION_REQREFUSE:
110                 return "reqrefuse";
111         /* Special actions (for non CAS permissions) */
112         case SECURITY_ACTION_NONCASDEMAND:
113                 return "noncasdemand";
114         case SECURITY_ACTION_NONCASLINKDEMAND:
115                 return "noncaslinkdemand";
116         case SECURITY_ACTION_NONCASINHERITANCE:
117                 return "noncasinheritance";
118         /* Fx 2.0 actions (for both CAS and non-CAS permissions) */
119         case SECURITY_ACTION_LINKDEMANDCHOICE:
120                 return "linkdemandor";
121         case SECURITY_ACTION_INHERITDEMANDCHOICE:
122                 return "inheritancedemandor";
123         case SECURITY_ACTION_DEMANDCHOICE:
124                 return "demandor";
125         default:
126                 g_snprintf (buf, sizeof (buf), "0x%04X", val);
127                 return buf;
128         }
129 }
130
131 #define OBJECT_TYPE_TYPEDEF     0
132 #define OBJECT_TYPE_METHODDEF   1
133 #define OBJECT_TYPE_ASSEMBLYDEF 2
134
135 static void
136 dump_declarative_security (MonoImage *m, guint32 objectType, guint32 token, const char *indent)
137 {
138         MonoTableInfo *t = &m->tables [MONO_TABLE_DECLSECURITY];
139         guint32 cols [MONO_DECL_SECURITY_SIZE];
140         int i, len;
141         guint32 idx;
142         const char *blob, *action;
143         
144         for (i = 1; i <= t->rows; i++) {
145                 mono_metadata_decode_row (t, i - 1, cols, MONO_DECL_SECURITY_SIZE);
146                 blob = mono_metadata_blob_heap (m, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
147                 len = mono_metadata_decode_blob_size (blob, &blob);
148                 action = get_il_security_action (cols [MONO_DECL_SECURITY_ACTION]);
149                 idx = cols [MONO_DECL_SECURITY_PARENT];
150                 if (((idx & MONO_HAS_DECL_SECURITY_MASK) == objectType) && ((idx >> MONO_HAS_DECL_SECURITY_BITS) == token)) {
151                         char *dump;
152                         if (blob [0] == MONO_DECLSEC_FORMAT_20) {
153                                 /* 2.0 declarative security format */
154                                 dump = dump_declsec_entry20 (m, blob, indent);
155                                 fprintf (output, "%s.permissionset %s = %s\n", indent, action, dump);
156                         } else {
157                                 /* 1.x declarative security metadata format */
158                                 dump = data_dump (blob, len, indent);
159                                 fprintf (output, "%s.permissionset %s = %s", indent, action, dump);
160                         }
161                         g_free (dump);
162                 }
163         }
164 }
165
166 static char *
167 assembly_flags (guint32 f)
168 {
169         if (f & ASSEMBLYREF_RETARGETABLE_FLAG)
170                 return g_strdup ("retargetable ");
171         return g_strdup ("");
172 }
173
174 static void
175 dis_directive_assembly (MonoImage *m)
176 {
177         MonoTableInfo *t  = &m->tables [MONO_TABLE_ASSEMBLY];
178         guint32 cols [MONO_ASSEMBLY_SIZE];
179         char *flags;
180         
181         if (t->base == NULL)
182                 return;
183
184         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
185         flags = assembly_flags (cols [MONO_ASSEMBLY_FLAGS]);
186         
187         fprintf (output, ".assembly %s'%s'\n{\n",
188                  flags, mono_metadata_string_heap (m, cols [MONO_ASSEMBLY_NAME]));
189         dump_cattrs (m, MONO_TOKEN_ASSEMBLY | 1, "  ");
190         dump_declarative_security (m, OBJECT_TYPE_ASSEMBLYDEF, 1, "  ");
191         fprintf (output,
192                  "  .hash algorithm 0x%08x\n"
193                  "  .ver  %d:%d:%d:%d\n",
194                  cols [MONO_ASSEMBLY_HASH_ALG],
195                  cols [MONO_ASSEMBLY_MAJOR_VERSION], cols [MONO_ASSEMBLY_MINOR_VERSION], 
196                  cols [MONO_ASSEMBLY_BUILD_NUMBER], cols [MONO_ASSEMBLY_REV_NUMBER]);
197         if (cols [MONO_ASSEMBLY_CULTURE]){
198                 const char *locale = mono_metadata_string_heap (m, cols [MONO_ASSEMBLY_CULTURE]);
199                 glong items_read, items_written;
200                 gunichar2 *render = g_utf8_to_utf16 (locale, strlen (locale), &items_read, &items_written, NULL);
201                 char *dump = data_dump ((const char *) render, items_written * sizeof (gunichar2), "\t\t");
202                 fprintf (output, "  .locale %s\n", dump);
203                 g_free (dump);
204                 g_free (render);
205                 
206         } if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
207                 const char* b = mono_metadata_blob_heap (m, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
208                 int len = mono_metadata_decode_blob_size (b, &b);
209                 char *dump = data_dump (b, len, "\t\t");
210                 fprintf (output, "  .publickey =%s", dump);
211                 g_free (dump);
212         }
213         fprintf (output, "}\n");
214         
215         g_free (flags);
216 }
217
218 static void
219 dis_directive_assemblyref (MonoImage *m)
220 {
221         MonoTableInfo *t = &m->tables [MONO_TABLE_ASSEMBLYREF];
222         guint32 cols [MONO_ASSEMBLYREF_SIZE];
223         int i;
224         
225         if (t->base == NULL)
226                 return;
227
228         for (i = 0; i < t->rows; i++){
229                 char *esc, *flags;
230
231                 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
232
233                 esc = get_escaped_name (mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_NAME]));
234                 flags = assembly_flags (cols [MONO_ASSEMBLYREF_FLAGS]);
235                 
236                 fprintf (output,
237                          ".assembly extern %s%s\n"
238                          "{\n"
239                          "  .ver %d:%d:%d:%d\n",
240                          flags,
241                          esc,
242                          cols [MONO_ASSEMBLYREF_MAJOR_VERSION], cols [MONO_ASSEMBLYREF_MINOR_VERSION], 
243                          cols [MONO_ASSEMBLYREF_BUILD_NUMBER], cols [MONO_ASSEMBLYREF_REV_NUMBER]
244                         );
245                 dump_cattrs (m, MONO_TOKEN_ASSEMBLY_REF | (i + 1), "  ");
246                 if (cols [MONO_ASSEMBLYREF_CULTURE]){
247                         fprintf (output, "  .locale %s\n", mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_CULTURE]));
248                 }
249                 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]){
250                         const char* b = mono_metadata_blob_heap (m, cols [MONO_ASSEMBLYREF_PUBLIC_KEY]);
251                         int len = mono_metadata_decode_blob_size (b, &b);
252                         char *dump = data_dump (b, len, "\t\t");
253                         fprintf (output, "  .publickeytoken =%s", dump);
254                         g_free (dump);
255                 }
256                 fprintf (output, "}\n");
257                 g_free (flags);
258                 g_free (esc);
259         }
260 }
261
262 static void
263 dis_directive_module (MonoImage *m)
264 {
265         MonoTableInfo *t = &m->tables [MONO_TABLE_MODULE];
266         int i;
267
268         for (i = 0; i < t->rows; i++){
269                 guint32 cols [MONO_MODULE_SIZE];
270                 const char *name;
271                 char *guid, *ename;
272                 
273                 mono_metadata_decode_row (t, i, cols, MONO_MODULE_SIZE);
274
275                 name = mono_metadata_string_heap (m, cols [MONO_MODULE_NAME]);
276                 ename = get_escaped_name (name);
277                 guid = get_guid (m, cols [MONO_MODULE_MVID]);
278                 fprintf (output, ".module %s // GUID = %s\n\n", ename, guid);
279                 g_free (ename);
280
281                 dump_cattrs (m, MONO_TOKEN_MODULE | (i + 1), "");
282         }
283 }
284
285 static void
286 dis_directive_moduleref (MonoImage *m)
287 {
288         MonoTableInfo *t = &m->tables [MONO_TABLE_MODULEREF];
289         int i;
290
291         for (i = 0; i < t->rows; i++){
292                 guint32 cols [MONO_MODULEREF_SIZE];
293                 
294                 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
295
296                 fprintf (output, ".module extern '%s'\n", mono_metadata_string_heap (m, cols [MONO_MODULEREF_NAME]));
297         }
298         
299 }
300
301 static void
302 dis_nt_header (MonoImage *m)
303 {
304         MonoCLIImageInfo *image_info = (MonoCLIImageInfo *)m->image_info;
305         if (image_info && image_info->cli_header.nt.pe_stack_reserve != 0x100000)
306                 fprintf (output, ".stackreserve 0x%x\n", image_info->cli_header.nt.pe_stack_reserve);
307 }
308
309 static void
310 dis_directive_file (MonoImage *m)
311 {
312         MonoTableInfo *t = &m->tables [MONO_TABLE_FILE];
313         int i, j, len;
314         guint32 entry_point;
315
316         entry_point = mono_image_get_entry_point (m);
317
318         for (i = 0; i < t->rows; i++){
319                 guint32 cols [MONO_FILE_SIZE];
320                 const char *name, *hash;
321                 guint32 token;
322
323                 mono_metadata_decode_row (t, i, cols, MONO_FILE_SIZE);
324
325                 name = mono_metadata_string_heap (m, cols [MONO_FILE_NAME]);
326
327                 hash = mono_metadata_blob_heap (m, cols [MONO_FILE_HASH_VALUE]);
328                 len = mono_metadata_decode_blob_size (hash, &hash);
329
330                 fprintf (output, ".file %s%s .hash = (",
331                                 cols [MONO_FILE_FLAGS] & FILE_CONTAINS_NO_METADATA ? "nometadata " : "", name);
332
333                 for (j = 0; j < len; ++j)
334                         fprintf (output, " %02X", hash [j] & 0xff);
335
336                 token = mono_metadata_make_token (MONO_TABLE_FILE, i + 1);
337                 fprintf (output, " )%s\n", (token == entry_point) ? " .entrypoint" : "");
338         }
339         
340 }
341
342 static void
343 dis_directive_mresource (MonoImage *m)
344 {
345         MonoTableInfo *t = &m->tables [MONO_TABLE_MANIFESTRESOURCE];
346         int i;
347
348         for (i = 0; i < t->rows; i++){
349                 guint32 cols [MONO_MANIFEST_SIZE];
350                 const char *name;
351                 guint32 impl, idx, name_token;
352
353                 mono_metadata_decode_row (t, i, cols, MONO_MANIFEST_SIZE);
354
355                 name = mono_metadata_string_heap (m, cols [MONO_MANIFEST_NAME]);
356
357                 fprintf (output, ".mresource %s '%s'\n", (cols [MONO_MANIFEST_FLAGS] & MANIFEST_RESOURCE_VISIBILITY_MASK) == (MANIFEST_RESOURCE_PUBLIC) ? "public" : "private", name);
358                 fprintf (output, "{\n");
359                 impl = cols [MONO_MANIFEST_IMPLEMENTATION];
360                 if (impl) {
361                         idx = impl >> MONO_IMPLEMENTATION_BITS;
362                         if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
363                                 name_token = mono_metadata_decode_row_col (&m->tables [MONO_TABLE_FILE], idx - 1, MONO_FILE_NAME);
364
365                                 fprintf (output, "    .file '%s' at 0x0\n", mono_metadata_string_heap (m, name_token));
366                         }
367                         if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
368                                 name_token = mono_metadata_decode_row_col (&m->tables [MONO_TABLE_ASSEMBLYREF], idx - 1, MONO_ASSEMBLYREF_NAME);
369                                 fprintf (output, "    .assembly extern '%s'\n", mono_metadata_string_heap (m, name_token));
370                         }
371                 }                               
372                 fprintf (output, "}\n");
373         }
374         
375 }
376
377 static dis_map_t visibility_map [] = {
378         { TYPE_ATTRIBUTE_NOT_PUBLIC,           "private " },
379         { TYPE_ATTRIBUTE_PUBLIC,               "public " },
380         { TYPE_ATTRIBUTE_NESTED_PUBLIC,        "nested public " },
381         { TYPE_ATTRIBUTE_NESTED_PRIVATE,       "nested private " },
382         { TYPE_ATTRIBUTE_NESTED_FAMILY,        "nested family " },
383         { TYPE_ATTRIBUTE_NESTED_ASSEMBLY,      "nested assembly " },
384         { TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM, "nested famandassem " },
385         { TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM,  "nested famorassem " },
386         { 0, NULL }
387 };
388
389 static dis_map_t layout_map [] = {
390         { TYPE_ATTRIBUTE_AUTO_LAYOUT,          "auto " },
391         { TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT,    "sequential " },
392         { TYPE_ATTRIBUTE_EXPLICIT_LAYOUT,      "explicit " },
393         { 0, NULL }
394 };
395
396 static dis_map_t format_map [] = {
397         { TYPE_ATTRIBUTE_ANSI_CLASS,           "ansi " },
398         { TYPE_ATTRIBUTE_UNICODE_CLASS,        "unicode " },
399         { TYPE_ATTRIBUTE_AUTO_CLASS,           "auto " },
400         { 0, NULL }
401 };
402
403 static char *
404 typedef_flags (guint32 flags)
405 {
406         static char buffer [1024];
407         int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
408         int layout = flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
409         int format = flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK;
410         
411         buffer [0] = 0;
412
413         strcat (buffer, map (visibility, visibility_map));
414         strcat (buffer, map (layout, layout_map));
415         strcat (buffer, map (format, format_map));
416         
417         if (flags & TYPE_ATTRIBUTE_ABSTRACT)
418                 strcat (buffer, "abstract ");
419         if (flags & TYPE_ATTRIBUTE_SEALED)
420                 strcat (buffer, "sealed ");
421         if (flags & TYPE_ATTRIBUTE_SPECIAL_NAME)
422                 strcat (buffer, "specialname ");
423         if (flags & TYPE_ATTRIBUTE_IMPORT)
424                 strcat (buffer, "import ");
425         if (flags & TYPE_ATTRIBUTE_SERIALIZABLE)
426                 strcat (buffer, "serializable ");
427         if (flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
428                 strcat (buffer, "beforefieldinit ");
429         if (flags & TYPE_ATTRIBUTE_FORWARDER)
430                 strcat (buffer, "forwarder ");
431
432         return buffer;
433 }
434
435 /**
436  * dis_field_list:
437  * @m: metadata context
438  * @start: starting index into the Field Table.
439  * @end: ending index into Field table.
440  *
441  * This routine displays all the decoded fields from @start to @end
442  */
443 static void
444 dis_field_list (MonoImage *m, guint32 start, guint32 end, MonoGenericContainer *container)
445 {
446         MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
447         guint32 cols [MONO_FIELD_SIZE];
448         char *esname;
449         char rva_desc [32];
450         guint32 rva;
451         int i;
452
453         if (end > t->rows + 1) {
454                 g_warning ("ERROR index out of range in fields");
455                 end = t->rows;
456         }
457                         
458         for (i = start; i < end; i++){
459                 char *sig, *flags, *attrs = NULL;
460                 char *marshal_str = NULL;
461                 guint32 field_offset = -1;
462
463                 if (!should_include_field (i + 1))
464                         continue;
465                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
466                 sig = get_field_signature (m, cols [MONO_FIELD_SIGNATURE], container);
467                 flags = field_flags (cols [MONO_FIELD_FLAGS]);
468                 
469                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) {
470                         const char *tp;
471                         MonoMarshalSpec *spec;
472                         
473                         tp = mono_metadata_get_marshal_info (m, i, TRUE);
474                         spec = mono_metadata_parse_marshal_spec (m, tp);
475                         marshal_str = dis_stringify_marshal_spec (spec);
476                 }
477
478                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
479                         mono_metadata_field_info (m, i, NULL, &rva, NULL);
480                         g_snprintf (rva_desc, sizeof (rva_desc), " at D_%08x", rva);
481                 } else {
482                         rva_desc [0] = 0;
483                 }
484                 
485                 mono_metadata_field_info (m, i, &field_offset, NULL, NULL);
486                 if (field_offset != -1)
487                         attrs = g_strdup_printf ("[%d]", field_offset);
488                 esname = get_escaped_name (mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
489                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_DEFAULT){
490                         char *lit;
491                         guint32 const_cols [MONO_CONSTANT_SIZE];
492                         guint32 crow;
493                         
494                         if ((crow = mono_metadata_get_constant_index (m, MONO_TOKEN_FIELD_DEF | (i+1), 0))) {
495                                 mono_metadata_decode_row (&m->tables [MONO_TABLE_CONSTANT], crow-1, const_cols, MONO_CONSTANT_SIZE);
496                                 lit = get_constant (m, (MonoTypeEnum)const_cols [MONO_CONSTANT_TYPE], const_cols [MONO_CONSTANT_VALUE]);
497                         } else {
498                                 lit = g_strdup ("not found");
499                         }
500                         
501                         fprintf (output, "    .field %s%s%s %s = ",
502                                  flags, marshal_str ? marshal_str : " ", sig, esname);
503                         fprintf (output, "%s\n", lit);
504                         g_free (lit);
505                 } else
506                         fprintf (output, "    .field %s %s%s%s %s%s\n",
507                                  attrs? attrs: "", flags, marshal_str ? marshal_str : " ", sig, esname, rva_desc);
508                 g_free (attrs);
509                 g_free (flags);
510                 g_free (marshal_str);
511                 g_free (sig);
512                 g_free (esname);
513                 dump_cattrs (m, MONO_TOKEN_FIELD_DEF | (i + 1), "    ");
514         }
515 }
516
517 static dis_map_t method_access_map [] = {
518         { METHOD_ATTRIBUTE_COMPILER_CONTROLLED, "privatescope " },
519         { METHOD_ATTRIBUTE_PRIVATE,             "private " },
520         { METHOD_ATTRIBUTE_FAM_AND_ASSEM,       "famandassem " },
521         { METHOD_ATTRIBUTE_ASSEM,               "assembly " },
522         { METHOD_ATTRIBUTE_FAMILY,              "family " },
523         { METHOD_ATTRIBUTE_FAM_OR_ASSEM,        "famorassem " },
524         { METHOD_ATTRIBUTE_PUBLIC,              "public " },
525         { 0, NULL }
526 };
527
528 static dis_map_t method_flags_map [] = {
529         { METHOD_ATTRIBUTE_STATIC,              "static " },
530         { METHOD_ATTRIBUTE_FINAL,               "final " },
531         { METHOD_ATTRIBUTE_VIRTUAL,             "virtual " },
532         { METHOD_ATTRIBUTE_HIDE_BY_SIG,         "hidebysig " },
533         { METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK,  "newslot " },
534         { METHOD_ATTRIBUTE_ABSTRACT,            "abstract " },
535         { METHOD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
536         { METHOD_ATTRIBUTE_RT_SPECIAL_NAME,     "rtspecialname " },
537         { METHOD_ATTRIBUTE_UNMANAGED_EXPORT,    "export " },
538 /* MS ilasm doesn't compile this statement - is must be added automagically when permissionset are present */
539         { METHOD_ATTRIBUTE_HAS_SECURITY,        "" /*"hassecurity"*/ },
540         { METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT,  "requiresecobj " },
541         { METHOD_ATTRIBUTE_PINVOKE_IMPL,        "pinvokeimpl " }, 
542         { METHOD_ATTRIBUTE_STRICT,                  "strict " }, 
543         { 0, NULL }
544 };
545
546 /**
547  * method_flags:
548  *
549  * Returns a stringified version of the Method's flags
550  */
551 static char *
552 method_flags (guint32 f)
553 {
554         GString *str = g_string_new ("");
555         int access = f & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
556         int rest = f & ~access;
557         char *s;
558         
559         g_string_append (str, map (access, method_access_map));
560         g_string_append (str, flags (rest, method_flags_map));
561
562         s = str->str;
563         g_string_free (str, FALSE);
564
565         return s;
566 }
567
568 static dis_map_t pinvoke_flags_map [] = {
569         { PINVOKE_ATTRIBUTE_NO_MANGLE ,            "nomangle " },
570         { PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR,   "lasterr " },
571         { PINVOKE_ATTRIBUTE_BEST_FIT_ENABLED,      "bestfit:on " },
572         { PINVOKE_ATTRIBUTE_BEST_FIT_DISABLED,      "bestfit:off " },
573         { PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_ENABLED, "charmaperror:on " },
574         { PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_DISABLED, "charmaperror:off " },
575         { 0, NULL }
576 };
577
578 static dis_map_t pinvoke_call_conv_map [] = {
579         { PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI,      "winapi " },
580         { PINVOKE_ATTRIBUTE_CALL_CONV_CDECL,       "cdecl " },
581         { PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL,     "stdcall " },
582         { PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL,    "thiscall " },
583         { PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL,    "fastcall " },
584         { 0, "" },
585         { -1, NULL }
586 };
587
588 static dis_map_t pinvoke_char_set_map [] = {
589         { PINVOKE_ATTRIBUTE_CHAR_SET_NOT_SPEC,     "" },
590         { PINVOKE_ATTRIBUTE_CHAR_SET_ANSI,         "ansi " },
591         { PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE ,     "unicode " },
592         { PINVOKE_ATTRIBUTE_CHAR_SET_AUTO,         "autochar " },
593         { 0, NULL }
594 };
595
596 /**
597  * pinvoke_flags:
598  *
599  * Returns a stringified version of the Method's pinvoke flags
600  */
601 static char *
602 pinvoke_flags (guint32 f)
603 {
604         GString *str = g_string_new ("");
605         int cset = f & PINVOKE_ATTRIBUTE_CHAR_SET_MASK;
606         int cconv = f & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
607         int rest = f & ~(cset | cconv);
608         char *s;
609
610         g_string_append (str, map (cset, pinvoke_char_set_map));
611         g_string_append (str, map (cconv, pinvoke_call_conv_map));
612         g_string_append (str, flags (rest, pinvoke_flags_map));
613
614         s = g_strdup(str->str);
615         g_string_free (str, FALSE);
616
617         return s;
618 }
619
620 static void
621 dis_locals (MonoImage *m, MonoMethodHeader *mh, const char *ptr) 
622 {
623         int i;
624
625         if (show_tokens) {
626                 unsigned char flags = *(const unsigned char *) ptr;
627                 unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
628                 guint16 fat_flags;
629                 guint32 local_var_sig_tok, init_locals;
630
631                 g_assert (format == METHOD_HEADER_FAT_FORMAT);
632                 fat_flags = read16 (ptr);
633                 ptr += 2;
634                 /* max_stack = read16 (ptr); */
635                 ptr += 2;
636                 /* code_size = read32 (ptr); */
637                 ptr += 4;
638                 local_var_sig_tok = read32 (ptr);
639                 ptr += 4;
640
641                 if (fat_flags & METHOD_HEADER_INIT_LOCALS)
642                         init_locals = 1;
643                 else
644                         init_locals = 0;
645
646                 fprintf(output, "\t.locals /*%08x*/ %s(\n",
647                         local_var_sig_tok, init_locals ? "init " : "");
648         } else
649                 fprintf(output, "\t.locals %s(\n", mh->init_locals ? "init " : "");
650
651         for (i=0; i < mh->num_locals; ++i) {
652                 char * desc;
653                 if (i)
654                         fprintf(output, ",\n");
655                 /* print also byref and pinned attributes */
656                 desc = dis_stringify_type (m, mh->locals[i], TRUE);
657                 fprintf(output, "\t\t%s\tV_%d", desc, i);
658                 g_free(desc);
659         }
660         fprintf(output, ")\n");
661 }
662
663 static void
664 dis_code (MonoImage *m, guint32 token, guint32 rva, MonoGenericContainer *container)
665 {
666         MonoError error;
667         MonoMethodHeader *mh;
668         const char *ptr = mono_image_rva_map (m, rva);
669         const char *loc;
670         gchar *override;
671         guint32 entry_point;
672
673         if (rva == 0)
674                 return;
675
676         override = get_method_override (m, token, container);
677         if (override) {
678                 fprintf (output, "\t.override %s\n", override);
679                 g_free (override);
680         }
681
682         mh = mono_metadata_parse_mh_full (m, container, ptr, &error);
683         entry_point = mono_image_get_entry_point (m);
684         if (entry_point && mono_metadata_token_index (entry_point) && mono_metadata_token_table (entry_point) == MONO_TABLE_METHOD) {
685                 loc = mono_metadata_locate_token (m, entry_point);
686                 if (rva == read32 (loc))
687                         fprintf (output, "\t.entrypoint\n");
688         }
689         
690         if (mh) {
691                 fprintf (output, "\t// Code size %d (0x%x)\n", mh->code_size, mh->code_size);
692                 fprintf (output, "\t.maxstack %d\n", mh->max_stack);
693                 if (mh->num_locals)
694                         dis_locals (m, mh, ptr);
695                 disassemble_cil (m, mh, container);
696 /*
697   hex_dump (mh->code, 0, mh->code_size);
698   printf ("\nAfter the code\n");
699   hex_dump (mh->code + mh->code_size, 0, 64);
700 */
701                 mono_metadata_free_mh (mh);
702         } else {
703                 mono_error_cleanup (&error);
704         }
705 }
706
707 static char *
708 pinvoke_info (MonoImage *m, guint32 mindex)
709 {
710         MonoTableInfo *im = &m->tables [MONO_TABLE_IMPLMAP];
711         MonoTableInfo *mr = &m->tables [MONO_TABLE_MODULEREF];
712         guint32 im_cols [MONO_IMPLMAP_SIZE];
713         guint32 mr_cols [MONO_MODULEREF_SIZE];
714         const char *import, *scope;
715         char *flags;
716         int i;
717
718         for (i = 0; i < im->rows; i++) {
719
720                 mono_metadata_decode_row (im, i, im_cols, MONO_IMPLMAP_SIZE);
721
722                 if ((im_cols [MONO_IMPLMAP_MEMBER] >> 1) == mindex + 1) {
723
724                         flags = pinvoke_flags (im_cols [MONO_IMPLMAP_FLAGS]);
725
726                         import = mono_metadata_string_heap (m, im_cols [MONO_IMPLMAP_NAME]);
727
728                         mono_metadata_decode_row (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, 
729                                                   mr_cols, MONO_MODULEREF_SIZE);
730
731                         scope = mono_metadata_string_heap (m, mr_cols [MONO_MODULEREF_NAME]);
732                                 
733                         return g_strdup_printf ("(\"%s\" as \"%s\" %s)", scope, import,
734                                                 flags);
735                         g_free (flags);
736                 }
737         }
738
739         return NULL;
740 }
741
742 /*
743  * dump_cattrs_for_type_params
744  *
745  * @m: 
746  * @token: TypeOrMethodDef token, owner for GenericParam
747  *
748  * Dumps the custom attributes for @token's type parameters
749  */
750 static void
751 dump_cattrs_for_type_params (MonoImage *m, guint32 token, const char *indent)
752 {
753         MonoTableInfo *tdef  = &m->tables [MONO_TABLE_GENERICPARAM];
754         guint32 cols [MONO_GENERICPARAM_SIZE];
755         guint32 owner = 0, i;
756         GList *list = NULL;
757
758         if (! (i = mono_metadata_get_generic_param_row (m, token, &owner)))
759                 return;
760
761         mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
762         do {
763                 list = dis_get_custom_attrs (m, mono_metadata_make_token (MONO_TABLE_GENERICPARAM, i));
764                 if (list) {
765                         fprintf (output, "%s.param type %s\n", indent, mono_metadata_string_heap (m, cols [MONO_GENERICPARAM_NAME]));
766                         dump_cattrs_list (list, indent);
767                 }
768
769                 if (++i > tdef->rows)
770                         break;
771                 mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
772         } while (cols [MONO_GENERICPARAM_OWNER] == owner);
773 }
774
775 static void
776 dump_cattrs_for_method_params (MonoImage *m, guint32 midx, MonoMethodSignature *sig) {
777         MonoTableInfo *methodt;
778         MonoTableInfo *paramt;
779         guint param_index, lastp, i;
780
781         methodt = &m->tables [MONO_TABLE_METHOD];
782         paramt = &m->tables [MONO_TABLE_PARAM];
783         param_index = mono_metadata_decode_row_col (methodt, midx, MONO_METHOD_PARAMLIST);
784         if (midx + 1 < methodt->rows)
785                 lastp = mono_metadata_decode_row_col (methodt, midx + 1, MONO_METHOD_PARAMLIST);
786         else
787                 lastp = paramt->rows + 1;
788         for (i = param_index; i < lastp; ++i) {
789                 char *lit;
790                 int crow;
791                 guint32 param_cols [MONO_PARAM_SIZE];
792                 GList *list;
793                 
794                 list = dis_get_custom_attrs (m, MONO_TOKEN_PARAM_DEF | i);
795
796                 mono_metadata_decode_row (paramt, i-1, param_cols, MONO_PARAM_SIZE);
797                 if (!(param_cols[MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_DEFAULT)) {
798                         if(list != NULL)
799                                 fprintf (output, "\t.param [%d]\n", param_cols[MONO_PARAM_SEQUENCE]);
800                 } else {
801                         fprintf (output, "\t.param [%d] = ", param_cols[MONO_PARAM_SEQUENCE]);
802                   
803                         if ((crow = mono_metadata_get_constant_index(m, MONO_TOKEN_PARAM_DEF | i, 0))) {
804                                 guint32 const_cols [MONO_CONSTANT_SIZE];
805                                 mono_metadata_decode_row( &m->tables[MONO_TABLE_CONSTANT], crow-1, const_cols, MONO_CONSTANT_SIZE);
806                                 lit = get_constant (m, (MonoTypeEnum)const_cols [MONO_CONSTANT_TYPE], const_cols [MONO_CONSTANT_VALUE]);
807                         }
808                         else {
809                                 lit = g_strdup ("not found");
810                         }
811                   fprintf(output, "%s\n", lit);
812                   g_free(lit);
813                 }
814                 dump_cattrs_list (list, "\t");
815         }
816 }
817
818 /**
819  * dis_method_list:
820  * @m: metadata context
821  * @start: starting index into the Method Table.
822  * @end: ending index into Method table.
823  *
824  * This routine displays the methods in the Method Table from @start to @end
825  */
826 static void
827 dis_method_list (const char *klass_name, MonoImage *m, guint32 start, guint32 end, MonoGenericContainer *type_container)
828 {
829         MonoTableInfo *t = &m->tables [MONO_TABLE_METHOD];
830         guint32 cols [MONO_METHOD_SIZE];
831         int i;
832
833         if (end > t->rows){
834                 fprintf (output, "ERROR index out of range in methods");
835                 /*exit (1);*/
836                 end = t->rows;
837         }
838
839         for (i = start; i < end; i++){
840                 MonoError error;
841                 MonoMethodSignature *ms;
842                 MonoGenericContainer *container;
843                 char *flags, *impl_flags;
844                 const char *sig, *method_name;
845                 char *sig_str;
846                 guint32 token;
847
848                 if (!should_include_method (i + 1))
849                         continue;
850                 mono_metadata_decode_row (t, i, cols, MONO_METHOD_SIZE);
851
852                 flags = method_flags (cols [MONO_METHOD_FLAGS]);
853                 impl_flags = get_method_impl_flags (cols [MONO_METHOD_IMPLFLAGS]);
854
855                 sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
856                 mono_metadata_decode_blob_size (sig, &sig);
857
858                 container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), type_container);
859                 if (container) {
860                         MonoError error;
861                         mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | (i + 1), container, &error);
862                         g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
863                 } else {
864                         container = type_container;
865                 }
866
867                 ms = mono_metadata_parse_method_signature_full (m, container, i + 1, sig, &sig, &error);
868                 if (ms != NULL){
869                         sig_str = dis_stringify_method_signature (m, ms, i + 1, container, FALSE);
870                         method_name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
871                 } else {
872                         sig_str = NULL;
873                         method_name = g_strdup ("<NULL METHOD SIGNATURE>");
874                         mono_error_cleanup (&error);
875                 }
876
877                 fprintf (output, "    // method line %d\n", i + 1);
878                 fprintf (output, "    .method %s", flags);
879
880                 if ((cols [MONO_METHOD_FLAGS] & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (cols [MONO_METHOD_RVA] == 0)) {
881                         gchar *pi = pinvoke_info (m, i);
882                         if (pi) {
883                                 fprintf (output, "%s", pi);
884                                 g_free (pi);
885                         }
886                 }
887
888                 fprintf (output, "\n           %s", sig_str);
889                 fprintf (output, " %s\n", impl_flags);
890                 g_free (flags);
891                 g_free (impl_flags);
892
893                 token = MONO_TOKEN_METHOD_DEF | (i + 1);
894                 
895                 fprintf (output, "    {\n");
896                 dump_cattrs (m, token, "        ");
897                 dump_cattrs_for_type_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), "        ");
898                 dump_cattrs_for_method_params (m, i, ms);
899
900                 fprintf (output, "        // Method begins at RVA 0x%x\n", cols [MONO_METHOD_RVA]);
901                 dump_declarative_security (m, OBJECT_TYPE_METHODDEF, i + 1, "        ");
902                 if (cols [MONO_METHOD_IMPLFLAGS] & METHOD_IMPL_ATTRIBUTE_NATIVE)
903                         fprintf (output, "          // Disassembly of native methods is not supported\n");
904                 else
905                         dis_code (m, token, cols [MONO_METHOD_RVA], container);
906                 if (klass_name)
907                         fprintf (output, "    } // end of method %s::%s\n\n", klass_name, method_name);
908                 else
909                         fprintf (output, "    } // end of global method %s\n\n", method_name);
910                 mono_metadata_free_method_signature (ms);
911                 g_free (sig_str);
912         }
913 }
914
915 typedef struct {
916         MonoTableInfo *t;
917         guint32 col_idx;
918         guint32 idx;
919         guint32 result;
920 } plocator_t;
921
922 static int
923 table_locator (const void *a, const void *b)
924 {
925         plocator_t *loc = (plocator_t *) a;
926         const char *bb = (const char *) b;
927         guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
928         guint32 col;
929         
930         col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
931
932         if (loc->idx == col) {
933                 loc->result = table_index;
934                 return 0;
935         }
936         if (loc->idx < col)
937                 return -1;
938         else 
939                 return 1;
940 }
941
942 static void
943 dis_property_methods (MonoImage *m, guint32 prop, MonoGenericContainer *container)
944 {
945         guint start, end;
946         MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
947         guint32 cols [MONO_METHOD_SEMA_SIZE];
948         char *sig;
949         const char *type[] = {NULL, ".set", ".get", NULL, ".other"};
950
951         start = mono_metadata_methods_from_property (m, prop, &end);
952         for (; start < end; ++start) {
953                 mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
954                 if (!should_include_method (cols [MONO_METHOD_SEMA_METHOD]))
955                         continue;
956                 sig = dis_stringify_method_signature_full (m, NULL, cols [MONO_METHOD_SEMA_METHOD], container, TRUE, FALSE);
957                 fprintf (output, "\t\t%s %s\n", type [cols [MONO_METHOD_SEMA_SEMANTICS]], sig);
958                 g_free (sig);
959         }
960 }
961 static char*
962 dis_property_signature (MonoImage *m, guint32 prop_idx, MonoGenericContainer *container)
963 {
964         MonoError error;
965         MonoTableInfo *propt = &m->tables [MONO_TABLE_PROPERTY];
966         const char *ptr;
967         guint32 pcount, i;
968         guint32 cols [MONO_PROPERTY_SIZE];
969         MonoType *type;
970         MonoType *param;
971         char *blurb, *qk;
972         const char *name;
973         int prop_flags;
974         GString *res = g_string_new ("");
975
976         mono_metadata_decode_row (propt, prop_idx, cols, MONO_PROPERTY_SIZE);
977         name = mono_metadata_string_heap (m, cols [MONO_PROPERTY_NAME]);
978         prop_flags = cols [MONO_PROPERTY_FLAGS];
979         ptr = mono_metadata_blob_heap (m, cols [MONO_PROPERTY_TYPE]);
980         mono_metadata_decode_blob_size (ptr, &ptr);
981         if (!(*ptr & 0x08))
982                 g_warning("incorrect signature in property blob: 0x%x", *ptr);
983         if (*ptr & 0x20)
984                 g_string_append (res, "instance ");
985         ptr++;
986         pcount = mono_metadata_decode_value (ptr, &ptr);
987         type = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, &error);
988         if (type) {
989                 blurb = dis_stringify_type (m, type, TRUE);
990         } else {
991                 blurb = g_strdup_printf ("Invalid type due to %s", mono_error_get_message (&error));
992                 mono_error_cleanup (&error);
993         }
994         if (prop_flags & 0x0200)
995                 g_string_append (res, "specialname ");
996         if (prop_flags & 0x0400)
997                 g_string_append (res, "rtspecialname ");
998         qk = get_escaped_name (name);
999         g_string_append_printf (res, "%s %s (", blurb, qk);
1000         g_free (qk);
1001         g_free (blurb);
1002         for (i = 0; i < pcount; i++) {
1003                 if (i)
1004                         g_string_append (res, ", ");
1005                 param = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, &error);
1006                 if (type) {
1007                         blurb = dis_stringify_param (m, param);
1008                 } else {
1009                         blurb = g_strdup_printf ("Invalid type due to %s", mono_error_get_message (&error));
1010                         mono_error_cleanup (&error);
1011                 }
1012
1013                 g_string_append (res, blurb);
1014                 g_free (blurb);
1015         }
1016         g_string_append_c (res, ')');
1017         blurb = res->str;
1018         g_string_free (res, FALSE);
1019         return blurb;
1020
1021 }
1022
1023 static void
1024 dis_property_list (MonoImage *m, guint32 typedef_row, MonoGenericContainer *container)
1025 {
1026         guint start, end, i;
1027         start = mono_metadata_properties_from_typedef (m, typedef_row, &end);
1028
1029         for (i = start; i < end; ++i) {
1030                 char *sig = dis_property_signature (m, i, container);
1031                 fprintf (output, "\t.property %s\n\t{\n", sig);
1032                 dump_cattrs (m, MONO_TOKEN_PROPERTY | (i + 1), "\t\t");
1033                 dis_property_methods (m, i, container);
1034                 fprintf (output, "\t}\n");
1035                 g_free (sig);
1036         }
1037 }
1038
1039 static char*
1040 dis_event_signature (MonoImage *m, guint32 event_idx, MonoGenericContainer *container)
1041 {
1042         MonoTableInfo *et = &m->tables [MONO_TABLE_EVENT];
1043         char *type, *result, *esname;
1044         guint32 cols [MONO_EVENT_SIZE];
1045         int event_flags;
1046         GString *res = g_string_new ("");
1047         
1048         mono_metadata_decode_row (et, event_idx, cols, MONO_EVENT_SIZE);
1049         esname = get_escaped_name (mono_metadata_string_heap (m, cols [MONO_EVENT_NAME]));
1050         type = get_typedef_or_ref (m, cols [MONO_EVENT_TYPE], container);
1051         event_flags = cols [MONO_EVENT_FLAGS];
1052
1053         if (event_flags & 0x0200)
1054                 g_string_append (res, "specialname ");
1055         if (event_flags & 0x0400)
1056                 g_string_append (res, "rtspecialname ");
1057         g_string_append_printf (res, "%s %s", type, esname);
1058
1059         g_free (type);
1060         g_free (esname);
1061         result = res->str;
1062         g_string_free (res, FALSE);
1063         return result;
1064 }
1065
1066 static void
1067 dis_event_methods (MonoImage *m, guint32 event, MonoGenericContainer *container)
1068 {
1069         guint start, end;
1070         MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
1071         guint32 cols [MONO_METHOD_SEMA_SIZE];
1072         char *sig;
1073         const char *type = "";
1074
1075         start = mono_metadata_methods_from_event (m, event, &end);
1076         for (; start < end; ++start) {
1077                 mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
1078                 if (!should_include_method (cols [MONO_METHOD_SEMA_METHOD]))
1079                         continue;
1080                 sig = dis_stringify_method_signature_full (m, NULL, cols [MONO_METHOD_SEMA_METHOD], container, TRUE, FALSE);
1081                 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
1082                 case METHOD_SEMANTIC_OTHER:
1083                         type = ".other"; break;
1084                 case METHOD_SEMANTIC_ADD_ON:
1085                         type = ".addon"; break;
1086                 case METHOD_SEMANTIC_REMOVE_ON:
1087                         type = ".removeon"; break;
1088                 case METHOD_SEMANTIC_FIRE:
1089                         type = ".fire"; break;
1090                 default:
1091                         break;
1092                 }
1093                 fprintf (output, "\t\t%s %s\n", type, sig);
1094                 g_free (sig);
1095         }
1096 }
1097
1098 static void
1099 dis_event_list (MonoImage *m, guint32 typedef_row, MonoGenericContainer *container)
1100 {
1101         guint start, end, i;
1102         start = mono_metadata_events_from_typedef (m, typedef_row, &end);
1103
1104         for (i = start; i < end; ++i) {
1105                 char *sig = dis_event_signature (m, i, container);
1106                 fprintf (output, "\t.event %s\n\t{\n", sig);
1107                 dump_cattrs (m, MONO_TOKEN_EVENT | (i + 1), "\t\t");
1108                 dis_event_methods (m, i, container);
1109                 fprintf (output, "\t}\n");
1110                 g_free (sig);
1111         }
1112 }
1113
1114 static void
1115 dis_interfaces (MonoImage *m, guint32 typedef_row, MonoGenericContainer *container)
1116 {
1117         plocator_t loc;
1118         guint start;
1119         gboolean first_interface = 1;
1120         guint32 cols [MONO_INTERFACEIMPL_SIZE];
1121         char *intf;
1122         MonoTableInfo *table = &m->tables [MONO_TABLE_INTERFACEIMPL];
1123
1124         if (!table->base)
1125                 return;
1126
1127         loc.t = table;
1128         loc.col_idx = MONO_INTERFACEIMPL_CLASS;
1129         loc.idx = typedef_row;
1130
1131         if (!mono_binary_search (&loc, table->base, table->rows, table->row_size, table_locator))
1132                 return;
1133
1134         start = loc.result;
1135         /*
1136          * We may end up in the middle of the rows... 
1137          */
1138         while (start > 0) {
1139                 if (loc.idx == mono_metadata_decode_row_col (table, start - 1, MONO_INTERFACEIMPL_CLASS))
1140                         start--;
1141                 else
1142                         break;
1143         }
1144         while (start < table->rows) {
1145                 mono_metadata_decode_row (table, start, cols, MONO_INTERFACEIMPL_SIZE);
1146                 if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
1147                         break;
1148                 intf = get_typedef_or_ref (m, cols [MONO_INTERFACEIMPL_INTERFACE], container);
1149                 if (first_interface) {
1150                         fprintf (output, "  \timplements %s", intf);
1151                         first_interface = 0;
1152                 } else {
1153                         fprintf (output, ", %s", intf);
1154                 }
1155                 g_free (intf);
1156                 ++start;
1157         }
1158 }
1159
1160 /**
1161  * dis_type:
1162  * @m: metadata context
1163  * @n: index of type to disassemble
1164  * @is_nested: nested type ?
1165  * @forward: forward declarations?
1166  *
1167  * Disassembles the type whose index in the TypeDef table is @n.
1168  */
1169 static void
1170 dis_type (MonoImage *m, int n, int is_nested, int forward)
1171 {
1172         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
1173         guint32 cols [MONO_TYPEDEF_SIZE];
1174         guint32 cols_next [MONO_TYPEDEF_SIZE];
1175         const char *name, *nspace;
1176         char *esname, *param;
1177         MonoGenericContainer *container;
1178         guint32 packing_size, class_size;
1179         gboolean next_is_valid, last;
1180         guint32 nested;
1181
1182         if (!should_include_type (n + 1))
1183                 return;
1184         mono_metadata_decode_row (t, n, cols, MONO_TYPEDEF_SIZE);
1185
1186         if (t->rows > n + 1) {
1187                 mono_metadata_decode_row (t, n + 1, cols_next, MONO_TYPEDEF_SIZE);
1188                 next_is_valid = 1;
1189         } else
1190                 next_is_valid = 0;
1191
1192         name = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME]);
1193         nspace = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE]);
1194         if (*nspace && !is_nested) {
1195                 char *esnspace;
1196                 esnspace = get_escaped_name (nspace);
1197                 fprintf (output, ".namespace %s\n{\n", esnspace);
1198                 g_free (esnspace);
1199         }
1200
1201         container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), NULL);
1202         if (container) {
1203                 MonoError error;
1204                 mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (n + 1), container, &error);
1205                 g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
1206         }
1207
1208         esname = get_escaped_name (name);
1209         if ((cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
1210                 fprintf (output, "  .class %s%s", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), esname);
1211                 
1212                 param = get_generic_param (m, container);
1213                 if (param) {
1214                         fprintf (output, "%s", param);
1215                         g_free (param);
1216                 }
1217                 fprintf (output, "\n");
1218                 if (cols [MONO_TYPEDEF_EXTENDS]) {
1219                         char *base = get_typedef_or_ref (m, cols [MONO_TYPEDEF_EXTENDS], container);
1220                         fprintf (output, "  \textends %s\n", base);
1221                         g_free (base);
1222                 }
1223         } else {
1224                 fprintf (output, "  .class interface %s%s", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), esname);
1225
1226                 param = get_generic_param (m, container);
1227                 if (param) {
1228                         fprintf (output, "%s", param);
1229                         g_free (param);
1230                 }
1231                 fprintf (output, "\n");
1232         }
1233
1234         g_free (esname);
1235         dis_interfaces (m, n + 1, container);
1236         fprintf (output, "  {\n");
1237         if (!forward) {
1238                 dump_cattrs (m, MONO_TOKEN_TYPE_DEF | (n + 1), "    ");
1239                 dump_cattrs_for_type_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), "    ");
1240                 dump_declarative_security (m, OBJECT_TYPE_TYPEDEF, (n + 1), "    ");
1241
1242                 if (mono_metadata_packing_from_typedef (m, n + 1, &packing_size, &class_size)) {
1243                         fprintf (output, "    .pack %d\n", packing_size);
1244                         fprintf (output, "    .size %d\n", class_size);
1245                 }
1246                 /*
1247                  * The value in the table is always valid, we know we have fields
1248                  * if the value stored is different than the next record.
1249                  */
1250         
1251                 if (next_is_valid)
1252                         last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
1253                 else
1254                         last = m->tables [MONO_TABLE_FIELD].rows;
1255                         
1256                 if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= m->tables [MONO_TABLE_FIELD].rows)
1257                         dis_field_list (m, cols [MONO_TYPEDEF_FIELD_LIST] - 1, last, container);
1258                 fprintf (output, "\n");
1259
1260                 if (next_is_valid)
1261                         last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
1262                 else
1263                         last = m->tables [MONO_TABLE_METHOD].rows;
1264         
1265                 if (cols [MONO_TYPEDEF_METHOD_LIST] && cols [MONO_TYPEDEF_METHOD_LIST] <= m->tables [MONO_TABLE_METHOD].rows)
1266                         dis_method_list (name, m, cols [MONO_TYPEDEF_METHOD_LIST] - 1, last, container);
1267
1268                 dis_property_list (m, n, container);
1269                 dis_event_list (m, n, container);
1270         }
1271
1272         t = &m->tables [MONO_TABLE_NESTEDCLASS];
1273         nested = mono_metadata_nesting_typedef (m, n + 1, 1);
1274         while (nested) {
1275                 dis_type (m, mono_metadata_decode_row_col (t, nested - 1, MONO_NESTED_CLASS_NESTED) - 1, 1, forward);
1276                 nested = mono_metadata_nesting_typedef (m, n + 1, nested + 1);
1277         }
1278         
1279         fprintf (output, "  } // end of class %s%s%s\n", nspace, *nspace? ".": "", name);
1280         if (*nspace && !is_nested)
1281                 fprintf (output, "}\n");
1282         fprintf (output, "\n");
1283 }
1284
1285
1286 /**
1287  * dis_globals
1288  * @m: metadata context
1289  *
1290  * disassembles all the global fields and methods
1291  */
1292 static void
1293 dis_globals (MonoImage *m)
1294 {
1295         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
1296         guint32 cols [MONO_TYPEDEF_SIZE];
1297         guint32 cols_next [MONO_TYPEDEF_SIZE];
1298         gboolean next_is_valid, last;
1299
1300         mono_metadata_decode_row (t, 0, cols, MONO_TYPEDEF_SIZE);
1301
1302         if (t->rows > 1) {
1303                 mono_metadata_decode_row (t, 1, cols_next, MONO_TYPEDEF_SIZE);
1304                 next_is_valid = 1;
1305         } else
1306                 next_is_valid = 0;
1307         
1308         /*
1309          * The value in the table is always valid, we know we have fields
1310          * if the value stored is different than the next record.
1311          */
1312
1313         if (next_is_valid)
1314                 last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
1315         else
1316                 last = m->tables [MONO_TABLE_FIELD].rows;
1317                         
1318         if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= m->tables [MONO_TABLE_FIELD].rows)
1319                 dis_field_list (m, cols [MONO_TYPEDEF_FIELD_LIST] - 1, last, NULL);
1320         fprintf (output, "\n");
1321
1322         if (next_is_valid)
1323                 last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
1324         else
1325                 last = m->tables [MONO_TABLE_METHOD].rows;
1326         
1327         if (cols [MONO_TYPEDEF_METHOD_LIST] && cols [MONO_TYPEDEF_METHOD_LIST] <= m->tables [MONO_TABLE_METHOD].rows)
1328                 dis_method_list (NULL, m, cols [MONO_TYPEDEF_METHOD_LIST] - 1, last, NULL);
1329
1330 }
1331
1332 static void dis_resources_worker (MonoImage *m, gboolean just_print)
1333 {
1334         MonoTableInfo *t = &m->tables [MONO_TABLE_MANIFESTRESOURCE];
1335         int i;
1336         
1337         for (i = 0; i < t->rows; i++){
1338                 guint32 cols [MONO_MANIFEST_SIZE];
1339                 const char *name, *res;
1340                 guint32 size;
1341                 FILE* fp;
1342
1343                 mono_metadata_decode_row (t, i, cols, MONO_MANIFEST_SIZE);
1344                 name = mono_metadata_string_heap (m, cols [MONO_MANIFEST_NAME]);
1345
1346                 if (just_print)
1347                         fprintf (output, "%8x: %s", cols [MONO_MANIFEST_OFFSET], name);
1348                 
1349                 if (! (res = mono_image_get_resource (m, cols [MONO_MANIFEST_OFFSET], &size))) {
1350                         if (just_print)
1351                                 fprintf (output, " (absent from image)\n");
1352                         continue;       
1353                 }
1354
1355                 if (just_print) {
1356                         fprintf (output, " (size %u)\n", size);
1357                         continue;
1358                 }
1359                 
1360                 if ( (fp = fopen (name, "ab")) ) {
1361                         if (ftell (fp) == 0)
1362                                 fwrite (res, size, 1, fp);
1363                         else 
1364                                 g_warning ("Error creating managed resource - %s : File already exists.", name);
1365
1366                         fclose (fp);
1367                 } else
1368                         g_warning ("Error creating managed resource - %s : %s", name, g_strerror (errno));
1369         }               
1370 }
1371
1372 static void
1373 dis_mresource (MonoImage *m)
1374 {
1375         dis_resources_worker (m, FALSE);
1376 }
1377
1378 static void
1379 dis_presource (MonoImage *m)
1380 {
1381         dis_resources_worker (m, TRUE);
1382 }
1383
1384 static char *
1385 exported_type_flags (guint32 flags)
1386 {
1387         static char buffer [1024];
1388         int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1389
1390         buffer [0] = 0;
1391
1392         if (flags & TYPE_ATTRIBUTE_FORWARDER) {
1393                 strcat (buffer, "forwarder ");
1394                 return buffer;
1395         }
1396
1397         strcat (buffer, map (visibility, visibility_map));
1398         return buffer;
1399 }
1400
1401 static char *
1402 get_escaped_fullname (MonoImage *m, guint32 nspace_idx, guint32 name_idx)
1403 {
1404         const char *name, *nspace;
1405         char *fullname, *esfullname;
1406
1407         nspace = mono_metadata_string_heap (m, nspace_idx);
1408         name = mono_metadata_string_heap (m, name_idx);
1409
1410         fullname = g_strdup_printf ("%s%s%s", nspace, *nspace ? "." : "", name);
1411         esfullname = get_escaped_name (fullname);
1412
1413         g_free (fullname);
1414
1415         return esfullname;
1416 }
1417
1418 static void
1419 dis_exported_types (MonoImage *m)
1420 {
1421         MonoTableInfo *t = &m->tables [MONO_TABLE_EXPORTEDTYPE];
1422         int i;
1423
1424         for (i = 1; i <= t->rows; i++) {
1425                 char *fullname;
1426                 guint32 impl, idx, type_token;
1427                 guint32 cols [MONO_EXP_TYPE_SIZE];
1428
1429                 mono_metadata_decode_row (t, i - 1, cols, MONO_EXP_TYPE_SIZE);
1430
1431                 fullname = get_escaped_fullname (m, cols [MONO_EXP_TYPE_NAMESPACE], cols [MONO_EXP_TYPE_NAME]);
1432
1433                 fprintf (output, "\n");
1434                 fprintf (output, ".class extern %s%s\n", exported_type_flags (cols [MONO_EXP_TYPE_FLAGS]), fullname);
1435                 fprintf (output, "{\n");
1436
1437                 g_free (fullname);
1438
1439                 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
1440                 if (impl) {
1441                         idx = impl >> MONO_IMPLEMENTATION_BITS;
1442                         switch (impl & MONO_IMPLEMENTATION_MASK) {
1443                         case MONO_IMPLEMENTATION_FILE:
1444                                 fprintf (output, "    .file '%s'\n",
1445                                         mono_metadata_string_heap (m, mono_metadata_decode_row_col (&m->tables [MONO_TABLE_FILE], idx - 1, MONO_FILE_NAME)));
1446                                 break;
1447                         case MONO_IMPLEMENTATION_ASSEMBLYREF:
1448                                 fprintf (output, "    .assembly extern '%s'\n",
1449                                         mono_metadata_string_heap (m, mono_metadata_decode_row_col (&m->tables [MONO_TABLE_ASSEMBLYREF], idx - 1, MONO_ASSEMBLYREF_NAME)));
1450                                 break;
1451                         case MONO_IMPLEMENTATION_EXP_TYPE:
1452                                 fullname = get_escaped_fullname (
1453                                         m,
1454                                         mono_metadata_decode_row_col (&m->tables [MONO_TABLE_EXPORTEDTYPE], idx - 1, MONO_EXP_TYPE_NAMESPACE),
1455                                         mono_metadata_decode_row_col (&m->tables [MONO_TABLE_EXPORTEDTYPE], idx - 1, MONO_EXP_TYPE_NAME));
1456                                 fprintf (output, "    .class extern %s\n", fullname);
1457                                 g_free (fullname);
1458                                 break;
1459                         default:
1460                                 g_assert_not_reached ();
1461                                 break;
1462                         }
1463                 }
1464
1465                 type_token = cols [MONO_EXP_TYPE_TYPEDEF];
1466                 if (type_token)
1467                         fprintf (output, "    .class 0x%08x\n", type_token | MONO_TOKEN_TYPE_DEF);
1468
1469                 fprintf (output, "}\n");
1470         }
1471 }
1472
1473 /**
1474  * dis_types:
1475  * @m: metadata context
1476  *
1477  * disassembles all types in the @m context
1478  */
1479 static void
1480 dis_types (MonoImage *m, int forward)
1481 {
1482         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
1483         int i;
1484         guint32 flags;
1485
1486         dis_globals (m);
1487         
1488         for (i = 1; i < t->rows; i++) {
1489                 flags = mono_metadata_decode_row_col (t, i, MONO_TYPEDEF_FLAGS);
1490                 flags &= TYPE_ATTRIBUTE_VISIBILITY_MASK;
1491                 if (flags == TYPE_ATTRIBUTE_PUBLIC || flags == TYPE_ATTRIBUTE_NOT_PUBLIC)
1492                         dis_type (m, i, 0, forward);
1493         }
1494 }
1495
1496 static const char *
1497 get_uninitialized_data_type (guint32 size)
1498 {
1499         switch (size) {
1500         case 1:
1501                 return "int8";
1502         case 2:
1503                 return "int16";
1504         case 4:
1505                 return "int32";
1506         case 8:
1507                 return "int64";
1508         default:
1509                 g_error ("get_uninitialized_data_type for size: %d\n", size);
1510         }
1511         return NULL;
1512 }
1513
1514 /**
1515  * dis_data:
1516  * @m: metadata context
1517  *
1518  * disassembles all data blobs references in the FieldRVA table in the @m context
1519  */
1520 static void
1521 dis_data (MonoImage *m)
1522 {
1523         MonoTableInfo *t = &m->tables [MONO_TABLE_FIELDRVA];
1524         MonoTableInfo *ft = &m->tables [MONO_TABLE_FIELD];
1525         int i, b;
1526         const char *rva, *sig;
1527         guint32 size;
1528         gint align;
1529         guint32 cols [MONO_FIELD_RVA_SIZE];
1530         MonoType *type;
1531
1532         for (i = 0; i < t->rows; i++) {
1533                 MonoError error;
1534                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_RVA_SIZE);
1535                 rva = mono_image_rva_map (m, cols [MONO_FIELD_RVA_RVA]);
1536                 sig = mono_metadata_blob_heap (m, mono_metadata_decode_row_col (ft, cols [MONO_FIELD_RVA_FIELD] -1, MONO_FIELD_SIGNATURE));
1537                 mono_metadata_decode_value (sig, &sig);
1538                 /* FIELD signature == 0x06 */
1539                 g_assert (*sig == 0x06);
1540                 type = mono_metadata_parse_type_checked (m, NULL, 0, FALSE, sig + 1, &sig, &error);
1541                 if (!type) {
1542                         fprintf (output, "// invalid field %d due to %s\n", i, mono_error_get_message (&error));
1543                         mono_error_cleanup (&error);
1544                         continue;
1545                 }
1546                 mono_class_init (mono_class_from_mono_type (type));
1547                 size = mono_type_size (type, &align);
1548
1549                 if (rva) {
1550                         fprintf (output, ".data D_%08x = bytearray (", cols [MONO_FIELD_RVA_RVA]);
1551                         for (b = 0; b < size; ++b) {
1552                                 if (!(b % 16))
1553                                         fprintf (output, "\n\t");
1554                                 fprintf (output, " %02X", rva [b] & 0xff);
1555                         }
1556                         fprintf (output, ") // size: %d\n", size);
1557                 } else
1558                         fprintf (output, ".data D_%08x = %s [%d]\n",
1559                                 cols [MONO_FIELD_RVA_RVA], get_uninitialized_data_type (size), size);
1560         }
1561 }
1562
1563 struct {
1564         const char *name;
1565         int table;
1566         void (*dumper) (MonoImage *m);
1567 } table_list [] = {
1568         { "--assembly",    MONO_TABLE_ASSEMBLY,         dump_table_assembly },
1569         { "--assemblyref", MONO_TABLE_ASSEMBLYREF,      dump_table_assemblyref },
1570         { "--classlayout", MONO_TABLE_CLASSLAYOUT,      dump_table_class_layout },
1571         { "--constant",    MONO_TABLE_CONSTANT,         dump_table_constant },
1572         { "--customattr",  MONO_TABLE_CUSTOMATTRIBUTE,  dump_table_customattr },
1573         { "--declsec",     MONO_TABLE_DECLSECURITY,     dump_table_declsec },
1574         { "--event",       MONO_TABLE_EVENT,            dump_table_event },
1575         { "--exported",    MONO_TABLE_EXPORTEDTYPE,     dump_table_exported },
1576         { "--fields",      MONO_TABLE_FIELD,            dump_table_field },
1577         { "--file",        MONO_TABLE_FILE,             dump_table_file },
1578         { "--genericpar",  MONO_TABLE_GENERICPARAM,     dump_table_genericpar },
1579         { "--interface",   MONO_TABLE_INTERFACEIMPL,    dump_table_interfaceimpl },
1580         { "--manifest",    MONO_TABLE_MANIFESTRESOURCE, dump_table_manifest },
1581         { "--marshal",     MONO_TABLE_FIELDMARSHAL,     dump_table_field_marshal },
1582         { "--memberref",   MONO_TABLE_MEMBERREF,        dump_table_memberref },
1583         { "--method",      MONO_TABLE_METHOD,           dump_table_method },
1584         { "--methodimpl",  MONO_TABLE_METHODIMPL,       dump_table_methodimpl },
1585         { "--methodsem",   MONO_TABLE_METHODSEMANTICS,  dump_table_methodsem },
1586         { "--methodspec",  MONO_TABLE_METHODSPEC,       dump_table_methodspec },
1587         { "--moduleref",   MONO_TABLE_MODULEREF,        dump_table_moduleref },
1588         { "--module",      MONO_TABLE_MODULE,           dump_table_module },
1589         { "--mresources",  0,   dis_mresource },
1590         { "--presources", 0, dis_presource },
1591         { "--nested",      MONO_TABLE_NESTEDCLASS,      dump_table_nestedclass },
1592         { "--param",       MONO_TABLE_PARAM,            dump_table_param },
1593         { "--parconst",    MONO_TABLE_GENERICPARAMCONSTRAINT, dump_table_parconstraint },
1594         { "--property",    MONO_TABLE_PROPERTY,         dump_table_property },
1595         { "--propertymap", MONO_TABLE_PROPERTYMAP,      dump_table_property_map },
1596         { "--typedef",     MONO_TABLE_TYPEDEF,          dump_table_typedef },
1597         { "--typeref",     MONO_TABLE_TYPEREF,          dump_table_typeref },
1598         { "--typespec",    MONO_TABLE_TYPESPEC,         dump_table_typespec },
1599         { "--implmap",     MONO_TABLE_IMPLMAP,          dump_table_implmap },
1600         { "--fieldrva",    MONO_TABLE_FIELDRVA,     dump_table_fieldrva },
1601         { "--standalonesig", MONO_TABLE_STANDALONESIG,  dump_table_standalonesig },
1602         { "--methodptr", MONO_TABLE_METHOD_POINTER,  dump_table_methodptr },
1603         { "--fieldptr", MONO_TABLE_FIELD_POINTER,  dump_table_fieldptr },
1604         { "--paramptr", MONO_TABLE_PARAM_POINTER,  dump_table_paramptr },
1605         { "--eventptr", MONO_TABLE_EVENT_POINTER,  dump_table_eventptr },
1606         { "--propertyptr", MONO_TABLE_PROPERTY_POINTER,  dump_table_propertyptr },
1607         { "--blob", 0, dump_stream_blob },
1608         { "--strings", 0, dump_stream_strings },
1609         { "--userstrings", 0, dump_stream_us },
1610         { NULL, -1, }
1611 };
1612
1613 /**
1614  * disassemble_file:
1615  * @file: file containing CIL code.
1616  *
1617  * Disassembles the @file file.
1618  */
1619 static void
1620 disassemble_file (const char *file)
1621 {
1622         MonoImageOpenStatus status;
1623         MonoImage *img;
1624
1625         img = mono_image_open (file, &status);
1626         if (!img) {
1627                 fprintf (stderr, "Error while trying to process %s\n", file);
1628                 return;
1629         } else {
1630                 /* FIXME: is this call necessary? */
1631                 mono_assembly_load_from_full (img, file, &status, FALSE);
1632         }
1633
1634         setup_filter (img);
1635
1636         if (dump_table != -1){
1637                 (*table_list [dump_table].dumper) (img);
1638         } else {
1639                 dump_header_data (img);
1640                 
1641                 dis_directive_assemblyref (img);
1642                 dis_directive_assembly (img);
1643                 dis_directive_file (img);
1644                 dis_directive_mresource (img);
1645                 dis_directive_module (img);
1646                 dis_directive_moduleref (img);
1647                 dis_exported_types (img);
1648                 dis_nt_header (img);
1649                 if (dump_managed_resources)
1650                         dis_mresource (img);
1651                 if (dump_forward_decls) {
1652                         fprintf (output, "// *************** Forward Declarations for Classes ***************\n\n"); 
1653                         dis_types (img, 1);
1654                         fprintf (output, "// *************** End-Of Forward Declarations for Classes ***************\n\n"); 
1655                 }       
1656                 dis_types (img, 0);
1657                 dis_data (img);
1658         }
1659         
1660         mono_image_close (img);
1661 }
1662
1663 typedef struct {
1664         int size;
1665         int count;
1666         int *elems;
1667 } TableFilter;
1668
1669 typedef struct {
1670         char *name;
1671         char *guid;
1672         TableFilter types;
1673         TableFilter fields;
1674         TableFilter methods;
1675 } ImageFilter;
1676
1677 static GList *filter_list = NULL;
1678 static ImageFilter *cur_filter = NULL;
1679
1680 static void     
1681 setup_filter (MonoImage *image)
1682 {
1683         ImageFilter *ifilter;
1684         GList *item;
1685         const char *name = mono_image_get_name (image);
1686
1687         for (item = filter_list; item; item = item->next) {
1688                 ifilter = (ImageFilter *)item->data;
1689                 if (strcmp (ifilter->name, name) == 0) {
1690                         cur_filter = ifilter;
1691                         return;
1692                 }
1693         }
1694         cur_filter = NULL;
1695 }
1696
1697 static int
1698 int_cmp (const void *e1, const void *e2)
1699 {
1700         const int *i1 = (const int *)e1;
1701         const int *i2 = (const int *)e2;
1702         return *i1 - *i2;
1703 }
1704
1705 static gboolean 
1706 table_includes (TableFilter *tf, int idx)
1707 {
1708         if (!tf->count)
1709                 return FALSE;
1710         return mono_binary_search (&idx, tf->elems, tf->count, sizeof (int), int_cmp) != NULL;
1711 }
1712
1713 static gboolean 
1714 should_include_type (int idx)
1715 {
1716         if (!cur_filter)
1717                 return TRUE;
1718         return table_includes (&cur_filter->types, idx);
1719 }
1720
1721 static gboolean
1722 should_include_method (int idx)
1723 {
1724         if (!cur_filter)
1725                 return TRUE;
1726         return table_includes (&cur_filter->methods, idx);
1727 }
1728
1729 static gboolean
1730 should_include_field (int idx)
1731 {
1732         if (!cur_filter)
1733                 return TRUE;
1734         return table_includes (&cur_filter->fields, idx);
1735 }
1736
1737 static ImageFilter*
1738 add_filter (const char *name)
1739 {
1740         ImageFilter *ifilter;
1741         GList *item;
1742
1743         for (item = filter_list; item; item = item->next) {
1744                 ifilter = (ImageFilter *)item->data;
1745                 if (strcmp (ifilter->name, name) == 0)
1746                         return ifilter;
1747         }
1748         ifilter = g_new0 (ImageFilter, 1);
1749         ifilter->name = g_strdup (name);
1750         filter_list = g_list_prepend (filter_list, ifilter);
1751         return ifilter;
1752 }
1753
1754 static void
1755 add_item (TableFilter *tf, int val)
1756 {
1757         if (tf->count >= tf->size) {
1758                 if (!tf->size) {
1759                         tf->size = 8;
1760                         tf->elems = (int *)g_malloc (sizeof (int) * tf->size);
1761                 } else {
1762                         tf->size *= 2;
1763                         tf->elems = (int *)g_realloc (tf->elems, sizeof (int) * tf->size);
1764                 }
1765         }
1766         tf->elems [tf->count++] = val;
1767 }
1768
1769 static void
1770 sort_filter_elems (void)
1771 {
1772         ImageFilter *ifilter;
1773         GList *item;
1774
1775         for (item = filter_list; item; item = item->next) {
1776                 ifilter = (ImageFilter *)item->data;
1777                 qsort (ifilter->types.elems, ifilter->types.count, sizeof (int), int_cmp);
1778                 qsort (ifilter->fields.elems, ifilter->fields.count, sizeof (int), int_cmp);
1779                 qsort (ifilter->methods.elems, ifilter->methods.count, sizeof (int), int_cmp);
1780         }
1781 }
1782
1783 static void
1784 load_filter (const char* filename)
1785 {
1786         FILE *file;
1787         char buf [1024];
1788         char *p, *s, *endptr;
1789         int line = 0;
1790         ImageFilter *ifilter = NULL;
1791         int value = 0;
1792         
1793         if (!(file = fopen (filename, "r"))) {
1794                 g_print ("Cannot open filter file '%s'\n", filename);
1795                 exit (1);
1796         }
1797         while (fgets (buf, sizeof (buf), file) != NULL) {
1798                 ++line;
1799                 s = buf;
1800                 while (*s && g_ascii_isspace (*s)) ++s;
1801                 switch (*s) {
1802                 case 0:
1803                 case '#':
1804                         break;
1805                 case '[':
1806                         p = strchr (s, ']');
1807                         if (!p)
1808                                 g_error ("No matching ']' in filter at line %d\n", line);
1809                         *p = 0;
1810                         ifilter = add_filter (s + 1);
1811                         break;
1812                 case 'T':
1813                         if (!ifilter)
1814                                 g_error ("Invalid format in filter at line %d\n", line);
1815                         if ((s [1] != ':') || !(value = strtol (s + 2, &endptr, 0)) || (endptr == s + 2))
1816                                 g_error ("Invalid type number in filter at line %d\n", line);
1817                         add_item (&ifilter->types, value);
1818                         break;
1819                 case 'M':
1820                         if (!ifilter)
1821                                 g_error ("Invalid format in filter at line %d\n", line);
1822                         if ((s [1] != ':') || !(value = strtol (s + 2, &endptr, 0)) || (endptr == s + 2))
1823                                 g_error ("Invalid method number in filter at line %d\n", line);
1824                         add_item (&ifilter->methods, value);
1825                         break;
1826                 case 'F':
1827                         if (!ifilter)
1828                                 g_error ("Invalid format in filter at line %d\n", line);
1829                         if ((s [1] != ':') || !(value = strtol (s + 2, &endptr, 0)) || (endptr == s + 2))
1830                                 g_error ("Invalid field number in filter at line %d\n", line);
1831                         add_item (&ifilter->fields, value);
1832                         break;
1833                 default:
1834                         g_error ("Invalid format in filter at line %d\n", line);
1835                 }
1836         }
1837         fclose (file);
1838         sort_filter_elems ();
1839 }
1840
1841
1842 static gboolean
1843 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1844                                         const gchar *path3, const gchar *path4, gboolean refonly)
1845 {
1846         gchar *fullpath;
1847
1848         *assembly = NULL;
1849         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1850         if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
1851                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1852
1853         g_free (fullpath);
1854         return (*assembly != NULL);
1855 }
1856
1857 static MonoAssembly *
1858 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1859 {
1860         MonoAssembly *result = NULL;
1861         gchar **path;
1862         gchar *filename;
1863         const gchar *local_culture;
1864         gint len;
1865
1866         if (!culture || *culture == '\0') {
1867                 local_culture = "";
1868         } else {
1869                 local_culture = culture;
1870         }
1871
1872         filename =  g_strconcat (name, ".dll", NULL);
1873         len = strlen (filename);
1874
1875         for (path = search_path; *path; path++) {
1876                 if (**path == '\0')
1877                         continue; /* Ignore empty ApplicationBase */
1878
1879                 /* See test cases in bug #58992 and bug #57710 */
1880                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1881                 strcpy (filename + len - 4, ".dll");
1882                 if (try_load_from (&result, *path, local_culture, "", filename, refonly))
1883                         break;
1884
1885                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1886                 strcpy (filename + len - 4, ".exe");
1887                 if (try_load_from (&result, *path, local_culture, "", filename, refonly))
1888                         break;
1889
1890                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1891                 strcpy (filename + len - 4, ".dll");
1892                 if (try_load_from (&result, *path, local_culture, name, filename, refonly))
1893                         break;
1894
1895                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1896                 strcpy (filename + len - 4, ".exe");
1897                 if (try_load_from (&result, *path, local_culture, name, filename, refonly))
1898                         break;
1899         }
1900
1901         g_free (filename);
1902         return result;
1903 }
1904
1905 /*
1906  * Try to load referenced assemblies from assemblies_path.
1907  */
1908 static MonoAssembly *
1909 monodis_preload (MonoAssemblyName *aname,
1910                                  gchar **assemblies_path,
1911                                  gpointer user_data)
1912 {
1913         MonoAssembly *result = NULL;
1914         gboolean refonly = GPOINTER_TO_UINT (user_data);
1915
1916         if (assemblies_path && assemblies_path [0] != NULL) {
1917                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1918         }
1919
1920         return result;
1921 }
1922
1923 static GList *loaded_assemblies = NULL;
1924
1925 static void
1926 monodis_assembly_load_hook (MonoAssembly *assembly, gpointer user_data)
1927 {
1928         loaded_assemblies = g_list_prepend (loaded_assemblies, assembly);
1929 }
1930
1931 static MonoAssembly *
1932 monodis_assembly_search_hook (MonoAssemblyName *aname, gpointer user_data)
1933 {
1934         GList *tmp;
1935
1936        for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
1937                MonoAssembly *ass = (MonoAssembly *)tmp->data;
1938                if (mono_assembly_names_equal (aname, &ass->aname))
1939                        return ass;
1940        }
1941        return NULL;
1942 }
1943
1944 static void
1945 usage (void)
1946 {
1947         GString *args = g_string_new ("[--output=filename] [--filter=filename] [--help] [--mscorlib]\n");
1948         int i;
1949         
1950         for (i = 0; table_list [i].name != NULL; i++){
1951                 g_string_append (args, "[");
1952                 g_string_append (args, table_list [i].name);
1953                 g_string_append (args, "] ");
1954                 if (((i-2) % 5) == 0)
1955                         g_string_append_c (args, '\n');
1956         }
1957         g_string_append (args, "[--forward-decls]");
1958         fprintf (stderr,
1959                  "monodis -- Mono Common Intermediate Language Disassembler\n" 
1960                  "Usage is: monodis %s file ..\n", args->str);
1961         exit (1);
1962 }
1963
1964 int
1965 main (int argc, char *argv [])
1966 {
1967         GList *input_files = NULL, *l;
1968         int i, j;
1969
1970         output = stdout;
1971         init_key_table ();
1972         for (i = 1; i < argc; i++){
1973                 if (argv [i][0] == '-'){
1974                         if (argv [i][1] == 'h')
1975                                 usage ();
1976                         else if (argv [i][1] == 'd')
1977                                 dump_header_data_p = TRUE;
1978                         else if (strcmp (argv [i], "--mscorlib") == 0) {
1979                                 substitute_with_mscorlib_p = TRUE;
1980                                 continue;
1981                         } else if (strcmp (argv [i], "--show-method-tokens") == 0) {
1982                                 show_method_tokens = TRUE;
1983                                 continue;
1984                         } else if (strcmp (argv [i], "--show-tokens") == 0) {
1985                                 show_tokens = TRUE;
1986                                 continue;
1987                         } else if (strncmp (argv [i], "--output=", 9) == 0) {
1988                                 output = fopen (argv [i]+9, "w");
1989                                 if (output == NULL) {
1990                                         fprintf (stderr, "Can't open output file `%s': %s\n",
1991                                                  argv [i]+9, strerror (errno));
1992                                         exit (1);
1993                                 }
1994                                 dump_managed_resources = TRUE;
1995                                 continue;
1996                         } else if (strncmp (argv [i], "--filter=", 9) == 0) {
1997                                 load_filter (argv [i]+9);
1998                                 continue;
1999                         } else if (strcmp (argv [i], "--forward-decls") == 0) {
2000                                 dump_forward_decls = TRUE;
2001                                 continue;
2002                         } else if (strcmp (argv [i], "--help") == 0)
2003                                 usage ();
2004                         for (j = 0; table_list [j].name != NULL; j++) {
2005                                 if (strcmp (argv [i], table_list [j].name) == 0)
2006                                         dump_table = j;
2007                         }
2008                         if (dump_table < 0)
2009                                 usage ();
2010                 } else
2011                         input_files = g_list_append (input_files, argv [i]);
2012         }
2013
2014         if (input_files == NULL)
2015                 usage ();
2016
2017         mono_install_assembly_load_hook (monodis_assembly_load_hook, NULL);
2018         mono_install_assembly_search_hook (monodis_assembly_search_hook, NULL);
2019
2020         /*
2021          * If we just have one file, use the corlib version it requires.
2022          */
2023         if (!input_files->next) {
2024                 char *filename = (char *)input_files->data;
2025
2026                 mono_init_from_assembly (argv [0], filename);
2027
2028                 mono_install_assembly_preload_hook (monodis_preload, GUINT_TO_POINTER (FALSE));
2029
2030                 disassemble_file (filename);
2031         } else {
2032                 mono_init (argv [0]);
2033
2034                 for (l = input_files; l; l = l->next)
2035                         disassemble_file ((const char *)l->data);
2036         }
2037
2038         return 0;
2039 }