VirtualBox

source: kStuff/trunk/kLdr/kLdrDyldMod.c@ 29

Last change on this file since 29 was 29, checked in by bird, 16 years ago

Finally got around execute the switch to the MIT license.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette