source: trunk/kLdr/kLdrDyld.c@ 2842

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

toplevel load api code is done.

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