source: trunk/kLdr/kLdrDyld.c@ 3003

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

made it compile again.

  • Property svn:keywords set to Id
File size: 48.8 KB
Line 
1/* $Id: kLdrDyld.c 2893 2006-12-22 18:01:38Z 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 pszSymbolVersion The symbol version. Optional.
531 * @param pValue Where to put the symbol value. Optional if pfKind is non-zero.
532 * @param pfKind Where to put the symbol kind flags. Optional if pValue is non-zero.
533 */
534int kLdrDyldQuerySymbol(HKLDRMOD hMod, uint32_t uSymbolOrdinal, const char *pszSymbolName,
535 const char *pszSymbolVersion, uintptr_t *pValue, uint32_t *pfKind)
536{
537 int rc;
538
539 /* validate & initialize */
540 if (pfKind)
541 *pfKind = 0;
542 if (pValue)
543 *pValue = 0;
544 if (!pfKind && !pValue)
545 return KLDR_ERR_INVALID_PARAMETER;
546 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
547 KLDRHLP_VALIDATE_OPTIONAL_STRING(pszSymbolName);
548
549 /* get sem & do work */
550 rc = kldrHlpSemRequest();
551 if (!rc)
552 {
553 rc = kldrDyldDoQuerySymbol(hMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
554 kldrHlpSemRelease();
555 }
556 return rc;
557}
558
559
560/**
561 * Worker kLdrDoLoadExe().
562 * Used after we've switch to the final process stack.
563 *
564 * @param pExe The executable module.
565 * @internal
566 */
567void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe)
568{
569 int rc;
570
571 /*
572 * Load the executable module with its prerequisites and initialize them.
573 */
574 g_cActiveLoadCalls++;
575 rc = kldrDyldDoLoad2(pExe, NULL, NULL, kLdrDyldSearch, kLdrDyldFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
576 if (rc)
577 kldrDyldFailure(rc, "load 2 failed for '%s', rc=%d", pExe->pMod->pszFilename);
578 g_cActiveLoadCalls--;
579 kldrDyldDoModuleTerminationAndGarabageCollection();
580
581 /*
582 * Invoke the executable entry point.
583 */
584 kldrDyldModStartExe(pExe);
585 kldrDyldFailure(-1, "failed to invoke main!");
586}
587
588
589/**
590 * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe().
591 * @internal
592 */
593static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
594 unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, size_t cchErr)
595{
596 int rc;
597
598 /*
599 * Try find the module among the ones that's already loaded.
600 */
601 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
602 if (!rc)
603 {
604 switch ((*ppMod)->enmState)
605 {
606 /*
607 * Prerequisites are ok, so nothing to do really.
608 */
609 case KLDRSTATE_GOOD:
610 case KLDRSTATE_INITIALIZING:
611 return kldrDyldModDynamicLoad(*ppMod);
612
613 /*
614 * The module can't be loaded because it failed to initialize.
615 */
616 case KLDRSTATE_INITIALIZATION_FAILED:
617 return KLDR_ERR_MODULE_INIT_FAILED_ALREADY;
618
619 /*
620 * Prerequisites needs loading / reattaching and the module
621 * (may depending on fFlags) needs to be initialized.
622 */
623 case KLDRSTATE_PENDING_INITIALIZATION:
624 break;
625
626 /*
627 * Prerequisites needs to be loaded again
628 */
629 case KLDRSTATE_PENDING_TERMINATION:
630 break;
631
632 /*
633 * The module has been terminated so it need to be reloaded, have it's
634 * prereqs loaded, fixed up and initialized before we can use it again.
635 */
636 case KLDRSTATE_PENDING_GC:
637 rc = kldrDyldModReload(*ppMod);
638 if (rc)
639 return kldrDyldCopyError(rc, pszErr, cchErr);
640 break;
641
642 /*
643 * Forget it, we don't know how to deal with re-initialization here.
644 */
645 case KLDRSTATE_TERMINATING:
646 KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING");
647 return KLDR_ERR_MODULE_TERMINATING;
648
649 /*
650 * Invalid state.
651 */
652 default:
653 KLDRDYLD_ASSERT(!"invalid state");
654 break;
655 }
656 }
657 else
658 {
659 /*
660 * We'll have to load it from file.
661 */
662 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
663 if (rc)
664 return kldrDyldCopyError(rc, pszErr, cchErr);
665 rc = kldrDyldModMap(*ppMod);
666 }
667
668 /*
669 * Join cause with kLdrDyldLoadExe.
670 */
671 if (!rc)
672 rc = kldrDyldDoLoad2(*ppMod, pszPrefix, pszSuffix, enmSearch, fFlags);
673 else
674 kldrDyldStackCleanupOne(*ppMod, rc);
675
676 /*
677 * Copy any error or warning to the error buffer.
678 */
679 return kldrDyldCopyError(rc, pszErr, cchErr);
680}
681
682
683/**
684 * 2nd half of kLdrDyldLoad() and kLdrDyldLoadExe().
685 *
686 * @internal
687 */
688static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix,
689 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
690{
691 /*
692 * Load prerequisites.
693 */
694 uint32_t i;
695 uint32_t iLoad1st = kldrDyldStackNewFrame(pLoadedMod);
696 int rc = kldrDyldDoLoadPrerequisites(pLoadedMod, pszPrefix, pszSuffix, enmSearch, fFlags);
697 uint32_t iLoadEnd = kldrDyldStackFrameCompleted();
698 if (rc)
699 {
700 kldrDyldModAddRef(pLoadedMod);
701 kldrDyldStackCleanupOne(pLoadedMod, rc); /* in case it didn't get pushed onto the stack. */
702 kldrDyldModDeref(pLoadedMod);
703 }
704
705 /*
706 * Apply fixups.
707 */
708 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
709 {
710 PKLDRDYLDMOD pMod = g_papStackMods[i];
711 if ( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
712 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES)
713 rc = kldrDyldModFixup(pMod);
714 }
715
716 /*
717 * Advance fixed up module onto initialization.
718 */
719 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
720 {
721 PKLDRDYLDMOD pMod = g_papStackMods[i];
722 if ( pMod->enmState == KLDRSTATE_FIXED_UP
723 || pMod->enmState == KLDRSTATE_RELOADED_FIXED_UP)
724 pMod->enmState = KLDRSTATE_PENDING_INITIALIZATION;
725 KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION
726 || pMod->enmState == KLDRSTATE_GOOD);
727 }
728
729 /*
730 * Call the initializers if we're loading in recursive mode or
731 * if we're the outermost load call.
732 */
733 if (fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
734 {
735 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
736 {
737 PKLDRDYLDMOD pMod = g_papStackMods[i];
738 if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION)
739 rc = kldrDyldModCallInit(pMod);
740 else if (pMod->enmState == KLDRSTATE_INITIALIZATION_FAILED)
741 rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY;
742 else
743 KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
744 }
745#ifdef KLDRDYLD_STRICT
746 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
747 KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
748#endif
749 }
750 else if (g_cActiveLoadCalls <= 1)
751 {
752 while (!rc && g_pkLdrDyldInitHead)
753 {
754 PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead;
755 g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
756 if (pMod->InitTerm.pNext)
757 pMod->InitTerm.pNext->InitTerm.pPrev = NULL;
758 else
759 g_pkLdrDyldInitTail = NULL;
760 pMod->fInitList = 0;
761 rc = kldrDyldModCallInit(pMod);
762 }
763 }
764
765 /*
766 * Complete the load by incrementing the dynamic load count of the
767 * requested module (return handle is already set).
768 */
769 if (!rc)
770 {
771 if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)
772 {
773 pLoadedMod->cDepRefs++; /* just make it stick. */
774 pLoadedMod->cRefs++;
775 }
776 else
777 rc = kldrDyldModDynamicLoad(pLoadedMod);
778 }
779
780 kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc);
781 return rc;
782}
783
784
785/**
786 * kldrDyldDoLoad() helper which will load prerequisites and
787 * build the initialization array / list.
788 *
789 * @returns 0 on success, non-zero error code on failure.
790 * @param pMod The module to start at.
791 * @param pszPrefix Prefix to use when searching.
792 * @param pszSuffix Suffix to use when searching.
793 * @param enmSearch Method to use when locating the module and any modules it may depend on.
794 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
795 */
796static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
797 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
798{
799 static struct
800 {
801 /** The module. */
802 PKLDRDYLDMOD pMod;
803 /** The number of prerequisite modules left to process.
804 * This starts at ~0U to inidicate that we need to load/check prerequisistes. */
805 unsigned cLeft;
806 } s_aEntries[64];
807 unsigned cEntries;
808 int rc = 0;
809
810 /* Prerequisites are always global and they just aren't executables. */
811 fFlags &= ~(KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
812
813 /* push the first entry. */
814 s_aEntries[0].pMod = pMod;
815 s_aEntries[0].cLeft = ~0U;
816 cEntries = 1;
817
818 /*
819 * The recursion loop.
820 */
821 while (!rc && cEntries > 0)
822 {
823 const unsigned i = cEntries - 1;
824 pMod = s_aEntries[i].pMod;
825 if (s_aEntries[i].cLeft == ~0U)
826 {
827 /*
828 * Load prerequisite modules.
829 */
830 switch (pMod->enmState)
831 {
832 /*
833 * Load immediate prerequisite modules and push the ones needing
834 * attention onto the stack.
835 */
836 case KLDRSTATE_MAPPED:
837 case KLDRSTATE_RELOADED:
838 case KLDRSTATE_PENDING_TERMINATION:
839 rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags);
840 KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_GOOD
841 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES
842 || pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
843 || rc);
844 if (!rc)
845 s_aEntries[i].cLeft = pMod->cPrereqs;
846 break;
847
848 /*
849 * Check its prerequisite modules the first time around.
850 */
851 case KLDRSTATE_PENDING_INITIALIZATION:
852 if (pMod->fAlreadySeen)
853 break;
854 pMod->fAlreadySeen = 1;
855 s_aEntries[i].cLeft = pMod->cPrereqs;
856 break;
857
858 /*
859 * These are ok.
860 */
861 case KLDRSTATE_LOADED_PREREQUISITES:
862 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
863 case KLDRSTATE_INITIALIZING:
864 case KLDRSTATE_GOOD:
865 s_aEntries[i].cLeft = 0;
866 break;
867
868 /*
869 * All other stats are invalid.
870 */
871 default:
872 KLDRDYLD_ASSERT(!"invalid state");
873 break;
874 }
875 }
876 else if (s_aEntries[i].cLeft > 0)
877 {
878 /*
879 * Recurse down into the next prereq.
880 */
881 KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs);
882 if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0]))
883 {
884 s_aEntries[cEntries].cLeft = ~(uint32_t)0;
885 s_aEntries[cEntries].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft];
886 s_aEntries[i].cLeft--;
887 cEntries++;
888 }
889 else
890 rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY;
891 }
892 else
893 {
894 /*
895 * We're done with this module, record it for init/cleanup.
896 */
897 cEntries--;
898 if (pMod->enmState != KLDRSTATE_GOOD)
899 {
900 kldrDyldStackAddModule(pMod);
901 if ( !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
902 && !pMod->fInitList)
903 {
904 pMod->fInitList = 1;
905 pMod->InitTerm.pNext = NULL;
906 pMod->InitTerm.pPrev = g_pkLdrDyldInitTail;
907 if (g_pkLdrDyldInitTail)
908 g_pkLdrDyldInitTail->InitTerm.pNext = pMod;
909 else
910 g_pkLdrDyldInitHead = pMod;
911 g_pkLdrDyldInitTail = pMod;
912 }
913 }
914 }
915 }
916
917 return rc;
918}
919
920
921/**
922 * Gets prerequisite module.
923 *
924 * This will try load the requested module if necessary, returning it in the MAPPED state.
925 *
926 * @returns 0 on success.
927 * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure.
928 * @param pszDll The name of the dll to look for.
929 * @param pszPrefix Prefix than can be used when searching.
930 * @param pszSuffix Suffix than can be used when searching.
931 * @param enmSearch Method to use when locating the module.
932 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
933 * @param pDep The depentant module.
934 * @param ppMod Where to put the module we get.
935 */
936int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
937 unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod)
938{
939 int rc;
940 PKLDRDYLDMOD pMod;
941
942 *ppMod = NULL;
943
944 /*
945 * Try find the module among the ones that's already loaded.
946 *
947 * This is very similar to the kldrDyldDoLoad code, except it has to deal with
948 * a couple of additional states and occurs only during prerequisite loading
949 * and the action taken is a little bit different.
950 */
951 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
952 if (!rc)
953 {
954 switch (pMod->enmState)
955 {
956 /*
957 * These are good.
958 */
959 case KLDRSTATE_MAPPED:
960 case KLDRSTATE_RELOADED:
961 case KLDRSTATE_LOADED_PREREQUISITES:
962 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
963 case KLDRSTATE_PENDING_INITIALIZATION:
964 case KLDRSTATE_INITIALIZING:
965 case KLDRSTATE_GOOD:
966 case KLDRSTATE_PENDING_TERMINATION:
967 break;
968
969 /*
970 * The module has been terminated so it need to be reloaded, have it's
971 * prereqs loaded, fixed up and initialized before we can use it again.
972 */
973 case KLDRSTATE_PENDING_GC:
974 rc = kldrDyldModReload(pMod);
975 break;
976
977 /*
978 * The module can't be loaded because it failed to initialize already.
979 */
980 case KLDRSTATE_INITIALIZATION_FAILED:
981 rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED;
982 break;
983
984 /*
985 * Forget it, no idea how to deal with re-initialization.
986 */
987 case KLDRSTATE_TERMINATING:
988 return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING;
989
990 /*
991 * Invalid state.
992 */
993 default:
994 KLDRDYLD_ASSERT(!"invalid state");
995 break;
996 }
997 }
998 else
999 {
1000 /*
1001 * We'll have to load it from file.
1002 */
1003 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
1004 if (!rc)
1005 rc = kldrDyldModMap(pMod);
1006 }
1007
1008 /*
1009 * On success add dependency.
1010 */
1011 if (!rc)
1012 {
1013 kldrDyldModAddDep(pMod, pDep);
1014 *ppMod = pMod;
1015 }
1016 return rc;
1017}
1018
1019
1020/**
1021 * Starts a new load stack frame.
1022 *
1023 * @returns Where the new stack frame starts.
1024 * @param pLoadMod The module being loaded (only used for asserting).
1025 */
1026static uint32_t kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod)
1027{
1028 /*
1029 * Clear the fAlreadySeen flags.
1030 */
1031 PKLDRDYLDMOD pMod = kLdrDyldHead;
1032 while (pMod)
1033 {
1034 pMod->fAlreadySeen = 0;
1035
1036#ifdef KLDRDYLD_ASSERT
1037 switch (pMod->enmState)
1038 {
1039 case KLDRSTATE_MAPPED:
1040 case KLDRSTATE_RELOADED:
1041 /* only the just loaded module can be in this state. */
1042 KLDRDYLD_ASSERT(pMod == pLoadMod);
1043 break;
1044
1045 case KLDRSTATE_PENDING_INITIALIZATION:
1046 case KLDRSTATE_INITIALIZING:
1047 case KLDRSTATE_PENDING_TERMINATION:
1048 case KLDRSTATE_PENDING_GC:
1049 case KLDRSTATE_TERMINATING:
1050 case KLDRSTATE_INITIALIZATION_FAILED:
1051 case KLDRSTATE_PENDING_DESTROY:
1052 /* requires recursion. */
1053 KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1);
1054 break;
1055
1056 case KLDRSTATE_GOOD:
1057 /* requires nothing. */
1058 break;
1059
1060 default:
1061 KLDRDYLD_ASSERT(!"Invalid state");
1062 break;
1063 }
1064#endif
1065
1066 /* next */
1067 pMod = pMod->Load.pNext;
1068 }
1069 return g_cStackMods;
1070}
1071
1072
1073/**
1074 * Records the module.
1075 *
1076 * @return 0 on success, KLDR_ERR_NO_MEMORY if we can't expand the table.
1077 * @param pMod The module to record.
1078 */
1079static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod)
1080{
1081 /*
1082 * Grow the stack if necessary.
1083 */
1084 if (g_cStackMods + 1 > g_cStackModsAllocated)
1085 {
1086 uint32_t cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
1087 void *pvOld = g_papStackMods;
1088 void *pvNew = kldrHlpAlloc(cNew * sizeof(g_papStackMods[0]));
1089 if (!pvNew)
1090 return KLDR_ERR_NO_MEMORY;
1091 kLdrHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
1092 g_papStackMods = (PPKLDRDYLDMOD)pvNew;
1093 kldrHlpFree(pvOld);
1094 }
1095
1096 /*
1097 * Add a reference and push the module onto the stack.
1098 */
1099 kldrDyldModAddRef(pMod);
1100 g_papStackMods[g_cStackMods++] = pMod;
1101 return 0;
1102}
1103
1104
1105/**
1106 * The frame has been completed.
1107 *
1108 * @returns Where the frame ends.
1109 */
1110static int kldrDyldStackFrameCompleted(void)
1111{
1112 return g_cStackMods;
1113}
1114
1115
1116/**
1117 * Worker routine for kldrDyldStackDropFrame() and kldrDyldDoLoad().
1118 *
1119 * @param pMod The module to perform cleanups on.
1120 * @param rc Used for state verification.
1121 */
1122static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc)
1123{
1124 switch (pMod->enmState)
1125 {
1126 /*
1127 * Just push it along to the PENDING_DESTROY state.
1128 */
1129 case KLDRSTATE_MAPPED:
1130 KLDRDYLD_ASSERT(rc);
1131 kldrDyldModUnmap(pMod);
1132 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1133 break;
1134
1135 /*
1136 * Move back to PENDING_GC.
1137 */
1138 case KLDRSTATE_RELOADED:
1139 KLDRDYLD_ASSERT(rc);
1140 pMod->enmState = KLDRSTATE_PENDING_GC;
1141 break;
1142
1143 /*
1144 * Unload prerequisites and unmap the modules.
1145 */
1146 case KLDRSTATE_LOADED_PREREQUISITES:
1147 case KLDRSTATE_FIXED_UP:
1148 KLDRDYLD_ASSERT(rc);
1149 kldrDyldModUnloadPrerequisites(pMod);
1150 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1151 kldrDyldModUnmap(pMod);
1152 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1153 break;
1154
1155 /*
1156 * Unload prerequisites and push it back to PENDING_GC.
1157 */
1158 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
1159 case KLDRSTATE_RELOADED_FIXED_UP:
1160 kldrDyldModUnloadPrerequisites(pMod);
1161 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC);
1162 break;
1163
1164 /*
1165 * Nothing to do, just asserting sanity.
1166 */
1167 case KLDRSTATE_INITIALIZING:
1168 /* Implies there is another load going on. */
1169 KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1);
1170 break;
1171 case KLDRSTATE_TERMINATING:
1172 /* GC in progress. */
1173 KLDRDYLD_ASSERT(g_fActiveGC);
1174 break;
1175 case KLDRSTATE_PENDING_TERMINATION:
1176 case KLDRSTATE_PENDING_INITIALIZATION:
1177 case KLDRSTATE_PENDING_GC:
1178 case KLDRSTATE_PENDING_DESTROY:
1179 KLDRDYLD_ASSERT(rc);
1180 break;
1181 case KLDRSTATE_GOOD:
1182 break;
1183
1184 /*
1185 * Bad states.
1186 */
1187 default:
1188 KLDRDYLD_ASSERT(!"drop frame bad state (a)");
1189 break;
1190 }
1191}
1192
1193
1194/**
1195 * Done with the stack frame, dereference all the modules in it.
1196 *
1197 * @param iLoad1st The start of the stack frame.
1198 * @param iLoadEnd The end of the stack frame.
1199 * @param rc Used for state verification.
1200 */
1201static void kldrDyldStackDropFrame(uint32_t iLoad1st, uint32_t iLoadEnd, int rc)
1202{
1203 uint32_t i;
1204 KLDRDYLD_ASSERT(iLoad1st <= g_cStackMods);
1205 KLDRDYLD_ASSERT(iLoadEnd == g_cStackMods);
1206
1207 /*
1208 * First pass: Do all the cleanups we can, but don't destroy anything just yet.
1209 */
1210 i = iLoadEnd;
1211 while (i-- > iLoad1st)
1212 {
1213 PKLDRDYLDMOD pMod = g_papStackMods[i];
1214 kldrDyldStackCleanupOne(pMod, rc);
1215 }
1216
1217 /*
1218 * Second pass: Release the references so modules pending destruction
1219 * can be completely removed.
1220 */
1221 for (i = iLoad1st; i < iLoadEnd ; i++)
1222 {
1223 PKLDRDYLDMOD pMod = g_papStackMods[i];
1224
1225 /*
1226 * Revalidate the module state.
1227 */
1228 switch (pMod->enmState)
1229 {
1230 case KLDRSTATE_INITIALIZING:
1231 case KLDRSTATE_TERMINATING:
1232 case KLDRSTATE_PENDING_TERMINATION:
1233 case KLDRSTATE_PENDING_INITIALIZATION:
1234 case KLDRSTATE_PENDING_GC:
1235 case KLDRSTATE_PENDING_DESTROY:
1236 case KLDRSTATE_GOOD:
1237 break;
1238 default:
1239 KLDRDYLD_ASSERT(!"drop frame bad state (b)");
1240 break;
1241 }
1242
1243 /*
1244 * Release it.
1245 */
1246 kldrDyldModDeref(pMod);
1247 }
1248
1249 /*
1250 * Drop the stack frame.
1251 */
1252 g_cStackMods = iLoad1st;
1253}
1254
1255
1256/**
1257 * Do garbage collection.
1258 *
1259 * This isn't doing anything unless it's called from the last
1260 * load or unload call.
1261 */
1262static void kldrDyldDoModuleTerminationAndGarabageCollection(void)
1263{
1264 PKLDRDYLDMOD pMod;
1265
1266 /*
1267 * We don't do anything until we're got rid of all recursive calls.
1268 * This will ensure that we get the most optimal termination order and
1269 * that we don't unload anything too early.
1270 */
1271 if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC)
1272 return;
1273 g_fActiveGC = 1;
1274
1275 do
1276 {
1277 /*
1278 * 1. Release prerequisites for any left over modules.
1279 */
1280 for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
1281 {
1282 kldrDyldModAddRef(pMod);
1283
1284 switch (pMod->enmState)
1285 {
1286 case KLDRSTATE_GOOD:
1287 case KLDRSTATE_PENDING_GC:
1288 case KLDRSTATE_PENDING_TERMINATION:
1289 break;
1290
1291 case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */
1292 case KLDRSTATE_PENDING_INITIALIZATION:
1293 kldrDyldModUnloadPrerequisites(pMod);
1294 break;
1295
1296 default:
1297 KLDRDYLD_ASSERT(!"invalid GC state (a)");
1298 break;
1299 }
1300
1301 kldrDyldModDeref(pMod);
1302 }
1303
1304 /*
1305 * 2. Do init calls until we encounter somebody calling load/unload.
1306 */
1307 for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext)
1308 {
1309 int fRestart = 0;
1310 kldrDyldModAddRef(pMod);
1311
1312 switch (pMod->enmState)
1313 {
1314 case KLDRSTATE_GOOD:
1315 case KLDRSTATE_PENDING_GC:
1316 break;
1317
1318 case KLDRSTATE_PENDING_TERMINATION:
1319 {
1320 const uint32_t cTotalLoadCalls = g_cTotalLoadCalls;
1321 const uint32_t cTotalUnloadCalls = g_cTotalUnloadCalls;
1322 kldrDyldModCallTerm(pMod);
1323 fRestart = cTotalLoadCalls != g_cTotalLoadCalls
1324 || cTotalUnloadCalls != g_cTotalUnloadCalls;
1325 break;
1326 }
1327
1328 default:
1329 KLDRDYLD_ASSERT(!"invalid GC state (b)");
1330 break;
1331 }
1332
1333 kldrDyldModDeref(pMod);
1334 if (fRestart)
1335 break;
1336 }
1337 } while (pMod);
1338
1339 /*
1340 * Unmap and destroy modules pending for GC.
1341 */
1342 pMod = kLdrDyldHead;
1343 while (pMod)
1344 {
1345 PKLDRDYLDMOD pNext = pMod->Load.pNext;
1346 kldrDyldModAddRef(pMod);
1347
1348 switch (pMod->enmState)
1349 {
1350 case KLDRSTATE_INITIALIZATION_FAILED:
1351 case KLDRSTATE_PENDING_GC:
1352 KLDRDYLD_ASSERT(!pMod->cDepRefs);
1353 KLDRDYLD_ASSERT(!pMod->cDynRefs);
1354 pMod->enmState = KLDRSTATE_GC;
1355 kldrDyldModUnmap(pMod);
1356 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1357 kldrDyldModDestroy(pMod);
1358 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED);
1359 break;
1360
1361 case KLDRSTATE_GOOD:
1362 break;
1363 default:
1364 KLDRDYLD_ASSERT(!"invalid GC state (c)");
1365 break;
1366 }
1367
1368 kldrDyldModDeref(pMod);
1369
1370 /* next */
1371 pMod = pNext;
1372 }
1373
1374 g_fActiveGC = 0;
1375}
1376
1377
1378/**
1379 * Worker for kLdrDyldUnload().
1380 * @internal
1381 */
1382static int kldrDyldDoUnload(PKLDRDYLDMOD pMod)
1383{
1384 return kldrDyldModDynamicUnload(pMod);
1385}
1386
1387
1388/**
1389 * Worker for kLdrDyldFindByName().
1390 * @internal
1391 */
1392static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
1393 unsigned fFlags, PPKLDRDYLDMOD ppMod)
1394{
1395 return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
1396}
1397
1398
1399/**
1400 * Worker for kLdrDyldFindByAddress().
1401 * @internal
1402 */
1403static int kldrDyldDoFindByAddress(uintptr_t Address, PPKLDRDYLDMOD ppMod, uint32_t *piSegment, uintptr_t *poffSegment)
1404{
1405 /* Scan the segments of each module in the load list. */
1406 PKLDRDYLDMOD pMod = kLdrDyldHead;
1407 while (pMod)
1408 {
1409 uint32_t iSeg;
1410 for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++)
1411 {
1412 KLDRADDR off = (KLDRADDR)Address - pMod->pMod->aSegments[iSeg].MapAddress;
1413 if (off < pMod->pMod->aSegments[iSeg].cb)
1414 {
1415 *ppMod = pMod->hMod;
1416 if (piSegment)
1417 *piSegment = iSeg;
1418 if (poffSegment)
1419 *poffSegment = (uintptr_t)off;
1420 return 0;
1421 }
1422 }
1423
1424 /* next */
1425 pMod = pMod->Load.pNext;
1426 }
1427
1428 return KLDR_ERR_MODULE_NOT_FOUND;
1429}
1430
1431
1432/**
1433 * Worker for kLdrDyldGetName().
1434 * @internal
1435 */
1436static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, size_t cchName)
1437{
1438 return kldrDyldModGetName(pMod, pszName, cchName);
1439}
1440
1441
1442/**
1443 * Worker for kLdrDyldGetFilename().
1444 * @internal
1445 */
1446static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename)
1447{
1448 return kldrDyldModGetFilename(pMod, pszFilename, cchFilename);
1449}
1450
1451
1452/**
1453 * Worker for kLdrDyldQuerySymbol().
1454 * @internal
1455 */
1456static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName, uintptr_t *pValue, uint32_t *pfKind)
1457{
1458 return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
1459}
1460
1461
1462/**
1463 * Panic / failure
1464 *
1465 * @returns rc if we're in a position where we can return.
1466 * @param rc Return code.
1467 * @param pszFormat Message string. Limited fprintf like formatted.
1468 * @param ... Message string arguments.
1469 */
1470int kldrDyldFailure(int rc, const char *pszFilename, ...)
1471{
1472 /** @todo print it. */
1473 if (g_fBootstrapping);
1474 kldrHlpExit(1);
1475 return rc;
1476}
1477
1478
1479/**
1480 * Copies the error string to the user buffer.
1481 *
1482 * @returns rc.
1483 * @param rc The status code.
1484 * @param pszErr Where to copy the error string to.
1485 * @param cchErr The size of the destination buffer.
1486 */
1487static int kldrDyldCopyError(int rc, char *pszErr, size_t cchErr)
1488{
1489 size_t cchToCopy;
1490
1491 /* if no error string, format the rc into a string. */
1492 if (!g_szkLdrDyldError[0] && rc)
1493 kldrHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10);
1494
1495 /* copy it if we got something. */
1496 if (cchErr && pszErr && g_szkLdrDyldError[0])
1497 {
1498 cchToCopy = kLdrHlpStrLen(g_szkLdrDyldError);
1499 if (cchToCopy >= cchErr)
1500 cchToCopy = cchErr - 1;
1501 kLdrHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy);
1502 pszErr[cchToCopy] = '\0';
1503 }
1504
1505 return rc;
1506}
1507
Note: See TracBrowser for help on using the repository browser.