source: trunk/kLdr/kLdrDyld.c@ 2843

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

executable bootstrapping.

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