2 * dis.c: Sample disassembler
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc.
13 #include <mono/metadata/assembly.h>
14 #include <mono/metadata/cil-coff.h>
15 #include <mono/metadata/endian.h>
16 #include <mono/metadata/typeattr.h>
17 #include <mono/metadata/fieldattr.h>
18 #include <mono/metadata/eltype.h>
23 /* True if you want to get a dump of the header data */
24 gboolean dump_header_data_p = FALSE;
27 dump_header_data (MonoAssembly *ass)
29 if (!dump_header_data_p)
33 "// Ximian's CIL disassembler, version 1.0\n"
34 "// Copyright (C) 2001 Ximian, Inc.\n\n");
37 #define CSIZE(x) (sizeof (x) / 4)
39 expand (metadata_tableinfo_t *t, int idx, guint32 *res, int res_size)
41 guint32 bitfield = t->size_bitfield;
42 int i, count = meta_table_count (bitfield);
43 char *data = t->base + idx * t->row_size;
45 g_assert (res_size == count);
47 for (i = 0; i < count; i++){
48 int n = meta_table_size (bitfield, i);
52 res [i] = *data; break;
54 res [i] = read16 (data); break;
57 res [i] = read32 (data); break;
60 g_assert_not_reached ();
67 dis_directive_assembly (metadata_t *m)
69 metadata_tableinfo_t *t = &m->tables [META_TABLE_ASSEMBLY];
75 expand (t, 0, cols, CSIZE (cols));
80 " .hash algorithm 0x%08x\n"
86 mono_metadata_string_heap (m, cols [7]),
88 cols [1], cols [2], cols [3], cols [4],
89 cols [8] ? "\n .locale" : "",
90 cols [8] ? mono_metadata_string_heap (m, cols [8]) : "",
91 cols [6] ? "\n .publickey" : ""
96 dis_directive_assemblyref (metadata_t *m)
98 metadata_tableinfo_t *t = &m->tables [META_TABLE_ASSEMBLYREF];
105 for (i = 0; i < t->rows; i++){
106 expand (t, i, cols, CSIZE (cols));
109 ".assembly extern %s\n"
111 " .ver %d.%d.%d.%d\n"
113 mono_metadata_string_heap (m, cols [6]),
114 cols [0], cols [1], cols [2], cols [3]
119 static map_t visibility_map [] = {
120 { TYPE_ATTRIBUTE_NOT_PUBLIC, "not-public " },
121 { TYPE_ATTRIBUTE_PUBLIC, "public " },
122 { TYPE_ATTRIBUTE_NESTED_PUBLIC, "nested-public " },
123 { TYPE_ATTRIBUTE_NESTED_PRIVATE, "nested-private " },
124 { TYPE_ATTRIBUTE_NESTED_FAMILY, "family " },
125 { TYPE_ATTRIBUTE_NESTED_ASSEMBLY, "nested-assembly" },
126 { TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM, "nested-fam-and-assembly" },
127 { TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM, "nested-fam-or-assembly" },
131 static map_t layout_map [] = {
132 { TYPE_ATTRIBUTE_AUTO_LAYOUT, "auto " },
133 { TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT, "sequential " },
134 { TYPE_ATTRIBUTE_EXPLICIT_LAYOUT, "explicit " },
138 static map_t format_map [] = {
139 { TYPE_ATTRIBUTE_ANSI_CLASS, "ansi " },
140 { TYPE_ATTRIBUTE_UNICODE_CLASS, "unicode " },
141 { TYPE_ATTRIBUTE_AUTO_CLASS, "auto " },
146 typedef_flags (guint32 flags)
148 static char buffer [1024];
149 int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
150 int layout = flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
151 int format = flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK;
155 strcat (buffer, map (visibility, visibility_map));
156 strcat (buffer, map (layout, layout_map));
157 strcat (buffer, map (format, format_map));
159 if (flags & TYPE_ATTRIBUTE_ABSTRACT)
160 strcat (buffer, "abstract ");
161 if (flags & TYPE_ATTRIBUTE_SEALED)
162 strcat (buffer, "sealed ");
163 if (flags & TYPE_ATTRIBUTE_SPECIAL_NAME)
164 strcat (buffer, "special-name ");
165 if (flags & TYPE_ATTRIBUTE_IMPORT)
166 strcat (buffer, "import ");
167 if (flags & TYPE_ATTRIBUTE_SERIALIZABLE)
168 strcat (buffer, "serializable ");
169 if (flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
170 strcat (buffer, "beforefieldinit ");
175 static map_t access_map [] = {
176 { FIELD_ATTRIBUTE_COMPILER_CONTROLLED, "compilercontrolled " },
177 { FIELD_ATTRIBUTE_PRIVATE, "private " },
178 { FIELD_ATTRIBUTE_FAM_AND_ASSEM, "famandassem " },
179 { FIELD_ATTRIBUTE_ASSEMBLY, "assembly " },
180 { FIELD_ATTRIBUTE_FAMILY, "family " },
181 { FIELD_ATTRIBUTE_FAM_OR_ASSEM, "famorassem " },
182 { FIELD_ATTRIBUTE_PUBLIC, "public " },
186 static map_t field_flags_map [] = {
187 { FIELD_ATTRIBUTE_STATIC, "static " },
188 { FIELD_ATTRIBUTE_INIT_ONLY, "initonly " },
189 { FIELD_ATTRIBUTE_LITERAL, "literal " },
190 { FIELD_ATTRIBUTE_NOT_SERIALIZED, "notserialized " },
191 { FIELD_ATTRIBUTE_SPECIAL_NAME, "specialname " },
192 { FIELD_ATTRIBUTE_PINVOKE_IMPL, "FIXME:pinvokeimpl " },
196 static map_t element_type_map [] = {
197 { ELEMENT_TYPE_END , "end" },
198 { ELEMENT_TYPE_VOID , "System.Void" },
199 { ELEMENT_TYPE_BOOLEAN , "System.Bool" },
200 { ELEMENT_TYPE_CHAR , "System.Char" },
201 { ELEMENT_TYPE_I1 , "System.SByte" },
202 { ELEMENT_TYPE_U1 , "System.Byte" },
203 { ELEMENT_TYPE_I2 , "System.Int16" },
204 { ELEMENT_TYPE_U2 , "System.UInt16" },
205 { ELEMENT_TYPE_I4 , "System.Int32" },
206 { ELEMENT_TYPE_U4 , "System.UInt32" },
207 { ELEMENT_TYPE_I8 , "System.Int64" },
208 { ELEMENT_TYPE_U8 , "System.UInt64" },
209 { ELEMENT_TYPE_R4 , "System.Single" },
210 { ELEMENT_TYPE_R8 , "System.Double" },
211 { ELEMENT_TYPE_STRING , "System.String" },
212 { ELEMENT_TYPE_TYPEDBYREF , "TypedByRef" },
213 { ELEMENT_TYPE_I , "System.Int32" },
214 { ELEMENT_TYPE_U , "System.UPtr" },
215 { ELEMENT_TYPE_OBJECT , "System.Object" },
222 * Returns a stringified version of a Field's flags
225 field_flags (guint32 f)
227 static char buffer [1024];
228 int access = f & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
232 strcat (buffer, map (access, access_map));
233 strcat (buffer, flags (f, field_flags_map));
234 return g_strdup (buffer);
239 * @ptr: pointer to decode from
240 * @len: result value is stored here.
242 * This routine decompresses 32-bit values as specified in the "Blob and
243 * Signature" section (22.2)
245 * Returns: updated pointer location
248 get_encoded_value (const char *_ptr, guint32 *len)
250 const unsigned char *ptr = (unsigned char *) _ptr;
251 unsigned char b = *ptr;
253 if ((b & 0x80) == 0){
256 } else if ((b & 0x40) == 0){
257 *len = ((b & 0x3f) << 8 | ptr [1]);
260 *len = ((b & 0x1f) << 24) |
271 * Decodes a CustomMod (22.2.7)
273 * Returns: updated pointer location
276 get_custom_mod (const char *ptr, char **return_value)
278 if ((*ptr == ELEMENT_TYPE_CMOD_OPT) ||
279 (*ptr == ELEMENT_TYPE_CMOD_REQD)){
280 fprintf (stderr, "FIXME: still do not support CustomMods (22.2.7)");
283 *return_value = NULL;
288 get_typedef (metadata_t *m, int idx)
292 expand (&m->tables [META_TABLE_TYPEDEF], idx - 1, cols, CSIZE (cols));
294 return g_strdup_printf (
296 mono_metadata_string_heap (m, cols [2]),
297 mono_metadata_string_heap (m, cols [1]));
301 get_module (metadata_t *m, int idx)
305 /* g_assert (idx <= m->tables [META_TABLE_MODULE].rows); */
307 /* return g_strdup_printf ("IDX=0x%x", idx); */
308 expand (&m->tables [META_TABLE_ASSEMBLYREF], 0, cols, CSIZE (cols));
310 return g_strdup (mono_metadata_string_heap (m, cols [6]));
314 get_typeref (metadata_t *m, int idx)
319 guint32 rs_idx, table;
321 expand (&m->tables [META_TABLE_TYPEREF], idx - 1, cols, CSIZE (cols));
323 t = mono_metadata_string_heap (m, cols [1]);
324 s = mono_metadata_string_heap (m, cols [2]);
325 rs_idx = cols [0] >> 3;
326 table = cols [0] & 7;
327 printf ("------------ %d %d --------\n", rs_idx, table);
331 x = get_module (m, rs_idx);
332 ret = g_strdup_printf ("[%08x:%s] %s.%s", cols [0], x, s, t);
336 case 1: /* ModuleRef */
337 ret = g_strdup_printf ("TypeRef: ModuleRef (%s.%s)", s, t);
339 case 3: /* AssemblyRef */
340 ret = g_strdup_printf ("TypeRef: AssemblyRef (%s.%s)", s, t);
342 case 4: /* TypeRef */
343 ret = g_strdup_printf ("TypeRef: TYPEREF! (%s.%s)", s, t);
346 ret = g_strdup ("ERROR");
353 typedef_or_ref (metadata_t *m, guint32 dor_token)
355 int table = dor_token & 0x03;
356 int idx = dor_token >> 2;
357 char *s, *temp = NULL;
360 case 0: /* TypeDef */
361 temp = get_typedef (m, idx);
362 s = g_strdup_printf ("%s", temp);
365 case 1: /* TypeRef */
366 temp = get_typeref (m, idx);
367 s = g_strdup_printf ("/* 0x%08x */ %s", dor_token, temp);
370 case 2: /* TypeSpec */
371 s = g_strdup_printf ("TypeSpec: 0x%08x", dor_token);
383 * get_encoded_typedef_or_ref:
384 * @m: metadata context
385 * @ptr: location to decode from.
386 * @result: pointer to string where resulting decoded string is stored
388 * result will point to a g_malloc()ed string.
390 * Returns: the new ptr to continue decoding
393 get_encoded_typedef_or_ref (metadata_t *m, const char *ptr, char **result)
397 ptr = get_encoded_value (ptr, &token);
399 *result = typedef_or_ref (m, token);
405 * methoddefref_signature:
406 * @m: metadata context
407 * @ptr: location to decode from.
408 * @result: pointer to string where resulting decoded string is stored
410 * This routine decodes into a string a MethodDef or a MethodRef.
412 * result will point to a g_malloc()ed string.
414 * Returns: the new ptr to continue decoding
417 methoddefref_signature (metadata_t *m, const char *ptr, char **result)
419 *result = g_strdup ("method-def-or-ref");
426 * @m: metadata context
427 * @ptr: location to decode from.
428 * @result: pointer to string where resulting decoded string is stored
430 * This routine returs in @result the stringified type pointed by @ptr.
432 * Returns: the new ptr to continue decoding
435 get_type (metadata_t *m, const char *ptr, char **result)
442 case ELEMENT_TYPE_BOOLEAN:
443 case ELEMENT_TYPE_CHAR:
444 case ELEMENT_TYPE_I1:
445 case ELEMENT_TYPE_U1:
446 case ELEMENT_TYPE_I2:
447 case ELEMENT_TYPE_U2:
448 case ELEMENT_TYPE_I4:
449 case ELEMENT_TYPE_U4:
450 case ELEMENT_TYPE_I8:
451 case ELEMENT_TYPE_U8:
452 case ELEMENT_TYPE_R4:
453 case ELEMENT_TYPE_R8:
455 case ELEMENT_TYPE_STRING:
456 case ELEMENT_TYPE_OBJECT:
457 *result = g_strdup (map (c, element_type_map));
460 case ELEMENT_TYPE_VALUETYPE:
461 case ELEMENT_TYPE_CLASS:
462 ptr = get_encoded_typedef_or_ref (m, ptr, result);
465 case ELEMENT_TYPE_FNPTR:
466 ptr = methoddefref_signature (m, ptr, result);
469 case ELEMENT_TYPE_ARRAY:
470 *result = g_strdup ("ARRAY:TODO");
473 case ELEMENT_TYPE_SZARRAY:
474 *result = g_strdup ("SZARRAY:TODO");
482 * Returns a stringified representation of a FieldSig (22.2.4)
485 field_signature (metadata_t *m, guint32 blob_signature)
487 char *allocated_modifier_string, *allocated_type_string;
488 const char *ptr = mono_metadata_blob_heap (m, blob_signature);
491 static char buffer [8192];
493 ptr = get_encoded_value (ptr, &len);
496 g_assert (*ptr == 0x06);
497 hex_dump (ptr, 0, len);
500 ptr = get_custom_mod (ptr, &allocated_modifier_string);
501 ptr = get_type (m, ptr, &allocated_type_string);
503 sprintf (buffer, "LEN=%d:::: ", len);
504 strcat (buffer, allocated_type_string);
506 if (allocated_modifier_string)
507 g_free (allocated_modifier_string);
508 if (allocated_type_string)
509 g_free (allocated_modifier_string);
511 return g_strdup (buffer);
516 * @m: metadata context
517 * @token: token to decode
519 * decodes the literal indexed by @token.
522 decode_literal (metadata_t *m, guint32 token)
524 return g_strdup ("LITERAL_VALUE");
529 * @m: metadata context
530 * @start: starting index into the Field Table.
531 * @end: ending index into Field table.
533 * This routine displays all the decoded fields from @start to @end
536 dis_field_list (metadata_t *m, guint32 start, guint32 end)
538 metadata_tableinfo_t *t = &m->tables [META_TABLE_FIELD];
542 if (end > t->rows + 1){
543 fprintf (output, "ERROR index out of range in fields");
547 for (i = start; i < end; i++){
550 expand (t, i, cols, CSIZE (cols));
551 sig = field_signature (m, cols [2]);
552 flags = field_flags (cols [0]);
554 if (cols [0] & FIELD_ATTRIBUTE_LITERAL){
555 char *lit = decode_literal (m, cols [2]);
557 fprintf (output, " .field %s %s %s = ",
559 mono_metadata_string_heap (m, cols [1]));
560 fprintf (output, "%s\n", lit);
563 fprintf (output, " .field %s %s %s\n",
565 mono_metadata_string_heap (m, cols [1]));
573 * @m: metadata context
574 * @start: starting index into the Method Table.
575 * @end: ending index into Method table.
577 * This routine displays the methods in the Method Table from @start to @end
580 dis_method_list (metadata_t *m, guint32 start, guint32 end)
586 * @m: metadata context
587 * @n: index of type to disassemble
589 * Disassembles the type whose index in the TypeDef table is @n.
592 dis_type (metadata_t *m, int n)
594 metadata_tableinfo_t *t = &m->tables [META_TABLE_TYPEDEF];
596 guint32 cols_next [6];
600 expand (t, n, cols, CSIZE (cols));
601 expand (t, n + 1, cols_next, CSIZE (cols_next));
603 name = mono_metadata_string_heap (m, cols [1]);
605 if ((cols [0] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS)
610 fprintf (output, " .%s %s%s\n", tn, typedef_flags (cols [0]), name);
611 fprintf (output, " \textends %s\n", typedef_or_ref (m, cols [3]));
612 fprintf (output, " {\n");
615 * The value in the table is always valid, we know we have fields
616 * if the value stored is different than the next record.
618 if (cols [4] != cols_next [4])
619 dis_field_list (m, cols [4] - 1, cols_next [4] - 1);
620 if (cols [4] != cols_next [5])
621 dis_method_list (m, cols [5], cols_next [5]);
623 fprintf (output, " }\n");
628 * @m: metadata context
630 * disassembles all types in the @m context
633 dis_types (metadata_t *m)
635 metadata_tableinfo_t *t = &m->tables [META_TABLE_TYPEDEF];
638 for (i = 0; i < t->rows; i++)
644 * @file: file containing CIL code.
646 * Disassembles the @file file.
649 disassemble_file (const char *file)
651 enum MonoAssemblyOpenStatus status;
653 cli_image_info_t *ii;
657 ass = mono_assembly_open (file, &status);
659 fprintf (stderr, "Error while trying to process %s\n", file);
663 dump_header_data (ass);
665 ii = ass->image_info;
666 m = &ii->cli_metadata;
667 dis_directive_assemblyref (m);
668 dis_directive_assembly (m);
671 mono_assembly_close (ass);
677 fprintf (stderr, "Usage is: monodis file1 ..\n");
682 main (int argc, char *argv [])
684 GList *input_files = NULL, *l;
688 for (i = 1; i < argc; i++){
689 if (argv [i][0] == '-'){
690 if (argv [i][1] == 'h')
692 else if (argv [i][1] == 'd')
693 dump_header_data_p = TRUE;
695 input_files = g_list_append (input_files, argv [i]);
698 if (input_files == NULL)
701 for (l = input_files; l; l = l->next)
702 disassemble_file (l->data);