source: trunk/kLdr/kLdrDyldMod.c@ 2846

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

nearly done with kLdrDyldMod.

File size: 28.2 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
55/**
56 * Creates a module from the specified file provider instance.
57 *
58 * @returns 0 on success and *ppMod pointing to the new instance.
59 * On failure a non-zero kLdr status code is returned.
60 * @param pRdr The file provider instance.
61 * @param ppMod Where to put the pointer to the new module on success.
62 */
63int kldrDyldModCreate(PKLDRRDR pRdr, PPKLDRDYLDMOD ppMod)
64{
65 PKLDRDYLDMOD pMod;
66 PKLDRMOD pRawMod;
67 int rc;
68
69 *ppMod = NULL;
70
71 /*
72 * Try open an module interpreter.
73 */
74 rc = kLdrModOpenFromRdr(pRdr, &pRawMod);
75 if (rc)
76 return kldrDyldFailure(rc, "%s: %rc", kLdrRdrName(pRdr), rc);
77
78 /*
79 * Allocate a new dyld module.
80 */
81 pMod = (PKLDRDYLDMOD)kldrHlpAlloc(sizeof(*pMod));
82 if (pMod)
83 {
84 pMod->enmState = KLDRSTATE_OPEN;
85 pMod->pMod = pRawMod;
86 pMod->hMod = pMod;
87 pMod->cDepRefs = pMod->cDynRefs = pMod->cRefs = 0;
88 pMod->fExecutable = 0;
89 switch (pRawMod->enmType)
90 {
91 case KLDRTYPE_EXECUTABLE_FIXED:
92 case KLDRTYPE_EXECUTABLE_RELOCATABLE:
93 case KLDRTYPE_EXECUTABLE_PIC:
94 pMod->fExecutable = 1;
95 break;
96 }
97 pMod->fGlobalOrSpecific = 0;
98 pMod->fBindable = 0;
99 pMod->fInitList = 0;
100 pMod->fAlreadySeen = 0;
101 pMod->fMapped = 0;
102 pMod->fAllocatedTLS = 0;
103 pMod->f25Reserved = 0;
104 pMod->InitTerm.pNext = NULL;
105 pMod->InitTerm.pPrev = NULL;
106 pMod->Bind.pNext = NULL;
107 pMod->Bind.pPrev = NULL;
108 pMod->cPrereqs = 0;
109 pMod->papPrereqs = NULL;
110 pMod->u32MagicHead = KLDRDYMOD_MAGIC;
111 pMod->u32MagicTail = KLDRDYMOD_MAGIC;
112
113 /* it. */
114 pMod->Load.pNext = NULL;
115 pMod->Load.pPrev = kLdrDyldTail;
116 if (kLdrDyldTail)
117 kLdrDyldTail->Load.pNext = pMod;
118 else
119 kLdrDyldHead = pMod;
120 kLdrDyldTail = pMod;
121
122 /* we're good. */
123 *ppMod = pMod;
124 rc = 0;
125 }
126 else
127 {
128 kLdrModClose(pRawMod);
129 rc = KLDR_ERR_NO_MEMORY;
130 }
131 return rc;
132}
133
134
135/**
136 * Creates a module for a native module.
137 *
138 * @returns 0 on success and *ppMod pointing to the new instance.
139 * On failure a non-zero kLdr status code is returned.
140 * @param hNativeModule The native handle.
141 * @param ppMod Where to put the pointer to the new module on success.
142 * @remark This function ain't finalized yet.
143 */
144int kldrDyldModCreateNative(uintptr_t hNativeModule)
145{
146#if 0
147 /*
148 * Check if this module is already loaded by the native OS loader.
149 */
150 rc = kld
151 {
152#ifdef __OS2__
153 HMODULE hmod = NULLHANDLE;
154 APIRET rc = DosQueryModuleHandle(kLdrRdrName(pRdr), &hmod);
155 if (!rc)
156
157#elif defined(__WIN__)
158 HMODULE hmod = NULL;
159 if (GetModuleHandle(kLdrRdrName(pRdr))
160
161#else
162# error "Port me"
163#endif
164 }
165#endif
166 return -1;
167}
168
169
170/**
171 * Destroys a module pending destruction.
172 *
173 * @param pMod The module in question.
174 */
175void kldrDyldModDestroy(PKLDRDYLDMOD pMod)
176{
177 /*
178 * Validate the state.
179 */
180 switch (pMod->enmState)
181 {
182 case KLDRSTATE_PENDING_DESTROY:
183 case KLDRSTATE_GC:
184 break;
185 default:
186 KLDRDYLDMOD_ASSERT(!"Invalid state");
187 break;
188 }
189 KLDRDYLDMOD_ASSERT(!pMod->fInitList);
190 KLDRDYLDMOD_ASSERT(!pMod->cDynRefs);
191 KLDRDYLDMOD_ASSERT(!pMod->cDepRefs);
192
193
194 /*
195 * Ensure that the module is unmapped.
196 */
197 if (pMod->fMapped)
198 kldrDyldModUnmap(pMod);
199}
200
201
202/**
203 * Unlinks the module from any list it might be in.
204 * It is assumed that the module is at least linked into the load list.
205 *
206 * @param pMod The moduel.
207 */
208static void kldrDyldModUnlink(PKLDRDYLDMOD pMod)
209{
210 /* load list */
211 if (pMod->Load.pNext)
212 pMod->Load.pNext->Load.pPrev = pMod->Load.pPrev;
213 else
214 kLdrDyldTail = pMod->Load.pPrev;
215 if (pMod->Load.pPrev)
216 pMod->Load.pPrev->Load.pNext = pMod->Load.pNext;
217 else
218 kLdrDyldHead = pMod->Load.pNext;
219
220 /* bind list */
221 if (pMod->fBindable)
222 kldrDyldModClearBindable(pMod);
223
224 /* init term */
225 if (pMod->fInitList)
226 {
227 KLDRDYLDMOD_ASSERT(pMod->enmState < KLDRSTATE_INITIALIZATION_FAILED);
228 pMod->fInitList = 0;
229 if (pMod->InitTerm.pNext)
230 pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev;
231 else
232 g_pkLdrDyldInitTail = pMod->InitTerm.pPrev;
233 if (pMod->InitTerm.pPrev)
234 pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext;
235 else
236 g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
237 }
238 else if (pMod->enmState > KLDRSTATE_INITIALIZATION_FAILED)
239 {
240 KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_GOOD);
241 if (pMod->InitTerm.pNext)
242 pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev;
243 else
244 g_pkLdrDyldTermTail = pMod->InitTerm.pPrev;
245 if (pMod->InitTerm.pPrev)
246 pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext;
247 else
248 g_pkLdrDyldTermHead = pMod->InitTerm.pNext;
249 }
250 pMod->InitTerm.pNext = NULL;
251 pMod->InitTerm.pPrev = NULL;
252}
253
254
255/**
256 * Marks a module as bindable, i.e. it'll be considered when
257 * resolving names the unix way.
258 *
259 * @param pMod The module.
260 * @param fDeep When set the module will be inserted at the head of the
261 * module list used to resolve symbols. This means that the
262 * symbols in this module will be prefered of all the other
263 * modules.
264 */
265void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep)
266{
267 KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_GC);
268 if (!pMod->fBindable)
269 {
270 pMod->fBindable = 1;
271 if (!fDeep)
272 {
273 pMod->Bind.pNext = NULL;
274 pMod->Bind.pPrev = g_pkLdrDyldBindTail;
275 if (g_pkLdrDyldBindTail)
276 g_pkLdrDyldBindTail->Bind.pNext = pMod;
277 else
278 g_pkLdrDyldBindHead = pMod;
279 g_pkLdrDyldBindTail = pMod;
280 }
281 else
282 {
283 pMod->Bind.pPrev = NULL;
284 pMod->Bind.pNext = g_pkLdrDyldBindHead;
285 if (g_pkLdrDyldBindHead)
286 g_pkLdrDyldBindHead->Bind.pPrev = pMod;
287 else
288 g_pkLdrDyldBindTail = pMod;
289 g_pkLdrDyldBindHead = pMod;
290 }
291 }
292}
293
294
295/**
296 * Marks a module as not bindable, i.e. it will not be considered when
297 * resolving names the unix way.
298 *
299 * @param pMod The module.
300 */
301void kldrDyldModClearBindable(PKLDRDYLDMOD pMod)
302{
303 KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_DESTROY);
304 if (pMod->fBindable)
305 {
306 pMod->fBindable = 0;
307 if (pMod->Bind.pPrev)
308 pMod->Bind.pPrev->Bind.pNext = pMod->Bind.pNext;
309 else
310 g_pkLdrDyldBindHead = pMod->Bind.pNext;
311 if (pMod->Bind.pNext)
312 pMod->Bind.pNext->Bind.pPrev = pMod->Bind.pPrev;
313 else
314 g_pkLdrDyldBindTail = pMod->Bind.pPrev;
315 pMod->Bind.pNext = NULL;
316 pMod->Bind.pPrev = NULL;
317 }
318}
319
320
321/**
322 * Marks the module as global instead of being specific.
323 *
324 * A global module can be a matching result when the request
325 * doesn't specify a path. A specific module will not match
326 * unless the path also matches.
327 *
328 * @param pMod The module.
329 */
330void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod)
331{
332 pMod->fGlobalOrSpecific = 1;
333}
334
335
336/**
337 * Marks the module as specific instead of global.
338 *
339 * See kldrDyldModMarkGlobal for an explanation of the two terms.
340 *
341 * @param pMod The module.
342 */
343void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod)
344{
345 pMod->fGlobalOrSpecific = 0;
346}
347
348
349/**
350 * Adds a reference to the module making sure it won't be freed just yet.
351 *
352 * @param pMod The module.
353 */
354void kldrDyldModAddRef(PKLDRDYLDMOD pMod)
355{
356 pMod->cRefs++;
357}
358
359
360/**
361 * Dereference a module.
362 *
363 * @param pMod
364 */
365void kldrDyldModDeref(PKLDRDYLDMOD pMod)
366{
367 /* validate input */
368 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
369 KLDRDYLDMOD_ASSERT(pMod->cRefs >= pMod->cDepRefs + pMod->cDynRefs);
370 KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END);
371
372 /* decrement. */
373 if (pMod->cRefs > 0)
374 pMod->cRefs--;
375
376 /* execute delayed freeing. */
377 if ( pMod->enmState == KLDRSTATE_DESTROYED
378 && !pMod->cRefs)
379 kldrHlpFree(pMod);
380}
381
382
383/**
384 * Increment the count of modules depending on this module.
385 *
386 * @param pMod The module.
387 * @param pDep The module which depends on us.
388 */
389void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep)
390{
391 (void)pDep;
392
393 /* validate state */
394 switch (pMod->enmState)
395 {
396 case KLDRSTATE_MAPPED:
397 case KLDRSTATE_RELOADED:
398 case KLDRSTATE_LOADED_PREREQUISITES:
399 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
400 case KLDRSTATE_PENDING_INITIALIZATION:
401 case KLDRSTATE_INITIALIZING:
402 case KLDRSTATE_GOOD:
403 break;
404 default:
405 KLDRDYLDMOD_ASSERT(!"invalid state");
406 break;
407
408 }
409 KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END);
410 pMod->cRefs++;
411 pMod->cDepRefs++;
412}
413
414
415/**
416 * Drop a dependency.
417 *
418 * @param pMod The module.
419 * @param pDep The module which depends on us.
420 */
421void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep)
422{
423 KLDRDYLDMOD_ASSERT(pMod->cDepRefs > 0);
424 if (pMod->cDepRefs == 0)
425 return;
426 KLDRDYLDMOD_ASSERT(pMod->cDepRefs <= pMod->cRefs);
427 KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_MAPPED && pMod->enmState <= KLDRSTATE_PENDING_DESTROY);
428
429 pMod->cRefs--;
430 pMod->cDepRefs--;
431 if ( pMod->cDepRefs > 0
432 || pMod->cDynRefs > 0)
433 return;
434
435 /*
436 * The module should be unloaded.
437 */
438 kldrDyldModUnloadPrerequisites(pMod);
439}
440
441
442/**
443 * Increment the dynamic load count.
444 *
445 * @returns 0
446 * @param pMod The module.
447 */
448int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod)
449{
450 KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_GOOD
451 || pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION
452 || pMod->enmState == KLDRSTATE_INITIALIZING);
453 pMod->cRefs++;
454 pMod->cDynRefs++;
455 return 0;
456}
457
458
459/**
460 * Decrement the dynamic load count of the module and unload the module
461 * if the total reference count reaches zero.
462 *
463 * This may cause a cascade of unloading to occure. See kldrDyldModUnloadPrerequisites().
464 *
465 * @returns status code.
466 * @retval 0 on success.
467 * @retval KLDR_ERR_NOT_LOADED_DYNAMICALLY if the module wasn't loaded dynamically.
468 * @param pMod The module to unload.
469 */
470int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod)
471{
472 if (pMod->cDynRefs == 0)
473 return KLDR_ERR_NOT_LOADED_DYNAMICALLY;
474 KLDRDYLDMOD_ASSERT(pMod->cDynRefs <= pMod->cRefs);
475 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
476
477 pMod->cRefs--;
478 pMod->cDynRefs--;
479 if ( pMod->cDynRefs > 0
480 || pMod->cDepRefs > 0)
481 return 0;
482
483 /*
484 * The module should be unloaded.
485 */
486 kldrDyldModUnloadPrerequisites(pMod);
487 return 0;
488}
489
490
491/**
492 * Worker for kldrDyldModUnloadPrerequisites.
493 *
494 * @returns The number of modules that now can be unloaded.
495 * @param pMod The module in question.
496 */
497static uint32_t kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod)
498{
499 PKLDRDYLDMOD pMod2;
500 uint32_t cToUnload = 0;
501 uint32_t i;
502
503 KLDRDYLDMOD_ASSERT(pMod->papPrereqs);
504
505 /*
506 * Release the one in this module.
507 */
508 for (i = 0; i < pMod->cPrereqs; i++)
509 {
510 pMod2 = pMod->papPrereqs[i];
511 if (pMod2)
512 {
513 /* do the derefering ourselves or we'll end up in a recursive loop here. */
514 KLDRDYLDMOD_ASSERT(pMod2->cDepRefs > 0);
515 KLDRDYLDMOD_ASSERT(pMod2->cRefs >= pMod2->cDepRefs);
516 pMod2->cDepRefs--;
517 pMod2->cRefs--;
518 cToUnload += !pMod2->cRefs;
519 }
520 }
521
522 /*
523 * Change the state
524 */
525 switch (pMod->enmState)
526 {
527 case KLDRSTATE_LOADED_PREREQUISITES:
528 case KLDRSTATE_FIXED_UP:
529 pMod->enmState = KLDRSTATE_PENDING_DESTROY;
530 kldrDyldModUnlink(pMod);
531 break;
532
533 case KLDRSTATE_PENDING_INITIALIZATION:
534 pMod->enmState = KLDRSTATE_PENDING_GC;
535 break;
536
537 case KLDRSTATE_RELOADED_FIXED_UP:
538 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
539 case KLDRSTATE_GOOD:
540 pMod->enmState = KLDRSTATE_PENDING_TERMINATION;
541 break;
542
543 case KLDRSTATE_INITIALIZATION_FAILED:
544 break;
545
546 default:
547 KLDRDYLDMOD_ASSERT(!"invalid state");
548 break;
549 }
550
551 return cToUnload;
552}
553
554
555/**
556 * This is the heart of the unload code.
557 *
558 * It will recursivly (using the load list) initiate module unloading
559 * of all affected modules.
560 *
561 * This function will cause a state transition to PENDING_DESTROY, PENDING_GC
562 * or PENDING_TERMINATION depending on the module state. There is one exception
563 * to this, and that's INITIALIZATION_FAILED, where the state will not be changed.
564 *
565 * @param pMod The module which prerequisites should be unloaded.
566 */
567void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod)
568{
569 uint32_t cToUnload;
570
571 /* sanity */
572#ifdef KLDRDYLD_STRICT
573 {
574 PKLDRDYLDMOD pMod2;
575 for (pMod2 = kLdrDyldHead; pMod2; pMod2 = pMod2->Load.pNext)
576 KLDRDYLDMOD_ASSERT(pMod2->enmState != KLDRSTATE_GOOD || pMod2->cRefs);
577 }
578#endif
579 KLDRDYLDMOD_ASSERT(pMod->papPrereqs);
580
581 /*
582 * Unload prereqs of the module we're called on first.
583 */
584 cToUnload = kldrDyldModUnloadPrerequisitesOne(pMod);
585
586 /*
587 * Iterate the load list in a cyclic manner until there are no more
588 * modules that can be pushed on into unloading.
589 */
590 while (cToUnload)
591 {
592 cToUnload = 0;
593 for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
594 {
595 if ( pMod->cRefs
596 || pMod->enmState >= KLDRSTATE_PENDING_TERMINATION
597 || pMod->enmState < KLDRSTATE_LOADED_PREREQUISITES)
598 continue;
599 cToUnload += kldrDyldModUnloadPrerequisitesOne(pMod);
600 }
601 }
602}
603
604
605int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
606 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
607{
608
609 return -1;
610}
611
612
613int kldrDyldModCheckPrerequisites(PKLDRDYLDMOD pMod)
614{
615 return -1;
616}
617
618
619/**
620 * Maps an open module.
621 *
622 * On success the module will be in the MAPPED state.
623 *
624 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
625 * @param pMod The module which needs to be unmapped and set pending for destruction.
626 */
627int kldrDyldModMap(PKLDRDYLDMOD pMod)
628{
629 int rc;
630
631 /* sanity */
632 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
633 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_OPEN);
634 KLDRDYLDMOD_ASSERT(!pMod->fMapped);
635 if (pMod->fMapped)
636 return 0;
637
638 /* do the job. */
639 rc = kLdrModMap(pMod->pMod);
640 if (!rc)
641 {
642 rc = kLdrModAllocTLS(pMod->pMod);
643 if (!rc)
644 {
645 /** @todo TLS */
646 pMod->fMapped = 1;
647 pMod->enmState = KLDRSTATE_MAPPED;
648 }
649 else
650 kLdrModUnmap(pMod->pMod);
651 }
652 return rc;
653}
654
655
656/**
657 * Unmaps the module, unlinks it from everywhere marks it PENDING_DESTROY.
658 *
659 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
660 * @param pMod The module which needs to be unmapped and set pending for destruction.
661 */
662int kldrDyldModUnmap(PKLDRDYLDMOD pMod)
663{
664 int rc;
665
666 /* sanity */
667 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
668 KLDRDYLDMOD_ASSERT(pMod->fMapped);
669 switch (pMod->enmState)
670 {
671 case KLDRSTATE_MAPPED:
672 case KLDRSTATE_GC:
673 case KLDRSTATE_PENDING_DESTROY:
674 break;
675 default:
676 KLDRDYLDMOD_ASSERT(!"invalid state");
677 return -1;
678 }
679
680 /* do the job. */
681 rc = kLdrModFreeTLS(pMod->pMod);
682 if (!rc)
683 {
684 rc = kLdrModUnmap(pMod->pMod);
685 if (!rc)
686 {
687 pMod->fMapped = 0;
688 if (pMod->enmState < KLDRSTATE_PENDING_DESTROY)
689 {
690 pMod->enmState = KLDRSTATE_PENDING_DESTROY;
691 kldrDyldModUnlink(pMod);
692 }
693 }
694 else
695 kLdrModAllocTLS(pMod->pMod);
696 }
697 return rc;
698}
699
700
701/**
702 * Reloads the module.
703 *
704 * Reloading means that all modified pages are restored to their original
705 * state. Whether this includes the code segments depends on whether the fixups
706 * depend on the addend in the place they are fixing up - so it's format specific.
707 *
708 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
709 * @param pMod The module which needs to be unmapped and set pending for destruction.
710 */
711int kldrDyldModReload(PKLDRDYLDMOD pMod)
712{
713 int rc;
714
715 /* sanity */
716 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
717 KLDRDYLDMOD_ASSERT(pMod->fMapped);
718 KLDRDYLDMOD_ASSERT(pMod->fAllocatedTLS);
719
720 switch (pMod->enmState)
721 {
722 case KLDRSTATE_MAPPED:
723 case KLDRSTATE_GC:
724 case KLDRSTATE_PENDING_DESTROY:
725 break;
726 default:
727 KLDRDYLDMOD_ASSERT(!"invalid state");
728 return -1;
729 }
730
731 /* Let the module interpreter do the reloading of the mapping. */
732 rc = kLdrModReload(pMod->pMod);
733 if (!rc)
734 {
735 /* Free and allocate the TLS anew to ensure we get clean entries. */
736 if (pMod->fAllocatedTLS)
737 rc = kLdrModFreeTLS(pMod->pMod);
738 if (!rc)
739 {
740 pMod->fAllocatedTLS = 0;
741 rc = kLdrModAllocTLS(pMod->pMod);
742 if (!rc)
743 {
744 pMod->fAllocatedTLS = 1;
745 pMod->enmState = KLDRSTATE_RELOADED;
746 }
747 }
748 }
749 return rc;
750}
751
752
753
754/**
755 * Applies fixups to a module which prerequisistes has been
756 * successfully loaded.
757 *
758 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
759 * @param pMod The module which needs to be unmapped and set pending for destruction.
760 */
761int kldrDyldModFixup(PKLDRDYLDMOD pMod)
762{
763 int rc;
764
765 /* sanity */
766 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
767 KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
768 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES);
769
770 /* do the job */
771 rc = kLdrModFixupMapping(pMod->pMod, NULL, NULL);/// @todo fixme.
772 if (!rc)
773 pMod->enmState = KLDRSTATE_FIXED_UP;
774 return rc;
775}
776
777
778/**
779 * Calls the module initialization entry point if any.
780 *
781 * This is considered to be a module specific thing and leave if
782 * to the module interpreter. They will have to deal with different
783 * module init practices between platforms should there be any.
784 *
785 * @returns 0 and state changed to GOOD on success.
786 * Non-zero OS or kLdr status code and status changed to INITIALIZATION_FAILED on failure.
787 * @param pMod The module that should be initialized.
788 */
789int kldrDyldModCallInit(PKLDRDYLDMOD pMod)
790{
791 int rc;
792
793 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_INITIALIZING);
794
795 rc = kLdrModCallInit(pMod->pMod);
796 if (!rc)
797 pMod->enmState = KLDRSTATE_GOOD;
798 else
799 pMod->enmState = KLDRSTATE_INITIALIZATION_FAILED;
800
801 return rc;
802}
803
804
805/**
806 * Calls the module termination entry point if any.
807 *
808 * This'll change the module status to PENDING_GC.
809 *
810 * @param pMod The module that should be initialized.
811 */
812void kldrDyldModCallTerm(PKLDRDYLDMOD pMod)
813{
814 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_TERMINATING);
815
816 kLdrModCallTerm(pMod->pMod);
817 pMod->enmState = KLDRSTATE_PENDING_GC;
818}
819
820
821/**
822 * Calls the thread attach entry point if any.
823 *
824 * @returns 0 on success, non-zero on failure.
825 * @param pMod The module.
826 */
827int kldrDyldModAttachThread(PKLDRDYLDMOD pMod)
828{
829 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
830
831 return kLdrModCallThread(pMod->pMod, 1 /* attach */);
832}
833
834
835/**
836 * Calls the thread detach entry point if any.
837 *
838 * @returns 0 on success, non-zero on failure.
839 * @param pMod The module.
840 */
841void kldrDyldModDetachThread(PKLDRDYLDMOD pMod)
842{
843 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
844
845 kLdrModCallThread(pMod->pMod, 0 /* detach */);
846}
847
848
849/**
850 * Gets the main stack, allocate it if necessary.
851 *
852 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
853 * @param pMod The module.
854 * @param ppvStack Where to store the address of the stack (lowest address).
855 * @param pcbStack Where to store the size of the stack.
856 */
857int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, size_t *pcbStack)
858{
859 int rc = 0;
860 KLDRSTACKINFO StackInfo;
861 KLDRDYLDMOD_ASSERT(pMod->fExecutable);
862
863 /*
864 * Since we might have to allocate the stack ourselves, and there will only
865 * ever be one main stack, we'll be keeping the main stack info in globals.
866 */
867 if (!g_fkLdrDyldDoneMainStack)
868 {
869 rc = kLdrModGetStackInfo(pMod->pMod, &StackInfo);
870 if (!rc)
871 {
872 /* check if there is a stack size override/default. */
873 size_t cbDefOverride;
874 if (kldrHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride))
875 cbDefOverride = 0;
876
877
878 /* needs allocating? */
879 if ( StackInfo.uLinkAddress == ~(uintmax_t)0
880 || StackInfo.cbStack < cbDefOverride)
881 {
882 size_t cbStack = (size_t)KLDR_MAX(StackInfo.cbStack, cbDefOverride);
883
884 g_pvkLdrDyldMainStack = kldrDyldOSAllocStack(cbStack);
885 if (g_pvkLdrDyldMainStack)
886 {
887 g_cbkLdrDyldMainStack = cbStack;
888 g_fkLdrDyldMainStackAllocated = 1;
889 }
890 else
891 rc = KLDR_ERR_MAIN_STACK_ALLOC_FAILED;
892 }
893 else
894 {
895 KLDRDYLDMOD_ASSERT(StackInfo.uLoadAddress != ~(uintmax_t)0);
896 KLDRDYLDMOD_ASSERT(StackInfo.cbStack > 0);
897
898 g_fkLdrDyldMainStackAllocated = 0;
899 g_pvkLdrDyldMainStack = (void *)(uintptr_t)StackInfo.uLoadAddress;
900 KLDRDYLDMOD_ASSERT((uintptr_t)g_pvkLdrDyldMainStack == StackInfo.uLoadAddress);
901
902 g_cbkLdrDyldMainStack = (size_t)StackInfo.cbStack;
903 KLDRDYLDMOD_ASSERT(StackInfo.cbStack == g_cbkLdrDyldMainStack);
904 }
905 }
906 if (!rc)
907 g_fkLdrDyldDoneMainStack = 1;
908 }
909
910 if (!rc)
911 {
912 if (ppvStack)
913 *ppvStack = g_pvkLdrDyldMainStack;
914 if (pcbStack)
915 *pcbStack = g_cbkLdrDyldMainStack;
916 }
917
918 return rc;
919}
920
921
922/**
923 * This starts the executable module.
924 *
925 * @returns non-zero OS or kLdr status code on failure.
926 * (won't return on success.)
927 * @param pMod The executable module.
928 */
929int kldrDyldModStartExe(PKLDRDYLDMOD pMod)
930{
931 int rc;
932 uintmax_t uValue;
933 void *pvStack;
934 size_t cbStack;
935 KLDRDYLDMOD_ASSERT(pMod->fExecutable);
936
937 rc = kLdrModQueryMainEntrypoint(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &uValue);
938 if (rc)
939 return rc;
940 rc = kldrDyldModGetMainStack(pMod, &pvStack, &cbStack);
941 if (rc)
942 return rc;
943 return kldrDyldOSStartExe((uintptr_t)uValue, pvStack, cbStack);
944}
945
946
947/**
948 * Gets the module name.
949 *
950 * @returns 0 on success, KLDR_ERR_BUFFER_OVERFLOW on failure.
951 * @param pMod The module.
952 * @param pszName Where to store the name.
953 * @param cchName The size of the name buffer.
954 */
955int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, size_t cchName)
956{
957 size_t cch = KLDR_MIN(cchName, pMod->pMod->cchName + 1);
958 if (cch)
959 {
960 kLdrHlpMemCopy(pszName, pMod->pMod->pszName, cch - 1);
961 pszName[cch - 1] = '\0';
962 }
963 return cchName <= pMod->pMod->cchName ? KLDR_ERR_BUFFER_OVERFLOW : 0;
964}
965
966
967/**
968 * Gets the module filename.
969 *
970 * @returns 0 on success, KLDR_ERR_BUFFER_OVERFLOW on failure.
971 * @param pMod The module.
972 * @param pszFilename Where to store the filename.
973 * @param cchFilename The size of the filename buffer.
974 */
975int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename)
976{
977 size_t cch = KLDR_MIN(cchFilename, pMod->pMod->cchFilename + 1);
978 if (cch)
979 {
980 kLdrHlpMemCopy(pszFilename, pMod->pMod->pszFilename, cch - 1);
981 pszFilename[cch - 1] = '\0';
982 }
983 return cchFilename <= pMod->pMod->cchFilename ? KLDR_ERR_BUFFER_OVERFLOW : 0;
984}
985
986
987/**
988 * Gets the address/value of a symbol in the specified module.
989 *
990 * @returns 0 on success, KLDR_ERR_SYMBOL_NOT_FOUND on failure.
991 * @param pMod The module.
992 * @param uSymbolOrdinal The symbol ordinal 0. This is ignored if the name is non-zero.
993 * @param pszSymbolName The symbol name. Can be NULL.
994 * @param puValue Where to store the value. optional.
995 * @param pfKind Where to store the symbol kind. optional.
996 */
997int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName,
998 uintptr_t *puValue, uint32_t *pfKind)
999{
1000 int rc;
1001 uintmax_t uValue = 0;
1002 uint32_t fKind = 0;
1003
1004 rc = kLdrModQuerySymbol(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
1005 pszSymbolName ? pszSymbolName : (const char *)uSymbolOrdinal, &uValue, pfKind);
1006 if (!rc)
1007 {
1008 if (puValue)
1009 {
1010 *puValue = (uintptr_t)uValue;
1011 KLDRDYLDMOD_ASSERT(*puValue == uValue);
1012 }
1013 if (pfKind)
1014 *pfKind = fKind;
1015 }
1016
1017 return rc;
1018}
1019
Note: See TracBrowser for help on using the repository browser.