New test.
[mono.git] / mono / dis / dis-cil.c
1 /*
2  * dis-cil.c: Disassembles CIL byte codes
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9 #include <config.h>
10 #include <glib.h>
11 #include <stdio.h>
12 #include <math.h>
13 #ifdef  HAVE_WCHAR_H
14 #include <wchar.h>
15 #endif
16 #include "meta.h"
17 #include "get.h"
18 #include "dump.h"
19 #include "dis-cil.h"
20 #include "mono/metadata/opcodes.h"
21 #include "mono/utils/mono-compiler.h"
22
23 #ifndef HAVE_ISINF
24
25 #ifdef HAVE_IEEEFP_H
26 #include <ieeefp.h>
27 int isinf (double);
28 int
29 isinf (double num)
30 {
31         fpclass_t klass;
32
33         klass = fpclass (num);
34         if (klass == FP_NINF)
35                 return -1;
36
37         if (klass == FP_PINF)
38                 return 1;
39
40         return 0;
41 }
42 #else
43 #error "Don't know how to implement isinf for this platform."
44 #endif
45
46 #endif
47
48 #define CODE_INDENT g_assert (indent_level < 512); \
49         indent[indent_level*2] = ' ';   \
50         indent[indent_level*2+1] = ' '; \
51         ++indent_level; \
52         indent[indent_level*2] = 0;
53 #define CODE_UNINDENT g_assert (indent_level);  \
54         --indent_level; \
55         indent[indent_level*2] = 0;
56
57 void
58 disassemble_cil (MonoImage *m, MonoMethodHeader *mh, MonoGenericContext *context)
59 {
60         const unsigned char *start = mh->code;
61         int size = mh->code_size;
62         const unsigned char *end = start + size;
63         const unsigned char *ptr = start;
64         const MonoOpcode *entry;
65         char indent[1024];
66         int i, j, indent_level = 0;
67         gboolean in_fault = 0;
68         const char *clause_names[] = {"catch", "filter", "finally", "", "fault"};
69         gboolean *trys = NULL;
70         indent [0] = 0;
71
72 #ifdef DEBUG
73         for (i = 0; i < mh->num_clauses; ++i) {
74 #define clause mh->clauses [i]
75                g_print ("/* out clause %d: from %d len=%d, handler at %d, %d */\n",
76                         clause.flags, clause.try_offset, clause.try_len, clause.handler_offset, clause.handler_len);
77 #undef clause
78         }
79 #endif
80
81        if (mh->num_clauses) {
82                trys = g_malloc0 (sizeof (gboolean) * mh->num_clauses);
83                trys [0] = 1;
84                for (i=1; i < mh->num_clauses; ++i) {
85 #define jcl mh->clauses [j]     
86 #define cl mh->clauses [i]      
87                        trys [i] = 1;
88                        for (j = 0; j < i; j++) {
89                                if (cl.try_offset == jcl.try_offset && cl.try_len == jcl.try_len) {
90                                        trys [i] = 0;
91                                        break;
92                                }
93                        }
94 #undef jcl
95 #undef cl
96                }
97        }
98
99         while (ptr < end){
100                 for (i = mh->num_clauses - 1; i >= 0 ; --i) {
101                         if (ptr == start + mh->clauses[i].try_offset && trys [i]) {
102                                 fprintf (output, "\t%s.try { // %d\n", indent, i);
103                                 CODE_INDENT;
104                         }
105                         
106                         if (ptr == start + mh->clauses[i].handler_offset) {
107                                 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FILTER) {
108                                         CODE_UNINDENT;
109                                         fprintf (output, "\t%s} { // %d\n", indent, i);
110                                 } else {
111                                         char * klass = mh->clauses[i].flags ? g_strdup ("") :
112                                                 dis_stringify_object_with_class (m, mh->clauses[i].data.catch_class,
113                                                                                  FALSE, FALSE);
114                                         fprintf (output, "\t%s%s %s { // %d\n", indent,
115                                                         clause_names [mh->clauses[i].flags], klass, i);
116                                         g_free (klass);
117                                 }
118                                 CODE_INDENT;
119                                 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
120                                         in_fault = 1;
121                         } 
122                         if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FILTER && ptr == start + mh->clauses[i].data.filter_offset) {
123                                 fprintf (output, "\t%s%s {\n", indent, clause_names[1]);
124                                 CODE_INDENT;
125                         }
126                 }
127                 fprintf (output, "\t%sIL_%04x: ", indent, (int) (ptr - start));
128                 i = *ptr;
129                 if (*ptr == 0xfe){
130                         ptr++;
131                         i = *ptr + 256;
132                 } 
133                 entry = &mono_opcodes [i];
134
135                 if (in_fault && entry->opval == 0xDC)
136                         fprintf (output, " %s", "endfault");
137                 else
138                         fprintf (output, " %s ", mono_opcode_name (i));
139                 ptr++;
140                 switch (entry->argument){
141                 case MonoInlineBrTarget: {
142                         gint target = read32 (ptr);
143                         fprintf (output, "IL_%04x\n", ((int) (ptr - start)) + 4 + target);
144                         ptr += 4;
145                         break;
146                 }
147                         
148                 case MonoInlineField: {
149                         guint32 token = read32 (ptr);
150                         char *s;
151                         
152                         s = get_field (m, token, context);
153                         fprintf (output, "%s", s);
154                         g_free (s);
155                         ptr += 4;
156                         break;
157                 }
158                 
159                 case MonoInlineI: {
160                         int value = read32 (ptr);
161
162                         fprintf (output, "%d", value);
163                         ptr += 4;
164                         break;
165                 }
166                 
167                 case MonoInlineI8: {
168                         gint64 top = read64 (ptr);
169
170                         fprintf (output, "0x%llx", (long long) top);
171                         ptr += 8;
172                         break;
173                 }
174                 
175                 case MonoInlineMethod: {
176                         guint32 token = read32 (ptr);
177                         char *s;
178
179                         s = get_method (m, token, context);
180                         fprintf (output, "%s", s);
181                         g_free (s);
182                         ptr += 4;
183                         break;
184                 }
185                 
186                 case MonoInlineNone:
187                         break;
188                         
189                 case MonoInlineR: {
190                         double r;
191                         int inf;
192                         readr8 (ptr, &r);
193                         inf = isinf (r);
194                         if (inf == -1) 
195                                 fprintf (output, "(00 00 00 00 00 00 f0 ff)"); /* negative infinity */
196                         else if (inf == 1)
197                                 fprintf (output, "(00 00 00 00 00 00 f0 7f)"); /* positive infinity */
198                         else if (isnan (r))
199                                 fprintf (output, "(00 00 00 00 00 00 f8 ff)"); /* NaN */
200                         else {
201                                 char *str = stringify_double (r);
202                                 fprintf (output, str);
203                                 g_free (str);
204                         }
205                         ptr += 8;
206                         break;
207                 }
208                 
209                 case MonoInlineSig: {
210                         guint32 token = read32 (ptr);
211                         fprintf (output, "signature-0x%08x", token);
212                         ptr += 4;
213                         break;
214                 }
215                 
216                 case MonoInlineString: {
217                         guint32 token = read32 (ptr);
218                         const char *us_ptr = mono_metadata_user_string (m, token & 0xffffff);
219                         int len = mono_metadata_decode_blob_size (us_ptr, (const char**)&us_ptr);
220
221                         char *s = get_encoded_user_string_or_bytearray (us_ptr, len);
222                         
223                         /*
224                          * See section 23.1.4 on the encoding of the #US heap
225                          */
226                         fprintf (output, "%s", s);
227                         g_free (s);
228                         ptr += 4;
229                         break;
230                 }
231
232                 case MonoInlineSwitch: {
233                         guint32 count = read32 (ptr);
234                         const unsigned char *endswitch;
235                         guint32 n;
236                         
237                         ptr += 4;
238                         endswitch = ptr + sizeof (guint32) * count;
239                         fprintf (output, count > 0 ? "(\n" : "( )");
240                         CODE_INDENT;
241                         for (n = 0; n < count; n++){
242                                 fprintf (output, "\t%sIL_%04x%s", indent, 
243                                                  (int)(endswitch-start+read32 (ptr)), 
244                                                  n == count - 1 ? ")" : ",\n");
245                                 ptr += 4;
246                         }
247                         CODE_UNINDENT;
248                         break;
249                 }
250
251                 case MonoInlineTok: {
252                         guint32 token = read32 (ptr);
253                         char *s;
254                         
255                         s = get_token (m, token, context);
256                         fprintf (output, "%s", s);
257                         g_free (s);
258                         
259                         ptr += 4;
260                         break;
261                 }
262                 
263                 case MonoInlineType: {
264                         guint32 token = read32 (ptr);
265                         char *s = get_token_type (m, token, context);
266                         fprintf (output, "%s", s);
267                         g_free (s);
268                         ptr += 4;
269                         break;
270                 }
271
272                 case MonoInlineVar: {
273                         guint16 var_idx = read16 (ptr);
274
275                         fprintf (output, "%d\n", var_idx);
276                         ptr += 2;
277                         break;
278                 }
279
280                 case MonoShortInlineBrTarget: {
281                         signed char x = *ptr;
282                         
283                         fprintf (output, "IL_%04x\n", (int)(ptr - start + 1 + x));
284                         ptr++;
285                         break;
286                 }
287
288                 case MonoShortInlineI: {
289                         char x = *ptr;
290
291                         fprintf (output, "0x%02x", x);
292                         ptr++;
293                         break;
294                 }
295
296                 case MonoShortInlineR: {
297                         float f;
298                         int inf;
299                         
300                         readr4 (ptr, &f);
301
302                         inf = isinf (f);
303                         if (inf == -1) 
304                                 fprintf (output, "(00 00 80 ff)"); /* negative infinity */
305                         else if (inf == 1)
306                                 fprintf (output, "(00 00 80 7f)"); /* positive infinity */
307                         else if (isnan (f))
308                                 fprintf (output, "(00 00 c0 ff)"); /* NaN */
309                         else {
310                                 char *str = stringify_double ((double) f);
311                                 fprintf (output, str);
312                                 g_free (str);
313                         }
314                         ptr += 4;
315                         break;
316                 }
317
318                 case MonoShortInlineVar: {
319                         unsigned char x = *ptr;
320
321                         fprintf (output, "%d", (int) x);
322                         ptr++;
323                         break;
324                 }
325                 default:
326                         break;
327                 }
328
329                 fprintf (output, "\n");
330                 for (i = 0; i < mh->num_clauses; ++i) {
331                         if (ptr == start + mh->clauses[i].try_offset + mh->clauses[i].try_len && trys [i]) {
332                                 CODE_UNINDENT;
333                                 fprintf (output, "\t%s} // end .try %d\n", indent, i);
334                         }
335                         if (ptr == start + mh->clauses[i].handler_offset + mh->clauses[i].handler_len) {
336                                 CODE_UNINDENT;
337                                 fprintf (output, "\t%s} // end handler %d\n", indent, i);
338                                 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
339                                         in_fault = 0;
340                         }
341                 }
342         }
343         if (trys)
344                 g_free (trys);
345 }