source: trunk/kLdr/kLdrDyldMod.c@ 2869

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

the simple testcase works.

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