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