VirtualBox

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

Last change on this file since 5 was 2, checked in by bird, 17 years ago

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

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

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