10c0fea5dSIngo Weinhold /*
2aa3507feSIngo Weinhold * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3b6455c08SAxel Dörfler * Copyright 2003-2011, Axel Dörfler, axeld@pinc-software.de.
40c0fea5dSIngo Weinhold * Distributed under the terms of the MIT License.
50c0fea5dSIngo Weinhold *
60c0fea5dSIngo Weinhold * Copyright 2002, Manuel J. Petit. All rights reserved.
70c0fea5dSIngo Weinhold * Copyright 2001, Travis Geiselbrecht. All rights reserved.
80c0fea5dSIngo Weinhold * Distributed under the terms of the NewOS License.
90c0fea5dSIngo Weinhold */
100c0fea5dSIngo Weinhold
110c0fea5dSIngo Weinhold #include "runtime_loader_private.h"
120c0fea5dSIngo Weinhold
13ca618b22SIngo Weinhold #include <ctype.h>
140c85bd05SIngo Weinhold #include <dlfcn.h>
150c0fea5dSIngo Weinhold #include <stdio.h>
160c0fea5dSIngo Weinhold #include <stdlib.h>
1734982809SIngo Weinhold #include <string.h>
180c0fea5dSIngo Weinhold
19ca618b22SIngo Weinhold #include <OS.h>
20ca618b22SIngo Weinhold
217486b72dSIngo Weinhold #include <syscalls.h>
2210b4b5d1SIngo Weinhold #include <util/kernel_cpp.h>
237486b72dSIngo Weinhold
24f2bb2575SIngo Weinhold #include <locks.h>
25f2bb2575SIngo Weinhold
2694830eb2SIngo Weinhold #include "add_ons.h"
2794830eb2SIngo Weinhold #include "elf_load_image.h"
2894830eb2SIngo Weinhold #include "elf_symbol_lookup.h"
2944c0c4d3SPawel Dziepak #include "elf_tls.h"
3094830eb2SIngo Weinhold #include "elf_versioning.h"
3194830eb2SIngo Weinhold #include "errors.h"
3294830eb2SIngo Weinhold #include "images.h"
330c0fea5dSIngo Weinhold
340c0fea5dSIngo Weinhold
3510b4b5d1SIngo Weinhold // TODO: implement better locking strategy
3610b4b5d1SIngo Weinhold // TODO: implement lazy binding
370c0fea5dSIngo Weinhold
380c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen())
390c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE ((void*)-2l)
400c85bd05SIngo Weinhold
41f7127458SIngo Weinhold static const char* const kLockName = "runtime loader";
42f7127458SIngo Weinhold
430c0fea5dSIngo Weinhold
440c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
45354b60afSAugustin Cavalier typedef void (*initfini_array_function)();
460c0fea5dSIngo Weinhold
4794830eb2SIngo Weinhold bool gProgramLoaded = false;
4894830eb2SIngo Weinhold image_t* gProgramImage;
49003ebb0eSIngo Weinhold
5035fa85dbSJérôme Duval static image_t** sPreloadedAddons = NULL;
5135fa85dbSJérôme Duval static uint32 sPreloadedAddonCount = 0;
520c0fea5dSIngo Weinhold
53f7127458SIngo Weinhold static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName);
540c0fea5dSIngo Weinhold
557486b72dSIngo Weinhold
560c0fea5dSIngo Weinhold static const char *
find_dt_string(image_t * image,int32 d_tag)5743d1a0dcSJérôme Duval find_dt_string(image_t *image, int32 d_tag)
580c0fea5dSIngo Weinhold {
590c0fea5dSIngo Weinhold int i;
60e3ac2588SAlex Smith elf_dyn *d = (elf_dyn *)image->dynamic_ptr;
610c0fea5dSIngo Weinhold
620c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) {
6343d1a0dcSJérôme Duval if (d[i].d_tag == d_tag)
640c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val);
650c0fea5dSIngo Weinhold }
660c0fea5dSIngo Weinhold
670c0fea5dSIngo Weinhold return NULL;
680c0fea5dSIngo Weinhold }
690c0fea5dSIngo Weinhold
700c0fea5dSIngo Weinhold
7143d1a0dcSJérôme Duval static const char *
find_dt_rpath(image_t * image)7243d1a0dcSJérôme Duval find_dt_rpath(image_t *image)
7343d1a0dcSJérôme Duval {
7443d1a0dcSJérôme Duval return find_dt_string(image, DT_RPATH);
7543d1a0dcSJérôme Duval }
7643d1a0dcSJérôme Duval
7743d1a0dcSJérôme Duval
7843d1a0dcSJérôme Duval static const char *
find_dt_runpath(image_t * image)7943d1a0dcSJérôme Duval find_dt_runpath(image_t *image)
8043d1a0dcSJérôme Duval {
8143d1a0dcSJérôme Duval return find_dt_string(image, DT_RUNPATH);
8243d1a0dcSJérôme Duval }
8343d1a0dcSJérôme Duval
8443d1a0dcSJérôme Duval
8535fa85dbSJérôme Duval image_id
preload_image(char const * path,image_t ** image)8635fa85dbSJérôme Duval preload_image(char const* path, image_t **image)
8735fa85dbSJérôme Duval {
8835fa85dbSJérôme Duval if (path == NULL)
8935fa85dbSJérôme Duval return B_BAD_VALUE;
9035fa85dbSJérôme Duval
9135fa85dbSJérôme Duval KTRACE("rld: preload_image(\"%s\")", path);
9235fa85dbSJérôme Duval
9343d1a0dcSJérôme Duval status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, NULL, image);
9435fa85dbSJérôme Duval if (status < B_OK) {
9535fa85dbSJérôme Duval KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
9635fa85dbSJérôme Duval strerror(status));
9735fa85dbSJérôme Duval return status;
9835fa85dbSJérôme Duval }
9935fa85dbSJérôme Duval
10035fa85dbSJérôme Duval if ((*image)->find_undefined_symbol == NULL)
10135fa85dbSJérôme Duval (*image)->find_undefined_symbol = find_undefined_symbol_global;
10235fa85dbSJérôme Duval
10335fa85dbSJérôme Duval KTRACE("rld: preload_image(\"%s\") done: id: %" B_PRId32, path, (*image)->id);
10435fa85dbSJérôme Duval
10535fa85dbSJérôme Duval return (*image)->id;
10635fa85dbSJérôme Duval }
10735fa85dbSJérôme Duval
10835fa85dbSJérôme Duval
10935fa85dbSJérôme Duval static void
preload_images(image_t ** image,int32 * _count=NULL)11035fa85dbSJérôme Duval preload_images(image_t **image, int32 *_count = NULL)
11135fa85dbSJérôme Duval {
11235fa85dbSJérôme Duval const char* imagePaths = getenv("LD_PRELOAD");
11335fa85dbSJérôme Duval if (imagePaths == NULL) {
11435fa85dbSJérôme Duval if (_count != NULL)
11535fa85dbSJérôme Duval *_count = 0;
11635fa85dbSJérôme Duval return;
11735fa85dbSJérôme Duval }
11835fa85dbSJérôme Duval
11935fa85dbSJérôme Duval int32 count = 0;
12035fa85dbSJérôme Duval
12135fa85dbSJérôme Duval while (*imagePaths != '\0') {
12235fa85dbSJérôme Duval // find begin of image path
12335fa85dbSJérôme Duval while (*imagePaths != '\0' && isspace(*imagePaths))
12435fa85dbSJérôme Duval imagePaths++;
12535fa85dbSJérôme Duval
12635fa85dbSJérôme Duval if (*imagePaths == '\0')
12735fa85dbSJérôme Duval break;
12835fa85dbSJérôme Duval
12935fa85dbSJérôme Duval // find end of image path
13035fa85dbSJérôme Duval const char* imagePath = imagePaths;
13135fa85dbSJérôme Duval while (*imagePaths != '\0' && !isspace(*imagePaths))
13235fa85dbSJérôme Duval imagePaths++;
13335fa85dbSJérôme Duval
13435fa85dbSJérôme Duval // extract the path
13535fa85dbSJérôme Duval char path[B_PATH_NAME_LENGTH];
13635fa85dbSJérôme Duval size_t pathLen = imagePaths - imagePath;
13735fa85dbSJérôme Duval if (pathLen > sizeof(path) - 1)
13835fa85dbSJérôme Duval continue;
13935fa85dbSJérôme Duval
14035fa85dbSJérôme Duval if (image == NULL) {
14135fa85dbSJérôme Duval count++;
14235fa85dbSJérôme Duval continue;
14335fa85dbSJérôme Duval }
14435fa85dbSJérôme Duval memcpy(path, imagePath, pathLen);
14535fa85dbSJérôme Duval path[pathLen] = '\0';
14635fa85dbSJérôme Duval
14735fa85dbSJérôme Duval // load the image
14835fa85dbSJérôme Duval preload_image(path, &image[count++]);
14935fa85dbSJérôme Duval }
15035fa85dbSJérôme Duval
15135fa85dbSJérôme Duval KTRACE("rld: preload_images count: %d", count);
15235fa85dbSJérôme Duval
15335fa85dbSJérôme Duval if (_count != NULL)
15435fa85dbSJérôme Duval *_count = count;
15535fa85dbSJérôme Duval }
15635fa85dbSJérôme Duval
15735fa85dbSJérôme Duval
1580c0fea5dSIngo Weinhold static status_t
load_immediate_dependencies(image_t * image,bool preload)15935fa85dbSJérôme Duval load_immediate_dependencies(image_t *image, bool preload)
1600c0fea5dSIngo Weinhold {
161e3ac2588SAlex Smith elf_dyn *d = (elf_dyn *)image->dynamic_ptr;
1624bef3723SAxel Dörfler bool reportErrors = report_errors();
16374c0424aSAxel Dörfler status_t status = B_OK;
1640c0fea5dSIngo Weinhold uint32 i, j;
16543d1a0dcSJérôme Duval const char *rpath = NULL, *runpath;
1660c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
1670c0fea5dSIngo Weinhold return B_OK;
1680c0fea5dSIngo Weinhold
1690c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED;
1700c0fea5dSIngo Weinhold
17135fa85dbSJérôme Duval int32 preloadedCount = 0;
17235fa85dbSJérôme Duval if (preload) {
17335fa85dbSJérôme Duval preload_images(NULL, &preloadedCount);
17435fa85dbSJérôme Duval image->num_needed += preloadedCount;
17535fa85dbSJérôme Duval }
1760c0fea5dSIngo Weinhold if (image->num_needed == 0)
1770c0fea5dSIngo Weinhold return B_OK;
1780c0fea5dSIngo Weinhold
179ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ")", image->name,
1807486b72dSIngo Weinhold image->id);
1817486b72dSIngo Weinhold
1820c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
1830c0fea5dSIngo Weinhold if (image->needed == NULL) {
184c533f813SIngo Weinhold FATAL("%s: Failed to allocate needed struct\n", image->path);
185ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32
186ded25be1SIngo Weinhold ") failed: no memory", image->name, image->id);
1870c0fea5dSIngo Weinhold return B_NO_MEMORY;
1880c0fea5dSIngo Weinhold }
1890c0fea5dSIngo Weinhold
1900c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *));
19135fa85dbSJérôme Duval if (preload)
19235fa85dbSJérôme Duval preload_images(image->needed);
19343d1a0dcSJérôme Duval runpath = find_dt_runpath(image);
19443d1a0dcSJérôme Duval if (runpath == NULL)
1950c0fea5dSIngo Weinhold rpath = find_dt_rpath(image);
1960c0fea5dSIngo Weinhold
19735fa85dbSJérôme Duval for (i = 0, j = preloadedCount; d[i].d_tag != DT_NULL; i++) {
1980c0fea5dSIngo Weinhold switch (d[i].d_tag) {
1990c0fea5dSIngo Weinhold case DT_NEEDED:
20074c0424aSAxel Dörfler {
20174c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val;
20274c0424aSAxel Dörfler const char *name = STRING(image, neededOffset);
2030c0fea5dSIngo Weinhold
20494830eb2SIngo Weinhold status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
20543d1a0dcSJérôme Duval rpath, runpath, image->path, &image->needed[j]);
20674c0424aSAxel Dörfler if (loadStatus < B_OK) {
20774c0424aSAxel Dörfler status = loadStatus;
20874c0424aSAxel Dörfler // correct error code in case the file could not been found
20974c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) {
21074c0424aSAxel Dörfler status = B_MISSING_LIBRARY;
21174c0424aSAxel Dörfler
21274c0424aSAxel Dörfler if (reportErrors)
21394830eb2SIngo Weinhold gErrorMessage.AddString("missing library", name);
21474c0424aSAxel Dörfler }
21574c0424aSAxel Dörfler
21674c0424aSAxel Dörfler // Collect all missing libraries in case we report back
2177486b72dSIngo Weinhold if (!reportErrors) {
218ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32
219ded25be1SIngo Weinhold ") failed: %s", image->name, image->id,
2207486b72dSIngo Weinhold strerror(status));
2210c0fea5dSIngo Weinhold return status;
22274c0424aSAxel Dörfler }
2237486b72dSIngo Weinhold }
2240c0fea5dSIngo Weinhold
2250c0fea5dSIngo Weinhold j += 1;
2260c0fea5dSIngo Weinhold break;
22774c0424aSAxel Dörfler }
2280c0fea5dSIngo Weinhold
2290c0fea5dSIngo Weinhold default:
2300c0fea5dSIngo Weinhold // ignore any other tag
2310c0fea5dSIngo Weinhold continue;
2320c0fea5dSIngo Weinhold }
2330c0fea5dSIngo Weinhold }
2340c0fea5dSIngo Weinhold
2357486b72dSIngo Weinhold if (status < B_OK) {
236ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") "
2377486b72dSIngo Weinhold "failed: %s", image->name, image->id,
2387486b72dSIngo Weinhold strerror(status));
23974c0424aSAxel Dörfler return status;
2407486b72dSIngo Weinhold }
24174c0424aSAxel Dörfler
2420c0fea5dSIngo Weinhold if (j != image->num_needed) {
2430c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()");
244ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") "
2457486b72dSIngo Weinhold "failed: internal error", image->name, image->id);
2460c0fea5dSIngo Weinhold return B_ERROR;
2470c0fea5dSIngo Weinhold }
2480c0fea5dSIngo Weinhold
249ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") done",
250ded25be1SIngo Weinhold image->name, image->id);
2517486b72dSIngo Weinhold
2520c0fea5dSIngo Weinhold return B_OK;
2530c0fea5dSIngo Weinhold }
2540c0fea5dSIngo Weinhold
2550c0fea5dSIngo Weinhold
2560c85bd05SIngo Weinhold static status_t
load_dependencies(image_t * image,bool preload=false)25735fa85dbSJérôme Duval load_dependencies(image_t* image, bool preload = false)
2580c85bd05SIngo Weinhold {
259003ebb0eSIngo Weinhold // load dependencies (breadth-first)
2600c85bd05SIngo Weinhold for (image_t* otherImage = image; otherImage != NULL;
2610c85bd05SIngo Weinhold otherImage = otherImage->next) {
26235fa85dbSJérôme Duval status_t status = load_immediate_dependencies(otherImage, preload);
2630c85bd05SIngo Weinhold if (status != B_OK)
2640c85bd05SIngo Weinhold return status;
26535fa85dbSJérôme Duval preload = false;
2660c85bd05SIngo Weinhold }
2670c85bd05SIngo Weinhold
268003ebb0eSIngo Weinhold // Check the needed versions for the given image and all newly loaded
269003ebb0eSIngo Weinhold // dependencies.
270003ebb0eSIngo Weinhold for (image_t* otherImage = image; otherImage != NULL;
271003ebb0eSIngo Weinhold otherImage = otherImage->next) {
272003ebb0eSIngo Weinhold status_t status = check_needed_image_versions(otherImage);
273003ebb0eSIngo Weinhold if (status != B_OK)
274003ebb0eSIngo Weinhold return status;
275003ebb0eSIngo Weinhold }
276003ebb0eSIngo Weinhold
2770c85bd05SIngo Weinhold return B_OK;
2780c85bd05SIngo Weinhold }
2790c85bd05SIngo Weinhold
2800c85bd05SIngo Weinhold
28194830eb2SIngo Weinhold static status_t
relocate_image(image_t * rootImage,image_t * image)28294830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
2830c0fea5dSIngo Weinhold {
28425dc253dSIngo Weinhold SymbolLookupCache cache(image);
28525dc253dSIngo Weinhold
28625dc253dSIngo Weinhold status_t status = arch_relocate_image(rootImage, image, &cache);
28794830eb2SIngo Weinhold if (status < B_OK) {
288c533f813SIngo Weinhold FATAL("%s: Troubles relocating: %s\n", image->path, strerror(status));
28994830eb2SIngo Weinhold return status;
2900c0fea5dSIngo Weinhold }
2910c0fea5dSIngo Weinhold
29294830eb2SIngo Weinhold _kern_image_relocated(image->id);
29394830eb2SIngo Weinhold image_event(image, IMAGE_EVENT_RELOCATED);
29494830eb2SIngo Weinhold return B_OK;
2950c0fea5dSIngo Weinhold }
2960c0fea5dSIngo Weinhold
2970c0fea5dSIngo Weinhold
2980c0fea5dSIngo Weinhold static status_t
relocate_dependencies(image_t * image)2990c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
3000c0fea5dSIngo Weinhold {
301ca618b22SIngo Weinhold // get the images that still have to be relocated
302ca618b22SIngo Weinhold image_t **list;
303ca618b22SIngo Weinhold ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
3040c0fea5dSIngo Weinhold if (count < B_OK)
3050c0fea5dSIngo Weinhold return count;
3060c0fea5dSIngo Weinhold
3070c85bd05SIngo Weinhold // relocate
308ca618b22SIngo Weinhold for (ssize_t i = 0; i < count; i++) {
30946f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]);
3100c85bd05SIngo Weinhold if (status < B_OK) {
3110c85bd05SIngo Weinhold free(list);
3120c0fea5dSIngo Weinhold return status;
3130c0fea5dSIngo Weinhold }
3140c85bd05SIngo Weinhold }
3150c0fea5dSIngo Weinhold
3160c0fea5dSIngo Weinhold free(list);
3170c0fea5dSIngo Weinhold return B_OK;
3180c0fea5dSIngo Weinhold }
3190c0fea5dSIngo Weinhold
3200c0fea5dSIngo Weinhold
3210c0fea5dSIngo Weinhold static void
init_dependencies(image_t * image,bool initHead)3220c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
3230c0fea5dSIngo Weinhold {
32458dcc29bSAugustin Cavalier image_t **initList = NULL;
3250c0fea5dSIngo Weinhold ssize_t count, i;
3260c0fea5dSIngo Weinhold
3273a75ef9aSJérôme Duval if (initHead && image->preinit_array) {
3283a75ef9aSJérôme Duval uint count_preinit = image->preinit_array_len / sizeof(addr_t);
3293a75ef9aSJérôme Duval for (uint j = 0; j < count_preinit; j++)
3303a75ef9aSJérôme Duval ((initfini_array_function)image->preinit_array[j])();
3313a75ef9aSJérôme Duval }
3323a75ef9aSJérôme Duval
3330c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
33458dcc29bSAugustin Cavalier if (count <= 0) {
33558dcc29bSAugustin Cavalier free(initList);
3360c0fea5dSIngo Weinhold return;
33758dcc29bSAugustin Cavalier }
3380c0fea5dSIngo Weinhold
3390c0fea5dSIngo Weinhold if (!initHead) {
3400c0fea5dSIngo Weinhold // this removes the "calling" image
3410c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED;
3420c0fea5dSIngo Weinhold initList[--count] = NULL;
3430c0fea5dSIngo Weinhold }
3440c0fea5dSIngo Weinhold
3450c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL)));
3460c0fea5dSIngo Weinhold for (i = 0; i < count; i++) {
3470c0fea5dSIngo Weinhold image = initList[i];
3480c0fea5dSIngo Weinhold
3490c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name));
3500c0fea5dSIngo Weinhold
351354b60afSAugustin Cavalier init_term_function before;
352354b60afSAugustin Cavalier if (find_symbol(image,
353354b60afSAugustin Cavalier SymbolLookupInfo(B_INIT_BEFORE_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
354354b60afSAugustin Cavalier (void**)&before) == B_OK) {
355354b60afSAugustin Cavalier before(image->id);
356e340f717SJérôme Duval }
357e340f717SJérôme Duval
358dd76bc97SIngo Weinhold if (image->init_routine != 0)
3590c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id);
36010b4b5d1SIngo Weinhold
361e340f717SJérôme Duval if (image->init_array) {
362e340f717SJérôme Duval uint count_init = image->init_array_len / sizeof(addr_t);
363e340f717SJérôme Duval for (uint j = 0; j < count_init; j++)
364354b60afSAugustin Cavalier ((initfini_array_function)image->init_array[j])();
365354b60afSAugustin Cavalier }
366354b60afSAugustin Cavalier
367354b60afSAugustin Cavalier init_term_function after;
368354b60afSAugustin Cavalier if (find_symbol(image,
369354b60afSAugustin Cavalier SymbolLookupInfo(B_INIT_AFTER_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
370354b60afSAugustin Cavalier (void**)&after) == B_OK) {
371354b60afSAugustin Cavalier after(image->id);
372e340f717SJérôme Duval }
373e340f717SJérôme Duval
37410b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_INITIALIZED);
3750c0fea5dSIngo Weinhold }
3760c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL)));
3770c0fea5dSIngo Weinhold
3780c0fea5dSIngo Weinhold free(initList);
3790c0fea5dSIngo Weinhold }
3800c0fea5dSIngo Weinhold
3810c0fea5dSIngo Weinhold
3820c0fea5dSIngo Weinhold static void
call_term_functions(image_t * image)3835d08e3a5SAugustin Cavalier call_term_functions(image_t* image)
3845d08e3a5SAugustin Cavalier {
3855d08e3a5SAugustin Cavalier init_term_function before;
3865d08e3a5SAugustin Cavalier if (find_symbol(image,
3875d08e3a5SAugustin Cavalier SymbolLookupInfo(B_TERM_BEFORE_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
3885d08e3a5SAugustin Cavalier (void**)&before) == B_OK) {
3895d08e3a5SAugustin Cavalier before(image->id);
3905d08e3a5SAugustin Cavalier }
3915d08e3a5SAugustin Cavalier
3925d08e3a5SAugustin Cavalier if (image->term_array) {
3935d08e3a5SAugustin Cavalier uint count_term = image->term_array_len / sizeof(addr_t);
3945d08e3a5SAugustin Cavalier for (uint i = count_term; i-- > 0;)
3955d08e3a5SAugustin Cavalier ((initfini_array_function)image->term_array[i])();
3965d08e3a5SAugustin Cavalier }
3975d08e3a5SAugustin Cavalier
3985d08e3a5SAugustin Cavalier if (image->term_routine)
3995d08e3a5SAugustin Cavalier ((init_term_function)image->term_routine)(image->id);
4005d08e3a5SAugustin Cavalier
4015d08e3a5SAugustin Cavalier init_term_function after;
4025d08e3a5SAugustin Cavalier if (find_symbol(image,
4035d08e3a5SAugustin Cavalier SymbolLookupInfo(B_TERM_AFTER_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
4045d08e3a5SAugustin Cavalier (void**)&after) == B_OK) {
4055d08e3a5SAugustin Cavalier after(image->id);
4065d08e3a5SAugustin Cavalier }
4075d08e3a5SAugustin Cavalier }
4085d08e3a5SAugustin Cavalier
4095d08e3a5SAugustin Cavalier
4105d08e3a5SAugustin Cavalier static void
inject_runtime_loader_api(image_t * rootImage)411ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
412ca618b22SIngo Weinhold {
413ca618b22SIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private
414ca618b22SIngo Weinhold // API.
415ca618b22SIngo Weinhold image_t* image;
4160c85bd05SIngo Weinhold void* _export;
417003ebb0eSIngo Weinhold if (find_symbol_breadth_first(rootImage,
418003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
419003ebb0eSIngo Weinhold &_export) == B_OK) {
4200c85bd05SIngo Weinhold *(void**)_export = &gRuntimeLoader;
421ca618b22SIngo Weinhold }
422ca618b22SIngo Weinhold }
423ca618b22SIngo Weinhold
424ca618b22SIngo Weinhold
425ca618b22SIngo Weinhold static status_t
add_preloaded_addon(image_t * image)42635fa85dbSJérôme Duval add_preloaded_addon(image_t* image)
427ca618b22SIngo Weinhold {
428ca618b22SIngo Weinhold // We realloc() everytime -- not particularly efficient, but good enough for
42935fa85dbSJérôme Duval // small number of preloaded addons.
43035fa85dbSJérôme Duval image_t** newArray = (image_t**)realloc(sPreloadedAddons,
43135fa85dbSJérôme Duval sizeof(image_t*) * (sPreloadedAddonCount + 1));
432ca618b22SIngo Weinhold if (newArray == NULL)
433ca618b22SIngo Weinhold return B_NO_MEMORY;
434ca618b22SIngo Weinhold
43535fa85dbSJérôme Duval sPreloadedAddons = newArray;
43635fa85dbSJérôme Duval newArray[sPreloadedAddonCount++] = image;
437ca618b22SIngo Weinhold
438ca618b22SIngo Weinhold return B_OK;
439ca618b22SIngo Weinhold }
440ca618b22SIngo Weinhold
441ca618b22SIngo Weinhold
442ca618b22SIngo Weinhold image_id
preload_addon(char const * path)44335fa85dbSJérôme Duval preload_addon(char const* path)
444ca618b22SIngo Weinhold {
445ca618b22SIngo Weinhold if (path == NULL)
446ca618b22SIngo Weinhold return B_BAD_VALUE;
447ca618b22SIngo Weinhold
44835fa85dbSJérôme Duval KTRACE("rld: preload_addon(\"%s\")", path);
449ca618b22SIngo Weinhold
450ca618b22SIngo Weinhold image_t *image = NULL;
45143d1a0dcSJérôme Duval status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, NULL, &image);
452ca618b22SIngo Weinhold if (status < B_OK) {
45335fa85dbSJérôme Duval KTRACE("rld: preload_addon(\"%s\") failed to load container: %s", path,
454ca618b22SIngo Weinhold strerror(status));
455ca618b22SIngo Weinhold return status;
456ca618b22SIngo Weinhold }
457ca618b22SIngo Weinhold
4580c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL)
4590c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global;
4600c85bd05SIngo Weinhold
4610c85bd05SIngo Weinhold status = load_dependencies(image);
462ca618b22SIngo Weinhold if (status < B_OK)
463ca618b22SIngo Weinhold goto err;
4640c85bd05SIngo Weinhold
4650c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL);
466ca618b22SIngo Weinhold
467ca618b22SIngo Weinhold status = relocate_dependencies(image);
468ca618b22SIngo Weinhold if (status < B_OK)
469ca618b22SIngo Weinhold goto err;
470ca618b22SIngo Weinhold
47135fa85dbSJérôme Duval status = add_preloaded_addon(image);
472ca618b22SIngo Weinhold if (status < B_OK)
473ca618b22SIngo Weinhold goto err;
474ca618b22SIngo Weinhold
475ca618b22SIngo Weinhold inject_runtime_loader_api(image);
476ca618b22SIngo Weinhold
477ca618b22SIngo Weinhold remap_images();
478ca618b22SIngo Weinhold init_dependencies(image, true);
479ca618b22SIngo Weinhold
48010b4b5d1SIngo Weinhold // if the image contains an add-on, register it
48110b4b5d1SIngo Weinhold runtime_loader_add_on* addOnStruct;
482003ebb0eSIngo Weinhold if (find_symbol(image,
483003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
48410b4b5d1SIngo Weinhold (void**)&addOnStruct) == B_OK) {
48594830eb2SIngo Weinhold add_add_on(image, addOnStruct);
48610b4b5d1SIngo Weinhold }
48710b4b5d1SIngo Weinhold
48835fa85dbSJérôme Duval KTRACE("rld: preload_addon(\"%s\") done: id: %" B_PRId32, path, image->id);
489ca618b22SIngo Weinhold
490ca618b22SIngo Weinhold return image->id;
491ca618b22SIngo Weinhold
492ca618b22SIngo Weinhold err:
49335fa85dbSJérôme Duval KTRACE("rld: preload_addon(\"%s\") failed: %s", path, strerror(status));
494ca618b22SIngo Weinhold
49594830eb2SIngo Weinhold dequeue_loaded_image(image);
496ca618b22SIngo Weinhold delete_image(image);
497ca618b22SIngo Weinhold return status;
498ca618b22SIngo Weinhold }
499ca618b22SIngo Weinhold
500ca618b22SIngo Weinhold
501ca618b22SIngo Weinhold static void
preload_addons()50235fa85dbSJérôme Duval preload_addons()
503ca618b22SIngo Weinhold {
50435fa85dbSJérôme Duval const char* imagePaths = getenv("LD_PRELOAD_ADDONS");
505ca618b22SIngo Weinhold if (imagePaths == NULL)
506ca618b22SIngo Weinhold return;
507ca618b22SIngo Weinhold
508ca618b22SIngo Weinhold while (*imagePaths != '\0') {
509ca618b22SIngo Weinhold // find begin of image path
510ca618b22SIngo Weinhold while (*imagePaths != '\0' && isspace(*imagePaths))
511ca618b22SIngo Weinhold imagePaths++;
512ca618b22SIngo Weinhold
513ca618b22SIngo Weinhold if (*imagePaths == '\0')
514ca618b22SIngo Weinhold break;
515ca618b22SIngo Weinhold
516ca618b22SIngo Weinhold // find end of image path
517ca618b22SIngo Weinhold const char* imagePath = imagePaths;
518ca618b22SIngo Weinhold while (*imagePaths != '\0' && !isspace(*imagePaths))
519ca618b22SIngo Weinhold imagePaths++;
520ca618b22SIngo Weinhold
521ca618b22SIngo Weinhold // extract the path
522ca618b22SIngo Weinhold char path[B_PATH_NAME_LENGTH];
523ca618b22SIngo Weinhold size_t pathLen = imagePaths - imagePath;
524ca618b22SIngo Weinhold if (pathLen > sizeof(path) - 1)
525ca618b22SIngo Weinhold continue;
526ca618b22SIngo Weinhold memcpy(path, imagePath, pathLen);
527ca618b22SIngo Weinhold path[pathLen] = '\0';
528ca618b22SIngo Weinhold
529ca618b22SIngo Weinhold // load the image
53035fa85dbSJérôme Duval preload_addon(path);
531ca618b22SIngo Weinhold }
532ca618b22SIngo Weinhold }
533ca618b22SIngo Weinhold
534ca618b22SIngo Weinhold
53574c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions
5360c0fea5dSIngo Weinhold
5370c0fea5dSIngo Weinhold
5380c0fea5dSIngo Weinhold image_id
load_program(char const * path,void ** _entry)5390c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
5400c0fea5dSIngo Weinhold {
5410c0fea5dSIngo Weinhold status_t status;
5420c0fea5dSIngo Weinhold image_t *image;
5430c0fea5dSIngo Weinhold
5447486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path);
5457486b72dSIngo Weinhold
546f167d21aSAugustin Cavalier RecursiveLocker _(sLock);
5470c0fea5dSIngo Weinhold // for now, just do stupid simple global locking
5480c0fea5dSIngo Weinhold
54935fa85dbSJérôme Duval preload_addons();
550ca618b22SIngo Weinhold
5510c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path));
5520c0fea5dSIngo Weinhold
55343d1a0dcSJérôme Duval status = load_image(path, B_APP_IMAGE, NULL, NULL, NULL, &gProgramImage);
55474c0424aSAxel Dörfler if (status < B_OK)
55574c0424aSAxel Dörfler goto err;
5560c0fea5dSIngo Weinhold
55794830eb2SIngo Weinhold if (gProgramImage->find_undefined_symbol == NULL)
55894830eb2SIngo Weinhold gProgramImage->find_undefined_symbol = find_undefined_symbol_global;
5590c85bd05SIngo Weinhold
56035fa85dbSJérôme Duval status = load_dependencies(gProgramImage, true);
5610c0fea5dSIngo Weinhold if (status < B_OK)
5620c0fea5dSIngo Weinhold goto err;
5630c85bd05SIngo Weinhold
56447bc6663SIngo Weinhold // Set RTLD_GLOBAL on all libraries including the program.
5650c85bd05SIngo Weinhold // This results in the desired symbol resolution for dlopen()ed libraries.
56694830eb2SIngo Weinhold set_image_flags_recursively(gProgramImage, RTLD_GLOBAL);
5670c0fea5dSIngo Weinhold
56894830eb2SIngo Weinhold status = relocate_dependencies(gProgramImage);
5690c0fea5dSIngo Weinhold if (status < B_OK)
5700c0fea5dSIngo Weinhold goto err;
5710c0fea5dSIngo Weinhold
57294830eb2SIngo Weinhold inject_runtime_loader_api(gProgramImage);
5730c0fea5dSIngo Weinhold
5740c0fea5dSIngo Weinhold remap_images();
57594830eb2SIngo Weinhold init_dependencies(gProgramImage, true);
5760c0fea5dSIngo Weinhold
5770c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our
5780c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so
57994830eb2SIngo Weinhold find_symbol_breadth_first(gProgramImage,
580003ebb0eSIngo Weinhold SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
581003ebb0eSIngo Weinhold (void**)&gGetEnv);
5820c0fea5dSIngo Weinhold
58394830eb2SIngo Weinhold if (gProgramImage->entry_point == 0) {
5840c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE;
5850c0fea5dSIngo Weinhold goto err;
5860c0fea5dSIngo Weinhold }
5870c0fea5dSIngo Weinhold
58894830eb2SIngo Weinhold *_entry = (void *)(gProgramImage->entry_point);
5890c0fea5dSIngo Weinhold
59094830eb2SIngo Weinhold gProgramLoaded = true;
5915d0638bfSIngo Weinhold
592ded25be1SIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %" B_PRId32 , path,
59394830eb2SIngo Weinhold *_entry, gProgramImage->id);
5947486b72dSIngo Weinhold
59594830eb2SIngo Weinhold return gProgramImage->id;
5960c0fea5dSIngo Weinhold
5970c0fea5dSIngo Weinhold err:
5987486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
5997486b72dSIngo Weinhold
60094830eb2SIngo Weinhold delete_image(gProgramImage);
60174c0424aSAxel Dörfler
6024bef3723SAxel Dörfler if (report_errors()) {
6034bef3723SAxel Dörfler // send error message
60494830eb2SIngo Weinhold gErrorMessage.AddInt32("error", status);
60594830eb2SIngo Weinhold gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
6064bef3723SAxel Dörfler -1, 0, find_thread(NULL));
6074bef3723SAxel Dörfler
6084bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
60994830eb2SIngo Weinhold gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0);
61074c0424aSAxel Dörfler }
61174c0424aSAxel Dörfler _kern_loading_app_failed(status);
61274c0424aSAxel Dörfler
6130c0fea5dSIngo Weinhold return status;
6140c0fea5dSIngo Weinhold }
6150c0fea5dSIngo Weinhold
6160c0fea5dSIngo Weinhold
6170c0fea5dSIngo Weinhold image_id
load_library(char const * path,uint32 flags,bool addOn,void * caller,void ** _handle)618b2b83ad1SJérôme Duval load_library(char const *path, uint32 flags, bool addOn, void* caller,
619b2b83ad1SJérôme Duval void** _handle)
6200c0fea5dSIngo Weinhold {
6210c0fea5dSIngo Weinhold image_t *image = NULL;
6220c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
6230c0fea5dSIngo Weinhold status_t status;
62443d1a0dcSJérôme Duval const char* rpath = NULL, *runpath = NULL;
625b2b83ad1SJérôme Duval const char* requestingObjectPath = NULL;
6260c0fea5dSIngo Weinhold
6270c85bd05SIngo Weinhold if (path == NULL && addOn)
6280c0fea5dSIngo Weinhold return B_BAD_VALUE;
6290c0fea5dSIngo Weinhold
630ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\", %#" B_PRIx32 ", %d)", path, flags, addOn);
6317486b72dSIngo Weinhold
632f167d21aSAugustin Cavalier RecursiveLocker _(sLock);
6330c0fea5dSIngo Weinhold // for now, just do stupid simple global locking
6340c0fea5dSIngo Weinhold
6350c0fea5dSIngo Weinhold // have we already loaded this library?
6360c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again
6370c0fea5dSIngo Weinhold if (!addOn) {
6380c85bd05SIngo Weinhold // a NULL path is fine -- it means the global scope shall be opened
6390c85bd05SIngo Weinhold if (path == NULL) {
6400c85bd05SIngo Weinhold *_handle = RLD_GLOBAL_SCOPE;
6410c85bd05SIngo Weinhold return 0;
6420c85bd05SIngo Weinhold }
6430c85bd05SIngo Weinhold
64494830eb2SIngo Weinhold image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
6450c85bd05SIngo Weinhold if (image != NULL && (flags & RTLD_GLOBAL) != 0)
6460c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL);
6470c85bd05SIngo Weinhold
6480c0fea5dSIngo Weinhold if (image) {
6490c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1);
650ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %" B_PRId32,
651ded25be1SIngo Weinhold path, image->id);
6520c85bd05SIngo Weinhold *_handle = image;
6530c0fea5dSIngo Weinhold return image->id;
6540c0fea5dSIngo Weinhold }
655b2b83ad1SJérôme Duval
656b2b83ad1SJérôme Duval // First of all, find the caller image.
657b2b83ad1SJérôme Duval image_t* callerImage = get_loaded_images().head;
658b2b83ad1SJérôme Duval for (; callerImage != NULL; callerImage = callerImage->next) {
659b2b83ad1SJérôme Duval elf_region_t& text = callerImage->regions[0];
660b2b83ad1SJérôme Duval if ((addr_t)caller >= text.vmstart
661b2b83ad1SJérôme Duval && (addr_t)caller < text.vmstart + text.vmsize) {
662b2b83ad1SJérôme Duval // found the image
663b2b83ad1SJérôme Duval break;
664b2b83ad1SJérôme Duval }
665b2b83ad1SJérôme Duval }
666b2b83ad1SJérôme Duval if (callerImage != NULL) {
66743d1a0dcSJérôme Duval runpath = find_dt_runpath(callerImage);
66843d1a0dcSJérôme Duval if (runpath == NULL)
669b2b83ad1SJérôme Duval rpath = find_dt_rpath(callerImage);
670b2b83ad1SJérôme Duval requestingObjectPath = callerImage->path;
671b2b83ad1SJérôme Duval }
6720c0fea5dSIngo Weinhold }
6730c0fea5dSIngo Weinhold
67443d1a0dcSJérôme Duval status = load_image(path, type, rpath, runpath, requestingObjectPath, &image);
6750c0fea5dSIngo Weinhold if (status < B_OK) {
6767486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
6777486b72dSIngo Weinhold strerror(status));
6780c0fea5dSIngo Weinhold return status;
6790c0fea5dSIngo Weinhold }
6800c0fea5dSIngo Weinhold
6810c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) {
6820c85bd05SIngo Weinhold if (addOn)
6830c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_add_on;
6840c85bd05SIngo Weinhold else
6850c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global;
6860c85bd05SIngo Weinhold }
6870c85bd05SIngo Weinhold
6880c85bd05SIngo Weinhold status = load_dependencies(image);
6890c0fea5dSIngo Weinhold if (status < B_OK)
6900c0fea5dSIngo Weinhold goto err;
6910c85bd05SIngo Weinhold
6920c85bd05SIngo Weinhold // If specified, set the RTLD_GLOBAL flag recursively on this image and all
6930c85bd05SIngo Weinhold // dependencies. If not specified, we temporarily set
6940c85bd05SIngo Weinhold // RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
6950c85bd05SIngo Weinhold // for undefined symbol resolution.
6960c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) != 0)
6970c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL);
6980c85bd05SIngo Weinhold else
6990c85bd05SIngo Weinhold set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
7000c0fea5dSIngo Weinhold
7010c0fea5dSIngo Weinhold status = relocate_dependencies(image);
7020c0fea5dSIngo Weinhold if (status < B_OK)
7030c0fea5dSIngo Weinhold goto err;
7040c0fea5dSIngo Weinhold
7050c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) == 0)
7060c85bd05SIngo Weinhold clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
7070c85bd05SIngo Weinhold
7080c0fea5dSIngo Weinhold remap_images();
7090c0fea5dSIngo Weinhold init_dependencies(image, true);
7100c0fea5dSIngo Weinhold
711ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %" B_PRId32, path, image->id);
7127486b72dSIngo Weinhold
7130c85bd05SIngo Weinhold *_handle = image;
7140c0fea5dSIngo Weinhold return image->id;
7150c0fea5dSIngo Weinhold
7160c0fea5dSIngo Weinhold err:
7177486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
7187486b72dSIngo Weinhold
719*1f1be520SAugustin Cavalier unload_library(image, -1, addOn);
7200c0fea5dSIngo Weinhold return status;
7210c0fea5dSIngo Weinhold }
7220c0fea5dSIngo Weinhold
7230c0fea5dSIngo Weinhold
7240c0fea5dSIngo Weinhold status_t
unload_library(void * handle,image_id imageID,bool addOn)7250c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
7260c0fea5dSIngo Weinhold {
7270c0fea5dSIngo Weinhold image_t *image;
7280c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
7290c0fea5dSIngo Weinhold
7300c85bd05SIngo Weinhold if (handle == NULL && imageID < 0)
7310c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID;
7320c0fea5dSIngo Weinhold
7330c85bd05SIngo Weinhold if (handle == RLD_GLOBAL_SCOPE)
7340c85bd05SIngo Weinhold return B_OK;
7350c85bd05SIngo Weinhold
736f167d21aSAugustin Cavalier RecursiveLocker _(sLock);
7370c0fea5dSIngo Weinhold // for now, just do stupid simple global locking
7380c0fea5dSIngo Weinhold
73994830eb2SIngo Weinhold if (gInvalidImageIDs) {
7409a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images
7419a6072a3SAxel Dörfler update_image_ids();
7429a6072a3SAxel Dörfler }
7439a6072a3SAxel Dörfler
7440c0fea5dSIngo Weinhold // we only check images that have been already initialized
7450c0fea5dSIngo Weinhold
7460c85bd05SIngo Weinhold if (handle != NULL) {
7470c85bd05SIngo Weinhold image = (image_t*)handle;
7480c85bd05SIngo Weinhold put_image(image);
7490c85bd05SIngo Weinhold } else {
75094830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, true);
751*1f1be520SAugustin Cavalier if (image == NULL)
752*1f1be520SAugustin Cavalier return B_BAD_IMAGE_ID;
753*1f1be520SAugustin Cavalier
7540c0fea5dSIngo Weinhold // unload image
755*1f1be520SAugustin Cavalier if (type != image->type)
756*1f1be520SAugustin Cavalier return B_BAD_VALUE;
7570c0fea5dSIngo Weinhold put_image(image);
7580c85bd05SIngo Weinhold }
7590c0fea5dSIngo Weinhold
76094830eb2SIngo Weinhold while ((image = get_disposable_images().head) != NULL) {
761ad59349eSX512 dequeue_disposable_image(image);
762ad59349eSX512
763*1f1be520SAugustin Cavalier if ((image->flags & RFLAG_INITIALIZED) != 0) {
764d64f6189SIngo Weinhold // Call the exit hooks that live in this image.
765d64f6189SIngo Weinhold // Note: With the Itanium ABI this shouldn't really be done this
766d64f6189SIngo Weinhold // way anymore, since global destructors are registered via
767d64f6189SIngo Weinhold // __cxa_atexit() (the ones that are registered dynamically) and the
768d64f6189SIngo Weinhold // termination routine should call __cxa_finalize() for the image.
769d64f6189SIngo Weinhold // The reason why we still do it is that hooks registered with
770d64f6189SIngo Weinhold // atexit() aren't associated with the image. We could find out
771d64f6189SIngo Weinhold // there which image the hooks lives in and register it
772d64f6189SIngo Weinhold // respectively, but since that would be done always, that's
773d64f6189SIngo Weinhold // probably more expensive than calling
774d64f6189SIngo Weinhold // call_atexit_hooks_for_range() only here, which happens only when
775d64f6189SIngo Weinhold // libraries are unloaded dynamically.
776*1f1be520SAugustin Cavalier if (gRuntimeLoader.call_atexit_hooks_for_range != NULL) {
7778c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range(
7783be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize);
7798c2a9d74SMichael Lotz }
7808c2a9d74SMichael Lotz
78110b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING);
78210b4b5d1SIngo Weinhold
7835d08e3a5SAugustin Cavalier call_term_functions(image);
784*1f1be520SAugustin Cavalier }
785354b60afSAugustin Cavalier
78644c0c4d3SPawel Dziepak TLSBlockTemplates::Get().Unregister(image->dso_tls_id);
78744c0c4d3SPawel Dziepak
7880c0fea5dSIngo Weinhold unmap_image(image);
7890c0fea5dSIngo Weinhold
79010b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING);
79110b4b5d1SIngo Weinhold
7920c0fea5dSIngo Weinhold delete_image(image);
7930c0fea5dSIngo Weinhold }
7940c0fea5dSIngo Weinhold
795*1f1be520SAugustin Cavalier return B_OK;
7960c0fea5dSIngo Weinhold }
7970c0fea5dSIngo Weinhold
7980c0fea5dSIngo Weinhold
7990c0fea5dSIngo Weinhold status_t
get_nth_symbol(image_id imageID,int32 num,char * nameBuffer,int32 * _nameLength,int32 * _type,void ** _location)8009a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
8019a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location)
8020c0fea5dSIngo Weinhold {
8030c0fea5dSIngo Weinhold int32 count = 0, j;
8040c0fea5dSIngo Weinhold uint32 i;
8050c0fea5dSIngo Weinhold image_t *image;
8060c0fea5dSIngo Weinhold
807f167d21aSAugustin Cavalier RecursiveLocker _(sLock);
8080c0fea5dSIngo Weinhold
8090c0fea5dSIngo Weinhold // get the image from those who have been already initialized
81094830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false);
811f167d21aSAugustin Cavalier if (image == NULL)
8120c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID;
8130c0fea5dSIngo Weinhold
8140c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one
8150c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) {
8160c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
817e3ac2588SAlex Smith elf_sym *symbol = &image->syms[j];
8180c0fea5dSIngo Weinhold
8190c0fea5dSIngo Weinhold if (count == num) {
82010b4b5d1SIngo Weinhold const char* symbolName = SYMNAME(image, symbol);
82110b4b5d1SIngo Weinhold strlcpy(nameBuffer, symbolName, *_nameLength);
82210b4b5d1SIngo Weinhold *_nameLength = strlen(symbolName);
8230c0fea5dSIngo Weinhold
82410b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value
82510b4b5d1SIngo Weinhold + image->regions[0].delta);
82610b4b5d1SIngo Weinhold int32 type;
827e3ac2588SAlex Smith if (symbol->Type() == STT_FUNC)
82810b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT;
829e3ac2588SAlex Smith else if (symbol->Type() == STT_OBJECT)
83010b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA;
8310c0fea5dSIngo Weinhold else
83210b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_ANY;
83310b4b5d1SIngo Weinhold // TODO: check with the return types of that BeOS function
8340c0fea5dSIngo Weinhold
83510b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &type);
83610b4b5d1SIngo Weinhold
83710b4b5d1SIngo Weinhold if (_type != NULL)
83810b4b5d1SIngo Weinhold *_type = type;
8390c0fea5dSIngo Weinhold if (_location != NULL)
84010b4b5d1SIngo Weinhold *_location = location;
8410c0fea5dSIngo Weinhold goto out;
8420c0fea5dSIngo Weinhold }
8430c0fea5dSIngo Weinhold count++;
8440c0fea5dSIngo Weinhold }
8450c0fea5dSIngo Weinhold }
8460c0fea5dSIngo Weinhold out:
8470c0fea5dSIngo Weinhold if (num != count)
8480c0fea5dSIngo Weinhold return B_BAD_INDEX;
8490c0fea5dSIngo Weinhold
8500c0fea5dSIngo Weinhold return B_OK;
8510c0fea5dSIngo Weinhold }
8520c0fea5dSIngo Weinhold
8530c0fea5dSIngo Weinhold
8540c0fea5dSIngo Weinhold status_t
get_nearest_symbol_at_address(void * address,image_id * _imageID,char ** _imagePath,char ** _imageName,char ** _symbolName,int32 * _type,void ** _location,bool * _exactMatch)85543e7b1c2SHamish Morrison get_nearest_symbol_at_address(void* address, image_id* _imageID,
856ebdc1d48SMichael Lotz char** _imagePath, char** _imageName, char** _symbolName, int32* _type,
857ebdc1d48SMichael Lotz void** _location, bool* _exactMatch)
858b6455c08SAxel Dörfler {
859f167d21aSAugustin Cavalier RecursiveLocker _(sLock);
860b6455c08SAxel Dörfler
861b6455c08SAxel Dörfler image_t* image = find_loaded_image_by_address((addr_t)address);
862f167d21aSAugustin Cavalier if (image == NULL)
863b6455c08SAxel Dörfler return B_BAD_VALUE;
864b6455c08SAxel Dörfler
865dee722ceSAugustin Cavalier if (_imageID != NULL)
866dee722ceSAugustin Cavalier *_imageID = image->id;
867dee722ceSAugustin Cavalier if (_imagePath != NULL)
868dee722ceSAugustin Cavalier *_imagePath = image->path;
869dee722ceSAugustin Cavalier if (_imageName != NULL)
870dee722ceSAugustin Cavalier *_imageName = image->name;
871dee722ceSAugustin Cavalier
872dee722ceSAugustin Cavalier // If the caller does not want the actual symbol name, only the image,
873dee722ceSAugustin Cavalier // we can just return immediately.
874dee722ceSAugustin Cavalier if (_symbolName == NULL && _type == NULL && _location == NULL)
875dee722ceSAugustin Cavalier return B_OK;
876dee722ceSAugustin Cavalier
877ebdc1d48SMichael Lotz bool exactMatch = false;
878e3ac2588SAlex Smith elf_sym* foundSymbol = NULL;
87943e7b1c2SHamish Morrison addr_t foundLocation = (addr_t)NULL;
88043e7b1c2SHamish Morrison
881ebdc1d48SMichael Lotz for (uint32 i = 0; i < HASHTABSIZE(image) && !exactMatch; i++) {
882b6455c08SAxel Dörfler for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF;
883b6455c08SAxel Dörfler j = HASHCHAINS(image)[j]) {
884e3ac2588SAlex Smith elf_sym *symbol = &image->syms[j];
885b6455c08SAxel Dörfler addr_t location = symbol->st_value + image->regions[0].delta;
886b6455c08SAxel Dörfler
88743e7b1c2SHamish Morrison if (location <= (addr_t)address && location >= foundLocation) {
88843e7b1c2SHamish Morrison foundSymbol = symbol;
88943e7b1c2SHamish Morrison foundLocation = location;
890b6455c08SAxel Dörfler
89143e7b1c2SHamish Morrison // jump out if we have an exact match
892ebdc1d48SMichael Lotz if (location + symbol->st_size > (addr_t)address) {
893ebdc1d48SMichael Lotz exactMatch = true;
89443e7b1c2SHamish Morrison break;
89543e7b1c2SHamish Morrison }
89643e7b1c2SHamish Morrison }
89743e7b1c2SHamish Morrison }
89843e7b1c2SHamish Morrison }
899b6455c08SAxel Dörfler
900ebdc1d48SMichael Lotz if (_exactMatch != NULL)
901ebdc1d48SMichael Lotz *_exactMatch = exactMatch;
90243e7b1c2SHamish Morrison
90343e7b1c2SHamish Morrison if (foundSymbol != NULL) {
90443e7b1c2SHamish Morrison *_symbolName = SYMNAME(image, foundSymbol);
90543e7b1c2SHamish Morrison
90643e7b1c2SHamish Morrison if (_type != NULL) {
907e3ac2588SAlex Smith if (foundSymbol->Type() == STT_FUNC)
90843e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_TEXT;
909e3ac2588SAlex Smith else if (foundSymbol->Type() == STT_OBJECT)
91043e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_DATA;
91143e7b1c2SHamish Morrison else
91243e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_ANY;
91343e7b1c2SHamish Morrison // TODO: check with the return types of that BeOS function
91443e7b1c2SHamish Morrison }
91543e7b1c2SHamish Morrison
916b6455c08SAxel Dörfler if (_location != NULL)
91743e7b1c2SHamish Morrison *_location = (void*)foundLocation;
91843e7b1c2SHamish Morrison } else {
91943e7b1c2SHamish Morrison *_symbolName = NULL;
92043e7b1c2SHamish Morrison if (_location != NULL)
92143e7b1c2SHamish Morrison *_location = NULL;
92243e7b1c2SHamish Morrison }
923b6455c08SAxel Dörfler
924b6455c08SAxel Dörfler return B_OK;
925b6455c08SAxel Dörfler }
926b6455c08SAxel Dörfler
927b6455c08SAxel Dörfler
928b6455c08SAxel Dörfler status_t
get_symbol(image_id imageID,char const * symbolName,int32 symbolType,bool recursive,image_id * _inImage,void ** _location)9299a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
93080ece785SIngo Weinhold bool recursive, image_id *_inImage, void **_location)
9310c0fea5dSIngo Weinhold {
9320c0fea5dSIngo Weinhold status_t status = B_OK;
9330c0fea5dSIngo Weinhold image_t *image;
9340c0fea5dSIngo Weinhold
9350c0fea5dSIngo Weinhold if (imageID < B_OK)
9360c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID;
9370c0fea5dSIngo Weinhold if (symbolName == NULL)
9380c0fea5dSIngo Weinhold return B_BAD_VALUE;
9390c0fea5dSIngo Weinhold
940354b60afSAugustin Cavalier // Previously, these functions were called in __haiku_init_before
941354b60afSAugustin Cavalier // and __haiku_init_after. Now we call them inside runtime_loader,
942354b60afSAugustin Cavalier // so we prevent applications from fetching them.
943354b60afSAugustin Cavalier if (strcmp(symbolName, B_INIT_BEFORE_FUNCTION_NAME) == 0
944354b60afSAugustin Cavalier || strcmp(symbolName, B_INIT_AFTER_FUNCTION_NAME) == 0
945354b60afSAugustin Cavalier || strcmp(symbolName, B_TERM_BEFORE_FUNCTION_NAME) == 0
946354b60afSAugustin Cavalier || strcmp(symbolName, B_TERM_AFTER_FUNCTION_NAME) == 0)
947354b60afSAugustin Cavalier return B_BAD_VALUE;
948354b60afSAugustin Cavalier
949f167d21aSAugustin Cavalier RecursiveLocker _(sLock);
9500c0fea5dSIngo Weinhold // for now, just do stupid simple global locking
9510c0fea5dSIngo Weinhold
9520c0fea5dSIngo Weinhold // get the image from those who have been already initialized
95394830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false);
95480ece785SIngo Weinhold if (image != NULL) {
95580ece785SIngo Weinhold if (recursive) {
95680ece785SIngo Weinhold // breadth-first search in the given image and its dependencies
957003ebb0eSIngo Weinhold status = find_symbol_breadth_first(image,
958003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL,
959003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION),
96080ece785SIngo Weinhold &image, _location);
961003ebb0eSIngo Weinhold } else {
962003ebb0eSIngo Weinhold status = find_symbol(image,
963003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL,
964003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION),
965003ebb0eSIngo Weinhold _location);
966003ebb0eSIngo Weinhold }
96780ece785SIngo Weinhold
96880ece785SIngo Weinhold if (status == B_OK && _inImage != NULL)
96980ece785SIngo Weinhold *_inImage = image->id;
97080ece785SIngo Weinhold } else
9710c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID;
9720c0fea5dSIngo Weinhold
9730c0fea5dSIngo Weinhold return status;
9740c0fea5dSIngo Weinhold }
9750c0fea5dSIngo Weinhold
9760c0fea5dSIngo Weinhold
9770c0fea5dSIngo Weinhold status_t
get_library_symbol(void * handle,void * caller,const char * symbolName,void ** _location)9780c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
9790c85bd05SIngo Weinhold void **_location)
9800c85bd05SIngo Weinhold {
9810c85bd05SIngo Weinhold status_t status = B_ENTRY_NOT_FOUND;
9820c85bd05SIngo Weinhold
9830c85bd05SIngo Weinhold if (symbolName == NULL)
9840c85bd05SIngo Weinhold return B_BAD_VALUE;
9850c85bd05SIngo Weinhold
986f167d21aSAugustin Cavalier RecursiveLocker _(sLock);
9870c85bd05SIngo Weinhold // for now, just do stupid simple global locking
9880c85bd05SIngo Weinhold
9890c85bd05SIngo Weinhold if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
9900c85bd05SIngo Weinhold // look in the default scope
9910c85bd05SIngo Weinhold image_t* image;
992e3ac2588SAlex Smith elf_sym* symbol = find_undefined_symbol_global(gProgramImage,
99394830eb2SIngo Weinhold gProgramImage,
994003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
995003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION),
996003ebb0eSIngo Weinhold &image);
9970c85bd05SIngo Weinhold if (symbol != NULL) {
9980c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value + image->regions[0].delta);
999e3ac2588SAlex Smith int32 symbolType = symbol->Type() == STT_FUNC
10000c85bd05SIngo Weinhold ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
10010c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, &symbolType);
10020c85bd05SIngo Weinhold status = B_OK;
10030c85bd05SIngo Weinhold }
10040c85bd05SIngo Weinhold } else if (handle == RTLD_NEXT) {
10050c85bd05SIngo Weinhold // Look in the default scope, but also in the dependencies of the
10060c85bd05SIngo Weinhold // calling image. Return the next after the caller symbol.
10070c85bd05SIngo Weinhold
1008a2dad9e1SIngo Weinhold // First of all, find the caller image.
100994830eb2SIngo Weinhold image_t* callerImage = get_loaded_images().head;
10100c85bd05SIngo Weinhold for (; callerImage != NULL; callerImage = callerImage->next) {
10110c85bd05SIngo Weinhold elf_region_t& text = callerImage->regions[0];
1012a2dad9e1SIngo Weinhold if ((addr_t)caller >= text.vmstart
1013a2dad9e1SIngo Weinhold && (addr_t)caller < text.vmstart + text.vmsize) {
1014a2dad9e1SIngo Weinhold // found the image
10150c85bd05SIngo Weinhold break;
10160c85bd05SIngo Weinhold }
10170c85bd05SIngo Weinhold }
10180c85bd05SIngo Weinhold
1019a2dad9e1SIngo Weinhold if (callerImage != NULL) {
10200c85bd05SIngo Weinhold // found the caller -- now search the global scope until we find
10210c85bd05SIngo Weinhold // the next symbol
1022a2dad9e1SIngo Weinhold bool hitCallerImage = false;
10230c85bd05SIngo Weinhold set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
10240c85bd05SIngo Weinhold
1025e3ac2588SAlex Smith elf_sym* candidateSymbol = NULL;
102625dc253dSIngo Weinhold image_t* candidateImage = NULL;
102725dc253dSIngo Weinhold
102894830eb2SIngo Weinhold image_t* image = get_loaded_images().head;
10290c85bd05SIngo Weinhold for (; image != NULL; image = image->next) {
1030a2dad9e1SIngo Weinhold // skip the caller image
1031a2dad9e1SIngo Weinhold if (image == callerImage) {
1032a2dad9e1SIngo Weinhold hitCallerImage = true;
1033a2dad9e1SIngo Weinhold continue;
1034a2dad9e1SIngo Weinhold }
1035a2dad9e1SIngo Weinhold
1036a2dad9e1SIngo Weinhold // skip all images up to the caller image; also skip add-on
1037a2dad9e1SIngo Weinhold // images and those not marked above for resolution
1038a2dad9e1SIngo Weinhold if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
10390c85bd05SIngo Weinhold || (image->flags
1040a2dad9e1SIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
10410c85bd05SIngo Weinhold continue;
10420c85bd05SIngo Weinhold }
10430c85bd05SIngo Weinhold
1044e3ac2588SAlex Smith elf_sym *symbol = find_symbol(image,
1045003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
1046003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION));
10470c85bd05SIngo Weinhold if (symbol == NULL)
10480c85bd05SIngo Weinhold continue;
10490c85bd05SIngo Weinhold
105025dc253dSIngo Weinhold // found a symbol
1051e3ac2588SAlex Smith bool isWeak = symbol->Bind() == STB_WEAK;
105225dc253dSIngo Weinhold if (candidateImage == NULL || !isWeak) {
105325dc253dSIngo Weinhold candidateSymbol = symbol;
105425dc253dSIngo Weinhold candidateImage = image;
105525dc253dSIngo Weinhold
105625dc253dSIngo Weinhold if (!isWeak)
105725dc253dSIngo Weinhold break;
105825dc253dSIngo Weinhold }
105925dc253dSIngo Weinhold
106025dc253dSIngo Weinhold // symbol is weak, so we need to continue
106125dc253dSIngo Weinhold }
106225dc253dSIngo Weinhold
106325dc253dSIngo Weinhold if (candidateSymbol != NULL) {
1064a2dad9e1SIngo Weinhold // found the symbol
106525dc253dSIngo Weinhold *_location = (void*)(candidateSymbol->st_value
106625dc253dSIngo Weinhold + candidateImage->regions[0].delta);
10670c85bd05SIngo Weinhold int32 symbolType = B_SYMBOL_TYPE_TEXT;
106825dc253dSIngo Weinhold patch_defined_symbol(candidateImage, symbolName, _location,
10690c85bd05SIngo Weinhold &symbolType);
10700c85bd05SIngo Weinhold status = B_OK;
10710c85bd05SIngo Weinhold }
10720c85bd05SIngo Weinhold
10730c85bd05SIngo Weinhold clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
10740c85bd05SIngo Weinhold }
10750c85bd05SIngo Weinhold } else {
10760c85bd05SIngo Weinhold // breadth-first search in the given image and its dependencies
10770c85bd05SIngo Weinhold image_t* inImage;
1078003ebb0eSIngo Weinhold status = find_symbol_breadth_first((image_t*)handle,
1079003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
1080003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION),
1081003ebb0eSIngo Weinhold &inImage, _location);
10820c85bd05SIngo Weinhold }
10830c85bd05SIngo Weinhold
10840c85bd05SIngo Weinhold return status;
10850c85bd05SIngo Weinhold }
10860c85bd05SIngo Weinhold
10870c85bd05SIngo Weinhold
10880c85bd05SIngo Weinhold status_t
get_next_image_dependency(image_id id,uint32 * cookie,const char ** _name)10890c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
10900c0fea5dSIngo Weinhold {
10910c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie;
1092e3ac2588SAlex Smith elf_dyn *dynamicSection;
10930c0fea5dSIngo Weinhold image_t *image;
10940c0fea5dSIngo Weinhold
10950c0fea5dSIngo Weinhold if (_name == NULL)
10960c0fea5dSIngo Weinhold return B_BAD_VALUE;
10970c0fea5dSIngo Weinhold
1098f167d21aSAugustin Cavalier RecursiveLocker _(sLock);
10990c0fea5dSIngo Weinhold
110094830eb2SIngo Weinhold image = find_loaded_image_by_id(id, false);
1101f167d21aSAugustin Cavalier if (image == NULL)
11020c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID;
11030c0fea5dSIngo Weinhold
1104e3ac2588SAlex Smith dynamicSection = (elf_dyn *)image->dynamic_ptr;
1105f167d21aSAugustin Cavalier if (dynamicSection == NULL || image->num_needed <= searchIndex)
11060c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND;
11070c0fea5dSIngo Weinhold
11080c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
11090c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED)
11100c0fea5dSIngo Weinhold continue;
11110c0fea5dSIngo Weinhold
11120c0fea5dSIngo Weinhold if (j++ == searchIndex) {
11130c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val;
11140c0fea5dSIngo Weinhold
11150c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset);
11160c0fea5dSIngo Weinhold *cookie = searchIndex + 1;
11170c0fea5dSIngo Weinhold return B_OK;
11180c0fea5dSIngo Weinhold }
11190c0fea5dSIngo Weinhold }
11200c0fea5dSIngo Weinhold
11210c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND;
11220c0fea5dSIngo Weinhold }
11230c0fea5dSIngo Weinhold
11240c0fea5dSIngo Weinhold
112574c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports
11260c0fea5dSIngo Weinhold
11270c0fea5dSIngo Weinhold
11289a6072a3SAxel Dörfler /*! Read and verify the ELF header */
11290c0fea5dSIngo Weinhold status_t
elf_verify_header(void * header,size_t length)1130e3ac2588SAlex Smith elf_verify_header(void *header, size_t length)
11310c0fea5dSIngo Weinhold {
11320c0fea5dSIngo Weinhold int32 programSize, sectionSize;
11330c0fea5dSIngo Weinhold
1134e3ac2588SAlex Smith if (length < sizeof(elf_ehdr))
11350c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE;
11360c0fea5dSIngo Weinhold
1137e3ac2588SAlex Smith return parse_elf_header((elf_ehdr *)header, &programSize, §ionSize);
11380c0fea5dSIngo Weinhold }
11390c0fea5dSIngo Weinhold
11400c0fea5dSIngo Weinhold
11412aaad308SJérôme Duval #ifdef _COMPAT_MODE
11422aaad308SJérôme Duval #ifdef __x86_64__
11432aaad308SJérôme Duval status_t
elf32_verify_header(void * header,size_t length)11442aaad308SJérôme Duval elf32_verify_header(void *header, size_t length)
11452aaad308SJérôme Duval {
11462aaad308SJérôme Duval int32 programSize, sectionSize;
11472aaad308SJérôme Duval
11482aaad308SJérôme Duval if (length < sizeof(Elf32_Ehdr))
11492aaad308SJérôme Duval return B_NOT_AN_EXECUTABLE;
11502aaad308SJérôme Duval
11512aaad308SJérôme Duval return parse_elf32_header((Elf32_Ehdr *)header, &programSize, §ionSize);
11522aaad308SJérôme Duval }
11532aaad308SJérôme Duval #else
11542aaad308SJérôme Duval status_t
elf64_verify_header(void * header,size_t length)11552aaad308SJérôme Duval elf64_verify_header(void *header, size_t length)
11562aaad308SJérôme Duval {
11572aaad308SJérôme Duval int32 programSize, sectionSize;
11582aaad308SJérôme Duval
11592aaad308SJérôme Duval if (length < sizeof(Elf64_Ehdr))
11602aaad308SJérôme Duval return B_NOT_AN_EXECUTABLE;
11612aaad308SJérôme Duval
11622aaad308SJérôme Duval return parse_elf64_header((Elf64_Ehdr *)header, &programSize, §ionSize);
11632aaad308SJérôme Duval }
11642aaad308SJérôme Duval #endif // __x86_64__
11652aaad308SJérôme Duval #endif // _COMPAT_MODE
11662aaad308SJérôme Duval
11672aaad308SJérôme Duval
11680c0fea5dSIngo Weinhold void
terminate_program(void)11690c0fea5dSIngo Weinhold terminate_program(void)
11700c0fea5dSIngo Weinhold {
11710c0fea5dSIngo Weinhold image_t **termList;
11720c0fea5dSIngo Weinhold ssize_t count, i;
11730c0fea5dSIngo Weinhold
1174aa3507feSIngo Weinhold count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED);
11750c0fea5dSIngo Weinhold if (count < B_OK)
11760c0fea5dSIngo Weinhold return;
11770c0fea5dSIngo Weinhold
117894830eb2SIngo Weinhold if (gInvalidImageIDs) {
11799a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images
11809a6072a3SAxel Dörfler update_image_ids();
11819a6072a3SAxel Dörfler }
11829a6072a3SAxel Dörfler
11830c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
11840c0fea5dSIngo Weinhold for (i = count; i-- > 0;) {
11850c0fea5dSIngo Weinhold image_t *image = termList[i];
11860c0fea5dSIngo Weinhold
11870c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name));
11880c0fea5dSIngo Weinhold
118910b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING);
119010b4b5d1SIngo Weinhold
11915d08e3a5SAugustin Cavalier call_term_functions(image);
119210b4b5d1SIngo Weinhold
119310b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING);
11940c0fea5dSIngo Weinhold }
11950c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL)));
11960c0fea5dSIngo Weinhold
11970c0fea5dSIngo Weinhold free(termList);
11980c0fea5dSIngo Weinhold }
11990c0fea5dSIngo Weinhold
12000c0fea5dSIngo Weinhold
12010c0fea5dSIngo Weinhold void
rldelf_init(void)12020c0fea5dSIngo Weinhold rldelf_init(void)
12030c0fea5dSIngo Weinhold {
120494830eb2SIngo Weinhold init_add_ons();
120594830eb2SIngo Weinhold
12060c0fea5dSIngo Weinhold // create the debug area
12070c0fea5dSIngo Weinhold {
1208e3ac2588SAlex Smith size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
12090c0fea5dSIngo Weinhold
12100c0fea5dSIngo Weinhold runtime_loader_debug_area *area;
12110c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
12129f3bd497SPawel Dziepak (void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK,
121340b0fbbbSAugustin Cavalier B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA);
12140c0fea5dSIngo Weinhold if (areaID < B_OK) {
12150c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n");
12160c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID);
12170c0fea5dSIngo Weinhold }
12180c0fea5dSIngo Weinhold
121994830eb2SIngo Weinhold area->loaded_images = &get_loaded_images();
12200c0fea5dSIngo Weinhold }
122174c0424aSAxel Dörfler
122274c0424aSAxel Dörfler // initialize error message if needed
12234bef3723SAxel Dörfler if (report_errors()) {
122474c0424aSAxel Dörfler void *buffer = malloc(1024);
122574c0424aSAxel Dörfler if (buffer == NULL)
122674c0424aSAxel Dörfler return;
122774c0424aSAxel Dörfler
122894830eb2SIngo Weinhold gErrorMessage.SetTo(buffer, 1024, 'Rler');
122974c0424aSAxel Dörfler }
12300c0fea5dSIngo Weinhold }
12311873b4b3SIngo Weinhold
12321873b4b3SIngo Weinhold
12331873b4b3SIngo Weinhold status_t
elf_reinit_after_fork(void)12349a6072a3SAxel Dörfler elf_reinit_after_fork(void)
12351873b4b3SIngo Weinhold {
1236f7127458SIngo Weinhold recursive_lock_init(&sLock, kLockName);
12371873b4b3SIngo Weinhold
12389a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and
1239cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork()
1240cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one
12419a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different.
124294830eb2SIngo Weinhold gInvalidImageIDs = true;
1243cbc456deSIngo Weinhold
12441873b4b3SIngo Weinhold return B_OK;
12451873b4b3SIngo Weinhold }
1246