1 /*
2  * main.c: Sample disassembler
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  *
9  * TODO:
10  *   Investigate how interface inheritance works and how it should be dumped.
11  *   Structs are not being labeled as `valuetype' classes
12  *
13  *   How are fields with literals mapped to constants?
14  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15  */
16 #include <config.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <glib.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include "meta.h"
24 #include "util.h"
25 #include "dump.h"
26 #include "get.h"
27 #include "dis-cil.h"
28 #include "declsec.h"
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/object-internals.h>
31 #include <mono/metadata/loader.h>
32 #include <mono/metadata/assembly-internals.h>
33 #include <mono/metadata/appdomain.h>
34 #include <mono/metadata/w32handle.h>
35 #include <mono/utils/bsearch.h>
36 #include <mono/utils/mono-counters.h>
37 
38 static void     setup_filter          (MonoImage *image);
39 static gboolean should_include_type   (int idx);
40 static gboolean should_include_method (int idx);
41 static gboolean should_include_field  (int idx);
42 
43 FILE *output;
44 
45 /* True if you want to get a dump of the header data */
46 gboolean dump_header_data_p = FALSE;
47 
48 /* True if you want to get forward declarations */
49 gboolean dump_forward_decls = FALSE;
50 
51 /* True if you want to dump managed resources as files */
52 gboolean dump_managed_resources = FALSE;
53 
54 gboolean substitute_with_mscorlib_p = FALSE;
55 
56 int dump_table = -1;
57 
58 static void
dump_header_data(MonoImage * img)59 dump_header_data (MonoImage *img)
60 {
61 	if (!dump_header_data_p)
62 		return;
63 
64 	fprintf (output,
65 		 "// Ximian's CIL disassembler, version 1.0\n"
66 		 "// Copyright (C) 2001 Ximian, Inc.\n\n");
67 }
68 
69 static void
dump_cattrs_list(GList * list,const char * indent)70 dump_cattrs_list (GList *list,  const char *indent)
71 {
72 	GList *tmp;
73 
74 	for (tmp = list; tmp; tmp = tmp->next) {
75 		fprintf (output, "%s%s\n", indent, (char*)tmp->data);
76 		g_free (tmp->data);
77 	}
78 	g_list_free (list);
79 }
80 
81 static void
dump_cattrs(MonoImage * m,guint32 token,const char * indent)82 dump_cattrs (MonoImage *m, guint32 token, const char *indent)
83 {
84 	GList *list;
85 
86 	list = dis_get_custom_attrs (m, token);
87 	dump_cattrs_list (list, indent);
88 }
89 
90 static const char*
get_il_security_action(int val)91 get_il_security_action (int val)
92 {
93 	static char buf [32];
94 
95 	switch (val) {
96 	case SECURITY_ACTION_DEMAND:
97 		return "demand";
98 	case SECURITY_ACTION_ASSERT:
99 		return "assert";
100 	case SECURITY_ACTION_DENY:
101 		return "deny";
102 	case SECURITY_ACTION_PERMITONLY:
103 		return "permitonly";
104 	case SECURITY_ACTION_LINKDEMAND:
105 		return "linkcheck";
106 	case SECURITY_ACTION_INHERITDEMAND:
107 		return "inheritcheck";
108 	case SECURITY_ACTION_REQMIN:
109 		return "reqmin";
110 	case SECURITY_ACTION_REQOPT:
111 		return "reqopt";
112 	case SECURITY_ACTION_REQREFUSE:
113 		return "reqrefuse";
114 	/* Special actions (for non CAS permissions) */
115 	case SECURITY_ACTION_NONCASDEMAND:
116 		return "noncasdemand";
117 	case SECURITY_ACTION_NONCASLINKDEMAND:
118 		return "noncaslinkdemand";
119 	case SECURITY_ACTION_NONCASINHERITANCE:
120 		return "noncasinheritance";
121 	/* Fx 2.0 actions (for both CAS and non-CAS permissions) */
122 	case SECURITY_ACTION_LINKDEMANDCHOICE:
123 		return "linkdemandor";
124 	case SECURITY_ACTION_INHERITDEMANDCHOICE:
125 		return "inheritancedemandor";
126 	case SECURITY_ACTION_DEMANDCHOICE:
127 		return "demandor";
128 	default:
129 		g_snprintf (buf, sizeof (buf), "0x%04X", val);
130 		return buf;
131 	}
132 }
133 
134 #define OBJECT_TYPE_TYPEDEF	0
135 #define OBJECT_TYPE_METHODDEF	1
136 #define OBJECT_TYPE_ASSEMBLYDEF	2
137 
138 static void
dump_declarative_security(MonoImage * m,guint32 objectType,guint32 token,const char * indent)139 dump_declarative_security (MonoImage *m, guint32 objectType, guint32 token, const char *indent)
140 {
141 	MonoTableInfo *t = &m->tables [MONO_TABLE_DECLSECURITY];
142 	guint32 cols [MONO_DECL_SECURITY_SIZE];
143 	int i, len;
144 	guint32 idx;
145 	const char *blob, *action;
146 
147 	for (i = 1; i <= t->rows; i++) {
148 		mono_metadata_decode_row (t, i - 1, cols, MONO_DECL_SECURITY_SIZE);
149 		blob = mono_metadata_blob_heap (m, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
150 		len = mono_metadata_decode_blob_size (blob, &blob);
151 		action = get_il_security_action (cols [MONO_DECL_SECURITY_ACTION]);
152 		idx = cols [MONO_DECL_SECURITY_PARENT];
153 		if (((idx & MONO_HAS_DECL_SECURITY_MASK) == objectType) && ((idx >> MONO_HAS_DECL_SECURITY_BITS) == token)) {
154 			char *dump;
155 			if (blob [0] == MONO_DECLSEC_FORMAT_20) {
156 				/* 2.0 declarative security format */
157 				dump = dump_declsec_entry20 (m, blob, indent);
158 				fprintf (output, "%s.permissionset %s = %s\n", indent, action, dump);
159 			} else {
160 				/* 1.x declarative security metadata format */
161 				dump = data_dump (blob, len, indent);
162 				fprintf (output, "%s.permissionset %s = %s", indent, action, dump);
163 			}
164 			g_free (dump);
165 		}
166 	}
167 }
168 
169 static char *
assembly_flags(guint32 f)170 assembly_flags (guint32 f)
171 {
172 	if (f & ASSEMBLYREF_RETARGETABLE_FLAG)
173 		return g_strdup ("retargetable ");
174 	return g_strdup ("");
175 }
176 
177 static void
dis_directive_assembly(MonoImage * m)178 dis_directive_assembly (MonoImage *m)
179 {
180 	MonoTableInfo *t  = &m->tables [MONO_TABLE_ASSEMBLY];
181 	guint32 cols [MONO_ASSEMBLY_SIZE];
182 	char *flags;
183 
184 	if (t->base == NULL)
185 		return;
186 
187 	mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
188 	flags = assembly_flags (cols [MONO_ASSEMBLY_FLAGS]);
189 
190 	fprintf (output, ".assembly %s'%s'\n{\n",
191 		 flags, mono_metadata_string_heap (m, cols [MONO_ASSEMBLY_NAME]));
192 	dump_cattrs (m, MONO_TOKEN_ASSEMBLY | 1, "  ");
193 	dump_declarative_security (m, OBJECT_TYPE_ASSEMBLYDEF, 1, "  ");
194 	fprintf (output,
195 		 "  .hash algorithm 0x%08x\n"
196 		 "  .ver  %d:%d:%d:%d\n",
197 		 cols [MONO_ASSEMBLY_HASH_ALG],
198 		 cols [MONO_ASSEMBLY_MAJOR_VERSION], cols [MONO_ASSEMBLY_MINOR_VERSION],
199 		 cols [MONO_ASSEMBLY_BUILD_NUMBER], cols [MONO_ASSEMBLY_REV_NUMBER]);
200 	if (cols [MONO_ASSEMBLY_CULTURE]){
201 		const char *locale = mono_metadata_string_heap (m, cols [MONO_ASSEMBLY_CULTURE]);
202 		glong items_read, items_written;
203 		gunichar2 *render = g_utf8_to_utf16 (locale, strlen (locale), &items_read, &items_written, NULL);
204 		char *dump = data_dump ((const char *) render, items_written * sizeof (gunichar2), "\t\t");
205 		fprintf (output, "  .locale %s\n", dump);
206 		g_free (dump);
207 		g_free (render);
208 
209 	} if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
210 		const char* b = mono_metadata_blob_heap (m, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
211 		int len = mono_metadata_decode_blob_size (b, &b);
212 		char *dump = data_dump (b, len, "\t\t");
213 		fprintf (output, "  .publickey =%s", dump);
214 		g_free (dump);
215 	}
216 	fprintf (output, "}\n");
217 
218 	g_free (flags);
219 }
220 
221 static void
dis_directive_assemblyref(MonoImage * m)222 dis_directive_assemblyref (MonoImage *m)
223 {
224 	MonoTableInfo *t = &m->tables [MONO_TABLE_ASSEMBLYREF];
225 	guint32 cols [MONO_ASSEMBLYREF_SIZE];
226 	int i;
227 
228 	if (t->base == NULL)
229 		return;
230 
231 	for (i = 0; i < t->rows; i++){
232 		char *esc, *flags;
233 
234 		mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
235 
236 		esc = get_escaped_name (mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_NAME]));
237 		flags = assembly_flags (cols [MONO_ASSEMBLYREF_FLAGS]);
238 
239 		fprintf (output,
240 			 ".assembly extern %s%s\n"
241 			 "{\n"
242 			 "  .ver %d:%d:%d:%d\n",
243 			 flags,
244 			 esc,
245 			 cols [MONO_ASSEMBLYREF_MAJOR_VERSION], cols [MONO_ASSEMBLYREF_MINOR_VERSION],
246 			 cols [MONO_ASSEMBLYREF_BUILD_NUMBER], cols [MONO_ASSEMBLYREF_REV_NUMBER]
247 			);
248 		dump_cattrs (m, MONO_TOKEN_ASSEMBLY_REF | (i + 1), "  ");
249 		if (cols [MONO_ASSEMBLYREF_CULTURE]){
250 			fprintf (output, "  .locale %s\n", mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_CULTURE]));
251 		}
252 		if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]){
253 			const char* b = mono_metadata_blob_heap (m, cols [MONO_ASSEMBLYREF_PUBLIC_KEY]);
254 			int len = mono_metadata_decode_blob_size (b, &b);
255 			char *dump = data_dump (b, len, "\t\t");
256 			fprintf (output, "  .publickeytoken =%s", dump);
257 			g_free (dump);
258 		}
259 		fprintf (output, "}\n");
260 		g_free (flags);
261 		g_free (esc);
262 	}
263 }
264 
265 static void
dis_directive_module(MonoImage * m)266 dis_directive_module (MonoImage *m)
267 {
268 	MonoTableInfo *t = &m->tables [MONO_TABLE_MODULE];
269 	int i;
270 
271 	for (i = 0; i < t->rows; i++){
272 		guint32 cols [MONO_MODULE_SIZE];
273 		const char *name;
274 		char *guid, *ename;
275 
276 		mono_metadata_decode_row (t, i, cols, MONO_MODULE_SIZE);
277 
278 		name = mono_metadata_string_heap (m, cols [MONO_MODULE_NAME]);
279 		ename = get_escaped_name (name);
280 		guid = get_guid (m, cols [MONO_MODULE_MVID]);
281 		fprintf (output, ".module %s // GUID = %s\n\n", ename, guid);
282 		g_free (ename);
283 
284 		dump_cattrs (m, MONO_TOKEN_MODULE | (i + 1), "");
285 	}
286 }
287 
288 static void
dis_directive_moduleref(MonoImage * m)289 dis_directive_moduleref (MonoImage *m)
290 {
291 	MonoTableInfo *t = &m->tables [MONO_TABLE_MODULEREF];
292 	int i;
293 
294 	for (i = 0; i < t->rows; i++){
295 		guint32 cols [MONO_MODULEREF_SIZE];
296 
297 		mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
298 
299 		fprintf (output, ".module extern '%s'\n", mono_metadata_string_heap (m, cols [MONO_MODULEREF_NAME]));
300 	}
301 
302 }
303 
304 static void
dis_nt_header(MonoImage * m)305 dis_nt_header (MonoImage *m)
306 {
307 	MonoCLIImageInfo *image_info = (MonoCLIImageInfo *)m->image_info;
308 	if (image_info && image_info->cli_header.nt.pe_stack_reserve != 0x100000)
309 		fprintf (output, ".stackreserve 0x%x\n", image_info->cli_header.nt.pe_stack_reserve);
310 }
311 
312 static void
dis_directive_file(MonoImage * m)313 dis_directive_file (MonoImage *m)
314 {
315 	MonoTableInfo *t = &m->tables [MONO_TABLE_FILE];
316 	int i, j, len;
317 	guint32 entry_point;
318 
319 	entry_point = mono_image_get_entry_point (m);
320 
321 	for (i = 0; i < t->rows; i++){
322 		guint32 cols [MONO_FILE_SIZE];
323 		const char *name, *hash;
324 		guint32 token;
325 
326 		mono_metadata_decode_row (t, i, cols, MONO_FILE_SIZE);
327 
328 		name = mono_metadata_string_heap (m, cols [MONO_FILE_NAME]);
329 
330 		hash = mono_metadata_blob_heap (m, cols [MONO_FILE_HASH_VALUE]);
331 		len = mono_metadata_decode_blob_size (hash, &hash);
332 
333 		fprintf (output, ".file %s%s .hash = (",
334 				cols [MONO_FILE_FLAGS] & FILE_CONTAINS_NO_METADATA ? "nometadata " : "", name);
335 
336 		for (j = 0; j < len; ++j)
337 			fprintf (output, " %02X", hash [j] & 0xff);
338 
339 		token = mono_metadata_make_token (MONO_TABLE_FILE, i + 1);
340 		fprintf (output, " )%s\n", (token == entry_point) ? " .entrypoint" : "");
341 	}
342 
343 }
344 
345 static void
dis_directive_mresource(MonoImage * m)346 dis_directive_mresource (MonoImage *m)
347 {
348 	MonoTableInfo *t = &m->tables [MONO_TABLE_MANIFESTRESOURCE];
349 	int i;
350 
351 	for (i = 0; i < t->rows; i++){
352 		guint32 cols [MONO_MANIFEST_SIZE];
353 		const char *name;
354 		guint32 impl, idx, name_token;
355 
356 		mono_metadata_decode_row (t, i, cols, MONO_MANIFEST_SIZE);
357 
358 		name = mono_metadata_string_heap (m, cols [MONO_MANIFEST_NAME]);
359 
360 		fprintf (output, ".mresource %s '%s'\n", (cols [MONO_MANIFEST_FLAGS] & MANIFEST_RESOURCE_VISIBILITY_MASK) == (MANIFEST_RESOURCE_PUBLIC) ? "public" : "private", name);
361 		fprintf (output, "{\n");
362 		impl = cols [MONO_MANIFEST_IMPLEMENTATION];
363 		if (impl) {
364 			idx = impl >> MONO_IMPLEMENTATION_BITS;
365 			if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
366 				name_token = mono_metadata_decode_row_col (&m->tables [MONO_TABLE_FILE], idx - 1, MONO_FILE_NAME);
367 
368 				fprintf (output, "    .file '%s' at 0x0\n", mono_metadata_string_heap (m, name_token));
369 			}
370 			if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
371 				name_token = mono_metadata_decode_row_col (&m->tables [MONO_TABLE_ASSEMBLYREF], idx - 1, MONO_ASSEMBLYREF_NAME);
372 				fprintf (output, "    .assembly extern '%s'\n", mono_metadata_string_heap (m, name_token));
373 			}
374 		}
375 		fprintf (output, "}\n");
376 	}
377 
378 }
379 
380 static dis_map_t visibility_map [] = {
381 	{ TYPE_ATTRIBUTE_NOT_PUBLIC,           "private " },
382 	{ TYPE_ATTRIBUTE_PUBLIC,               "public " },
383 	{ TYPE_ATTRIBUTE_NESTED_PUBLIC,        "nested public " },
384 	{ TYPE_ATTRIBUTE_NESTED_PRIVATE,       "nested private " },
385 	{ TYPE_ATTRIBUTE_NESTED_FAMILY,	       "nested family " },
386 	{ TYPE_ATTRIBUTE_NESTED_ASSEMBLY,      "nested assembly " },
387 	{ TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM, "nested famandassem " },
388 	{ TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM,  "nested famorassem " },
389 	{ 0, NULL }
390 };
391 
392 static dis_map_t layout_map [] = {
393 	{ TYPE_ATTRIBUTE_AUTO_LAYOUT,          "auto " },
394 	{ TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT,    "sequential " },
395 	{ TYPE_ATTRIBUTE_EXPLICIT_LAYOUT,      "explicit " },
396 	{ 0, NULL }
397 };
398 
399 static dis_map_t format_map [] = {
400 	{ TYPE_ATTRIBUTE_ANSI_CLASS,           "ansi " },
401 	{ TYPE_ATTRIBUTE_UNICODE_CLASS,	       "unicode " },
402 	{ TYPE_ATTRIBUTE_AUTO_CLASS,           "auto " },
403 	{ 0, NULL }
404 };
405 
406 static char *
typedef_flags(guint32 flags)407 typedef_flags (guint32 flags)
408 {
409 	static char buffer [1024];
410 	int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
411 	int layout = flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
412 	int format = flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK;
413 
414 	buffer [0] = 0;
415 
416 	strcat (buffer, map (visibility, visibility_map));
417 	strcat (buffer, map (layout, layout_map));
418 	strcat (buffer, map (format, format_map));
419 
420 	if (flags & TYPE_ATTRIBUTE_ABSTRACT)
421 		strcat (buffer, "abstract ");
422 	if (flags & TYPE_ATTRIBUTE_SEALED)
423 		strcat (buffer, "sealed ");
424 	if (flags & TYPE_ATTRIBUTE_SPECIAL_NAME)
425 		strcat (buffer, "specialname ");
426 	if (flags & TYPE_ATTRIBUTE_IMPORT)
427 		strcat (buffer, "import ");
428 	if (flags & TYPE_ATTRIBUTE_SERIALIZABLE)
429 		strcat (buffer, "serializable ");
430 	if (flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
431 		strcat (buffer, "beforefieldinit ");
432 	if (flags & TYPE_ATTRIBUTE_FORWARDER)
433 		strcat (buffer, "forwarder ");
434 
435 	return buffer;
436 }
437 
438 /**
439  * dis_field_list:
440  * @m: metadata context
441  * @start: starting index into the Field Table.
442  * @end: ending index into Field table.
443  *
444  * This routine displays all the decoded fields from @start to @end
445  */
446 static void
dis_field_list(MonoImage * m,guint32 start,guint32 end,MonoGenericContainer * container)447 dis_field_list (MonoImage *m, guint32 start, guint32 end, MonoGenericContainer *container)
448 {
449 	MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
450 	guint32 cols [MONO_FIELD_SIZE];
451 	char *esname;
452 	char rva_desc [32];
453 	guint32 rva;
454 	int i;
455 
456 	if (end > t->rows + 1) {
457 		g_warning ("ERROR index out of range in fields");
458 		end = t->rows;
459 	}
460 
461 	for (i = start; i < end; i++){
462 		char *sig, *flags, *attrs = NULL;
463 		char *marshal_str = NULL;
464 		guint32 field_offset = -1;
465 
466 		if (!should_include_field (i + 1))
467 			continue;
468 		mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
469 		sig = get_field_signature (m, cols [MONO_FIELD_SIGNATURE], container);
470 		flags = field_flags (cols [MONO_FIELD_FLAGS]);
471 
472 		if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) {
473 			const char *tp;
474 			MonoMarshalSpec *spec;
475 
476 			tp = mono_metadata_get_marshal_info (m, i, TRUE);
477 			spec = mono_metadata_parse_marshal_spec (m, tp);
478 			marshal_str = dis_stringify_marshal_spec (spec);
479 		}
480 
481 		if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
482 			mono_metadata_field_info (m, i, NULL, &rva, NULL);
483 			g_snprintf (rva_desc, sizeof (rva_desc), " at D_%08x", rva);
484 		} else {
485 			rva_desc [0] = 0;
486 		}
487 
488 		mono_metadata_field_info (m, i, &field_offset, NULL, NULL);
489 		if (field_offset != -1)
490 			attrs = g_strdup_printf ("[%d]", field_offset);
491 		esname = get_escaped_name (mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
492 		if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_DEFAULT){
493 			char *lit;
494 			guint32 const_cols [MONO_CONSTANT_SIZE];
495 			guint32 crow;
496 
497 			if ((crow = mono_metadata_get_constant_index (m, MONO_TOKEN_FIELD_DEF | (i+1), 0))) {
498 				mono_metadata_decode_row (&m->tables [MONO_TABLE_CONSTANT], crow-1, const_cols, MONO_CONSTANT_SIZE);
499 				lit = get_constant (m, (MonoTypeEnum)const_cols [MONO_CONSTANT_TYPE], const_cols [MONO_CONSTANT_VALUE]);
500 			} else {
501 				lit = g_strdup ("not found");
502 			}
503 
504 			fprintf (output, "    .field %s%s%s %s = ",
505 				 flags, marshal_str ? marshal_str : " ", sig, esname);
506 			fprintf (output, "%s\n", lit);
507 			g_free (lit);
508 		} else
509 			fprintf (output, "    .field %s %s%s%s %s%s\n",
510 				 attrs? attrs: "", flags, marshal_str ? marshal_str : " ", sig, esname, rva_desc);
511 		g_free (attrs);
512 		g_free (flags);
513 		g_free (marshal_str);
514 		g_free (sig);
515 		g_free (esname);
516 		dump_cattrs (m, MONO_TOKEN_FIELD_DEF | (i + 1), "    ");
517 	}
518 }
519 
520 static dis_map_t method_access_map [] = {
521 	{ METHOD_ATTRIBUTE_COMPILER_CONTROLLED, "privatescope " },
522 	{ METHOD_ATTRIBUTE_PRIVATE,             "private " },
523 	{ METHOD_ATTRIBUTE_FAM_AND_ASSEM,       "famandassem " },
524 	{ METHOD_ATTRIBUTE_ASSEM,               "assembly " },
525 	{ METHOD_ATTRIBUTE_FAMILY,              "family " },
526 	{ METHOD_ATTRIBUTE_FAM_OR_ASSEM,        "famorassem " },
527 	{ METHOD_ATTRIBUTE_PUBLIC,              "public " },
528 	{ 0, NULL }
529 };
530 
531 static dis_map_t method_flags_map [] = {
532 	{ METHOD_ATTRIBUTE_STATIC,              "static " },
533 	{ METHOD_ATTRIBUTE_FINAL,               "final " },
534 	{ METHOD_ATTRIBUTE_VIRTUAL,             "virtual " },
535 	{ METHOD_ATTRIBUTE_HIDE_BY_SIG,         "hidebysig " },
536 	{ METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK,  "newslot " },
537 	{ METHOD_ATTRIBUTE_ABSTRACT,            "abstract " },
538 	{ METHOD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
539 	{ METHOD_ATTRIBUTE_RT_SPECIAL_NAME,     "rtspecialname " },
540 	{ METHOD_ATTRIBUTE_UNMANAGED_EXPORT,    "export " },
541 /* MS ilasm doesn't compile this statement - is must be added automagically when permissionset are present */
542 	{ METHOD_ATTRIBUTE_HAS_SECURITY,        "" /*"hassecurity"*/ },
543 	{ METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT,  "requiresecobj " },
544 	{ METHOD_ATTRIBUTE_PINVOKE_IMPL,        "pinvokeimpl " },
545 	{ METHOD_ATTRIBUTE_STRICT,	            "strict " },
546 	{ 0, NULL }
547 };
548 
549 /**
550  * method_flags:
551  *
552  * Returns a stringified version of the Method's flags
553  */
554 static char *
method_flags(guint32 f)555 method_flags (guint32 f)
556 {
557 	GString *str = g_string_new ("");
558 	int access = f & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
559 	int rest = f & ~access;
560 	char *s;
561 
562 	g_string_append (str, map (access, method_access_map));
563 	g_string_append (str, flags (rest, method_flags_map));
564 
565 	s = str->str;
566 	g_string_free (str, FALSE);
567 
568 	return s;
569 }
570 
571 static dis_map_t pinvoke_flags_map [] = {
572 	{ PINVOKE_ATTRIBUTE_NO_MANGLE ,            "nomangle " },
573 	{ PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR,   "lasterr " },
574 	{ PINVOKE_ATTRIBUTE_BEST_FIT_ENABLED,      "bestfit:on " },
575 	{ PINVOKE_ATTRIBUTE_BEST_FIT_DISABLED,      "bestfit:off " },
576 	{ PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_ENABLED, "charmaperror:on " },
577 	{ PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_DISABLED, "charmaperror:off " },
578 	{ 0, NULL }
579 };
580 
581 static dis_map_t pinvoke_call_conv_map [] = {
582 	{ PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI,      "winapi " },
583 	{ PINVOKE_ATTRIBUTE_CALL_CONV_CDECL,       "cdecl " },
584 	{ PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL,     "stdcall " },
585 	{ PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL,    "thiscall " },
586 	{ PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL,    "fastcall " },
587 	{ 0, "" },
588 	{ -1, NULL }
589 };
590 
591 static dis_map_t pinvoke_char_set_map [] = {
592 	{ PINVOKE_ATTRIBUTE_CHAR_SET_NOT_SPEC,     "" },
593 	{ PINVOKE_ATTRIBUTE_CHAR_SET_ANSI,         "ansi " },
594 	{ PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE ,     "unicode " },
595 	{ PINVOKE_ATTRIBUTE_CHAR_SET_AUTO,         "autochar " },
596 	{ 0, NULL }
597 };
598 
599 /**
600  * pinvoke_flags:
601  *
602  * Returns a stringified version of the Method's pinvoke flags
603  */
604 static char *
pinvoke_flags(guint32 f)605 pinvoke_flags (guint32 f)
606 {
607 	GString *str = g_string_new ("");
608 	int cset = f & PINVOKE_ATTRIBUTE_CHAR_SET_MASK;
609 	int cconv = f & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
610 	int rest = f & ~(cset | cconv);
611 	char *s;
612 
613 	g_string_append (str, map (cset, pinvoke_char_set_map));
614 	g_string_append (str, map (cconv, pinvoke_call_conv_map));
615 	g_string_append (str, flags (rest, pinvoke_flags_map));
616 
617 	s = g_strdup(str->str);
618 	g_string_free (str, FALSE);
619 
620 	return s;
621 }
622 
623 static void
dis_locals(MonoImage * m,MonoMethodHeader * mh,const char * ptr)624 dis_locals (MonoImage *m, MonoMethodHeader *mh, const char *ptr)
625 {
626 	int i;
627 
628 	if (show_tokens) {
629 		unsigned char flags = *(const unsigned char *) ptr;
630 		unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
631 		guint16 fat_flags;
632 		guint32 local_var_sig_tok, init_locals;
633 
634 		g_assert (format == METHOD_HEADER_FAT_FORMAT);
635 		fat_flags = read16 (ptr);
636 		ptr += 2;
637 		/* max_stack = read16 (ptr); */
638 		ptr += 2;
639 		/* code_size = read32 (ptr); */
640 		ptr += 4;
641 		local_var_sig_tok = read32 (ptr);
642 		ptr += 4;
643 
644 		if (fat_flags & METHOD_HEADER_INIT_LOCALS)
645 			init_locals = 1;
646 		else
647 			init_locals = 0;
648 
649 		fprintf(output, "\t.locals /*%08x*/ %s(\n",
650 			local_var_sig_tok, init_locals ? "init " : "");
651 	} else
652 		fprintf(output, "\t.locals %s(\n", mh->init_locals ? "init " : "");
653 
654 	for (i=0; i < mh->num_locals; ++i) {
655 		char * desc;
656 		if (i)
657 			fprintf(output, ",\n");
658 		/* print also byref and pinned attributes */
659 		desc = dis_stringify_type (m, mh->locals[i], TRUE);
660 		fprintf(output, "\t\t%s\tV_%d", desc, i);
661 		g_free(desc);
662 	}
663 	fprintf(output, ")\n");
664 }
665 
666 static void
dis_code(MonoImage * m,guint32 token,guint32 rva,MonoGenericContainer * container)667 dis_code (MonoImage *m, guint32 token, guint32 rva, MonoGenericContainer *container)
668 {
669 	MonoError error;
670 	MonoMethodHeader *mh;
671 	const char *ptr = mono_image_rva_map (m, rva);
672 	const char *loc;
673 	gchar *override;
674 	guint32 entry_point;
675 
676 	if (rva == 0)
677 		return;
678 
679 	override = get_method_override (m, token, container);
680 	if (override) {
681 		fprintf (output, "\t.override %s\n", override);
682 		g_free (override);
683 	}
684 
685 	mh = mono_metadata_parse_mh_full (m, container, ptr, &error);
686 	entry_point = mono_image_get_entry_point (m);
687 	if (entry_point && mono_metadata_token_index (entry_point) && mono_metadata_token_table (entry_point) == MONO_TABLE_METHOD) {
688 		loc = mono_metadata_locate_token (m, entry_point);
689 		if (rva == read32 (loc))
690 			fprintf (output, "\t.entrypoint\n");
691 	}
692 
693 	if (mh) {
694 		fprintf (output, "\t// Code size %d (0x%x)\n", mh->code_size, mh->code_size);
695 		fprintf (output, "\t.maxstack %d\n", mh->max_stack);
696 		if (mh->num_locals)
697 			dis_locals (m, mh, ptr);
698 		disassemble_cil (m, mh, container);
699 /*
700   hex_dump (mh->code, 0, mh->code_size);
701   printf ("\nAfter the code\n");
702   hex_dump (mh->code + mh->code_size, 0, 64);
703 */
704 		mono_metadata_free_mh (mh);
705 	} else {
706 		mono_error_cleanup (&error);
707 	}
708 }
709 
710 static char *
pinvoke_info(MonoImage * m,guint32 mindex)711 pinvoke_info (MonoImage *m, guint32 mindex)
712 {
713 	MonoTableInfo *im = &m->tables [MONO_TABLE_IMPLMAP];
714 	MonoTableInfo *mr = &m->tables [MONO_TABLE_MODULEREF];
715 	guint32 im_cols [MONO_IMPLMAP_SIZE];
716 	guint32 mr_cols [MONO_MODULEREF_SIZE];
717 	const char *import, *scope;
718 	char *flags;
719 	int i;
720 
721 	for (i = 0; i < im->rows; i++) {
722 
723 		mono_metadata_decode_row (im, i, im_cols, MONO_IMPLMAP_SIZE);
724 
725 		if ((im_cols [MONO_IMPLMAP_MEMBER] >> 1) == mindex + 1) {
726 
727 			flags = pinvoke_flags (im_cols [MONO_IMPLMAP_FLAGS]);
728 
729 			import = mono_metadata_string_heap (m, im_cols [MONO_IMPLMAP_NAME]);
730 
731 			mono_metadata_decode_row (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1,
732 						  mr_cols, MONO_MODULEREF_SIZE);
733 
734 			scope = mono_metadata_string_heap (m, mr_cols [MONO_MODULEREF_NAME]);
735 
736 			return g_strdup_printf ("(\"%s\" as \"%s\" %s)", scope, import,
737 						flags);
738 			g_free (flags);
739 		}
740 	}
741 
742 	return NULL;
743 }
744 
745 /*
746  * dump_cattrs_for_type_params
747  *
748  * @m:
749  * @token: TypeOrMethodDef token, owner for GenericParam
750  *
751  * Dumps the custom attributes for @token's type parameters
752  */
753 static void
dump_cattrs_for_type_params(MonoImage * m,guint32 token,const char * indent)754 dump_cattrs_for_type_params (MonoImage *m, guint32 token, const char *indent)
755 {
756 	MonoTableInfo *tdef  = &m->tables [MONO_TABLE_GENERICPARAM];
757 	guint32 cols [MONO_GENERICPARAM_SIZE];
758 	guint32 owner = 0, i;
759 	GList *list = NULL;
760 
761 	if (! (i = mono_metadata_get_generic_param_row (m, token, &owner)))
762 		return;
763 
764 	mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
765 	do {
766 		list = dis_get_custom_attrs (m, mono_metadata_make_token (MONO_TABLE_GENERICPARAM, i));
767 		if (list) {
768 			fprintf (output, "%s.param type %s\n", indent, mono_metadata_string_heap (m, cols [MONO_GENERICPARAM_NAME]));
769 			dump_cattrs_list (list, indent);
770 		}
771 
772 		if (++i > tdef->rows)
773 			break;
774 		mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
775 	} while (cols [MONO_GENERICPARAM_OWNER] == owner);
776 }
777 
778 static void
dump_cattrs_for_method_params(MonoImage * m,guint32 midx,MonoMethodSignature * sig)779 dump_cattrs_for_method_params (MonoImage *m, guint32 midx, MonoMethodSignature *sig) {
780 	MonoTableInfo *methodt;
781 	MonoTableInfo *paramt;
782 	guint param_index, lastp, i;
783 
784 	methodt = &m->tables [MONO_TABLE_METHOD];
785 	paramt = &m->tables [MONO_TABLE_PARAM];
786 	param_index = mono_metadata_decode_row_col (methodt, midx, MONO_METHOD_PARAMLIST);
787 	if (midx + 1 < methodt->rows)
788 		lastp = mono_metadata_decode_row_col (methodt, midx + 1, MONO_METHOD_PARAMLIST);
789 	else
790 		lastp = paramt->rows + 1;
791 	for (i = param_index; i < lastp; ++i) {
792 	  	char *lit;
793 	  	int crow;
794 		guint32 param_cols [MONO_PARAM_SIZE];
795 		GList *list;
796 
797 		list = dis_get_custom_attrs (m, MONO_TOKEN_PARAM_DEF | i);
798 
799 		mono_metadata_decode_row (paramt, i-1, param_cols, MONO_PARAM_SIZE);
800 		if (!(param_cols[MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_DEFAULT)) {
801 			if(list != NULL)
802 				fprintf (output, "\t.param [%d]\n", param_cols[MONO_PARAM_SEQUENCE]);
803 		} else {
804 			fprintf (output, "\t.param [%d] = ", param_cols[MONO_PARAM_SEQUENCE]);
805 
806 			if ((crow = mono_metadata_get_constant_index(m, MONO_TOKEN_PARAM_DEF | i, 0))) {
807 				guint32 const_cols [MONO_CONSTANT_SIZE];
808 				mono_metadata_decode_row( &m->tables[MONO_TABLE_CONSTANT], crow-1, const_cols, MONO_CONSTANT_SIZE);
809 				lit = get_constant (m, (MonoTypeEnum)const_cols [MONO_CONSTANT_TYPE], const_cols [MONO_CONSTANT_VALUE]);
810 			}
811 			else {
812 				lit = g_strdup ("not found");
813 			}
814 		  fprintf(output, "%s\n", lit);
815 		  g_free(lit);
816 		}
817 		dump_cattrs_list (list, "\t");
818 	}
819 }
820 
821 /**
822  * dis_method_list:
823  * @m: metadata context
824  * @start: starting index into the Method Table.
825  * @end: ending index into Method table.
826  *
827  * This routine displays the methods in the Method Table from @start to @end
828  */
829 static void
dis_method_list(const char * klass_name,MonoImage * m,guint32 start,guint32 end,MonoGenericContainer * type_container)830 dis_method_list (const char *klass_name, MonoImage *m, guint32 start, guint32 end, MonoGenericContainer *type_container)
831 {
832 	MonoTableInfo *t = &m->tables [MONO_TABLE_METHOD];
833 	guint32 cols [MONO_METHOD_SIZE];
834 	int i;
835 
836 	if (end > t->rows){
837 		fprintf (output, "ERROR index out of range in methods");
838 		/*exit (1);*/
839 		end = t->rows;
840 	}
841 
842 	for (i = start; i < end; i++){
843 		MonoError error;
844 		MonoMethodSignature *ms;
845 		MonoGenericContainer *container;
846 		char *flags, *impl_flags;
847 		const char *sig, *method_name;
848 		char *sig_str;
849 		guint32 token;
850 
851 		if (!should_include_method (i + 1))
852 			continue;
853 		mono_metadata_decode_row (t, i, cols, MONO_METHOD_SIZE);
854 
855 		flags = method_flags (cols [MONO_METHOD_FLAGS]);
856 		impl_flags = get_method_impl_flags (cols [MONO_METHOD_IMPLFLAGS]);
857 
858 		sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
859 		mono_metadata_decode_blob_size (sig, &sig);
860 
861 		container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), type_container);
862 		if (container) {
863 			MonoError error;
864 			mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | (i + 1), container, &error);
865 			g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
866 		} else {
867 			container = type_container;
868 		}
869 
870 		ms = mono_metadata_parse_method_signature_full (m, container, i + 1, sig, &sig, &error);
871 		if (ms != NULL){
872 			sig_str = dis_stringify_method_signature (m, ms, i + 1, container, FALSE);
873 			method_name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
874 		} else {
875 			sig_str = NULL;
876 			method_name = g_strdup ("<NULL METHOD SIGNATURE>");
877 			mono_error_cleanup (&error);
878 		}
879 
880 		fprintf (output, "    // method line %d\n", i + 1);
881 		fprintf (output, "    .method %s", flags);
882 
883 		if ((cols [MONO_METHOD_FLAGS] & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (cols [MONO_METHOD_RVA] == 0)) {
884 			gchar *pi = pinvoke_info (m, i);
885 			if (pi) {
886 				fprintf (output, "%s", pi);
887 				g_free (pi);
888 			}
889 		}
890 
891 		fprintf (output, "\n           %s", sig_str);
892 		fprintf (output, " %s\n", impl_flags);
893 		g_free (flags);
894 		g_free (impl_flags);
895 
896 		token = MONO_TOKEN_METHOD_DEF | (i + 1);
897 
898 		fprintf (output, "    {\n");
899 		dump_cattrs (m, token, "        ");
900 		dump_cattrs_for_type_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), "        ");
901 		dump_cattrs_for_method_params (m, i, ms);
902 
903 		fprintf (output, "        // Method begins at RVA 0x%x\n", cols [MONO_METHOD_RVA]);
904 		dump_declarative_security (m, OBJECT_TYPE_METHODDEF, i + 1, "        ");
905 		if (cols [MONO_METHOD_IMPLFLAGS] & METHOD_IMPL_ATTRIBUTE_NATIVE)
906 			fprintf (output, "          // Disassembly of native methods is not supported\n");
907 		else
908 			dis_code (m, token, cols [MONO_METHOD_RVA], container);
909 		if (klass_name)
910 			fprintf (output, "    } // end of method %s::%s\n\n", klass_name, method_name);
911 		else
912 			fprintf (output, "    } // end of global method %s\n\n", method_name);
913 		mono_metadata_free_method_signature (ms);
914 		g_free (sig_str);
915 	}
916 }
917 
918 typedef struct {
919 	MonoTableInfo *t;
920 	guint32 col_idx;
921 	guint32 idx;
922 	guint32 result;
923 } plocator_t;
924 
925 static int
table_locator(const void * a,const void * b)926 table_locator (const void *a, const void *b)
927 {
928 	plocator_t *loc = (plocator_t *) a;
929 	const char *bb = (const char *) b;
930 	guint32 table_index = (bb - loc->t->base) / loc->t->row_size;
931 	guint32 col;
932 
933 	col = mono_metadata_decode_row_col (loc->t, table_index, loc->col_idx);
934 
935 	if (loc->idx == col) {
936 		loc->result = table_index;
937 		return 0;
938 	}
939 	if (loc->idx < col)
940 		return -1;
941 	else
942 		return 1;
943 }
944 
945 static void
dis_property_methods(MonoImage * m,guint32 prop,MonoGenericContainer * container)946 dis_property_methods (MonoImage *m, guint32 prop, MonoGenericContainer *container)
947 {
948 	guint start, end;
949 	MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
950 	guint32 cols [MONO_METHOD_SEMA_SIZE];
951 	char *sig;
952 	const char *type[] = {NULL, ".set", ".get", NULL, ".other"};
953 
954 	start = mono_metadata_methods_from_property (m, prop, &end);
955 	for (; start < end; ++start) {
956 		mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
957 		if (!should_include_method (cols [MONO_METHOD_SEMA_METHOD]))
958 			continue;
959 		sig = dis_stringify_method_signature_full (m, NULL, cols [MONO_METHOD_SEMA_METHOD], container, TRUE, FALSE);
960 		fprintf (output, "\t\t%s %s\n", type [cols [MONO_METHOD_SEMA_SEMANTICS]], sig);
961 		g_free (sig);
962 	}
963 }
964 static char*
dis_property_signature(MonoImage * m,guint32 prop_idx,MonoGenericContainer * container)965 dis_property_signature (MonoImage *m, guint32 prop_idx, MonoGenericContainer *container)
966 {
967 	MonoError error;
968 	MonoTableInfo *propt = &m->tables [MONO_TABLE_PROPERTY];
969 	const char *ptr;
970 	guint32 pcount, i;
971 	guint32 cols [MONO_PROPERTY_SIZE];
972 	MonoType *type;
973 	MonoType *param;
974 	char *blurb, *qk;
975 	const char *name;
976 	int prop_flags;
977 	GString *res = g_string_new ("");
978 
979 	mono_metadata_decode_row (propt, prop_idx, cols, MONO_PROPERTY_SIZE);
980 	name = mono_metadata_string_heap (m, cols [MONO_PROPERTY_NAME]);
981 	prop_flags = cols [MONO_PROPERTY_FLAGS];
982 	ptr = mono_metadata_blob_heap (m, cols [MONO_PROPERTY_TYPE]);
983 	mono_metadata_decode_blob_size (ptr, &ptr);
984 	if (!(*ptr & 0x08))
985 		g_warning("incorrect signature in property blob: 0x%x", *ptr);
986 	if (*ptr & 0x20)
987 		g_string_append (res, "instance ");
988 	ptr++;
989 	pcount = mono_metadata_decode_value (ptr, &ptr);
990 	type = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, &error);
991 	if (type) {
992 		blurb = dis_stringify_type (m, type, TRUE);
993 	} else {
994 		blurb = g_strdup_printf ("Invalid type due to %s", mono_error_get_message (&error));
995 		mono_error_cleanup (&error);
996 	}
997 	if (prop_flags & 0x0200)
998 		g_string_append (res, "specialname ");
999 	if (prop_flags & 0x0400)
1000 		g_string_append (res, "rtspecialname ");
1001 	qk = get_escaped_name (name);
1002 	g_string_append_printf (res, "%s %s (", blurb, qk);
1003 	g_free (qk);
1004 	g_free (blurb);
1005 	for (i = 0; i < pcount; i++) {
1006 		if (i)
1007 			g_string_append (res, ", ");
1008 		param = mono_metadata_parse_type_checked (m, container, 0, FALSE, ptr, &ptr, &error);
1009 		if (type) {
1010 			blurb = dis_stringify_param (m, param);
1011 		} else {
1012 			blurb = g_strdup_printf ("Invalid type due to %s", mono_error_get_message (&error));
1013 			mono_error_cleanup (&error);
1014 		}
1015 
1016 		g_string_append (res, blurb);
1017 		g_free (blurb);
1018 	}
1019 	g_string_append_c (res, ')');
1020 	blurb = res->str;
1021 	g_string_free (res, FALSE);
1022 	return blurb;
1023 
1024 }
1025 
1026 static void
dis_property_list(MonoImage * m,guint32 typedef_row,MonoGenericContainer * container)1027 dis_property_list (MonoImage *m, guint32 typedef_row, MonoGenericContainer *container)
1028 {
1029 	guint start, end, i;
1030 	start = mono_metadata_properties_from_typedef (m, typedef_row, &end);
1031 
1032 	for (i = start; i < end; ++i) {
1033 		char *sig = dis_property_signature (m, i, container);
1034 		fprintf (output, "\t.property %s\n\t{\n", sig);
1035 		dump_cattrs (m, MONO_TOKEN_PROPERTY | (i + 1), "\t\t");
1036 		dis_property_methods (m, i, container);
1037 		fprintf (output, "\t}\n");
1038 		g_free (sig);
1039 	}
1040 }
1041 
1042 static char*
dis_event_signature(MonoImage * m,guint32 event_idx,MonoGenericContainer * container)1043 dis_event_signature (MonoImage *m, guint32 event_idx, MonoGenericContainer *container)
1044 {
1045 	MonoTableInfo *et = &m->tables [MONO_TABLE_EVENT];
1046 	char *type, *result, *esname;
1047 	guint32 cols [MONO_EVENT_SIZE];
1048 	int event_flags;
1049 	GString *res = g_string_new ("");
1050 
1051 	mono_metadata_decode_row (et, event_idx, cols, MONO_EVENT_SIZE);
1052 	esname = get_escaped_name (mono_metadata_string_heap (m, cols [MONO_EVENT_NAME]));
1053 	type = get_typedef_or_ref (m, cols [MONO_EVENT_TYPE], container);
1054 	event_flags = cols [MONO_EVENT_FLAGS];
1055 
1056 	if (event_flags & 0x0200)
1057 		g_string_append (res, "specialname ");
1058 	if (event_flags & 0x0400)
1059 		g_string_append (res, "rtspecialname ");
1060 	g_string_append_printf (res, "%s %s", type, esname);
1061 
1062 	g_free (type);
1063 	g_free (esname);
1064 	result = res->str;
1065 	g_string_free (res, FALSE);
1066 	return result;
1067 }
1068 
1069 static void
dis_event_methods(MonoImage * m,guint32 event,MonoGenericContainer * container)1070 dis_event_methods (MonoImage *m, guint32 event, MonoGenericContainer *container)
1071 {
1072 	guint start, end;
1073 	MonoTableInfo *msemt = &m->tables [MONO_TABLE_METHODSEMANTICS];
1074 	guint32 cols [MONO_METHOD_SEMA_SIZE];
1075 	char *sig;
1076 	const char *type = "";
1077 
1078 	start = mono_metadata_methods_from_event (m, event, &end);
1079 	for (; start < end; ++start) {
1080 		mono_metadata_decode_row (msemt, start, cols, MONO_METHOD_SEMA_SIZE);
1081 		if (!should_include_method (cols [MONO_METHOD_SEMA_METHOD]))
1082 			continue;
1083 		sig = dis_stringify_method_signature_full (m, NULL, cols [MONO_METHOD_SEMA_METHOD], container, TRUE, FALSE);
1084 		switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
1085 		case METHOD_SEMANTIC_OTHER:
1086 			type = ".other"; break;
1087 		case METHOD_SEMANTIC_ADD_ON:
1088 			type = ".addon"; break;
1089 		case METHOD_SEMANTIC_REMOVE_ON:
1090 			type = ".removeon"; break;
1091 		case METHOD_SEMANTIC_FIRE:
1092 			type = ".fire"; break;
1093 		default:
1094 			break;
1095 		}
1096 		fprintf (output, "\t\t%s %s\n", type, sig);
1097 		g_free (sig);
1098 	}
1099 }
1100 
1101 static void
dis_event_list(MonoImage * m,guint32 typedef_row,MonoGenericContainer * container)1102 dis_event_list (MonoImage *m, guint32 typedef_row, MonoGenericContainer *container)
1103 {
1104 	guint start, end, i;
1105 	start = mono_metadata_events_from_typedef (m, typedef_row, &end);
1106 
1107 	for (i = start; i < end; ++i) {
1108 		char *sig = dis_event_signature (m, i, container);
1109 		fprintf (output, "\t.event %s\n\t{\n", sig);
1110 		dump_cattrs (m, MONO_TOKEN_EVENT | (i + 1), "\t\t");
1111 		dis_event_methods (m, i, container);
1112 		fprintf (output, "\t}\n");
1113 		g_free (sig);
1114 	}
1115 }
1116 
1117 static void
dis_interfaces(MonoImage * m,guint32 typedef_row,MonoGenericContainer * container)1118 dis_interfaces (MonoImage *m, guint32 typedef_row, MonoGenericContainer *container)
1119 {
1120 	plocator_t loc;
1121 	guint start;
1122 	gboolean first_interface = 1;
1123 	guint32 cols [MONO_INTERFACEIMPL_SIZE];
1124 	char *intf;
1125 	MonoTableInfo *table = &m->tables [MONO_TABLE_INTERFACEIMPL];
1126 
1127 	if (!table->base)
1128 		return;
1129 
1130 	loc.t = table;
1131 	loc.col_idx = MONO_INTERFACEIMPL_CLASS;
1132 	loc.idx = typedef_row;
1133 
1134 	if (!mono_binary_search (&loc, table->base, table->rows, table->row_size, table_locator))
1135 		return;
1136 
1137 	start = loc.result;
1138 	/*
1139 	 * We may end up in the middle of the rows...
1140 	 */
1141 	while (start > 0) {
1142 		if (loc.idx == mono_metadata_decode_row_col (table, start - 1, MONO_INTERFACEIMPL_CLASS))
1143 			start--;
1144 		else
1145 			break;
1146 	}
1147 	while (start < table->rows) {
1148 		mono_metadata_decode_row (table, start, cols, MONO_INTERFACEIMPL_SIZE);
1149 		if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
1150 			break;
1151 		intf = get_typedef_or_ref (m, cols [MONO_INTERFACEIMPL_INTERFACE], container);
1152 		if (first_interface) {
1153 			fprintf (output, "  \timplements %s", intf);
1154 			first_interface = 0;
1155 		} else {
1156 			fprintf (output, ", %s", intf);
1157 		}
1158 		g_free (intf);
1159 		++start;
1160 	}
1161 }
1162 
1163 /**
1164  * dis_type:
1165  * @m: metadata context
1166  * @n: index of type to disassemble
1167  * @is_nested: nested type ?
1168  * @forward: forward declarations?
1169  *
1170  * Disassembles the type whose index in the TypeDef table is @n.
1171  */
1172 static void
dis_type(MonoImage * m,int n,int is_nested,int forward)1173 dis_type (MonoImage *m, int n, int is_nested, int forward)
1174 {
1175 	MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
1176 	guint32 cols [MONO_TYPEDEF_SIZE];
1177 	guint32 cols_next [MONO_TYPEDEF_SIZE];
1178 	const char *name, *nspace;
1179 	char *esname, *param;
1180 	MonoGenericContainer *container;
1181 	guint32 packing_size, class_size;
1182 	gboolean next_is_valid, last;
1183 	guint32 nested;
1184 
1185 	if (!should_include_type (n + 1))
1186 		return;
1187 	mono_metadata_decode_row (t, n, cols, MONO_TYPEDEF_SIZE);
1188 
1189 	if (t->rows > n + 1) {
1190 		mono_metadata_decode_row (t, n + 1, cols_next, MONO_TYPEDEF_SIZE);
1191 		next_is_valid = 1;
1192 	} else
1193 		next_is_valid = 0;
1194 
1195 	name = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME]);
1196 	nspace = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE]);
1197 	if (*nspace && !is_nested) {
1198 		char *esnspace;
1199 		esnspace = get_escaped_name (nspace);
1200 		fprintf (output, ".namespace %s\n{\n", esnspace);
1201 		g_free (esnspace);
1202 	}
1203 
1204 	container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), NULL);
1205 	if (container) {
1206 		MonoError error;
1207 		mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (n + 1), container, &error);
1208 		g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
1209 	}
1210 
1211 	esname = get_escaped_name (name);
1212 	if ((cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
1213 		fprintf (output, "  .class %s%s", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), esname);
1214 
1215                 param = get_generic_param (m, container);
1216 		if (param) {
1217 			fprintf (output, "%s", param);
1218 			g_free (param);
1219 		}
1220                 fprintf (output, "\n");
1221 		if (cols [MONO_TYPEDEF_EXTENDS]) {
1222 			char *base = get_typedef_or_ref (m, cols [MONO_TYPEDEF_EXTENDS], container);
1223 			fprintf (output, "  \textends %s\n", base);
1224 			g_free (base);
1225 		}
1226 	} else {
1227 		fprintf (output, "  .class interface %s%s", typedef_flags (cols [MONO_TYPEDEF_FLAGS]), esname);
1228 
1229                 param = get_generic_param (m, container);
1230 		if (param) {
1231 			fprintf (output, "%s", param);
1232 			g_free (param);
1233 		}
1234 		fprintf (output, "\n");
1235 	}
1236 
1237 	g_free (esname);
1238 	dis_interfaces (m, n + 1, container);
1239 	fprintf (output, "  {\n");
1240         if (!forward) {
1241         	dump_cattrs (m, MONO_TOKEN_TYPE_DEF | (n + 1), "    ");
1242         	dump_cattrs_for_type_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), "    ");
1243 	        dump_declarative_security (m, OBJECT_TYPE_TYPEDEF, (n + 1), "    ");
1244 
1245         	if (mono_metadata_packing_from_typedef (m, n + 1, &packing_size, &class_size)) {
1246 	        	fprintf (output, "    .pack %d\n", packing_size);
1247 	        	fprintf (output, "    .size %d\n", class_size);
1248         	}
1249         	/*
1250 	         * The value in the table is always valid, we know we have fields
1251         	 * if the value stored is different than the next record.
1252         	 */
1253 
1254         	if (next_is_valid)
1255 	        	last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
1256         	else
1257 	        	last = m->tables [MONO_TABLE_FIELD].rows;
1258 
1259         	if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= m->tables [MONO_TABLE_FIELD].rows)
1260 		        dis_field_list (m, cols [MONO_TYPEDEF_FIELD_LIST] - 1, last, container);
1261         	fprintf (output, "\n");
1262 
1263         	if (next_is_valid)
1264 	        	last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
1265         	else
1266 	        	last = m->tables [MONO_TABLE_METHOD].rows;
1267 
1268         	if (cols [MONO_TYPEDEF_METHOD_LIST] && cols [MONO_TYPEDEF_METHOD_LIST] <= m->tables [MONO_TABLE_METHOD].rows)
1269 	        	dis_method_list (name, m, cols [MONO_TYPEDEF_METHOD_LIST] - 1, last, container);
1270 
1271         	dis_property_list (m, n, container);
1272 	        dis_event_list (m, n, container);
1273         }
1274 
1275 	t = &m->tables [MONO_TABLE_NESTEDCLASS];
1276 	nested = mono_metadata_nesting_typedef (m, n + 1, 1);
1277 	while (nested) {
1278 		dis_type (m, mono_metadata_decode_row_col (t, nested - 1, MONO_NESTED_CLASS_NESTED) - 1, 1, forward);
1279 		nested = mono_metadata_nesting_typedef (m, n + 1, nested + 1);
1280 	}
1281 
1282 	fprintf (output, "  } // end of class %s%s%s\n", nspace, *nspace? ".": "", name);
1283 	if (*nspace && !is_nested)
1284 		fprintf (output, "}\n");
1285 	fprintf (output, "\n");
1286 }
1287 
1288 
1289 /**
1290  * dis_globals
1291  * @m: metadata context
1292  *
1293  * disassembles all the global fields and methods
1294  */
1295 static void
dis_globals(MonoImage * m)1296 dis_globals (MonoImage *m)
1297 {
1298         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
1299 	guint32 cols [MONO_TYPEDEF_SIZE];
1300 	guint32 cols_next [MONO_TYPEDEF_SIZE];
1301 	gboolean next_is_valid, last;
1302 
1303         mono_metadata_decode_row (t, 0, cols, MONO_TYPEDEF_SIZE);
1304 
1305 	if (t->rows > 1) {
1306 		mono_metadata_decode_row (t, 1, cols_next, MONO_TYPEDEF_SIZE);
1307 		next_is_valid = 1;
1308 	} else
1309 		next_is_valid = 0;
1310 
1311 	/*
1312 	 * The value in the table is always valid, we know we have fields
1313 	 * if the value stored is different than the next record.
1314 	 */
1315 
1316 	if (next_is_valid)
1317 		last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
1318 	else
1319 		last = m->tables [MONO_TABLE_FIELD].rows;
1320 
1321 	if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= m->tables [MONO_TABLE_FIELD].rows)
1322 		dis_field_list (m, cols [MONO_TYPEDEF_FIELD_LIST] - 1, last, NULL);
1323 	fprintf (output, "\n");
1324 
1325 	if (next_is_valid)
1326 		last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
1327 	else
1328 		last = m->tables [MONO_TABLE_METHOD].rows;
1329 
1330 	if (cols [MONO_TYPEDEF_METHOD_LIST] && cols [MONO_TYPEDEF_METHOD_LIST] <= m->tables [MONO_TABLE_METHOD].rows)
1331 		dis_method_list (NULL, m, cols [MONO_TYPEDEF_METHOD_LIST] - 1, last, NULL);
1332 
1333 }
1334 
dis_resources_worker(MonoImage * m,gboolean just_print)1335 static void dis_resources_worker (MonoImage *m, gboolean just_print)
1336 {
1337 	MonoTableInfo *t = &m->tables [MONO_TABLE_MANIFESTRESOURCE];
1338 	int i;
1339 
1340 	for (i = 0; i < t->rows; i++){
1341 		guint32 cols [MONO_MANIFEST_SIZE];
1342 		const char *name, *res;
1343 		guint32 size;
1344 		FILE* fp;
1345 
1346 		mono_metadata_decode_row (t, i, cols, MONO_MANIFEST_SIZE);
1347 		name = mono_metadata_string_heap (m, cols [MONO_MANIFEST_NAME]);
1348 
1349 		if (just_print)
1350 			fprintf (output, "%8x: %s", cols [MONO_MANIFEST_OFFSET], name);
1351 
1352 		if (! (res = mono_image_get_resource (m, cols [MONO_MANIFEST_OFFSET], &size))) {
1353 			if (just_print)
1354 				fprintf (output, " (absent from image)\n");
1355 			continue;
1356 		}
1357 
1358 		if (just_print) {
1359 			fprintf (output, " (size %u)\n", size);
1360 			continue;
1361 		}
1362 
1363 		if ( (fp = fopen (name, "ab")) ) {
1364 			if (ftell (fp) == 0)
1365 				fwrite (res, size, 1, fp);
1366 			else
1367 				g_warning ("Error creating managed resource - %s : File already exists.", name);
1368 
1369 			fclose (fp);
1370 		} else
1371 			g_warning ("Error creating managed resource - %s : %s", name, g_strerror (errno));
1372 	}
1373 }
1374 
1375 static void
dis_mresource(MonoImage * m)1376 dis_mresource (MonoImage *m)
1377 {
1378 	dis_resources_worker (m, FALSE);
1379 }
1380 
1381 static void
dis_presource(MonoImage * m)1382 dis_presource (MonoImage *m)
1383 {
1384 	dis_resources_worker (m, TRUE);
1385 }
1386 
1387 static char *
exported_type_flags(guint32 flags)1388 exported_type_flags (guint32 flags)
1389 {
1390 	static char buffer [1024];
1391 	int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1392 
1393 	buffer [0] = 0;
1394 
1395 	if (flags & TYPE_ATTRIBUTE_FORWARDER) {
1396 		strcat (buffer, "forwarder ");
1397 		return buffer;
1398 	}
1399 
1400 	strcat (buffer, map (visibility, visibility_map));
1401 	return buffer;
1402 }
1403 
1404 static char *
get_escaped_fullname(MonoImage * m,guint32 nspace_idx,guint32 name_idx)1405 get_escaped_fullname (MonoImage *m, guint32 nspace_idx, guint32 name_idx)
1406 {
1407 	const char *name, *nspace;
1408 	char *fullname, *esfullname;
1409 
1410 	nspace = mono_metadata_string_heap (m, nspace_idx);
1411 	name = mono_metadata_string_heap (m, name_idx);
1412 
1413 	fullname = g_strdup_printf ("%s%s%s", nspace, *nspace ? "." : "", name);
1414 	esfullname = get_escaped_name (fullname);
1415 
1416 	g_free (fullname);
1417 
1418 	return esfullname;
1419 }
1420 
1421 static void
dis_exported_types(MonoImage * m)1422 dis_exported_types (MonoImage *m)
1423 {
1424 	MonoTableInfo *t = &m->tables [MONO_TABLE_EXPORTEDTYPE];
1425 	int i;
1426 
1427 	for (i = 1; i <= t->rows; i++) {
1428 		char *fullname;
1429 		guint32 impl, idx, type_token;
1430 		guint32 cols [MONO_EXP_TYPE_SIZE];
1431 
1432 		mono_metadata_decode_row (t, i - 1, cols, MONO_EXP_TYPE_SIZE);
1433 
1434 		fullname = get_escaped_fullname (m, cols [MONO_EXP_TYPE_NAMESPACE], cols [MONO_EXP_TYPE_NAME]);
1435 
1436 		fprintf (output, "\n");
1437 		fprintf (output, ".class extern %s%s\n", exported_type_flags (cols [MONO_EXP_TYPE_FLAGS]), fullname);
1438 		fprintf (output, "{\n");
1439 
1440 		g_free (fullname);
1441 
1442 		impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
1443 		if (impl) {
1444 			idx = impl >> MONO_IMPLEMENTATION_BITS;
1445 			switch (impl & MONO_IMPLEMENTATION_MASK) {
1446 			case MONO_IMPLEMENTATION_FILE:
1447 				fprintf (output, "    .file '%s'\n",
1448 					mono_metadata_string_heap (m, mono_metadata_decode_row_col (&m->tables [MONO_TABLE_FILE], idx - 1, MONO_FILE_NAME)));
1449 				break;
1450 			case MONO_IMPLEMENTATION_ASSEMBLYREF:
1451 				fprintf (output, "    .assembly extern '%s'\n",
1452 					mono_metadata_string_heap (m, mono_metadata_decode_row_col (&m->tables [MONO_TABLE_ASSEMBLYREF], idx - 1, MONO_ASSEMBLYREF_NAME)));
1453 				break;
1454 			case MONO_IMPLEMENTATION_EXP_TYPE:
1455 				fullname = get_escaped_fullname (
1456 					m,
1457 					mono_metadata_decode_row_col (&m->tables [MONO_TABLE_EXPORTEDTYPE], idx - 1, MONO_EXP_TYPE_NAMESPACE),
1458 					mono_metadata_decode_row_col (&m->tables [MONO_TABLE_EXPORTEDTYPE], idx - 1, MONO_EXP_TYPE_NAME));
1459 				fprintf (output, "    .class extern %s\n", fullname);
1460 				g_free (fullname);
1461 				break;
1462 			default:
1463 				g_assert_not_reached ();
1464 				break;
1465 			}
1466 		}
1467 
1468 		type_token = cols [MONO_EXP_TYPE_TYPEDEF];
1469 		if (type_token)
1470 			fprintf (output, "    .class 0x%08x\n", type_token | MONO_TOKEN_TYPE_DEF);
1471 
1472 		fprintf (output, "}\n");
1473 	}
1474 }
1475 
1476 /**
1477  * dis_types:
1478  * @m: metadata context
1479  *
1480  * disassembles all types in the @m context
1481  */
1482 static void
dis_types(MonoImage * m,int forward)1483 dis_types (MonoImage *m, int forward)
1484 {
1485 	MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
1486 	int i;
1487 	guint32 flags;
1488 
1489         dis_globals (m);
1490 
1491 	for (i = 1; i < t->rows; i++) {
1492 		flags = mono_metadata_decode_row_col (t, i, MONO_TYPEDEF_FLAGS);
1493 		flags &= TYPE_ATTRIBUTE_VISIBILITY_MASK;
1494 		if (flags == TYPE_ATTRIBUTE_PUBLIC || flags == TYPE_ATTRIBUTE_NOT_PUBLIC)
1495 			dis_type (m, i, 0, forward);
1496 	}
1497 }
1498 
1499 static const char *
get_uninitialized_data_type(guint32 size)1500 get_uninitialized_data_type (guint32 size)
1501 {
1502 	switch (size) {
1503 	case 1:
1504 		return "int8";
1505 	case 2:
1506 		return "int16";
1507 	case 4:
1508 		return "int32";
1509 	case 8:
1510 		return "int64";
1511 	default:
1512 		g_error ("get_uninitialized_data_type for size: %d\n", size);
1513 	}
1514 	return NULL;
1515 }
1516 
1517 /**
1518  * dis_data:
1519  * @m: metadata context
1520  *
1521  * disassembles all data blobs references in the FieldRVA table in the @m context
1522  */
1523 static void
dis_data(MonoImage * m)1524 dis_data (MonoImage *m)
1525 {
1526 	MonoTableInfo *t = &m->tables [MONO_TABLE_FIELDRVA];
1527 	MonoTableInfo *ft = &m->tables [MONO_TABLE_FIELD];
1528 	int i, b;
1529 	const char *rva, *sig;
1530 	guint32 size;
1531 	gint align;
1532 	guint32 cols [MONO_FIELD_RVA_SIZE];
1533 	MonoType *type;
1534 
1535 	for (i = 0; i < t->rows; i++) {
1536 		MonoError error;
1537 		mono_metadata_decode_row (t, i, cols, MONO_FIELD_RVA_SIZE);
1538 		rva = mono_image_rva_map (m, cols [MONO_FIELD_RVA_RVA]);
1539 		sig = mono_metadata_blob_heap (m, mono_metadata_decode_row_col (ft, cols [MONO_FIELD_RVA_FIELD] -1, MONO_FIELD_SIGNATURE));
1540 		mono_metadata_decode_value (sig, &sig);
1541 		/* FIELD signature == 0x06 */
1542 		g_assert (*sig == 0x06);
1543 		type = mono_metadata_parse_type_checked (m, NULL, 0, FALSE, sig + 1, &sig, &error);
1544 		if (!type) {
1545 			fprintf (output, "// invalid field %d due to %s\n", i, mono_error_get_message (&error));
1546 			mono_error_cleanup (&error);
1547 			continue;
1548 		}
1549 		mono_class_init (mono_class_from_mono_type (type));
1550 		size = mono_type_size (type, &align);
1551 
1552 		if (rva) {
1553 			fprintf (output, ".data D_%08x = bytearray (", cols [MONO_FIELD_RVA_RVA]);
1554 			for (b = 0; b < size; ++b) {
1555 				if (!(b % 16))
1556 					fprintf (output, "\n\t");
1557 				fprintf (output, " %02X", rva [b] & 0xff);
1558 			}
1559 			fprintf (output, ") // size: %d\n", size);
1560 		} else
1561 			fprintf (output, ".data D_%08x = %s [%d]\n",
1562 				cols [MONO_FIELD_RVA_RVA], get_uninitialized_data_type (size), size);
1563 	}
1564 }
1565 
1566 struct {
1567 	const char *name;
1568 	int table;
1569 	void (*dumper) (MonoImage *m);
1570 } table_list [] = {
1571 	{ "--assembly",    MONO_TABLE_ASSEMBLY,    	dump_table_assembly },
1572 	{ "--assemblyref", MONO_TABLE_ASSEMBLYREF, 	dump_table_assemblyref },
1573 	{ "--classlayout", MONO_TABLE_CLASSLAYOUT, 	dump_table_class_layout },
1574 	{ "--constant",    MONO_TABLE_CONSTANT,    	dump_table_constant },
1575 	{ "--customattr",  MONO_TABLE_CUSTOMATTRIBUTE,  dump_table_customattr },
1576 	{ "--declsec",     MONO_TABLE_DECLSECURITY, 	dump_table_declsec },
1577 	{ "--event",       MONO_TABLE_EVENT,       	dump_table_event },
1578 	{ "--exported",    MONO_TABLE_EXPORTEDTYPE,     dump_table_exported },
1579 	{ "--fields",      MONO_TABLE_FIELD,       	dump_table_field },
1580 	{ "--file",        MONO_TABLE_FILE,        	dump_table_file },
1581 	{ "--genericpar",  MONO_TABLE_GENERICPARAM,     dump_table_genericpar },
1582 	{ "--interface",   MONO_TABLE_INTERFACEIMPL,    dump_table_interfaceimpl },
1583 	{ "--manifest",    MONO_TABLE_MANIFESTRESOURCE, dump_table_manifest },
1584 	{ "--marshal",     MONO_TABLE_FIELDMARSHAL,	dump_table_field_marshal },
1585 	{ "--memberref",   MONO_TABLE_MEMBERREF,   	dump_table_memberref },
1586 	{ "--method",      MONO_TABLE_METHOD,      	dump_table_method },
1587 	{ "--methodimpl",  MONO_TABLE_METHODIMPL,  	dump_table_methodimpl },
1588 	{ "--methodsem",   MONO_TABLE_METHODSEMANTICS,  dump_table_methodsem },
1589 	{ "--methodspec",  MONO_TABLE_METHODSPEC,       dump_table_methodspec },
1590 	{ "--moduleref",   MONO_TABLE_MODULEREF,   	dump_table_moduleref },
1591 	{ "--module",      MONO_TABLE_MODULE,      	dump_table_module },
1592 	{ "--mresources",  0,	dis_mresource },
1593 	{ "--presources", 0, dis_presource },
1594 	{ "--nested",      MONO_TABLE_NESTEDCLASS, 	dump_table_nestedclass },
1595 	{ "--param",       MONO_TABLE_PARAM,       	dump_table_param },
1596 	{ "--parconst",    MONO_TABLE_GENERICPARAMCONSTRAINT, dump_table_parconstraint },
1597 	{ "--property",    MONO_TABLE_PROPERTY,    	dump_table_property },
1598 	{ "--propertymap", MONO_TABLE_PROPERTYMAP, 	dump_table_property_map },
1599 	{ "--typedef",     MONO_TABLE_TYPEDEF,     	dump_table_typedef },
1600 	{ "--typeref",     MONO_TABLE_TYPEREF,     	dump_table_typeref },
1601 	{ "--typespec",    MONO_TABLE_TYPESPEC,     	dump_table_typespec },
1602 	{ "--implmap",     MONO_TABLE_IMPLMAP,     	dump_table_implmap },
1603 	{ "--fieldrva",    MONO_TABLE_FIELDRVA,     dump_table_fieldrva },
1604 	{ "--standalonesig", MONO_TABLE_STANDALONESIG,  dump_table_standalonesig },
1605 	{ "--methodptr", MONO_TABLE_METHOD_POINTER,  dump_table_methodptr },
1606 	{ "--fieldptr", MONO_TABLE_FIELD_POINTER,  dump_table_fieldptr },
1607 	{ "--paramptr", MONO_TABLE_PARAM_POINTER,  dump_table_paramptr },
1608 	{ "--eventptr", MONO_TABLE_EVENT_POINTER,  dump_table_eventptr },
1609 	{ "--propertyptr", MONO_TABLE_PROPERTY_POINTER,  dump_table_propertyptr },
1610 	{ "--blob", 0, dump_stream_blob },
1611 	{ "--strings", 0, dump_stream_strings },
1612 	{ "--userstrings", 0, dump_stream_us },
1613 	{ NULL, -1, }
1614 };
1615 
1616 /**
1617  * disassemble_file:
1618  * @file: file containing CIL code.
1619  *
1620  * Disassembles the @file file.
1621  */
1622 static int
disassemble_file(const char * file)1623 disassemble_file (const char *file)
1624 {
1625 	MonoImageOpenStatus status;
1626 	MonoImage *img;
1627 
1628 	img = mono_image_open (file, &status);
1629 	if (!img) {
1630 		fprintf (stderr, "Error while trying to process %s\n", file);
1631 		return 1;
1632 	} else {
1633 		/* FIXME: is this call necessary? */
1634 		mono_assembly_load_from_full (img, file, &status, FALSE);
1635 	}
1636 
1637 	setup_filter (img);
1638 
1639 	if (dump_table != -1){
1640 		(*table_list [dump_table].dumper) (img);
1641 	} else {
1642 		dump_header_data (img);
1643 
1644 		dis_directive_assemblyref (img);
1645 		dis_directive_assembly (img);
1646 		dis_directive_file (img);
1647 		dis_directive_mresource (img);
1648 		dis_directive_module (img);
1649 		dis_directive_moduleref (img);
1650 		dis_exported_types (img);
1651 		dis_nt_header (img);
1652                 if (dump_managed_resources)
1653         		dis_mresource (img);
1654 		if (dump_forward_decls) {
1655 			fprintf (output, "// *************** Forward Declarations for Classes ***************\n\n");
1656 			dis_types (img, 1);
1657 			fprintf (output, "// *************** End-Of Forward Declarations for Classes ***************\n\n");
1658 		}
1659 		dis_types (img, 0);
1660 		dis_data (img);
1661 	}
1662 
1663 	mono_image_close (img);
1664 	return 0;
1665 }
1666 
1667 typedef struct {
1668 	int size;
1669 	int count;
1670 	int *elems;
1671 } TableFilter;
1672 
1673 typedef struct {
1674 	char *name;
1675 	char *guid;
1676 	TableFilter types;
1677 	TableFilter fields;
1678 	TableFilter methods;
1679 } ImageFilter;
1680 
1681 static GList *filter_list = NULL;
1682 static ImageFilter *cur_filter = NULL;
1683 
1684 static void
setup_filter(MonoImage * image)1685 setup_filter (MonoImage *image)
1686 {
1687 	ImageFilter *ifilter;
1688 	GList *item;
1689 	const char *name = mono_image_get_name (image);
1690 
1691 	for (item = filter_list; item; item = item->next) {
1692 		ifilter = (ImageFilter *)item->data;
1693 		if (strcmp (ifilter->name, name) == 0) {
1694 			cur_filter = ifilter;
1695 			return;
1696 		}
1697 	}
1698 	cur_filter = NULL;
1699 }
1700 
1701 static int
int_cmp(const void * e1,const void * e2)1702 int_cmp (const void *e1, const void *e2)
1703 {
1704 	const int *i1 = (const int *)e1;
1705 	const int *i2 = (const int *)e2;
1706 	return *i1 - *i2;
1707 }
1708 
1709 static gboolean
table_includes(TableFilter * tf,int idx)1710 table_includes (TableFilter *tf, int idx)
1711 {
1712 	if (!tf->count)
1713 		return FALSE;
1714 	return mono_binary_search (&idx, tf->elems, tf->count, sizeof (int), int_cmp) != NULL;
1715 }
1716 
1717 static gboolean
should_include_type(int idx)1718 should_include_type (int idx)
1719 {
1720 	if (!cur_filter)
1721 		return TRUE;
1722 	return table_includes (&cur_filter->types, idx);
1723 }
1724 
1725 static gboolean
should_include_method(int idx)1726 should_include_method (int idx)
1727 {
1728 	if (!cur_filter)
1729 		return TRUE;
1730 	return table_includes (&cur_filter->methods, idx);
1731 }
1732 
1733 static gboolean
should_include_field(int idx)1734 should_include_field (int idx)
1735 {
1736 	if (!cur_filter)
1737 		return TRUE;
1738 	return table_includes (&cur_filter->fields, idx);
1739 }
1740 
1741 static ImageFilter*
add_filter(const char * name)1742 add_filter (const char *name)
1743 {
1744 	ImageFilter *ifilter;
1745 	GList *item;
1746 
1747 	for (item = filter_list; item; item = item->next) {
1748 		ifilter = (ImageFilter *)item->data;
1749 		if (strcmp (ifilter->name, name) == 0)
1750 			return ifilter;
1751 	}
1752 	ifilter = g_new0 (ImageFilter, 1);
1753 	ifilter->name = g_strdup (name);
1754 	filter_list = g_list_prepend (filter_list, ifilter);
1755 	return ifilter;
1756 }
1757 
1758 static void
add_item(TableFilter * tf,int val)1759 add_item (TableFilter *tf, int val)
1760 {
1761 	if (tf->count >= tf->size) {
1762 		if (!tf->size) {
1763 			tf->size = 8;
1764 			tf->elems = (int *)g_malloc (sizeof (int) * tf->size);
1765 		} else {
1766 			tf->size *= 2;
1767 			tf->elems = (int *)g_realloc (tf->elems, sizeof (int) * tf->size);
1768 		}
1769 	}
1770 	tf->elems [tf->count++] = val;
1771 }
1772 
1773 static void
sort_filter_elems(void)1774 sort_filter_elems (void)
1775 {
1776 	ImageFilter *ifilter;
1777 	GList *item;
1778 
1779 	for (item = filter_list; item; item = item->next) {
1780 		ifilter = (ImageFilter *)item->data;
1781 		qsort (ifilter->types.elems, ifilter->types.count, sizeof (int), int_cmp);
1782 		qsort (ifilter->fields.elems, ifilter->fields.count, sizeof (int), int_cmp);
1783 		qsort (ifilter->methods.elems, ifilter->methods.count, sizeof (int), int_cmp);
1784 	}
1785 }
1786 
1787 static void
load_filter(const char * filename)1788 load_filter (const char* filename)
1789 {
1790 	FILE *file;
1791 	char buf [1024];
1792 	char *p, *s, *endptr;
1793 	int line = 0;
1794 	ImageFilter *ifilter = NULL;
1795 	int value = 0;
1796 
1797 	if (!(file = fopen (filename, "r"))) {
1798 		g_print ("Cannot open filter file '%s'\n", filename);
1799 		exit (1);
1800 	}
1801 	while (fgets (buf, sizeof (buf), file) != NULL) {
1802 		++line;
1803 		s = buf;
1804 		while (*s && g_ascii_isspace (*s)) ++s;
1805 		switch (*s) {
1806 		case 0:
1807 		case '#':
1808 			break;
1809 		case '[':
1810 			p = strchr (s, ']');
1811 			if (!p)
1812 				g_error ("No matching ']' in filter at line %d\n", line);
1813 			*p = 0;
1814 			ifilter = add_filter (s + 1);
1815 			break;
1816 		case 'T':
1817 			if (!ifilter)
1818 				g_error ("Invalid format in filter at line %d\n", line);
1819 			if ((s [1] != ':') || !(value = strtol (s + 2, &endptr, 0)) || (endptr == s + 2))
1820 				g_error ("Invalid type number in filter at line %d\n", line);
1821 			add_item (&ifilter->types, value);
1822 			break;
1823 		case 'M':
1824 			if (!ifilter)
1825 				g_error ("Invalid format in filter at line %d\n", line);
1826 			if ((s [1] != ':') || !(value = strtol (s + 2, &endptr, 0)) || (endptr == s + 2))
1827 				g_error ("Invalid method number in filter at line %d\n", line);
1828 			add_item (&ifilter->methods, value);
1829 			break;
1830 		case 'F':
1831 			if (!ifilter)
1832 				g_error ("Invalid format in filter at line %d\n", line);
1833 			if ((s [1] != ':') || !(value = strtol (s + 2, &endptr, 0)) || (endptr == s + 2))
1834 				g_error ("Invalid field number in filter at line %d\n", line);
1835 			add_item (&ifilter->fields, value);
1836 			break;
1837 		default:
1838 			g_error ("Invalid format in filter at line %d\n", line);
1839 		}
1840 	}
1841 	fclose (file);
1842 	sort_filter_elems ();
1843 }
1844 
1845 
1846 static gboolean
try_load_from(MonoAssembly ** assembly,const gchar * path1,const gchar * path2,const gchar * path3,const gchar * path4,gboolean refonly,MonoAssemblyCandidatePredicate predicate,gpointer user_data)1847 try_load_from (MonoAssembly **assembly,
1848 	       const gchar *path1, const gchar *path2,
1849 	       const gchar *path3, const gchar *path4, gboolean refonly,
1850 	       MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1851 {
1852 	gchar *fullpath;
1853 
1854 	*assembly = NULL;
1855 	fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1856 	if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
1857 		*assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1858 
1859 	g_free (fullpath);
1860 	return (*assembly != NULL);
1861 }
1862 
1863 static MonoAssembly *
real_load(gchar ** search_path,const gchar * culture,const gchar * name,gboolean refonly,MonoAssemblyCandidatePredicate predicate,gpointer user_data)1864 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly,
1865 	   MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1866 {
1867 	MonoAssembly *result = NULL;
1868 	gchar **path;
1869 	gchar *filename;
1870 	const gchar *local_culture;
1871 	gint len;
1872 
1873 	if (!culture || *culture == '\0') {
1874 		local_culture = "";
1875 	} else {
1876 		local_culture = culture;
1877 	}
1878 
1879 	filename =  g_strconcat (name, ".dll", NULL);
1880 	len = strlen (filename);
1881 
1882 	for (path = search_path; *path; path++) {
1883 		if (**path == '\0')
1884 			continue; /* Ignore empty ApplicationBase */
1885 
1886 		/* See test cases in bug #58992 and bug #57710 */
1887 		/* 1st try: [culture]/[name].dll (culture may be empty) */
1888 		strcpy (filename + len - 4, ".dll");
1889 		if (try_load_from (&result, *path, local_culture, "", filename, refonly, predicate, user_data))
1890 			break;
1891 
1892 		/* 2nd try: [culture]/[name].exe (culture may be empty) */
1893 		strcpy (filename + len - 4, ".exe");
1894 		if (try_load_from (&result, *path, local_culture, "", filename, refonly, predicate, user_data))
1895 			break;
1896 
1897 		/* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1898 		strcpy (filename + len - 4, ".dll");
1899 		if (try_load_from (&result, *path, local_culture, name, filename, refonly, predicate, user_data))
1900 			break;
1901 
1902 		/* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1903 		strcpy (filename + len - 4, ".exe");
1904 		if (try_load_from (&result, *path, local_culture, name, filename, refonly, predicate, user_data))
1905 			break;
1906 	}
1907 
1908 	g_free (filename);
1909 	return result;
1910 }
1911 
1912 /*
1913  * Try to load referenced assemblies from assemblies_path.
1914  */
1915 static MonoAssembly *
monodis_preload(MonoAssemblyName * aname,gchar ** assemblies_path,gpointer user_data)1916 monodis_preload (MonoAssemblyName *aname,
1917 				 gchar **assemblies_path,
1918 				 gpointer user_data)
1919 {
1920 	MonoAssembly *result = NULL;
1921 	gboolean refonly = GPOINTER_TO_UINT (user_data);
1922 
1923 	if (assemblies_path && assemblies_path [0] != NULL) {
1924 		result = real_load (assemblies_path, aname->culture, aname->name, refonly, NULL, NULL);
1925 	}
1926 
1927 	return result;
1928 }
1929 
1930 static GList *loaded_assemblies = NULL;
1931 
1932 static void
monodis_assembly_load_hook(MonoAssembly * assembly,gpointer user_data)1933 monodis_assembly_load_hook (MonoAssembly *assembly, gpointer user_data)
1934 {
1935 	loaded_assemblies = g_list_prepend (loaded_assemblies, assembly);
1936 }
1937 
1938 static MonoAssembly *
monodis_assembly_search_hook(MonoAssemblyName * aname,gpointer user_data)1939 monodis_assembly_search_hook (MonoAssemblyName *aname, gpointer user_data)
1940 {
1941         GList *tmp;
1942 
1943        for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
1944                MonoAssembly *ass = (MonoAssembly *)tmp->data;
1945                if (mono_assembly_names_equal (aname, &ass->aname))
1946 		       return ass;
1947        }
1948        return NULL;
1949 }
1950 
1951 static void
usage(void)1952 usage (void)
1953 {
1954 	GString *args = g_string_new ("[--output=filename] [--filter=filename]\n");
1955 	int i;
1956 
1957 	g_string_append (args, "[--help] [--mscorlib] [--show-tokens] [--show-method-tokens]\n");
1958 
1959 	for (i = 0; table_list [i].name != NULL; i++){
1960 		g_string_append (args, "[");
1961 		g_string_append (args, table_list [i].name);
1962 		g_string_append (args, "] ");
1963 		if (((i-2) % 5) == 0)
1964 			g_string_append_c (args, '\n');
1965 	}
1966 	g_string_append (args, "[--forward-decls]");
1967 	fprintf (stderr,
1968 		 "monodis -- Mono Common Intermediate Language Disassembler\n"
1969 		 "Usage is: monodis %s file ..\n", args->str);
1970 	exit (1);
1971 }
1972 
1973 static void
thread_state_init(MonoThreadUnwindState * ctx)1974 thread_state_init (MonoThreadUnwindState *ctx)
1975 {
1976 }
1977 
1978 int
main(int argc,char * argv[])1979 main (int argc, char *argv [])
1980 {
1981 	MonoThreadInfoRuntimeCallbacks ticallbacks;
1982 
1983 	GList *input_files = NULL, *l;
1984 	int i, j;
1985 
1986 	output = stdout;
1987 	init_key_table ();
1988 	for (i = 1; i < argc; i++){
1989 		if (argv [i][0] == '-'){
1990 			if (argv [i][1] == 'h')
1991 				usage ();
1992 			else if (argv [i][1] == 'd')
1993 				dump_header_data_p = TRUE;
1994 			else if (strcmp (argv [i], "--mscorlib") == 0) {
1995 				substitute_with_mscorlib_p = TRUE;
1996 				continue;
1997 			} else if (strcmp (argv [i], "--show-method-tokens") == 0) {
1998 				show_method_tokens = TRUE;
1999 				continue;
2000 			} else if (strcmp (argv [i], "--show-tokens") == 0) {
2001 				show_tokens = TRUE;
2002 				continue;
2003 			} else if (strncmp (argv [i], "--output=", 9) == 0) {
2004 				output = fopen (argv [i]+9, "w");
2005 				if (output == NULL) {
2006 					fprintf (stderr, "Can't open output file `%s': %s\n",
2007 						 argv [i]+9, strerror (errno));
2008 					exit (1);
2009 				}
2010 				dump_managed_resources = TRUE;
2011 				continue;
2012 			} else if (strncmp (argv [i], "--filter=", 9) == 0) {
2013 				load_filter (argv [i]+9);
2014 				continue;
2015 			} else if (strcmp (argv [i], "--forward-decls") == 0) {
2016 				dump_forward_decls = TRUE;
2017 				continue;
2018 			} else if (strcmp (argv [i], "--help") == 0)
2019 				usage ();
2020 			for (j = 0; table_list [j].name != NULL; j++) {
2021 				if (strcmp (argv [i], table_list [j].name) == 0)
2022 					dump_table = j;
2023 			}
2024 			if (dump_table < 0)
2025 				usage ();
2026 		} else
2027 			input_files = g_list_append (input_files, argv [i]);
2028 	}
2029 
2030 	if (input_files == NULL)
2031 		usage ();
2032 
2033 	CHECKED_MONO_INIT ();
2034 	mono_counters_init ();
2035 	mono_tls_init_runtime_keys ();
2036 	memset (&ticallbacks, 0, sizeof (ticallbacks));
2037 	ticallbacks.thread_state_init = thread_state_init;
2038 #ifndef HOST_WIN32
2039 	mono_w32handle_init ();
2040 #endif
2041 	mono_thread_info_runtime_init (&ticallbacks);
2042 
2043 	mono_install_assembly_load_hook (monodis_assembly_load_hook, NULL);
2044 	mono_install_assembly_search_hook (monodis_assembly_search_hook, NULL);
2045 
2046 	/*
2047 	 * If we just have one file, use the corlib version it requires.
2048 	 */
2049 	if (!input_files->next) {
2050 		char *filename = (char *)input_files->data;
2051 
2052 		mono_init_from_assembly (argv [0], filename);
2053 
2054 		mono_install_assembly_preload_hook (monodis_preload, GUINT_TO_POINTER (FALSE));
2055 
2056 		return disassemble_file (filename);
2057 	} else {
2058 		mono_init (argv [0]);
2059 
2060 		i = 0;
2061 		for (l = input_files; l; l = l->next)
2062 			if (disassemble_file ((const char *)l->data) == 1) i = 1;
2063 		return i;
2064 	}
2065 
2066 	return 0;
2067 }
2068