2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "assembly-internals.h"
21 #include "image-internals.h"
22 #include "object-internals.h"
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/custom-attrs-internals.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include <mono/metadata/reflection-internals.h>
31 #include <mono/metadata/mono-endian.h>
32 #include <mono/metadata/mono-debug.h>
33 #include <mono/utils/mono-uri.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/mono-config-dirs.h>
36 #include <mono/utils/mono-digest.h>
37 #include <mono/utils/mono-logger-internals.h>
38 #include <mono/utils/mono-path.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/metadata/coree.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/utils/mono-io-portability.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-os-mutex.h>
47 #include <sys/types.h>
52 #ifdef PLATFORM_MACOSX
53 #include <mach-o/dyld.h>
56 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
58 const char* assembly_name;
59 guint8 version_set_index;
60 const char* new_assembly_name;
61 gboolean only_lower_versions;
64 /* the default search path is empty, the first slot is replaced with the computed value */
72 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
73 static char **assemblies_path = NULL;
75 /* Contains the list of directories that point to auxiliary GACs */
76 static char **extra_gac_paths = NULL;
78 #ifndef DISABLE_ASSEMBLY_REMAPPING
80 static GHashTable* assembly_remapping_table;
81 /* The list of system assemblies what will be remapped to the running
83 * This list is stored in @assembly_remapping_table during initialization.
84 * Keep it sorted just to make maintenance easier.
86 * The integer number is an index in the MonoRuntimeInfo structure, whose
87 * values can be found in domain.c - supported_runtimes. Look there
88 * to understand what remapping will be made.
90 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
93 static const AssemblyVersionMap framework_assemblies [] = {
95 {"Commons.Xml.Relaxng", 0},
102 {"Microsoft.Build.Engine", 2, NULL, TRUE},
103 {"Microsoft.Build.Framework", 2, NULL, TRUE},
104 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
105 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
106 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
107 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
108 {"Microsoft.VisualBasic", 1},
109 {"Microsoft.VisualC", 1},
111 {"Mono.CompilerServices.SymbolWriter", 0},
113 {"Mono.Data.SybaseClient", 0},
114 {"Mono.Data.Tds", 0},
115 {"Mono.Data.TdsClient", 0},
116 {"Mono.GetOptions", 0},
119 {"Mono.Security", 0},
120 {"Mono.Security.Win32", 0},
122 {"Novell.Directory.Ldap", 0},
125 {"System.ComponentModel.Composition", 2},
126 {"System.ComponentModel.DataAnnotations", 2},
127 {"System.Configuration", 0},
128 {"System.Configuration.Install", 0},
131 {"System.Data.Linq", 2},
132 {"System.Data.OracleClient", 0},
133 {"System.Data.Services", 2},
134 {"System.Data.Services.Client", 2},
135 {"System.Data.SqlXml", 0},
136 {"System.Design", 0},
137 {"System.DirectoryServices", 0},
138 {"System.Drawing", 0},
139 {"System.Drawing.Design", 0},
140 {"System.EnterpriseServices", 0},
141 {"System.IO.Compression", 2},
142 {"System.IdentityModel", 3},
143 {"System.IdentityModel.Selectors", 3},
144 {"System.Management", 0},
145 {"System.Messaging", 0},
147 {"System.Net.Http", 3},
148 {"System.Numerics.Vectors", 3},
149 {"System.Runtime.InteropServices.RuntimeInformation", 2},
150 {"System.Runtime.Remoting", 0},
151 {"System.Runtime.Serialization", 3},
152 {"System.Runtime.Serialization.Formatters", 3},
153 {"System.Runtime.Serialization.Formatters.Soap", 0},
154 {"System.Security", 0},
155 {"System.ServiceModel", 3},
156 {"System.ServiceModel.Duplex", 3},
157 {"System.ServiceModel.Http", 3},
158 {"System.ServiceModel.NetTcp", 3},
159 {"System.ServiceModel.Primitives", 3},
160 {"System.ServiceModel.Security", 3},
161 {"System.ServiceModel.Web", 2},
162 {"System.ServiceProcess", 0},
163 {"System.Text.Encoding.CodePages", 3},
164 {"System.Transactions", 0},
166 {"System.Web.Abstractions", 2},
167 {"System.Web.DynamicData", 2},
168 {"System.Web.Extensions", 2},
169 {"System.Web.Mobile", 0},
170 {"System.Web.Routing", 2},
171 {"System.Web.Services", 0},
172 {"System.Windows.Forms", 0},
174 {"System.Xml.Linq", 2},
175 {"System.Xml.ReaderWriter", 3},
176 {"System.Xml.XPath.XmlDocument", 3},
183 * keeps track of loaded assemblies
185 static GList *loaded_assemblies = NULL;
186 static MonoAssembly *corlib;
188 #if defined(__native_client__)
190 /* On Native Client, allow mscorlib to be loaded from memory */
191 /* instead of loaded off disk. If these are not set, default */
192 /* mscorlib loading will take place */
194 /* NOTE: If mscorlib data is passed to mono in this way then */
195 /* it needs to remain allocated during the use of mono. */
197 static void *corlibData = NULL;
198 static size_t corlibSize = 0;
201 mono_set_corlib_data (void *data, size_t size)
209 static char* unquote (const char *str);
211 /* This protects loaded_assemblies and image->references */
212 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
213 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
214 static mono_mutex_t assemblies_mutex;
216 /* If defined, points to the bundled assembly information */
217 const MonoBundledAssembly **bundles;
219 static mono_mutex_t assembly_binding_mutex;
221 /* Loaded assembly binding info */
222 static GSList *loaded_assembly_bindings = NULL;
224 /* Class lazy loading functions */
225 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
227 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
229 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
231 mono_assembly_is_in_gac (const gchar *filanem);
234 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
237 encode_public_tok (const guchar *token, gint32 len)
239 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
243 res = (gchar *)g_malloc (len * 2 + 1);
244 for (i = 0; i < len; i++) {
245 res [i * 2] = allowed [token [i] >> 4];
246 res [i * 2 + 1] = allowed [token [i] & 0xF];
253 * mono_public_tokens_are_equal:
254 * @pubt1: first public key token
255 * @pubt2: second public key token
257 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
261 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
263 return memcmp (pubt1, pubt2, 16) == 0;
267 * mono_set_assemblies_path:
268 * @path: list of paths that contain directories where Mono will look for assemblies
270 * Use this method to override the standard assembly lookup system and
271 * override any assemblies coming from the GAC. This is the method
272 * that supports the MONO_PATH variable.
274 * Notice that MONO_PATH and this method are really a very bad idea as
275 * it prevents the GAC from working and it prevents the standard
276 * resolution mechanisms from working. Nonetheless, for some debugging
277 * situations and bootstrapping setups, this is useful to have.
280 mono_set_assemblies_path (const char* path)
282 char **splitted, **dest;
284 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
286 g_strfreev (assemblies_path);
287 assemblies_path = dest = splitted;
289 char *tmp = *splitted;
291 *dest++ = mono_path_canonicalize (tmp);
297 if (g_getenv ("MONO_DEBUG") == NULL)
300 splitted = assemblies_path;
302 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
303 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
309 /* Native Client can't get this info from an environment variable so */
310 /* it's passed in to the runtime, or set manually by embedding code. */
311 #ifdef __native_client__
312 char* nacl_mono_path = NULL;
316 check_path_env (void)
319 path = g_getenv ("MONO_PATH");
320 #ifdef __native_client__
322 path = nacl_mono_path;
324 if (!path || assemblies_path != NULL)
327 mono_set_assemblies_path(path);
331 check_extra_gac_path_env (void) {
333 char **splitted, **dest;
335 path = g_getenv ("MONO_GAC_PREFIX");
339 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
341 g_strfreev (extra_gac_paths);
342 extra_gac_paths = dest = splitted;
350 if (g_getenv ("MONO_DEBUG") == NULL)
354 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
355 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
362 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
364 if (!info || !info->name)
367 if (strcmp (info->name, aname->name))
370 if (info->major != aname->major || info->minor != aname->minor)
373 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
376 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
379 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
386 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
392 g_free (info->culture);
396 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
399 guint32 cols [MONO_MANIFEST_SIZE];
400 const gchar *filename;
401 gchar *subpath, *fullpath;
403 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
404 /* MS Impl. accepts policy assemblies with more than
405 * one manifest resource, and only takes the first one */
407 binding_info->is_valid = FALSE;
411 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
412 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
413 binding_info->is_valid = FALSE;
417 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
418 g_assert (filename != NULL);
420 subpath = g_path_get_dirname (image->name);
421 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
422 mono_config_parse_publisher_policy (fullpath, binding_info);
426 /* Define the optional elements/attributes before checking */
427 if (!binding_info->culture)
428 binding_info->culture = g_strdup ("");
430 /* Check that the most important elements/attributes exist */
431 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
432 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
433 mono_assembly_binding_info_free (binding_info);
434 binding_info->is_valid = FALSE;
438 binding_info->is_valid = TRUE;
442 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
444 if (v->major > aname->major)
446 else if (v->major < aname->major)
449 if (v->minor > aname->minor)
451 else if (v->minor < aname->minor)
454 if (v->build > aname->build)
456 else if (v->build < aname->build)
459 if (v->revision > aname->revision)
461 else if (v->revision < aname->revision)
468 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
473 /* If has_old_version_top doesn't exist, we don't have an interval */
474 if (!info->has_old_version_top) {
475 if (compare_versions (&info->old_version_bottom, name) == 0)
481 /* Check that the version defined by name is valid for the interval */
482 if (compare_versions (&info->old_version_top, name) < 0)
485 /* We should be greater or equal than the small version */
486 if (compare_versions (&info->old_version_bottom, name) > 0)
493 * mono_assembly_names_equal:
495 * @r: second assembly.
497 * Compares two MonoAssemblyNames and returns whether they are equal.
499 * This compares the names, the cultures, the release version and their
502 * Returns: TRUE if both assembly names are equal.
505 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
507 if (!l->name || !r->name)
510 if (strcmp (l->name, r->name))
513 if (l->culture && r->culture && strcmp (l->culture, r->culture))
516 if (l->major != r->major || l->minor != r->minor ||
517 l->build != r->build || l->revision != r->revision)
518 if (! ((l->major == 0 && l->minor == 0 && l->build == 0 && l->revision == 0) || (r->major == 0 && r->minor == 0 && r->build == 0 && r->revision == 0)))
521 if (!l->public_key_token [0] || !r->public_key_token [0])
524 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
530 static MonoAssembly *
531 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
535 MonoAssembly *result;
537 for (i = 0; search_path [i]; ++i) {
538 fullpath = g_build_filename (search_path [i], basename, NULL);
539 result = mono_assembly_open_full (fullpath, status, refonly);
548 * mono_assembly_setrootdir:
549 * @root_dir: The pathname of the root directory where we will locate assemblies
551 * This routine sets the internal default root directory for looking up
554 * This is used by Windows installations to compute dynamically the
555 * place where the Mono assemblies are located.
559 mono_assembly_setrootdir (const char *root_dir)
562 * Override the MONO_ASSEMBLIES directory configured at compile time.
564 /* Leak if called more than once */
565 default_path [0] = g_strdup (root_dir);
569 * mono_assembly_getrootdir:
571 * Obtains the root directory used for looking up assemblies.
573 * Returns: a string with the directory, this string should not be freed.
575 G_CONST_RETURN gchar *
576 mono_assembly_getrootdir (void)
578 return default_path [0];
582 * mono_native_getrootdir:
584 * Obtains the root directory used for looking up native libs (.so, .dylib).
586 * Returns: a string with the directory, this string should be freed by
590 mono_native_getrootdir (void)
592 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
598 * @assembly_dir: the base directory for assemblies
599 * @config_dir: the base directory for configuration files
601 * This routine is used internally and by developers embedding
602 * the runtime into their own applications.
604 * There are a number of cases to consider: Mono as a system-installed
605 * package that is available on the location preconfigured or Mono in
606 * a relocated location.
608 * If you are using a system-installed Mono, you can pass NULL
609 * to both parameters. If you are not, you should compute both
610 * directory values and call this routine.
612 * The values for a given PREFIX are:
614 * assembly_dir: PREFIX/lib
615 * config_dir: PREFIX/etc
617 * Notice that embedders that use Mono in a relocated way must
618 * compute the location at runtime, as they will be in control
619 * of where Mono is installed.
622 mono_set_dirs (const char *assembly_dir, const char *config_dir)
624 if (assembly_dir == NULL)
625 assembly_dir = mono_config_get_assemblies_dir ();
626 if (config_dir == NULL)
627 config_dir = mono_config_get_cfg_dir ();
628 mono_assembly_setrootdir (assembly_dir);
629 mono_set_config_dir (config_dir);
635 compute_base (char *path)
637 char *p = strrchr (path, '/');
641 /* Not a well known Mono executable, we are embedded, cant guess the base */
642 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
646 p = strrchr (path, '/');
650 if (strcmp (p, "/bin") != 0)
659 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
662 static G_GNUC_UNUSED void
666 char *config, *lib, *mono;
671 * Only /usr prefix is treated specially
673 bindir = mono_config_get_bin_dir ();
675 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
680 config = g_build_filename (base, "etc", NULL);
681 lib = g_build_filename (base, "lib", NULL);
682 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
683 if (stat (mono, &buf) == -1)
686 mono_set_dirs (lib, config);
694 #endif /* HOST_WIN32 */
699 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
700 * this auto-detects the prefix where Mono was installed.
703 mono_set_rootdir (void)
705 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
706 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
709 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
713 * _NSGetExecutablePath may return -1 to indicate buf is not large
714 * enough, but we ignore that case to avoid having to do extra dynamic
715 * allocation for the path and hope that 4096 is enough - this is
716 * ok in the Linux/Solaris case below at least...
720 guint buf_size = sizeof (buf);
723 if (_NSGetExecutablePath (buf, &buf_size) == 0)
724 name = g_strdup (buf);
733 resolvedname = mono_path_resolve_symlinks (name);
735 bindir = g_path_get_dirname (resolvedname);
736 installdir = g_path_get_dirname (bindir);
737 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
739 config = g_build_filename (root, "..", "etc", NULL);
741 mono_set_dirs (root, config);
743 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
744 mono_set_dirs (root, config);
754 g_free (resolvedname);
755 #elif defined(DISABLE_MONO_AUTODETECTION)
763 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
771 /* Solaris 10 style */
772 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
773 s = readlink (str, buf, sizeof (buf)-1);
785 * mono_assemblies_init:
787 * Initialize global variables used by this module.
790 mono_assemblies_init (void)
793 * Initialize our internal paths if we have not been initialized yet.
794 * This happens when embedders use Mono.
796 if (mono_assembly_getrootdir () == NULL)
800 check_extra_gac_path_env ();
802 mono_os_mutex_init_recursive (&assemblies_mutex);
803 mono_os_mutex_init (&assembly_binding_mutex);
805 #ifndef DISABLE_ASSEMBLY_REMAPPING
806 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
809 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
810 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
816 mono_assembly_binding_lock (void)
818 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
822 mono_assembly_binding_unlock (void)
824 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
828 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
830 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
831 guint32 cols [MONO_ASSEMBLY_SIZE];
832 gint32 machine, flags;
837 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
840 aname->hash_value = NULL;
841 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
843 aname->name = g_strdup (aname->name);
844 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
846 aname->culture = g_strdup (aname->culture);
847 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
848 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
849 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
850 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
851 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
852 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
853 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
854 guchar* token = (guchar *)g_malloc (8);
859 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
860 len = mono_metadata_decode_blob_size (pkey, &pkey);
861 aname->public_key = (guchar*)pkey;
863 mono_digest_get_public_token (token, aname->public_key, len);
864 encoded = encode_public_tok (token, 8);
865 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
871 aname->public_key = NULL;
872 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
875 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
876 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
878 const gchar *pkey_end;
879 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
880 pkey_end += len; /* move to end */
881 size_t size = pkey_end - (const gchar*)aname->public_key;
882 guchar *tmp = g_new (guchar, size);
883 memcpy (tmp, aname->public_key, size);
884 aname->public_key = tmp;
889 aname->public_key = 0;
891 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
892 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
894 case COFF_MACHINE_I386:
895 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
896 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
897 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
898 else if ((flags & 0x70) == 0x70)
899 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
901 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
903 case COFF_MACHINE_IA64:
904 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
906 case COFF_MACHINE_AMD64:
907 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
909 case COFF_MACHINE_ARM:
910 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
920 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
922 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
926 * mono_stringify_assembly_name:
927 * @aname: the assembly name.
929 * Convert @aname into its string format. The returned string is dynamically
930 * allocated and should be freed by the caller.
932 * Returns: a newly allocated string with a string representation of
936 mono_stringify_assembly_name (MonoAssemblyName *aname)
938 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
940 return g_strdup_printf (
941 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
942 quote, aname->name, quote,
943 aname->major, aname->minor, aname->build, aname->revision,
944 aname->culture && *aname->culture? aname->culture: "neutral",
945 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
946 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
950 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
952 const gchar *public_tok;
955 public_tok = mono_metadata_blob_heap (image, key_index);
956 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
958 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
960 mono_digest_get_public_token (token, (guchar*)public_tok, len);
961 return encode_public_tok (token, 8);
964 return encode_public_tok ((guchar*)public_tok, len);
968 * mono_assembly_addref:
969 * @assemnly: the assembly to reference
971 * This routine increments the reference count on a MonoAssembly.
972 * The reference count is reduced every time the method mono_assembly_close() is
976 mono_assembly_addref (MonoAssembly *assembly)
978 InterlockedIncrement (&assembly->ref_count);
982 * CAUTION: This table must be kept in sync with
983 * ivkm/reflect/Fusion.cs
986 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
987 #define WINFX_KEY "31bf3856ad364e35"
988 #define ECMA_KEY "b77a5c561934e089"
989 #define MSFINAL_KEY "b03f5f7f11d50a3a"
990 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
998 static KeyRemapEntry key_remap_table[] = {
999 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1000 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1001 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1002 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1003 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1004 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1005 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1006 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1007 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1008 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1009 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1010 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1011 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1012 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1013 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1014 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1015 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1016 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1017 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1018 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1019 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1020 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1021 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1022 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1023 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1024 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1025 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1026 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1027 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1031 remap_keys (MonoAssemblyName *aname)
1034 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1035 const KeyRemapEntry *entry = &key_remap_table [i];
1037 if (strcmp (aname->name, entry->name) ||
1038 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1041 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1043 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1044 "Remapped public key token of retargetable assembly %s from %s to %s",
1045 aname->name, entry->from, entry->to);
1050 static MonoAssemblyName *
1051 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1053 const MonoRuntimeInfo *current_runtime;
1055 if (aname->name == NULL) return aname;
1057 current_runtime = mono_get_runtime_info ();
1059 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1060 const AssemblyVersionSet* vset;
1062 /* Remap to current runtime */
1063 vset = ¤t_runtime->version_sets [0];
1065 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1066 dest_aname->major = vset->major;
1067 dest_aname->minor = vset->minor;
1068 dest_aname->build = vset->build;
1069 dest_aname->revision = vset->revision;
1070 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1072 /* Remap assembly name */
1073 if (!strcmp (aname->name, "System.Net"))
1074 dest_aname->name = g_strdup ("System");
1076 remap_keys (dest_aname);
1078 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1079 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1081 aname->major, aname->minor, aname->build, aname->revision,
1083 vset->major, vset->minor, vset->build, vset->revision
1089 #ifndef DISABLE_ASSEMBLY_REMAPPING
1090 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1092 const AssemblyVersionSet* vset;
1093 int index = vmap->version_set_index;
1094 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1095 vset = ¤t_runtime->version_sets [index];
1097 if (aname->major == vset->major && aname->minor == vset->minor &&
1098 aname->build == vset->build && aname->revision == vset->revision) {
1099 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1101 aname->major, aname->minor, aname->build, aname->revision);
1105 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1106 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1107 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1109 aname->major, aname->minor, aname->build, aname->revision,
1110 vset->major, vset->minor, vset->build, vset->revision
1115 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1116 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1117 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1119 aname->major, aname->minor, aname->build, aname->revision,
1120 vset->major, vset->minor, vset->build, vset->revision
1123 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1124 dest_aname->major = vset->major;
1125 dest_aname->minor = vset->minor;
1126 dest_aname->build = vset->build;
1127 dest_aname->revision = vset->revision;
1128 if (vmap->new_assembly_name != NULL) {
1129 dest_aname->name = vmap->new_assembly_name;
1130 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1131 "The assembly name %s was remapped to %s",
1143 * mono_assembly_get_assemblyref:
1144 * @image: pointer to the MonoImage to extract the information from.
1145 * @index: index to the assembly reference in the image.
1146 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1148 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1151 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1154 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1157 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1159 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1161 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1162 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1163 aname->hash_value = hash;
1164 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1165 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1166 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1167 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1168 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1169 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1170 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1172 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1173 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1174 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1177 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1182 mono_assembly_load_reference (MonoImage *image, int index)
1184 MonoAssembly *reference;
1185 MonoAssemblyName aname;
1186 MonoImageOpenStatus status;
1189 * image->references is shared between threads, so we need to access
1190 * it inside a critical section.
1192 mono_assemblies_lock ();
1193 if (!image->references) {
1194 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1196 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1197 image->nreferences = t->rows;
1199 reference = image->references [index];
1200 mono_assemblies_unlock ();
1204 mono_assembly_get_assemblyref (image, index, &aname);
1206 if (image->assembly && image->assembly->ref_only) {
1207 /* We use the loaded corlib */
1208 if (!strcmp (aname.name, "mscorlib"))
1209 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1211 reference = mono_assembly_loaded_full (&aname, TRUE);
1213 /* Try a postload search hook */
1214 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1218 * Here we must advice that the error was due to
1219 * a non loaded reference using the ReflectionOnly api
1222 reference = (MonoAssembly *)REFERENCE_MISSING;
1224 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1225 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1226 * accordingly, it would fail on the MS runtime before).
1227 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1228 * example bug-349190.2.cs and who knows how much more code in the wild.
1230 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1231 if (!reference && image->assembly)
1232 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1235 if (reference == NULL){
1238 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1239 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 : "" );
1240 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1241 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1242 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1243 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1244 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1245 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1247 extra_msg = g_strdup ("");
1250 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1251 " Assembly: %s (assemblyref_index=%d)\n"
1252 " Version: %d.%d.%d.%d\n"
1253 " Public Key: %s\n%s",
1254 image->name, aname.name, index,
1255 aname.major, aname.minor, aname.build, aname.revision,
1256 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1261 mono_assemblies_lock ();
1262 if (reference == NULL) {
1263 /* Flag as not found */
1264 reference = (MonoAssembly *)REFERENCE_MISSING;
1267 if (!image->references [index]) {
1268 if (reference != REFERENCE_MISSING){
1269 mono_assembly_addref (reference);
1270 if (image->assembly)
1271 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1272 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1274 if (image->assembly)
1275 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1276 image->assembly->aname.name, image->assembly);
1279 image->references [index] = reference;
1281 mono_assemblies_unlock ();
1283 if (image->references [index] != reference) {
1284 /* Somebody loaded it before us */
1285 mono_assembly_close (reference);
1290 * mono_assembly_load_references:
1293 * @deprecated: There is no reason to use this method anymore, it does nothing
1295 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1298 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1300 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1301 *status = MONO_IMAGE_OK;
1304 typedef struct AssemblyLoadHook AssemblyLoadHook;
1305 struct AssemblyLoadHook {
1306 AssemblyLoadHook *next;
1307 MonoAssemblyLoadFunc func;
1311 AssemblyLoadHook *assembly_load_hook = NULL;
1314 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1316 AssemblyLoadHook *hook;
1318 for (hook = assembly_load_hook; hook; hook = hook->next) {
1319 hook->func (ass, hook->user_data);
1324 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1326 AssemblyLoadHook *hook;
1328 g_return_if_fail (func != NULL);
1330 hook = g_new0 (AssemblyLoadHook, 1);
1332 hook->user_data = user_data;
1333 hook->next = assembly_load_hook;
1334 assembly_load_hook = hook;
1338 free_assembly_load_hooks (void)
1340 AssemblyLoadHook *hook, *next;
1342 for (hook = assembly_load_hook; hook; hook = next) {
1348 typedef struct AssemblySearchHook AssemblySearchHook;
1349 struct AssemblySearchHook {
1350 AssemblySearchHook *next;
1351 MonoAssemblySearchFunc func;
1357 AssemblySearchHook *assembly_search_hook = NULL;
1359 static MonoAssembly*
1360 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1362 AssemblySearchHook *hook;
1364 for (hook = assembly_search_hook; hook; hook = hook->next) {
1365 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1368 * A little explanation is in order here.
1370 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1371 * The embedding API exposes a search hook that doesn't take such argument.
1373 * The original fix would call the default search hook before all the registered ones and pass
1374 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1375 * rely on. Which is the ordering between user hooks and the default runtime hook.
1377 * Registering the hook after mono_jit_init would let your hook run before the default one and
1378 * when using it to handle non standard app layouts this could save your app from a massive amount
1379 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1380 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1382 * So what's the fix? We register the default hook using regular means and special case it when iterating
1383 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1386 if (hook->func == (void*)mono_domain_assembly_postload_search)
1387 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1389 ass = hook->func (aname, hook->user_data);
1399 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1401 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1405 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1407 AssemblySearchHook *hook;
1409 g_return_if_fail (func != NULL);
1411 hook = g_new0 (AssemblySearchHook, 1);
1413 hook->user_data = user_data;
1414 hook->refonly = refonly;
1415 hook->postload = postload;
1416 hook->next = assembly_search_hook;
1417 assembly_search_hook = hook;
1421 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1423 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1427 free_assembly_search_hooks (void)
1429 AssemblySearchHook *hook, *next;
1431 for (hook = assembly_search_hook; hook; hook = next) {
1438 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1440 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1444 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1446 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1450 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1452 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1455 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1456 struct AssemblyPreLoadHook {
1457 AssemblyPreLoadHook *next;
1458 MonoAssemblyPreLoadFunc func;
1462 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1463 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1465 static MonoAssembly *
1466 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1468 AssemblyPreLoadHook *hook;
1469 MonoAssembly *assembly;
1471 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1472 assembly = hook->func (aname, assemblies_path, hook->user_data);
1473 if (assembly != NULL)
1480 static MonoAssembly *
1481 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1483 AssemblyPreLoadHook *hook;
1484 MonoAssembly *assembly;
1486 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1487 assembly = hook->func (aname, assemblies_path, hook->user_data);
1488 if (assembly != NULL)
1496 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1498 AssemblyPreLoadHook *hook;
1500 g_return_if_fail (func != NULL);
1502 hook = g_new0 (AssemblyPreLoadHook, 1);
1504 hook->user_data = user_data;
1505 hook->next = assembly_preload_hook;
1506 assembly_preload_hook = hook;
1510 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1512 AssemblyPreLoadHook *hook;
1514 g_return_if_fail (func != NULL);
1516 hook = g_new0 (AssemblyPreLoadHook, 1);
1518 hook->user_data = user_data;
1519 hook->next = assembly_refonly_preload_hook;
1520 assembly_refonly_preload_hook = hook;
1524 free_assembly_preload_hooks (void)
1526 AssemblyPreLoadHook *hook, *next;
1528 for (hook = assembly_preload_hook; hook; hook = next) {
1533 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1540 absolute_dir (const gchar *filename)
1551 if (g_path_is_absolute (filename)) {
1552 part = g_path_get_dirname (filename);
1553 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1558 cwd = g_get_current_dir ();
1559 mixed = g_build_filename (cwd, filename, NULL);
1560 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1565 for (i = 0; (part = parts [i]) != NULL; i++) {
1566 if (!strcmp (part, "."))
1569 if (!strcmp (part, "..")) {
1570 if (list && list->next) /* Don't remove root */
1571 list = g_list_delete_link (list, list);
1573 list = g_list_prepend (list, part);
1577 result = g_string_new ("");
1578 list = g_list_reverse (list);
1580 /* Ignores last data pointer, which should be the filename */
1581 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1583 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1588 g_string_free (result, FALSE);
1593 return g_strdup (".");
1600 * mono_assembly_open_from_bundle:
1601 * @filename: Filename requested
1602 * @status: return status code
1604 * This routine tries to open the assembly specified by `filename' from the
1605 * defined bundles, if found, returns the MonoImage for it, if not found
1609 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1613 gchar *lowercase_filename;
1614 MonoImage *image = NULL;
1615 gboolean is_satellite = FALSE;
1617 * we do a very simple search for bundled assemblies: it's not a general
1618 * purpose assembly loading mechanism.
1624 lowercase_filename = g_utf8_strdown (filename, -1);
1625 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1626 g_free (lowercase_filename);
1627 name = g_path_get_basename (filename);
1628 mono_assemblies_lock ();
1629 for (i = 0; !image && bundles [i]; ++i) {
1630 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1631 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1635 mono_assemblies_unlock ();
1637 mono_image_addref (image);
1638 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1647 * mono_assemblies_open_full:
1648 * @filename: the file to load
1649 * @status: return status code
1650 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1652 * This loads an assembly from the specified @filename. The @filename allows
1653 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1654 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1655 * is treated as a local path.
1657 * First, an attempt is made to load the assembly from the bundled executable (for those
1658 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1659 * assembly has been registered as an embedded assembly). If this is not the case, then
1660 * the assembly is loaded from disk using `api:mono_image_open_full`.
1662 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1663 * the assembly is made.
1665 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1666 * the `System.Reflection` API.
1668 * Returns: NULL on error, with the @status set to an error code, or a pointer
1672 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1676 MonoImageOpenStatus def_status;
1679 gboolean loaded_from_bundle;
1681 g_return_val_if_fail (filename != NULL, NULL);
1684 status = &def_status;
1685 *status = MONO_IMAGE_OK;
1687 if (strncmp (filename, "file://", 7) == 0) {
1688 GError *error = NULL;
1689 gchar *uri = (gchar *) filename;
1693 * MS allows file://c:/... and fails on file://localhost/c:/...
1694 * They also throw an IndexOutOfRangeException if "file://"
1697 uri = g_strdup_printf ("file:///%s", uri + 7);
1700 uri = mono_escape_uri_string (tmpuri);
1701 fname = g_filename_from_uri (uri, NULL, &error);
1704 if (tmpuri != filename)
1707 if (error != NULL) {
1708 g_warning ("%s\n", error->message);
1709 g_error_free (error);
1710 fname = g_strdup (filename);
1713 fname = g_strdup (filename);
1716 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1717 "Assembly Loader probing location: '%s'.", fname);
1720 if (!mono_assembly_is_in_gac (fname)) {
1722 new_fname = mono_make_shadow_copy (fname, &error);
1723 if (!is_ok (&error)) {
1724 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1725 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1726 mono_error_cleanup (&error);
1727 *status = MONO_IMAGE_IMAGE_INVALID;
1732 if (new_fname && new_fname != fname) {
1735 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1736 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1741 // If VM built with mkbundle
1742 loaded_from_bundle = FALSE;
1743 if (bundles != NULL) {
1744 image = mono_assembly_open_from_bundle (fname, status, refonly);
1745 loaded_from_bundle = image != NULL;
1749 image = mono_image_open_full (fname, status, refonly);
1752 if (*status == MONO_IMAGE_OK)
1753 *status = MONO_IMAGE_ERROR_ERRNO;
1758 if (image->assembly) {
1759 /* Already loaded by another appdomain */
1760 mono_assembly_invoke_load_hook (image->assembly);
1761 mono_image_close (image);
1763 return image->assembly;
1766 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1769 if (!loaded_from_bundle)
1770 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1771 "Assembly Loader loaded assembly from location: '%s'.", filename);
1773 mono_config_for_assembly (ass->image);
1776 /* Clear the reference added by mono_image_open */
1777 mono_image_close (image);
1785 free_item (gpointer val, gpointer user_data)
1791 * mono_assembly_load_friends:
1794 * Load the list of friend assemblies that are allowed to access
1795 * the assembly's internal types and members. They are stored as assembly
1796 * names in custom attributes.
1798 * This is an internal method, we need this because when we load mscorlib
1799 * we do not have the internals visible cattr loaded yet,
1800 * so we need to load these after we initialize the runtime.
1802 * LOCKING: Acquires the assemblies lock plus the loader lock.
1805 mono_assembly_load_friends (MonoAssembly* ass)
1809 MonoCustomAttrInfo* attrs;
1812 if (ass->friend_assembly_names_inited)
1815 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1816 mono_error_assert_ok (&error);
1818 mono_assemblies_lock ();
1819 ass->friend_assembly_names_inited = TRUE;
1820 mono_assemblies_unlock ();
1824 mono_assemblies_lock ();
1825 if (ass->friend_assembly_names_inited) {
1826 mono_assemblies_unlock ();
1829 mono_assemblies_unlock ();
1833 * We build the list outside the assemblies lock, the worse that can happen
1834 * is that we'll need to free the allocated list.
1836 for (i = 0; i < attrs->num_attrs; ++i) {
1837 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1838 MonoAssemblyName *aname;
1840 /* Do some sanity checking */
1841 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1843 if (attr->data_size < 4)
1845 data = (const char*)attr->data;
1846 /* 0xFF means null string, see custom attr format */
1847 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1849 mono_metadata_decode_value (data + 2, &data);
1850 aname = g_new0 (MonoAssemblyName, 1);
1851 /*g_print ("friend ass: %s\n", data);*/
1852 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1853 list = g_slist_prepend (list, aname);
1858 mono_custom_attrs_free (attrs);
1860 mono_assemblies_lock ();
1861 if (ass->friend_assembly_names_inited) {
1862 mono_assemblies_unlock ();
1863 g_slist_foreach (list, free_item, NULL);
1864 g_slist_free (list);
1867 ass->friend_assembly_names = list;
1869 /* Because of the double checked locking pattern above */
1870 mono_memory_barrier ();
1871 ass->friend_assembly_names_inited = TRUE;
1872 mono_assemblies_unlock ();
1875 struct HasReferenceAssemblyAttributeIterData {
1880 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1882 gboolean stop_scanning = FALSE;
1883 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1885 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1886 /* Note we don't check the assembly name, same as coreCLR. */
1887 iter_data->has_attr = TRUE;
1888 stop_scanning = TRUE;
1891 return stop_scanning;
1895 * mono_assembly_has_reference_assembly_attribute:
1896 * @assembly: a MonoAssembly
1897 * @error: set on error.
1899 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1900 * On error returns FALSE and sets @error.
1903 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1908 * This might be called during assembly loading, so do everything using the low-level
1912 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1914 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1916 return iter_data.has_attr;
1920 * mono_assembly_open:
1921 * @filename: Opens the assembly pointed out by this name
1922 * @status: return status code
1924 * This loads an assembly from the specified @filename. The @filename allows
1925 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1926 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1927 * is treated as a local path.
1929 * First, an attempt is made to load the assembly from the bundled executable (for those
1930 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1931 * assembly has been registered as an embedded assembly). If this is not the case, then
1932 * the assembly is loaded from disk using `api:mono_image_open_full`.
1934 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1935 * the assembly is made.
1937 * Return: a pointer to the MonoAssembly if @filename contains a valid
1938 * assembly or NULL on error. Details about the error are stored in the
1942 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1944 return mono_assembly_open_full (filename, status, FALSE);
1948 * mono_assembly_load_from_full:
1949 * @image: Image to load the assembly from
1950 * @fname: assembly name to associate with the assembly
1951 * @status: returns the status condition
1952 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1954 * If the provided @image has an assembly reference, it will process the given
1955 * image as an assembly with the given name.
1957 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1959 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1960 * set to #MONO_IMAGE_OK; or NULL on error.
1962 * If there is an error loading the assembly the @status will indicate the
1963 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1964 * image did not contain an assembly reference table.
1967 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1968 MonoImageOpenStatus *status, gboolean refonly)
1970 MonoAssembly *ass, *ass2;
1973 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1974 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1975 *status = MONO_IMAGE_IMAGE_INVALID;
1979 #if defined (HOST_WIN32)
1984 tmp_fn = g_strdup (fname);
1985 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1986 if (tmp_fn [i] == '/')
1990 base_dir = absolute_dir (tmp_fn);
1994 base_dir = absolute_dir (fname);
1998 * Create assembly struct, and enter it into the assembly cache
2000 ass = g_new0 (MonoAssembly, 1);
2001 ass->basedir = base_dir;
2002 ass->ref_only = refonly;
2005 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2007 mono_assembly_fill_assembly_name (image, &ass->aname);
2009 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2010 // MS.NET doesn't support loading other mscorlibs
2013 mono_image_addref (mono_defaults.corlib);
2014 *status = MONO_IMAGE_OK;
2015 return mono_defaults.corlib->assembly;
2018 /* Add a non-temporary reference because of ass->image */
2019 mono_image_addref (image);
2021 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);
2024 * The load hooks might take locks so we can't call them while holding the
2027 if (ass->aname.name) {
2028 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2032 mono_image_close (image);
2033 *status = MONO_IMAGE_OK;
2038 /* We need to check for ReferenceAssmeblyAttribute before we
2039 * mark the assembly as loaded and before we fire the load
2040 * hook. Otherwise mono_domain_fire_assembly_load () in
2041 * appdomain.c will cache a mapping from the assembly name to
2042 * this image and we won't be able to look for a different
2046 MonoError refasm_error;
2047 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2048 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2051 mono_image_close (image);
2052 *status = MONO_IMAGE_IMAGE_INVALID;
2055 mono_error_cleanup (&refasm_error);
2058 mono_assemblies_lock ();
2060 if (image->assembly) {
2062 * This means another thread has already loaded the assembly, but not yet
2063 * called the load hooks so the search hook can't find the assembly.
2065 mono_assemblies_unlock ();
2066 ass2 = image->assembly;
2069 mono_image_close (image);
2070 *status = MONO_IMAGE_OK;
2074 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2076 image->assembly = ass;
2078 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2079 mono_assemblies_unlock ();
2082 if (image->is_module_handle)
2083 mono_image_fixup_vtable (image);
2086 mono_assembly_invoke_load_hook (ass);
2088 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2094 * mono_assembly_load_from:
2095 * @image: Image to load the assembly from
2096 * @fname: assembly name to associate with the assembly
2097 * @status: return status code
2099 * If the provided @image has an assembly reference, it will process the given
2100 * image as an assembly with the given name.
2102 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2104 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2105 * @refonly parameter set to FALSE.
2106 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2107 * set to #MONO_IMAGE_OK; or NULL on error.
2109 * If there is an error loading the assembly the @status will indicate the
2110 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2111 * image did not contain an assembly reference table.
2115 mono_assembly_load_from (MonoImage *image, const char *fname,
2116 MonoImageOpenStatus *status)
2118 return mono_assembly_load_from_full (image, fname, status, FALSE);
2122 * mono_assembly_name_free:
2123 * @aname: assembly name to free
2125 * Frees the provided assembly name object.
2126 * (it does not frees the object itself, only the name members).
2129 mono_assembly_name_free (MonoAssemblyName *aname)
2134 g_free ((void *) aname->name);
2135 g_free ((void *) aname->culture);
2136 g_free ((void *) aname->hash_value);
2137 g_free ((guint8*) aname->public_key);
2141 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2144 gchar header [16], val, *arr;
2145 gint i, j, offset, bitlen, keylen, pkeylen;
2147 keylen = strlen (key) >> 1;
2151 /* allow the ECMA standard key */
2152 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2154 *pubkey = g_strdup (key);
2160 val = g_ascii_xdigit_value (key [0]) << 4;
2161 val |= g_ascii_xdigit_value (key [1]);
2166 val = g_ascii_xdigit_value (key [24]);
2167 val |= g_ascii_xdigit_value (key [25]);
2179 /* We need the first 16 bytes
2180 * to check whether this key is valid or not */
2181 pkeylen = strlen (pkey) >> 1;
2185 for (i = 0, j = 0; i < 16; i++) {
2186 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2187 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2190 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2191 header [1] != 0x02 || /* Version (0x02) */
2192 header [2] != 0x00 || /* Reserved (word) */
2193 header [3] != 0x00 ||
2194 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2197 /* Based on this length, we _should_ be able to know if the length is right */
2198 bitlen = read32 (header + 12) >> 3;
2199 if ((bitlen + 16 + 4) != pkeylen)
2202 /* parsing is OK and the public key itself is not requested back */
2206 /* Encode the size of the blob */
2208 if (keylen <= 127) {
2209 arr = (gchar *)g_malloc (keylen + 1);
2210 arr [offset++] = keylen;
2212 arr = (gchar *)g_malloc (keylen + 2);
2213 arr [offset++] = 0x80; /* 10bs */
2214 arr [offset++] = keylen;
2217 for (i = offset, j = 0; i < keylen + offset; i++) {
2218 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2219 arr [i] |= g_ascii_xdigit_value (key [j++]);
2228 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)
2230 gint major, minor, build, revision;
2233 gchar *pkey, *pkeyptr, *encoded, tok [8];
2235 memset (aname, 0, sizeof (MonoAssemblyName));
2238 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2239 if (version_parts < 2 || version_parts > 4)
2242 /* FIXME: we should set build & revision to -1 (instead of 0)
2243 if these are not set in the version string. That way, later on,
2244 we can still determine if these were specified. */
2245 aname->major = major;
2246 aname->minor = minor;
2247 if (version_parts >= 3)
2248 aname->build = build;
2251 if (version_parts == 4)
2252 aname->revision = revision;
2254 aname->revision = 0;
2257 aname->flags = flags;
2259 aname->name = g_strdup (name);
2262 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2263 aname->culture = g_strdup ("");
2265 aname->culture = g_strdup (culture);
2268 if (token && strncmp (token, "null", 4) != 0) {
2271 /* the constant includes the ending NULL, hence the -1 */
2272 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2273 mono_assembly_name_free (aname);
2276 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2277 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2283 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2284 mono_assembly_name_free (aname);
2289 if (save_public_key)
2290 aname->public_key = (guint8*)pkey;
2293 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2297 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2298 // We also need to generate the key token
2299 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2300 encoded = encode_public_tok ((guchar*) tok, 8);
2301 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2304 if (save_public_key)
2305 aname->public_key = (guint8*) pkey;
2314 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2319 parts = g_strsplit (dirname, "_", 3);
2320 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2325 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2331 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2333 char *eqsign = strchr (pair, '=');
2341 *key = (gchar*)pair;
2342 *keylen = eqsign - *key;
2343 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2345 *value = g_strstrip (eqsign + 1);
2350 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2354 gchar *version = NULL;
2356 gchar *culture = NULL;
2358 gchar *token = NULL;
2362 gchar *retargetable = NULL;
2363 gchar *retargetable_uq;
2367 gchar *value, *part_name;
2368 guint32 part_name_len;
2371 gboolean version_defined;
2372 gboolean token_defined;
2374 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2376 if (!is_version_defined)
2377 is_version_defined = &version_defined;
2378 *is_version_defined = FALSE;
2379 if (!is_token_defined)
2380 is_token_defined = &token_defined;
2381 *is_token_defined = FALSE;
2383 parts = tmp = g_strsplit (name, ",", 6);
2384 if (!tmp || !*tmp) {
2389 dllname = g_strstrip (*tmp);
2394 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2395 goto cleanup_and_fail;
2397 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2398 *is_version_defined = TRUE;
2400 if (strlen (version) == 0) {
2401 goto cleanup_and_fail;
2407 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2409 if (strlen (culture) == 0) {
2410 goto cleanup_and_fail;
2416 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2417 *is_token_defined = TRUE;
2419 if (strlen (token) == 0) {
2420 goto cleanup_and_fail;
2426 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2428 if (strlen (key) == 0) {
2429 goto cleanup_and_fail;
2435 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2436 retargetable = value;
2437 retargetable_uq = unquote (retargetable);
2438 if (retargetable_uq != NULL)
2439 retargetable = retargetable_uq;
2441 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2442 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2443 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2444 g_free (retargetable_uq);
2445 goto cleanup_and_fail;
2448 g_free (retargetable_uq);
2453 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2455 procarch_uq = unquote (procarch);
2456 if (procarch_uq != NULL)
2457 procarch = procarch_uq;
2459 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2460 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2461 else if (!g_ascii_strcasecmp (procarch, "X86"))
2462 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2463 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2464 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2465 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2466 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2468 g_free (procarch_uq);
2469 goto cleanup_and_fail;
2472 g_free (procarch_uq);
2481 /* if retargetable flag is set, then we must have a fully qualified name */
2482 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2483 goto cleanup_and_fail;
2486 dllname_uq = unquote (dllname);
2487 version_uq = unquote (version);
2488 culture_uq = unquote (culture);
2489 token_uq = unquote (token);
2490 key_uq = unquote (key);
2492 res = build_assembly_name (
2493 dllname_uq == NULL ? dllname : dllname_uq,
2494 version_uq == NULL ? version : version_uq,
2495 culture_uq == NULL ? culture : culture_uq,
2496 token_uq == NULL ? token : token_uq,
2497 key_uq == NULL ? key : key_uq,
2498 flags, arch, aname, save_public_key);
2500 g_free (dllname_uq);
2501 g_free (version_uq);
2502 g_free (culture_uq);
2515 unquote (const char *str)
2523 slen = strlen (str);
2527 if (*str != '\'' && *str != '\"')
2530 end = str + slen - 1;
2534 return g_strndup (str + 1, slen - 2);
2538 * mono_assembly_name_parse:
2539 * @name: name to parse
2540 * @aname: the destination assembly name
2542 * Parses an assembly qualified type name and assigns the name,
2543 * version, culture and token to the provided assembly name object.
2545 * Returns: TRUE if the name could be parsed.
2548 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2550 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2554 * mono_assembly_name_new:
2555 * @name: name to parse
2557 * Allocate a new MonoAssemblyName and fill its values from the
2560 * Returns: a newly allocated structure or NULL if there was any failure.
2563 mono_assembly_name_new (const char *name)
2565 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2566 if (mono_assembly_name_parse (name, aname))
2573 mono_assembly_name_get_name (MonoAssemblyName *aname)
2579 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2581 return aname->culture;
2585 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2587 if (aname->public_key_token [0])
2588 return aname->public_key_token;
2593 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2596 *minor = aname->minor;
2598 *build = aname->build;
2600 *revision = aname->revision;
2601 return aname->major;
2604 static MonoAssembly*
2605 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2607 gchar *fullpath = NULL;
2609 const char* direntry;
2610 MonoAssemblyName gac_aname;
2611 gint major=-1, minor=0, build=0, revision=0;
2612 gboolean exact_version;
2614 dirhandle = g_dir_open (basepath, 0, NULL);
2618 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2620 while ((direntry = g_dir_read_name (dirhandle))) {
2621 gboolean match = TRUE;
2623 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2626 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2629 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2630 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2634 if (exact_version) {
2635 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2636 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2638 else if (gac_aname.major < major)
2640 else if (gac_aname.major == major) {
2641 if (gac_aname.minor < minor)
2643 else if (gac_aname.minor == minor) {
2644 if (gac_aname.build < build)
2646 else if (gac_aname.build == build && gac_aname.revision <= revision)
2653 major = gac_aname.major;
2654 minor = gac_aname.minor;
2655 build = gac_aname.build;
2656 revision = gac_aname.revision;
2658 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2661 mono_assembly_name_free (&gac_aname);
2664 g_dir_close (dirhandle);
2666 if (fullpath == NULL)
2669 MonoAssembly *res = mono_assembly_open (fullpath, status);
2676 * mono_assembly_load_with_partial_name:
2677 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2678 * @status: return status code
2680 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2681 * so it might contain a qualified type name, version, culture and token.
2683 * This will load the assembly from the file whose name is derived from the assembly name
2684 * by appending the .dll extension.
2686 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2687 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2688 * if that fails from the GAC.
2690 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2693 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2697 MonoAssemblyName *aname, base_name;
2698 MonoAssemblyName mapped_aname;
2699 gchar *fullname, *gacpath;
2702 memset (&base_name, 0, sizeof (MonoAssemblyName));
2705 if (!mono_assembly_name_parse (name, aname))
2709 * If no specific version has been requested, make sure we load the
2710 * correct version for system assemblies.
2712 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2713 aname = mono_assembly_remap_version (aname, &mapped_aname);
2715 res = mono_assembly_loaded (aname);
2717 mono_assembly_name_free (aname);
2721 res = invoke_assembly_preload_hook (aname, assemblies_path);
2723 res->in_gac = FALSE;
2724 mono_assembly_name_free (aname);
2728 fullname = g_strdup_printf ("%s.dll", aname->name);
2730 if (extra_gac_paths) {
2731 paths = extra_gac_paths;
2732 while (!res && *paths) {
2733 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2734 res = probe_for_partial_name (gacpath, fullname, aname, status);
2743 mono_assembly_name_free (aname);
2747 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2748 res = probe_for_partial_name (gacpath, fullname, aname, status);
2752 mono_assembly_name_free (aname);
2757 MonoDomain *domain = mono_domain_get ();
2759 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2760 if (!is_ok (&error)) {
2761 mono_error_cleanup (&error);
2762 if (*status == MONO_IMAGE_OK)
2763 *status = MONO_IMAGE_IMAGE_INVALID;
2771 mono_assembly_is_in_gac (const gchar *filename)
2773 const gchar *rootdir;
2777 if (filename == NULL)
2780 for (paths = extra_gac_paths; paths && *paths; paths++) {
2781 if (strstr (*paths, filename) != *paths)
2784 gp = (gchar *) (filename + strlen (*paths));
2785 if (*gp != G_DIR_SEPARATOR)
2788 if (strncmp (gp, "lib", 3))
2791 if (*gp != G_DIR_SEPARATOR)
2794 if (strncmp (gp, "mono", 4))
2797 if (*gp != G_DIR_SEPARATOR)
2800 if (strncmp (gp, "gac", 3))
2803 if (*gp != G_DIR_SEPARATOR)
2809 rootdir = mono_assembly_getrootdir ();
2810 if (strstr (filename, rootdir) != filename)
2813 gp = (gchar *) (filename + strlen (rootdir));
2814 if (*gp != G_DIR_SEPARATOR)
2817 if (strncmp (gp, "mono", 4))
2820 if (*gp != G_DIR_SEPARATOR)
2823 if (strncmp (gp, "gac", 3))
2826 if (*gp != G_DIR_SEPARATOR)
2832 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2835 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2839 if (strstr (aname->name, ".dll")) {
2840 len = strlen (aname->name) - 4;
2841 name = (gchar *)g_malloc (len + 1);
2842 memcpy (name, aname->name, len);
2845 name = g_strdup (aname->name);
2848 culture = g_utf8_strdown (aname->culture, -1);
2850 culture = g_strdup ("");
2852 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2853 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2857 filename = g_strconcat (pname, ".dll", NULL);
2858 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2864 if (extra_gac_paths) {
2865 paths = extra_gac_paths;
2866 while (!image && *paths) {
2867 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2868 "lib", "mono", "gac", subpath, NULL);
2869 image = mono_image_open (fullpath, NULL);
2880 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2881 "mono", "gac", subpath, NULL);
2882 image = mono_image_open (fullpath, NULL);
2889 static MonoAssemblyName*
2890 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2892 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2893 dest_name->major = info->new_version.major;
2894 dest_name->minor = info->new_version.minor;
2895 dest_name->build = info->new_version.build;
2896 dest_name->revision = info->new_version.revision;
2901 /* LOCKING: assembly_binding lock must be held */
2902 static MonoAssemblyBindingInfo*
2903 search_binding_loaded (MonoAssemblyName *aname)
2907 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2908 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2909 if (assembly_binding_maps_name (info, aname))
2916 static inline gboolean
2917 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2919 if (left->major != right->major || left->minor != right->minor ||
2920 left->build != right->build || left->revision != right->revision)
2926 static inline gboolean
2927 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2929 if (left->has_old_version_bottom != right->has_old_version_bottom)
2932 if (left->has_old_version_top != right->has_old_version_top)
2935 if (left->has_new_version != right->has_new_version)
2938 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2941 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2944 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2950 /* LOCKING: assumes all the necessary locks are held */
2952 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2954 MonoAssemblyBindingInfo *info_copy;
2956 MonoAssemblyBindingInfo *info_tmp;
2957 MonoDomain *domain = (MonoDomain*)user_data;
2962 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2963 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2964 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2968 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2969 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2971 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2973 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2975 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2979 get_version_number (int major, int minor)
2981 return major * 256 + minor;
2984 static inline gboolean
2985 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2987 int aname_version_number = get_version_number (aname->major, aname->minor);
2988 if (!info->has_old_version_bottom)
2991 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2994 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2997 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2998 info->major = aname->major;
2999 info->minor = aname->minor;
3004 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3005 static MonoAssemblyBindingInfo*
3006 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3008 MonoAssemblyBindingInfo *info;
3011 if (!domain->assembly_bindings)
3015 for (list = domain->assembly_bindings; list; list = list->next) {
3016 info = (MonoAssemblyBindingInfo *)list->data;
3017 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3023 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3024 info->has_new_version && assembly_binding_maps_name (info, aname))
3025 info->is_valid = TRUE;
3027 info->is_valid = FALSE;
3033 static MonoAssemblyName*
3034 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3037 MonoAssemblyBindingInfo *info, *info2;
3041 if (aname->public_key_token [0] == 0)
3044 domain = mono_domain_get ();
3046 mono_assembly_binding_lock ();
3047 info = search_binding_loaded (aname);
3048 mono_assembly_binding_unlock ();
3051 mono_domain_lock (domain);
3052 info = get_per_domain_assembly_binding_info (domain, aname);
3053 mono_domain_unlock (domain);
3057 if (!check_policy_versions (info, aname))
3060 mono_assembly_bind_version (info, aname, dest_name);
3064 if (domain && domain->setup && domain->setup->configuration_file) {
3065 mono_domain_lock (domain);
3066 if (!domain->assembly_bindings_parsed) {
3067 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3068 /* expect this to succeed because mono_domain_set_options_from_config () did
3069 * the same thing when the domain was created. */
3070 mono_error_assert_ok (&error);
3072 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3074 if (!domain_config_file_path)
3075 domain_config_file_path = domain_config_file_name;
3077 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3078 domain->assembly_bindings_parsed = TRUE;
3079 if (domain_config_file_name != domain_config_file_path)
3080 g_free (domain_config_file_name);
3081 g_free (domain_config_file_path);
3084 info2 = get_per_domain_assembly_binding_info (domain, aname);
3087 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3088 info->name = g_strdup (info2->name);
3089 info->culture = g_strdup (info2->culture);
3090 info->domain_id = domain->domain_id;
3093 mono_domain_unlock (domain);
3097 info = g_new0 (MonoAssemblyBindingInfo, 1);
3098 info->major = aname->major;
3099 info->minor = aname->minor;
3102 if (!info->is_valid) {
3103 ppimage = mono_assembly_load_publisher_policy (aname);
3105 get_publisher_policy_info (ppimage, aname, info);
3106 mono_image_close (ppimage);
3110 /* Define default error value if needed */
3111 if (!info->is_valid) {
3112 info->name = g_strdup (aname->name);
3113 info->culture = g_strdup (aname->culture);
3114 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3117 mono_assembly_binding_lock ();
3118 info2 = search_binding_loaded (aname);
3120 /* This binding was added by another thread
3122 mono_assembly_binding_info_free (info);
3127 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3129 mono_assembly_binding_unlock ();
3131 if (!info->is_valid || !check_policy_versions (info, aname))
3134 mono_assembly_bind_version (info, aname, dest_name);
3139 * mono_assembly_load_from_gac
3141 * @aname: The assembly name object
3143 static MonoAssembly*
3144 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3146 MonoAssembly *result = NULL;
3147 gchar *name, *version, *culture, *fullpath, *subpath;
3152 if (aname->public_key_token [0] == 0) {
3156 if (strstr (aname->name, ".dll")) {
3157 len = strlen (filename) - 4;
3158 name = (gchar *)g_malloc (len + 1);
3159 memcpy (name, aname->name, len);
3162 name = g_strdup (aname->name);
3165 if (aname->culture) {
3166 culture = g_utf8_strdown (aname->culture, -1);
3168 culture = g_strdup ("");
3171 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3172 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3173 aname->minor, aname->build, aname->revision,
3177 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3182 if (extra_gac_paths) {
3183 paths = extra_gac_paths;
3184 while (!result && *paths) {
3185 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3186 result = mono_assembly_open_full (fullpath, status, refonly);
3193 result->in_gac = TRUE;
3198 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3199 "mono", "gac", subpath, NULL);
3200 result = mono_assembly_open_full (fullpath, status, refonly);
3204 result->in_gac = TRUE;
3212 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3215 MonoAssemblyName *aname;
3218 /* g_print ("corlib already loaded\n"); */
3222 // In native client, Corlib is embedded in the executable as static variable corlibData
3223 #if defined(__native_client__)
3224 if (corlibData != NULL && corlibSize != 0) {
3226 /* First "FALSE" instructs mono not to make a copy. */
3227 /* Second "FALSE" says this is not just a ref. */
3228 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3229 if (image == NULL || status != 0)
3230 g_print("mono_image_open_from_data_full failed: %d\n", status);
3231 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3232 if (corlib == NULL || status != 0)
3233 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3239 // A nonstandard preload hook may provide a special mscorlib assembly
3240 aname = mono_assembly_name_new ("mscorlib.dll");
3241 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3242 mono_assembly_name_free (aname);
3245 goto return_corlib_and_facades;
3247 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3248 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3249 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3251 goto return_corlib_and_facades;
3254 /* Normal case: Load corlib from mono/<version> */
3255 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3256 if (assemblies_path) { // Custom assemblies path
3257 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3259 g_free (corlib_file);
3260 goto return_corlib_and_facades;
3263 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3264 g_free (corlib_file);
3266 return_corlib_and_facades:
3267 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3268 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3273 static MonoAssembly*
3274 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3276 MonoError refasm_error;
3277 error_init (&refasm_error);
3278 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3281 mono_error_cleanup (&refasm_error);
3287 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3288 const char *basedir,
3289 MonoImageOpenStatus *status,
3292 MonoAssembly *result;
3293 char *fullpath, *filename;
3294 MonoAssemblyName maped_aname;
3295 MonoAssemblyName maped_name_pp;
3300 aname = mono_assembly_remap_version (aname, &maped_aname);
3302 /* Reflection only assemblies don't get assembly binding */
3304 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3306 result = mono_assembly_loaded_full (aname, refonly);
3310 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3312 result->in_gac = FALSE;
3316 /* Currently we retrieve the loaded corlib for reflection
3317 * only requests, like a common reflection only assembly
3319 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3320 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3323 len = strlen (aname->name);
3324 for (ext_index = 0; ext_index < 2; ext_index ++) {
3325 ext = ext_index == 0 ? ".dll" : ".exe";
3326 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3327 filename = g_strdup (aname->name);
3328 /* Don't try appending .dll/.exe if it already has one of those extensions */
3331 filename = g_strconcat (aname->name, ext, NULL);
3334 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3341 fullpath = g_build_filename (basedir, filename, NULL);
3342 result = mono_assembly_open_full (fullpath, status, refonly);
3345 result->in_gac = FALSE;
3351 result = load_in_path (filename, default_path, status, refonly);
3353 result->in_gac = FALSE;
3363 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3365 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3368 /* Try a postload search hook */
3369 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3370 result = prevent_reference_assembly_from_running (result, refonly);
3376 * mono_assembly_load_full:
3377 * @aname: A MonoAssemblyName with the assembly name to load.
3378 * @basedir: A directory to look up the assembly at.
3379 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3380 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3382 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3383 * attempts to load the assembly from that directory before probing the standard locations.
3385 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3386 * assembly binding takes place.
3388 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3389 * value pointed by status is updated with an error code.
3392 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3394 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3398 * mono_assembly_load:
3399 * @aname: A MonoAssemblyName with the assembly name to load.
3400 * @basedir: A directory to look up the assembly at.
3401 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3403 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3404 * attempts to load the assembly from that directory before probing the standard locations.
3406 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3407 * value pointed by status is updated with an error code.
3410 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3412 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3416 * mono_assembly_loaded_full:
3417 * @aname: an assembly to look for.
3418 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3420 * This is used to determine if the specified assembly has been loaded
3421 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3422 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3425 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3428 MonoAssemblyName maped_aname;
3430 aname = mono_assembly_remap_version (aname, &maped_aname);
3432 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3438 * mono_assembly_loaded:
3439 * @aname: an assembly to look for.
3441 * This is used to determine if the specified assembly has been loaded
3443 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3444 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3447 mono_assembly_loaded (MonoAssemblyName *aname)
3449 return mono_assembly_loaded_full (aname, FALSE);
3453 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3455 if (assembly == NULL || assembly == REFERENCE_MISSING)
3458 if (assembly_is_dynamic (assembly)) {
3460 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3461 for (i = 0; i < dynimg->image.module_count; ++i)
3462 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3463 mono_dynamic_image_release_gc_roots (dynimg);
3468 * Returns whether mono_assembly_close_finish() must be called as
3469 * well. See comment for mono_image_close_except_pools() for why we
3470 * unload in two steps.
3473 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3476 g_return_val_if_fail (assembly != NULL, FALSE);
3478 if (assembly == REFERENCE_MISSING)
3481 /* Might be 0 already */
3482 if (InterlockedDecrement (&assembly->ref_count) > 0)
3485 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3487 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3489 mono_debug_close_image (assembly->image);
3491 mono_assemblies_lock ();
3492 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3493 mono_assemblies_unlock ();
3495 assembly->image->assembly = NULL;
3497 if (!mono_image_close_except_pools (assembly->image))
3498 assembly->image = NULL;
3500 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3501 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3502 mono_assembly_name_free (fname);
3505 g_slist_free (assembly->friend_assembly_names);
3506 g_free (assembly->basedir);
3508 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3514 mono_assembly_close_finish (MonoAssembly *assembly)
3516 g_assert (assembly && assembly != REFERENCE_MISSING);
3518 if (assembly->image)
3519 mono_image_close_finish (assembly->image);
3521 if (assembly_is_dynamic (assembly)) {
3522 g_free ((char*)assembly->aname.culture);
3529 * mono_assembly_close:
3530 * @assembly: the assembly to release.
3532 * This method releases a reference to the @assembly. The assembly is
3533 * only released when all the outstanding references to it are released.
3536 mono_assembly_close (MonoAssembly *assembly)
3538 if (mono_assembly_close_except_image_pools (assembly))
3539 mono_assembly_close_finish (assembly);
3543 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3546 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3547 mono_error_assert_ok (&error);
3552 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3554 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3559 * mono_assembly_foreach:
3560 * @func: function to invoke for each assembly loaded
3561 * @user_data: data passed to the callback
3563 * Invokes the provided @func callback for each assembly loaded into
3564 * the runtime. The first parameter passed to the callback is the
3565 * `MonoAssembly*`, and the second parameter is the @user_data.
3567 * This is done for all assemblies loaded in the runtime, not just
3568 * those loaded in the current application domain.
3571 mono_assembly_foreach (GFunc func, gpointer user_data)
3576 * We make a copy of the list to avoid calling the callback inside the
3577 * lock, which could lead to deadlocks.
3579 mono_assemblies_lock ();
3580 copy = g_list_copy (loaded_assemblies);
3581 mono_assemblies_unlock ();
3583 g_list_foreach (loaded_assemblies, func, user_data);
3589 * mono_assemblies_cleanup:
3591 * Free all resources used by this module.
3594 mono_assemblies_cleanup (void)
3598 mono_os_mutex_destroy (&assemblies_mutex);
3599 mono_os_mutex_destroy (&assembly_binding_mutex);
3601 for (l = loaded_assembly_bindings; l; l = l->next) {
3602 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3604 mono_assembly_binding_info_free (info);
3607 g_slist_free (loaded_assembly_bindings);
3609 free_assembly_load_hooks ();
3610 free_assembly_search_hooks ();
3611 free_assembly_preload_hooks ();
3614 /*LOCKING takes the assembly_binding lock*/
3616 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3620 mono_assembly_binding_lock ();
3621 iter = &loaded_assembly_bindings;
3624 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3626 if (info->domain_id == domain_id) {
3628 mono_assembly_binding_info_free (info);
3635 mono_assembly_binding_unlock ();
3639 * Holds the assembly of the application, for
3640 * System.Diagnostics.Process::MainModule
3642 static MonoAssembly *main_assembly=NULL;
3645 mono_assembly_set_main (MonoAssembly *assembly)
3647 main_assembly = assembly;
3651 * mono_assembly_get_main:
3653 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3656 mono_assembly_get_main (void)
3658 return (main_assembly);
3662 * mono_assembly_get_image:
3663 * @assembly: The assembly to retrieve the image from
3665 * Returns: the MonoImage associated with this assembly.
3668 mono_assembly_get_image (MonoAssembly *assembly)
3670 return assembly->image;
3674 * mono_assembly_get_name:
3675 * @assembly: The assembly to retrieve the name from
3677 * The returned name's lifetime is the same as @assembly's.
3679 * Returns: the MonoAssemblyName associated with this assembly.
3682 mono_assembly_get_name (MonoAssembly *assembly)
3684 return &assembly->aname;
3688 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3690 bundles = assemblies;
3693 #define MONO_DECLSEC_FORMAT_10 0x3C
3694 #define MONO_DECLSEC_FORMAT_20 0x2E
3695 #define MONO_DECLSEC_FIELD 0x53
3696 #define MONO_DECLSEC_PROPERTY 0x54
3698 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3699 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3700 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3701 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3702 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3705 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3709 case MONO_DECLSEC_PROPERTY:
3711 case MONO_DECLSEC_FIELD:
3713 *abort_decoding = TRUE;
3718 if (*p++ != MONO_TYPE_BOOLEAN) {
3719 *abort_decoding = TRUE;
3723 /* property name length */
3724 len = mono_metadata_decode_value (p, &p);
3726 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3737 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3739 int i, j, num, len, params_len;
3741 if (*p == MONO_DECLSEC_FORMAT_10) {
3742 gsize read, written;
3743 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3745 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3751 if (*p++ != MONO_DECLSEC_FORMAT_20)
3754 /* number of encoded permission attributes */
3755 num = mono_metadata_decode_value (p, &p);
3756 for (i = 0; i < num; ++i) {
3757 gboolean is_valid = FALSE;
3758 gboolean abort_decoding = FALSE;
3760 /* attribute name length */
3761 len = mono_metadata_decode_value (p, &p);
3763 /* We don't really need to fully decode the type. Comparing the name is enough */
3764 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3768 /*size of the params table*/
3769 params_len = mono_metadata_decode_value (p, &p);
3771 const char *params_end = p + params_len;
3773 /* number of parameters */
3774 len = mono_metadata_decode_value (p, &p);
3776 for (j = 0; j < len; ++j) {
3777 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3793 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3796 guint32 cols [MONO_DECL_SECURITY_SIZE];
3800 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3801 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3803 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3805 for (i = 0; i < t->rows; ++i) {
3806 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3807 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3809 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3812 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3813 len = mono_metadata_decode_blob_size (blob, &blob);
3817 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3818 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3823 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);