VirtualBox

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

Last change on this file since 5 was 2, checked in by bird, 17 years ago

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

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

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