X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fimage.c;h=1db273008c8d2d1ae7889118b664a970c122717f;hb=4e4851142302b80c66174d23dffb42a87cb7948c;hp=38b74578f072aa3083814096f3411347f16345a4;hpb=2f159741e9bdd69dde9ea22b1fb41b9e89af6607;p=mono.git diff --git a/mono/metadata/image.c b/mono/metadata/image.c index 38b74578f07..1db273008c8 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -19,11 +19,13 @@ #include "cil-coff.h" #include "rawbuffer.h" #include "mono-endian.h" -#include "private.h" #include "tabledefs.h" #include "tokentype.h" #include "metadata-internals.h" #include +#include +#include +#include #define INVALID_ADDRESS 0xffffffff @@ -32,6 +34,8 @@ */ 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 CRITICAL_SECTION images_mutex; @@ -129,6 +133,8 @@ mono_images_init (void) 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); } /** @@ -157,20 +163,10 @@ mono_image_ensure_section_idx (MonoImage *image, int section) writable = sect->st_flags & SECT_FLAGS_MEM_WRITE; - if (!image->f) { - if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len) - return FALSE; - /* 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; - return TRUE; - } - iinfo->cli_sections [section] = mono_raw_buffer_load ( - fileno (image->f), writable, - sect->st_raw_data_ptr, sect->st_raw_data_size); - - if (iinfo->cli_sections [section] == NULL) + if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len) return FALSE; - + /* 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; return TRUE; } @@ -212,15 +208,10 @@ load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset) for (i = 0; i < top; i++){ MonoSectionTable *t = &iinfo->cli_section_tables [i]; - if (!image->f) { - if (offset + sizeof (MonoSectionTable) > image->raw_data_len) - return FALSE; - memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable)); - offset += sizeof (MonoSectionTable); - } else { - if (fread (t, sizeof (MonoSectionTable), 1, image->f) != 1) - return FALSE; - } + if (offset + sizeof (MonoSectionTable) > image->raw_data_len) + return FALSE; + memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable)); + offset += sizeof (MonoSectionTable); #if G_BYTE_ORDER != G_LITTLE_ENDIAN t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size); @@ -243,23 +234,14 @@ static gboolean load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo) { guint32 offset; - int n; offset = mono_cli_rva_image_map (iinfo, iinfo->cli_header.datadir.pe_cli_header.rva); if (offset == INVALID_ADDRESS) return FALSE; - if (!image->f) { - if (offset + sizeof (MonoCLIHeader) > image->raw_data_len) - return FALSE; - memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader)); - } else { - if (fseek (image->f, offset, SEEK_SET) != 0) - return FALSE; - - if ((n = fread (&iinfo->cli_cli_header, sizeof (MonoCLIHeader), 1, image->f)) != 1) - return FALSE; - } + if (offset + sizeof (MonoCLIHeader) > image->raw_data_len) + return FALSE; + memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader)); #if G_BYTE_ORDER != G_LITTLE_ENDIAN #define SWAP32(x) (x) = GUINT32_FROM_LE ((x)) @@ -327,15 +309,9 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) size = iinfo->cli_cli_header.ch_metadata.size; - if (!image->f) { - if (offset + size > image->raw_data_len) - return FALSE; - image->raw_metadata = image->raw_data + offset; - } else { - image->raw_metadata = mono_raw_buffer_load (fileno (image->f), FALSE, offset, size); - if (image->raw_metadata == NULL) - return FALSE; - } + if (offset + size > image->raw_data_len) + return FALSE; + image->raw_metadata = image->raw_data + offset; ptr = image->raw_metadata; @@ -478,6 +454,7 @@ load_modules (MonoImage *image, MonoImageOpenStatus *status) MonoTableInfo *t; int i; char *base_dir; + gboolean refonly = image->ref_only; if (image->modules) return; @@ -494,7 +471,7 @@ load_modules (MonoImage *image, MonoImageOpenStatus *status) 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 (module_ref, status); + image->modules [i] = mono_image_open_full (module_ref, status, refonly); if (image->modules [i]) { /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */ } @@ -579,14 +556,16 @@ register_guid (gpointer key, gpointer value, gpointer user_data) } static void -build_guid_table (void) +build_guid_table (gboolean refonly) { - g_hash_table_foreach (loaded_images_hash, register_guid, NULL); + GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash; + g_hash_table_foreach (loaded_images, register_guid, NULL); } void mono_image_init (MonoImage *image) { + image->mempool = mono_mempool_new (); image->method_cache = g_hash_table_new (NULL, NULL); image->class_cache = g_hash_table_new (NULL, NULL); image->field_cache = g_hash_table_new (NULL, NULL); @@ -624,7 +603,6 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, MonoCLIImageInfo *iinfo; MonoDotNetHeader *header; MonoMSDOSHeader msdos; - int n; guint32 offset = 0; mono_image_init (image); @@ -635,35 +613,21 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, if (status) *status = MONO_IMAGE_IMAGE_INVALID; - if (!image->f) { - if (offset + sizeof (msdos) > image->raw_data_len) - goto invalid_image; - memcpy (&msdos, image->raw_data + offset, sizeof (msdos)); - } else { - if (fread (&msdos, sizeof (msdos), 1, image->f) != 1) - goto invalid_image; - } + 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); - if (msdos.pe_offset != sizeof (msdos)) { - if (image->f) - fseek (image->f, msdos.pe_offset, SEEK_SET); - } offset = msdos.pe_offset; - if (!image->f) { - if (offset + sizeof (MonoDotNetHeader) > image->raw_data_len) - goto invalid_image; - memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader)); - offset += sizeof (MonoDotNetHeader); - } else { - if ((n = fread (header, sizeof (MonoDotNetHeader), 1, image->f)) != 1) - goto invalid_image; - } + 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)) @@ -803,11 +767,12 @@ invalid_image: static MonoImage * do_mono_image_open (const char *fname, MonoImageOpenStatus *status, - gboolean care_about_cli) + gboolean care_about_cli, gboolean refonly) { MonoCLIImageInfo *iinfo; MonoImage *image; FILE *filed; + struct stat stat_buf; if ((filed = fopen (fname, "rb")) == NULL){ if (status) @@ -815,40 +780,88 @@ do_mono_image_open (const char *fname, MonoImageOpenStatus *status, return NULL; } + if (fstat (fileno (filed), &stat_buf)) { + fclose (filed); + if (status) + *status = MONO_IMAGE_ERROR_ERRNO; + return NULL; + } image = g_new0 (MonoImage, 1); image->ref_count = 1; - image->f = filed; + image->file_descr = filed; + 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->ref_only = refonly; return do_mono_image_load (image, status, care_about_cli); } MonoImage * -mono_image_loaded (const char *name) +mono_image_loaded_full (const char *name, gboolean refonly) { MonoImage *res; + GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash; EnterCriticalSection (&images_mutex); - res = g_hash_table_lookup (loaded_images_hash, name); + res = g_hash_table_lookup (loaded_images, name); LeaveCriticalSection (&images_mutex); return res; } MonoImage * -mono_image_loaded_by_guid (const char *guid) +mono_image_loaded (const char *name) +{ + return mono_image_loaded_full (name, FALSE); +} + +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; EnterCriticalSection (&images_mutex); - res = g_hash_table_lookup (loaded_images_guid_hash, guid); + res = g_hash_table_lookup (loaded_images, guid); LeaveCriticalSection (&images_mutex); return res; } MonoImage * -mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status) +mono_image_loaded_by_guid (const char *guid) +{ + return mono_image_loaded_by_guid_full (guid, FALSE); +} + +static MonoImage * +register_image (MonoImage *image) +{ + MonoImage *image2; + GHashTable *loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash; + + EnterCriticalSection (&images_mutex); + image2 = g_hash_table_lookup (loaded_images, image->name); + + if (image2) { + /* Somebody else beat us to it */ + mono_image_addref (image2); + LeaveCriticalSection (&images_mutex); + mono_image_close (image); + return image2; + } + 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); + LeaveCriticalSection (&images_mutex); + + return image; +} + +MonoImage * +mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly) { MonoCLIImageInfo *iinfo; MonoImage *image; @@ -878,22 +891,26 @@ mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, Mon image->name = g_strdup_printf ("data-%p", datac); iinfo = g_new0 (MonoCLIImageInfo, 1); image->image_info = iinfo; + image->ref_only = refonly; + + image = do_mono_image_load (image, status, TRUE); + if (image == NULL) + return NULL; - return do_mono_image_load (image, status, TRUE); + return register_image (image); } -/** - * mono_image_open: - * @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. - * if NULL, then check the value of @status for details on the error - */ MonoImage * -mono_image_open (const char *fname, MonoImageOpenStatus *status) +mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status) { - MonoImage *image, *image2; + return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE); +} + +MonoImage * +mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly) +{ + MonoImage *image; + GHashTable *loaded_images; char *absfname; g_return_val_if_fail (fname != NULL, NULL); @@ -907,37 +924,36 @@ mono_image_open (const char *fname, MonoImageOpenStatus *status) * the same image, we discard all but the first copy. */ EnterCriticalSection (&images_mutex); - image = g_hash_table_lookup (loaded_images_hash, absfname); + loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash; + image = g_hash_table_lookup (loaded_images, absfname); g_free (absfname); if (image){ - image->ref_count++; + mono_image_addref (image); LeaveCriticalSection (&images_mutex); return image; } LeaveCriticalSection (&images_mutex); - image = do_mono_image_open (fname, status, TRUE); + image = do_mono_image_open (fname, status, TRUE, refonly); if (image == NULL) return NULL; - EnterCriticalSection (&images_mutex); - image2 = g_hash_table_lookup (loaded_images_hash, image->name); - - if (image2) { - /* Somebody else beat us to it */ - image2->ref_count ++; - LeaveCriticalSection (&images_mutex); - mono_image_close (image); - return image2; - } - g_hash_table_insert (loaded_images_hash, image->name, image); - if (image->assembly_name && (g_hash_table_lookup (loaded_images_hash, image->assembly_name) == NULL)) - g_hash_table_insert (loaded_images_hash, (char *) image->assembly_name, image); - g_hash_table_insert (loaded_images_guid_hash, image->guid, image); - LeaveCriticalSection (&images_mutex); + return register_image (image); +} - return image; +/** + * mono_image_open: + * @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. + * if NULL, then check the value of @status for details on the error + */ +MonoImage * +mono_image_open (const char *fname, MonoImageOpenStatus *status) +{ + return mono_image_open_full (fname, status, FALSE); } /** @@ -956,7 +972,7 @@ mono_pe_file_open (const char *fname, MonoImageOpenStatus *status) { g_return_val_if_fail (fname != NULL, NULL); - return(do_mono_image_open (fname, status, FALSE)); + return(do_mono_image_open (fname, status, FALSE, FALSE)); } static void @@ -1012,34 +1028,39 @@ void mono_image_close (MonoImage *image) { MonoImage *image2; + GHashTable *loaded_images, *loaded_images_guid; + int i; g_return_if_fail (image != NULL); - EnterCriticalSection (&images_mutex); - /*g_print ("destroy image %p (dynamic: %d) refcount: %d\n", image, image->dynamic, image->ref_count);*/ - g_assert (image->ref_count > 0); - if (--image->ref_count) { - LeaveCriticalSection (&images_mutex); + if (InterlockedDecrement (&image->ref_count)) return; - } - image2 = g_hash_table_lookup (loaded_images_hash, image->name); + + EnterCriticalSection (&images_mutex); + 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_hash, image->name); - g_hash_table_remove (loaded_images_guid_hash, image->guid); + g_hash_table_remove (loaded_images, image->name); + g_hash_table_remove (loaded_images_guid, image->guid); /* Multiple images might have the same guid */ - build_guid_table (); + build_guid_table (image->ref_only); } - if (image->assembly_name && (g_hash_table_lookup (loaded_images_hash, image->assembly_name) == image)) - g_hash_table_remove (loaded_images_hash, (char *) image->assembly_name); + if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == image)) + g_hash_table_remove (loaded_images, (char *) image->assembly_name); LeaveCriticalSection (&images_mutex); - if (image->f) - fclose (image->f); + if (image->file_descr) { + fclose (image->file_descr); + image->file_descr = NULL; + if (image->raw_data != NULL) + mono_raw_buffer_free (image->raw_data); + } + if (image->raw_data_allocated) { /* image->raw_metadata and cli_sections might lie inside image->raw_data */ MonoCLIImageInfo *ii = image->image_info; - int i; if ((image->raw_metadata > image->raw_data) && (image->raw_metadata <= (image->raw_data + image->raw_data_len))) @@ -1078,18 +1099,9 @@ mono_image_close (MonoImage *image) g_hash_table_foreach (image->helper_signatures, free_mr_signatures, NULL); g_hash_table_destroy (image->helper_signatures); - if (image->raw_metadata != NULL) - mono_raw_buffer_free (image->raw_metadata); - if (image->image_info){ MonoCLIImageInfo *ii = image->image_info; - int i; - for (i = 0; i < ii->cli_section_count; i++){ - if (!ii->cli_sections [i]) - continue; - mono_raw_buffer_free (ii->cli_sections [i]); - } if (ii->cli_section_tables) g_free (ii->cli_section_tables); if (ii->cli_sections) @@ -1097,13 +1109,19 @@ mono_image_close (MonoImage *image) g_free (image->image_info); } + for (i = 0; i < image->module_count; ++i) { + if (image->modules [i]) + mono_image_close (image->modules [i]); + } /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/ if (!image->dynamic) { + mono_mempool_destroy (image->mempool); g_free (image); } else { /* Dynamic images are GC_MALLOCed */ struct _MonoDynamicImage *di = (struct _MonoDynamicImage*)image; int i; + g_free ((char*)image->module_name); if (di->typespec) g_hash_table_destroy (di->typespec); if (di->typeref) @@ -1127,6 +1145,7 @@ mono_image_close (MonoImage *image) g_hash_table_destroy (di->method_aux_hash); g_free (di->strong_name); g_free (di->win32_res); + /*g_print ("string heap destroy for image %p\n", di);*/ mono_dynamic_stream_reset (&di->sheap); mono_dynamic_stream_reset (&di->code); mono_dynamic_stream_reset (&di->resources); @@ -1137,6 +1156,7 @@ mono_image_close (MonoImage *image) for (i = 0; i < MONO_TABLE_NUM; ++i) { g_free (di->tables [i].values); } + mono_mempool_destroy (image->mempool); } } @@ -1427,6 +1447,12 @@ mono_image_get_filename (MonoImage *image) return image->name; } +const char* +mono_image_get_guid (MonoImage *image) +{ + return image->guid; +} + const MonoTableInfo* mono_image_get_table_info (MonoImage *image, int table_id) {