a1fba0e24a1945cff4b0f3bd8d45bf483b266fdb
[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 void
81 dissasemble_cil (metadata_t *m, const unsigned char *start, int size) 
82 {
83         const unsigned char *end = start + size;
84         const unsigned char *ptr = start;
85         opcode_t *entry;
86
87         while (ptr < end){
88                 if (*ptr == 0xfe){
89                         ptr++;
90                         entry = &opcodes [*ptr + 256];
91                 } else 
92                         entry = &opcodes [*ptr];
93
94                 fprintf (output, "\tIL_%04x: %s ", (int) (ptr - start), entry->name);
95                 ptr++;
96                 switch (entry->argument){
97                 case InlineBrTarget: {
98                         gint target = *(gint32 *) ptr;
99                         fprintf (output, "IL_%04x", ((int) (ptr - start)) + 4 + target);
100                         ptr += 4;
101                         break;
102                 }
103                         
104                 case InlineField: {
105                         guint32 token = *(guint32 *) ptr;
106                         char *s;
107                         
108                         s = get_field (m, token);
109                         fprintf (output, "%s", s);
110                         g_free (s);
111                         ptr += 4;
112                         break;
113                 }
114                 
115                 case InlineI: {
116                         int value = *(int *) ptr;
117
118                         fprintf (output, "%d", value);
119                         ptr += 4;
120                         break;
121                 }
122                 
123                 case InlineI8: {
124                         gint64 top = *(guint64 *) ptr;
125
126                         fprintf (output, "%lld", (long long) top);
127                         ptr += 8;
128                         break;
129                 }
130                 
131                 case InlineMethod: {
132                         guint32 token = *(guint32 *) ptr;
133                         char *s;
134
135                         s = get_method (m, token);
136                         fprintf (output, "%s", s);
137                         g_free (s);
138                         ptr += 4;
139                         break;
140                 }
141                 
142                 case InlineNone:
143                         break;
144                         
145                 case InlineR: {
146                         double r = *(double *) ptr;
147                         fprintf (output, "%g", r);
148                         ptr += 8;
149                         break;
150                 }
151                 
152                 case InlineSig: {
153                         guint32 token = *(guint32 *) ptr;
154                         fprintf (output, "signature-0x%08x", token);
155                         ptr += 4;
156                         break;
157                 }
158                 
159                 case InlineString: {
160                         guint32 token = *(guint32 *) ptr;
161                         
162                         char *s = get_encoded_user_string (
163                                 mono_metadata_user_string (m, token & 0xffffff));
164                         
165                         /*
166                          * See section 23.1.4 on the encoding of the #US heap
167                          */
168                         fprintf (output, "\"%s\"", s);
169                         g_free (s);
170                         ptr += 4;
171                         break;
172                 }
173
174                 case InlineSwitch: {
175                         guint32 count = *(guint32 *) ptr;
176                         guint32 i;
177                         
178                         ptr += 4;
179                         fprintf (output, "(\n\t\t\t");
180                         for (i = 0; i < count; i++){
181                                 fprintf (output, "IL_%x", *(guint32 *) ptr);
182                                 ptr += 4;
183                         }
184                         fprintf (output, "\t\t\t)");
185                         break;
186                 }
187
188                 case InlineTok: {
189                         guint32 token = *(guint32 *) ptr;
190                         char *s;
191                         
192                         s = get_token (m, token);
193                         fprintf (output, "%s", s);
194                         g_free (s);
195                         
196                         ptr += 4;
197                         break;
198                 }
199                 
200                 case InlineType: {
201                         guint32 token = *(guint32 *) ptr;
202                         char *s = get_token_type (m, token);
203                         fprintf (output, "%s", s);
204                         g_free (s);
205                         ptr += 4;
206                         break;
207                 }
208
209                 case InlineVar: {
210                         gint16 var_idx = *(gint16 *) ptr;
211
212                         fprintf (output, "variable-%d\n", var_idx);
213                         ptr += 2;
214                         break;
215                 }
216
217                 case ShortInlineBrTarget: {
218                         signed char x = *ptr;
219                         
220                         fprintf (output, "IL_%04x", ptr - start + 1 + x);
221                         ptr++;
222                         break;
223                 }
224
225                 case ShortInlineI: {
226                         char x = *ptr;
227
228                         fprintf (output, "0x%02x", x);
229                         ptr++;
230                         break;
231                 }
232
233                 case ShortInlineR: {
234                         float f = *(float *) ptr;
235
236                         fprintf (output, "%g", (double) f);
237                         ptr += 4;
238                         break;
239                 }
240
241                 case ShortInlineVar: {
242                         signed char x = *ptr;
243
244                         fprintf (output, "V_%d", (int) x);
245                         ptr++;
246                         break;
247                 }
248
249                 }
250
251                 fprintf (output, "\n");
252         }
253 }