source: trunk/kLdr/kLdrDyld.c@ 2875

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

Got the stub loader working (but without stack allocation/switching).

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