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