2001-08-02 Dietmar Maurer <dietmar@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 "cli.h"
30
31
32 static char *dll_map[] = {
33         "libc", "libc.so.6",
34         "libm", "libm.so.6",
35         "cygwin1.dll", "libc.so.6", 
36         NULL, NULL
37 };
38
39 static const char *
40 mono_map_dll (const char *name)
41 {
42         int i = 0;
43
44         while (dll_map [i]) {
45                 if (!strcmp (dll_map [i], name))
46                         return  dll_map [i + 1];
47                 i += 2;
48         }
49
50         return name;
51 }
52
53 /**
54  * mono_get_string_class_info:
55  * @ttoken: pointer to location to store type definition token
56  * @cl: pointer where image will be stored
57  *
58  * This routine locates information about the System.String class. A reference
59  * to the image containing the class is returned in @cl. The type definition 
60  * token is returned in @ttoken. 
61  *
62  * Returns: the method definition token for System.String::.ctor (char *)
63  */
64
65 guint32
66 mono_get_string_class_info (guint *ttoken, MonoImage **cl)
67 {
68         static guint32 ctor = 0, tt = 0;
69         enum MonoImageOpenStatus status = MONO_IMAGE_OK; 
70         MonoAssembly *ass;
71         static MonoImage *corlib;
72         MonoMetadata *m;
73         MonoTableInfo *t;
74         guint32 cols [MAX (MONO_TYPEDEF_SIZE, MONO_METHOD_SIZE)];
75         guint32 ncols [MONO_TYPEDEF_SIZE];
76         guint32 i, first = 0, last = 0;
77         const char *name, *nspace;
78
79         if (ctor) {
80                 *ttoken = tt;
81                 *cl = corlib;
82                 return ctor;
83         }
84
85         ass = mono_assembly_open (CORLIB_NAME, NULL, &status);
86         g_assert (status == MONO_IMAGE_OK);
87         g_assert (ass != NULL);
88         
89         *cl = corlib = ass->image;
90         g_assert (corlib != NULL);
91        
92         m = &corlib->metadata;
93         t = &m->tables [MONO_TABLE_TYPEDEF];
94
95         for (i = 0; i < t->rows; i++) {
96                 mono_metadata_decode_row (t, i, cols, MONO_TYPEDEF_SIZE);
97                 name = mono_metadata_string_heap (m, cols[1]);
98                 nspace = mono_metadata_string_heap (m, cols[2]);
99
100                 if (((cols [0] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS) &&
101                     !strcmp (nspace, "System") && !strcmp (name, "String")) {
102
103                         *ttoken = tt = MONO_TOKEN_TYPE_DEF | (i + 1);
104
105                         first = cols [5] - 1;
106
107                         if (i + 1 < t->rows) {
108                                 mono_metadata_decode_row (t, i + 1, ncols, 
109                                                           MONO_TYPEDEF_SIZE);
110                                 last =  ncols [5] - 1;
111                         } else
112                                 last = m->tables [MONO_TABLE_METHOD].rows;
113                         break;
114                 }
115         }
116
117         g_assert (last - first > 0);
118
119         t = &m->tables [MONO_TABLE_METHOD];
120         g_assert (last < t->rows);
121
122         for (i = first; i < last; i++) {
123                 const char *ptr;
124                 int len;
125                 guint8 sig[] = { 0x20, 0x01, 0x01, 0x0f, 0x03 };
126                 mono_metadata_decode_row (t, i, cols, MONO_METHOD_SIZE);
127
128                 if (!strcmp (mono_metadata_string_heap (m, cols [3]), 
129                              ".ctor") &&
130                     (cols [2] & METHOD_ATTRIBUTE_SPECIAL_NAME)) {
131
132                         ptr = mono_metadata_blob_heap (m, cols [4]);
133                         len = mono_metadata_decode_value (ptr, &ptr);
134
135                         if (len == 5 && !memcmp (ptr, sig, len)) {
136                                 ctor = MONO_TOKEN_METHOD_DEF | (i + 1);
137                                 break;
138                         }
139                 } 
140
141         }
142
143         return ctor;
144 }
145
146 static guint32
147 typedef_from_name (MonoImage *image, const char *name, const char *nspace, guint32 *mlist)
148 {
149         MonoMetadata *m = &image->metadata;
150         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
151         guint32 i;
152         guint32 cols [MONO_TYPEDEF_SIZE];
153
154         for (i=0; i < t->rows; ++i) {
155                 mono_metadata_decode_row (t, i, cols, MONO_TYPEDEF_SIZE);
156                 if (strcmp (name, mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME])) == 0 
157                                 && strcmp (nspace, mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE])) == 0) {
158                         *mlist = cols [MONO_TYPEDEF_METHOD_LIST];
159                         return i + 1;
160                 }
161         }
162         g_assert_not_reached ();
163         return 0;
164 }
165
166 static void
167 methoddef_from_memberref (MonoImage *image, guint32 index, MonoImage **rimage, guint32 *rindex)
168 {
169         MonoMetadata *m = &image->metadata;
170         MonoTableInfo *tables = m->tables;
171         guint32 cols[6];
172         guint32 nindex, sig_len, msig_len, class, i;
173         const char *sig, *msig, *mname, *name, *nspace;
174
175         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], index-1, cols, 3);
176         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
177         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
178         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
179                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
180         sig = mono_metadata_blob_heap (m, cols [MONO_MEMBERREF_SIGNATURE]);
181         sig_len = mono_metadata_decode_blob_size (sig, &sig);
182         mname = mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]);
183
184         switch (class) {
185         case MEMBERREF_PARENT_TYPEREF: {
186                 guint32 scopeindex, scopetable;
187
188                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
189                 scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
190                 scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
191                 /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
192                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
193                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
194                 switch (scopetable) {
195                 case RESOLTION_SCOPE_ASSEMBLYREF:
196                         /*
197                          * To find the method we have the following info:
198                          * *) name and namespace of the class from the TYPEREF table
199                          * *) name and signature of the method from the MEMBERREF table
200                          */
201                         nspace = mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]);
202                         name = mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]);
203
204                         /* this will triggered by references to mscorlib */
205                         g_assert (image->references [scopeindex-1] != NULL);
206
207                         image = image->references [scopeindex-1]->image;
208
209                         m = &image->metadata;
210                         tables = &m->tables [MONO_TABLE_METHOD];
211                         typedef_from_name (image, name, nspace, &i);
212                         /* mostly dumb search for now */
213                         for (;i < tables->rows; ++i) {
214                                 mono_metadata_decode_row (tables, i, cols, MONO_METHOD_SIZE);
215                                 msig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
216                                 msig_len = mono_metadata_decode_blob_size (msig, &msig);
217                                 
218                                 if (strcmp (mname, mono_metadata_string_heap (m, cols [MONO_METHOD_NAME])) == 0 
219                                                 && sig_len == msig_len
220                                                 && strncmp (sig, msig, sig_len) == 0) {
221                                         *rimage = image;
222                                         *rindex = i + 1;
223                                         return;
224                                 }
225                         }
226                         g_assert_not_reached ();
227                         break;
228                 default:
229                         g_assert_not_reached ();
230                 }
231                 break;
232         }
233         default:
234                 g_assert_not_reached ();
235         }
236 }
237
238 static ffi_type *
239 ves_map_ffi_type (MonoType *type)
240 {
241         ffi_type *rettype;
242
243         if (!type)
244                 return &ffi_type_void;
245
246         switch (type->type) {
247         case MONO_TYPE_I1:
248                 rettype = &ffi_type_sint8;
249                 break;
250         case MONO_TYPE_BOOLEAN:
251         case MONO_TYPE_U1:
252                 rettype = &ffi_type_uint8;
253                 break;
254         case MONO_TYPE_I2:
255                 rettype = &ffi_type_sint16;
256                 break;
257         case MONO_TYPE_U2:
258         case MONO_TYPE_CHAR:
259                 rettype = &ffi_type_uint16;
260                 break;
261         case MONO_TYPE_I4:
262                 rettype = &ffi_type_sint32;
263                 break;
264         case MONO_TYPE_U4:
265                 rettype = &ffi_type_sint32;
266                 break;
267         case MONO_TYPE_R4:
268                 rettype = &ffi_type_float;
269                 break;
270         case MONO_TYPE_R8:
271                 rettype = &ffi_type_double;
272                 break;
273         case MONO_TYPE_STRING:
274                 rettype = &ffi_type_pointer;
275                 break;
276         default:
277                 g_warning ("not implemented");
278                 g_assert_not_reached ();
279         }
280
281         return rettype;
282 }
283
284 extern cos();
285 static void
286 fill_pinvoke_info (MonoImage *image, MonoMethodPInvoke *piinfo, int index)
287 {
288         MonoMethod *mh = &piinfo->method;
289         MonoTableInfo *tables = image->metadata.tables;
290         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
291         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
292         guint32 im_cols [4];
293         guint32 mr_cols [1];
294         const char *import = NULL;
295         const char *scope = NULL;
296         char *full_name;
297         GModule *gmodule;
298         ffi_type **args, *rettype;
299         int i, acount;
300
301         for (i = 0; i < im->rows; i++) {
302                         
303                 mono_metadata_decode_row (im, i, im_cols, 4);
304
305                 if ((im_cols[1] >> 1) == index + 1) {
306
307                         import = mono_metadata_string_heap (&image->metadata, 
308                                                             im_cols [2]);
309
310                         mono_metadata_decode_row (mr, im_cols [3] - 1, mr_cols,
311                                                   1);
312                         
313                         scope = mono_metadata_string_heap (&image->metadata, 
314                                                            mr_cols [0]);
315                 }
316         }
317
318         g_assert (import && scope);
319
320         scope = mono_map_dll (scope);
321         full_name = g_module_build_path (NULL, scope);
322         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
323         g_free (full_name);
324
325         g_assert (gmodule);
326
327         piinfo->cif = g_new (ffi_cif , 1);
328         piinfo->piflags = im_cols [0];
329
330         g_module_symbol (gmodule, import, &piinfo->addr); 
331
332         g_assert (piinfo->addr);
333
334         acount = mh->signature->param_count;
335
336         args = g_new (ffi_type *, acount);
337
338         for (i = 0; i < acount; i++)
339                 args[i] = ves_map_ffi_type (mh->signature->params [i]->type);
340
341         rettype = ves_map_ffi_type (mh->signature->ret->type);
342
343         if (!ffi_prep_cif (piinfo->cif, FFI_DEFAULT_ABI, acount, rettype, 
344                            args) == FFI_OK) {
345                 g_warning ("prepare pinvoke failed");
346                 g_assert_not_reached ();
347         }
348 }
349
350 MonoMethod *
351 mono_get_method (MonoImage *image, guint32 token)
352 {
353         MonoMethod *result;
354         int table = mono_metadata_token_table (token);
355         int index = mono_metadata_token_index (token);
356         MonoTableInfo *tables = image->metadata.tables;
357         const char *loc;
358         const char *sig = NULL;
359         int size;
360         guint32 cols[6];
361
362         if (table == MONO_TABLE_METHOD && (result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token))))
363                         return result;
364         
365         if (table != MONO_TABLE_METHOD) {
366                 g_assert (table == MONO_TABLE_MEMBERREF);
367                 methoddef_from_memberref (image, index, &image, &token);
368                 return mono_get_method (image, MONO_TOKEN_METHOD_DEF | token);
369         }
370
371         mono_metadata_decode_row (&tables [table], index - 1, cols, 6);
372
373         if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL)
374                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
375         else
376                 result = (MonoMethod *)g_new0 (MonoMethodManaged, 1);
377
378         result->image = image;
379         result->flags = cols [2];
380         result->iflags = cols [1];
381         result->name = mono_metadata_string_heap (&image->metadata, cols [3]);
382
383         if (!sig) /* already taken from the methodref */
384                 sig = mono_metadata_blob_heap (&image->metadata, cols [4]);
385         size = mono_metadata_decode_blob_size (sig, &sig);
386         result->signature = mono_metadata_parse_method_signature (&image->metadata, 0, sig, NULL);
387
388
389         if (result->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
390                 fill_pinvoke_info (image, (MonoMethodPInvoke *)result, 
391                                    index - 1);
392         } else {
393                 /* if this is a methodref from another module/assembly, this fails */
394                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
395                 g_assert (loc);
396                 ((MonoMethodManaged *)result)->header = 
397                         mono_metadata_parse_mh (&image->metadata, loc);
398         }
399
400         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
401
402         return result;
403 }
404
405 void
406 mono_free_method  (MonoMethod *method)
407 {
408         mono_metadata_free_method_signature (method->signature);
409         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
410                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
411                 g_free (piinfo->cif->arg_types);
412                 g_free (piinfo->cif);
413         } else {
414                 mono_metadata_free_mh (((MonoMethodManaged *)method)->header);
415         }
416
417         g_free (method);
418 }
419