*** empty log message ***
[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
19 char *
20 get_typedef (metadata_t *m, int idx)
21 {
22         guint32 cols [6];
23
24         mono_metadata_decode_row (&m->tables [META_TABLE_TYPEDEF], idx - 1, cols, CSIZE (cols));
25
26         return g_strdup_printf (
27                 "%s.%s",
28                 mono_metadata_string_heap (m, cols [2]),
29                 mono_metadata_string_heap (m, cols [1]));
30 }
31
32 char *
33 get_module (metadata_t *m, int idx)
34 {
35         guint32 cols [5];
36         
37         /*
38          * There MUST BE only one module in the Module table
39          */
40         g_assert (idx == 1);
41             
42         mono_metadata_decode_row (&m->tables [META_TABLE_MODULEREF], idx - 1, cols, CSIZE (cols));
43
44         return g_strdup (mono_metadata_string_heap (m, cols [6]));
45 }
46
47 char *
48 get_assemblyref (metadata_t *m, int idx)
49 {
50         guint32 cols [9];
51         
52         mono_metadata_decode_row (&m->tables [META_TABLE_ASSEMBLYREF], idx - 1, cols, CSIZE (cols));
53
54         return g_strdup (mono_metadata_string_heap (m, cols [6]));
55 }
56
57 /*
58  *
59  * Returns a string representing the ArrayShape (22.2.16).
60  */
61 static const char *
62 get_array_shape (metadata_t *m, const char *ptr, char **result)
63 {
64         GString *res = g_string_new ("[");
65         guint32 rank, num_sizes, num_lo_bounds;
66         guint32 *sizes = NULL, *lo_bounds = NULL;
67         int i, r;
68         char buffer [80];
69         
70         rank = mono_metadata_decode_value (ptr, &ptr);
71         num_sizes = mono_metadata_decode_value (ptr, &ptr);
72
73         if (num_sizes > 0)
74                 sizes = g_new (guint32, num_sizes);
75         
76         for (i = 0; i < num_sizes; i++)
77                 sizes [i] = mono_metadata_decode_value (ptr, &ptr);
78
79         num_lo_bounds = mono_metadata_decode_value (ptr, &ptr);
80         if (num_lo_bounds > 0)
81                 lo_bounds = g_new (guint32, num_lo_bounds);
82         
83         for (i = 0; i < num_lo_bounds; i++)
84                 lo_bounds [i] = mono_metadata_decode_value (ptr, &ptr);
85
86         for (r = 0; r < rank; r++){
87                 if (r < num_sizes){
88                         if (r < num_lo_bounds){
89                                 sprintf (buffer, "%d..%d", lo_bounds [r], lo_bounds [r] + sizes [r] - 1);
90                         } else {
91                                 sprintf (buffer, "0..%d", sizes [r] - 1);
92                         }
93                 } else
94                         buffer [0] = 0;
95                 
96                 g_string_append (res, buffer);
97                 if ((r + 1) != rank)
98                         g_string_append (res, ", ");
99         }
100         g_string_append (res, "]");
101         
102         if (sizes)
103                 g_free (sizes);
104
105         if (lo_bounds)
106                 g_free (lo_bounds);
107
108         *result = res->str;
109         g_string_free (res, FALSE);
110
111         return ptr;
112 }
113
114 /**
115  * get_typespec:
116  * @m: metadata context
117  * @blob_idx: index into the blob heap
118  *
119  * Returns the stringified representation of a TypeSpec signature (22.2.17)
120  */
121 char *
122 get_typespec (metadata_t *m, guint32 idx)
123 {
124         guint32 cols [1];
125         const char *ptr;
126         char *s, *result;
127         GString *res = g_string_new ("");
128         int len;
129
130         mono_metadata_decode_row (&m->tables [META_TABLE_TYPESPEC], idx-1, cols, CSIZE (cols));
131         ptr = mono_metadata_blob_heap (m, cols [0]);
132         len = mono_metadata_decode_value (ptr, &ptr);
133         
134         switch (*ptr++){
135         case ELEMENT_TYPE_PTR:
136                 ptr = get_custom_mod (m, ptr, &s);
137                 if (s){
138                         g_string_append (res, s);
139                         g_string_append_c (res, ' ');
140                         g_free (s);
141                 }
142                 
143                 if (*ptr == ELEMENT_TYPE_VOID)
144                         g_string_append (res, "void");
145                 else {
146                         ptr = get_type (m, ptr, &s);
147                         if (s)
148                                 g_string_append (res, s);
149                 }
150                 break;
151                 
152         case ELEMENT_TYPE_FNPTR:
153                 g_string_append (res, "FNPTR ");
154                 /*
155                  * we assume MethodRefSig, as we do not know
156                  * whether it is a MethodDefSig or a MethodRefSig.
157                  */
158                 printf ("\n FNPTR:\n");
159                 
160                 hex_dump (ptr, 0, 40);
161                 break;
162                         
163         case ELEMENT_TYPE_ARRAY:
164                 ptr = get_type (m, ptr, &s);
165                 g_string_append (res, s);
166                 g_free (s);
167                 g_string_append_c (res, ' ');
168                 ptr = get_array_shape (m, ptr, &s);
169                 g_string_append (res, s);
170                 g_free (s);
171                 break;
172                 
173         case ELEMENT_TYPE_SZARRAY:
174                 ptr = get_custom_mod (m, ptr, &s);
175                 if (s){
176                         g_string_append (res, s);
177                         g_string_append_c (res, ' ');
178                         g_free (s);
179                 }
180                 ptr = get_type (m, ptr, &s);
181                 g_string_append (res, s);
182                 g_string_append (res, "[]");
183                 g_free (s);
184         }
185
186         result = res->str;
187         g_string_free (res, FALSE);
188
189         return result;
190 }
191
192 char *
193 get_typeref (metadata_t *m, int idx)
194 {
195         guint32 cols [3];
196         const char *s, *t;
197         char *x, *ret;
198         guint32 rs_idx, table;
199         
200         mono_metadata_decode_row (&m->tables [META_TABLE_TYPEREF], idx - 1, cols, CSIZE (cols));
201
202         t = mono_metadata_string_heap (m, cols [1]);
203         s = mono_metadata_string_heap (m, cols [2]);
204
205         rs_idx = cols [0] >> 2;
206         /*
207          * Two bits in Beta2.
208          * ECMA spec claims 3 bits
209          */
210         table = cols [0] & 3;
211         
212         switch (table){
213         case 0: /* Module */
214                 x = get_module (m, rs_idx);
215                 ret = g_strdup_printf ("TODO:TypeRef-Module [%s] %s.%s", x, s, t);
216                 g_free (x);
217                 break;
218
219         case 1: /* ModuleRef */
220                 ret = g_strdup_printf ("TODO:TypeRef-ModuleRef (%s.%s)", s, t);
221                 break;
222                               
223         case 2: /*
224                  * AssemblyRef (ECMA docs claim it is 3, but it looks to
225                  * me like it is 2 (tokens are prefixed with 0x23)
226                  */
227                 x = get_assemblyref (m, rs_idx);
228                 ret = g_strdup_printf ("[%s] %s.%s", x, s, t);
229                 g_free (x);
230                 break;
231                 
232         case 4: /* TypeRef */
233                 ret =  g_strdup_printf ("TODO:TypeRef-TypeRef: TYPEREF! (%s.%s)", s, t);
234                 break;
235                 
236         default:
237                 ret = g_strdup_printf ("Unknown table in TypeRef %d", table);
238         }
239
240         return ret;
241 }
242
243 /**
244  * get_typedef_or_ref:
245  * @m: metadata context
246  * @dor_token: def or ref encoded index
247  *
248  * Low two bits contain table to lookup from
249  * high bits contain the index into the def or ref table
250  *
251  * Returns: a stringified version of the MethodDef or MethodRef
252  * at (dor_token >> 2) 
253  */
254 char *
255 get_typedef_or_ref (metadata_t *m, guint32 dor_token)
256 {
257         char *temp = NULL, *s;
258         int table, idx;
259
260         /*
261          * low 2 bits contain encoding
262          */
263         table = dor_token & 0x03;
264         idx = dor_token >> 2;
265         
266         switch (table){
267         case 0: /* TypeDef */
268                 temp = get_typedef (m, idx);
269                 s = g_strdup_printf ("%s", temp);
270                 break;
271                 
272         case 1: /* TypeRef */
273                 temp = get_typeref (m, idx);
274                 s = g_strdup_printf ("%s", temp);
275                 break;
276                 
277         case 2: /* TypeSpec */
278                 s = get_typespec (m, idx);
279                 break;
280
281         default:
282                 g_error ("Unhandled encoding for typedef-or-ref coded index");
283
284         }
285         
286         if (temp)
287                 g_free (temp);
288
289         return s;
290 }
291
292 /** 
293  * get_encoded_typedef_or_ref:
294  * @m: metadata context 
295  * @ptr: location to decode from.
296  * @result: pointer to string where resulting decoded string is stored
297  *
298  * result will point to a g_malloc()ed string.
299  *
300  * Returns: the new ptr to continue decoding
301  */
302 const char *
303 get_encoded_typedef_or_ref (metadata_t *m, const char *ptr, char **result)
304 {
305         guint32 token;
306         
307         token = mono_metadata_decode_value (ptr, &ptr);
308
309         *result = get_typedef_or_ref (m, token);
310
311         return ptr;
312 }
313
314 /**
315  * get_custom_mod:
316  *
317  * Decodes a CustomMod (22.2.7)
318  *
319  * Returns: updated pointer location
320  */
321 const char *
322 get_custom_mod (metadata_t *m, const char *ptr, char **return_value)
323 {
324         char *s;
325         
326         if ((*ptr == ELEMENT_TYPE_CMOD_OPT) ||
327             (*ptr == ELEMENT_TYPE_CMOD_REQD)){
328                 ptr++;
329                 ptr = get_encoded_typedef_or_ref (m, ptr, &s);
330
331                 *return_value = g_strconcat ("CMOD ", s, NULL);
332                 g_free (s);
333         } else
334                 *return_value = NULL;
335         return ptr;
336 }
337
338
339 static map_t element_type_map [] = {
340         { ELEMENT_TYPE_END        , "end" },
341         { ELEMENT_TYPE_VOID       , "void" },
342         { ELEMENT_TYPE_BOOLEAN    , "bool" },
343         { ELEMENT_TYPE_CHAR       , "char" }, 
344         { ELEMENT_TYPE_I1         , "sbyte" },
345         { ELEMENT_TYPE_U1         , "byte" }, 
346         { ELEMENT_TYPE_I2         , "int16" },
347         { ELEMENT_TYPE_U2         , "uint16" },
348         { ELEMENT_TYPE_I4         , "int32" },
349         { ELEMENT_TYPE_U4         , "uint32" },
350         { ELEMENT_TYPE_I8         , "int64" },
351         { ELEMENT_TYPE_U8         , "uint64" },
352         { ELEMENT_TYPE_R4         , "float32" },
353         { ELEMENT_TYPE_R8         , "float64" },
354         { ELEMENT_TYPE_STRING     , "string" },
355         { ELEMENT_TYPE_TYPEDBYREF , "TypedByRef" },
356         { ELEMENT_TYPE_I          , "native int" },
357         { ELEMENT_TYPE_U          , "native unsigned int" },
358         { ELEMENT_TYPE_OBJECT     , "object" },
359         { 0, NULL }
360 };
361
362 static map_t call_conv_type_map [] = {
363         { MONO_CALL_DEFAULT     , "default" },
364         { MONO_CALL_C           , "c" },
365         { MONO_CALL_STDCALL     , "stdcall" },
366         { MONO_CALL_THISCALL    , "thiscall" },
367         { MONO_CALL_FASTCALL    , "fastcall" },
368         { MONO_CALL_VARARG      , "vararg" },
369         { 0, NULL }
370 };
371
372 char*
373 dis_stringify_token (metadata_t *m, guint32 token)
374 {
375         guint idx = token & 0xffffff;
376         switch (token >> 24) {
377         case META_TABLE_TYPEDEF: return get_typedef (m, idx);
378         case META_TABLE_TYPEREF: return get_typeref (m, idx);
379         case META_TABLE_TYPESPEC: return get_typespec (m, idx);
380         default:
381                  break;
382         }
383         return g_strdup_printf("0x%08x", token);
384 }
385
386 char*
387 dis_stringify_array (metadata_t *m, MonoArray *array) 
388 {
389         char *type;
390         GString *s = g_string_new("");
391         int i;
392         
393         type = dis_stringify_type (m, array->type);
394         g_string_append (s, type);
395         g_free (type);
396         g_string_append_c (s, '[');
397         for (i = 0; i < array->rank; ++i) {
398                 if (i)
399                         g_string_append_c (s, ',');
400                 if (i < array->numsizes) {
401                         if (i < array->numlobounds && array->lobounds[i] != 0)
402                                 g_string_sprintfa (s, "%d..%d", array->lobounds[i], array->sizes[i]);
403                         else
404                                 g_string_sprintfa (s, "%d", array->sizes[i]);
405                 }
406         }
407         g_string_append_c (s, ']');
408         type = s->str;
409         g_string_free (s, FALSE);
410         return type;
411 }
412
413 char*
414 dis_stringify_modifiers (metadata_t *m, int n, MonoCustomMod *mod)
415 {
416         GString *s = g_string_new("");
417         char *result;
418         int i;
419         for (i = 0; i < n; ++i) {
420                 char *tok = dis_stringify_token (m, mod[i].token);
421                 g_string_sprintfa (s, "%s %s", mod[i].mod == ELEMENT_TYPE_CMOD_OPT ? "opt": "reqd", tok);
422                 g_free (tok);
423         }
424         g_string_append_c (s, ' ');
425         result = s->str;
426         g_string_free (s, FALSE);
427         return result;
428 }
429
430 char*
431 dis_stringify_param (metadata_t *m, MonoParam *param) 
432 {
433         char *mods = NULL;
434         char *t;
435         char *result;
436         if (param->num_modifiers)
437                 mods = dis_stringify_modifiers (m, param->num_modifiers, param->modifiers);
438         if (param->typedbyref)
439                 t = g_strdup ("TypedByRef");
440         else if (!param->type)
441                 t = g_strdup ("void");
442         else
443                 t = dis_stringify_type (m, param->type);
444         result = g_strjoin (mods ? mods : "", t, NULL);
445         g_free (t);
446         g_free (mods);
447         return result;
448 }
449
450 char*
451 dis_stringify_method_signature (metadata_t *m, MonoMethodSignature *method)
452 {
453         return g_strdup ("method-signature");
454 }
455
456 char*
457 dis_stringify_type (metadata_t *m, MonoType *type)
458 {
459         char *bare = NULL;
460         char *byref;
461         char *result;
462
463         if (!type)
464                 return g_strdup ("void");
465
466         byref = type->byref ? "ref " : "";
467
468         switch (type->type){
469         case ELEMENT_TYPE_BOOLEAN:
470         case ELEMENT_TYPE_CHAR:
471         case ELEMENT_TYPE_I1:
472         case ELEMENT_TYPE_U1:
473         case ELEMENT_TYPE_I2:
474         case ELEMENT_TYPE_U2:
475         case ELEMENT_TYPE_I4:
476         case ELEMENT_TYPE_U4:
477         case ELEMENT_TYPE_I8:
478         case ELEMENT_TYPE_U8:
479         case ELEMENT_TYPE_R4:
480         case ELEMENT_TYPE_R8:
481         case ELEMENT_TYPE_I:
482         case ELEMENT_TYPE_U:
483         case ELEMENT_TYPE_STRING:
484         case ELEMENT_TYPE_OBJECT:
485         case ELEMENT_TYPE_TYPEDBYREF:
486                 bare = g_strdup (map (type->type, element_type_map));
487                 break;
488                 
489         case ELEMENT_TYPE_VALUETYPE:
490         case ELEMENT_TYPE_CLASS:
491                 bare = dis_stringify_token (m, type->data.token);
492                 break;
493                 
494         case ELEMENT_TYPE_FNPTR:
495                 bare = dis_stringify_method_signature (m, type->data.method);
496                 break;
497         case ELEMENT_TYPE_PTR:
498         case ELEMENT_TYPE_SZARRAY: {
499                 char *child_type;
500                 char *mods;
501                 if (type->custom_mod) {
502                         mods = dis_stringify_modifiers (m, type->data.mtype->num_modifiers, type->data.mtype->modifiers);       
503                         child_type = dis_stringify_type (m, type->data.mtype->type);
504                 } else {
505                         mods = g_strdup("");
506                         child_type = dis_stringify_type (m, type->data.type);
507                 }
508                 
509                 bare = g_strdup_printf (type->type == ELEMENT_TYPE_PTR ? "%s%s*" : "%s%s[]", mods, child_type);
510                 g_free (child_type);
511                 g_free (mods);
512                 break;
513         }
514         case ELEMENT_TYPE_ARRAY:
515                 bare = dis_stringify_array (m, type->data.array);
516                 break;
517         default:
518                 g_error ("Do not know how to stringify type 0x%x", type->type);
519         }
520
521         result = g_strjoin (byref, bare, NULL);
522         g_free (bare);
523         return result;
524 }
525
526 /**
527  * get_type:
528  * @m: metadata context 
529  * @ptr: location to decode from.
530  * @result: pointer to string where resulting decoded string is stored
531  *
532  * This routine returs in @result the stringified type pointed by @ptr.
533  * (22.2.12)
534  *
535  * Returns: the new ptr to continue decoding
536  */
537 const char *
538 get_type (metadata_t *m, const char *ptr, char **result)
539 {
540         MonoType *type = mono_metadata_parse_type (m, ptr, &ptr);
541         *result = dis_stringify_type (m, type);
542         mono_metadata_free_type (type);
543         return ptr;
544 }
545
546 /**
547  * 
548  * Returns a stringified representation of a FieldSig (22.2.4)
549  */
550 char *
551 get_field_signature (metadata_t *m, guint32 blob_signature)
552 {
553         char *allocated_modifier_string, *allocated_type_string;
554         const char *ptr = mono_metadata_blob_heap (m, blob_signature);
555         const char *base;
556         char *res;
557         int len;
558         
559         len = mono_metadata_decode_value (ptr, &ptr);
560         base = ptr;
561         /* FIELD is 0x06 */
562         g_assert (*ptr == 0x06);
563 /*      hex_dump (ptr, 0, len); */
564         ptr++; len--;
565         
566         ptr = get_custom_mod (m, ptr, &allocated_modifier_string);
567         ptr = get_type (m, ptr, &allocated_type_string);
568
569         res = g_strdup_printf (
570                 "%s %s",
571                 allocated_modifier_string ? allocated_modifier_string : "",
572                 allocated_type_string);
573         
574         if (allocated_modifier_string)
575                 g_free (allocated_modifier_string);
576         if (allocated_type_string)
577                 g_free (allocated_modifier_string);
578         
579         return res;
580 }
581
582 ElementTypeEnum
583 get_field_literal_type (metadata_t *m, guint32 blob_signature)
584 {
585         const char *ptr = mono_metadata_blob_heap (m, blob_signature);
586         int len;
587         char *allocated_modifier_string;
588         
589         len = mono_metadata_decode_value (ptr, &ptr);
590
591         /* FIELD is 0x06 */
592         g_assert (*ptr == 0x06);
593         ptr++; len--;
594         
595         ptr = get_custom_mod (m, ptr, &allocated_modifier_string);
596         if (allocated_modifier_string)
597                 g_free (allocated_modifier_string);
598
599         return (ElementTypeEnum) *ptr;
600         
601 }
602
603 /**
604  * decode_literal:
605  * @m: metadata context
606  * @token: token to decode
607  *
608  * decodes the literal indexed by @token.
609  */
610 char *
611 decode_literal (metadata_t *m, guint32 token)
612 {
613         return g_strdup ("LITERAL_VALUE");
614 }
615
616 /**
617  * get_ret_type:
618  * @m: metadata context 
619  * @ptr: location to decode from.
620  * @result: pointer to string where resulting decoded string is stored
621  *
622  * This routine returns in @result the stringified RetType (22.2.11)
623  *
624  * Returns: the new ptr to continue decoding.
625  */
626 const char *
627 get_ret_type (metadata_t *m, const char *ptr, char **ret_type)
628 {
629         GString *str = g_string_new ("");
630         char *mod = NULL;
631         char *allocated_type_string;
632         
633         ptr = get_custom_mod (m, ptr, &mod);
634         if (mod){
635                 g_string_append (str, mod);
636                 g_string_append_c (str, ' ');
637                 g_free (mod);
638         }
639
640         if (*ptr == ELEMENT_TYPE_TYPEDBYREF){
641                 /* TODO: what does `typedbyref' mean? */
642                 g_string_append (str, "/* FIXME: What does this mean? */ typedbyref ");
643                 ptr++;
644         } else if (*ptr == ELEMENT_TYPE_VOID){
645                  g_string_append (str, "void");
646                  ptr++;
647         } else {
648                 if (*ptr == ELEMENT_TYPE_BYREF){
649                         g_string_append (str, "[out] ");
650                         ptr++;
651                 }
652
653                 ptr = get_type (m, ptr, &allocated_type_string);
654                 g_string_append (str, allocated_type_string);
655                 g_free (allocated_type_string);
656         }
657
658         *ret_type = str->str;
659         g_string_free (str, FALSE);
660
661         return ptr;
662 }
663
664 /**
665  * get_param:
666  * @m: metadata context 
667  * @ptr: location to decode from.
668  * @result: pointer to string where resulting decoded string is stored
669  *
670  * This routine returns in @result the stringified Param (22.2.10)
671  *
672  * Returns: the new ptr to continue decoding.
673  */
674 const char *
675 get_param (metadata_t *m, const char *ptr, char **retval)
676 {
677         GString *str = g_string_new ("");
678         char *allocated_mod_string, *allocated_type_string;
679         
680         ptr = get_custom_mod (m, ptr, &allocated_mod_string);
681         if (allocated_mod_string){
682                 g_string_append (str, allocated_mod_string);
683                 g_string_append_c (str, ' ');
684                 g_free (allocated_mod_string);
685         }
686         
687         if (*ptr == ELEMENT_TYPE_TYPEDBYREF){
688                 g_string_append (str, "/*FIXME: what does typedbyref mean? */ typedbyref ");
689                 ptr++;
690         } else {
691                 if (*ptr == ELEMENT_TYPE_BYREF){
692                         g_string_append (str, "[out] ");
693                         ptr++;
694                 }
695                 ptr = get_type (m, ptr, &allocated_type_string);
696                 g_string_append (str, allocated_type_string);
697                 g_free (allocated_type_string);
698         }
699
700         *retval = str->str;
701         g_string_free (str, FALSE);
702         return ptr;
703 }
704
705 static map_t param_map [] = {
706         { PARAM_ATTRIBUTE_IN,                "[in] " },
707         { PARAM_ATTRIBUTE_OUT,               "[out] " },
708         { PARAM_ATTRIBUTE_OPTIONAL,          "optional " },
709         { PARAM_ATTRIBUTE_HAS_DEFAULT,       "hasdefault " },
710         { PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL, "fieldmarshal " },
711         { 0, NULL }
712 };
713
714 char *
715 param_flags (guint32 f)
716 {
717         return g_strdup (flags (f, param_map));
718 }
719
720 static map_t field_access_map [] = {
721         { FIELD_ATTRIBUTE_COMPILER_CONTROLLED, "compilercontrolled " },
722         { FIELD_ATTRIBUTE_PRIVATE,             "private " },
723         { FIELD_ATTRIBUTE_FAM_AND_ASSEM,       "famandassem " },
724         { FIELD_ATTRIBUTE_ASSEMBLY,            "assembly " },
725         { FIELD_ATTRIBUTE_FAMILY,              "family " },
726         { FIELD_ATTRIBUTE_FAM_OR_ASSEM,        "famorassem " },
727         { FIELD_ATTRIBUTE_PUBLIC,              "public " },
728         { 0, NULL }
729 };
730
731 static map_t field_flags_map [] = {
732         { FIELD_ATTRIBUTE_STATIC,              "static " },
733         { FIELD_ATTRIBUTE_INIT_ONLY,           "initonly " },
734         { FIELD_ATTRIBUTE_LITERAL,             "literal " },
735         { FIELD_ATTRIBUTE_NOT_SERIALIZED,      "notserialized " },
736         { FIELD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
737         { FIELD_ATTRIBUTE_PINVOKE_IMPL,        "FIXME:pinvokeimpl " },
738         { 0, NULL }
739 };
740
741 /**
742  * field_flags:
743  *
744  * Returns a stringified version of a Field's flags
745  */
746 char *
747 field_flags (guint32 f)
748 {
749         static char buffer [1024];
750         int access = f & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
751         
752         buffer [0] = 0;
753
754         strcat (buffer, map (access, field_access_map));
755         strcat (buffer, flags (f, field_flags_map));
756         return g_strdup (buffer);
757 }
758
759 /**
760  * Returns a stringifed representation of a MethodRefSig (22.2.2)
761  */
762 char *
763 get_methodref_signature (metadata_t *m, guint32 blob_signature, const char *fancy_name)
764 {
765         GString *res = g_string_new ("");
766         const char *ptr = mono_metadata_blob_heap (m, blob_signature);
767         char *allocated_ret_type, *s;
768         gboolean seen_vararg = 0;
769         int param_count, signature_len;
770         int i;
771         
772         signature_len = mono_metadata_decode_value (ptr, &ptr);
773
774         if (*ptr & 0x20){
775                 if (*ptr & 0x40)
776                         g_string_append (res, "explicit-this ");
777                 else
778                         g_string_append (res, "instance "); /* has-this */
779         }
780
781         if (*ptr & 0x05)
782                 seen_vararg = 1;
783
784         ptr++;
785         param_count = mono_metadata_decode_value (ptr, &ptr);
786         ptr = get_ret_type (m, ptr, &allocated_ret_type);
787
788         g_string_append (res, allocated_ret_type);
789
790         if (fancy_name){
791                 g_string_append_c (res, ' ');
792                 g_string_append (res, fancy_name);
793         }
794         
795         g_string_append (res, " (");
796         
797         /*
798          * param_count describes parameters *before* and *after*
799          * the vararg sentinel
800          */
801         for (i = 0; i < param_count; i++){
802                 char *param = NULL;
803                 
804                 /*
805                  * If ptr is a SENTINEL
806                  */
807                 if (*ptr == 0x41){
808                         g_string_append (res, " varargs ");
809                         continue;
810                 }
811
812                 ptr = get_param (m, ptr, &param);
813                 g_string_append (res, param);
814                 if (i+1 != param_count)
815                         g_string_append (res, ", ");
816                 g_free (param);
817         }
818         g_string_append (res, ")");
819         
820         /*
821          * cleanup and return
822          */
823         g_free (allocated_ret_type);
824         s = res->str;
825         g_string_free (res, FALSE);
826         return s;
827 }
828
829 /**
830  * get_field:
831  * @m: metadata context
832  * @token: a FIELD_DEF token
833  *
834  * This routine has to locate the TypeDef that "owns" this Field.
835  * Since there is no backpointer in the Field table, we have to scan
836  * the TypeDef table and locate the actual "owner" of the field
837  */
838 char *
839 get_field (metadata_t *m, guint32 token)
840 {
841         int idx = mono_metadata_token_index (token);
842         metadata_tableinfo_t *tdef = &m->tables [META_TABLE_TYPEDEF];
843         guint32 cols [3];
844         char *sig, *res, *type;
845         guint32 type_idx;
846
847         /*
848          * We can get here also with a MenberRef token (for a field
849          * defined in another module/assembly, just like in get_method ()
850          */
851         if (mono_metadata_token_code (token) == TOKEN_TYPE_MEMBER_REF) {
852                 return g_strdup_printf ("fieldref-0x%08x", token);
853         }
854         g_assert (mono_metadata_token_code (token) == TOKEN_TYPE_FIELD_DEF);
855
856         mono_metadata_decode_row (&m->tables [META_TABLE_FIELD], idx - 1, cols, CSIZE (cols));
857         sig = get_field_signature (m, cols [2]);
858
859         /*
860          * To locate the actual "container" for this field, we have to scan
861          * the TypeDef table.  LAME!
862          */
863         type_idx = mono_metadata_typedef_from_field (m, idx);
864
865         type = get_typedef (m, type_idx);
866         res = g_strdup_printf ("%s %s.%s",
867                                sig, type,
868                                mono_metadata_string_heap (m, cols [1]));
869         g_free (type);
870         g_free (sig);
871
872         return res;
873 }
874
875 static char *
876 get_memberref_parent (metadata_t *m, guint32 mrp_token)
877 {
878         /*
879          * mrp_index is a MemberRefParent coded index
880          */
881         guint32 table = mrp_token & 7;
882         guint32 idx = mrp_token >> 3;
883
884         switch (table){
885         case 0: /* TypeDef */
886                 return get_typedef (m, idx);
887                 
888         case 1: /* TypeRef */
889                 return get_typeref (m, idx);
890                 
891         case 2: /* ModuleRef */
892                 return g_strdup_printf ("TODO:MemberRefParent-ModuleRef");
893                 
894         case 3: /* MethodDef */
895                 return g_strdup ("TODO:MethodDef");
896                 
897         case 4: /* TypeSpec */
898                 return get_typespec (m, idx);
899         }
900         g_assert_not_reached ();
901         return NULL;
902 }
903
904 /**
905  * get_method:
906  * @m: metadata context
907  * @token: a METHOD_DEF or MEMBER_REF token
908  *
909  * This routine has to locate the TypeDef that "owns" this Field.
910  * Since there is no backpointer in the Field table, we have to scan
911  * the TypeDef table and locate the actual "owner" of the field
912  */
913 char *
914 get_method (metadata_t *m, guint32 token)
915 {
916         int idx = mono_metadata_token_index (token);
917         guint32 member_cols [3], method_cols [6];
918         char *res, *class, *fancy_name, *sig;
919         
920         switch (mono_metadata_token_code (token)){
921         case TOKEN_TYPE_METHOD_DEF:
922
923                 mono_metadata_decode_row (&m->tables [META_TABLE_METHOD], 
924                                           idx - 1, method_cols, 6);
925
926                 fancy_name = mono_metadata_string_heap (m, method_cols [3]);
927
928                 sig = get_methodref_signature (m, method_cols [4], fancy_name);
929
930                 return sig;
931                 
932         case TOKEN_TYPE_MEMBER_REF: {
933                 
934                 mono_metadata_decode_row (&m->tables [META_TABLE_MEMBERREF],
935                                           idx - 1, member_cols,
936                                           CSIZE (member_cols));
937                 class = get_memberref_parent (m, member_cols [0]);
938                 fancy_name = g_strconcat (
939                         class, "::",
940                         mono_metadata_string_heap (m, member_cols [1]),
941                         NULL);
942                 
943                 sig = get_methodref_signature (
944                         m, member_cols [2], fancy_name);
945                 g_free (fancy_name);
946
947                 res = g_strdup_printf ("%s", sig);
948                 g_free (sig);
949                 return res;
950         }
951                 
952         default:
953                 g_assert_not_reached ();
954         }
955         g_assert_not_reached ();
956         return NULL;
957 }
958
959 /**
960  * get_constant:
961  * @m: metadata context
962  * @blob_index: index into the blob where the constant is stored
963  *
964  * Returns: An allocated value representing a stringified version of the
965  * constant.
966  */
967 char *
968 get_constant (metadata_t *m, ElementTypeEnum t, guint32 blob_index)
969 {
970         const char *ptr = mono_metadata_blob_heap (m, blob_index);
971         int len;
972         
973         len = mono_metadata_decode_value (ptr, &ptr);
974         
975         switch (t){
976         case ELEMENT_TYPE_BOOLEAN:
977                 return g_strdup_printf ("%s", *ptr ? "true" : "false");
978                 
979         case ELEMENT_TYPE_CHAR:
980                 return g_strdup_printf ("%c", *ptr);
981                 
982         case ELEMENT_TYPE_U1:
983                 return g_strdup_printf ("0x%02x", (int) (*ptr));
984                 break;
985                 
986         case ELEMENT_TYPE_I2:
987                 return g_strdup_printf ("%d", (int) (*(gint16 *) ptr));
988                 
989         case ELEMENT_TYPE_I4:
990                 return g_strdup_printf ("%d", *(gint32 *) ptr);
991                 
992         case ELEMENT_TYPE_I8:
993                 /*
994                  * FIXME: This is not endian portable, does only 
995                  * matter for debugging, but still.
996                  */
997                 return g_strdup_printf ("0x%08x%08x", *(guint32 *) ptr, *(guint32 *) (ptr + 4));
998                 
999         case ELEMENT_TYPE_U8:
1000                 return g_strdup_printf ("0x%08x%08x", *(guint32 *) ptr, *(guint32 *) (ptr + 4));                
1001         case ELEMENT_TYPE_R4:
1002                 return g_strdup_printf ("%g", (double) (* (float *) ptr));
1003                 
1004         case ELEMENT_TYPE_R8:
1005                 return g_strdup_printf ("%g", * (double *) ptr);
1006                 
1007         case ELEMENT_TYPE_STRING: {
1008                 int len, i, j, e;
1009                 char *res;
1010                 e = len = 0;
1011                 for (i = 0; !ptr [i+1]; i += 2){
1012                         len++;
1013                         switch (ptr [i]) {
1014                         case '"':
1015                         case '\\':
1016                         case '\n': /* add more */
1017                                 e++;
1018                         }
1019                 }
1020                 res = g_malloc (len + e + 3);
1021                 j = 1;
1022                 res [0] = '"';
1023
1024                 for (i = 0; i < len; i += 2){
1025                         switch(ptr[i]) {
1026                         case '"': 
1027                                 res[j++] = '\\';
1028                                 res[j++] = '"';
1029                         case '\\': 
1030                                 res[j++] = '\\';
1031                                 res[j++] = '\\';
1032                         case '\n':
1033                                 res[j++] = '\\';
1034                                 res[j++] = 'n';
1035                                 break;
1036                         default:
1037                                 res[j++] = isprint (ptr [i]) ? ptr [i] : '.';
1038                                 break;
1039                         }
1040                 }
1041                 res[j++] = '"';
1042                 res[j] = 0;
1043                 return res;
1044         }
1045                 
1046         case ELEMENT_TYPE_CLASS:
1047                 return g_strdup ("CLASS CONSTANT.  MUST BE ZERO");
1048                 
1049                 /*
1050                  * These are non CLS compliant:
1051                  */
1052         case ELEMENT_TYPE_I1:
1053                 return g_strdup_printf ("%d", (int) *ptr);
1054
1055         case ELEMENT_TYPE_U2:
1056                 return g_strdup_printf ("0x%04x", (unsigned int) (*(guint16 *) ptr));
1057                 
1058         case ELEMENT_TYPE_U4:
1059                 return g_strdup_printf ("0x%04x", (unsigned int) (*(guint32 *) ptr));
1060                 
1061         default:
1062                 g_error ("Unknown ELEMENT_TYPE (%d) on constant at Blob index (0x%08x)\n",
1063                          (int) *ptr, blob_index);
1064                 return g_strdup_printf ("Unknown");
1065         }
1066
1067 }
1068
1069 /**
1070  * get_token:
1071  * @m: metadata context
1072  * @token: token that we want to decode.
1073  *
1074  * Returns: An allocated value representing a stringified version of the
1075  * constant.
1076  */
1077 char *
1078 get_token (metadata_t *m, guint32 token)
1079 {
1080         switch (mono_metadata_token_code (token)){
1081         case TOKEN_TYPE_FIELD_DEF:
1082                 return (get_field (m, token));
1083                 
1084         default:
1085                 g_error ("Do not know how to decode tokens of type 0x%08x", token);
1086         }
1087
1088         g_assert_not_reached ();
1089         return g_strdup ("ERROR");
1090 }
1091
1092 /**
1093  * get_token_type:
1094  * @m: metadata context
1095  * @token: the token can belong to any of the following tables:
1096  * TOKEN_TYPE_TYPE_REF, TOKEN_TYPE_TYPE_DEF, TOKEN_TYPE_TYPE_SPEC
1097  *
1098  * Returns: a stringified version of the MethodDef or MethodRef or TypeSpecn
1099  * at (token & 0xffffff) 
1100  */
1101 char *
1102 get_token_type (metadata_t *m, guint32 token)
1103 {
1104         char *temp = NULL, *s;
1105         int idx;
1106
1107         idx = mono_metadata_token_index (token);
1108         
1109         switch (mono_metadata_token_code (token)){
1110         case TOKEN_TYPE_TYPE_DEF:
1111                 temp = get_typedef (m, idx);
1112                 s = g_strdup_printf ("%s", temp);
1113                 break;
1114                 
1115         case TOKEN_TYPE_TYPE_REF: 
1116                 temp = get_typeref (m, idx);
1117                 s = g_strdup_printf ("%s", temp);
1118                 break;
1119                 
1120         case TOKEN_TYPE_TYPE_SPEC:
1121                 s = get_typespec (m, idx);
1122                 break;
1123
1124         default:
1125                 g_error ("Unhandled encoding for typedef-or-ref coded index");
1126
1127         }
1128         
1129         if (temp)
1130                 g_free (temp);
1131
1132         return s;
1133 }