source: trunk/kLdr/kLdrDyld.c@ 2887

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

Bugfixing.

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