source: trunk/kLdr/kLdrDyld.c@ 2847

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

Roughly done with kldrDyldMod now.

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