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.
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"
22 struct MonoMethodDesc
{
28 gboolean include_namespace
, klass_glob
, name_glob
;
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"
39 #define WRAPPER(a,b) b,
40 #include "wrapper-types.h"
43 static const gint16 opidx
[] = {
44 #define WRAPPER(a,b) [MONO_WRAPPER_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
45 #include "wrapper-types.h"
50 wrapper_type_to_str (guint32 wrapper_type
)
52 g_assert (wrapper_type
< MONO_WRAPPER_NUM
);
54 return (const char*)&opstr
+ opidx
[wrapper_type
];
58 #define WRAPPER(a,b) b,
59 static const char* const
60 wrapper_type_names
[MONO_WRAPPER_NUM
+ 1] = {
61 #include "wrapper-types.h"
66 wrapper_type_to_str (guint32 wrapper_type
)
68 g_assert (wrapper_type
< MONO_WRAPPER_NUM
);
70 return wrapper_type_names
[wrapper_type
];
76 append_class_name (GString
*res
, MonoClass
*klass
, gboolean include_namespace
)
79 g_string_append (res
, "Unknown");
82 if (klass
->nested_in
) {
83 append_class_name (res
, klass
->nested_in
, include_namespace
);
84 g_string_append_c (res
, '/');
86 if (include_namespace
&& *(klass
->name_space
)) {
87 g_string_append (res
, klass
->name_space
);
88 g_string_append_c (res
, '.');
90 g_string_append (res
, klass
->name
);
94 find_system_class (const char *name
)
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
;
119 mono_type_get_desc (GString
*res
, MonoType
*type
, gboolean include_namespace
)
123 switch (type
->type
) {
125 g_string_append (res
, "void"); break;
127 g_string_append (res
, "char"); break;
128 case MONO_TYPE_BOOLEAN
:
129 g_string_append (res
, "bool"); break;
131 g_string_append (res
, "byte"); break;
133 g_string_append (res
, "sbyte"); break;
135 g_string_append (res
, "uint16"); break;
137 g_string_append (res
, "int16"); break;
139 g_string_append (res
, "uint"); break;
141 g_string_append (res
, "int"); break;
143 g_string_append (res
, "ulong"); break;
145 g_string_append (res
, "long"); break;
146 case MONO_TYPE_FNPTR
: /* who cares for the exact signature? */
147 g_string_append (res
, "*()"); break;
149 g_string_append (res
, "uintptr"); break;
151 g_string_append (res
, "intptr"); break;
153 g_string_append (res
, "single"); break;
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;
161 mono_type_get_desc (res
, type
->data
.type
, include_namespace
);
162 g_string_append_c (res
, '*');
164 case MONO_TYPE_ARRAY
:
165 mono_type_get_desc (res
, &type
->data
.array
->eklass
->byval_arg
, include_namespace
);
166 g_string_append_c (res
, '[');
167 for (i
= 1; i
< type
->data
.array
->rank
; ++i
)
168 g_string_append_c (res
, ',');
169 g_string_append_c (res
, ']');
171 case MONO_TYPE_SZARRAY
:
172 mono_type_get_desc (res
, &type
->data
.klass
->byval_arg
, include_namespace
);
173 g_string_append (res
, "[]");
175 case MONO_TYPE_CLASS
:
176 case MONO_TYPE_VALUETYPE
:
177 append_class_name (res
, type
->data
.klass
, include_namespace
);
179 case MONO_TYPE_GENERICINST
: {
180 MonoGenericContext
*context
;
182 mono_type_get_desc (res
, &type
->data
.generic_class
->container_class
->byval_arg
, include_namespace
);
183 g_string_append (res
, "<");
184 context
= &type
->data
.generic_class
->context
;
185 if (context
->class_inst
) {
186 for (i
= 0; i
< context
->class_inst
->type_argc
; ++i
) {
188 g_string_append (res
, ", ");
189 mono_type_get_desc (res
, context
->class_inst
->type_argv
[i
], include_namespace
);
192 if (context
->method_inst
) {
193 if (context
->class_inst
)
194 g_string_append (res
, "; ");
195 for (i
= 0; i
< context
->method_inst
->type_argc
; ++i
) {
197 g_string_append (res
, ", ");
198 mono_type_get_desc (res
, context
->method_inst
->type_argv
[i
], include_namespace
);
201 g_string_append (res
, ">");
206 if (type
->data
.generic_param
) {
207 const char *name
= mono_generic_param_name (type
->data
.generic_param
);
209 g_string_append (res
, name
);
211 g_string_append_printf (res
, "%s%d", type
->type
== MONO_TYPE_VAR
? "!" : "!!", mono_generic_param_num (type
->data
.generic_param
));
213 g_string_append (res
, "<unknown>");
216 case MONO_TYPE_TYPEDBYREF
:
217 g_string_append (res
, "typedbyref");
223 g_string_append_c (res
, '&');
227 mono_type_full_name (MonoType
*type
)
231 str
= g_string_new ("");
232 mono_type_get_desc (str
, type
, TRUE
);
233 return g_string_free (str
, FALSE
);
237 mono_signature_get_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
244 return g_strdup ("<invalid signature>");
246 res
= g_string_new ("");
248 for (i
= 0; i
< sig
->param_count
; ++i
) {
250 g_string_append_c (res
, ',');
251 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
254 g_string_free (res
, FALSE
);
259 mono_signature_full_name (MonoMethodSignature
*sig
)
266 return g_strdup ("<invalid signature>");
268 res
= g_string_new ("");
270 mono_type_get_desc (res
, sig
->ret
, TRUE
);
271 g_string_append_c (res
, '(');
272 for (i
= 0; i
< sig
->param_count
; ++i
) {
274 g_string_append_c (res
, ',');
275 mono_type_get_desc (res
, sig
->params
[i
], TRUE
);
277 g_string_append_c (res
, ')');
279 g_string_free (res
, FALSE
);
284 ginst_get_desc (GString
*str
, MonoGenericInst
*ginst
)
288 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
290 g_string_append (str
, ", ");
291 mono_type_get_desc (str
, ginst
->type_argv
[i
], TRUE
);
296 mono_context_get_desc (MonoGenericContext
*context
)
301 str
= g_string_new ("");
302 g_string_append (str
, "<");
304 if (context
->class_inst
)
305 ginst_get_desc (str
, context
->class_inst
);
306 if (context
->method_inst
) {
307 if (context
->class_inst
)
308 g_string_append (str
, "; ");
309 ginst_get_desc (str
, context
->method_inst
);
312 g_string_append (str
, ">");
313 res
= g_strdup (str
->str
);
314 g_string_free (str
, TRUE
);
319 * mono_method_desc_new:
320 * @name: the method name.
321 * @include_namespace: whether the name includes a namespace or not.
323 * Creates a method description for @name, which conforms to the following
326 * [namespace.]classname:methodname[(args...)]
328 * in all the loaded assemblies.
330 * Both classname and methodname can contain '*' which matches anything.
332 * Returns: a parsed representation of the method description.
335 mono_method_desc_new (const char *name
, gboolean include_namespace
)
337 MonoMethodDesc
*result
;
338 char *class_name
, *class_nspace
, *method_name
, *use_args
, *end
;
340 int generic_delim_stack
;
342 class_nspace
= g_strdup (name
);
343 use_args
= strchr (class_nspace
, '(');
345 /* Allow a ' ' between the method name and the signature */
346 if (use_args
> class_nspace
&& use_args
[-1] == ' ')
349 end
= strchr (use_args
, ')');
351 g_free (class_nspace
);
356 method_name
= strrchr (class_nspace
, ':');
358 g_free (class_nspace
);
361 /* allow two :: to separate the method name */
362 if (method_name
!= class_nspace
&& method_name
[-1] == ':')
363 method_name
[-1] = 0;
365 class_name
= strrchr (class_nspace
, '.');
370 class_name
= class_nspace
;
373 result
= g_new0 (MonoMethodDesc
, 1);
374 result
->include_namespace
= include_namespace
;
375 result
->name
= method_name
;
376 result
->klass
= class_name
;
377 result
->name_space
= use_namespace
? class_nspace
: NULL
;
378 result
->args
= use_args
? use_args
: NULL
;
379 if (strstr (result
->name
, "*"))
380 result
->name_glob
= TRUE
;
381 if (strstr (result
->klass
, "*"))
382 result
->klass_glob
= TRUE
;
386 result
->num_args
= 1;
387 generic_delim_stack
= 0;
390 generic_delim_stack
++;
391 else if (*end
== '>')
392 generic_delim_stack
--;
394 if (*end
== ',' && generic_delim_stack
== 0)
404 mono_method_desc_from_method (MonoMethod
*method
)
406 MonoMethodDesc
*result
;
408 result
= g_new0 (MonoMethodDesc
, 1);
409 result
->include_namespace
= TRUE
;
410 result
->name
= g_strdup (method
->name
);
411 result
->klass
= g_strdup (method
->klass
->name
);
412 result
->name_space
= g_strdup (method
->klass
->name_space
);
418 * mono_method_desc_free:
419 * @desc: method description to be released
421 * Releases the MonoMethodDesc object @desc.
424 mono_method_desc_free (MonoMethodDesc
*desc
)
426 if (desc
->name_space
)
427 g_free (desc
->name_space
);
428 else if (desc
->klass
)
429 g_free (desc
->klass
);
434 * mono_method_descr_match:
435 * @desc: MonoMethoDescription
436 * @method: MonoMethod to test
438 * Determines whether the specified @method matches the provided @desc description.
440 * namespace and class are supposed to match already if this function is used.
441 * Returns: True if the method matches the description, false otherwise.
444 mono_method_desc_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
449 name_match
= strcmp (desc
->name
, method
->name
) == 0;
454 if (desc
->num_args
!= mono_method_signature (method
)->param_count
)
456 sig
= mono_signature_get_desc (mono_method_signature (method
), desc
->include_namespace
);
457 if (strcmp (sig
, desc
->args
)) {
466 my_strrchr (const char *str
, char ch
, int *len
)
470 for (pos
= (*len
)-1; pos
>= 0; pos
--) {
482 match_class (MonoMethodDesc
*desc
, int pos
, MonoClass
*klass
)
486 if (desc
->klass_glob
&& !strcmp (desc
->klass
, "*"))
489 if (desc
->klass_glob
&& g_pattern_match_simple (desc
->klass
, klass
->name
))
492 p
= my_strrchr (desc
->klass
, '/', &pos
);
494 if (strncmp (desc
->klass
, klass
->name
, pos
))
496 if (desc
->name_space
&& strcmp (desc
->name_space
, klass
->name_space
))
501 if (strcmp (p
+1, klass
->name
))
503 if (!klass
->nested_in
)
506 return match_class (desc
, pos
, klass
->nested_in
);
510 mono_method_desc_full_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
514 if (!match_class (desc
, strlen (desc
->klass
), method
->klass
))
517 return mono_method_desc_match (desc
, method
);
521 mono_method_desc_search_in_class (MonoMethodDesc
*desc
, MonoClass
*klass
)
524 gpointer iter
= NULL
;
526 while ((m
= mono_class_get_methods (klass
, &iter
)))
527 if (mono_method_desc_match (desc
, m
))
533 mono_method_desc_search_in_image (MonoMethodDesc
*desc
, MonoImage
*image
)
536 const MonoTableInfo
*methods
;
540 /* Handle short names for system classes */
541 if (!desc
->name_space
&& image
== mono_defaults
.corlib
) {
542 klass
= find_system_class (desc
->klass
);
544 return mono_method_desc_search_in_class (desc
, klass
);
547 if (desc
->name_space
&& desc
->klass
) {
548 klass
= mono_class_try_load_from_name (image
, desc
->name_space
, desc
->klass
);
551 return mono_method_desc_search_in_class (desc
, klass
);
554 /* FIXME: Is this call necessary? We don't use its result. */
555 mono_image_get_table_info (image
, MONO_TABLE_TYPEDEF
);
556 methods
= mono_image_get_table_info (image
, MONO_TABLE_METHOD
);
557 for (i
= 0; i
< mono_table_info_get_rows (methods
); ++i
) {
559 guint32 token
= mono_metadata_decode_row_col (methods
, i
, MONO_METHOD_NAME
);
560 const char *n
= mono_metadata_string_heap (image
, token
);
562 if (strcmp (n
, desc
->name
))
564 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, &error
);
566 mono_error_cleanup (&error
);
569 if (mono_method_desc_full_match (desc
, method
))
575 static const unsigned char*
576 dis_one (GString
*str
, MonoDisHelper
*dh
, MonoMethod
*method
, const unsigned char *ip
, const unsigned char *end
)
579 MonoMethodHeader
*header
= mono_method_get_header_checked (method
, &error
);
580 const MonoOpcode
*opcode
;
581 guint32 label
, token
;
585 const unsigned char* il_code
;
588 g_string_append_printf (str
, "could not disassemble, bad header due to %s", mono_error_get_message (&error
));
589 mono_error_cleanup (&error
);
592 il_code
= mono_method_header_get_code (header
, NULL
, NULL
);
594 label
= ip
- il_code
;
596 tmp
= dh
->indenter (dh
, method
, label
);
597 g_string_append (str
, tmp
);
600 if (dh
->label_format
)
601 g_string_append_printf (str
, dh
->label_format
, label
);
603 i
= mono_opcode_value (&ip
, end
);
605 opcode
= &mono_opcodes
[i
];
606 g_string_append_printf (str
, "%-10s", mono_opcode_name (i
));
608 switch (opcode
->argument
) {
612 case MonoInlineField
:
613 case MonoInlineMethod
:
618 tmp
= dh
->tokener (dh
, method
, token
);
619 g_string_append (str
, tmp
);
622 g_string_append_printf (str
, "0x%08x", token
);
626 case MonoInlineString
: {
632 if (!image_is_dynamic (method
->klass
->image
) && !method_is_dynamic (method
)) {
634 blob
= mono_metadata_user_string (method
->klass
->image
, mono_metadata_token_index (token
));
636 len2
= mono_metadata_decode_blob_size (blob
, &blob
);
639 #ifdef NO_UNALIGNED_ACCESS
640 /* The blob might not be 2 byte aligned */
641 blob2
= g_malloc ((len2
* 2) + 1);
642 memcpy (blob2
, blob
, len2
* 2);
647 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
649 guint16
*buf
= g_new (guint16
, len2
+ 1);
652 for (i
= 0; i
< len2
; ++i
)
653 buf
[i
] = GUINT16_FROM_LE (((guint16
*)blob2
) [i
]);
654 s
= g_utf16_to_utf8 (buf
, len2
, NULL
, NULL
, NULL
);
658 s
= g_utf16_to_utf8 ((gunichar2
*)blob2
, len2
, NULL
, NULL
, NULL
);
661 g_string_append_printf (str
, "\"%s\"", s
);
670 g_string_append_printf (str
, "%d", read16 (ip
));
673 case MonoShortInlineVar
:
674 g_string_append_printf (str
, "%d", (*ip
));
677 case MonoInlineBrTarget
:
680 if (dh
->label_target
)
681 g_string_append_printf (str
, dh
->label_target
, ip
+ sval
- il_code
);
683 g_string_append_printf (str
, "%d", sval
);
685 case MonoShortInlineBrTarget
:
686 sval
= *(const signed char*)ip
;
688 if (dh
->label_target
)
689 g_string_append_printf (str
, dh
->label_target
, ip
+ sval
- il_code
);
691 g_string_append_printf (str
, "%d", sval
);
693 case MonoInlineSwitch
: {
694 const unsigned char *end
;
698 g_string_append_c (str
, '(');
699 for (i
= 0; i
< sval
; ++i
) {
701 g_string_append (str
, ", ");
703 if (dh
->label_target
)
704 g_string_append_printf (str
, dh
->label_target
, end
+ label
- il_code
);
706 g_string_append_printf (str
, "%d", label
);
709 g_string_append_c (str
, ')');
715 g_string_append_printf (str
, "%g", r
);
719 case MonoShortInlineR
: {
722 g_string_append_printf (str
, "%g", r
);
727 g_string_append_printf (str
, "%d", (gint32
)read32 (ip
));
730 case MonoShortInlineI
:
731 g_string_append_printf (str
, "%d", *(const signed char*)ip
);
738 g_assert_not_reached ();
741 g_string_append (str
, dh
->newline
);
743 mono_metadata_free_mh (header
);
750 "IL_%04x: ", /* label_format */
751 "IL_%04x", /* label_target */
758 mono_disasm_code_one (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
**endp
)
761 GString
*res
= g_string_new ("");
765 /* set ip + 2 as the end: this is just a debugging method */
766 ip
= dis_one (res
, dh
, method
, ip
, ip
+ 2);
771 g_string_free (res
, FALSE
);
776 mono_disasm_code (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
* end
)
779 GString
*res
= g_string_new ("");
784 ip
= dis_one (res
, dh
, method
, ip
, end
);
788 g_string_free (res
, FALSE
);
793 * mono_field_full_name:
794 * @field: field to retrieve information for
796 * Returns: the full name for the field, made up of the namespace, type name and the field name.
799 mono_field_full_name (MonoClassField
*field
)
802 const char *nspace
= field
->parent
->name_space
;
804 res
= g_strdup_printf ("%s%s%s:%s", nspace
, *nspace
? "." : "",
805 field
->parent
->name
, mono_field_get_name (field
));
811 mono_method_get_name_full (MonoMethod
*method
, gboolean signature
, gboolean ret
, MonoTypeNameFormat format
)
816 char *inst_desc
= NULL
;
818 if (format
== MONO_TYPE_NAME_FORMAT_IL
)
819 klass_desc
= mono_type_full_name (&method
->klass
->byval_arg
);
821 klass_desc
= mono_type_get_name_full (&method
->klass
->byval_arg
, format
);
823 if (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->context
.method_inst
) {
824 GString
*str
= g_string_new ("");
825 if (format
== MONO_TYPE_NAME_FORMAT_IL
)
826 g_string_append (str
, "<");
828 g_string_append (str
, "[");
829 ginst_get_desc (str
, ((MonoMethodInflated
*)method
)->context
.method_inst
);
830 if (format
== MONO_TYPE_NAME_FORMAT_IL
)
831 g_string_append_c (str
, '>');
833 g_string_append_c (str
, ']');
835 inst_desc
= str
->str
;
836 g_string_free (str
, FALSE
);
837 } else if (method
->is_generic
) {
838 MonoGenericContainer
*container
= mono_method_get_generic_container (method
);
840 GString
*str
= g_string_new ("");
841 if (format
== MONO_TYPE_NAME_FORMAT_IL
)
842 g_string_append (str
, "<");
844 g_string_append (str
, "[");
845 ginst_get_desc (str
, container
->context
.method_inst
);
846 if (format
== MONO_TYPE_NAME_FORMAT_IL
)
847 g_string_append_c (str
, '>');
849 g_string_append_c (str
, ']');
851 inst_desc
= str
->str
;
852 g_string_free (str
, FALSE
);
855 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
856 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
858 strcpy (wrapper
, "");
861 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
863 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
864 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
866 strcpy (wrapper
, "");
868 char *ret_str
= mono_type_full_name (mono_method_signature (method
)->ret
);
869 res
= g_strdup_printf ("%s%s %s:%s%s (%s)", wrapper
, ret_str
, klass_desc
,
870 method
->name
, inst_desc
? inst_desc
: "", tmpsig
);
873 res
= g_strdup_printf ("%s%s:%s%s (%s)", wrapper
, klass_desc
,
874 method
->name
, inst_desc
? inst_desc
: "", tmpsig
);
878 res
= g_strdup_printf ("%s%s:%s%s", wrapper
, klass_desc
,
879 method
->name
, inst_desc
? inst_desc
: "");
889 mono_method_full_name (MonoMethod
*method
, gboolean signature
)
891 return mono_method_get_name_full (method
, signature
, FALSE
, MONO_TYPE_NAME_FORMAT_IL
);
895 mono_method_get_full_name (MonoMethod
*method
)
897 return mono_method_get_name_full (method
, TRUE
, TRUE
, MONO_TYPE_NAME_FORMAT_IL
);
901 print_name_space (MonoClass
*klass
)
903 if (klass
->nested_in
) {
904 print_name_space (klass
->nested_in
);
905 g_print ("%s", klass
->nested_in
->name
);
908 if (klass
->name_space
[0]) {
909 g_print ("%s", klass
->name_space
);
916 * mono_object_describe:
918 * Prints to stdout a small description of the object @obj.
919 * For use in a debugger.
922 mono_object_describe (MonoObject
*obj
)
928 g_print ("(null)\n");
931 klass
= mono_object_class (obj
);
932 if (klass
== mono_defaults
.string_class
) {
933 char *utf8
= mono_string_to_utf8_checked ((MonoString
*)obj
, &error
);
934 mono_error_cleanup (&error
); /* FIXME don't swallow the error */
935 if (utf8
&& strlen (utf8
) > 60) {
942 g_print ("String at %p, length: %d, '%s'\n", obj
, mono_string_length ((MonoString
*) obj
), utf8
);
944 g_print ("String at %p, length: %d, unable to decode UTF16\n", obj
, mono_string_length ((MonoString
*) obj
));
947 } else if (klass
->rank
) {
948 MonoArray
*array
= (MonoArray
*)obj
;
949 sep
= print_name_space (klass
);
950 g_print ("%s%s", sep
, klass
->name
);
951 g_print (" at %p, rank: %d, length: %d\n", obj
, klass
->rank
, (int)mono_array_length (array
));
953 sep
= print_name_space (klass
);
954 g_print ("%s%s", sep
, klass
->name
);
955 g_print (" object at %p (klass: %p)\n", obj
, klass
);
961 print_field_value (const char *field_ptr
, MonoClassField
*field
, int type_offset
)
964 g_print ("At %p (ofs: %2d) %s: ", field_ptr
, field
->offset
+ type_offset
, mono_field_get_name (field
));
965 type
= mono_type_get_underlying_type (field
->type
);
967 switch (type
->type
) {
971 case MONO_TYPE_FNPTR
:
972 g_print ("%p\n", *(const void**)field_ptr
);
974 case MONO_TYPE_STRING
:
975 case MONO_TYPE_SZARRAY
:
976 case MONO_TYPE_CLASS
:
977 case MONO_TYPE_OBJECT
:
978 case MONO_TYPE_ARRAY
:
979 mono_object_describe (*(MonoObject
**)field_ptr
);
981 case MONO_TYPE_GENERICINST
:
982 if (!mono_type_generic_inst_is_valuetype (type
)) {
983 mono_object_describe (*(MonoObject
**)field_ptr
);
988 case MONO_TYPE_VALUETYPE
: {
989 MonoClass
*k
= mono_class_from_mono_type (type
);
990 g_print ("%s ValueType (type: %p) at %p\n", k
->name
, k
, field_ptr
);
994 g_print ("%d\n", *(gint8
*)field_ptr
);
997 g_print ("%d\n", *(guint8
*)field_ptr
);
1000 g_print ("%d\n", *(gint16
*)field_ptr
);
1003 g_print ("%d\n", *(guint16
*)field_ptr
);
1006 g_print ("%d\n", *(gint32
*)field_ptr
);
1009 g_print ("%u\n", *(guint32
*)field_ptr
);
1012 g_print ("%lld\n", (long long int)*(gint64
*)field_ptr
);
1015 g_print ("%llu\n", (long long unsigned int)*(guint64
*)field_ptr
);
1018 g_print ("%f\n", *(gfloat
*)field_ptr
);
1021 g_print ("%f\n", *(gdouble
*)field_ptr
);
1023 case MONO_TYPE_BOOLEAN
:
1024 g_print ("%s (%d)\n", *(guint8
*)field_ptr
? "True": "False", *(guint8
*)field_ptr
);
1026 case MONO_TYPE_CHAR
:
1027 g_print ("'%c' (%d 0x%04x)\n", *(guint16
*)field_ptr
, *(guint16
*)field_ptr
, *(guint16
*)field_ptr
);
1030 g_assert_not_reached ();
1036 objval_describe (MonoClass
*klass
, const char *addr
)
1038 MonoClassField
*field
;
1040 const char *field_ptr
;
1041 gssize type_offset
= 0;
1043 if (klass
->valuetype
)
1044 type_offset
= -sizeof (MonoObject
);
1046 for (p
= klass
; p
!= NULL
; p
= p
->parent
) {
1047 gpointer iter
= NULL
;
1048 int printed_header
= FALSE
;
1049 while ((field
= mono_class_get_fields (p
, &iter
))) {
1050 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
1053 if (p
!= klass
&& !printed_header
) {
1055 g_print ("In class ");
1056 sep
= print_name_space (p
);
1057 g_print ("%s%s:\n", sep
, p
->name
);
1058 printed_header
= TRUE
;
1060 field_ptr
= (const char*)addr
+ field
->offset
+ type_offset
;
1062 print_field_value (field_ptr
, field
, type_offset
);
1068 * mono_object_describe_fields:
1070 * Prints to stdout a small description of each field of the object @obj.
1071 * For use in a debugger.
1074 mono_object_describe_fields (MonoObject
*obj
)
1076 MonoClass
*klass
= mono_object_class (obj
);
1077 objval_describe (klass
, (char*)obj
);
1081 * mono_value_describe_fields:
1083 * Prints to stdout a small description of each field of the value type
1084 * stored at @addr of type @klass.
1085 * For use in a debugger.
1088 mono_value_describe_fields (MonoClass
* klass
, const char* addr
)
1090 objval_describe (klass
, addr
);
1094 * mono_class_describe_statics:
1096 * Prints to stdout a small description of each static field of the type @klass
1097 * in the current application domain.
1098 * For use in a debugger.
1101 mono_class_describe_statics (MonoClass
* klass
)
1104 MonoClassField
*field
;
1106 const char *field_ptr
;
1107 MonoVTable
*vtable
= mono_class_vtable_full (mono_domain_get (), klass
, &error
);
1110 if (!vtable
|| !is_ok (&error
)) {
1111 mono_error_cleanup (&error
);
1115 if (!(addr
= (const char *)mono_vtable_get_static_field_data (vtable
)))
1118 for (p
= klass
; p
!= NULL
; p
= p
->parent
) {
1119 gpointer iter
= NULL
;
1120 while ((field
= mono_class_get_fields (p
, &iter
))) {
1121 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
1123 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
1126 field_ptr
= (const char*)addr
+ field
->offset
;
1128 print_field_value (field_ptr
, field
, 0);
1134 * mono_print_method_code
1135 * @MonoMethod: a pointer to the method
1137 * This method is used from a debugger to print the code of the method.
1139 * This prints the IL code of the method in the standard output.
1142 mono_method_print_code (MonoMethod
*method
)
1146 MonoMethodHeader
*header
= mono_method_get_header_checked (method
, &error
);
1148 printf ("METHOD HEADER NOT FOUND DUE TO: %s\n", mono_error_get_message (&error
));
1149 mono_error_cleanup (&error
);
1152 code
= mono_disasm_code (0, method
, header
->code
, header
->code
+ header
->code_size
);
1153 printf ("CODE FOR %s:\n%s\n", mono_method_full_name (method
, TRUE
), code
);