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

Last change on this file since 3578 was 3578, checked in by bird, 18 years ago

kLdrRdr cleanup.

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