VirtualBox

source: kStuff/trunk/kLdr/kLdrDyld.c@ 89

Last change on this file since 89 was 29, checked in by bird, 16 years ago

Finally got around execute the switch to the MIT license.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette