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/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
);
330 /* allow two :: to separate the method name */
331 if (*method_name
== ':')
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
)
471 if (!match_class (desc
, strlen (desc
->klass
), method
->klass
))
474 return mono_method_desc_match (desc
, method
);
478 mono_method_desc_search_in_class (MonoMethodDesc
*desc
, MonoClass
*klass
)
481 gpointer iter
= NULL
;
483 while ((m
= mono_class_get_methods (klass
, &iter
)))
484 if (mono_method_desc_match (desc
, m
))
490 mono_method_desc_search_in_image (MonoMethodDesc
*desc
, MonoImage
*image
)
493 const MonoTableInfo
*tdef
;
494 const MonoTableInfo
*methods
;
498 /* Handle short names for system classes */
499 if (!desc
->namespace && image
== mono_defaults
.corlib
) {
500 klass
= find_system_class (desc
->klass
);
502 return mono_method_desc_search_in_class (desc
, klass
);
505 if (desc
->namespace && desc
->klass
) {
506 klass
= mono_class_from_name (image
, desc
->namespace, desc
->klass
);
509 return mono_method_desc_search_in_class (desc
, klass
);
512 tdef
= mono_image_get_table_info (image
, MONO_TABLE_TYPEDEF
);
513 methods
= mono_image_get_table_info (image
, MONO_TABLE_METHOD
);
514 for (i
= 0; i
< mono_table_info_get_rows (methods
); ++i
) {
515 guint32 token
= mono_metadata_decode_row_col (methods
, i
, MONO_METHOD_NAME
);
516 const char *n
= mono_metadata_string_heap (image
, token
);
518 if (strcmp (n
, desc
->name
))
520 method
= mono_get_method (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
);
521 if (mono_method_desc_full_match (desc
, method
))
527 static const unsigned char*
528 dis_one (GString
*str
, MonoDisHelper
*dh
, MonoMethod
*method
, const unsigned char *ip
, const unsigned char *end
)
530 MonoMethodHeader
*header
= mono_method_get_header (method
);
531 const MonoOpcode
*opcode
;
532 guint32 label
, token
;
536 const unsigned char* il_code
= mono_method_header_get_code (header
, NULL
, NULL
);
538 label
= ip
- il_code
;
540 tmp
= dh
->indenter (dh
, method
, label
);
541 g_string_append (str
, tmp
);
544 if (dh
->label_format
)
545 g_string_append_printf (str
, dh
->label_format
, label
);
547 i
= mono_opcode_value (&ip
, end
);
549 opcode
= &mono_opcodes
[i
];
550 g_string_append_printf (str
, "%-10s", mono_opcode_name (i
));
552 switch (opcode
->argument
) {
556 case MonoInlineField
:
557 case MonoInlineMethod
:
562 tmp
= dh
->tokener (dh
, method
, token
);
563 g_string_append (str
, tmp
);
566 g_string_append_printf (str
, "0x%08x", token
);
570 case MonoInlineString
: {
576 if (!method
->klass
->image
->dynamic
) {
578 blob
= mono_metadata_user_string (method
->klass
->image
, mono_metadata_token_index (token
));
580 len2
= mono_metadata_decode_blob_size (blob
, &blob
);
583 #ifdef NO_UNALIGNED_ACCESS
584 /* The blob might not be 2 byte aligned */
585 blob2
= g_malloc ((len2
* 2) + 1);
586 memcpy (blob2
, blob
, len2
* 2);
591 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
593 guint16
*buf
= g_new (guint16
, len2
+ 1);
596 for (i
= 0; i
< len2
; ++i
)
597 buf
[i
] = GUINT16_FROM_LE (((guint16
*)blob2
) [i
]);
598 s
= g_utf16_to_utf8 (buf
, len2
, NULL
, NULL
, NULL
);
602 s
= g_utf16_to_utf8 ((gunichar2
*)blob2
, len2
, NULL
, NULL
, NULL
);
605 g_string_append_printf (str
, "\"%s\"", s
);
614 g_string_append_printf (str
, "%d", read16 (ip
));
617 case MonoShortInlineVar
:
618 g_string_append_printf (str
, "%d", (*ip
));
621 case MonoInlineBrTarget
:
624 if (dh
->label_target
)
625 g_string_append_printf (str
, dh
->label_target
, ip
+ sval
- il_code
);
627 g_string_append_printf (str
, "%d", sval
);
629 case MonoShortInlineBrTarget
:
630 sval
= *(const signed char*)ip
;
632 if (dh
->label_target
)
633 g_string_append_printf (str
, dh
->label_target
, ip
+ sval
- il_code
);
635 g_string_append_printf (str
, "%d", sval
);
637 case MonoInlineSwitch
: {
638 const unsigned char *end
;
642 g_string_append_c (str
, '(');
643 for (i
= 0; i
< sval
; ++i
) {
645 g_string_append (str
, ", ");
647 if (dh
->label_target
)
648 g_string_append_printf (str
, dh
->label_target
, end
+ label
- il_code
);
650 g_string_append_printf (str
, "%d", label
);
653 g_string_append_c (str
, ')');
659 g_string_append_printf (str
, "%g", r
);
663 case MonoShortInlineR
: {
666 g_string_append_printf (str
, "%g", r
);
671 g_string_append_printf (str
, "%d", (gint32
)read32 (ip
));
674 case MonoShortInlineI
:
675 g_string_append_printf (str
, "%d", *(const signed char*)ip
);
682 g_assert_not_reached ();
685 g_string_append (str
, dh
->newline
);
687 mono_metadata_free_mh (header
);
694 "IL_%04x: ", /* label_format */
695 "IL_%04x", /* label_target */
702 mono_disasm_code_one (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
**endp
)
705 GString
*res
= g_string_new ("");
709 /* set ip + 2 as the end: this is just a debugging method */
710 ip
= dis_one (res
, dh
, method
, ip
, ip
+ 2);
715 g_string_free (res
, FALSE
);
720 mono_disasm_code (MonoDisHelper
*dh
, MonoMethod
*method
, const guchar
*ip
, const guchar
* end
)
723 GString
*res
= g_string_new ("");
728 ip
= dis_one (res
, dh
, method
, ip
, end
);
732 g_string_free (res
, FALSE
);
737 mono_field_full_name (MonoClassField
*field
)
740 const char *nspace
= field
->parent
->name_space
;
742 res
= g_strdup_printf ("%s%s%s:%s", nspace
, *nspace
? "." : "",
743 field
->parent
->name
, mono_field_get_name (field
));
749 mono_method_full_name (MonoMethod
*method
, gboolean signature
)
753 char *klass_desc
= mono_type_full_name (&method
->klass
->byval_arg
);
754 char *inst_desc
= NULL
;
756 if (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->context
.method_inst
) {
757 GString
*str
= g_string_new ("");
758 g_string_append (str
, "<");
759 ginst_get_desc (str
, ((MonoMethodInflated
*)method
)->context
.method_inst
);
760 g_string_append (str
, ">");
762 inst_desc
= str
->str
;
763 g_string_free (str
, FALSE
);
764 } else if (method
->is_generic
) {
765 MonoGenericContainer
*container
= mono_method_get_generic_container (method
);
767 GString
*str
= g_string_new ("");
768 g_string_append (str
, "<");
769 ginst_get_desc (str
, container
->context
.method_inst
);
770 g_string_append (str
, ">");
772 inst_desc
= str
->str
;
773 g_string_free (str
, FALSE
);
776 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
777 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
779 strcpy (wrapper
, "");
782 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
784 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
785 sprintf (wrapper
, "(wrapper %s) ", wrapper_type_to_str (method
->wrapper_type
));
787 strcpy (wrapper
, "");
788 res
= g_strdup_printf ("%s%s:%s%s (%s)", wrapper
, klass_desc
,
789 method
->name
, inst_desc
? inst_desc
: "", tmpsig
);
792 res
= g_strdup_printf ("%s%s:%s%s", wrapper
, klass_desc
,
793 method
->name
, inst_desc
? inst_desc
: "");
803 print_name_space (MonoClass
*klass
)
805 if (klass
->nested_in
) {
806 print_name_space (klass
->nested_in
);
807 g_print ("%s", klass
->nested_in
->name
);
810 if (klass
->name_space
[0]) {
811 g_print ("%s", klass
->name_space
);
818 * mono_object_describe:
820 * Prints to stdout a small description of the object @obj.
821 * For use in a debugger.
824 mono_object_describe (MonoObject
*obj
)
829 g_print ("(null)\n");
832 klass
= mono_object_class (obj
);
833 if (klass
== mono_defaults
.string_class
) {
834 char *utf8
= mono_string_to_utf8 ((MonoString
*)obj
);
835 if (strlen (utf8
) > 60) {
841 g_print ("String at %p, length: %d, '%s'\n", obj
, mono_string_length ((MonoString
*) obj
), utf8
);
843 } else if (klass
->rank
) {
844 MonoArray
*array
= (MonoArray
*)obj
;
845 sep
= print_name_space (klass
);
846 g_print ("%s%s", sep
, klass
->name
);
847 g_print (" at %p, rank: %d, length: %d\n", obj
, klass
->rank
, (int)mono_array_length (array
));
849 sep
= print_name_space (klass
);
850 g_print ("%s%s", sep
, klass
->name
);
851 g_print (" object at %p (klass: %p)\n", obj
, klass
);
857 print_field_value (const char *field_ptr
, MonoClassField
*field
, int type_offset
)
860 g_print ("At %p (ofs: %2d) %s: ", field_ptr
, field
->offset
+ type_offset
, mono_field_get_name (field
));
861 type
= mono_type_get_underlying_type (field
->type
);
863 switch (type
->type
) {
867 case MONO_TYPE_FNPTR
:
868 g_print ("%p\n", *(const void**)field_ptr
);
870 case MONO_TYPE_STRING
:
871 case MONO_TYPE_SZARRAY
:
872 case MONO_TYPE_CLASS
:
873 case MONO_TYPE_OBJECT
:
874 case MONO_TYPE_ARRAY
:
875 mono_object_describe (*(MonoObject
**)field_ptr
);
877 case MONO_TYPE_GENERICINST
:
878 if (!mono_type_generic_inst_is_valuetype (type
)) {
879 mono_object_describe (*(MonoObject
**)field_ptr
);
884 case MONO_TYPE_VALUETYPE
: {
885 MonoClass
*k
= mono_class_from_mono_type (type
);
886 g_print ("%s ValueType (type: %p) at %p\n", k
->name
, k
, field_ptr
);
890 g_print ("%d\n", *(gint8
*)field_ptr
);
893 g_print ("%d\n", *(guint8
*)field_ptr
);
896 g_print ("%d\n", *(gint16
*)field_ptr
);
899 g_print ("%d\n", *(guint16
*)field_ptr
);
902 g_print ("%d\n", *(gint32
*)field_ptr
);
905 g_print ("%u\n", *(guint32
*)field_ptr
);
908 g_print ("%lld\n", (long long int)*(gint64
*)field_ptr
);
911 g_print ("%llu\n", (long long unsigned int)*(guint64
*)field_ptr
);
914 g_print ("%f\n", *(gfloat
*)field_ptr
);
917 g_print ("%f\n", *(gdouble
*)field_ptr
);
919 case MONO_TYPE_BOOLEAN
:
920 g_print ("%s (%d)\n", *(guint8
*)field_ptr
? "True": "False", *(guint8
*)field_ptr
);
923 g_print ("'%c' (%d 0x%04x)\n", *(guint16
*)field_ptr
, *(guint16
*)field_ptr
, *(guint16
*)field_ptr
);
926 g_assert_not_reached ();
932 objval_describe (MonoClass
*class, const char *addr
)
934 MonoClassField
*field
;
936 const char *field_ptr
;
937 gssize type_offset
= 0;
938 if (class->valuetype
)
939 type_offset
= -sizeof (MonoObject
);
941 for (p
= class; p
!= NULL
; p
= p
->parent
) {
942 gpointer iter
= NULL
;
943 int printed_header
= FALSE
;
944 while ((field
= mono_class_get_fields (p
, &iter
))) {
945 if (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
))
948 if (p
!= class && !printed_header
) {
950 g_print ("In class ");
951 sep
= print_name_space (p
);
952 g_print ("%s%s:\n", sep
, p
->name
);
953 printed_header
= TRUE
;
955 field_ptr
= (const char*)addr
+ field
->offset
+ type_offset
;
957 print_field_value (field_ptr
, field
, type_offset
);
963 * mono_object_describe_fields:
965 * Prints to stdout a small description of each field of the object @obj.
966 * For use in a debugger.
969 mono_object_describe_fields (MonoObject
*obj
)
971 MonoClass
*class = mono_object_class (obj
);
972 objval_describe (class, (char*)obj
);
976 * mono_value_describe_fields:
978 * Prints to stdout a small description of each field of the value type
979 * stored at @addr of type @klass.
980 * For use in a debugger.
983 mono_value_describe_fields (MonoClass
* klass
, const char* addr
)
985 objval_describe (klass
, addr
);
989 * mono_class_describe_statics:
991 * Prints to stdout a small description of each static field of the type @klass
992 * in the current application domain.
993 * For use in a debugger.
996 mono_class_describe_statics (MonoClass
* klass
)
998 MonoClassField
*field
;
1000 const char *field_ptr
;
1001 MonoVTable
*vtable
= mono_class_vtable_full (mono_domain_get (), klass
, FALSE
);
1006 if (!(addr
= vtable
->data
))
1009 for (p
= klass
; p
!= NULL
; p
= p
->parent
) {
1010 gpointer iter
= NULL
;
1011 while ((field
= mono_class_get_fields (p
, &iter
))) {
1012 if (field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
1014 if (!(field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_HAS_FIELD_RVA
)))
1017 field_ptr
= (const char*)addr
+ field
->offset
;
1019 print_field_value (field_ptr
, field
, 0);