merge -r 58784:58785
[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 dissasemble_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, 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 pcl mh->clauses [i-1]   
86 #define cl mh->clauses [i]      
87                        if (pcl.try_offset != cl.try_offset || pcl.try_len != cl.try_len)
88                                trys [i] = 1;
89 #undef pcl
90 #undef cl
91                }
92        }
93
94         while (ptr < end){
95                 for (i = mh->num_clauses - 1; i >= 0 ; --i) {
96                         if (ptr == start + mh->clauses[i].try_offset && trys [i]) {
97                                 fprintf (output, "\t%s.try { // %d\n", indent, i);
98                                 CODE_INDENT;
99                         }
100                         
101                         if (ptr == start + mh->clauses[i].handler_offset) {
102                                 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FILTER) {
103                                         CODE_UNINDENT;
104                                         fprintf (output, "\t%s} { // %d\n", indent, i);
105                                 } else {
106                                         char * klass = mh->clauses[i].flags ? g_strdup ("") :
107                                                 dis_stringify_object_with_class (m, mh->clauses[i].data.catch_class,
108                                                                                  FALSE, FALSE);
109                                         fprintf (output, "\t%s%s %s { // %d\n", indent,
110                                                         clause_names [mh->clauses[i].flags], klass, i);
111                                         g_free (klass);
112                                 }
113                                 CODE_INDENT;
114                                 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
115                                         in_fault = 1;
116                         } 
117                         if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FILTER && ptr == start + mh->clauses[i].data.filter_offset) {
118                                 fprintf (output, "\t%s%s {\n", indent, clause_names[1]);
119                                 CODE_INDENT;
120                         }
121                 }
122                 fprintf (output, "\t%sIL_%04x: ", indent, (int) (ptr - start));
123                 i = *ptr;
124                 if (*ptr == 0xfe){
125                         ptr++;
126                         i = *ptr + 256;
127                 } 
128                 entry = &mono_opcodes [i];
129
130                 if (in_fault && entry->opval == 0xDC)
131                         fprintf (output, " %s", "endfault");
132                 else
133                         fprintf (output, " %s ", mono_opcode_name (i));
134                 ptr++;
135                 switch (entry->argument){
136                 case MonoInlineBrTarget: {
137                         gint target = read32 (ptr);
138                         fprintf (output, "IL_%04x\n", ((int) (ptr - start)) + 4 + target);
139                         ptr += 4;
140                         break;
141                 }
142                         
143                 case MonoInlineField: {
144                         guint32 token = read32 (ptr);
145                         char *s;
146                         
147                         s = get_field (m, token, context);
148                         fprintf (output, "%s", s);
149                         g_free (s);
150                         ptr += 4;
151                         break;
152                 }
153                 
154                 case MonoInlineI: {
155                         int value = read32 (ptr);
156
157                         fprintf (output, "%d", value);
158                         ptr += 4;
159                         break;
160                 }
161                 
162                 case MonoInlineI8: {
163                         gint64 top = read64 (ptr);
164
165                         fprintf (output, "0x%llx", (long long) top);
166                         ptr += 8;
167                         break;
168                 }
169                 
170                 case MonoInlineMethod: {
171                         guint32 token = read32 (ptr);
172                         char *s;
173
174                         s = get_method (m, token, context);
175                         fprintf (output, "%s", s);
176                         g_free (s);
177                         ptr += 4;
178                         break;
179                 }
180                 
181                 case MonoInlineNone:
182                         break;
183                         
184                 case MonoInlineR: {
185                         double r;
186                         int inf;
187                         readr8 (ptr, &r);
188                         inf = isinf (r);
189                         if (inf == -1) 
190                                 fprintf (output, "(00 00 00 00 00 00 f0 ff)"); /* negative infinity */
191                         else if (inf == 1)
192                                 fprintf (output, "(00 00 00 00 00 00 f0 7f)"); /* positive infinity */
193                         else if (isnan (r))
194                                 fprintf (output, "(00 00 00 00 00 00 f8 ff)"); /* NaN */
195                         else
196                                 fprintf (output, "%.20g", r);
197                         ptr += 8;
198                         break;
199                 }
200                 
201                 case MonoInlineSig: {
202                         guint32 token = read32 (ptr);
203                         fprintf (output, "signature-0x%08x", token);
204                         ptr += 4;
205                         break;
206                 }
207                 
208                 case MonoInlineString: {
209                         guint32 token = read32 (ptr);
210                         const char *us_ptr = mono_metadata_user_string (m, token & 0xffffff);
211                         int len = mono_metadata_decode_blob_size (us_ptr, (const char**)&us_ptr);
212
213                         char *s = get_encoded_user_string_or_bytearray (us_ptr, len);
214                         
215                         /*
216                          * See section 23.1.4 on the encoding of the #US heap
217                          */
218                         fprintf (output, "%s", s);
219                         g_free (s);
220                         ptr += 4;
221                         break;
222                 }
223
224                 case MonoInlineSwitch: {
225                         guint32 count = read32 (ptr);
226                         const unsigned char *endswitch;
227                         guint32 n;
228                         
229                         ptr += 4;
230                         endswitch = ptr + sizeof (guint32) * count;
231                         fprintf (output, count > 0 ? "(\n" : "( )");
232                         CODE_INDENT;
233                         for (n = 0; n < count; n++){
234                                 fprintf (output, "\t%sIL_%04x%s", indent, 
235                                                  (int)(endswitch-start+read32 (ptr)), 
236                                                  n == count - 1 ? ")" : ",\n");
237                                 ptr += 4;
238                         }
239                         CODE_UNINDENT;
240                         break;
241                 }
242
243                 case MonoInlineTok: {
244                         guint32 token = read32 (ptr);
245                         char *s;
246                         
247                         s = get_token (m, token, context);
248                         fprintf (output, "%s", s);
249                         g_free (s);
250                         
251                         ptr += 4;
252                         break;
253                 }
254                 
255                 case MonoInlineType: {
256                         guint32 token = read32 (ptr);
257                         char *s = get_token_type (m, token, context);
258                         fprintf (output, "%s", s);
259                         g_free (s);
260                         ptr += 4;
261                         break;
262                 }
263
264                 case MonoInlineVar: {
265                         guint16 var_idx = read16 (ptr);
266
267                         fprintf (output, "%d\n", var_idx);
268                         ptr += 2;
269                         break;
270                 }
271
272                 case MonoShortInlineBrTarget: {
273                         signed char x = *ptr;
274                         
275                         fprintf (output, "IL_%04x\n", (int)(ptr - start + 1 + x));
276                         ptr++;
277                         break;
278                 }
279
280                 case MonoShortInlineI: {
281                         char x = *ptr;
282
283                         fprintf (output, "0x%02x", x);
284                         ptr++;
285                         break;
286                 }
287
288                 case MonoShortInlineR: {
289                         float f;
290                         int inf;
291                         
292                         readr4 (ptr, &f);
293
294                         inf = isinf (f);
295                         if (inf == -1) 
296                                 fprintf (output, "(00 00 80 ff)"); /* negative infinity */
297                         else if (inf == 1)
298                                 fprintf (output, "(00 00 80 7f)"); /* positive infinity */
299                         else if (isnan (f))
300                                 fprintf (output, "(00 00 c0 ff)"); /* NaN */
301                         else
302                                 fprintf (output, "%.20g", (double) f);
303                         ptr += 4;
304                         break;
305                 }
306
307                 case MonoShortInlineVar: {
308                         unsigned char x = *ptr;
309
310                         fprintf (output, "%d", (int) x);
311                         ptr++;
312                         break;
313                 }
314                 default:
315                         break;
316                 }
317
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]) {
321                                 CODE_UNINDENT;
322                                 fprintf (output, "\t%s} // end .try %d\n", indent, i);
323                         }
324                         if (ptr == start + mh->clauses[i].handler_offset + mh->clauses[i].handler_len) {
325                                 CODE_UNINDENT;
326                                 fprintf (output, "\t%s} // end handler %d\n", indent, i);
327                                 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
328                                         in_fault = 0;
329                         }
330                 }
331         }
332         if (trys)
333                 g_free (trys);
334 }