[docs] Update formatting in mono-api-methods.
[mono.git] / mono / metadata / debug-helpers.c
1 /**
2  * \file
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
7  * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
8  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9  */
10
11 #include <string.h>
12 #include "mono/metadata/tokentype.h"
13 #include "mono/metadata/opcodes.h"
14 #include "mono/metadata/metadata-internals.h"
15 #include "mono/metadata/class-internals.h"
16 #include "mono/metadata/object-internals.h"
17 #include "mono/metadata/mono-endian.h"
18 #include "mono/metadata/debug-helpers.h"
19 #include "mono/metadata/tabledefs.h"
20 #include "mono/metadata/appdomain.h"
21
22 struct MonoMethodDesc {
23         char *name_space;
24         char *klass;
25         char *name;
26         char *args;
27         guint num_args;
28         gboolean include_namespace, klass_glob, name_glob;
29 };
30
31 #ifdef HAVE_ARRAY_ELEM_INIT
32 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
33 #define MSGSTRFIELD1(line) str##line
34 static const struct msgstr_t {
35 #define WRAPPER(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
36 #include "wrapper-types.h"
37 #undef WRAPPER
38 } opstr = {
39 #define WRAPPER(a,b) b,
40 #include "wrapper-types.h"
41 #undef WRAPPER
42 };
43 static const gint16 opidx [] = {
44 #define WRAPPER(a,b) [MONO_WRAPPER_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
45 #include "wrapper-types.h"
46 #undef WRAPPER
47 };
48
49 static const char*
50 wrapper_type_to_str (guint32 wrapper_type)
51 {
52         g_assert (wrapper_type < MONO_WRAPPER_NUM);
53
54         return (const char*)&opstr + opidx [wrapper_type];
55 }
56
57 #else
58 #define WRAPPER(a,b) b,
59 static const char* const
60 wrapper_type_names [MONO_WRAPPER_NUM + 1] = {
61 #include "wrapper-types.h"
62         NULL
63 };
64
65 static const char*
66 wrapper_type_to_str (guint32 wrapper_type)
67 {
68         g_assert (wrapper_type < MONO_WRAPPER_NUM);
69
70         return wrapper_type_names [wrapper_type];
71 }
72
73 #endif
74
75 static void
76 append_class_name (GString *res, MonoClass *klass, gboolean include_namespace)
77 {
78         if (!klass) {
79                 g_string_append (res, "Unknown");
80                 return;
81         }
82         if (klass->nested_in) {
83                 append_class_name (res, klass->nested_in, include_namespace);
84                 g_string_append_c (res, '/');
85         }
86         if (include_namespace && *(klass->name_space)) {
87                 g_string_append (res, klass->name_space);
88                 g_string_append_c (res, '.');
89         }
90         g_string_append (res, klass->name);
91 }
92
93 static MonoClass*
94 find_system_class (const char *name)
95 {
96         if (!strcmp (name, "void")) 
97                 return mono_defaults.void_class;
98         else if (!strcmp (name, "char")) return mono_defaults.char_class;
99         else if (!strcmp (name, "bool")) return mono_defaults.boolean_class;
100         else if (!strcmp (name, "byte")) return mono_defaults.byte_class;
101         else if (!strcmp (name, "sbyte")) return mono_defaults.sbyte_class;
102         else if (!strcmp (name, "uint16")) return mono_defaults.uint16_class;
103         else if (!strcmp (name, "int16")) return mono_defaults.int16_class;
104         else if (!strcmp (name, "uint")) return mono_defaults.uint32_class;
105         else if (!strcmp (name, "int")) return mono_defaults.int32_class;
106         else if (!strcmp (name, "ulong")) return mono_defaults.uint64_class;
107         else if (!strcmp (name, "long")) return mono_defaults.int64_class;
108         else if (!strcmp (name, "uintptr")) return mono_defaults.uint_class;
109         else if (!strcmp (name, "intptr")) return mono_defaults.int_class;
110         else if (!strcmp (name, "single")) return mono_defaults.single_class;
111         else if (!strcmp (name, "double")) return mono_defaults.double_class;
112         else if (!strcmp (name, "string")) return mono_defaults.string_class;
113         else if (!strcmp (name, "object")) return mono_defaults.object_class;
114         else
115                 return NULL;
116 }
117
118 void
119 mono_type_get_desc (GString *res, MonoType *type, gboolean include_namespace)
120 {
121         int i;
122
123         switch (type->type) {
124         case MONO_TYPE_VOID:
125                 g_string_append (res, "void"); break;
126         case MONO_TYPE_CHAR:
127                 g_string_append (res, "char"); break;
128         case MONO_TYPE_BOOLEAN:
129                 g_string_append (res, "bool"); break;
130         case MONO_TYPE_U1:
131                 g_string_append (res, "byte"); break;
132         case MONO_TYPE_I1:
133                 g_string_append (res, "sbyte"); break;
134         case MONO_TYPE_U2:
135                 g_string_append (res, "uint16"); break;
136         case MONO_TYPE_I2:
137                 g_string_append (res, "int16"); break;
138         case MONO_TYPE_U4:
139                 g_string_append (res, "uint"); break;
140         case MONO_TYPE_I4:
141                 g_string_append (res, "int"); break;
142         case MONO_TYPE_U8:
143                 g_string_append (res, "ulong"); break;
144         case MONO_TYPE_I8:
145                 g_string_append (res, "long"); break;
146         case MONO_TYPE_FNPTR: /* who cares for the exact signature? */
147                 g_string_append (res, "*()"); break;
148         case MONO_TYPE_U:
149                 g_string_append (res, "uintptr"); break;
150         case MONO_TYPE_I:
151                 g_string_append (res, "intptr"); break;
152         case MONO_TYPE_R4:
153                 g_string_append (res, "single"); break;
154         case MONO_TYPE_R8:
155                 g_string_append (res, "double"); break;
156         case MONO_TYPE_STRING:
157                 g_string_append (res, "string"); break;
158         case MONO_TYPE_OBJECT:
159                 g_string_append (res, "object"); break;
160         case MONO_TYPE_PTR:
161                 mono_type_get_desc (res, type->data.type, include_namespace);
162                 g_string_append_c (res, '*');
163                 break;
164         case MONO_TYPE_ARRAY:
165                 mono_type_get_desc (res, &type->data.array->eklass->byval_arg, include_namespace);
166                 g_string_append_c (res, '[');
167                 for (i = 1; i < type->data.array->rank; ++i)
168                         g_string_append_c (res, ',');
169                 g_string_append_c (res, ']');
170                 break;
171         case MONO_TYPE_SZARRAY:
172                 mono_type_get_desc (res, &type->data.klass->byval_arg, include_namespace);
173                 g_string_append (res, "[]");
174                 break;
175         case MONO_TYPE_CLASS:
176         case MONO_TYPE_VALUETYPE:
177                 append_class_name (res, type->data.klass, include_namespace);
178                 break;
179         case MONO_TYPE_GENERICINST: {
180                 MonoGenericContext *context;
181
182                 mono_type_get_desc (res, &type->data.generic_class->container_class->byval_arg, include_namespace);
183                 g_string_append (res, "<");
184                 context = &type->data.generic_class->context;
185                 if (context->class_inst) {
186                         for (i = 0; i < context->class_inst->type_argc; ++i) {
187                                 if (i > 0)
188                                         g_string_append (res, ", ");
189                                 mono_type_get_desc (res, context->class_inst->type_argv [i], include_namespace);
190                         }
191                 }
192                 if (context->method_inst) {
193                         if (context->class_inst)
194                                         g_string_append (res, "; ");
195                         for (i = 0; i < context->method_inst->type_argc; ++i) {
196                                 if (i > 0)
197                                         g_string_append (res, ", ");
198                                 mono_type_get_desc (res, context->method_inst->type_argv [i], include_namespace);
199                         }
200                 }
201                 g_string_append (res, ">");
202                 break;
203         }
204         case MONO_TYPE_VAR:
205         case MONO_TYPE_MVAR:
206                 if (type->data.generic_param) {
207                         const char *name = mono_generic_param_name (type->data.generic_param);
208                         if (name)
209                                 g_string_append (res, name);
210                         else
211                                 g_string_append_printf (res, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", mono_generic_param_num (type->data.generic_param));
212                 } else {
213                         g_string_append (res, "<unknown>");
214                 }
215                 break;
216         case MONO_TYPE_TYPEDBYREF:
217                 g_string_append (res, "typedbyref");
218                 break;
219         default:
220                 break;
221         }
222         if (type->byref)
223                 g_string_append_c (res, '&');
224 }
225
226 char*
227 mono_type_full_name (MonoType *type)
228 {
229         GString *str;
230
231         str = g_string_new ("");
232         mono_type_get_desc (str, type, TRUE);
233         return g_string_free (str, FALSE);
234 }
235
236 /**
237  * mono_signature_get_desc:
238  */
239 char*
240 mono_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
241 {
242         int i;
243         char *result;
244         GString *res;
245
246         if (!sig)
247                 return g_strdup ("<invalid signature>");
248
249         res = g_string_new ("");
250
251         for (i = 0; i < sig->param_count; ++i) {
252                 if (i > 0)
253                         g_string_append_c (res, ',');
254                 mono_type_get_desc (res, sig->params [i], include_namespace);
255         }
256         result = res->str;
257         g_string_free (res, FALSE);
258         return result;
259 }
260
261 char*
262 mono_signature_full_name (MonoMethodSignature *sig)
263 {
264         int i;
265         char *result;
266         GString *res;
267
268         if (!sig)
269                 return g_strdup ("<invalid signature>");
270
271         res = g_string_new ("");
272
273         mono_type_get_desc (res, sig->ret, TRUE);
274         g_string_append_c (res, '(');
275         for (i = 0; i < sig->param_count; ++i) {
276                 if (i > 0)
277                         g_string_append_c (res, ',');
278                 mono_type_get_desc (res, sig->params [i], TRUE);
279         }
280         g_string_append_c (res, ')');
281         result = res->str;
282         g_string_free (res, FALSE);
283         return result;
284 }
285
286 void
287 mono_ginst_get_desc (GString *str, MonoGenericInst *ginst)
288 {
289         int i;
290
291         for (i = 0; i < ginst->type_argc; ++i) {
292                 if (i > 0)
293                         g_string_append (str, ", ");
294                 mono_type_get_desc (str, ginst->type_argv [i], TRUE);
295         }
296 }
297
298 char*
299 mono_context_get_desc (MonoGenericContext *context)
300 {
301         GString *str;
302         char *res;
303
304         str = g_string_new ("");
305         g_string_append (str, "<");
306
307         if (context->class_inst)
308                 mono_ginst_get_desc (str, context->class_inst);
309         if (context->method_inst) {
310                 if (context->class_inst)
311                         g_string_append (str, "; ");
312                 mono_ginst_get_desc (str, context->method_inst);
313         }
314
315         g_string_append (str, ">");
316         res = g_strdup (str->str);
317         g_string_free (str, TRUE);
318         return res;
319 }       
320
321 /**
322  * mono_method_desc_new:
323  * \param name the method name.
324  * \param include_namespace whether the name includes a namespace or not.
325  *
326  * Creates a method description for \p name, which conforms to the following
327  * specification:
328  *
329  * <code>[namespace.]classname:methodname[(args...)]</code>
330  *
331  * in all the loaded assemblies.
332  *
333  * Both classname and methodname can contain <code>*</code> which matches anything.
334  *
335  * \returns a parsed representation of the method description.
336  */
337 MonoMethodDesc*
338 mono_method_desc_new (const char *name, gboolean include_namespace)
339 {
340         MonoMethodDesc *result;
341         char *class_name, *class_nspace, *method_name, *use_args, *end;
342         int use_namespace;
343         int generic_delim_stack;
344         
345         class_nspace = g_strdup (name);
346         use_args = strchr (class_nspace, '(');
347         if (use_args) {
348                 /* Allow a ' ' between the method name and the signature */
349                 if (use_args > class_nspace && use_args [-1] == ' ')
350                         use_args [-1] = 0;
351                 *use_args++ = 0;
352                 end = strchr (use_args, ')');
353                 if (!end) {
354                         g_free (class_nspace);
355                         return NULL;
356                 }
357                 *end = 0;
358         }
359         method_name = strrchr (class_nspace, ':');
360         if (!method_name) {
361                 g_free (class_nspace);
362                 return NULL;
363         }
364         /* allow two :: to separate the method name */
365         if (method_name != class_nspace && method_name [-1] == ':')
366                 method_name [-1] = 0;
367         *method_name++ = 0;
368         class_name = strrchr (class_nspace, '.');
369         if (class_name) {
370                 *class_name++ = 0;
371                 use_namespace = 1;
372         } else {
373                 class_name = class_nspace;
374                 use_namespace = 0;
375         }
376         result = g_new0 (MonoMethodDesc, 1);
377         result->include_namespace = include_namespace;
378         result->name = method_name;
379         result->klass = class_name;
380         result->name_space = use_namespace? class_nspace: NULL;
381         result->args = use_args? use_args: NULL;
382         if (strstr (result->name, "*"))
383                 result->name_glob = TRUE;
384         if (strstr (result->klass, "*"))
385                 result->klass_glob = TRUE;
386         if (use_args) {
387                 end = use_args;
388                 if (*end)
389                         result->num_args = 1;
390                 generic_delim_stack = 0;
391                 while (*end) {
392                         if (*end == '<')
393                                 generic_delim_stack++;
394                         else if (*end == '>')
395                                 generic_delim_stack--;
396
397                         if (*end == ',' && generic_delim_stack == 0)
398                                 result->num_args++;
399                         ++end;
400                 }
401         }
402
403         return result;
404 }
405
406 /**
407  * mono_method_desc_from_method:
408  */
409 MonoMethodDesc*
410 mono_method_desc_from_method (MonoMethod *method)
411 {
412         MonoMethodDesc *result;
413         
414         result = g_new0 (MonoMethodDesc, 1);
415         result->include_namespace = TRUE;
416         result->name = g_strdup (method->name);
417         result->klass = g_strdup (method->klass->name);
418         result->name_space = g_strdup (method->klass->name_space);
419
420         return result;
421 }
422
423 /**
424  * mono_method_desc_free:
425  * \param desc method description to be released
426  * Releases the \c MonoMethodDesc object \p desc.
427  */
428 void
429 mono_method_desc_free (MonoMethodDesc *desc)
430 {
431         if (desc->name_space)
432                 g_free (desc->name_space);
433         else if (desc->klass)
434                 g_free (desc->klass);
435         g_free (desc);
436 }
437
438 /**
439  * mono_method_desc_match:
440  * \param desc \c MonoMethoDescription
441  * \param method \c MonoMethod to test
442  *
443  * Determines whether the specified \p method matches the provided \p desc description.
444  *
445  * namespace and class are supposed to match already if this function is used.
446  * \returns TRUE if the method matches the description, FALSE otherwise.
447  */
448 gboolean
449 mono_method_desc_match (MonoMethodDesc *desc, MonoMethod *method)
450 {
451         char *sig;
452         gboolean name_match;
453
454         name_match = strcmp (desc->name, method->name) == 0;
455         if (!name_match)
456                 return FALSE;
457         if (!desc->args)
458                 return TRUE;
459         if (desc->num_args != mono_method_signature (method)->param_count)
460                 return FALSE;
461         sig = mono_signature_get_desc (mono_method_signature (method), desc->include_namespace);
462         if (strcmp (sig, desc->args)) {
463                 g_free (sig);
464                 return FALSE;
465         }
466         g_free (sig);
467         return TRUE;
468 }
469
470 static const char *
471 my_strrchr (const char *str, char ch, int *len)
472 {
473         int pos;
474
475         for (pos = (*len)-1; pos >= 0; pos--) {
476                 if (str [pos] != ch)
477                         continue;
478
479                 *len = pos;
480                 return str + pos;
481         }
482
483         return NULL;
484 }
485
486 static gboolean
487 match_class (MonoMethodDesc *desc, int pos, MonoClass *klass)
488 {
489         const char *p;
490
491         if (desc->klass_glob && !strcmp (desc->klass, "*"))
492                 return TRUE;
493 #ifndef _EGLIB_MAJOR
494         if (desc->klass_glob && g_pattern_match_simple (desc->klass, klass->name))
495                 return TRUE;
496 #endif
497         p = my_strrchr (desc->klass, '/', &pos);
498         if (!p) {
499                 if (strncmp (desc->klass, klass->name, pos))
500                         return FALSE;
501                 if (desc->name_space && strcmp (desc->name_space, klass->name_space))
502                         return FALSE;
503                 return TRUE;
504         }
505
506         if (strcmp (p+1, klass->name))
507                 return FALSE;
508         if (!klass->nested_in)
509                 return FALSE;
510
511         return match_class (desc, pos, klass->nested_in);
512 }
513
514 /**
515  * mono_method_desc_full_match:
516  */
517 gboolean
518 mono_method_desc_full_match (MonoMethodDesc *desc, MonoMethod *method)
519 {
520         if (!desc->klass)
521                 return FALSE;
522         if (!match_class (desc, strlen (desc->klass), method->klass))
523                 return FALSE;
524
525         return mono_method_desc_match (desc, method);
526 }
527
528 /**
529  * mono_method_desc_search_in_class:
530  */
531 MonoMethod*
532 mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass)
533 {
534         MonoMethod* m;
535         gpointer iter = NULL;
536         
537         while ((m = mono_class_get_methods (klass, &iter)))
538                 if (mono_method_desc_match (desc, m))
539                         return m;
540         return NULL;
541 }
542
543 /**
544  * mono_method_desc_search_in_image:
545  */
546 MonoMethod*
547 mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image)
548 {
549         MonoClass *klass;
550         const MonoTableInfo *methods;
551         MonoMethod *method;
552         int i;
553
554         /* Handle short names for system classes */
555         if (!desc->name_space && image == mono_defaults.corlib) {
556                 klass = find_system_class (desc->klass);
557                 if (klass)
558                         return mono_method_desc_search_in_class (desc, klass);
559         }
560
561         if (desc->name_space && desc->klass) {
562                 klass = mono_class_try_load_from_name (image, desc->name_space, desc->klass);
563                 if (!klass)
564                         return NULL;
565                 return mono_method_desc_search_in_class (desc, klass);
566         }
567
568         /* FIXME: Is this call necessary?  We don't use its result. */
569         mono_image_get_table_info (image, MONO_TABLE_TYPEDEF);
570         methods = mono_image_get_table_info (image, MONO_TABLE_METHOD);
571         for (i = 0; i < mono_table_info_get_rows (methods); ++i) {
572                 MonoError error;
573                 guint32 token = mono_metadata_decode_row_col (methods, i, MONO_METHOD_NAME);
574                 const char *n = mono_metadata_string_heap (image, token);
575
576                 if (strcmp (n, desc->name))
577                         continue;
578                 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
579                 if (!method) {
580                         mono_error_cleanup (&error);
581                         continue;
582                 }
583                 if (mono_method_desc_full_match (desc, method))
584                         return method;
585         }
586         return NULL;
587 }
588
589 static const unsigned char*
590 dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned char *ip, const unsigned char *end)
591 {
592         MonoError error;
593         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
594         const MonoOpcode *opcode;
595         guint32 label, token;
596         gint32 sval;
597         int i;
598         char *tmp;
599         const unsigned char* il_code;
600
601         if (!header) {
602                 g_string_append_printf (str, "could not disassemble, bad header due to %s", mono_error_get_message (&error));
603                 mono_error_cleanup (&error);
604                 return end;
605         }
606         il_code = mono_method_header_get_code (header, NULL, NULL);
607
608         label = ip - il_code;
609         if (dh->indenter) {
610                 tmp = dh->indenter (dh, method, label);
611                 g_string_append (str, tmp);
612                 g_free (tmp);
613         }
614         if (dh->label_format)
615                 g_string_append_printf (str, dh->label_format, label);
616         
617         i = mono_opcode_value (&ip, end);
618         ip++;
619         opcode = &mono_opcodes [i];
620         g_string_append_printf (str, "%-10s", mono_opcode_name (i));
621
622         switch (opcode->argument) {
623         case MonoInlineNone:
624                 break;
625         case MonoInlineType:
626         case MonoInlineField:
627         case MonoInlineMethod:
628         case MonoInlineTok:
629         case MonoInlineSig:
630                 token = read32 (ip);
631                 if (dh->tokener) {
632                         tmp = dh->tokener (dh, method, token);
633                         g_string_append (str, tmp);
634                         g_free (tmp);
635                 } else {
636                         g_string_append_printf (str, "0x%08x", token);
637                 }
638                 ip += 4;
639                 break;
640         case MonoInlineString: {
641                 const char *blob;
642                 char *s;
643                 size_t len2;
644                 char *blob2 = NULL;
645
646                 if (!image_is_dynamic (method->klass->image) && !method_is_dynamic (method)) {
647                         token = read32 (ip);
648                         blob = mono_metadata_user_string (method->klass->image, mono_metadata_token_index (token));
649
650                         len2 = mono_metadata_decode_blob_size (blob, &blob);
651                         len2 >>= 1;
652
653 #ifdef NO_UNALIGNED_ACCESS
654                         /* The blob might not be 2 byte aligned */
655                         blob2 = g_malloc ((len2 * 2) + 1);
656                         memcpy (blob2, blob, len2 * 2);
657 #else
658                         blob2 = (char*)blob;
659 #endif
660
661 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
662                         {
663                                 guint16 *buf = g_new (guint16, len2 + 1);
664                                 int i;
665
666                                 for (i = 0; i < len2; ++i)
667                                         buf [i] = GUINT16_FROM_LE (((guint16*)blob2) [i]);
668                                 s = g_utf16_to_utf8 (buf, len2, NULL, NULL, NULL);
669                                 g_free (buf);
670                         }
671 #else
672                                 s = g_utf16_to_utf8 ((gunichar2*)blob2, len2, NULL, NULL, NULL);
673 #endif
674
675                         g_string_append_printf (str, "\"%s\"", s);
676                         g_free (s);
677                         if (blob != blob2)
678                                 g_free (blob2);
679                 }
680                 ip += 4;
681                 break;
682         }
683         case MonoInlineVar:
684                 g_string_append_printf (str, "%d", read16 (ip));
685                 ip += 2;
686                 break;
687         case MonoShortInlineVar:
688                 g_string_append_printf (str, "%d", (*ip));
689                 ip ++;
690                 break;
691         case MonoInlineBrTarget:
692                 sval = read32 (ip);
693                 ip += 4;
694                 if (dh->label_target)
695                         g_string_append_printf (str, dh->label_target, ip + sval - il_code);
696                 else
697                         g_string_append_printf (str, "%d", sval);
698                 break;
699         case MonoShortInlineBrTarget:
700                 sval = *(const signed char*)ip;
701                 ip ++;
702                 if (dh->label_target)
703                         g_string_append_printf (str, dh->label_target, ip + sval - il_code);
704                 else
705                         g_string_append_printf (str, "%d", sval);
706                 break;
707         case MonoInlineSwitch: {
708                 const unsigned char *end;
709                 sval = read32 (ip);
710                 ip += 4;
711                 end = ip + sval * 4;
712                 g_string_append_c (str, '(');
713                 for (i = 0; i < sval; ++i) {
714                         if (i > 0)
715                                 g_string_append (str, ", ");
716                         label = read32 (ip);
717                         if (dh->label_target)
718                                 g_string_append_printf (str, dh->label_target, end + label - il_code);
719                         else
720                                 g_string_append_printf (str, "%d", label);
721                         ip += 4;
722                 }
723                 g_string_append_c (str, ')');
724                 break;
725         }
726         case MonoInlineR: {
727                 double r;
728                 readr8 (ip, &r);
729                 g_string_append_printf (str, "%g", r);
730                 ip += 8;
731                 break;
732         }
733         case MonoShortInlineR: {
734                 float r;
735                 readr4 (ip, &r);
736                 g_string_append_printf (str, "%g", r);
737                 ip += 4;
738                 break;
739         }
740         case MonoInlineI:
741                 g_string_append_printf (str, "%d", (gint32)read32 (ip));
742                 ip += 4;
743                 break;
744         case MonoShortInlineI:
745                 g_string_append_printf (str, "%d", *(const signed char*)ip);
746                 ip ++;
747                 break;
748         case MonoInlineI8:
749                 ip += 8;
750                 break;
751         default:
752                 g_assert_not_reached ();
753         }
754         if (dh->newline)
755                 g_string_append (str, dh->newline);
756
757         mono_metadata_free_mh (header);
758         return ip;
759 }
760
761 static MonoDisHelper
762 default_dh = {
763         "\n",
764         "IL_%04x: ", /* label_format */
765         "IL_%04x", /* label_target */
766         NULL, /* indenter */
767         NULL, /* tokener */
768         NULL  /* user data */
769 };
770
771 char*
772 mono_disasm_code_one (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const guchar **endp)
773 {
774         char *result;
775         GString *res = g_string_new ("");
776
777         if (!dh)
778                 dh = &default_dh;
779         /* set ip + 2 as the end: this is just a debugging method */
780         ip = dis_one (res, dh, method, ip, ip + 2);
781         if (endp)
782                 *endp = ip;
783         
784         result = res->str;
785         g_string_free (res, FALSE);
786         return result;
787 }
788
789 char*
790 mono_disasm_code (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const guchar* end)
791 {
792         char *result;
793         GString *res = g_string_new ("");
794
795         if (!dh)
796                 dh = &default_dh;
797         while (ip < end) {
798                 ip = dis_one (res, dh, method, ip, end);
799         }
800         
801         result = res->str;
802         g_string_free (res, FALSE);
803         return result;
804 }
805
806 /**
807  * mono_field_full_name:
808  * \param field field to retrieve information for
809  * \returns the full name for the field, made up of the namespace, type name and the field name.
810  */
811 char *
812 mono_field_full_name (MonoClassField *field)
813 {
814         char *res;
815         const char *nspace = field->parent->name_space;
816
817         res = g_strdup_printf ("%s%s%s:%s", nspace, *nspace ? "." : "",
818                                                    field->parent->name, mono_field_get_name (field));
819
820         return res;
821 }
822
823 char *
824 mono_method_get_name_full (MonoMethod *method, gboolean signature, gboolean ret, MonoTypeNameFormat format)
825 {
826         char *res;
827         char wrapper [64];
828         char *klass_desc;
829         char *inst_desc = NULL;
830         MonoError error;
831
832         if (format == MONO_TYPE_NAME_FORMAT_IL)
833                 klass_desc = mono_type_full_name (&method->klass->byval_arg);
834         else
835                 klass_desc = mono_type_get_name_full (&method->klass->byval_arg, format);
836
837         if (method->is_inflated && ((MonoMethodInflated*)method)->context.method_inst) {
838                 GString *str = g_string_new ("");
839                 if (format == MONO_TYPE_NAME_FORMAT_IL)
840                         g_string_append (str, "<");
841                 else
842                         g_string_append (str, "[");
843                 mono_ginst_get_desc (str, ((MonoMethodInflated*)method)->context.method_inst);
844                 if (format == MONO_TYPE_NAME_FORMAT_IL)
845                         g_string_append_c (str, '>');
846                 else
847                         g_string_append_c (str, ']');
848
849                 inst_desc = str->str;
850                 g_string_free (str, FALSE);
851         } else if (method->is_generic) {
852                 MonoGenericContainer *container = mono_method_get_generic_container (method);
853
854                 GString *str = g_string_new ("");
855                 if (format == MONO_TYPE_NAME_FORMAT_IL)
856                         g_string_append (str, "<");
857                 else
858                         g_string_append (str, "[");
859                 mono_ginst_get_desc (str, container->context.method_inst);
860                 if (format == MONO_TYPE_NAME_FORMAT_IL)
861                         g_string_append_c (str, '>');
862                 else
863                         g_string_append_c (str, ']');
864
865                 inst_desc = str->str;
866                 g_string_free (str, FALSE);
867         }
868
869         if (method->wrapper_type != MONO_WRAPPER_NONE)
870                 sprintf (wrapper, "(wrapper %s) ", wrapper_type_to_str (method->wrapper_type));
871         else
872                 strcpy (wrapper, "");
873
874         if (signature) {
875                 MonoMethodSignature *sig = mono_method_signature_checked (method, &error);
876                 char *tmpsig;
877
878                 if (!is_ok (&error)) {
879                         tmpsig = g_strdup_printf ("<unable to load signature>");
880                         mono_error_cleanup (&error);
881                 } else {
882                         tmpsig = mono_signature_get_desc (sig, TRUE);
883                 }
884
885                 if (method->wrapper_type != MONO_WRAPPER_NONE)
886                         sprintf (wrapper, "(wrapper %s) ", wrapper_type_to_str (method->wrapper_type));
887                 else
888                         strcpy (wrapper, "");
889                 if (ret && sig) {
890                         char *ret_str = mono_type_full_name (sig->ret);
891                         res = g_strdup_printf ("%s%s %s:%s%s (%s)", wrapper, ret_str, klass_desc,
892                                                                    method->name, inst_desc ? inst_desc : "", tmpsig);
893                         g_free (ret_str);
894                 } else {
895                         res = g_strdup_printf ("%s%s:%s%s (%s)", wrapper, klass_desc,
896                                                                    method->name, inst_desc ? inst_desc : "", tmpsig);
897                 }
898                 g_free (tmpsig);
899         } else {
900                 res = g_strdup_printf ("%s%s:%s%s", wrapper, klass_desc,
901                                                            method->name, inst_desc ? inst_desc : "");
902         }
903
904         g_free (klass_desc);
905         g_free (inst_desc);
906
907         return res;
908 }
909
910 /**
911  * mono_method_full_name:
912  */
913 char *
914 mono_method_full_name (MonoMethod *method, gboolean signature)
915 {
916         return mono_method_get_name_full (method, signature, FALSE, MONO_TYPE_NAME_FORMAT_IL);
917 }
918
919 char *
920 mono_method_get_full_name (MonoMethod *method)
921 {
922         return mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL);
923 }
924
925 static const char*
926 print_name_space (MonoClass *klass)
927 {
928         if (klass->nested_in) {
929                 print_name_space (klass->nested_in);
930                 g_print ("%s", klass->nested_in->name);
931                 return "/";
932         }
933         if (klass->name_space [0]) {
934                 g_print ("%s", klass->name_space);
935                 return ".";
936         }
937         return "";
938 }
939
940 /**
941  * mono_object_describe:
942  *
943  * Prints to stdout a small description of the object \p obj.
944  * For use in a debugger.
945  */
946 void
947 mono_object_describe (MonoObject *obj)
948 {
949         MonoError error;
950         MonoClass* klass;
951         const char* sep;
952         if (!obj) {
953                 g_print ("(null)\n");
954                 return;
955         }
956         klass = mono_object_class (obj);
957         if (klass == mono_defaults.string_class) {
958                 char *utf8 = mono_string_to_utf8_checked ((MonoString*)obj, &error);
959                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
960                 if (utf8 && strlen (utf8) > 60) {
961                         utf8 [57] = '.';
962                         utf8 [58] = '.';
963                         utf8 [59] = '.';
964                         utf8 [60] = 0;
965                 }
966                 if (utf8) {
967                         g_print ("String at %p, length: %d, '%s'\n", obj, mono_string_length ((MonoString*) obj), utf8);
968                 } else {
969                         g_print ("String at %p, length: %d, unable to decode UTF16\n", obj, mono_string_length ((MonoString*) obj));
970                 }
971                 g_free (utf8);
972         } else if (klass->rank) {
973                 MonoArray *array = (MonoArray*)obj;
974                 sep = print_name_space (klass);
975                 g_print ("%s%s", sep, klass->name);
976                 g_print (" at %p, rank: %d, length: %d\n", obj, klass->rank, (int)mono_array_length (array));
977         } else {
978                 sep = print_name_space (klass);
979                 g_print ("%s%s", sep, klass->name);
980                 g_print (" object at %p (klass: %p)\n", obj, klass);
981         }
982
983 }
984
985 static void
986 print_field_value (const char *field_ptr, MonoClassField *field, int type_offset)
987 {
988         MonoType *type;
989         g_print ("At %p (ofs: %2d) %s: ", field_ptr, field->offset + type_offset, mono_field_get_name (field));
990         type = mono_type_get_underlying_type (field->type);
991
992         switch (type->type) {
993         case MONO_TYPE_I:
994         case MONO_TYPE_U:
995         case MONO_TYPE_PTR:
996         case MONO_TYPE_FNPTR:
997                 g_print ("%p\n", *(const void**)field_ptr);
998                 break;
999         case MONO_TYPE_STRING:
1000         case MONO_TYPE_SZARRAY:
1001         case MONO_TYPE_CLASS:
1002         case MONO_TYPE_OBJECT:
1003         case MONO_TYPE_ARRAY:
1004                 mono_object_describe (*(MonoObject**)field_ptr);
1005                 break;
1006         case MONO_TYPE_GENERICINST:
1007                 if (!mono_type_generic_inst_is_valuetype (type)) {
1008                         mono_object_describe (*(MonoObject**)field_ptr);
1009                         break;
1010                 } else {
1011                         /* fall through */
1012                 }
1013         case MONO_TYPE_VALUETYPE: {
1014                 MonoClass *k = mono_class_from_mono_type (type);
1015                 g_print ("%s ValueType (type: %p) at %p\n", k->name, k, field_ptr);
1016                 break;
1017         }
1018         case MONO_TYPE_I1:
1019                 g_print ("%d\n", *(gint8*)field_ptr);
1020                 break;
1021         case MONO_TYPE_U1:
1022                 g_print ("%d\n", *(guint8*)field_ptr);
1023                 break;
1024         case MONO_TYPE_I2:
1025                 g_print ("%d\n", *(gint16*)field_ptr);
1026                 break;
1027         case MONO_TYPE_U2:
1028                 g_print ("%d\n", *(guint16*)field_ptr);
1029                 break;
1030         case MONO_TYPE_I4:
1031                 g_print ("%d\n", *(gint32*)field_ptr);
1032                 break;
1033         case MONO_TYPE_U4:
1034                 g_print ("%u\n", *(guint32*)field_ptr);
1035                 break;
1036         case MONO_TYPE_I8:
1037                 g_print ("%lld\n", (long long int)*(gint64*)field_ptr);
1038                 break;
1039         case MONO_TYPE_U8:
1040                 g_print ("%llu\n", (long long unsigned int)*(guint64*)field_ptr);
1041                 break;
1042         case MONO_TYPE_R4:
1043                 g_print ("%f\n", *(gfloat*)field_ptr);
1044                 break;
1045         case MONO_TYPE_R8:
1046                 g_print ("%f\n", *(gdouble*)field_ptr);
1047                 break;
1048         case MONO_TYPE_BOOLEAN:
1049                 g_print ("%s (%d)\n", *(guint8*)field_ptr? "True": "False", *(guint8*)field_ptr);
1050                 break;
1051         case MONO_TYPE_CHAR:
1052                 g_print ("'%c' (%d 0x%04x)\n", *(guint16*)field_ptr, *(guint16*)field_ptr, *(guint16*)field_ptr);
1053                 break;
1054         default:
1055                 g_assert_not_reached ();
1056                 break;
1057         }
1058 }
1059
1060 static void
1061 objval_describe (MonoClass *klass, const char *addr)
1062 {
1063         MonoClassField *field;
1064         MonoClass *p;
1065         const char *field_ptr;
1066         gssize type_offset = 0;
1067
1068         if (klass->valuetype)
1069                 type_offset = -sizeof (MonoObject);
1070
1071         for (p = klass; p != NULL; p = p->parent) {
1072                 gpointer iter = NULL;
1073                 int printed_header = FALSE;
1074                 while ((field = mono_class_get_fields (p, &iter))) {
1075                         if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
1076                                 continue;
1077
1078                         if (p != klass && !printed_header) {
1079                                 const char *sep;
1080                                 g_print ("In class ");
1081                                 sep = print_name_space (p);
1082                                 g_print ("%s%s:\n", sep, p->name);
1083                                 printed_header = TRUE;
1084                         }
1085                         field_ptr = (const char*)addr + field->offset + type_offset;
1086
1087                         print_field_value (field_ptr, field, type_offset);
1088                 }
1089         }
1090 }
1091
1092 /**
1093  * mono_object_describe_fields:
1094  *
1095  * Prints to stdout a small description of each field of the object \p obj.
1096  * For use in a debugger.
1097  */
1098 void
1099 mono_object_describe_fields (MonoObject *obj)
1100 {
1101         MonoClass *klass = mono_object_class (obj);
1102         objval_describe (klass, (char*)obj);
1103 }
1104
1105 /**
1106  * mono_value_describe_fields:
1107  *
1108  * Prints to stdout a small description of each field of the value type
1109  * stored at \p addr of type \p klass.
1110  * For use in a debugger.
1111  */
1112 void
1113 mono_value_describe_fields (MonoClass* klass, const char* addr)
1114 {
1115         objval_describe (klass, addr);
1116 }
1117
1118 /**
1119  * mono_class_describe_statics:
1120  *
1121  * Prints to stdout a small description of each static field of the type \p klass
1122  * in the current application domain.
1123  * For use in a debugger.
1124  */
1125 void
1126 mono_class_describe_statics (MonoClass* klass)
1127 {
1128         MonoError error;
1129         MonoClassField *field;
1130         MonoClass *p;
1131         const char *field_ptr;
1132         MonoVTable *vtable = mono_class_vtable_full (mono_domain_get (), klass, &error);
1133         const char *addr;
1134
1135         if (!vtable || !is_ok (&error)) {
1136                 mono_error_cleanup (&error);
1137                 return;
1138         }
1139
1140         if (!(addr = (const char *)mono_vtable_get_static_field_data (vtable)))
1141                 return;
1142
1143         for (p = klass; p != NULL; p = p->parent) {
1144                 gpointer iter = NULL;
1145                 while ((field = mono_class_get_fields (p, &iter))) {
1146                         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
1147                                 continue;
1148                         if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
1149                                 continue;
1150
1151                         field_ptr = (const char*)addr + field->offset;
1152
1153                         print_field_value (field_ptr, field, 0);
1154                 }
1155         }
1156 }
1157
1158 /**
1159  * mono_print_method_code
1160  * \param method: a pointer to the method
1161  *
1162  * This method is used from a debugger to print the code of the method.
1163  *
1164  * This prints the IL code of the method in the standard output.
1165  */
1166 void
1167 mono_method_print_code (MonoMethod *method)
1168 {
1169         MonoError error;
1170         char *code;
1171         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
1172         if (!header) {
1173                 printf ("METHOD HEADER NOT FOUND DUE TO: %s\n", mono_error_get_message (&error));
1174                 mono_error_cleanup (&error);
1175                 return;
1176         }
1177         code = mono_disasm_code (0, method, header->code, header->code + header->code_size);
1178         printf ("CODE FOR %s:\n%s\n", mono_method_full_name (method, TRUE), code);
1179         g_free (code);
1180 }