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