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