source: trunk/src/win32k/ldr/myldrFindModule.cpp

Last change on this file was 6192, checked in by bird, 24 years ago

Corrected bad search. DBE.DLL migth return the DBEQ.DLL mte. Corrected bad implementation of the loader name bug.

File size: 17.2 KB
RevLine 
[6192]1/* $Id: myldrFindModule.cpp,v 1.3 2001-07-07 04:39:11 bird Exp $
[4779]2 *
3 * ldrFindModule - ldrFindModule replacement with support for long DLL names
4 * and .DLL-extention dependency.
5 *
6 * Copyright (c) 1999-2000 knut st. osmundsen (knut.stange.osmundsen@mynd.no)
7 *
8 * Project Odin Software License can be found in LICENSE.TXT
9 *
10 */
11
12/*******************************************************************************
13* Defined Constants And Macros *
14*******************************************************************************/
15#define INCL_DOSERRORS
16#define INCL_NOPMAPI
[5086]17#define INCL_OS2KRNL_LDR
[4779]18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <os2.h>
23
24#include <memory.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "devSegDf.h" /* Win32k segment definitions. */
29#include "log.h"
30#include "avl.h"
31#include <peexe.h>
32#include <exe386.h>
33#include "OS2Krnl.h"
34#include "dev32.h"
35#include "ldr.h"
36#include "ModuleBase.h"
37#include "options.h"
38
39/*******************************************************************************
40* Global Variables *
41*******************************************************************************/
42extern PPMTE pmte_h;
43extern PPMTE pprogram_h;
44extern PPMTE pprogram_l;
45extern PPMTE pglobal_h;
46extern PPMTE pglobal_l;
47extern PPMTE pspecific_h;
48extern PPMTE pspecific_l;
49
[6192]50/*******************************************************************************
51* Internal Functions *
52*******************************************************************************/
53int mymemicmp(void *pv1, void *pv2, unsigned int cch);
[4779]54
[6192]55
[4779]56/**
57 * Finds a module if it's loaded.
58 *
59 * This replacement will support DLLs with non DLL extention
60 * and names longer than 8 chars.
61 *
62 * @returns NO_ERROR on success.
[6192]63 * If not found we'll still return NO_ERROR, but *ppMTE is NULL.
[4779]64 * OS/2 errorcode on error.
65 * @param pachFilename Pointer to module filename.
66 * If usClass isn't CLASS_GLOBAL then the string
67 * will have to be null terminated or in ldrpFileNameBuf.
68 * If it's in the ldrpFileNameBuf we assume a fullly qualified name.
69 * @param cchFilename Length of modulefilename. This should including the terminator
70 * character if usClass isn't CLASS_GLOBAL.
71 * @param usClass Module class. (CLASS_*)
72 * @param ppMTE Pointer to pMTE found.
73 * @sketch
74 * Check that parameters are supported - backout to original ldrFindModule.
75 * Check for empty name.
76 * Decide upon where to start search for the module - depends on usClass.
77 * *TODO*
78 */
79ULONG LDRCALL myldrFindModule(PCHAR pachFilename, USHORT cchFilename, USHORT usClass, PPMTE ppMTE)
80{
[6192]81 /*
82 * Log.
83 */
84 kprintf(("myldrFindModule: fn=%.*s len=%d class=0x%02x ppMTE=0x%08x\n", cchFilename, pachFilename, cchFilename, usClass, ppMTE));
85
[4779]86 /* Check if this feature is enabled */
87 if (isDllFixesDisabled())
88 {
89 #ifdef DEBUG
90 APIRET rc = ldrFindModule(pachFilename, cchFilename, usClass, ppMTE);
[6192]91 if (rc == NO_ERROR && *ppMTE == NULL)
92 kprintf(("myldrFindModule: Not Found\n"));
93 else
94 kprintf((usClass == CLASS_GLOBAL
95 ? "myldrFindModule: Found pmte=0x%08x hmte=0x%04x modname=%.8s path=%s (GLOBAL)\n"
96 : "myldrFindModule: Found pmte=0x%08x hmte=0x%04x modname=%.8s path=%s (%x)\n",
97 *ppMTE, (*ppMTE)->mte_handle, (*ppMTE)->mte_modname,
98 (*ppMTE)->mte_swapmte->smte_path, (*ppMTE)->mte_flags1 & CLASS_MASK));
[4779]99 return rc;
100 #else
101 return ldrFindModule(pachFilename, cchFilename, usClass, ppMTE);
102 #endif
103 }
104
105 /* Static variables */
106 static PMTE pmteNULL = NULL;
107 static PPMTE ppmteNULL = &pmteNULL;
108 static PPMTE * apppmteHeadTail[] =
109 {/* head tail */
110 &pmte_h, &ppmteNULL, /* CLASS_ALL 0x00000000 */
111 &pprogram_h, &pprogram_l, /* CLASS_PROGRAM 0x00000040 */
112 &pglobal_h, &pglobal_l, /* CLASS_GLOBAL 0x00000080 */
113 &pspecific_h, &pspecific_l, /* CLASS_SPECIFIC 0x000000c0 */
114 };
115
116 /* Local variables */
117 PMTE pmte; /* Current MTE. */
118 PMTE pmteEnd; /* The MTE top stop at. */
119 ULONG rc; /* Return code. */
120 PCHAR pachName; /* Pointer to the name part of pachFilename. */
121 int cchName; /* Length of the name part of pachFilename. (No extention.) */
122 PCHAR pachExt; /* Pointer to the extention part of pachFilename. (not dot!) */
123 int cchExt; /* Length of the extention part of pachFilename. (not dot!) */
124 int cchName8; /* Length of modname in MTE. */
[6192]125 int fDllExt = FALSE; /* Set if we have a .DLL extention. */
[4779]126
127 /*
128 * Check if everything is the way it used to be... (unsupported kernel changes, etc.)
129 */
130 #ifdef DEBUG
131 if (usClass & ~(CLASS_ALL | CLASS_PROGRAM | CLASS_GLOBAL | CLASS_SPECIFIC | SEARCH_FULL_NAME))
132 {
133 kprintf(("myldrFindModule: Unknown class flag! usClass=%d\n", usClass));
134 return ldrFindModule(pachFilename, cchFilename, usClass, ppMTE);
135 }
136 #endif
137
138 if (pachFilename < (PCHAR)0x10000 || ppMTE < (PPMTE)0x10000)
139 {
140 kprintf(("myldrFindModule: Invalid pointer(s); pachFilename=0x%08x ppMTE=0x%08x", pachFilename, ppMTE));
141 return ERROR_INVALID_ACCESS;
142 }
143
144
145 /*
146 * Can't find an empty name.
147 */
148 if (cchFilename == 0)
149 {
150 *ppMTE = NULL;
151 kprintf(("myldrFindModule: Not found; cchFilename = 0\n"));
152 return ERROR_FILE_NOT_FOUND;
153 }
154
155
156 /*
157 * Find start and end mte node
158 */
159 pmte = **apppmteHeadTail[usClass >> 5];
160 pmteEnd = **apppmteHeadTail[(usClass >> 5) + 1];
161 if (pmteEnd != NULL) /* Advance one node - see loop condition. */
162 pmteEnd = pmteEnd->mte_link;
163
164
165 /*
166 * Translate filename path if we're searching for a full name.
167 */
168 if (usClass != CLASS_GLOBAL)
169 {
170 if (pachFilename != ldrpFileNameBuf)
171 {
172 rc = ldrTransPath(pachFilename);
173 if (rc)
174 return rc;
175 pachFilename = ldrpFileNameBuf;
176 cchFilename = (USHORT)(strlen(pachFilename) + 1);
177 ldrUCaseString(pachFilename, cchFilename);
178 }
179 #ifdef DEBUG
180 else
181 {
182 if (cchFilename != strlen(pachFilename) + 1)
183 kprintf(("myldrFindModule: %.*s cchFilename=%d strlen+1=%d\n",
184 cchFilename, pachFilename, cchFilename, strlen(pachFilename) + 1));
185 cchFilename = (USHORT)(strlen(pachFilename) + 1);
186 }
187 #endif
188 }
189
190
191 /*
192 * Depending on the search type we'll have to find the name and
193 * extention of the filename passed in to us.
194 */
195 if (usClass == CLASS_GLOBAL)
196 { /*
197 * Dll, assumes modulename only (no path!).
198 * Find the extention.
199 * Determin name and extention length.
200 * (NB! Can't use ldrGetFileName since it's looking for a slash.)
201 */
202 pachName = pachFilename;
203 pachExt = pachFilename + cchFilename - 1;
204 while (pachExt >= pachName && *pachExt != '.')
205 pachExt--;
206 if (pachExt < pachFilename)
207 {
208 cchName = cchFilename;
209 pachExt = "DLL";
210 cchExt = 3;
[6192]211 fDllExt = TRUE;
[4779]212 }
213 else
214 {
215 cchName = pachExt - pachName;
[6192]216 cchExt = cchFilename - cchName - 1;
217 if ( cchExt == 3 && !memcmp(pachExt, ".DLL", 4)
218 || cchName < 8 && !memcmp(pachExt, ".DLL", min(3, cchExt))
219 )
220 fDllExt = TRUE;
[4779]221 pachExt++;
222 }
223
[6192]224 if (fDllExt)
225 cchName8 = cchName > 8 ? 8 : cchName;
226 else
227 cchName8 = cchFilename > 8 ? 8 : cchFilename;
[4779]228
229 #ifdef DEBUG
230 if ( memchr(pachFilename, '\\', cchFilename)
231 || memchr(pachFilename, '/', cchFilename)
232 || (cchFilename > 2 && pachFilename[1] == ':')
233 )
234 {
235 kprintf(("myldrFindModule: Invalid name in class global; name=%.*s\n", cchFilename, pachFilename));
236 return ERROR_INVALID_NAME;
237 }
238 #endif
239 } else if ( (usClass & ~SEARCH_FULL_NAME) == CLASS_SPECIFIC
240 || usClass & CLASS_GLOBAL
241 )
242 { /*
243 * Find name and extention, and the length of those.
244 */
245 cchName = (int)ldrGetFileName2(pachFilename, (PCHAR*)SSToDS(&pachName), (PCHAR*)SSToDS(&pachExt));
246 cchName8 = cchName > 8 ? 8 : cchName;
247 cchExt = (pachExt) ? strlen(pachExt) : 0;
248 #ifdef DEBUG
249 if (cchName <= 0)
250 {
251 kprintf(("myldrFindModule: Invalid name! ldrGetFileName2 failed; name=%.*s\n", cchFilename, pachFilename));
252 return ERROR_INVALID_NAME;
253 }
254 #endif
255 }
256 else
257 { /*
258 * Search the whole path no need for extention or name.
259 */
260 cchName8 = cchExt = cchName = 0;
261 pachName = pachExt = NULL;
262 }
263
264
265 /*
266 * Search loop.
267 */
268 for (pmte = pmte; pmte != pmteEnd; pmte = pmte->mte_link)
269 {
270 /*
271 * Check that we're still searching within mte of the correct class.
272 * (Isn't this a debug sanity check? It's present in release kernel too!
273 * If this test is true the MTE list is corrupted!)
274 */
275 if ( (usClass & CLASS_MASK) != CLASS_ALL
276 && (pmte->mte_flags1 & CLASS_MASK) != (usClass & CLASS_MASK))
277 {
278 kprintf(("myldrFindModule: Bad MTE list? Stopped on wrong class test. pmte=0x%08x usClass=0x%04x\n",
279 pmte, usClass));
280 break;
281 }
282
283
284 /*
285 * Look if this module matches. Lookup on global (DLL) modules
286 * are special case.
287 */
288 if (usClass == CLASS_GLOBAL)
[6192]289 {
290 #if 0 /* fault code... Search for DBE.DLL may hit DBEQ.DLL.. */
291 /*
[4779]292 * DLLs, match name only:
293 * Check the module name from the resident MTE.
294 * Check the filename part of the fullname in the SwapMTE.
295 * Check extention.
296 */
297 PCHAR pachName2;
298 PCHAR pachExt2;
299 PSMTE pSMTE = pmte->mte_swapmte;
300
301 if ( !memcmp(pmte->mte_modname, pachFilename, cchName8)
302 && ( /* Filename < 8 char, check modname only. */
303 (cchFilename < 8 && pmte->mte_modname[cchFilename] == '\0')
304 || /* Filename >= 8 chars, we'll have to check the fullname. */
305 ( ldrGetFileName2(pSMTE->smte_path, (PCHAR*)SSToDS(&pachName2), (PCHAR*)SSToDS(&pachExt2)) == cchName
306 && !memcmp(pachName2, pachName, cchName)
307 && (cchExt == 0
308 ? pachExt2 == NULL || *pachExt2 == '\0' /* If no extention the internal name contains a '.'. The filename may also contain a dot or it should not have an extention! This works for both cases. */
309 : cchExt == pSMTE->smte_path - pachExt2 + /* This works when pachExt2 is NULL too. */
310 (pSMTE->smte_pathlen /* DOSCALLS don't have smte_pathlen set correctly */
311 ? pSMTE->smte_pathlen
312 : strlen(pSMTE->smte_path)
313 )
314 && !memcmp(pachExt2, pachExt, cchExt)
315 )
316 )
317 )
318 )
[6192]319 #else
320 BOOL fFound; /* Flag which is set if this mte match the name we're searching for. */
321
322 if (cchName <= 8 && fDllExt)
323 { /*
324 * Compatability code.
325 * Well only near compatible. If the internalname contains .DLL we will be able
326 * to find a few modules which OS2 normally won't find. Disable the latest check
327 * to make us 100% compatible.
328 */
329 fFound = !memcmp(pmte->mte_modname, pachFilename, cchName)
330 && ( cchName == 8
331 || pmte->mte_modname[cchName] == '\0'
332 || !memcmp(&pmte->mte_modname[cchName], ".DLL", min(5, 8 - cchName)) /* extra feature */
333 );
334 }
335 else
336 { /*
337 * Extention code.
338 * There is a part of the name in the mte_modname. Check that first to eliminate
339 * the next step where we access swappable code.
340 * fDllExt:
341 * These may or may not include the .DLL extention in the internal name.
342 * !fDllExt:
343 * These should contain the entire name in the internal name.
344 * If no filename extension, then the internal name should end with a '.'.
345 * NB! We have an issue of casesensitivity here... (ARG!!!)
346 * That make this stuff a bit more expensive...
347 * Possible fix is to use the filename, or to require an uppercased internal name...
348 */
349 fFound = !memcmp(pmte->mte_modname, pachFilename, cchName8);
350 if (fFound)
351 {
352 PCHAR pachResName; /* Pointer to the internal name - resname.0 */
353 pachResName = (PCHAR)pmte->mte_swapmte->smte_restab;
354 if ((char*)pachResName < (char*)0x10000)
355 {
356 kprintf(("myldrFindModule: Holy Hand Grenade! there aint any resident names for this mte (0x%x)\n", pmte));
357 pachResName = "\0";
358 }
359 if (fDllExt)
360 fFound = ( *pachResName == cchName
361 || ( *pachResName == cchName + 4
362 && !mymemicmp(&pachResName[1+cchName], ".DLL", 4)
363 )
364 )
365 && !mymemicmp(pachResName + 1, pachFilename, cchName);
366 else
367 fFound = *pachResName == cchName + cchExt + 1
368 && !mymemicmp(pachResName+1, pachFilename, cchName + cchExt + 1);
369 }
370 }
371
372 if (fFound)
373 #endif
[4779]374 {
375 *ppMTE = pmte;
376 kprintf(("myldrFindModule: Found pmte=0x%08x hmte=0x%04x modname=%.8s path=%s (GLOBAL)\n",
[6192]377 pmte, pmte->mte_handle, pmte->mte_modname, pmte->mte_swapmte->smte_path));
[4779]378 return NO_ERROR;
379 }
380 }
381 else
382 { /*
383 * All, match full name:
384 * Check the module name before checking the
385 * fullname in the SwapMTE.
386 */
387 PSMTE pSMTE = pmte->mte_swapmte;
[6192]388 if ( ( cchName8 == 0 /* This is 0 if we should not check the mte_modname. */
389 || !memcmp(pmte->mte_modname, pachName, cchName8)
390 )
[4779]391 && pSMTE->smte_pathlen == cchFilename - 1
392 && !memcmp(pSMTE->smte_path, pachFilename, cchFilename) /* checks the '\0' too. */
393 )
394 {
395 *ppMTE = pmte;
396 kprintf(("myldrFindModule: Found pmte=0x%08x hmte=0x%04x modname=%.8s path=%s (%x)\n",
397 pmte, pmte->mte_handle, pmte->mte_modname, pSMTE->smte_path, pmte->mte_flags1 & CLASS_MASK));
398 return NO_ERROR;
399 }
400 }
401 } /* Search loop */
402
403
404 /*
405 * Not found. (*ppMte indicates this).
406 */
407 *ppMTE = NULL;
408 kprintf(("myldrFindModule: Not Found\n"));
409 return NO_ERROR;
410}
411
[6192]412
413
414/**
415 * This function is needed since pv1 might be a mixed case name.
416 * @returns same as memcmp.
417 * @param pv1 Pointer to resident name or part of that. Might be mixed cased.
418 This is uppercased.
419 * @param pv2 Pointer to name. ASSUMES Uppercase.
420 * @param cch Length
421 * @remark
422 */
423int mymemicmp(void *pv1, void *pv2, unsigned int cch)
424{
425#if 0 /* safe code which doesn't modify the resident name... */
426 if (!memcmp(pv1, pv2, cch))
427 return 0;
428 char *pach = (char*)SSToDS(alloca(cch));
429 memcpy(pach, pv2, cch);
430 ldrUCaseString(pach, cch);
431 return memcmp(pv1, pach, cch);
432#else
433 if (!memcmp(pv1, pv2, cch))
434 return 0;
435 ldrUCaseString((PCHAR)pv1, cch);
436 return memcmp(pv1, pv2, cch);
437#endif
438}
Note: See TracBrowser for help on using the repository browser.