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