source: trunk/kLdr/kLdrDyld.c@ 2868

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

Did the remaining search bit (I hope).

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