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/metadata-internals.h"
14 #include "mono/metadata/class-internals.h"
15 #include "mono/metadata/object-internals.h"
16 #include "mono/metadata/mono-endian.h"
17 #include "mono/metadata/debug-helpers.h"
18 #include "mono/metadata/tabledefs.h"
19 #include "mono/metadata/appdomain.h"
21 struct MonoMethodDesc
{
27 gboolean include_namespace
, klass_glob
, name_glob
;
30 #ifdef HAVE_ARRAY_ELEM_INIT
31 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
32 #define MSGSTRFIELD1(line) str##line
33 static const struct msgstr_t
{
34 #define WRAPPER(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
35 #include "wrapper-types.h"
38 #define WRAPPER(a,b) b,
39 #include "wrapper-types.h"
42 static const gint16 opidx
[] = {
43 #define WRAPPER(a,b) [MONO_WRAPPER_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
44 #include "wrapper-types.h"
49 wrapper_type_to_str (guint32 wrapper_type
)
51 g_assert (wrapper_type
< MONO_WRAPPER_NUM
);
53 return (const char*)&opstr
+ opidx
[wrapper_type
];
57 #define WRAPPER(a,b) b,
58 static const char* const
59 wrapper_type_names
[MONO_WRAPPER_NUM
+ 1] = {
60 #include "wrapper-types.h"
65 wrapper_type_to_str (guint32 wrapper_type
)
67 g_assert (wrapper_type
< MONO_WRAPPER_NUM
);
69 return wrapper_type_names
[wrapper_type
];
75 append_class_name (GString
*res
, MonoClass
*class, gboolean include_namespace
)
78 g_string_append (res
, "Unknown");
81 if (class->nested_in
) {
82 append_class_name (res
, class->nested_in
, include_namespace
);
83 g_string_append_c (res
, '/');
85 if (include_namespace
&& *(class->name_space
))
86 g_string_append_printf (res
, "%s.", class->name_space
);
87 g_string_append_printf (res
, "%s", class->name
);
91 find_system_class (const char *name
)
93 if (!strcmp (name
, "void"))
94 return mono_defaults
.void_class
;
95 else if (!strcmp (name
, "char")) return mono_defaults
.char_class
;
96 else if (!strcmp (name
, "bool")) return mono_defaults
.boolean_class
;
97 else if (!strcmp (name
, "byte")) return mono_defaults
.byte_class
;
98 else if (!strcmp (name
, "sbyte")) return mono_defaults
.sbyte_class
;
99 else if (!strcmp (name
, "uint16")) return mono_defaults
.uint16_class
;
100 else if (!strcmp (name
, "int16")) return mono_defaults
.int16_class
;
101 else if (!strcmp (name
, "uint")) return mono_defaults
.uint32_class
;
102 else if (!strcmp (name
, "int")) return mono_defaults
.int32_class
;
103 else if (!strcmp (name
, "ulong")) return mono_defaults
.uint64_class
;
104 else if (!strcmp (name
, "long")) return mono_defaults
.int64_class
;
105 else if (!strcmp (name
, "uintptr")) return mono_defaults
.uint_class
;
106 else if (!strcmp (name
, "intptr")) return mono_defaults
.int_class
;
107 else if (!strcmp (name
, "single")) return mono_defaults
.single_class
;
108 else if (!strcmp (name
, "double")) return mono_defaults
.double_class
;
109 else if (!strcmp (name
, "string")) return mono_defaults
.string_class
;
110 else if (!strcmp (name
, "object")) return mono_defaults
.object_class
;
116 mono_type_get_desc (GString
*res
, MonoType
*type
, gboolean include_namespace
)
120 switch (type
->type
) {
122 g_string_append (res
, "void"); break;
124 g_string_append (res
, "char"); break;
125 case MONO_TYPE_BOOLEAN
:
126 g_string_append (res
, "bool"); break;
128 g_string_append (res
, "byte"); break;
130 g_string_append (res
, "sbyte"); break;
132 g_string_append (res
, "uint16"); break;
134 g_string_append (res
, "int16"); break;
136 g_string_append (res
, "uint"); break;
138 g_string_append (res
, "int"); break;
140 g_string_append (res
, "ulong"); break;
142 g_string_append (res
, "long"); break;
143 case MONO_TYPE_FNPTR
: /* who cares for the exact signature? */
144 g_string_append (res
, "*()"); break;
146 g_string_append (res
, "uintptr"); break;
148 g_string_append (res
, "intptr"); break;
150 g_string_append (res
, "single"); break;
152 g_string_append (res
, "double"); break;
153 case MONO_TYPE_STRING
:
154 g_string_append (res
, "string"); break;
155 case MONO_TYPE_OBJECT
:
156 g_string_append (res
, "object"); break;
158 mono_type_get_desc (res
, type
->data
.type
, include_namespace
);
159 g_string_append_c (res
, '*');
161 case MONO_TYPE_ARRAY
:
162 mono_type_get_desc (res
, &type
->data
.array
->eklass
->byval_arg
, include_namespace
);
163 g_string_append_printf (res
, "[%d]", type
->data
.array
->rank
);
165 case MONO_TYPE_SZARRAY
:
166 mono_type_get_desc (res
, &type
->data
.klass
->byval_arg
, include_namespace
);
167 g_string_append (res
, "[]");
169 case MONO_TYPE_CLASS
:
170 case MONO_TYPE_VALUETYPE
:
171 append_class_name (res
, type
->data
.klass
, include_namespace
);
173 case MONO_TYPE_GENERICINST
: {
174 MonoGenericContext
*context
;
176 mono_type_get_desc (res
, &type
->data
.generic_class
->container_class
->byval_arg
, include_namespace
);
177 g_string_append (res
, "<");
178 context
= &type
->data
.generic_class
->context
;
179 if (context
->class_inst
) {
180 for (i
= 0; i
< context
->class_inst
->type_argc
; ++i
) {
182 g_string_append (res
, ", ");
183 mono_type_get_desc (res
, context
->class_inst
->type_argv
[i
], include_namespace
);
186 if (context
->method_inst
) {
187 if (context
->class_inst
)
188 g_string_append (res
, "; ");
189 for (i
= 0; i
< context
->method_inst
->type_argc
; ++i
) {
191 g_string_append (res
, ", ");
192 mono_type_get_desc (res
, context
->method_inst
->type_argv
[i
], include_namespace
);
195 g_string_append (res
, ">");
200 if (type
->data
.generic_param
) {
201 MonoGenericParamInfo
*info
= mono_generic_param_info (type
->data
.generic_param
);
203 g_string_append (res
, info
->name
);
205 g_string_append_printf (res
, "%s%d", type
->type
== MONO_TYPE_VAR
? "!" : "!!", mono_generic_param_num (type
->data
.generic_param
));
207 g_string_append (res
, "<unknown>");
210 case MONO_TYPE_TYPEDBYREF
:
211 g_string_append (res
, "typedbyref");
217 g_string_append_c (res
, '&');
221 mono_type_full_name (MonoType
*type
)
225 str
= g_string_new ("");
226 mono_type_get_desc (str
, type
, TRUE
);
227 return g_string_free (str
, FALSE
);
231 mono_signature_get_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
238 return g_strdup ("<invalid signature>");
240 res
= g_string_new ("");
242 for (i
= 0; i
< sig
->param_count
; ++i
) {
244 g_string_append_c (res
, ',');
245 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
248 g_string_free (res
, FALSE
);
253 ginst_get_desc (GString
*str
, MonoGenericInst
*ginst
)
257 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
259 g_string_append (str
, ", ");
260 mono_type_get_desc (str
, ginst
->type_argv
[i
], TRUE
);
265 mono_context_get_desc (MonoGenericContext
*context
)
270 str
= g_string_new ("");
271 g_string_append (str
, "<");
273 if (context
->class_inst
)
274 ginst_get_desc (str
, context
->class_inst
);
275 if (context
->method_inst
) {
276 if (context
->class_inst
)
277 g_string_append (str
, "; ");
278 ginst_get_desc (str
, context
->method_inst
);
281 g_string_append (str
, ">");
282 res
= g_strdup (str
->str
);
283 g_string_free (str
, TRUE
);
288 * mono_method_desc_new:
289 * @name: the method name.
290 * @include_namespace: whether the name includes a namespace or not.
292 * Creates a method description for @name, which conforms to the following
295 * [namespace.]classname:methodname[(args...)]
297 * in all the loaded assemblies.
299 * Both classname and methodname can contain '*' which matches anything.
301 * Returns: a parsed representation of the method description.
304 mono_method_desc_new (const char *name
, gboolean include_namespace
)
306 MonoMethodDesc
*result
;
307 char *class_name
, *class_nspace
, *method_name
, *use_args
, *end
;
310 class_nspace
= g_strdup (name
);
311 use_args
= strchr (class_nspace
, '(');
313 /* Allow a ' ' between the method name and the signature */
314 if (use_args
> class_nspace
&& use_args
[-1] == ' ')
317 end
= strchr (use_args
, ')');
319 g_free (class_nspace
);
324 method_name
= strrchr (class_nspace
, ':');
326 g_free (class_nspace
);
329 /* allow two :: to separate the method name */
330 if (method_name
!= class_nspace
&& method_name
[-1] == ':')
331 method_name
[-1] = 0;
333 class_name
= strrchr (class_nspace
, '.');
338 class_name
= class_nspace
;
341 result
= g_new0 (MonoMethodDesc
, 1);
342 result
->include_namespace
= include_namespace
;
343 result
->name
= method_name
;
344 result
->klass
= class_name
;
345 result
->namespace = use_namespace
? class_nspace
: NULL
;
346 result
->args
= use_args
? use_args
: NULL
;
347 if (strstr (result
->name
, "*"))
348 result
->name_glob
= TRUE
;
349 if (strstr (result
->klass
, "*"))
350 result
->klass_glob
= TRUE
;
354 result
->num_args
= 1;
366 mono_method_desc_from_method (MonoMethod
*method
)
368 MonoMethodDesc
*result
;
370 result
= g_new0 (MonoMethodDesc
, 1);
371 result
->include_namespace
= TRUE
;
372 result
->name
= g_strdup (method
->name
);
373 result
->klass
= g_strdup (method
->klass
->name
);
374 result
->namespace = g_strdup (method
->klass
->name_space
);
380 * mono_method_desc_free:
381 * @desc: method description to be released
383 * Releases the MonoMethodDesc object @desc.
386 mono_method_desc_free (MonoMethodDesc
*desc
)
389 g_free (desc
->namespace);
390 else if (desc
->klass
)
391 g_free (desc
->klass
);
396 * namespace and class are supposed to match already if this function is used.
399 mono_method_desc_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
404 name_match
= strcmp (desc
->name
, method
->name
) == 0;
406 if (!name_match
&& desc
->name_glob
)
407 name_match
= g_pattern_match_simple (desc
->name
, method
->name
);
413 if (desc
->num_args
!= mono_method_signature (method
)->param_count
)
415 sig
= mono_signature_get_desc (mono_method_signature (method
), desc
->include_namespace
);
416 if (strcmp (sig
, desc
->args
)) {
425 my_strrchr (const char *str
, char ch
, int *len
)
429 for (pos
= (*len
)-1; pos
>= 0; pos
--) {
441 match_class (MonoMethodDesc
*desc
, int pos
, MonoClass
*klass
)
445 if (desc
->klass_glob
&& !strcmp (desc
->klass
, "*"))
448 if (desc
->klass_glob
&& g_pattern_match_simple (desc
->klass
, klass
->name
))
451 p
= my_strrchr (desc
->klass
, '/', &pos
);
453 if (strncmp (desc
->klass
, klass
->name
, pos
))
455 if (desc
->namespace && strcmp (desc
->namespace, klass
->name_space
))
460 if (strcmp (p
+1, klass
->name
))
462 if (!klass
->nested_in
)
465 return match_class (desc
, pos
, klass
->nested_in
);
469 mono_method_desc_full_match (MonoMethodDesc
*desc
, MonoMethod
*method
)
473 if (!match_class (desc
, strlen (desc
->klass
), method
->klass
))
476 return mono_method_desc_match (desc
, method
);
480 mono_method_desc_search_in_class (MonoMethodDesc
*desc
, MonoClass
*klass
)
483 gpointer iter
= NULL
;
485 while ((m
= mono_class_get_methods (klass
, &iter
)))
486 if (mono_method_desc_match (desc
, m
))
492 mono_method_desc_search_in_image (MonoMethodDesc
*desc
, MonoImage
*image
)
495 const MonoTableInfo
*tdef
;
496 const MonoTableInfo
*methods
;
500 /* Handle short names for system classes */
501 if (!desc
->namespace && image
== mono_defaults
.corlib
) {
502 klass
= find_system_class (desc
->klass
);
504 return mono_method_desc_search_in_class (desc
, klass
);
507 if (desc
->namespace && desc
->klass
) {
508 klass
= mono_class_from_name (image
, desc
->namespace, desc
->klass
);
511 return mono_method_desc_search_in_class (desc
, klass
);
514 tdef
= mono_image_get_table_info (image
, MONO_TABLE_TYPEDEF
);
515 methods
= mono_image_get_table_info (image
, MONO_TABLE_METHOD
);
516 for (i
= 0; i
< mono_table_info_get_rows (methods
); ++i
) {
517 guint32 token
= mono_metadata_decode_row_col (methods
, i
, MONO_METHOD_NAME
);
518 const char *n
= mono_metadata_string_heap (image
, token
);
520 if (strcmp (n
, desc
->name
))
522 method
= mono_get_method (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
);
523 if (mono_method_desc_full_match (desc
, method
))
529 static const unsigned char*
530 dis_one (GString
*str
, MonoDisHelper
*dh
, MonoMethod
*method
, const unsigned char *ip
, const unsigned char *end
)
532 MonoMethodHeader
*header
= mono_method_get_header (method
);
533 const MonoOpcode
*opcode
;
534 guint32 label
, token
;
538 const unsigned char* il_code
= mono_method_header_get_code (header
, NULL
, NULL
);
540 label
= ip
- il_code
;
542 tmp
= dh
->indenter (dh
, method
, label
);
543 g_string_append (str
, tmp
);
546 if (dh
->label_format
)
547 g_string_append_printf (str
, dh
->label_format
, label
);
549 i
= mono_opcode_value (&ip
, end
);
551 opcode
= &mono_opcodes
[i
];
552 g_string_append_printf (str
, "%-10s", mono_opcode_name (i
));
554 switch (opcode
->argument
) {
558 case MonoInlineField
:
559 case MonoInlineMethod
:
564 tmp
= dh
->tokener (dh
, method
, token
);
565 g_string_append (str
, tmp
);
568 g_string_append_printf (str
, "0x%08x", token
);
572 case MonoInlineString
: {
578 if (!method
->klass
->image
->dynamic
&& !method
->dynamic
) {
580 blob
= mono_metadata_user_string (method
->klass
->image
, mono_metadata_token_index (token
));
582 len2
= mono_metadata_decode_blob_size (blob
, &blob
);
585 #ifdef NO_UNALIGNED_ACCESS
586 /* The blob might not be 2 byte aligned */
587 blob2
= g_malloc ((len2
* 2) + 1);
588 memcpy (blob2
, blob
, len2
* 2);
593 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
595 guint16
*buf
= g_new (guint16
, len2
+ 1);
598 for (i
= 0; i
< len2
; ++i
)
599 buf
[i
] = GUINT16_FROM_LE (((guint16
*)blob2
) [i
]);
600 s
= g_utf16_to_utf8 (buf
, len2
, NULL
, NULL
, NULL
);
604 s
= g_utf16_to_utf8 ((gunichar2
*)blob2
, len2
, NULL
, NULL
, NULL
);
607 g_string_append_printf (str
, "\"%s\"", s
);
616 g_string_append_printf (str
, "%d", read16 (ip
));
619 case MonoShortInlineVar
:
620 g_string_append_printf (str
, "%d", (*ip
));
623 case MonoInlineBrTarget
:
626 if (dh
->label_target
)
627 g_string_append_printf (str
, dh
->label_target
, ip
+ sval
- il_code
);
629 g_string_append_printf (str
, "%d", sval
);
631 case MonoShortInlineBrTarget
:
632 sval
= *(const signed char*)ip
;
634 if (dh
->label_target
)
635 g_string_append_printf (str
, dh
->label_target
, ip
+ sval
- il_code
);
637 g_string_append_printf (str
, "%d", sval
);
639 case MonoInlineSwitch
: {
640 const unsigned char *end
;
644 g_string_append_c (str
, '(');
645 for (i
= 0; i
< sval
; ++i
) {
647 g_string_append (str
, ", ");
649 if (dh
->label_target
)
650 g_string_append_printf (str
, dh
->label_target
, end
+ label
- il_code
);
652 g_string_append_printf (str
, "%d", label
);
655 g_string_append_c (str
, ')');
661 g_string_append_printf (str
, "%g", r
);
665 case MonoShortInlineR
: {
668 g_string_append_printf (str
, "%g", r
);
673 g_string_append_printf (str
, "%d", (gint32
)read32 (ip
));
676 case MonoShortInlineI
:
677 g_string_append_printf (str
, "%d", *(const signed char*)ip
);
684 g_assert_not_reached ();
687 g_string_append (str
, dh
->newline
);
689 mono_metadata_free_mh (header
);
696 "IL_%04x: ", /* label_format */
697 "IL_%04x", /* label_target */
704 mono_disasm_code_one (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
**endp
)
707 GString
*res
= g_string_new ("");
711 /* set ip + 2 as the end: this is just a debugging method */
712 ip
= dis_one (res
, dh
, method
, ip
, ip
+ 2);
717 g_string_free (res
, FALSE
);
722 mono_disasm_code (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
* end
)
725 GString
*res
= g_string_new ("");
730 ip
= dis_one (res
, dh
, method
, ip
, end
);
734 g_string_free (res
, FALSE
);
739 mono_field_full_name (MonoClassField
*field
)
742 const char *nspace
= field
->parent
->name_space
;
744 res
= g_strdup_printf ("%s%s%s:%s", nspace
, *nspace
? "." : "",
745 field
->parent
->name
, mono_field_get_name (field
));
751 mono_method_full_name (MonoMethod
*method
, gboolean signature
)
755 char *klass_desc
= mono_type_full_name (&method
->klass
->byval_arg
);
756 char *inst_desc
= NULL
;
758 if (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->context
.method_inst
) {
759 GString
*str
= g_string_new ("");
760 g_string_append (str
, "<");
761 ginst_get_desc (str
, ((MonoMethodInflated
*)method
)->context
.method_inst
);
762 g_string_append (str
, ">");
764 inst_desc
= str
->str
;
765 g_string_free (str
, FALSE
);
766 } else if (method
->is_generic
) {
767 MonoGenericContainer
*container
= mono_method_get_generic_container (method
);
769 GString
*str
= g_string_new ("");
770 g_string_append (str
, "<");
771 ginst_get_desc (str
, container
->context
.method_inst
);
772 g_string_append (str
, ">");
774 inst_desc
= str
->str
;
775 g_string_free (str
, FALSE
);
778 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
779 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
781 strcpy (wrapper
, "");
784 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
786 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
787 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
789 strcpy (wrapper
, "");
790 res
= g_strdup_printf ("%s%s:%s%s (%s)", wrapper
, klass_desc
,
791 method
->name
, inst_desc
? inst_desc
: "", tmpsig
);
794 res
= g_strdup_printf ("%s%s:%s%s", wrapper
, klass_desc
,
795 method
->name
, inst_desc
? inst_desc
: "");
805 print_name_space (MonoClass
*klass
)
807 if (klass
->nested_in
) {
808 print_name_space (klass
->nested_in
);
809 g_print ("%s", klass
->nested_in
->name
);
812 if (klass
->name_space
[0]) {
813 g_print ("%s", klass
->name_space
);
820 * mono_object_describe:
822 * Prints to stdout a small description of the object @obj.
823 * For use in a debugger.
826 mono_object_describe (MonoObject
*obj
)
831 g_print ("(null)\n");
834 klass
= mono_object_class (obj
);
835 if (klass
== mono_defaults
.string_class
) {
836 char *utf8
= mono_string_to_utf8 ((MonoString
*)obj
);
837 if (strlen (utf8
) > 60) {
843 g_print ("String at %p, length: %d, '%s'\n", obj
, mono_string_length ((MonoString
*) obj
), utf8
);
845 } else if (klass
->rank
) {
846 MonoArray
*array
= (MonoArray
*)obj
;
847 sep
= print_name_space (klass
);
848 g_print ("%s%s", sep
, klass
->name
);
849 g_print (" at %p, rank: %d, length: %d\n", obj
, klass
->rank
, (int)mono_array_length (array
));
851 sep
= print_name_space (klass
);
852 g_print ("%s%s", sep
, klass
->name
);
853 g_print (" object at %p (klass: %p)\n", obj
, klass
);
859 print_field_value (const char *field_ptr
, MonoClassField
*field
, int type_offset
)
862 g_print ("At %p (ofs: %2d) %s: ", field_ptr
, field
->offset
+ type_offset
, mono_field_get_name (field
));
863 type
= mono_type_get_underlying_type (field
->type
);
865 switch (type
->type
) {
869 case MONO_TYPE_FNPTR
:
870 g_print ("%p\n", *(const void**)field_ptr
);
872 case MONO_TYPE_STRING
:
873 case MONO_TYPE_SZARRAY
:
874 case MONO_TYPE_CLASS
:
875 case MONO_TYPE_OBJECT
:
876 case MONO_TYPE_ARRAY
:
877 mono_object_describe (*(MonoObject
**)field_ptr
);
879 case MONO_TYPE_GENERICINST
:
880 if (!mono_type_generic_inst_is_valuetype (type
)) {
881 mono_object_describe (*(MonoObject
**)field_ptr
);
886 case MONO_TYPE_VALUETYPE
: {
887 MonoClass
*k
= mono_class_from_mono_type (type
);
888 g_print ("%s ValueType (type: %p) at %p\n", k
->name
, k
, field_ptr
);
892 g_print ("%d\n", *(gint8
*)field_ptr
);
895 g_print ("%d\n", *(guint8
*)field_ptr
);
898 g_print ("%d\n", *(gint16
*)field_ptr
);
901 g_print ("%d\n", *(guint16
*)field_ptr
);
904 g_print ("%d\n", *(gint32
*)field_ptr
);
907 g_print ("%u\n", *(guint32
*)field_ptr
);
910 g_print ("%lld\n", (long long int)*(gint64
*)field_ptr
);
913 g_print ("%llu\n", (long long unsigned int)*(guint64
*)field_ptr
);
916 g_print ("%f\n", *(gfloat
*)field_ptr
);
919 g_print ("%f\n", *(gdouble
*)field_ptr
);
921 case MONO_TYPE_BOOLEAN
:
922 g_print ("%s (%d)\n", *(guint8
*)field_ptr
? "True": "False", *(guint8
*)field_ptr
);
925 g_print ("'%c' (%d 0x%04x)\n", *(guint16
*)field_ptr
, *(guint16
*)field_ptr
, *(guint16
*)field_ptr
);
928 g_assert_not_reached ();
934 objval_describe (MonoClass
*class, const char *addr
)
936 MonoClassField
*field
;
938 const char *field_ptr
;
939 gssize type_offset
= 0;
940 if (class->valuetype
)
941 type_offset
= -sizeof (MonoObject
);
943 for (p
= class; p
!= NULL
; p
= p
->parent
) {
944 gpointer iter
= NULL
;
945 int printed_header
= FALSE
;
946 while ((field
= mono_class_get_fields (p
, &iter
))) {
947 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
950 if (p
!= class && !printed_header
) {
952 g_print ("In class ");
953 sep
= print_name_space (p
);
954 g_print ("%s%s:\n", sep
, p
->name
);
955 printed_header
= TRUE
;
957 field_ptr
= (const char*)addr
+ field
->offset
+ type_offset
;
959 print_field_value (field_ptr
, field
, type_offset
);
965 * mono_object_describe_fields:
967 * Prints to stdout a small description of each field of the object @obj.
968 * For use in a debugger.
971 mono_object_describe_fields (MonoObject
*obj
)
973 MonoClass
*class = mono_object_class (obj
);
974 objval_describe (class, (char*)obj
);
978 * mono_value_describe_fields:
980 * Prints to stdout a small description of each field of the value type
981 * stored at @addr of type @klass.
982 * For use in a debugger.
985 mono_value_describe_fields (MonoClass
* klass
, const char* addr
)
987 objval_describe (klass
, addr
);
991 * mono_class_describe_statics:
993 * Prints to stdout a small description of each static field of the type @klass
994 * in the current application domain.
995 * For use in a debugger.
998 mono_class_describe_statics (MonoClass
* klass
)
1000 MonoClassField
*field
;
1002 const char *field_ptr
;
1003 MonoVTable
*vtable
= mono_class_vtable_full (mono_domain_get (), klass
, FALSE
);
1008 if (!(addr
= mono_vtable_get_static_field_data (vtable
)))
1011 for (p
= klass
; p
!= NULL
; p
= p
->parent
) {
1012 gpointer iter
= NULL
;
1013 while ((field
= mono_class_get_fields (p
, &iter
))) {
1014 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
1016 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
1019 field_ptr
= (const char*)addr
+ field
->offset
;
1021 print_field_value (field_ptr
, field
, 0);