7708b6c088b3fc7ecd9d0ba6fd517a1e1292905f
[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 <wchar.h>
13 #include "meta.h"
14 #include "get.h"
15 #include "dump.h"
16 #include "dis-cil.h"
17
18 enum {
19         InlineBrTarget,
20         InlineField,
21         InlineI,
22         InlineI8,
23         InlineMethod,
24         InlineNone,
25         InlineR,
26         InlineSig,
27         InlineString,
28         InlineSwitch,
29         InlineTok,
30         InlineType,
31         InlineVar,
32         ShortInlineBrTarget,
33         ShortInlineI,
34         ShortInlineR,
35         ShortInlineVar
36 };
37
38 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
39         { b, e, g, h, i },
40
41 typedef struct {
42         char *name;
43         int   argument;
44
45         /*
46          * we are not really using any of the following:
47          */
48         int   bytes;
49         unsigned char  o1, o2;
50 } opcode_t;
51
52 static opcode_t opcodes [300] = {
53 #include "mono/cil/opcode.def"
54 };
55
56 /*
57  * Strings on the US heap are encoded using UTF-16.  Poor man's
58  * UTF-16 to UTF-8.  I know its broken, use libunicode later.
59  */
60 static char *
61 get_encoded_user_string (const char *ptr)
62 {
63         char *res;
64         int len, i, j;
65
66         len = mono_metadata_decode_blob_size (ptr, &ptr);
67         res = g_malloc (len + 1);
68
69         /*
70          * I should really use some kind of libunicode here
71          */
72         for (i = 0, j = 0; i < len; j++, i += 2)
73                 res [j] = ptr [i];
74
75         res [j] = 0;
76                 
77         return res;
78 }
79
80 #define CODE_INDENT g_assert (indent_level < 127); \
81         indent[indent_level*2] = ' ';   \
82         indent[indent_level*2+1] = ' '; \
83         ++indent_level; \
84         indent[indent_level*2] = 0;
85 #define CODE_UNINDENT g_assert (indent_level);  \
86         --indent_level; \
87         indent[indent_level*2] = 0;
88
89 void
90 dissasemble_cil (metadata_t *m, MonoMetaMethodHeader *mh) 
91 {
92         const unsigned char *start = mh->code;
93         int size = mh->code_size;
94         const unsigned char *end = start + size;
95         const unsigned char *ptr = start;
96         opcode_t *entry;
97         char indent[256];
98         int i, indent_level = 0;
99         char *clause_names[] = {"catch", "filter", "finally", "fault"};
100
101         indent [0] = 0;
102
103         while (ptr < end){
104                 /* first pass to get the end clauses */
105                 for (i = 0; i < mh->num_clauses; ++i) {
106                         if (!mh->clauses[i].flags && ptr == start + mh->clauses[i].try_offset + mh->clauses[i].try_len) {
107                                 CODE_UNINDENT;
108                                 fprintf (output, "\t%s} // end .try %d\n", indent, i);
109                         }
110                         if (ptr == start + mh->clauses[i].handler_offset + mh->clauses[i].handler_len) {
111                                 CODE_UNINDENT;
112                                 fprintf (output, "\t%s} // end handler %d\n", indent, i);
113                         }
114                 }
115                 for (i = 0; i < mh->num_clauses; ++i) {
116                         if (!mh->clauses[i].flags && ptr == start + mh->clauses[i].try_offset) {
117                                 fprintf (output, "\t%s.try { // %d\n", indent, i);
118                                 CODE_INDENT;
119                         }
120                         if (ptr == start + mh->clauses[i].handler_offset) {
121                                 char * klass = mh->clauses[i].flags ? g_strdup ("") : dis_stringify_token (m, mh->clauses[i].token_or_filter);
122                                 fprintf (output, "\t%s%s %s { // %d\n", indent, clause_names [mh->clauses[i].flags], klass, i);
123                                 CODE_INDENT;
124                                 g_free (klass);
125                         }
126                 }
127                 if (*ptr == 0xfe){
128                         ptr++;
129                         entry = &opcodes [*ptr + 256];
130                 } else 
131                         entry = &opcodes [*ptr];
132
133                 fprintf (output, "\t%sIL_%04x: %s ", indent, (int) (ptr - start), entry->name);
134                 ptr++;
135                 switch (entry->argument){
136                 case InlineBrTarget: {
137                         gint target = *(gint32 *) ptr;
138                         fprintf (output, "IL_%04x", ((int) (ptr - start)) + 4 + target);
139                         ptr += 4;
140                         break;
141                 }
142                         
143                 case InlineField: {
144                         guint32 token = *(guint32 *) ptr;
145                         char *s;
146                         
147                         s = get_field (m, token);
148                         fprintf (output, "%s", s);
149                         g_free (s);
150                         ptr += 4;
151                         break;
152                 }
153                 
154                 case InlineI: {
155                         int value = *(int *) ptr;
156
157                         fprintf (output, "%d", value);
158                         ptr += 4;
159                         break;
160                 }
161                 
162                 case InlineI8: {
163                         gint64 top = *(guint64 *) ptr;
164
165                         fprintf (output, "%lld", (long long) top);
166                         ptr += 8;
167                         break;
168                 }
169                 
170                 case InlineMethod: {
171                         guint32 token = *(guint32 *) ptr;
172                         char *s;
173
174                         s = get_method (m, token);
175                         fprintf (output, "%s", s);
176                         g_free (s);
177                         ptr += 4;
178                         break;
179                 }
180                 
181                 case InlineNone:
182                         break;
183                         
184                 case InlineR: {
185                         double r = *(double *) ptr;
186                         fprintf (output, "%g", r);
187                         ptr += 8;
188                         break;
189                 }
190                 
191                 case InlineSig: {
192                         guint32 token = *(guint32 *) ptr;
193                         fprintf (output, "signature-0x%08x", token);
194                         ptr += 4;
195                         break;
196                 }
197                 
198                 case InlineString: {
199                         guint32 token = *(guint32 *) ptr;
200                         
201                         char *s = get_encoded_user_string (
202                                 mono_metadata_user_string (m, token & 0xffffff));
203                         
204                         /*
205                          * See section 23.1.4 on the encoding of the #US heap
206                          */
207                         fprintf (output, "\"%s\"", s);
208                         g_free (s);
209                         ptr += 4;
210                         break;
211                 }
212
213                 case InlineSwitch: {
214                         guint32 count = *(guint32 *) ptr;
215                         guint32 i;
216                         
217                         ptr += 4;
218                         fprintf (output, "(\n\t\t\t");
219                         for (i = 0; i < count; i++){
220                                 fprintf (output, "IL_%x", *(guint32 *) ptr);
221                                 ptr += 4;
222                         }
223                         fprintf (output, "\t\t\t)");
224                         break;
225                 }
226
227                 case InlineTok: {
228                         guint32 token = *(guint32 *) ptr;
229                         char *s;
230                         
231                         s = get_token (m, token);
232                         fprintf (output, "%s", s);
233                         g_free (s);
234                         
235                         ptr += 4;
236                         break;
237                 }
238                 
239                 case InlineType: {
240                         guint32 token = *(guint32 *) ptr;
241                         char *s = get_token_type (m, token);
242                         fprintf (output, "%s", s);
243                         g_free (s);
244                         ptr += 4;
245                         break;
246                 }
247
248                 case InlineVar: {
249                         gint16 var_idx = *(gint16 *) ptr;
250
251                         fprintf (output, "variable-%d\n", var_idx);
252                         ptr += 2;
253                         break;
254                 }
255
256                 case ShortInlineBrTarget: {
257                         signed char x = *ptr;
258                         
259                         fprintf (output, "IL_%04x", ptr - start + 1 + x);
260                         ptr++;
261                         break;
262                 }
263
264                 case ShortInlineI: {
265                         char x = *ptr;
266
267                         fprintf (output, "0x%02x", x);
268                         ptr++;
269                         break;
270                 }
271
272                 case ShortInlineR: {
273                         float f = *(float *) ptr;
274
275                         fprintf (output, "%g", (double) f);
276                         ptr += 4;
277                         break;
278                 }
279
280                 case ShortInlineVar: {
281                         signed char x = *ptr;
282
283                         fprintf (output, "V_%d", (int) x);
284                         ptr++;
285                         break;
286                 }
287                 default:
288                         break;
289                 }
290
291                 fprintf (output, "\n");
292         }
293 }