*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*/
#include <config.h>
#include <stdio.h>
#include <mono/utils/mono-path.h>
#include <mono/metadata/reflection.h>
#include <mono/metadata/coree.h>
+#include <mono/utils/mono-io-portability.h>
+#include <mono/utils/atomic.h>
#ifndef HOST_WIN32
#include <sys/types.h>
#ifndef DISABLE_ASSEMBLY_REMAPPING
/* The list of system assemblies what will be remapped to the running
* runtime version. WARNING: this list must be sorted.
+ * The integer number is an index in the MonoRuntimeInfo structure, whose
+ * values can be found in domain.c - supported_runtimes. Look there
+ * to understand what remapping will be made.
*/
static const AssemblyVersionMap framework_assemblies [] = {
{"Accessibility", 0},
{"System.Management", 0},
{"System.Messaging", 0},
{"System.Runtime.Remoting", 0},
+ {"System.Runtime.Serialization", 3},
{"System.Runtime.Serialization.Formatters.Soap", 0},
{"System.Security", 0},
{"System.ServiceProcess", 0},
+ {"System.Transactions", 0},
{"System.Web", 0},
{"System.Web.Abstractions", 2},
{"System.Web.Mobile", 0},
return memcmp (pubt1, pubt2, 16) == 0;
}
-static void
-check_path_env (void)
+/**
+ * mono_set_assemblies_path:
+ * @path: list of paths that contain directories where Mono will look for assemblies
+ *
+ * Use this method to override the standard assembly lookup system and
+ * override any assemblies coming from the GAC. This is the method
+ * that supports the MONO_PATH variable.
+ *
+ * Notice that MONO_PATH and this method are really a very bad idea as
+ * it prevents the GAC from working and it prevents the standard
+ * resolution mechanisms from working. Nonetheless, for some debugging
+ * situations and bootstrapping setups, this is useful to have.
+ */
+void
+mono_set_assemblies_path (const char* path)
{
- const char *path;
char **splitted, **dest;
- path = g_getenv ("MONO_PATH");
- if (!path)
- return;
-
splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
if (assemblies_path)
g_strfreev (assemblies_path);
}
}
+/* Native Client can't get this info from an environment variable so */
+/* it's passed in to the runtime, or set manually by embedding code. */
+#ifdef __native_client__
+char* nacl_mono_path = NULL;
+#endif
+
+static void
+check_path_env (void)
+{
+ const char* path;
+ path = g_getenv ("MONO_PATH");
+#ifdef __native_client__
+ if (!path)
+ path = nacl_mono_path;
+#endif
+ if (!path || assemblies_path != NULL)
+ return;
+
+ mono_set_assemblies_path(path);
+}
+
static void
check_extra_gac_path_env (void) {
const char *path;
return NULL;
/* Not a well known Mono executable, we are embedded, cant guess the base */
- if (strcmp (p, "/mono") && strcmp (p, "/monodis") && strcmp (p, "/mint") && strcmp (p, "/monodiet"))
+ if (strcmp (p, "/mono") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis") && strcmp (p, "/mint") && strcmp (p, "/monodiet"))
return NULL;
*p = 0;
mono_set_dirs (MONO_ASSEMBLIES, MONO_CFG_DIR);
}
-static void
+static G_GNUC_UNUSED void
set_dirs (char *exe)
{
char *base;
config = g_build_filename (base, "etc", NULL);
lib = g_build_filename (base, "lib", NULL);
- mono = g_build_filename (lib, "mono/1.0", NULL);
+ mono = g_build_filename (lib, "mono/2.0", NULL);
if (stat (mono, &buf) == -1)
fallback ();
else {
fallback ();
return;
}
-
- name = mono_path_resolve_symlinks (name);
}
#endif
InterlockedIncrement (&assembly->ref_count);
}
-#ifndef DISABLE_ASSEMBLY_REMAPPING
+#define SILVERLIGHT_KEY "7cec85d7bea7798e"
+#define WINFX_KEY "31bf3856ad364e35"
+#define ECMA_KEY "b77a5c561934e089"
+#define MSFINAL_KEY "b03f5f7f11d50a3a"
+
+typedef struct {
+ const char *name;
+ const char *from;
+ const char *to;
+} KeyRemapEntry;
+
+static KeyRemapEntry key_remap_table[] = {
+ { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
+ { "System", SILVERLIGHT_KEY, ECMA_KEY },
+ { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
+ { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
+ { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
+ { "System.Numerics", WINFX_KEY, ECMA_KEY },
+ { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
+ { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
+ { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
+ { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
+ { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
+ { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
+ { "System.Xml.Serialization", WINFX_KEY, MSFINAL_KEY }
+};
+
+static void
+remap_keys (MonoAssemblyName *aname)
+{
+ int i;
+ for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
+ const KeyRemapEntry *entry = &key_remap_table [i];
+
+ if (strcmp (aname->name, entry->name) ||
+ !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
+ continue;
+
+ memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+
+ mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
+ "Remapped public key token of retargetable assembly %s from %s to %s",
+ aname->name, entry->from, entry->to);
+ return;
+ }
+}
+
static MonoAssemblyName *
mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
{
int pos, first, last;
if (aname->name == NULL) return aname;
+
current_runtime = mono_get_runtime_info ();
+ if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
+ const AssemblyVersionSet* vset;
+
+ /* Remap to current runtime */
+ vset = ¤t_runtime->version_sets [0];
+
+ memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
+ dest_aname->major = vset->major;
+ dest_aname->minor = vset->minor;
+ dest_aname->build = vset->build;
+ dest_aname->revision = vset->revision;
+ dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
+
+ /* Remap assembly name */
+ if (!strcmp (aname->name, "System.Net"))
+ dest_aname->name = g_strdup ("System");
+
+ remap_keys (dest_aname);
+
+ mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
+ "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
+ aname->name,
+ aname->major, aname->minor, aname->build, aname->revision,
+ dest_aname->name,
+ vset->major, vset->minor, vset->build, vset->revision
+ );
+
+ return dest_aname;
+ }
+
+#ifndef DISABLE_ASSEMBLY_REMAPPING
first = 0;
last = G_N_ELEMENTS (framework_assemblies) - 1;
first = pos + 1;
}
}
+#endif
+
return aname;
}
-#endif
/*
* mono_assembly_get_assemblyref:
if (reference != REFERENCE_MISSING){
mono_assembly_addref (reference);
if (image->assembly)
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d",
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
} else {
if (image->assembly)
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n",
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
image->assembly->aname.name, image->assembly);
}
/* Add a non-temporary reference because of ass->image */
mono_image_addref (image);
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s %p -> %s %p: %d", ass->aname.name, ass, image->name, image, image->ref_count);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s[%p] -> %s[%p]: %d", ass->aname.name, ass, image->name, image, image->ref_count);
/*
* The load hooks might take locks so we can't call them while holding the
}
static gboolean
-parse_public_key (const gchar *key, gchar** pubkey)
+parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
{
const gchar *pkey;
gchar header [16], val, *arr;
keylen = strlen (key) >> 1;
if (keylen < 1)
return FALSE;
-
+
+ /* allow the ECMA standard key */
+ if (strcmp (key, "00000000000000000400000000000000") == 0) {
+ if (pubkey) {
+ *pubkey = g_strdup (key);
+ *is_ecma = TRUE;
+ }
+ return TRUE;
+ }
+ *is_ecma = FALSE;
val = g_ascii_xdigit_value (key [0]) << 4;
val |= g_ascii_xdigit_value (key [1]);
switch (val) {
}
if (key) {
- if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey)) {
+ gboolean is_ecma;
+ if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
mono_assembly_name_free (aname);
return FALSE;
}
+
+ if (is_ecma) {
+ if (save_public_key)
+ aname->public_key = (guint8*)pkey;
+ else
+ g_free (pkey);
+ g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
+ return TRUE;
+ }
len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
// We also need to generate the key token
return res;
}
+static gboolean
+split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
+{
+ char *eqsign = strchr (pair, '=');
+ if (!eqsign) {
+ *key = NULL;
+ *keylen = 0;
+ *value = NULL;
+ return FALSE;
+ }
+
+ *key = (gchar*)pair;
+ *keylen = eqsign - *key;
+ while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
+ (*keylen)--;
+ *value = g_strstrip (eqsign + 1);
+ return TRUE;
+}
+
gboolean
mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
{
gchar *key = NULL;
gchar *retargetable = NULL;
gboolean res;
- gchar *value;
+ gchar *value, *part_name;
+ guint32 part_name_len;
gchar **parts;
gchar **tmp;
gboolean version_defined;
gboolean token_defined;
guint32 flags = 0;
- guint32 arch = PROCESSOR_ARCHITECTURE_NONE;
+ guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
if (!is_version_defined)
is_version_defined = &version_defined;
tmp++;
while (*tmp) {
- value = g_strstrip (*tmp);
- if (!g_ascii_strncasecmp (value, "Version=", 8)) {
+ if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
+ goto cleanup_and_fail;
+
+ if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
*is_version_defined = TRUE;
- version = g_strstrip (value + 8);
+ version = value;
if (strlen (version) == 0) {
goto cleanup_and_fail;
}
continue;
}
- if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
- culture = g_strstrip (value + 8);
+ if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
+ culture = value;
if (strlen (culture) == 0) {
goto cleanup_and_fail;
}
continue;
}
- if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
+ if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
*is_token_defined = TRUE;
- token = g_strstrip (value + 15);
+ token = value;
if (strlen (token) == 0) {
goto cleanup_and_fail;
}
continue;
}
- if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) {
- key = g_strstrip (value + 10);
+ if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
+ key = value;
if (strlen (key) == 0) {
goto cleanup_and_fail;
}
continue;
}
- if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) {
- retargetable = g_strstrip (value + 13);
+ if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
+ retargetable = value;
if (strlen (retargetable) == 0) {
goto cleanup_and_fail;
}
continue;
}
- if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) {
- char *s = g_strstrip (value + 22);
- if (!g_ascii_strcasecmp (s, "None"))
- arch = PROCESSOR_ARCHITECTURE_NONE;
- else if (!g_ascii_strcasecmp (s, "MSIL"))
- arch = PROCESSOR_ARCHITECTURE_MSIL;
- else if (!g_ascii_strcasecmp (s, "X86"))
- arch = PROCESSOR_ARCHITECTURE_X86;
- else if (!g_ascii_strcasecmp (s, "IA64"))
- arch = PROCESSOR_ARCHITECTURE_IA64;
- else if (!g_ascii_strcasecmp (s, "AMD64"))
- arch = PROCESSOR_ARCHITECTURE_AMD64;
+ if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
+ if (!g_ascii_strcasecmp (value, "None"))
+ arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
+ else if (!g_ascii_strcasecmp (value, "MSIL"))
+ arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
+ else if (!g_ascii_strcasecmp (value, "X86"))
+ arch = MONO_PROCESSOR_ARCHITECTURE_X86;
+ else if (!g_ascii_strcasecmp (value, "IA64"))
+ arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
+ else if (!g_ascii_strcasecmp (value, "AMD64"))
+ arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
else
goto cleanup_and_fail;
tmp++;
{
MonoAssembly *res;
MonoAssemblyName *aname, base_name;
-#ifndef DISABLE_ASSEMBLY_REMAPPING
- MonoAssemblyName maped_aname;
-#endif
+ MonoAssemblyName mapped_aname;
gchar *fullname, *gacpath;
gchar **paths;
if (!mono_assembly_name_parse (name, aname))
return NULL;
-#ifndef DISABLE_ASSEMBLY_REMAPPING
/*
* If no specific version has been requested, make sure we load the
* correct version for system assemblies.
*/
if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
- aname = mono_assembly_remap_version (aname, &maped_aname);
-#endif
+ aname = mono_assembly_remap_version (aname, &mapped_aname);
res = mono_assembly_loaded (aname);
if (res) {
if (domain && domain->setup && domain->setup->configuration_file) {
mono_domain_lock (domain);
if (!domain->assembly_bindings_parsed) {
- gchar *domain_config_file = mono_string_to_utf8 (domain->setup->configuration_file);
+ gchar *domain_config_file_name = mono_string_to_utf8 (domain->setup->configuration_file);
+ gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
- mono_config_parse_assembly_bindings (domain_config_file, aname->major, aname->minor, domain, assembly_binding_info_parsed);
+ if (!domain_config_file_path)
+ domain_config_file_path = domain_config_file_name;
+
+ mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
domain->assembly_bindings_parsed = TRUE;
- g_free (domain_config_file);
+ if (domain_config_file_name != domain_config_file_path)
+ g_free (domain_config_file_name);
+ g_free (domain_config_file_path);
}
mono_domain_unlock (domain);
mono_loader_lock ();
mono_domain_lock (domain);
- info = get_per_domain_assembly_binding_info (domain, aname);
+ info2 = get_per_domain_assembly_binding_info (domain, aname);
+
+ if (info2) {
+ info = g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
+ info->name = g_strdup (info2->name);
+ info->culture = g_strdup (info2->culture);
+ info->domain_id = domain->domain_id;
+ }
+
mono_domain_unlock (domain);
mono_loader_unlock ();
}
{
MonoAssembly *result;
char *fullpath, *filename;
-#ifndef DISABLE_ASSEMBLY_REMAPPING
MonoAssemblyName maped_aname;
-#endif
MonoAssemblyName maped_name_pp;
int ext_index;
const char *ext;
int len;
-#ifndef DISABLE_ASSEMBLY_REMAPPING
aname = mono_assembly_remap_version (aname, &maped_aname);
-#endif
/* Reflection only assemblies don't get assembly binding */
if (!refonly)
mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
{
MonoAssembly *res;
-#ifndef DISABLE_ASSEMBLY_REMAPPING
MonoAssemblyName maped_aname;
aname = mono_assembly_remap_version (aname, &maped_aname);
-#endif
res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE);
return mono_assembly_loaded_full (aname, FALSE);
}
+void
+mono_assembly_release_gc_roots (MonoAssembly *assembly)
+{
+ if (assembly == NULL || assembly == REFERENCE_MISSING)
+ return;
+
+ if (assembly->dynamic) {
+ int i;
+ MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
+ for (i = 0; i < dynimg->image.module_count; ++i)
+ mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
+ mono_dynamic_image_release_gc_roots (dynimg);
+ }
+}
+
/*
* Returns whether mono_assembly_close_finish() must be called as
* well. See comment for mono_image_close_except_pools() for why we
free_assembly_preload_hooks ();
}
+/*LOCKING assumes loader lock is held*/
+void
+mono_assembly_cleanup_domain_bindings (guint32 domain_id)
+{
+ GSList **iter = &loaded_assembly_bindings;
+
+ while (*iter) {
+ GSList *l = *iter;
+ MonoAssemblyBindingInfo *info = l->data;
+
+ if (info->domain_id == domain_id) {
+ *iter = l->next;
+ mono_assembly_binding_info_free (info);
+ g_free (info);
+ g_slist_free_1 (l);
+ } else {
+ iter = &l->next;
+ }
+ }
+}
+
/*
* Holds the assembly of the application, for
* System.Diagnostics.Process::MainModule