Reduce TLS accesses. (#11487)
[mono-project.git] / mono / metadata / debug-helpers.c
blobbe995b490aa5e5ba1fe47f4840169489c7c65d35
1 /**
2 * \file
4 * Author:
5 * Mono Project (http://www.mono-project.com)
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 */
11 #include <config.h>
12 #include <string.h>
13 #include "mono/metadata/tokentype.h"
14 #include "mono/metadata/opcodes.h"
15 #include "mono/metadata/metadata-internals.h"
16 #include "mono/metadata/class-internals.h"
17 #include "mono/metadata/object-internals.h"
18 #include "mono/metadata/mono-endian.h"
19 #include "mono/metadata/debug-helpers.h"
20 #include "mono/metadata/tabledefs.h"
21 #include "mono/metadata/appdomain.h"
22 #include "mono/metadata/abi-details.h"
23 #ifdef MONO_CLASS_DEF_PRIVATE
24 /* Rationale: we want the functions in this file to work even when everything
25 * is broken. They may be called from a debugger session, for example. If
26 * MonoClass getters include assertions or trigger class loading, we don't want
27 * that kicked off by a call to one of the functions in here.
29 #define REALLY_INCLUDE_CLASS_DEF 1
30 #include <mono/metadata/class-private-definition.h>
31 #undef REALLY_INCLUDE_CLASS_DEF
32 #endif
35 struct MonoMethodDesc {
36 char *name_space;
37 char *klass;
38 char *name;
39 char *args;
40 guint num_args;
41 gboolean include_namespace, klass_glob, name_glob;
44 // This, instead of an array of pointers, to optimize away a pointer and a relocation per string.
45 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
46 #define MSGSTRFIELD1(line) str##line
47 static const struct msgstr_t {
48 #define WRAPPER(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
49 #include "wrapper-types.h"
50 #undef WRAPPER
51 } opstr = {
52 #define WRAPPER(a,b) b,
53 #include "wrapper-types.h"
54 #undef WRAPPER
56 static const gint16 opidx [] = {
57 #define WRAPPER(a,b) offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
58 #include "wrapper-types.h"
59 #undef WRAPPER
62 const char*
63 mono_wrapper_type_to_str (guint32 wrapper_type)
65 g_assert (wrapper_type < MONO_WRAPPER_NUM);
67 return (const char*)&opstr + opidx [wrapper_type];
70 static void
71 append_class_name (GString *res, MonoClass *klass, gboolean include_namespace)
73 if (!klass) {
74 g_string_append (res, "Unknown");
75 return;
77 if (klass->nested_in) {
78 append_class_name (res, klass->nested_in, include_namespace);
79 g_string_append_c (res, '/');
81 if (include_namespace && *(klass->name_space)) {
82 g_string_append (res, klass->name_space);
83 g_string_append_c (res, '.');
85 g_string_append (res, klass->name);
88 static MonoClass*
89 find_system_class (const char *name)
91 if (!strcmp (name, "void"))
92 return mono_defaults.void_class;
93 else if (!strcmp (name, "char")) return mono_defaults.char_class;
94 else if (!strcmp (name, "bool")) return mono_defaults.boolean_class;
95 else if (!strcmp (name, "byte")) return mono_defaults.byte_class;
96 else if (!strcmp (name, "sbyte")) return mono_defaults.sbyte_class;
97 else if (!strcmp (name, "uint16")) return mono_defaults.uint16_class;
98 else if (!strcmp (name, "int16")) return mono_defaults.int16_class;
99 else if (!strcmp (name, "uint")) return mono_defaults.uint32_class;
100 else if (!strcmp (name, "int")) return mono_defaults.int32_class;
101 else if (!strcmp (name, "ulong")) return mono_defaults.uint64_class;
102 else if (!strcmp (name, "long")) return mono_defaults.int64_class;
103 else if (!strcmp (name, "uintptr")) return mono_defaults.uint_class;
104 else if (!strcmp (name, "intptr")) return mono_defaults.int_class;
105 else if (!strcmp (name, "single")) return mono_defaults.single_class;
106 else if (!strcmp (name, "double")) return mono_defaults.double_class;
107 else if (!strcmp (name, "string")) return mono_defaults.string_class;
108 else if (!strcmp (name, "object")) return mono_defaults.object_class;
109 else
110 return NULL;
113 void
114 mono_type_get_desc (GString *res, MonoType *type, gboolean include_namespace)
116 int i;
118 switch (type->type) {
119 case MONO_TYPE_VOID:
120 g_string_append (res, "void"); break;
121 case MONO_TYPE_CHAR:
122 g_string_append (res, "char"); break;
123 case MONO_TYPE_BOOLEAN:
124 g_string_append (res, "bool"); break;
125 case MONO_TYPE_U1:
126 g_string_append (res, "byte"); break;
127 case MONO_TYPE_I1:
128 g_string_append (res, "sbyte"); break;
129 case MONO_TYPE_U2:
130 g_string_append (res, "uint16"); break;
131 case MONO_TYPE_I2:
132 g_string_append (res, "int16"); break;
133 case MONO_TYPE_U4:
134 g_string_append (res, "uint"); break;
135 case MONO_TYPE_I4:
136 g_string_append (res, "int"); break;
137 case MONO_TYPE_U8:
138 g_string_append (res, "ulong"); break;
139 case MONO_TYPE_I8:
140 g_string_append (res, "long"); break;
141 case MONO_TYPE_FNPTR: /* who cares for the exact signature? */
142 g_string_append (res, "*()"); break;
143 case MONO_TYPE_U:
144 g_string_append (res, "uintptr"); break;
145 case MONO_TYPE_I:
146 g_string_append (res, "intptr"); break;
147 case MONO_TYPE_R4:
148 g_string_append (res, "single"); break;
149 case MONO_TYPE_R8:
150 g_string_append (res, "double"); break;
151 case MONO_TYPE_STRING:
152 g_string_append (res, "string"); break;
153 case MONO_TYPE_OBJECT:
154 g_string_append (res, "object"); break;
155 case MONO_TYPE_PTR:
156 mono_type_get_desc (res, type->data.type, include_namespace);
157 g_string_append_c (res, '*');
158 break;
159 case MONO_TYPE_ARRAY:
160 mono_type_get_desc (res, &type->data.array->eklass->_byval_arg, include_namespace);
161 g_string_append_c (res, '[');
162 for (i = 1; i < type->data.array->rank; ++i)
163 g_string_append_c (res, ',');
164 g_string_append_c (res, ']');
165 break;
166 case MONO_TYPE_SZARRAY:
167 mono_type_get_desc (res, &type->data.klass->_byval_arg, include_namespace);
168 g_string_append (res, "[]");
169 break;
170 case MONO_TYPE_CLASS:
171 case MONO_TYPE_VALUETYPE:
172 append_class_name (res, type->data.klass, include_namespace);
173 break;
174 case MONO_TYPE_GENERICINST: {
175 MonoGenericContext *context;
177 mono_type_get_desc (res, &type->data.generic_class->container_class->_byval_arg, include_namespace);
178 g_string_append (res, "<");
179 context = &type->data.generic_class->context;
180 if (context->class_inst) {
181 for (i = 0; i < context->class_inst->type_argc; ++i) {
182 if (i > 0)
183 g_string_append (res, ", ");
184 mono_type_get_desc (res, context->class_inst->type_argv [i], include_namespace);
187 if (context->method_inst) {
188 if (context->class_inst)
189 g_string_append (res, "; ");
190 for (i = 0; i < context->method_inst->type_argc; ++i) {
191 if (i > 0)
192 g_string_append (res, ", ");
193 mono_type_get_desc (res, context->method_inst->type_argv [i], include_namespace);
196 g_string_append (res, ">");
197 break;
199 case MONO_TYPE_VAR:
200 case MONO_TYPE_MVAR:
201 if (type->data.generic_param) {
202 const char *name = mono_generic_param_name (type->data.generic_param);
203 if (name)
204 g_string_append (res, name);
205 else
206 g_string_append_printf (res, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", mono_generic_param_num (type->data.generic_param));
207 } else {
208 g_string_append (res, "<unknown>");
210 break;
211 case MONO_TYPE_TYPEDBYREF:
212 g_string_append (res, "typedbyref");
213 break;
214 default:
215 break;
217 if (type->byref)
218 g_string_append_c (res, '&');
222 * mono_type_full_name:
224 char*
225 mono_type_full_name (MonoType *type)
227 GString *str;
229 str = g_string_new ("");
230 mono_type_get_desc (str, type, TRUE);
231 return g_string_free (str, FALSE);
235 * mono_signature_get_desc:
237 char*
238 mono_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
240 int i;
241 char *result;
242 GString *res;
244 if (!sig)
245 return g_strdup ("<invalid signature>");
247 res = g_string_new ("");
249 for (i = 0; i < sig->param_count; ++i) {
250 if (i > 0)
251 g_string_append_c (res, ',');
252 mono_type_get_desc (res, sig->params [i], include_namespace);
254 result = res->str;
255 g_string_free (res, FALSE);
256 return result;
259 char*
260 mono_signature_full_name (MonoMethodSignature *sig)
262 int i;
263 char *result;
264 GString *res;
266 if (!sig)
267 return g_strdup ("<invalid signature>");
269 res = g_string_new ("");
271 mono_type_get_desc (res, sig->ret, TRUE);
272 g_string_append_c (res, '(');
273 for (i = 0; i < sig->param_count; ++i) {
274 if (i > 0)
275 g_string_append_c (res, ',');
276 mono_type_get_desc (res, sig->params [i], TRUE);
278 g_string_append_c (res, ')');
279 result = res->str;
280 g_string_free (res, FALSE);
281 return result;
284 void
285 mono_ginst_get_desc (GString *str, MonoGenericInst *ginst)
287 int i;
289 for (i = 0; i < ginst->type_argc; ++i) {
290 if (i > 0)
291 g_string_append (str, ", ");
292 mono_type_get_desc (str, ginst->type_argv [i], TRUE);
296 char*
297 mono_context_get_desc (MonoGenericContext *context)
299 GString *str;
300 char *res;
302 str = g_string_new ("");
303 g_string_append (str, "<");
305 if (context->class_inst)
306 mono_ginst_get_desc (str, context->class_inst);
307 if (context->method_inst) {
308 if (context->class_inst)
309 g_string_append (str, "; ");
310 mono_ginst_get_desc (str, context->method_inst);
313 g_string_append (str, ">");
314 res = g_strdup (str->str);
315 g_string_free (str, TRUE);
316 return res;
320 * mono_method_desc_new:
321 * \param name the method name.
322 * \param include_namespace whether the name includes a namespace or not.
324 * Creates a method description for \p name, which conforms to the following
325 * specification:
327 * <code>[namespace.]classname:methodname[(args...)]</code>
329 * in all the loaded assemblies.
331 * Both classname and methodname can contain <code>*</code> which matches anything.
333 * \returns a parsed representation of the method description.
335 MonoMethodDesc*
336 mono_method_desc_new (const char *name, gboolean include_namespace)
338 MonoMethodDesc *result;
339 char *class_name, *class_nspace, *method_name, *use_args, *end;
340 int use_namespace;
341 int generic_delim_stack;
343 class_nspace = g_strdup (name);
344 use_args = strchr (class_nspace, '(');
345 if (use_args) {
346 /* Allow a ' ' between the method name and the signature */
347 if (use_args > class_nspace && use_args [-1] == ' ')
348 use_args [-1] = 0;
349 *use_args++ = 0;
350 end = strchr (use_args, ')');
351 if (!end) {
352 g_free (class_nspace);
353 return NULL;
355 *end = 0;
357 method_name = strrchr (class_nspace, ':');
358 if (!method_name) {
359 g_free (class_nspace);
360 return NULL;
362 /* allow two :: to separate the method name */
363 if (method_name != class_nspace && method_name [-1] == ':')
364 method_name [-1] = 0;
365 *method_name++ = 0;
366 class_name = strrchr (class_nspace, '.');
367 if (class_name) {
368 *class_name++ = 0;
369 use_namespace = 1;
370 } else {
371 class_name = class_nspace;
372 use_namespace = 0;
374 result = g_new0 (MonoMethodDesc, 1);
375 result->include_namespace = include_namespace;
376 result->name = method_name;
377 result->klass = class_name;
378 result->name_space = use_namespace? class_nspace: NULL;
379 result->args = use_args? use_args: NULL;
380 if (strstr (result->name, "*"))
381 result->name_glob = TRUE;
382 if (strstr (result->klass, "*"))
383 result->klass_glob = TRUE;
384 if (use_args) {
385 end = use_args;
386 if (*end)
387 result->num_args = 1;
388 generic_delim_stack = 0;
389 while (*end) {
390 if (*end == '<')
391 generic_delim_stack++;
392 else if (*end == '>')
393 generic_delim_stack--;
395 if (*end == ',' && generic_delim_stack == 0)
396 result->num_args++;
397 ++end;
401 return result;
405 * mono_method_desc_from_method:
407 MonoMethodDesc*
408 mono_method_desc_from_method (MonoMethod *method)
410 MonoMethodDesc *result;
412 result = g_new0 (MonoMethodDesc, 1);
413 result->include_namespace = TRUE;
414 result->name = g_strdup (method->name);
415 result->klass = g_strdup (method->klass->name);
416 result->name_space = g_strdup (method->klass->name_space);
418 return result;
422 * mono_method_desc_free:
423 * \param desc method description to be released
424 * Releases the \c MonoMethodDesc object \p desc.
426 void
427 mono_method_desc_free (MonoMethodDesc *desc)
429 if (desc->name_space)
430 g_free (desc->name_space);
431 else if (desc->klass)
432 g_free (desc->klass);
433 g_free (desc);
437 * mono_method_desc_match:
438 * \param desc \c MonoMethoDescription
439 * \param method \c MonoMethod to test
441 * Determines whether the specified \p method matches the provided \p desc description.
443 * namespace and class are supposed to match already if this function is used.
444 * \returns TRUE if the method matches the description, FALSE otherwise.
446 gboolean
447 mono_method_desc_match (MonoMethodDesc *desc, MonoMethod *method)
449 char *sig;
450 gboolean name_match;
452 name_match = strcmp (desc->name, method->name) == 0;
453 if (!name_match)
454 return FALSE;
455 if (!desc->args)
456 return TRUE;
457 if (desc->num_args != mono_method_signature_internal (method)->param_count)
458 return FALSE;
459 sig = mono_signature_get_desc (mono_method_signature_internal (method), desc->include_namespace);
460 if (strcmp (sig, desc->args)) {
461 g_free (sig);
462 return FALSE;
464 g_free (sig);
465 return TRUE;
468 static const char *
469 my_strrchr (const char *str, char ch, int *len)
471 int pos;
473 for (pos = (*len)-1; pos >= 0; pos--) {
474 if (str [pos] != ch)
475 continue;
477 *len = pos;
478 return str + pos;
481 return NULL;
484 static gboolean
485 match_class (MonoMethodDesc *desc, int pos, MonoClass *klass)
487 const char *p;
488 gboolean is_terminal = TRUE;
490 if (desc->klass_glob && !strcmp (desc->klass, "*"))
491 return TRUE;
492 #ifndef _EGLIB_MAJOR
493 if (desc->klass_glob && g_pattern_match_simple (desc->klass, klass->name))
494 return TRUE;
495 #endif
496 if (desc->klass[pos] == '/')
497 is_terminal = FALSE;
499 p = my_strrchr (desc->klass, '/', &pos);
500 if (!p) {
501 if (is_terminal && strcmp (desc->klass, klass->name))
502 return FALSE;
503 if (!is_terminal && strncmp (desc->klass, klass->name, pos))
504 return FALSE;
505 if (desc->name_space && strcmp (desc->name_space, klass->name_space))
506 return FALSE;
507 return TRUE;
510 if (strcmp (p+1, klass->name))
511 return FALSE;
512 if (!klass->nested_in)
513 return FALSE;
515 return match_class (desc, pos, klass->nested_in);
519 * mono_method_desc_is_full:
521 gboolean
522 mono_method_desc_is_full (MonoMethodDesc *desc)
524 return desc->klass && desc->klass[0] != '\0';
528 * mono_method_desc_full_match:
529 * \param desc A method description that you created with mono_method_desc_new
530 * \param method a MonoMethod instance that you want to match against
532 * This method is used to check whether the method matches the provided
533 * description, by making sure that the method matches both the class and the method parameters.
535 * \returns TRUE if the specified method matches the specified description, FALSE otherwise.
537 gboolean
538 mono_method_desc_full_match (MonoMethodDesc *desc, MonoMethod *method)
540 if (!desc)
541 return FALSE;
542 if (!desc->klass)
543 return FALSE;
544 if (!match_class (desc, strlen (desc->klass), method->klass))
545 return FALSE;
547 return mono_method_desc_match (desc, method);
551 * mono_method_desc_search_in_class:
553 MonoMethod*
554 mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass)
556 MonoMethod* m;
557 gpointer iter = NULL;
559 while ((m = mono_class_get_methods (klass, &iter)))
560 if (mono_method_desc_match (desc, m))
561 return m;
562 return NULL;
566 * mono_method_desc_search_in_image:
568 MonoMethod*
569 mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image)
571 MonoClass *klass;
572 const MonoTableInfo *methods;
573 MonoMethod *method;
574 int i;
576 /* Handle short names for system classes */
577 if (!desc->name_space && image == mono_defaults.corlib) {
578 klass = find_system_class (desc->klass);
579 if (klass)
580 return mono_method_desc_search_in_class (desc, klass);
583 if (desc->name_space && desc->klass) {
584 klass = mono_class_try_load_from_name (image, desc->name_space, desc->klass);
585 if (!klass)
586 return NULL;
587 return mono_method_desc_search_in_class (desc, klass);
590 /* FIXME: Is this call necessary? We don't use its result. */
591 mono_image_get_table_info (image, MONO_TABLE_TYPEDEF);
592 methods = mono_image_get_table_info (image, MONO_TABLE_METHOD);
593 for (i = 0; i < mono_table_info_get_rows (methods); ++i) {
594 ERROR_DECL (error);
595 guint32 token = mono_metadata_decode_row_col (methods, i, MONO_METHOD_NAME);
596 const char *n = mono_metadata_string_heap (image, token);
598 if (strcmp (n, desc->name))
599 continue;
600 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, error);
601 if (!method) {
602 mono_error_cleanup (error);
603 continue;
605 if (mono_method_desc_full_match (desc, method))
606 return method;
608 return NULL;
611 static const unsigned char*
612 dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned char *ip, const unsigned char *end)
614 ERROR_DECL (error);
615 MonoMethodHeader *header = mono_method_get_header_checked (method, error);
616 const MonoOpcode *opcode;
617 guint32 label, token;
618 gint32 sval;
619 int i;
620 char *tmp;
621 const unsigned char* il_code;
623 if (!header) {
624 g_string_append_printf (str, "could not disassemble, bad header due to %s", mono_error_get_message (error));
625 mono_error_cleanup (error);
626 return end;
628 il_code = mono_method_header_get_code (header, NULL, NULL);
630 label = ip - il_code;
631 if (dh->indenter) {
632 tmp = dh->indenter (dh, method, label);
633 g_string_append (str, tmp);
634 g_free (tmp);
636 if (dh->label_format)
637 g_string_append_printf (str, dh->label_format, label);
639 i = mono_opcode_value (&ip, end);
640 ip++;
641 opcode = &mono_opcodes [i];
642 g_string_append_printf (str, "%-10s", mono_opcode_name (i));
644 switch (opcode->argument) {
645 case MonoInlineNone:
646 break;
647 case MonoInlineType:
648 case MonoInlineField:
649 case MonoInlineMethod:
650 case MonoInlineTok:
651 case MonoInlineSig:
652 token = read32 (ip);
653 if (dh->tokener) {
654 tmp = dh->tokener (dh, method, token);
655 g_string_append (str, tmp);
656 g_free (tmp);
657 } else {
658 g_string_append_printf (str, "0x%08x", token);
660 ip += 4;
661 break;
662 case MonoInlineString: {
663 const char *blob;
664 char *s;
665 size_t len2;
666 char *blob2 = NULL;
668 if (!image_is_dynamic (method->klass->image) && !method_is_dynamic (method)) {
669 token = read32 (ip);
670 blob = mono_metadata_user_string (method->klass->image, mono_metadata_token_index (token));
672 len2 = mono_metadata_decode_blob_size (blob, &blob);
673 len2 >>= 1;
675 #ifdef NO_UNALIGNED_ACCESS
676 /* The blob might not be 2 byte aligned */
677 blob2 = g_malloc ((len2 * 2) + 1);
678 memcpy (blob2, blob, len2 * 2);
679 #else
680 blob2 = (char*)blob;
681 #endif
683 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
685 guint16 *buf = g_new (guint16, len2 + 1);
686 int i;
688 for (i = 0; i < len2; ++i)
689 buf [i] = GUINT16_FROM_LE (((guint16*)blob2) [i]);
690 s = g_utf16_to_utf8 (buf, len2, NULL, NULL, NULL);
691 g_free (buf);
693 #else
694 s = g_utf16_to_utf8 ((gunichar2*)blob2, len2, NULL, NULL, NULL);
695 #endif
697 g_string_append_printf (str, "\"%s\"", s);
698 g_free (s);
699 if (blob != blob2)
700 g_free (blob2);
702 ip += 4;
703 break;
705 case MonoInlineVar:
706 g_string_append_printf (str, "%d", read16 (ip));
707 ip += 2;
708 break;
709 case MonoShortInlineVar:
710 g_string_append_printf (str, "%d", (*ip));
711 ip ++;
712 break;
713 case MonoInlineBrTarget:
714 sval = read32 (ip);
715 ip += 4;
716 if (dh->label_target)
717 g_string_append_printf (str, dh->label_target, ip + sval - il_code);
718 else
719 g_string_append_printf (str, "%d", sval);
720 break;
721 case MonoShortInlineBrTarget:
722 sval = *(const signed char*)ip;
723 ip ++;
724 if (dh->label_target)
725 g_string_append_printf (str, dh->label_target, ip + sval - il_code);
726 else
727 g_string_append_printf (str, "%d", sval);
728 break;
729 case MonoInlineSwitch: {
730 const unsigned char *end;
731 sval = read32 (ip);
732 ip += 4;
733 end = ip + sval * 4;
734 g_string_append_c (str, '(');
735 for (i = 0; i < sval; ++i) {
736 if (i > 0)
737 g_string_append (str, ", ");
738 label = read32 (ip);
739 if (dh->label_target)
740 g_string_append_printf (str, dh->label_target, end + label - il_code);
741 else
742 g_string_append_printf (str, "%d", label);
743 ip += 4;
745 g_string_append_c (str, ')');
746 break;
748 case MonoInlineR: {
749 double r;
750 readr8 (ip, &r);
751 g_string_append_printf (str, "%g", r);
752 ip += 8;
753 break;
755 case MonoShortInlineR: {
756 float r;
757 readr4 (ip, &r);
758 g_string_append_printf (str, "%g", r);
759 ip += 4;
760 break;
762 case MonoInlineI:
763 g_string_append_printf (str, "%d", (gint32)read32 (ip));
764 ip += 4;
765 break;
766 case MonoShortInlineI:
767 g_string_append_printf (str, "%d", *(const signed char*)ip);
768 ip ++;
769 break;
770 case MonoInlineI8:
771 ip += 8;
772 break;
773 default:
774 g_assert_not_reached ();
776 if (dh->newline)
777 g_string_append (str, dh->newline);
779 mono_metadata_free_mh (header);
780 return ip;
783 static MonoDisHelper
784 default_dh = {
785 "\n",
786 "IL_%04x: ", /* label_format */
787 "IL_%04x", /* label_target */
788 NULL, /* indenter */
789 NULL, /* tokener */
790 NULL /* user data */
794 * mono_disasm_code_one:
796 char*
797 mono_disasm_code_one (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const guchar **endp)
799 char *result;
800 GString *res = g_string_new ("");
802 if (!dh)
803 dh = &default_dh;
804 /* set ip + 2 as the end: this is just a debugging method */
805 ip = dis_one (res, dh, method, ip, ip + 2);
806 if (endp)
807 *endp = ip;
809 result = res->str;
810 g_string_free (res, FALSE);
811 return result;
815 * mono_disasm_code:
817 char*
818 mono_disasm_code (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const guchar* end)
820 char *result;
821 GString *res = g_string_new ("");
823 if (!dh)
824 dh = &default_dh;
825 while (ip < end) {
826 ip = dis_one (res, dh, method, ip, end);
829 result = res->str;
830 g_string_free (res, FALSE);
831 return result;
835 * mono_field_full_name:
836 * \param field field to retrieve information for
837 * \returns the full name for the field, made up of the namespace, type name and the field name.
839 char *
840 mono_field_full_name (MonoClassField *field)
842 char *res;
843 const char *nspace = field->parent->name_space;
845 res = g_strdup_printf ("%s%s%s:%s", nspace, *nspace ? "." : "",
846 field->parent->name, mono_field_get_name (field));
848 return res;
851 char *
852 mono_method_get_name_full (MonoMethod *method, gboolean signature, gboolean ret, MonoTypeNameFormat format)
854 char *res;
855 char wrapper [64];
856 char *klass_desc;
857 char *inst_desc = NULL;
858 ERROR_DECL (error);
860 const char *class_method_separator = ":";
861 const char *method_sig_space = " ";
862 if (format == MONO_TYPE_NAME_FORMAT_REFLECTION) {
863 class_method_separator = ".";
864 method_sig_space = "";
867 if (format == MONO_TYPE_NAME_FORMAT_IL)
868 klass_desc = mono_type_full_name (&method->klass->_byval_arg);
869 else
870 klass_desc = mono_type_get_name_full (&method->klass->_byval_arg, format);
872 if (method->is_inflated && ((MonoMethodInflated*)method)->context.method_inst) {
873 GString *str = g_string_new ("");
874 if (format == MONO_TYPE_NAME_FORMAT_IL)
875 g_string_append (str, "<");
876 else
877 g_string_append (str, "[");
878 mono_ginst_get_desc (str, ((MonoMethodInflated*)method)->context.method_inst);
879 if (format == MONO_TYPE_NAME_FORMAT_IL)
880 g_string_append_c (str, '>');
881 else
882 g_string_append_c (str, ']');
884 inst_desc = str->str;
885 g_string_free (str, FALSE);
886 } else if (method->is_generic) {
887 MonoGenericContainer *container = mono_method_get_generic_container (method);
889 GString *str = g_string_new ("");
890 if (format == MONO_TYPE_NAME_FORMAT_IL)
891 g_string_append (str, "<");
892 else
893 g_string_append (str, "[");
894 mono_ginst_get_desc (str, container->context.method_inst);
895 if (format == MONO_TYPE_NAME_FORMAT_IL)
896 g_string_append_c (str, '>');
897 else
898 g_string_append_c (str, ']');
900 inst_desc = str->str;
901 g_string_free (str, FALSE);
904 if (method->wrapper_type != MONO_WRAPPER_NONE)
905 sprintf (wrapper, "(wrapper %s) ", mono_wrapper_type_to_str (method->wrapper_type));
906 else
907 strcpy (wrapper, "");
909 if (signature) {
910 MonoMethodSignature *sig = mono_method_signature_checked (method, error);
911 char *tmpsig;
913 if (!is_ok (error)) {
914 tmpsig = g_strdup_printf ("<unable to load signature>");
915 mono_error_cleanup (error);
916 } else {
917 tmpsig = mono_signature_get_desc (sig, TRUE);
920 if (method->wrapper_type != MONO_WRAPPER_NONE)
921 sprintf (wrapper, "(wrapper %s) ", mono_wrapper_type_to_str (method->wrapper_type));
922 else
923 strcpy (wrapper, "");
924 if (ret && sig) {
925 char *ret_str = mono_type_full_name (sig->ret);
926 res = g_strdup_printf ("%s%s %s%s%s%s%s(%s)", wrapper, ret_str, klass_desc,
927 class_method_separator,
928 method->name, inst_desc ? inst_desc : "", method_sig_space, tmpsig);
929 g_free (ret_str);
930 } else {
931 res = g_strdup_printf ("%s%s%s%s%s%s(%s)", wrapper, klass_desc,
932 class_method_separator,
933 method->name, inst_desc ? inst_desc : "", method_sig_space, tmpsig);
935 g_free (tmpsig);
936 } else {
937 res = g_strdup_printf ("%s%s%s%s%s", wrapper, klass_desc,
938 class_method_separator,
939 method->name, inst_desc ? inst_desc : "");
942 g_free (klass_desc);
943 g_free (inst_desc);
945 return res;
949 * mono_method_full_name:
951 char *
952 mono_method_full_name (MonoMethod *method, gboolean signature)
954 char *res;
955 MONO_ENTER_GC_UNSAFE;
956 res = mono_method_get_name_full (method, signature, FALSE, MONO_TYPE_NAME_FORMAT_IL);
957 MONO_EXIT_GC_UNSAFE;
958 return res;
961 char *
962 mono_method_get_full_name (MonoMethod *method)
964 return mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL);
968 * mono_method_get_reflection_name:
970 * Returns the name of the method, including signature, using the same formating as reflection.
972 char *
973 mono_method_get_reflection_name (MonoMethod *method)
975 return mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
978 static const char*
979 print_name_space (MonoClass *klass)
981 if (klass->nested_in) {
982 print_name_space (klass->nested_in);
983 g_print ("%s", klass->nested_in->name);
984 return "/";
986 if (klass->name_space [0]) {
987 g_print ("%s", klass->name_space);
988 return ".";
990 return "";
994 * mono_object_describe:
996 * Prints to stdout a small description of the object \p obj.
997 * For use in a debugger.
999 void
1000 mono_object_describe (MonoObject *obj)
1002 ERROR_DECL (error);
1003 MonoClass* klass;
1004 const char* sep;
1005 if (!obj) {
1006 g_print ("(null)\n");
1007 return;
1009 klass = mono_object_class (obj);
1010 if (klass == mono_defaults.string_class) {
1011 char *utf8 = mono_string_to_utf8_checked_internal ((MonoString*)obj, error);
1012 mono_error_cleanup (error); /* FIXME don't swallow the error */
1013 if (utf8 && strlen (utf8) > 60) {
1014 utf8 [57] = '.';
1015 utf8 [58] = '.';
1016 utf8 [59] = '.';
1017 utf8 [60] = 0;
1019 if (utf8) {
1020 g_print ("String at %p, length: %d, '%s'\n", obj, mono_string_length_internal ((MonoString*) obj), utf8);
1021 } else {
1022 g_print ("String at %p, length: %d, unable to decode UTF16\n", obj, mono_string_length_internal ((MonoString*) obj));
1024 g_free (utf8);
1025 } else if (klass->rank) {
1026 MonoArray *array = (MonoArray*)obj;
1027 sep = print_name_space (klass);
1028 g_print ("%s%s", sep, klass->name);
1029 g_print (" at %p, rank: %d, length: %d\n", obj, klass->rank, (int)mono_array_length_internal (array));
1030 } else {
1031 sep = print_name_space (klass);
1032 g_print ("%s%s", sep, klass->name);
1033 g_print (" object at %p (klass: %p)\n", obj, klass);
1038 static void
1039 print_field_value (const char *field_ptr, MonoClassField *field, int type_offset)
1041 MonoType *type;
1042 g_print ("At %p (ofs: %2d) %s: ", field_ptr, field->offset + type_offset, mono_field_get_name (field));
1043 type = mono_type_get_underlying_type (field->type);
1045 switch (type->type) {
1046 case MONO_TYPE_I:
1047 case MONO_TYPE_U:
1048 case MONO_TYPE_PTR:
1049 case MONO_TYPE_FNPTR:
1050 g_print ("%p\n", *(const void**)field_ptr);
1051 break;
1052 case MONO_TYPE_STRING:
1053 case MONO_TYPE_SZARRAY:
1054 case MONO_TYPE_CLASS:
1055 case MONO_TYPE_OBJECT:
1056 case MONO_TYPE_ARRAY:
1057 mono_object_describe (*(MonoObject**)field_ptr);
1058 break;
1059 case MONO_TYPE_GENERICINST:
1060 if (!mono_type_generic_inst_is_valuetype (type)) {
1061 mono_object_describe (*(MonoObject**)field_ptr);
1062 break;
1063 } else {
1064 /* fall through */
1066 case MONO_TYPE_VALUETYPE: {
1067 MonoClass *k = mono_class_from_mono_type_internal (type);
1068 g_print ("%s ValueType (type: %p) at %p\n", k->name, k, field_ptr);
1069 break;
1071 case MONO_TYPE_I1:
1072 g_print ("%d\n", *(gint8*)field_ptr);
1073 break;
1074 case MONO_TYPE_U1:
1075 g_print ("%d\n", *(guint8*)field_ptr);
1076 break;
1077 case MONO_TYPE_I2:
1078 g_print ("%d\n", *(gint16*)field_ptr);
1079 break;
1080 case MONO_TYPE_U2:
1081 g_print ("%d\n", *(guint16*)field_ptr);
1082 break;
1083 case MONO_TYPE_I4:
1084 g_print ("%d\n", *(gint32*)field_ptr);
1085 break;
1086 case MONO_TYPE_U4:
1087 g_print ("%u\n", *(guint32*)field_ptr);
1088 break;
1089 case MONO_TYPE_I8:
1090 g_print ("%lld\n", (long long int)*(gint64*)field_ptr);
1091 break;
1092 case MONO_TYPE_U8:
1093 g_print ("%llu\n", (long long unsigned int)*(guint64*)field_ptr);
1094 break;
1095 case MONO_TYPE_R4:
1096 g_print ("%f\n", *(gfloat*)field_ptr);
1097 break;
1098 case MONO_TYPE_R8:
1099 g_print ("%f\n", *(gdouble*)field_ptr);
1100 break;
1101 case MONO_TYPE_BOOLEAN:
1102 g_print ("%s (%d)\n", *(guint8*)field_ptr? "True": "False", *(guint8*)field_ptr);
1103 break;
1104 case MONO_TYPE_CHAR:
1105 g_print ("'%c' (%d 0x%04x)\n", *(guint16*)field_ptr, *(guint16*)field_ptr, *(guint16*)field_ptr);
1106 break;
1107 default:
1108 g_assert_not_reached ();
1109 break;
1113 static void
1114 objval_describe (MonoClass *klass, const char *addr)
1116 MonoClassField *field;
1117 MonoClass *p;
1118 const char *field_ptr;
1119 gssize type_offset = 0;
1121 if (klass->valuetype)
1122 type_offset = - MONO_ABI_SIZEOF (MonoObject);
1124 for (p = klass; p != NULL; p = p->parent) {
1125 gpointer iter = NULL;
1126 int printed_header = FALSE;
1127 while ((field = mono_class_get_fields_internal (p, &iter))) {
1128 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
1129 continue;
1131 if (p != klass && !printed_header) {
1132 const char *sep;
1133 g_print ("In class ");
1134 sep = print_name_space (p);
1135 g_print ("%s%s:\n", sep, p->name);
1136 printed_header = TRUE;
1138 field_ptr = (const char*)addr + field->offset + type_offset;
1140 print_field_value (field_ptr, field, type_offset);
1146 * mono_object_describe_fields:
1148 * Prints to stdout a small description of each field of the object \p obj.
1149 * For use in a debugger.
1151 void
1152 mono_object_describe_fields (MonoObject *obj)
1154 MonoClass *klass = mono_object_class (obj);
1155 objval_describe (klass, (char*)obj);
1159 * mono_value_describe_fields:
1161 * Prints to stdout a small description of each field of the value type
1162 * stored at \p addr of type \p klass.
1163 * For use in a debugger.
1165 void
1166 mono_value_describe_fields (MonoClass* klass, const char* addr)
1168 objval_describe (klass, addr);
1172 * mono_class_describe_statics:
1174 * Prints to stdout a small description of each static field of the type \p klass
1175 * in the current application domain.
1176 * For use in a debugger.
1178 void
1179 mono_class_describe_statics (MonoClass* klass)
1181 ERROR_DECL (error);
1182 MonoClassField *field;
1183 MonoClass *p;
1184 const char *field_ptr;
1185 MonoVTable *vtable = mono_class_vtable_checked (mono_domain_get (), klass, error);
1186 const char *addr;
1188 if (!vtable || !is_ok (error)) {
1189 mono_error_cleanup (error);
1190 return;
1193 if (!(addr = (const char *)mono_vtable_get_static_field_data (vtable)))
1194 return;
1196 for (p = klass; p != NULL; p = p->parent) {
1197 gpointer iter = NULL;
1198 while ((field = mono_class_get_fields_internal (p, &iter))) {
1199 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
1200 continue;
1201 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
1202 continue;
1204 field_ptr = (const char*)addr + field->offset;
1206 print_field_value (field_ptr, field, 0);
1212 * mono_print_method_code
1213 * \param method: a pointer to the method
1215 * This method is used from a debugger to print the code of the method.
1217 * This prints the IL code of the method in the standard output.
1219 void
1220 mono_method_print_code (MonoMethod *method)
1222 ERROR_DECL (error);
1223 char *code;
1224 MonoMethodHeader *header = mono_method_get_header_checked (method, error);
1225 if (!header) {
1226 printf ("METHOD HEADER NOT FOUND DUE TO: %s\n", mono_error_get_message (error));
1227 mono_error_cleanup (error);
1228 return;
1230 code = mono_disasm_code (0, method, header->code, header->code + header->code_size);
1231 printf ("CODE FOR %s:\n%s\n", mono_method_full_name (method, TRUE), code);
1232 g_free (code);