2 * dis.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
26 /* True if you want to get a dump of the header data */
27 gboolean dump_header_data_p = FALSE;
32 dump_header_data (MonoAssembly *ass)
34 if (!dump_header_data_p)
38 "// Ximian's CIL disassembler, version 1.0\n"
39 "// Copyright (C) 2001 Ximian, Inc.\n\n");
43 dis_directive_assembly (metadata_t *m)
45 metadata_tableinfo_t *t = &m->tables [META_TABLE_ASSEMBLY];
51 expand (t, 0, cols, CSIZE (cols));
56 " .hash algorithm 0x%08x\n"
62 mono_metadata_string_heap (m, cols [7]),
64 cols [1], cols [2], cols [3], cols [4],
65 cols [8] ? "\n .locale" : "",
66 cols [8] ? mono_metadata_string_heap (m, cols [8]) : "",
67 cols [6] ? "\n .publickey" : ""
72 dis_directive_assemblyref (metadata_t *m)
74 metadata_tableinfo_t *t = &m->tables [META_TABLE_ASSEMBLYREF];
81 for (i = 0; i < t->rows; i++){
82 expand (t, i, cols, CSIZE (cols));
85 ".assembly extern %s\n"
89 mono_metadata_string_heap (m, cols [6]),
90 cols [0], cols [1], cols [2], cols [3]
95 static map_t visibility_map [] = {
96 { TYPE_ATTRIBUTE_NOT_PUBLIC, "private " },
97 { TYPE_ATTRIBUTE_PUBLIC, "public " },
98 { TYPE_ATTRIBUTE_NESTED_PUBLIC, "nested-public " },
99 { TYPE_ATTRIBUTE_NESTED_PRIVATE, "nested-private " },
100 { TYPE_ATTRIBUTE_NESTED_FAMILY, "family " },
101 { TYPE_ATTRIBUTE_NESTED_ASSEMBLY, "nested-assembly" },
102 { TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM, "nested-fam-and-assembly" },
103 { TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM, "nested-fam-or-assembly" },
107 static map_t layout_map [] = {
108 { TYPE_ATTRIBUTE_AUTO_LAYOUT, "auto " },
109 { TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT, "sequential " },
110 { TYPE_ATTRIBUTE_EXPLICIT_LAYOUT, "explicit " },
114 static map_t format_map [] = {
115 { TYPE_ATTRIBUTE_ANSI_CLASS, "ansi " },
116 { TYPE_ATTRIBUTE_UNICODE_CLASS, "unicode " },
117 { TYPE_ATTRIBUTE_AUTO_CLASS, "auto " },
122 typedef_flags (guint32 flags)
124 static char buffer [1024];
125 int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
126 int layout = flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
127 int format = flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK;
131 strcat (buffer, map (visibility, visibility_map));
132 strcat (buffer, map (layout, layout_map));
133 strcat (buffer, map (format, format_map));
135 if (flags & TYPE_ATTRIBUTE_ABSTRACT)
136 strcat (buffer, "abstract ");
137 if (flags & TYPE_ATTRIBUTE_SEALED)
138 strcat (buffer, "sealed ");
139 if (flags & TYPE_ATTRIBUTE_SPECIAL_NAME)
140 strcat (buffer, "special-name ");
141 if (flags & TYPE_ATTRIBUTE_IMPORT)
142 strcat (buffer, "import ");
143 if (flags & TYPE_ATTRIBUTE_SERIALIZABLE)
144 strcat (buffer, "serializable ");
145 if (flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
146 strcat (buffer, "beforefieldinit ");
153 * @m: metadata context
154 * @start: starting index into the Field Table.
155 * @end: ending index into Field table.
157 * This routine displays all the decoded fields from @start to @end
160 dis_field_list (metadata_t *m, guint32 start, guint32 end)
162 metadata_tableinfo_t *t = &m->tables [META_TABLE_FIELD];
166 if (end > t->rows + 1){
167 fprintf (output, "ERROR index out of range in fields");
171 for (i = start; i < end; i++){
174 expand (t, i, cols, CSIZE (cols));
175 sig = get_field_signature (m, cols [2]);
176 flags = field_flags (cols [0]);
178 if (cols [0] & FIELD_ATTRIBUTE_LITERAL){
179 char *lit = decode_literal (m, cols [2]);
181 fprintf (output, " .field %s %s %s = ",
183 mono_metadata_string_heap (m, cols [1]));
184 fprintf (output, "%s\n", lit);
187 fprintf (output, " .field %s %s %s\n",
189 mono_metadata_string_heap (m, cols [1]));
195 static map_t method_access_map [] = {
196 { METHOD_ATTRIBUTE_COMPILER_CONTROLLED, "compilercontrolled " },
197 { METHOD_ATTRIBUTE_PRIVATE, "private" },
198 { METHOD_ATTRIBUTE_FAM_AND_ASSEM, "famandassem" },
199 { METHOD_ATTRIBUTE_ASSEM, "assembly " },
200 { METHOD_ATTRIBUTE_FAMILY, "family " },
201 { METHOD_ATTRIBUTE_FAM_OR_ASSEM, "famorassem " },
202 { METHOD_ATTRIBUTE_PUBLIC, "public " },
206 static map_t method_flags_map [] = {
207 { METHOD_ATTRIBUTE_STATIC, "static " },
208 { METHOD_ATTRIBUTE_FINAL, "final " },
209 { METHOD_ATTRIBUTE_VIRTUAL, "virtual " },
210 { METHOD_ATTRIBUTE_HIDE_BY_SIG, "hidebysig " },
211 { METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK, "newslot " },
212 { METHOD_ATTRIBUTE_ABSTRACT, "abstract " },
213 { METHOD_ATTRIBUTE_SPECIAL_NAME, "specialname " },
214 { METHOD_ATTRIBUTE_RT_SPECIAL_NAME, "rtspecialname " },
215 { METHOD_ATTRIBUTE_PINVOKE_IMPL, "pinvokeimpl " },
216 { METHOD_ATTRIBUTE_UNMANAGED_EXPORT, "export " },
217 { METHOD_ATTRIBUTE_HAS_SECURITY, "hassecurity" },
218 { METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT, "requiresecobj" },
225 * Returns a stringified version of the Method's flags
228 method_flags (guint32 f)
230 GString *str = g_string_new ("");
231 int access = f & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
234 g_string_append (str, map (access, method_access_map));
235 g_string_append (str, flags (f, method_flags_map));
238 g_string_free (str, FALSE);
243 static map_t method_impl_map [] = {
244 { METHOD_IMPL_ATTRIBUTE_IL, "cil " },
245 { METHOD_IMPL_ATTRIBUTE_NATIVE, "native " },
246 { METHOD_IMPL_ATTRIBUTE_OPTIL, "optil " },
247 { METHOD_IMPL_ATTRIBUTE_RUNTIME, "runtime " },
251 static map_t managed_type_map [] = {
252 { METHOD_IMPL_ATTRIBUTE_UNMANAGED, "unmanaged " },
253 { METHOD_IMPL_ATTRIBUTE_MANAGED, "managed " },
257 static map_t managed_impl_flags [] = {
258 { METHOD_IMPL_ATTRIBUTE_FORWARD_REF, "fwdref " },
259 { METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG, "preservesig " },
260 { METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL, "internalcall " },
261 { METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED, "synchronized " },
262 { METHOD_IMPL_ATTRIBUTE_NOINLINING, "noinline " },
267 method_impl_flags (guint32 f)
269 GString *str = g_string_new ("");
271 int code_type = f & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
272 int managed_type = f & METHOD_IMPL_ATTRIBUTE_MANAGED_MASK;
274 g_string_append (str, map (code_type, method_impl_map));
275 g_string_append (str, map (managed_type, managed_type_map));
276 g_string_append (str, flags (f, managed_impl_flags));
279 g_string_free (str, FALSE);
284 dis_code (metadata_t *m, cli_image_info_t *ii, guint32 rva)
286 const char *ptr = cli_rva_map (ii, rva);
291 hex_dump (ptr, 0, 64);
302 * parse_method_signature:
303 * @m: metadata context
304 * @blob_signature: pointer to the signature in the Blob heap
306 * 22.2.1: MethodDefSig.
308 * Returns the parsed information in the MethodSignature structure
309 * needs to be deallocated with free_method_signature().
311 static MethodSignature *
312 parse_method_signature (metadata_t *m, guint32 blob_signature)
314 GString *res = g_string_new ("");
315 const char *ptr = mono_metadata_blob_heap (m, blob_signature);
316 MethodSignature *ms = g_new0 (MethodSignature, 1);
320 ptr = get_encoded_value (ptr, &len);
321 fprintf (output, " // SIG: ");
322 hex_dump (ptr, 0, -len);
323 fprintf (output, "\n");
327 ptr = get_encoded_value (ptr, &ms->param_count);
328 ptr = get_ret_type (m, ptr, &ms->ret_type);
329 ms->param = g_new (char *, ms->param_count);
331 for (i = 0; i < ms->param_count; i++)
332 ptr = get_param (m, ptr, &(ms->param [i]));
335 g_string_free (res, FALSE);
340 free_method_signature (MethodSignature *ms)
344 for (i = 0; i < ms->param_count; i++)
345 g_free (ms->param [i]);
347 g_free (ms->ret_type);
353 * @m: metadata context
354 * @start: starting index into the Method Table.
355 * @end: ending index into Method table.
357 * This routine displays the methods in the Method Table from @start to @end
360 dis_method_list (metadata_t *m, cli_image_info_t *ii, guint32 start, guint32 end)
362 metadata_tableinfo_t *t = &m->tables [META_TABLE_METHOD];
363 metadata_tableinfo_t *p = &m->tables [META_TABLE_PARAM];
365 guint32 cols_next [6];
366 guint32 param_cols [3];
369 if (end > t->rows + 1){
370 fprintf (output, "ERROR index out of range in methods");
374 for (i = start; i < end; i++){
376 char *flags, *impl_flags;
378 expand (t, i, cols, CSIZE (cols));
379 expand (t, i + 1, cols_next, CSIZE (cols_next));
381 flags = method_flags (cols [2]);
382 impl_flags = method_impl_flags (cols [1]);
384 ms = parse_method_signature (m, cols [4]);
392 mono_metadata_string_heap (m, cols [3]));
393 if (ms->param_count > 0){
396 fprintf (output, "(\n");
397 for (i = 0; i < ms->param_count; i++){
400 expand (p, i, param_cols, CSIZE (param_cols));
401 pf = param_flags (param_cols [0]);
403 output, "\t\t%s %s %s%s", pf, ms->param [i],
404 mono_metadata_string_heap (m, param_cols [2]),
405 (i+1 == ms->param_count) ? ")" : ",\n");
411 fprintf (output, " %s\n", impl_flags);
415 fprintf (output, " {\n");
416 fprintf (output, " // Method begins at RVA 0x%x\n", cols [0]);
417 dis_code (m, ii, cols [0]);
418 fprintf (output, " }\n\n");
419 free_method_signature (ms);
425 * @m: metadata context
426 * @n: index of type to disassemble
428 * Disassembles the type whose index in the TypeDef table is @n.
431 dis_type (metadata_t *m, cli_image_info_t *ii, int n)
433 metadata_tableinfo_t *t = &m->tables [META_TABLE_TYPEDEF];
435 guint32 cols_next [6];
438 expand (t, n, cols, CSIZE (cols));
439 expand (t, n + 1, cols_next, CSIZE (cols_next));
441 fprintf (output, ".namespace %s\n{\n", mono_metadata_string_heap (m, cols [2]));
442 name = mono_metadata_string_heap (m, cols [1]);
444 if ((cols [0] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
445 char *base = get_typedef_or_ref (m, cols [3]);
446 fprintf (output, " .class %s%s\n", typedef_flags (cols [0]), name);
447 fprintf (output, " \textends %s\n", base);
450 fprintf (output, " .class interface %s%s\n", typedef_flags (cols [0]), name);
452 fprintf (output, " {\n");
455 * The value in the table is always valid, we know we have fields
456 * if the value stored is different than the next record.
458 if (cols [4] != cols_next [4])
459 dis_field_list (m, cols [4] - 1, cols_next [4] - 1);
460 fprintf (output, "\n");
461 if (cols [4] != cols_next [5])
462 dis_method_list (m, ii, cols [5] - 1, cols_next [5] - 1);
464 fprintf (output, " }\n}\n\n");
469 * @m: metadata context
471 * disassembles all types in the @m context
474 dis_types (metadata_t *m, cli_image_info_t *ii)
476 metadata_tableinfo_t *t = &m->tables [META_TABLE_TYPEDEF];
479 for (i = 0; i < t->rows; i++)
485 * @file: file containing CIL code.
487 * Disassembles the @file file.
490 disassemble_file (const char *file)
492 enum MonoAssemblyOpenStatus status;
494 cli_image_info_t *ii;
498 ass = mono_assembly_open (file, &status);
500 fprintf (stderr, "Error while trying to process %s\n", file);
504 ii = ass->image_info;
505 m = &ii->cli_metadata;
507 if (dump_table != -1){
509 case META_TABLE_TYPEDEF:
510 dump_table_typedef (m);
512 case META_TABLE_TYPEREF:
513 dump_table_typeref (m);
515 case META_TABLE_ASSEMBLYREF:
516 dump_table_assemblyref (m);
518 case META_TABLE_PARAM:
519 dump_table_param (m);
522 g_error ("Internal error");
525 dump_header_data (ass);
527 dis_directive_assemblyref (m);
528 dis_directive_assembly (m);
532 mono_assembly_close (ass);
538 fprintf (stderr, "Usage is: monodis [--typeref][--typedef][--assemblyref] file ..\n");
543 main (int argc, char *argv [])
545 GList *input_files = NULL, *l;
549 for (i = 1; i < argc; i++){
550 if (argv [i][0] == '-'){
551 if (argv [i][1] == 'h')
553 else if (argv [i][1] == 'd')
554 dump_header_data_p = TRUE;
555 else if (strcmp (argv [i], "--help") == 0)
557 else if (strcmp (argv [i], "--typeref") == 0)
558 dump_table = META_TABLE_TYPEREF;
559 else if (strcmp (argv [i], "--typedef") == 0)
560 dump_table = META_TABLE_TYPEDEF;
561 else if (strcmp (argv [i], "--assemblyref") == 0)
562 dump_table = META_TABLE_ASSEMBLYREF;
563 else if (strcmp (argv [i], "--param") == 0)
564 dump_table = META_TABLE_PARAM;
566 input_files = g_list_append (input_files, argv [i]);
569 if (input_files == NULL)
572 for (l = input_files; l; l = l->next)
573 disassemble_file (l->data);