Tue Aug 22 15:53:29 CEST 2006 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / dis / get.c
index 0142d90ed9f9600b2f3e39f26dcc9f876cc63de1..4386b66cb462d5692bfa6ec8ecc4c8e5b4e77e4f 100644 (file)
 #include <string.h>
 #include <ctype.h>
 #include <glib.h>
+#include <math.h>
 #include "meta.h"
 #include "util.h"
 #include "get.h"
+#include <mono/utils/mono-compiler.h>
 #include <mono/metadata/class.h>
 #include <mono/metadata/marshal.h>
 
@@ -25,8 +27,13 @@ get_memberref_context (MonoImage *m, guint32 mrp_token, MonoGenericContext *cont
 
 static char *
 get_memberref_parent (MonoImage *m, guint32 mrp_token, MonoGenericContext *context);
+static gboolean
+cant_print_generic_param_name (MonoGenericParam *gparam);
 
 GHashTable *key_table = NULL;
+GHashTable *mono_generic_params_with_ambiguous_names = NULL;
+GHashTable *generic_containers = NULL;
 gboolean show_method_tokens = FALSE;
 gboolean show_tokens = FALSE;
 
@@ -38,6 +45,10 @@ get_typedef (MonoImage *m, int idx)
        char *tstring, *result;
         guint32 token;
         
+       if (idx == 1)
+               /* <Module> */
+               return NULL;
+
        mono_metadata_decode_row (&m->tables [MONO_TABLE_TYPEDEF], idx - 1, cols, MONO_TYPEDEF_SIZE);
 
         ns = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE]);
@@ -81,7 +92,7 @@ get_module (MonoImage *m, int idx)
            
        mono_metadata_decode_row (&m->tables [MONO_TABLE_MODULE], idx - 1, cols, MONO_MODULE_SIZE);
 
-       return g_strdup (mono_metadata_string_heap (m, cols [MONO_MODULE_NAME]));
+       return get_escaped_name (mono_metadata_string_heap (m, cols [MONO_MODULE_NAME]));
 }
 
 char *
@@ -91,7 +102,7 @@ get_moduleref (MonoImage *m, int idx)
        
        mono_metadata_decode_row (&m->tables [MONO_TABLE_MODULEREF], idx - 1, cols, MONO_MODULEREF_SIZE);
 
-       return g_strdup (mono_metadata_string_heap (m, cols [MONO_MODULEREF_NAME]));
+       return get_escaped_name (mono_metadata_string_heap (m, cols [MONO_MODULEREF_NAME]));
 }
 
 char *
@@ -101,7 +112,31 @@ get_assemblyref (MonoImage *m, int idx)
        
        mono_metadata_decode_row (&m->tables [MONO_TABLE_ASSEMBLYREF], idx - 1, cols, MONO_ASSEMBLYREF_SIZE);
 
-       return g_strdup (mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_NAME]));
+       return get_escaped_name (mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_NAME]));
+}
+
+static char *
+stringify_array (guint32 rank, guint32 num_sizes, guint32 num_lo_bounds, gint32 *sizes, gint32 *lo_bounds)
+{
+       GString *res = g_string_new ("[");
+       int i;
+
+       for (i = 0; i < rank; i++) {
+               if (i)
+                       g_string_append_c (res, ',');
+               if (i < num_lo_bounds)
+                       g_string_sprintfa (res, "%d...", lo_bounds [i]);
+               if (i < num_sizes) {
+                       if (i < num_lo_bounds)
+                               g_string_sprintfa (res, "%d", lo_bounds [i] + sizes [i] - 1);
+                       else
+                               g_string_sprintfa (res, "%d", sizes [i]);
+               }
+
+       }
+       g_string_append (res, "]");
+
+       return g_string_free (res, FALSE);
 }
 
 /*
@@ -111,52 +146,30 @@ get_assemblyref (MonoImage *m, int idx)
 static const char *
 get_array_shape (MonoImage *m, const char *ptr, char **result)
 {
-       GString *res = g_string_new ("[");
        guint32 rank, num_sizes, num_lo_bounds;
-       guint32 *sizes = NULL, *lo_bounds = NULL;
-       int i, r;
-       char buffer [80];
+       gint32 *sizes = NULL, *lo_bounds = NULL;
+       int i;
        
        rank = mono_metadata_decode_value (ptr, &ptr);
        num_sizes = mono_metadata_decode_value (ptr, &ptr);
 
        if (num_sizes > 0)
-               sizes = g_new (guint32, num_sizes);
+               sizes = g_new (gint32, num_sizes);
        
        for (i = 0; i < num_sizes; i++)
                sizes [i] = mono_metadata_decode_value (ptr, &ptr);
 
        num_lo_bounds = mono_metadata_decode_value (ptr, &ptr);
        if (num_lo_bounds > 0)
-               lo_bounds = g_new (guint32, num_lo_bounds);
+               lo_bounds = g_new (gint32, num_lo_bounds);
        
        for (i = 0; i < num_lo_bounds; i++)
-               lo_bounds [i] = mono_metadata_decode_value (ptr, &ptr);
-
-       for (r = 0; r < rank; r++){
-               if (r < num_sizes){
-                       if (r < num_lo_bounds){
-                               sprintf (buffer, "%d..%d", lo_bounds [r], lo_bounds [r] + sizes [r] - 1);
-                       } else {
-                               sprintf (buffer, "0..%d", sizes [r] - 1);
-                       }
-               } else
-                       buffer [0] = 0;
-               
-               g_string_append (res, buffer);
-               if ((r + 1) != rank)
-                       g_string_append (res, ", ");
-       }
-       g_string_append (res, "]");
-       
-       if (sizes)
-               g_free (sizes);
+               lo_bounds [i] = mono_metadata_decode_signed_value (ptr, &ptr);
 
-       if (lo_bounds)
-               g_free (lo_bounds);
+       *result = stringify_array (rank, num_sizes, num_lo_bounds, sizes, lo_bounds);
 
-       *result = res->str;
-       g_string_free (res, FALSE);
+       g_free (sizes);
+       g_free (lo_bounds);
 
        return ptr;
 }
@@ -176,15 +189,12 @@ get_typespec (MonoImage *m, guint32 idx, gboolean is_def, MonoGenericContext *co
        char *s, *result;
        GString *res = g_string_new ("");
        int len;
-
-       MonoType *type;
-
-       type = mono_type_create_from_typespec_full (m, context, idx);
+       MonoMethodSignature *sig;
 
        mono_metadata_decode_row (&m->tables [MONO_TABLE_TYPESPEC], idx-1, cols, MONO_TYPESPEC_SIZE);
        ptr = mono_metadata_blob_heap (m, cols [MONO_TYPESPEC_SIGNATURE]);
        len = mono_metadata_decode_value (ptr, &ptr);
-       
+
        switch (*ptr++){
        case MONO_TYPE_PTR:
                ptr = get_custom_mod (m, ptr, &s);
@@ -193,26 +203,27 @@ get_typespec (MonoImage *m, guint32 idx, gboolean is_def, MonoGenericContext *co
                        g_string_append_c (res, ' ');
                        g_free (s);
                }
-               
+
                if (*ptr == MONO_TYPE_VOID)
                        g_string_append (res, "void");
                else {
-                       ptr = get_type (m, ptr, &s, context);
+                       ptr = get_type (m, ptr, &s, is_def, context);
                        if (s)
                                g_string_append (res, s);
                }
                g_string_append (res, "*");
                break;
-               
+
        case MONO_TYPE_FNPTR:
-               s = dis_stringify_function_ptr (m, type->data.method);
+               sig = mono_metadata_parse_method_signature_full (m, context ? context->container : NULL, 0, ptr, &ptr);
+               s = dis_stringify_function_ptr (m, sig);
                g_string_append (res, "method ");
                g_string_append (res, s);
                g_free (s);
                break;
-                       
+
        case MONO_TYPE_ARRAY:
-               ptr = get_type (m, ptr, &s, context);
+               ptr = get_type (m, ptr, &s, is_def, context);
                g_string_append (res, s);
                g_free (s);
                g_string_append_c (res, ' ');
@@ -220,7 +231,7 @@ get_typespec (MonoImage *m, guint32 idx, gboolean is_def, MonoGenericContext *co
                g_string_append (res, s);
                g_free (s);
                break;
-               
+
        case MONO_TYPE_SZARRAY:
                ptr = get_custom_mod (m, ptr, &s);
                if (s){
@@ -228,14 +239,14 @@ get_typespec (MonoImage *m, guint32 idx, gboolean is_def, MonoGenericContext *co
                        g_string_append_c (res, ' ');
                        g_free (s);
                }
-               ptr = get_type (m, ptr, &s, context);
+               ptr = get_type (m, ptr, &s, is_def, context);
                g_string_append (res, s);
                g_string_append (res, "[]");
                g_free (s);
                break;
 
        default:
-               s = dis_stringify_type (m, type, is_def);
+               ptr = get_type (m, ptr - 1, &s, is_def, context);
                g_string_append (res, s);
                g_free (s);
                break;
@@ -410,19 +421,19 @@ const char *
 get_custom_mod (MonoImage *m, const char *ptr, char **return_value)
 {
        char *s;
-       const char *reqd;
+       const char *mod;
        
        *return_value = NULL;
        while ((*ptr == MONO_TYPE_CMOD_OPT) ||
                   (*ptr == MONO_TYPE_CMOD_REQD)) {
-               reqd = (*ptr == MONO_TYPE_CMOD_REQD) ? "reqd" : "opt";
+               mod = (*ptr == MONO_TYPE_CMOD_REQD) ? "modreq" : "modopt";
                ptr++;
                ptr = get_encoded_typedef_or_ref (m, ptr, &s);
 
                if (*return_value == NULL)
-                       *return_value = g_strconcat (reqd, " ", s, NULL);
+                       *return_value = g_strconcat (" ", mod, " (", s, ")", NULL);
                else
-                       *return_value = g_strconcat (*return_value, " ", reqd, " ", s, NULL);
+                       *return_value = g_strconcat (*return_value, " ", mod, " (", s, ")", NULL);
                g_free (s);
        }
        return ptr;
@@ -445,7 +456,7 @@ static dis_map_t element_type_map [] = {
        { MONO_TYPE_R4         , "float32" },
        { MONO_TYPE_R8         , "float64" },
        { MONO_TYPE_STRING     , "string" },
-       { MONO_TYPE_TYPEDBYREF , "TypedByRef" },
+       { MONO_TYPE_TYPEDBYREF , "typedref" },
        { MONO_TYPE_I          , "native int" },
        { MONO_TYPE_U          , "native unsigned int" },
        { MONO_TYPE_OBJECT     , "object" },
@@ -479,28 +490,16 @@ dis_stringify_token (MonoImage *m, guint32 token)
 char*
 dis_stringify_array (MonoImage *m, MonoArrayType *array, gboolean is_def)
 {
-       char *type;
-       GString *s = g_string_new("");
-       int i;
+       char *type, *arr_str, *ret;
        
        type = dis_stringify_type (m, &array->eklass->byval_arg, is_def);
-       g_string_append (s, type);
+       arr_str = stringify_array (array->rank, array->numsizes, array->numlobounds, array->sizes, array->lobounds);
+
+       ret = g_strconcat (type, arr_str, NULL);
+       
+       g_free (arr_str);
        g_free (type);
-       g_string_append_c (s, '[');
-       for (i = 0; i < array->rank; ++i) {
-               if (i)
-                       g_string_append_c (s, ',');
-               if (i < array->numsizes) {
-                       if (i < array->numlobounds && array->lobounds[i] != 0)
-                               g_string_sprintfa (s, "%d..%d", array->lobounds[i], array->sizes[i]);
-                       else
-                               g_string_sprintfa (s, "%d", array->sizes[i]);
-               }
-       }
-       g_string_append_c (s, ']');
-       type = s->str;
-       g_string_free (s, FALSE);
-       return type;
+       return ret;
 }
 
 char*
@@ -513,7 +512,7 @@ dis_stringify_modifiers (MonoImage *m, int n, MonoCustomMod *mod)
                char *tok = dis_stringify_token (m, mod[i].token);
                if (i > 0)
                        g_string_sprintfa (s, " ");
-               g_string_sprintfa (s, "%s (%s)", mod[i].required ? "modreq": "modopt", tok);
+               g_string_sprintfa (s, " %s (%s)", mod[i].required ? "modreq": "modopt", tok);
                g_free (tok);
        }
        g_string_append_c (s, ' ');
@@ -539,6 +538,106 @@ dis_stringify_param (MonoImage *m, MonoType *param)
        return result;
 }
 
+static char*
+dis_stringify_variant_type (MonoMarshalVariant variant)
+{
+       switch (variant) {
+       case MONO_VARIANT_EMPTY:
+               return g_strdup ("");
+       case MONO_VARIANT_NULL:
+               return g_strdup ("null");
+       case MONO_VARIANT_I2:
+               return g_strdup ("int16");
+       case MONO_VARIANT_I4:
+               return g_strdup ("int32");
+       case MONO_VARIANT_R4:
+               return g_strdup ("float32");
+       case MONO_VARIANT_R8:
+               return g_strdup ("float64");
+       case MONO_VARIANT_CY:
+               return g_strdup ("currency");
+       case MONO_VARIANT_DATE:
+               return g_strdup ("date");
+       case MONO_VARIANT_BSTR:
+               return g_strdup ("bstr");
+       case MONO_VARIANT_DISPATCH:
+               return g_strdup ("idispatch");
+       case MONO_VARIANT_ERROR:
+               return g_strdup ("error");
+       case MONO_VARIANT_BOOL:
+               return g_strdup ("bool");
+       case MONO_VARIANT_VARIANT:
+               return g_strdup ("variant");
+       case MONO_VARIANT_UNKNOWN:
+               return g_strdup ("iunknown");
+       case MONO_VARIANT_DECIMAL:
+               return g_strdup ("decimal");
+       case MONO_VARIANT_I1:
+               return g_strdup ("int8");
+       case MONO_VARIANT_UI1:
+               return g_strdup ("unsigned int8");
+       case MONO_VARIANT_UI2:
+               return g_strdup ("unsigned int16");
+       case MONO_VARIANT_UI4:
+               return g_strdup ("unsigned int32");
+       case MONO_VARIANT_I8:
+               return g_strdup ("int64");
+       case MONO_VARIANT_UI8:
+               return g_strdup ("unsigned int64");
+       case MONO_VARIANT_INT:
+               return g_strdup ("int");
+       case MONO_VARIANT_UINT:
+               return g_strdup ("unsigned int");
+       case MONO_VARIANT_VOID:
+               return g_strdup ("void");
+       case MONO_VARIANT_HRESULT:
+               return g_strdup ("hresult");
+       case MONO_VARIANT_PTR:
+               return g_strdup ("*");
+       case MONO_VARIANT_SAFEARRAY:
+               return g_strdup ("safearray");
+       case MONO_VARIANT_CARRAY:
+               return g_strdup ("carray");
+       case MONO_VARIANT_USERDEFINED:
+               return g_strdup ("userdefined");
+       case MONO_VARIANT_LPSTR:
+               return g_strdup ("lpstr");
+       case MONO_VARIANT_LPWSTR:
+               return g_strdup ("lpwstr");
+       case MONO_VARIANT_RECORD:
+               return g_strdup ("record");
+       case MONO_VARIANT_FILETIME:
+               return g_strdup ("filetime");
+       case MONO_VARIANT_BLOB:
+               return g_strdup ("blob");
+       case MONO_VARIANT_STREAM:
+               return g_strdup ("stream");
+       case MONO_VARIANT_STORAGE:
+               return g_strdup ("storage");
+       case MONO_VARIANT_STREAMED_OBJECT:
+               return g_strdup ("streamed_object");
+       case MONO_VARIANT_STORED_OBJECT:
+               return g_strdup ("stored_object");
+       case MONO_VARIANT_BLOB_OBJECT:
+               return g_strdup ("blob_object");
+       case MONO_VARIANT_CF:
+               return g_strdup ("cf");
+       case MONO_VARIANT_CLSID:
+               return g_strdup ("clsid");
+       case MONO_VARIANT_VECTOR:
+               /* FIXME: output: <v_type> vector */
+               return g_strdup ("vector");
+       case MONO_VARIANT_ARRAY:
+               /* FIXME: output: <v_type> [ ] */
+               return g_strdup ("[]");
+       case MONO_VARIANT_BYREF:
+               /* FIXME: output: <v_type> & */
+               return g_strdup ("&");
+       default:
+               return g_strdup ("unknown");
+       }
+}
+
 static char*
 dis_stringify_native_type (MonoMarshalNative native)
 {
@@ -614,16 +713,16 @@ dis_stringify_native_type (MonoMarshalNative native)
        }
 }
 
-static char*
+char*
 dis_stringify_marshal_spec (MonoMarshalSpec *spec)
 {
        switch (spec->native) {
        case MONO_NATIVE_BYVALTSTR:
-               return g_strdup_printf ("fixed sysstring [%d]", spec->data.array_data.num_elem);
+               return g_strdup_printf (" marshal (fixed sysstring [%d])", spec->data.array_data.num_elem);
        case MONO_NATIVE_BYVALARRAY:
-               return g_strdup_printf ("fixed array [%d]", spec->data.array_data.num_elem);
+               return g_strdup_printf (" marshal (fixed array [%d])", spec->data.array_data.num_elem);
        case MONO_NATIVE_LPARRAY: {
-               char *elem_type, *elems;
+               char *elem_type, *elems, *ret;
                guint32 num_elem = spec->data.array_data.num_elem;
                guint32 param_num = spec->data.array_data.param_num;
 
@@ -636,11 +735,33 @@ dis_stringify_marshal_spec (MonoMarshalSpec *spec)
                        elems = g_strdup_printf ("+ %d", param_num);
                else
                        elems = g_strdup_printf ("%d + %d", num_elem, param_num);
-
-               return g_strdup_printf ("%s[%s]", elem_type, elems);
+                       
+               ret = g_strdup_printf (" marshal (%s[%s])", elem_type, elems);
+               g_free (elem_type);
+               g_free (elems);
+               return ret;
        }
-       default:
-               return dis_stringify_native_type (spec->native);
+       case MONO_NATIVE_SAFEARRAY: {
+               char *elem_type = NULL, *ret;
+               
+               if (spec->data.safearray_data.elem_type != 0)
+                       elem_type = dis_stringify_variant_type (spec->data.safearray_data.elem_type);
+               ret = g_strdup_printf (" marshal (safearray %s)", elem_type ? elem_type : "");
+               
+               g_free (elem_type);
+               return ret;
+       }
+       case MONO_NATIVE_CUSTOM:
+               return g_strdup_printf (" marshal (custom (\"%s\", \"%s\"))", 
+                       spec->data.custom_data.custom_name ? spec->data.custom_data.custom_name : "", 
+                       spec->data.custom_data.cookie ? spec->data.custom_data.cookie : "");
+       default: {
+               char *native_type, *ret;
+               native_type = dis_stringify_native_type (spec->native);
+               ret = g_strdup_printf (" marshal (%s)", native_type);
+               g_free (native_type);
+               return ret;
+       }       
        }
 }
 
@@ -676,11 +797,11 @@ get_generic_param (MonoImage *m, MonoGenericContainer *container)
                        g_string_append (result, ",");
 
                flags = param->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
-               if (flags == GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT)
+               if ((flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT)
                        g_string_append (result, "class ");
-               else if (flags == GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
+               if ((flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) == GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
                        g_string_append (result, "valuetype ");
-               else if (flags == GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT)
+               if ((flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) == GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT)
                        g_string_append (result, ".ctor ");
 
                for (constr = param->constraints; constr && *constr; constr++) {
@@ -714,19 +835,38 @@ get_generic_param (MonoImage *m, MonoGenericContainer *container)
 char*
 dis_stringify_method_signature (MonoImage *m, MonoMethodSignature *method, int methoddef_row,
                                MonoGenericContext *context, gboolean fully_qualified)
+{
+       return dis_stringify_method_signature_full (m, method, methoddef_row, context, fully_qualified, TRUE);
+}
+
+/* 
+ * @m: metadata context
+ * @method: MonoMethodSignature to dis-stringify
+ * @methoddef_row: row index in the Method table
+ * @context: generic context, generic method's context in case of a Generic method
+ *          or a generic type's context. if !@context, treats it as a non-generic method
+ * @fully_qualified: TRUE to print type name also.
+ *
+ * Returns: Allocated stringified method signature
+ */
+char*
+dis_stringify_method_signature_full (MonoImage *m, MonoMethodSignature *method, int methoddef_row,
+                               MonoGenericContext *context, gboolean fully_qualified, gboolean with_marshal_info)
 {
        guint32 cols [MONO_METHOD_SIZE];
        guint32 pcols [MONO_PARAM_SIZE];
-       guint32 param_index = 0;
-       const char *name = "";
+       guint32 param_index = 0, next_param_index = 0;
+       gboolean has_param_row;
+       const char *method_name = "";
        int free_method = 0;
        char *retval, *esname;
        char *type = NULL;
-       char *marshal_info = NULL;
+       char *marshal_info = NULL, *ret_marshal_info = NULL;
        char *gen_param = NULL;
        GString *result = g_string_new ("");
+       GString *result_ret = g_string_new ("");
        MonoGenericContainer *container = NULL;
-       int i;
+       int i, start;
         
        g_assert (method || methoddef_row);
 
@@ -734,76 +874,114 @@ dis_stringify_method_signature (MonoImage *m, MonoMethodSignature *method, int m
                mono_metadata_decode_row (&m->tables [MONO_TABLE_METHOD], methoddef_row -1, cols, MONO_METHOD_SIZE);
                if (fully_qualified)
                        type = get_typedef (m, mono_metadata_typedef_from_method (m, methoddef_row));
-               name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
+               method_name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
                param_index = cols [MONO_METHOD_PARAMLIST];
                if (!method) {
                        const char *sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
 
                        container = mono_metadata_load_generic_params (
                                m, MONO_TOKEN_METHOD_DEF | methoddef_row, context ? context->container : NULL);
-                       if (container)
+                       if (container) {
+                               mono_metadata_load_generic_param_constraints (
+                                       m, MONO_TOKEN_METHOD_DEF | methoddef_row, container);
                                context = (MonoGenericContext *) container;
+                       }
 
                        mono_metadata_decode_blob_size (sig, &sig);
-                       method = mono_metadata_parse_method_signature_full (m, context, methoddef_row, sig, &sig);
+                       method = mono_metadata_parse_method_signature_full (m, container, methoddef_row, sig, &sig);
                        free_method = 1;
                } else if (context)
                        container = context->container;
 
                if (container && container->is_method)
                        gen_param = get_generic_param (m, container);
-       }
-       
-       retval = dis_stringify_param (m, method->ret);
-       if (method->hasthis)
-               g_string_append (result, "instance ");
-       g_string_append (result, map (method->call_convention, call_conv_type_map));
-       g_string_sprintfa (result, " %s ", retval);
-       if (type) {
-               char *estype = get_escaped_name (type);
-               g_string_sprintfa (result, "%s::", estype);
-               g_free (estype);
-       }
-       esname = get_escaped_name (name);
-       g_string_append (result, esname);
-       g_free (esname);
-        if (gen_param) {
-                g_string_append (result, gen_param);
-                g_free (gen_param);
-        }
-       g_string_append (result, " (");
-       g_free (retval);
-       for (i = 0; i < method->param_count; ++i) {
-               if (param_index && param_index <= m->tables [MONO_TABLE_PARAM].rows) {
+               
+               if (methoddef_row < m->tables [MONO_TABLE_METHOD].rows) {
+                       mono_metadata_decode_row (&m->tables [MONO_TABLE_METHOD], methoddef_row, cols, MONO_METHOD_SIZE);
+                       next_param_index = cols [MONO_METHOD_PARAMLIST];
+               } else {
+                       next_param_index = m->tables [MONO_TABLE_PARAM].rows + 1;
+               }
+       } 
+
+       start = method->hasthis ? 0 : 1;
+       for (i = 0; i < method->param_count + 1; ++i) {
+               marshal_info = NULL;
+               has_param_row = param_index && param_index < next_param_index;
+               esname = NULL;
+
+               if (method->param_count == 0 && !has_param_row)
+                       /* method has zero parameters, and no row for return val in the PARAM table */
+                       continue;
+               
+               if (has_param_row)
                        mono_metadata_decode_row (&m->tables [MONO_TABLE_PARAM], param_index - 1, pcols, MONO_PARAM_SIZE);
-                       name = mono_metadata_string_heap (m, pcols [MONO_PARAM_NAME]);
-                       method->params [i]->attrs = pcols [MONO_PARAM_FLAGS];
+               
+               if (has_param_row && i == pcols [MONO_PARAM_SEQUENCE]) {
+                       if (i)
+                               esname = get_escaped_name (
+                                               mono_metadata_string_heap (m, pcols [MONO_PARAM_NAME]));
 
-                       if (pcols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) {
+                       if (with_marshal_info && (pcols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)) {
                                const char *tp;
                                MonoMarshalSpec *spec;
                                tp = mono_metadata_get_marshal_info (m, param_index - 1, FALSE);
                                g_assert (tp);
                                spec = mono_metadata_parse_marshal_spec (m, tp);
 
-                               marshal_info = g_strdup_printf (" marshal (%s)", dis_stringify_marshal_spec (spec));
+                               if (i)
+                                       marshal_info = dis_stringify_marshal_spec (spec);
+                               else
+                                       ret_marshal_info = dis_stringify_marshal_spec (spec);
                        }
-
-                       param_index++;
+                       param_index ++;
                } else {
-                       name = "";
+                       if (i)
+                               /* A_[0-9]* does not require escaping */
+                               esname = g_strdup_printf ("A_%i", i - start);
                }
-               if (i)
+
+               if (!i)
+                       continue;
+
+               if (i > 1)
                        g_string_append (result, ", ");
-               retval = dis_stringify_param (m, method->params [i]);
 
-               esname = get_escaped_name (name);
-               g_string_append_printf (result, "%s %s%s", retval, esname, marshal_info ? marshal_info : "");
+               retval = dis_stringify_param (m, method->params [i - 1]);
+
+               g_string_append_printf (result, "%s%s %s", retval, marshal_info ? marshal_info : "", esname);
                g_free (retval);
                g_free (esname);
+               g_free (marshal_info);
        }
        g_string_append (result, ") ");
 
+       retval = dis_stringify_param (m, method->ret);
+
+       if (method->hasthis)
+               g_string_append (result_ret, "instance ");
+       g_string_append (result_ret, map (method->call_convention, call_conv_type_map));
+       g_string_sprintfa (result_ret, " %s%s ", retval, ret_marshal_info ? ret_marshal_info :"");
+       g_free (ret_marshal_info);
+       if (type) {
+               char *estype = get_escaped_name (type);
+               g_string_sprintfa (result_ret, "%s::", estype);
+               g_free (estype);
+               g_free (type);
+       }
+       esname = get_escaped_name (method_name);
+       g_string_append (result_ret, esname);
+       g_free (esname);
+       if (gen_param) {
+               g_string_append (result_ret, gen_param);
+               g_free (gen_param);
+       }
+       g_string_append (result_ret, " (");
+       g_free (retval);
+
+       g_string_prepend (result, result_ret->str);
+       g_string_free (result_ret, FALSE);
+
        if (show_method_tokens && methoddef_row)
                g_string_append_printf (result, " /* 0x%X */ ",
                                (methoddef_row >> MONO_TYPEORMETHOD_BITS) | MONO_TOKEN_METHOD_DEF);
@@ -852,6 +1030,10 @@ get_escaped_class_name (MonoClass *c)
 {
        char *result, *esname;
 
+       if (c->type_token == mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1))
+               /* <Module> */
+               return NULL;
+
        if (c->rank || c->byval_arg.type == MONO_TYPE_PTR) 
                g_assert (0);
 
@@ -879,6 +1061,10 @@ dis_stringify_object_with_class (MonoImage *m, MonoClass *c, gboolean prefix, gb
        const char *otype = type->type == MONO_TYPE_VALUETYPE ? "valuetype " : "class " ;
        char *assemblyref = NULL, *result, *esname, *generic = NULL;
        
+       if (c->type_token == mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1))
+               /* <Module> */
+               return NULL;
+
        if (m != c->image) {
                if (c->image->assembly_name) {
                        /* we cheat */
@@ -997,17 +1183,15 @@ dis_stringify_type (MonoImage *m, MonoType *type, gboolean is_def)
                bare = g_strdup ("void");
                break;
        case MONO_TYPE_MVAR:
-               if (is_def) {
-                       g_assert (type->data.generic_param->name);
-                       bare = g_strdup_printf ("!!%s", type->data.generic_param->name);
-               } else
+               if (is_def && !cant_print_generic_param_name (type->data.generic_param))
+                       bare = g_strdup_printf ("!!%s", get_escaped_name (type->data.generic_param->name));
+               else
                        bare = g_strdup_printf ("!!%d", type->data.generic_param->num);
                break;
        case MONO_TYPE_VAR:
-               if (is_def) {
-                       g_assert (type->data.generic_param->name);
-                       bare = g_strdup_printf ("!%s", type->data.generic_param->name);
-               } else
+               if (is_def && !cant_print_generic_param_name (type->data.generic_param))
+                       bare = g_strdup_printf ("!%s", get_escaped_name (type->data.generic_param->name));
+               else
                        bare = g_strdup_printf ("!%d", type->data.generic_param->num);
                break;
        case MONO_TYPE_GENERICINST: {
@@ -1038,8 +1222,12 @@ dis_stringify_type (MonoImage *m, MonoType *type, gboolean is_def)
 
        if (type->byref)
                byref = "&";
+       
+       if (!bare)
+               /* bare is NULL, for <Module> */
+               return bare;
                
-       result = g_strconcat (mods ? mods : "", bare, byref, pinned, NULL);
+       result = g_strconcat (bare, byref, pinned, mods ? mods : "", NULL);
 
        g_free (bare);
 
@@ -1058,7 +1246,7 @@ dis_stringify_type (MonoImage *m, MonoType *type, gboolean is_def)
  * Returns: the new ptr to continue decoding
  */
 const char *
-get_type (MonoImage *m, const char *ptr, char **result, MonoGenericContext *context)
+get_type (MonoImage *m, const char *ptr, char **result, gboolean is_def, MonoGenericContext *context)
 {
        const char *start = ptr;
        guint32 type;
@@ -1089,7 +1277,7 @@ get_type (MonoImage *m, const char *ptr, char **result, MonoGenericContext *cont
                int count, i;
                char *temp;
 
-               ptr = get_type (m, ptr, &temp, context);
+               ptr = get_type (m, ptr, &temp, is_def, context);
                g_string_append (str, temp);
                g_free (temp);
 
@@ -1099,7 +1287,7 @@ get_type (MonoImage *m, const char *ptr, char **result, MonoGenericContext *cont
                for (i = 0; i < count; i++) {
                        if (i)
                                g_string_append (str, ",");
-                       ptr = get_type (m, ptr, &temp, context);
+                       ptr = get_type (m, ptr, &temp, is_def, context);
                        g_string_append (str, temp);
                }
 
@@ -1110,8 +1298,8 @@ get_type (MonoImage *m, const char *ptr, char **result, MonoGenericContext *cont
        }
 
        default:
-               t = mono_metadata_parse_type_full (m, context, MONO_PARSE_TYPE, 0, start, &ptr);
-               *result = dis_stringify_type (m, t, FALSE);
+               t = mono_metadata_parse_type_full (m, context ? context->container : NULL, MONO_PARSE_TYPE, 0, start, &ptr);
+               *result = dis_stringify_type (m, t, is_def);
                mono_metadata_free_type (t);
                break;
        }
@@ -1140,12 +1328,12 @@ get_field_signature (MonoImage *m, guint32 blob_signature, MonoGenericContext *c
        ptr++; len--;
        
        ptr = get_custom_mod (m, ptr, &allocated_modifier_string);
-       ptr = get_type (m, ptr, &allocated_type_string, context);
+       ptr = get_type (m, ptr, &allocated_type_string, FALSE, context);
 
        res = g_strdup_printf (
-               "%s %s",
-               allocated_modifier_string ? allocated_modifier_string : "",
-               allocated_type_string);
+               "%s%s",
+               allocated_type_string,
+               allocated_modifier_string ? allocated_modifier_string : "");
        
        if (allocated_modifier_string)
                g_free (allocated_modifier_string);
@@ -1205,31 +1393,35 @@ get_ret_type (MonoImage *m, const char *ptr, char **ret_type, MonoGenericContext
        GString *str = g_string_new ("");
        char *mod = NULL;
        char *allocated_type_string;
+       int has_byref = 0;
        
        ptr = get_custom_mod (m, ptr, &mod);
-       if (mod){
-               g_string_append (str, mod);
-               g_string_append_c (str, ' ');
-               g_free (mod);
-       }
 
        if (*ptr == MONO_TYPE_TYPEDBYREF){
-               g_string_append (str, "typedbyref");
+               g_string_append (str, "typedref");
                ptr++;
        } else if (*ptr == MONO_TYPE_VOID){
                 g_string_append (str, "void");
                 ptr++;
        } else {
                 if (*ptr == MONO_TYPE_BYREF){
-                       g_string_append (str, "[out] ");
+                       has_byref = 1;
                        ptr++;
                }
 
-               ptr = get_type (m, ptr, &allocated_type_string, context);
+               ptr = get_type (m, ptr, &allocated_type_string, FALSE, context);
                g_string_append (str, allocated_type_string);
+               if (has_byref)
+                       g_string_append (str, "& ");
                g_free (allocated_type_string);
        }
 
+       if (mod){
+               g_string_append (str, mod);
+               g_string_append_c (str, ' ');
+               g_free (mod);
+       }
+
        *ret_type = str->str;
        g_string_free (str, FALSE);
 
@@ -1253,14 +1445,9 @@ get_param (MonoImage *m, const char *ptr, char **retval, MonoGenericContext *con
        char *allocated_mod_string, *allocated_type_string;
        
        ptr = get_custom_mod (m, ptr, &allocated_mod_string);
-       if (allocated_mod_string){
-               g_string_append (str, allocated_mod_string);
-               g_string_append_c (str, ' ');
-               g_free (allocated_mod_string);
-       }
        
        if (*ptr == MONO_TYPE_TYPEDBYREF){
-               g_string_append (str, " typedbyref ");
+               g_string_append (str, " typedref ");
                ptr++;
        } else {
                gboolean by_ref = 0;
@@ -1269,18 +1456,54 @@ get_param (MonoImage *m, const char *ptr, char **retval, MonoGenericContext *con
                        ptr++;
                        by_ref = 1;
                }
-               ptr = get_type (m, ptr, &allocated_type_string, context);
+               ptr = get_type (m, ptr, &allocated_type_string, FALSE, context);
                g_string_append (str, allocated_type_string);
                if (by_ref)
                        g_string_append_c (str, '&');
                g_free (allocated_type_string);
        }
 
+       if (allocated_mod_string){
+               g_string_append (str, allocated_mod_string);
+               g_string_append_c (str, ' ');
+               g_free (allocated_mod_string);
+       }
+
        *retval = str->str;
        g_string_free (str, FALSE);
        return ptr;
 }
 
+/**
+ * str_escape 
+ * 
+ * @str: string to process
+ * @list: list of chars to escape
+ * 
+ * Returns: an allocated escaped string.
+ */
+static char*
+str_escape (const char *str, const char *list)
+{
+       const char *p = str;
+       GString *res;
+
+       res = g_string_sized_new (strlen (str));
+
+       for (;;) {
+               while (*p && !strchr (list, *p))
+                       ++p;
+               g_string_append_len (res, str, p - str);
+               if (!*p)
+                       break;
+               g_string_append_c (res, '\\');
+               str = p;
+               ++p;
+       }
+                       
+       return g_string_free (res, FALSE);
+}
+
 /**
  * get_escaped_name
  *
@@ -1291,7 +1514,10 @@ char*
 get_escaped_name (const char *name)
 {
        const char *s;
-       char *tmp, *tmp2;
+       char *ret, *esc;
+
+       if (!name)
+               return NULL;
 
        g_assert (key_table);
 
@@ -1313,16 +1539,19 @@ get_escaped_name (const char *name)
 
        for (s = name; *s; s++) {
                if (isalnum (*s) || *s == '_' || *s == '$' || *s == '@' ||
-                   *s == '?' || *s == '.' || *s == 0 || *s == '!')
+                   *s == '?' || *s == '.' || *s == 0 || *s == '!' || *s == '`')
                        continue;
 
-               return g_strdup_printf ("'%s'", name);
+               esc = str_escape (name, "'\\");
+               ret = g_strdup_printf ("'%s'", esc);
+               g_free (esc);
+               return ret;
        }
        
        if (g_hash_table_lookup (key_table, name))
                return g_strdup_printf ("'%s'", name);
                        
-       return g_strdup (name);
+       return str_escape (name, "'\\");
 }
 
 static dis_map_t param_map [] = {
@@ -1359,7 +1588,7 @@ static dis_map_t field_flags_map [] = {
        { FIELD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
        { FIELD_ATTRIBUTE_PINVOKE_IMPL,        "FIXME:pinvokeimpl " },
        { FIELD_ATTRIBUTE_RT_SPECIAL_NAME,        "rtspecialname " },
-       { FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL,        "hasfieldmarshal " },
+       /*{ FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL,        "hasfieldmarshal " },*/
        { 0, NULL }
 };
 
@@ -1385,8 +1614,7 @@ field_flags (guint32 f)
  * Returns a stringifed representation of a MethodRefSig (22.2.2)
  */
 char *
-get_methodref_signature (MonoImage *m, guint32 blob_signature, const char *fancy_name,
-                        MonoGenericContext *context)
+get_methodref_signature (MonoImage *m, guint32 blob_signature, const char *fancy_name)
 {
        GString *res = g_string_new ("");
        const char *ptr = mono_metadata_blob_heap (m, blob_signature);
@@ -1420,7 +1648,7 @@ get_methodref_signature (MonoImage *m, guint32 blob_signature, const char *fancy
                gen_count = mono_metadata_decode_value (ptr, &ptr);
        param_count = mono_metadata_decode_value (ptr, &ptr);
        if (cconv != 0xa) {
-               ptr = get_ret_type (m, ptr, &allocated_ret_type, context);
+               ptr = get_ret_type (m, ptr, &allocated_ret_type, NULL);
                g_string_append (res, allocated_ret_type);
                g_free (allocated_ret_type);
        }
@@ -1451,7 +1679,7 @@ get_methodref_signature (MonoImage *m, guint32 blob_signature, const char *fancy
                        ptr++;
                }
 
-               ptr = get_param (m, ptr, &param, context);
+               ptr = get_param (m, ptr, &param, NULL);
                g_string_append (res, param);
                if (i+1 != param_count)
                        g_string_append (res, ", ");
@@ -1488,7 +1716,11 @@ get_fieldref_signature (MonoImage *m, int idx, MonoGenericContext *context)
        type = get_memberref_parent (m, cols [MONO_MEMBERREF_CLASS], context);
        esname = get_escaped_name (mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));
 
-        full_sig = g_strdup_printf ("%s %s::%s", sig, type, esname);
+       full_sig = g_strdup_printf ("%s %s%s%s", 
+                       sig, 
+                       type ? type : "", 
+                       type ? "::" : "",
+                       esname);
         g_free (sig);
        g_free (type);
        g_free (esname);
@@ -1534,8 +1766,11 @@ get_field (MonoImage *m, guint32 token, MonoGenericContext *context)
        type = get_typedef (m, type_idx);
        estype = get_escaped_name (type);
        esname = get_escaped_name (mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]));
-       res = g_strdup_printf ("%s %s::%s",
-                       sig, estype, esname);
+       res = g_strdup_printf ("%s %s%s%s",
+                       sig, 
+                       estype ? estype : "",
+                       estype ? "::" : "",
+                       esname);
 
        g_free (type);
        g_free (sig);
@@ -1620,17 +1855,19 @@ get_method_core (MonoImage *m, guint32 token, gboolean fullsig, MonoGenericConte
        char *name;
 
        MonoMethod *mh;
+       MonoGenericContext *gc = context;
 
        mh = mono_get_method_full (m, token, NULL, context);
        if (mh) {
+               mh = mono_get_inflated_method (mh);
                if (mono_method_signature (mh)->is_inflated)
                        context = ((MonoMethodInflated *) mh)->context;
                esname = get_escaped_name (mh->name);
                sig = dis_stringify_type (m, &mh->klass->byval_arg, TRUE);
                if (show_tokens)
-                       name = g_strdup_printf ("%s/*%08x*/::%s", sig, token, esname);
+                       name = g_strdup_printf ("%s/*%08x*/%s%s", sig ? sig : "", token, sig ? "::" : "", esname);
                else
-                       name = g_strdup_printf ("%s::%s", sig, esname);
+                       name = g_strdup_printf ("%s%s%s", sig ? sig : "", sig ? "::" : "", esname);
                g_free (sig);
                g_free (esname);
        } else
@@ -1641,25 +1878,45 @@ get_method_core (MonoImage *m, guint32 token, gboolean fullsig, MonoGenericConte
                mono_metadata_decode_row (&m->tables [MONO_TABLE_METHOD], 
                                          idx - 1, method_cols, MONO_METHOD_SIZE);
 
-               sig = get_methodref_signature (m, method_cols [MONO_METHOD_SIGNATURE], name, context);
+               sig = get_methodref_signature (m, method_cols [MONO_METHOD_SIGNATURE], name);
                break;
                
        case MONO_TOKEN_MEMBER_REF: {
                mono_metadata_decode_row (&m->tables [MONO_TABLE_MEMBERREF],
                                          idx - 1, member_cols, MONO_MEMBERREF_SIZE);
-               if (!name)
-                       name = g_strdup_printf ("%s::%s",
-                                               get_memberref_parent (m, member_cols [MONO_MEMBERREF_CLASS], context),
+               if (!name) {
+                       char *parent = get_memberref_parent (m, member_cols [MONO_MEMBERREF_CLASS], context),
+                       name = g_strdup_printf ("%s%s%s",
+                                               parent ? parent : "", 
+                                               parent ? "::" : "",
                                                mono_metadata_string_heap (m, member_cols [MONO_MEMBERREF_NAME]));
+                       g_free (parent);
+               }
+               if (mh) {
+                       int arity = 0;
+
+                       if (mh->generic_container)
+                               arity = mh->generic_container->type_argc;
+                       else
+                       if (mh->is_inflated && ((MonoMethodInflated *)mh)->declaring->generic_container)
+                               arity = ((MonoMethodInflated*) mh)->declaring->generic_container->type_argc;
+
+                       if (arity > 0) {
+                               char *str = g_strdup_printf ("%s <[%d]>", name, arity);
+                               g_free (name);
+                               name = str;
+                       }
+               }
+                               
                sig = get_methodref_signature (
-                       m, member_cols [MONO_MEMBERREF_SIGNATURE], name, context);
+                       m, member_cols [MONO_MEMBERREF_SIGNATURE], name);
                break;
        }
        case MONO_TOKEN_METHOD_SPEC: {
                 mono_metadata_decode_row (&m->tables [MONO_TABLE_METHODSPEC],
                                 idx - 1, member_cols, MONO_METHODSPEC_SIZE);
                token = member_cols [MONO_METHODSPEC_METHOD];
-                sig = get_methodspec (m, idx, token, name, context);
+                sig = get_methodspec (m, idx, token, name, gc);
                break;
        }
 
@@ -1707,13 +1964,16 @@ get_methoddef (MonoImage *m, guint32 idx)
        mh = mono_get_method (m, MONO_TOKEN_METHOD_DEF | idx, NULL);
        if (mh) {
                sig = dis_stringify_type (m, &mh->klass->byval_arg, FALSE);
-               name = g_strdup_printf ("%s::%s", sig, mh->name);
+               name = g_strdup_printf ("%s%s%s", 
+                               sig ? sig : "",
+                               sig ? "::" : "",
+                               mh->name);
                g_free (sig);
        } else
                name = NULL;
         mono_metadata_decode_row (&m->tables [MONO_TABLE_METHOD], 
                         idx - 1, cols, MONO_METHOD_SIZE);
-        sig = get_methodref_signature (m, cols [MONO_METHOD_SIGNATURE], name, NULL);
+        sig = get_methodref_signature (m, cols [MONO_METHOD_SIGNATURE], name);
         
         return sig;
 }
@@ -1764,6 +2024,9 @@ get_methodspec (MonoImage *m, int idx, guint32 token, const char *fancy_name, Mo
         const char *ptr;
        guint32 sig = 0;
        int param_count, cconv, i, gen_count = 0;
+       MonoGenericContainer *container = NULL;
+       MonoGenericContext *parent_context = context;
+       MonoMethod *mh = NULL;
 
        switch (token & MONO_METHODDEFORREF_MASK) {
        case MONO_METHODDEFORREF_METHODDEF:
@@ -1784,6 +2047,11 @@ get_methodspec (MonoImage *m, int idx, guint32 token, const char *fancy_name, Mo
 
        ptr = mono_metadata_blob_heap (m, sig);
        mono_metadata_decode_value (ptr, &ptr);
+       
+       mh = mono_get_method_full (m, method_dor_to_token (token), NULL, parent_context);
+       g_assert (mh);
+       if ((container = mh->generic_container))
+               context = (MonoGenericContext*) container;
 
        if (*ptr & 0x20){
                if (*ptr & 0x40)
@@ -1814,7 +2082,7 @@ get_methodspec (MonoImage *m, int idx, guint32 token, const char *fancy_name, Mo
         mono_metadata_decode_row (&m->tables [MONO_TABLE_METHODSPEC],
                         idx - 1, member_cols, MONO_METHODSPEC_SIZE);
         token = member_cols [MONO_METHODSPEC_SIGNATURE];
-        type_param = get_method_type_param (m, token, context);
+        type_param = get_method_type_param (m, token, parent_context);
         g_string_append (res, type_param);
        g_string_append (res, " (");
 
@@ -1841,6 +2109,107 @@ get_methodspec (MonoImage *m, int idx, guint32 token, const char *fancy_name, Mo
        return s;
 }
 
+/*
+ * get_encoded_user_string_bytearray:
+ * @ptr: pointer into the US heap
+ * @len: length of string in the heap.
+ *
+ * Strings on the US heap are encoded using UTF-16. Print a bytearray.
+ */
+static char*
+get_encoded_user_string_bytearray (const unsigned char* ptr, int len)
+{
+       gchar *str;
+       int i, j, tspaces = (len % 16);
+       GString *res;
+
+       if (len == 0)
+               return g_strdup_printf ("\"\"");
+
+       res = g_string_new ("bytearray (\n\t");
+
+       for (i = 1; i <= len; ++i) {
+               g_string_append_printf (res, "%02x ", ptr [i-1]);
+
+               if (i % 16 == 0) {
+                       if (i == len)
+                               g_string_append (res, ")// ");
+                       else
+                               g_string_append (res, " // ");
+
+                       for(j = i - 16; j < i; ++j) 
+                               g_string_append_printf (res, "%c", isprint (ptr [j]) ? ptr [j] : '.');
+                       g_string_append (res, "\n\t");
+               }
+       }
+
+       if (tspaces) {
+               g_string_append (res, ")  ");
+               for (i = tspaces + 1; i < 16; ++i)
+                       g_string_append_printf (res, "   ");
+
+               g_string_append (res, " // ");
+               for(i = len - tspaces; i < len; ++i)
+                       g_string_append_printf (res, "%c", isprint (ptr [i]) ? ptr [i] : '.');
+               g_string_append (res, "\n\t");
+       } 
+
+       str = res->str;
+       g_string_free (res, FALSE);
+       return str;
+}
+
+/*
+ * get_encoded_user_string_or_bytearray:
+ * @ptr: pointer into the US heap
+ *
+ * Strings on the US heap are encoded using UTF-16. Print as string
+ * if possible, else emit a bytearray.
+ */
+char*
+get_encoded_user_string_or_bytearray (const unsigned char *ptr, int len)
+{
+       unsigned char *res, *eres, *result;
+       int i;
+
+       res = g_malloc ((len >> 1) + 1);
+
+       /*
+        * I should really use some kind of libunicode here
+        */
+       for (i = 0; i + 1 < len; i += 2) {
+               if (ptr [i + 1] || 
+                   (!isprint (ptr [i]) && ptr [i] != '\\' && ptr [i] != '"' && 
+                    ptr [i] != '\r' && ptr [i] != '\n' && ptr [i] != '\t')) {
+                       g_free (res);
+                       return get_encoded_user_string_bytearray (ptr, len);
+               }
+
+               res [i >> 1] = ptr [i];
+       }       
+
+       res [len >> 1] = 0;
+
+       eres = g_strescape (res, NULL);
+       result = g_strdup_printf ("\"%s\"", eres);
+       g_free (res);
+       g_free (eres);
+       
+       return result;
+}
+
+char *
+stringify_double (double r)
+{
+       char *ret, *ptr;
+
+       ret = g_strdup_printf ("%.17g.", r);
+       ptr = ret + strlen (ret) - 1;
+       if (strpbrk (ret, ".eE") != ptr)
+               *ptr = '\0';
+
+       return ret;
+}
 
 /**
  * get_constant:
@@ -1876,70 +2245,60 @@ get_constant (MonoImage *m, MonoTypeEnum t, guint32 blob_index)
                
        case MONO_TYPE_U4:
        case MONO_TYPE_I4:
-               return g_strdup_printf ("int32(%d)", read32 (ptr));
+               return g_strdup_printf ("int32(0x%08x)", read32 (ptr));
                
+       case MONO_TYPE_U8:
        case MONO_TYPE_I8: {
                guint32 low, high;
                low = read32 (ptr);
                high = read32 (ptr + 4);
                return g_strdup_printf ("int64(0x%08x%08x)", high, low);
        }
-       case MONO_TYPE_U8: {
-               guint32 low, high;
-               low = read32 (ptr);
-               high = read32 (ptr + 4);
-               return g_strdup_printf ("0x%08x%08x", high, low);
-       }
        case MONO_TYPE_R4: {
+               gboolean normal;
                float r;
                readr4 (ptr, &r);
-               return g_strdup_printf ("float32(%g)", (double) r);
-       }
+
+               /* Crazy solaris systems doesn't have isnormal */
+#ifdef HAVE_FINITE
+               normal = finite (r);
+#else
+               normal = isnormal (r);
+#endif
+               if (!normal) {
+                       return g_strdup_printf ("float32(0x%08x)", read32 (ptr));
+               } else {
+                       char *str = stringify_double ((double) r);
+                       char *ret = g_strdup_printf ("float32(%s)", str);
+                       g_free (str);
+                       return ret;
+               }
+       }       
        case MONO_TYPE_R8: {
+               gboolean normal;
                double r;
                readr8 (ptr, &r);
-               return g_strdup_printf ("float64(%g)", r);
-       }
-       case MONO_TYPE_STRING: {
-               gchar *str;
-               int i, j, tspaces = (len%16);
-               GString *res;
-
-               if (len == 0)
-                       return g_strdup_printf ("\"\"");
 
-               res = g_string_new ("bytearray (\n\t");
-
-               for(i = 1; i <= len; ++i) {
-                       g_string_append_printf(res, "%02x ", ptr[i-1]);
-
-                       if(i%16 == 0) {
-                               if(i == len)
-                                       g_string_append(res, ")// ");
-                               else
-                                       g_string_append(res, " // ");
-
-                               for(j = i-16; j < i; ++j) 
-                                       g_string_append_printf(res, "%c", isprint(ptr[j]) ? ptr[j] : '.');
-                               g_string_append(res, "\n\t");
-                       }
+               /* Crazy solaris systems doesn't have isnormal */
+#ifdef HAVE_FINITE
+               normal = finite (r);
+#else
+               normal = isnormal (r);
+#endif
+               if (!normal) {
+                       guint32 low, high;
+                       low = read32 (ptr);
+                       high = read32 (ptr + 4);
+                       return g_strdup_printf ("float64(0x%08x%08x)", high, low);
+               } else {
+                       char *str = stringify_double (r);
+                       char *ret = g_strdup_printf ("float64(%s)", str);
+                       g_free (str);
+                       return ret;
                }
-
-               if(tspaces) {
-                       g_string_append(res, ")  ");
-                       for(i = tspaces+1; i < 16; ++i)
-                               g_string_append_printf(res, "   ");
-
-                       g_string_append(res, " // ");
-                       for(i = len-tspaces; i < len; ++i)
-                               g_string_append_printf(res, "%c", isprint(ptr[i]) ? ptr[i] : '.');
-                       g_string_append(res, "\n\t");
-               } 
-
-               str = res->str;
-               g_string_free(res, FALSE);
-               return str;
        }
+       case MONO_TYPE_STRING:
+               return get_encoded_user_string_or_bytearray (ptr, len);
                
        case MONO_TYPE_CLASS:
                return g_strdup ("nullref");
@@ -1992,9 +2351,11 @@ get_token (MonoImage *m, guint32 token, MonoGenericContext *context)
                        result = g_strdup_printf ("field %s", temp);
                        g_free (temp);
                        return result;
-               }
-               else {
-                       g_error ("Do not know how to decode tokens of type 0x%08x", token);
+               } else {
+                       temp = get_method (m, token, context);
+                       result = g_strdup_printf ("method %s", temp);
+                       g_free (temp);
+                       return result;
                }
                break;
        }
@@ -2084,6 +2445,9 @@ dis_get_custom_attrs (MonoImage *m, guint32 token)
        case MONO_TABLE_ASSEMBLY:
                idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
                break;
+       case MONO_TABLE_ASSEMBLYREF:
+               idx |= MONO_CUSTOM_ATTR_ASSEMBLYREF;
+               break;
        case MONO_TABLE_MODULE:
                idx |= MONO_CUSTOM_ATTR_MODULE;
                break;
@@ -2102,6 +2466,9 @@ dis_get_custom_attrs (MonoImage *m, guint32 token)
        case MONO_TABLE_PARAM:
                idx |= MONO_CUSTOM_ATTR_PARAMDEF;
                break;
+       case MONO_TABLE_GENERICPARAM:
+               idx |= MONO_CUSTOM_ATTR_GENERICPAR;
+               break;
        default:
                g_print ("Missing custom attr get support for token 0x%08x\n", token);
                return NULL;
@@ -2248,6 +2615,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "autochar", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "auto", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "beforefieldinit", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "bestfit", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "beq", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "beq.s", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "bge", GINT_TO_POINTER (TRUE));
@@ -2289,6 +2657,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "bytearray", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "byvalstr", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "call", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "callconv", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "calli", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "callmostderived", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "callvirt", GINT_TO_POINTER (TRUE));
@@ -2301,6 +2670,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "cgt", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "cgt.un", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "char", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "charmaperror", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "cil", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "ckfinite", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "class", GINT_TO_POINTER (TRUE));
@@ -2375,6 +2745,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "final", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "finally", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "fixed", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "flags", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "float32", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "float64", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "float", GINT_TO_POINTER (TRUE));
@@ -2433,6 +2804,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "ldc.i8", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "ldc.r4", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "ldc.r8", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "ldelem", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "ldelema", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "ldelem.i1", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "ldelem.i2", GINT_TO_POINTER (TRUE));
@@ -2520,6 +2892,8 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "nullref", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "object", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "objectref", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "off", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "on", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "opt", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "optil", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "or", GINT_TO_POINTER (TRUE));
@@ -2541,6 +2915,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "preservesig", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "private", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "privatescope", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "property", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "protected", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "public", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "readonly", GINT_TO_POINTER (TRUE));
@@ -2574,6 +2949,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "starg.s", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "static", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "stdcall", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "stelem", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "stelem.i1", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "stelem.i2", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "stelem.i4", GINT_TO_POINTER (TRUE));
@@ -2590,6 +2966,8 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "stind.i", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "stind.r4", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "stind.r8", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "stloc", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "stobj", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "storage", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "stored_object", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "streamed_object", GINT_TO_POINTER (TRUE));
@@ -2597,6 +2975,11 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "strict", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "string", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "struct", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "stsfld", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "sub", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "sub.ovf", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "sub.ovf.un", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "switch", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "synchronized", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "syschar", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "sysstring", GINT_TO_POINTER (TRUE));
@@ -2607,6 +2990,12 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "true", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "type", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "typedref", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "uint", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "uint8", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "uint16", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "uint32", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "uint64", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "unbox", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "unicode", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "unmanagedexp", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "unmanaged", GINT_TO_POINTER (TRUE));
@@ -2622,6 +3011,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "wchar", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "winapi", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "with", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "xor", GINT_TO_POINTER (TRUE));
 }
 
 guint32
@@ -2650,9 +3040,80 @@ get_method_override (MonoImage *m, guint32 token, MonoGenericContext *context)
                impl = method_dor_to_token (cols [MONO_METHODIMPL_BODY]);
                decl = method_dor_to_token (cols [MONO_METHODIMPL_DECLARATION]);
 
-               if (token == impl)
-                       return get_method_core (m, decl, FALSE, context);
+               if (token == impl) {
+                       MonoMethod *mh = NULL;
+                       mh = mono_get_method_full (m, decl, NULL, context);
+                       mh = mono_get_inflated_method (mh);
+
+                       if (mh && (mh->klass && (mh->klass->generic_class || mh->klass->generic_container))) {
+                               char *meth_str;
+                               char *ret;
+                               
+                               meth_str = get_method_core (m, decl, TRUE, context);
+                               ret = g_strdup_printf ("method %s", meth_str);
+                               g_free (meth_str);
+                               return ret;
+                       } else {
+                               return get_method_core (m, decl, FALSE, context);
+                       }
+               }
        }
 
        return NULL;
 }
+
+static void
+check_ambiguous_genparams (MonoGenericContainer *container)
+{
+       GSList *dup_list = NULL, *l;
+       GHashTable *table = NULL;
+       gpointer *p;
+       int i;
+
+       if (!container)
+               return;
+       
+       if (generic_containers && g_hash_table_lookup (generic_containers, container))
+               /* Already been checked for ambiguous gen params */
+               return;
+
+       table = g_hash_table_new (g_str_hash, g_str_equal);
+       for (i = 0; i < container->type_argc; i++) {
+               MonoGenericParam *param = &container->type_params [i];
+
+               if ((p = g_hash_table_lookup (table, param->name)))
+                       dup_list = g_slist_prepend (g_slist_prepend (dup_list, GUINT_TO_POINTER (i + 1)), p);
+               else
+                       g_hash_table_insert (table, (char*)param->name, GUINT_TO_POINTER (i + 1));
+       }
+
+       if (dup_list) {
+               if (!mono_generic_params_with_ambiguous_names)
+                       mono_generic_params_with_ambiguous_names = g_hash_table_new (NULL, NULL);
+               for (l = dup_list; l; l = l->next) {
+                       int param = GPOINTER_TO_UINT (l->data);
+                       g_hash_table_insert (mono_generic_params_with_ambiguous_names,
+                                &container->type_params [param-1],
+                                &container->type_params [param-1]);
+               }
+               g_slist_free (dup_list);
+       }
+
+       if (!generic_containers)
+               generic_containers = g_hash_table_new (NULL, NULL);
+
+       g_hash_table_insert (generic_containers, container, container);
+       g_hash_table_destroy (table);
+}
+       
+static gboolean
+cant_print_generic_param_name (MonoGenericParam *gparam)
+{
+       g_assert (gparam);
+
+       check_ambiguous_genparams (gparam->owner);
+       return (!gparam->owner || (mono_generic_params_with_ambiguous_names && 
+                       g_hash_table_lookup (mono_generic_params_with_ambiguous_names, gparam)));
+}
+
+