* dis-cil.c (get_encoded_user_string): use g_strescape instead of
[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, *result;
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         result = g_strescape (res, NULL);
43         g_free (res);
44         
45         return result;
46 }
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) 
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_token (m, mh->clauses[i].token_or_filter);
108                                         fprintf (output, "\t%s%s %s { // %d\n", indent,
109                                                         clause_names [mh->clauses[i].flags], klass, i);
110                                         g_free (klass);
111                                 }
112                                 CODE_INDENT;
113                                 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
114                                         in_fault = 1;
115                         } 
116                         if (mh->clauses[i].flags == 1 && ptr == start + mh->clauses[i].token_or_filter) {
117                                 fprintf (output, "\t%s%s {\n", indent, clause_names[1]);
118                                 CODE_INDENT;
119                         }
120                 }
121                 fprintf (output, "\t%sIL_%04x: ", indent, (int) (ptr - start));
122                 i = *ptr;
123                 if (*ptr == 0xfe){
124                         ptr++;
125                         i = *ptr + 256;
126                 } 
127                 entry = &mono_opcodes [i];
128
129                 if (in_fault && entry->opval == 0xDC)
130                         fprintf (output, " %s", "endfault");
131                 else
132                         fprintf (output, " %s ", mono_opcode_names [i]);
133                 ptr++;
134                 switch (entry->argument){
135                 case MonoInlineBrTarget: {
136                         gint target = read32 (ptr);
137                         fprintf (output, "IL_%04x\n", ((int) (ptr - start)) + 4 + target);
138                         ptr += 4;
139                         break;
140                 }
141                         
142                 case MonoInlineField: {
143                         guint32 token = read32 (ptr);
144                         char *s;
145                         
146                         s = get_field (m, token);
147                         fprintf (output, "%s", s);
148                         g_free (s);
149                         ptr += 4;
150                         break;
151                 }
152                 
153                 case MonoInlineI: {
154                         int value = read32 (ptr);
155
156                         fprintf (output, "%d", value);
157                         ptr += 4;
158                         break;
159                 }
160                 
161                 case MonoInlineI8: {
162                         gint64 top = read64 (ptr);
163
164                         fprintf (output, "0x%llx", (long long) top);
165                         ptr += 8;
166                         break;
167                 }
168                 
169                 case MonoInlineMethod: {
170                         guint32 token = read32 (ptr);
171                         char *s;
172
173                         s = get_method (m, token);
174                         fprintf (output, "%s", s);
175                         g_free (s);
176                         ptr += 4;
177                         break;
178                 }
179                 
180                 case MonoInlineNone:
181                         break;
182                         
183                 case MonoInlineR: {
184                         double r;
185                         readr8 (ptr, &r);
186                         fprintf (output, "%g", r);
187                         ptr += 8;
188                         break;
189                 }
190                 
191                 case MonoInlineSig: {
192                         guint32 token = read32 (ptr);
193                         fprintf (output, "signature-0x%08x", token);
194                         ptr += 4;
195                         break;
196                 }
197                 
198                 case MonoInlineString: {
199                         guint32 token = read32 (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 MonoInlineSwitch: {
214                         guint32 count = read32 (ptr);
215                         const unsigned char *endswitch;
216                         guint32 n;
217                         
218                         ptr += 4;
219                         endswitch = ptr + sizeof (guint32) * count;
220                         fprintf (output, "(\n");
221                         CODE_INDENT;
222                         for (n = 0; n < count; n++){
223                                 fprintf (output, "\t%sIL_%04x%s", indent, 
224                                         endswitch-start+read32 (ptr), 
225                                         n == count - 1 ? ")" : ",\n");
226                                 ptr += 4;
227                         }
228                         CODE_UNINDENT;
229                         break;
230                 }
231
232                 case MonoInlineTok: {
233                         guint32 token = read32 (ptr);
234                         char *s;
235                         
236                         s = get_token (m, token);
237                         fprintf (output, "%s", s);
238                         g_free (s);
239                         
240                         ptr += 4;
241                         break;
242                 }
243                 
244                 case MonoInlineType: {
245                         guint32 token = read32 (ptr);
246                         char *s = get_token_type (m, token);
247                         fprintf (output, "%s", s);
248                         g_free (s);
249                         ptr += 4;
250                         break;
251                 }
252
253                 case MonoInlineVar: {
254                         guint16 var_idx = read16 (ptr);
255
256                         fprintf (output, "%d\n", var_idx);
257                         ptr += 2;
258                         break;
259                 }
260
261                 case MonoShortInlineBrTarget: {
262                         signed char x = *ptr;
263                         
264                         fprintf (output, "IL_%04x\n", ptr - start + 1 + x);
265                         ptr++;
266                         break;
267                 }
268
269                 case MonoShortInlineI: {
270                         char x = *ptr;
271
272                         fprintf (output, "0x%02x", x);
273                         ptr++;
274                         break;
275                 }
276
277                 case MonoShortInlineR: {
278                         float f;
279                         readr4 (ptr, &f);
280
281                         fprintf (output, "%g", (double) f);
282                         ptr += 4;
283                         break;
284                 }
285
286                 case MonoShortInlineVar: {
287                         unsigned char x = *ptr;
288
289                         fprintf (output, "%d", (int) x);
290                         ptr++;
291                         break;
292                 }
293                 default:
294                         break;
295                 }
296
297                 fprintf (output, "\n");
298                 for (i = 0; i < mh->num_clauses; ++i) {
299                         if (ptr == start + mh->clauses[i].try_offset + mh->clauses[i].try_len && trys [i]) {
300                                 CODE_UNINDENT;
301                                 fprintf (output, "\t%s} // end .try %d\n", indent, i);
302                         }
303                         if (ptr == start + mh->clauses[i].handler_offset + mh->clauses[i].handler_len) {
304                                 CODE_UNINDENT;
305                                 fprintf (output, "\t%s} // end handler %d\n", indent, i);
306                                 if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
307                                         in_fault = 0;
308                         }
309                 }
310         }
311         if (trys)
312                 g_free (trys);
313 }