2 * dis-cil.c: Disassembles CIL byte codes
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc.
20 #include "mono/metadata/opcodes.h"
23 * Strings on the US heap are encoded using UTF-16. Poor man's
24 * UTF-16 to UTF-8. I know its broken, use libunicode later.
27 get_encoded_user_string (const char *ptr)
32 len = mono_metadata_decode_blob_size (ptr, &ptr);
33 res = g_malloc (len + 1);
36 * I should really use some kind of libunicode here
38 for (i = 0, j = 0; i < len; j++, i += 2)
43 result = g_strescape (res, NULL);
49 #define CODE_INDENT g_assert (indent_level < 512); \
50 indent[indent_level*2] = ' '; \
51 indent[indent_level*2+1] = ' '; \
53 indent[indent_level*2] = 0;
54 #define CODE_UNINDENT g_assert (indent_level); \
56 indent[indent_level*2] = 0;
59 dissasemble_cil (MonoImage *m, MonoMethodHeader *mh, MonoGenericContext *context)
61 const unsigned char *start = mh->code;
62 int size = mh->code_size;
63 const unsigned char *end = start + size;
64 const unsigned char *ptr = start;
65 const MonoOpcode *entry;
67 int i, indent_level = 0;
68 gboolean in_fault = 0;
69 const char *clause_names[] = {"catch", "filter", "finally", "", "fault"};
70 gboolean *trys = NULL;
74 for (i = 0; i < mh->num_clauses; ++i) {
75 #define clause mh->clauses [i]
76 g_print ("/* out clause %d: from %d len=%d, handler at %d, %d */\n",
77 clause.flags, clause.try_offset, clause.try_len, clause.handler_offset, clause.handler_len);
82 if (mh->num_clauses) {
83 trys = g_malloc0 (sizeof (gboolean) * mh->num_clauses);
85 for (i=1; i < mh->num_clauses; ++i) {
86 #define pcl mh->clauses [i-1]
87 #define cl mh->clauses [i]
88 if (pcl.try_offset != cl.try_offset || pcl.try_len != cl.try_len)
96 for (i = mh->num_clauses - 1; i >= 0 ; --i) {
97 if (ptr == start + mh->clauses[i].try_offset && trys [i]) {
98 fprintf (output, "\t%s.try { // %d\n", indent, i);
102 if (ptr == start + mh->clauses[i].handler_offset) {
103 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FILTER) {
105 fprintf (output, "\t%s} { // %d\n", indent, i);
107 char * klass = mh->clauses[i].flags ? g_strdup ("") :
108 dis_stringify_object_with_class (m, mh->clauses[i].data.catch_class,
110 fprintf (output, "\t%s%s %s { // %d\n", indent,
111 clause_names [mh->clauses[i].flags], klass, i);
115 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
118 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FILTER && ptr == start + mh->clauses[i].data.filter_offset) {
119 fprintf (output, "\t%s%s {\n", indent, clause_names[1]);
123 fprintf (output, "\t%sIL_%04x: ", indent, (int) (ptr - start));
129 entry = &mono_opcodes [i];
131 if (in_fault && entry->opval == 0xDC)
132 fprintf (output, " %s", "endfault");
134 fprintf (output, " %s ", mono_opcode_name (i));
136 switch (entry->argument){
137 case MonoInlineBrTarget: {
138 gint target = read32 (ptr);
139 fprintf (output, "IL_%04x\n", ((int) (ptr - start)) + 4 + target);
144 case MonoInlineField: {
145 guint32 token = read32 (ptr);
148 s = get_field (m, token, context);
149 fprintf (output, "%s", s);
156 int value = read32 (ptr);
158 fprintf (output, "%d", value);
164 gint64 top = read64 (ptr);
166 fprintf (output, "0x%llx", (long long) top);
171 case MonoInlineMethod: {
172 guint32 token = read32 (ptr);
175 s = get_method (m, token, context);
176 fprintf (output, "%s", s);
191 fprintf (output, "(00 00 00 00 00 00 f0 ff)"); /* negative infinity */
193 fprintf (output, "(00 00 00 00 00 00 f0 7f)"); /* positive infinity */
195 fprintf (output, "(00 00 00 00 00 00 f8 ff)"); /* NaN */
197 fprintf (output, "%g", r);
202 case MonoInlineSig: {
203 guint32 token = read32 (ptr);
204 fprintf (output, "signature-0x%08x", token);
209 case MonoInlineString: {
210 guint32 token = read32 (ptr);
212 char *s = get_encoded_user_string (
213 mono_metadata_user_string (m, token & 0xffffff));
216 * See section 23.1.4 on the encoding of the #US heap
218 fprintf (output, "\"%s\"", s);
224 case MonoInlineSwitch: {
225 guint32 count = read32 (ptr);
226 const unsigned char *endswitch;
230 endswitch = ptr + sizeof (guint32) * count;
231 fprintf (output, count > 0 ? "(\n" : "( )");
233 for (n = 0; n < count; n++){
234 fprintf (output, "\t%sIL_%04x%s", indent,
235 endswitch-start+read32 (ptr),
236 n == count - 1 ? ")" : ",\n");
243 case MonoInlineTok: {
244 guint32 token = read32 (ptr);
247 s = get_token (m, token, context);
248 fprintf (output, "%s", s);
255 case MonoInlineType: {
256 guint32 token = read32 (ptr);
257 char *s = get_token_type (m, token, context);
258 fprintf (output, "%s", s);
264 case MonoInlineVar: {
265 guint16 var_idx = read16 (ptr);
267 fprintf (output, "%d\n", var_idx);
272 case MonoShortInlineBrTarget: {
273 signed char x = *ptr;
275 fprintf (output, "IL_%04x\n", ptr - start + 1 + x);
280 case MonoShortInlineI: {
283 fprintf (output, "0x%02x", x);
288 case MonoShortInlineR: {
296 fprintf (output, "(00 00 80 ff)"); /* negative infinity */
298 fprintf (output, "(00 00 80 7f)"); /* positive infinity */
300 fprintf (output, "(00 00 c0 ff)"); /* NaN */
302 fprintf (output, "%g", (double) f);
307 case MonoShortInlineVar: {
308 unsigned char x = *ptr;
310 fprintf (output, "%d", (int) x);
318 fprintf (output, "\n");
319 for (i = 0; i < mh->num_clauses; ++i) {
320 if (ptr == start + mh->clauses[i].try_offset + mh->clauses[i].try_len && trys [i]) {
322 fprintf (output, "\t%s} // end .try %d\n", indent, i);
324 if (ptr == start + mh->clauses[i].handler_offset + mh->clauses[i].handler_len) {
326 fprintf (output, "\t%s} // end handler %d\n", indent, i);
327 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)