source: trunk/kLdr/kLdrDyld.c@ 2874

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

windows exe stub.

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