source: trunk/kLdr/kLdrDyld.c@ 2870

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

Test all kLdrDyld apis.

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