X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fimage.c;h=ab03895ee7c68ebd2d80900306557d9db92ecb28;hb=3d0e5bf63c66a86f9f2ce2c0ea6ec6c33371af90;hp=18629b28c484a934aaa2d7eb8a5691866b88d112;hpb=fcb7a55456c6633ae69356d839c0da4f2ab1f791;p=mono.git diff --git a/mono/metadata/image.c b/mono/metadata/image.c index 18629b28c48..ab03895ee7c 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -22,12 +22,19 @@ #include "tabledefs.h" #include "tokentype.h" #include "metadata-internals.h" +#include "profiler-private.h" #include "loader.h" #include #include +#include +#include +#include +#include #include #include +#ifdef HAVE_UNISTD_H #include +#endif #define INVALID_ADDRESS 0xffffffff @@ -35,9 +42,7 @@ * Keeps track of the various assemblies loaded */ static GHashTable *loaded_images_hash; -static GHashTable *loaded_images_guid_hash; static GHashTable *loaded_images_refonly_hash; -static GHashTable *loaded_images_refonly_guid_hash; static gboolean debug_assembly_unload = FALSE; @@ -62,6 +67,17 @@ mono_cli_rva_image_map (MonoCLIImageInfo *iinfo, guint32 addr) return INVALID_ADDRESS; } +/** + * mono_images_rva_map: + * @image: a MonoImage + * @addr: relative virtual address (RVA) + * + * This is a low-level routine used by the runtime to map relative + * virtual address (RVA) into their location in memory. + * + * Returns: the address in memory for the given RVA, or NULL if the + * RVA is not valid for this image. + */ char * mono_image_rva_map (MonoImage *image, guint32 addr) { @@ -85,50 +101,6 @@ mono_image_rva_map (MonoImage *image, guint32 addr) return NULL; } -static gchar * -canonicalize_path (const char *path) -{ - gchar *abspath, *pos, *lastpos, *dest; - int backc; - - if (g_path_is_absolute (path)) { - abspath = g_strdup (path); - } else { - gchar *tmpdir = g_get_current_dir (); - abspath = g_build_filename (tmpdir, path, NULL); - g_free (tmpdir); - } - - abspath = g_strreverse (abspath); - - backc = 0; - dest = lastpos = abspath; - pos = strchr (lastpos, G_DIR_SEPARATOR); - - while (pos != NULL) { - int len = pos - lastpos; - if (len == 1 && lastpos [0] == '.') { - // nop - } else if (len == 2 && lastpos [0] == '.' && lastpos [1] == '.') { - backc++; - } else if (len > 0) { - if (backc > 0) { - backc--; - } else { - if (dest != lastpos) - /* The two strings can overlap */ - memmove (dest, lastpos, len + 1); - dest += len + 1; - } - } - lastpos = pos + 1; - pos = strchr (lastpos, G_DIR_SEPARATOR); - } - - if (dest != lastpos) strcpy (dest, lastpos); - return g_strreverse (abspath); -} - /** * mono_images_init: * @@ -140,13 +112,25 @@ mono_images_init (void) InitializeCriticalSection (&images_mutex); loaded_images_hash = g_hash_table_new (g_str_hash, g_str_equal); - loaded_images_guid_hash = g_hash_table_new (g_str_hash, g_str_equal); loaded_images_refonly_hash = g_hash_table_new (g_str_hash, g_str_equal); - loaded_images_refonly_guid_hash = g_hash_table_new (g_str_hash, g_str_equal); debug_assembly_unload = getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL; } +/** + * mono_images_cleanup: + * + * Free all resources used by this module. + */ +void +mono_images_cleanup (void) +{ + DeleteCriticalSection (&images_mutex); + + g_hash_table_destroy (loaded_images_hash); + g_hash_table_destroy (loaded_images_refonly_hash); +} + /** * mono_image_ensure_section_idx: * @image: The image we are operating on @@ -372,8 +356,11 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) image->heap_guid.size = read32 (ptr + 4); ptr += 8 + 6; } else if (strncmp (ptr + 8, "#-", 3) == 0) { - g_print ("Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).", image->name); - return FALSE; + image->heap_tables.data = image->raw_metadata + read32 (ptr); + image->heap_tables.size = read32 (ptr + 4); + ptr += 8 + 3; + image->uncompressed_metadata = TRUE; + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).\n", image->name); } else { g_message ("Unknown heap type: %s\n", ptr + 8); ptr += 8 + strlen (ptr + 8) + 1; @@ -386,7 +373,7 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) g_assert (image->heap_guid.data); g_assert (image->heap_guid.size >= 16); - image->guid = mono_guid_to_string (image->heap_guid.data); + image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data); return TRUE; } @@ -450,143 +437,154 @@ load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo) } void -mono_image_add_to_name_cache (MonoImage *image, const char *nspace, - const char *name, guint32 index) +mono_image_check_for_module_cctor (MonoImage *image) { - GHashTable *nspace_table; - GHashTable *name_cache = image->name_cache; - - if (!(nspace_table = g_hash_table_lookup (name_cache, nspace))) { - nspace_table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table); + MonoTableInfo *t, *mt; + t = &image->tables [MONO_TABLE_TYPEDEF]; + mt = &image->tables [MONO_TABLE_METHOD]; + if (mono_get_runtime_info ()->framework_version [0] == '1') { + image->checked_module_cctor = TRUE; + return; + } + if (image->dynamic) { + /* FIXME: */ + image->checked_module_cctor = TRUE; + return; } - g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index)); + if (t->rows >= 1) { + guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME); + const char *name = mono_metadata_string_heap (image, nameidx); + if (strcmp (name, "") == 0) { + guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1; + guint32 last_method; + if (t->rows > 1) + last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1; + else + last_method = mt->rows; + for (; first_method < last_method; first_method++) { + nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME); + name = mono_metadata_string_heap (image, nameidx); + if (strcmp (name, ".cctor") == 0) { + image->has_module_cctor = TRUE; + image->checked_module_cctor = TRUE; + return; + } + } + } + } + image->has_module_cctor = FALSE; + image->checked_module_cctor = TRUE; } static void -load_modules (MonoImage *image, MonoImageOpenStatus *status) +load_modules (MonoImage *image) { MonoTableInfo *t; - int i; - char *base_dir; - gboolean refonly = image->ref_only; if (image->modules) return; t = &image->tables [MONO_TABLE_MODULEREF]; image->modules = g_new0 (MonoImage *, t->rows); + image->modules_loaded = g_new0 (gboolean, t->rows); image->module_count = t->rows; - base_dir = g_path_get_dirname (image->name); - for (i = 0; i < t->rows; i++){ - char *module_ref; - const char *name; - guint32 cols [MONO_MODULEREF_SIZE]; - - mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE); - name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]); - module_ref = g_build_filename (base_dir, name, NULL); - image->modules [i] = mono_image_open_full (module_ref, status, refonly); - if (image->modules [i]) { - mono_image_addref (image->modules [i]); - /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */ - } - /* - * FIXME: what do we do here? it could be a native dll... - * We should probably do lazy-loading of modules. - */ - if (status) - *status = MONO_IMAGE_OK; - g_free (module_ref); - } - - g_free (base_dir); } -static void -load_class_names (MonoImage *image) +/** + * mono_image_load_module: + * + * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if + * it cannot be loaded. + */ +MonoImage* +mono_image_load_module (MonoImage *image, int idx) { - MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF]; - guint32 cols [MONO_TYPEDEF_SIZE]; - const char *name; - const char *nspace; - guint32 i, visib, nspace_index; - GHashTable *name_cache2, *nspace_table; - - /* Temporary hash table to avoid lookups in the nspace_table */ - name_cache2 = g_hash_table_new (NULL, NULL); - - for (i = 1; i <= t->rows; ++i) { - mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE); - /* nested types are accessed from the nesting name */ - visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK; - if (visib > TYPE_ATTRIBUTE_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_ASSEMBLY) + MonoTableInfo *t; + MonoTableInfo *file_table; + int i; + char *base_dir; + gboolean refonly = image->ref_only; + GList *list_iter, *valid_modules = NULL; + MonoImageOpenStatus status; + + g_assert (idx <= image->module_count); + if (image->modules_loaded [idx - 1]) + return image->modules [idx - 1]; + + file_table = &image->tables [MONO_TABLE_FILE]; + for (i = 0; i < file_table->rows; i++) { + guint32 cols [MONO_FILE_SIZE]; + mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE); + if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA) continue; - name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); - nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); - - nspace_index = cols [MONO_TYPEDEF_NAMESPACE]; - nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index)); - if (!nspace_table) { - nspace_table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table); - g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index), - nspace_table); - } - g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i)); + valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME])); } - /* Load type names from EXPORTEDTYPES table */ + t = &image->tables [MONO_TABLE_MODULEREF]; + base_dir = g_path_get_dirname (image->name); + { - MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE]; - guint32 cols [MONO_EXP_TYPE_SIZE]; - int i; + char *module_ref; + const char *name; + guint32 cols [MONO_MODULEREF_SIZE]; + /* if there is no file table, we try to load the module... */ + int valid = file_table->rows == 0; - for (i = 0; i < t->rows; ++i) { - mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE); - name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]); - nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]); - - nspace_index = cols [MONO_EXP_TYPE_NAMESPACE]; - nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index)); - if (!nspace_table) { - nspace_table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table); - g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index), - nspace_table); + mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE); + name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]); + for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) { + /* be safe with string dups, but we could just compare string indexes */ + if (strcmp (list_iter->data, name) == 0) { + valid = TRUE; + break; + } + } + if (valid) { + module_ref = g_build_filename (base_dir, name, NULL); + image->modules [idx - 1] = mono_image_open_full (module_ref, &status, refonly); + if (image->modules [idx - 1]) { + mono_image_addref (image->modules [idx - 1]); + image->modules [idx - 1]->assembly = image->assembly; + /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */ } - g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1))); + g_free (module_ref); } } - g_hash_table_destroy (name_cache2); + image->modules_loaded [idx - 1] = TRUE; + + g_free (base_dir); + g_list_free (valid_modules); + + return image->modules [idx - 1]; } -static void -register_guid (gpointer key, gpointer value, gpointer user_data) +static gpointer +class_key_extract (gpointer value) { - MonoImage *image = (MonoImage*)value; + MonoClass *class = value; - if (!g_hash_table_lookup (loaded_images_guid_hash, image)) - g_hash_table_insert (loaded_images_guid_hash, image->guid, image); + return GUINT_TO_POINTER (class->type_token); } -static void -build_guid_table (gboolean refonly) +static gpointer* +class_next_value (gpointer value) { - GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash; - g_hash_table_foreach (loaded_images, register_guid, NULL); + MonoClass *class = value; + + return (gpointer*)&class->next_class_cache; } void mono_image_init (MonoImage *image) { - image->mempool = mono_mempool_new (); + image->mempool = mono_mempool_new_size (512); image->method_cache = g_hash_table_new (NULL, NULL); - image->class_cache = g_hash_table_new (NULL, NULL); + mono_internal_hash_table_init (&image->class_cache, + g_direct_hash, + class_key_extract, + class_next_value); image->field_cache = g_hash_table_new (NULL, NULL); - image->name_cache = g_hash_table_new (g_str_hash, g_str_equal); - image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); image->delegate_begin_invoke_cache = g_hash_table_new ((GHashFunc)mono_signature_hash, @@ -601,55 +599,59 @@ mono_image_init (MonoImage *image) g_hash_table_new ((GHashFunc)mono_signature_hash, (GCompareFunc)mono_metadata_signature_equal); + image->runtime_invoke_direct_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); image->managed_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); image->native_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); image->remoting_invoke_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->cominterop_invoke_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->cominterop_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); image->synchronized_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); image->unbox_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->ldfld_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->ldflda_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->ldfld_remote_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->stfld_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->stfld_remote_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->isinst_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->castclass_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->proxy_isinst_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); + image->typespec_cache = g_hash_table_new (NULL, NULL); image->memberref_signatures = g_hash_table_new (NULL, NULL); image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal); image->method_signatures = g_hash_table_new (NULL, NULL); } -static MonoImage * -do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, - gboolean care_about_cli) -{ - MonoCLIImageInfo *iinfo; - MonoDotNetHeader *header; - MonoMSDOSHeader msdos; - guint32 offset = 0; - - mono_image_init (image); - - iinfo = image->image_info; - header = &iinfo->cli_header; - - if (status) - *status = MONO_IMAGE_IMAGE_INVALID; +#if G_BYTE_ORDER != G_LITTLE_ENDIAN +#define SWAP64(x) (x) = GUINT64_FROM_LE ((x)) +#define SWAP32(x) (x) = GUINT32_FROM_LE ((x)) +#define SWAP16(x) (x) = GUINT16_FROM_LE ((x)) +#define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0) +#else +#define SWAP64(x) +#define SWAP32(x) +#define SWAP16(x) +#define SWAPPDE(x) +#endif - if (offset + sizeof (msdos) > image->raw_data_len) - goto invalid_image; - memcpy (&msdos, image->raw_data + offset, sizeof (msdos)); - - if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z')) - goto invalid_image; - - msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset); +/* + * Returns < 0 to indicate an error. + */ +static int +do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset) +{ + MonoDotNetHeader64 header64; - offset = msdos.pe_offset; + if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len) + return -1; - if (offset + sizeof (MonoDotNetHeader) > image->raw_data_len) - goto invalid_image; memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader)); - offset += sizeof (MonoDotNetHeader); -#if G_BYTE_ORDER != G_LITTLE_ENDIAN -#define SWAP32(x) (x) = GUINT32_FROM_LE ((x)) -#define SWAP16(x) (x) = GUINT16_FROM_LE ((x)) -#define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0) + if (header->pesig [0] != 'P' || header->pesig [1] != 'E') + return -1; + + /* endian swap the fields common between PE and PE+ */ SWAP32 (header->coff.coff_time); SWAP32 (header->coff.coff_symptr); SWAP32 (header->coff.coff_symcount); @@ -659,15 +661,71 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, SWAP16 (header->coff.coff_attributes); /* MonoPEHeader */ SWAP32 (header->pe.pe_code_size); - SWAP32 (header->pe.pe_data_size); SWAP32 (header->pe.pe_uninit_data_size); SWAP32 (header->pe.pe_rva_entry_point); SWAP32 (header->pe.pe_rva_code_base); SWAP32 (header->pe.pe_rva_data_base); SWAP16 (header->pe.pe_magic); + /* now we are ready for the basic tests */ + + if (header->pe.pe_magic == 0x10B) { + offset += sizeof (MonoDotNetHeader); + SWAP32 (header->pe.pe_data_size); + if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4)) + return -1; + + SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */ + SWAP32 (header->nt.pe_stack_reserve); + SWAP32 (header->nt.pe_stack_commit); + SWAP32 (header->nt.pe_heap_reserve); + SWAP32 (header->nt.pe_heap_commit); + } else if (header->pe.pe_magic == 0x20B) { + /* PE32+ file format */ + if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4)) + return -1; + memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64)); + offset += sizeof (MonoDotNetHeader64); + /* copy the fields already swapped. the last field, pe_data_size, is missing */ + memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4); + /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much. + * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant + */ + SWAP64 (header64.nt.pe_image_base); + header->nt.pe_image_base = header64.nt.pe_image_base; + SWAP64 (header64.nt.pe_stack_reserve); + header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve; + SWAP64 (header64.nt.pe_stack_commit); + header->nt.pe_stack_commit = header64.nt.pe_stack_commit; + SWAP64 (header64.nt.pe_heap_reserve); + header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve; + SWAP64 (header64.nt.pe_heap_commit); + header->nt.pe_heap_commit = header64.nt.pe_heap_commit; + + header->nt.pe_section_align = header64.nt.pe_section_align; + header->nt.pe_file_alignment = header64.nt.pe_file_alignment; + header->nt.pe_os_major = header64.nt.pe_os_major; + header->nt.pe_os_minor = header64.nt.pe_os_minor; + header->nt.pe_user_major = header64.nt.pe_user_major; + header->nt.pe_user_minor = header64.nt.pe_user_minor; + header->nt.pe_subsys_major = header64.nt.pe_subsys_major; + header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor; + header->nt.pe_reserved_1 = header64.nt.pe_reserved_1; + header->nt.pe_image_size = header64.nt.pe_image_size; + header->nt.pe_header_size = header64.nt.pe_header_size; + header->nt.pe_checksum = header64.nt.pe_checksum; + header->nt.pe_subsys_required = header64.nt.pe_subsys_required; + header->nt.pe_dll_flags = header64.nt.pe_dll_flags; + header->nt.pe_loader_flags = header64.nt.pe_loader_flags; + header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count; + + /* copy the datadir */ + memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir)); + } else { + return -1; + } + /* MonoPEHeaderNT: not used yet */ - SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */ SWAP32 (header->nt.pe_section_align); /* must be 8192 */ SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */ SWAP16 (header->nt.pe_os_major); /* must be 4 */ @@ -682,10 +740,6 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, SWAP32 (header->nt.pe_checksum); SWAP16 (header->nt.pe_subsys_required); SWAP16 (header->nt.pe_dll_flags); - SWAP32 (header->nt.pe_stack_reserve); - SWAP32 (header->nt.pe_stack_commit); - SWAP32 (header->nt.pe_heap_reserve); - SWAP32 (header->nt.pe_heap_commit); SWAP32 (header->nt.pe_loader_flags); SWAP32 (header->nt.pe_data_dir_count); @@ -707,19 +761,49 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, SWAPPDE (header->datadir.pe_cli_header); SWAPPDE (header->datadir.pe_reserved); -#undef SWAP32 -#undef SWAP16 -#undef SWAPPDE -#endif + return offset; +} - if (header->coff.coff_machine != 0x14c) +static MonoImage * +do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, + gboolean care_about_cli) +{ + MonoCLIImageInfo *iinfo; + MonoDotNetHeader *header; + MonoMSDOSHeader msdos; + gint32 offset = 0; + + mono_profiler_module_event (image, MONO_PROFILE_START_LOAD); + + mono_image_init (image); + + iinfo = image->image_info; + header = &iinfo->cli_header; + + if (status) + *status = MONO_IMAGE_IMAGE_INVALID; + + if (offset + sizeof (msdos) > image->raw_data_len) + goto invalid_image; + memcpy (&msdos, image->raw_data + offset, sizeof (msdos)); + + if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z')) goto invalid_image; + + msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset); + + offset = msdos.pe_offset; - if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4)) + offset = do_load_header (image, header, offset); + if (offset < 0) goto invalid_image; - if (header->pesig[0] != 'P' || header->pesig[1] != 'E' || header->pe.pe_magic != 0x10B) + /* + * this tests for a x86 machine type, but itanium, amd64 and others could be used, too. + * we skip this test. + if (header->coff.coff_machine != 0x14c) goto invalid_image; + */ #if 0 /* @@ -755,8 +839,6 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, if (!load_metadata (image, iinfo)) goto invalid_image; - load_class_names (image); - /* modules don't have an assembly table row */ if (image->tables [MONO_TABLE_ASSEMBLY].rows) image->assembly_name = mono_metadata_string_heap (image, @@ -767,15 +849,17 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE], 0, MONO_MODULE_NAME)); - load_modules (image, status); + load_modules (image); done: + mono_profiler_module_loaded (image, MONO_PROFILE_OK); if (status) *status = MONO_IMAGE_OK; return image; invalid_image: + mono_profiler_module_loaded (image, MONO_PROFILE_FAILED); mono_image_close (image); return NULL; } @@ -790,9 +874,19 @@ do_mono_image_open (const char *fname, MonoImageOpenStatus *status, struct stat stat_buf; if ((filed = fopen (fname, "rb")) == NULL){ - if (status) - *status = MONO_IMAGE_ERROR_ERRNO; - return NULL; + if (IS_PORTABILITY_SET) { + gchar *ffname = mono_portability_find_file (fname, TRUE); + if (ffname) { + filed = fopen (ffname, "rb"); + g_free (ffname); + } + } + + if (filed == NULL) { + if (status) + *status = MONO_IMAGE_ERROR_ERRNO; + return NULL; + } } if (fstat (fileno (filed), &stat_buf)) { @@ -802,13 +896,16 @@ do_mono_image_open (const char *fname, MonoImageOpenStatus *status, return NULL; } image = g_new0 (MonoImage, 1); - image->file_descr = filed; + image->raw_buffer_used = TRUE; image->raw_data_len = stat_buf.st_size; image->raw_data = mono_raw_buffer_load (fileno (filed), FALSE, 0, stat_buf.st_size); iinfo = g_new0 (MonoCLIImageInfo, 1); image->image_info = iinfo; - image->name = canonicalize_path (fname); + image->name = mono_path_resolve_symlinks (fname); image->ref_only = refonly; + image->ref_count = 1; + + fclose (filed); return do_mono_image_load (image, status, care_about_cli); } @@ -825,22 +922,50 @@ mono_image_loaded_full (const char *name, gboolean refonly) return res; } +/** + * mono_image_loaded: + * @name: name of the image to load + * + * This routine ensures that the given image is loaded. + * + * Returns: the loaded MonoImage, or NULL on failure. + */ MonoImage * mono_image_loaded (const char *name) { return mono_image_loaded_full (name, FALSE); } +typedef struct { + MonoImage *res; + const char* guid; +} GuidData; + +static void +find_by_guid (gpointer key, gpointer val, gpointer user_data) +{ + GuidData *data = user_data; + MonoImage *image; + + if (data->res) + return; + image = val; + if (strcmp (data->guid, mono_image_get_guid (image)) == 0) + data->res = image; +} + MonoImage * mono_image_loaded_by_guid_full (const char *guid, gboolean refonly) { - MonoImage *res; - GHashTable *loaded_images = refonly ? loaded_images_refonly_guid_hash : loaded_images_guid_hash; + GuidData data; + GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash; + data.res = NULL; + data.guid = guid; mono_images_lock (); - res = g_hash_table_lookup (loaded_images, guid); + g_hash_table_foreach (loaded_images, find_by_guid, &data); mono_images_unlock (); - return res; + return data.res; } MonoImage * @@ -868,7 +993,6 @@ register_image (MonoImage *image) g_hash_table_insert (loaded_images, image->name, image); if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == NULL)) g_hash_table_insert (loaded_images, (char *) image->assembly_name, image); - g_hash_table_insert (image->ref_only ? loaded_images_refonly_guid_hash : loaded_images_guid_hash, image->guid, image); mono_images_unlock (); return image; @@ -928,7 +1052,7 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r g_return_val_if_fail (fname != NULL, NULL); - absfname = canonicalize_path (fname); + absfname = mono_path_canonicalize (fname); /* * The easiest solution would be to do all the loading inside the mutex, @@ -942,6 +1066,7 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r g_free (absfname); if (image){ + mono_image_addref (image); mono_images_unlock (); return image; } @@ -959,7 +1084,9 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r * @fname: filename that points to the module we want to open * @status: An error condition is returned in this field * - * Returns: An open image of type %MonoImage or NULL on error. + * Returns: An open image of type %MonoImage or NULL on error. + * The caller holds a temporary reference to the returned image which should be cleared + * when no longer needed by calling mono_image_close (). * if NULL, then check the value of @status for details on the error */ MonoImage * @@ -993,11 +1120,13 @@ free_hash_table (gpointer key, gpointer val, gpointer user_data) g_hash_table_destroy ((GHashTable*)val); } +/* static void free_mr_signatures (gpointer key, gpointer val, gpointer user_data) { mono_metadata_free_method_signature ((MonoMethodSignature*)val); } +*/ static void free_blob_cache_entry (gpointer key, gpointer val, gpointer user_data) @@ -1011,6 +1140,12 @@ free_remoting_wrappers (gpointer key, gpointer val, gpointer user_data) g_free (val); } +static void +free_array_cache_entry (gpointer key, gpointer val, gpointer user_data) +{ + g_slist_free ((GSList*)val); +} + /** * mono_image_addref: * @image: The image file we wish to add a reference to @@ -1046,7 +1181,7 @@ void mono_image_close (MonoImage *image) { MonoImage *image2; - GHashTable *loaded_images, *loaded_images_guid; + GHashTable *loaded_images; int i; g_return_if_fail (image != NULL); @@ -1054,28 +1189,42 @@ mono_image_close (MonoImage *image) if (InterlockedDecrement (&image->ref_count) > 0) return; + mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image); - + + mono_metadata_clean_for_image (image); + + /* + * The caches inside a MonoImage might refer to metadata which is stored in referenced + * assemblies, so we can't release these references in mono_assembly_close () since the + * MonoImage might outlive its associated MonoAssembly. + */ + if (image->references) { + int i; + + for (i = 0; image->references [i]; i++) { + if (image->references [i]) + mono_assembly_close (image->references [i]); + } + + g_free (image->references); + image->references = NULL; + } + mono_images_lock (); loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash; - loaded_images_guid = image->ref_only ? loaded_images_refonly_guid_hash : loaded_images_guid_hash; image2 = g_hash_table_lookup (loaded_images, image->name); if (image == image2) { /* This is not true if we are called from mono_image_open () */ g_hash_table_remove (loaded_images, image->name); - g_hash_table_remove (loaded_images_guid, image->guid); } if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == image)) g_hash_table_remove (loaded_images, (char *) image->assembly_name); - /* Multiple images might have the same guid */ - build_guid_table (image->ref_only); - mono_images_unlock (); - if (image->file_descr) { - fclose (image->file_descr); - image->file_descr = NULL; + if (image->raw_buffer_used) { if (image->raw_data != NULL) mono_raw_buffer_free (image->raw_data); } @@ -1106,22 +1255,43 @@ mono_image_close (MonoImage *image) } g_hash_table_destroy (image->method_cache); - g_hash_table_destroy (image->class_cache); + mono_internal_hash_table_destroy (&image->class_cache); g_hash_table_destroy (image->field_cache); - g_hash_table_destroy (image->array_cache); - g_hash_table_foreach (image->name_cache, free_hash_table, NULL); - g_hash_table_destroy (image->name_cache); + if (image->array_cache) { + g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL); + g_hash_table_destroy (image->array_cache); + } + if (image->ptr_cache) + g_hash_table_destroy (image->ptr_cache); + if (image->name_cache) { + g_hash_table_foreach (image->name_cache, free_hash_table, NULL); + g_hash_table_destroy (image->name_cache); + } g_hash_table_destroy (image->native_wrapper_cache); g_hash_table_destroy (image->managed_wrapper_cache); g_hash_table_destroy (image->delegate_begin_invoke_cache); g_hash_table_destroy (image->delegate_end_invoke_cache); g_hash_table_destroy (image->delegate_invoke_cache); + if (image->delegate_abstract_invoke_cache) + g_hash_table_destroy (image->delegate_abstract_invoke_cache); g_hash_table_foreach (image->remoting_invoke_cache, free_remoting_wrappers, NULL); g_hash_table_destroy (image->remoting_invoke_cache); g_hash_table_destroy (image->runtime_invoke_cache); + g_hash_table_destroy (image->runtime_invoke_direct_cache); g_hash_table_destroy (image->synchronized_cache); g_hash_table_destroy (image->unbox_wrapper_cache); + g_hash_table_destroy (image->cominterop_invoke_cache); + g_hash_table_destroy (image->cominterop_wrapper_cache); g_hash_table_destroy (image->typespec_cache); + g_hash_table_destroy (image->ldfld_wrapper_cache); + g_hash_table_destroy (image->ldflda_wrapper_cache); + g_hash_table_destroy (image->ldfld_remote_wrapper_cache); + g_hash_table_destroy (image->stfld_wrapper_cache); + g_hash_table_destroy (image->stfld_remote_wrapper_cache); + g_hash_table_destroy (image->isinst_cache); + g_hash_table_destroy (image->castclass_cache); + g_hash_table_destroy (image->proxy_isinst_cache); + /* The ownership of signatures is not well defined */ //g_hash_table_foreach (image->memberref_signatures, free_mr_signatures, NULL); g_hash_table_destroy (image->memberref_signatures); @@ -1129,6 +1299,15 @@ mono_image_close (MonoImage *image) g_hash_table_destroy (image->helper_signatures); g_hash_table_destroy (image->method_signatures); + if (image->generic_class_cache) + g_hash_table_destroy (image->generic_class_cache); + + if (image->rgctx_template_hash) + g_hash_table_destroy (image->rgctx_template_hash); + + if (image->generic_class_open_instances_hash) + g_hash_table_destroy (image->generic_class_open_instances_hash); + if (image->interface_bitset) { mono_unload_interface_ids (image->interface_bitset); mono_bitset_free (image->interface_bitset); @@ -1147,6 +1326,12 @@ mono_image_close (MonoImage *image) if (image->modules [i]) mono_image_close (image->modules [i]); } + if (image->modules) + g_free (image->modules); + if (image->modules_loaded) + g_free (image->modules_loaded); + if (image->references) + g_free (image->references); /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/ if (!image->dynamic) { if (debug_assembly_unload) @@ -1198,6 +1383,8 @@ mono_image_close (MonoImage *image) } mono_mempool_destroy (image->mempool); } + + mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD); } /** @@ -1228,7 +1415,8 @@ mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id, MonoPEResourceDirEntry *entry, MonoPEResourceDir *root, guint32 level) { - gboolean is_string=entry->name_is_string; + gboolean is_string, is_dir; + guint32 name_offset, dir_offset; /* Level 0 holds a directory entry for each type of resource * (identified by ID or name). @@ -1240,22 +1428,32 @@ mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id, * Level 2 holds a directory entry for each language pointing to * the actual data. */ + name_offset = GUINT32_FROM_LE (entry->name_offset) & 0x7fffffff; + dir_offset = GUINT32_FROM_LE (entry->dir_offset) & 0x7fffffff; + +#if G_BYTE_ORDER != G_LITTLE_ENDIAN + is_string = (GUINT32_FROM_LE (entry->name_offset) & 0x80000000) != 0; + is_dir = (GUINT32_FROM_LE (entry->dir_offset) & 0x80000000) != 0; +#else + is_string = entry->name_is_string; + is_dir = entry->is_dir; +#endif if(level==0) { - if((is_string==FALSE && entry->name_offset!=res_id) || + if((is_string==FALSE && name_offset!=res_id) || (is_string==TRUE)) { return(NULL); } } else if (level==1) { #if 0 if(name!=NULL && - is_string==TRUE && name!=lookup (entry->name_offset)) { + is_string==TRUE && name!=lookup (name_offset)) { return(NULL); } #endif } else if (level==2) { if ((is_string == FALSE && - entry->name_offset != lang_id && + name_offset != lang_id && lang_id != 0) || (is_string == TRUE)) { return(NULL); @@ -1264,12 +1462,12 @@ mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id, g_assert_not_reached (); } - if(entry->is_dir==TRUE) { - MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+entry->dir_offset); + if(is_dir==TRUE) { + MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset); MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1); guint32 entries, i; - - entries=res_dir->res_named_entries + res_dir->res_id_entries; + + entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries); for(i=0; idir_offset); - - return(data_entry); + MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset); + MonoPEResourceDataEntry *res; + + res = g_new0 (MonoPEResourceDataEntry, 1); + + res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset); + res->rde_size = GUINT32_TO_LE (data_entry->rde_size); + res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage); + res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved); + + return (res); } } @@ -1300,7 +1506,8 @@ mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id, * @name: the resource name to lookup. * * Returns: NULL if not found, otherwise a pointer to the in-memory representation - * of the given resource. + * of the given resource. The caller should free it using g_free () when no longer + * needed. */ gpointer mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name) @@ -1341,8 +1548,8 @@ mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, g if(resource_dir==NULL) { return(NULL); } - - entries=resource_dir->res_named_entries + resource_dir->res_id_entries; + + entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries); res_entries=(MonoPEResourceDirEntry *)(resource_dir+1); for(i=0; i t->rows) return NULL; - if (image->files && image->files [fileidx - 1]) + mono_loader_lock (); + if (image->files && image->files [fileidx - 1]) { + mono_loader_unlock (); return image->files [fileidx - 1]; + } if (!image->files) image->files = g_new0 (MonoImage*, t->rows); @@ -1441,11 +1651,23 @@ mono_image_load_file_for_image (MonoImage *image, int fileidx) image->files [fileidx - 1] = res; } + mono_loader_unlock (); g_free (name); g_free (base_dir); return res; } +/** + * mono_image_get_strong_name: + * @image: a MonoImage + * @size: a guint32 pointer, or NULL. + * + * If the image has a strong name, and @size is not NULL, the value + * pointed to by size will have the size of the strong name. + * + * Returns: NULL if the image does not have a strong name, or a + * pointer to the public key. + */ const char* mono_image_get_strong_name (MonoImage *image, guint32 *size) { @@ -1463,6 +1685,17 @@ mono_image_get_strong_name (MonoImage *image, guint32 *size) return data; } +/** + * mono_image_strong_name_position: + * @image: a MonoImage + * @size: a guint32 pointer, or NULL. + * + * If the image has a strong name, and @size is not NULL, the value + * pointed to by size will have the size of the strong name. + * + * Returns: the position within the image file where the strong name + * is stored. + */ guint32 mono_image_strong_name_position (MonoImage *image, guint32 *size) { @@ -1489,11 +1722,30 @@ mono_image_strong_name_position (MonoImage *image, guint32 *size) return 0; } +/** + * mono_image_get_public_key: + * @image: a MonoImage + * @size: a guint32 pointer, or NULL. + * + * This is used to obtain the public key in the @image. + * + * If the image has a public key, and @size is not NULL, the value + * pointed to by size will have the size of the public key. + * + * Returns: NULL if the image does not have a public key, or a pointer + * to the public key. + */ const char* mono_image_get_public_key (MonoImage *image, guint32 *size) { const char *pubkey; guint32 len, tok; + + if (image->dynamic) { + if (size) + *size = ((MonoDynamicImage*)image)->public_key_len; + return (char*)((MonoDynamicImage*)image)->public_key; + } if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1) return NULL; tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY); @@ -1506,12 +1758,26 @@ mono_image_get_public_key (MonoImage *image, guint32 *size) return pubkey; } +/** + * mono_image_get_name: + * @name: a MonoImage + * + * Returns: the name of the assembly. + */ const char* mono_image_get_name (MonoImage *image) { return image->assembly_name; } +/** + * mono_image_get_filename: + * @image: a MonoImage + * + * Used to get the filename that hold the actual MonoImage + * + * Returns: the filename. + */ const char* mono_image_get_filename (MonoImage *image) { @@ -1546,18 +1812,45 @@ mono_table_info_get_rows (const MonoTableInfo *table) return table->rows; } +/** + * mono_image_get_assembly: + * @image: the MonoImage. + * + * Use this routine to get the assembly that owns this image. + * + * Returns: the assembly that holds this image. + */ MonoAssembly* mono_image_get_assembly (MonoImage *image) { return image->assembly; } +/** + * mono_image_is_dynamic: + * @image: the MonoImage + * + * Determines if the given image was created dynamically through the + * System.Reflection.Emit API + * + * Returns: TRUE if the image was created dynamically, FALSE if not. + */ gboolean mono_image_is_dynamic (MonoImage *image) { return image->dynamic; } +/** + * mono_image_has_authenticode_entry: + * @image: the MonoImage + * + * Use this routine to determine if the image has a Authenticode + * Certificate Table. + * + * Returns: TRUE if the image contains an authenticode entry in the PE + * directory. + */ gboolean mono_image_has_authenticode_entry (MonoImage *image) {