#define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
#define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
+#define mono_images_storage_lock() do { if (mutex_inited) mono_os_mutex_lock (&images_storage_mutex); } while (0)
+#define mono_images_storage_unlock() do { if (mutex_inited) mono_os_mutex_unlock (&images_storage_mutex); } while (0)
static gboolean mutex_inited;
static mono_mutex_t images_mutex;
+static mono_mutex_t images_storage_mutex;
+
+/* Maps string keys to MonoImageStorage values.
+ *
+ * The MonoImageStorage in the hash owns the key.
+ */
+static GHashTable *images_storage_hash;
static void install_pe_loader (void);
image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
}
-/* returns offset relative to image->raw_data */
+/* returns offset relative to m_image_get_raw_data (image) */
guint32
mono_cli_rva_image_map (MonoImage *image, guint32 addr)
{
if ((addr >= tables->st_virtual_address) &&
(addr < tables->st_virtual_address + tables->st_raw_data_size)){
#ifdef HOST_WIN32
- if (image->is_module_handle)
+ if (m_image_is_module_handle (image))
return addr;
#endif
return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
int i;
#ifdef HOST_WIN32
- if (image->is_module_handle) {
- if (addr && addr < image->raw_data_len)
- return image->raw_data + addr;
+ if (m_image_is_module_handle (image)) {
+ if (addr && addr < m_image_get_raw_data_len (image))
+ return m_image_get_raw_data (image) + addr;
else
return NULL;
}
void
mono_images_init (void)
{
+ mono_os_mutex_init (&images_storage_mutex);
mono_os_mutex_init_recursive (&images_mutex);
+ images_storage_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
int hash_idx;
for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
g_hash_table_destroy (loaded_images_hashes [hash_idx]);
+ g_hash_table_destroy (images_storage_hash);
+
+ mono_os_mutex_destroy (&images_storage_mutex);
+
mutex_inited = FALSE;
}
sect = &iinfo->cli_section_tables [section];
- if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
+ if (sect->st_raw_data_ptr + sect->st_raw_data_size > m_image_get_raw_data_len (image))
return FALSE;
#ifdef HOST_WIN32
- if (image->is_module_handle)
- iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
+ if (m_image_is_module_handle (image))
+ iinfo->cli_sections [section] = m_image_get_raw_data (image) + sect->st_virtual_address;
else
#endif
/* FIXME: we ignore the writable flag since we don't patch the binary */
- iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
+ iinfo->cli_sections [section] = m_image_get_raw_data (image) + sect->st_raw_data_ptr;
return TRUE;
}
for (i = 0; i < top; i++){
MonoSectionTable *t = &iinfo->cli_section_tables [i];
- if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
+ if (offset + sizeof (MonoSectionTable) > m_image_get_raw_data_len (image))
return FALSE;
- memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
+ memcpy (t, m_image_get_raw_data (image) + offset, sizeof (MonoSectionTable));
offset += sizeof (MonoSectionTable);
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
if (offset == INVALID_ADDRESS)
return FALSE;
- if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
+ if (offset + sizeof (MonoCLIHeader) > m_image_get_raw_data_len (image))
return FALSE;
- memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
+ memcpy (&iinfo->cli_cli_header, m_image_get_raw_data (image) + offset, sizeof (MonoCLIHeader));
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
#define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
size = iinfo->cli_cli_header.ch_metadata.size;
- if (offset + size > image->raw_data_len)
+ if (offset + size > m_image_get_raw_data_len (image))
return FALSE;
- image->raw_metadata = image->raw_data + offset;
+ image->raw_metadata = m_image_get_raw_data (image) + offset;
/* 24.2.1: Metadata root starts here */
ptr = image->raw_metadata;
image->modules [idx - 1] = moduleImage;
#ifdef HOST_WIN32
- if (image->modules [idx - 1]->is_module_handle)
+ if (m_image_is_module_handle (image->modules [idx - 1]))
mono_image_fixup_vtable (image->modules [idx - 1]);
#endif
/* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
MonoDotNetHeader64 header64;
#ifdef HOST_WIN32
- if (!image->is_module_handle)
+ if (!m_image_is_module_handle (image))
#endif
- if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
+ if (offset + sizeof (MonoDotNetHeader32) > m_image_get_raw_data_len (image))
return -1;
- memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
+ memcpy (header, m_image_get_raw_data (image) + offset, sizeof (MonoDotNetHeader));
if (header->pesig [0] != 'P' || header->pesig [1] != 'E' || header->pesig [2] || header->pesig [3])
return -1;
/* 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));
+ memcpy (&header64, m_image_get_raw_data (image) + 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);
SWAPPDE (header->datadir.pe_reserved);
#ifdef HOST_WIN32
- if (image->is_module_handle)
- image->raw_data_len = header->nt.pe_image_size;
+ if (m_image_is_module_handle (image))
+ image->storage->raw_data_len = header->nt.pe_image_size;
#endif
return offset;
header = &iinfo->cli_header;
#ifdef HOST_WIN32
- if (!image->is_module_handle)
+ if (!m_image_is_module_handle (image))
#endif
- if (offset + sizeof (msdos) > image->raw_data_len)
+ if (offset + sizeof (msdos) > m_image_get_raw_data_len (image))
goto invalid_image;
- memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
+ memcpy (&msdos, m_image_get_raw_data (image) + offset, sizeof (msdos));
if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
goto invalid_image;
static gboolean
pe_image_match (MonoImage *image)
{
- if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
+ if (m_image_get_raw_data (image) [0] == 'M' && m_image_get_raw_data (image) [1] == 'Z')
return TRUE;
return FALSE;
}
return NULL;
}
-static MonoImage *
-do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
- gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
+static gboolean
+mono_image_storage_trypublish (MonoImageStorage *candidate, MonoImageStorage **out_storage)
+{
+ gboolean result;
+ mono_images_storage_lock ();
+ MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, candidate->key);
+ if (val) {
+ mono_refcount_inc (val);
+ *out_storage = val;
+ result = FALSE;
+ } else {
+ g_hash_table_insert (images_storage_hash, candidate->key, candidate);
+ result = TRUE;
+ }
+ mono_images_storage_unlock ();
+ return result;
+}
+
+static void
+mono_image_storage_unpublish (MonoImageStorage *storage)
{
- MonoCLIImageInfo *iinfo;
- MonoImage *image;
- MonoFileMap *filed;
+ mono_images_storage_lock ();
+ g_assert (storage->ref.ref == 0);
+
+ MonoImageStorage *published = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, storage->key);
+ if (published == storage) {
+ g_hash_table_remove (images_storage_hash, storage->key);
+ }
+ mono_images_storage_unlock ();
+}
+
+static gboolean
+mono_image_storage_tryaddref (const char *key, MonoImageStorage **found)
+{
+ gboolean result = FALSE;
+ mono_images_storage_lock ();
+ MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, key);
+ if (val) {
+ mono_refcount_inc (val);
+ *found = val;
+ result = TRUE;
+ }
+ mono_images_storage_unlock ();
+ return result;
+}
+
+static void
+mono_image_storage_dtor (gpointer self)
+{
+ MonoImageStorage *storage = (MonoImageStorage *)self;
+
+ mono_image_storage_unpublish (storage);
+
+ if (storage->raw_buffer_used) {
+ if (storage->raw_data != NULL) {
+#ifndef HOST_WIN32
+ if (storage->fileio_used)
+ mono_file_unmap_fileio (storage->raw_data, storage->raw_data_handle);
+ else
+#endif
+ mono_file_unmap (storage->raw_data, storage->raw_data_handle);
+ }
+ }
+ if (storage->raw_data_allocated) {
+ g_free (storage->raw_data);
+ }
+
+ g_free (storage->key);
+
+ g_free (storage);
+}
+
+static void
+mono_image_storage_close (MonoImageStorage *storage)
+{
+ mono_refcount_dec (storage);
+}
+
+static MonoImageStorage *
+mono_image_storage_open (const char *fname)
+{
+ char *key = NULL;
+
+ key = mono_path_resolve_symlinks (fname);
+ MonoImageStorage *published_storage = NULL;
+ if (mono_image_storage_tryaddref (key, &published_storage)) {
+ g_free (key);
+ return published_storage;
+ }
+
+ MonoFileMap *filed;
if ((filed = mono_file_map_open (fname)) == NULL){
if (IS_PORTABILITY_SET) {
gchar *ffname = mono_portability_find_file (fname, TRUE);
}
if (filed == NULL) {
- if (status)
- *status = MONO_IMAGE_ERROR_ERRNO;
+ g_free (key);
return NULL;
}
}
- image = g_new0 (MonoImage, 1);
- image->raw_buffer_used = TRUE;
- image->raw_data_len = mono_file_map_size (filed);
- image->raw_data = (char *)mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
+ MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
+ mono_refcount_init (storage, mono_image_storage_dtor);
+ storage->raw_buffer_used = TRUE;
+ storage->raw_data_len = mono_file_map_size (filed);
+ storage->raw_data = (char*)mono_file_map (storage->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &storage->raw_data_handle);
#if defined(HAVE_MMAP) && !defined (HOST_WIN32)
- if (!image->raw_data) {
- image->fileio_used = TRUE;
- image->raw_data = (char *)mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
+ if (!storage->raw_data) {
+ storage->fileio_used = TRUE;
+ storage->raw_data = (char *)mono_file_map_fileio (storage->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &storage->raw_data_handle);
}
#endif
- if (!image->raw_data) {
- mono_file_map_close (filed);
+ mono_file_map_close (filed);
+
+ storage->key = key;
+
+ MonoImageStorage *other_storage = NULL;
+ if (!mono_image_storage_trypublish (storage, &other_storage)) {
+ mono_image_storage_close (storage);
+ storage = other_storage;
+ }
+ return storage;
+}
+
+static MonoImageStorage *
+mono_image_storage_new_raw_data (char *datac, guint32 data_len, gboolean raw_data_allocated, const char *name)
+{
+ char *key = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup (name);
+ MonoImageStorage *published_storage = NULL;
+ if (mono_image_storage_tryaddref (key, &published_storage)) {
+ g_free (key);
+ return published_storage;
+ }
+
+ MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
+ mono_refcount_init (storage, mono_image_storage_dtor);
+
+ storage->raw_data = datac;
+ storage->raw_data_len = data_len;
+ storage->raw_data_allocated = raw_data_allocated;
+
+ storage->key = key;
+ MonoImageStorage *other_storage = NULL;
+ if (!mono_image_storage_trypublish (storage, &other_storage)) {
+ mono_image_storage_close (storage);
+ storage = other_storage;
+ }
+ return storage;
+}
+
+static MonoImage *
+do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
+ gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
+{
+ MonoCLIImageInfo *iinfo;
+ MonoImage *image;
+
+ MonoImageStorage *storage = mono_image_storage_open (fname);
+
+ if (!storage) {
+ if (status)
+ *status = MONO_IMAGE_ERROR_ERRNO;
+ return NULL;
+ }
+
+ image = g_new0 (MonoImage, 1);
+ image->storage = storage;
+ if (!m_image_get_raw_data (image)) {
+ mono_image_storage_close (image->storage);
g_free (image);
if (status)
*status = MONO_IMAGE_IMAGE_INVALID;
/* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
- mono_file_map_close (filed);
return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
}
memcpy (datac, data, data_len);
}
+ MonoImageStorage *storage = mono_image_storage_new_raw_data (datac, data_len, need_copy, name);
image = g_new0 (MonoImage, 1);
- image->raw_data = datac;
- image->raw_data_len = data_len;
- image->raw_data_allocated = need_copy;
+ image->storage = storage;
image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
iinfo = g_new0 (MonoCLIImageInfo, 1);
image->image_info = iinfo;
}
#ifdef HOST_WIN32
+static MonoImageStorage *
+mono_image_storage_open_from_module_handle (HMODULE module_handle, const char *fname, gboolean has_entry_point)
+{
+ char *key = g_strdup (fname);
+ MonoImageStorage *published_storage = NULL;
+ if (mono_image_storage_tryaddref (key, &published_storage)) {
+ g_free (key);
+ return published_storage;
+ }
+
+ MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
+ mono_refcount_init (storage, mono_image_storage_dtor);
+ storage->raw_data = (char*) module_handle;
+ storage->is_module_handle = TRUE;
+ storage->has_entry_point = has_entry_point;
+
+ storage->key = key;
+
+ MonoImageStorage *other_storage = NULL;
+ if (!mono_image_storage_trypublish (storage, &other_storage)) {
+ mono_image_storage_close (storage);
+ storage = other_storage;
+ }
+ return storage;
+}
+
/* fname is not duplicated. */
MonoImage*
mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
MonoImage* image;
MonoCLIImageInfo* iinfo;
+ MonoImageStorage *storage = mono_image_storage_open_from_module_handle (module_handle, fname, has_entry_point);
image = g_new0 (MonoImage, 1);
- image->raw_data = (char*) module_handle;
- image->is_module_handle = TRUE;
+ image->storage = storage;
iinfo = g_new0 (MonoCLIImageInfo, 1);
image->image_info = iinfo;
image->name = fname;
image->ref_count = has_entry_point ? 0 : 1;
- image->has_entry_point = has_entry_point;
image = do_mono_image_load (image, status, TRUE, TRUE);
if (image == NULL)
mono_images_unlock ();
return NULL;
}
- g_assert (image->is_module_handle);
- if (image->has_entry_point && image->ref_count == 0) {
+ g_assert (m_image_is_module_handle (image));
+ if (m_image_has_entry_point (image) && image->ref_count == 0) {
/* Increment reference count on images loaded outside of the runtime. */
fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
/* The image is already loaded because _CorDllMain removes images from the hash. */
module_handle = LoadLibrary (fname_utf16);
- g_assert (module_handle == (HMODULE) image->raw_data);
+ g_assert (module_handle == (HMODULE) m_image_get_raw_data (image));
}
mono_image_addref (image);
mono_images_unlock ();
}
if (image) {
- g_assert (image->is_module_handle);
- g_assert (image->has_entry_point);
+ g_assert (m_image_is_module_handle (image));
+ g_assert (m_image_has_entry_point (image));
g_free (absfname);
return image;
}
guint16 slot_type;
int slot_count;
- g_assert (image->is_module_handle);
+ g_assert (m_image_is_module_handle (image));
iinfo = image->image_info;
de = &iinfo->cli_cli_header.ch_vtable_fixups;
mono_images_unlock ();
#ifdef HOST_WIN32
- if (image->is_module_handle && image->has_entry_point) {
+ if (m_image_is_module_handle (image) && m_image_has_entry_point (image)) {
mono_images_lock ();
if (image->ref_count == 0) {
/* Image will be closed by _CorDllMain. */
- FreeLibrary ((HMODULE) image->raw_data);
+ FreeLibrary ((HMODULE) m_image_get_raw_data (image));
mono_images_unlock ();
return FALSE;
}
}
}
-#ifdef HOST_WIN32
- mono_images_lock ();
- if (image->is_module_handle && !image->has_entry_point)
- FreeLibrary ((HMODULE) image->raw_data);
- mono_images_unlock ();
-#endif
+ /* a MonoDynamicImage doesn't have any storage */
+ g_assert (image_is_dynamic (image) || image->storage != NULL);
- if (image->raw_buffer_used) {
- if (image->raw_data != NULL) {
-#ifndef HOST_WIN32
- if (image->fileio_used)
- mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
- else
-#endif
- mono_file_unmap (image->raw_data, image->raw_data_handle);
- }
- }
-
- if (image->raw_data_allocated) {
+ if (image->storage && m_image_is_raw_data_allocated (image)) {
/* FIXME: do we need this? (image is disposed anyway) */
- /* image->raw_metadata and cli_sections might lie inside image->raw_data */
+ /* image->raw_metadata and cli_sections might lie inside m_image_get_raw_data (image) */
MonoCLIImageInfo *ii = image->image_info;
- if ((image->raw_metadata > image->raw_data) &&
- (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
+ if ((image->raw_metadata > m_image_get_raw_data (image)) &&
+ (image->raw_metadata <= (m_image_get_raw_data (image) + m_image_get_raw_data_len (image))))
image->raw_metadata = NULL;
for (i = 0; i < ii->cli_section_count; i++)
- if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
- ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
+ if (((char*)(ii->cli_sections [i]) > m_image_get_raw_data (image)) &&
+ ((char*)(ii->cli_sections [i]) <= ((char*)m_image_get_raw_data (image) + m_image_get_raw_data_len (image))))
ii->cli_sections [i] = NULL;
- g_free (image->raw_data);
}
+#ifdef HOST_WIN32
+ mono_images_lock ();
+ if (m_image_is_module_handle (image) && !m_image_has_entry_point (image))
+ FreeLibrary ((HMODULE) m_image_get_raw_data (image));
+ mono_images_unlock ();
+#endif
+ if (image->storage)
+ mono_image_storage_close (image->storage);
+
if (debug_assembly_unload) {
char *old_name = image->name;
image->name = g_strdup_printf ("%s - UNLOADED", old_name);
mono_image_unlock (image);
/* vtable fixup can't happen with the image lock held */
#ifdef HOST_WIN32
- if (res->is_module_handle)
+ if (m_image_is_module_handle (res))
mono_image_fixup_vtable (res);
#endif
}