Mon Aug 20 19:33:34 CEST 2001 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / dis / main.c
1 /*
2  * main.c: Sample disassembler
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  *
9  * TODO:
10  *   Investigate how interface inheritance works and how it should be dumped.
11  *   Structs are not being labeled as `valuetype' classes
12  *   
13  *   How are fields with literals mapped to constants?
14  */
15 #include <config.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <glib.h>
19 #include <stdlib.h>
20 #include "meta.h"
21 #include "util.h"
22 #include "dump.h"
23 #include "get.h"
24 #include "dis-cil.h"
25
26 FILE *output;
27
28 /* True if you want to get a dump of the header data */
29 gboolean dump_header_data_p = FALSE;
30
31 int dump_table = -1;
32
33 static void
34 dump_header_data (MonoImage *img)
35 {
36         if (!dump_header_data_p)
37                 return;
38
39         fprintf (output,
40                  "// Ximian's CIL disassembler, version 1.0\n"
41                  "// Copyright (C) 2001 Ximian, Inc.\n\n");
42 }
43
44 static void
45 dis_directive_assembly (MonoMetadata *m)
46 {
47         MonoTableInfo *t  = &m->tables [MONO_TABLE_ASSEMBLY];
48         guint32 cols [MONO_ASSEMBLY_SIZE];
49         
50         if (t->base == NULL)
51                 return;
52
53         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
54         
55         fprintf (output,
56                  ".assembly %s\n"
57                  "{\n"
58                  "  .hash algorithm 0x%08x\n"
59                  "  .ver  %d.%d.%d.%d"
60                  "%s %s"
61                  "%s"
62                  "\n"
63                  "}\n",
64                  mono_metadata_string_heap (m, cols [MONO_ASSEMBLY_NAME]),
65                  cols [MONO_ASSEMBLY_HASH_ALG],
66                  cols [MONO_ASSEMBLY_MAJOR_VERSION], cols [MONO_ASSEMBLY_MINOR_VERSION], 
67                  cols [MONO_ASSEMBLY_BUILD_NUMBER], cols [MONO_ASSEMBLY_REV_NUMBER],
68                  cols [MONO_ASSEMBLY_CULTURE] ? "\n  .locale" : "",
69                  cols [MONO_ASSEMBLY_CULTURE] ? mono_metadata_string_heap (m, cols [MONO_ASSEMBLY_CULTURE]) : "",
70                  cols [MONO_ASSEMBLY_PUBLIC_KEY] ? "\n  .publickey" : ""
71                 );
72 }
73
74 static void
75 dis_directive_assemblyref (MonoMetadata *m)
76 {
77         MonoTableInfo *t = &m->tables [MONO_TABLE_ASSEMBLYREF];
78         guint32 cols [MONO_ASSEMBLYREF_SIZE];
79         int i;
80         
81         if (t->base == NULL)
82                 return;
83
84         for (i = 0; i < t->rows; i++){
85                 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
86
87                 fprintf (output,
88                          ".assembly extern %s\n"
89                          "{\n"
90                          "  .ver %d.%d.%d.%d\n"
91                          "}\n",
92                          mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_NAME]),
93                          cols [MONO_ASSEMBLYREF_MAJOR_VERSION], cols [MONO_ASSEMBLYREF_MINOR_VERSION], 
94                          cols [MONO_ASSEMBLYREF_BUILD_NUMBER], cols [MONO_ASSEMBLYREF_REV_NUMBER]
95                         );
96         }
97 }
98
99 static map_t visibility_map [] = {
100         { TYPE_ATTRIBUTE_NOT_PUBLIC,           "private " },
101         { TYPE_ATTRIBUTE_PUBLIC,               "public " },
102         { TYPE_ATTRIBUTE_NESTED_PUBLIC,        "nested-public " },
103         { TYPE_ATTRIBUTE_NESTED_PRIVATE,       "nested-private " },
104         { TYPE_ATTRIBUTE_NESTED_FAMILY,        "family " },
105         { TYPE_ATTRIBUTE_NESTED_ASSEMBLY,      "nested-assembly" },
106         { TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM, "nested-fam-and-assembly" },
107         { TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM,  "nested-fam-or-assembly" },
108         { 0, NULL }
109 };
110
111 static map_t layout_map [] = {
112         { TYPE_ATTRIBUTE_AUTO_LAYOUT,          "auto " },
113         { TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT,    "sequential " },
114         { TYPE_ATTRIBUTE_EXPLICIT_LAYOUT,      "explicit " },
115         { 0, NULL }
116 };
117
118 static map_t format_map [] = {
119         { TYPE_ATTRIBUTE_ANSI_CLASS,           "ansi " },
120         { TYPE_ATTRIBUTE_UNICODE_CLASS,        "unicode " },
121         { TYPE_ATTRIBUTE_AUTO_CLASS,           "auto " },
122         { 0, NULL }
123 };
124
125 static char *
126 typedef_flags (guint32 flags)
127 {
128         static char buffer [1024];
129         int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
130         int layout = flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
131         int format = flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK;
132         
133         buffer [0] = 0;
134
135         strcat (buffer, map (visibility, visibility_map));
136         strcat (buffer, map (layout, layout_map));
137         strcat (buffer, map (format, format_map));
138         
139         if (flags & TYPE_ATTRIBUTE_ABSTRACT)
140                 strcat (buffer, "abstract ");
141         if (flags & TYPE_ATTRIBUTE_SEALED)
142                 strcat (buffer, "sealed ");
143         if (flags & TYPE_ATTRIBUTE_SPECIAL_NAME)
144                 strcat (buffer, "special-name ");
145         if (flags & TYPE_ATTRIBUTE_IMPORT)
146                 strcat (buffer, "import ");
147         if (flags & TYPE_ATTRIBUTE_SERIALIZABLE)
148                 strcat (buffer, "serializable ");
149         if (flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
150                 strcat (buffer, "beforefieldinit ");
151
152         return buffer;
153 }
154
155 /**
156  * dis_field_list:
157  * @m: metadata context
158  * @start: starting index into the Field Table.
159  * @end: ending index into Field table.
160  *
161  * This routine displays all the decoded fields from @start to @end
162  */
163 static void
164 dis_field_list (MonoMetadata *m, guint32 start, guint32 end)
165 {
166         MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
167         guint32 cols [MONO_FIELD_SIZE];
168         int i;
169
170         if (end > t->rows + 1) {
171                 g_warning ("ERROR index out of range in fields");
172                 end = t->rows;
173         }
174                         
175         for (i = start; i < end; i++){
176                 char *sig, *flags;
177                 
178                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
179                 sig = get_field_signature (m, cols [MONO_FIELD_SIGNATURE]);
180                 flags = field_flags (cols [MONO_FIELD_FLAGS]);
181                 
182                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_LITERAL){
183                         MonoTypeEnum type;
184                         char *lit;
185                         
186                         type = get_field_literal_type (m, cols [MONO_FIELD_SIGNATURE]);
187                         lit = g_strdup ("FIXME:Do-not-know-how-to-get-this-from-the-constants-table");
188                         /* get_constant (m, type, cols [2]); */
189                         
190                         fprintf (output, "    .field %s %s %s = ",
191                                  flags, sig,
192                                  mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
193                         fprintf (output, "%s\n", lit);
194                         g_free (lit);
195                 } else 
196                         fprintf (output, "    .field %s %s %s\n",
197                                  flags, sig,
198                                  mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
199                 g_free (flags);
200                 g_free (sig);
201         }
202 }
203
204 static map_t method_access_map [] = {
205         { METHOD_ATTRIBUTE_COMPILER_CONTROLLED, "compilercontrolled " },
206         { METHOD_ATTRIBUTE_PRIVATE,             "private" },
207         { METHOD_ATTRIBUTE_FAM_AND_ASSEM,       "famandassem" },
208         { METHOD_ATTRIBUTE_ASSEM,               "assembly " },
209         { METHOD_ATTRIBUTE_FAMILY,              "family " },
210         { METHOD_ATTRIBUTE_FAM_OR_ASSEM,        "famorassem " },
211         { METHOD_ATTRIBUTE_PUBLIC,              "public " },
212         { 0, NULL }
213 };
214
215 static map_t method_flags_map [] = {
216         { METHOD_ATTRIBUTE_STATIC,              "static " },
217         { METHOD_ATTRIBUTE_FINAL,               "final " },
218         { METHOD_ATTRIBUTE_VIRTUAL,             "virtual " },
219         { METHOD_ATTRIBUTE_HIDE_BY_SIG,         "hidebysig " },
220         { METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK,  "newslot " },
221         { METHOD_ATTRIBUTE_ABSTRACT,            "abstract " },
222         { METHOD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
223         { METHOD_ATTRIBUTE_RT_SPECIAL_NAME,     "rtspecialname " },
224         { METHOD_ATTRIBUTE_UNMANAGED_EXPORT,    "export " },
225         { METHOD_ATTRIBUTE_HAS_SECURITY,        "hassecurity" },
226         { METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT,  "requiresecobj" },
227         { METHOD_ATTRIBUTE_PINVOKE_IMPL,        "pinvokeimpl " }, 
228         { 0, NULL }
229 };
230
231 /**
232  * method_flags:
233  *
234  * Returns a stringified version of the Method's flags
235  */
236 static char *
237 method_flags (guint32 f)
238 {
239         GString *str = g_string_new ("");
240         int access = f & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
241         char *s;
242         
243         g_string_append (str, map (access, method_access_map));
244         g_string_append (str, flags (f, method_flags_map));
245
246         s = str->str;
247         g_string_free (str, FALSE);
248
249         return s;
250 }
251
252 static map_t pinvoke_flags_map [] = {
253         { PINVOKE_ATTRIBUTE_NO_MANGLE ,            "nomangle " },
254         { PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR,   "lasterr " },
255         { 0, NULL }
256 };
257
258 static map_t pinvoke_call_conv_map [] = {
259         { PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI,      "winapi " },
260         { PINVOKE_ATTRIBUTE_CALL_CONV_CDECL,       "cdecl " },
261         { PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL,     "stdcall " },
262         { PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL,    "thiscall " },
263         { PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL,    "fastcall " },
264         { 0, NULL }
265 };
266
267 static map_t pinvoke_char_set_map [] = {
268         { PINVOKE_ATTRIBUTE_CHAR_SET_NOT_SPEC,     "" },
269         { PINVOKE_ATTRIBUTE_CHAR_SET_ANSI,         "ansi " },
270         { PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE ,     "unicode " },
271         { PINVOKE_ATTRIBUTE_CHAR_SET_AUTO,         "autochar " },
272         { 0, NULL }
273 };
274
275 /**
276  * pinvoke_flags:
277  *
278  * Returns a stringified version of the Method's pinvoke flags
279  */
280 static char *
281 pinvoke_flags (guint32 f)
282 {
283         GString *str = g_string_new ("");
284         int cset = f & PINVOKE_ATTRIBUTE_CHAR_SET_MASK;
285         int cconv = f & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
286         char *s;
287         
288         g_string_append (str, map (cset, pinvoke_char_set_map));
289         g_string_append (str, map (cconv, pinvoke_call_conv_map));
290         g_string_append (str, flags (f, pinvoke_flags_map));
291
292         s = g_strdup(str->str);
293         g_string_free (str, FALSE);
294
295         return s;
296 }
297
298 static map_t method_impl_map [] = {
299         { METHOD_IMPL_ATTRIBUTE_IL,              "cil " },
300         { METHOD_IMPL_ATTRIBUTE_NATIVE,          "native " },
301         { METHOD_IMPL_ATTRIBUTE_OPTIL,           "optil " },
302         { METHOD_IMPL_ATTRIBUTE_RUNTIME,         "runtime " },
303         { 0, NULL }
304 };
305
306 static map_t managed_type_map [] = {
307         { METHOD_IMPL_ATTRIBUTE_UNMANAGED,       "unmanaged " },
308         { METHOD_IMPL_ATTRIBUTE_MANAGED,         "managed " },
309         { 0, NULL }
310 };
311
312 static map_t managed_impl_flags [] = {
313         { METHOD_IMPL_ATTRIBUTE_FORWARD_REF,     "fwdref " },
314         { METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG,    "preservesig " },
315         { METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL,   "internalcall " },
316         { METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED,    "synchronized " },
317         { METHOD_IMPL_ATTRIBUTE_NOINLINING,      "noinline " },
318         { 0, NULL }
319 };
320
321 static char *
322 method_impl_flags (guint32 f)
323 {
324         GString *str = g_string_new ("");
325         char *s;
326         int code_type = f & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
327         int managed_type = f & METHOD_IMPL_ATTRIBUTE_MANAGED_MASK;
328
329         g_string_append (str, map (code_type, method_impl_map));
330         g_string_append (str, map (managed_type, managed_type_map));
331         g_string_append (str, flags (f, managed_impl_flags));
332         
333         s = str->str;
334         g_string_free (str, FALSE);
335         return s;
336 }
337
338 static void
339 dis_locals (MonoMetadata *m, MonoMethodHeader *mh) 
340 {
341         int i;
342
343         fprintf(output, "\t.locals %s(\n", mh->init_locals ? "init " : "");
344         for (i=0; i < mh->num_locals; ++i) {
345                 char * desc;
346                 /* print also byref and pinned attributes */
347                 desc = dis_stringify_type (m, mh->locals[i]);
348                 fprintf(output, "\t\t%s\tV_%d\n", desc, i);
349                 g_free(desc);
350         }
351         fprintf(output, "\t)\n");
352 }
353
354 static void
355 dis_code (MonoMetadata *m, MonoCLIImageInfo *ii, guint32 rva)
356 {
357         MonoMethodHeader *mh;
358         const char *ptr = mono_cli_rva_map (ii, rva);
359         char *loc;
360
361         if (rva == 0)
362                 return;
363
364         mh = mono_metadata_parse_mh (m, ptr);
365         if (ii->cli_cli_header.ch_entry_point){
366                 loc = mono_metadata_locate_token (m, ii->cli_cli_header.ch_entry_point);
367                 if (rva == read32 (loc))
368                         fprintf (output, "\t.entrypoint\n");
369         }
370         
371         fprintf (output, "\t.maxstack %d\n", mh->max_stack);
372         fprintf (output, "\t// Code size=%d (0x%x)\n", mh->code_size, mh->code_size);
373         printf ("\t// Values Code Size=%d/0x%x\n\n",
374                 mh->code_size, mh->code_size);
375         if (mh->num_locals)
376                 dis_locals (m, mh);
377         dissasemble_cil (m, mh);
378         
379 /*
380   hex_dump (mh->code, 0, mh->code_size);
381   printf ("\nAfter the code\n");
382   hex_dump (mh->code + mh->code_size, 0, 64);
383 */
384         mono_metadata_free_mh (mh);
385 }
386
387 static char *
388 pinvoke_info (MonoMetadata *m, guint32 mindex)
389 {
390         MonoTableInfo *im = &m->tables [MONO_TABLE_IMPLMAP];
391         MonoTableInfo *mr = &m->tables [MONO_TABLE_MODULEREF];
392         guint32 im_cols [MONO_IMPLMAP_SIZE];
393         guint32 mr_cols [MONO_MODULEREF_SIZE];
394         const char *import, *scope;
395         char *flags;
396         int i;
397
398         for (i = 0; i < im->rows; i++) {
399
400                 mono_metadata_decode_row (im, i, im_cols, MONO_IMPLMAP_SIZE);
401
402                 if ((im_cols [MONO_IMPLMAP_MEMBER] >> 1) == mindex + 1) {
403
404                         flags = pinvoke_flags (im_cols [MONO_IMPLMAP_FLAGS]);
405
406                         import = mono_metadata_string_heap (m, im_cols [MONO_IMPLMAP_NAME]);
407
408                         mono_metadata_decode_row (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, 
409                                                   mr_cols, MONO_MODULEREF_SIZE);
410
411                         scope = mono_metadata_string_heap (m, mr_cols [MONO_MODULEREF_NAME]);
412                                 
413                         return g_strdup_printf ("(%s as %s %s)", scope, import,
414                                                 flags);
415                         g_free (flags);
416                 }
417         }
418
419         return NULL;
420 }
421
422 /**
423  * dis_method_list:
424  * @m: metadata context
425  * @start: starting index into the Method Table.
426  * @end: ending index into Method table.
427  *
428  * This routine displays the methods in the Method Table from @start to @end
429  */
430 static void
431 dis_method_list (MonoMetadata *m, MonoCLIImageInfo *ii, guint32 start, guint32 end)
432 {
433         MonoTableInfo *t = &m->tables [MONO_TABLE_METHOD];
434         guint32 cols [MONO_METHOD_SIZE];
435         int i;
436
437         if (end > t->rows){
438                 fprintf (output, "ERROR index out of range in methods");
439                 /*exit (1);*/
440                 end = t->rows;
441         }
442
443         for (i = start; i < end; i++){
444                 MonoMethodSignature *ms;
445                 char *flags, *impl_flags;
446                 const char *sig;
447                 char *sig_str;
448                 
449                 mono_metadata_decode_row (t, i, cols, MONO_METHOD_SIZE);
450
451                 flags = method_flags (cols [MONO_METHOD_FLAGS]);
452                 impl_flags = method_impl_flags (cols [MONO_METHOD_IMPLFALGS]);
453
454                 sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
455                 mono_metadata_decode_blob_size (sig, &sig);
456                 ms = mono_metadata_parse_method_signature (m, 1, sig, &sig);
457                 sig_str = dis_stringify_method_signature (m, ms, i + 1);
458                         
459                 fprintf (output, "    .method %s", flags);
460
461                 if (cols [MONO_METHOD_FLAGS] & METHOD_ATTRIBUTE_PINVOKE_IMPL)
462                         fprintf (output, "%s", pinvoke_info (m, i));
463
464                 fprintf (output, "\n           %s", sig_str);
465                 fprintf (output, " %s\n", impl_flags);
466                 g_free (flags);
467                 g_free (impl_flags);
468                 
469                 fprintf (output, "    {\n");
470                 fprintf (output, "        // Method begins at RVA 0x%x\n", cols [MONO_METHOD_RVA]);
471                 dis_code (m, ii, cols [MONO_METHOD_RVA]);
472                 fprintf (output, "    }\n\n");
473                 mono_metadata_free_method_signature (ms);
474                 g_free (sig_str);
475         }
476 }
477
478 typedef struct {
479         MonoTableInfo *t;
480         guint32 col_idx;
481         guint32 idx;
482         guint32 result;
483 } plocator_t;
484
485 static int
486 table_locator (const void *a, const void *b)
487 {
488         plocator_t *loc = (plocator_t *) a;
489         char *bb = (char *) b;
490         guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
491         guint32 col;
492         
493         col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
494
495         if (loc->idx == col) {
496                 loc->result = table_index;
497                 return 0;
498         }
499         if (loc->idx < col)
500                 return -1;
501         else 
502                 return 1;
503 }
504
505 static void
506 dis_property_methods (MonoMetadata *m, guint32 prop)
507 {
508         plocator_t loc;
509         guint start;
510         guint32 cols [MONO_METHOD_SEMA_SIZE];
511         MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
512         char *sig;
513         char *type[] = {NULL, ".set", ".get", NULL, ".other"};
514
515         loc.t = msemt;
516         loc.col_idx = MONO_METHOD_SEMA_ASSOCIATION;
517         loc.idx = (prop << 1) | 1; /* Method association coded index */
518
519         if (!bsearch (&loc, msemt->base, msemt->rows, msemt->row_size, table_locator))
520                 return;
521
522         start = loc.result;
523         /*
524          * We may end up in the middle of the rows... 
525          */
526         while (start > 0) {
527                 if (loc.idx == mono_metadata_decode_row_col (msemt, start - 1, MONO_METHOD_SEMA_ASSOCIATION))
528                         start--;
529                 else
530                         break;
531         }
532         while (start < msemt->rows) {
533                 mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
534                 if (cols [MONO_METHOD_SEMA_ASSOCIATION] != loc.idx)
535                         break;
536                 sig = dis_stringify_method_signature (m, NULL, cols [MONO_METHOD_SEMA_METHOD]);
537                 fprintf (output, "\t\t%s %s\n", type [cols [MONO_METHOD_SEMA_SEMANTICS]], sig);
538                 g_free (sig);
539                 ++start;
540         }
541 }
542
543 static char*
544 dis_property_signature (MonoMetadata *m, guint32 prop_idx)
545 {
546         MonoTableInfo *propt = &m->tables [MONO_TABLE_PROPERTY];
547         const char *ptr;
548         guint32 pcount, i;
549         guint32 cols [MONO_PROPERTY_SIZE];
550         MonoType *type;
551         MonoParam *param;
552         char *blurb;
553         const char *name;
554         int prop_flags;
555         GString *res = g_string_new ("");
556
557         mono_metadata_decode_row (propt, prop_idx, cols, MONO_PROPERTY_SIZE);
558         name = mono_metadata_string_heap (m, cols [MONO_PROPERTY_NAME]);
559         prop_flags = cols [MONO_PROPERTY_FLAGS];
560         ptr = mono_metadata_blob_heap (m, cols [MONO_PROPERTY_TYPE]);
561         mono_metadata_decode_blob_size (ptr, &ptr);
562         /* ECMA claims 0x08 ... */
563         if (*ptr != 0x28 && *ptr != 0x08)
564                 g_warning("incorrect signature in propert blob: 0x%x", *ptr);
565         ptr++;
566         pcount = mono_metadata_decode_value (ptr, &ptr);
567         type = mono_metadata_parse_type (m, ptr, &ptr);
568         blurb = dis_stringify_type (m, type);
569         if (prop_flags & 0x0200)
570                 g_string_append (res, "special ");
571         if (prop_flags & 0x0400)
572                 g_string_append (res, "runtime ");
573         if (prop_flags & 0x1000)
574                 g_string_append (res, "hasdefault ");
575         g_string_sprintfa (res, "%s %s (", blurb, name);
576         g_free (blurb);
577         mono_metadata_free_type (type);
578         for (i = 0; i < pcount; i++) {
579                 if (i)
580                         g_string_append (res, ", ");
581                 param = mono_metadata_parse_param (m, 0, ptr, &ptr);
582                 blurb = dis_stringify_param (m, param);
583                 g_string_append (res, blurb);
584                 mono_metadata_free_param (param);
585                 g_free (blurb);
586         }
587         g_string_append_c (res, ')');
588         blurb = res->str;
589         g_string_free (res, FALSE);
590         return blurb;
591
592 }
593
594 static void
595 dis_property_list (MonoMetadata *m, guint32 typedef_row)
596 {
597         plocator_t loc;
598         guint32 start, end, i;
599         MonoTableInfo *tdef  = &m->tables [MONO_TABLE_PROPERTYMAP];
600
601         loc.t = tdef;
602         loc.col_idx = MONO_PROPERTY_MAP_PARENT;
603         loc.idx = typedef_row + 1;
604
605         if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
606                 return;
607         
608         start = mono_metadata_decode_row_col (tdef, loc.result, MONO_PROPERTY_MAP_PROPERTY_LIST);
609         if (loc.result + 1 < tdef->rows) {
610                 end = mono_metadata_decode_row_col (tdef, loc.result + 1, MONO_PROPERTY_MAP_PROPERTY_LIST) - 1;
611         } else {
612                 end = m->tables [MONO_TABLE_PROPERTY].rows;
613         }
614
615         for (i = start - 1; i < end; ++i) {
616                 char *sig = dis_property_signature (m, i);
617                 fprintf (output, "\t.property %s\n\t{\n", sig);
618                 dis_property_methods (m, i + 1);
619                 fprintf (output, "\t}\n");
620                 g_free (sig);
621         }
622 }
623
624 /**
625  * dis_type:
626  * @m: metadata context
627  * @n: index of type to disassemble
628  *
629  * Disassembles the type whose index in the TypeDef table is @n.
630  */
631 static void
632 dis_type (MonoMetadata *m, MonoCLIImageInfo *ii, int n)
633 {
634         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
635         guint32 cols [MONO_TYPEDEF_SIZE];
636         guint32 cols_next [MONO_TYPEDEF_SIZE];
637         const char *name;
638         gboolean next_is_valid, last;
639         
640         mono_metadata_decode_row (t, n, cols, MONO_TYPEDEF_SIZE);
641
642         if (t->rows > n + 1) {
643                 mono_metadata_decode_row (t, n + 1, cols_next, MONO_TYPEDEF_SIZE);
644                 next_is_valid = 1;
645         } else
646                 next_is_valid = 0;
647
648         fprintf (output, ".namespace %s\n{\n", mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE]));
649         name = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME]);
650
651         if ((cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
652                 char *base = get_typedef_or_ref (m, cols [MONO_TYPEDEF_EXTENDS]);
653                 fprintf (output, "  .class %s%s\n", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), name);
654                 fprintf (output, "  \textends %s\n", base);
655                 g_free (base);
656         } else
657                 fprintf (output, "  .class interface %s%s\n", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), name);
658         
659         fprintf (output, "  {\n");
660
661         /*
662          * The value in the table is always valid, we know we have fields
663          * if the value stored is different than the next record.
664          */
665
666         if (next_is_valid)
667                 last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
668         else
669                 last = m->tables [MONO_TABLE_FIELD].rows;
670                         
671         if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= m->tables [MONO_TABLE_FIELD].rows)
672                 dis_field_list (m, cols [MONO_TYPEDEF_FIELD_LIST] - 1, last);
673         fprintf (output, "\n");
674
675         if (next_is_valid)
676                 last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
677         else
678                 last = m->tables [MONO_TABLE_METHOD].rows;
679         
680         if (cols [MONO_TYPEDEF_METHOD_LIST] < m->tables [MONO_TABLE_METHOD].rows)
681                 dis_method_list (m, ii, cols [MONO_TYPEDEF_METHOD_LIST] - 1, last);
682
683         dis_property_list (m, n);
684         
685         fprintf (output, "  }\n}\n\n");
686 }
687
688 /**
689  * dis_types:
690  * @m: metadata context
691  *
692  * disassembles all types in the @m context
693  */
694 static void
695 dis_types (MonoMetadata *m, MonoCLIImageInfo *ii)
696 {
697         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
698         int i;
699
700         for (i = 1; i < t->rows; i++)
701                 dis_type (m, ii, i);
702 }
703
704 struct {
705         char *name;
706         int table;
707         void (*dumper) (MonoMetadata *m);
708 } table_list [] = {
709         { "--assembly",    MONO_TABLE_ASSEMBLY,    dump_table_assembly },
710         { "--assemblyref", MONO_TABLE_ASSEMBLYREF, dump_table_assemblyref },
711         { "--fields",      MONO_TABLE_FIELD,       dump_table_field },
712         { "--memberref",   MONO_TABLE_MEMBERREF,   dump_table_memberref },
713         { "--param",       MONO_TABLE_PARAM,       dump_table_param },
714         { "--typedef",     MONO_TABLE_TYPEDEF,     dump_table_typedef },
715         { "--typeref",     MONO_TABLE_TYPEREF,     dump_table_typeref },
716         { "--classlayout", MONO_TABLE_CLASSLAYOUT, dump_table_class_layout },
717         { "--constant",    MONO_TABLE_CONSTANT,    dump_table_constant },
718         { "--property",    MONO_TABLE_PROPERTY,    dump_table_property },
719         { "--propertymap", MONO_TABLE_PROPERTYMAP, dump_table_property_map },
720         { "--event",       MONO_TABLE_EVENT,       dump_table_event },
721         { "--file",        MONO_TABLE_FILE,        dump_table_file },
722         { "--moduleref",   MONO_TABLE_MODULEREF,   dump_table_moduleref },
723         { "--method",      MONO_TABLE_METHOD,      dump_table_method },
724         { "--methodsem",   MONO_TABLE_METHODSEMANTICS,      dump_table_methodsem },
725         { NULL, -1 }
726 };
727
728 /**
729  * disassemble_file:
730  * @file: file containing CIL code.
731  *
732  * Disassembles the @file file.
733  */
734 static void
735 disassemble_file (const char *file)
736 {
737         enum MonoImageOpenStatus status;
738         MonoImage *img;
739         MonoCLIImageInfo *ii;
740         MonoMetadata *m;
741
742         fprintf (output, "// Disassembling %s\n", file);
743
744         img = mono_image_open (file, &status);
745         if (img == NULL){
746                 fprintf (stderr, "Error while trying to process %s\n", file);
747                 return;
748         }
749
750         ii = img->image_info;
751         m = &img->metadata;
752         
753         if (dump_table != -1){
754                 (*table_list [dump_table].dumper) (m);
755         } else {
756                 dump_header_data (img);
757                 
758                 dis_directive_assemblyref (m);
759                 dis_directive_assembly (m);
760                 dis_types (m, ii);
761         }
762         
763         mono_image_close (img);
764 }
765
766 static void
767 usage (void)
768 {
769         GString *args = g_string_new ("[--help] ");
770         int i;
771         
772         for (i = 0; table_list [i].name != NULL; i++){
773                 g_string_append (args, "[");
774                 g_string_append (args, table_list [i].name);
775                 g_string_append (args, "] ");
776                 if (((i-2) % 5) == 0)
777                         g_string_append_c (args, '\n');
778         }
779         fprintf (stderr,
780                  "Usage is: monodis %s file ..\n", args->str);
781         exit (1);
782 }
783
784 int
785 main (int argc, char *argv [])
786 {
787         GList *input_files = NULL, *l;
788         int i, j;
789
790         output = stdout;
791         for (i = 1; i < argc; i++){
792                 if (argv [i][0] == '-'){
793                         if (argv [i][1] == 'h')
794                                 usage ();
795                         else if (argv [i][1] == 'd')
796                                 dump_header_data_p = TRUE;
797                         else if (strcmp (argv [i], "--help") == 0)
798                                 usage ();
799                         for (j = 0; table_list [j].name != NULL; j++) {
800                                 if (strcmp (argv [i], table_list [j].name) == 0)
801                                         dump_table = j;
802                         }
803                         if (dump_table < 0)
804                                 usage ();
805                 } else
806                         input_files = g_list_append (input_files, argv [i]);
807         }
808
809         if (input_files == NULL)
810                 usage ();
811         
812         for (l = input_files; l; l = l->next)
813                 disassemble_file (l->data);
814
815         return 0;
816 }