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