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.
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
35 struct MonoMethodDesc
{
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"
52 #define WRAPPER(a,b) b,
53 #include "wrapper-types.h"
56 static const gint16 opidx
[] = {
57 #define WRAPPER(a,b) offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
58 #include "wrapper-types.h"
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
];
71 append_class_name (GString
*res
, MonoClass
*klass
, gboolean include_namespace
)
74 g_string_append (res
, "Unknown");
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
);
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
;
114 mono_type_get_desc (GString
*res
, MonoType
*type
, gboolean include_namespace
)
118 switch (type
->type
) {
120 g_string_append (res
, "void"); break;
122 g_string_append (res
, "char"); break;
123 case MONO_TYPE_BOOLEAN
:
124 g_string_append (res
, "bool"); break;
126 g_string_append (res
, "byte"); break;
128 g_string_append (res
, "sbyte"); break;
130 g_string_append (res
, "uint16"); break;
132 g_string_append (res
, "int16"); break;
134 g_string_append (res
, "uint"); break;
136 g_string_append (res
, "int"); break;
138 g_string_append (res
, "ulong"); break;
140 g_string_append (res
, "long"); break;
141 case MONO_TYPE_FNPTR
: /* who cares for the exact signature? */
142 g_string_append (res
, "*()"); break;
144 g_string_append (res
, "uintptr"); break;
146 g_string_append (res
, "intptr"); break;
148 g_string_append (res
, "single"); break;
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;
156 mono_type_get_desc (res
, type
->data
.type
, include_namespace
);
157 g_string_append_c (res
, '*');
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
, ']');
166 case MONO_TYPE_SZARRAY
:
167 mono_type_get_desc (res
, &type
->data
.klass
->_byval_arg
, include_namespace
);
168 g_string_append (res
, "[]");
170 case MONO_TYPE_CLASS
:
171 case MONO_TYPE_VALUETYPE
:
172 append_class_name (res
, type
->data
.klass
, include_namespace
);
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
) {
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
) {
192 g_string_append (res
, ", ");
193 mono_type_get_desc (res
, context
->method_inst
->type_argv
[i
], include_namespace
);
196 g_string_append (res
, ">");
201 if (type
->data
.generic_param
) {
202 const char *name
= mono_generic_param_name (type
->data
.generic_param
);
204 g_string_append (res
, name
);
206 g_string_append_printf (res
, "%s%d", type
->type
== MONO_TYPE_VAR
? "!" : "!!", mono_generic_param_num (type
->data
.generic_param
));
208 g_string_append (res
, "<unknown>");
211 case MONO_TYPE_TYPEDBYREF
:
212 g_string_append (res
, "typedbyref");
218 g_string_append_c (res
, '&');
222 * mono_type_full_name:
225 mono_type_full_name (MonoType
*type
)
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:
238 mono_signature_get_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
245 return g_strdup ("<invalid signature>");
247 res
= g_string_new ("");
249 for (i
= 0; i
< sig
->param_count
; ++i
) {
251 g_string_append_c (res
, ',');
252 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
255 g_string_free (res
, FALSE
);
260 mono_signature_full_name (MonoMethodSignature
*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
) {
275 g_string_append_c (res
, ',');
276 mono_type_get_desc (res
, sig
->params
[i
], TRUE
);
278 g_string_append_c (res
, ')');
280 g_string_free (res
, FALSE
);
285 mono_ginst_get_desc (GString
*str
, MonoGenericInst
*ginst
)
289 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
291 g_string_append (str
, ", ");
292 mono_type_get_desc (str
, ginst
->type_argv
[i
], TRUE
);
297 mono_context_get_desc (MonoGenericContext
*context
)
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
);
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
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.
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
;
341 int generic_delim_stack
;
343 class_nspace
= g_strdup (name
);
344 use_args
= strchr (class_nspace
, '(');
346 /* Allow a ' ' between the method name and the signature */
347 if (use_args
> class_nspace
&& use_args
[-1] == ' ')
350 end
= strchr (use_args
, ')');
352 g_free (class_nspace
);
357 method_name
= strrchr (class_nspace
, ':');
359 g_free (class_nspace
);
362 /* allow two :: to separate the method name */
363 if (method_name
!= class_nspace
&& method_name
[-1] == ':')
364 method_name
[-1] = 0;
366 class_name
= strrchr (class_nspace
, '.');
371 class_name
= class_nspace
;
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
;
387 result
->num_args
= 1;
388 generic_delim_stack
= 0;
391 generic_delim_stack
++;
392 else if (*end
== '>')
393 generic_delim_stack
--;
395 if (*end
== ',' && generic_delim_stack
== 0)
405 * mono_method_desc_from_method:
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
);
422 * mono_method_desc_free:
423 * \param desc method description to be released
424 * Releases the \c MonoMethodDesc object \p desc.
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
);
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.
447 mono_method_desc_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
452 name_match
= strcmp (desc
->name
, method
->name
) == 0;
457 if (desc
->num_args
!= mono_method_signature_internal (method
)->param_count
)
459 sig
= mono_signature_get_desc (mono_method_signature_internal (method
), desc
->include_namespace
);
460 if (strcmp (sig
, desc
->args
)) {
469 my_strrchr (const char *str
, char ch
, int *len
)
473 for (pos
= (*len
)-1; pos
>= 0; pos
--) {
485 match_class (MonoMethodDesc
*desc
, int pos
, MonoClass
*klass
)
488 gboolean is_terminal
= TRUE
;
490 if (desc
->klass_glob
&& !strcmp (desc
->klass
, "*"))
493 if (desc
->klass_glob
&& g_pattern_match_simple (desc
->klass
, klass
->name
))
496 if (desc
->klass
[pos
] == '/')
499 p
= my_strrchr (desc
->klass
, '/', &pos
);
501 if (is_terminal
&& strcmp (desc
->klass
, klass
->name
))
503 if (!is_terminal
&& strncmp (desc
->klass
, klass
->name
, pos
))
505 if (desc
->name_space
&& strcmp (desc
->name_space
, klass
->name_space
))
510 if (strcmp (p
+1, klass
->name
))
512 if (!klass
->nested_in
)
515 return match_class (desc
, pos
, klass
->nested_in
);
519 * mono_method_desc_is_full:
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.
538 mono_method_desc_full_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
544 if (!match_class (desc
, strlen (desc
->klass
), method
->klass
))
547 return mono_method_desc_match (desc
, method
);
551 * mono_method_desc_search_in_class:
554 mono_method_desc_search_in_class (MonoMethodDesc
*desc
, MonoClass
*klass
)
557 gpointer iter
= NULL
;
559 while ((m
= mono_class_get_methods (klass
, &iter
)))
560 if (mono_method_desc_match (desc
, m
))
566 * mono_method_desc_search_in_image:
569 mono_method_desc_search_in_image (MonoMethodDesc
*desc
, MonoImage
*image
)
572 const MonoTableInfo
*methods
;
576 /* Handle short names for system classes */
577 if (!desc
->name_space
&& image
== mono_defaults
.corlib
) {
578 klass
= find_system_class (desc
->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
);
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
) {
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
))
600 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
, NULL
, error
);
602 mono_error_cleanup (error
);
605 if (mono_method_desc_full_match (desc
, method
))
611 static const unsigned char*
612 dis_one (GString
*str
, MonoDisHelper
*dh
, MonoMethod
*method
, const unsigned char *ip
, const unsigned char *end
)
615 MonoMethodHeader
*header
= mono_method_get_header_checked (method
, error
);
616 const MonoOpcode
*opcode
;
617 guint32 label
, token
;
621 const unsigned char* il_code
;
624 g_string_append_printf (str
, "could not disassemble, bad header due to %s", mono_error_get_message (error
));
625 mono_error_cleanup (error
);
628 il_code
= mono_method_header_get_code (header
, NULL
, NULL
);
630 label
= ip
- il_code
;
632 tmp
= dh
->indenter (dh
, method
, label
);
633 g_string_append (str
, tmp
);
636 if (dh
->label_format
)
637 g_string_append_printf (str
, dh
->label_format
, label
);
639 i
= mono_opcode_value (&ip
, end
);
641 opcode
= &mono_opcodes
[i
];
642 g_string_append_printf (str
, "%-10s", mono_opcode_name (i
));
644 switch (opcode
->argument
) {
648 case MonoInlineField
:
649 case MonoInlineMethod
:
654 tmp
= dh
->tokener (dh
, method
, token
);
655 g_string_append (str
, tmp
);
658 g_string_append_printf (str
, "0x%08x", token
);
662 case MonoInlineString
: {
668 if (!image_is_dynamic (method
->klass
->image
) && !method_is_dynamic (method
)) {
670 blob
= mono_metadata_user_string (method
->klass
->image
, mono_metadata_token_index (token
));
672 len2
= mono_metadata_decode_blob_size (blob
, &blob
);
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);
683 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
685 guint16
*buf
= g_new (guint16
, len2
+ 1);
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
);
694 s
= g_utf16_to_utf8 ((gunichar2
*)blob2
, len2
, NULL
, NULL
, NULL
);
697 g_string_append_printf (str
, "\"%s\"", s
);
706 g_string_append_printf (str
, "%d", read16 (ip
));
709 case MonoShortInlineVar
:
710 g_string_append_printf (str
, "%d", (*ip
));
713 case MonoInlineBrTarget
:
716 if (dh
->label_target
)
717 g_string_append_printf (str
, dh
->label_target
, ip
+ sval
- il_code
);
719 g_string_append_printf (str
, "%d", sval
);
721 case MonoShortInlineBrTarget
:
722 sval
= *(const signed char*)ip
;
724 if (dh
->label_target
)
725 g_string_append_printf (str
, dh
->label_target
, ip
+ sval
- il_code
);
727 g_string_append_printf (str
, "%d", sval
);
729 case MonoInlineSwitch
: {
730 const unsigned char *end
;
734 g_string_append_c (str
, '(');
735 for (i
= 0; i
< sval
; ++i
) {
737 g_string_append (str
, ", ");
739 if (dh
->label_target
)
740 g_string_append_printf (str
, dh
->label_target
, end
+ label
- il_code
);
742 g_string_append_printf (str
, "%d", label
);
745 g_string_append_c (str
, ')');
751 g_string_append_printf (str
, "%g", r
);
755 case MonoShortInlineR
: {
758 g_string_append_printf (str
, "%g", r
);
763 g_string_append_printf (str
, "%d", (gint32
)read32 (ip
));
766 case MonoShortInlineI
:
767 g_string_append_printf (str
, "%d", *(const signed char*)ip
);
774 g_assert_not_reached ();
777 g_string_append (str
, dh
->newline
);
779 mono_metadata_free_mh (header
);
786 "IL_%04x: ", /* label_format */
787 "IL_%04x", /* label_target */
794 * mono_disasm_code_one:
797 mono_disasm_code_one (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
**endp
)
800 GString
*res
= g_string_new ("");
804 /* set ip + 2 as the end: this is just a debugging method */
805 ip
= dis_one (res
, dh
, method
, ip
, ip
+ 2);
810 g_string_free (res
, FALSE
);
818 mono_disasm_code (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
* end
)
821 GString
*res
= g_string_new ("");
826 ip
= dis_one (res
, dh
, method
, ip
, end
);
830 g_string_free (res
, FALSE
);
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.
840 mono_field_full_name (MonoClassField
*field
)
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
));
852 mono_method_get_name_full (MonoMethod
*method
, gboolean signature
, gboolean ret
, MonoTypeNameFormat format
)
857 char *inst_desc
= NULL
;
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
);
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
, "<");
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
, '>');
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
, "<");
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
, '>');
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
));
907 strcpy (wrapper
, "");
910 MonoMethodSignature
*sig
= mono_method_signature_checked (method
, error
);
913 if (!is_ok (error
)) {
914 tmpsig
= g_strdup_printf ("<unable to load signature>");
915 mono_error_cleanup (error
);
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
));
923 strcpy (wrapper
, "");
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
);
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
);
937 res
= g_strdup_printf ("%s%s%s%s%s", wrapper
, klass_desc
,
938 class_method_separator
,
939 method
->name
, inst_desc
? inst_desc
: "");
949 * mono_method_full_name:
952 mono_method_full_name (MonoMethod
*method
, gboolean signature
)
955 MONO_ENTER_GC_UNSAFE
;
956 res
= mono_method_get_name_full (method
, signature
, FALSE
, MONO_TYPE_NAME_FORMAT_IL
);
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.
973 mono_method_get_reflection_name (MonoMethod
*method
)
975 return mono_method_get_name_full (method
, TRUE
, FALSE
, MONO_TYPE_NAME_FORMAT_REFLECTION
);
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
);
986 if (klass
->name_space
[0]) {
987 g_print ("%s", klass
->name_space
);
994 * mono_object_describe:
996 * Prints to stdout a small description of the object \p obj.
997 * For use in a debugger.
1000 mono_object_describe (MonoObject
*obj
)
1006 g_print ("(null)\n");
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) {
1020 g_print ("String at %p, length: %d, '%s'\n", obj
, mono_string_length_internal ((MonoString
*) obj
), utf8
);
1022 g_print ("String at %p, length: %d, unable to decode UTF16\n", obj
, mono_string_length_internal ((MonoString
*) obj
));
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
));
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
);
1039 print_field_value (const char *field_ptr
, MonoClassField
*field
, int type_offset
)
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
) {
1049 case MONO_TYPE_FNPTR
:
1050 g_print ("%p\n", *(const void**)field_ptr
);
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
);
1059 case MONO_TYPE_GENERICINST
:
1060 if (!mono_type_generic_inst_is_valuetype (type
)) {
1061 mono_object_describe (*(MonoObject
**)field_ptr
);
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
);
1072 g_print ("%d\n", *(gint8
*)field_ptr
);
1075 g_print ("%d\n", *(guint8
*)field_ptr
);
1078 g_print ("%d\n", *(gint16
*)field_ptr
);
1081 g_print ("%d\n", *(guint16
*)field_ptr
);
1084 g_print ("%d\n", *(gint32
*)field_ptr
);
1087 g_print ("%u\n", *(guint32
*)field_ptr
);
1090 g_print ("%lld\n", (long long int)*(gint64
*)field_ptr
);
1093 g_print ("%llu\n", (long long unsigned int)*(guint64
*)field_ptr
);
1096 g_print ("%f\n", *(gfloat
*)field_ptr
);
1099 g_print ("%f\n", *(gdouble
*)field_ptr
);
1101 case MONO_TYPE_BOOLEAN
:
1102 g_print ("%s (%d)\n", *(guint8
*)field_ptr
? "True": "False", *(guint8
*)field_ptr
);
1104 case MONO_TYPE_CHAR
:
1105 g_print ("'%c' (%d 0x%04x)\n", *(guint16
*)field_ptr
, *(guint16
*)field_ptr
, *(guint16
*)field_ptr
);
1108 g_assert_not_reached ();
1114 objval_describe (MonoClass
*klass
, const char *addr
)
1116 MonoClassField
*field
;
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
))
1131 if (p
!= klass
&& !printed_header
) {
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.
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.
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.
1179 mono_class_describe_statics (MonoClass
* klass
)
1182 MonoClassField
*field
;
1184 const char *field_ptr
;
1185 MonoVTable
*vtable
= mono_class_vtable_checked (mono_domain_get (), klass
, error
);
1188 if (!vtable
|| !is_ok (error
)) {
1189 mono_error_cleanup (error
);
1193 if (!(addr
= (const char *)mono_vtable_get_static_field_data (vtable
)))
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
)
1201 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
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.
1220 mono_method_print_code (MonoMethod
*method
)
1224 MonoMethodHeader
*header
= mono_method_get_header_checked (method
, error
);
1226 printf ("METHOD HEADER NOT FOUND DUE TO: %s\n", mono_error_get_message (error
));
1227 mono_error_cleanup (error
);
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
);