1 /**
2 * \file
3 *
4 * Author:
5 * Mono Project (http://www.mono-project.com)
6 *
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.
9 */
10
11 #include <config.h>
12 #include <string.h>
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
23 struct MonoMethodDesc {
24 char *name_space;
25 char *klass;
26 char *name;
27 char *args;
28 guint num_args;
29 gboolean include_namespace, klass_glob, name_glob;
30 };
31
32 #ifdef HAVE_ARRAY_ELEM_INIT
33 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
34 #define MSGSTRFIELD1(line) str##line
35 static const struct msgstr_t {
36 #define WRAPPER(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
37 #include "wrapper-types.h"
38 #undef WRAPPER
39 } opstr = {
40 #define WRAPPER(a,b) b,
41 #include "wrapper-types.h"
42 #undef WRAPPER
43 };
44 static const gint16 opidx [] = {
45 #define WRAPPER(a,b) [MONO_WRAPPER_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
46 #include "wrapper-types.h"
47 #undef WRAPPER
48 };
49
50 static const char*
wrapper_type_to_str(guint32 wrapper_type)51 wrapper_type_to_str (guint32 wrapper_type)
52 {
53 g_assert (wrapper_type < MONO_WRAPPER_NUM);
54
55 return (const char*)&opstr + opidx [wrapper_type];
56 }
57
58 #else
59 #define WRAPPER(a,b) b,
60 static const char* const
61 wrapper_type_names [MONO_WRAPPER_NUM + 1] = {
62 #include "wrapper-types.h"
63 NULL
64 };
65
66 static const char*
wrapper_type_to_str(guint32 wrapper_type)67 wrapper_type_to_str (guint32 wrapper_type)
68 {
69 g_assert (wrapper_type < MONO_WRAPPER_NUM);
70
71 return wrapper_type_names [wrapper_type];
72 }
73
74 #endif
75
76 static void
append_class_name(GString * res,MonoClass * klass,gboolean include_namespace)77 append_class_name (GString *res, MonoClass *klass, gboolean include_namespace)
78 {
79 if (!klass) {
80 g_string_append (res, "Unknown");
81 return;
82 }
83 if (klass->nested_in) {
84 append_class_name (res, klass->nested_in, include_namespace);
85 g_string_append_c (res, '/');
86 }
87 if (include_namespace && *(klass->name_space)) {
88 g_string_append (res, klass->name_space);
89 g_string_append_c (res, '.');
90 }
91 g_string_append (res, klass->name);
92 }
93
94 static MonoClass*
find_system_class(const char * name)95 find_system_class (const char *name)
96 {
97 if (!strcmp (name, "void"))
98 return mono_defaults.void_class;
99 else if (!strcmp (name, "char")) return mono_defaults.char_class;
100 else if (!strcmp (name, "bool")) return mono_defaults.boolean_class;
101 else if (!strcmp (name, "byte")) return mono_defaults.byte_class;
102 else if (!strcmp (name, "sbyte")) return mono_defaults.sbyte_class;
103 else if (!strcmp (name, "uint16")) return mono_defaults.uint16_class;
104 else if (!strcmp (name, "int16")) return mono_defaults.int16_class;
105 else if (!strcmp (name, "uint")) return mono_defaults.uint32_class;
106 else if (!strcmp (name, "int")) return mono_defaults.int32_class;
107 else if (!strcmp (name, "ulong")) return mono_defaults.uint64_class;
108 else if (!strcmp (name, "long")) return mono_defaults.int64_class;
109 else if (!strcmp (name, "uintptr")) return mono_defaults.uint_class;
110 else if (!strcmp (name, "intptr")) return mono_defaults.int_class;
111 else if (!strcmp (name, "single")) return mono_defaults.single_class;
112 else if (!strcmp (name, "double")) return mono_defaults.double_class;
113 else if (!strcmp (name, "string")) return mono_defaults.string_class;
114 else if (!strcmp (name, "object")) return mono_defaults.object_class;
115 else
116 return NULL;
117 }
118
119 void
mono_type_get_desc(GString * res,MonoType * type,gboolean include_namespace)120 mono_type_get_desc (GString *res, MonoType *type, gboolean include_namespace)
121 {
122 int i;
123
124 switch (type->type) {
125 case MONO_TYPE_VOID:
126 g_string_append (res, "void"); break;
127 case MONO_TYPE_CHAR:
128 g_string_append (res, "char"); break;
129 case MONO_TYPE_BOOLEAN:
130 g_string_append (res, "bool"); break;
131 case MONO_TYPE_U1:
132 g_string_append (res, "byte"); break;
133 case MONO_TYPE_I1:
134 g_string_append (res, "sbyte"); break;
135 case MONO_TYPE_U2:
136 g_string_append (res, "uint16"); break;
137 case MONO_TYPE_I2:
138 g_string_append (res, "int16"); break;
139 case MONO_TYPE_U4:
140 g_string_append (res, "uint"); break;
141 case MONO_TYPE_I4:
142 g_string_append (res, "int"); break;
143 case MONO_TYPE_U8:
144 g_string_append (res, "ulong"); break;
145 case MONO_TYPE_I8:
146 g_string_append (res, "long"); break;
147 case MONO_TYPE_FNPTR: /* who cares for the exact signature? */
148 g_string_append (res, "*()"); break;
149 case MONO_TYPE_U:
150 g_string_append (res, "uintptr"); break;
151 case MONO_TYPE_I:
152 g_string_append (res, "intptr"); break;
153 case MONO_TYPE_R4:
154 g_string_append (res, "single"); break;
155 case MONO_TYPE_R8:
156 g_string_append (res, "double"); break;
157 case MONO_TYPE_STRING:
158 g_string_append (res, "string"); break;
159 case MONO_TYPE_OBJECT:
160 g_string_append (res, "object"); break;
161 case MONO_TYPE_PTR:
162 mono_type_get_desc (res, type->data.type, include_namespace);
163 g_string_append_c (res, '*');
164 break;
165 case MONO_TYPE_ARRAY:
166 mono_type_get_desc (res, &type->data.array->eklass->byval_arg, include_namespace);
167 g_string_append_c (res, '[');
168 for (i = 1; i < type->data.array->rank; ++i)
169 g_string_append_c (res, ',');
170 g_string_append_c (res, ']');
171 break;
172 case MONO_TYPE_SZARRAY:
173 mono_type_get_desc (res, &type->data.klass->byval_arg, include_namespace);
174 g_string_append (res, "[]");
175 break;
176 case MONO_TYPE_CLASS:
177 case MONO_TYPE_VALUETYPE:
178 append_class_name (res, type->data.klass, include_namespace);
179 break;
180 case MONO_TYPE_GENERICINST: {
181 MonoGenericContext *context;
182
183 mono_type_get_desc (res, &type->data.generic_class->container_class->byval_arg, include_namespace);
184 g_string_append (res, "<");
185 context = &type->data.generic_class->context;
186 if (context->class_inst) {
187 for (i = 0; i < context->class_inst->type_argc; ++i) {
188 if (i > 0)
189 g_string_append (res, ", ");
190 mono_type_get_desc (res, context->class_inst->type_argv [i], include_namespace);
191 }
192 }
193 if (context->method_inst) {
194 if (context->class_inst)
195 g_string_append (res, "; ");
196 for (i = 0; i < context->method_inst->type_argc; ++i) {
197 if (i > 0)
198 g_string_append (res, ", ");
199 mono_type_get_desc (res, context->method_inst->type_argv [i], include_namespace);
200 }
201 }
202 g_string_append (res, ">");
203 break;
204 }
205 case MONO_TYPE_VAR:
206 case MONO_TYPE_MVAR:
207 if (type->data.generic_param) {
208 const char *name = mono_generic_param_name (type->data.generic_param);
209 if (name)
210 g_string_append (res, name);
211 else
212 g_string_append_printf (res, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", mono_generic_param_num (type->data.generic_param));
213 } else {
214 g_string_append (res, "<unknown>");
215 }
216 break;
217 case MONO_TYPE_TYPEDBYREF:
218 g_string_append (res, "typedbyref");
219 break;
220 default:
221 break;
222 }
223 if (type->byref)
224 g_string_append_c (res, '&');
225 }
226
227 /**
228 * mono_type_full_name:
229 */
230 char*
mono_type_full_name(MonoType * type)231 mono_type_full_name (MonoType *type)
232 {
233 GString *str;
234
235 str = g_string_new ("");
236 mono_type_get_desc (str, type, TRUE);
237 return g_string_free (str, FALSE);
238 }
239
240 /**
241 * mono_signature_get_desc:
242 */
243 char*
mono_signature_get_desc(MonoMethodSignature * sig,gboolean include_namespace)244 mono_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
245 {
246 int i;
247 char *result;
248 GString *res;
249
250 if (!sig)
251 return g_strdup ("<invalid signature>");
252
253 res = g_string_new ("");
254
255 for (i = 0; i < sig->param_count; ++i) {
256 if (i > 0)
257 g_string_append_c (res, ',');
258 mono_type_get_desc (res, sig->params [i], include_namespace);
259 }
260 result = res->str;
261 g_string_free (res, FALSE);
262 return result;
263 }
264
265 char*
mono_signature_full_name(MonoMethodSignature * sig)266 mono_signature_full_name (MonoMethodSignature *sig)
267 {
268 int i;
269 char *result;
270 GString *res;
271
272 if (!sig)
273 return g_strdup ("<invalid signature>");
274
275 res = g_string_new ("");
276
277 mono_type_get_desc (res, sig->ret, TRUE);
278 g_string_append_c (res, '(');
279 for (i = 0; i < sig->param_count; ++i) {
280 if (i > 0)
281 g_string_append_c (res, ',');
282 mono_type_get_desc (res, sig->params [i], TRUE);
283 }
284 g_string_append_c (res, ')');
285 result = res->str;
286 g_string_free (res, FALSE);
287 return result;
288 }
289
290 /*
291 * Returns a string ready to be consumed by managed code when formating a string to include class + method name.
292 * IE, say you have void Foo:Bar(int). It will return "void {0}(int)".
293 * The reason for this is that managed exception constructors for missing members require a both class and member names to be provided independently of the signature.
294 */
295 char*
mono_signature_get_managed_fmt_string(MonoMethodSignature * sig)296 mono_signature_get_managed_fmt_string (MonoMethodSignature *sig)
297 {
298 int i;
299 char *result;
300 GString *res;
301
302 if (!sig)
303 return g_strdup ("<invalid signature>");
304
305 res = g_string_new ("");
306
307 mono_type_get_desc (res, sig->ret, TRUE);
308
309 g_string_append (res, " {0}");
310
311 if (sig->generic_param_count) {
312 g_string_append_c (res, '<');
313 for (i = 0; i < sig->generic_param_count; ++i) {
314 if (i > 0)
315 g_string_append (res, ",");
316 g_string_append_printf (res, "!%d", i);
317 }
318 g_string_append_c (res, '>');
319 }
320
321 g_string_append_c (res, '(');
322 for (i = 0; i < sig->param_count; ++i) {
323 if (i > 0)
324 g_string_append_c (res, ',');
325 mono_type_get_desc (res, sig->params [i], TRUE);
326 }
327 g_string_append_c (res, ')');
328 result = res->str;
329 g_string_free (res, FALSE);
330 return result;
331 }
332
333 void
mono_ginst_get_desc(GString * str,MonoGenericInst * ginst)334 mono_ginst_get_desc (GString *str, MonoGenericInst *ginst)
335 {
336 int i;
337
338 for (i = 0; i < ginst->type_argc; ++i) {
339 if (i > 0)
340 g_string_append (str, ", ");
341 mono_type_get_desc (str, ginst->type_argv [i], TRUE);
342 }
343 }
344
345 char*
mono_context_get_desc(MonoGenericContext * context)346 mono_context_get_desc (MonoGenericContext *context)
347 {
348 GString *str;
349 char *res;
350
351 str = g_string_new ("");
352 g_string_append (str, "<");
353
354 if (context->class_inst)
355 mono_ginst_get_desc (str, context->class_inst);
356 if (context->method_inst) {
357 if (context->class_inst)
358 g_string_append (str, "; ");
359 mono_ginst_get_desc (str, context->method_inst);
360 }
361
362 g_string_append (str, ">");
363 res = g_strdup (str->str);
364 g_string_free (str, TRUE);
365 return res;
366 }
367
368 /**
369 * mono_method_desc_new:
370 * \param name the method name.
371 * \param include_namespace whether the name includes a namespace or not.
372 *
373 * Creates a method description for \p name, which conforms to the following
374 * specification:
375 *
376 * <code>[namespace.]classname:methodname[(args...)]</code>
377 *
378 * in all the loaded assemblies.
379 *
380 * Both classname and methodname can contain <code>*</code> which matches anything.
381 *
382 * \returns a parsed representation of the method description.
383 */
384 MonoMethodDesc*
mono_method_desc_new(const char * name,gboolean include_namespace)385 mono_method_desc_new (const char *name, gboolean include_namespace)
386 {
387 MonoMethodDesc *result;
388 char *class_name, *class_nspace, *method_name, *use_args, *end;
389 int use_namespace;
390 int generic_delim_stack;
391
392 class_nspace = g_strdup (name);
393 use_args = strchr (class_nspace, '(');
394 if (use_args) {
395 /* Allow a ' ' between the method name and the signature */
396 if (use_args > class_nspace && use_args [-1] == ' ')
397 use_args [-1] = 0;
398 *use_args++ = 0;
399 end = strchr (use_args, ')');
400 if (!end) {
401 g_free (class_nspace);
402 return NULL;
403 }
404 *end = 0;
405 }
406 method_name = strrchr (class_nspace, ':');
407 if (!method_name) {
408 g_free (class_nspace);
409 return NULL;
410 }
411 /* allow two :: to separate the method name */
412 if (method_name != class_nspace && method_name [-1] == ':')
413 method_name [-1] = 0;
414 *method_name++ = 0;
415 class_name = strrchr (class_nspace, '.');
416 if (class_name) {
417 *class_name++ = 0;
418 use_namespace = 1;
419 } else {
420 class_name = class_nspace;
421 use_namespace = 0;
422 }
423 result = g_new0 (MonoMethodDesc, 1);
424 result->include_namespace = include_namespace;
425 result->name = method_name;
426 result->klass = class_name;
427 result->name_space = use_namespace? class_nspace: NULL;
428 result->args = use_args? use_args: NULL;
429 if (strstr (result->name, "*"))
430 result->name_glob = TRUE;
431 if (strstr (result->klass, "*"))
432 result->klass_glob = TRUE;
433 if (use_args) {
434 end = use_args;
435 if (*end)
436 result->num_args = 1;
437 generic_delim_stack = 0;
438 while (*end) {
439 if (*end == '<')
440 generic_delim_stack++;
441 else if (*end == '>')
442 generic_delim_stack--;
443
444 if (*end == ',' && generic_delim_stack == 0)
445 result->num_args++;
446 ++end;
447 }
448 }
449
450 return result;
451 }
452
453 /**
454 * mono_method_desc_from_method:
455 */
456 MonoMethodDesc*
mono_method_desc_from_method(MonoMethod * method)457 mono_method_desc_from_method (MonoMethod *method)
458 {
459 MonoMethodDesc *result;
460
461 result = g_new0 (MonoMethodDesc, 1);
462 result->include_namespace = TRUE;
463 result->name = g_strdup (method->name);
464 result->klass = g_strdup (method->klass->name);
465 result->name_space = g_strdup (method->klass->name_space);
466
467 return result;
468 }
469
470 /**
471 * mono_method_desc_free:
472 * \param desc method description to be released
473 * Releases the \c MonoMethodDesc object \p desc.
474 */
475 void
mono_method_desc_free(MonoMethodDesc * desc)476 mono_method_desc_free (MonoMethodDesc *desc)
477 {
478 if (desc->name_space)
479 g_free (desc->name_space);
480 else if (desc->klass)
481 g_free (desc->klass);
482 g_free (desc);
483 }
484
485 /**
486 * mono_method_desc_match:
487 * \param desc \c MonoMethoDescription
488 * \param method \c MonoMethod to test
489 *
490 * Determines whether the specified \p method matches the provided \p desc description.
491 *
492 * namespace and class are supposed to match already if this function is used.
493 * \returns TRUE if the method matches the description, FALSE otherwise.
494 */
495 gboolean
mono_method_desc_match(MonoMethodDesc * desc,MonoMethod * method)496 mono_method_desc_match (MonoMethodDesc *desc, MonoMethod *method)
497 {
498 char *sig;
499 gboolean name_match;
500
501 name_match = strcmp (desc->name, method->name) == 0;
502 if (!name_match)
503 return FALSE;
504 if (!desc->args)
505 return TRUE;
506 if (desc->num_args != mono_method_signature (method)->param_count)
507 return FALSE;
508 sig = mono_signature_get_desc (mono_method_signature (method), desc->include_namespace);
509 if (strcmp (sig, desc->args)) {
510 g_free (sig);
511 return FALSE;
512 }
513 g_free (sig);
514 return TRUE;
515 }
516
517 static const char *
my_strrchr(const char * str,char ch,int * len)518 my_strrchr (const char *str, char ch, int *len)
519 {
520 int pos;
521
522 for (pos = (*len)-1; pos >= 0; pos--) {
523 if (str [pos] != ch)
524 continue;
525
526 *len = pos;
527 return str + pos;
528 }
529
530 return NULL;
531 }
532
533 static gboolean
match_class(MonoMethodDesc * desc,int pos,MonoClass * klass)534 match_class (MonoMethodDesc *desc, int pos, MonoClass *klass)
535 {
536 const char *p;
537 gboolean is_terminal = TRUE;
538
539 if (desc->klass_glob && !strcmp (desc->klass, "*"))
540 return TRUE;
541 #ifndef _EGLIB_MAJOR
542 if (desc->klass_glob && g_pattern_match_simple (desc->klass, klass->name))
543 return TRUE;
544 #endif
545 if (desc->klass[pos] == '/')
546 is_terminal = FALSE;
547
548 p = my_strrchr (desc->klass, '/', &pos);
549 if (!p) {
550 if (is_terminal && strcmp (desc->klass, klass->name))
551 return FALSE;
552 if (!is_terminal && strncmp (desc->klass, klass->name, pos))
553 return FALSE;
554 if (desc->name_space && strcmp (desc->name_space, klass->name_space))
555 return FALSE;
556 return TRUE;
557 }
558
559 if (strcmp (p+1, klass->name))
560 return FALSE;
561 if (!klass->nested_in)
562 return FALSE;
563
564 return match_class (desc, pos, klass->nested_in);
565 }
566
567 /**
568 * mono_method_desc_is_full:
569 */
570 gboolean
mono_method_desc_is_full(MonoMethodDesc * desc)571 mono_method_desc_is_full (MonoMethodDesc *desc)
572 {
573 return desc->klass && desc->klass[0] != '\0';
574 }
575
576 /**
577 * mono_method_desc_full_match:
578 */
579 gboolean
mono_method_desc_full_match(MonoMethodDesc * desc,MonoMethod * method)580 mono_method_desc_full_match (MonoMethodDesc *desc, MonoMethod *method)
581 {
582 if (!desc->klass)
583 return FALSE;
584 if (!match_class (desc, strlen (desc->klass), method->klass))
585 return FALSE;
586
587 return mono_method_desc_match (desc, method);
588 }
589
590 /**
591 * mono_method_desc_search_in_class:
592 */
593 MonoMethod*
mono_method_desc_search_in_class(MonoMethodDesc * desc,MonoClass * klass)594 mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass)
595 {
596 MonoMethod* m;
597 gpointer iter = NULL;
598
599 while ((m = mono_class_get_methods (klass, &iter)))
600 if (mono_method_desc_match (desc, m))
601 return m;
602 return NULL;
603 }
604
605 /**
606 * mono_method_desc_search_in_image:
607 */
608 MonoMethod*
mono_method_desc_search_in_image(MonoMethodDesc * desc,MonoImage * image)609 mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image)
610 {
611 MonoClass *klass;
612 const MonoTableInfo *methods;
613 MonoMethod *method;
614 int i;
615
616 /* Handle short names for system classes */
617 if (!desc->name_space && image == mono_defaults.corlib) {
618 klass = find_system_class (desc->klass);
619 if (klass)
620 return mono_method_desc_search_in_class (desc, klass);
621 }
622
623 if (desc->name_space && desc->klass) {
624 klass = mono_class_try_load_from_name (image, desc->name_space, desc->klass);
625 if (!klass)
626 return NULL;
627 return mono_method_desc_search_in_class (desc, klass);
628 }
629
630 /* FIXME: Is this call necessary? We don't use its result. */
631 mono_image_get_table_info (image, MONO_TABLE_TYPEDEF);
632 methods = mono_image_get_table_info (image, MONO_TABLE_METHOD);
633 for (i = 0; i < mono_table_info_get_rows (methods); ++i) {
634 MonoError error;
635 guint32 token = mono_metadata_decode_row_col (methods, i, MONO_METHOD_NAME);
636 const char *n = mono_metadata_string_heap (image, token);
637
638 if (strcmp (n, desc->name))
639 continue;
640 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
641 if (!method) {
642 mono_error_cleanup (&error);
643 continue;
644 }
645 if (mono_method_desc_full_match (desc, method))
646 return method;
647 }
648 return NULL;
649 }
650
651 static const unsigned char*
dis_one(GString * str,MonoDisHelper * dh,MonoMethod * method,const unsigned char * ip,const unsigned char * end)652 dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned char *ip, const unsigned char *end)
653 {
654 MonoError error;
655 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
656 const MonoOpcode *opcode;
657 guint32 label, token;
658 gint32 sval;
659 int i;
660 char *tmp;
661 const unsigned char* il_code;
662
663 if (!header) {
664 g_string_append_printf (str, "could not disassemble, bad header due to %s", mono_error_get_message (&error));
665 mono_error_cleanup (&error);
666 return end;
667 }
668 il_code = mono_method_header_get_code (header, NULL, NULL);
669
670 label = ip - il_code;
671 if (dh->indenter) {
672 tmp = dh->indenter (dh, method, label);
673 g_string_append (str, tmp);
674 g_free (tmp);
675 }
676 if (dh->label_format)
677 g_string_append_printf (str, dh->label_format, label);
678
679 i = mono_opcode_value (&ip, end);
680 ip++;
681 opcode = &mono_opcodes [i];
682 g_string_append_printf (str, "%-10s", mono_opcode_name (i));
683
684 switch (opcode->argument) {
685 case MonoInlineNone:
686 break;
687 case MonoInlineType:
688 case MonoInlineField:
689 case MonoInlineMethod:
690 case MonoInlineTok:
691 case MonoInlineSig:
692 token = read32 (ip);
693 if (dh->tokener) {
694 tmp = dh->tokener (dh, method, token);
695 g_string_append (str, tmp);
696 g_free (tmp);
697 } else {
698 g_string_append_printf (str, "0x%08x", token);
699 }
700 ip += 4;
701 break;
702 case MonoInlineString: {
703 const char *blob;
704 char *s;
705 size_t len2;
706 char *blob2 = NULL;
707
708 if (!image_is_dynamic (method->klass->image) && !method_is_dynamic (method)) {
709 token = read32 (ip);
710 blob = mono_metadata_user_string (method->klass->image, mono_metadata_token_index (token));
711
712 len2 = mono_metadata_decode_blob_size (blob, &blob);
713 len2 >>= 1;
714
715 #ifdef NO_UNALIGNED_ACCESS
716 /* The blob might not be 2 byte aligned */
717 blob2 = g_malloc ((len2 * 2) + 1);
718 memcpy (blob2, blob, len2 * 2);
719 #else
720 blob2 = (char*)blob;
721 #endif
722
723 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
724 {
725 guint16 *buf = g_new (guint16, len2 + 1);
726 int i;
727
728 for (i = 0; i < len2; ++i)
729 buf [i] = GUINT16_FROM_LE (((guint16*)blob2) [i]);
730 s = g_utf16_to_utf8 (buf, len2, NULL, NULL, NULL);
731 g_free (buf);
732 }
733 #else
734 s = g_utf16_to_utf8 ((gunichar2*)blob2, len2, NULL, NULL, NULL);
735 #endif
736
737 g_string_append_printf (str, "\"%s\"", s);
738 g_free (s);
739 if (blob != blob2)
740 g_free (blob2);
741 }
742 ip += 4;
743 break;
744 }
745 case MonoInlineVar:
746 g_string_append_printf (str, "%d", read16 (ip));
747 ip += 2;
748 break;
749 case MonoShortInlineVar:
750 g_string_append_printf (str, "%d", (*ip));
751 ip ++;
752 break;
753 case MonoInlineBrTarget:
754 sval = read32 (ip);
755 ip += 4;
756 if (dh->label_target)
757 g_string_append_printf (str, dh->label_target, ip + sval - il_code);
758 else
759 g_string_append_printf (str, "%d", sval);
760 break;
761 case MonoShortInlineBrTarget:
762 sval = *(const signed char*)ip;
763 ip ++;
764 if (dh->label_target)
765 g_string_append_printf (str, dh->label_target, ip + sval - il_code);
766 else
767 g_string_append_printf (str, "%d", sval);
768 break;
769 case MonoInlineSwitch: {
770 const unsigned char *end;
771 sval = read32 (ip);
772 ip += 4;
773 end = ip + sval * 4;
774 g_string_append_c (str, '(');
775 for (i = 0; i < sval; ++i) {
776 if (i > 0)
777 g_string_append (str, ", ");
778 label = read32 (ip);
779 if (dh->label_target)
780 g_string_append_printf (str, dh->label_target, end + label - il_code);
781 else
782 g_string_append_printf (str, "%d", label);
783 ip += 4;
784 }
785 g_string_append_c (str, ')');
786 break;
787 }
788 case MonoInlineR: {
789 double r;
790 readr8 (ip, &r);
791 g_string_append_printf (str, "%g", r);
792 ip += 8;
793 break;
794 }
795 case MonoShortInlineR: {
796 float r;
797 readr4 (ip, &r);
798 g_string_append_printf (str, "%g", r);
799 ip += 4;
800 break;
801 }
802 case MonoInlineI:
803 g_string_append_printf (str, "%d", (gint32)read32 (ip));
804 ip += 4;
805 break;
806 case MonoShortInlineI:
807 g_string_append_printf (str, "%d", *(const signed char*)ip);
808 ip ++;
809 break;
810 case MonoInlineI8:
811 ip += 8;
812 break;
813 default:
814 g_assert_not_reached ();
815 }
816 if (dh->newline)
817 g_string_append (str, dh->newline);
818
819 mono_metadata_free_mh (header);
820 return ip;
821 }
822
823 static MonoDisHelper
824 default_dh = {
825 "\n",
826 "IL_%04x: ", /* label_format */
827 "IL_%04x", /* label_target */
828 NULL, /* indenter */
829 NULL, /* tokener */
830 NULL /* user data */
831 };
832
833 /**
834 * mono_disasm_code_one:
835 */
836 char*
mono_disasm_code_one(MonoDisHelper * dh,MonoMethod * method,const guchar * ip,const guchar ** endp)837 mono_disasm_code_one (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const guchar **endp)
838 {
839 char *result;
840 GString *res = g_string_new ("");
841
842 if (!dh)
843 dh = &default_dh;
844 /* set ip + 2 as the end: this is just a debugging method */
845 ip = dis_one (res, dh, method, ip, ip + 2);
846 if (endp)
847 *endp = ip;
848
849 result = res->str;
850 g_string_free (res, FALSE);
851 return result;
852 }
853
854 /**
855 * mono_disasm_code:
856 */
857 char*
mono_disasm_code(MonoDisHelper * dh,MonoMethod * method,const guchar * ip,const guchar * end)858 mono_disasm_code (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const guchar* end)
859 {
860 char *result;
861 GString *res = g_string_new ("");
862
863 if (!dh)
864 dh = &default_dh;
865 while (ip < end) {
866 ip = dis_one (res, dh, method, ip, end);
867 }
868
869 result = res->str;
870 g_string_free (res, FALSE);
871 return result;
872 }
873
874 /**
875 * mono_field_full_name:
876 * \param field field to retrieve information for
877 * \returns the full name for the field, made up of the namespace, type name and the field name.
878 */
879 char *
mono_field_full_name(MonoClassField * field)880 mono_field_full_name (MonoClassField *field)
881 {
882 char *res;
883 const char *nspace = field->parent->name_space;
884
885 res = g_strdup_printf ("%s%s%s:%s", nspace, *nspace ? "." : "",
886 field->parent->name, mono_field_get_name (field));
887
888 return res;
889 }
890
891 char *
mono_method_get_name_full(MonoMethod * method,gboolean signature,gboolean ret,MonoTypeNameFormat format)892 mono_method_get_name_full (MonoMethod *method, gboolean signature, gboolean ret, MonoTypeNameFormat format)
893 {
894 char *res;
895 char wrapper [64];
896 char *klass_desc;
897 char *inst_desc = NULL;
898 MonoError error;
899
900 const char *class_method_separator = ":";
901 const char *method_sig_space = " ";
902 if (format == MONO_TYPE_NAME_FORMAT_REFLECTION) {
903 class_method_separator = ".";
904 method_sig_space = "";
905 }
906
907 if (format == MONO_TYPE_NAME_FORMAT_IL)
908 klass_desc = mono_type_full_name (&method->klass->byval_arg);
909 else
910 klass_desc = mono_type_get_name_full (&method->klass->byval_arg, format);
911
912 if (method->is_inflated && ((MonoMethodInflated*)method)->context.method_inst) {
913 GString *str = g_string_new ("");
914 if (format == MONO_TYPE_NAME_FORMAT_IL)
915 g_string_append (str, "<");
916 else
917 g_string_append (str, "[");
918 mono_ginst_get_desc (str, ((MonoMethodInflated*)method)->context.method_inst);
919 if (format == MONO_TYPE_NAME_FORMAT_IL)
920 g_string_append_c (str, '>');
921 else
922 g_string_append_c (str, ']');
923
924 inst_desc = str->str;
925 g_string_free (str, FALSE);
926 } else if (method->is_generic) {
927 MonoGenericContainer *container = mono_method_get_generic_container (method);
928
929 GString *str = g_string_new ("");
930 if (format == MONO_TYPE_NAME_FORMAT_IL)
931 g_string_append (str, "<");
932 else
933 g_string_append (str, "[");
934 mono_ginst_get_desc (str, container->context.method_inst);
935 if (format == MONO_TYPE_NAME_FORMAT_IL)
936 g_string_append_c (str, '>');
937 else
938 g_string_append_c (str, ']');
939
940 inst_desc = str->str;
941 g_string_free (str, FALSE);
942 }
943
944 if (method->wrapper_type != MONO_WRAPPER_NONE)
945 sprintf (wrapper, "(wrapper %s) ", wrapper_type_to_str (method->wrapper_type));
946 else
947 strcpy (wrapper, "");
948
949 if (signature) {
950 MonoMethodSignature *sig = mono_method_signature_checked (method, &error);
951 char *tmpsig;
952
953 if (!is_ok (&error)) {
954 tmpsig = g_strdup_printf ("<unable to load signature>");
955 mono_error_cleanup (&error);
956 } else {
957 tmpsig = mono_signature_get_desc (sig, TRUE);
958 }
959
960 if (method->wrapper_type != MONO_WRAPPER_NONE)
961 sprintf (wrapper, "(wrapper %s) ", wrapper_type_to_str (method->wrapper_type));
962 else
963 strcpy (wrapper, "");
964 if (ret && sig) {
965 char *ret_str = mono_type_full_name (sig->ret);
966 res = g_strdup_printf ("%s%s %s%s%s%s%s(%s)", wrapper, ret_str, klass_desc,
967 class_method_separator,
968 method->name, inst_desc ? inst_desc : "", method_sig_space, tmpsig);
969 g_free (ret_str);
970 } else {
971 res = g_strdup_printf ("%s%s%s%s%s%s(%s)", wrapper, klass_desc,
972 class_method_separator,
973 method->name, inst_desc ? inst_desc : "", method_sig_space, tmpsig);
974 }
975 g_free (tmpsig);
976 } else {
977 res = g_strdup_printf ("%s%s%s%s%s", wrapper, klass_desc,
978 class_method_separator,
979 method->name, inst_desc ? inst_desc : "");
980 }
981
982 g_free (klass_desc);
983 g_free (inst_desc);
984
985 return res;
986 }
987
988 /**
989 * mono_method_full_name:
990 */
991 char *
mono_method_full_name(MonoMethod * method,gboolean signature)992 mono_method_full_name (MonoMethod *method, gboolean signature)
993 {
994 return mono_method_get_name_full (method, signature, FALSE, MONO_TYPE_NAME_FORMAT_IL);
995 }
996
997 char *
mono_method_get_full_name(MonoMethod * method)998 mono_method_get_full_name (MonoMethod *method)
999 {
1000 return mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL);
1001 }
1002
1003 /**
1004 * mono_method_get_reflection_name:
1005 *
1006 * Returns the name of the method, including signature, using the same formating as reflection.
1007 */
1008 char *
mono_method_get_reflection_name(MonoMethod * method)1009 mono_method_get_reflection_name (MonoMethod *method)
1010 {
1011 return mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
1012 }
1013
1014 static const char*
print_name_space(MonoClass * klass)1015 print_name_space (MonoClass *klass)
1016 {
1017 if (klass->nested_in) {
1018 print_name_space (klass->nested_in);
1019 g_print ("%s", klass->nested_in->name);
1020 return "/";
1021 }
1022 if (klass->name_space [0]) {
1023 g_print ("%s", klass->name_space);
1024 return ".";
1025 }
1026 return "";
1027 }
1028
1029 /**
1030 * mono_object_describe:
1031 *
1032 * Prints to stdout a small description of the object \p obj.
1033 * For use in a debugger.
1034 */
1035 void
mono_object_describe(MonoObject * obj)1036 mono_object_describe (MonoObject *obj)
1037 {
1038 MonoError error;
1039 MonoClass* klass;
1040 const char* sep;
1041 if (!obj) {
1042 g_print ("(null)\n");
1043 return;
1044 }
1045 klass = mono_object_class (obj);
1046 if (klass == mono_defaults.string_class) {
1047 char *utf8 = mono_string_to_utf8_checked ((MonoString*)obj, &error);
1048 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1049 if (utf8 && strlen (utf8) > 60) {
1050 utf8 [57] = '.';
1051 utf8 [58] = '.';
1052 utf8 [59] = '.';
1053 utf8 [60] = 0;
1054 }
1055 if (utf8) {
1056 g_print ("String at %p, length: %d, '%s'\n", obj, mono_string_length ((MonoString*) obj), utf8);
1057 } else {
1058 g_print ("String at %p, length: %d, unable to decode UTF16\n", obj, mono_string_length ((MonoString*) obj));
1059 }
1060 g_free (utf8);
1061 } else if (klass->rank) {
1062 MonoArray *array = (MonoArray*)obj;
1063 sep = print_name_space (klass);
1064 g_print ("%s%s", sep, klass->name);
1065 g_print (" at %p, rank: %d, length: %d\n", obj, klass->rank, (int)mono_array_length (array));
1066 } else {
1067 sep = print_name_space (klass);
1068 g_print ("%s%s", sep, klass->name);
1069 g_print (" object at %p (klass: %p)\n", obj, klass);
1070 }
1071
1072 }
1073
1074 static void
print_field_value(const char * field_ptr,MonoClassField * field,int type_offset)1075 print_field_value (const char *field_ptr, MonoClassField *field, int type_offset)
1076 {
1077 MonoType *type;
1078 g_print ("At %p (ofs: %2d) %s: ", field_ptr, field->offset + type_offset, mono_field_get_name (field));
1079 type = mono_type_get_underlying_type (field->type);
1080
1081 switch (type->type) {
1082 case MONO_TYPE_I:
1083 case MONO_TYPE_U:
1084 case MONO_TYPE_PTR:
1085 case MONO_TYPE_FNPTR:
1086 g_print ("%p\n", *(const void**)field_ptr);
1087 break;
1088 case MONO_TYPE_STRING:
1089 case MONO_TYPE_SZARRAY:
1090 case MONO_TYPE_CLASS:
1091 case MONO_TYPE_OBJECT:
1092 case MONO_TYPE_ARRAY:
1093 mono_object_describe (*(MonoObject**)field_ptr);
1094 break;
1095 case MONO_TYPE_GENERICINST:
1096 if (!mono_type_generic_inst_is_valuetype (type)) {
1097 mono_object_describe (*(MonoObject**)field_ptr);
1098 break;
1099 } else {
1100 /* fall through */
1101 }
1102 case MONO_TYPE_VALUETYPE: {
1103 MonoClass *k = mono_class_from_mono_type (type);
1104 g_print ("%s ValueType (type: %p) at %p\n", k->name, k, field_ptr);
1105 break;
1106 }
1107 case MONO_TYPE_I1:
1108 g_print ("%d\n", *(gint8*)field_ptr);
1109 break;
1110 case MONO_TYPE_U1:
1111 g_print ("%d\n", *(guint8*)field_ptr);
1112 break;
1113 case MONO_TYPE_I2:
1114 g_print ("%d\n", *(gint16*)field_ptr);
1115 break;
1116 case MONO_TYPE_U2:
1117 g_print ("%d\n", *(guint16*)field_ptr);
1118 break;
1119 case MONO_TYPE_I4:
1120 g_print ("%d\n", *(gint32*)field_ptr);
1121 break;
1122 case MONO_TYPE_U4:
1123 g_print ("%u\n", *(guint32*)field_ptr);
1124 break;
1125 case MONO_TYPE_I8:
1126 g_print ("%lld\n", (long long int)*(gint64*)field_ptr);
1127 break;
1128 case MONO_TYPE_U8:
1129 g_print ("%llu\n", (long long unsigned int)*(guint64*)field_ptr);
1130 break;
1131 case MONO_TYPE_R4:
1132 g_print ("%f\n", *(gfloat*)field_ptr);
1133 break;
1134 case MONO_TYPE_R8:
1135 g_print ("%f\n", *(gdouble*)field_ptr);
1136 break;
1137 case MONO_TYPE_BOOLEAN:
1138 g_print ("%s (%d)\n", *(guint8*)field_ptr? "True": "False", *(guint8*)field_ptr);
1139 break;
1140 case MONO_TYPE_CHAR:
1141 g_print ("'%c' (%d 0x%04x)\n", *(guint16*)field_ptr, *(guint16*)field_ptr, *(guint16*)field_ptr);
1142 break;
1143 default:
1144 g_assert_not_reached ();
1145 break;
1146 }
1147 }
1148
1149 static void
objval_describe(MonoClass * klass,const char * addr)1150 objval_describe (MonoClass *klass, const char *addr)
1151 {
1152 MonoClassField *field;
1153 MonoClass *p;
1154 const char *field_ptr;
1155 gssize type_offset = 0;
1156
1157 if (klass->valuetype)
1158 type_offset = -sizeof (MonoObject);
1159
1160 for (p = klass; p != NULL; p = p->parent) {
1161 gpointer iter = NULL;
1162 int printed_header = FALSE;
1163 while ((field = mono_class_get_fields (p, &iter))) {
1164 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
1165 continue;
1166
1167 if (p != klass && !printed_header) {
1168 const char *sep;
1169 g_print ("In class ");
1170 sep = print_name_space (p);
1171 g_print ("%s%s:\n", sep, p->name);
1172 printed_header = TRUE;
1173 }
1174 field_ptr = (const char*)addr + field->offset + type_offset;
1175
1176 print_field_value (field_ptr, field, type_offset);
1177 }
1178 }
1179 }
1180
1181 /**
1182 * mono_object_describe_fields:
1183 *
1184 * Prints to stdout a small description of each field of the object \p obj.
1185 * For use in a debugger.
1186 */
1187 void
mono_object_describe_fields(MonoObject * obj)1188 mono_object_describe_fields (MonoObject *obj)
1189 {
1190 MonoClass *klass = mono_object_class (obj);
1191 objval_describe (klass, (char*)obj);
1192 }
1193
1194 /**
1195 * mono_value_describe_fields:
1196 *
1197 * Prints to stdout a small description of each field of the value type
1198 * stored at \p addr of type \p klass.
1199 * For use in a debugger.
1200 */
1201 void
mono_value_describe_fields(MonoClass * klass,const char * addr)1202 mono_value_describe_fields (MonoClass* klass, const char* addr)
1203 {
1204 objval_describe (klass, addr);
1205 }
1206
1207 /**
1208 * mono_class_describe_statics:
1209 *
1210 * Prints to stdout a small description of each static field of the type \p klass
1211 * in the current application domain.
1212 * For use in a debugger.
1213 */
1214 void
mono_class_describe_statics(MonoClass * klass)1215 mono_class_describe_statics (MonoClass* klass)
1216 {
1217 MonoError error;
1218 MonoClassField *field;
1219 MonoClass *p;
1220 const char *field_ptr;
1221 MonoVTable *vtable = mono_class_vtable_full (mono_domain_get (), klass, &error);
1222 const char *addr;
1223
1224 if (!vtable || !is_ok (&error)) {
1225 mono_error_cleanup (&error);
1226 return;
1227 }
1228
1229 if (!(addr = (const char *)mono_vtable_get_static_field_data (vtable)))
1230 return;
1231
1232 for (p = klass; p != NULL; p = p->parent) {
1233 gpointer iter = NULL;
1234 while ((field = mono_class_get_fields (p, &iter))) {
1235 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
1236 continue;
1237 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
1238 continue;
1239
1240 field_ptr = (const char*)addr + field->offset;
1241
1242 print_field_value (field_ptr, field, 0);
1243 }
1244 }
1245 }
1246
1247 /**
1248 * mono_print_method_code
1249 * \param method: a pointer to the method
1250 *
1251 * This method is used from a debugger to print the code of the method.
1252 *
1253 * This prints the IL code of the method in the standard output.
1254 */
1255 void
mono_method_print_code(MonoMethod * method)1256 mono_method_print_code (MonoMethod *method)
1257 {
1258 MonoError error;
1259 char *code;
1260 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
1261 if (!header) {
1262 printf ("METHOD HEADER NOT FOUND DUE TO: %s\n", mono_error_get_message (&error));
1263 mono_error_cleanup (&error);
1264 return;
1265 }
1266 code = mono_disasm_code (0, method, header->code, header->code + header->code_size);
1267 printf ("CODE FOR %s:\n%s\n", mono_method_full_name (method, TRUE), code);
1268 g_free (code);
1269 }
1270