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