source: trunk/kStuff/kLdr/kLdrDyld.c

Last change on this file was 3601, checked in by bird, 18 years ago

license update.

  • Property svn:keywords set to Id
File size: 48.8 KB
RevLine 
[2826]1/* $Id: kLdrDyld.c 3601 2007-10-29 00:21:13Z bird $ */
[2825]2/** @file
3 * kLdr - The Dynamic Loader.
[3601]4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
[2825]8 *
[3601]9 * This file is part of kStuff.
[2825]10 *
[3601]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.
[2825]15 *
[3601]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.
[2825]21 *
[3601]22 * kStuff is distributed in the hope that it will be useful,
[2825]23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[3601]24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
[2825]26 *
[3601]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
[2825]31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
[3570]36#include <k/kLdr.h>
[2825]37#include "kLdrInternal.h"
38
39
40/*******************************************************************************
[2836]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
[3573]51# define KLDRDYLD_ASSERT(expr) kHlpAssert(expr)
[2836]52#else
53# define KLDRDYLD_ASSERT(expr) do {} while (0)
54#endif
55
56
57/*******************************************************************************
[2842]58* Structures and Typedefs *
59*******************************************************************************/
60
61
62/*******************************************************************************
[2825]63* Global Variables *
64*******************************************************************************/
[2843]65/** Pointer to the executable module.
66 * (This is exported, so no prefix.) */
67PKLDRDYLDMOD kLdrDyldExe = NULL;
[2825]68/** Pointer to the head module (the executable).
69 * (This is exported, so no prefix.) */
[2833]70PKLDRDYLDMOD kLdrDyldHead = NULL;
[2825]71/** Pointer to the tail module.
72 * (This is exported, so no prefix.) */
[2833]73PKLDRDYLDMOD kLdrDyldTail = NULL;
[2842]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;
[2869]81/** Pointer to the tail module of the initalization list.*/
[2842]82PKLDRDYLDMOD g_pkLdrDyldInitTail;
[2869]83/** Pointer to the head module of the termination order list.
84 * This is a LIFO just like the the init list. */
[2836]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
[2843]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. */
[3567]102KU32 kLdrDyldFlags = 0;
[2843]103/** The default search method. */
[2875]104KLDRDYLDSEARCH kLdrDyldSearch = KLDRDYLD_SEARCH_HOST;
[2843]105
106
[2846]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. */
[3567]116KSIZE g_cbkLdrDyldMainStack = 0;
[2846]117/** @} */
118
119
[2843]120/** The load stack.
121 * This contains frames with modules affected by active loads.
[2836]122 *
[2843]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.
[2836]126 */
[2837]127static PPKLDRDYLDMOD g_papStackMods;
128/** The number of used entries in the g_papStackMods array. */
[3567]129static KU32 g_cStackMods;
[2837]130/** The number of entries allocated for the g_papStackMods array. */
[3567]131static KU32 g_cStackModsAllocated;
[2837]132/** Number of active load calls. */
[3567]133static KU32 g_cActiveLoadCalls;
[2837]134/** Number of active unload calls. */
[3567]135static KU32 g_cActiveUnloadCalls;
[2842]136/** Total number of load calls. */
[3567]137static KU32 g_cTotalLoadCalls;
[2842]138/** Total mumber of unload calls. */
[3567]139static KU32 g_cTotalUnloadCalls;
[2837]140/** Boolean flag indicating that GC is active. */
[3567]141static KU32 g_fActiveGC;
[2836]142
143
[2825]144
145/*******************************************************************************
146* Internal Functions *
147*******************************************************************************/
[2842]148/** @name API worker routines.
149 * @internal
150 * @{ */
[3567]151void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack);
[2843]152static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
[3567]153 unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr);
[2843]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,
[2842]157 KLDRDYLDSEARCH enmSearch, unsigned fFlags);
[2836]158static int kldrDyldDoUnload(PKLDRDYLDMOD pMod);
[2843]159static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
[2836]160 unsigned fFlags, PPKLDRDYLDMOD ppMod);
[3567]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);
[2842]165/** @} */
[2825]166
[2842]167/** @name Misc load/unload workers
168 * @internal
169 * @{
170 */
171static void kldrDyldDoModuleTerminationAndGarabageCollection(void);
172/** @} */
[2825]173
[2842]174/** @name The load stack.
175 * @internal
176 * @{ */
[3567]177static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pMod);
[2842]178static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod);
179static int kldrDyldStackFrameCompleted(void);
[2845]180static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc);
[3567]181static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc);
[2842]182/** @} */
[2833]183
[3567]184static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr);
[2837]185
186
187
[2825]188/**
[2833]189 * Initialize the dynamic loader.
[2825]190 */
[2869]191int kldrDyldInit(void)
[2825]192{
[2836]193 kLdrDyldHead = kLdrDyldTail = NULL;
194 g_pkLdrDyldTermHead = g_pkLdrDyldTermTail = NULL;
195 g_pkLdrDyldBindHead = g_pkLdrDyldBindTail = NULL;
[2833]196 kLdrDyldFlags = 0;
[2836]197 g_szkLdrDyldError[0] = '\0';
[2846]198
199 g_fkLdrDyldDoneMainStack = 0;
200 g_fkLdrDyldMainStackAllocated = 0;
201 g_pvkLdrDyldMainStack = NULL;
202 g_cbkLdrDyldMainStack = 0;
203
[2869]204 return kldrDyldFindInit();
[2825]205}
206
207
[2833]208/**
209 * Terminate the dynamic loader.
210 */
[2869]211void kldrDyldTerm(void)
[2833]212{
[2825]213
[2833]214}
215
216
217/**
[2843]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.
[2874]232 * @param pvOS OS specific argument.
[2843]233 */
[2875]234#ifndef __OS2__ /* kLdrDyldLoadExe is implemented in assembly on OS/2. */
235void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS)
[2874]236#else
[2875]237void kldrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS)
[2874]238#endif
[2843]239{
[2867]240 void *pvStack;
[3567]241 KSIZE cbStack;
[2867]242 PKLDRDYLDMOD pExe;
[2843]243 int rc;
244
245 /*
[2875]246 * Indicate that we're boostrapping and ensure that initialization was successful.
[2843]247 */
[2875]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))
[3579]260 kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad fFlags=%#x", pArgs->fFlags);
[2875]261 if ( pArgs->enmSearch <= KLDRDYLD_SEARCH_INVALID
262 || pArgs->enmSearch >= KLDRDYLD_SEARCH_END)
[3579]263 kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad enmSearch=%d", pArgs->enmSearch);
[2875]264
265 /*
266 * Set defaults.
267 */
268 kLdrDyldFlags |= (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT);
[2843]269 kLdrDyldSearch = pArgs->enmSearch;
[2875]270
271 /** @todo make sense of this default prefix/suffix stuff. */
[2867]272 if (pArgs->szDefPrefix[0] != '\0')
[3573]273 kHlpMemCopy(kLdrDyldDefPrefix, pArgs->szDefPrefix, K_MIN(sizeof(pArgs->szDefPrefix), sizeof(kLdrDyldDefPrefix)));
[2867]274 if (pArgs->szDefSuffix[0] != '\0')
[3573]275 kHlpMemCopy(kLdrDyldDefSuffix, pArgs->szDefSuffix, K_MIN(sizeof(pArgs->szDefSuffix), sizeof(kLdrDyldDefSuffix)));
[2843]276
[2875]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 */
[3573]280 cbStack = sizeof(kLdrDyldLibraryPath) - kHlpStrLen(kLdrDyldLibraryPath); /* borrow cbStack for a itty bit. */
281 kHlpMemCopy(kLdrDyldLibraryPath, pArgs->szLibPath, K_MIN(sizeof(pArgs->szLibPath), cbStack));
[2875]282 kLdrDyldLibraryPath[sizeof(kLdrDyldLibraryPath) - 1] = '\0';
[2843]283
284 /*
285 * Make sure we own the loader semaphore (necessary for init).
286 */
[3576]287 rc = kLdrDyldSemRequest();
[2843]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 */
[2875]294 rc = kldrDyldFindNewModule(pArgs->szExecutable, NULL, NULL, pArgs->enmSearch,
295 pArgs->fFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE, &pExe);
[2843]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 /*
[2846]305 * Query the stack and go to OS specific code to
[2843]306 * setup and switch stack. The OS specific code will call us
307 * back at kldrDyldDoLoadExe.
308 */
[2846]309 rc = kldrDyldModGetMainStack(pExe, &pvStack, &cbStack);
[2843]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/**
[2833]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.
[2843]322 * @param pszPrefix Prefix to use when searching.
323 * @param pszSuffix Suffix to use when searching.
[2833]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 */
[2843]330int kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
[3567]331 unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr)
[2833]332{
333 int rc;
334
335 /* validate arguments and initialize return values. */
336 if (pszErr && cchErr)
337 *pszErr = '\0';
338 *phMod = NIL_HKLDRMOD;
[3573]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);
[2833]344
345 /* get the semaphore and do the job. */
[3576]346 rc = kLdrDyldSemRequest();
[2833]347 if (!rc)
348 {
349 PKLDRDYLDMOD pMod = NULL;
[2842]350 g_cTotalLoadCalls++;
[2837]351 g_cActiveLoadCalls++;
[2869]352 rc = kldrDyldDoLoad(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod, pszErr, cchErr);
[2837]353 g_cActiveLoadCalls--;
354 kldrDyldDoModuleTerminationAndGarabageCollection();
[3576]355 kLdrDyldSemRelease();
[2870]356 *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
[2833]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 */
[3576]376 rc = kLdrDyldSemRequest();
[2833]377 if (!rc)
378 {
[2842]379 g_cTotalUnloadCalls++;
[2837]380 g_cActiveUnloadCalls++;
[2836]381 rc = kldrDyldDoUnload(hMod);
[2837]382 g_cActiveUnloadCalls--;
383 kldrDyldDoModuleTerminationAndGarabageCollection();
[3576]384 kLdrDyldSemRelease();
[2833]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.
[2837]397 * @returns KLDR_ERR_MODULE_NOT_FOUND or some I/O error on failure.
[2833]398 * @param pszDll The name of the dll to look for.
[2843]399 * @param pszPrefix Prefix than can be used when searching.
400 * @param pszSuffix Suffix than can be used when searching.
[2833]401 * @param enmSearch Method to use when locating the module.
[2836]402 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
[2833]403 * @param phMod Where to store the handle of the module on success.
404 */
[2843]405int kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
[2836]406 unsigned fFlags, PHKLDRMOD phMod)
[2833]407{
408 int rc;
409
410 /* validate & initialize */
411 *phMod = NIL_HKLDRMOD;
[3573]412 K_VALIDATE_STRING(pszDll);
[2833]413
414 /* get sem & do work */
[3576]415 rc = kLdrDyldSemRequest();
[2833]416 if (!rc)
417 {
418 PKLDRDYLDMOD pMod = NULL;
[2870]419 rc = kldrDyldDoFindByName(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
[3576]420 kLdrDyldSemRelease();
[2870]421 *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
[2833]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 */
[3567]440int kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment)
[2833]441{
442 int rc;
443
444 /* validate & initialize */
445 *phMod = NIL_HKLDRMOD;
446 if (piSegment)
[3567]447 *piSegment = ~(KU32)0;
[2833]448 if (poffSegment)
[3567]449 *poffSegment = ~(KUPTR)0;
[2833]450
451 /* get sem & do work */
[3576]452 rc = kLdrDyldSemRequest();
[2833]453 if (!rc)
454 {
455 PKLDRDYLDMOD pMod = NULL;
[2836]456 rc = kldrDyldDoFindByAddress(Address, &pMod, piSegment, poffSegment);
[3576]457 kLdrDyldSemRelease();
[2870]458 *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
[2833]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.
[3579]468 * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure.
[2833]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 */
[3567]474int kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName)
[2833]475{
476 int rc;
477
478 /* validate */
479 if (pszName && cchName)
480 *pszName = '\0';
481 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
[3573]482 K_VALIDATE_BUFFER(pszName, cchName);
[2833]483
484 /* get sem & do work */
[3576]485 rc = kLdrDyldSemRequest();
[2833]486 if (!rc)
487 {
[2836]488 rc = kldrDyldDoGetName(hMod, pszName, cchName);
[3576]489 kLdrDyldSemRelease();
[2833]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.
[3579]499 * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure.
[2833]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 */
[3567]505int kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename)
[2833]506{
507 int rc;
508
509 /* validate & initialize */
510 if (pszFilename && cchFilename);
511 *pszFilename = '\0';
512 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
[3573]513 K_VALIDATE_BUFFER(pszFilename, cchFilename);
[2833]514
515 /* get sem & do work */
[3576]516 rc = kLdrDyldSemRequest();
[2833]517 if (!rc)
518 {
[2836]519 rc = kldrDyldDoGetFilename(hMod, pszFilename, cchFilename);
[3576]520 kLdrDyldSemRelease();
[2833]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.
[3579]530 * @returns KERR_INVALID_HANDLE or KLDR_ERR_SYMBOL_NOT_FOUND on failure.
[2893]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.
[2833]537 */
[3567]538int kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName,
539 const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind)
[2833]540{
541 int rc;
542
543 /* validate & initialize */
544 if (pfKind)
545 *pfKind = 0;
546 if (pValue)
547 *pValue = 0;
548 if (!pfKind && !pValue)
[3579]549 return KERR_INVALID_PARAMETER;
[2833]550 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
[3573]551 K_VALIDATE_OPTIONAL_STRING(pszSymbolName);
[2833]552
553 /* get sem & do work */
[3576]554 rc = kLdrDyldSemRequest();
[2833]555 if (!rc)
556 {
[2836]557 rc = kldrDyldDoQuerySymbol(hMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
[3576]558 kLdrDyldSemRelease();
[2833]559 }
560 return rc;
561}
562
563
[2843]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;
[2833]574
[2843]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
[2837]593/**
[2842]594 * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe().
595 * @internal
[2837]596 */
[2843]597static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
[3567]598 unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr)
[2837]599{
600 int rc;
[2833]601
[2837]602 /*
603 * Try find the module among the ones that's already loaded.
604 */
[2843]605 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
[2837]606 if (!rc)
607 {
608 switch ((*ppMod)->enmState)
609 {
610 /*
[2842]611 * Prerequisites are ok, so nothing to do really.
[2837]612 */
613 case KLDRSTATE_GOOD:
614 case KLDRSTATE_INITIALIZING:
[2842]615 return kldrDyldModDynamicLoad(*ppMod);
[2837]616
617 /*
[2842]618 * The module can't be loaded because it failed to initialize.
[2837]619 */
[2842]620 case KLDRSTATE_INITIALIZATION_FAILED:
621 return KLDR_ERR_MODULE_INIT_FAILED_ALREADY;
[2837]622
623 /*
[2842]624 * Prerequisites needs loading / reattaching and the module
625 * (may depending on fFlags) needs to be initialized.
[2837]626 */
[2842]627 case KLDRSTATE_PENDING_INITIALIZATION:
[2837]628 break;
629
630 /*
[2842]631 * Prerequisites needs to be loaded again
[2837]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;
[2836]659 }
660 }
[2837]661 else
662 {
663 /*
664 * We'll have to load it from file.
665 */
[2843]666 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
[2837]667 if (rc)
668 return kldrDyldCopyError(rc, pszErr, cchErr);
669 rc = kldrDyldModMap(*ppMod);
670 }
[2833]671
[2843]672 /*
673 * Join cause with kLdrDyldLoadExe.
674 */
[2836]675 if (!rc)
[2843]676 rc = kldrDyldDoLoad2(*ppMod, pszPrefix, pszSuffix, enmSearch, fFlags);
677 else
[2845]678 kldrDyldStackCleanupOne(*ppMod, rc);
[2833]679
[2843]680 /*
681 * Copy any error or warning to the error buffer.
682 */
683 return kldrDyldCopyError(rc, pszErr, cchErr);
684}
[2837]685
[2843]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 */
[3567]698 KU32 i;
699 KU32 iLoad1st = kldrDyldStackNewFrame(pLoadedMod);
[2843]700 int rc = kldrDyldDoLoadPrerequisites(pLoadedMod, pszPrefix, pszSuffix, enmSearch, fFlags);
[3567]701 KU32 iLoadEnd = kldrDyldStackFrameCompleted();
[2845]702 if (rc)
[2887]703 {
704 kldrDyldModAddRef(pLoadedMod);
[2845]705 kldrDyldStackCleanupOne(pLoadedMod, rc); /* in case it didn't get pushed onto the stack. */
[2887]706 kldrDyldModDeref(pLoadedMod);
707 }
[2843]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 {
[2842]739 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
740 {
741 PKLDRDYLDMOD pMod = g_papStackMods[i];
[2843]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);
[2837]748 }
[2842]749#ifdef KLDRDYLD_STRICT
[2843]750 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
751 KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
[2842]752#endif
[2843]753 }
754 else if (g_cActiveLoadCalls <= 1)
755 {
756 while (!rc && g_pkLdrDyldInitHead)
[2842]757 {
[2843]758 PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead;
759 g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
760 if (pMod->InitTerm.pNext)
761 pMod->InitTerm.pNext->InitTerm.pPrev = NULL;
[2871]762 else
763 g_pkLdrDyldInitTail = NULL;
764 pMod->fInitList = 0;
[2843]765 rc = kldrDyldModCallInit(pMod);
[2837]766 }
[2843]767 }
[2837]768
[2843]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)
[2837]774 {
[2843]775 if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)
[2875]776 {
777 pLoadedMod->cDepRefs++; /* just make it stick. */
778 pLoadedMod->cRefs++;
779 }
[2843]780 else
781 rc = kldrDyldModDynamicLoad(pLoadedMod);
[2837]782 }
783
[2843]784 kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc);
785 return rc;
[2833]786}
787
788
789/**
[2842]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.
[2847]795 * @param pszPrefix Prefix to use when searching.
796 * @param pszSuffix Suffix to use when searching.
[2842]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.
[2833]799 */
[2843]800static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
[2842]801 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
[2833]802{
[2842]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;
[2833]813
[2868]814 /* Prerequisites are always global and they just aren't executables. */
815 fFlags &= ~(KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
816
[2842]817 /* push the first entry. */
818 s_aEntries[0].pMod = pMod;
819 s_aEntries[0].cLeft = ~0U;
820 cEntries = 1;
[2833]821
[2842]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:
[2843]843 rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags);
[2842]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;
[2833]851
[2842]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;
[2833]861
[2842]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)
[2836]881 {
[2842]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]))
[2836]887 {
[3567]888 s_aEntries[cEntries].cLeft = ~(KU32)0;
[2869]889 s_aEntries[cEntries].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft];
[2842]890 s_aEntries[i].cLeft--;
[2869]891 cEntries++;
[2836]892 }
[2842]893 else
894 rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY;
[2836]895 }
[2842]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 }
[2836]919 }
920
[2842]921 return rc;
[2833]922}
923
924
925/**
[2842]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.
[2843]933 * @param pszPrefix Prefix than can be used when searching.
934 * @param pszSuffix Suffix than can be used when searching.
[2842]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.
[2833]939 */
[2843]940int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
[2842]941 unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod)
[2833]942{
[2842]943 int rc;
944 PKLDRDYLDMOD pMod;
[2833]945
[2842]946 *ppMod = NULL;
[2833]947
[2825]948 /*
[2842]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.
[2825]954 */
[2843]955 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
[2842]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;
[2825]972
[2842]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;
[2825]980
[2842]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;
[2825]987
[2842]988 /*
989 * Forget it, no idea how to deal with re-initialization.
990 */
991 case KLDRSTATE_TERMINATING:
992 return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING;
[2825]993
[2842]994 /*
995 * Invalid state.
996 */
997 default:
998 KLDRDYLD_ASSERT(!"invalid state");
999 break;
[2825]1000 }
[2842]1001 }
1002 else
[2825]1003 {
[2842]1004 /*
1005 * We'll have to load it from file.
1006 */
[2869]1007 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
[2842]1008 if (!rc)
1009 rc = kldrDyldModMap(pMod);
[2825]1010 }
1011
1012 /*
[2842]1013 * On success add dependency.
[2825]1014 */
[2842]1015 if (!rc)
[2825]1016 {
[2845]1017 kldrDyldModAddDep(pMod, pDep);
1018 *ppMod = pMod;
[2825]1019 }
[2842]1020 return rc;
[2825]1021}
1022
1023
1024/**
[2842]1025 * Starts a new load stack frame.
[2837]1026 *
[2842]1027 * @returns Where the new stack frame starts.
1028 * @param pLoadMod The module being loaded (only used for asserting).
[2837]1029 */
[3567]1030static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod)
[2837]1031{
1032 /*
[2842]1033 * Clear the fAlreadySeen flags.
[2837]1034 */
[2842]1035 PKLDRDYLDMOD pMod = kLdrDyldHead;
1036 while (pMod)
[2837]1037 {
[2842]1038 pMod->fAlreadySeen = 0;
[2837]1039
[2842]1040#ifdef KLDRDYLD_ASSERT
[2837]1041 switch (pMod->enmState)
1042 {
[2842]1043 case KLDRSTATE_MAPPED:
1044 case KLDRSTATE_RELOADED:
1045 /* only the just loaded module can be in this state. */
1046 KLDRDYLD_ASSERT(pMod == pLoadMod);
[2837]1047 break;
1048
1049 case KLDRSTATE_PENDING_INITIALIZATION:
[2842]1050 case KLDRSTATE_INITIALIZING:
[2837]1051 case KLDRSTATE_PENDING_TERMINATION:
1052 case KLDRSTATE_PENDING_GC:
[2842]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);
[2837]1058 break;
1059
1060 case KLDRSTATE_GOOD:
[2842]1061 /* requires nothing. */
[2837]1062 break;
1063
1064 default:
[2842]1065 KLDRDYLD_ASSERT(!"Invalid state");
[2837]1066 break;
1067 }
[2842]1068#endif
[2837]1069
1070 /* next */
[2836]1071 pMod = pMod->Load.pNext;
1072 }
[2837]1073 return g_cStackMods;
[2836]1074}
1075
1076
1077/**
[2837]1078 * Records the module.
[2836]1079 *
[3579]1080 * @return 0 on success, KERR_NO_MEMORY if we can't expand the table.
[2836]1081 * @param pMod The module to record.
1082 */
[2842]1083static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod)
[2836]1084{
[2837]1085 /*
1086 * Grow the stack if necessary.
1087 */
1088 if (g_cStackMods + 1 > g_cStackModsAllocated)
1089 {
[3567]1090 KU32 cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
[2837]1091 void *pvOld = g_papStackMods;
[3573]1092 void *pvNew = kHlpAlloc(cNew * sizeof(g_papStackMods[0]));
[2837]1093 if (!pvNew)
[3579]1094 return KERR_NO_MEMORY;
[3573]1095 kHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
[2837]1096 g_papStackMods = (PPKLDRDYLDMOD)pvNew;
[3573]1097 kHlpFree(pvOld);
[2837]1098 }
1099
1100 /*
1101 * Add a reference and push the module onto the stack.
1102 */
[2845]1103 kldrDyldModAddRef(pMod);
1104 g_papStackMods[g_cStackMods++] = pMod;
1105 return 0;
[2836]1106}
1107
1108
[2837]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}
[2836]1118
[2837]1119
[2836]1120/**
[2845]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/**
[2842]1199 * Done with the stack frame, dereference all the modules in it.
[2836]1200 *
[2842]1201 * @param iLoad1st The start of the stack frame.
1202 * @param iLoadEnd The end of the stack frame.
[2837]1203 * @param rc Used for state verification.
[2836]1204 */
[3567]1205static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc)
[2836]1206{
[3567]1207 KU32 i;
[2869]1208 KLDRDYLD_ASSERT(iLoad1st <= g_cStackMods);
1209 KLDRDYLD_ASSERT(iLoadEnd == g_cStackMods);
[2836]1210
[2837]1211 /*
[2842]1212 * First pass: Do all the cleanups we can, but don't destroy anything just yet.
[2837]1213 */
[2869]1214 i = iLoadEnd;
1215 while (i-- > iLoad1st)
[2837]1216 {
[2869]1217 PKLDRDYLDMOD pMod = g_papStackMods[i];
[2845]1218 kldrDyldStackCleanupOne(pMod, rc);
[2837]1219 }
1220
1221 /*
[2842]1222 * Second pass: Release the references so modules pending destruction
1223 * can be completely removed.
[2837]1224 */
[2869]1225 for (i = iLoad1st; i < iLoadEnd ; i++)
[2837]1226 {
[2869]1227 PKLDRDYLDMOD pMod = g_papStackMods[i];
[2837]1228
1229 /*
[2842]1230 * Revalidate the module state.
[2837]1231 */
1232 switch (pMod->enmState)
1233 {
1234 case KLDRSTATE_INITIALIZING:
1235 case KLDRSTATE_TERMINATING:
[2842]1236 case KLDRSTATE_PENDING_TERMINATION:
[2837]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 }
[2869]1252
1253 /*
1254 * Drop the stack frame.
1255 */
1256 g_cStackMods = iLoad1st;
[2836]1257}
1258
1259
1260/**
[2842]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 */
[2866]1284 for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
[2842]1285 {
1286 kldrDyldModAddRef(pMod);
1287
1288 switch (pMod->enmState)
1289 {
1290 case KLDRSTATE_GOOD:
1291 case KLDRSTATE_PENDING_GC:
[2869]1292 case KLDRSTATE_PENDING_TERMINATION:
[2842]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 {
[3567]1324 const KU32 cTotalLoadCalls = g_cTotalLoadCalls;
1325 const KU32 cTotalUnloadCalls = g_cTotalUnloadCalls;
[2842]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;
[2845]1350 kldrDyldModAddRef(pMod);
1351
[2842]1352 switch (pMod->enmState)
1353 {
1354 case KLDRSTATE_INITIALIZATION_FAILED:
1355 case KLDRSTATE_PENDING_GC:
[2869]1356 KLDRDYLD_ASSERT(!pMod->cDepRefs);
1357 KLDRDYLD_ASSERT(!pMod->cDynRefs);
[2842]1358 pMod->enmState = KLDRSTATE_GC;
1359 kldrDyldModUnmap(pMod);
[2845]1360 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
[2842]1361 kldrDyldModDestroy(pMod);
[2845]1362 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED);
[2842]1363 break;
1364
1365 case KLDRSTATE_GOOD:
1366 break;
1367 default:
1368 KLDRDYLD_ASSERT(!"invalid GC state (c)");
1369 break;
1370 }
1371
[2845]1372 kldrDyldModDeref(pMod);
1373
[2842]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 */
[2843]1396static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
[2842]1397 unsigned fFlags, PPKLDRDYLDMOD ppMod)
1398{
[2843]1399 return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
[2842]1400}
1401
1402
1403/**
1404 * Worker for kLdrDyldFindByAddress().
1405 * @internal
1406 */
[3567]1407static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment)
[2842]1408{
1409 /* Scan the segments of each module in the load list. */
1410 PKLDRDYLDMOD pMod = kLdrDyldHead;
1411 while (pMod)
1412 {
[3567]1413 KU32 iSeg;
[2842]1414 for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++)
1415 {
[2848]1416 KLDRADDR off = (KLDRADDR)Address - pMod->pMod->aSegments[iSeg].MapAddress;
[2842]1417 if (off < pMod->pMod->aSegments[iSeg].cb)
1418 {
1419 *ppMod = pMod->hMod;
1420 if (piSegment)
1421 *piSegment = iSeg;
1422 if (poffSegment)
[3567]1423 *poffSegment = (KUPTR)off;
[2842]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 */
[3567]1440static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName)
[2842]1441{
1442 return kldrDyldModGetName(pMod, pszName, cchName);
1443}
1444
1445
1446/**
1447 * Worker for kLdrDyldGetFilename().
1448 * @internal
1449 */
[3567]1450static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename)
[2842]1451{
1452 return kldrDyldModGetFilename(pMod, pszFilename, cchFilename);
1453}
1454
1455
1456/**
1457 * Worker for kLdrDyldQuerySymbol().
1458 * @internal
1459 */
[3567]1460static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind)
[2842]1461{
1462 return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
1463}
1464
1465
1466/**
[2825]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 */
[2843]1474int kldrDyldFailure(int rc, const char *pszFilename, ...)
[2825]1475{
[2869]1476 /** @todo print it. */
1477 if (g_fBootstrapping);
[3573]1478 kHlpExit(1);
[2825]1479 return rc;
1480}
1481
1482
[2836]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 */
[3567]1491static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr)
[2836]1492{
[3567]1493 KSIZE cchToCopy;
[2836]1494
1495 /* if no error string, format the rc into a string. */
1496 if (!g_szkLdrDyldError[0] && rc)
[3573]1497 kHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10);
[2836]1498
1499 /* copy it if we got something. */
1500 if (cchErr && pszErr && g_szkLdrDyldError[0])
1501 {
[3573]1502 cchToCopy = kHlpStrLen(g_szkLdrDyldError);
[2836]1503 if (cchToCopy >= cchErr)
1504 cchToCopy = cchErr - 1;
[3573]1505 kHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy);
[2836]1506 pszErr[cchToCopy] = '\0';
1507 }
1508
1509 return rc;
1510}
1511
Note: See TracBrowser for help on using the repository browser.