* main.c/get.c: Remove magic numbers, use constants.
[mono.git] / mono / dis / get.c
1 /*
2  * get.c: Functions to get stringified values from the metadata tables.
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9 #include <config.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <glib.h>
15 #include "meta.h"
16 #include "util.h"
17 #include "get.h"
18 #include <mono/metadata/class.h>
19 #include <mono/metadata/marshal.h>
20
21 extern gboolean substitute_with_mscorlib_p;
22
23 static char *
24 get_memberref_parent (MonoImage *m, guint32 mrp_token);
25
26 char *
27 get_typedef (MonoImage *m, int idx)
28 {
29         guint32 cols [MONO_TYPEDEF_SIZE];
30         const char *ns;
31
32         mono_metadata_decode_row (&m->tables [MONO_TABLE_TYPEDEF], idx - 1, cols, MONO_TYPEDEF_SIZE);
33
34         ns = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE]);
35         return g_strdup_printf (
36                 "%s%s%s", ns, *ns?".":"",
37                 mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME]));
38 }
39
40 char *
41 get_module (MonoImage *m, int idx)
42 {
43         guint32 cols [MONO_MODULE_SIZE];
44         
45         /*
46          * There MUST BE only one module in the Module table
47          */
48         g_assert (idx == 1);
49             
50         mono_metadata_decode_row (&m->tables [MONO_TABLE_MODULE], idx - 1, cols, MONO_MODULE_SIZE);
51
52         return g_strdup (mono_metadata_string_heap (m, cols [MONO_MODULE_NAME]));
53 }
54
55 char *
56 get_assemblyref (MonoImage *m, int idx)
57 {
58         guint32 cols [MONO_ASSEMBLYREF_SIZE];
59         
60         mono_metadata_decode_row (&m->tables [MONO_TABLE_ASSEMBLYREF], idx - 1, cols, MONO_ASSEMBLYREF_SIZE);
61
62         return g_strdup (mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_NAME]));
63 }
64
65 /*
66  *
67  * Returns a string representing the ArrayShape (22.2.16).
68  */
69 static const char *
70 get_array_shape (MonoImage *m, const char *ptr, char **result)
71 {
72         GString *res = g_string_new ("[");
73         guint32 rank, num_sizes, num_lo_bounds;
74         guint32 *sizes = NULL, *lo_bounds = NULL;
75         int i, r;
76         char buffer [80];
77         
78         rank = mono_metadata_decode_value (ptr, &ptr);
79         num_sizes = mono_metadata_decode_value (ptr, &ptr);
80
81         if (num_sizes > 0)
82                 sizes = g_new (guint32, num_sizes);
83         
84         for (i = 0; i < num_sizes; i++)
85                 sizes [i] = mono_metadata_decode_value (ptr, &ptr);
86
87         num_lo_bounds = mono_metadata_decode_value (ptr, &ptr);
88         if (num_lo_bounds > 0)
89                 lo_bounds = g_new (guint32, num_lo_bounds);
90         
91         for (i = 0; i < num_lo_bounds; i++)
92                 lo_bounds [i] = mono_metadata_decode_value (ptr, &ptr);
93
94         for (r = 0; r < rank; r++){
95                 if (r < num_sizes){
96                         if (r < num_lo_bounds){
97                                 sprintf (buffer, "%d..%d", lo_bounds [r], lo_bounds [r] + sizes [r] - 1);
98                         } else {
99                                 sprintf (buffer, "0..%d", sizes [r] - 1);
100                         }
101                 } else
102                         buffer [0] = 0;
103                 
104                 g_string_append (res, buffer);
105                 if ((r + 1) != rank)
106                         g_string_append (res, ", ");
107         }
108         g_string_append (res, "]");
109         
110         if (sizes)
111                 g_free (sizes);
112
113         if (lo_bounds)
114                 g_free (lo_bounds);
115
116         *result = res->str;
117         g_string_free (res, FALSE);
118
119         return ptr;
120 }
121
122 /**
123  * get_typespec:
124  * @m: metadata context
125  * @blob_idx: index into the blob heap
126  *
127  * Returns the stringified representation of a TypeSpec signature (22.2.17)
128  */
129 char *
130 get_typespec (MonoImage *m, guint32 idx)
131 {
132         guint32 cols [MONO_TYPESPEC_SIZE];
133         const char *ptr;
134         char *s, *result;
135         GString *res = g_string_new ("");
136         int len;
137
138         mono_metadata_decode_row (&m->tables [MONO_TABLE_TYPESPEC], idx-1, cols, MONO_TYPESPEC_SIZE);
139         ptr = mono_metadata_blob_heap (m, cols [MONO_TYPESPEC_SIGNATURE]);
140         len = mono_metadata_decode_value (ptr, &ptr);
141         
142         switch (*ptr++){
143         case MONO_TYPE_PTR:
144                 ptr = get_custom_mod (m, ptr, &s);
145                 if (s){
146                         g_string_append (res, s);
147                         g_string_append_c (res, ' ');
148                         g_free (s);
149                 }
150                 
151                 if (*ptr == MONO_TYPE_VOID)
152                         g_string_append (res, "void");
153                 else {
154                         ptr = get_type (m, ptr, &s);
155                         if (s)
156                                 g_string_append (res, s);
157                 }
158                 break;
159                 
160         case MONO_TYPE_FNPTR:
161                 g_string_append (res, "FNPTR ");
162                 /*
163                  * we assume MethodRefSig, as we do not know
164                  * whether it is a MethodDefSig or a MethodRefSig.
165                  */
166                 printf ("\n FNPTR:\n");
167                 
168                 hex_dump (ptr, 0, 40);
169                 break;
170                         
171         case MONO_TYPE_ARRAY:
172                 ptr = get_type (m, ptr, &s);
173                 g_string_append (res, s);
174                 g_free (s);
175                 g_string_append_c (res, ' ');
176                 ptr = get_array_shape (m, ptr, &s);
177                 g_string_append (res, s);
178                 g_free (s);
179                 break;
180                 
181         case MONO_TYPE_SZARRAY:
182                 ptr = get_custom_mod (m, ptr, &s);
183                 if (s){
184                         g_string_append (res, s);
185                         g_string_append_c (res, ' ');
186                         g_free (s);
187                 }
188                 ptr = get_type (m, ptr, &s);
189                 g_string_append (res, s);
190                 g_string_append (res, "[]");
191                 g_free (s);
192         }
193
194         result = res->str;
195         g_string_free (res, FALSE);
196
197         return result;
198 }
199
200 char *
201 get_typeref (MonoImage *m, int idx)
202 {
203         guint32 cols [MONO_TYPEREF_SIZE];
204         const char *s, *t;
205         char *x, *ret;
206         guint32 rs_idx, table;
207         
208         mono_metadata_decode_row (&m->tables [MONO_TABLE_TYPEREF], idx - 1, cols, MONO_TYPEREF_SIZE);
209
210         t = mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]);
211         s = mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]);
212
213         rs_idx = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
214         table = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
215         
216         switch (table){
217         case RESOLTION_SCOPE_MODULE: /* Module */
218                 x = get_module (m, rs_idx);
219                 ret = g_strdup_printf ("[%s] %s%s%s", x, s, *s?".":"", t);
220                 g_free (x);
221                 break;
222
223         case RESOLTION_SCOPE_MODULEREF: /* ModuleRef */
224                 ret = g_strdup_printf ("TODO:TypeRef-ModuleRef (%s.%s)", s, t);
225                 break;
226                               
227         case RESOLTION_SCOPE_ASSEMBLYREF: /*
228                  * AssemblyRef (ECMA docs claim it is 3, but it looks to
229                  * me like it is 2 (tokens are prefixed with 0x23)
230                  */
231                 x = get_assemblyref (m, rs_idx);
232                 ret = g_strdup_printf ("[%s]%s%s%s", x, s, *s?".":"", t);
233                 g_free (x);
234                 break;
235                 
236         case RESOLTION_SCOPE_TYPEREF: /* TypeRef */
237                 x = get_typeref (m, rs_idx);
238                 ret =  g_strdup_printf ("%s/%s", x, t);
239                 g_free (x);
240                 break;
241                 
242         default:
243                 ret = g_strdup_printf ("Unknown table in TypeRef %d", table);
244         }
245
246         return ret;
247 }
248
249 /**
250  * get_typedef_or_ref:
251  * @m: metadata context
252  * @dor_token: def or ref encoded index
253  *
254  * Low two bits contain table to lookup from
255  * high bits contain the index into the def or ref table
256  *
257  * Returns: a stringified version of the MethodDef or MethodRef
258  * at (dor_token >> 2) 
259  */
260 char *
261 get_typedef_or_ref (MonoImage *m, guint32 dor_token)
262 {
263         char *temp = NULL, *s;
264         int table, idx;
265
266         /*
267          * low 2 bits contain encoding
268          */
269         table = dor_token & TYPEDEFORREF_MASK;
270         idx = dor_token >> TYPEDEFORREF_BITS;
271         
272         switch (table){
273         case 0: /* TypeDef */
274                 temp = get_typedef (m, idx);
275                 s = g_strdup_printf ("%s", temp);
276                 break;
277                 
278         case 1: /* TypeRef */
279                 temp = get_typeref (m, idx);
280                 s = g_strdup_printf ("%s", temp);
281                 break;
282                 
283         case 2: /* TypeSpec */
284                 s = get_typespec (m, idx);
285                 break;
286
287         default:
288                 g_error ("Unhandled encoding for typedef-or-ref coded index 0x%08x", dor_token);
289
290         }
291         
292         if (temp)
293                 g_free (temp);
294
295         return s;
296 }
297
298 /**
299  * get_type_or_methdef
300  * @m: metadata context
301  * @dor_token: type or method def encoded index
302  *
303  * Low bit contains the table to lookup from
304  * high bits contain the index into the type def or method def table
305  *
306  * Returns: a stringified version of the TypeOrMethodDef token
307  */
308 char *
309 get_type_or_methdef (MonoImage *m, guint32 dor_token)
310 {
311         if (dor_token & MONO_TYPEORMETHOD_METHOD) /* MethodDef */
312                 return get_methoddef (m, dor_token >> MONO_TYPEORMETHOD_BITS);
313         else  /* TypeDef */
314                 return get_typedef (m, dor_token >> MONO_TYPEORMETHOD_BITS);
315 }
316
317 /** 
318  * get_encoded_typedef_or_ref:
319  * @m: metadata context 
320  * @ptr: location to decode from.
321  * @result: pointer to string where resulting decoded string is stored
322  *
323  * result will point to a g_malloc()ed string.
324  *
325  * Returns: the new ptr to continue decoding
326  */
327 const char *
328 get_encoded_typedef_or_ref (MonoImage *m, const char *ptr, char **result)
329 {
330         guint32 token;
331         
332         token = mono_metadata_decode_value (ptr, &ptr);
333
334         *result = get_typedef_or_ref (m, token);
335
336         return ptr;
337 }
338
339 /**
340  * get_custom_mod:
341  *
342  * Decodes a CustomMod (22.2.7)
343  *
344  * Returns: updated pointer location
345  */
346 const char *
347 get_custom_mod (MonoImage *m, const char *ptr, char **return_value)
348 {
349         char *s;
350         const char *reqd;
351         
352         *return_value = NULL;
353         while ((*ptr == MONO_TYPE_CMOD_OPT) ||
354                    (*ptr == MONO_TYPE_CMOD_REQD)) {
355                 reqd = (*ptr == MONO_TYPE_CMOD_REQD) ? "reqd" : "opt";
356                 ptr++;
357                 ptr = get_encoded_typedef_or_ref (m, ptr, &s);
358
359                 if (*return_value == NULL)
360                         *return_value = g_strconcat (reqd, " ", s, NULL);
361                 else
362                         *return_value = g_strconcat (*return_value, " ", reqd, " ", s, NULL);
363                 g_free (s);
364         }
365         return ptr;
366 }
367
368
369 static map_t element_type_map [] = {
370         { MONO_TYPE_END        , "end" },
371         { MONO_TYPE_VOID       , "void" },
372         { MONO_TYPE_BOOLEAN    , "bool" },
373         { MONO_TYPE_CHAR       , "char" }, 
374         { MONO_TYPE_I1         , "int8" },
375         { MONO_TYPE_U1         , "unsigned int8" }, 
376         { MONO_TYPE_I2         , "int16" },
377         { MONO_TYPE_U2         , "unsigned int16" },
378         { MONO_TYPE_I4         , "int32" },
379         { MONO_TYPE_U4         , "unsigned int32" },
380         { MONO_TYPE_I8         , "int64" },
381         { MONO_TYPE_U8         , "unsigned int64" },
382         { MONO_TYPE_R4         , "float32" },
383         { MONO_TYPE_R8         , "float64" },
384         { MONO_TYPE_STRING     , "string" },
385         { MONO_TYPE_TYPEDBYREF , "TypedByRef" },
386         { MONO_TYPE_I          , "native int" },
387         { MONO_TYPE_U          , "native unsigned int" },
388         { MONO_TYPE_OBJECT     , "object" },
389         { 0, NULL }
390 };
391
392 static map_t call_conv_type_map [] = {
393         { MONO_CALL_DEFAULT     , "default" },
394         { MONO_CALL_C           , "c" },
395         { MONO_CALL_STDCALL     , "stdcall" },
396         { MONO_CALL_THISCALL    , "thiscall" },
397         { MONO_CALL_FASTCALL    , "fastcall" },
398         { MONO_CALL_VARARG      , "vararg" },
399         { 0, NULL }
400 };
401
402 char*
403 dis_stringify_token (MonoImage *m, guint32 token)
404 {
405         guint idx = token & 0xffffff;
406         switch (token >> 24) {
407         case MONO_TABLE_TYPEDEF: return get_typedef (m, idx);
408         case MONO_TABLE_TYPEREF: return get_typeref (m, idx);
409         case MONO_TABLE_TYPESPEC: return get_typespec (m, idx);
410         default:
411                  break;
412         }
413         return g_strdup_printf("0x%08x", token);
414 }
415
416 char*
417 dis_stringify_array (MonoImage *m, MonoArrayType *array) 
418 {
419         char *type;
420         GString *s = g_string_new("");
421         int i;
422         
423         type = dis_stringify_type (m, &array->eklass->byval_arg);
424         g_string_append (s, type);
425         g_free (type);
426         g_string_append_c (s, '[');
427         for (i = 0; i < array->rank; ++i) {
428                 if (i)
429                         g_string_append_c (s, ',');
430                 if (i < array->numsizes) {
431                         if (i < array->numlobounds && array->lobounds[i] != 0)
432                                 g_string_sprintfa (s, "%d..%d", array->lobounds[i], array->sizes[i]);
433                         else
434                                 g_string_sprintfa (s, "%d", array->sizes[i]);
435                 }
436         }
437         g_string_append_c (s, ']');
438         type = s->str;
439         g_string_free (s, FALSE);
440         return type;
441 }
442
443 char*
444 dis_stringify_modifiers (MonoImage *m, int n, MonoCustomMod *mod)
445 {
446         GString *s = g_string_new("");
447         char *result;
448         int i;
449         for (i = 0; i < n; ++i) {
450                 char *tok = dis_stringify_token (m, mod[i].token);
451                 if (i > 0)
452                         g_string_sprintfa (s, " ");
453                 g_string_sprintfa (s, "%s (%s)", mod[i].required ? "modopt": "modreq", tok);
454                 g_free (tok);
455         }
456         g_string_append_c (s, ' ');
457         result = s->str;
458         g_string_free (s, FALSE);
459         return result;
460 }
461
462 char*
463 dis_stringify_param (MonoImage *m, MonoType *param) 
464 {
465         char *t;
466         char *result;
467         const char *out = param->attrs & 2 ? "[out] ": "";
468         t = dis_stringify_type (m, param);
469         result = g_strconcat (out, t, NULL);
470         g_free (t);
471         return result;
472 }
473
474 /**
475  * get_generic_param
476  * @m: metadata context 
477  * @table_type: The type of table we are getting generics for (0 for typedef, 1 for method)
478  * @row: The row in the table
479  *
480  * Returns: Allocated stringified generic parameters
481  */
482 char*
483 get_generic_param (MonoImage *m, int table_type, guint32 row)
484 {
485         MonoTableInfo *t = &m->tables [MONO_TABLE_GENERICPARAM];
486         GString *result = g_string_new ("");
487         char *retval;
488         guint32 cols [MONO_GENERICPARAM_SIZE];
489         int i, own_tok, table, idx, found_count;
490
491         g_assert (table_type != MONO_TYPEORMETHOD_TYPE || table_type != MONO_TYPEORMETHOD_METHOD);
492         
493         found_count = 0;
494         for (i = 1; i <= t->rows; i++) {
495                 mono_metadata_decode_row (t, i-1, cols, MONO_GENERICPARAM_SIZE);
496                 own_tok = cols [MONO_GENERICPARAM_OWNER];
497                 table = own_tok & MONO_TYPEORMETHOD_MASK;
498                 idx = own_tok >> MONO_TYPEORMETHOD_BITS;
499                 
500                 if (table != table_type || idx != row)
501                         continue;
502
503                 if (found_count == 0)
504                         g_string_append_printf (result, "<%s",
505                                         mono_metadata_string_heap (m, cols [MONO_GENERICPARAM_NAME]));
506                 else
507                         g_string_append_printf (result, ", %s",
508                                         mono_metadata_string_heap (m, cols [MONO_GENERICPARAM_NAME]));
509                 found_count++;
510         }
511
512         if (found_count)
513                 g_string_append_c (result, '>');
514         retval = result->str;
515         g_string_free (result, FALSE);
516         return retval;
517 }
518
519 char*
520 dis_stringify_method_signature (MonoImage *m, MonoMethodSignature *method, int methoddef_row, gboolean fully_qualified)
521 {
522         guint32 cols [MONO_METHOD_SIZE];
523         guint32 pcols [MONO_PARAM_SIZE];
524         guint32 param_index = 0;
525         const char *name = "";
526         int free_method = 0;
527         char *retval;
528         char *type = NULL;
529         char *gen_param;
530         GString *result = g_string_new ("");
531         int i;
532         
533         g_assert (method || methoddef_row);
534
535         if (methoddef_row) {
536                 mono_metadata_decode_row (&m->tables [MONO_TABLE_METHOD], methoddef_row -1, cols, MONO_METHOD_SIZE);
537                 if (fully_qualified)
538                         type = get_typedef (m, mono_metadata_typedef_from_method (m, methoddef_row));
539                 name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
540                 param_index = cols [MONO_METHOD_PARAMLIST];
541                 if (!method) {
542                         const char *sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
543                         mono_metadata_decode_blob_size (sig, &sig);
544                         method = mono_metadata_parse_method_signature (m, methoddef_row, sig, &sig);
545                         free_method = 1;
546                 }      
547                 gen_param = get_generic_param (m, 1, methoddef_row);
548         }
549         
550         retval = dis_stringify_param (m, method->ret);
551         if (method->hasthis)
552                 g_string_append (result, "instance ");
553         g_string_append (result, map (method->call_convention, call_conv_type_map));
554         g_string_sprintfa (result, " %s ", retval);
555         if (type)
556                 g_string_sprintfa (result, "%s::", type);
557         g_string_append (result, name);
558         if (gen_param) {
559                 g_string_append (result, gen_param);
560                 g_free (gen_param);
561         }
562         g_string_append (result, " (");
563         g_free (retval);
564         for (i = 0; i < method->param_count; ++i) {
565                 if (param_index && param_index <= m->tables [MONO_TABLE_PARAM].rows) {
566                         mono_metadata_decode_row (&m->tables [MONO_TABLE_PARAM], param_index - 1, pcols, MONO_PARAM_SIZE);
567                         name = mono_metadata_string_heap (m, pcols [MONO_PARAM_NAME]);
568                         method->params [i]->attrs = pcols [MONO_PARAM_FLAGS];
569                         param_index++;
570                 } else {
571                         name = "";
572                 }
573                 if (i)
574                         g_string_append (result, ", ");
575                 retval = dis_stringify_param (m, method->params [i]);
576                 g_string_sprintfa (result, "%s '%s'", retval, name);
577                 g_free (retval);
578         }
579         g_string_append (result, ") ");
580
581         if (free_method)
582                 mono_metadata_free_method_signature (method);
583         retval = result->str;
584         g_string_free (result, FALSE);
585
586         return retval;
587 }
588
589 static char *
590 dis_stringify_object_with_class (MonoImage *m, MonoClass *c)
591 {
592         /* FIXME: handle MONO_TYPE_OBJECT ... */
593         const char *otype = c->byval_arg.type == MONO_TYPE_CLASS? "class" : "valuetype";
594         char *assemblyref = NULL, *result;
595         if (m != c->image) {
596                 if (c->image->assembly_name) {
597                         /* we cheat */
598                         if (substitute_with_mscorlib_p && !strcmp ("corlib", c->image->assembly_name))
599                                 assemblyref = g_strdup_printf ("[%s]", "mscorlib");
600                         else
601                                 assemblyref = g_strdup_printf ("[%s]", c->image->assembly->aname.name);
602                 } else {
603                         assemblyref = g_strdup_printf ("[.module %s]", c->image->module_name);
604                 }
605         }
606         result = g_strdup_printf ("%s %s%s%s%s", otype, assemblyref?assemblyref:"", c->name_space, 
607                                 *c->name_space?".":"", c->name);
608         g_free (assemblyref);
609         return result;
610 }
611
612 static char *
613 dis_stringify_object (MonoImage *m, MonoType *type)
614 {
615         MonoClass *c = mono_class_from_mono_type (type);
616         return dis_stringify_object_with_class (m, c);
617 }
618
619 char*
620 dis_stringify_type (MonoImage *m, MonoType *type)
621 {
622         const char *pinned = "", *byref = "";
623         char *bare = NULL, *mods = NULL;
624         char *result;
625
626         if (type->num_mods)
627                 mods = dis_stringify_modifiers (m, type->num_mods, type->modifiers);
628
629         switch (type->type){
630         case MONO_TYPE_BOOLEAN:
631         case MONO_TYPE_CHAR:
632         case MONO_TYPE_I1:
633         case MONO_TYPE_U1:
634         case MONO_TYPE_I2:
635         case MONO_TYPE_U2:
636         case MONO_TYPE_I4:
637         case MONO_TYPE_U4:
638         case MONO_TYPE_I8:
639         case MONO_TYPE_U8:
640         case MONO_TYPE_R4:
641         case MONO_TYPE_R8:
642         case MONO_TYPE_I:
643         case MONO_TYPE_U:
644         case MONO_TYPE_STRING:
645         case MONO_TYPE_OBJECT:
646         case MONO_TYPE_TYPEDBYREF:
647                 bare = g_strdup (map (type->type, element_type_map));
648                 break;
649                 
650         case MONO_TYPE_VALUETYPE:
651         case MONO_TYPE_CLASS:
652                 bare = dis_stringify_object (m, type);
653                 break;
654                 
655         case MONO_TYPE_FNPTR:
656                 bare = dis_stringify_method_signature (m, type->data.method, 0, FALSE);
657                 break;
658         case MONO_TYPE_PTR: {
659                 char *child_type;
660                 child_type = dis_stringify_type (m, type->data.type);
661                 
662                 bare = g_strdup_printf ("%s*", child_type);
663                 g_free (child_type);
664                 break;
665         }
666         case MONO_TYPE_SZARRAY: {
667                 char *child_type;
668                 child_type = dis_stringify_type (m, &type->data.klass->byval_arg);
669                 
670                 bare = g_strdup_printf ("%s[]", child_type);
671                 g_free (child_type);
672                 break;
673         }
674         case MONO_TYPE_ARRAY:
675                 bare = dis_stringify_array (m, type->data.array);
676                 break;
677         case MONO_TYPE_VOID:
678                 bare = g_strdup ("void");
679                 break;
680         case MONO_TYPE_MVAR:
681                 bare = g_strdup_printf ("!!%d", type->data.generic_param->num);
682                 break;
683         case MONO_TYPE_VAR:
684                 bare = g_strdup_printf ("!%d", type->data.generic_param->num);
685                 break;
686         case MONO_TYPE_GENERICINST: {
687                 GString *str = g_string_new ("");
688                 int i;
689                 char *generic_type = dis_stringify_type (m, type->data.generic_inst->generic_type);
690
691                 for (i = 0; i < type->data.generic_inst->type_argc; i++){
692                         char *t = dis_stringify_type (m, type->data.generic_inst->type_argv [i]);
693
694                         g_string_append (str, t);
695                         if (i+1 != type->data.generic_inst->type_argc)
696                                 g_string_append (str, ", ");
697                         g_free (t);
698                 }
699                 bare = g_strdup_printf ("%s<%s>", generic_type, str->str);
700                 g_string_free (str, TRUE);
701                 break;
702         }
703                 
704         default:
705                 g_error ("Do not know how to stringify type 0x%x", type->type);
706         }
707         
708         if (type->pinned)
709                 pinned = " pinned";
710
711         if (type->byref)
712                 byref = "&";
713                 
714         result = g_strconcat (mods ? mods : "", bare, byref, pinned, NULL);
715
716         g_free (bare);
717
718         return result;
719 }
720
721 /**
722  * get_type:
723  * @m: metadata context 
724  * @ptr: location to decode from.
725  * @result: pointer to string where resulting decoded string is stored
726  *
727  * This routine returs in @result the stringified type pointed by @ptr.
728  * (22.2.12)
729  *
730  * Returns: the new ptr to continue decoding
731  */
732 const char *
733 get_type (MonoImage *m, const char *ptr, char **result)
734 {
735         MonoType *type = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
736         *result = dis_stringify_type (m, type);
737         mono_metadata_free_type (type);
738         return ptr;
739 }
740
741 /**
742  * 
743  * Returns a stringified representation of a FieldSig (22.2.4)
744  */
745 char *
746 get_field_signature (MonoImage *m, guint32 blob_signature)
747 {
748         char *allocated_modifier_string, *allocated_type_string;
749         const char *ptr = mono_metadata_blob_heap (m, blob_signature);
750         const char *base;
751         char *res;
752         int len;
753         
754         len = mono_metadata_decode_value (ptr, &ptr);
755         base = ptr;
756         /* FIELD is 0x06 */
757         g_assert (*ptr == 0x06);
758 /*      hex_dump (ptr, 0, len); */
759         ptr++; len--;
760         
761         ptr = get_custom_mod (m, ptr, &allocated_modifier_string);
762         ptr = get_type (m, ptr, &allocated_type_string);
763
764         res = g_strdup_printf (
765                 "%s %s",
766                 allocated_modifier_string ? allocated_modifier_string : "",
767                 allocated_type_string);
768         
769         if (allocated_modifier_string)
770                 g_free (allocated_modifier_string);
771         if (allocated_type_string)
772                 g_free (allocated_type_string);
773         
774         return res;
775 }
776
777 MonoTypeEnum
778 get_field_literal_type (MonoImage *m, guint32 blob_signature)
779 {
780         const char *ptr = mono_metadata_blob_heap (m, blob_signature);
781         int len;
782         char *allocated_modifier_string;
783         
784         len = mono_metadata_decode_value (ptr, &ptr);
785
786         /* FIELD is 0x06 */
787         g_assert (*ptr == 0x06);
788         ptr++; len--;
789         
790         ptr = get_custom_mod (m, ptr, &allocated_modifier_string);
791         if (allocated_modifier_string)
792                 g_free (allocated_modifier_string);
793
794         return (MonoTypeEnum) *ptr;
795         
796 }
797
798 /**
799  * decode_literal:
800  * @m: metadata context
801  * @token: token to decode
802  *
803  * decodes the literal indexed by @token.
804  */
805 char *
806 decode_literal (MonoImage *m, guint32 token)
807 {
808         return g_strdup ("LITERAL_VALUE");
809 }
810
811 /**
812  * get_ret_type:
813  * @m: metadata context 
814  * @ptr: location to decode from.
815  * @result: pointer to string where resulting decoded string is stored
816  *
817  * This routine returns in @result the stringified RetType (22.2.11)
818  *
819  * Returns: the new ptr to continue decoding.
820  */
821 const char *
822 get_ret_type (MonoImage *m, const char *ptr, char **ret_type)
823 {
824         GString *str = g_string_new ("");
825         char *mod = NULL;
826         char *allocated_type_string;
827         
828         ptr = get_custom_mod (m, ptr, &mod);
829         if (mod){
830                 g_string_append (str, mod);
831                 g_string_append_c (str, ' ');
832                 g_free (mod);
833         }
834
835         if (*ptr == MONO_TYPE_TYPEDBYREF){
836                 /* TODO: what does `typedbyref' mean? */
837                 g_string_append (str, "/* FIXME: What does this mean? */ typedbyref ");
838                 ptr++;
839         } else if (*ptr == MONO_TYPE_VOID){
840                  g_string_append (str, "void");
841                  ptr++;
842         } else {
843                 if (*ptr == MONO_TYPE_BYREF){
844                         g_string_append (str, "[out] ");
845                         ptr++;
846                 }
847
848                 ptr = get_type (m, ptr, &allocated_type_string);
849                 g_string_append (str, allocated_type_string);
850                 g_free (allocated_type_string);
851         }
852
853         *ret_type = str->str;
854         g_string_free (str, FALSE);
855
856         return ptr;
857 }
858
859 /**
860  * get_param:
861  * @m: metadata context 
862  * @ptr: location to decode from.
863  * @result: pointer to string where resulting decoded string is stored
864  *
865  * This routine returns in @result the stringified Param (22.2.10)
866  *
867  * Returns: the new ptr to continue decoding.
868  */
869 const char *
870 get_param (MonoImage *m, const char *ptr, char **retval)
871 {
872         GString *str = g_string_new ("");
873         char *allocated_mod_string, *allocated_type_string;
874         
875         ptr = get_custom_mod (m, ptr, &allocated_mod_string);
876         if (allocated_mod_string){
877                 g_string_append (str, allocated_mod_string);
878                 g_string_append_c (str, ' ');
879                 g_free (allocated_mod_string);
880         }
881         
882         if (*ptr == MONO_TYPE_TYPEDBYREF){
883                 g_string_append (str, " typedbyref ");
884                 ptr++;
885         } else {
886                  if (*ptr == MONO_TYPE_BYREF){
887                         g_string_append (str, "[out] ");
888                         ptr++;
889                 }
890                 ptr = get_type (m, ptr, &allocated_type_string);
891                 g_string_append (str, allocated_type_string);
892                 g_free (allocated_type_string);
893         }
894
895         *retval = str->str;
896         g_string_free (str, FALSE);
897         return ptr;
898 }
899
900 static map_t param_map [] = {
901         { PARAM_ATTRIBUTE_IN,                "[in] " },
902         { PARAM_ATTRIBUTE_OUT,               "[out] " },
903         { PARAM_ATTRIBUTE_OPTIONAL,          "optional " },
904         { PARAM_ATTRIBUTE_HAS_DEFAULT,       "hasdefault " },
905         { PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL, "fieldmarshal " },
906         { 0, NULL }
907 };
908
909 char *
910 param_flags (guint32 f)
911 {
912         return g_strdup (flags (f, param_map));
913 }
914
915 static map_t field_access_map [] = {
916         { FIELD_ATTRIBUTE_COMPILER_CONTROLLED, "compilercontrolled " },
917         { FIELD_ATTRIBUTE_PRIVATE,             "private " },
918         { FIELD_ATTRIBUTE_FAM_AND_ASSEM,       "famandassem " },
919         { FIELD_ATTRIBUTE_ASSEMBLY,            "assembly " },
920         { FIELD_ATTRIBUTE_FAMILY,              "family " },
921         { FIELD_ATTRIBUTE_FAM_OR_ASSEM,        "famorassem " },
922         { FIELD_ATTRIBUTE_PUBLIC,              "public " },
923         { 0, NULL }
924 };
925
926 static map_t field_flags_map [] = {
927         { FIELD_ATTRIBUTE_STATIC,              "static " },
928         { FIELD_ATTRIBUTE_INIT_ONLY,           "initonly " },
929         { FIELD_ATTRIBUTE_LITERAL,             "literal " },
930         { FIELD_ATTRIBUTE_NOT_SERIALIZED,      "notserialized " },
931         { FIELD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
932         { FIELD_ATTRIBUTE_PINVOKE_IMPL,        "FIXME:pinvokeimpl " },
933         { FIELD_ATTRIBUTE_RT_SPECIAL_NAME,        "rtspecialname " },
934         { FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL,        "hasfieldmarshal " },
935         { FIELD_ATTRIBUTE_HAS_DEFAULT,        "hasdefault " },
936         { FIELD_ATTRIBUTE_HAS_FIELD_RVA,        "hasfieldrva " },
937         { 0, NULL }
938 };
939
940 /**
941  * field_flags:
942  *
943  * Returns a stringified version of a Field's flags
944  */
945 char *
946 field_flags (guint32 f)
947 {
948         char buffer [1024];
949         int access = f & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
950         
951         buffer [0] = 0;
952
953         strcat (buffer, map (access, field_access_map));
954         strcat (buffer, flags (f, field_flags_map));
955         return g_strdup (buffer);
956 }
957
958 /**
959  * Returns a stringifed representation of a MethodRefSig (22.2.2)
960  */
961 char *
962 get_methodref_signature (MonoImage *m, guint32 blob_signature, const char *fancy_name)
963 {
964         GString *res = g_string_new ("");
965         const char *ptr = mono_metadata_blob_heap (m, blob_signature);
966         char *allocated_ret_type, *s;
967         gboolean seen_vararg = 0;
968         int param_count, signature_len;
969         int i, gen_count = 0;
970         int cconv;
971         
972         signature_len = mono_metadata_decode_value (ptr, &ptr);
973
974         if (*ptr & 0x20){
975                 if (*ptr & 0x40)
976                         g_string_append (res, "explicit-this ");
977                 else
978                         g_string_append (res, "instance "); /* has-this */
979         }
980
981         if (*ptr & 0x05)
982                 seen_vararg = 1;
983         if (*ptr & 0x10)
984                 gen_count = 1;
985         cconv = *ptr & 0x0f;
986         ptr++;
987         if (gen_count)
988                 gen_count = mono_metadata_decode_value (ptr, &ptr);
989         param_count = mono_metadata_decode_value (ptr, &ptr);
990         if (cconv != 0xa) {
991                 ptr = get_ret_type (m, ptr, &allocated_ret_type);
992                 g_string_append (res, allocated_ret_type);
993                 g_free (allocated_ret_type);
994         }
995
996         if (fancy_name){
997                 g_string_append_c (res, ' ');
998                 g_string_append (res, fancy_name);
999         }
1000         
1001         g_string_append (res, "(");
1002         
1003         /*
1004          * param_count describes parameters *before* and *after*
1005          * the vararg sentinel
1006          */
1007         for (i = 0; i < param_count; i++){
1008                 char *param = NULL;
1009                 
1010                 /*
1011                  * If ptr is a SENTINEL
1012                  */
1013                 if (*ptr == 0x41){
1014                         g_string_append (res, " varargs ");
1015                         continue;
1016                 }
1017
1018                 ptr = get_param (m, ptr, &param);
1019                 g_string_append (res, param);
1020                 if (i+1 != param_count)
1021                         g_string_append (res, ", ");
1022                 g_free (param);
1023         }
1024         g_string_append (res, ")");
1025         
1026         /*
1027          * cleanup and return
1028          */
1029         s = res->str;
1030         g_string_free (res, FALSE);
1031         return s;
1032 }
1033
1034 /**
1035  * Returns a stringifed representation of a field ref
1036  */
1037 char *
1038 get_fieldref_signature (MonoImage *m, int idx)
1039 {
1040         guint32 cols [MONO_MEMBERREF_SIZE];
1041         char *sig;
1042         char *full_sig;
1043
1044         mono_metadata_decode_row (&m->tables [MONO_TABLE_MEMBERREF],
1045                         idx - 1, cols, MONO_MEMBERREF_SIZE);
1046
1047         sig = get_field_signature (m, cols [MONO_FIELD_SIGNATURE]);
1048         full_sig = g_strdup_printf ("%s %s::%s", sig,
1049                         get_memberref_parent (m, cols [MONO_MEMBERREF_CLASS]),
1050                         mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));
1051         g_free (sig);
1052         
1053         return full_sig;
1054 }
1055
1056 /**
1057  * get_field:
1058  * @m: metadata context
1059  * @token: a FIELD_DEF token
1060  *
1061  * This routine has to locate the TypeDef that "owns" this Field.
1062  * Since there is no backpointer in the Field table, we have to scan
1063  * the TypeDef table and locate the actual "owner" of the field
1064  */
1065 char *
1066 get_field (MonoImage *m, guint32 token)
1067 {
1068         int idx = mono_metadata_token_index (token);
1069         guint32 cols [MONO_FIELD_SIZE];
1070         char *sig, *res, *type;
1071         guint32 type_idx;
1072
1073         /*
1074          * We can get here also with a MenberRef token (for a field
1075          * defined in another module/assembly, just like in get_method ()
1076          */
1077         if (mono_metadata_token_code (token) == MONO_TOKEN_MEMBER_REF) {
1078                 return get_fieldref_signature (m, idx);
1079         }
1080         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1081
1082         mono_metadata_decode_row (&m->tables [MONO_TABLE_FIELD], idx - 1, cols, MONO_FIELD_SIZE);
1083         sig = get_field_signature (m, cols [MONO_FIELD_SIGNATURE]);
1084
1085         /*
1086          * To locate the actual "container" for this field, we have to scan
1087          * the TypeDef table.  LAME!
1088          */
1089         type_idx = mono_metadata_typedef_from_field (m, idx);
1090
1091         type = get_typedef (m, type_idx);
1092         res = g_strdup_printf ("%s %s::%s",
1093                                sig, type,
1094                                mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
1095         g_free (type);
1096         g_free (sig);
1097
1098         return res;
1099 }
1100
1101 static char *
1102 get_memberref_parent (MonoImage *m, guint32 mrp_token)
1103 {
1104         /*
1105          * mrp_index is a MemberRefParent coded index
1106          */
1107         guint32 table = mrp_token & 7;
1108         guint32 idx = mrp_token >> 3;
1109
1110         switch (table){
1111         case 0: /* TypeDef */
1112                 return get_typedef (m, idx);
1113                 
1114         case 1: /* TypeRef */
1115                 return get_typeref (m, idx);
1116                 
1117         case 2: /* ModuleRef */
1118                 return g_strdup_printf ("TODO:MemberRefParent-ModuleRef");
1119                 
1120         case 3: /* MethodDef */
1121                 return g_strdup ("TODO:MethodDef");
1122                 
1123         case 4: /* TypeSpec */
1124                 return get_typespec (m, idx);
1125         }
1126         g_assert_not_reached ();
1127         return NULL;
1128 }
1129
1130 /**
1131  * get_method:
1132  * @m: metadata context
1133  * @token: a METHOD_DEF or MEMBER_REF token
1134  *
1135  * This routine has to locate the TypeDef that "owns" this Field.
1136  * Since there is no backpointer in the Field table, we have to scan
1137  * the TypeDef table and locate the actual "owner" of the field
1138  */
1139 char *
1140 get_method (MonoImage *m, guint32 token)
1141 {
1142         int idx = mono_metadata_token_index (token);
1143         guint32 member_cols [MONO_MEMBERREF_SIZE], method_cols [MONO_METHOD_SIZE];
1144         char *sig;
1145         const char *name;
1146
1147         MonoMethod *mh;
1148
1149         mh = mono_get_method (m, token, NULL);
1150         if (mh) {
1151                 sig = dis_stringify_object_with_class (m, mh->klass);
1152                 name = g_strdup_printf ("%s::%s", sig, mh->name);
1153                 g_free (sig);
1154         } else
1155                 name = NULL;
1156
1157         switch (mono_metadata_token_code (token)){
1158         case MONO_TOKEN_METHOD_DEF:
1159                 mono_metadata_decode_row (&m->tables [MONO_TABLE_METHOD], 
1160                                           idx - 1, method_cols, MONO_METHOD_SIZE);
1161
1162                 sig = get_methodref_signature (m, method_cols [MONO_METHOD_SIGNATURE], name);
1163                 return sig;
1164                 
1165         case MONO_TOKEN_MEMBER_REF: {
1166                 mono_metadata_decode_row (&m->tables [MONO_TABLE_MEMBERREF],
1167                                           idx - 1, member_cols, MONO_MEMBERREF_SIZE);
1168                 if (!name)
1169                         name = g_strdup_printf ("%s::%s",
1170                                         get_memberref_parent (m, member_cols [MONO_MEMBERREF_CLASS]),
1171                                         mono_metadata_string_heap (m, member_cols [MONO_MEMBERREF_NAME]));
1172                 sig = get_methodref_signature (
1173                         m, member_cols [MONO_MEMBERREF_SIGNATURE], name);
1174                 return sig;
1175         }
1176         case MONO_TOKEN_METHOD_SPEC: {
1177                 mono_metadata_decode_row (&m->tables [MONO_TABLE_METHODSPEC], idx - 1, member_cols, MONO_METHODSPEC_SIZE);
1178                 token = member_cols [MONO_METHODSPEC_METHOD];
1179                 if ((token & METHODDEFORREF_MASK) == METHODDEFORREF_METHODDEF)
1180                         token = MONO_TOKEN_METHOD_DEF | (token >> METHODDEFORREF_BITS);
1181                 else
1182                         token = MONO_TOKEN_MEMBER_REF | (token >> METHODDEFORREF_BITS);
1183                 return get_method (m, token);
1184
1185         }
1186
1187         default:
1188                 g_assert_not_reached ();
1189         }
1190         g_assert_not_reached ();
1191         return NULL;
1192 }
1193
1194 /**
1195  * get_methoddef
1196  * @m: metadata context
1197  * @idx: index into the method table
1198  *
1199  * Returns: A stringified version of the method signature.
1200  */
1201 char *
1202 get_methoddef (MonoImage *m, guint32 idx)
1203 {
1204         guint32 cols [MONO_METHOD_SIZE];
1205         char *sig;
1206         const char *name;
1207
1208         MonoMethod *mh;
1209
1210         mh = mono_get_method (m, MONO_TOKEN_METHOD_DEF | idx, NULL);
1211         if (mh) {
1212                 sig = dis_stringify_object_with_class (m, mh->klass);
1213                 name = g_strdup_printf ("%s::%s", sig, mh->name);
1214                 g_free (sig);
1215         } else
1216                 name = NULL;
1217         mono_metadata_decode_row (&m->tables [MONO_TABLE_METHOD], 
1218                         idx - 1, cols, MONO_METHOD_SIZE);
1219         sig = get_methodref_signature (m, cols [MONO_METHOD_SIGNATURE], name);
1220         
1221         return sig;
1222 }
1223
1224 /**
1225  * get_constant:
1226  * @m: metadata context
1227  * @blob_index: index into the blob where the constant is stored
1228  *
1229  * Returns: An allocated value representing a stringified version of the
1230  * constant.
1231  */
1232 char *
1233 get_constant (MonoImage *m, MonoTypeEnum t, guint32 blob_index)
1234 {
1235         const char *ptr = mono_metadata_blob_heap (m, blob_index);
1236         int len;
1237         
1238         len = mono_metadata_decode_value (ptr, &ptr);
1239         
1240         switch (t){
1241         case MONO_TYPE_BOOLEAN:
1242                 return g_strdup_printf ("%s", *ptr ? "true" : "false");
1243                 
1244         case MONO_TYPE_CHAR:
1245                 return g_strdup_printf ("%c", *ptr); /* FIXME: unicode char */
1246                 
1247         case MONO_TYPE_U1:
1248         case MONO_TYPE_I1:
1249                 return g_strdup_printf ("int8(0x%02x)", (int) (*ptr));
1250                 break;
1251                 
1252         case MONO_TYPE_U2:
1253         case MONO_TYPE_I2:
1254                 return g_strdup_printf ("int16(0x%08x)", (int) read16 (ptr));
1255                 
1256         case MONO_TYPE_U4:
1257         case MONO_TYPE_I4:
1258                 return g_strdup_printf ("int32(%d)", read32 (ptr));
1259                 
1260         case MONO_TYPE_I8: {
1261                 guint32 low, high;
1262                 low = read32 (ptr);
1263                 high = read32 (ptr + 4);
1264                 return g_strdup_printf ("0x%08x%08x", high, low);
1265         }
1266         case MONO_TYPE_U8: {
1267                 guint32 low, high;
1268                 low = read32 (ptr);
1269                 high = read32 (ptr + 4);
1270                 return g_strdup_printf ("0x%08x%08x", high, low);
1271         }
1272         case MONO_TYPE_R4: {
1273                 float r;
1274                 readr4 (ptr, &r);
1275                 return g_strdup_printf ("%g", (double) r);
1276         }
1277         case MONO_TYPE_R8: {
1278                 double r;
1279                 readr8 (ptr, &r);
1280                 return g_strdup_printf ("%g", r);
1281         }
1282         case MONO_TYPE_STRING: {
1283                 int i, j, e;
1284                 char *res;
1285                 e = len = 0;
1286                 for (i = 0; !ptr [i+1]; i += 2){
1287                         len++;
1288                         switch (ptr [i]) {
1289                         case '"':
1290                         case '\\':
1291                         case '\n': /* add more */
1292                                 e++;
1293                         }
1294                 }
1295                 res = g_malloc (len + e + 3);
1296                 j = 1;
1297                 res [0] = '"';
1298
1299                 for (i = 0; i < len; i += 2){
1300                         switch(ptr[i]) {
1301                         case '"': 
1302                                 res[j++] = '\\';
1303                                 res[j++] = '"';
1304                         case '\\': 
1305                                 res[j++] = '\\';
1306                                 res[j++] = '\\';
1307                         case '\n':
1308                                 res[j++] = '\\';
1309                                 res[j++] = 'n';
1310                                 break;
1311                         default:
1312                                 res[j++] = isprint (ptr [i]) ? ptr [i] : '.';
1313                                 break;
1314                         }
1315                 }
1316                 res[j++] = '"';
1317                 res[j] = 0;
1318                 return res;
1319         }
1320                 
1321         case MONO_TYPE_CLASS:
1322                 return g_strdup ("CLASS CONSTANT.  MUST BE ZERO");
1323                 
1324         default:
1325                 g_error ("Unknown MONO_TYPE (%d) on constant at Blob index (0x%08x)\n",
1326                          (int) *ptr, blob_index);
1327                 return g_strdup_printf ("Unknown");
1328         }
1329
1330 }
1331
1332 /**
1333  * get_token:
1334  * @m: metadata context
1335  * @token: token that we want to decode.
1336  *
1337  * Returns: An allocated value representing a stringified version of the
1338  * constant.
1339  */
1340 char *
1341 get_token (MonoImage *m, guint32 token)
1342 {
1343         guint32 idx = mono_metadata_token_index (token);
1344
1345         switch (mono_metadata_token_code (token)){
1346         case MONO_TOKEN_FIELD_DEF:
1347                 return (get_field (m, token));
1348         case MONO_TOKEN_TYPE_DEF:
1349                 return get_typedef (m, idx);
1350         case MONO_TOKEN_TYPE_REF:
1351                 return get_typeref (m, idx);
1352         case MONO_TOKEN_TYPE_SPEC:
1353                 return get_typespec (m, idx);
1354         default:                
1355                 g_error ("Do not know how to decode tokens of type 0x%08x", token);
1356         }
1357
1358         g_assert_not_reached ();
1359         return g_strdup ("ERROR");
1360 }
1361
1362 /**
1363  * get_token_type:
1364  * @m: metadata context
1365  * @token: the token can belong to any of the following tables:
1366  * MONO_TOKEN_TYPE_REF, MONO_TOKEN_TYPE_DEF, MONO_TOKEN_TYPE_SPEC
1367  *
1368  * Returns: a stringified version of the MethodDef or MethodRef or TypeSpecn
1369  * at (token & 0xffffff) 
1370  */
1371 char *
1372 get_token_type (MonoImage *m, guint32 token)
1373 {
1374         char *temp = NULL, *s;
1375         int idx;
1376
1377         idx = mono_metadata_token_index (token);
1378         
1379         switch (mono_metadata_token_code (token)){
1380         case MONO_TOKEN_TYPE_DEF:
1381                 temp = get_typedef (m, idx);
1382                 s = g_strdup_printf ("%s", temp);
1383                 break;
1384                 
1385         case MONO_TOKEN_TYPE_REF: 
1386                 temp = get_typeref (m, idx);
1387                 s = g_strdup_printf ("%s", temp);
1388                 break;
1389                 
1390         case MONO_TOKEN_TYPE_SPEC:
1391                 s = get_typespec (m, idx);
1392                 break;
1393
1394         default:
1395                 g_error ("Unhandled encoding for token 0x%08x", token);
1396
1397         }
1398         
1399         if (temp)
1400                 g_free (temp);
1401
1402         return s;
1403 }
1404
1405 char *
1406 get_guid (MonoImage *m, guint32 guid_index)
1407 {
1408         const unsigned char *guid;
1409         char *result;
1410
1411         guid = mono_metadata_guid_heap (m, guid_index);
1412
1413         result = g_strdup_printf ("{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}", 
1414                         guid [3], guid [2], guid [1], guid [0], guid [5], guid [4], guid [7], guid [6],
1415                         guid [8], guid [9], guid [10], guid [11], guid [12], guid [13], guid [14], guid [15]);
1416         return result;
1417 }
1418
1419 GList *
1420 dis_get_custom_attrs (MonoImage *m, guint32 token)
1421 {
1422         GList *list = NULL;
1423         guint32 idx, i, len, mtoken;
1424         guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1425         MonoTableInfo *ca;
1426         char *method;
1427         GString *attr;
1428         const char *val;
1429
1430         idx = mono_metadata_token_index (token);
1431         idx <<= CUSTOM_ATTR_BITS;
1432         
1433         switch (mono_metadata_token_table (token)) {
1434         case MONO_TABLE_TYPEDEF:
1435                 idx |= CUSTOM_ATTR_TYPEDEF;
1436                 break;
1437         case MONO_TABLE_ASSEMBLY:
1438                 idx |= CUSTOM_ATTR_ASSEMBLY;
1439                 break;
1440         case MONO_TABLE_PROPERTY:
1441                 idx |= CUSTOM_ATTR_PROPERTY;
1442                 break;
1443         case MONO_TABLE_EVENT:
1444                 idx |= CUSTOM_ATTR_EVENT;
1445                 break;
1446         case MONO_TABLE_FIELD:
1447                 idx |= CUSTOM_ATTR_FIELDDEF;
1448                 break;
1449         case MONO_TABLE_METHOD:
1450                 idx |= CUSTOM_ATTR_METHODDEF;
1451                 break;
1452         case MONO_TABLE_PARAM:
1453                 idx |= CUSTOM_ATTR_PARAMDEF;
1454                 break;
1455         default:
1456                 g_print ("Missing custom attr get support for token 0x%08x\n", token);
1457                 return NULL;
1458         }
1459
1460         ca = &m->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1461         /* the table is not sorted */
1462         for (i = 0; i < ca->rows; ++i) {
1463                 char *dump;
1464                 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
1465                 if (cols [MONO_CUSTOM_ATTR_PARENT] != idx)
1466                         continue;
1467                 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> CUSTOM_ATTR_TYPE_BITS;
1468                 switch (cols [MONO_CUSTOM_ATTR_TYPE] & CUSTOM_ATTR_TYPE_MASK) {
1469                 case CUSTOM_ATTR_TYPE_METHODDEF:
1470                         mtoken |= MONO_TOKEN_METHOD_DEF;
1471                         break;
1472                 case CUSTOM_ATTR_TYPE_MEMBERREF:
1473                         mtoken |= MONO_TOKEN_MEMBER_REF;
1474                         break;
1475                 default:
1476                         g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1477                         break;
1478                 }
1479                 method = get_method (m, mtoken);
1480                 val = mono_metadata_blob_heap (m, cols [MONO_CUSTOM_ATTR_VALUE]);
1481                 len = mono_metadata_decode_value (val, &val);
1482                 attr = g_string_new (".custom ");
1483                 dump = data_dump (val, len, "\t\t");
1484                 g_string_sprintfa (attr, "%s = %s", method, dump);
1485                 g_free (dump);
1486                 list = g_list_append (list, attr->str);
1487                 g_string_free (attr, FALSE);
1488                 g_free (method);
1489         }
1490         return list;
1491 }
1492
1493 char*
1494 get_marshal_info (MonoImage *m, const char *blob) {
1495         int len, size = 0;
1496
1497         len = mono_metadata_decode_blob_size (blob, &blob);
1498
1499         switch (*blob) {
1500         case MONO_NATIVE_BOOLEAN:
1501                 return g_strdup ("bool");
1502         case MONO_NATIVE_I1:
1503                 return g_strdup ("int8");
1504         case MONO_NATIVE_U1:
1505                 return g_strdup ("unsigned int8");
1506         case MONO_NATIVE_I2:
1507                 return g_strdup ("int16");
1508         case MONO_NATIVE_U2:
1509                 return g_strdup ("unsigned int16");
1510         case MONO_NATIVE_I4:
1511                 return g_strdup ("int32");
1512         case MONO_NATIVE_U4:
1513                 return g_strdup ("unsigned int32");
1514         case MONO_NATIVE_I8:
1515                 return g_strdup ("int64");
1516         case MONO_NATIVE_U8:
1517                 return g_strdup ("unsigned int64");
1518         case MONO_NATIVE_R4:
1519                 return g_strdup ("float32");
1520         case MONO_NATIVE_R8:
1521                 return g_strdup ("float64");
1522         case MONO_NATIVE_CURRENCY:
1523                 return g_strdup ("currency");
1524         case MONO_NATIVE_BSTR:
1525                 return g_strdup ("bstr");
1526         case MONO_NATIVE_LPSTR:
1527                 return g_strdup ("lpstr");
1528         case MONO_NATIVE_LPWSTR:
1529                 return g_strdup ("lpwstr");
1530         case MONO_NATIVE_LPTSTR:
1531                 return g_strdup ("lptstr");
1532         case MONO_NATIVE_BYVALTSTR:
1533                 size = mono_metadata_decode_value (blob + 1, &blob);
1534                 return g_strdup_printf ("fixed sysstring [%d]", size);
1535         case MONO_NATIVE_IUNKNOWN:
1536                 return g_strdup ("iunknown");
1537         case MONO_NATIVE_IDISPATCH:
1538                 return g_strdup ("idispatch");
1539         case MONO_NATIVE_STRUCT:
1540                 return g_strdup ("struct");
1541         case MONO_NATIVE_INTERFACE:
1542                 return g_strdup ("interface");
1543         case MONO_NATIVE_SAFEARRAY:
1544                 return g_strdup ("safearray");
1545         case MONO_NATIVE_BYVALARRAY:
1546                 size = mono_metadata_decode_value (blob + 1, &blob);
1547                 return g_strdup_printf ("fixed array [%d]", size);
1548         case MONO_NATIVE_INT:
1549                 return g_strdup ("int");
1550         case MONO_NATIVE_UINT:
1551                 return g_strdup ("unsigned int");
1552         case MONO_NATIVE_VBBYREFSTR:
1553                 return g_strdup ("vbbyrefstr");
1554         case MONO_NATIVE_ANSIBSTR:
1555                 return g_strdup ("ansi bstr");
1556         case MONO_NATIVE_TBSTR:
1557                 return g_strdup ("tbstr");
1558         case MONO_NATIVE_VARIANTBOOL:
1559                 return g_strdup ("variant bool");
1560         case MONO_NATIVE_FUNC:
1561                 return g_strdup ("method");
1562         case MONO_NATIVE_ASANY:
1563                 return g_strdup ("as any");
1564         case MONO_NATIVE_LPARRAY:
1565                 return g_strdup ("[]");
1566         case MONO_NATIVE_LPSTRUCT:
1567                 return g_strdup ("lpstruct");
1568         case MONO_NATIVE_CUSTOM:
1569                 return g_strdup ("custom");
1570         case MONO_NATIVE_ERROR:
1571                 return g_strdup ("error");
1572         default:
1573                 return g_strdup ("unknown");
1574         }
1575 }
1576