2003-09-04 Martin Baulig <martin@ximian.com>
[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 #ifdef  HAVE_WCHAR_H
13 #include <wchar.h>
14 #endif
15 #include "meta.h"
16 #include "get.h"
17 #include "dump.h"
18 #include "dis-cil.h"
19 #include "mono/metadata/opcodes.h"
20
21 /*
22  * Strings on the US heap are encoded using UTF-16.  Poor man's
23  * UTF-16 to UTF-8.  I know its broken, use libunicode later.
24  */
25 static char *
26 get_encoded_user_string (const char *ptr)
27 {
28         char *res;
29         int len, i, j;
30
31         len = mono_metadata_decode_blob_size (ptr, &ptr);
32         res = g_malloc (len + 1);
33
34         /*
35          * I should really use some kind of libunicode here
36          */
37         for (i = 0, j = 0; i < len; j++, i += 2)
38                 res [j] = ptr [i];
39
40         res [j] = 0;
41                 
42         return res;
43 }
44
45 #define CODE_INDENT g_assert (indent_level < 512); \
46         indent[indent_level*2] = ' ';   \
47         indent[indent_level*2+1] = ' '; \
48         ++indent_level; \
49         indent[indent_level*2] = 0;
50 #define CODE_UNINDENT g_assert (indent_level);  \
51         --indent_level; \
52         indent[indent_level*2] = 0;
53
54 void
55 dissasemble_cil (MonoImage *m, MonoMethodHeader *mh) 
56 {
57         const unsigned char *start = mh->code;
58         int size = mh->code_size;
59         const unsigned char *end = start + size;
60         const unsigned char *ptr = start;
61         const MonoOpcode *entry;
62         char indent[1024];
63         int i, indent_level = 0;
64         const char *clause_names[] = {"catch", "filter", "finally", "fault"};
65
66         indent [0] = 0;
67
68 #ifdef DEBUG
69         for (i = 0; i < mh->num_clauses; ++i) {
70 #define clause mh->clauses [i]
71                 g_print ("out clause %d: from %d len=%d, handler at %d, %d\n", 
72                         clause.flags, clause.try_offset, clause.try_len, clause.handler_offset, clause.handler_len);
73 #undef clause
74         }
75 #endif
76         while (ptr < end){
77                 for (i = mh->num_clauses - 1; i >= 0 ; --i) {
78                         if ((mh->clauses[i].flags == 0 || mh->clauses[i].flags == 2) && ptr == start + mh->clauses[i].try_offset) {
79                                 fprintf (output, "\t%s.try { // %d\n", indent, i);
80                                 CODE_INDENT;
81                         }
82                         if (ptr == start + mh->clauses[i].handler_offset) {
83                                 char * klass = mh->clauses[i].flags ? g_strdup ("") : dis_stringify_token (m, mh->clauses[i].token_or_filter);
84                                 fprintf (output, "\t%s%s %s { // %d\n", indent, clause_names [mh->clauses[i].flags], klass, i);
85                                 CODE_INDENT;
86                                 g_free (klass);
87                         }
88                 }
89                 fprintf (output, "\t%sIL_%04x: ", indent, (int) (ptr - start));
90                 i = *ptr;
91                 if (*ptr == 0xfe){
92                         ptr++;
93                         i = *ptr + 256;
94                 } 
95                 entry = &mono_opcodes [i];
96
97                 fprintf (output, "%s ", mono_opcode_names [i]);
98                 ptr++;
99                 switch (entry->argument){
100                 case MonoInlineBrTarget: {
101                         gint target = read32 (ptr);
102                         fprintf (output, "IL_%04x\n", ((int) (ptr - start)) + 4 + target);
103                         ptr += 4;
104                         break;
105                 }
106                         
107                 case MonoInlineField: {
108                         guint32 token = read32 (ptr);
109                         char *s;
110                         
111                         s = get_field (m, token);
112                         fprintf (output, "%s", s);
113                         g_free (s);
114                         ptr += 4;
115                         break;
116                 }
117                 
118                 case MonoInlineI: {
119                         int value = read32 (ptr);
120
121                         fprintf (output, "%d", value);
122                         ptr += 4;
123                         break;
124                 }
125                 
126                 case MonoInlineI8: {
127                         gint64 top = read64 (ptr);
128
129                         fprintf (output, "0x%llx", (long long) top);
130                         ptr += 8;
131                         break;
132                 }
133                 
134                 case MonoInlineMethod: {
135                         guint32 token = read32 (ptr);
136                         char *s;
137
138                         s = get_method (m, token);
139                         fprintf (output, "%s", s);
140                         g_free (s);
141                         ptr += 4;
142                         break;
143                 }
144                 
145                 case MonoInlineNone:
146                         break;
147                         
148                 case MonoInlineR: {
149                         double r;
150                         readr8 (ptr, &r);
151                         fprintf (output, "%g", r);
152                         ptr += 8;
153                         break;
154                 }
155                 
156                 case MonoInlineSig: {
157                         guint32 token = read32 (ptr);
158                         fprintf (output, "signature-0x%08x", token);
159                         ptr += 4;
160                         break;
161                 }
162                 
163                 case MonoInlineString: {
164                         guint32 token = read32 (ptr);
165                         
166                         char *s = get_encoded_user_string (
167                                 mono_metadata_user_string (m, token & 0xffffff));
168                         
169                         /*
170                          * See section 23.1.4 on the encoding of the #US heap
171                          */
172                         fprintf (output, "\"%s\"", s);
173                         g_free (s);
174                         ptr += 4;
175                         break;
176                 }
177
178                 case MonoInlineSwitch: {
179                         guint32 count = read32 (ptr);
180                         const unsigned char *endswitch;
181                         guint32 n;
182                         
183                         ptr += 4;
184                         endswitch = ptr + sizeof (guint32) * count;
185                         fprintf (output, "(\n");
186                         CODE_INDENT;
187                         for (n = 0; n < count; n++){
188                                 fprintf (output, "\t%sIL_%04x%s", indent, 
189                                         endswitch-start+read32 (ptr), 
190                                         n == count - 1 ? ")" : ",\n");
191                                 ptr += 4;
192                         }
193                         CODE_UNINDENT;
194                         break;
195                 }
196
197                 case MonoInlineTok: {
198                         guint32 token = read32 (ptr);
199                         char *s;
200                         
201                         s = get_token (m, token);
202                         fprintf (output, "%s", s);
203                         g_free (s);
204                         
205                         ptr += 4;
206                         break;
207                 }
208                 
209                 case MonoInlineType: {
210                         guint32 token = read32 (ptr);
211                         char *s = get_token_type (m, token);
212                         fprintf (output, "%s", s);
213                         g_free (s);
214                         ptr += 4;
215                         break;
216                 }
217
218                 case MonoInlineVar: {
219                         guint16 var_idx = read16 (ptr);
220
221                         fprintf (output, "%d\n", var_idx);
222                         ptr += 2;
223                         break;
224                 }
225
226                 case MonoShortInlineBrTarget: {
227                         signed char x = *ptr;
228                         
229                         fprintf (output, "IL_%04x\n", ptr - start + 1 + x);
230                         ptr++;
231                         break;
232                 }
233
234                 case MonoShortInlineI: {
235                         char x = *ptr;
236
237                         fprintf (output, "0x%02x", x);
238                         ptr++;
239                         break;
240                 }
241
242                 case MonoShortInlineR: {
243                         float f;
244                         readr4 (ptr, &f);
245
246                         fprintf (output, "%g", (double) f);
247                         ptr += 4;
248                         break;
249                 }
250
251                 case MonoShortInlineVar: {
252                         unsigned char x = *ptr;
253
254                         fprintf (output, "%d", (int) x);
255                         ptr++;
256                         break;
257                 }
258                 default:
259                         break;
260                 }
261
262                 fprintf (output, "\n");
263                 for (i = 0; i < mh->num_clauses; ++i) {
264                         if ((mh->clauses[i].flags == 0 || mh->clauses[i].flags == 2)  && ptr == start + mh->clauses[i].try_offset + mh->clauses[i].try_len) {
265                                 CODE_UNINDENT;
266                                 fprintf (output, "\t%s} // end .try %d\n", indent, i);
267                         }
268                         if (ptr == start + mh->clauses[i].handler_offset + mh->clauses[i].handler_len) {
269                                 CODE_UNINDENT;
270                                 fprintf (output, "\t%s} // end handler %d\n", indent, i);
271                         }
272                 }
273         }
274 }