source: trunk/kLdr/kLdrDyld.c@ 2845

Last change on this file since 2845 was 2845, checked in by bird, 19 years ago

kldrDyldMod* in progress.

  • Property svn:keywords set to Id
File size: 46.2 KB
Line 
1/* $Id: kLdrDyld.c 2845 2006-11-01 01:39:03Z bird $ */
2/** @file
3 *
4 * kLdr - The Dynamic Loader.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include "kLdrHlp.h"
33#include "kLdrInternal.h"
34
35
36/*******************************************************************************
37* Defined Constants And Macros *
38*******************************************************************************/
39/** @def KLDRDYLD_STRICT
40 * Define KLDRDYLD_STRICT to enabled strict checks in kLdrDyld. */
41#define KLDRDYLD_STRICT 1
42
43/** @def KLDRDYLD_ASSERT
44 * Assert that an expression is true when KLDRDYLD_STRICT is defined.
45 */
46#ifdef KLDRDYLD_STRICT
47# define KLDRDYLD_ASSERT(expr) kldrHlpAssert(expr)
48#else
49# define KLDRDYLD_ASSERT(expr) do {} while (0)
50#endif
51
52
53/*******************************************************************************
54* Structures and Typedefs *
55*******************************************************************************/
56
57
58/*******************************************************************************
59* Global Variables *
60*******************************************************************************/
61/** Pointer to the executable module.
62 * (This is exported, so no prefix.) */
63PKLDRDYLDMOD kLdrDyldExe = NULL;
64/** Pointer to the head module (the executable).
65 * (This is exported, so no prefix.) */
66PKLDRDYLDMOD kLdrDyldHead = NULL;
67/** Pointer to the tail module.
68 * (This is exported, so no prefix.) */
69PKLDRDYLDMOD kLdrDyldTail = NULL;
70/** Pointer to the head module of the initialization list.
71 * The outermost load call will pop elements from this list in LIFO order (i.e.
72 * from the tail). The list is only used during non-recursive initialization
73 * and may therefore share the pNext/pPrev members with the termination list
74 * since we don't push a module onto the termination list untill it has been
75 * successfully initialized. */
76PKLDRDYLDMOD g_pkLdrDyldInitHead;
77/** Pointer to the tail module of the initalization list. */
78PKLDRDYLDMOD g_pkLdrDyldInitTail;
79/** Pointer to the head module of the termination order list. */
80PKLDRDYLDMOD g_pkLdrDyldTermHead;
81/** Pointer to the tail module of the termination order list. */
82PKLDRDYLDMOD g_pkLdrDyldTermTail;
83/** Pointer to the head module of the bind order list.
84 * The modules in this list makes up the global namespace used when binding symbol unix fashion. */
85PKLDRDYLDMOD g_pkLdrDyldBindHead;
86/** Pointer to the tail module of the bind order list. */
87PKLDRDYLDMOD g_pkLdrDyldBindTail;
88
89/** Flag indicating bootstrap time.
90 * When set the error behaviour changes. Any kind of serious failure
91 * is fatal and will terminate the process. */
92int g_fBootstrapping;
93/** The global error buffer. */
94char g_szkLdrDyldError[1024];
95
96/** The Library search path. */
97char kLdrDyldLibraryPath[4096];
98
99/** The default flags. */
100uint32_t kLdrDyldFlags = 0;
101/** The default search method. */
102KLDRDYLDSEARCH kLdrDyldSearch = KLDRDYLD_SEARCH_INVALID;
103/** The default DLL prefix. */
104char kLdrDyldDefPrefix[16];
105/** The default DLL suffix. */
106char kLdrDyldDefSuffix[16];
107
108
109/** The load stack.
110 * This contains frames with modules affected by active loads.
111 *
112 * Each kLdrDyldLoad and kLdrDyldLoadExe call will create a new stack frame containing
113 * all the modules involved in the operation. The modules will be ordered in recursive
114 * init order within the frame.
115 */
116static PPKLDRDYLDMOD g_papStackMods;
117/** The number of used entries in the g_papStackMods array. */
118static uint32_t g_cStackMods;
119/** The number of entries allocated for the g_papStackMods array. */
120static uint32_t g_cStackModsAllocated;
121/** Number of active load calls. */
122static uint32_t g_cActiveLoadCalls;
123/** Number of active unload calls. */
124static uint32_t g_cActiveUnloadCalls;
125/** Total number of load calls. */
126static uint32_t g_cTotalLoadCalls;
127/** Total mumber of unload calls. */
128static uint32_t g_cTotalUnloadCalls;
129/** Boolean flag indicating that GC is active. */
130static uint32_t g_fActiveGC;
131
132
133
134/*******************************************************************************
135* Internal Functions *
136*******************************************************************************/
137/** @name API worker routines.
138 * @internal
139 * @{ */
140void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, size_t cbStack);
141void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe);
142static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
143 unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, size_t cchErr);
144static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix,
145 KLDRDYLDSEARCH enmSearch, unsigned fFlags);
146static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
147 KLDRDYLDSEARCH enmSearch, unsigned fFlags);
148static int kldrDyldDoUnload(PKLDRDYLDMOD pMod);
149static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
150 unsigned fFlags, PPKLDRDYLDMOD ppMod);
151static int kldrDyldDoFindByAddress(uintptr_t Address, PPKLDRDYLDMOD ppMod, uint32_t *piSegment, uintptr_t *poffSegment);
152static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, size_t cchName);
153static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename);
154static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName, uintptr_t *pValue, uint32_t *pfKind);
155/** @} */
156
157/** @name Misc load/unload workers
158 * @internal
159 * @{
160 */
161static void kldrDyldDoModuleTerminationAndGarabageCollection(void);
162/** @} */
163
164/** @name The load stack.
165 * @internal
166 * @{ */
167static uint32_t kldrDyldStackNewFrame(PKLDRDYLDMOD pMod);
168static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod);
169static int kldrDyldStackFrameCompleted(void);
170static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc);
171static void kldrDyldStackDropFrame(uint32_t iLoad1st, uint32_t iLoadEnd, int rc);
172/** @} */
173
174static int kldrDyldCopyError(int rc, char *pszErr, size_t cchErr);
175
176
177
178/**
179 * Initialize the dynamic loader.
180 */
181int kldrDyInit(void)
182{
183 kLdrDyldHead = kLdrDyldTail = NULL;
184 g_pkLdrDyldTermHead = g_pkLdrDyldTermTail = NULL;
185 g_pkLdrDyldBindHead = g_pkLdrDyldBindTail = NULL;
186 kLdrDyldFlags = 0;
187 g_szkLdrDyldError[0] = '\0';
188 return 0;
189}
190
191
192/**
193 * Terminate the dynamic loader.
194 */
195void kldrDyTerm(void)
196{
197
198}
199
200
201/**
202 * Bootstrap an executable.
203 *
204 * This is called from the executable stub to replace the stub and run the
205 * executable specified in the argument package.
206 *
207 * Since this is boostrap time there isn't anything to return to. So, instead
208 * the process will be terminated upon failure.
209 *
210 * We also have to keep in mind that this function is called on a small, small,
211 * stack and therefore any kind of large stack objects or deep recursions must
212 * be avoided. Since loading the executable will involve more or less all
213 * operations in the loader, this restriction really applies everywhere.
214 *
215 * @param pArgs Pointer to the argument package residing in the executable stub.
216 */
217void kldrDoDyldLoadExe(PKLDREXEARGS pArgs)
218{
219 void *pvStack = NULL;
220 size_t cbStack = 0;
221 PKLDRDYLDMOD pExe = NULL;
222 int rc;
223
224 /*
225 * Copy the arguments into the globals and do loader init.
226 */
227 kLdrDyldFlags = pArgs->fFlags;
228 kLdrDyldSearch = pArgs->enmSearch;
229 kLdrHlpMemCopy(kLdrDyldDefPrefix, pArgs->szDefPrefix, KLDR_MIN(sizeof(pArgs->szDefPrefix), sizeof(kLdrDyldDefPrefix)));
230 kLdrHlpMemCopy(kLdrDyldDefSuffix, pArgs->szDefSuffix, KLDR_MIN(sizeof(pArgs->szDefSuffix), sizeof(kLdrDyldDefSuffix)));
231 kLdrHlpMemCopy(kLdrDyldLibraryPath, pArgs->szLibPath, KLDR_MIN(sizeof(pArgs->szLibPath), sizeof(kLdrDyldLibraryPath)));
232
233 g_fBootstrapping = 1;
234 rc = kldrInit();
235 if (rc)
236 kldrDyldFailure(rc, "Init failure, rc=%d", rc);
237
238 /*
239 * Make sure we own the loader semaphore (necessary for init).
240 */
241 rc = kldrHlpSemRequest();
242 if (rc)
243 kldrDyldFailure(rc, "Sem req. failure, rc=%d", rc);
244
245 /*
246 * Open and map the executable module before we join paths with kLdrDyldLoad().
247 */
248 rc = kldrDyldFindNewModule(pArgs->szExecutable, NULL, NULL, kLdrDyldSearch,
249 kLdrDyldFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE, &pExe);
250 if (rc)
251 kldrDyldFailure(rc, "Can't find/open the executable '%s', rc=%d", pArgs->szExecutable, rc);
252 rc = kldrDyldModMap(pExe);
253 if (rc)
254 kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc);
255
256 kLdrDyldExe = pExe;
257
258 /*
259 * Query the stack information and go to OS specific code to
260 * setup and switch stack. The OS specific code will call us
261 * back at kldrDyldDoLoadExe.
262 */
263 rc = kldrDyldModGetStackInfo(pExe, &pvStack, &cbStack);
264 if (rc)
265 kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc);
266 kldrDyldDoLoadExeStackSwitch(pExe, pvStack, cbStack);
267 kldrDyldFailure(-1, "Failed to setup the stack for '%s'.", pExe->pMod->pszFilename);
268}
269
270
271/**
272 * Loads a module into the current process.
273 *
274 * @returns 0 on success, non-zero native OS status code or kLdr status code on failure.
275 * @param pszDll The name of the dll to open.
276 * @param pszPrefix Prefix to use when searching.
277 * @param pszSuffix Suffix to use when searching.
278 * @param enmSearch Method to use when locating the module and any modules it may depend on.
279 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
280 * @param phMod Where to store the handle to the loaded module.
281 * @param pszErr Where to store extended error information. (optional)
282 * @param cchErr The size of the buffer pointed to by pszErr.
283 */
284int kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
285 unsigned fFlags, PHKLDRMOD phMod, char *pszErr, size_t cchErr)
286{
287 int rc;
288
289 /* validate arguments and initialize return values. */
290 if (pszErr && cchErr)
291 *pszErr = '\0';
292 *phMod = NIL_HKLDRMOD;
293 KLDRHLP_VALIDATE_STRING(pszDll);
294 KLDRHLP_VALIDATE_OPTIONAL_STRING(pszPrefix);
295 KLDRHLP_VALIDATE_OPTIONAL_STRING(pszSuffix);
296 KLDRHLP_VALIDATE_ENUM(enmSearch, KLDRDYLD_SEARCH);
297 KLDRHLP_VALIDATE_OPTIONAL_BUFFER(pszErr, cchErr);
298
299 /* get the semaphore and do the job. */
300 rc = kldrHlpSemRequest();
301 if (!rc)
302 {
303 PKLDRDYLDMOD pMod = NULL;
304 g_cTotalLoadCalls++;
305 g_cActiveLoadCalls++;
306 rc = kldrDyldDoLoad(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, phMod, pszErr, cchErr);
307 g_cActiveLoadCalls--;
308 kldrDyldDoModuleTerminationAndGarabageCollection();
309 kldrHlpSemRelease();
310 *phMod = pMod;
311 }
312 return rc;
313}
314
315
316/**
317 * Unloads a module loaded by kLdrDyldLoad.
318 *
319 * @returns 0 on success, non-zero native OS status code or kLdr status code on failure.
320 * @param hMod Module handle.
321 */
322int kLdrDyldUnload(HKLDRMOD hMod)
323{
324 int rc;
325
326 /* validate */
327 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
328
329 /* get sem & do work */
330 rc = kldrHlpSemRequest();
331 if (!rc)
332 {
333 g_cTotalUnloadCalls++;
334 g_cActiveUnloadCalls++;
335 rc = kldrDyldDoUnload(hMod);
336 g_cActiveUnloadCalls--;
337 kldrDyldDoModuleTerminationAndGarabageCollection();
338 kldrHlpSemRelease();
339 }
340 return rc;
341}
342
343
344/**
345 * Finds a module by name or filename.
346 *
347 * This call does not increase any reference counters and must not be
348 * paired with kLdrDyldUnload() like kLdrDyldLoad().
349 *
350 * @returns 0 on success.
351 * @returns KLDR_ERR_MODULE_NOT_FOUND or some I/O error on failure.
352 * @param pszDll The name of the dll to look for.
353 * @param pszPrefix Prefix than can be used when searching.
354 * @param pszSuffix Suffix than can be used when searching.
355 * @param enmSearch Method to use when locating the module.
356 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
357 * @param phMod Where to store the handle of the module on success.
358 */
359int kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
360 unsigned fFlags, PHKLDRMOD phMod)
361{
362 int rc;
363
364 /* validate & initialize */
365 *phMod = NIL_HKLDRMOD;
366 KLDRHLP_VALIDATE_STRING(pszDll);
367
368 /* get sem & do work */
369 rc = kldrHlpSemRequest();
370 if (!rc)
371 {
372 PKLDRDYLDMOD pMod = NULL;
373 rc = kldrDyldDoFindByName(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, phMod);
374 kldrHlpSemRelease();
375 *phMod = pMod;
376 }
377 return rc;
378}
379
380
381/**
382 * Finds a module by address.
383 *
384 * This call does not increase any reference counters and must not be
385 * paired with kLdrDyldUnload() like kLdrDyldLoad().
386 *
387 * @returns 0 on success.
388 * @returns KLDR_ERR_MODULE_NOT_FOUND on failure.
389 * @param Address The address believed to be within some module.
390 * @param phMod Where to store the module handle on success.
391 * @param piSegment Where to store the segment number. (optional)
392 * @param poffSegment Where to store the offset into the segment. (optional)
393 */
394int kLdrDyldFindByAddress(uintptr_t Address, PHKLDRMOD phMod, uint32_t *piSegment, uintptr_t *poffSegment)
395{
396 int rc;
397
398 /* validate & initialize */
399 *phMod = NIL_HKLDRMOD;
400 if (piSegment)
401 *piSegment = ~(uint32_t)0;
402 if (poffSegment)
403 *poffSegment = ~(uintptr_t)0;
404
405 /* get sem & do work */
406 rc = kldrHlpSemRequest();
407 if (!rc)
408 {
409 PKLDRDYLDMOD pMod = NULL;
410 rc = kldrDyldDoFindByAddress(Address, &pMod, piSegment, poffSegment);
411 kldrHlpSemRelease();
412 *phMod = pMod;
413 }
414 return rc;
415}
416
417
418/**
419 * Gets the module name.
420 *
421 * @returns 0 on success and pszName filled with the name.
422 * @returns KLDR_ERR_INVALID_HANDLE or KLDR_ERR_BUFFER_OVERFLOW on failure.
423 * @param hMod The module handle.
424 * @param pszName Where to put the name.
425 * @param cchName The size of the name buffer.
426 * @see kLdrDyldGetFilename
427 */
428int kLdrDyldGetName(HKLDRMOD hMod, char *pszName, size_t cchName)
429{
430 int rc;
431
432 /* validate */
433 if (pszName && cchName)
434 *pszName = '\0';
435 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
436 KLDRHLP_VALIDATE_BUFFER(pszName, cchName);
437
438 /* get sem & do work */
439 rc = kldrHlpSemRequest();
440 if (!rc)
441 {
442 rc = kldrDyldDoGetName(hMod, pszName, cchName);
443 kldrHlpSemRelease();
444 }
445 return rc;
446}
447
448
449/**
450 * Gets the module filename.
451 *
452 * @returns 0 on success and pszFilename filled with the name.
453 * @returns KLDR_ERR_INVALID_HANDLE or KLDR_ERR_BUFFER_OVERFLOW on failure.
454 * @param hMod The module handle.
455 * @param pszFilename Where to put the filename.
456 * @param cchFilename The size of the filename buffer.
457 * @see kLdrDyldGetName
458 */
459int kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, size_t cchFilename)
460{
461 int rc;
462
463 /* validate & initialize */
464 if (pszFilename && cchFilename);
465 *pszFilename = '\0';
466 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
467 KLDRHLP_VALIDATE_BUFFER(pszFilename, cchFilename);
468
469 /* get sem & do work */
470 rc = kldrHlpSemRequest();
471 if (!rc)
472 {
473 rc = kldrDyldDoGetFilename(hMod, pszFilename, cchFilename);
474 kldrHlpSemRelease();
475 }
476 return rc;
477}
478
479
480/**
481 * Queries the value and type of a symbol.
482 *
483 * @returns 0 on success and pValue and pfKind set.
484 * @returns KLDR_ERR_INVALID_HANDLE or KLDR_ERR_SYMBOL_NOT_FOUND on failure.
485 * @param hMod The module handle.
486 * @param uSymbolOrdinal The symbol ordinal. This is ignored if pszSymbolName is non-zero.
487 * @param pszSymbolName The symbol name.
488 * @param pValue Where to put the symbol value. Optional if pfKind is non-zero.
489 * @param pfKind Where to put the symbol kind flags. Optional if pValue is non-zero.
490 */
491int kLdrDyldQuerySymbol(HKLDRMOD hMod, uint32_t uSymbolOrdinal, const char *pszSymbolName, uintptr_t *pValue, uint32_t *pfKind)
492{
493 int rc;
494
495 /* validate & initialize */
496 if (pfKind)
497 *pfKind = 0;
498 if (pValue)
499 *pValue = 0;
500 if (!pfKind && !pValue)
501 return KLDR_ERR_INVALID_PARAMETER;
502 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
503 KLDRHLP_VALIDATE_OPTIONAL_STRING(pszSymbolName);
504
505 /* get sem & do work */
506 rc = kldrHlpSemRequest();
507 if (!rc)
508 {
509 rc = kldrDyldDoQuerySymbol(hMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
510 kldrHlpSemRelease();
511 }
512 return rc;
513}
514
515
516/**
517 * Worker kLdrDoLoadExe().
518 * Used after we've switch to the final process stack.
519 *
520 * @param pExe The executable module.
521 * @internal
522 */
523void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe)
524{
525 int rc;
526
527 /*
528 * Load the executable module with its prerequisites and initialize them.
529 */
530 g_cActiveLoadCalls++;
531 rc = kldrDyldDoLoad2(pExe, NULL, NULL, kLdrDyldSearch, kLdrDyldFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
532 if (rc)
533 kldrDyldFailure(rc, "load 2 failed for '%s', rc=%d", pExe->pMod->pszFilename);
534 g_cActiveLoadCalls--;
535 kldrDyldDoModuleTerminationAndGarabageCollection();
536
537 /*
538 * Invoke the executable entry point.
539 */
540 kldrDyldModStartExe(pExe);
541 kldrDyldFailure(-1, "failed to invoke main!");
542}
543
544
545/**
546 * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe().
547 * @internal
548 */
549static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
550 unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, size_t cchErr)
551{
552 int rc;
553
554 /*
555 * Try find the module among the ones that's already loaded.
556 */
557 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
558 if (!rc)
559 {
560 switch ((*ppMod)->enmState)
561 {
562 /*
563 * Prerequisites are ok, so nothing to do really.
564 */
565 case KLDRSTATE_GOOD:
566 case KLDRSTATE_INITIALIZING:
567 return kldrDyldModDynamicLoad(*ppMod);
568
569 /*
570 * The module can't be loaded because it failed to initialize.
571 */
572 case KLDRSTATE_INITIALIZATION_FAILED:
573 return KLDR_ERR_MODULE_INIT_FAILED_ALREADY;
574
575 /*
576 * Prerequisites needs loading / reattaching and the module
577 * (may depending on fFlags) needs to be initialized.
578 */
579 case KLDRSTATE_PENDING_INITIALIZATION:
580 break;
581
582 /*
583 * Prerequisites needs to be loaded again
584 */
585 case KLDRSTATE_PENDING_TERMINATION:
586 break;
587
588 /*
589 * The module has been terminated so it need to be reloaded, have it's
590 * prereqs loaded, fixed up and initialized before we can use it again.
591 */
592 case KLDRSTATE_PENDING_GC:
593 rc = kldrDyldModReload(*ppMod);
594 if (rc)
595 return kldrDyldCopyError(rc, pszErr, cchErr);
596 break;
597
598 /*
599 * Forget it, we don't know how to deal with re-initialization here.
600 */
601 case KLDRSTATE_TERMINATING:
602 KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING");
603 return KLDR_ERR_MODULE_TERMINATING;
604
605 /*
606 * Invalid state.
607 */
608 default:
609 KLDRDYLD_ASSERT(!"invalid state");
610 break;
611 }
612 }
613 else
614 {
615 /*
616 * We'll have to load it from file.
617 */
618 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
619 if (rc)
620 return kldrDyldCopyError(rc, pszErr, cchErr);
621 rc = kldrDyldModMap(*ppMod);
622 }
623
624 /*
625 * Join cause with kLdrDyldLoadExe.
626 */
627 if (!rc)
628 rc = kldrDyldDoLoad2(*ppMod, pszPrefix, pszSuffix, enmSearch, fFlags);
629 else
630 kldrDyldStackCleanupOne(*ppMod, rc);
631
632 /*
633 * Copy any error or warning to the error buffer.
634 */
635 return kldrDyldCopyError(rc, pszErr, cchErr);
636}
637
638
639/**
640 * 2nd half of kLdrDyldLoad() and kLdrDyldLoadExe().
641 *
642 * @internal
643 */
644static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix,
645 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
646{
647 /*
648 * Load prerequisites.
649 */
650 uint32_t i;
651 uint32_t iLoad1st = kldrDyldStackNewFrame(pLoadedMod);
652 int rc = kldrDyldDoLoadPrerequisites(pLoadedMod, pszPrefix, pszSuffix, enmSearch, fFlags);
653 uint32_t iLoadEnd = kldrDyldStackFrameCompleted();
654 if (rc)
655 kldrDyldStackCleanupOne(pLoadedMod, rc); /* in case it didn't get pushed onto the stack. */
656
657 /*
658 * Apply fixups.
659 */
660 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
661 {
662 PKLDRDYLDMOD pMod = g_papStackMods[i];
663 if ( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
664 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES)
665 rc = kldrDyldModFixup(pMod);
666 }
667
668 /*
669 * Advance fixed up module onto initialization.
670 */
671 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
672 {
673 PKLDRDYLDMOD pMod = g_papStackMods[i];
674 if ( pMod->enmState == KLDRSTATE_FIXED_UP
675 || pMod->enmState == KLDRSTATE_RELOADED_FIXED_UP)
676 pMod->enmState = KLDRSTATE_PENDING_INITIALIZATION;
677 KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION
678 || pMod->enmState == KLDRSTATE_GOOD);
679 }
680
681 /*
682 * Call the initializers if we're loading in recursive mode or
683 * if we're the outermost load call.
684 */
685 if (fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
686 {
687 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
688 {
689 PKLDRDYLDMOD pMod = g_papStackMods[i];
690 if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION)
691 rc = kldrDyldModCallInit(pMod);
692 else if (pMod->enmState == KLDRSTATE_INITIALIZATION_FAILED)
693 rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY;
694 else
695 KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
696 }
697#ifdef KLDRDYLD_STRICT
698 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
699 KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
700#endif
701 }
702 else if (g_cActiveLoadCalls <= 1)
703 {
704 while (!rc && g_pkLdrDyldInitHead)
705 {
706 PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead;
707 g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
708 if (pMod->InitTerm.pNext)
709 pMod->InitTerm.pNext->InitTerm.pPrev = NULL;
710 rc = kldrDyldModCallInit(pMod);
711 }
712 }
713
714 /*
715 * Complete the load by incrementing the dynamic load count of the
716 * requested module (return handle is already set).
717 */
718 if (!rc)
719 {
720 if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)
721 pLoadedMod->cDepRefs = 0xffff;
722 else
723 rc = kldrDyldModDynamicLoad(pLoadedMod);
724 }
725
726 kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc);
727 return rc;
728}
729
730
731/**
732 * kldrDyldDoLoad() helper which will load prerequisites and
733 * build the initialization array / list.
734 *
735 * @returns 0 on success, non-zero error code on failure.
736 * @param pMod The module to start at.
737 * @param pszPrefix Prefix to use when searching.
738 * @param pszSuffix Suffix to use when searching.
739 * @param enmSearch Method to use when locating the module and any modules it may depend on.
740 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
741 */
742static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
743 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
744{
745 static struct
746 {
747 /** The module. */
748 PKLDRDYLDMOD pMod;
749 /** The number of prerequisite modules left to process.
750 * This starts at ~0U to inidicate that we need to load/check prerequisistes. */
751 unsigned cLeft;
752 } s_aEntries[64];
753 unsigned cEntries;
754 int rc = 0;
755
756 /* push the first entry. */
757 s_aEntries[0].pMod = pMod;
758 s_aEntries[0].cLeft = ~0U;
759 cEntries = 1;
760
761 /*
762 * The recursion loop.
763 */
764 while (!rc && cEntries > 0)
765 {
766 const unsigned i = cEntries - 1;
767 pMod = s_aEntries[i].pMod;
768 if (s_aEntries[i].cLeft == ~0U)
769 {
770 /*
771 * Load prerequisite modules.
772 */
773 switch (pMod->enmState)
774 {
775 /*
776 * Load immediate prerequisite modules and push the ones needing
777 * attention onto the stack.
778 */
779 case KLDRSTATE_MAPPED:
780 case KLDRSTATE_RELOADED:
781 case KLDRSTATE_PENDING_TERMINATION:
782 rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags);
783 KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_GOOD
784 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES
785 || pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
786 || rc);
787 if (!rc)
788 s_aEntries[i].cLeft = pMod->cPrereqs;
789 break;
790
791 /*
792 * Check its prerequisite modules the first time around.
793 */
794 case KLDRSTATE_PENDING_INITIALIZATION:
795 if (pMod->fAlreadySeen)
796 break;
797 pMod->fAlreadySeen = 1;
798 s_aEntries[i].cLeft = pMod->cPrereqs;
799 break;
800
801 /*
802 * These are ok.
803 */
804 case KLDRSTATE_LOADED_PREREQUISITES:
805 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
806 case KLDRSTATE_INITIALIZING:
807 case KLDRSTATE_GOOD:
808 s_aEntries[i].cLeft = 0;
809 break;
810
811 /*
812 * All other stats are invalid.
813 */
814 default:
815 KLDRDYLD_ASSERT(!"invalid state");
816 break;
817 }
818 }
819 else if (s_aEntries[i].cLeft > 0)
820 {
821 /*
822 * Recurse down into the next prereq.
823 */
824 KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs);
825 if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0]))
826 {
827 s_aEntries[cEntries++].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft];
828 s_aEntries[i].cLeft--;
829 }
830 else
831 rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY;
832 }
833 else
834 {
835 /*
836 * We're done with this module, record it for init/cleanup.
837 */
838 cEntries--;
839 if (pMod->enmState != KLDRSTATE_GOOD)
840 {
841 kldrDyldStackAddModule(pMod);
842 if ( !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
843 && !pMod->fInitList)
844 {
845 pMod->fInitList = 1;
846 pMod->InitTerm.pNext = NULL;
847 pMod->InitTerm.pPrev = g_pkLdrDyldInitTail;
848 if (g_pkLdrDyldInitTail)
849 g_pkLdrDyldInitTail->InitTerm.pNext = pMod;
850 else
851 g_pkLdrDyldInitHead = pMod;
852 g_pkLdrDyldInitTail = pMod;
853 }
854 }
855 }
856 }
857
858 return rc;
859}
860
861
862/**
863 * Gets prerequisite module.
864 *
865 * This will try load the requested module if necessary, returning it in the MAPPED state.
866 *
867 * @returns 0 on success.
868 * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure.
869 * @param pszDll The name of the dll to look for.
870 * @param pszPrefix Prefix than can be used when searching.
871 * @param pszSuffix Suffix than can be used when searching.
872 * @param enmSearch Method to use when locating the module.
873 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
874 * @param pDep The depentant module.
875 * @param ppMod Where to put the module we get.
876 */
877int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
878 unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod)
879{
880 int rc;
881 PKLDRDYLDMOD pMod;
882
883 *ppMod = NULL;
884
885 /*
886 * Try find the module among the ones that's already loaded.
887 *
888 * This is very similar to the kldrDyldDoLoad code, except it has to deal with
889 * a couple of additional states and occurs only during prerequisite loading
890 * and the action taken is a little bit different.
891 */
892 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
893 if (!rc)
894 {
895 switch (pMod->enmState)
896 {
897 /*
898 * These are good.
899 */
900 case KLDRSTATE_MAPPED:
901 case KLDRSTATE_RELOADED:
902 case KLDRSTATE_LOADED_PREREQUISITES:
903 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
904 case KLDRSTATE_PENDING_INITIALIZATION:
905 case KLDRSTATE_INITIALIZING:
906 case KLDRSTATE_GOOD:
907 case KLDRSTATE_PENDING_TERMINATION:
908 break;
909
910 /*
911 * The module has been terminated so it need to be reloaded, have it's
912 * prereqs loaded, fixed up and initialized before we can use it again.
913 */
914 case KLDRSTATE_PENDING_GC:
915 rc = kldrDyldModReload(pMod);
916 break;
917
918 /*
919 * The module can't be loaded because it failed to initialize already.
920 */
921 case KLDRSTATE_INITIALIZATION_FAILED:
922 rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED;
923 break;
924
925 /*
926 * Forget it, no idea how to deal with re-initialization.
927 */
928 case KLDRSTATE_TERMINATING:
929 return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING;
930
931 /*
932 * Invalid state.
933 */
934 default:
935 KLDRDYLD_ASSERT(!"invalid state");
936 break;
937 }
938 }
939 else
940 {
941 /*
942 * We'll have to load it from file.
943 */
944 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
945 if (!rc)
946 rc = kldrDyldModMap(pMod);
947 }
948
949 /*
950 * On success add dependency.
951 */
952 if (!rc)
953 {
954 kldrDyldModAddDep(pMod, pDep);
955 *ppMod = pMod;
956 }
957 return rc;
958}
959
960
961/**
962 * Starts a new load stack frame.
963 *
964 * @returns Where the new stack frame starts.
965 * @param pLoadMod The module being loaded (only used for asserting).
966 */
967static uint32_t kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod)
968{
969 /*
970 * Clear the fAlreadySeen flags.
971 */
972 PKLDRDYLDMOD pMod = kLdrDyldHead;
973 while (pMod)
974 {
975 pMod->fAlreadySeen = 0;
976
977#ifdef KLDRDYLD_ASSERT
978 switch (pMod->enmState)
979 {
980 case KLDRSTATE_MAPPED:
981 case KLDRSTATE_RELOADED:
982 /* only the just loaded module can be in this state. */
983 KLDRDYLD_ASSERT(pMod == pLoadMod);
984 break;
985
986 case KLDRSTATE_PENDING_INITIALIZATION:
987 case KLDRSTATE_INITIALIZING:
988 case KLDRSTATE_PENDING_TERMINATION:
989 case KLDRSTATE_PENDING_GC:
990 case KLDRSTATE_TERMINATING:
991 case KLDRSTATE_INITIALIZATION_FAILED:
992 case KLDRSTATE_PENDING_DESTROY:
993 /* requires recursion. */
994 KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1);
995 break;
996
997 case KLDRSTATE_GOOD:
998 /* requires nothing. */
999 break;
1000
1001 default:
1002 KLDRDYLD_ASSERT(!"Invalid state");
1003 break;
1004 }
1005#endif
1006
1007 /* next */
1008 pMod = pMod->Load.pNext;
1009 }
1010 return g_cStackMods;
1011}
1012
1013
1014/**
1015 * Records the module.
1016 *
1017 * @return 0 on success, KLDR_ERR_NO_MEMORY if we can't expand the table.
1018 * @param pMod The module to record.
1019 */
1020static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod)
1021{
1022 /*
1023 * Grow the stack if necessary.
1024 */
1025 if (g_cStackMods + 1 > g_cStackModsAllocated)
1026 {
1027 uint32_t cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
1028 void *pvOld = g_papStackMods;
1029 void *pvNew = kldrHlpAlloc(cNew * sizeof(g_papStackMods[0]));
1030 if (!pvNew)
1031 return KLDR_ERR_NO_MEMORY;
1032 kLdrHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
1033 g_papStackMods = (PPKLDRDYLDMOD)pvNew;
1034 kldrHlpFree(pvOld);
1035 }
1036
1037 /*
1038 * Add a reference and push the module onto the stack.
1039 */
1040 kldrDyldModAddRef(pMod);
1041 g_papStackMods[g_cStackMods++] = pMod;
1042 return 0;
1043}
1044
1045
1046/**
1047 * The frame has been completed.
1048 *
1049 * @returns Where the frame ends.
1050 */
1051static int kldrDyldStackFrameCompleted(void)
1052{
1053 return g_cStackMods;
1054}
1055
1056
1057/**
1058 * Worker routine for kldrDyldStackDropFrame() and kldrDyldDoLoad().
1059 *
1060 * @param pMod The module to perform cleanups on.
1061 * @param rc Used for state verification.
1062 */
1063static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc)
1064{
1065 switch (pMod->enmState)
1066 {
1067 /*
1068 * Just push it along to the PENDING_DESTROY state.
1069 */
1070 case KLDRSTATE_MAPPED:
1071 KLDRDYLD_ASSERT(rc);
1072 kldrDyldModUnmap(pMod);
1073 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1074 break;
1075
1076 /*
1077 * Move back to PENDING_GC.
1078 */
1079 case KLDRSTATE_RELOADED:
1080 KLDRDYLD_ASSERT(rc);
1081 pMod->enmState = KLDRSTATE_PENDING_GC;
1082 break;
1083
1084 /*
1085 * Unload prerequisites and unmap the modules.
1086 */
1087 case KLDRSTATE_LOADED_PREREQUISITES:
1088 case KLDRSTATE_FIXED_UP:
1089 KLDRDYLD_ASSERT(rc);
1090 kldrDyldModUnloadPrerequisites(pMod);
1091 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1092 kldrDyldModUnmap(pMod);
1093 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1094 break;
1095
1096 /*
1097 * Unload prerequisites and push it back to PENDING_GC.
1098 */
1099 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
1100 case KLDRSTATE_RELOADED_FIXED_UP:
1101 kldrDyldModUnloadPrerequisites(pMod);
1102 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC);
1103 break;
1104
1105 /*
1106 * Nothing to do, just asserting sanity.
1107 */
1108 case KLDRSTATE_INITIALIZING:
1109 /* Implies there is another load going on. */
1110 KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1);
1111 break;
1112 case KLDRSTATE_TERMINATING:
1113 /* GC in progress. */
1114 KLDRDYLD_ASSERT(g_fActiveGC);
1115 break;
1116 case KLDRSTATE_PENDING_TERMINATION:
1117 case KLDRSTATE_PENDING_INITIALIZATION:
1118 case KLDRSTATE_PENDING_GC:
1119 case KLDRSTATE_PENDING_DESTROY:
1120 KLDRDYLD_ASSERT(rc);
1121 break;
1122 case KLDRSTATE_GOOD:
1123 break;
1124
1125 /*
1126 * Bad states.
1127 */
1128 default:
1129 KLDRDYLD_ASSERT(!"drop frame bad state (a)");
1130 break;
1131 }
1132}
1133
1134
1135/**
1136 * Done with the stack frame, dereference all the modules in it.
1137 *
1138 * @param iLoad1st The start of the stack frame.
1139 * @param iLoadEnd The end of the stack frame.
1140 * @param rc Used for state verification.
1141 */
1142static void kldrDyldStackDropFrame(uint32_t iLoad1st, uint32_t iLoadEnd, int rc)
1143{
1144 uint32_t iStack;
1145 KLDRDYLD_ASSERT(iLoadEnd <= g_cStackMods);
1146 KLDRDYLD_ASSERT(iLoad1st == g_cStackMods);
1147
1148 /*
1149 * First pass: Do all the cleanups we can, but don't destroy anything just yet.
1150 */
1151 for (iStack = iLoadEnd; iStack < iLoad1st; iStack++)
1152 {
1153 PKLDRDYLDMOD pMod = g_papStackMods[--iLoad1st];
1154 kldrDyldStackCleanupOne(pMod, rc);
1155 }
1156
1157 /*
1158 * Second pass: Release the references so modules pending destruction
1159 * can be completely removed.
1160 */
1161 while (iLoad1st > iLoadEnd)
1162 {
1163 /*
1164 * Pop a module.
1165 */
1166 PKLDRDYLDMOD pMod = g_papStackMods[--iLoad1st];
1167 g_cStackMods = iLoad1st;
1168
1169 /*
1170 * Revalidate the module state.
1171 */
1172 switch (pMod->enmState)
1173 {
1174 case KLDRSTATE_INITIALIZING:
1175 case KLDRSTATE_TERMINATING:
1176 case KLDRSTATE_PENDING_TERMINATION:
1177 case KLDRSTATE_PENDING_INITIALIZATION:
1178 case KLDRSTATE_PENDING_GC:
1179 case KLDRSTATE_PENDING_DESTROY:
1180 case KLDRSTATE_GOOD:
1181 break;
1182 default:
1183 KLDRDYLD_ASSERT(!"drop frame bad state (b)");
1184 break;
1185 }
1186
1187 /*
1188 * Release it.
1189 */
1190 kldrDyldModDeref(pMod);
1191 }
1192}
1193
1194
1195/**
1196 * Do garbage collection.
1197 *
1198 * This isn't doing anything unless it's called from the last
1199 * load or unload call.
1200 */
1201static void kldrDyldDoModuleTerminationAndGarabageCollection(void)
1202{
1203 PKLDRDYLDMOD pMod;
1204
1205 /*
1206 * We don't do anything until we're got rid of all recursive calls.
1207 * This will ensure that we get the most optimal termination order and
1208 * that we don't unload anything too early.
1209 */
1210 if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC)
1211 return;
1212 g_fActiveGC = 1;
1213
1214 do
1215 {
1216 /*
1217 * 1. Release prerequisites for any left over modules.
1218 */
1219 for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext);
1220 {
1221 kldrDyldModAddRef(pMod);
1222
1223 switch (pMod->enmState)
1224 {
1225 case KLDRSTATE_GOOD:
1226 case KLDRSTATE_PENDING_GC:
1227 break;
1228
1229 case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */
1230 case KLDRSTATE_PENDING_INITIALIZATION:
1231 case KLDRSTATE_PENDING_TERMINATION:
1232 kldrDyldModUnloadPrerequisites(pMod);
1233 break;
1234
1235 default:
1236 KLDRDYLD_ASSERT(!"invalid GC state (a)");
1237 break;
1238 }
1239
1240 kldrDyldModDeref(pMod);
1241 }
1242
1243 /*
1244 * 2. Do init calls until we encounter somebody calling load/unload.
1245 */
1246 for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext)
1247 {
1248 int fRestart = 0;
1249 kldrDyldModAddRef(pMod);
1250
1251 switch (pMod->enmState)
1252 {
1253 case KLDRSTATE_GOOD:
1254 case KLDRSTATE_PENDING_GC:
1255 break;
1256
1257 case KLDRSTATE_PENDING_TERMINATION:
1258 {
1259 const uint32_t cTotalLoadCalls = g_cTotalLoadCalls;
1260 const uint32_t cTotalUnloadCalls = g_cTotalUnloadCalls;
1261 kldrDyldModCallTerm(pMod);
1262 fRestart = cTotalLoadCalls != g_cTotalLoadCalls
1263 || cTotalUnloadCalls != g_cTotalUnloadCalls;
1264 break;
1265 }
1266
1267 default:
1268 KLDRDYLD_ASSERT(!"invalid GC state (b)");
1269 break;
1270 }
1271
1272 kldrDyldModDeref(pMod);
1273 if (fRestart)
1274 break;
1275 }
1276 } while (pMod);
1277
1278 /*
1279 * Unmap and destroy modules pending for GC.
1280 */
1281 pMod = kLdrDyldHead;
1282 while (pMod)
1283 {
1284 PKLDRDYLDMOD pNext = pMod->Load.pNext;
1285 kldrDyldModAddRef(pMod);
1286
1287 switch (pMod->enmState)
1288 {
1289 case KLDRSTATE_INITIALIZATION_FAILED:
1290 case KLDRSTATE_PENDING_GC:
1291 KLDRDYLD_ASSERT(pMod->cRefs == 0); /* ??? */
1292 pMod->enmState = KLDRSTATE_GC;
1293 kldrDyldModUnmap(pMod);
1294 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1295 kldrDyldModDestroy(pMod);
1296 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED);
1297 break;
1298
1299 case KLDRSTATE_GOOD:
1300 break;
1301 default:
1302 KLDRDYLD_ASSERT(!"invalid GC state (c)");
1303 break;
1304 }
1305
1306 kldrDyldModDeref(pMod);
1307
1308 /* next */
1309 pMod = pNext;
1310 }
1311
1312 g_fActiveGC = 0;
1313}
1314
1315
1316/**
1317 * Worker for kLdrDyldUnload().
1318 * @internal
1319 */
1320static int kldrDyldDoUnload(PKLDRDYLDMOD pMod)
1321{
1322 return kldrDyldModDynamicUnload(pMod);
1323}
1324
1325
1326/**
1327 * Worker for kLdrDyldFindByName().
1328 * @internal
1329 */
1330static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
1331 unsigned fFlags, PPKLDRDYLDMOD ppMod)
1332{
1333 return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
1334}
1335
1336
1337/**
1338 * Worker for kLdrDyldFindByAddress().
1339 * @internal
1340 */
1341static int kldrDyldDoFindByAddress(uintptr_t Address, PPKLDRDYLDMOD ppMod, uint32_t *piSegment, uintptr_t *poffSegment)
1342{
1343 /* Scan the segments of each module in the load list. */
1344 PKLDRDYLDMOD pMod = kLdrDyldHead;
1345 while (pMod)
1346 {
1347 uint32_t iSeg;
1348 for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++)
1349 {
1350 uintmax_t off = (uintmax_t)Address - pMod->pMod->aSegments[iSeg].LoadAddress;
1351 if (off < pMod->pMod->aSegments[iSeg].cb)
1352 {
1353 *ppMod = pMod->hMod;
1354 if (piSegment)
1355 *piSegment = iSeg;
1356 if (poffSegment)
1357 *poffSegment = (uintptr_t)off;
1358 return 0;
1359 }
1360 }
1361
1362 /* next */
1363 pMod = pMod->Load.pNext;
1364 }
1365
1366 return KLDR_ERR_MODULE_NOT_FOUND;
1367}
1368
1369
1370/**
1371 * Worker for kLdrDyldGetName().
1372 * @internal
1373 */
1374static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, size_t cchName)
1375{
1376 return kldrDyldModGetName(pMod, pszName, cchName);
1377}
1378
1379
1380/**
1381 * Worker for kLdrDyldGetFilename().
1382 * @internal
1383 */
1384static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename)
1385{
1386 return kldrDyldModGetFilename(pMod, pszFilename, cchFilename);
1387}
1388
1389
1390/**
1391 * Worker for kLdrDyldQuerySymbol().
1392 * @internal
1393 */
1394static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName, uintptr_t *pValue, uint32_t *pfKind)
1395{
1396 return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
1397}
1398
1399
1400/**
1401 * Panic / failure
1402 *
1403 * @returns rc if we're in a position where we can return.
1404 * @param rc Return code.
1405 * @param pszFormat Message string. Limited fprintf like formatted.
1406 * @param ... Message string arguments.
1407 */
1408int kldrDyldFailure(int rc, const char *pszFilename, ...)
1409{
1410 kldrHlpExit(1);
1411 return rc;
1412}
1413
1414
1415/**
1416 * Copies the error string to the user buffer.
1417 *
1418 * @returns rc.
1419 * @param rc The status code.
1420 * @param pszErr Where to copy the error string to.
1421 * @param cchErr The size of the destination buffer.
1422 */
1423static int kldrDyldCopyError(int rc, char *pszErr, size_t cchErr)
1424{
1425 size_t cchToCopy;
1426
1427 /* if no error string, format the rc into a string. */
1428 if (!g_szkLdrDyldError[0] && rc)
1429 kldrHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10);
1430
1431 /* copy it if we got something. */
1432 if (cchErr && pszErr && g_szkLdrDyldError[0])
1433 {
1434 cchToCopy = kLdrHlpStrLen(g_szkLdrDyldError);
1435 if (cchToCopy >= cchErr)
1436 cchToCopy = cchErr - 1;
1437 kLdrHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy);
1438 pszErr[cchToCopy] = '\0';
1439 }
1440
1441 return rc;
1442}
1443
Note: See TracBrowser for help on using the repository browser.