source: trunk/kStuff/kLdr/kLdrDyld.c@ 3576

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

adding some missing stuff. kHlp\Bare\kHlpBareHeap.c

  • Property svn:keywords set to Id
File size: 48.5 KB
Line 
1/* $Id: kLdrDyld.c 3576 2007-09-02 20:23:54Z bird $ */
2/** @file
3 *
4 * kLdr - The Dynamic Loader.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird@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* Header Files *
30*******************************************************************************/
31#include <k/kLdr.h>
32#include "kLdrInternal.h"
33
34
35/*******************************************************************************
36* Defined Constants And Macros *
37*******************************************************************************/
38/** @def KLDRDYLD_STRICT
39 * Define KLDRDYLD_STRICT to enabled strict checks in kLdrDyld. */
40#define KLDRDYLD_STRICT 1
41
42/** @def KLDRDYLD_ASSERT
43 * Assert that an expression is true when KLDRDYLD_STRICT is defined.
44 */
45#ifdef KLDRDYLD_STRICT
46# define KLDRDYLD_ASSERT(expr) kHlpAssert(expr)
47#else
48# define KLDRDYLD_ASSERT(expr) do {} while (0)
49#endif
50
51
52/*******************************************************************************
53* Structures and Typedefs *
54*******************************************************************************/
55
56
57/*******************************************************************************
58* Global Variables *
59*******************************************************************************/
60/** Pointer to the executable module.
61 * (This is exported, so no prefix.) */
62PKLDRDYLDMOD kLdrDyldExe = NULL;
63/** Pointer to the head module (the executable).
64 * (This is exported, so no prefix.) */
65PKLDRDYLDMOD kLdrDyldHead = NULL;
66/** Pointer to the tail module.
67 * (This is exported, so no prefix.) */
68PKLDRDYLDMOD kLdrDyldTail = NULL;
69/** Pointer to the head module of the initialization list.
70 * The outermost load call will pop elements from this list in LIFO order (i.e.
71 * from the tail). The list is only used during non-recursive initialization
72 * and may therefore share the pNext/pPrev members with the termination list
73 * since we don't push a module onto the termination list untill it has been
74 * successfully initialized. */
75PKLDRDYLDMOD g_pkLdrDyldInitHead;
76/** Pointer to the tail module of the initalization list.*/
77PKLDRDYLDMOD g_pkLdrDyldInitTail;
78/** Pointer to the head module of the termination order list.
79 * This is a LIFO just like the the init list. */
80PKLDRDYLDMOD g_pkLdrDyldTermHead;
81/** Pointer to the tail module of the termination order list. */
82PKLDRDYLDMOD g_pkLdrDyldTermTail;
83/** Pointer to the head module of the bind order list.
84 * The modules in this list makes up the global namespace used when binding symbol unix fashion. */
85PKLDRDYLDMOD g_pkLdrDyldBindHead;
86/** Pointer to the tail module of the bind order list. */
87PKLDRDYLDMOD g_pkLdrDyldBindTail;
88
89/** Flag indicating bootstrap time.
90 * When set the error behaviour changes. Any kind of serious failure
91 * is fatal and will terminate the process. */
92int g_fBootstrapping;
93/** The global error buffer. */
94char g_szkLdrDyldError[1024];
95
96/** The default flags. */
97KU32 kLdrDyldFlags = 0;
98/** The default search method. */
99KLDRDYLDSEARCH kLdrDyldSearch = KLDRDYLD_SEARCH_HOST;
100
101
102/** @name The main stack.
103 * @{ */
104/** Indicates that the other MainStack globals have been filled in. */
105unsigned g_fkLdrDyldDoneMainStack = 0;
106/** Whether the stack was allocated seperatly or was part of the executable. */
107unsigned g_fkLdrDyldMainStackAllocated = 0;
108/** Pointer to the main stack object. */
109void *g_pvkLdrDyldMainStack = NULL;
110/** The size of the main stack object. */
111KSIZE g_cbkLdrDyldMainStack = 0;
112/** @} */
113
114
115/** The load stack.
116 * This contains frames with modules affected by active loads.
117 *
118 * Each kLdrDyldLoad and kLdrDyldLoadExe call will create a new stack frame containing
119 * all the modules involved in the operation. The modules will be ordered in recursive
120 * init order within the frame.
121 */
122static PPKLDRDYLDMOD g_papStackMods;
123/** The number of used entries in the g_papStackMods array. */
124static KU32 g_cStackMods;
125/** The number of entries allocated for the g_papStackMods array. */
126static KU32 g_cStackModsAllocated;
127/** Number of active load calls. */
128static KU32 g_cActiveLoadCalls;
129/** Number of active unload calls. */
130static KU32 g_cActiveUnloadCalls;
131/** Total number of load calls. */
132static KU32 g_cTotalLoadCalls;
133/** Total mumber of unload calls. */
134static KU32 g_cTotalUnloadCalls;
135/** Boolean flag indicating that GC is active. */
136static KU32 g_fActiveGC;
137
138
139
140/*******************************************************************************
141* Internal Functions *
142*******************************************************************************/
143/** @name API worker routines.
144 * @internal
145 * @{ */
146void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack);
147static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
148 unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr);
149static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix,
150 KLDRDYLDSEARCH enmSearch, unsigned fFlags);
151static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
152 KLDRDYLDSEARCH enmSearch, unsigned fFlags);
153static int kldrDyldDoUnload(PKLDRDYLDMOD pMod);
154static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
155 unsigned fFlags, PPKLDRDYLDMOD ppMod);
156static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment);
157static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName);
158static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename);
159static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind);
160/** @} */
161
162/** @name Misc load/unload workers
163 * @internal
164 * @{
165 */
166static void kldrDyldDoModuleTerminationAndGarabageCollection(void);
167/** @} */
168
169/** @name The load stack.
170 * @internal
171 * @{ */
172static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pMod);
173static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod);
174static int kldrDyldStackFrameCompleted(void);
175static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc);
176static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc);
177/** @} */
178
179static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr);
180
181
182
183/**
184 * Initialize the dynamic loader.
185 */
186int kldrDyldInit(void)
187{
188 kLdrDyldHead = kLdrDyldTail = NULL;
189 g_pkLdrDyldTermHead = g_pkLdrDyldTermTail = NULL;
190 g_pkLdrDyldBindHead = g_pkLdrDyldBindTail = NULL;
191 kLdrDyldFlags = 0;
192 g_szkLdrDyldError[0] = '\0';
193
194 g_fkLdrDyldDoneMainStack = 0;
195 g_fkLdrDyldMainStackAllocated = 0;
196 g_pvkLdrDyldMainStack = NULL;
197 g_cbkLdrDyldMainStack = 0;
198
199 return kldrDyldFindInit();
200}
201
202
203/**
204 * Terminate the dynamic loader.
205 */
206void kldrDyldTerm(void)
207{
208
209}
210
211
212/**
213 * Bootstrap an executable.
214 *
215 * This is called from the executable stub to replace the stub and run the
216 * executable specified in the argument package.
217 *
218 * Since this is boostrap time there isn't anything to return to. So, instead
219 * the process will be terminated upon failure.
220 *
221 * We also have to keep in mind that this function is called on a small, small,
222 * stack and therefore any kind of large stack objects or deep recursions must
223 * be avoided. Since loading the executable will involve more or less all
224 * operations in the loader, this restriction really applies everywhere.
225 *
226 * @param pArgs Pointer to the argument package residing in the executable stub.
227 * @param pvOS OS specific argument.
228 */
229#ifndef __OS2__ /* kLdrDyldLoadExe is implemented in assembly on OS/2. */
230void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS)
231#else
232void kldrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS)
233#endif
234{
235 void *pvStack;
236 KSIZE cbStack;
237 PKLDRDYLDMOD pExe;
238 int rc;
239
240 /*
241 * Indicate that we're boostrapping and ensure that initialization was successful.
242 */
243 g_fBootstrapping = 1;
244 rc = kldrInit();
245 if (rc)
246 kldrDyldFailure(rc, "Init failure, rc=%d", rc);
247
248 /*
249 * Validate the argument package.
250 */
251 if (pArgs->fFlags & ~( KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS
252 | KLDRYDLD_LOAD_FLAGS_DEEP_SYMBOLS
253 | KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT
254 | KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
255 kldrDyldFailure(KLDR_ERR_INVALID_PARAMETER, "Bad fFlags=%#x", pArgs->fFlags);
256 if ( pArgs->enmSearch <= KLDRDYLD_SEARCH_INVALID
257 || pArgs->enmSearch >= KLDRDYLD_SEARCH_END)
258 kldrDyldFailure(KLDR_ERR_INVALID_PARAMETER, "Bad enmSearch=%d", pArgs->enmSearch);
259
260 /*
261 * Set defaults.
262 */
263 kLdrDyldFlags |= (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT);
264 kLdrDyldSearch = pArgs->enmSearch;
265
266 /** @todo make sense of this default prefix/suffix stuff. */
267 if (pArgs->szDefPrefix[0] != '\0')
268 kHlpMemCopy(kLdrDyldDefPrefix, pArgs->szDefPrefix, K_MIN(sizeof(pArgs->szDefPrefix), sizeof(kLdrDyldDefPrefix)));
269 if (pArgs->szDefSuffix[0] != '\0')
270 kHlpMemCopy(kLdrDyldDefSuffix, pArgs->szDefSuffix, K_MIN(sizeof(pArgs->szDefSuffix), sizeof(kLdrDyldDefSuffix)));
271
272 /** @todo append that path to the one for the specified search method. */
273 /** @todo create a function for doing this, an exposed api preferably. */
274 /* append path */
275 cbStack = sizeof(kLdrDyldLibraryPath) - kHlpStrLen(kLdrDyldLibraryPath); /* borrow cbStack for a itty bit. */
276 kHlpMemCopy(kLdrDyldLibraryPath, pArgs->szLibPath, K_MIN(sizeof(pArgs->szLibPath), cbStack));
277 kLdrDyldLibraryPath[sizeof(kLdrDyldLibraryPath) - 1] = '\0';
278
279 /*
280 * Make sure we own the loader semaphore (necessary for init).
281 */
282 rc = kLdrDyldSemRequest();
283 if (rc)
284 kldrDyldFailure(rc, "Sem req. failure, rc=%d", rc);
285
286 /*
287 * Open and map the executable module before we join paths with kLdrDyldLoad().
288 */
289 rc = kldrDyldFindNewModule(pArgs->szExecutable, NULL, NULL, pArgs->enmSearch,
290 pArgs->fFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE, &pExe);
291 if (rc)
292 kldrDyldFailure(rc, "Can't find/open the executable '%s', rc=%d", pArgs->szExecutable, rc);
293 rc = kldrDyldModMap(pExe);
294 if (rc)
295 kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc);
296
297 kLdrDyldExe = pExe;
298
299 /*
300 * Query the stack and go to OS specific code to
301 * setup and switch stack. The OS specific code will call us
302 * back at kldrDyldDoLoadExe.
303 */
304 rc = kldrDyldModGetMainStack(pExe, &pvStack, &cbStack);
305 if (rc)
306 kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc);
307 kldrDyldDoLoadExeStackSwitch(pExe, pvStack, cbStack);
308 kldrDyldFailure(-1, "Failed to setup the stack for '%s'.", pExe->pMod->pszFilename);
309}
310
311
312/**
313 * Loads a module into the current process.
314 *
315 * @returns 0 on success, non-zero native OS status code or kLdr status code on failure.
316 * @param pszDll The name of the dll to open.
317 * @param pszPrefix Prefix to use when searching.
318 * @param pszSuffix Suffix to use when searching.
319 * @param enmSearch Method to use when locating the module and any modules it may depend on.
320 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
321 * @param phMod Where to store the handle to the loaded module.
322 * @param pszErr Where to store extended error information. (optional)
323 * @param cchErr The size of the buffer pointed to by pszErr.
324 */
325int kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
326 unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr)
327{
328 int rc;
329
330 /* validate arguments and initialize return values. */
331 if (pszErr && cchErr)
332 *pszErr = '\0';
333 *phMod = NIL_HKLDRMOD;
334 K_VALIDATE_STRING(pszDll);
335 K_VALIDATE_OPTIONAL_STRING(pszPrefix);
336 K_VALIDATE_OPTIONAL_STRING(pszSuffix);
337 K_VALIDATE_ENUM(enmSearch, KLDRDYLD_SEARCH);
338 K_VALIDATE_OPTIONAL_BUFFER(pszErr, cchErr);
339
340 /* get the semaphore and do the job. */
341 rc = kLdrDyldSemRequest();
342 if (!rc)
343 {
344 PKLDRDYLDMOD pMod = NULL;
345 g_cTotalLoadCalls++;
346 g_cActiveLoadCalls++;
347 rc = kldrDyldDoLoad(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod, pszErr, cchErr);
348 g_cActiveLoadCalls--;
349 kldrDyldDoModuleTerminationAndGarabageCollection();
350 kLdrDyldSemRelease();
351 *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
352 }
353 return rc;
354}
355
356
357/**
358 * Unloads a module loaded by kLdrDyldLoad.
359 *
360 * @returns 0 on success, non-zero native OS status code or kLdr status code on failure.
361 * @param hMod Module handle.
362 */
363int kLdrDyldUnload(HKLDRMOD hMod)
364{
365 int rc;
366
367 /* validate */
368 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
369
370 /* get sem & do work */
371 rc = kLdrDyldSemRequest();
372 if (!rc)
373 {
374 g_cTotalUnloadCalls++;
375 g_cActiveUnloadCalls++;
376 rc = kldrDyldDoUnload(hMod);
377 g_cActiveUnloadCalls--;
378 kldrDyldDoModuleTerminationAndGarabageCollection();
379 kLdrDyldSemRelease();
380 }
381 return rc;
382}
383
384
385/**
386 * Finds a module by name or filename.
387 *
388 * This call does not increase any reference counters and must not be
389 * paired with kLdrDyldUnload() like kLdrDyldLoad().
390 *
391 * @returns 0 on success.
392 * @returns KLDR_ERR_MODULE_NOT_FOUND or some I/O error on failure.
393 * @param pszDll The name of the dll to look for.
394 * @param pszPrefix Prefix than can be used when searching.
395 * @param pszSuffix Suffix than can be used when searching.
396 * @param enmSearch Method to use when locating the module.
397 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
398 * @param phMod Where to store the handle of the module on success.
399 */
400int kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
401 unsigned fFlags, PHKLDRMOD phMod)
402{
403 int rc;
404
405 /* validate & initialize */
406 *phMod = NIL_HKLDRMOD;
407 K_VALIDATE_STRING(pszDll);
408
409 /* get sem & do work */
410 rc = kLdrDyldSemRequest();
411 if (!rc)
412 {
413 PKLDRDYLDMOD pMod = NULL;
414 rc = kldrDyldDoFindByName(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
415 kLdrDyldSemRelease();
416 *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
417 }
418 return rc;
419}
420
421
422/**
423 * Finds a module by address.
424 *
425 * This call does not increase any reference counters and must not be
426 * paired with kLdrDyldUnload() like kLdrDyldLoad().
427 *
428 * @returns 0 on success.
429 * @returns KLDR_ERR_MODULE_NOT_FOUND on failure.
430 * @param Address The address believed to be within some module.
431 * @param phMod Where to store the module handle on success.
432 * @param piSegment Where to store the segment number. (optional)
433 * @param poffSegment Where to store the offset into the segment. (optional)
434 */
435int kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment)
436{
437 int rc;
438
439 /* validate & initialize */
440 *phMod = NIL_HKLDRMOD;
441 if (piSegment)
442 *piSegment = ~(KU32)0;
443 if (poffSegment)
444 *poffSegment = ~(KUPTR)0;
445
446 /* get sem & do work */
447 rc = kLdrDyldSemRequest();
448 if (!rc)
449 {
450 PKLDRDYLDMOD pMod = NULL;
451 rc = kldrDyldDoFindByAddress(Address, &pMod, piSegment, poffSegment);
452 kLdrDyldSemRelease();
453 *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
454 }
455 return rc;
456}
457
458
459/**
460 * Gets the module name.
461 *
462 * @returns 0 on success and pszName filled with the name.
463 * @returns KLDR_ERR_INVALID_HANDLE or KLDR_ERR_BUFFER_OVERFLOW on failure.
464 * @param hMod The module handle.
465 * @param pszName Where to put the name.
466 * @param cchName The size of the name buffer.
467 * @see kLdrDyldGetFilename
468 */
469int kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName)
470{
471 int rc;
472
473 /* validate */
474 if (pszName && cchName)
475 *pszName = '\0';
476 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
477 K_VALIDATE_BUFFER(pszName, cchName);
478
479 /* get sem & do work */
480 rc = kLdrDyldSemRequest();
481 if (!rc)
482 {
483 rc = kldrDyldDoGetName(hMod, pszName, cchName);
484 kLdrDyldSemRelease();
485 }
486 return rc;
487}
488
489
490/**
491 * Gets the module filename.
492 *
493 * @returns 0 on success and pszFilename filled with the name.
494 * @returns KLDR_ERR_INVALID_HANDLE or KLDR_ERR_BUFFER_OVERFLOW on failure.
495 * @param hMod The module handle.
496 * @param pszFilename Where to put the filename.
497 * @param cchFilename The size of the filename buffer.
498 * @see kLdrDyldGetName
499 */
500int kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename)
501{
502 int rc;
503
504 /* validate & initialize */
505 if (pszFilename && cchFilename);
506 *pszFilename = '\0';
507 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
508 K_VALIDATE_BUFFER(pszFilename, cchFilename);
509
510 /* get sem & do work */
511 rc = kLdrDyldSemRequest();
512 if (!rc)
513 {
514 rc = kldrDyldDoGetFilename(hMod, pszFilename, cchFilename);
515 kLdrDyldSemRelease();
516 }
517 return rc;
518}
519
520
521/**
522 * Queries the value and type of a symbol.
523 *
524 * @returns 0 on success and pValue and pfKind set.
525 * @returns KLDR_ERR_INVALID_HANDLE or KLDR_ERR_SYMBOL_NOT_FOUND on failure.
526 * @param hMod The module handle.
527 * @param uSymbolOrdinal The symbol ordinal. This is ignored if pszSymbolName is non-zero.
528 * @param pszSymbolName The symbol name.
529 * @param pszSymbolVersion The symbol version. Optional.
530 * @param pValue Where to put the symbol value. Optional if pfKind is non-zero.
531 * @param pfKind Where to put the symbol kind flags. Optional if pValue is non-zero.
532 */
533int kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName,
534 const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind)
535{
536 int rc;
537
538 /* validate & initialize */
539 if (pfKind)
540 *pfKind = 0;
541 if (pValue)
542 *pValue = 0;
543 if (!pfKind && !pValue)
544 return KLDR_ERR_INVALID_PARAMETER;
545 KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
546 K_VALIDATE_OPTIONAL_STRING(pszSymbolName);
547
548 /* get sem & do work */
549 rc = kLdrDyldSemRequest();
550 if (!rc)
551 {
552 rc = kldrDyldDoQuerySymbol(hMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
553 kLdrDyldSemRelease();
554 }
555 return rc;
556}
557
558
559/**
560 * Worker kLdrDoLoadExe().
561 * Used after we've switch to the final process stack.
562 *
563 * @param pExe The executable module.
564 * @internal
565 */
566void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe)
567{
568 int rc;
569
570 /*
571 * Load the executable module with its prerequisites and initialize them.
572 */
573 g_cActiveLoadCalls++;
574 rc = kldrDyldDoLoad2(pExe, NULL, NULL, kLdrDyldSearch, kLdrDyldFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
575 if (rc)
576 kldrDyldFailure(rc, "load 2 failed for '%s', rc=%d", pExe->pMod->pszFilename);
577 g_cActiveLoadCalls--;
578 kldrDyldDoModuleTerminationAndGarabageCollection();
579
580 /*
581 * Invoke the executable entry point.
582 */
583 kldrDyldModStartExe(pExe);
584 kldrDyldFailure(-1, "failed to invoke main!");
585}
586
587
588/**
589 * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe().
590 * @internal
591 */
592static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
593 unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr)
594{
595 int rc;
596
597 /*
598 * Try find the module among the ones that's already loaded.
599 */
600 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
601 if (!rc)
602 {
603 switch ((*ppMod)->enmState)
604 {
605 /*
606 * Prerequisites are ok, so nothing to do really.
607 */
608 case KLDRSTATE_GOOD:
609 case KLDRSTATE_INITIALIZING:
610 return kldrDyldModDynamicLoad(*ppMod);
611
612 /*
613 * The module can't be loaded because it failed to initialize.
614 */
615 case KLDRSTATE_INITIALIZATION_FAILED:
616 return KLDR_ERR_MODULE_INIT_FAILED_ALREADY;
617
618 /*
619 * Prerequisites needs loading / reattaching and the module
620 * (may depending on fFlags) needs to be initialized.
621 */
622 case KLDRSTATE_PENDING_INITIALIZATION:
623 break;
624
625 /*
626 * Prerequisites needs to be loaded again
627 */
628 case KLDRSTATE_PENDING_TERMINATION:
629 break;
630
631 /*
632 * The module has been terminated so it need to be reloaded, have it's
633 * prereqs loaded, fixed up and initialized before we can use it again.
634 */
635 case KLDRSTATE_PENDING_GC:
636 rc = kldrDyldModReload(*ppMod);
637 if (rc)
638 return kldrDyldCopyError(rc, pszErr, cchErr);
639 break;
640
641 /*
642 * Forget it, we don't know how to deal with re-initialization here.
643 */
644 case KLDRSTATE_TERMINATING:
645 KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING");
646 return KLDR_ERR_MODULE_TERMINATING;
647
648 /*
649 * Invalid state.
650 */
651 default:
652 KLDRDYLD_ASSERT(!"invalid state");
653 break;
654 }
655 }
656 else
657 {
658 /*
659 * We'll have to load it from file.
660 */
661 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
662 if (rc)
663 return kldrDyldCopyError(rc, pszErr, cchErr);
664 rc = kldrDyldModMap(*ppMod);
665 }
666
667 /*
668 * Join cause with kLdrDyldLoadExe.
669 */
670 if (!rc)
671 rc = kldrDyldDoLoad2(*ppMod, pszPrefix, pszSuffix, enmSearch, fFlags);
672 else
673 kldrDyldStackCleanupOne(*ppMod, rc);
674
675 /*
676 * Copy any error or warning to the error buffer.
677 */
678 return kldrDyldCopyError(rc, pszErr, cchErr);
679}
680
681
682/**
683 * 2nd half of kLdrDyldLoad() and kLdrDyldLoadExe().
684 *
685 * @internal
686 */
687static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix,
688 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
689{
690 /*
691 * Load prerequisites.
692 */
693 KU32 i;
694 KU32 iLoad1st = kldrDyldStackNewFrame(pLoadedMod);
695 int rc = kldrDyldDoLoadPrerequisites(pLoadedMod, pszPrefix, pszSuffix, enmSearch, fFlags);
696 KU32 iLoadEnd = kldrDyldStackFrameCompleted();
697 if (rc)
698 {
699 kldrDyldModAddRef(pLoadedMod);
700 kldrDyldStackCleanupOne(pLoadedMod, rc); /* in case it didn't get pushed onto the stack. */
701 kldrDyldModDeref(pLoadedMod);
702 }
703
704 /*
705 * Apply fixups.
706 */
707 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
708 {
709 PKLDRDYLDMOD pMod = g_papStackMods[i];
710 if ( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
711 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES)
712 rc = kldrDyldModFixup(pMod);
713 }
714
715 /*
716 * Advance fixed up module onto initialization.
717 */
718 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
719 {
720 PKLDRDYLDMOD pMod = g_papStackMods[i];
721 if ( pMod->enmState == KLDRSTATE_FIXED_UP
722 || pMod->enmState == KLDRSTATE_RELOADED_FIXED_UP)
723 pMod->enmState = KLDRSTATE_PENDING_INITIALIZATION;
724 KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION
725 || pMod->enmState == KLDRSTATE_GOOD);
726 }
727
728 /*
729 * Call the initializers if we're loading in recursive mode or
730 * if we're the outermost load call.
731 */
732 if (fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
733 {
734 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
735 {
736 PKLDRDYLDMOD pMod = g_papStackMods[i];
737 if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION)
738 rc = kldrDyldModCallInit(pMod);
739 else if (pMod->enmState == KLDRSTATE_INITIALIZATION_FAILED)
740 rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY;
741 else
742 KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
743 }
744#ifdef KLDRDYLD_STRICT
745 for (i = iLoad1st; !rc && i < iLoadEnd; i++)
746 KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
747#endif
748 }
749 else if (g_cActiveLoadCalls <= 1)
750 {
751 while (!rc && g_pkLdrDyldInitHead)
752 {
753 PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead;
754 g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
755 if (pMod->InitTerm.pNext)
756 pMod->InitTerm.pNext->InitTerm.pPrev = NULL;
757 else
758 g_pkLdrDyldInitTail = NULL;
759 pMod->fInitList = 0;
760 rc = kldrDyldModCallInit(pMod);
761 }
762 }
763
764 /*
765 * Complete the load by incrementing the dynamic load count of the
766 * requested module (return handle is already set).
767 */
768 if (!rc)
769 {
770 if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)
771 {
772 pLoadedMod->cDepRefs++; /* just make it stick. */
773 pLoadedMod->cRefs++;
774 }
775 else
776 rc = kldrDyldModDynamicLoad(pLoadedMod);
777 }
778
779 kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc);
780 return rc;
781}
782
783
784/**
785 * kldrDyldDoLoad() helper which will load prerequisites and
786 * build the initialization array / list.
787 *
788 * @returns 0 on success, non-zero error code on failure.
789 * @param pMod The module to start at.
790 * @param pszPrefix Prefix to use when searching.
791 * @param pszSuffix Suffix to use when searching.
792 * @param enmSearch Method to use when locating the module and any modules it may depend on.
793 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
794 */
795static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
796 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
797{
798 static struct
799 {
800 /** The module. */
801 PKLDRDYLDMOD pMod;
802 /** The number of prerequisite modules left to process.
803 * This starts at ~0U to inidicate that we need to load/check prerequisistes. */
804 unsigned cLeft;
805 } s_aEntries[64];
806 unsigned cEntries;
807 int rc = 0;
808
809 /* Prerequisites are always global and they just aren't executables. */
810 fFlags &= ~(KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
811
812 /* push the first entry. */
813 s_aEntries[0].pMod = pMod;
814 s_aEntries[0].cLeft = ~0U;
815 cEntries = 1;
816
817 /*
818 * The recursion loop.
819 */
820 while (!rc && cEntries > 0)
821 {
822 const unsigned i = cEntries - 1;
823 pMod = s_aEntries[i].pMod;
824 if (s_aEntries[i].cLeft == ~0U)
825 {
826 /*
827 * Load prerequisite modules.
828 */
829 switch (pMod->enmState)
830 {
831 /*
832 * Load immediate prerequisite modules and push the ones needing
833 * attention onto the stack.
834 */
835 case KLDRSTATE_MAPPED:
836 case KLDRSTATE_RELOADED:
837 case KLDRSTATE_PENDING_TERMINATION:
838 rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags);
839 KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_GOOD
840 || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES
841 || pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
842 || rc);
843 if (!rc)
844 s_aEntries[i].cLeft = pMod->cPrereqs;
845 break;
846
847 /*
848 * Check its prerequisite modules the first time around.
849 */
850 case KLDRSTATE_PENDING_INITIALIZATION:
851 if (pMod->fAlreadySeen)
852 break;
853 pMod->fAlreadySeen = 1;
854 s_aEntries[i].cLeft = pMod->cPrereqs;
855 break;
856
857 /*
858 * These are ok.
859 */
860 case KLDRSTATE_LOADED_PREREQUISITES:
861 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
862 case KLDRSTATE_INITIALIZING:
863 case KLDRSTATE_GOOD:
864 s_aEntries[i].cLeft = 0;
865 break;
866
867 /*
868 * All other stats are invalid.
869 */
870 default:
871 KLDRDYLD_ASSERT(!"invalid state");
872 break;
873 }
874 }
875 else if (s_aEntries[i].cLeft > 0)
876 {
877 /*
878 * Recurse down into the next prereq.
879 */
880 KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs);
881 if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0]))
882 {
883 s_aEntries[cEntries].cLeft = ~(KU32)0;
884 s_aEntries[cEntries].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft];
885 s_aEntries[i].cLeft--;
886 cEntries++;
887 }
888 else
889 rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY;
890 }
891 else
892 {
893 /*
894 * We're done with this module, record it for init/cleanup.
895 */
896 cEntries--;
897 if (pMod->enmState != KLDRSTATE_GOOD)
898 {
899 kldrDyldStackAddModule(pMod);
900 if ( !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
901 && !pMod->fInitList)
902 {
903 pMod->fInitList = 1;
904 pMod->InitTerm.pNext = NULL;
905 pMod->InitTerm.pPrev = g_pkLdrDyldInitTail;
906 if (g_pkLdrDyldInitTail)
907 g_pkLdrDyldInitTail->InitTerm.pNext = pMod;
908 else
909 g_pkLdrDyldInitHead = pMod;
910 g_pkLdrDyldInitTail = pMod;
911 }
912 }
913 }
914 }
915
916 return rc;
917}
918
919
920/**
921 * Gets prerequisite module.
922 *
923 * This will try load the requested module if necessary, returning it in the MAPPED state.
924 *
925 * @returns 0 on success.
926 * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure.
927 * @param pszDll The name of the dll to look for.
928 * @param pszPrefix Prefix than can be used when searching.
929 * @param pszSuffix Suffix than can be used when searching.
930 * @param enmSearch Method to use when locating the module.
931 * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
932 * @param pDep The depentant module.
933 * @param ppMod Where to put the module we get.
934 */
935int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
936 unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod)
937{
938 int rc;
939 PKLDRDYLDMOD pMod;
940
941 *ppMod = NULL;
942
943 /*
944 * Try find the module among the ones that's already loaded.
945 *
946 * This is very similar to the kldrDyldDoLoad code, except it has to deal with
947 * a couple of additional states and occurs only during prerequisite loading
948 * and the action taken is a little bit different.
949 */
950 rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
951 if (!rc)
952 {
953 switch (pMod->enmState)
954 {
955 /*
956 * These are good.
957 */
958 case KLDRSTATE_MAPPED:
959 case KLDRSTATE_RELOADED:
960 case KLDRSTATE_LOADED_PREREQUISITES:
961 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
962 case KLDRSTATE_PENDING_INITIALIZATION:
963 case KLDRSTATE_INITIALIZING:
964 case KLDRSTATE_GOOD:
965 case KLDRSTATE_PENDING_TERMINATION:
966 break;
967
968 /*
969 * The module has been terminated so it need to be reloaded, have it's
970 * prereqs loaded, fixed up and initialized before we can use it again.
971 */
972 case KLDRSTATE_PENDING_GC:
973 rc = kldrDyldModReload(pMod);
974 break;
975
976 /*
977 * The module can't be loaded because it failed to initialize already.
978 */
979 case KLDRSTATE_INITIALIZATION_FAILED:
980 rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED;
981 break;
982
983 /*
984 * Forget it, no idea how to deal with re-initialization.
985 */
986 case KLDRSTATE_TERMINATING:
987 return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING;
988
989 /*
990 * Invalid state.
991 */
992 default:
993 KLDRDYLD_ASSERT(!"invalid state");
994 break;
995 }
996 }
997 else
998 {
999 /*
1000 * We'll have to load it from file.
1001 */
1002 rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
1003 if (!rc)
1004 rc = kldrDyldModMap(pMod);
1005 }
1006
1007 /*
1008 * On success add dependency.
1009 */
1010 if (!rc)
1011 {
1012 kldrDyldModAddDep(pMod, pDep);
1013 *ppMod = pMod;
1014 }
1015 return rc;
1016}
1017
1018
1019/**
1020 * Starts a new load stack frame.
1021 *
1022 * @returns Where the new stack frame starts.
1023 * @param pLoadMod The module being loaded (only used for asserting).
1024 */
1025static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod)
1026{
1027 /*
1028 * Clear the fAlreadySeen flags.
1029 */
1030 PKLDRDYLDMOD pMod = kLdrDyldHead;
1031 while (pMod)
1032 {
1033 pMod->fAlreadySeen = 0;
1034
1035#ifdef KLDRDYLD_ASSERT
1036 switch (pMod->enmState)
1037 {
1038 case KLDRSTATE_MAPPED:
1039 case KLDRSTATE_RELOADED:
1040 /* only the just loaded module can be in this state. */
1041 KLDRDYLD_ASSERT(pMod == pLoadMod);
1042 break;
1043
1044 case KLDRSTATE_PENDING_INITIALIZATION:
1045 case KLDRSTATE_INITIALIZING:
1046 case KLDRSTATE_PENDING_TERMINATION:
1047 case KLDRSTATE_PENDING_GC:
1048 case KLDRSTATE_TERMINATING:
1049 case KLDRSTATE_INITIALIZATION_FAILED:
1050 case KLDRSTATE_PENDING_DESTROY:
1051 /* requires recursion. */
1052 KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1);
1053 break;
1054
1055 case KLDRSTATE_GOOD:
1056 /* requires nothing. */
1057 break;
1058
1059 default:
1060 KLDRDYLD_ASSERT(!"Invalid state");
1061 break;
1062 }
1063#endif
1064
1065 /* next */
1066 pMod = pMod->Load.pNext;
1067 }
1068 return g_cStackMods;
1069}
1070
1071
1072/**
1073 * Records the module.
1074 *
1075 * @return 0 on success, KLDR_ERR_NO_MEMORY if we can't expand the table.
1076 * @param pMod The module to record.
1077 */
1078static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod)
1079{
1080 /*
1081 * Grow the stack if necessary.
1082 */
1083 if (g_cStackMods + 1 > g_cStackModsAllocated)
1084 {
1085 KU32 cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
1086 void *pvOld = g_papStackMods;
1087 void *pvNew = kHlpAlloc(cNew * sizeof(g_papStackMods[0]));
1088 if (!pvNew)
1089 return KLDR_ERR_NO_MEMORY;
1090 kHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
1091 g_papStackMods = (PPKLDRDYLDMOD)pvNew;
1092 kHlpFree(pvOld);
1093 }
1094
1095 /*
1096 * Add a reference and push the module onto the stack.
1097 */
1098 kldrDyldModAddRef(pMod);
1099 g_papStackMods[g_cStackMods++] = pMod;
1100 return 0;
1101}
1102
1103
1104/**
1105 * The frame has been completed.
1106 *
1107 * @returns Where the frame ends.
1108 */
1109static int kldrDyldStackFrameCompleted(void)
1110{
1111 return g_cStackMods;
1112}
1113
1114
1115/**
1116 * Worker routine for kldrDyldStackDropFrame() and kldrDyldDoLoad().
1117 *
1118 * @param pMod The module to perform cleanups on.
1119 * @param rc Used for state verification.
1120 */
1121static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc)
1122{
1123 switch (pMod->enmState)
1124 {
1125 /*
1126 * Just push it along to the PENDING_DESTROY state.
1127 */
1128 case KLDRSTATE_MAPPED:
1129 KLDRDYLD_ASSERT(rc);
1130 kldrDyldModUnmap(pMod);
1131 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1132 break;
1133
1134 /*
1135 * Move back to PENDING_GC.
1136 */
1137 case KLDRSTATE_RELOADED:
1138 KLDRDYLD_ASSERT(rc);
1139 pMod->enmState = KLDRSTATE_PENDING_GC;
1140 break;
1141
1142 /*
1143 * Unload prerequisites and unmap the modules.
1144 */
1145 case KLDRSTATE_LOADED_PREREQUISITES:
1146 case KLDRSTATE_FIXED_UP:
1147 KLDRDYLD_ASSERT(rc);
1148 kldrDyldModUnloadPrerequisites(pMod);
1149 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1150 kldrDyldModUnmap(pMod);
1151 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1152 break;
1153
1154 /*
1155 * Unload prerequisites and push it back to PENDING_GC.
1156 */
1157 case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
1158 case KLDRSTATE_RELOADED_FIXED_UP:
1159 kldrDyldModUnloadPrerequisites(pMod);
1160 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC);
1161 break;
1162
1163 /*
1164 * Nothing to do, just asserting sanity.
1165 */
1166 case KLDRSTATE_INITIALIZING:
1167 /* Implies there is another load going on. */
1168 KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1);
1169 break;
1170 case KLDRSTATE_TERMINATING:
1171 /* GC in progress. */
1172 KLDRDYLD_ASSERT(g_fActiveGC);
1173 break;
1174 case KLDRSTATE_PENDING_TERMINATION:
1175 case KLDRSTATE_PENDING_INITIALIZATION:
1176 case KLDRSTATE_PENDING_GC:
1177 case KLDRSTATE_PENDING_DESTROY:
1178 KLDRDYLD_ASSERT(rc);
1179 break;
1180 case KLDRSTATE_GOOD:
1181 break;
1182
1183 /*
1184 * Bad states.
1185 */
1186 default:
1187 KLDRDYLD_ASSERT(!"drop frame bad state (a)");
1188 break;
1189 }
1190}
1191
1192
1193/**
1194 * Done with the stack frame, dereference all the modules in it.
1195 *
1196 * @param iLoad1st The start of the stack frame.
1197 * @param iLoadEnd The end of the stack frame.
1198 * @param rc Used for state verification.
1199 */
1200static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc)
1201{
1202 KU32 i;
1203 KLDRDYLD_ASSERT(iLoad1st <= g_cStackMods);
1204 KLDRDYLD_ASSERT(iLoadEnd == g_cStackMods);
1205
1206 /*
1207 * First pass: Do all the cleanups we can, but don't destroy anything just yet.
1208 */
1209 i = iLoadEnd;
1210 while (i-- > iLoad1st)
1211 {
1212 PKLDRDYLDMOD pMod = g_papStackMods[i];
1213 kldrDyldStackCleanupOne(pMod, rc);
1214 }
1215
1216 /*
1217 * Second pass: Release the references so modules pending destruction
1218 * can be completely removed.
1219 */
1220 for (i = iLoad1st; i < iLoadEnd ; i++)
1221 {
1222 PKLDRDYLDMOD pMod = g_papStackMods[i];
1223
1224 /*
1225 * Revalidate the module state.
1226 */
1227 switch (pMod->enmState)
1228 {
1229 case KLDRSTATE_INITIALIZING:
1230 case KLDRSTATE_TERMINATING:
1231 case KLDRSTATE_PENDING_TERMINATION:
1232 case KLDRSTATE_PENDING_INITIALIZATION:
1233 case KLDRSTATE_PENDING_GC:
1234 case KLDRSTATE_PENDING_DESTROY:
1235 case KLDRSTATE_GOOD:
1236 break;
1237 default:
1238 KLDRDYLD_ASSERT(!"drop frame bad state (b)");
1239 break;
1240 }
1241
1242 /*
1243 * Release it.
1244 */
1245 kldrDyldModDeref(pMod);
1246 }
1247
1248 /*
1249 * Drop the stack frame.
1250 */
1251 g_cStackMods = iLoad1st;
1252}
1253
1254
1255/**
1256 * Do garbage collection.
1257 *
1258 * This isn't doing anything unless it's called from the last
1259 * load or unload call.
1260 */
1261static void kldrDyldDoModuleTerminationAndGarabageCollection(void)
1262{
1263 PKLDRDYLDMOD pMod;
1264
1265 /*
1266 * We don't do anything until we're got rid of all recursive calls.
1267 * This will ensure that we get the most optimal termination order and
1268 * that we don't unload anything too early.
1269 */
1270 if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC)
1271 return;
1272 g_fActiveGC = 1;
1273
1274 do
1275 {
1276 /*
1277 * 1. Release prerequisites for any left over modules.
1278 */
1279 for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
1280 {
1281 kldrDyldModAddRef(pMod);
1282
1283 switch (pMod->enmState)
1284 {
1285 case KLDRSTATE_GOOD:
1286 case KLDRSTATE_PENDING_GC:
1287 case KLDRSTATE_PENDING_TERMINATION:
1288 break;
1289
1290 case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */
1291 case KLDRSTATE_PENDING_INITIALIZATION:
1292 kldrDyldModUnloadPrerequisites(pMod);
1293 break;
1294
1295 default:
1296 KLDRDYLD_ASSERT(!"invalid GC state (a)");
1297 break;
1298 }
1299
1300 kldrDyldModDeref(pMod);
1301 }
1302
1303 /*
1304 * 2. Do init calls until we encounter somebody calling load/unload.
1305 */
1306 for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext)
1307 {
1308 int fRestart = 0;
1309 kldrDyldModAddRef(pMod);
1310
1311 switch (pMod->enmState)
1312 {
1313 case KLDRSTATE_GOOD:
1314 case KLDRSTATE_PENDING_GC:
1315 break;
1316
1317 case KLDRSTATE_PENDING_TERMINATION:
1318 {
1319 const KU32 cTotalLoadCalls = g_cTotalLoadCalls;
1320 const KU32 cTotalUnloadCalls = g_cTotalUnloadCalls;
1321 kldrDyldModCallTerm(pMod);
1322 fRestart = cTotalLoadCalls != g_cTotalLoadCalls
1323 || cTotalUnloadCalls != g_cTotalUnloadCalls;
1324 break;
1325 }
1326
1327 default:
1328 KLDRDYLD_ASSERT(!"invalid GC state (b)");
1329 break;
1330 }
1331
1332 kldrDyldModDeref(pMod);
1333 if (fRestart)
1334 break;
1335 }
1336 } while (pMod);
1337
1338 /*
1339 * Unmap and destroy modules pending for GC.
1340 */
1341 pMod = kLdrDyldHead;
1342 while (pMod)
1343 {
1344 PKLDRDYLDMOD pNext = pMod->Load.pNext;
1345 kldrDyldModAddRef(pMod);
1346
1347 switch (pMod->enmState)
1348 {
1349 case KLDRSTATE_INITIALIZATION_FAILED:
1350 case KLDRSTATE_PENDING_GC:
1351 KLDRDYLD_ASSERT(!pMod->cDepRefs);
1352 KLDRDYLD_ASSERT(!pMod->cDynRefs);
1353 pMod->enmState = KLDRSTATE_GC;
1354 kldrDyldModUnmap(pMod);
1355 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
1356 kldrDyldModDestroy(pMod);
1357 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED);
1358 break;
1359
1360 case KLDRSTATE_GOOD:
1361 break;
1362 default:
1363 KLDRDYLD_ASSERT(!"invalid GC state (c)");
1364 break;
1365 }
1366
1367 kldrDyldModDeref(pMod);
1368
1369 /* next */
1370 pMod = pNext;
1371 }
1372
1373 g_fActiveGC = 0;
1374}
1375
1376
1377/**
1378 * Worker for kLdrDyldUnload().
1379 * @internal
1380 */
1381static int kldrDyldDoUnload(PKLDRDYLDMOD pMod)
1382{
1383 return kldrDyldModDynamicUnload(pMod);
1384}
1385
1386
1387/**
1388 * Worker for kLdrDyldFindByName().
1389 * @internal
1390 */
1391static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
1392 unsigned fFlags, PPKLDRDYLDMOD ppMod)
1393{
1394 return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
1395}
1396
1397
1398/**
1399 * Worker for kLdrDyldFindByAddress().
1400 * @internal
1401 */
1402static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment)
1403{
1404 /* Scan the segments of each module in the load list. */
1405 PKLDRDYLDMOD pMod = kLdrDyldHead;
1406 while (pMod)
1407 {
1408 KU32 iSeg;
1409 for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++)
1410 {
1411 KLDRADDR off = (KLDRADDR)Address - pMod->pMod->aSegments[iSeg].MapAddress;
1412 if (off < pMod->pMod->aSegments[iSeg].cb)
1413 {
1414 *ppMod = pMod->hMod;
1415 if (piSegment)
1416 *piSegment = iSeg;
1417 if (poffSegment)
1418 *poffSegment = (KUPTR)off;
1419 return 0;
1420 }
1421 }
1422
1423 /* next */
1424 pMod = pMod->Load.pNext;
1425 }
1426
1427 return KLDR_ERR_MODULE_NOT_FOUND;
1428}
1429
1430
1431/**
1432 * Worker for kLdrDyldGetName().
1433 * @internal
1434 */
1435static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName)
1436{
1437 return kldrDyldModGetName(pMod, pszName, cchName);
1438}
1439
1440
1441/**
1442 * Worker for kLdrDyldGetFilename().
1443 * @internal
1444 */
1445static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename)
1446{
1447 return kldrDyldModGetFilename(pMod, pszFilename, cchFilename);
1448}
1449
1450
1451/**
1452 * Worker for kLdrDyldQuerySymbol().
1453 * @internal
1454 */
1455static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind)
1456{
1457 return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
1458}
1459
1460
1461/**
1462 * Panic / failure
1463 *
1464 * @returns rc if we're in a position where we can return.
1465 * @param rc Return code.
1466 * @param pszFormat Message string. Limited fprintf like formatted.
1467 * @param ... Message string arguments.
1468 */
1469int kldrDyldFailure(int rc, const char *pszFilename, ...)
1470{
1471 /** @todo print it. */
1472 if (g_fBootstrapping);
1473 kHlpExit(1);
1474 return rc;
1475}
1476
1477
1478/**
1479 * Copies the error string to the user buffer.
1480 *
1481 * @returns rc.
1482 * @param rc The status code.
1483 * @param pszErr Where to copy the error string to.
1484 * @param cchErr The size of the destination buffer.
1485 */
1486static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr)
1487{
1488 KSIZE cchToCopy;
1489
1490 /* if no error string, format the rc into a string. */
1491 if (!g_szkLdrDyldError[0] && rc)
1492 kHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10);
1493
1494 /* copy it if we got something. */
1495 if (cchErr && pszErr && g_szkLdrDyldError[0])
1496 {
1497 cchToCopy = kHlpStrLen(g_szkLdrDyldError);
1498 if (cchToCopy >= cchErr)
1499 cchToCopy = cchErr - 1;
1500 kHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy);
1501 pszErr[cchToCopy] = '\0';
1502 }
1503
1504 return rc;
1505}
1506
Note: See TracBrowser for help on using the repository browser.