source: trunk/kStuff/kLdr/kLdrDyldMod.c

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

license update.

  • Property svn:keywords set to Id
File size: 37.9 KB
RevLine 
[2878]1/* $Id: kLdrDyldMod.c 3601 2007-10-29 00:21:13Z bird $ */
[2835]2/** @file
3 * kLdr - The Dynamic Loader, Dyld module methods.
[3601]4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
[2835]8 *
[3601]9 * This file is part of kStuff.
[2835]10 *
[3601]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.
[2835]15 *
[3601]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.
[2835]21 *
[3601]22 * kStuff is distributed in the hope that it will be useful,
[2835]23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[3601]24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
[2835]26 *
[3601]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
[2835]31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
[3570]36#include <k/kLdr.h>
[2835]37#include "kLdrInternal.h"
38
39
[2837]40/*******************************************************************************
41* Defined Constants And Macros *
42*******************************************************************************/
[2845]43/** @def KLDRDYLDMOD_STRICT
44 * Define KLDRDYLDMOD_STRICT to enabled strict checks in kLdrDyld. */
45#define KLDRDYLDMOD_STRICT 1
46
[2837]47/** @def KLDRDYLDMOD_ASSERT
48 * Assert that an expression is true when KLDRDYLD_STRICT is defined.
49 */
[2845]50#ifdef KLDRDYLDMOD_STRICT
[3573]51# define KLDRDYLDMOD_ASSERT(expr) kHlpAssert(expr)
[2837]52#else
53# define KLDRDYLDMOD_ASSERT(expr) do {} while (0)
54#endif
[2835]55
[2847]56/*******************************************************************************
57* Internal Functions *
58*******************************************************************************/
59static void kldrDyldModUnlink(PKLDRDYLDMOD pMod);
[2835]60
61
[2847]62
[2842]63/**
[2845]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.
[2868]69 * @param fFlags Load/search flags.
[2845]70 * @param ppMod Where to put the pointer to the new module on success.
71 */
[3578]72int kldrDyldModCreate(PKRDR pRdr, KU32 fFlags, PPKLDRDYLDMOD ppMod)
[2845]73{
74 PKLDRDYLDMOD pMod;
75 PKLDRMOD pRawMod;
76 int rc;
77
78 *ppMod = NULL;
79
[2868]80/** @todo deal with fFlags (exec/dll) */
81
[2845]82 /*
83 * Try open an module interpreter.
84 */
85 rc = kLdrModOpenFromRdr(pRdr, &pRawMod);
86 if (rc)
[3578]87 return kldrDyldFailure(rc, "%s: %rc", kRdrName(pRdr), rc);
[2845]88
89 /*
[2870]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 /*
[2845]123 * Allocate a new dyld module.
124 */
[3573]125 pMod = (PKLDRDYLDMOD)kHlpAlloc(sizeof(*pMod));
[2845]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;
[2883]139 default:
140 pMod->fExecutable = 0;
141 break;
[2845]142 }
143 pMod->fGlobalOrSpecific = 0;
144 pMod->fBindable = 0;
145 pMod->fInitList = 0;
146 pMod->fAlreadySeen = 0;
147 pMod->fMapped = 0;
[2846]148 pMod->fAllocatedTLS = 0;
149 pMod->f25Reserved = 0;
[2845]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
[2870]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 */
[2845]182 *ppMod = pMod;
183 rc = 0;
184 }
185 else
186 {
187 kLdrModClose(pRawMod);
[3579]188 rc = KERR_NO_MEMORY;
[2845]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 */
[3567]203int kldrDyldModCreateNative(KUPTR hNativeModule)
[2845]204{
205#if 0
206 /*
207 * Check if this module is already loaded by the native OS loader.
208 */
209 rc = kld
210 {
[3582]211#if K_OS == K_OS_OS2
[2845]212 HMODULE hmod = NULLHANDLE;
[3578]213 APIRET rc = DosQueryModuleHandle(kRdrName(pRdr), &hmod);
[2845]214 if (!rc)
215
[3582]216#elif K_OS == K_OS_WINDOWS
[2845]217 HMODULE hmod = NULL;
[3578]218 if (GetModuleHandle(kRdrName(pRdr))
[2845]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{
[2847]236 int rc;
237
[2845]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 */
[2847]257 if (pMod->fAllocatedTLS)
258 {
259 kLdrModFreeTLS(pMod->pMod);
260 pMod->fAllocatedTLS = 0;
261 }
[2845]262 if (pMod->fMapped)
[2847]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 {
[3567]280 KU32 i = pMod->cPrereqs;
[2847]281 while (i-- > 0)
282 {
283 KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL);
284 pMod->papPrereqs[i] = NULL;
285 }
286
[3573]287 kHlpFree(pMod->papPrereqs);
[2847]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;
[3573]310 kHlpFree(pMod);
[2847]311 }
[2845]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/**
[2846]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/**
[2845]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)
[2847]492 {
493 pMod->u32MagicHead = 1;
494 pMod->u32MagicTail = 2;
[3573]495 kHlpFree(pMod);
[2847]496 }
[2845]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/**
[2842]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);
[2837]593
[2842]594 pMod->cRefs--;
595 pMod->cDynRefs--;
[2845]596 if ( pMod->cDynRefs > 0
597 || pMod->cDepRefs > 0)
[2842]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 */
[3567]614static KU32 kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod)
[2842]615{
616 PKLDRDYLDMOD pMod2;
[3567]617 KU32 cToUnload = 0;
618 KU32 i;
[2842]619
[2869]620 KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs);
[2842]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 {
[2847]630 pMod->papPrereqs[i] = NULL;
631
[2842]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--;
[2869]637 cToUnload += !pMod2->cDepRefs && !pMod2->cDynRefs;
[2842]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 *
[2845]680 * This function will cause a state transition to PENDING_DESTROY, PENDING_GC
[2842]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 */
[2837]686void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod)
687{
[3567]688 KU32 cToUnload;
[2837]689
[2842]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 {
[2869]714 if ( pMod->cDepRefs
715 || pMod->cDynRefs
[2842]716 || pMod->enmState >= KLDRSTATE_PENDING_TERMINATION
717 || pMod->enmState < KLDRSTATE_LOADED_PREREQUISITES)
718 continue;
719 cToUnload += kldrDyldModUnloadPrerequisitesOne(pMod);
720 }
721 }
[2837]722}
723
724
[2847]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 */
[2845]740int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
741 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
742{
[3567]743 KI32 cPrereqs;
744 KU32 i;
745 int rc = 0;
[2846]746
[2847]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 }
[2842]757
[2847]758 /*
759 * Query number of prerequiste modules and allocate the array.
760 */
[2848]761 cPrereqs = kLdrModNumberOfImports(pMod->pMod, NULL);
[3573]762 kHlpAssert(cPrereqs >= 0);
[2847]763 if (pMod->cPrereqs != cPrereqs)
764 {
765 KLDRDYLDMOD_ASSERT(!pMod->papPrereqs);
[3573]766 pMod->papPrereqs = (PPKLDRDYLDMOD)kHlpAllocZ(sizeof(pMod->papPrereqs[0]) * cPrereqs);
[2847]767 if (!pMod->papPrereqs)
[3579]768 return KERR_NO_MEMORY;
[2847]769 pMod->cPrereqs = cPrereqs;
770 }
771 else
772 KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs);
[2842]773
[2847]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);
[2848]783 rc = kLdrModGetImport(pMod->pMod, NULL, i, s_szPrereq, sizeof(s_szPrereq));
[2847]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;
[2845]798}
[2842]799
[2845]800
801/**
[2846]802 * Maps an open module.
[2845]803 *
[2846]804 * On success the module will be in the MAPPED state.
[2845]805 *
[2846]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.
[2845]808 */
[2846]809int kldrDyldModMap(PKLDRDYLDMOD pMod)
[2837]810{
[2846]811 int rc;
[2845]812
[2846]813 /* sanity */
814 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_OPEN);
815 KLDRDYLDMOD_ASSERT(!pMod->fMapped);
816 if (pMod->fMapped)
817 return 0;
[2845]818
[2846]819 /* do the job. */
820 rc = kLdrModMap(pMod->pMod);
821 if (!rc)
[2845]822 {
[2846]823 rc = kLdrModAllocTLS(pMod->pMod);
824 if (!rc)
[2845]825 {
[2846]826 /** @todo TLS */
827 pMod->fMapped = 1;
828 pMod->enmState = KLDRSTATE_MAPPED;
[2845]829 }
830 else
[2846]831 kLdrModUnmap(pMod->pMod);
[2845]832 }
[2846]833 return rc;
[2845]834}
835
836
837/**
[2846]838 * Unmaps the module, unlinks it from everywhere marks it PENDING_DESTROY.
[2845]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 */
[2846]843int kldrDyldModUnmap(PKLDRDYLDMOD pMod)
[2845]844{
845 int rc;
846
847 /* sanity */
[2837]848 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
[2846]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 }
[2837]860
[2845]861 /* do the job. */
[2847]862 if (pMod->fAllocatedTLS)
863 {
864 kLdrModFreeTLS(pMod->pMod);
865 pMod->fAllocatedTLS = 0;
866 }
867 rc = kLdrModUnmap(pMod->pMod);
[2845]868 if (!rc)
869 {
[2847]870 pMod->fMapped = 0;
871 if (pMod->enmState < KLDRSTATE_PENDING_DESTROY)
[2846]872 {
[2847]873 pMod->enmState = KLDRSTATE_PENDING_DESTROY;
874 kldrDyldModUnlink(pMod);
[2846]875 }
[2845]876 }
[2847]877
[2845]878 return rc;
879}
[2837]880
[2845]881
882/**
[2846]883 * Reloads the module.
[2845]884 *
[2846]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 *
[2845]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 */
[2846]892int kldrDyldModReload(PKLDRDYLDMOD pMod)
[2845]893{
894 int rc;
895
896 /* sanity */
897 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
898 KLDRDYLDMOD_ASSERT(pMod->fMapped);
[2846]899
[2837]900 switch (pMod->enmState)
901 {
902 case KLDRSTATE_MAPPED:
903 case KLDRSTATE_GC:
904 case KLDRSTATE_PENDING_DESTROY:
905 break;
906 default:
[2845]907 KLDRDYLDMOD_ASSERT(!"invalid state");
908 return -1;
[2837]909 }
910
[2847]911 /* Free TLS before reloading. */
912 if (pMod->fAllocatedTLS)
913 {
914 kLdrModFreeTLS(pMod->pMod);
915 pMod->fAllocatedTLS = 0;
916 }
917
[2846]918 /* Let the module interpreter do the reloading of the mapping. */
919 rc = kLdrModReload(pMod->pMod);
[2845]920 if (!rc)
[2837]921 {
[2847]922 rc = kLdrModAllocTLS(pMod->pMod);
[2846]923 if (!rc)
[2837]924 {
[2847]925 pMod->fAllocatedTLS = 1;
926 pMod->enmState = KLDRSTATE_RELOADED;
[2845]927 }
928 }
929 return rc;
930}
[2837]931
932
[2850]933/**
934 * @copydoc FNKLDRMODGETIMPORT
935 * pvUser points to the KLDRDYLDMOD.
936 */
[3567]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)
[2850]940{
[2854]941 static int s_cRecursiveCalls = 0;
942 PKLDRDYLDMOD pDyldMod = (PKLDRDYLDMOD)pvUser;
[2850]943 int rc;
[2846]944
[2854]945 /* guard against too deep forwarder recursion. */
946 if (s_cRecursiveCalls >= 5)
947 return KLDR_ERR_TOO_LONG_FORWARDER_CHAIN;
948 s_cRecursiveCalls++;
949
[2850]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,
[2893]964 iSymbol, pchSymbol, cchSymbol, pszVersion,
965 kldrDyldModFixupGetImportCallback, pPrereqMod, puValue, pfKind);
[2850]966 if (rc)
967 {
[2893]968 if (pchSymbol)
969 kldrDyldFailure(rc, "%s[%d]->%s.%.*s%s", pDyldMod->pMod->pszName, iImport,
970 pPrereqMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : "");
[2850]971 else
[2893]972 kldrDyldFailure(rc, "%s[%d]->%s.%d%s", pDyldMod->pMod->pszName, iImport,
973 pPrereqMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : "");
[2850]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 {
[3567]984 KU32 fKind;
[2850]985 KLDRADDR uValue;
986 rc = kLdrModQuerySymbol(pBindMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
[2893]987 iSymbol, pchSymbol, cchSymbol, pszVersion,
988 kldrDyldModFixupGetImportCallback, pBindMod, &uValue, &fKind);
[2850]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 {
[2893]1008 if (pchSymbol)
1009 kldrDyldFailure(rc, "%s->%.*s%s", pDyldMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : "");
[2850]1010 else
[2893]1011 kldrDyldFailure(rc, "%s->%d%s", pDyldMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : "");
[2850]1012 }
1013 }
1014
[2854]1015 s_cRecursiveCalls--;
[2850]1016 return rc;
1017}
1018
1019
[2845]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;
[2837]1030
[2845]1031 /* sanity */
1032 KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
1033 KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
1034 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES);
[2837]1035
[2845]1036 /* do the job */
[2883]1037 rc = kLdrModFixupMapping(pMod->pMod, kldrDyldModFixupGetImportCallback, pMod);/** @todo fixme. */
[2845]1038 if (!rc)
1039 pMod->enmState = KLDRSTATE_FIXED_UP;
1040 return rc;
1041}
[2837]1042
[2845]1043
[2846]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;
[2845]1058
[2869]1059 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION);
[2871]1060 KLDRDYLDMOD_ASSERT(!pMod->fInitList);
[2845]1061
[2869]1062 pMod->enmState = KLDRSTATE_INITIALIZING;
[3567]1063 rc = kLdrModCallInit(pMod->pMod, (KUPTR)pMod->hMod);
[2846]1064 if (!rc)
[2869]1065 {
[2846]1066 pMod->enmState = KLDRSTATE_GOOD;
[2869]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 }
[2846]1076 else
1077 pMod->enmState = KLDRSTATE_INITIALIZATION_FAILED;
[2845]1078
[2846]1079 return rc;
1080}
[2845]1081
[2846]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{
[2869]1092 KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_TERMINATION);
[2846]1093
[2869]1094 pMod->enmState = KLDRSTATE_TERMINATING;
[3567]1095 kLdrModCallTerm(pMod->pMod, (KUPTR)pMod->hMod);
[2846]1096 pMod->enmState = KLDRSTATE_PENDING_GC;
[2869]1097 /* unlinking on destruction. */
[2846]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
[3567]1111 return kLdrModCallThread(pMod->pMod, (KUPTR)pMod->hMod, 1 /* attach */);
[2846]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
[3567]1125 kLdrModCallThread(pMod->pMod, (KUPTR)pMod->hMod, 0 /* detach */);
[2846]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 */
[3567]1137int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, KSIZE *pcbStack)
[2846]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 {
[2848]1149 rc = kLdrModGetStackInfo(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &StackInfo);
[2846]1150 if (!rc)
1151 {
1152 /* check if there is a stack size override/default. */
[3567]1153 KSIZE cbDefOverride;
[3573]1154 if (kHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride))
[2846]1155 cbDefOverride = 0;
1156
1157
1158 /* needs allocating? */
[2848]1159 if ( StackInfo.LinkAddress == NIL_KLDRADDR
[2846]1160 || StackInfo.cbStack < cbDefOverride)
1161 {
[3569]1162 KSIZE cbStack = (KSIZE)K_MAX(StackInfo.cbStack, cbDefOverride);
[2846]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 {
[2848]1175 KLDRDYLDMOD_ASSERT(StackInfo.Address != NIL_KLDRADDR);
[2846]1176 KLDRDYLDMOD_ASSERT(StackInfo.cbStack > 0);
1177
1178 g_fkLdrDyldMainStackAllocated = 0;
[3567]1179 g_pvkLdrDyldMainStack = (void *)(KUPTR)StackInfo.Address;
1180 KLDRDYLDMOD_ASSERT((KUPTR)g_pvkLdrDyldMainStack == StackInfo.Address);
[2846]1181
[3567]1182 g_cbkLdrDyldMainStack = (KSIZE)StackInfo.cbStack;
[2846]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;
[2848]1212 KLDRADDR MainEPAddress;
[2846]1213 void *pvStack;
[3567]1214 KSIZE cbStack;
[2846]1215 KLDRDYLDMOD_ASSERT(pMod->fExecutable);
1216
[2848]1217 rc = kLdrModQueryMainEntrypoint(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &MainEPAddress);
[2846]1218 if (rc)
1219 return rc;
1220 rc = kldrDyldModGetMainStack(pMod, &pvStack, &cbStack);
1221 if (rc)
1222 return rc;
[3567]1223 return kldrDyldOSStartExe((KUPTR)MainEPAddress, pvStack, cbStack);
[2846]1224}
1225
1226
1227/**
1228 * Gets the module name.
1229 *
[3579]1230 * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure.
[2846]1231 * @param pMod The module.
1232 * @param pszName Where to store the name.
1233 * @param cchName The size of the name buffer.
1234 */
[3567]1235int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName)
[2846]1236{
[3569]1237 KSIZE cch = K_MIN(cchName, pMod->pMod->cchName + 1);
[2846]1238 if (cch)
1239 {
[3573]1240 kHlpMemCopy(pszName, pMod->pMod->pszName, cch - 1);
[2846]1241 pszName[cch - 1] = '\0';
1242 }
[3579]1243 return cchName <= pMod->pMod->cchName ? KERR_BUFFER_OVERFLOW : 0;
[2846]1244}
1245
1246
1247/**
1248 * Gets the module filename.
1249 *
[3579]1250 * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure.
[2846]1251 * @param pMod The module.
1252 * @param pszFilename Where to store the filename.
1253 * @param cchFilename The size of the filename buffer.
1254 */
[3567]1255int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename)
[2846]1256{
[3569]1257 KSIZE cch = K_MIN(cchFilename, pMod->pMod->cchFilename + 1);
[2846]1258 if (cch)
1259 {
[3573]1260 kHlpMemCopy(pszFilename, pMod->pMod->pszFilename, cch - 1);
[2846]1261 pszFilename[cch - 1] = '\0';
1262 }
[3579]1263 return cchFilename <= pMod->pMod->cchFilename ? KERR_BUFFER_OVERFLOW : 0;
[2846]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 */
[3567]1277int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName,
1278 KUPTR *puValue, KU32 *pfKind)
[2846]1279{
1280 int rc;
[2848]1281 KLDRADDR uValue = 0;
[3567]1282 KU32 fKind = 0;
[2846]1283
1284 rc = kLdrModQuerySymbol(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
[3573]1285 uSymbolOrdinal, pszSymbolName, kHlpStrLen(pszSymbolName), NULL,
[2893]1286 kldrDyldModFixupGetImportCallback, pMod,
[2854]1287 &uValue, &fKind);
[2846]1288 if (!rc)
1289 {
1290 if (puValue)
1291 {
[3567]1292 *puValue = (KUPTR)uValue;
[2846]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.