/* * mono_opcode_value_and_size: * * Returns the size of the opcode starting at *@ip, or -1 on error. * Value is the opcode number. */ int mono_opcode_value_and_size (const unsigned char **ip, const unsigned char *end, int *value) { const unsigned char *start = *ip, *p; int i = *value = mono_opcode_value (ip, end); int size = 0; if (i < 0 || i >= MONO_CEE_LAST) return -1; p = *ip; switch (mono_opcodes [i].argument) { case MonoInlineNone: size = 1; break; case MonoInlineString: case MonoInlineType: case MonoInlineField: case MonoInlineMethod: case MonoInlineTok: case MonoInlineSig: case MonoShortInlineR: case MonoInlineI: case MonoInlineBrTarget: size = 5; break; case MonoInlineVar: size = 3; break; case MonoShortInlineVar: case MonoShortInlineI: case MonoShortInlineBrTarget: size = 2; break; case MonoInlineR: case MonoInlineI8: size = 9; break; case MonoInlineSwitch: { guint32 entries; if (ADDP_IS_GREATER_OR_OVF (p, 5, end)) return -1; entries = read32 (p + 1); if (entries >= (0xFFFFFFFFU / 4)) return -1; size = 4 + 4 * entries; break; } default: g_error ("Invalid opcode %d argument %d max opcode %d\n", i, mono_opcodes [i].argument, MONO_CEE_LAST); } if (ADDP_IS_GREATER_OR_OVF (p, size, end)) return -1; return (p - start) + size; }
static const unsigned char* dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned char *ip, const unsigned char *end) { MonoMethodHeader *header = mono_method_get_header (method); const MonoOpcode *opcode; guint32 label, token; gint32 sval; int i; char *tmp; const unsigned char* il_code = mono_method_header_get_code (header, NULL, NULL); label = ip - il_code; if (dh->indenter) { tmp = dh->indenter (dh, method, label); g_string_append (str, tmp); g_free (tmp); } if (dh->label_format) g_string_append_printf (str, dh->label_format, label); i = mono_opcode_value (&ip, end); ip++; opcode = &mono_opcodes [i]; g_string_append_printf (str, "%-10s", mono_opcode_name (i)); switch (opcode->argument) { case MonoInlineNone: break; case MonoInlineType: case MonoInlineField: case MonoInlineMethod: case MonoInlineTok: case MonoInlineSig: token = read32 (ip); if (dh->tokener) { tmp = dh->tokener (dh, method, token); g_string_append (str, tmp); g_free (tmp); } else { g_string_append_printf (str, "0x%08x", token); } ip += 4; break; case MonoInlineString: { const char *blob; char *s; size_t len2; char *blob2 = NULL; if (!image_is_dynamic (method->klass->image) && !method_is_dynamic (method)) { token = read32 (ip); blob = mono_metadata_user_string (method->klass->image, mono_metadata_token_index (token)); len2 = mono_metadata_decode_blob_size (blob, &blob); len2 >>= 1; #ifdef NO_UNALIGNED_ACCESS /* The blob might not be 2 byte aligned */ blob2 = g_malloc ((len2 * 2) + 1); memcpy (blob2, blob, len2 * 2); #else blob2 = (char*)blob; #endif #if G_BYTE_ORDER != G_LITTLE_ENDIAN { guint16 *buf = g_new (guint16, len2 + 1); int i; for (i = 0; i < len2; ++i) buf [i] = GUINT16_FROM_LE (((guint16*)blob2) [i]); s = g_utf16_to_utf8 (buf, len2, NULL, NULL, NULL); g_free (buf); } #else s = g_utf16_to_utf8 ((gunichar2*)blob2, len2, NULL, NULL, NULL); #endif g_string_append_printf (str, "\"%s\"", s); g_free (s); if (blob != blob2) g_free (blob2); } ip += 4; break; } case MonoInlineVar: g_string_append_printf (str, "%d", read16 (ip)); ip += 2; break; case MonoShortInlineVar: g_string_append_printf (str, "%d", (*ip)); ip ++; break; case MonoInlineBrTarget: sval = read32 (ip); ip += 4; if (dh->label_target) g_string_append_printf (str, dh->label_target, ip + sval - il_code); else g_string_append_printf (str, "%d", sval); break; case MonoShortInlineBrTarget: sval = *(const signed char*)ip; ip ++; if (dh->label_target) g_string_append_printf (str, dh->label_target, ip + sval - il_code); else g_string_append_printf (str, "%d", sval); break; case MonoInlineSwitch: { const unsigned char *end; sval = read32 (ip); ip += 4; end = ip + sval * 4; g_string_append_c (str, '('); for (i = 0; i < sval; ++i) { if (i > 0) g_string_append (str, ", "); label = read32 (ip); if (dh->label_target) g_string_append_printf (str, dh->label_target, end + label - il_code); else g_string_append_printf (str, "%d", label); ip += 4; } g_string_append_c (str, ')'); break; } case MonoInlineR: { double r; readr8 (ip, &r); g_string_append_printf (str, "%g", r); ip += 8; break; } case MonoShortInlineR: { float r; readr4 (ip, &r); g_string_append_printf (str, "%g", r); ip += 4; break; } case MonoInlineI: g_string_append_printf (str, "%d", (gint32)read32 (ip)); ip += 4; break; case MonoShortInlineI: g_string_append_printf (str, "%d", *(const signed char*)ip); ip ++; break; case MonoInlineI8: ip += 8; break; default: g_assert_not_reached (); }