2 * main.c: Sample disassembler
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc.
10 * Investigate how interface inheritance works and how it should be dumped.
11 * Structs are not being labeled as `valuetype' classes
27 /* True if you want to get a dump of the header data */
28 gboolean dump_header_data_p = FALSE;
33 dump_header_data (MonoAssembly *ass)
35 if (!dump_header_data_p)
39 "// Ximian's CIL disassembler, version 1.0\n"
40 "// Copyright (C) 2001 Ximian, Inc.\n\n");
44 dis_directive_assembly (metadata_t *m)
46 metadata_tableinfo_t *t = &m->tables [META_TABLE_ASSEMBLY];
52 expand (t, 0, cols, CSIZE (cols));
57 " .hash algorithm 0x%08x\n"
63 mono_metadata_string_heap (m, cols [7]),
65 cols [1], cols [2], cols [3], cols [4],
66 cols [8] ? "\n .locale" : "",
67 cols [8] ? mono_metadata_string_heap (m, cols [8]) : "",
68 cols [6] ? "\n .publickey" : ""
73 dis_directive_assemblyref (metadata_t *m)
75 metadata_tableinfo_t *t = &m->tables [META_TABLE_ASSEMBLYREF];
82 for (i = 0; i < t->rows; i++){
83 expand (t, i, cols, CSIZE (cols));
86 ".assembly extern %s\n"
90 mono_metadata_string_heap (m, cols [6]),
91 cols [0], cols [1], cols [2], cols [3]
96 static map_t visibility_map [] = {
97 { TYPE_ATTRIBUTE_NOT_PUBLIC, "private " },
98 { TYPE_ATTRIBUTE_PUBLIC, "public " },
99 { TYPE_ATTRIBUTE_NESTED_PUBLIC, "nested-public " },
100 { TYPE_ATTRIBUTE_NESTED_PRIVATE, "nested-private " },
101 { TYPE_ATTRIBUTE_NESTED_FAMILY, "family " },
102 { TYPE_ATTRIBUTE_NESTED_ASSEMBLY, "nested-assembly" },
103 { TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM, "nested-fam-and-assembly" },
104 { TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM, "nested-fam-or-assembly" },
108 static map_t layout_map [] = {
109 { TYPE_ATTRIBUTE_AUTO_LAYOUT, "auto " },
110 { TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT, "sequential " },
111 { TYPE_ATTRIBUTE_EXPLICIT_LAYOUT, "explicit " },
115 static map_t format_map [] = {
116 { TYPE_ATTRIBUTE_ANSI_CLASS, "ansi " },
117 { TYPE_ATTRIBUTE_UNICODE_CLASS, "unicode " },
118 { TYPE_ATTRIBUTE_AUTO_CLASS, "auto " },
123 typedef_flags (guint32 flags)
125 static char buffer [1024];
126 int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
127 int layout = flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
128 int format = flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK;
132 strcat (buffer, map (visibility, visibility_map));
133 strcat (buffer, map (layout, layout_map));
134 strcat (buffer, map (format, format_map));
136 if (flags & TYPE_ATTRIBUTE_ABSTRACT)
137 strcat (buffer, "abstract ");
138 if (flags & TYPE_ATTRIBUTE_SEALED)
139 strcat (buffer, "sealed ");
140 if (flags & TYPE_ATTRIBUTE_SPECIAL_NAME)
141 strcat (buffer, "special-name ");
142 if (flags & TYPE_ATTRIBUTE_IMPORT)
143 strcat (buffer, "import ");
144 if (flags & TYPE_ATTRIBUTE_SERIALIZABLE)
145 strcat (buffer, "serializable ");
146 if (flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
147 strcat (buffer, "beforefieldinit ");
154 * @m: metadata context
155 * @start: starting index into the Field Table.
156 * @end: ending index into Field table.
158 * This routine displays all the decoded fields from @start to @end
161 dis_field_list (metadata_t *m, guint32 start, guint32 end)
163 metadata_tableinfo_t *t = &m->tables [META_TABLE_FIELD];
167 if (end > t->rows + 1)
168 g_error ("ERROR index out of range in fields");
170 for (i = start; i < end; i++){
173 expand (t, i, cols, CSIZE (cols));
174 sig = get_field_signature (m, cols [2]);
175 flags = field_flags (cols [0]);
177 if (cols [0] & FIELD_ATTRIBUTE_LITERAL){
178 char *lit = decode_literal (m, cols [2]);
180 fprintf (output, " .field %s %s %s = ",
182 mono_metadata_string_heap (m, cols [1]));
183 fprintf (output, "%s\n", lit);
186 fprintf (output, " .field %s %s %s\n",
188 mono_metadata_string_heap (m, cols [1]));
194 static map_t method_access_map [] = {
195 { METHOD_ATTRIBUTE_COMPILER_CONTROLLED, "compilercontrolled " },
196 { METHOD_ATTRIBUTE_PRIVATE, "private" },
197 { METHOD_ATTRIBUTE_FAM_AND_ASSEM, "famandassem" },
198 { METHOD_ATTRIBUTE_ASSEM, "assembly " },
199 { METHOD_ATTRIBUTE_FAMILY, "family " },
200 { METHOD_ATTRIBUTE_FAM_OR_ASSEM, "famorassem " },
201 { METHOD_ATTRIBUTE_PUBLIC, "public " },
205 static map_t method_flags_map [] = {
206 { METHOD_ATTRIBUTE_STATIC, "static " },
207 { METHOD_ATTRIBUTE_FINAL, "final " },
208 { METHOD_ATTRIBUTE_VIRTUAL, "virtual " },
209 { METHOD_ATTRIBUTE_HIDE_BY_SIG, "hidebysig " },
210 { METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK, "newslot " },
211 { METHOD_ATTRIBUTE_ABSTRACT, "abstract " },
212 { METHOD_ATTRIBUTE_SPECIAL_NAME, "specialname " },
213 { METHOD_ATTRIBUTE_RT_SPECIAL_NAME, "rtspecialname " },
214 { METHOD_ATTRIBUTE_PINVOKE_IMPL, "pinvokeimpl " },
215 { METHOD_ATTRIBUTE_UNMANAGED_EXPORT, "export " },
216 { METHOD_ATTRIBUTE_HAS_SECURITY, "hassecurity" },
217 { METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT, "requiresecobj" },
224 * Returns a stringified version of the Method's flags
227 method_flags (guint32 f)
229 GString *str = g_string_new ("");
230 int access = f & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
233 g_string_append (str, map (access, method_access_map));
234 g_string_append (str, flags (f, method_flags_map));
237 g_string_free (str, FALSE);
242 static map_t method_impl_map [] = {
243 { METHOD_IMPL_ATTRIBUTE_IL, "cil " },
244 { METHOD_IMPL_ATTRIBUTE_NATIVE, "native " },
245 { METHOD_IMPL_ATTRIBUTE_OPTIL, "optil " },
246 { METHOD_IMPL_ATTRIBUTE_RUNTIME, "runtime " },
250 static map_t managed_type_map [] = {
251 { METHOD_IMPL_ATTRIBUTE_UNMANAGED, "unmanaged " },
252 { METHOD_IMPL_ATTRIBUTE_MANAGED, "managed " },
256 static map_t managed_impl_flags [] = {
257 { METHOD_IMPL_ATTRIBUTE_FORWARD_REF, "fwdref " },
258 { METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG, "preservesig " },
259 { METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL, "internalcall " },
260 { METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED, "synchronized " },
261 { METHOD_IMPL_ATTRIBUTE_NOINLINING, "noinline " },
266 method_impl_flags (guint32 f)
268 GString *str = g_string_new ("");
270 int code_type = f & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
271 int managed_type = f & METHOD_IMPL_ATTRIBUTE_MANAGED_MASK;
273 g_string_append (str, map (code_type, method_impl_map));
274 g_string_append (str, map (managed_type, managed_type_map));
275 g_string_append (str, flags (f, managed_impl_flags));
278 g_string_free (str, FALSE);
283 dis_code (metadata_t *m, cli_image_info_t *ii, guint32 rva)
285 MonoMetaMethodHeader *mh;
286 const char *ptr = cli_rva_map (ii, rva);
291 mh = mono_metadata_parse_mh (ptr);
292 fprintf (output, "\t.maxstack %d\n", mh->max_stack);
293 fprintf (output, "\t// Code size=%d (0x%x)\n", mh->code_size, mh->code_size);
294 printf ("\t// Values Code Size=%d/0x%x\n\t// LocalTok=%x\n\n",
295 mh->code_size, mh->code_size, mh->local_var_sig_tok);
296 dissasemble_cil (m, mh->code, mh->code_size);
299 hex_dump (mh->code, 0, mh->code_size);
300 printf ("\nAfter the code\n");
301 hex_dump (mh->code + mh->code_size, 0, 64);
303 mono_metadata_free_mh (mh);
314 * parse_method_signature:
315 * @m: metadata context
316 * @blob_signature: pointer to the signature in the Blob heap
318 * 22.2.1: MethodDefSig.
320 * Returns the parsed information in the MethodSignature structure
321 * needs to be deallocated with free_method_signature().
323 static MethodSignature *
324 parse_method_signature (metadata_t *m, guint32 blob_signature)
326 GString *res = g_string_new ("");
327 const char *ptr = mono_metadata_blob_heap (m, blob_signature);
328 MethodSignature *ms = g_new0 (MethodSignature, 1);
332 ptr = get_encoded_value (ptr, &len);
333 fprintf (output, " // SIG: ");
334 hex_dump (ptr, 0, -len);
335 fprintf (output, "\n");
339 ptr = get_encoded_value (ptr, &ms->param_count);
340 ptr = get_ret_type (m, ptr, &ms->ret_type);
341 ms->param = g_new (char *, ms->param_count);
343 for (i = 0; i < ms->param_count; i++)
344 ptr = get_param (m, ptr, &(ms->param [i]));
347 g_string_free (res, FALSE);
352 free_method_signature (MethodSignature *ms)
356 for (i = 0; i < ms->param_count; i++)
357 g_free (ms->param [i]);
359 g_free (ms->ret_type);
365 * @m: metadata context
366 * @start: starting index into the Method Table.
367 * @end: ending index into Method table.
369 * This routine displays the methods in the Method Table from @start to @end
372 dis_method_list (metadata_t *m, cli_image_info_t *ii, guint32 start, guint32 end)
374 metadata_tableinfo_t *t = &m->tables [META_TABLE_METHOD];
375 metadata_tableinfo_t *p = &m->tables [META_TABLE_PARAM];
377 guint32 cols_next [6];
378 guint32 param_cols [3];
382 fprintf (output, "ERROR index out of range in methods");
386 for (i = start; i < end; i++){
388 char *flags, *impl_flags;
390 expand (t, i, cols, CSIZE (cols));
391 expand (t, i + 1, cols_next, CSIZE (cols_next));
393 flags = method_flags (cols [2]);
394 impl_flags = method_impl_flags (cols [1]);
396 ms = parse_method_signature (m, cols [4]);
404 mono_metadata_string_heap (m, cols [3]));
405 if (ms->param_count > 0){
408 fprintf (output, "(\n");
409 for (i = 0; i < ms->param_count; i++){
412 expand (p, i, param_cols, CSIZE (param_cols));
413 pf = param_flags (param_cols [0]);
415 output, "\t\t%s %s %s%s", pf, ms->param [i],
416 mono_metadata_string_heap (m, param_cols [2]),
417 (i+1 == ms->param_count) ? ")" : ",\n");
423 fprintf (output, " %s\n", impl_flags);
427 fprintf (output, " {\n");
428 fprintf (output, " // Method begins at RVA 0x%x\n", cols [0]);
429 dis_code (m, ii, cols [0]);
430 fprintf (output, " }\n\n");
431 free_method_signature (ms);
437 * @m: metadata context
438 * @n: index of type to disassemble
440 * Disassembles the type whose index in the TypeDef table is @n.
443 dis_type (metadata_t *m, cli_image_info_t *ii, int n)
445 metadata_tableinfo_t *t = &m->tables [META_TABLE_TYPEDEF];
447 guint32 cols_next [6];
449 gboolean next_is_valid, last;
451 expand (t, n, cols, CSIZE (cols));
454 expand (t, n + 1, cols_next, CSIZE (cols_next));
459 fprintf (output, ".namespace %s\n{\n", mono_metadata_string_heap (m, cols [2]));
460 name = mono_metadata_string_heap (m, cols [1]);
462 if ((cols [0] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
463 char *base = get_typedef_or_ref (m, cols [3]);
464 fprintf (output, " .class %s%s\n", typedef_flags (cols [0]), name);
465 fprintf (output, " \textends %s\n", base);
468 fprintf (output, " .class interface %s%s\n", typedef_flags (cols [0]), name);
470 fprintf (output, " {\n");
473 * The value in the table is always valid, we know we have fields
474 * if the value stored is different than the next record.
477 last = cols_next [4] - 1;
479 last = m->tables [META_TABLE_FIELD].rows;
481 if (cols [4] != cols_next [4] && cols_next [4] != 0)
482 dis_field_list (m, cols [4] - 1, last);
483 fprintf (output, "\n");
486 last = cols_next [5] - 1;
488 last = m->tables [META_TABLE_METHOD].rows;
490 if (cols [4] != cols_next [5] && cols_next [5] != 0)
491 dis_method_list (m, ii, cols [5] - 1, last);
493 fprintf (output, " }\n}\n\n");
498 * @m: metadata context
500 * disassembles all types in the @m context
503 dis_types (metadata_t *m, cli_image_info_t *ii)
505 metadata_tableinfo_t *t = &m->tables [META_TABLE_TYPEDEF];
508 for (i = 1; i < t->rows; i++)
514 * @file: file containing CIL code.
516 * Disassembles the @file file.
519 disassemble_file (const char *file)
521 enum MonoAssemblyOpenStatus status;
523 cli_image_info_t *ii;
527 ass = mono_assembly_open (file, &status);
529 fprintf (stderr, "Error while trying to process %s\n", file);
533 ii = ass->image_info;
534 m = &ii->cli_metadata;
536 if (dump_table != -1){
538 case META_TABLE_TYPEDEF:
539 dump_table_typedef (m);
541 case META_TABLE_TYPEREF:
542 dump_table_typeref (m);
544 case META_TABLE_ASSEMBLYREF:
545 dump_table_assemblyref (m);
547 case META_TABLE_PARAM:
548 dump_table_param (m);
550 case META_TABLE_FIELD:
551 dump_table_field (m);
554 g_error ("Internal error");
557 dump_header_data (ass);
559 dis_directive_assemblyref (m);
560 dis_directive_assembly (m);
564 mono_assembly_close (ass);
570 fprintf (stderr, "Usage is: monodis [--typeref][--typedef][--assemblyref] file ..\n");
575 main (int argc, char *argv [])
577 GList *input_files = NULL, *l;
581 for (i = 1; i < argc; i++){
582 if (argv [i][0] == '-'){
583 if (argv [i][1] == 'h')
585 else if (argv [i][1] == 'd')
586 dump_header_data_p = TRUE;
587 else if (strcmp (argv [i], "--help") == 0)
589 else if (strcmp (argv [i], "--typeref") == 0)
590 dump_table = META_TABLE_TYPEREF;
591 else if (strcmp (argv [i], "--typedef") == 0)
592 dump_table = META_TABLE_TYPEDEF;
593 else if (strcmp (argv [i], "--assemblyref") == 0)
594 dump_table = META_TABLE_ASSEMBLYREF;
595 else if (strcmp (argv [i], "--param") == 0)
596 dump_table = META_TABLE_PARAM;
597 else if (strcmp (argv [i], "--fields") == 0)
598 dump_table = META_TABLE_FIELD;
600 input_files = g_list_append (input_files, argv [i]);
603 if (input_files == NULL)
606 for (l = input_files; l; l = l->next)
607 disassemble_file (l->data);