source: trunk/kLdr/kLdrDyld.c@ 2867

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

top half of the filesearching is done.

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