Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mono / metadata / debug-helpers.c
index af4ef825232eebc5bbc424ac22e8cca9dce5a523..a20e8ae06e03a9ade8d5e64419f4d0a4b9122220 100644 (file)
@@ -1,8 +1,18 @@
+/*
+ * debug-helpers.c:
+ *
+ * Author:
+ *     Mono Project (http://www.mono-project.com)
+ *
+ * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
+ */
 
 #include <string.h>
 #include "mono/metadata/tokentype.h"
 #include "mono/metadata/opcodes.h"
+#include "mono/metadata/metadata-internals.h"
 #include "mono/metadata/class-internals.h"
+#include "mono/metadata/object-internals.h"
 #include "mono/metadata/mono-endian.h"
 #include "mono/metadata/debug-helpers.h"
 #include "mono/metadata/tabledefs.h"
@@ -14,7 +24,7 @@ struct MonoMethodDesc {
        char *name;
        char *args;
        guint num_args;
-       gboolean include_namespace;
+       gboolean include_namespace, klass_glob, name_glob;
 };
 
 #ifdef HAVE_ARRAY_ELEM_INIT
@@ -73,12 +83,40 @@ append_class_name (GString *res, MonoClass *class, gboolean include_namespace)
                g_string_append_c (res, '/');
        }
        if (include_namespace && *(class->name_space))
-               g_string_sprintfa (res, "%s.", class->name_space);
-       g_string_sprintfa (res, "%s", class->name);
+               g_string_append_printf (res, "%s.", class->name_space);
+       g_string_append_printf (res, "%s", class->name);
+}
+
+static MonoClass*
+find_system_class (const char *name)
+{
+       if (!strcmp (name, "void")) 
+               return mono_defaults.void_class;
+       else if (!strcmp (name, "char")) return mono_defaults.char_class;
+       else if (!strcmp (name, "bool")) return mono_defaults.boolean_class;
+       else if (!strcmp (name, "byte")) return mono_defaults.byte_class;
+       else if (!strcmp (name, "sbyte")) return mono_defaults.sbyte_class;
+       else if (!strcmp (name, "uint16")) return mono_defaults.uint16_class;
+       else if (!strcmp (name, "int16")) return mono_defaults.int16_class;
+       else if (!strcmp (name, "uint")) return mono_defaults.uint32_class;
+       else if (!strcmp (name, "int")) return mono_defaults.int32_class;
+       else if (!strcmp (name, "ulong")) return mono_defaults.uint64_class;
+       else if (!strcmp (name, "long")) return mono_defaults.int64_class;
+       else if (!strcmp (name, "uintptr")) return mono_defaults.uint_class;
+       else if (!strcmp (name, "intptr")) return mono_defaults.int_class;
+       else if (!strcmp (name, "single")) return mono_defaults.single_class;
+       else if (!strcmp (name, "double")) return mono_defaults.double_class;
+       else if (!strcmp (name, "string")) return mono_defaults.string_class;
+       else if (!strcmp (name, "object")) return mono_defaults.object_class;
+       else
+               return NULL;
 }
 
 void
-mono_type_get_desc (GString *res, MonoType *type, gboolean include_namespace) {
+mono_type_get_desc (GString *res, MonoType *type, gboolean include_namespace)
+{
+       int i;
+
        switch (type->type) {
        case MONO_TYPE_VOID:
                g_string_append (res, "void"); break;
@@ -121,8 +159,8 @@ mono_type_get_desc (GString *res, MonoType *type, gboolean include_namespace) {
                g_string_append_c (res, '*');
                break;
        case MONO_TYPE_ARRAY:
-               append_class_name (res, type->data.array->eklass, include_namespace);
-               g_string_sprintfa (res, "[%d]", type->data.array->rank);
+               mono_type_get_desc (res, &type->data.array->eklass->byval_arg, include_namespace);
+               g_string_append_printf (res, "[%d]", type->data.array->rank);
                break;
        case MONO_TYPE_SZARRAY:
                mono_type_get_desc (res, &type->data.klass->byval_arg, include_namespace);
@@ -132,12 +170,45 @@ mono_type_get_desc (GString *res, MonoType *type, gboolean include_namespace) {
        case MONO_TYPE_VALUETYPE:
                append_class_name (res, type->data.klass, include_namespace);
                break;
-       case MONO_TYPE_GENERICINST:
+       case MONO_TYPE_GENERICINST: {
+               MonoGenericContext *context;
+
                mono_type_get_desc (res, &type->data.generic_class->container_class->byval_arg, include_namespace);
+               g_string_append (res, "<");
+               context = &type->data.generic_class->context;
+               if (context->class_inst) {
+                       for (i = 0; i < context->class_inst->type_argc; ++i) {
+                               if (i > 0)
+                                       g_string_append (res, ", ");
+                               mono_type_get_desc (res, context->class_inst->type_argv [i], include_namespace);
+                       }
+               }
+               if (context->method_inst) {
+                       if (context->class_inst)
+                                       g_string_append (res, "; ");
+                       for (i = 0; i < context->method_inst->type_argc; ++i) {
+                               if (i > 0)
+                                       g_string_append (res, ", ");
+                               mono_type_get_desc (res, context->method_inst->type_argv [i], include_namespace);
+                       }
+               }
+               g_string_append (res, ">");
                break;
+       }
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
-               g_string_append (res, type->data.generic_param->name);
+               if (type->data.generic_param) {
+                       MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
+                       if (info)
+                               g_string_append (res, info->name);
+                       else
+                               g_string_append_printf (res, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", mono_generic_param_num (type->data.generic_param));
+               } else {
+                       g_string_append (res, "<unknown>");
+               }
+               break;
+       case MONO_TYPE_TYPEDBYREF:
+               g_string_append (res, "typedbyref");
                break;
        default:
                break;
@@ -150,14 +221,10 @@ char*
 mono_type_full_name (MonoType *type)
 {
        GString *str;
-       char *res;
 
        str = g_string_new ("");
        mono_type_get_desc (str, type, TRUE);
-
-       res = g_strdup (str->str);
-       g_string_free (str, TRUE);
-       return res;
+       return g_string_free (str, FALSE);
 }
 
 char*
@@ -165,7 +232,12 @@ mono_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
 {
        int i;
        char *result;
-       GString *res = g_string_new ("");
+       GString *res;
+
+       if (!sig)
+               return g_strdup ("<invalid signature>");
+
+       res = g_string_new ("");
 
        for (i = 0; i < sig->param_count; ++i) {
                if (i > 0)
@@ -177,6 +249,41 @@ mono_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
        return result;
 }
 
+static void
+ginst_get_desc (GString *str, MonoGenericInst *ginst)
+{
+       int i;
+
+       for (i = 0; i < ginst->type_argc; ++i) {
+               if (i > 0)
+                       g_string_append (str, ", ");
+               mono_type_get_desc (str, ginst->type_argv [i], TRUE);
+       }
+}
+
+char*
+mono_context_get_desc (MonoGenericContext *context)
+{
+       GString *str;
+       char *res;
+
+       str = g_string_new ("");
+       g_string_append (str, "<");
+
+       if (context->class_inst)
+               ginst_get_desc (str, context->class_inst);
+       if (context->method_inst) {
+               if (context->class_inst)
+                       g_string_append (str, "; ");
+               ginst_get_desc (str, context->method_inst);
+       }
+
+       g_string_append (str, ">");
+       res = g_strdup (str->str);
+       g_string_free (str, TRUE);
+       return res;
+}      
+
 /**
  * mono_method_desc_new:
  * @name: the method name.
@@ -189,6 +296,8 @@ mono_signature_get_desc (MonoMethodSignature *sig, gboolean include_namespace)
  *
  * in all the loaded assemblies.
  *
+ * Both classname and methodname can contain '*' which matches anything.
+ *
  * Returns: a parsed representation of the method description.
  */
 MonoMethodDesc*
@@ -201,6 +310,9 @@ mono_method_desc_new (const char *name, gboolean include_namespace)
        class_nspace = g_strdup (name);
        use_args = strchr (class_nspace, '(');
        if (use_args) {
+               /* Allow a ' ' between the method name and the signature */
+               if (use_args > class_nspace && use_args [-1] == ' ')
+                       use_args [-1] = 0;
                *use_args++ = 0;
                end = strchr (use_args, ')');
                if (!end) {
@@ -214,10 +326,10 @@ mono_method_desc_new (const char *name, gboolean include_namespace)
                g_free (class_nspace);
                return NULL;
        }
-       *method_name++ = 0;
        /* allow two :: to separate the method name */
-       if (*method_name == ':')
-               method_name++;
+       if (method_name != class_nspace && method_name [-1] == ':')
+               method_name [-1] = 0;
+       *method_name++ = 0;
        class_name = strrchr (class_nspace, '.');
        if (class_name) {
                *class_name++ = 0;
@@ -232,6 +344,10 @@ mono_method_desc_new (const char *name, gboolean include_namespace)
        result->klass = class_name;
        result->namespace = use_namespace? class_nspace: NULL;
        result->args = use_args? use_args: NULL;
+       if (strstr (result->name, "*"))
+               result->name_glob = TRUE;
+       if (strstr (result->klass, "*"))
+               result->klass_glob = TRUE;
        if (use_args) {
                end = use_args;
                if (*end)
@@ -283,7 +399,14 @@ gboolean
 mono_method_desc_match (MonoMethodDesc *desc, MonoMethod *method)
 {
        char *sig;
-       if (strcmp (desc->name, method->name))
+       gboolean name_match;
+
+       name_match = strcmp (desc->name, method->name) == 0;
+#ifndef _EGLIB_MAJOR
+       if (!name_match && desc->name_glob)
+               name_match = g_pattern_match_simple (desc->name, method->name);
+#endif
+       if (!name_match)
                return FALSE;
        if (!desc->args)
                return TRUE;
@@ -298,13 +421,58 @@ mono_method_desc_match (MonoMethodDesc *desc, MonoMethod *method)
        return TRUE;
 }
 
+static const char *
+my_strrchr (const char *str, char ch, int *len)
+{
+       int pos;
+
+       for (pos = (*len)-1; pos >= 0; pos--) {
+               if (str [pos] != ch)
+                       continue;
+
+               *len = pos;
+               return str + pos;
+       }
+
+       return NULL;
+}
+
+static gboolean
+match_class (MonoMethodDesc *desc, int pos, MonoClass *klass)
+{
+       const char *p;
+
+       if (desc->klass_glob && !strcmp (desc->klass, "*"))
+               return TRUE;
+#ifndef _EGLIB_MAJOR
+       if (desc->klass_glob && g_pattern_match_simple (desc->klass, klass->name))
+               return TRUE;
+#endif
+       p = my_strrchr (desc->klass, '/', &pos);
+       if (!p) {
+               if (strncmp (desc->klass, klass->name, pos))
+                       return FALSE;
+               if (desc->namespace && strcmp (desc->namespace, klass->name_space))
+                       return FALSE;
+               return TRUE;
+       }
+
+       if (strcmp (p+1, klass->name))
+               return FALSE;
+       if (!klass->nested_in)
+               return FALSE;
+
+       return match_class (desc, pos, klass->nested_in);
+}
+
 gboolean
 mono_method_desc_full_match (MonoMethodDesc *desc, MonoMethod *method)
 {
-       if (strcmp (desc->klass, method->klass->name))
+       if (!desc->klass)
                return FALSE;
-       if (desc->namespace && strcmp (desc->namespace, method->klass->name_space))
+       if (!match_class (desc, strlen (desc->klass), method->klass))
                return FALSE;
+
        return mono_method_desc_match (desc, method);
 }
 
@@ -329,6 +497,13 @@ mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image)
        MonoMethod *method;
        int i;
 
+       /* Handle short names for system classes */
+       if (!desc->namespace && image == mono_defaults.corlib) {
+               klass = find_system_class (desc->klass);
+               if (klass)
+                       return mono_method_desc_search_in_class (desc, klass);
+       }
+
        if (desc->namespace && desc->klass) {
                klass = mono_class_from_name (image, desc->namespace, desc->klass);
                if (!klass)
@@ -369,12 +544,12 @@ dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned cha
                g_free (tmp);
        }
        if (dh->label_format)
-               g_string_sprintfa (str, dh->label_format, label);
+               g_string_append_printf (str, dh->label_format, label);
        
        i = mono_opcode_value (&ip, end);
        ip++;
        opcode = &mono_opcodes [i];
-       g_string_sprintfa (str, "%-10s", mono_opcode_name (i));
+       g_string_append_printf (str, "%-10s", mono_opcode_name (i));
 
        switch (opcode->argument) {
        case MonoInlineNone:
@@ -390,37 +565,76 @@ dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned cha
                        g_string_append (str, tmp);
                        g_free (tmp);
                } else {
-                       g_string_sprintfa (str, "0x%08x", token);
+                       g_string_append_printf (str, "0x%08x", token);
                }
                ip += 4;
                break;
-       case MonoInlineString:
-               /* TODO */
+       case MonoInlineString: {
+               const char *blob;
+               char *s;
+               size_t len2;
+               char *blob2 = NULL;
+
+               if (!method->klass->image->dynamic) {
+                       token = read32 (ip);
+                       blob = mono_metadata_user_string (method->klass->image, mono_metadata_token_index (token));
+
+                       len2 = mono_metadata_decode_blob_size (blob, &blob);
+                       len2 >>= 1;
+
+#ifdef NO_UNALIGNED_ACCESS
+                       /* The blob might not be 2 byte aligned */
+                       blob2 = g_malloc ((len2 * 2) + 1);
+                       memcpy (blob2, blob, len2 * 2);
+#else
+                       blob2 = (char*)blob;
+#endif
+
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+                       {
+                               guint16 *buf = g_new (guint16, len2 + 1);
+                               int i;
+
+                               for (i = 0; i < len2; ++i)
+                                       buf [i] = GUINT16_FROM_LE (((guint16*)blob2) [i]);
+                               s = g_utf16_to_utf8 (buf, len2, NULL, NULL, NULL);
+                               g_free (buf);
+                       }
+#else
+                               s = g_utf16_to_utf8 ((gunichar2*)blob2, len2, NULL, NULL, NULL);
+#endif
+
+                       g_string_append_printf (str, "\"%s\"", s);
+                       g_free (s);
+                       if (blob != blob2)
+                               g_free (blob2);
+               }
                ip += 4;
                break;
+       }
        case MonoInlineVar:
-               g_string_sprintfa (str, "%d", read16 (ip));
+               g_string_append_printf (str, "%d", read16 (ip));
                ip += 2;
                break;
        case MonoShortInlineVar:
-               g_string_sprintfa (str, "%d", (*ip));
+               g_string_append_printf (str, "%d", (*ip));
                ip ++;
                break;
        case MonoInlineBrTarget:
                sval = read32 (ip);
                ip += 4;
                if (dh->label_target)
-                       g_string_sprintfa (str, dh->label_target, ip + sval - il_code);
+                       g_string_append_printf (str, dh->label_target, ip + sval - il_code);
                else
-                       g_string_sprintfa (str, "%d", sval);
+                       g_string_append_printf (str, "%d", sval);
                break;
        case MonoShortInlineBrTarget:
                sval = *(const signed char*)ip;
                ip ++;
                if (dh->label_target)
-                       g_string_sprintfa (str, dh->label_target, ip + sval - il_code);
+                       g_string_append_printf (str, dh->label_target, ip + sval - il_code);
                else
-                       g_string_sprintfa (str, "%d", sval);
+                       g_string_append_printf (str, "%d", sval);
                break;
        case MonoInlineSwitch: {
                const unsigned char *end;
@@ -433,9 +647,9 @@ dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned cha
                                g_string_append (str, ", ");
                        label = read32 (ip);
                        if (dh->label_target)
-                               g_string_sprintfa (str, dh->label_target, end + label - il_code);
+                               g_string_append_printf (str, dh->label_target, end + label - il_code);
                        else
-                               g_string_sprintfa (str, "%d", label);
+                               g_string_append_printf (str, "%d", label);
                        ip += 4;
                }
                g_string_append_c (str, ')');
@@ -444,23 +658,23 @@ dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned cha
        case MonoInlineR: {
                double r;
                readr8 (ip, &r);
-               g_string_sprintfa (str, "%g", r);
+               g_string_append_printf (str, "%g", r);
                ip += 8;
                break;
        }
        case MonoShortInlineR: {
                float r;
                readr4 (ip, &r);
-               g_string_sprintfa (str, "%g", r);
+               g_string_append_printf (str, "%g", r);
                ip += 4;
                break;
        }
        case MonoInlineI:
-               g_string_sprintfa (str, "%d", (gint32)read32 (ip));
+               g_string_append_printf (str, "%d", (gint32)read32 (ip));
                ip += 4;
                break;
        case MonoShortInlineI:
-               g_string_sprintfa (str, "%d", *(const signed char*)ip);
+               g_string_append_printf (str, "%d", *(const signed char*)ip);
                ip ++;
                break;
        case MonoInlineI8:
@@ -472,6 +686,7 @@ dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned cha
        if (dh->newline)
                g_string_append (str, dh->newline);
 
+       mono_metadata_free_mh (header);
        return ip;
 }
 
@@ -520,12 +735,50 @@ mono_disasm_code (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const
        return result;
 }
 
+char *
+mono_field_full_name (MonoClassField *field)
+{
+       char *res;
+       const char *nspace = field->parent->name_space;
+
+       res = g_strdup_printf ("%s%s%s:%s", nspace, *nspace ? "." : "",
+                                                  field->parent->name, mono_field_get_name (field));
+
+       return res;
+}
+
 char *
 mono_method_full_name (MonoMethod *method, gboolean signature)
 {
        char *res;
        char wrapper [64];
-       const char *nspace = method->klass->name_space;
+       char *klass_desc = mono_type_full_name (&method->klass->byval_arg);
+       char *inst_desc = NULL;
+
+       if (method->is_inflated && ((MonoMethodInflated*)method)->context.method_inst) {
+               GString *str = g_string_new ("");
+               g_string_append (str, "<");
+               ginst_get_desc (str, ((MonoMethodInflated*)method)->context.method_inst);
+               g_string_append (str, ">");
+
+               inst_desc = str->str;
+               g_string_free (str, FALSE);
+       } else if (method->is_generic) {
+               MonoGenericContainer *container = mono_method_get_generic_container (method);
+
+               GString *str = g_string_new ("");
+               g_string_append (str, "<");
+               ginst_get_desc (str, container->context.method_inst);
+               g_string_append (str, ">");
+
+               inst_desc = str->str;
+               g_string_free (str, FALSE);
+       }
+
+       if (method->wrapper_type != MONO_WRAPPER_NONE)
+               sprintf (wrapper, "(wrapper %s) ", wrapper_type_to_str (method->wrapper_type));
+       else
+               strcpy (wrapper, "");
 
        if (signature) {
                char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
@@ -534,17 +787,17 @@ mono_method_full_name (MonoMethod *method, gboolean signature)
                        sprintf (wrapper, "(wrapper %s) ", wrapper_type_to_str (method->wrapper_type));
                else
                        strcpy (wrapper, "");
-               res = g_strdup_printf ("%s%s%s%s:%s (%s)", wrapper, 
-                                                          nspace, *nspace ? "." : "",
-                                                          method->klass->name, method->name, tmpsig);
+               res = g_strdup_printf ("%s%s:%s%s (%s)", wrapper, klass_desc, 
+                                                          method->name, inst_desc ? inst_desc : "", tmpsig);
                g_free (tmpsig);
        } else {
-
-               res = g_strdup_printf ("%02d %s%s%s:%s", method->wrapper_type,
-                                                          nspace, *nspace ? "." : "",
-                                                          method->klass->name, method->name);
+               res = g_strdup_printf ("%s%s:%s%s", wrapper, klass_desc,
+                                                          method->name, inst_desc ? inst_desc : "");
        }
 
+       g_free (klass_desc);
+       g_free (inst_desc);
+
        return res;
 }
 
@@ -553,11 +806,11 @@ print_name_space (MonoClass *klass)
 {
        if (klass->nested_in) {
                print_name_space (klass->nested_in);
-               g_print (klass->nested_in->name);
+               g_print ("%s", klass->nested_in->name);
                return "/";
        }
        if (klass->name_space [0]) {
-               g_print (klass->name_space);
+               g_print ("%s", klass->name_space);
                return ".";
        }
        return "";
@@ -593,7 +846,7 @@ mono_object_describe (MonoObject *obj)
                MonoArray *array = (MonoArray*)obj;
                sep = print_name_space (klass);
                g_print ("%s%s", sep, klass->name);
-               g_print (" at %p, rank: %d, length: %d\n", obj, klass->rank, mono_array_length (array));
+               g_print (" at %p, rank: %d, length: %d\n", obj, klass->rank, (int)mono_array_length (array));
        } else {
                sep = print_name_space (klass);
                g_print ("%s%s", sep, klass->name);
@@ -606,7 +859,7 @@ static void
 print_field_value (const char *field_ptr, MonoClassField *field, int type_offset)
 {
        MonoType *type;
-       g_print ("At %p (ofs: %2d) %s: ", field_ptr, field->offset + type_offset, field->name);
+       g_print ("At %p (ofs: %2d) %s: ", field_ptr, field->offset + type_offset, mono_field_get_name (field));
        type = mono_type_get_underlying_type (field->type);
 
        switch (type->type) {
@@ -654,10 +907,10 @@ print_field_value (const char *field_ptr, MonoClassField *field, int type_offset
                g_print ("%u\n", *(guint32*)field_ptr);
                break;
        case MONO_TYPE_I8:
-               g_print ("%lld\n", *(gint64*)field_ptr);
+               g_print ("%lld\n", (long long int)*(gint64*)field_ptr);
                break;
        case MONO_TYPE_U8:
-               g_print ("%llu\n", *(guint64*)field_ptr);
+               g_print ("%llu\n", (long long unsigned int)*(guint64*)field_ptr);
                break;
        case MONO_TYPE_R4:
                g_print ("%f\n", *(gfloat*)field_ptr);
@@ -683,7 +936,7 @@ objval_describe (MonoClass *class, const char *addr)
        MonoClassField *field;
        MonoClass *p;
        const char *field_ptr;
-       int type_offset = 0;
+       gssize type_offset = 0;
        if (class->valuetype)
                type_offset = -sizeof (MonoObject);
 
@@ -747,8 +1000,12 @@ mono_class_describe_statics (MonoClass* klass)
        MonoClassField *field;
        MonoClass *p;
        const char *field_ptr;
-       const char *addr = mono_class_vtable (mono_domain_get (), klass)->data;
-       if (!addr)
+       MonoVTable *vtable = mono_class_vtable_full (mono_domain_get (), klass, FALSE);
+       const char *addr;
+
+       if (!vtable)
+               return;
+       if (!(addr = mono_vtable_get_static_field_data (vtable)))
                return;
 
        for (p = klass; p != NULL; p = p->parent) {
@@ -765,4 +1022,3 @@ mono_class_describe_statics (MonoClass* klass)
                }
        }
 }
-