Mon Mar 25 13:04:56 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / loader.c
1 /*
2  * loader.c: Image Loader 
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Miguel de Icaza (miguel@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  *
10  * This file is used by the interpreter and the JIT engine to locate
11  * assemblies.  Used to load AssemblyRef and later to resolve various
12  * kinds of `Refs'.
13  *
14  * TODO:
15  *   This should keep track of the assembly versions that we are loading.
16  *
17  */
18 #include <config.h>
19 #include <glib.h>
20 #include <gmodule.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <mono/metadata/metadata.h>
24 #include <mono/metadata/image.h>
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/tokentype.h>
27 #include <mono/metadata/cil-coff.h>
28 #include <mono/metadata/tabledefs.h>
29 #include <mono/metadata/loader.h>
30 #include <mono/metadata/class.h>
31
32 static gboolean dummy_icall = TRUE;
33
34 MonoDefaults mono_defaults;
35
36 #ifdef __CYGWIN__
37 #define mono_map_dll(name) (name)
38 #else
39 static char *dll_map[] = {
40         "libc", "libc.so.6",
41         "libm", "libm.so.6",
42         "cygwin1.dll", "libc.so.6", 
43         NULL, NULL
44 };
45
46 static const char *
47 mono_map_dll (const char *name)
48 {
49         int i = 0;
50
51         while (dll_map [i]) {
52                 if (!strcmp (dll_map [i], name))
53                         return  dll_map [i + 1];
54                 i += 2;
55         }
56
57         return name;
58 }
59 #endif
60
61 static GHashTable *icall_hash = NULL;
62
63 void
64 mono_add_internal_call (const char *name, gpointer method)
65 {
66         if (!icall_hash) {
67                 dummy_icall = FALSE;
68                 icall_hash = g_hash_table_new (g_str_hash , g_str_equal);
69         }
70
71         g_hash_table_insert (icall_hash, g_strdup (name), method);
72 }
73
74 static void
75 ves_icall_dummy ()
76 {
77         g_warning ("the mono runtime is not initialized");
78         g_assert_not_reached ();
79 }
80
81 gpointer
82 mono_lookup_internal_call (const char *name)
83 {
84         gpointer res;
85
86         if (dummy_icall)
87                 return ves_icall_dummy;
88
89         if (!icall_hash) {
90                 g_warning ("icall_hash not initialized");
91                 g_assert_not_reached ();
92         }
93
94         if (!(res = g_hash_table_lookup (icall_hash, name))) {
95                 g_warning ("cant resolve internal call to \"%s\"", name);
96                 return NULL;
97         }
98
99         return res;
100 }
101
102 MonoClassField*
103 mono_field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass)
104 {
105         MonoImage *mimage;
106         MonoClass *klass;
107         MonoTableInfo *tables = image->tables;
108         guint32 cols[6];
109         guint32 nindex, class, i;
110         const char *fname, *name, *nspace;
111         const char *ptr;
112         guint32 index = mono_metadata_token_index (token);
113
114         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], index-1, cols, MONO_MEMBERREF_SIZE);
115         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
116         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
117
118         fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
119         
120         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
121         mono_metadata_decode_blob_size (ptr, &ptr);
122         /* we may want to check the signature here... */
123
124         switch (class) {
125         case MEMBERREF_PARENT_TYPEREF: {
126                 guint32 scopeindex, scopetable;
127
128                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
129                 scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
130                 scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
131                 /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
132                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
133                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
134                 switch (scopetable) {
135                 case RESOLTION_SCOPE_ASSEMBLYREF:
136                         /*
137                          * To find the field we have the following info:
138                          * *) name and namespace of the class from the TYPEREF table
139                          * *) name and signature of the field from the MEMBERREF table
140                          */
141                         nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
142                         name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
143
144                         /* this will triggered by references to mscorlib */
145                         if (image->references [scopeindex-1] == NULL)
146                                 g_error ("Reference to mscorlib? Probably need to implement %s.%s::%s in corlib", nspace, name, fname);
147
148                         mimage = image->references [scopeindex-1]->image;
149
150                         klass = mono_class_from_name (mimage, nspace, name);
151                         mono_class_init (klass);
152
153                         /* mostly dumb search for now */
154                         for (i = 0; i < klass->field.count; ++i) {
155                                 MonoClassField *f = &klass->fields [i];
156                                 if (!strcmp (fname, f->name)) {
157                                         if (retklass)
158                                                 *retklass = klass;
159                                         return f;
160                                 }
161                         }
162                         g_warning ("Missing field %s.%s::%s", nspace, name, fname);
163                         return NULL;
164                 default:
165                         return NULL;
166                 }
167                 break;
168         }
169         default:
170                 return NULL;
171         }
172 }
173
174 static MonoMethod *
175 method_from_memberref (MonoImage *image, guint32 index)
176 {
177         MonoImage *mimage;
178         MonoClass *klass;
179         MonoTableInfo *tables = image->tables;
180         guint32 cols[6];
181         guint32 nindex, class, i;
182         const char *mname, *name, *nspace;
183         MonoMethodSignature *sig;
184         const char *ptr;
185
186         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], index-1, cols, 3);
187         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
188         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
189         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
190                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
191
192         mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
193         
194         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
195         mono_metadata_decode_blob_size (ptr, &ptr);
196         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
197
198         switch (class) {
199         case MEMBERREF_PARENT_TYPEREF: {
200                 guint32 scopeindex, scopetable;
201
202                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
203                 scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
204                 scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
205                 /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
206                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
207                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
208                 switch (scopetable) {
209                 case RESOLTION_SCOPE_ASSEMBLYREF:
210                         /*
211                          * To find the method we have the following info:
212                          * *) name and namespace of the class from the TYPEREF table
213                          * *) name and signature of the method from the MEMBERREF table
214                          */
215                         nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
216                         name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
217
218                         /* this will triggered by references to mscorlib */
219                         if (image->references [scopeindex-1] == NULL)
220                                 g_error ("Reference to mscorlib? Probably need to implement %s.%s::%s in corlib", nspace, name, mname);
221
222                         mimage = image->references [scopeindex-1]->image;
223
224                         klass = mono_class_from_name (mimage, nspace, name);
225                         g_assert (klass != NULL);
226                         mono_class_init (klass);
227
228                         /* mostly dumb search for now */
229                         for (i = 0; i < klass->method.count; ++i) {
230                                 MonoMethod *m = klass->methods [i];
231                                 if (!strcmp (mname, m->name)) {
232                                         if (mono_metadata_signature_equal (sig, m->signature)) {
233                                                 mono_metadata_free_method_signature (sig);
234                                                 return m;
235                                         }
236                                 }
237                         }
238                         g_warning ("Missing method %s.%s::%s", nspace, name, mname);
239                         mono_metadata_free_method_signature (sig);
240                         return NULL;
241                 default:
242                         mono_metadata_free_method_signature (sig);
243                         return NULL;
244                 }
245                 break;
246         }
247         case MEMBERREF_PARENT_TYPESPEC: {
248                 guint32 bcols [MONO_TYPESPEC_SIZE];
249                 guint32 len;
250                 MonoType *type;
251                 MonoMethod *result;
252
253                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
254                                           bcols, MONO_TYPESPEC_SIZE);
255                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
256                 len = mono_metadata_decode_value (ptr, &ptr);   
257                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
258
259                 if (type->type != MONO_TYPE_ARRAY)
260                         g_assert_not_reached ();                
261
262                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
263                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
264                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
265                 result->signature = sig;
266                 result->name = mname;
267
268                 if (!strcmp (mname, ".ctor")) {
269                         /* we special-case this in the runtime. */
270                         result->addr = NULL;
271                         return result;
272                 }
273                 
274                 if (!strcmp (mname, "Set")) {
275                         g_assert (sig->hasthis);
276                         g_assert (type->data.array->rank + 1 == sig->param_count);
277
278                         result->addr = mono_lookup_internal_call ("__array_Set");
279                         return result;
280                 }
281
282                 if (!strcmp (mname, "Get")) {
283                         g_assert (sig->hasthis);
284                         g_assert (type->data.array->rank == sig->param_count);
285
286                         result->addr = mono_lookup_internal_call ("__array_Get");
287                         return result;
288                 }
289
290                 if (!strcmp (mname, "Address")) {
291                         g_assert (sig->hasthis);
292                         g_assert (type->data.array->rank == sig->param_count);
293
294                         result->addr = mono_lookup_internal_call ("__array_Address");
295                         return result;
296                 }
297
298                 g_assert_not_reached ();
299                 break;
300         }
301         default:
302                 g_assert_not_reached ();
303         }
304
305         return NULL;
306 }
307
308 static void
309 fill_pinvoke_info (MonoImage *image, MonoMethodPInvoke *piinfo, int index)
310 {
311         MonoMethod *mh = &piinfo->method;
312         MonoTableInfo *tables = image->tables;
313         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
314         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
315         guint32 im_cols [4];
316         guint32 mr_cols [1];
317         const char *import = NULL;
318         const char *scope = NULL;
319         char *full_name;
320         GModule *gmodule;
321         int i;
322
323         for (i = 0; i < im->rows; i++) {
324                         
325                 mono_metadata_decode_row (im, i, im_cols, 4);
326
327                 if ((im_cols[1] >> 1) == index + 1) {
328
329                         import = mono_metadata_string_heap (image, im_cols [2]);
330
331                         mono_metadata_decode_row (mr, im_cols [3] - 1, mr_cols,
332                                                   1);
333                         
334                         scope = mono_metadata_string_heap (image, mr_cols [0]);
335                 }
336         }
337
338         piinfo->piflags = im_cols [0];
339
340         g_assert (import && scope);
341
342         scope = mono_map_dll (scope);
343         full_name = g_module_build_path (NULL, scope);
344         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
345
346         mh->addr = NULL;
347         if (!gmodule) {
348                 if (!(gmodule=g_module_open (scope, G_MODULE_BIND_LAZY))) {
349                         g_warning ("Failed to load library %s (%s)", full_name, scope);
350                         g_free (full_name);
351                         return;
352                 }
353         }
354         g_free (full_name);
355
356         g_module_symbol (gmodule, import, &mh->addr); 
357
358         if (!mh->addr) {
359                 g_warning ("Failed to load function %s from %s", import, scope);
360                 return;
361         }
362
363         mh->flags |= METHOD_ATTRIBUTE_PINVOKE_IMPL;
364 }
365
366 MonoMethod *
367 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
368 {
369         MonoMethod *result;
370         int table = mono_metadata_token_table (token);
371         int index = mono_metadata_token_index (token);
372         MonoTableInfo *tables = image->tables;
373         const char *loc, *sig = NULL;
374         char *name;
375         int size;
376         guint32 cols [MONO_TYPEDEF_SIZE];
377
378         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token))))
379                         return result;
380
381         if (table != MONO_TABLE_METHOD) {
382                 if (table != MONO_TABLE_MEMBERREF)
383                         g_print("got wrong token: 0x%08x\n", token);
384                 g_assert (table == MONO_TABLE_MEMBERREF);
385                 result = method_from_memberref (image, index);
386                 g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
387                 return result;
388         }
389
390         mono_metadata_decode_row (&tables [table], index - 1, cols, 6);
391
392         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
393             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
394                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
395         else 
396                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
397         
398         result->slot = -1;
399         result->klass = klass;
400         result->flags = cols [2];
401         result->iflags = cols [1];
402         result->name = mono_metadata_string_heap (image, cols [3]);
403
404         if (!sig) /* already taken from the methodref */
405                 sig = mono_metadata_blob_heap (image, cols [4]);
406         size = mono_metadata_decode_blob_size (sig, &sig);
407         result->signature = mono_metadata_parse_method_signature (image, 0, sig, NULL);
408
409         if (!result->klass) {
410                 guint32 type = mono_metadata_typedef_from_method (image, token);
411                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
412         }
413
414         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
415                 name = g_strconcat (result->klass->name_space, ".", result->klass->name, "::", 
416                                     mono_metadata_string_heap (image, cols [MONO_METHOD_NAME]), NULL);
417                 result->addr = mono_lookup_internal_call (name);
418                 g_free (name);
419                 result->flags |= METHOD_ATTRIBUTE_PINVOKE_IMPL;
420         } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
421                 fill_pinvoke_info (image, (MonoMethodPInvoke *)result, index - 1);
422         } else {
423                 /* if this is a methodref from another module/assembly, this fails */
424                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
425
426                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
427                                         !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
428                         g_assert (loc);
429                         ((MonoMethodNormal *)result)->header = mono_metadata_parse_mh (image, loc);
430                 }
431         }
432
433         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
434
435         return result;
436 }
437
438 void
439 mono_free_method  (MonoMethod *method)
440 {
441         mono_metadata_free_method_signature (method->signature);
442         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
443                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
444                 g_free (piinfo->code);
445         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
446                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
447         }
448
449         g_free (method);
450 }
451
452 void
453 mono_method_get_param_names (MonoMethod *method, const char **names)
454 {
455         int i, lastp;
456         MonoClass *klass = method->klass;
457         MonoTableInfo *methodt = &klass->image->tables [MONO_TABLE_METHOD];
458         MonoTableInfo *paramt = &klass->image->tables [MONO_TABLE_PARAM];
459
460         if (!method->signature->param_count)
461                 return;
462         for (i = 0; i < method->signature->param_count; ++i)
463                 names [i] = "";
464
465         mono_class_init (klass);
466         if (!klass->methods)
467                 return;
468
469         for (i = 0; i < klass->method.count; ++i) {
470                 if (method == klass->methods [i]) {
471                         guint32 index = klass->method.first + i;
472                         guint32 cols [MONO_PARAM_SIZE];
473                         guint param_index = mono_metadata_decode_row_col (methodt, index, MONO_METHOD_PARAMLIST);
474
475                         if (index < methodt->rows)
476                                 lastp = mono_metadata_decode_row_col (methodt, index + 1, MONO_METHOD_PARAMLIST);
477                         else
478                                 lastp = paramt->rows;
479                         for (i = param_index; i < lastp; ++i) {
480                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
481                                 if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
482                                         names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
483                         }
484                         return;
485                 }
486         }
487 }
488