Added get_page_size function.
[wine] / loader / loadorder.c
1 /*
2  * Module/Library loadorder
3  *
4  * Copyright 1999 Bertho Stultiens
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
10
11 #include "config.h"
12 #include "windef.h"
13 #include "options.h"
14 #include "loadorder.h"
15 #include "heap.h"
16 #include "options.h"
17 #include "module.h"
18 #include "elfdll.h"
19 #include "debugtools.h"
20
21 DEFAULT_DEBUG_CHANNEL(module)
22
23
24 /* #define DEBUG_LOADORDER */
25
26 #define LOADORDER_ALLOC_CLUSTER 32      /* Allocate with 32 entries at a time */
27
28 static module_loadorder_t default_loadorder;
29 static module_loadorder_t *module_loadorder = NULL;
30 static int nmodule_loadorder = 0;
31 static int nmodule_loadorder_alloc = 0;
32
33 static struct tagDllOverride {
34         char *key,*value;
35 } DefaultDllOverrides[] = {
36         {"kernel32,gdi32,user32",       "builtin"},
37         {"krnl386,gdi,user",            "builtin"},
38         {"toolhelp",                    "builtin"},
39         {"comdlg32,commdlg",            "elfdll,builtin,native"},
40         {"version,ver",                 "elfdll,builtin,native"},
41         {"shell32,shell",               "builtin,native"},
42         {"shlwapi",                     "native,builtin"},
43         {"lz32,lzexpand",               "builtin,native"},
44         {"commctrl,comctl32",           "builtin,native"},
45         {"wsock32,winsock",             "builtin"},
46         {"advapi32,crtdll,ntdll",       "builtin,native"},
47         {"mpr,winspool.drv",            "builtin,native"},
48         {"ddraw,dinput,dsound",         "builtin,native"},
49         {"winmm, mmsystem",             "builtin"},
50         {"msvideo, msvfw32",            "builtin, native"},
51         {"mcicda.drv, mciseq.drv",      "builtin, native"},
52         {"mciwave.drv",                 "builtin, native"},
53         {"mciavi.drv, mcianim.drv",     "native, builtin"},
54         {"msacm.drv, midimap.drv",      "builtin, native"},
55         {"w32skrnl",                    "builtin"},
56         {"wnaspi32,wow32",              "builtin"},
57         {"system,display,wprocs ",      "builtin"},
58         {"wineps",                      "builtin"},
59         {"icmp",                        "builtin"},
60         /* we have to use libglide2x.so instead of glide2x.dll ... */
61         {"glide2x",                     "so,native"},
62         {NULL,NULL},
63 };
64
65 /***************************************************************************
66  *      cmp_sort_func   (internal, static)
67  *
68  * Sorting and comparing function used in sort and search of loadorder
69  * entries.
70  */
71 static int cmp_sort_func(const void *s1, const void *s2)
72 {
73         return strcasecmp(((module_loadorder_t *)s1)->modulename, ((module_loadorder_t *)s2)->modulename);
74 }
75
76
77 /***************************************************************************
78  *      get_tok (internal, static)
79  *
80  * strtok wrapper for non-destructive buffer writing.
81  * NOTE: strtok is not reentrant and therefore this code is neither.
82  */
83 static char *get_tok(const char *str, const char *delim)
84 {
85         static char *buf = NULL;
86         char *cptr;
87
88         if(!str && !buf)
89                 return NULL;
90
91         if(str && buf)
92         {
93                 HeapFree(SystemHeap, 0, buf);
94                 buf = NULL;
95         }
96
97         if(str && !buf)
98         {
99                 buf = HEAP_strdupA(SystemHeap, 0, str);
100                 cptr = strtok(buf, delim);
101         }
102         else
103         {
104                 cptr = strtok(NULL, delim);
105         }
106
107         if(!cptr)
108         {
109                 HeapFree(SystemHeap, 0, buf);
110                 buf = NULL;
111         }
112         return cptr;
113 }
114
115
116 /***************************************************************************
117  *      ParseLoadOrder  (internal, static)
118  *
119  * Parses the loadorder options from the configuration and puts it into
120  * a structure.
121  */
122 static BOOL ParseLoadOrder(char *order, module_loadorder_t *mlo)
123 {
124         char *cptr;
125         int n = 0;
126
127         memset(mlo->loadorder, 0, sizeof(mlo->loadorder));
128
129         cptr = get_tok(order, ", \t");
130         while(cptr)
131         {
132                 char type = MODULE_LOADORDER_INVALID;
133
134                 if(n >= MODULE_LOADORDER_NTYPES)
135                 {
136                         ERR("More than existing %d module-types specified, rest ignored", MODULE_LOADORDER_NTYPES);
137                         break;
138                 }
139
140                 switch(*cptr)
141                 {
142                 case 'N':       /* Native */
143                 case 'n': type = MODULE_LOADORDER_DLL; break;
144
145                 case 'E':       /* Elfdll */
146                 case 'e': type = MODULE_LOADORDER_ELFDLL; break;
147
148                 case 'S':       /* So */
149                 case 's': type = MODULE_LOADORDER_SO; break;
150
151                 case 'B':       /* Builtin */
152                 case 'b': type = MODULE_LOADORDER_BI; break;
153
154                 default:
155                         ERR("Invalid load order module-type '%s', ignored\n", cptr);
156                 }
157
158                 if(type != MODULE_LOADORDER_INVALID)
159                 {
160                         mlo->loadorder[n++] = type;
161                 }
162                 cptr = get_tok(NULL, ", \t");
163         }
164         return TRUE;
165 }
166
167
168 /***************************************************************************
169  *      AddLoadOrder    (internal, static)
170  *
171  * Adds an entry in the list of overrides. If the entry exists then the
172  * override parameter determines whether it will be overwriten.
173  */
174 static BOOL AddLoadOrder(module_loadorder_t *plo, BOOL override)
175 {
176         int i;
177
178         /* TRACE(module, "'%s' -> %08lx\n", plo->modulename, *(DWORD *)(plo->loadorder)); */
179
180         for(i = 0; i < nmodule_loadorder; i++)
181         {
182                 if(!cmp_sort_func(plo, &module_loadorder[i]))
183                 {
184                         if(!override)
185                                 ERR("Module '%s' is already in the list of overrides, using first definition\n", plo->modulename);
186                         else
187                                 memcpy(module_loadorder[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
188                         return TRUE;
189                 }
190         }
191
192         if(nmodule_loadorder >= nmodule_loadorder_alloc)
193         {
194                 /* No space in current array, make it larger */
195                 nmodule_loadorder_alloc += LOADORDER_ALLOC_CLUSTER;
196                 module_loadorder = (module_loadorder_t *)HeapReAlloc(SystemHeap,
197                                                                      0,
198                                                                      module_loadorder,
199                                                                      nmodule_loadorder_alloc * sizeof(module_loadorder_t));
200                 if(!module_loadorder)
201                 {
202                         MESSAGE("Virtual memory exhausted\n");
203                         exit(1);
204                 }
205         }
206         memcpy(module_loadorder[nmodule_loadorder].loadorder, plo->loadorder, sizeof(plo->loadorder));
207         module_loadorder[nmodule_loadorder].modulename = HEAP_strdupA(SystemHeap, 0, plo->modulename);
208         nmodule_loadorder++;
209         return TRUE;
210 }
211
212
213 /***************************************************************************
214  *      AddLoadOrderSet (internal, static)
215  *
216  * Adds an set of entries in the list of overrides from the key parameter.
217  * If the entry exists then the override parameter determines whether it
218  * will be overwriten.
219  */
220 static BOOL AddLoadOrderSet(char *key, char *order, BOOL override)
221 {
222         module_loadorder_t ldo;
223         char *cptr;
224
225         /* Parse the loadorder before the rest because strtok is not reentrant */
226         if(!ParseLoadOrder(order, &ldo))
227                 return FALSE;
228
229         cptr = get_tok(key, ", \t");
230         while(cptr)
231         {
232                 char *ext = strrchr(cptr, '.');
233                 if(ext)
234                 {
235                         if(strlen(ext) == 4 && (!strcasecmp(ext, ".dll") || !strcasecmp(ext, ".exe")))
236                                 MESSAGE("Warning: Loadorder override '%s' contains an extension and might not be found during lookup\n", cptr);
237                 }
238
239                 ldo.modulename = cptr;
240                 if(!AddLoadOrder(&ldo, override))
241                         return FALSE;
242                 cptr = get_tok(NULL, ", \t");
243         }
244         return TRUE;
245 }
246
247
248 /***************************************************************************
249  *      ParseCommandlineOverrides       (internal, static)
250  *
251  * The commandline is in the form:
252  * name[,name,...]=native[,b,...][:...]
253  */
254 static BOOL ParseCommandlineOverrides(void)
255 {
256         char *cpy;
257         char *key;
258         char *next;
259         char *value;
260         BOOL retval = TRUE;
261
262         if(!Options.dllFlags)
263                 return TRUE;
264
265         cpy = HEAP_strdupA(SystemHeap, 0, Options.dllFlags);
266         key = cpy;
267         next = key;
268         for(; next; key = next)
269         {
270                 next = strchr(key, ':');
271                 if(next)
272                 {
273                         *next = '\0';
274                         next++;
275                 }
276                 value = strchr(key, '=');
277                 if(!value)
278                 {
279                         retval = FALSE;
280                         goto endit;
281                 }
282                 *value = '\0';
283                 value++;
284
285                 TRACE("Commandline override '%s' = '%s'\n", key, value);
286                 
287                 if(!AddLoadOrderSet(key, value, TRUE))
288                 {
289                         retval = FALSE;
290                         goto endit;
291                 }
292         }
293 endit:
294         HeapFree(SystemHeap, 0, cpy);
295         return retval;;
296 }
297
298
299 /***************************************************************************
300  *      MODULE_InitLoadOrder    (internal)
301  *
302  * Initialize the load order from the wine.conf file.
303  * The section has tyhe following format:
304  * Section:
305  *      [DllDefaults]
306  *
307  * Keys:
308  *      EXTRA_LD_LIBRARY_PATH=/usr/local/lib/wine[:/more/path/to/search[:...]]
309  * The path will be appended to any existing LD_LIBRARY_PATH from the 
310  * environment (see note in code below).
311  *
312  *      DefaultLoadOrder=native,elfdll,so,builtin
313  * A comma seperated list of module-types to try to load in that specific
314  * order. The DefaultLoadOrder key is used as a fallback when a module is
315  * not specified explicitely. If the DefaultLoadOrder key is not found, 
316  * then the order "dll,elfdll,so,bi" is used
317  * The possible module-types are:
318  *      - native        Native windows dll files
319  *      - elfdll        Dlls encapsulated in .so libraries
320  *      - so            Native .so libraries mapped to dlls
321  *      - builtin       Built-in modules
322  *
323  * Case is not important and only the first letter of each type is enough to
324  * identify the type n[ative], e[lfdll], s[o], b[uiltin]. Also whitespace is
325  * ignored.
326  * E.g.:
327  *      n,el    ,s , b
328  * is equal to:
329  *      native,elfdll,so,builtin
330  *
331  * Section:
332  *      [DllOverrides]
333  *
334  * Keys:
335  * There are no explicit keys defined other than module/library names. A comma
336  * separated list of modules is followed by an assignment of the load-order
337  * for these specific modules. See above for possible types. You should not
338  * specify an extension.
339  * Examples:
340  * kernel32, gdi32, user32 = builtin
341  * kernel, gdi, user = builtin
342  * comdlg32 = elfdll, native, builtin
343  * commdlg = native, builtin
344  * version, ver = elfdll, native, builtin
345  *
346  * Section:
347  *      [DllPairs]
348  *
349  * Keys:
350  * This is a simple pairing in the form 'name1 = name2'. It is supposed to
351  * identify the dlls that cannot live without eachother unless they are
352  * loaded in the same format. Examples are common dialogs and controls,
353  * shell, kernel, gdi, user, etc...
354  * The code will issue a warning if the loadorder of these pairs are different
355  * and might cause hard-to-find bugs due to incompatible pairs loaded at
356  * run-time. Note that this pairing gives *no* guarantee that the pairs
357  * actually get loaded as the same type, nor that the correct versions are
358  * loaded (might be implemented later). It merely notes obvious trouble.
359  * Examples:
360  * kernel = kernel32
361  * commdlg = comdlg32
362  *
363  */
364
365 #define BUFFERSIZE      1024
366
367 BOOL MODULE_InitLoadOrder(void)
368 {
369         char buffer[BUFFERSIZE];
370         int nbuffer;
371
372 #if defined(HAVE_DL_API)
373         /* Get/set the new LD_LIBRARY_PATH */
374         nbuffer = PROFILE_GetWineIniString("DllDefaults", "EXTRA_LD_LIBRARY_PATH", "", buffer, sizeof(buffer));
375
376         if(nbuffer)
377         {
378                 extra_ld_library_path = HEAP_strdupA(SystemHeap, 0, buffer);
379                 TRACE("Setting extra LD_LIBRARY_PATH=%s\n", buffer);
380         }
381 #endif
382
383         /* Get the default load order */
384         nbuffer = PROFILE_GetWineIniString("DllDefaults", "DefaultLoadOrder", "n,e,s,b", buffer, sizeof(buffer));
385         if(!nbuffer)
386         {
387                 MESSAGE("MODULE_InitLoadOrder: misteriously read nothing from default loadorder\n");
388                 return FALSE;
389         }
390
391         TRACE("Setting default loadorder=%s\n", buffer);
392
393         if(!ParseLoadOrder(buffer, &default_loadorder))
394                 return FALSE;
395         default_loadorder.modulename = "<none>";
396
397         {
398             int i;
399             for (i=0;DefaultDllOverrides[i].key;i++)
400                 AddLoadOrderSet(
401                     DefaultDllOverrides[i].key,
402                     DefaultDllOverrides[i].value,
403                     FALSE
404                 );
405         }
406
407         /* Read the explicitely defined orders for specific modules as an entire section */
408         nbuffer = PROFILE_GetWineIniString("DllOverrides", NULL, "", buffer, sizeof(buffer));
409         if(nbuffer == BUFFERSIZE-2)
410         {
411                 ERR("BUFFERSIZE %d is too small to read [DllOverrides]. Needs to grow in the source\n", BUFFERSIZE);
412                 return FALSE;
413         }
414         if(nbuffer)
415         {
416                 /* We only have the keys in the buffer, not the values */
417                 char *key;
418                 char value[BUFFERSIZE];
419                 char *next;
420
421                 for(key = buffer; *key; key = next)
422                 {
423                         next = key + strlen(key) + 1;
424
425                         nbuffer = PROFILE_GetWineIniString("DllOverrides", key, "", value, sizeof(value));
426                         if(!nbuffer)
427                         {
428                                 ERR("Module(s) '%s' will always fail to load. Are you sure you want this?\n", key);
429                                 value[0] = '\0';        /* Just in case */
430                         }
431                         if(nbuffer == BUFFERSIZE-2)
432                         {
433                                 ERR("BUFFERSIZE %d is too small to read [DllOverrides] key '%s'. Needs to grow in the source\n", BUFFERSIZE, key);
434                                 return FALSE;
435                         }
436
437                         TRACE("Key '%s' uses override '%s'\n", key, value);
438
439                         if(!AddLoadOrderSet(key, value, TRUE))
440                                 return FALSE;
441                 }
442         }
443
444         /* Add the commandline overrides to the pool */
445         if(!ParseCommandlineOverrides())
446         {
447                 MESSAGE(        "Syntax: -dll name[,name[,...]]={native|elfdll|so|builtin}[,{n|e|s|b}[,...]][:...]\n"
448                         "    - 'name' is the name of any dll without extension\n"
449                         "    - the order of loading (native, elfdll, so and builtin) can be abbreviated\n"
450                         "      with the first letter\n"
451                         "    - different loadorders for different dlls can be specified by seperating the\n"
452                         "      commandline entries with a ':'\n"
453                         "    Example:\n"
454                         "    -dll comdlg32,commdlg=n:shell,shell32=b\n"
455                    );
456                 return FALSE;
457         }
458
459         /* Sort the array for quick lookup */
460         qsort(module_loadorder, nmodule_loadorder, sizeof(module_loadorder[0]), cmp_sort_func);
461
462         /* Check the pairs of dlls */
463         nbuffer = PROFILE_GetWineIniString("DllPairs", NULL, "", buffer, sizeof(buffer));
464         if(nbuffer == BUFFERSIZE-2)
465         {
466                 ERR("BUFFERSIZE %d is too small to read [DllPairs]. Needs to grow in the source\n", BUFFERSIZE);
467                 return FALSE;
468         }
469         if(nbuffer)
470         {
471                 /* We only have the keys in the buffer, not the values */
472                 char *key;
473                 char value[BUFFERSIZE];
474                 char *next;
475
476                 for(key = buffer; *key; key = next)
477                 {
478                         module_loadorder_t *plo1, *plo2;
479
480                         next = key + strlen(key) + 1;
481
482                         nbuffer = PROFILE_GetWineIniString("DllPairs", key, "", value, sizeof(value));
483                         if(!nbuffer)
484                         {
485                                 ERR("Module pair '%s' is not associated with another module?\n", key);
486                                 continue;
487                         }
488                         if(nbuffer == BUFFERSIZE-2)
489                         {
490                                 ERR("BUFFERSIZE %d is too small to read [DllPairs] key '%s'. Needs to grow in the source\n", BUFFERSIZE, key);
491                                 return FALSE;
492                         }
493
494                         plo1 = MODULE_GetLoadOrder(key);
495                         plo2 = MODULE_GetLoadOrder(value);
496                         assert(plo1 && plo2);
497
498                         if(memcmp(plo1->loadorder, plo2->loadorder, sizeof(plo1->loadorder)))
499                                 MESSAGE("Warning: Modules '%s' and '%s' have different loadorder which may cause trouble\n", key, value);
500                 }
501         }
502
503         if(TRACE_ON(module))
504         {
505                 int i, j;
506                 static char types[6] = "-NESB";
507
508                 for(i = 0; i < nmodule_loadorder; i++)
509                 {
510                         DPRINTF("%3d: %-12s:", i, module_loadorder[i].modulename);
511                         for(j = 0; j < MODULE_LOADORDER_NTYPES; j++)
512                                 DPRINTF(" %c", types[module_loadorder[i].loadorder[j] % (MODULE_LOADORDER_NTYPES+1)]);
513                         DPRINTF("\n");
514                 }
515         }
516
517         return TRUE;
518 }
519
520
521 /***************************************************************************
522  *      MODULE_GetLoadOrder     (internal)
523  *
524  * Locate the loadorder of a module.
525  * Any path is stripped from the path-argument and so are the extension
526  * '.dll' and '.exe'. A lookup in the table can yield an override for
527  * the specific dll. Otherwise the default load order is returned.
528  */
529 module_loadorder_t *MODULE_GetLoadOrder(const char *path)
530 {
531         module_loadorder_t lo, *tmp;
532         char fname[256];
533         char *cptr;
534         char *name;
535         int len;
536
537         assert(path != NULL);
538
539         /* Strip path information */
540         cptr = strrchr(path, '\\');
541         if(!cptr)
542                 name = strrchr(path, '/');
543         else
544                 name = strrchr(cptr, '/');
545
546         if(!name)
547                 name = cptr ? cptr+1 : (char *)path;
548         else
549                 name++;
550
551         if((cptr = strchr(name, ':')) != NULL)  /* Also strip drive if in format 'C:MODULE.DLL' */
552                 name = cptr+1;
553
554         len = strlen(name);
555         if(len >= sizeof(fname) || len <= 0)
556         {
557                 ERR("Path '%s' -> '%s' reduces to zilch or just too large...\n", path, name);
558                 return &default_loadorder;
559         }
560
561         strcpy(fname, name);
562         if(len >= 4 && (!lstrcmpiA(fname+len-4, ".dll") || !lstrcmpiA(fname+len-4, ".exe")))
563                 fname[len-4] = '\0';
564
565         lo.modulename = fname;
566         tmp = bsearch(&lo, module_loadorder, nmodule_loadorder, sizeof(module_loadorder[0]), cmp_sort_func);
567
568         TRACE("Looking for '%s' (%s), found '%s'\n", path, fname, tmp ? tmp->modulename : "<nothing>");
569
570         if(!tmp)
571                 return &default_loadorder;
572         return tmp;
573 }
574