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