3 * kLdr - The Dynamic Loader, Dyld module methods.
7 * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
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
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
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.
31 /*******************************************************************************
33 *******************************************************************************/
35 #include "kLdrInternal.h"
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
45 /** @def KLDRDYLDMOD_ASSERT
46 * Assert that an expression is true when KLDRDYLD_STRICT is defined.
48 #ifdef KLDRDYLDMOD_STRICT
49 # define KLDRDYLDMOD_ASSERT(expr) kHlpAssert(expr)
51 # define KLDRDYLDMOD_ASSERT(expr) do {} while (0)
54 /*******************************************************************************
55 * Internal Functions *
56 *******************************************************************************/
57 static void kldrDyldModUnlink(PKLDRDYLDMOD pMod
);
62 * Creates a module from the specified file provider instance.
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.
70 int kldrDyldModCreate(PKRDR pRdr
, KU32 fFlags
, PPKLDRDYLDMOD ppMod
)
78 /** @todo deal with fFlags (exec/dll) */
79 /** @todo Check up the cpu architecture. */
82 * Try open an module interpreter.
84 rc
= kLdrModOpenFromRdr(pRdr
, 0 /*fFlags*/, KCPUARCH_UNKNOWN
, &pRawMod
);
86 return kldrDyldFailure(rc
, "%s: %rc", kRdrName(pRdr
), rc
);
89 * Match the module aginst the load flags.
91 switch (pRawMod
->enmType
)
93 case KLDRTYPE_EXECUTABLE_FIXED
:
94 case KLDRTYPE_EXECUTABLE_RELOCATABLE
:
95 case KLDRTYPE_EXECUTABLE_PIC
:
96 if (!(fFlags
& KLDRDYLD_LOAD_FLAGS_EXECUTABLE
))
98 kLdrModClose(pRawMod
);
99 return KLDR_ERR_NOT_EXE
;
103 case KLDRTYPE_OBJECT
: /* We can handle these as DLLs. */
104 case KLDRTYPE_SHARED_LIBRARY_FIXED
:
105 case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
:
106 case KLDRTYPE_SHARED_LIBRARY_PIC
:
107 case KLDRTYPE_FORWARDER_DLL
:
108 if (fFlags
& KLDRDYLD_LOAD_FLAGS_EXECUTABLE
)
110 kLdrModClose(pRawMod
);
111 return KLDR_ERR_NOT_DLL
;
116 KLDRDYLDMOD_ASSERT(!"Bad enmType!");
118 return fFlags
& KLDRDYLD_LOAD_FLAGS_EXECUTABLE
? KLDR_ERR_NOT_EXE
: KLDR_ERR_NOT_DLL
;
122 * Allocate a new dyld module.
124 pMod
= (PKLDRDYLDMOD
)kHlpAlloc(sizeof(*pMod
));
127 pMod
->enmState
= KLDRSTATE_OPEN
;
128 pMod
->pMod
= pRawMod
;
130 pMod
->cDepRefs
= pMod
->cDynRefs
= pMod
->cRefs
= 0;
131 switch (pRawMod
->enmType
)
133 case KLDRTYPE_EXECUTABLE_FIXED
:
134 case KLDRTYPE_EXECUTABLE_RELOCATABLE
:
135 case KLDRTYPE_EXECUTABLE_PIC
:
136 pMod
->fExecutable
= 1;
139 pMod
->fExecutable
= 0;
142 pMod
->fGlobalOrSpecific
= 0;
145 pMod
->fAlreadySeen
= 0;
147 pMod
->fAllocatedTLS
= 0;
148 pMod
->f25Reserved
= 0;
149 pMod
->InitTerm
.pNext
= NULL
;
150 pMod
->InitTerm
.pPrev
= NULL
;
151 pMod
->Bind
.pNext
= NULL
;
152 pMod
->Bind
.pPrev
= NULL
;
154 pMod
->papPrereqs
= NULL
;
155 pMod
->u32MagicHead
= KLDRDYMOD_MAGIC
;
156 pMod
->u32MagicTail
= KLDRDYMOD_MAGIC
;
159 pMod
->Load
.pNext
= NULL
;
160 pMod
->Load
.pPrev
= kLdrDyldTail
;
162 kLdrDyldTail
->Load
.pNext
= pMod
;
167 /* deal with the remaining flags. */
168 if (fFlags
& KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE
)
169 kldrDyldModMarkSpecific(pMod
);
171 kldrDyldModMarkGlobal(pMod
);
173 if (fFlags
& KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS
)
174 kldrDyldModSetBindable(pMod
, 0 /* not deep binable */);
176 kldrDyldModClearBindable(pMod
);
186 kLdrModClose(pRawMod
);
194 * Creates a module for a native module.
196 * @returns 0 on success and *ppMod pointing to the new instance.
197 * On failure a non-zero kLdr status code is returned.
198 * @param hNativeModule The native handle.
199 * @param ppMod Where to put the pointer to the new module on success.
200 * @remark This function ain't finalized yet.
202 int kldrDyldModCreateNative(KUPTR hNativeModule
)
206 * Check if this module is already loaded by the native OS loader.
211 HMODULE hmod
= NULLHANDLE
;
212 APIRET rc
= DosQueryModuleHandle(kRdrName(pRdr
), &hmod
);
215 #elif K_OS == K_OS_WINDOWS
217 if (GetModuleHandle(kRdrName(pRdr
))
229 * Destroys a module pending destruction.
231 * @param pMod The module in question.
233 void kldrDyldModDestroy(PKLDRDYLDMOD pMod
)
238 * Validate the state.
240 switch (pMod
->enmState
)
242 case KLDRSTATE_PENDING_DESTROY
:
246 KLDRDYLDMOD_ASSERT(!"Invalid state");
249 KLDRDYLDMOD_ASSERT(!pMod
->fInitList
);
250 KLDRDYLDMOD_ASSERT(!pMod
->cDynRefs
);
251 KLDRDYLDMOD_ASSERT(!pMod
->cDepRefs
);
254 * Ensure that the module is unmapped.
256 if (pMod
->fAllocatedTLS
)
258 kLdrModFreeTLS(pMod
->pMod
, KLDRMOD_INT_MAP
);
259 pMod
->fAllocatedTLS
= 0;
263 rc
= kLdrModUnmap(pMod
->pMod
); KLDRDYLDMOD_ASSERT(!rc
);
268 * Ensure it's unlinked from all chains.
270 if (pMod
->enmState
< KLDRSTATE_PENDING_DESTROY
)
271 kldrDyldModUnlink(pMod
);
274 * Free everything associated with the module.
276 /* the prerequisite array. */
277 if (pMod
->papPrereqs
)
279 KU32 i
= pMod
->cPrereqs
;
282 KLDRDYLDMOD_ASSERT(pMod
->papPrereqs
[i
] == NULL
);
283 pMod
->papPrereqs
[i
] = NULL
;
286 kHlpFree(pMod
->papPrereqs
);
287 pMod
->papPrereqs
= NULL
;
291 /* the module interpreter. */
294 rc
= kLdrModClose(pMod
->pMod
); KLDRDYLDMOD_ASSERT(!rc
);
300 * Finally, change the module state and free the module if
301 * there are not more references to it. If somebody is still
302 * referencing it, postpone the freeing to Deref.
304 pMod
->enmState
= KLDRSTATE_DESTROYED
;
307 pMod
->u32MagicHead
= 1;
308 pMod
->u32MagicTail
= 2;
315 * Unlinks the module from any list it might be in.
316 * It is assumed that the module is at least linked into the load list.
318 * @param pMod The moduel.
320 static void kldrDyldModUnlink(PKLDRDYLDMOD pMod
)
323 if (pMod
->Load
.pNext
)
324 pMod
->Load
.pNext
->Load
.pPrev
= pMod
->Load
.pPrev
;
326 kLdrDyldTail
= pMod
->Load
.pPrev
;
327 if (pMod
->Load
.pPrev
)
328 pMod
->Load
.pPrev
->Load
.pNext
= pMod
->Load
.pNext
;
330 kLdrDyldHead
= pMod
->Load
.pNext
;
334 kldrDyldModClearBindable(pMod
);
339 KLDRDYLDMOD_ASSERT(pMod
->enmState
< KLDRSTATE_INITIALIZATION_FAILED
);
341 if (pMod
->InitTerm
.pNext
)
342 pMod
->InitTerm
.pNext
->InitTerm
.pPrev
= pMod
->InitTerm
.pPrev
;
344 g_pkLdrDyldInitTail
= pMod
->InitTerm
.pPrev
;
345 if (pMod
->InitTerm
.pPrev
)
346 pMod
->InitTerm
.pPrev
->InitTerm
.pNext
= pMod
->InitTerm
.pNext
;
348 g_pkLdrDyldInitHead
= pMod
->InitTerm
.pNext
;
350 else if (pMod
->enmState
> KLDRSTATE_INITIALIZATION_FAILED
)
352 KLDRDYLDMOD_ASSERT(pMod
->enmState
>= KLDRSTATE_GOOD
);
353 if (pMod
->InitTerm
.pNext
)
354 pMod
->InitTerm
.pNext
->InitTerm
.pPrev
= pMod
->InitTerm
.pPrev
;
356 g_pkLdrDyldTermTail
= pMod
->InitTerm
.pPrev
;
357 if (pMod
->InitTerm
.pPrev
)
358 pMod
->InitTerm
.pPrev
->InitTerm
.pNext
= pMod
->InitTerm
.pNext
;
360 g_pkLdrDyldTermHead
= pMod
->InitTerm
.pNext
;
362 pMod
->InitTerm
.pNext
= NULL
;
363 pMod
->InitTerm
.pPrev
= NULL
;
368 * Marks a module as bindable, i.e. it'll be considered when
369 * resolving names the unix way.
371 * @param pMod The module.
372 * @param fDeep When set the module will be inserted at the head of the
373 * module list used to resolve symbols. This means that the
374 * symbols in this module will be prefered of all the other
377 void kldrDyldModSetBindable(PKLDRDYLDMOD pMod
, unsigned fDeep
)
379 KLDRDYLDMOD_ASSERT(pMod
->enmState
>= KLDRSTATE_OPEN
&& pMod
->enmState
< KLDRSTATE_PENDING_GC
);
380 if (!pMod
->fBindable
)
385 pMod
->Bind
.pNext
= NULL
;
386 pMod
->Bind
.pPrev
= g_pkLdrDyldBindTail
;
387 if (g_pkLdrDyldBindTail
)
388 g_pkLdrDyldBindTail
->Bind
.pNext
= pMod
;
390 g_pkLdrDyldBindHead
= pMod
;
391 g_pkLdrDyldBindTail
= pMod
;
395 pMod
->Bind
.pPrev
= NULL
;
396 pMod
->Bind
.pNext
= g_pkLdrDyldBindHead
;
397 if (g_pkLdrDyldBindHead
)
398 g_pkLdrDyldBindHead
->Bind
.pPrev
= pMod
;
400 g_pkLdrDyldBindTail
= pMod
;
401 g_pkLdrDyldBindHead
= pMod
;
408 * Marks a module as not bindable, i.e. it will not be considered when
409 * resolving names the unix way.
411 * @param pMod The module.
413 void kldrDyldModClearBindable(PKLDRDYLDMOD pMod
)
415 KLDRDYLDMOD_ASSERT(pMod
->enmState
>= KLDRSTATE_OPEN
&& pMod
->enmState
< KLDRSTATE_PENDING_DESTROY
);
419 if (pMod
->Bind
.pPrev
)
420 pMod
->Bind
.pPrev
->Bind
.pNext
= pMod
->Bind
.pNext
;
422 g_pkLdrDyldBindHead
= pMod
->Bind
.pNext
;
423 if (pMod
->Bind
.pNext
)
424 pMod
->Bind
.pNext
->Bind
.pPrev
= pMod
->Bind
.pPrev
;
426 g_pkLdrDyldBindTail
= pMod
->Bind
.pPrev
;
427 pMod
->Bind
.pNext
= NULL
;
428 pMod
->Bind
.pPrev
= NULL
;
434 * Marks the module as global instead of being specific.
436 * A global module can be a matching result when the request
437 * doesn't specify a path. A specific module will not match
438 * unless the path also matches.
440 * @param pMod The module.
442 void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod
)
444 pMod
->fGlobalOrSpecific
= 1;
449 * Marks the module as specific instead of global.
451 * See kldrDyldModMarkGlobal for an explanation of the two terms.
453 * @param pMod The module.
455 void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod
)
457 pMod
->fGlobalOrSpecific
= 0;
462 * Adds a reference to the module making sure it won't be freed just yet.
464 * @param pMod The module.
466 void kldrDyldModAddRef(PKLDRDYLDMOD pMod
)
473 * Dereference a module.
477 void kldrDyldModDeref(PKLDRDYLDMOD pMod
)
480 KLDRDYLDMOD_ASSERT(pMod
->cRefs
> 0);
481 KLDRDYLDMOD_ASSERT(pMod
->cRefs
>= pMod
->cDepRefs
+ pMod
->cDynRefs
);
482 KLDRDYLDMOD_ASSERT(pMod
->enmState
> KLDRSTATE_INVALID
&& pMod
->enmState
<= KLDRSTATE_END
);
488 /* execute delayed freeing. */
489 if ( pMod
->enmState
== KLDRSTATE_DESTROYED
492 pMod
->u32MagicHead
= 1;
493 pMod
->u32MagicTail
= 2;
500 * Increment the count of modules depending on this module.
502 * @param pMod The module.
503 * @param pDep The module which depends on us.
505 void kldrDyldModAddDep(PKLDRDYLDMOD pMod
, PKLDRDYLDMOD pDep
)
510 switch (pMod
->enmState
)
512 case KLDRSTATE_MAPPED
:
513 case KLDRSTATE_RELOADED
:
514 case KLDRSTATE_LOADED_PREREQUISITES
:
515 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES
:
516 case KLDRSTATE_PENDING_INITIALIZATION
:
517 case KLDRSTATE_INITIALIZING
:
521 KLDRDYLDMOD_ASSERT(!"invalid state");
525 KLDRDYLDMOD_ASSERT(pMod
->enmState
> KLDRSTATE_INVALID
&& pMod
->enmState
<= KLDRSTATE_END
);
534 * @param pMod The module.
535 * @param pDep The module which depends on us.
537 void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod
, PKLDRDYLDMOD pDep
)
539 KLDRDYLDMOD_ASSERT(pMod
->cDepRefs
> 0);
540 if (pMod
->cDepRefs
== 0)
542 KLDRDYLDMOD_ASSERT(pMod
->cDepRefs
<= pMod
->cRefs
);
543 KLDRDYLDMOD_ASSERT(pMod
->enmState
>= KLDRSTATE_MAPPED
&& pMod
->enmState
<= KLDRSTATE_PENDING_DESTROY
);
547 if ( pMod
->cDepRefs
> 0
548 || pMod
->cDynRefs
> 0)
552 * The module should be unloaded.
554 kldrDyldModUnloadPrerequisites(pMod
);
559 * Increment the dynamic load count.
562 * @param pMod The module.
564 int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod
)
566 KLDRDYLDMOD_ASSERT( pMod
->enmState
== KLDRSTATE_GOOD
567 || pMod
->enmState
== KLDRSTATE_PENDING_INITIALIZATION
568 || pMod
->enmState
== KLDRSTATE_INITIALIZING
);
576 * Decrement the dynamic load count of the module and unload the module
577 * if the total reference count reaches zero.
579 * This may cause a cascade of unloading to occure. See kldrDyldModUnloadPrerequisites().
581 * @returns status code.
582 * @retval 0 on success.
583 * @retval KLDR_ERR_NOT_LOADED_DYNAMICALLY if the module wasn't loaded dynamically.
584 * @param pMod The module to unload.
586 int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod
)
588 if (pMod
->cDynRefs
== 0)
589 return KLDR_ERR_NOT_LOADED_DYNAMICALLY
;
590 KLDRDYLDMOD_ASSERT(pMod
->cDynRefs
<= pMod
->cRefs
);
591 KLDRDYLDMOD_ASSERT(pMod
->enmState
== KLDRSTATE_GOOD
);
595 if ( pMod
->cDynRefs
> 0
596 || pMod
->cDepRefs
> 0)
600 * The module should be unloaded.
602 kldrDyldModUnloadPrerequisites(pMod
);
608 * Worker for kldrDyldModUnloadPrerequisites.
610 * @returns The number of modules that now can be unloaded.
611 * @param pMod The module in question.
613 static KU32
kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod
)
619 KLDRDYLDMOD_ASSERT(pMod
->papPrereqs
|| !pMod
->cPrereqs
);
622 * Release the one in this module.
624 for (i
= 0; i
< pMod
->cPrereqs
; i
++)
626 pMod2
= pMod
->papPrereqs
[i
];
629 pMod
->papPrereqs
[i
] = NULL
;
631 /* do the derefering ourselves or we'll end up in a recursive loop here. */
632 KLDRDYLDMOD_ASSERT(pMod2
->cDepRefs
> 0);
633 KLDRDYLDMOD_ASSERT(pMod2
->cRefs
>= pMod2
->cDepRefs
);
636 cToUnload
+= !pMod2
->cDepRefs
&& !pMod2
->cDynRefs
;
643 switch (pMod
->enmState
)
645 case KLDRSTATE_LOADED_PREREQUISITES
:
646 case KLDRSTATE_FIXED_UP
:
647 pMod
->enmState
= KLDRSTATE_PENDING_DESTROY
;
648 kldrDyldModUnlink(pMod
);
651 case KLDRSTATE_PENDING_INITIALIZATION
:
652 pMod
->enmState
= KLDRSTATE_PENDING_GC
;
655 case KLDRSTATE_RELOADED_FIXED_UP
:
656 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES
:
658 pMod
->enmState
= KLDRSTATE_PENDING_TERMINATION
;
661 case KLDRSTATE_INITIALIZATION_FAILED
:
665 KLDRDYLDMOD_ASSERT(!"invalid state");
674 * This is the heart of the unload code.
676 * It will recursivly (using the load list) initiate module unloading
677 * of all affected modules.
679 * This function will cause a state transition to PENDING_DESTROY, PENDING_GC
680 * or PENDING_TERMINATION depending on the module state. There is one exception
681 * to this, and that's INITIALIZATION_FAILED, where the state will not be changed.
683 * @param pMod The module which prerequisites should be unloaded.
685 void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod
)
690 #ifdef KLDRDYLD_STRICT
693 for (pMod2
= kLdrDyldHead
; pMod2
; pMod2
= pMod2
->Load
.pNext
)
694 KLDRDYLDMOD_ASSERT(pMod2
->enmState
!= KLDRSTATE_GOOD
|| pMod2
->cRefs
);
697 KLDRDYLDMOD_ASSERT(pMod
->papPrereqs
);
700 * Unload prereqs of the module we're called on first.
702 cToUnload
= kldrDyldModUnloadPrerequisitesOne(pMod
);
705 * Iterate the load list in a cyclic manner until there are no more
706 * modules that can be pushed on into unloading.
711 for (pMod
= kLdrDyldHead
; pMod
; pMod
= pMod
->Load
.pNext
)
715 || pMod
->enmState
>= KLDRSTATE_PENDING_TERMINATION
716 || pMod
->enmState
< KLDRSTATE_LOADED_PREREQUISITES
)
718 cToUnload
+= kldrDyldModUnloadPrerequisitesOne(pMod
);
725 * Loads the prerequisite modules this module depends on.
727 * To find each of the prerequisite modules this method calls
728 * kldrDyldGetPrerequisite() and it will make sure the modules
729 * are added to the load stack frame.
731 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
732 * The state is changed to LOADED_PREREQUISITES or RELOADED_LOADED_PREREQUISITES.
733 * @param pMod The module.
734 * @param pszPrefix Prefix to use when searching.
735 * @param pszSuffix Suffix to use when searching.
736 * @param enmSearch Method to use when locating the module and any modules it may depend on.
737 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
739 int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod
, const char *pszPrefix
, const char *pszSuffix
,
740 KLDRDYLDSEARCH enmSearch
, unsigned fFlags
)
747 switch (pMod
->enmState
)
749 case KLDRSTATE_MAPPED
:
750 case KLDRSTATE_RELOADED
:
753 KLDRDYLDMOD_ASSERT(!"invalid state");
758 * Query number of prerequiste modules and allocate the array.
760 cPrereqs
= kLdrModNumberOfImports(pMod
->pMod
, NULL
);
761 kHlpAssert(cPrereqs
>= 0);
762 if (pMod
->cPrereqs
!= cPrereqs
)
764 KLDRDYLDMOD_ASSERT(!pMod
->papPrereqs
);
765 pMod
->papPrereqs
= (PPKLDRDYLDMOD
)kHlpAllocZ(sizeof(pMod
->papPrereqs
[0]) * cPrereqs
);
766 if (!pMod
->papPrereqs
)
767 return KERR_NO_MEMORY
;
768 pMod
->cPrereqs
= cPrereqs
;
771 KLDRDYLDMOD_ASSERT(pMod
->papPrereqs
|| !pMod
->cPrereqs
);
774 * Iterate the prerequisites and load them.
776 for (i
= 0; i
< pMod
->cPrereqs
; i
++)
778 static char s_szPrereq
[260];
779 PKLDRDYLDMOD pPrereqMod
;
781 KLDRDYLDMOD_ASSERT(pMod
->papPrereqs
[i
] == NULL
);
782 rc
= kLdrModGetImport(pMod
->pMod
, NULL
, i
, s_szPrereq
, sizeof(s_szPrereq
));
785 rc
= kldrDyldGetPrerequisite(s_szPrereq
, pszPrefix
, pszSuffix
, enmSearch
, fFlags
, pMod
, &pPrereqMod
);
788 pMod
->papPrereqs
[i
] = pPrereqMod
;
791 /* change the state regardless of what happend. */
792 if (pMod
->enmState
== KLDRSTATE_MAPPED
)
793 pMod
->enmState
= KLDRSTATE_LOADED_PREREQUISITES
;
795 pMod
->enmState
= KLDRSTATE_RELOADED_LOADED_PREREQUISITES
;
801 * Maps an open module.
803 * On success the module will be in the MAPPED state.
805 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
806 * @param pMod The module which needs to be unmapped and set pending for destruction.
808 int kldrDyldModMap(PKLDRDYLDMOD pMod
)
813 KLDRDYLDMOD_ASSERT(pMod
->enmState
== KLDRSTATE_OPEN
);
814 KLDRDYLDMOD_ASSERT(!pMod
->fMapped
);
819 rc
= kLdrModMap(pMod
->pMod
);
822 rc
= kLdrModAllocTLS(pMod
->pMod
, KLDRMOD_INT_MAP
);
827 pMod
->enmState
= KLDRSTATE_MAPPED
;
830 kLdrModUnmap(pMod
->pMod
);
837 * Unmaps the module, unlinks it from everywhere marks it PENDING_DESTROY.
839 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
840 * @param pMod The module which needs to be unmapped and set pending for destruction.
842 int kldrDyldModUnmap(PKLDRDYLDMOD pMod
)
847 KLDRDYLDMOD_ASSERT(pMod
->cRefs
> 0);
848 KLDRDYLDMOD_ASSERT(pMod
->fMapped
);
849 switch (pMod
->enmState
)
851 case KLDRSTATE_MAPPED
:
853 case KLDRSTATE_PENDING_DESTROY
:
856 KLDRDYLDMOD_ASSERT(!"invalid state");
861 if (pMod
->fAllocatedTLS
)
863 kLdrModFreeTLS(pMod
->pMod
, KLDRMOD_INT_MAP
);
864 pMod
->fAllocatedTLS
= 0;
866 rc
= kLdrModUnmap(pMod
->pMod
);
870 if (pMod
->enmState
< KLDRSTATE_PENDING_DESTROY
)
872 pMod
->enmState
= KLDRSTATE_PENDING_DESTROY
;
873 kldrDyldModUnlink(pMod
);
882 * Reloads the module.
884 * Reloading means that all modified pages are restored to their original
885 * state. Whether this includes the code segments depends on whether the fixups
886 * depend on the addend in the place they are fixing up - so it's format specific.
888 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
889 * @param pMod The module which needs to be unmapped and set pending for destruction.
891 int kldrDyldModReload(PKLDRDYLDMOD pMod
)
896 KLDRDYLDMOD_ASSERT(pMod
->cRefs
> 0);
897 KLDRDYLDMOD_ASSERT(pMod
->fMapped
);
899 switch (pMod
->enmState
)
901 case KLDRSTATE_MAPPED
:
903 case KLDRSTATE_PENDING_DESTROY
:
906 KLDRDYLDMOD_ASSERT(!"invalid state");
910 /* Free TLS before reloading. */
911 if (pMod
->fAllocatedTLS
)
913 kLdrModFreeTLS(pMod
->pMod
, KLDRMOD_INT_MAP
);
914 pMod
->fAllocatedTLS
= 0;
917 /* Let the module interpreter do the reloading of the mapping. */
918 rc
= kLdrModReload(pMod
->pMod
);
921 rc
= kLdrModAllocTLS(pMod
->pMod
, KLDRMOD_INT_MAP
);
924 pMod
->fAllocatedTLS
= 1;
925 pMod
->enmState
= KLDRSTATE_RELOADED
;
933 * @copydoc FNKLDRMODGETIMPORT
934 * pvUser points to the KLDRDYLDMOD.
936 static int kldrDyldModFixupGetImportCallback(PKLDRMOD pMod
, KU32 iImport
, KU32 iSymbol
,
937 const char *pchSymbol
, KSIZE cchSymbol
, const char *pszVersion
,
938 PKLDRADDR puValue
, KU32
*pfKind
, void *pvUser
)
940 static int s_cRecursiveCalls
= 0;
941 PKLDRDYLDMOD pDyldMod
= (PKLDRDYLDMOD
)pvUser
;
944 /* guard against too deep forwarder recursion. */
945 if (s_cRecursiveCalls
>= 5)
946 return KLDR_ERR_TOO_LONG_FORWARDER_CHAIN
;
949 if (iImport
!= NIL_KLDRMOD_IMPORT
)
951 /* specific import module search. */
952 PKLDRDYLDMOD pPrereqMod
;
954 KLDRDYLDMOD_ASSERT(iImport
< pDyldMod
->cPrereqs
);
955 pPrereqMod
= pDyldMod
->papPrereqs
[iImport
];
957 KLDRDYLDMOD_ASSERT(pPrereqMod
);
958 KLDRDYLDMOD_ASSERT(pPrereqMod
->u32MagicHead
== KLDRDYMOD_MAGIC
);
959 KLDRDYLDMOD_ASSERT(pPrereqMod
->u32MagicTail
== KLDRDYMOD_MAGIC
);
960 KLDRDYLDMOD_ASSERT(pPrereqMod
->enmState
< KLDRSTATE_TERMINATING
);
962 rc
= kLdrModQuerySymbol(pPrereqMod
->pMod
, NULL
, KLDRMOD_BASEADDRESS_MAP
,
963 iSymbol
, pchSymbol
, cchSymbol
, pszVersion
,
964 kldrDyldModFixupGetImportCallback
, pPrereqMod
, puValue
, pfKind
);
968 kldrDyldFailure(rc
, "%s[%d]->%s.%.*s%s", pDyldMod
->pMod
->pszName
, iImport
,
969 pPrereqMod
->pMod
->pszName
, cchSymbol
, pchSymbol
, pszVersion
? pszVersion
: "");
971 kldrDyldFailure(rc
, "%s[%d]->%s.%d%s", pDyldMod
->pMod
->pszName
, iImport
,
972 pPrereqMod
->pMod
->pszName
, iSymbol
, pszVersion
? pszVersion
: "");
977 /* bind list search. */
979 PKLDRDYLDMOD pBindMod
= g_pkLdrDyldBindHead
;
985 rc
= kLdrModQuerySymbol(pBindMod
->pMod
, NULL
, KLDRMOD_BASEADDRESS_MAP
,
986 iSymbol
, pchSymbol
, cchSymbol
, pszVersion
,
987 kldrDyldModFixupGetImportCallback
, pBindMod
, &uValue
, &fKind
);
990 || !(fKind
& KLDRSYMKIND_WEAK
)
997 if (!(fKind
& KLDRSYMKIND_WEAK
))
1002 pBindMod
= pBindMod
->Bind
.pNext
;
1004 rc
= fFound
? 0 : KLDR_ERR_SYMBOL_NOT_FOUND
;
1008 kldrDyldFailure(rc
, "%s->%.*s%s", pDyldMod
->pMod
->pszName
, cchSymbol
, pchSymbol
, pszVersion
? pszVersion
: "");
1010 kldrDyldFailure(rc
, "%s->%d%s", pDyldMod
->pMod
->pszName
, iSymbol
, pszVersion
? pszVersion
: "");
1014 s_cRecursiveCalls
--;
1020 * Applies fixups to a module which prerequisistes has been
1021 * successfully loaded.
1023 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
1024 * @param pMod The module which needs to be unmapped and set pending for destruction.
1026 int kldrDyldModFixup(PKLDRDYLDMOD pMod
)
1031 KLDRDYLDMOD_ASSERT(pMod
->cRefs
> 0);
1032 KLDRDYLDMOD_ASSERT( pMod
->enmState
== KLDRSTATE_LOADED_PREREQUISITES
1033 || pMod
->enmState
== KLDRSTATE_RELOADED_LOADED_PREREQUISITES
);
1036 rc
= kLdrModFixupMapping(pMod
->pMod
, kldrDyldModFixupGetImportCallback
, pMod
);/** @todo fixme. */
1038 pMod
->enmState
= KLDRSTATE_FIXED_UP
;
1044 * Calls the module initialization entry point if any.
1046 * This is considered to be a module specific thing and leave if
1047 * to the module interpreter. They will have to deal with different
1048 * module init practices between platforms should there be any.
1050 * @returns 0 and state changed to GOOD on success.
1051 * Non-zero OS or kLdr status code and status changed to INITIALIZATION_FAILED on failure.
1052 * @param pMod The module that should be initialized.
1054 int kldrDyldModCallInit(PKLDRDYLDMOD pMod
)
1058 KLDRDYLDMOD_ASSERT(pMod
->enmState
== KLDRSTATE_PENDING_INITIALIZATION
);
1059 KLDRDYLDMOD_ASSERT(!pMod
->fInitList
);
1061 pMod
->enmState
= KLDRSTATE_INITIALIZING
;
1062 rc
= kLdrModCallInit(pMod
->pMod
, KLDRMOD_INT_MAP
, (KUPTR
)pMod
->hMod
);
1065 pMod
->enmState
= KLDRSTATE_GOOD
;
1066 /* push it onto the termination list.*/
1067 pMod
->InitTerm
.pPrev
= NULL
;
1068 pMod
->InitTerm
.pNext
= g_pkLdrDyldTermHead
;
1069 if (g_pkLdrDyldTermHead
)
1070 g_pkLdrDyldTermHead
->InitTerm
.pPrev
= pMod
;
1072 g_pkLdrDyldTermTail
= pMod
;
1073 g_pkLdrDyldTermHead
= pMod
;
1076 pMod
->enmState
= KLDRSTATE_INITIALIZATION_FAILED
;
1083 * Calls the module termination entry point if any.
1085 * This'll change the module status to PENDING_GC.
1087 * @param pMod The module that should be initialized.
1089 void kldrDyldModCallTerm(PKLDRDYLDMOD pMod
)
1091 KLDRDYLDMOD_ASSERT(pMod
->enmState
== KLDRSTATE_PENDING_TERMINATION
);
1093 pMod
->enmState
= KLDRSTATE_TERMINATING
;
1094 kLdrModCallTerm(pMod
->pMod
, KLDRMOD_INT_MAP
, (KUPTR
)pMod
->hMod
);
1095 pMod
->enmState
= KLDRSTATE_PENDING_GC
;
1096 /* unlinking on destruction. */
1101 * Calls the thread attach entry point if any.
1103 * @returns 0 on success, non-zero on failure.
1104 * @param pMod The module.
1106 int kldrDyldModAttachThread(PKLDRDYLDMOD pMod
)
1108 KLDRDYLDMOD_ASSERT(pMod
->enmState
== KLDRSTATE_GOOD
);
1110 return kLdrModCallThread(pMod
->pMod
, KLDRMOD_INT_MAP
, (KUPTR
)pMod
->hMod
, 1 /* attach */);
1115 * Calls the thread detach entry point if any.
1117 * @returns 0 on success, non-zero on failure.
1118 * @param pMod The module.
1120 void kldrDyldModDetachThread(PKLDRDYLDMOD pMod
)
1122 KLDRDYLDMOD_ASSERT(pMod
->enmState
== KLDRSTATE_GOOD
);
1124 kLdrModCallThread(pMod
->pMod
, KLDRMOD_INT_MAP
, (KUPTR
)pMod
->hMod
, 0 /* detach */);
1129 * Gets the main stack, allocate it if necessary.
1131 * @returns 0 on success, non-zero native OS or kLdr status code on failure.
1132 * @param pMod The module.
1133 * @param ppvStack Where to store the address of the stack (lowest address).
1134 * @param pcbStack Where to store the size of the stack.
1136 int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod
, void **ppvStack
, KSIZE
*pcbStack
)
1139 KLDRSTACKINFO StackInfo
;
1140 KLDRDYLDMOD_ASSERT(pMod
->fExecutable
);
1143 * Since we might have to allocate the stack ourselves, and there will only
1144 * ever be one main stack, we'll be keeping the main stack info in globals.
1146 if (!g_fkLdrDyldDoneMainStack
)
1148 rc
= kLdrModGetStackInfo(pMod
->pMod
, NULL
, KLDRMOD_BASEADDRESS_MAP
, &StackInfo
);
1151 /* check if there is a stack size override/default. */
1152 KSIZE cbDefOverride
;
1153 if (kHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride
))
1157 /* needs allocating? */
1158 if ( StackInfo
.LinkAddress
== NIL_KLDRADDR
1159 || StackInfo
.cbStack
< cbDefOverride
)
1161 KSIZE cbStack
= (KSIZE
)K_MAX(StackInfo
.cbStack
, cbDefOverride
);
1163 g_pvkLdrDyldMainStack
= kldrDyldOSAllocStack(cbStack
);
1164 if (g_pvkLdrDyldMainStack
)
1166 g_cbkLdrDyldMainStack
= cbStack
;
1167 g_fkLdrDyldMainStackAllocated
= 1;
1170 rc
= KLDR_ERR_MAIN_STACK_ALLOC_FAILED
;
1174 KLDRDYLDMOD_ASSERT(StackInfo
.Address
!= NIL_KLDRADDR
);
1175 KLDRDYLDMOD_ASSERT(StackInfo
.cbStack
> 0);
1177 g_fkLdrDyldMainStackAllocated
= 0;
1178 g_pvkLdrDyldMainStack
= (void *)(KUPTR
)StackInfo
.Address
;
1179 KLDRDYLDMOD_ASSERT((KUPTR
)g_pvkLdrDyldMainStack
== StackInfo
.Address
);
1181 g_cbkLdrDyldMainStack
= (KSIZE
)StackInfo
.cbStack
;
1182 KLDRDYLDMOD_ASSERT(StackInfo
.cbStack
== g_cbkLdrDyldMainStack
);
1186 g_fkLdrDyldDoneMainStack
= 1;
1192 *ppvStack
= g_pvkLdrDyldMainStack
;
1194 *pcbStack
= g_cbkLdrDyldMainStack
;
1202 * This starts the executable module.
1204 * @returns non-zero OS or kLdr status code on failure.
1205 * (won't return on success.)
1206 * @param pMod The executable module.
1208 int kldrDyldModStartExe(PKLDRDYLDMOD pMod
)
1211 KLDRADDR MainEPAddress
;
1214 KLDRDYLDMOD_ASSERT(pMod
->fExecutable
);
1216 rc
= kLdrModQueryMainEntrypoint(pMod
->pMod
, NULL
, KLDRMOD_BASEADDRESS_MAP
, &MainEPAddress
);
1219 rc
= kldrDyldModGetMainStack(pMod
, &pvStack
, &cbStack
);
1222 return kldrDyldOSStartExe((KUPTR
)MainEPAddress
, pvStack
, cbStack
);
1227 * Gets the module name.
1229 * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure.
1230 * @param pMod The module.
1231 * @param pszName Where to store the name.
1232 * @param cchName The size of the name buffer.
1234 int kldrDyldModGetName(PKLDRDYLDMOD pMod
, char *pszName
, KSIZE cchName
)
1236 KSIZE cch
= K_MIN(cchName
, pMod
->pMod
->cchName
+ 1);
1239 kHlpMemCopy(pszName
, pMod
->pMod
->pszName
, cch
- 1);
1240 pszName
[cch
- 1] = '\0';
1242 return cchName
<= pMod
->pMod
->cchName
? KERR_BUFFER_OVERFLOW
: 0;
1247 * Gets the module filename.
1249 * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure.
1250 * @param pMod The module.
1251 * @param pszFilename Where to store the filename.
1252 * @param cchFilename The size of the filename buffer.
1254 int kldrDyldModGetFilename(PKLDRDYLDMOD pMod
, char *pszFilename
, KSIZE cchFilename
)
1256 KSIZE cch
= K_MIN(cchFilename
, pMod
->pMod
->cchFilename
+ 1);
1259 kHlpMemCopy(pszFilename
, pMod
->pMod
->pszFilename
, cch
- 1);
1260 pszFilename
[cch
- 1] = '\0';
1262 return cchFilename
<= pMod
->pMod
->cchFilename
? KERR_BUFFER_OVERFLOW
: 0;
1267 * Gets the address/value of a symbol in the specified module.
1269 * @returns 0 on success, KLDR_ERR_SYMBOL_NOT_FOUND on failure.
1270 * @param pMod The module.
1271 * @param uSymbolOrdinal The symbol ordinal 0. This is ignored if the name is non-zero.
1272 * @param pszSymbolName The symbol name. Can be NULL.
1273 * @param puValue Where to store the value. optional.
1274 * @param pfKind Where to store the symbol kind. optional.
1276 int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod
, KU32 uSymbolOrdinal
, const char *pszSymbolName
,
1277 KUPTR
*puValue
, KU32
*pfKind
)
1280 KLDRADDR uValue
= 0;
1283 rc
= kLdrModQuerySymbol(pMod
->pMod
, NULL
, KLDRMOD_BASEADDRESS_MAP
,
1284 uSymbolOrdinal
, pszSymbolName
, kHlpStrLen(pszSymbolName
), NULL
,
1285 kldrDyldModFixupGetImportCallback
, pMod
,
1291 *puValue
= (KUPTR
)uValue
;
1292 KLDRDYLDMOD_ASSERT(*puValue
== uValue
);