source: trunk/kLdr/kLdrDyldMod.c@ 2847

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

Roughly done with kldrDyldMod now.

File size: 32.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);
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, 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/**
881 * Applies fixups to a module which prerequisistes has been
882 * successfully loaded.
883 *
884 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
885 * @param pMod The module which needs to be unmapped and set pending for destruction.
886 */
887int kldrDyldModFixup(PKLDRDYLDMOD pMod)
888{
889 int rc;
890
891 /* sanity */
892 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
893 KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
894 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES);
895
896 /* do the job */
897 rc = kLdrModFixupMapping(pMod->pMod, NULL, NULL);/// @todo fixme.
898 if (!rc)
899 pMod->enmState = KLDRSTATE_FIXED_UP;
900 return rc;
901}
902
903
904/**
905 * Calls the module initialization entry point if any.
906 *
907 * This is considered to be a module specific thing and leave if
908 * to the module interpreter. They will have to deal with different
909 * module init practices between platforms should there be any.
910 *
911 * @returns 0 and state changed to GOOD on success.
912 * Non-zero OS or kLdr status code and status changed to INITIALIZATION_FAILED on failure.
913 * @param pMod The module that should be initialized.
914 */
915int kldrDyldModCallInit(PKLDRDYLDMOD pMod)
916{
917 int rc;
918
919 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_INITIALIZING);
920
921 rc = kLdrModCallInit(pMod->pMod);
922 if (!rc)
923 pMod->enmState = KLDRSTATE_GOOD;
924 else
925 pMod->enmState = KLDRSTATE_INITIALIZATION_FAILED;
926
927 return rc;
928}
929
930
931/**
932 * Calls the module termination entry point if any.
933 *
934 * This'll change the module status to PENDING_GC.
935 *
936 * @param pMod The module that should be initialized.
937 */
938void kldrDyldModCallTerm(PKLDRDYLDMOD pMod)
939{
940 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_TERMINATING);
941
942 kLdrModCallTerm(pMod->pMod);
943 pMod->enmState = KLDRSTATE_PENDING_GC;
944}
945
946
947/**
948 * Calls the thread attach entry point if any.
949 *
950 * @returns 0 on success, non-zero on failure.
951 * @param pMod The module.
952 */
953int kldrDyldModAttachThread(PKLDRDYLDMOD pMod)
954{
955 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
956
957 return kLdrModCallThread(pMod->pMod, 1 /* attach */);
958}
959
960
961/**
962 * Calls the thread detach entry point if any.
963 *
964 * @returns 0 on success, non-zero on failure.
965 * @param pMod The module.
966 */
967void kldrDyldModDetachThread(PKLDRDYLDMOD pMod)
968{
969 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
970
971 kLdrModCallThread(pMod->pMod, 0 /* detach */);
972}
973
974
975/**
976 * Gets the main stack, allocate it if necessary.
977 *
978 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
979 * @param pMod The module.
980 * @param ppvStack Where to store the address of the stack (lowest address).
981 * @param pcbStack Where to store the size of the stack.
982 */
983int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, size_t *pcbStack)
984{
985 int rc = 0;
986 KLDRSTACKINFO StackInfo;
987 KLDRDYLDMOD_ASSERT(pMod->fExecutable);
988
989 /*
990 * Since we might have to allocate the stack ourselves, and there will only
991 * ever be one main stack, we'll be keeping the main stack info in globals.
992 */
993 if (!g_fkLdrDyldDoneMainStack)
994 {
995 rc = kLdrModGetStackInfo(pMod->pMod, &StackInfo);
996 if (!rc)
997 {
998 /* check if there is a stack size override/default. */
999 size_t cbDefOverride;
1000 if (kldrHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride))
1001 cbDefOverride = 0;
1002
1003
1004 /* needs allocating? */
1005 if ( StackInfo.uLinkAddress == ~(uintmax_t)0
1006 || StackInfo.cbStack < cbDefOverride)
1007 {
1008 size_t cbStack = (size_t)KLDR_MAX(StackInfo.cbStack, cbDefOverride);
1009
1010 g_pvkLdrDyldMainStack = kldrDyldOSAllocStack(cbStack);
1011 if (g_pvkLdrDyldMainStack)
1012 {
1013 g_cbkLdrDyldMainStack = cbStack;
1014 g_fkLdrDyldMainStackAllocated = 1;
1015 }
1016 else
1017 rc = KLDR_ERR_MAIN_STACK_ALLOC_FAILED;
1018 }
1019 else
1020 {
1021 KLDRDYLDMOD_ASSERT(StackInfo.uLoadAddress != ~(uintmax_t)0);
1022 KLDRDYLDMOD_ASSERT(StackInfo.cbStack > 0);
1023
1024 g_fkLdrDyldMainStackAllocated = 0;
1025 g_pvkLdrDyldMainStack = (void *)(uintptr_t)StackInfo.uLoadAddress;
1026 KLDRDYLDMOD_ASSERT((uintptr_t)g_pvkLdrDyldMainStack == StackInfo.uLoadAddress);
1027
1028 g_cbkLdrDyldMainStack = (size_t)StackInfo.cbStack;
1029 KLDRDYLDMOD_ASSERT(StackInfo.cbStack == g_cbkLdrDyldMainStack);
1030 }
1031 }
1032 if (!rc)
1033 g_fkLdrDyldDoneMainStack = 1;
1034 }
1035
1036 if (!rc)
1037 {
1038 if (ppvStack)
1039 *ppvStack = g_pvkLdrDyldMainStack;
1040 if (pcbStack)
1041 *pcbStack = g_cbkLdrDyldMainStack;
1042 }
1043
1044 return rc;
1045}
1046
1047
1048/**
1049 * This starts the executable module.
1050 *
1051 * @returns non-zero OS or kLdr status code on failure.
1052 * (won't return on success.)
1053 * @param pMod The executable module.
1054 */
1055int kldrDyldModStartExe(PKLDRDYLDMOD pMod)
1056{
1057 int rc;
1058 uintmax_t uValue;
1059 void *pvStack;
1060 size_t cbStack;
1061 KLDRDYLDMOD_ASSERT(pMod->fExecutable);
1062
1063 rc = kLdrModQueryMainEntrypoint(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &uValue);
1064 if (rc)
1065 return rc;
1066 rc = kldrDyldModGetMainStack(pMod, &pvStack, &cbStack);
1067 if (rc)
1068 return rc;
1069 return kldrDyldOSStartExe((uintptr_t)uValue, pvStack, cbStack);
1070}
1071
1072
1073/**
1074 * Gets the module name.
1075 *
1076 * @returns 0 on success, KLDR_ERR_BUFFER_OVERFLOW on failure.
1077 * @param pMod The module.
1078 * @param pszName Where to store the name.
1079 * @param cchName The size of the name buffer.
1080 */
1081int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, size_t cchName)
1082{
1083 size_t cch = KLDR_MIN(cchName, pMod->pMod->cchName + 1);
1084 if (cch)
1085 {
1086 kLdrHlpMemCopy(pszName, pMod->pMod->pszName, cch - 1);
1087 pszName[cch - 1] = '\0';
1088 }
1089 return cchName <= pMod->pMod->cchName ? KLDR_ERR_BUFFER_OVERFLOW : 0;
1090}
1091
1092
1093/**
1094 * Gets the module filename.
1095 *
1096 * @returns 0 on success, KLDR_ERR_BUFFER_OVERFLOW on failure.
1097 * @param pMod The module.
1098 * @param pszFilename Where to store the filename.
1099 * @param cchFilename The size of the filename buffer.
1100 */
1101int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename)
1102{
1103 size_t cch = KLDR_MIN(cchFilename, pMod->pMod->cchFilename + 1);
1104 if (cch)
1105 {
1106 kLdrHlpMemCopy(pszFilename, pMod->pMod->pszFilename, cch - 1);
1107 pszFilename[cch - 1] = '\0';
1108 }
1109 return cchFilename <= pMod->pMod->cchFilename ? KLDR_ERR_BUFFER_OVERFLOW : 0;
1110}
1111
1112
1113/**
1114 * Gets the address/value of a symbol in the specified module.
1115 *
1116 * @returns 0 on success, KLDR_ERR_SYMBOL_NOT_FOUND on failure.
1117 * @param pMod The module.
1118 * @param uSymbolOrdinal The symbol ordinal 0. This is ignored if the name is non-zero.
1119 * @param pszSymbolName The symbol name. Can be NULL.
1120 * @param puValue Where to store the value. optional.
1121 * @param pfKind Where to store the symbol kind. optional.
1122 */
1123int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName,
1124 uintptr_t *puValue, uint32_t *pfKind)
1125{
1126 int rc;
1127 uintmax_t uValue = 0;
1128 uint32_t fKind = 0;
1129
1130 rc = kLdrModQuerySymbol(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
1131 pszSymbolName ? pszSymbolName : (const char *)uSymbolOrdinal, &uValue, pfKind);
1132 if (!rc)
1133 {
1134 if (puValue)
1135 {
1136 *puValue = (uintptr_t)uValue;
1137 KLDRDYLDMOD_ASSERT(*puValue == uValue);
1138 }
1139 if (pfKind)
1140 *pfKind = fKind;
1141 }
1142
1143 return rc;
1144}
1145
Note: See TracBrowser for help on using the repository browser.