#include <mono/utils/mono-uri.h>
#include <mono/metadata/mono-config.h>
#include <mono/utils/mono-digest.h>
-#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-path.h>
#include <mono/metadata/reflection.h>
#include <mono/metadata/coree.h>
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#endif
+#ifdef PLATFORM_MACOSX
+#include <mach-o/dyld.h>
+#endif
+
/* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
typedef struct {
const char* assembly_name;
/* Contains the list of directories that point to auxiliary GACs */
static char **extra_gac_paths = NULL;
+#ifndef DISABLE_ASSEMBLY_REMAPPING
/* The list of system assemblies what will be remapped to the running
* runtime version. WARNING: this list must be sorted.
*/
{"Npgsql", 0},
{"PEAPI", 0},
{"System", 0},
+ {"System.ComponentModel.DataAnnotations", 2},
+ {"System.Configuration", 0},
{"System.Configuration.Install", 0},
+ {"System.Core", 2},
{"System.Data", 0},
+ {"System.Data.Linq", 2},
{"System.Data.OracleClient", 0},
{"System.Data.SqlXml", 0},
{"System.Design", 0},
{"System.Security", 0},
{"System.ServiceProcess", 0},
{"System.Web", 0},
+ {"System.Web.Abstractions", 2},
{"System.Web.Mobile", 0},
+ {"System.Web.Routing", 2},
{"System.Web.Services", 0},
{"System.Windows.Forms", 0},
{"System.Xml", 0},
{"mscorlib", 0}
};
+#endif
/*
* keeps track of loaded assemblies
static GList *loaded_assemblies = NULL;
static MonoAssembly *corlib;
+#if defined(__native_client__)
+
+/* On Native Client, allow mscorlib to be loaded from memory */
+/* instead of loaded off disk. If these are not set, default */
+/* mscorlib loading will take place */
+
+/* NOTE: If mscorlib data is passed to mono in this way then */
+/* it needs to remain allocated during the use of mono. */
+
+static void *corlibData = NULL;
+static size_t corlibSize = 0;
+
+void
+mono_set_corlib_data (void *data, size_t size)
+{
+ corlibData = data;
+ corlibSize = size;
+}
+
+#endif
+
/* This protects loaded_assemblies and image->references */
#define mono_assemblies_lock() EnterCriticalSection (&assemblies_mutex)
#define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex)
if (g_getenv ("MONO_DEBUG") == NULL)
return;
+ splitted = assemblies_path;
while (*splitted) {
if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
static gboolean
assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
{
+ if (!info || !info->name)
+ return FALSE;
+
if (strcmp (info->name, aname->name))
return FALSE;
if (info->major != aname->major || info->minor != aname->minor)
return FALSE;
- if ((info->culture != NULL) != (aname->culture != NULL))
+ if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
return FALSE;
- if (info->culture && strcmp (info->culture, aname->culture))
+ if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
return FALSE;
if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
static void
mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
{
+ if (!info)
+ return;
+
g_free (info->name);
g_free (info->culture);
}
mono_set_config_dir (config_dir);
}
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
static char *
compute_base (char *path)
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 {
g_free (mono);
}
-#endif /* PLATFORM_WIN32 */
+#endif /* HOST_WIN32 */
/**
* mono_set_rootdir:
void
mono_set_rootdir (void)
{
-#ifdef PLATFORM_WIN32
- gchar *bindir, *installdir, *root, *name, *config;
+#if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
+ gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
+#ifdef HOST_WIN32
name = mono_get_module_file_name ((HMODULE) &__ImageBase);
- bindir = g_path_get_dirname (name);
+#else
+ {
+ /*
+ * _NSGetExecutablePath may return -1 to indicate buf is not large
+ * enough, but we ignore that case to avoid having to do extra dynamic
+ * allocation for the path and hope that 4096 is enough - this is
+ * ok in the Linux/Solaris case below at least...
+ */
+
+ gchar buf[4096];
+ guint buf_size = sizeof (buf);
+
+ if (_NSGetExecutablePath (buf, &buf_size) == 0)
+ name = g_strdup (buf);
+
+ if (name == NULL) {
+ fallback ();
+ return;
+ }
+ }
+#endif
+
+ resolvedname = mono_path_resolve_symlinks (name);
+
+ bindir = g_path_get_dirname (resolvedname);
installdir = g_path_get_dirname (bindir);
root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
config = g_build_filename (root, "..", "etc", NULL);
+#ifdef HOST_WIN32
mono_set_dirs (root, config);
+#else
+ if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
+ mono_set_dirs (root, config);
+ else
+ fallback ();
+#endif
g_free (config);
g_free (root);
g_free (installdir);
g_free (bindir);
g_free (name);
+ g_free (resolvedname);
#elif defined(DISABLE_MONO_AUTODETECTION)
fallback ();
#else
char*
mono_stringify_assembly_name (MonoAssemblyName *aname)
{
+ const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
+
return g_strdup_printf (
- "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
- aname->name,
+ "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
+ quote, aname->name, quote,
aname->major, aname->minor, aname->build, aname->revision,
aname->culture && *aname->culture? aname->culture: "neutral",
aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
InterlockedIncrement (&assembly->ref_count);
}
+#ifndef DISABLE_ASSEMBLY_REMAPPING
static MonoAssemblyName *
mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
{
}
return aname;
}
+#endif
/*
* mono_assembly_get_assemblyref:
reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status);
if (reference == NULL){
- char *extra_msg = g_strdup ("");
+ char *extra_msg;
if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly != NULL ? image->assembly->basedir : "" );
extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
} else if (status == MONO_IMAGE_IMAGE_INVALID) {
extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
+ } else {
+ extra_msg = g_strdup ("");
}
- g_warning ("The following assembly referenced from %s could not be loaded:\n"
+ mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
" Assembly: %s (assemblyref_index=%d)\n"
" Version: %d.%d.%d.%d\n"
" Public Key: %s\n%s",
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\n",
+ 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);
}
mono_assemblies_lock ();
for (i = 0; !image && bundles [i]; ++i) {
if (strcmp (bundles [i]->name, name) == 0) {
- image = mono_image_open_from_data_full ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly);
+ image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
break;
}
}
return NULL;
}
-#if defined (PLATFORM_WIN32)
+#if defined (HOST_WIN32)
{
gchar *tmp_fn;
int i;
/* 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\n", 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
loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
mono_assemblies_unlock ();
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
if (image->is_module_handle)
mono_image_fixup_vtable (image);
#endif
arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
arr [i] |= g_ascii_xdigit_value (key [j++]);
}
- if (pubkey)
- *pubkey = arr;
+
+ *pubkey = arr;
return TRUE;
}
static gboolean
-build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, MonoAssemblyName *aname, gboolean save_public_key)
+build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, guint32 arch, MonoAssemblyName *aname, gboolean save_public_key)
{
gint major, minor, build, revision;
gint len;
}
aname->flags = flags;
+ aname->arch = arch;
aname->name = g_strdup (name);
if (culture) {
return FALSE;
}
- res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, aname, FALSE);
+ res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
g_strfreev (parts);
return res;
}
gboolean version_defined;
gboolean token_defined;
guint32 flags = 0;
+ guint32 arch = PROCESSOR_ARCHITECTURE_NONE;
if (!is_version_defined)
is_version_defined = &version_defined;
}
if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) {
- /* this is ignored for now, until we can change MonoAssemblyName */
+ 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;
+ else
+ goto cleanup_and_fail;
tmp++;
continue;
}
goto cleanup_and_fail;
}
- res = build_assembly_name (dllname, version, culture, token, key, flags,
+ res = build_assembly_name (dllname, version, culture, token, key, flags, arch,
aname, save_public_key);
g_strfreev (parts);
return res;
return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
}
+/**
+ * mono_assembly_name_new:
+ * @name: name to parse
+ *
+ * Allocate a new MonoAssemblyName and fill its values from the
+ * passed @name.
+ *
+ * Returns: a newly allocated structure or NULL if there was any failure.
+ */
+MonoAssemblyName*
+mono_assembly_name_new (const char *name)
+{
+ MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
+ if (mono_assembly_name_parse (name, aname))
+ return aname;
+ g_free (aname);
+ return NULL;
+}
+
+const char*
+mono_assembly_name_get_name (MonoAssemblyName *aname)
+{
+ return aname->name;
+}
+
+const char*
+mono_assembly_name_get_culture (MonoAssemblyName *aname)
+{
+ return aname->culture;
+}
+
+mono_byte*
+mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
+{
+ if (aname->public_key_token [0])
+ return aname->public_key_token;
+ return NULL;
+}
+
+uint16_t
+mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
+{
+ if (minor)
+ *minor = aname->minor;
+ if (build)
+ *build = aname->build;
+ if (revision)
+ *revision = aname->revision;
+ return aname->major;
+}
+
static MonoAssembly*
probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
{
mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
{
MonoAssembly *res;
- MonoAssemblyName *aname, base_name, maped_aname;
+ MonoAssemblyName *aname, base_name;
+#ifndef DISABLE_ASSEMBLY_REMAPPING
+ MonoAssemblyName maped_aname;
+#endif
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
res = mono_assembly_loaded (aname);
if (res) {
return NULL;
}
+static inline gboolean
+info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
+{
+ if (left->major != right->major || left->minor != right->minor ||
+ left->build != right->build || left->revision != right->revision)
+ return FALSE;
+
+ return TRUE;
+}
+
+static inline gboolean
+info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
+{
+ if (left->has_old_version_bottom != right->has_old_version_bottom)
+ return FALSE;
+
+ if (left->has_old_version_top != right->has_old_version_top)
+ return FALSE;
+
+ if (left->has_new_version != right->has_new_version)
+ return FALSE;
+
+ if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
+ return FALSE;
+
+ if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
+ return FALSE;
+
+ if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* LOCKING: assumes all the necessary locks are held */
+static void
+assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
+{
+ MonoAssemblyBindingInfo *info_copy;
+ GSList *tmp;
+ MonoAssemblyBindingInfo *info_tmp;
+ MonoDomain *domain = (MonoDomain*)user_data;
+
+ if (!domain)
+ return;
+
+ for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
+ info_tmp = tmp->data;
+ if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
+ return;
+ }
+
+ info_copy = mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
+ memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
+ if (info->name)
+ info_copy->name = mono_mempool_strdup (domain->mp, info->name);
+ if (info->culture)
+ info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
+
+ domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
+}
+
+static inline gboolean
+info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
+{
+ if (!info->has_old_version_bottom)
+ return FALSE;
+
+ if (info->old_version_bottom.major > aname->major || info->old_version_bottom.minor > aname->minor)
+ return FALSE;
+
+ if (info->has_old_version_top && (info->old_version_top.major < aname->major || info->old_version_top.minor < aname->minor))
+ return FALSE;
+
+ /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
+ info->major = aname->major;
+ info->minor = aname->minor;
+
+ return TRUE;
+}
+
+/* LOCKING: Assumes that we are already locked - both loader and domain locks */
+static MonoAssemblyBindingInfo*
+get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
+{
+ MonoAssemblyBindingInfo *info;
+ GSList *list;
+
+ if (!domain->assembly_bindings)
+ return NULL;
+
+ info = NULL;
+ for (list = domain->assembly_bindings; list; list = list->next) {
+ info = list->data;
+ if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
+ break;
+ info = NULL;
+ }
+
+ if (info) {
+ if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
+ info->has_new_version && assembly_binding_maps_name (info, aname))
+ info->is_valid = TRUE;
+ else
+ info->is_valid = FALSE;
+ }
+
+ return info;
+}
+
static MonoAssemblyName*
mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
{
MonoAssemblyBindingInfo *info, *info2;
MonoImage *ppimage;
+ MonoDomain *domain;
if (aname->public_key_token [0] == 0)
return aname;
+ domain = mono_domain_get ();
mono_loader_lock ();
info = search_binding_loaded (aname);
+ if (!info) {
+ mono_domain_lock (domain);
+ info = get_per_domain_assembly_binding_info (domain, aname);
+ mono_domain_unlock (domain);
+ }
+
mono_loader_unlock ();
if (info) {
if (!check_policy_versions (info, aname))
return dest_name;
}
- info = g_new0 (MonoAssemblyBindingInfo, 1);
- info->major = aname->major;
- info->minor = aname->minor;
-
- ppimage = mono_assembly_load_publisher_policy (aname);
- if (ppimage) {
- get_publisher_policy_info (ppimage, aname, info);
- mono_image_close (ppimage);
+ 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);
+
+ mono_config_parse_assembly_bindings (domain_config_file, aname->major, aname->minor, domain, assembly_binding_info_parsed);
+ domain->assembly_bindings_parsed = TRUE;
+ g_free (domain_config_file);
+ }
+ mono_domain_unlock (domain);
+
+ mono_loader_lock ();
+ mono_domain_lock (domain);
+ 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 ();
+ }
+
+ if (!info) {
+ info = g_new0 (MonoAssemblyBindingInfo, 1);
+ info->major = aname->major;
+ info->minor = aname->minor;
+ }
+
+ if (!info->is_valid) {
+ ppimage = mono_assembly_load_publisher_policy (aname);
+ if (ppimage) {
+ get_publisher_policy_info (ppimage, aname, info);
+ mono_image_close (ppimage);
+ }
}
/* Define default error value if needed */
return result;
}
-
MonoAssembly*
mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
{
char *corlib_file;
+ MonoAssemblyName *aname;
if (corlib) {
/* g_print ("corlib already loaded\n"); */
return corlib;
}
-
+
+#if defined(__native_client__)
+ if (corlibData != NULL && corlibSize != 0) {
+ int status = 0;
+ /* First "FALSE" instructs mono not to make a copy. */
+ /* Second "FALSE" says this is not just a ref. */
+ MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
+ if (image == NULL || status != 0)
+ g_print("mono_image_open_from_data_full failed: %d\n", status);
+ corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
+ if (corlib == NULL || status != 0)
+ g_print ("mono_assembly_load_from_full failed: %d\n", status);
+ if (corlib)
+ return corlib;
+ }
+#endif
+
+ aname = mono_assembly_name_new ("mscorlib.dll");
+ corlib = invoke_assembly_preload_hook (aname, assemblies_path);
+ mono_assembly_name_free (aname);
+ g_free (aname);
+ if (corlib != NULL)
+ return corlib;
+
if (assemblies_path) {
corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
if (corlib)
{
MonoAssembly *result;
char *fullpath, *filename;
- MonoAssemblyName maped_aname, maped_name_pp;
+#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);
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