2 * console-io.c: ConsoleDriver internal calls
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
11 #include "mono/metadata/tokentype.h"
12 #include "mono/metadata/opcodes.h"
13 #include "mono/metadata/class-internals.h"
14 #include "mono/metadata/mono-endian.h"
15 #include "mono/metadata/debug-helpers.h"
16 #include "mono/metadata/tabledefs.h"
17 #include "mono/metadata/appdomain.h"
19 struct MonoMethodDesc
{
25 gboolean include_namespace
;
28 #ifdef HAVE_ARRAY_ELEM_INIT
29 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
30 #define MSGSTRFIELD1(line) str##line
31 static const struct msgstr_t
{
32 #define WRAPPER(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
33 #include "wrapper-types.h"
36 #define WRAPPER(a,b) b,
37 #include "wrapper-types.h"
40 static const gint16 opidx
[] = {
41 #define WRAPPER(a,b) [MONO_WRAPPER_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
42 #include "wrapper-types.h"
47 wrapper_type_to_str (guint32 wrapper_type
)
49 g_assert (wrapper_type
< MONO_WRAPPER_NUM
);
51 return (const char*)&opstr
+ opidx
[wrapper_type
];
55 #define WRAPPER(a,b) b,
56 static const char* const
57 wrapper_type_names
[MONO_WRAPPER_NUM
+ 1] = {
58 #include "wrapper-types.h"
63 wrapper_type_to_str (guint32 wrapper_type
)
65 g_assert (wrapper_type
< MONO_WRAPPER_NUM
);
67 return wrapper_type_names
[wrapper_type
];
73 append_class_name (GString
*res
, MonoClass
*class, gboolean include_namespace
)
76 g_string_append (res
, "Unknown");
79 if (class->nested_in
) {
80 append_class_name (res
, class->nested_in
, include_namespace
);
81 g_string_append_c (res
, '/');
83 if (include_namespace
&& *(class->name_space
))
84 g_string_sprintfa (res
, "%s.", class->name_space
);
85 g_string_sprintfa (res
, "%s", class->name
);
89 mono_type_get_desc (GString
*res
, MonoType
*type
, gboolean include_namespace
)
95 g_string_append (res
, "void"); break;
97 g_string_append (res
, "char"); break;
98 case MONO_TYPE_BOOLEAN
:
99 g_string_append (res
, "bool"); break;
101 g_string_append (res
, "byte"); break;
103 g_string_append (res
, "sbyte"); break;
105 g_string_append (res
, "uint16"); break;
107 g_string_append (res
, "int16"); break;
109 g_string_append (res
, "uint"); break;
111 g_string_append (res
, "int"); break;
113 g_string_append (res
, "ulong"); break;
115 g_string_append (res
, "long"); break;
116 case MONO_TYPE_FNPTR
: /* who cares for the exact signature? */
117 g_string_append (res
, "*()"); break;
119 g_string_append (res
, "uintptr"); break;
121 g_string_append (res
, "intptr"); break;
123 g_string_append (res
, "single"); break;
125 g_string_append (res
, "double"); break;
126 case MONO_TYPE_STRING
:
127 g_string_append (res
, "string"); break;
128 case MONO_TYPE_OBJECT
:
129 g_string_append (res
, "object"); break;
131 mono_type_get_desc (res
, type
->data
.type
, include_namespace
);
132 g_string_append_c (res
, '*');
134 case MONO_TYPE_ARRAY
:
135 mono_type_get_desc (res
, &type
->data
.array
->eklass
->byval_arg
, include_namespace
);
136 g_string_sprintfa (res
, "[%d]", type
->data
.array
->rank
);
138 case MONO_TYPE_SZARRAY
:
139 mono_type_get_desc (res
, &type
->data
.klass
->byval_arg
, include_namespace
);
140 g_string_append (res
, "[]");
142 case MONO_TYPE_CLASS
:
143 case MONO_TYPE_VALUETYPE
:
144 append_class_name (res
, type
->data
.klass
, include_namespace
);
146 case MONO_TYPE_GENERICINST
: {
147 MonoGenericContext
*context
;
149 mono_type_get_desc (res
, &type
->data
.generic_class
->container_class
->byval_arg
, include_namespace
);
150 g_string_append (res
, "<");
151 context
= &type
->data
.generic_class
->context
;
152 if (context
->class_inst
) {
153 for (i
= 0; i
< context
->class_inst
->type_argc
; ++i
) {
155 g_string_append (res
, ", ");
156 mono_type_get_desc (res
, context
->class_inst
->type_argv
[i
], include_namespace
);
159 if (context
->method_inst
) {
160 if (context
->class_inst
)
161 g_string_append (res
, "; ");
162 for (i
= 0; i
< context
->method_inst
->type_argc
; ++i
) {
164 g_string_append (res
, ", ");
165 mono_type_get_desc (res
, context
->method_inst
->type_argv
[i
], include_namespace
);
168 g_string_append (res
, ">");
173 g_string_append (res
, type
->data
.generic_param
->name
);
179 g_string_append_c (res
, '&');
183 mono_type_full_name (MonoType
*type
)
188 str
= g_string_new ("");
189 mono_type_get_desc (str
, type
, TRUE
);
191 res
= g_strdup (str
->str
);
192 g_string_free (str
, TRUE
);
197 mono_signature_get_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
201 GString
*res
= g_string_new ("");
203 for (i
= 0; i
< sig
->param_count
; ++i
) {
205 g_string_append_c (res
, ',');
206 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
209 g_string_free (res
, FALSE
);
214 ginst_get_desc (GString
*str
, MonoGenericInst
*ginst
)
218 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
220 g_string_append (str
, ", ");
221 mono_type_get_desc (str
, ginst
->type_argv
[i
], TRUE
);
226 mono_context_get_desc (MonoGenericContext
*context
)
231 str
= g_string_new ("");
232 g_string_append (str
, "<");
234 if (context
->class_inst
)
235 ginst_get_desc (str
, context
->class_inst
);
236 if (context
->method_inst
) {
237 if (context
->class_inst
)
238 g_string_append (str
, "; ");
239 ginst_get_desc (str
, context
->method_inst
);
242 g_string_append (str
, ">");
243 res
= g_strdup (str
->str
);
244 g_string_free (str
, TRUE
);
249 * mono_method_desc_new:
250 * @name: the method name.
251 * @include_namespace: whether the name includes a namespace or not.
253 * Creates a method description for @name, which conforms to the following
256 * [namespace.]classname:methodname[(args...)]
258 * in all the loaded assemblies.
260 * Returns: a parsed representation of the method description.
263 mono_method_desc_new (const char *name
, gboolean include_namespace
)
265 MonoMethodDesc
*result
;
266 char *class_name
, *class_nspace
, *method_name
, *use_args
, *end
;
269 class_nspace
= g_strdup (name
);
270 use_args
= strchr (class_nspace
, '(');
273 end
= strchr (use_args
, ')');
275 g_free (class_nspace
);
280 method_name
= strrchr (class_nspace
, ':');
282 g_free (class_nspace
);
286 /* allow two :: to separate the method name */
287 if (*method_name
== ':')
289 class_name
= strrchr (class_nspace
, '.');
294 class_name
= class_nspace
;
297 result
= g_new0 (MonoMethodDesc
, 1);
298 result
->include_namespace
= include_namespace
;
299 result
->name
= method_name
;
300 result
->klass
= class_name
;
301 result
->namespace = use_namespace
? class_nspace
: NULL
;
302 result
->args
= use_args
? use_args
: NULL
;
306 result
->num_args
= 1;
318 mono_method_desc_from_method (MonoMethod
*method
)
320 MonoMethodDesc
*result
;
322 result
= g_new0 (MonoMethodDesc
, 1);
323 result
->include_namespace
= TRUE
;
324 result
->name
= g_strdup (method
->name
);
325 result
->klass
= g_strdup (method
->klass
->name
);
326 result
->namespace = g_strdup (method
->klass
->name_space
);
332 * mono_method_desc_free:
333 * @desc: method description to be released
335 * Releases the MonoMethodDesc object @desc.
338 mono_method_desc_free (MonoMethodDesc
*desc
)
341 g_free (desc
->namespace);
342 else if (desc
->klass
)
343 g_free (desc
->klass
);
348 * namespace and class are supposed to match already if this function is used.
351 mono_method_desc_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
354 if (strcmp (desc
->name
, method
->name
))
358 if (desc
->num_args
!= mono_method_signature (method
)->param_count
)
360 sig
= mono_signature_get_desc (mono_method_signature (method
), desc
->include_namespace
);
361 if (strcmp (sig
, desc
->args
)) {
370 my_strrchr (const char *str
, char ch
, int *len
)
374 for (pos
= (*len
)-1; pos
>= 0; pos
--) {
386 match_class (MonoMethodDesc
*desc
, int pos
, MonoClass
*klass
)
390 p
= my_strrchr (desc
->klass
, '/', &pos
);
392 if (strncmp (desc
->klass
, klass
->name
, pos
))
394 if (desc
->namespace && strcmp (desc
->namespace, klass
->name_space
))
399 if (strcmp (p
+1, klass
->name
))
401 if (!klass
->nested_in
)
404 return match_class (desc
, pos
, klass
->nested_in
);
408 mono_method_desc_full_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
410 if (!match_class (desc
, strlen (desc
->klass
), method
->klass
))
413 return mono_method_desc_match (desc
, method
);
417 mono_method_desc_search_in_class (MonoMethodDesc
*desc
, MonoClass
*klass
)
420 gpointer iter
= NULL
;
422 while ((m
= mono_class_get_methods (klass
, &iter
)))
423 if (mono_method_desc_match (desc
, m
))
429 mono_method_desc_search_in_image (MonoMethodDesc
*desc
, MonoImage
*image
)
432 const MonoTableInfo
*tdef
;
433 const MonoTableInfo
*methods
;
437 if (desc
->namespace && desc
->klass
) {
438 klass
= mono_class_from_name (image
, desc
->namespace, desc
->klass
);
441 return mono_method_desc_search_in_class (desc
, klass
);
444 tdef
= mono_image_get_table_info (image
, MONO_TABLE_TYPEDEF
);
445 methods
= mono_image_get_table_info (image
, MONO_TABLE_METHOD
);
446 for (i
= 0; i
< mono_table_info_get_rows (methods
); ++i
) {
447 guint32 token
= mono_metadata_decode_row_col (methods
, i
, MONO_METHOD_NAME
);
448 const char *n
= mono_metadata_string_heap (image
, token
);
450 if (strcmp (n
, desc
->name
))
452 method
= mono_get_method (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
);
453 if (mono_method_desc_full_match (desc
, method
))
459 static const unsigned char*
460 dis_one (GString
*str
, MonoDisHelper
*dh
, MonoMethod
*method
, const unsigned char *ip
, const unsigned char *end
)
462 MonoMethodHeader
*header
= mono_method_get_header (method
);
463 const MonoOpcode
*opcode
;
464 guint32 label
, token
;
468 const unsigned char* il_code
= mono_method_header_get_code (header
, NULL
, NULL
);
470 label
= ip
- il_code
;
472 tmp
= dh
->indenter (dh
, method
, label
);
473 g_string_append (str
, tmp
);
476 if (dh
->label_format
)
477 g_string_sprintfa (str
, dh
->label_format
, label
);
479 i
= mono_opcode_value (&ip
, end
);
481 opcode
= &mono_opcodes
[i
];
482 g_string_sprintfa (str
, "%-10s", mono_opcode_name (i
));
484 switch (opcode
->argument
) {
488 case MonoInlineField
:
489 case MonoInlineMethod
:
494 tmp
= dh
->tokener (dh
, method
, token
);
495 g_string_append (str
, tmp
);
498 g_string_sprintfa (str
, "0x%08x", token
);
502 case MonoInlineString
:
507 g_string_sprintfa (str
, "%d", read16 (ip
));
510 case MonoShortInlineVar
:
511 g_string_sprintfa (str
, "%d", (*ip
));
514 case MonoInlineBrTarget
:
517 if (dh
->label_target
)
518 g_string_sprintfa (str
, dh
->label_target
, ip
+ sval
- il_code
);
520 g_string_sprintfa (str
, "%d", sval
);
522 case MonoShortInlineBrTarget
:
523 sval
= *(const signed char*)ip
;
525 if (dh
->label_target
)
526 g_string_sprintfa (str
, dh
->label_target
, ip
+ sval
- il_code
);
528 g_string_sprintfa (str
, "%d", sval
);
530 case MonoInlineSwitch
: {
531 const unsigned char *end
;
535 g_string_append_c (str
, '(');
536 for (i
= 0; i
< sval
; ++i
) {
538 g_string_append (str
, ", ");
540 if (dh
->label_target
)
541 g_string_sprintfa (str
, dh
->label_target
, end
+ label
- il_code
);
543 g_string_sprintfa (str
, "%d", label
);
546 g_string_append_c (str
, ')');
552 g_string_sprintfa (str
, "%g", r
);
556 case MonoShortInlineR
: {
559 g_string_sprintfa (str
, "%g", r
);
564 g_string_sprintfa (str
, "%d", (gint32
)read32 (ip
));
567 case MonoShortInlineI
:
568 g_string_sprintfa (str
, "%d", *(const signed char*)ip
);
575 g_assert_not_reached ();
578 g_string_append (str
, dh
->newline
);
586 "IL_%04x: ", /* label_format */
587 "IL_%04x", /* label_target */
594 mono_disasm_code_one (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
**endp
)
597 GString
*res
= g_string_new ("");
601 /* set ip + 2 as the end: this is just a debugging method */
602 ip
= dis_one (res
, dh
, method
, ip
, ip
+ 2);
607 g_string_free (res
, FALSE
);
612 mono_disasm_code (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
* end
)
615 GString
*res
= g_string_new ("");
620 ip
= dis_one (res
, dh
, method
, ip
, end
);
624 g_string_free (res
, FALSE
);
629 mono_field_full_name (MonoClassField
*field
)
632 const char *nspace
= field
->parent
->name_space
;
634 res
= g_strdup_printf ("%s%s%s:%s", nspace
, *nspace
? "." : "",
635 field
->parent
->name
, mono_field_get_name (field
));
641 mono_method_full_name (MonoMethod
*method
, gboolean signature
)
645 char *klass_desc
= mono_type_full_name (&method
->klass
->byval_arg
);
646 char *inst_desc
= NULL
;
648 if (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->context
.method_inst
) {
649 GString
*str
= g_string_new ("");
650 g_string_append (str
, "<");
651 ginst_get_desc (str
, ((MonoMethodInflated
*)method
)->context
.method_inst
);
652 g_string_append (str
, ">");
654 inst_desc
= str
->str
;
655 g_string_free (str
, FALSE
);
658 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
659 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
661 strcpy (wrapper
, "");
664 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
666 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
667 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
669 strcpy (wrapper
, "");
670 res
= g_strdup_printf ("%s%s:%s%s (%s)", wrapper
, klass_desc
,
671 method
->name
, inst_desc
? inst_desc
: "", tmpsig
);
674 res
= g_strdup_printf ("%s%s:%s%s", wrapper
, klass_desc
,
675 method
->name
, inst_desc
? inst_desc
: "");
685 print_name_space (MonoClass
*klass
)
687 if (klass
->nested_in
) {
688 print_name_space (klass
->nested_in
);
689 g_print (klass
->nested_in
->name
);
692 if (klass
->name_space
[0]) {
693 g_print (klass
->name_space
);
700 * mono_object_describe:
702 * Prints to stdout a small description of the object @obj.
703 * For use in a debugger.
706 mono_object_describe (MonoObject
*obj
)
711 g_print ("(null)\n");
714 klass
= mono_object_class (obj
);
715 if (klass
== mono_defaults
.string_class
) {
716 char *utf8
= mono_string_to_utf8 ((MonoString
*)obj
);
717 if (strlen (utf8
) > 60) {
723 g_print ("String at %p, length: %d, '%s'\n", obj
, mono_string_length ((MonoString
*) obj
), utf8
);
725 } else if (klass
->rank
) {
726 MonoArray
*array
= (MonoArray
*)obj
;
727 sep
= print_name_space (klass
);
728 g_print ("%s%s", sep
, klass
->name
);
729 g_print (" at %p, rank: %d, length: %d\n", obj
, klass
->rank
, mono_array_length (array
));
731 sep
= print_name_space (klass
);
732 g_print ("%s%s", sep
, klass
->name
);
733 g_print (" object at %p (klass: %p)\n", obj
, klass
);
739 print_field_value (const char *field_ptr
, MonoClassField
*field
, int type_offset
)
742 g_print ("At %p (ofs: %2d) %s: ", field_ptr
, field
->offset
+ type_offset
, mono_field_get_name (field
));
743 type
= mono_type_get_underlying_type (field
->type
);
745 switch (type
->type
) {
749 case MONO_TYPE_FNPTR
:
750 g_print ("%p\n", *(const void**)field_ptr
);
752 case MONO_TYPE_STRING
:
753 case MONO_TYPE_SZARRAY
:
754 case MONO_TYPE_CLASS
:
755 case MONO_TYPE_OBJECT
:
756 case MONO_TYPE_ARRAY
:
757 mono_object_describe (*(MonoObject
**)field_ptr
);
759 case MONO_TYPE_GENERICINST
:
760 if (!mono_type_generic_inst_is_valuetype (type
)) {
761 mono_object_describe (*(MonoObject
**)field_ptr
);
766 case MONO_TYPE_VALUETYPE
: {
767 MonoClass
*k
= mono_class_from_mono_type (type
);
768 g_print ("%s ValueType (type: %p) at %p\n", k
->name
, k
, field_ptr
);
772 g_print ("%d\n", *(gint8
*)field_ptr
);
775 g_print ("%d\n", *(guint8
*)field_ptr
);
778 g_print ("%d\n", *(gint16
*)field_ptr
);
781 g_print ("%d\n", *(guint16
*)field_ptr
);
784 g_print ("%d\n", *(gint32
*)field_ptr
);
787 g_print ("%u\n", *(guint32
*)field_ptr
);
790 g_print ("%lld\n", (long long int)*(gint64
*)field_ptr
);
793 g_print ("%llu\n", (long long unsigned int)*(guint64
*)field_ptr
);
796 g_print ("%f\n", *(gfloat
*)field_ptr
);
799 g_print ("%f\n", *(gdouble
*)field_ptr
);
801 case MONO_TYPE_BOOLEAN
:
802 g_print ("%s (%d)\n", *(guint8
*)field_ptr
? "True": "False", *(guint8
*)field_ptr
);
805 g_print ("'%c' (%d 0x%04x)\n", *(guint16
*)field_ptr
, *(guint16
*)field_ptr
, *(guint16
*)field_ptr
);
808 g_assert_not_reached ();
814 objval_describe (MonoClass
*class, const char *addr
)
816 MonoClassField
*field
;
818 const char *field_ptr
;
819 gssize type_offset
= 0;
820 if (class->valuetype
)
821 type_offset
= -sizeof (MonoObject
);
823 for (p
= class; p
!= NULL
; p
= p
->parent
) {
824 gpointer iter
= NULL
;
825 int printed_header
= FALSE
;
826 while ((field
= mono_class_get_fields (p
, &iter
))) {
827 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
830 if (p
!= class && !printed_header
) {
832 g_print ("In class ");
833 sep
= print_name_space (p
);
834 g_print ("%s%s:\n", sep
, p
->name
);
835 printed_header
= TRUE
;
837 field_ptr
= (const char*)addr
+ field
->offset
+ type_offset
;
839 print_field_value (field_ptr
, field
, type_offset
);
845 * mono_object_describe_fields:
847 * Prints to stdout a small description of each field of the object @obj.
848 * For use in a debugger.
851 mono_object_describe_fields (MonoObject
*obj
)
853 MonoClass
*class = mono_object_class (obj
);
854 objval_describe (class, (char*)obj
);
858 * mono_value_describe_fields:
860 * Prints to stdout a small description of each field of the value type
861 * stored at @addr of type @klass.
862 * For use in a debugger.
865 mono_value_describe_fields (MonoClass
* klass
, const char* addr
)
867 objval_describe (klass
, addr
);
871 * mono_class_describe_statics:
873 * Prints to stdout a small description of each static field of the type @klass
874 * in the current application domain.
875 * For use in a debugger.
878 mono_class_describe_statics (MonoClass
* klass
)
880 MonoClassField
*field
;
882 const char *field_ptr
;
883 const char *addr
= mono_class_vtable (mono_domain_get (), klass
)->data
;
887 for (p
= klass
; p
!= NULL
; p
= p
->parent
) {
888 gpointer iter
= NULL
;
889 while ((field
= mono_class_get_fields (p
, &iter
))) {
890 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
892 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
895 field_ptr
= (const char*)addr
+ field
->offset
;
897 print_field_value (field_ptr
, field
, 0);