VirtualBox

source: kStuff/trunk/kLdr/kLdrDyldMod.c

Last change on this file was 81, checked in by bird, 8 years ago

kLdr: some refactoring and fixes.

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