Mon Mar 11 11:12:23 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                         /* 
229                          * FIXME: this is a workaround for the different signatures
230                          * in delegates constructors you get in user code (native int)
231                          * and in mscorlib (native unsigned int)
232                          */
233                         if (klass->parent && klass->parent->parent == mono_defaults.delegate_class) {
234                                 for (i = 0; i < klass->method.count; ++i) {
235                                         MonoMethod *m = klass->methods [i];
236                                         if (!strcmp (mname, m->name)) {
237                                                 if (!strcmp (mname, ".ctor")) {
238                                                         /* we assume signature is correct */
239                                                         mono_metadata_free_method_signature (sig);
240                                                         return m;
241                                                 }
242                                                 if (mono_metadata_signature_equal (sig, m->signature)) {
243                                                         mono_metadata_free_method_signature (sig);
244                                                         return m;
245                                                 }
246                                         }
247                                 }
248                         }
249                         /* mostly dumb search for now */
250                         for (i = 0; i < klass->method.count; ++i) {
251                                 MonoMethod *m = klass->methods [i];
252                                 if (!strcmp (mname, m->name)) {
253                                         if (mono_metadata_signature_equal (sig, m->signature)) {
254                                                 mono_metadata_free_method_signature (sig);
255                                                 return m;
256                                         }
257                                 }
258                         }
259                         g_warning ("Missing method %s.%s::%s", nspace, name, mname);
260                         mono_metadata_free_method_signature (sig);
261                         return NULL;
262                 default:
263                         mono_metadata_free_method_signature (sig);
264                         return NULL;
265                 }
266                 break;
267         }
268         case MEMBERREF_PARENT_TYPESPEC: {
269                 guint32 bcols [MONO_TYPESPEC_SIZE];
270                 guint32 len;
271                 MonoType *type;
272                 MonoMethod *result;
273
274                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
275                                           bcols, MONO_TYPESPEC_SIZE);
276                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
277                 len = mono_metadata_decode_value (ptr, &ptr);   
278                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
279
280                 if (type->type != MONO_TYPE_ARRAY)
281                         g_assert_not_reached ();                
282
283                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
284                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
285                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
286                 result->signature = sig;
287                 result->name = mname;
288
289                 if (!strcmp (mname, ".ctor")) {
290                         /* we special-case this in the runtime. */
291                         result->addr = NULL;
292                         return result;
293                 }
294                 
295                 if (!strcmp (mname, "Set")) {
296                         g_assert (sig->hasthis);
297                         g_assert (type->data.array->rank + 1 == sig->param_count);
298
299                         result->addr = mono_lookup_internal_call ("__array_Set");
300                         return result;
301                 }
302
303                 if (!strcmp (mname, "Get")) {
304                         g_assert (sig->hasthis);
305                         g_assert (type->data.array->rank == sig->param_count);
306
307                         result->addr = mono_lookup_internal_call ("__array_Get");
308                         return result;
309                 }
310
311                 if (!strcmp (mname, "Address")) {
312                         g_assert (sig->hasthis);
313                         g_assert (type->data.array->rank == sig->param_count);
314
315                         result->addr = mono_lookup_internal_call ("__array_Address");
316                         return result;
317                 }
318
319                 g_assert_not_reached ();
320                 break;
321         }
322         default:
323                 g_assert_not_reached ();
324         }
325
326         return NULL;
327 }
328
329 static void
330 fill_pinvoke_info (MonoImage *image, MonoMethodPInvoke *piinfo, int index)
331 {
332         MonoMethod *mh = &piinfo->method;
333         MonoTableInfo *tables = image->tables;
334         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
335         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
336         guint32 im_cols [4];
337         guint32 mr_cols [1];
338         const char *import = NULL;
339         const char *scope = NULL;
340         char *full_name;
341         GModule *gmodule;
342         int i;
343
344         for (i = 0; i < im->rows; i++) {
345                         
346                 mono_metadata_decode_row (im, i, im_cols, 4);
347
348                 if ((im_cols[1] >> 1) == index + 1) {
349
350                         import = mono_metadata_string_heap (image, im_cols [2]);
351
352                         mono_metadata_decode_row (mr, im_cols [3] - 1, mr_cols,
353                                                   1);
354                         
355                         scope = mono_metadata_string_heap (image, mr_cols [0]);
356                 }
357         }
358
359         piinfo->piflags = im_cols [0];
360
361         g_assert (import && scope);
362
363         scope = mono_map_dll (scope);
364         full_name = g_module_build_path (NULL, scope);
365         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
366
367         mh->addr = NULL;
368         if (!gmodule) {
369                 if (!(gmodule=g_module_open (scope, G_MODULE_BIND_LAZY))) {
370                         g_warning ("Failed to load library %s (%s)", full_name, scope);
371                         g_free (full_name);
372                         return;
373                 }
374         }
375         g_free (full_name);
376
377         g_module_symbol (gmodule, import, &mh->addr); 
378
379         if (!mh->addr) {
380                 g_warning ("Failed to load function %s from %s", import, scope);
381                 return;
382         }
383
384         mh->flags |= METHOD_ATTRIBUTE_PINVOKE_IMPL;
385 }
386
387 MonoMethod *
388 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
389 {
390         MonoMethod *result;
391         int table = mono_metadata_token_table (token);
392         int index = mono_metadata_token_index (token);
393         MonoTableInfo *tables = image->tables;
394         const char *loc, *sig = NULL;
395         char *name;
396         int size;
397         guint32 cols [MONO_TYPEDEF_SIZE];
398
399         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token))))
400                         return result;
401
402         if (table != MONO_TABLE_METHOD) {
403                 if (table != MONO_TABLE_MEMBERREF)
404                         g_print("got wrong token: 0x%08x\n", token);
405                 g_assert (table == MONO_TABLE_MEMBERREF);
406                 result = method_from_memberref (image, index);
407                 g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
408                 return result;
409         }
410
411         mono_metadata_decode_row (&tables [table], index - 1, cols, 6);
412
413         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
414             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
415                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
416         else 
417                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
418         
419         result->slot = -1;
420         result->klass = klass;
421         result->flags = cols [2];
422         result->iflags = cols [1];
423         result->name = mono_metadata_string_heap (image, cols [3]);
424
425         if (!sig) /* already taken from the methodref */
426                 sig = mono_metadata_blob_heap (image, cols [4]);
427         size = mono_metadata_decode_blob_size (sig, &sig);
428         result->signature = mono_metadata_parse_method_signature (image, 0, sig, NULL);
429
430         if (!result->klass) {
431                 guint32 type = mono_metadata_typedef_from_method (image, token);
432                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
433         }
434
435         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
436                 name = g_strconcat (result->klass->name_space, ".", result->klass->name, "::", 
437                                     mono_metadata_string_heap (image, cols [MONO_METHOD_NAME]), NULL);
438                 result->addr = mono_lookup_internal_call (name);
439                 g_free (name);
440                 result->flags |= METHOD_ATTRIBUTE_PINVOKE_IMPL;
441         } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
442                 fill_pinvoke_info (image, (MonoMethodPInvoke *)result, index - 1);
443         } else {
444                 /* if this is a methodref from another module/assembly, this fails */
445                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
446
447                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
448                                         !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
449                         g_assert (loc);
450                         ((MonoMethodNormal *)result)->header = mono_metadata_parse_mh (image, loc);
451                 }
452         }
453
454         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
455
456         return result;
457 }
458
459 void
460 mono_free_method  (MonoMethod *method)
461 {
462         mono_metadata_free_method_signature (method->signature);
463         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
464                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
465                 g_free (piinfo->code);
466         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
467                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
468         }
469
470         g_free (method);
471 }
472
473 void
474 mono_method_get_param_names (MonoMethod *method, const char **names)
475 {
476         int i, lastp;
477         MonoClass *klass = method->klass;
478         MonoTableInfo *methodt = &klass->image->tables [MONO_TABLE_METHOD];
479         MonoTableInfo *paramt = &klass->image->tables [MONO_TABLE_PARAM];
480
481         if (!method->signature->param_count)
482                 return;
483         for (i = 0; i < method->signature->param_count; ++i)
484                 names [i] = "";
485
486         mono_class_init (klass);
487         if (!klass->methods)
488                 return;
489
490         for (i = 0; i < klass->method.count; ++i) {
491                 if (method == klass->methods [i]) {
492                         guint32 index = klass->method.first + i;
493                         guint32 cols [MONO_PARAM_SIZE];
494                         guint param_index = mono_metadata_decode_row_col (methodt, index, MONO_METHOD_PARAMLIST);
495
496                         if (index < methodt->rows)
497                                 lastp = mono_metadata_decode_row_col (methodt, index + 1, MONO_METHOD_PARAMLIST);
498                         else
499                                 lastp = paramt->rows;
500                         for (i = param_index; i < lastp; ++i) {
501                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
502                                 if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
503                                         names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
504                         }
505                         return;
506                 }
507         }
508 }
509