xref: /haiku/src/system/runtime_loader/elf.cpp (revision 1f1be520070165ce402b46d17a44a2941c0dda2f)
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, &sectionSize);
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, &sectionSize);
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, &sectionSize);
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