source: trunk/kLdr/kLdrDyldMod.c@ 2893

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

made it compile again.

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