source: trunk/kLdr/kLdrDyld.c@ 2871

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

More testing and another bug fixed.

  • Property svn:keywords set to Id
File size: 47.5 KB
Line 
1/* $Id: kLdrDyld.c 2871 2006-11-12 06:16:41Z 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 else
729 g_pkLdrDyldInitTail = NULL;
730 pMod->fInitList = 0;
731 rc = kldrDyldModCallInit(pMod);
732 }
733 }
734
735 /*
736 * Complete the load by incrementing the dynamic load count of the
737 * requested module (return handle is already set).
738 */
739 if (!rc)
740 {
741 if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)
742 pLoadedMod->cDepRefs = 0xffff;
743 else
744 rc = kldrDyldModDynamicLoad(pLoadedMod);
745 }
746
747 kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc);
748 return rc;
749}
750
751
752/**
753 * kldrDyldDoLoad() helper which will load prerequisites and
754 * build the initialization array / list.
755 *
756 * @returns 0 on success, non-zero error code on failure.
757 * @param pMod The module to start at.
758 * @param pszPrefix Prefix to use when searching.
759 * @param pszSuffix Suffix to use when searching.
760 * @param enmSearch Method to use when locating the module and any modules it may depend on.
761 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
762 */
763static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
764 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
765{
766 static struct
767 {
768 /** The module. */
769 PKLDRDYLDMOD pMod;
770 /** The number of prerequisite modules left to process.
771 * This starts at ~0U to inidicate that we need to load/check prerequisistes. */
772 unsigned cLeft;
773 } s_aEntries[64];
774 unsigned cEntries;
775 int rc = 0;
776
777 /* Prerequisites are always global and they just aren't executables. */
778 fFlags &= ~(KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
779
780 /* push the first entry. */
781 s_aEntries[0].pMod = pMod;
782 s_aEntries[0].cLeft = ~0U;
783 cEntries = 1;
784
785 /*
786 * The recursion loop.
787 */
788 while (!rc && cEntries > 0)
789 {
790 const unsigned i = cEntries - 1;
791 pMod = s_aEntries[i].pMod;
792 if (s_aEntries[i].cLeft == ~0U)
793 {
794 /*
795 * Load prerequisite modules.
796 */
797 switch (pMod->enmState)
798 {
799 /*
800 * Load immediate prerequisite modules and push the ones needing
801 * attention onto the stack.
802 */
803 case KLDRSTATE_MAPPED:
804 case KLDRSTATE_RELOADED:
805 case KLDRSTATE_PENDING_TERMINATION:
806 rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags);
807 KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_GOOD
808 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES
809 || pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
810 || rc);
811 if (!rc)
812 s_aEntries[i].cLeft = pMod->cPrereqs;
813 break;
814
815 /*
816 * Check its prerequisite modules the first time around.
817 */
818 case KLDRSTATE_PENDING_INITIALIZATION:
819 if (pMod->fAlreadySeen)
820 break;
821 pMod->fAlreadySeen = 1;
822 s_aEntries[i].cLeft = pMod->cPrereqs;
823 break;
824
825 /*
826 * These are ok.
827 */
828 case KLDRSTATE_LOADED_PREREQUISITES:
829 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
830 case KLDRSTATE_INITIALIZING:
831 case KLDRSTATE_GOOD:
832 s_aEntries[i].cLeft = 0;
833 break;
834
835 /*
836 * All other stats are invalid.
837 */
838 default:
839 KLDRDYLD_ASSERT(!"invalid state");
840 break;
841 }
842 }
843 else if (s_aEntries[i].cLeft > 0)
844 {
845 /*
846 * Recurse down into the next prereq.
847 */
848 KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs);
849 if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0]))
850 {
851 s_aEntries[cEntries].cLeft = ~(uint32_t)0;
852 s_aEntries[cEntries].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft];
853 s_aEntries[i].cLeft--;
854 cEntries++;
855 }
856 else
857 rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY;
858 }
859 else
860 {
861 /*
862 * We're done with this module, record it for init/cleanup.
863 */
864 cEntries--;
865 if (pMod->enmState != KLDRSTATE_GOOD)
866 {
867 kldrDyldStackAddModule(pMod);
868 if ( !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
869 && !pMod->fInitList)
870 {
871 pMod->fInitList = 1;
872 pMod->InitTerm.pNext = NULL;
873 pMod->InitTerm.pPrev = g_pkLdrDyldInitTail;
874 if (g_pkLdrDyldInitTail)
875 g_pkLdrDyldInitTail->InitTerm.pNext = pMod;
876 else
877 g_pkLdrDyldInitHead = pMod;
878 g_pkLdrDyldInitTail = pMod;
879 }
880 }
881 }
882 }
883
884 return rc;
885}
886
887
888/**
889 * Gets prerequisite module.
890 *
891 * This will try load the requested module if necessary, returning it in the MAPPED state.
892 *
893 * @returns 0 on success.
894 * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure.
895 * @param pszDll The name of the dll to look for.
896 * @param pszPrefix Prefix than can be used when searching.
897 * @param pszSuffix Suffix than can be used when searching.
898 * @param enmSearch Method to use when locating the module.
899 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
900 * @param pDep The depentant module.
901 * @param ppMod Where to put the module we get.
902 */
903int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
904 unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod)
905{
906 int rc;
907 PKLDRDYLDMOD pMod;
908
909 *ppMod = NULL;
910
911 /*
912 * Try find the module among the ones that's already loaded.
913 *
914 * This is very similar to the kldrDyldDoLoad code, except it has to deal with
915 * a couple of additional states and occurs only during prerequisite loading
916 * and the action taken is a little bit different.
917 */
918 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
919 if (!rc)
920 {
921 switch (pMod->enmState)
922 {
923 /*
924 * These are good.
925 */
926 case KLDRSTATE_MAPPED:
927 case KLDRSTATE_RELOADED:
928 case KLDRSTATE_LOADED_PREREQUISITES:
929 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
930 case KLDRSTATE_PENDING_INITIALIZATION:
931 case KLDRSTATE_INITIALIZING:
932 case KLDRSTATE_GOOD:
933 case KLDRSTATE_PENDING_TERMINATION:
934 break;
935
936 /*
937 * The module has been terminated so it need to be reloaded, have it's
938 * prereqs loaded, fixed up and initialized before we can use it again.
939 */
940 case KLDRSTATE_PENDING_GC:
941 rc = kldrDyldModReload(pMod);
942 break;
943
944 /*
945 * The module can't be loaded because it failed to initialize already.
946 */
947 case KLDRSTATE_INITIALIZATION_FAILED:
948 rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED;
949 break;
950
951 /*
952 * Forget it, no idea how to deal with re-initialization.
953 */
954 case KLDRSTATE_TERMINATING:
955 return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING;
956
957 /*
958 * Invalid state.
959 */
960 default:
961 KLDRDYLD_ASSERT(!"invalid state");
962 break;
963 }
964 }
965 else
966 {
967 /*
968 * We'll have to load it from file.
969 */
970 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
971 if (!rc)
972 rc = kldrDyldModMap(pMod);
973 }
974
975 /*
976 * On success add dependency.
977 */
978 if (!rc)
979 {
980 kldrDyldModAddDep(pMod, pDep);
981 *ppMod = pMod;
982 }
983 return rc;
984}
985
986
987/**
988 * Starts a new load stack frame.
989 *
990 * @returns Where the new stack frame starts.
991 * @param pLoadMod The module being loaded (only used for asserting).
992 */
993static uint32_t kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod)
994{
995 /*
996 * Clear the fAlreadySeen flags.
997 */
998 PKLDRDYLDMOD pMod = kLdrDyldHead;
999 while (pMod)
1000 {
1001 pMod->fAlreadySeen = 0;
1002
1003#ifdef KLDRDYLD_ASSERT
1004 switch (pMod->enmState)
1005 {
1006 case KLDRSTATE_MAPPED:
1007 case KLDRSTATE_RELOADED:
1008 /* only the just loaded module can be in this state. */
1009 KLDRDYLD_ASSERT(pMod == pLoadMod);
1010 break;
1011
1012 case KLDRSTATE_PENDING_INITIALIZATION:
1013 case KLDRSTATE_INITIALIZING:
1014 case KLDRSTATE_PENDING_TERMINATION:
1015 case KLDRSTATE_PENDING_GC:
1016 case KLDRSTATE_TERMINATING:
1017 case KLDRSTATE_INITIALIZATION_FAILED:
1018 case KLDRSTATE_PENDING_DESTROY:
1019 /* requires recursion. */
1020 KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1);
1021 break;
1022
1023 case KLDRSTATE_GOOD:
1024 /* requires nothing. */
1025 break;
1026
1027 default:
1028 KLDRDYLD_ASSERT(!"Invalid state");
1029 break;
1030 }
1031#endif
1032
1033 /* next */
1034 pMod = pMod->Load.pNext;
1035 }
1036 return g_cStackMods;
1037}
1038
1039
1040/**
1041 * Records the module.
1042 *
1043 * @return 0 on success, KLDR_ERR_NO_MEMORY if we can't expand the table.
1044 * @param pMod The module to record.
1045 */
1046static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod)
1047{
1048 /*
1049 * Grow the stack if necessary.
1050 */
1051 if (g_cStackMods + 1 > g_cStackModsAllocated)
1052 {
1053 uint32_t cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
1054 void *pvOld = g_papStackMods;
1055 void *pvNew = kldrHlpAlloc(cNew * sizeof(g_papStackMods[0]));
1056 if (!pvNew)
1057 return KLDR_ERR_NO_MEMORY;
1058 kLdrHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
1059 g_papStackMods = (PPKLDRDYLDMOD)pvNew;
1060 kldrHlpFree(pvOld);
1061 }
1062
1063 /*
1064 * Add a reference and push the module onto the stack.
1065 */
1066 kldrDyldModAddRef(pMod);
1067 g_papStackMods[g_cStackMods++] = pMod;
1068 return 0;
1069}
1070
1071
1072/**
1073 * The frame has been completed.
1074 *
1075 * @returns Where the frame ends.
1076 */
1077static int kldrDyldStackFrameCompleted(void)
1078{
1079 return g_cStackMods;
1080}
1081
1082
1083/**
1084 * Worker routine for kldrDyldStackDropFrame() and kldrDyldDoLoad().
1085 *
1086 * @param pMod The module to perform cleanups on.
1087 * @param rc Used for state verification.
1088 */
1089static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc)
1090{
1091 switch (pMod->enmState)
1092 {
1093 /*
1094 * Just push it along to the PENDING_DESTROY state.
1095 */
1096 case KLDRSTATE_MAPPED:
1097 KLDRDYLD_ASSERT(rc);
1098 kldrDyldModUnmap(pMod);
1099 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1100 break;
1101
1102 /*
1103 * Move back to PENDING_GC.
1104 */
1105 case KLDRSTATE_RELOADED:
1106 KLDRDYLD_ASSERT(rc);
1107 pMod->enmState = KLDRSTATE_PENDING_GC;
1108 break;
1109
1110 /*
1111 * Unload prerequisites and unmap the modules.
1112 */
1113 case KLDRSTATE_LOADED_PREREQUISITES:
1114 case KLDRSTATE_FIXED_UP:
1115 KLDRDYLD_ASSERT(rc);
1116 kldrDyldModUnloadPrerequisites(pMod);
1117 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1118 kldrDyldModUnmap(pMod);
1119 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1120 break;
1121
1122 /*
1123 * Unload prerequisites and push it back to PENDING_GC.
1124 */
1125 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
1126 case KLDRSTATE_RELOADED_FIXED_UP:
1127 kldrDyldModUnloadPrerequisites(pMod);
1128 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC);
1129 break;
1130
1131 /*
1132 * Nothing to do, just asserting sanity.
1133 */
1134 case KLDRSTATE_INITIALIZING:
1135 /* Implies there is another load going on. */
1136 KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1);
1137 break;
1138 case KLDRSTATE_TERMINATING:
1139 /* GC in progress. */
1140 KLDRDYLD_ASSERT(g_fActiveGC);
1141 break;
1142 case KLDRSTATE_PENDING_TERMINATION:
1143 case KLDRSTATE_PENDING_INITIALIZATION:
1144 case KLDRSTATE_PENDING_GC:
1145 case KLDRSTATE_PENDING_DESTROY:
1146 KLDRDYLD_ASSERT(rc);
1147 break;
1148 case KLDRSTATE_GOOD:
1149 break;
1150
1151 /*
1152 * Bad states.
1153 */
1154 default:
1155 KLDRDYLD_ASSERT(!"drop frame bad state (a)");
1156 break;
1157 }
1158}
1159
1160
1161/**
1162 * Done with the stack frame, dereference all the modules in it.
1163 *
1164 * @param iLoad1st The start of the stack frame.
1165 * @param iLoadEnd The end of the stack frame.
1166 * @param rc Used for state verification.
1167 */
1168static void kldrDyldStackDropFrame(uint32_t iLoad1st, uint32_t iLoadEnd, int rc)
1169{
1170 uint32_t i;
1171 KLDRDYLD_ASSERT(iLoad1st <= g_cStackMods);
1172 KLDRDYLD_ASSERT(iLoadEnd == g_cStackMods);
1173
1174 /*
1175 * First pass: Do all the cleanups we can, but don't destroy anything just yet.
1176 */
1177 i = iLoadEnd;
1178 while (i-- > iLoad1st)
1179 {
1180 PKLDRDYLDMOD pMod = g_papStackMods[i];
1181 kldrDyldStackCleanupOne(pMod, rc);
1182 }
1183
1184 /*
1185 * Second pass: Release the references so modules pending destruction
1186 * can be completely removed.
1187 */
1188 for (i = iLoad1st; i < iLoadEnd ; i++)
1189 {
1190 PKLDRDYLDMOD pMod = g_papStackMods[i];
1191
1192 /*
1193 * Revalidate the module state.
1194 */
1195 switch (pMod->enmState)
1196 {
1197 case KLDRSTATE_INITIALIZING:
1198 case KLDRSTATE_TERMINATING:
1199 case KLDRSTATE_PENDING_TERMINATION:
1200 case KLDRSTATE_PENDING_INITIALIZATION:
1201 case KLDRSTATE_PENDING_GC:
1202 case KLDRSTATE_PENDING_DESTROY:
1203 case KLDRSTATE_GOOD:
1204 break;
1205 default:
1206 KLDRDYLD_ASSERT(!"drop frame bad state (b)");
1207 break;
1208 }
1209
1210 /*
1211 * Release it.
1212 */
1213 kldrDyldModDeref(pMod);
1214 }
1215
1216 /*
1217 * Drop the stack frame.
1218 */
1219 g_cStackMods = iLoad1st;
1220}
1221
1222
1223/**
1224 * Do garbage collection.
1225 *
1226 * This isn't doing anything unless it's called from the last
1227 * load or unload call.
1228 */
1229static void kldrDyldDoModuleTerminationAndGarabageCollection(void)
1230{
1231 PKLDRDYLDMOD pMod;
1232
1233 /*
1234 * We don't do anything until we're got rid of all recursive calls.
1235 * This will ensure that we get the most optimal termination order and
1236 * that we don't unload anything too early.
1237 */
1238 if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC)
1239 return;
1240 g_fActiveGC = 1;
1241
1242 do
1243 {
1244 /*
1245 * 1. Release prerequisites for any left over modules.
1246 */
1247 for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
1248 {
1249 kldrDyldModAddRef(pMod);
1250
1251 switch (pMod->enmState)
1252 {
1253 case KLDRSTATE_GOOD:
1254 case KLDRSTATE_PENDING_GC:
1255 case KLDRSTATE_PENDING_TERMINATION:
1256 break;
1257
1258 case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */
1259 case KLDRSTATE_PENDING_INITIALIZATION:
1260 kldrDyldModUnloadPrerequisites(pMod);
1261 break;
1262
1263 default:
1264 KLDRDYLD_ASSERT(!"invalid GC state (a)");
1265 break;
1266 }
1267
1268 kldrDyldModDeref(pMod);
1269 }
1270
1271 /*
1272 * 2. Do init calls until we encounter somebody calling load/unload.
1273 */
1274 for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext)
1275 {
1276 int fRestart = 0;
1277 kldrDyldModAddRef(pMod);
1278
1279 switch (pMod->enmState)
1280 {
1281 case KLDRSTATE_GOOD:
1282 case KLDRSTATE_PENDING_GC:
1283 break;
1284
1285 case KLDRSTATE_PENDING_TERMINATION:
1286 {
1287 const uint32_t cTotalLoadCalls = g_cTotalLoadCalls;
1288 const uint32_t cTotalUnloadCalls = g_cTotalUnloadCalls;
1289 kldrDyldModCallTerm(pMod);
1290 fRestart = cTotalLoadCalls != g_cTotalLoadCalls
1291 || cTotalUnloadCalls != g_cTotalUnloadCalls;
1292 break;
1293 }
1294
1295 default:
1296 KLDRDYLD_ASSERT(!"invalid GC state (b)");
1297 break;
1298 }
1299
1300 kldrDyldModDeref(pMod);
1301 if (fRestart)
1302 break;
1303 }
1304 } while (pMod);
1305
1306 /*
1307 * Unmap and destroy modules pending for GC.
1308 */
1309 pMod = kLdrDyldHead;
1310 while (pMod)
1311 {
1312 PKLDRDYLDMOD pNext = pMod->Load.pNext;
1313 kldrDyldModAddRef(pMod);
1314
1315 switch (pMod->enmState)
1316 {
1317 case KLDRSTATE_INITIALIZATION_FAILED:
1318 case KLDRSTATE_PENDING_GC:
1319 KLDRDYLD_ASSERT(!pMod->cDepRefs);
1320 KLDRDYLD_ASSERT(!pMod->cDynRefs);
1321 pMod->enmState = KLDRSTATE_GC;
1322 kldrDyldModUnmap(pMod);
1323 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1324 kldrDyldModDestroy(pMod);
1325 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED);
1326 break;
1327
1328 case KLDRSTATE_GOOD:
1329 break;
1330 default:
1331 KLDRDYLD_ASSERT(!"invalid GC state (c)");
1332 break;
1333 }
1334
1335 kldrDyldModDeref(pMod);
1336
1337 /* next */
1338 pMod = pNext;
1339 }
1340
1341 g_fActiveGC = 0;
1342}
1343
1344
1345/**
1346 * Worker for kLdrDyldUnload().
1347 * @internal
1348 */
1349static int kldrDyldDoUnload(PKLDRDYLDMOD pMod)
1350{
1351 return kldrDyldModDynamicUnload(pMod);
1352}
1353
1354
1355/**
1356 * Worker for kLdrDyldFindByName().
1357 * @internal
1358 */
1359static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
1360 unsigned fFlags, PPKLDRDYLDMOD ppMod)
1361{
1362 return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
1363}
1364
1365
1366/**
1367 * Worker for kLdrDyldFindByAddress().
1368 * @internal
1369 */
1370static int kldrDyldDoFindByAddress(uintptr_t Address, PPKLDRDYLDMOD ppMod, uint32_t *piSegment, uintptr_t *poffSegment)
1371{
1372 /* Scan the segments of each module in the load list. */
1373 PKLDRDYLDMOD pMod = kLdrDyldHead;
1374 while (pMod)
1375 {
1376 uint32_t iSeg;
1377 for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++)
1378 {
1379 KLDRADDR off = (KLDRADDR)Address - pMod->pMod->aSegments[iSeg].MapAddress;
1380 if (off < pMod->pMod->aSegments[iSeg].cb)
1381 {
1382 *ppMod = pMod->hMod;
1383 if (piSegment)
1384 *piSegment = iSeg;
1385 if (poffSegment)
1386 *poffSegment = (uintptr_t)off;
1387 return 0;
1388 }
1389 }
1390
1391 /* next */
1392 pMod = pMod->Load.pNext;
1393 }
1394
1395 return KLDR_ERR_MODULE_NOT_FOUND;
1396}
1397
1398
1399/**
1400 * Worker for kLdrDyldGetName().
1401 * @internal
1402 */
1403static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, size_t cchName)
1404{
1405 return kldrDyldModGetName(pMod, pszName, cchName);
1406}
1407
1408
1409/**
1410 * Worker for kLdrDyldGetFilename().
1411 * @internal
1412 */
1413static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename)
1414{
1415 return kldrDyldModGetFilename(pMod, pszFilename, cchFilename);
1416}
1417
1418
1419/**
1420 * Worker for kLdrDyldQuerySymbol().
1421 * @internal
1422 */
1423static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName, uintptr_t *pValue, uint32_t *pfKind)
1424{
1425 return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
1426}
1427
1428
1429/**
1430 * Panic / failure
1431 *
1432 * @returns rc if we're in a position where we can return.
1433 * @param rc Return code.
1434 * @param pszFormat Message string. Limited fprintf like formatted.
1435 * @param ... Message string arguments.
1436 */
1437int kldrDyldFailure(int rc, const char *pszFilename, ...)
1438{
1439 /** @todo print it. */
1440 if (g_fBootstrapping);
1441 kldrHlpExit(1);
1442 return rc;
1443}
1444
1445
1446/**
1447 * Copies the error string to the user buffer.
1448 *
1449 * @returns rc.
1450 * @param rc The status code.
1451 * @param pszErr Where to copy the error string to.
1452 * @param cchErr The size of the destination buffer.
1453 */
1454static int kldrDyldCopyError(int rc, char *pszErr, size_t cchErr)
1455{
1456 size_t cchToCopy;
1457
1458 /* if no error string, format the rc into a string. */
1459 if (!g_szkLdrDyldError[0] && rc)
1460 kldrHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10);
1461
1462 /* copy it if we got something. */
1463 if (cchErr && pszErr && g_szkLdrDyldError[0])
1464 {
1465 cchToCopy = kLdrHlpStrLen(g_szkLdrDyldError);
1466 if (cchToCopy >= cchErr)
1467 cchToCopy = cchErr - 1;
1468 kLdrHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy);
1469 pszErr[cchToCopy] = '\0';
1470 }
1471
1472 return rc;
1473}
1474
Note: See TracBrowser for help on using the repository browser.