Merge pull request #2200 from xmcclure/image-audit-oops
[mono.git] / mono / dis / main.c
index 3844e9af766242faa430446a22cc48dcaaaa8a47..4d4a51cd8e77fedf3e286e921b33e2cb2adb4e17 100644 (file)
@@ -30,6 +30,7 @@
 #include <mono/metadata/loader.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/appdomain.h>
+#include <mono/utils/bsearch.h>
 
 static void     setup_filter          (MonoImage *image);
 static gboolean should_include_type   (int idx);
@@ -535,8 +536,8 @@ static dis_map_t method_flags_map [] = {
        { METHOD_ATTRIBUTE_RT_SPECIAL_NAME,     "rtspecialname " },
        { METHOD_ATTRIBUTE_UNMANAGED_EXPORT,    "export " },
 /* MS ilasm doesn't compile this statement - is must be added automagically when permissionset are present */
-/*     { METHOD_ATTRIBUTE_HAS_SECURITY,        "hassecurity" }, */
-       { METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT,  "requiresecobj" },
+       { METHOD_ATTRIBUTE_HAS_SECURITY,        "" /*"hassecurity"*/ },
+       { METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT,  "requiresecobj " },
        { METHOD_ATTRIBUTE_PINVOKE_IMPL,        "pinvokeimpl " }, 
        { METHOD_ATTRIBUTE_STRICT,                  "strict " }, 
        { 0, NULL }
@@ -552,10 +553,11 @@ method_flags (guint32 f)
 {
        GString *str = g_string_new ("");
        int access = f & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
+       int rest = f & ~access;
        char *s;
        
        g_string_append (str, map (access, method_access_map));
-       g_string_append (str, flags (f, method_flags_map));
+       g_string_append (str, flags (rest, method_flags_map));
 
        s = str->str;
        g_string_free (str, FALSE);
@@ -566,10 +568,10 @@ method_flags (guint32 f)
 static dis_map_t pinvoke_flags_map [] = {
        { PINVOKE_ATTRIBUTE_NO_MANGLE ,            "nomangle " },
        { PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR,   "lasterr " },
-       { PINVOKE_ATTRIBUTE_BEST_FIT_ENABLED,      "bestfit:on" },
-       { PINVOKE_ATTRIBUTE_BEST_FIT_DISABLED,      "bestfit:off" },
-       { PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_ENABLED, "charmaperror:on" },
-       { PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_DISABLED, "charmaperror:off" },
+       { PINVOKE_ATTRIBUTE_BEST_FIT_ENABLED,      "bestfit:on " },
+       { PINVOKE_ATTRIBUTE_BEST_FIT_DISABLED,      "bestfit:off " },
+       { PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_ENABLED, "charmaperror:on " },
+       { PINVOKE_ATTRIBUTE_THROW_ON_UNMAPPABLE_DISABLED, "charmaperror:off " },
        { 0, NULL }
 };
 
@@ -602,11 +604,12 @@ pinvoke_flags (guint32 f)
        GString *str = g_string_new ("");
        int cset = f & PINVOKE_ATTRIBUTE_CHAR_SET_MASK;
        int cconv = f & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
+       int rest = f & ~(cset | cconv);
        char *s;
 
        g_string_append (str, map (cset, pinvoke_char_set_map));
        g_string_append (str, map (cconv, pinvoke_call_conv_map));
-       g_string_append (str, flags (f, pinvoke_flags_map));
+       g_string_append (str, flags (rest, pinvoke_flags_map));
 
        s = g_strdup(str->str);
        g_string_free (str, FALSE);
@@ -614,46 +617,6 @@ pinvoke_flags (guint32 f)
        return s;
 }
 
-static dis_map_t method_impl_map [] = {
-       { METHOD_IMPL_ATTRIBUTE_IL,              "cil " },
-       { METHOD_IMPL_ATTRIBUTE_NATIVE,          "native " },
-       { METHOD_IMPL_ATTRIBUTE_OPTIL,           "optil " },
-       { METHOD_IMPL_ATTRIBUTE_RUNTIME,         "runtime " },
-       { 0, NULL }
-};
-
-static dis_map_t managed_type_map [] = {
-       { METHOD_IMPL_ATTRIBUTE_UNMANAGED,       "unmanaged " },
-       { METHOD_IMPL_ATTRIBUTE_MANAGED,         "managed " },
-       { 0, NULL }
-};
-
-static dis_map_t managed_impl_flags [] = {
-       { METHOD_IMPL_ATTRIBUTE_FORWARD_REF,     "fwdref " },
-       { METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG,    "preservesig " },
-       { METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL,   "internalcall " },
-       { METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED,    "synchronized " },
-       { METHOD_IMPL_ATTRIBUTE_NOINLINING,      "noinlining " },
-       { 0, NULL }
-};
-
-static char *
-method_impl_flags (guint32 f)
-{
-       GString *str = g_string_new ("");
-       char *s;
-       int code_type = f & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
-       int managed_type = f & METHOD_IMPL_ATTRIBUTE_MANAGED_MASK;
-
-       g_string_append (str, map (code_type, method_impl_map));
-       g_string_append (str, map (managed_type, managed_type_map));
-       g_string_append (str, flags (f, managed_impl_flags));
-       
-       s = str->str;
-       g_string_free (str, FALSE);
-       return s;
-}
-
 static void
 dis_locals (MonoImage *m, MonoMethodHeader *mh, const char *ptr) 
 {
@@ -663,16 +626,14 @@ dis_locals (MonoImage *m, MonoMethodHeader *mh, const char *ptr)
                unsigned char flags = *(const unsigned char *) ptr;
                unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
                guint16 fat_flags;
-               guint32 local_var_sig_tok, max_stack, code_size, init_locals;
-               int hsize;
+               guint32 local_var_sig_tok, init_locals;
 
                g_assert (format == METHOD_HEADER_FAT_FORMAT);
                fat_flags = read16 (ptr);
                ptr += 2;
-               hsize = (fat_flags >> 12) & 0xf;
-               max_stack = read16 (ptr);
+               /* max_stack = read16 (ptr); */
                ptr += 2;
-               code_size = read32 (ptr);
+               /* code_size = read32 (ptr); */
                ptr += 4;
                local_var_sig_tok = read32 (ptr);
                ptr += 4;
@@ -718,7 +679,8 @@ dis_code (MonoImage *m, guint32 token, guint32 rva, MonoGenericContainer *contai
        }
 
        mh = mono_metadata_parse_mh_full (m, container, ptr);
-       if ((entry_point = mono_image_get_entry_point (m)) && mono_metadata_token_index (entry_point)){
+       entry_point = mono_image_get_entry_point (m);
+       if (entry_point && mono_metadata_token_index (entry_point) && mono_metadata_token_table (entry_point) == MONO_TABLE_METHOD) {
                loc = mono_metadata_locate_token (m, entry_point);
                if (rva == read32 (loc))
                        fprintf (output, "\t.entrypoint\n");
@@ -872,6 +834,7 @@ dis_method_list (const char *klass_name, MonoImage *m, guint32 start, guint32 en
        }
 
        for (i = start; i < end; i++){
+               MonoError error;
                MonoMethodSignature *ms;
                MonoGenericContainer *container;
                char *flags, *impl_flags;
@@ -884,20 +847,29 @@ dis_method_list (const char *klass_name, MonoImage *m, guint32 start, guint32 en
                mono_metadata_decode_row (t, i, cols, MONO_METHOD_SIZE);
 
                flags = method_flags (cols [MONO_METHOD_FLAGS]);
-               impl_flags = method_impl_flags (cols [MONO_METHOD_IMPLFLAGS]);
+               impl_flags = get_method_impl_flags (cols [MONO_METHOD_IMPLFLAGS]);
 
                sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
                mono_metadata_decode_blob_size (sig, &sig);
 
                container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), type_container);
-               if (container)
-                       mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_METHOD_DEF | (i + 1), container);
-               else 
+               if (container) {
+                       MonoError error;
+                       mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | (i + 1), container, &error);
+                       g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
+               } else {
                        container = type_container;
+               }
 
-               ms = mono_metadata_parse_method_signature_full (m, container, i + 1, sig, &sig);
-               sig_str = dis_stringify_method_signature (m, ms, i + 1, container, FALSE);
-               method_name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
+               ms = mono_metadata_parse_method_signature_full (m, container, i + 1, sig, &sig, &error);
+               if (ms != NULL){
+                       sig_str = dis_stringify_method_signature (m, ms, i + 1, container, FALSE);
+                       method_name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
+               } else {
+                       sig_str = NULL;
+                       method_name = g_strdup ("<NULL METHOD SIGNATURE>");
+                       mono_error_cleanup (&error);
+               }
 
                fprintf (output, "    // method line %d\n", i + 1);
                fprintf (output, "    .method %s", flags);
@@ -1008,20 +980,20 @@ dis_property_signature (MonoImage *m, guint32 prop_idx, MonoGenericContainer *co
                g_string_append (res, "instance ");
        ptr++;
        pcount = mono_metadata_decode_value (ptr, &ptr);
-       type = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, ptr, &ptr);
+       type = mono_metadata_parse_type_full (m, container, 0, ptr, &ptr);
        blurb = dis_stringify_type (m, type, TRUE);
        if (prop_flags & 0x0200)
                g_string_append (res, "specialname ");
        if (prop_flags & 0x0400)
                g_string_append (res, "rtspecialname ");
        qk = get_escaped_name (name);
-       g_string_sprintfa (res, "%s %s (", blurb, qk);
+       g_string_append_printf (res, "%s %s (", blurb, qk);
        g_free (qk);
        g_free (blurb);
        for (i = 0; i < pcount; i++) {
                if (i)
                        g_string_append (res, ", ");
-               param = mono_metadata_parse_type_full (m, container, MONO_PARSE_PARAM, 0, ptr, &ptr);
+               param = mono_metadata_parse_type_full (m, container, 0, ptr, &ptr);
                blurb = dis_stringify_param (m, param);
                g_string_append (res, blurb);
                g_free (blurb);
@@ -1067,7 +1039,7 @@ dis_event_signature (MonoImage *m, guint32 event_idx, MonoGenericContainer *cont
                g_string_append (res, "specialname ");
        if (event_flags & 0x0400)
                g_string_append (res, "rtspecialname ");
-       g_string_sprintfa (res, "%s %s", type, esname);
+       g_string_append_printf (res, "%s %s", type, esname);
 
        g_free (type);
        g_free (esname);
@@ -1141,7 +1113,7 @@ dis_interfaces (MonoImage *m, guint32 typedef_row, MonoGenericContainer *contain
        loc.col_idx = MONO_INTERFACEIMPL_CLASS;
        loc.idx = typedef_row;
 
-       if (!bsearch (&loc, table->base, table->rows, table->row_size, table_locator))
+       if (!mono_binary_search (&loc, table->base, table->rows, table->row_size, table_locator))
                return;
 
        start = loc.result;
@@ -1204,12 +1176,19 @@ dis_type (MonoImage *m, int n, int is_nested, int forward)
 
        name = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME]);
        nspace = mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE]);
-       if (*nspace && !is_nested) 
-               fprintf (output, ".namespace %s\n{\n", nspace);
+       if (*nspace && !is_nested) {
+               char *esnspace;
+               esnspace = get_escaped_name (nspace);
+               fprintf (output, ".namespace %s\n{\n", esnspace);
+               g_free (esnspace);
+       }
 
        container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), NULL);
-       if (container)
-               mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_TYPE_DEF | (n + 1), container);
+       if (container) {
+               MonoError error;
+               mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (n + 1), container, &error);
+               g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
+       }
 
        esname = get_escaped_name (name);
        if ((cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
@@ -1217,7 +1196,7 @@ dis_type (MonoImage *m, int n, int is_nested, int forward)
                
                 param = get_generic_param (m, container);
                if (param) {
-                       fprintf (output, param);
+                       fprintf (output, "%s", param);
                        g_free (param);
                }
                 fprintf (output, "\n");
@@ -1231,7 +1210,7 @@ dis_type (MonoImage *m, int n, int is_nested, int forward)
 
                 param = get_generic_param (m, container);
                if (param) {
-                       fprintf (output, param);
+                       fprintf (output, "%s", param);
                        g_free (param);
                }
                fprintf (output, "\n");
@@ -1335,8 +1314,7 @@ dis_globals (MonoImage *m)
 
 }
 
-static void
-dis_mresource (MonoImage *m)
+static void dis_resources_worker (MonoImage *m, gboolean just_print)
 {
        MonoTableInfo *t = &m->tables [MONO_TABLE_MANIFESTRESOURCE];
        int i;
@@ -1349,10 +1327,21 @@ dis_mresource (MonoImage *m)
 
                mono_metadata_decode_row (t, i, cols, MONO_MANIFEST_SIZE);
                name = mono_metadata_string_heap (m, cols [MONO_MANIFEST_NAME]);
+
+               if (just_print)
+                       fprintf (output, "%8x: %s", cols [MONO_MANIFEST_OFFSET], name);
                
-               if (! (res = mono_image_get_resource (m, cols [MONO_MANIFEST_OFFSET], &size)))
+               if (! (res = mono_image_get_resource (m, cols [MONO_MANIFEST_OFFSET], &size))) {
+                       if (just_print)
+                               fprintf (output, " (absent from image)\n");
                        continue;       
+               }
 
+               if (just_print) {
+                       fprintf (output, " (size %u)\n", size);
+                       continue;
+               }
+               
                if ( (fp = fopen (name, "ab")) ) {
                        if (ftell (fp) == 0)
                                fwrite (res, size, 1, fp);
@@ -1365,6 +1354,107 @@ dis_mresource (MonoImage *m)
        }               
 }
 
+static void
+dis_mresource (MonoImage *m)
+{
+       dis_resources_worker (m, FALSE);
+}
+
+static void
+dis_presource (MonoImage *m)
+{
+       dis_resources_worker (m, TRUE);
+}
+
+static char *
+exported_type_flags (guint32 flags)
+{
+       static char buffer [1024];
+       int visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+
+       buffer [0] = 0;
+
+       if (flags & TYPE_ATTRIBUTE_FORWARDER) {
+               strcat (buffer, "forwarder ");
+               return buffer;
+       }
+
+       strcat (buffer, map (visibility, visibility_map));
+       return buffer;
+}
+
+static char *
+get_escaped_fullname (MonoImage *m, guint32 nspace_idx, guint32 name_idx)
+{
+       const char *name, *nspace;
+       char *fullname, *esfullname;
+
+       nspace = mono_metadata_string_heap (m, nspace_idx);
+       name = mono_metadata_string_heap (m, name_idx);
+
+       fullname = g_strdup_printf ("%s%s%s", nspace, *nspace ? "." : "", name);
+       esfullname = get_escaped_name (fullname);
+
+       g_free (fullname);
+
+       return esfullname;
+}
+
+static void
+dis_exported_types (MonoImage *m)
+{
+       MonoTableInfo *t = &m->tables [MONO_TABLE_EXPORTEDTYPE];
+       int i;
+
+       for (i = 1; i <= t->rows; i++) {
+               char *fullname;
+               guint32 impl, idx, type_token;
+               guint32 cols [MONO_EXP_TYPE_SIZE];
+
+               mono_metadata_decode_row (t, i - 1, cols, MONO_EXP_TYPE_SIZE);
+
+               fullname = get_escaped_fullname (m, cols [MONO_EXP_TYPE_NAMESPACE], cols [MONO_EXP_TYPE_NAME]);
+
+               fprintf (output, "\n");
+               fprintf (output, ".class extern %s%s\n", exported_type_flags (cols [MONO_EXP_TYPE_FLAGS]), fullname);
+               fprintf (output, "{\n");
+
+               g_free (fullname);
+
+               impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
+               if (impl) {
+                       idx = impl >> MONO_IMPLEMENTATION_BITS;
+                       switch (impl & MONO_IMPLEMENTATION_MASK) {
+                       case MONO_IMPLEMENTATION_FILE:
+                               fprintf (output, "    .file '%s'\n",
+                                       mono_metadata_string_heap (m, mono_metadata_decode_row_col (&m->tables [MONO_TABLE_FILE], idx - 1, MONO_FILE_NAME)));
+                               break;
+                       case MONO_IMPLEMENTATION_ASSEMBLYREF:
+                               fprintf (output, "    .assembly extern '%s'\n",
+                                       mono_metadata_string_heap (m, mono_metadata_decode_row_col (&m->tables [MONO_TABLE_ASSEMBLYREF], idx - 1, MONO_ASSEMBLYREF_NAME)));
+                               break;
+                       case MONO_IMPLEMENTATION_EXP_TYPE:
+                               fullname = get_escaped_fullname (
+                                       m,
+                                       mono_metadata_decode_row_col (&m->tables [MONO_TABLE_EXPORTEDTYPE], idx - 1, MONO_EXP_TYPE_NAMESPACE),
+                                       mono_metadata_decode_row_col (&m->tables [MONO_TABLE_EXPORTEDTYPE], idx - 1, MONO_EXP_TYPE_NAME));
+                               fprintf (output, "    .class extern %s\n", fullname);
+                               g_free (fullname);
+                               break;
+                       default:
+                               g_assert_not_reached ();
+                               break;
+                       }
+               }
+
+               type_token = cols [MONO_EXP_TYPE_TYPEDEF];
+               if (type_token)
+                       fprintf (output, "    .class 0x%08x\n", type_token | MONO_TOKEN_TYPE_DEF);
+
+               fprintf (output, "}\n");
+       }
+}
+
 /**
  * dis_types:
  * @m: metadata context
@@ -1476,6 +1566,7 @@ struct {
        { "--moduleref",   MONO_TABLE_MODULEREF,        dump_table_moduleref },
        { "--module",      MONO_TABLE_MODULE,           dump_table_module },
        { "--mresources",  0,   dis_mresource },
+       { "--presources", 0, dis_presource },
        { "--nested",      MONO_TABLE_NESTEDCLASS,      dump_table_nestedclass },
        { "--param",       MONO_TABLE_PARAM,            dump_table_param },
        { "--parconst",    MONO_TABLE_GENERICPARAMCONSTRAINT, dump_table_parconstraint },
@@ -1509,15 +1600,14 @@ disassemble_file (const char *file)
 {
        MonoImageOpenStatus status;
        MonoImage *img;
-       MonoAssembly *assembly;
-
 
        img = mono_image_open (file, &status);
        if (!img) {
                fprintf (stderr, "Error while trying to process %s\n", file);
                return;
        } else {
-               assembly = mono_assembly_load_from_full (img, file, &status, FALSE);
+               /* FIXME: is this call necessary? */
+               mono_assembly_load_from_full (img, file, &status, FALSE);
        }
 
        setup_filter (img);
@@ -1533,6 +1623,7 @@ disassemble_file (const char *file)
                dis_directive_mresource (img);
                dis_directive_module (img);
                dis_directive_moduleref (img);
+               dis_exported_types (img);
                dis_nt_header (img);
                 if (dump_managed_resources)
                        dis_mresource (img);
@@ -1595,7 +1686,7 @@ table_includes (TableFilter *tf, int idx)
 {
        if (!tf->count)
                return FALSE;
-       return bsearch (&idx, tf->elems, tf->count, sizeof (int), int_cmp) != NULL;
+       return mono_binary_search (&idx, tf->elems, tf->count, sizeof (int), int_cmp) != NULL;
 }
 
 static gboolean