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