3 #include "mono/metadata/tokentype.h"
4 #include "mono/metadata/opcodes.h"
5 #include "mono/metadata/class-internals.h"
6 #include "mono/metadata/mono-endian.h"
7 #include "mono/metadata/debug-helpers.h"
8 #include "mono/metadata/tabledefs.h"
9 #include "mono/metadata/appdomain.h"
11 struct MonoMethodDesc
{
17 gboolean include_namespace
;
20 static const char *wrapper_type_names
[] = {
23 "delegate-begin-invoke",
24 "delegate-end-invoke",
30 "remoting-invoke-with-check",
52 append_class_name (GString
*res
, MonoClass
*class, gboolean include_namespace
)
55 g_string_append (res
, "Unknown");
58 if (class->nested_in
) {
59 append_class_name (res
, class->nested_in
, include_namespace
);
60 g_string_append_c (res
, '/');
62 if (include_namespace
&& *(class->name_space
))
63 g_string_sprintfa (res
, "%s.", class->name_space
);
64 g_string_sprintfa (res
, "%s", class->name
);
68 mono_type_get_desc (GString
*res
, MonoType
*type
, gboolean include_namespace
) {
71 g_string_append (res
, "void"); break;
73 g_string_append (res
, "char"); break;
74 case MONO_TYPE_BOOLEAN
:
75 g_string_append (res
, "bool"); break;
77 g_string_append (res
, "byte"); break;
79 g_string_append (res
, "sbyte"); break;
81 g_string_append (res
, "uint16"); break;
83 g_string_append (res
, "int16"); break;
85 g_string_append (res
, "uint"); break;
87 g_string_append (res
, "int"); break;
89 g_string_append (res
, "ulong"); break;
91 g_string_append (res
, "long"); break;
92 case MONO_TYPE_FNPTR
: /* who cares for the exact signature? */
93 g_string_append (res
, "*()"); break;
95 g_string_append (res
, "uintptr"); break;
97 g_string_append (res
, "intptr"); break;
99 g_string_append (res
, "single"); break;
101 g_string_append (res
, "double"); break;
102 case MONO_TYPE_STRING
:
103 g_string_append (res
, "string"); break;
104 case MONO_TYPE_OBJECT
:
105 g_string_append (res
, "object"); break;
107 mono_type_get_desc (res
, type
->data
.type
, include_namespace
);
108 g_string_append_c (res
, '*');
110 case MONO_TYPE_ARRAY
:
111 append_class_name (res
, type
->data
.array
->eklass
, include_namespace
);
112 g_string_sprintfa (res
, "[%d]", type
->data
.array
->rank
);
114 case MONO_TYPE_SZARRAY
:
115 mono_type_get_desc (res
, &type
->data
.klass
->byval_arg
, include_namespace
);
116 g_string_append (res
, "[]");
118 case MONO_TYPE_CLASS
:
119 case MONO_TYPE_VALUETYPE
:
120 append_class_name (res
, type
->data
.klass
, include_namespace
);
122 case MONO_TYPE_GENERICINST
:
123 mono_type_get_desc (res
, &type
->data
.generic_class
->container_class
->byval_arg
, include_namespace
);
127 g_string_append (res
, type
->data
.generic_param
->name
);
133 g_string_append_c (res
, '&');
137 mono_type_full_name (MonoType
*type
)
142 str
= g_string_new ("");
143 mono_type_get_desc (str
, type
, TRUE
);
145 res
= g_strdup (str
->str
);
146 g_string_free (str
, TRUE
);
151 mono_signature_get_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
155 GString
*res
= g_string_new ("");
157 for (i
= 0; i
< sig
->param_count
; ++i
) {
159 g_string_append_c (res
, ',');
160 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
163 g_string_free (res
, FALSE
);
168 * mono_method_desc_new:
169 * @name: the method name.
170 * @include_namespace: whether the name includes a namespace or not.
172 * Creates a method description for @name, which conforms to the following
175 * [namespace.]classname:methodname[(args...)]
177 * in all the loaded assemblies.
179 * Returns: a parsed representation of the method description.
182 mono_method_desc_new (const char *name
, gboolean include_namespace
)
184 MonoMethodDesc
*result
;
185 char *class_name
, *class_nspace
, *method_name
, *use_args
, *end
;
188 class_nspace
= g_strdup (name
);
189 use_args
= strchr (class_nspace
, '(');
192 end
= strchr (use_args
, ')');
194 g_free (class_nspace
);
199 method_name
= strrchr (class_nspace
, ':');
201 g_free (class_nspace
);
205 /* allow two :: to separate the method name */
206 if (*method_name
== ':')
208 class_name
= strrchr (class_nspace
, '.');
213 class_name
= class_nspace
;
216 result
= g_new0 (MonoMethodDesc
, 1);
217 result
->include_namespace
= include_namespace
;
218 result
->name
= method_name
;
219 result
->klass
= class_name
;
220 result
->namespace = use_namespace
? class_nspace
: NULL
;
221 result
->args
= use_args
? use_args
: NULL
;
225 result
->num_args
= 1;
237 mono_method_desc_from_method (MonoMethod
*method
)
239 MonoMethodDesc
*result
;
241 result
= g_new0 (MonoMethodDesc
, 1);
242 result
->include_namespace
= TRUE
;
243 result
->name
= g_strdup (method
->name
);
244 result
->klass
= g_strdup (method
->klass
->name
);
245 result
->namespace = g_strdup (method
->klass
->name_space
);
251 * mono_method_desc_free:
252 * @desc: method description to be released
254 * Releases the MonoMethodDesc object @desc.
257 mono_method_desc_free (MonoMethodDesc
*desc
)
260 g_free (desc
->namespace);
261 else if (desc
->klass
)
262 g_free (desc
->klass
);
267 * namespace and class are supposed to match already if this function is used.
270 mono_method_desc_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
273 if (strcmp (desc
->name
, method
->name
))
277 if (desc
->num_args
!= mono_method_signature (method
)->param_count
)
279 sig
= mono_signature_get_desc (mono_method_signature (method
), desc
->include_namespace
);
280 if (strcmp (sig
, desc
->args
)) {
289 mono_method_desc_full_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
291 if (strcmp (desc
->klass
, method
->klass
->name
))
293 if (desc
->namespace && strcmp (desc
->namespace, method
->klass
->name_space
))
295 return mono_method_desc_match (desc
, method
);
299 mono_method_desc_search_in_class (MonoMethodDesc
*desc
, MonoClass
*klass
)
302 gpointer iter
= NULL
;
304 while ((m
= mono_class_get_methods (klass
, &iter
)))
305 if (mono_method_desc_match (desc
, m
))
311 mono_method_desc_search_in_image (MonoMethodDesc
*desc
, MonoImage
*image
)
314 const MonoTableInfo
*tdef
;
315 const MonoTableInfo
*methods
;
319 if (desc
->namespace && desc
->klass
) {
320 klass
= mono_class_from_name (image
, desc
->namespace, desc
->klass
);
323 return mono_method_desc_search_in_class (desc
, klass
);
326 tdef
= mono_image_get_table_info (image
, MONO_TABLE_TYPEDEF
);
327 methods
= mono_image_get_table_info (image
, MONO_TABLE_METHOD
);
328 for (i
= 0; i
< mono_table_info_get_rows (methods
); ++i
) {
329 guint32 token
= mono_metadata_decode_row_col (methods
, i
, MONO_METHOD_NAME
);
330 const char *n
= mono_metadata_string_heap (image
, token
);
332 if (strcmp (n
, desc
->name
))
334 method
= mono_get_method (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
);
335 if (mono_method_desc_full_match (desc
, method
))
341 static const unsigned char*
342 dis_one (GString
*str
, MonoDisHelper
*dh
, MonoMethod
*method
, const unsigned char *ip
, const unsigned char *end
)
344 MonoMethodHeader
*header
= mono_method_get_header (method
);
345 const MonoOpcode
*opcode
;
346 guint32 label
, token
;
350 const unsigned char* il_code
= mono_method_header_get_code (header
, NULL
, NULL
);
352 label
= ip
- il_code
;
354 tmp
= dh
->indenter (dh
, method
, label
);
355 g_string_append (str
, tmp
);
358 if (dh
->label_format
)
359 g_string_sprintfa (str
, dh
->label_format
, label
);
361 i
= mono_opcode_value (&ip
, end
);
363 opcode
= &mono_opcodes
[i
];
364 g_string_sprintfa (str
, "%-10s", mono_opcode_name (i
));
366 switch (opcode
->argument
) {
370 case MonoInlineField
:
371 case MonoInlineMethod
:
376 tmp
= dh
->tokener (dh
, method
, token
);
377 g_string_append (str
, tmp
);
380 g_string_sprintfa (str
, "0x%08x", token
);
384 case MonoInlineString
:
389 g_string_sprintfa (str
, "%d", read16 (ip
));
392 case MonoShortInlineVar
:
393 g_string_sprintfa (str
, "%d", (*ip
));
396 case MonoInlineBrTarget
:
399 if (dh
->label_target
)
400 g_string_sprintfa (str
, dh
->label_target
, ip
+ sval
- il_code
);
402 g_string_sprintfa (str
, "%d", sval
);
404 case MonoShortInlineBrTarget
:
405 sval
= *(const signed char*)ip
;
407 if (dh
->label_target
)
408 g_string_sprintfa (str
, dh
->label_target
, ip
+ sval
- il_code
);
410 g_string_sprintfa (str
, "%d", sval
);
412 case MonoInlineSwitch
: {
413 const unsigned char *end
;
417 g_string_append_c (str
, '(');
418 for (i
= 0; i
< sval
; ++i
) {
420 g_string_append (str
, ", ");
422 if (dh
->label_target
)
423 g_string_sprintfa (str
, dh
->label_target
, end
+ label
- il_code
);
425 g_string_sprintfa (str
, "%d", label
);
428 g_string_append_c (str
, ')');
434 g_string_sprintfa (str
, "%g", r
);
438 case MonoShortInlineR
: {
441 g_string_sprintfa (str
, "%g", r
);
446 g_string_sprintfa (str
, "%d", (gint32
)read32 (ip
));
449 case MonoShortInlineI
:
450 g_string_sprintfa (str
, "%d", *(const signed char*)ip
);
457 g_assert_not_reached ();
460 g_string_append (str
, dh
->newline
);
468 "IL_%04x: ", /* label_format */
469 "IL_%04x", /* label_target */
476 mono_disasm_code_one (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
**endp
)
479 GString
*res
= g_string_new ("");
483 /* set ip + 2 as the end: this is just a debugging method */
484 ip
= dis_one (res
, dh
, method
, ip
, ip
+ 2);
489 g_string_free (res
, FALSE
);
494 mono_disasm_code (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
* end
)
497 GString
*res
= g_string_new ("");
502 ip
= dis_one (res
, dh
, method
, ip
, end
);
506 g_string_free (res
, FALSE
);
511 wrapper_type_to_str (guint32 wrapper_type
)
513 g_assert (wrapper_type
< sizeof (wrapper_type_names
) / sizeof (char*));
515 return wrapper_type_names
[wrapper_type
];
519 mono_method_full_name (MonoMethod
*method
, gboolean signature
)
523 const char *nspace
= method
->klass
->name_space
;
526 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
528 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
529 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
531 strcpy (wrapper
, "");
532 res
= g_strdup_printf ("%s%s%s%s:%s (%s)", wrapper
,
533 nspace
, *nspace
? "." : "",
534 method
->klass
->name
, method
->name
, tmpsig
);
538 res
= g_strdup_printf ("%02d %s%s%s:%s", method
->wrapper_type
,
539 nspace
, *nspace
? "." : "",
540 method
->klass
->name
, method
->name
);
547 print_name_space (MonoClass
*klass
)
549 if (klass
->nested_in
) {
550 print_name_space (klass
->nested_in
);
551 g_print (klass
->nested_in
->name
);
554 if (klass
->name_space
[0]) {
555 g_print (klass
->name_space
);
562 * mono_object_describe:
564 * Prints to stdout a small description of the object @obj.
565 * For use in a debugger.
568 mono_object_describe (MonoObject
*obj
)
573 g_print ("(null)\n");
576 klass
= mono_object_class (obj
);
577 if (klass
== mono_defaults
.string_class
) {
578 char *utf8
= mono_string_to_utf8 ((MonoString
*)obj
);
579 if (strlen (utf8
) > 60) {
585 g_print ("String at %p, length: %d, '%s'\n", obj
, mono_string_length ((MonoString
*) obj
), utf8
);
587 } else if (klass
->rank
) {
588 MonoArray
*array
= (MonoArray
*)obj
;
589 sep
= print_name_space (klass
);
590 g_print ("%s%s", sep
, klass
->name
);
591 g_print (" at %p, rank: %d, length: %d\n", obj
, klass
->rank
, mono_array_length (array
));
593 sep
= print_name_space (klass
);
594 g_print ("%s%s", sep
, klass
->name
);
595 g_print (" object at %p (klass: %p)\n", obj
, klass
);
601 print_field_value (const char *field_ptr
, MonoClassField
*field
, int type_offset
)
604 g_print ("At %p (ofs: %2d) %s: ", field_ptr
, field
->offset
+ type_offset
, field
->name
);
605 type
= mono_type_get_underlying_type (field
->type
);
607 switch (type
->type
) {
611 case MONO_TYPE_FNPTR
:
612 g_print ("%p\n", *(const void**)field_ptr
);
614 case MONO_TYPE_STRING
:
615 case MONO_TYPE_SZARRAY
:
616 case MONO_TYPE_CLASS
:
617 case MONO_TYPE_OBJECT
:
618 case MONO_TYPE_ARRAY
:
619 mono_object_describe (*(MonoObject
**)field_ptr
);
621 case MONO_TYPE_GENERICINST
:
622 if (!mono_type_generic_inst_is_valuetype (type
)) {
623 mono_object_describe (*(MonoObject
**)field_ptr
);
628 case MONO_TYPE_VALUETYPE
: {
629 MonoClass
*k
= mono_class_from_mono_type (type
);
630 g_print ("%s ValueType (type: %p) at %p\n", k
->name
, k
, field_ptr
);
634 g_print ("%d\n", *(gint8
*)field_ptr
);
637 g_print ("%d\n", *(guint8
*)field_ptr
);
640 g_print ("%d\n", *(gint16
*)field_ptr
);
643 g_print ("%d\n", *(guint16
*)field_ptr
);
646 g_print ("%d\n", *(gint32
*)field_ptr
);
649 g_print ("%u\n", *(guint32
*)field_ptr
);
652 g_print ("%lld\n", *(gint64
*)field_ptr
);
655 g_print ("%llu\n", *(guint64
*)field_ptr
);
658 g_print ("%f\n", *(gfloat
*)field_ptr
);
661 g_print ("%f\n", *(gdouble
*)field_ptr
);
663 case MONO_TYPE_BOOLEAN
:
664 g_print ("%s (%d)\n", *(guint8
*)field_ptr
? "True": "False", *(guint8
*)field_ptr
);
667 g_print ("'%c' (%d 0x%04x)\n", *(guint16
*)field_ptr
, *(guint16
*)field_ptr
, *(guint16
*)field_ptr
);
670 g_assert_not_reached ();
676 objval_describe (MonoClass
*class, const char *addr
)
678 MonoClassField
*field
;
680 const char *field_ptr
;
682 if (class->valuetype
)
683 type_offset
= -sizeof (MonoObject
);
685 for (p
= class; p
!= NULL
; p
= p
->parent
) {
686 gpointer iter
= NULL
;
687 int printed_header
= FALSE
;
688 while ((field
= mono_class_get_fields (p
, &iter
))) {
689 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
692 if (p
!= class && !printed_header
) {
694 g_print ("In class ");
695 sep
= print_name_space (p
);
696 g_print ("%s%s:\n", sep
, p
->name
);
697 printed_header
= TRUE
;
699 field_ptr
= (const char*)addr
+ field
->offset
+ type_offset
;
701 print_field_value (field_ptr
, field
, type_offset
);
707 * mono_object_describe_fields:
709 * Prints to stdout a small description of each field of the object @obj.
710 * For use in a debugger.
713 mono_object_describe_fields (MonoObject
*obj
)
715 MonoClass
*class = mono_object_class (obj
);
716 objval_describe (class, (char*)obj
);
720 * mono_value_describe_fields:
722 * Prints to stdout a small description of each field of the value type
723 * stored at @addr of type @klass.
724 * For use in a debugger.
727 mono_value_describe_fields (MonoClass
* klass
, const char* addr
)
729 objval_describe (klass
, addr
);
733 * mono_class_describe_statics:
735 * Prints to stdout a small description of each static field of the type @klass
736 * in the current application domain.
737 * For use in a debugger.
740 mono_class_describe_statics (MonoClass
* klass
)
742 MonoClassField
*field
;
744 const char *field_ptr
;
745 const char *addr
= mono_class_vtable (mono_domain_get (), klass
)->data
;
749 for (p
= klass
; p
!= NULL
; p
= p
->parent
) {
750 gpointer iter
= NULL
;
751 while ((field
= mono_class_get_fields (p
, &iter
))) {
752 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
754 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
757 field_ptr
= (const char*)addr
+ field
->offset
;
759 print_field_value (field_ptr
, field
, 0);