1 /* $Id: kLdrDyldFind.c 29 2009-07-01 20:30:29Z bird $ */
2 /** @file
3  * kLdr - The Dynamic Loader, File Searching Methods.
4  */
5 
6 /*
7  * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
8  *
9  * Permission is hereby granted, free of charge, to any person
10  * obtaining a copy of this software and associated documentation
11  * files (the "Software"), to deal in the Software without
12  * restriction, including without limitation the rights to use,
13  * copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following
16  * conditions:
17  *
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  * OTHER DEALINGS IN THE SOFTWARE.
29  */
30 
31 /*******************************************************************************
32 *   Header Files                                                               *
33 *******************************************************************************/
34 #include <k/kLdr.h>
35 #include "kLdrInternal.h"
36 
37 #if K_OS == K_OS_LINUX
38 # include <k/kHlpSys.h>
39 
40 #elif K_OS == K_OS_OS2
41 # define INCL_BASE
42 # define INCL_ERRORS
43 # include <os2.h>
44 # ifndef LIBPATHSTRICT
45 #  define LIBPATHSTRICT 3
46 # endif
47   extern APIRET APIENTRY DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction);
48 # define QHINF_EXEINFO       1 /* NE exeinfo. */
49 # define QHINF_READRSRCTBL   2 /* Reads from the resource table. */
50 # define QHINF_READFILE      3 /* Reads from the executable file. */
51 # define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */
52 # define QHINF_LIBPATH       5 /* Gets the entire libpath. */
53 # define QHINF_FIXENTRY      6 /* NE only */
54 # define QHINF_STE           7 /* NE only */
55 # define QHINF_MAPSEL        8 /* NE only */
56 
57 #elif K_OS == K_OS_WINDOWS
58 # undef IMAGE_DOS_SIGNATURE
59 # undef IMAGE_NT_SIGNATURE
60 # include <Windows.h>
61 
62 #endif
63 
64 
65 /*******************************************************************************
66 *   Defined Constants And Macros                                               *
67 *******************************************************************************/
68 /** @def KLDRDYLDFIND_STRICT
69  * Define KLDRDYLDFIND_STRICT to enabled strict checks in kLdrDyldFind. */
70 #define KLDRDYLDFIND_STRICT 1
71 
72 /** @def KLDRDYLDFIND_ASSERT
73  * Assert that an expression is true when KLDRDYLDFIND_STRICT is defined.
74  */
75 #ifdef KLDRDYLDFIND_STRICT
76 # define KLDRDYLDFIND_ASSERT(expr)  kHlpAssert(expr)
77 #else
78 # define KLDRDYLDFIND_ASSERT(expr)  do {} while (0)
79 #endif
80 
81 
82 /*******************************************************************************
83 *   Structures and Typedefs                                                    *
84 *******************************************************************************/
85 /**
86  * Search arguments.
87  * This avoids a bunch of unnecessary string lengths and calculations.
88  */
89 typedef struct KLDRDYLDFINDARGS
90 {
91     const char *pszName;
92     KSIZE       cchName;
93 
94     const char *pszPrefix;
95     KSIZE       cchPrefix;
96 
97     const char *pszSuffix;
98     KSIZE       cchSuffix;
99 
100     KSIZE       cchMaxLength;
101 
102     KLDRDYLDSEARCH  enmSearch;
103     KU32            fFlags;
104     PPKRDR          ppRdr;
105 } KLDRDYLDFINDARGS, *PKLDRDYLDFINDARGS;
106 
107 typedef const KLDRDYLDFINDARGS *PCKLDRDYLDFINDARGS;
108 
109 
110 /*******************************************************************************
111 *   Global Variables                                                           *
112 *******************************************************************************/
113 /** @name The kLdr search method parameters.
114  * @{ */
115 /** The kLdr EXE search path.
116  * During EXE searching the it's initialized with the values of the KLDR_PATH and
117  * the PATH env.vars. Both ';' and ':' can be used as separators.
118  */
119 char            kLdrDyldExePath[8192];
120 /** The kLdr DLL search path.
121  * During initialization the KLDR_LIBRARY_PATH env.var. and the path in the
122  * executable stub is appended. Both ';' and ':' can be used as separators.
123  */
124 char            kLdrDyldLibraryPath[8192];
125 /** The kLdr application directory.
126  * This is initialized when the executable is 'loaded' or by a kLdr user.
127  */
128 char            kLdrDyldAppDir[260];
129 /** The default kLdr DLL prefix.
130  * This is initialized with the KLDR_DEF_PREFIX env.var. + the prefix in the executable stub.
131  */
132 char            kLdrDyldDefPrefix[16];
133 /** The default kLdr DLL suffix.
134  * This is initialized with the KLDR_DEF_SUFFIX env.var. + the prefix in the executable stub.
135  */
136 char            kLdrDyldDefSuffix[16];
137 /** @} */
138 
139 
140 /** @name The OS/2 search method parameters.
141  * @{
142  */
143 /** The OS/2 LIBPATH.
144  * This is queried from the os2krnl on OS/2, while on other systems initialized using
145  * the KLDR_OS2_LIBPATH env.var.
146  */
147 char            kLdrDyldOS2Libpath[2048];
148 /** The OS/2 LIBPATHSTRICT ("T" or '\0').
149  * This is queried from the os2krnl on OS/2, while on other systems initialized using
150  * the KLDR_OS2_LIBPATHSTRICT env.var.
151  */
152 char            kLdrDyldOS2LibpathStrict[8];
153 /** The OS/2 BEGINLIBPATH.
154  * This is queried from the os2krnl on OS/2, while on other systems initialized using
155  * the KLDR_OS2_BEGINLIBPATH env.var.
156  */
157 char            kLdrDyldOS2BeginLibpath[2048];
158 /** The OS/2 ENDLIBPATH.
159  * This is queried from the os2krnl on OS/2, while on other systems initialized using
160  * the KLDR_OS2_ENDLIBPATH env.var.
161  */
162 char            kLdrDyldOS2EndLibpath[2048];
163 /** @} */
164 
165 
166 /** @name The Windows search method parameters.
167  * @{ */
168 /** The Windows application directory.
169  * This is initialized when the executable is 'loaded' or by a kLdr user.
170  */
171 char            kLdrDyldWindowsAppDir[260];
172 /** The Windows system directory.
173  * This is queried from the Win32/64 subsystem on Windows, while on other systems
174  * initialized using the KLDR_WINDOWS_SYSTEM_DIR env.var.
175  */
176 char            kLdrDyldWindowsSystemDir[260];
177 /** The Windows directory.
178  * This is queried from the Win32/64 subsystem on Windows, while on other systems
179  * initialized using the KLDR_WINDOWS_DIR env.var.
180  */
181 char            kLdrDyldWindowsDir[260];
182 /** The Windows path.
183  * This is queried from the PATH env.var. on Windows, while on other systems
184  * initialized using the KLDR_WINDOWS_PATH env.var. and falling back on
185  * the PATH env.var. if it wasn't found.
186  */
187 char            kLdrDyldWindowsPath[8192];
188 /** @} */
189 
190 
191 /** @name The Common Unix search method parameters.
192  * @{
193  */
194 /** The Common Unix library path.
195  * Initialized from the env.var. KLDR_UNIX_LIBRARY_PATH or LD_LIBRARY_PATH or the
196  * former wasn't found.
197  */
198 char            kLdrDyldUnixLibraryPath[8192];
199 /** The Common Unix system library path. */
200 char            kLdrDyldUnixSystemLibraryPath[1024] = "/lib;/usr/lib";
201 /** @} */
202 
203 /** @todo Deal with DT_RUNPATH and DT_RPATH. */
204 /** @todo ld.so.cache? */
205 
206 
207 /*******************************************************************************
208 *   Internal Functions                                                         *
209 *******************************************************************************/
210 static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
211                                 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr);
212 static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
213                                    KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr);
214 static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr);
215 static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs);
216 static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs);
217 static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **pszPrefix,
218                                    const char **pszSuffix, const char *pszName, KU32 fFlags);
219 
220 
221 /**
222  * Initializes the find paths.
223  *
224  * @returns 0 on success, non-zero on failure.
225  */
kldrDyldFindInit(void)226 int kldrDyldFindInit(void)
227 {
228     KSIZE   cch;
229     int     rc;
230     char    szTmp[sizeof(kLdrDyldDefSuffix)];
231 
232     /*
233      * The kLdr search parameters.
234      */
235     rc = kHlpGetEnv("KLDR_LIBRARY_PATH", kLdrDyldLibraryPath, sizeof(kLdrDyldLibraryPath));
236     rc = kHlpGetEnv("KLDR_DEF_PREFIX", szTmp, sizeof(szTmp));
237     if (!rc)
238         kHlpMemCopy(kLdrDyldDefPrefix, szTmp, sizeof(szTmp));
239     rc = kHlpGetEnv("KLDR_DEF_SUFFIX", szTmp, sizeof(szTmp));
240     if (!rc)
241         kHlpMemCopy(kLdrDyldDefSuffix, szTmp, sizeof(szTmp));
242 
243     /*
244      * The OS/2 search parameters.
245      */
246 #if K_OS == K_OS_OS2
247     rc = DosQueryHeaderInfo(NULLHANDLE, 0, kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath), QHINF_LIBPATH);
248     if (rc)
249         return rc;
250     rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2LibpathStrict, LIBPATHSTRICT);
251     if (rc)
252         kLdrDyldOS2LibpathStrict[0] = '\0';
253     rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2BeginLibpath, BEGIN_LIBPATH);
254     if (rc)
255         kLdrDyldOS2BeginLibpath[0] = '\0';
256     rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2EndLibpath, END_LIBPATH);
257     if (rc)
258         kLdrDyldOS2EndLibpath[0] = '\0';
259 
260 #else
261     kHlpGetEnv("KLDR_OS2_LIBPATH", kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath));
262     kHlpGetEnv("KLDR_OS2_LIBPATHSTRICT", kLdrDyldOS2LibpathStrict, sizeof(kLdrDyldOS2LibpathStrict));
263     if (    kLdrDyldOS2LibpathStrict[0] == 'T'
264         ||  kLdrDyldOS2LibpathStrict[0] == 't')
265         kLdrDyldOS2LibpathStrict[0] = 'T';
266     else
267         kLdrDyldOS2LibpathStrict[0] = '\0';
268     kLdrDyldOS2LibpathStrict[1] = '\0';
269     kHlpGetEnv("KLDR_OS2_BEGINLIBPATH", kLdrDyldOS2BeginLibpath, sizeof(kLdrDyldOS2BeginLibpath));
270     kHlpGetEnv("KLDR_OS2_ENDLIBPATH", kLdrDyldOS2EndLibpath, sizeof(kLdrDyldOS2EndLibpath));
271 #endif
272 
273     /*
274      * The windows search parameters.
275      */
276 #if K_OS == K_OS_WINDOWS
277     cch = GetSystemDirectory(kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir));
278     if (cch >= sizeof(kLdrDyldWindowsSystemDir))
279         return (rc = GetLastError()) ? rc : -1;
280     cch = GetWindowsDirectory(kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir));
281     if (cch >= sizeof(kLdrDyldWindowsDir))
282         return (rc = GetLastError()) ? rc : -1;
283     kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
284 #else
285     kHlpGetEnv("KLDR_WINDOWS_SYSTEM_DIR", kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir));
286     kHlpGetEnv("KLDR_WINDOWS_DIR", kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir));
287     rc = kHlpGetEnv("KLDR_WINDOWS_PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
288     if (rc)
289         kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
290 #endif
291 
292     /*
293      * The Unix search parameters.
294      */
295     rc = kHlpGetEnv("KLDR_UNIX_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath));
296     if (rc)
297         kHlpGetEnv("LD_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath));
298 
299     (void)cch;
300     return 0;
301 }
302 
303 
304 /**
305  * Lazily initialize the two application directory paths.
306  */
kldrDyldFindLazyInitAppDir(void)307 static void kldrDyldFindLazyInitAppDir(void)
308 {
309     if (!kLdrDyldAppDir[0])
310     {
311 #if K_OS == K_OS_DARWIN
312         /** @todo implement this! */
313         kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
314         kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
315 
316 #elif K_OS == K_OS_LINUX
317         KSSIZE cch = kHlpSys_readlink("/proc/self/exe", kLdrDyldAppDir, sizeof(kLdrDyldAppDir) - 1);
318         if (cch > 0)
319         {
320             kLdrDyldAppDir[cch] = '\0';
321             *kHlpGetFilename(kLdrDyldAppDir) = '\0';
322             kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
323         }
324         else
325         {
326             kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
327             kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
328         }
329 
330 #elif K_OS == K_OS_OS2
331         PPIB pPib;
332         PTIB pTib;
333         APIRET rc;
334 
335         DosGetInfoBlocks(&pTib, &pPib);
336         rc = DosQueryModuleName(pPib->pib_hmte, sizeof(kLdrDyldAppDir), kLdrDyldAppDir);
337         if (!rc)
338         {
339             *kHlpGetFilename(kLdrDyldAppDir) = '\0';
340              kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
341         }
342         else
343         {
344             kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
345             kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
346         }
347 
348 #elif K_OS == K_OS_WINDOWS
349         DWORD dwSize = GetModuleFileName(NULL /* the executable */, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
350         if (dwSize > 0)
351         {
352             *kHlpGetFilename(kLdrDyldAppDir) = '\0';
353             kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
354         }
355         else
356         {
357             kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
358             kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
359         }
360 
361 #else
362 # error "Port me"
363 #endif
364     }
365 }
366 
367 
368 /**
369  * Locates and opens a module using the specified search method.
370  *
371  * @returns 0 and *ppMod on success, non-zero OS specific error on failure.
372  *
373  * @param   pszName         Partial or complete name, it's specific to the search method to determin which.
374  * @param   pszPrefix       Prefix than can be used when searching.
375  * @param   pszSuffix       Suffix than can be used when searching.
376  * @param   enmSearch       The file search method to apply.
377  * @param   fFlags          Search flags.
378  * @param   ppMod           Where to store the file provider instance on success.
379  */
kldrDyldFindNewModule(const char * pszName,const char * pszPrefix,const char * pszSuffix,KLDRDYLDSEARCH enmSearch,unsigned fFlags,PPKLDRDYLDMOD ppMod)380 int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
381                           KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod)
382 {
383     int rc;
384     PKRDR pRdr = NULL;
385 
386     *ppMod = NULL;
387 
388     /*
389      * If this isn't just a filename, we the caller has specified a file
390      * that should be opened directly and not a module name to be searched for.
391      */
392     if (!kHlpIsFilenameOnly(pszName))
393         rc = kldrDyldFindTryOpen(pszName, &pRdr);
394     else if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
395         rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
396     else
397         rc = kldrDyldFindDoExeSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
398     if (!rc)
399     {
400 #ifdef KLDRDYLDFIND_STRICT
401         /* Sanity check of kldrDyldFindExistingModule. */
402         if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)
403         {
404             const char     *pszFilename = kRdrName(pRdr);
405             const KSIZE     cchFilename = kHlpStrLen(pszFilename);
406             PKLDRDYLDMOD    pCur;
407             for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
408                 KLDRDYLDFIND_ASSERT(    pCur->pMod->cchFilename != cchFilename
409                                     ||  kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename));
410         }
411 #endif
412 
413         /*
414          * Check for matching non-global modules that should be promoted.
415          */
416         if (!(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
417         {
418             const char     *pszFilename = kRdrName(pRdr);
419             const KSIZE     cchFilename = kHlpStrLen(pszFilename);
420             PKLDRDYLDMOD    pCur;
421             for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
422             {
423                 if (    !pCur->fGlobalOrSpecific
424                     &&  pCur->pMod->cchFilename == cchFilename
425                     &&  !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename))
426                 {
427                     kRdrClose(pRdr);
428                     kldrDyldModMarkGlobal(pCur);
429                     *ppMod = pCur;
430                     return 0;
431                 }
432                 KLDRDYLDFIND_ASSERT(    pCur->pMod->cchFilename != cchFilename
433                                     ||  kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename));
434             }
435         }
436 
437         /*
438          * Create a new module.
439          */
440         rc = kldrDyldModCreate(pRdr, fFlags, ppMod);
441         if (rc)
442             kRdrClose(pRdr);
443     }
444     return rc;
445 }
446 
447 
448 /**
449  * Searches for a DLL file using the specified method.
450  *
451  * @returns 0 on success and *ppMod pointing to the new module.
452  * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
453  * @returns non-zero kLdr or OS specific status code on other failures.
454  * @param   pszName     The name.
455  * @param   pszPrefix   The prefix, optional.
456  * @param   pszSuffix   The suffix, optional.
457  * @param   enmSearch   The search method.
458  * @param   fFlags      The load/search flags.
459  * @param   ppRdr       Where to store the pointer to the file provider instance on success.
460  */
kldrDyldFindDoDllSearch(const char * pszName,const char * pszPrefix,const char * pszSuffix,KLDRDYLDSEARCH enmSearch,unsigned fFlags,PPKRDR ppRdr)461 static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
462                                    KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr)
463 {
464     int rc;
465     KLDRDYLDFINDARGS Args;
466 
467     /*
468      * Initialize the argument structure and resolve defaults.
469      */
470     Args.enmSearch = enmSearch;
471     Args.pszPrefix = pszPrefix;
472     Args.pszSuffix = pszSuffix;
473     rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags);
474     if (rc)
475         return rc;
476     Args.pszName = pszName;
477     Args.cchName = kHlpStrLen(pszName);
478     Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0;
479     Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0;
480     Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix;
481     Args.fFlags = fFlags;
482     Args.ppRdr = ppRdr;
483 
484     /*
485      * Apply the specified search method.
486      */
487 /** @todo get rid of the strlen() on the various paths here! */
488     switch (Args.enmSearch)
489     {
490         case KLDRDYLD_SEARCH_KLDR:
491         {
492             kldrDyldFindLazyInitAppDir();
493             if (kLdrDyldAppDir[0] != '\0')
494             {
495                 rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args);
496                 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
497                     break;
498             }
499             rc = kldrDyldFindTryOpenPath(".", 1, &Args);
500             if (rc != KLDR_ERR_MODULE_NOT_FOUND)
501                 break;
502             rc = kldrDyldFindEnumeratePath(kLdrDyldLibraryPath, &Args);
503             break;
504         }
505 
506         case KLDRDYLD_SEARCH_OS2:
507         {
508             rc = kldrDyldFindEnumeratePath(kLdrDyldOS2BeginLibpath, &Args);
509             if (rc != KLDR_ERR_MODULE_NOT_FOUND)
510                 break;
511             rc = kldrDyldFindEnumeratePath(kLdrDyldOS2Libpath, &Args);
512             if (rc != KLDR_ERR_MODULE_NOT_FOUND)
513                 break;
514             rc = kldrDyldFindEnumeratePath(kLdrDyldOS2EndLibpath, &Args);
515             break;
516         }
517 
518         case KLDRDYLD_SEARCH_WINDOWS:
519         case KLDRDYLD_SEARCH_WINDOWS_ALTERED:
520         {
521             kldrDyldFindLazyInitAppDir();
522             rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsAppDir, kHlpStrLen(kLdrDyldWindowsAppDir), &Args);
523             if (rc != KLDR_ERR_MODULE_NOT_FOUND)
524                 break;
525             if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED)
526             {
527                 rc = kldrDyldFindTryOpenPath(".", 1, &Args);
528                 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
529                     break;
530             }
531             rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsSystemDir, kHlpStrLen(kLdrDyldWindowsSystemDir), &Args);
532             if (rc != KLDR_ERR_MODULE_NOT_FOUND)
533                 break;
534             rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsDir, kHlpStrLen(kLdrDyldWindowsDir), &Args);
535             if (rc != KLDR_ERR_MODULE_NOT_FOUND)
536                 break;
537             if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS)
538             {
539                 rc = kldrDyldFindTryOpenPath(".", 1, &Args);
540                 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
541                     break;
542             }
543             rc = kldrDyldFindEnumeratePath(kLdrDyldWindowsPath, &Args);
544             break;
545         }
546 
547         case KLDRDYLD_SEARCH_UNIX_COMMON:
548         {
549             rc = kldrDyldFindEnumeratePath(kLdrDyldUnixLibraryPath, &Args);
550             if (rc == KLDR_ERR_MODULE_NOT_FOUND)
551                 break;
552             rc = kldrDyldFindEnumeratePath(kLdrDyldUnixSystemLibraryPath, &Args);
553             break;
554         }
555 
556         default: kHlpAssert(!"internal error"); return -1;
557     }
558     return rc;
559 }
560 
561 
562 /**
563  * Searches for an EXE file using the specified method.
564  *
565  * @returns 0 on success and *ppMod pointing to the new module.
566  * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
567  * @returns non-zero kLdr or OS specific status code on other failures.
568  * @param   pszName     The name.
569  * @param   pszPrefix   The prefix, optional.
570  * @param   pszSuffix   The suffix, optional.
571  * @param   enmSearch   The search method.
572  * @param   fFlags      The load/search flags.
573  * @param   ppRdr       Where to store the pointer to the file provider instance on success.
574  */
kldrDyldFindDoExeSearch(const char * pszName,const char * pszPrefix,const char * pszSuffix,KLDRDYLDSEARCH enmSearch,unsigned fFlags,PPKRDR ppRdr)575 static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
576                                    KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr)
577 {
578     int rc;
579     KLDRDYLDFINDARGS Args;
580 
581     /*
582      * Initialize the argument structure and resolve defaults.
583      */
584     Args.enmSearch = enmSearch;
585     Args.pszPrefix = pszPrefix;
586     Args.pszSuffix = pszSuffix;
587     rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags);
588     if (rc)
589         return rc;
590     Args.pszName = pszName;
591     Args.cchName = kHlpStrLen(pszName);
592     Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0;
593     Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0;
594     Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix;
595     Args.fFlags = fFlags;
596     Args.ppRdr = ppRdr;
597 
598     /*
599      * If we're bootstrapping a process, we'll start by looking in the
600      * application directory and the check out the path.
601      */
602     if (g_fBootstrapping)
603     {
604         kldrDyldFindLazyInitAppDir();
605         if (kLdrDyldAppDir[0] != '\0')
606         {
607             rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args);
608             if (rc != KLDR_ERR_MODULE_NOT_FOUND)
609                 return rc;
610         }
611     }
612 
613     /*
614      * Search the EXE search path. Initialize it the first time around.
615      */
616     if (!kLdrDyldExePath[0])
617     {
618         KSIZE cch;
619         kHlpGetEnv("KLDR_EXE_PATH", kLdrDyldExePath, sizeof(kLdrDyldExePath) - 10);
620         cch = kHlpStrLen(kLdrDyldExePath);
621         kLdrDyldExePath[cch++] = ';';
622         kHlpGetEnv("PATH", &kLdrDyldExePath[cch], sizeof(kLdrDyldExePath) - cch);
623     }
624     return kldrDyldFindEnumeratePath(kLdrDyldExePath, &Args);
625 }
626 
627 
628 /**
629  * Try open the specfied file.
630  *
631  * @returns 0 on success and *ppMod pointing to the new module.
632  * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
633  * @returns non-zero kLdr or OS specific status code on other failures.
634  * @param   pszFilename     The filename.
635  * @param   ppRdr           Where to store the pointer to the new module.
636  */
kldrDyldFindTryOpen(const char * pszFilename,PPKRDR ppRdr)637 static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr)
638 {
639     int rc;
640 
641     /*
642      * Try open the file.
643      */
644     rc = kRdrOpen(ppRdr, pszFilename);
645     if (!rc)
646         return 0;
647     /** @todo deal with return codes properly. */
648     if (rc >= KERR_BASE && rc <= KERR_END)
649         return rc;
650 
651     return KLDR_ERR_MODULE_NOT_FOUND;
652 }
653 
654 
655 /**
656  * Composes a filename from the specified directory path,
657  * prefix (optional), name and suffix (optional, will try with and without).
658  *
659  * @param   pchPath     The directory path - this doesn't have to be null terminated.
660  * @param   cchPath     The length of the path.
661  * @param   pArgs       The search argument structure.
662  *
663  * @returns See kldrDyldFindTryOpen
664  */
kldrDyldFindTryOpenPath(const char * pchPath,KSIZE cchPath,PCKLDRDYLDFINDARGS pArgs)665 static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs)
666 {
667     static char s_szFilename[1024];
668     char *psz;
669     int rc;
670 
671     /*
672      * Ignore any attempts at opening empty paths.
673      * This can happen when a *Dir globals is empty.
674      */
675     if (!cchPath)
676         return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */
677 
678     /*
679      * Limit check first.
680      */
681     if (cchPath + 1 + pArgs->cchMaxLength >= sizeof(s_szFilename))
682     {
683         KLDRDYLDFIND_ASSERT(!"too long");
684         return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */
685     }
686 
687     /*
688      * The directory path.
689      */
690     kHlpMemCopy(s_szFilename, pchPath, cchPath);
691     psz = &s_szFilename[cchPath];
692     if (psz[-1] != '/'
693 #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
694         && psz[-1] != '\\'
695         && psz[-1] != ':'
696 #endif
697         )
698         *psz++ = '/';
699 
700     /*
701      * The name.
702      */
703     if (pArgs->cchPrefix)
704     {
705         kHlpMemCopy(psz, pArgs->pszPrefix, pArgs->cchPrefix);
706         psz += pArgs->cchPrefix;
707     }
708     kHlpMemCopy(psz, pArgs->pszName, pArgs->cchName);
709     psz += pArgs->cchName;
710     if (pArgs->cchSuffix)
711     {
712         kHlpMemCopy(psz, pArgs->pszSuffix, pArgs->cchSuffix);
713         psz += pArgs->cchSuffix;
714     }
715     *psz = '\0';
716 
717 
718     /*
719      * Try open it.
720      */
721     rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr);
722     /* If we're opening an executable, try again without the suffix.*/
723     if (    rc
724         &&  pArgs->cchSuffix
725         &&  (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
726     {
727         psz -= pArgs->cchSuffix;
728         *psz = '\0';
729         rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr);
730     }
731     return rc;
732 }
733 
734 
735 /**
736  * Enumerates the specfied path.
737  *
738  * @returns Any return code from the kldrDyldFindTryOpenPath() which isn't KLDR_ERR_MODULE_NOT_FOUND.
739  * @returns KLDR_ERR_MODULE_NOT_FOUND if the end of the search path was reached.
740  * @param   pszSearchPath   The search path to enumeare.
741  * @param   pArgs       The search argument structure.
742  */
kldrDyldFindEnumeratePath(const char * pszSearchPath,PCKLDRDYLDFINDARGS pArgs)743 static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs)
744 {
745     const char *psz = pszSearchPath;
746     for (;;)
747     {
748         const char *pszEnd;
749         KSIZE       cchPath;
750 
751         /*
752          * Trim.
753          */
754         while (*psz == ';' || *psz == ':')
755             psz++;
756         if (*psz == '\0')
757             return KLDR_ERR_MODULE_NOT_FOUND;
758 
759         /*
760          * Find the end.
761          */
762         pszEnd = psz + 1;
763         while (     *pszEnd != '\0'
764                &&   *pszEnd != ';'
765 #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
766                && (     *pszEnd != ':'
767                    ||   (   pszEnd - psz == 1
768                          && (   (*psz >= 'A' && *psz <= 'Z')
769                              || (*psz >= 'a' && *psz <= 'z')
770                             )
771                         )
772                   )
773 #else
774                && *pszEnd != ':'
775 #endif
776               )
777             pszEnd++;
778 
779         /*
780          * If not empty path, try open the module using it.
781          */
782         cchPath = pszEnd - psz;
783         if (cchPath > 0)
784         {
785             int rc;
786             rc = kldrDyldFindTryOpenPath(psz, cchPath, pArgs);
787             if (rc != KLDR_ERR_MODULE_NOT_FOUND)
788                 return rc;
789         }
790 
791         /* next */
792         psz = pszEnd;
793     }
794 }
795 
796 
797 /**
798  * Resolve default search method, prefix and suffix.
799  *
800  * @returns 0 on success, KERR_INVALID_PARAMETER on failure.
801  * @param   penmSearch  The search method. In/Out.
802  * @param   ppszPrefix  The prefix. In/Out.
803  * @param   ppszSuffix  The suffix. In/Out.
804  * @param   pszName     The name. In.
805  * @param   fFlags      The load/search flags.
806  */
kldrDyldFindGetDefaults(KLDRDYLDSEARCH * penmSearch,const char ** ppszPrefix,const char ** ppszSuffix,const char * pszName,KU32 fFlags)807 static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **ppszPrefix, const char **ppszSuffix,
808                                    const char *pszName, KU32 fFlags)
809 {
810     unsigned fCaseSensitive;
811 
812     /*
813      * Fixup search method alias.
814      */
815     if (*penmSearch == KLDRDYLD_SEARCH_HOST)
816 #if K_OS == K_OS_DARWIN
817         /** @todo *penmSearch = KLDRDYLD_SEARCH_DARWIN; */
818         *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON;
819 #elif K_OS == K_OS_FREEBSD \
820    || K_OS == K_OS_LINUX \
821    || K_OS == K_OS_NETBSD \
822    || K_OS == K_OS_OPENBSD \
823    || K_OS == K_OS_SOLARIS
824         *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON;
825 #elif K_OS == K_OS_OS2
826         *penmSearch = KLDRDYLD_SEARCH_OS2;
827 #elif K_OS == K_OS_WINDOWS
828         *penmSearch = KLDRDYLD_SEARCH_WINDOWS;
829 #else
830 # error "Port me"
831 #endif
832 
833     /*
834      * Apply search method specific prefix/suffix.
835      */
836     switch (*penmSearch)
837     {
838         case KLDRDYLD_SEARCH_KLDR:
839             if (!*ppszPrefix && kLdrDyldDefPrefix[0])
840                 *ppszPrefix = kLdrDyldDefPrefix;
841             if (!*ppszSuffix && kLdrDyldDefSuffix[0])
842                 *ppszSuffix = kLdrDyldDefSuffix;
843             fCaseSensitive = 1;
844             break;
845 
846         case KLDRDYLD_SEARCH_OS2:
847             if (!*ppszSuffix)
848                 *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe";
849             fCaseSensitive = 0;
850             break;
851 
852         case KLDRDYLD_SEARCH_WINDOWS:
853         case KLDRDYLD_SEARCH_WINDOWS_ALTERED:
854             if (!*ppszSuffix)
855                 *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe";
856             fCaseSensitive = 0;
857             break;
858 
859         case KLDRDYLD_SEARCH_UNIX_COMMON:
860             fCaseSensitive = 1;
861             break;
862 
863         default:
864             KLDRDYLDFIND_ASSERT(!"invalid search method");
865             return KERR_INVALID_PARAMETER;
866     }
867 
868     /*
869      * Drop the suffix if it's already included in the name.
870      */
871     if (*ppszSuffix)
872     {
873         const KSIZE cchName = kHlpStrLen(pszName);
874         const KSIZE cchSuffix = kHlpStrLen(*ppszSuffix);
875         if (    cchName > cchSuffix
876             &&  (   fCaseSensitive
877                  ?  !kHlpMemComp(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix)
878                  :  !kHlpMemICompAscii(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix))
879            )
880             *ppszSuffix = NULL;
881     }
882 
883     return 0;
884 }
885 
886 
887 /**
888  * Locates an already open module using the specified search method.
889  *
890  * @returns 0 and *ppMod on success, non-zero OS specific error on failure.
891  *
892  * @param   pszName         Partial or complete name, it's specific to the search method to determin which.
893  * @param   pszPrefix       Prefix than can be used when searching.
894  * @param   pszSuffix       Suffix than can be used when searching.
895  * @param   enmSearch       The file search method to apply.
896  * @param   fFlags          Search flags.
897  * @param   ppMod           Where to store the file provider instance on success.
898  */
kldrDyldFindExistingModule(const char * pszName,const char * pszPrefix,const char * pszSuffix,KLDRDYLDSEARCH enmSearch,unsigned fFlags,PPKLDRDYLDMOD ppMod)899 int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
900                                KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod)
901 {
902 
903     int rc;
904     unsigned fOS2LibpathStrict;
905     *ppMod = NULL;
906 
907     /*
908      * Don't bother if no modules are loaded yet.
909      */
910     if (!kLdrDyldHead)
911         return KLDR_ERR_MODULE_NOT_FOUND;
912 
913     /*
914      * Defaults.
915      */
916     rc = kldrDyldFindGetDefaults(&enmSearch, &pszPrefix, &pszSuffix, pszName, fFlags);
917     if (rc)
918         return rc;
919 
920     /*
921      * If this isn't just a filename, the caller has specified a file
922      * that should be opened directly and not a module name to be searched for.
923      *
924      * In order to do the right thing we'll have to open the file and get the
925      * correct filename for it.
926      *
927      * The OS/2 libpath strict method require us to find the correct DLL first.
928      */
929     fOS2LibpathStrict = 0;
930     if (    !kHlpIsFilenameOnly(pszName)
931         ||  (fOS2LibpathStrict = (   enmSearch == KLDRDYLD_SEARCH_OS2
932                                   && kLdrDyldOS2LibpathStrict[0] == 'T')
933             )
934        )
935     {
936         PKRDR pRdr;
937         if (fOS2LibpathStrict)
938             rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
939         else
940             rc = kldrDyldFindTryOpen(pszName, &pRdr);
941         if (!rc)
942         {
943             /* do a filename based search. */
944             const char     *pszFilename = kRdrName(pRdr);
945             const KSIZE     cchFilename = kHlpStrLen(pszFilename);
946             PKLDRDYLDMOD    pCur;
947             rc = KLDR_ERR_MODULE_NOT_FOUND;
948             for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
949             {
950                 if (    pCur->pMod->cchFilename == cchFilename
951                     &&  !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename))
952                 {
953                     *ppMod = pCur;
954                     rc = 0;
955                     break;
956                 }
957             }
958             kRdrClose(pRdr);
959         }
960     }
961     else
962     {
963         const KSIZE     cchName = kHlpStrLen(pszName);
964         const KSIZE     cchPrefix = pszPrefix ? kHlpStrLen(pszPrefix) : 0;
965         const KSIZE     cchSuffix = pszSuffix ? kHlpStrLen(pszSuffix) : 0;
966         const char     *pszNameSuffix = kHlpGetSuff(pszName);
967         PKLDRDYLDMOD    pCur = kLdrDyldHead;
968 
969         /*
970          * Some of the methods are case insensitive (ASCII), others are case sensitive.
971          * To avoid having todo indirect calls to the compare functions here, we split
972          * ways even if it means a lot of duplicate code.
973          */
974         if (   enmSearch == KLDRDYLD_SEARCH_OS2
975             || enmSearch == KLDRDYLD_SEARCH_WINDOWS
976             || enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED)
977         {
978             const unsigned fNameHasSuffix = pszNameSuffix
979                                          && kHlpStrLen(pszNameSuffix) == cchSuffix
980                                          && !kHlpMemICompAscii(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix);
981             for (; pCur; pCur = pCur->Load.pNext)
982             {
983                 /* match global / specific */
984                 if (    !pCur->fGlobalOrSpecific
985                     &&  !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
986                     continue;
987 
988                 /* match name */
989                 if (    pCur->pMod->cchName == cchName
990                     &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName))
991                     break;
992                 if (cchPrefix)
993                 {
994                     if (    pCur->pMod->cchName == cchName + cchPrefix
995                         &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
996                         &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName))
997                     break;
998                 }
999                 if (cchSuffix)
1000                 {
1001                     if (    pCur->pMod->cchName == cchName + cchSuffix
1002                         &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix)
1003                         &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName))
1004                     break;
1005                     if (    fNameHasSuffix
1006                         &&  pCur->pMod->cchName == cchName - cchSuffix
1007                         &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName - cchSuffix))
1008                     break;
1009                     if (cchPrefix)
1010                     {
1011                         if (    pCur->pMod->cchName == cchName + cchPrefix + cchSuffix
1012                             &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
1013                             &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName)
1014                             &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix))
1015                         break;
1016                         if (    fNameHasSuffix
1017                             &&  pCur->pMod->cchName == cchName + cchPrefix - cchSuffix
1018                             &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
1019                             &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix))
1020                         break;
1021                     }
1022                 }
1023             }
1024         }
1025         else
1026         {
1027             const unsigned fNameHasSuffix = pszNameSuffix
1028                                          && kHlpStrLen(pszNameSuffix) == cchSuffix
1029                                          && kHlpMemComp(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix);
1030             for (; pCur; pCur = pCur->Load.pNext)
1031             {
1032                 /* match global / specific */
1033                 if (    !pCur->fGlobalOrSpecific
1034                     &&  !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
1035                     continue;
1036 
1037                 /* match name */
1038                 if (    pCur->pMod->cchName == cchName
1039                     &&  !kHlpMemComp(pCur->pMod->pszName, pszName, cchName))
1040                     break;
1041                 if (cchPrefix)
1042                 {
1043                     if (    pCur->pMod->cchName == cchName + cchPrefix
1044                         &&  !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1045                         &&  !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName))
1046                     break;
1047                 }
1048                 if (cchSuffix)
1049                 {
1050                     if (    pCur->pMod->cchName == cchName + cchSuffix
1051                         &&  !kHlpMemComp(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix)
1052                         &&  !kHlpMemComp(pCur->pMod->pszName, pszName, cchName))
1053                     break;
1054                     if (    fNameHasSuffix
1055                         &&  pCur->pMod->cchName == cchName - cchSuffix
1056                         &&  !kHlpMemComp(pCur->pMod->pszName, pszName, cchName - cchSuffix))
1057                     break;
1058                     if (cchPrefix)
1059                     {
1060                         if (    pCur->pMod->cchName == cchName + cchPrefix + cchSuffix
1061                             &&  !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1062                             &&  !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName)
1063                             &&  !kHlpMemComp(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix))
1064                         break;
1065                         if (    pCur->pMod->cchName == cchName + cchPrefix - cchSuffix
1066                             &&  !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1067                             &&  !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix))
1068                         break;
1069                     }
1070                 }
1071             }
1072         }
1073 
1074         /* search result. */
1075         if (pCur)
1076         {
1077             *ppMod = pCur;
1078             rc = 0;
1079         }
1080         else
1081             rc = KLDR_ERR_MODULE_NOT_FOUND;
1082     }
1083 
1084     return rc;
1085 }
1086 
1087