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