source: trunk/kLdr/kLdrDyld.c@ 2837

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

in progress...

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