source: trunk/kLdr/kLdrDyldMod.c@ 2856

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

More code.

File size: 35.1 KB
Line 
1/* $Id: $ */
2/** @file
3 *
4 * kLdr - The Dynamic Loader, Dyld module methods.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@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/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#include <kLdr.h>
33#include "kLdrInternal.h"
34#include "kLdrHlp.h"
35
36
37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** @def KLDRDYLDMOD_STRICT
41 * Define KLDRDYLDMOD_STRICT to enabled strict checks in kLdrDyld. */
42#define KLDRDYLDMOD_STRICT 1
43
44/** @def KLDRDYLDMOD_ASSERT
45 * Assert that an expression is true when KLDRDYLD_STRICT is defined.
46 */
47#ifdef KLDRDYLDMOD_STRICT
48# define KLDRDYLDMOD_ASSERT(expr) kldrHlpAssert(expr)
49#else
50# define KLDRDYLDMOD_ASSERT(expr) do {} while (0)
51#endif
52
53/*******************************************************************************
54* Internal Functions *
55*******************************************************************************/
56static void kldrDyldModUnlink(PKLDRDYLDMOD pMod);
57
58
59
60/**
61 * Creates a module from the specified file provider instance.
62 *
63 * @returns 0 on success and *ppMod pointing to the new instance.
64 * On failure a non-zero kLdr status code is returned.
65 * @param pRdr The file provider instance.
66 * @param ppMod Where to put the pointer to the new module on success.
67 */
68int kldrDyldModCreate(PKLDRRDR pRdr, PPKLDRDYLDMOD ppMod)
69{
70 PKLDRDYLDMOD pMod;
71 PKLDRMOD pRawMod;
72 int rc;
73
74 *ppMod = NULL;
75
76 /*
77 * Try open an module interpreter.
78 */
79 rc = kLdrModOpenFromRdr(pRdr, &pRawMod);
80 if (rc)
81 return kldrDyldFailure(rc, "%s: %rc", kLdrRdrName(pRdr), rc);
82
83 /*
84 * Allocate a new dyld module.
85 */
86 pMod = (PKLDRDYLDMOD)kldrHlpAlloc(sizeof(*pMod));
87 if (pMod)
88 {
89 pMod->enmState = KLDRSTATE_OPEN;
90 pMod->pMod = pRawMod;
91 pMod->hMod = pMod;
92 pMod->cDepRefs = pMod->cDynRefs = pMod->cRefs = 0;
93 pMod->fExecutable = 0;
94 switch (pRawMod->enmType)
95 {
96 case KLDRTYPE_EXECUTABLE_FIXED:
97 case KLDRTYPE_EXECUTABLE_RELOCATABLE:
98 case KLDRTYPE_EXECUTABLE_PIC:
99 pMod->fExecutable = 1;
100 break;
101 }
102 pMod->fGlobalOrSpecific = 0;
103 pMod->fBindable = 0;
104 pMod->fInitList = 0;
105 pMod->fAlreadySeen = 0;
106 pMod->fMapped = 0;
107 pMod->fAllocatedTLS = 0;
108 pMod->f25Reserved = 0;
109 pMod->InitTerm.pNext = NULL;
110 pMod->InitTerm.pPrev = NULL;
111 pMod->Bind.pNext = NULL;
112 pMod->Bind.pPrev = NULL;
113 pMod->cPrereqs = 0;
114 pMod->papPrereqs = NULL;
115 pMod->u32MagicHead = KLDRDYMOD_MAGIC;
116 pMod->u32MagicTail = KLDRDYMOD_MAGIC;
117
118 /* it. */
119 pMod->Load.pNext = NULL;
120 pMod->Load.pPrev = kLdrDyldTail;
121 if (kLdrDyldTail)
122 kLdrDyldTail->Load.pNext = pMod;
123 else
124 kLdrDyldHead = pMod;
125 kLdrDyldTail = pMod;
126
127 /* we're good. */
128 *ppMod = pMod;
129 rc = 0;
130 }
131 else
132 {
133 kLdrModClose(pRawMod);
134 rc = KLDR_ERR_NO_MEMORY;
135 }
136 return rc;
137}
138
139
140/**
141 * Creates a module for a native module.
142 *
143 * @returns 0 on success and *ppMod pointing to the new instance.
144 * On failure a non-zero kLdr status code is returned.
145 * @param hNativeModule The native handle.
146 * @param ppMod Where to put the pointer to the new module on success.
147 * @remark This function ain't finalized yet.
148 */
149int kldrDyldModCreateNative(uintptr_t hNativeModule)
150{
151#if 0
152 /*
153 * Check if this module is already loaded by the native OS loader.
154 */
155 rc = kld
156 {
157#ifdef __OS2__
158 HMODULE hmod = NULLHANDLE;
159 APIRET rc = DosQueryModuleHandle(kLdrRdrName(pRdr), &hmod);
160 if (!rc)
161
162#elif defined(__WIN__)
163 HMODULE hmod = NULL;
164 if (GetModuleHandle(kLdrRdrName(pRdr))
165
166#else
167# error "Port me"
168#endif
169 }
170#endif
171 return -1;
172}
173
174
175/**
176 * Destroys a module pending destruction.
177 *
178 * @param pMod The module in question.
179 */
180void kldrDyldModDestroy(PKLDRDYLDMOD pMod)
181{
182 int rc;
183
184 /*
185 * Validate the state.
186 */
187 switch (pMod->enmState)
188 {
189 case KLDRSTATE_PENDING_DESTROY:
190 case KLDRSTATE_GC:
191 break;
192 default:
193 KLDRDYLDMOD_ASSERT(!"Invalid state");
194 break;
195 }
196 KLDRDYLDMOD_ASSERT(!pMod->fInitList);
197 KLDRDYLDMOD_ASSERT(!pMod->cDynRefs);
198 KLDRDYLDMOD_ASSERT(!pMod->cDepRefs);
199
200 /*
201 * Ensure that the module is unmapped.
202 */
203 if (pMod->fAllocatedTLS)
204 {
205 kLdrModFreeTLS(pMod->pMod);
206 pMod->fAllocatedTLS = 0;
207 }
208 if (pMod->fMapped)
209 {
210 rc = kLdrModUnmap(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc);
211 pMod->fMapped = 0;
212 }
213
214 /*
215 * Ensure it's unlinked from all chains.
216 */
217 if (pMod->enmState < KLDRSTATE_PENDING_DESTROY)
218 kldrDyldModUnlink(pMod);
219
220 /*
221 * Free everything associated with the module.
222 */
223 /* the prerequisite array. */
224 if (pMod->papPrereqs)
225 {
226 uint32_t i = pMod->cPrereqs;
227 while (i-- > 0)
228 {
229 KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL);
230 pMod->papPrereqs[i] = NULL;
231 }
232
233 kldrHlpFree(pMod->papPrereqs);
234 pMod->papPrereqs = NULL;
235 pMod->cPrereqs = 0;
236 }
237
238 /* the module interpreter. */
239 if (pMod->pMod)
240 {
241 rc = kLdrModClose(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc);
242 pMod->pMod = NULL;
243 }
244
245
246 /*
247 * Finally, change the module state and free the module if
248 * there are not more references to it. If somebody is still
249 * referencing it, postpone the freeing to Deref.
250 */
251 pMod->enmState = KLDRSTATE_DESTROYED;
252 if (!pMod->cRefs)
253 {
254 pMod->u32MagicHead = 1;
255 pMod->u32MagicTail = 2;
256 kldrHlpFree(pMod);
257 }
258}
259
260
261/**
262 * Unlinks the module from any list it might be in.
263 * It is assumed that the module is at least linked into the load list.
264 *
265 * @param pMod The moduel.
266 */
267static void kldrDyldModUnlink(PKLDRDYLDMOD pMod)
268{
269 /* load list */
270 if (pMod->Load.pNext)
271 pMod->Load.pNext->Load.pPrev = pMod->Load.pPrev;
272 else
273 kLdrDyldTail = pMod->Load.pPrev;
274 if (pMod->Load.pPrev)
275 pMod->Load.pPrev->Load.pNext = pMod->Load.pNext;
276 else
277 kLdrDyldHead = pMod->Load.pNext;
278
279 /* bind list */
280 if (pMod->fBindable)
281 kldrDyldModClearBindable(pMod);
282
283 /* init term */
284 if (pMod->fInitList)
285 {
286 KLDRDYLDMOD_ASSERT(pMod->enmState < KLDRSTATE_INITIALIZATION_FAILED);
287 pMod->fInitList = 0;
288 if (pMod->InitTerm.pNext)
289 pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev;
290 else
291 g_pkLdrDyldInitTail = pMod->InitTerm.pPrev;
292 if (pMod->InitTerm.pPrev)
293 pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext;
294 else
295 g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
296 }
297 else if (pMod->enmState > KLDRSTATE_INITIALIZATION_FAILED)
298 {
299 KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_GOOD);
300 if (pMod->InitTerm.pNext)
301 pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev;
302 else
303 g_pkLdrDyldTermTail = pMod->InitTerm.pPrev;
304 if (pMod->InitTerm.pPrev)
305 pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext;
306 else
307 g_pkLdrDyldTermHead = pMod->InitTerm.pNext;
308 }
309 pMod->InitTerm.pNext = NULL;
310 pMod->InitTerm.pPrev = NULL;
311}
312
313
314/**
315 * Marks a module as bindable, i.e. it'll be considered when
316 * resolving names the unix way.
317 *
318 * @param pMod The module.
319 * @param fDeep When set the module will be inserted at the head of the
320 * module list used to resolve symbols. This means that the
321 * symbols in this module will be prefered of all the other
322 * modules.
323 */
324void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep)
325{
326 KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_GC);
327 if (!pMod->fBindable)
328 {
329 pMod->fBindable = 1;
330 if (!fDeep)
331 {
332 pMod->Bind.pNext = NULL;
333 pMod->Bind.pPrev = g_pkLdrDyldBindTail;
334 if (g_pkLdrDyldBindTail)
335 g_pkLdrDyldBindTail->Bind.pNext = pMod;
336 else
337 g_pkLdrDyldBindHead = pMod;
338 g_pkLdrDyldBindTail = pMod;
339 }
340 else
341 {
342 pMod->Bind.pPrev = NULL;
343 pMod->Bind.pNext = g_pkLdrDyldBindHead;
344 if (g_pkLdrDyldBindHead)
345 g_pkLdrDyldBindHead->Bind.pPrev = pMod;
346 else
347 g_pkLdrDyldBindTail = pMod;
348 g_pkLdrDyldBindHead = pMod;
349 }
350 }
351}
352
353
354/**
355 * Marks a module as not bindable, i.e. it will not be considered when
356 * resolving names the unix way.
357 *
358 * @param pMod The module.
359 */
360void kldrDyldModClearBindable(PKLDRDYLDMOD pMod)
361{
362 KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_DESTROY);
363 if (pMod->fBindable)
364 {
365 pMod->fBindable = 0;
366 if (pMod->Bind.pPrev)
367 pMod->Bind.pPrev->Bind.pNext = pMod->Bind.pNext;
368 else
369 g_pkLdrDyldBindHead = pMod->Bind.pNext;
370 if (pMod->Bind.pNext)
371 pMod->Bind.pNext->Bind.pPrev = pMod->Bind.pPrev;
372 else
373 g_pkLdrDyldBindTail = pMod->Bind.pPrev;
374 pMod->Bind.pNext = NULL;
375 pMod->Bind.pPrev = NULL;
376 }
377}
378
379
380/**
381 * Marks the module as global instead of being specific.
382 *
383 * A global module can be a matching result when the request
384 * doesn't specify a path. A specific module will not match
385 * unless the path also matches.
386 *
387 * @param pMod The module.
388 */
389void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod)
390{
391 pMod->fGlobalOrSpecific = 1;
392}
393
394
395/**
396 * Marks the module as specific instead of global.
397 *
398 * See kldrDyldModMarkGlobal for an explanation of the two terms.
399 *
400 * @param pMod The module.
401 */
402void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod)
403{
404 pMod->fGlobalOrSpecific = 0;
405}
406
407
408/**
409 * Adds a reference to the module making sure it won't be freed just yet.
410 *
411 * @param pMod The module.
412 */
413void kldrDyldModAddRef(PKLDRDYLDMOD pMod)
414{
415 pMod->cRefs++;
416}
417
418
419/**
420 * Dereference a module.
421 *
422 * @param pMod
423 */
424void kldrDyldModDeref(PKLDRDYLDMOD pMod)
425{
426 /* validate input */
427 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
428 KLDRDYLDMOD_ASSERT(pMod->cRefs >= pMod->cDepRefs + pMod->cDynRefs);
429 KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END);
430
431 /* decrement. */
432 if (pMod->cRefs > 0)
433 pMod->cRefs--;
434
435 /* execute delayed freeing. */
436 if ( pMod->enmState == KLDRSTATE_DESTROYED
437 && !pMod->cRefs)
438 {
439 pMod->u32MagicHead = 1;
440 pMod->u32MagicTail = 2;
441 kldrHlpFree(pMod);
442 }
443}
444
445
446/**
447 * Increment the count of modules depending on this module.
448 *
449 * @param pMod The module.
450 * @param pDep The module which depends on us.
451 */
452void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep)
453{
454 (void)pDep;
455
456 /* validate state */
457 switch (pMod->enmState)
458 {
459 case KLDRSTATE_MAPPED:
460 case KLDRSTATE_RELOADED:
461 case KLDRSTATE_LOADED_PREREQUISITES:
462 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
463 case KLDRSTATE_PENDING_INITIALIZATION:
464 case KLDRSTATE_INITIALIZING:
465 case KLDRSTATE_GOOD:
466 break;
467 default:
468 KLDRDYLDMOD_ASSERT(!"invalid state");
469 break;
470
471 }
472 KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END);
473 pMod->cRefs++;
474 pMod->cDepRefs++;
475}
476
477
478/**
479 * Drop a dependency.
480 *
481 * @param pMod The module.
482 * @param pDep The module which depends on us.
483 */
484void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep)
485{
486 KLDRDYLDMOD_ASSERT(pMod->cDepRefs > 0);
487 if (pMod->cDepRefs == 0)
488 return;
489 KLDRDYLDMOD_ASSERT(pMod->cDepRefs <= pMod->cRefs);
490 KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_MAPPED && pMod->enmState <= KLDRSTATE_PENDING_DESTROY);
491
492 pMod->cRefs--;
493 pMod->cDepRefs--;
494 if ( pMod->cDepRefs > 0
495 || pMod->cDynRefs > 0)
496 return;
497
498 /*
499 * The module should be unloaded.
500 */
501 kldrDyldModUnloadPrerequisites(pMod);
502}
503
504
505/**
506 * Increment the dynamic load count.
507 *
508 * @returns 0
509 * @param pMod The module.
510 */
511int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod)
512{
513 KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_GOOD
514 || pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION
515 || pMod->enmState == KLDRSTATE_INITIALIZING);
516 pMod->cRefs++;
517 pMod->cDynRefs++;
518 return 0;
519}
520
521
522/**
523 * Decrement the dynamic load count of the module and unload the module
524 * if the total reference count reaches zero.
525 *
526 * This may cause a cascade of unloading to occure. See kldrDyldModUnloadPrerequisites().
527 *
528 * @returns status code.
529 * @retval 0 on success.
530 * @retval KLDR_ERR_NOT_LOADED_DYNAMICALLY if the module wasn't loaded dynamically.
531 * @param pMod The module to unload.
532 */
533int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod)
534{
535 if (pMod->cDynRefs == 0)
536 return KLDR_ERR_NOT_LOADED_DYNAMICALLY;
537 KLDRDYLDMOD_ASSERT(pMod->cDynRefs <= pMod->cRefs);
538 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
539
540 pMod->cRefs--;
541 pMod->cDynRefs--;
542 if ( pMod->cDynRefs > 0
543 || pMod->cDepRefs > 0)
544 return 0;
545
546 /*
547 * The module should be unloaded.
548 */
549 kldrDyldModUnloadPrerequisites(pMod);
550 return 0;
551}
552
553
554/**
555 * Worker for kldrDyldModUnloadPrerequisites.
556 *
557 * @returns The number of modules that now can be unloaded.
558 * @param pMod The module in question.
559 */
560static uint32_t kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod)
561{
562 PKLDRDYLDMOD pMod2;
563 uint32_t cToUnload = 0;
564 uint32_t i;
565
566 KLDRDYLDMOD_ASSERT(pMod->papPrereqs);
567
568 /*
569 * Release the one in this module.
570 */
571 for (i = 0; i < pMod->cPrereqs; i++)
572 {
573 pMod2 = pMod->papPrereqs[i];
574 if (pMod2)
575 {
576 pMod->papPrereqs[i] = NULL;
577
578 /* do the derefering ourselves or we'll end up in a recursive loop here. */
579 KLDRDYLDMOD_ASSERT(pMod2->cDepRefs > 0);
580 KLDRDYLDMOD_ASSERT(pMod2->cRefs >= pMod2->cDepRefs);
581 pMod2->cDepRefs--;
582 pMod2->cRefs--;
583 cToUnload += !pMod2->cRefs;
584 }
585 }
586
587 /*
588 * Change the state
589 */
590 switch (pMod->enmState)
591 {
592 case KLDRSTATE_LOADED_PREREQUISITES:
593 case KLDRSTATE_FIXED_UP:
594 pMod->enmState = KLDRSTATE_PENDING_DESTROY;
595 kldrDyldModUnlink(pMod);
596 break;
597
598 case KLDRSTATE_PENDING_INITIALIZATION:
599 pMod->enmState = KLDRSTATE_PENDING_GC;
600 break;
601
602 case KLDRSTATE_RELOADED_FIXED_UP:
603 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
604 case KLDRSTATE_GOOD:
605 pMod->enmState = KLDRSTATE_PENDING_TERMINATION;
606 break;
607
608 case KLDRSTATE_INITIALIZATION_FAILED:
609 break;
610
611 default:
612 KLDRDYLDMOD_ASSERT(!"invalid state");
613 break;
614 }
615
616 return cToUnload;
617}
618
619
620/**
621 * This is the heart of the unload code.
622 *
623 * It will recursivly (using the load list) initiate module unloading
624 * of all affected modules.
625 *
626 * This function will cause a state transition to PENDING_DESTROY, PENDING_GC
627 * or PENDING_TERMINATION depending on the module state. There is one exception
628 * to this, and that's INITIALIZATION_FAILED, where the state will not be changed.
629 *
630 * @param pMod The module which prerequisites should be unloaded.
631 */
632void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod)
633{
634 uint32_t cToUnload;
635
636 /* sanity */
637#ifdef KLDRDYLD_STRICT
638 {
639 PKLDRDYLDMOD pMod2;
640 for (pMod2 = kLdrDyldHead; pMod2; pMod2 = pMod2->Load.pNext)
641 KLDRDYLDMOD_ASSERT(pMod2->enmState != KLDRSTATE_GOOD || pMod2->cRefs);
642 }
643#endif
644 KLDRDYLDMOD_ASSERT(pMod->papPrereqs);
645
646 /*
647 * Unload prereqs of the module we're called on first.
648 */
649 cToUnload = kldrDyldModUnloadPrerequisitesOne(pMod);
650
651 /*
652 * Iterate the load list in a cyclic manner until there are no more
653 * modules that can be pushed on into unloading.
654 */
655 while (cToUnload)
656 {
657 cToUnload = 0;
658 for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
659 {
660 if ( pMod->cRefs
661 || pMod->enmState >= KLDRSTATE_PENDING_TERMINATION
662 || pMod->enmState < KLDRSTATE_LOADED_PREREQUISITES)
663 continue;
664 cToUnload += kldrDyldModUnloadPrerequisitesOne(pMod);
665 }
666 }
667}
668
669
670/**
671 * Loads the prerequisite modules this module depends on.
672 *
673 * To find each of the prerequisite modules this method calls
674 * kldrDyldGetPrerequisite() and it will make sure the modules
675 * are added to the load stack frame.
676 *
677 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
678 * The state is changed to LOADED_PREREQUISITES or RELOADED_LOADED_PREREQUISITES.
679 * @param pMod The module.
680 * @param pszPrefix Prefix to use when searching.
681 * @param pszSuffix Suffix to use when searching.
682 * @param enmSearch Method to use when locating the module and any modules it may depend on.
683 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
684 */
685int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
686 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
687{
688 int32_t cPrereqs;
689 uint32_t i;
690 int rc = 0;
691
692 /* sanity */
693 switch (pMod->enmState)
694 {
695 case KLDRSTATE_MAPPED:
696 case KLDRSTATE_RELOADED:
697 break;
698 default:
699 KLDRDYLDMOD_ASSERT(!"invalid state");
700 return -1;
701 }
702
703 /*
704 * Query number of prerequiste modules and allocate the array.
705 */
706 cPrereqs = kLdrModNumberOfImports(pMod->pMod, NULL);
707 kldrHlpAssert(cPrereqs >= 0);
708 if (pMod->cPrereqs != cPrereqs)
709 {
710 KLDRDYLDMOD_ASSERT(!pMod->papPrereqs);
711 pMod->papPrereqs = (PPKLDRDYLDMOD)kldrHlpAllocZ(sizeof(pMod->papPrereqs[0]) * cPrereqs);
712 if (!pMod->papPrereqs)
713 return KLDR_ERR_NO_MEMORY;
714 pMod->cPrereqs = cPrereqs;
715 }
716 else
717 KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs);
718
719 /*
720 * Iterate the prerequisites and load them.
721 */
722 for (i = 0; i < pMod->cPrereqs; i++)
723 {
724 static char s_szPrereq[260];
725 PKLDRDYLDMOD pPrereqMod;
726
727 KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL);
728 rc = kLdrModGetImport(pMod->pMod, NULL, i, s_szPrereq, sizeof(s_szPrereq));
729 if (rc)
730 break;
731 rc = kldrDyldGetPrerequisite(s_szPrereq, pszPrefix, pszSuffix, enmSearch, fFlags, pMod, &pPrereqMod);
732 if (rc)
733 break;
734 pMod->papPrereqs[i] = pPrereqMod;
735 }
736
737 /* change the state regardless of what happend. */
738 if (pMod->enmState == KLDRSTATE_MAPPED)
739 pMod->enmState = KLDRSTATE_LOADED_PREREQUISITES;
740 else
741 pMod->enmState = KLDRSTATE_RELOADED_LOADED_PREREQUISITES;
742 return rc;
743}
744
745
746/**
747 * Maps an open module.
748 *
749 * On success the module will be in the MAPPED state.
750 *
751 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
752 * @param pMod The module which needs to be unmapped and set pending for destruction.
753 */
754int kldrDyldModMap(PKLDRDYLDMOD pMod)
755{
756 int rc;
757
758 /* sanity */
759 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
760 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_OPEN);
761 KLDRDYLDMOD_ASSERT(!pMod->fMapped);
762 if (pMod->fMapped)
763 return 0;
764
765 /* do the job. */
766 rc = kLdrModMap(pMod->pMod);
767 if (!rc)
768 {
769 rc = kLdrModAllocTLS(pMod->pMod);
770 if (!rc)
771 {
772 /** @todo TLS */
773 pMod->fMapped = 1;
774 pMod->enmState = KLDRSTATE_MAPPED;
775 }
776 else
777 kLdrModUnmap(pMod->pMod);
778 }
779 return rc;
780}
781
782
783/**
784 * Unmaps the module, unlinks it from everywhere marks it PENDING_DESTROY.
785 *
786 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
787 * @param pMod The module which needs to be unmapped and set pending for destruction.
788 */
789int kldrDyldModUnmap(PKLDRDYLDMOD pMod)
790{
791 int rc;
792
793 /* sanity */
794 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
795 KLDRDYLDMOD_ASSERT(pMod->fMapped);
796 switch (pMod->enmState)
797 {
798 case KLDRSTATE_MAPPED:
799 case KLDRSTATE_GC:
800 case KLDRSTATE_PENDING_DESTROY:
801 break;
802 default:
803 KLDRDYLDMOD_ASSERT(!"invalid state");
804 return -1;
805 }
806
807 /* do the job. */
808 if (pMod->fAllocatedTLS)
809 {
810 kLdrModFreeTLS(pMod->pMod);
811 pMod->fAllocatedTLS = 0;
812 }
813 rc = kLdrModUnmap(pMod->pMod);
814 if (!rc)
815 {
816 pMod->fMapped = 0;
817 if (pMod->enmState < KLDRSTATE_PENDING_DESTROY)
818 {
819 pMod->enmState = KLDRSTATE_PENDING_DESTROY;
820 kldrDyldModUnlink(pMod);
821 }
822 }
823
824 return rc;
825}
826
827
828/**
829 * Reloads the module.
830 *
831 * Reloading means that all modified pages are restored to their original
832 * state. Whether this includes the code segments depends on whether the fixups
833 * depend on the addend in the place they are fixing up - so it's format specific.
834 *
835 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
836 * @param pMod The module which needs to be unmapped and set pending for destruction.
837 */
838int kldrDyldModReload(PKLDRDYLDMOD pMod)
839{
840 int rc;
841
842 /* sanity */
843 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
844 KLDRDYLDMOD_ASSERT(pMod->fMapped);
845
846 switch (pMod->enmState)
847 {
848 case KLDRSTATE_MAPPED:
849 case KLDRSTATE_GC:
850 case KLDRSTATE_PENDING_DESTROY:
851 break;
852 default:
853 KLDRDYLDMOD_ASSERT(!"invalid state");
854 return -1;
855 }
856
857 /* Free TLS before reloading. */
858 if (pMod->fAllocatedTLS)
859 {
860 kLdrModFreeTLS(pMod->pMod);
861 pMod->fAllocatedTLS = 0;
862 }
863
864 /* Let the module interpreter do the reloading of the mapping. */
865 rc = kLdrModReload(pMod->pMod);
866 if (!rc)
867 {
868 rc = kLdrModAllocTLS(pMod->pMod);
869 if (!rc)
870 {
871 pMod->fAllocatedTLS = 1;
872 pMod->enmState = KLDRSTATE_RELOADED;
873 }
874 }
875 return rc;
876}
877
878
879/**
880 * @copydoc FNKLDRMODGETIMPORT
881 * pvUser points to the KLDRDYLDMOD.
882 */
883static int kldrDyldModFixupGetImportCallback(PKLDRMOD pMod, uint32_t iImport, uint32_t uSymbol, const char *pszSymbol,
884 PKLDRADDR puValue, uint32_t *pfKind, void *pvUser)
885{
886 static int s_cRecursiveCalls = 0;
887 PKLDRDYLDMOD pDyldMod = (PKLDRDYLDMOD)pvUser;
888 int rc;
889
890 /* guard against too deep forwarder recursion. */
891 if (s_cRecursiveCalls >= 5)
892 return KLDR_ERR_TOO_LONG_FORWARDER_CHAIN;
893 s_cRecursiveCalls++;
894
895 if (iImport != NIL_KLDRMOD_IMPORT)
896 {
897 /* specific import module search. */
898 PKLDRDYLDMOD pPrereqMod;
899
900 KLDRDYLDMOD_ASSERT(iImport < pDyldMod->cPrereqs);
901 pPrereqMod = pDyldMod->papPrereqs[iImport];
902
903 KLDRDYLDMOD_ASSERT(pPrereqMod);
904 KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicHead == KLDRDYMOD_MAGIC);
905 KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicTail == KLDRDYMOD_MAGIC);
906 KLDRDYLDMOD_ASSERT(pPrereqMod->enmState < KLDRSTATE_TERMINATING);
907
908 rc = kLdrModQuerySymbol(pPrereqMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
909 uSymbol, pszSymbol, kldrDyldModFixupGetImportCallback, pPrereqMod, puValue, pfKind);
910 if (rc)
911 {
912 if (pszSymbol)
913 kldrDyldFailure(rc, "%s[%d]->%s.%s", pDyldMod->pMod->pszName, iImport,
914 pPrereqMod->pMod->pszName, pszSymbol);
915 else
916 kldrDyldFailure(rc, "%s[%d]->%s.%d", pDyldMod->pMod->pszName, iImport,
917 pPrereqMod->pMod->pszName, uSymbol);
918 }
919 }
920 else
921 {
922 /* bind list search. */
923 unsigned fFound = 0;
924 PKLDRDYLDMOD pBindMod = g_pkLdrDyldBindHead;
925 rc = 0;
926 while (pBindMod)
927 {
928 uint32_t fKind;
929 KLDRADDR uValue;
930 rc = kLdrModQuerySymbol(pBindMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
931 uSymbol, pszSymbol, kldrDyldModFixupGetImportCallback, pBindMod, &uValue, &fKind);
932 if ( !rc
933 && ( !fFound
934 || !(fKind & KLDRSYMKIND_WEAK)
935 )
936 )
937 {
938 *pfKind = fKind;
939 *puValue = uValue;
940 fFound = 1;
941 if (!(fKind & KLDRSYMKIND_WEAK))
942 break;
943 }
944
945 /* next */
946 pBindMod = pBindMod->Bind.pNext;
947 }
948 rc = fFound ? 0 : KLDR_ERR_SYMBOL_NOT_FOUND;
949 if (!fFound)
950 {
951 if (pszSymbol)
952 kldrDyldFailure(rc, "%s->%s", pDyldMod->pMod->pszName, pszSymbol);
953 else
954 kldrDyldFailure(rc, "%s->%d", pDyldMod->pMod->pszName, uSymbol);
955 }
956 }
957
958 s_cRecursiveCalls--;
959 return rc;
960}
961
962
963/**
964 * Applies fixups to a module which prerequisistes has been
965 * successfully loaded.
966 *
967 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
968 * @param pMod The module which needs to be unmapped and set pending for destruction.
969 */
970int kldrDyldModFixup(PKLDRDYLDMOD pMod)
971{
972 int rc;
973
974 /* sanity */
975 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
976 KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
977 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES);
978
979 /* do the job */
980 rc = kLdrModFixupMapping(pMod->pMod, kldrDyldModFixupGetImportCallback, pMod);/// @todo fixme.
981 if (!rc)
982 pMod->enmState = KLDRSTATE_FIXED_UP;
983 return rc;
984}
985
986
987/**
988 * Calls the module initialization entry point if any.
989 *
990 * This is considered to be a module specific thing and leave if
991 * to the module interpreter. They will have to deal with different
992 * module init practices between platforms should there be any.
993 *
994 * @returns 0 and state changed to GOOD on success.
995 * Non-zero OS or kLdr status code and status changed to INITIALIZATION_FAILED on failure.
996 * @param pMod The module that should be initialized.
997 */
998int kldrDyldModCallInit(PKLDRDYLDMOD pMod)
999{
1000 int rc;
1001
1002 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_INITIALIZING);
1003
1004 rc = kLdrModCallInit(pMod->pMod, (uintptr_t)pMod->hMod);
1005 if (!rc)
1006 pMod->enmState = KLDRSTATE_GOOD;
1007 else
1008 pMod->enmState = KLDRSTATE_INITIALIZATION_FAILED;
1009
1010 return rc;
1011}
1012
1013
1014/**
1015 * Calls the module termination entry point if any.
1016 *
1017 * This'll change the module status to PENDING_GC.
1018 *
1019 * @param pMod The module that should be initialized.
1020 */
1021void kldrDyldModCallTerm(PKLDRDYLDMOD pMod)
1022{
1023 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_TERMINATING);
1024
1025 kLdrModCallTerm(pMod->pMod, (uintptr_t)pMod->hMod);
1026 pMod->enmState = KLDRSTATE_PENDING_GC;
1027}
1028
1029
1030/**
1031 * Calls the thread attach entry point if any.
1032 *
1033 * @returns 0 on success, non-zero on failure.
1034 * @param pMod The module.
1035 */
1036int kldrDyldModAttachThread(PKLDRDYLDMOD pMod)
1037{
1038 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
1039
1040 return kLdrModCallThread(pMod->pMod, (uintptr_t)pMod->hMod, 1 /* attach */);
1041}
1042
1043
1044/**
1045 * Calls the thread detach entry point if any.
1046 *
1047 * @returns 0 on success, non-zero on failure.
1048 * @param pMod The module.
1049 */
1050void kldrDyldModDetachThread(PKLDRDYLDMOD pMod)
1051{
1052 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
1053
1054 kLdrModCallThread(pMod->pMod, (uintptr_t)pMod->hMod, 0 /* detach */);
1055}
1056
1057
1058/**
1059 * Gets the main stack, allocate it if necessary.
1060 *
1061 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
1062 * @param pMod The module.
1063 * @param ppvStack Where to store the address of the stack (lowest address).
1064 * @param pcbStack Where to store the size of the stack.
1065 */
1066int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, size_t *pcbStack)
1067{
1068 int rc = 0;
1069 KLDRSTACKINFO StackInfo;
1070 KLDRDYLDMOD_ASSERT(pMod->fExecutable);
1071
1072 /*
1073 * Since we might have to allocate the stack ourselves, and there will only
1074 * ever be one main stack, we'll be keeping the main stack info in globals.
1075 */
1076 if (!g_fkLdrDyldDoneMainStack)
1077 {
1078 rc = kLdrModGetStackInfo(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &StackInfo);
1079 if (!rc)
1080 {
1081 /* check if there is a stack size override/default. */
1082 size_t cbDefOverride;
1083 if (kldrHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride))
1084 cbDefOverride = 0;
1085
1086
1087 /* needs allocating? */
1088 if ( StackInfo.LinkAddress == NIL_KLDRADDR
1089 || StackInfo.cbStack < cbDefOverride)
1090 {
1091 size_t cbStack = (size_t)KLDR_MAX(StackInfo.cbStack, cbDefOverride);
1092
1093 g_pvkLdrDyldMainStack = kldrDyldOSAllocStack(cbStack);
1094 if (g_pvkLdrDyldMainStack)
1095 {
1096 g_cbkLdrDyldMainStack = cbStack;
1097 g_fkLdrDyldMainStackAllocated = 1;
1098 }
1099 else
1100 rc = KLDR_ERR_MAIN_STACK_ALLOC_FAILED;
1101 }
1102 else
1103 {
1104 KLDRDYLDMOD_ASSERT(StackInfo.Address != NIL_KLDRADDR);
1105 KLDRDYLDMOD_ASSERT(StackInfo.cbStack > 0);
1106
1107 g_fkLdrDyldMainStackAllocated = 0;
1108 g_pvkLdrDyldMainStack = (void *)(uintptr_t)StackInfo.Address;
1109 KLDRDYLDMOD_ASSERT((uintptr_t)g_pvkLdrDyldMainStack == StackInfo.Address);
1110
1111 g_cbkLdrDyldMainStack = (size_t)StackInfo.cbStack;
1112 KLDRDYLDMOD_ASSERT(StackInfo.cbStack == g_cbkLdrDyldMainStack);
1113 }
1114 }
1115 if (!rc)
1116 g_fkLdrDyldDoneMainStack = 1;
1117 }
1118
1119 if (!rc)
1120 {
1121 if (ppvStack)
1122 *ppvStack = g_pvkLdrDyldMainStack;
1123 if (pcbStack)
1124 *pcbStack = g_cbkLdrDyldMainStack;
1125 }
1126
1127 return rc;
1128}
1129
1130
1131/**
1132 * This starts the executable module.
1133 *
1134 * @returns non-zero OS or kLdr status code on failure.
1135 * (won't return on success.)
1136 * @param pMod The executable module.
1137 */
1138int kldrDyldModStartExe(PKLDRDYLDMOD pMod)
1139{
1140 int rc;
1141 KLDRADDR MainEPAddress;
1142 void *pvStack;
1143 size_t cbStack;
1144 KLDRDYLDMOD_ASSERT(pMod->fExecutable);
1145
1146 rc = kLdrModQueryMainEntrypoint(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &MainEPAddress);
1147 if (rc)
1148 return rc;
1149 rc = kldrDyldModGetMainStack(pMod, &pvStack, &cbStack);
1150 if (rc)
1151 return rc;
1152 return kldrDyldOSStartExe((uintptr_t)MainEPAddress, pvStack, cbStack);
1153}
1154
1155
1156/**
1157 * Gets the module name.
1158 *
1159 * @returns 0 on success, KLDR_ERR_BUFFER_OVERFLOW on failure.
1160 * @param pMod The module.
1161 * @param pszName Where to store the name.
1162 * @param cchName The size of the name buffer.
1163 */
1164int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, size_t cchName)
1165{
1166 size_t cch = KLDR_MIN(cchName, pMod->pMod->cchName + 1);
1167 if (cch)
1168 {
1169 kLdrHlpMemCopy(pszName, pMod->pMod->pszName, cch - 1);
1170 pszName[cch - 1] = '\0';
1171 }
1172 return cchName <= pMod->pMod->cchName ? KLDR_ERR_BUFFER_OVERFLOW : 0;
1173}
1174
1175
1176/**
1177 * Gets the module filename.
1178 *
1179 * @returns 0 on success, KLDR_ERR_BUFFER_OVERFLOW on failure.
1180 * @param pMod The module.
1181 * @param pszFilename Where to store the filename.
1182 * @param cchFilename The size of the filename buffer.
1183 */
1184int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename)
1185{
1186 size_t cch = KLDR_MIN(cchFilename, pMod->pMod->cchFilename + 1);
1187 if (cch)
1188 {
1189 kLdrHlpMemCopy(pszFilename, pMod->pMod->pszFilename, cch - 1);
1190 pszFilename[cch - 1] = '\0';
1191 }
1192 return cchFilename <= pMod->pMod->cchFilename ? KLDR_ERR_BUFFER_OVERFLOW : 0;
1193}
1194
1195
1196/**
1197 * Gets the address/value of a symbol in the specified module.
1198 *
1199 * @returns 0 on success, KLDR_ERR_SYMBOL_NOT_FOUND on failure.
1200 * @param pMod The module.
1201 * @param uSymbolOrdinal The symbol ordinal 0. This is ignored if the name is non-zero.
1202 * @param pszSymbolName The symbol name. Can be NULL.
1203 * @param puValue Where to store the value. optional.
1204 * @param pfKind Where to store the symbol kind. optional.
1205 */
1206int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName,
1207 uintptr_t *puValue, uint32_t *pfKind)
1208{
1209 int rc;
1210 KLDRADDR uValue = 0;
1211 uint32_t fKind = 0;
1212
1213 rc = kLdrModQuerySymbol(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
1214 uSymbolOrdinal, pszSymbolName, kldrDyldModFixupGetImportCallback, pMod,
1215 &uValue, &fKind);
1216 if (!rc)
1217 {
1218 if (puValue)
1219 {
1220 *puValue = (uintptr_t)uValue;
1221 KLDRDYLDMOD_ASSERT(*puValue == uValue);
1222 }
1223 if (pfKind)
1224 *pfKind = fKind;
1225 }
1226
1227 return rc;
1228}
1229
Note: See TracBrowser for help on using the repository browser.