xref: /haiku/src/system/runtime_loader/elf.cpp (revision 58dcc29b6d1ca38f57e26cae6a34a8713f41fa5b)
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 *
570c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
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++) {
630c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
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 
7135fa85dbSJérôme Duval image_id
7235fa85dbSJérôme Duval preload_image(char const* path, image_t **image)
7335fa85dbSJérôme Duval {
7435fa85dbSJérôme Duval 	if (path == NULL)
7535fa85dbSJérôme Duval 		return B_BAD_VALUE;
7635fa85dbSJérôme Duval 
7735fa85dbSJérôme Duval 	KTRACE("rld: preload_image(\"%s\")", path);
7835fa85dbSJérôme Duval 
7935fa85dbSJérôme Duval 	status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, image);
8035fa85dbSJérôme Duval 	if (status < B_OK) {
8135fa85dbSJérôme Duval 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
8235fa85dbSJérôme Duval 			strerror(status));
8335fa85dbSJérôme Duval 		return status;
8435fa85dbSJérôme Duval 	}
8535fa85dbSJérôme Duval 
8635fa85dbSJérôme Duval 	if ((*image)->find_undefined_symbol == NULL)
8735fa85dbSJérôme Duval 		(*image)->find_undefined_symbol = find_undefined_symbol_global;
8835fa85dbSJérôme Duval 
8935fa85dbSJérôme Duval 	KTRACE("rld: preload_image(\"%s\") done: id: %" B_PRId32, path, (*image)->id);
9035fa85dbSJérôme Duval 
9135fa85dbSJérôme Duval 	return (*image)->id;
9235fa85dbSJérôme Duval }
9335fa85dbSJérôme Duval 
9435fa85dbSJérôme Duval 
9535fa85dbSJérôme Duval static void
9635fa85dbSJérôme Duval preload_images(image_t **image, int32 *_count = NULL)
9735fa85dbSJérôme Duval {
9835fa85dbSJérôme Duval 	const char* imagePaths = getenv("LD_PRELOAD");
9935fa85dbSJérôme Duval 	if (imagePaths == NULL) {
10035fa85dbSJérôme Duval 		if (_count != NULL)
10135fa85dbSJérôme Duval 			*_count = 0;
10235fa85dbSJérôme Duval 		return;
10335fa85dbSJérôme Duval 	}
10435fa85dbSJérôme Duval 
10535fa85dbSJérôme Duval 	int32 count = 0;
10635fa85dbSJérôme Duval 
10735fa85dbSJérôme Duval 	while (*imagePaths != '\0') {
10835fa85dbSJérôme Duval 		// find begin of image path
10935fa85dbSJérôme Duval 		while (*imagePaths != '\0' && isspace(*imagePaths))
11035fa85dbSJérôme Duval 			imagePaths++;
11135fa85dbSJérôme Duval 
11235fa85dbSJérôme Duval 		if (*imagePaths == '\0')
11335fa85dbSJérôme Duval 			break;
11435fa85dbSJérôme Duval 
11535fa85dbSJérôme Duval 		// find end of image path
11635fa85dbSJérôme Duval 		const char* imagePath = imagePaths;
11735fa85dbSJérôme Duval 		while (*imagePaths != '\0' && !isspace(*imagePaths))
11835fa85dbSJérôme Duval 			imagePaths++;
11935fa85dbSJérôme Duval 
12035fa85dbSJérôme Duval 		// extract the path
12135fa85dbSJérôme Duval 		char path[B_PATH_NAME_LENGTH];
12235fa85dbSJérôme Duval 		size_t pathLen = imagePaths - imagePath;
12335fa85dbSJérôme Duval 		if (pathLen > sizeof(path) - 1)
12435fa85dbSJérôme Duval 			continue;
12535fa85dbSJérôme Duval 
12635fa85dbSJérôme Duval 		if (image == NULL) {
12735fa85dbSJérôme Duval 			count++;
12835fa85dbSJérôme Duval 			continue;
12935fa85dbSJérôme Duval 		}
13035fa85dbSJérôme Duval 		memcpy(path, imagePath, pathLen);
13135fa85dbSJérôme Duval 		path[pathLen] = '\0';
13235fa85dbSJérôme Duval 
13335fa85dbSJérôme Duval 		// load the image
13435fa85dbSJérôme Duval 		preload_image(path, &image[count++]);
13535fa85dbSJérôme Duval 	}
13635fa85dbSJérôme Duval 
13735fa85dbSJérôme Duval 	KTRACE("rld: preload_images count: %d", count);
13835fa85dbSJérôme Duval 
13935fa85dbSJérôme Duval 	if (_count != NULL)
14035fa85dbSJérôme Duval 		*_count = count;
14135fa85dbSJérôme Duval }
14235fa85dbSJérôme Duval 
14335fa85dbSJérôme Duval 
1440c0fea5dSIngo Weinhold static status_t
14535fa85dbSJérôme Duval load_immediate_dependencies(image_t *image, bool preload)
1460c0fea5dSIngo Weinhold {
147e3ac2588SAlex Smith 	elf_dyn *d = (elf_dyn *)image->dynamic_ptr;
1484bef3723SAxel Dörfler 	bool reportErrors = report_errors();
14974c0424aSAxel Dörfler 	status_t status = B_OK;
1500c0fea5dSIngo Weinhold 	uint32 i, j;
1510c0fea5dSIngo Weinhold 	const char *rpath;
1520c0fea5dSIngo Weinhold 
1530c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
1540c0fea5dSIngo Weinhold 		return B_OK;
1550c0fea5dSIngo Weinhold 
1560c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
1570c0fea5dSIngo Weinhold 
15835fa85dbSJérôme Duval 	int32 preloadedCount = 0;
15935fa85dbSJérôme Duval 	if (preload) {
16035fa85dbSJérôme Duval 		preload_images(NULL, &preloadedCount);
16135fa85dbSJérôme Duval 		image->num_needed += preloadedCount;
16235fa85dbSJérôme Duval 	}
1630c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
1640c0fea5dSIngo Weinhold 		return B_OK;
1650c0fea5dSIngo Weinhold 
166ded25be1SIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ")", image->name,
1677486b72dSIngo Weinhold 		image->id);
1687486b72dSIngo Weinhold 
1690c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
1700c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
171c533f813SIngo Weinhold 		FATAL("%s: Failed to allocate needed struct\n", image->path);
172ded25be1SIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32
173ded25be1SIngo Weinhold 			") failed: no memory", image->name, image->id);
1740c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
1750c0fea5dSIngo Weinhold 	}
1760c0fea5dSIngo Weinhold 
1770c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
17835fa85dbSJérôme Duval 	if (preload)
17935fa85dbSJérôme Duval 		preload_images(image->needed);
1800c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
1810c0fea5dSIngo Weinhold 
18235fa85dbSJérôme Duval 	for (i = 0, j = preloadedCount; d[i].d_tag != DT_NULL; i++) {
1830c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
1840c0fea5dSIngo Weinhold 			case DT_NEEDED:
18574c0424aSAxel Dörfler 			{
18674c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
18774c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
1880c0fea5dSIngo Weinhold 
18994830eb2SIngo Weinhold 				status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
1908d23c440SIngo Weinhold 					rpath, image->path, &image->needed[j]);
19174c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
19274c0424aSAxel Dörfler 					status = loadStatus;
19374c0424aSAxel Dörfler 					// correct error code in case the file could not been found
19474c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
19574c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
19674c0424aSAxel Dörfler 
19774c0424aSAxel Dörfler 						if (reportErrors)
19894830eb2SIngo Weinhold 							gErrorMessage.AddString("missing library", name);
19974c0424aSAxel Dörfler 					}
20074c0424aSAxel Dörfler 
20174c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
2027486b72dSIngo Weinhold 					if (!reportErrors) {
203ded25be1SIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32
204ded25be1SIngo Weinhold 							") failed: %s", image->name, image->id,
2057486b72dSIngo Weinhold 							strerror(status));
2060c0fea5dSIngo Weinhold 						return status;
20774c0424aSAxel Dörfler 					}
2087486b72dSIngo Weinhold 				}
2090c0fea5dSIngo Weinhold 
2100c0fea5dSIngo Weinhold 				j += 1;
2110c0fea5dSIngo Weinhold 				break;
21274c0424aSAxel Dörfler 			}
2130c0fea5dSIngo Weinhold 
2140c0fea5dSIngo Weinhold 			default:
2150c0fea5dSIngo Weinhold 				// ignore any other tag
2160c0fea5dSIngo Weinhold 				continue;
2170c0fea5dSIngo Weinhold 		}
2180c0fea5dSIngo Weinhold 	}
2190c0fea5dSIngo Weinhold 
2207486b72dSIngo Weinhold 	if (status < B_OK) {
221ded25be1SIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") "
2227486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
2237486b72dSIngo Weinhold 			strerror(status));
22474c0424aSAxel Dörfler 		return status;
2257486b72dSIngo Weinhold 	}
22674c0424aSAxel Dörfler 
2270c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
2280c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
229ded25be1SIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") "
2307486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
2310c0fea5dSIngo Weinhold 		return B_ERROR;
2320c0fea5dSIngo Weinhold 	}
2330c0fea5dSIngo Weinhold 
234ded25be1SIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") done",
235ded25be1SIngo Weinhold 		image->name, image->id);
2367486b72dSIngo Weinhold 
2370c0fea5dSIngo Weinhold 	return B_OK;
2380c0fea5dSIngo Weinhold }
2390c0fea5dSIngo Weinhold 
2400c0fea5dSIngo Weinhold 
2410c85bd05SIngo Weinhold static status_t
24235fa85dbSJérôme Duval load_dependencies(image_t* image, bool preload = false)
2430c85bd05SIngo Weinhold {
244003ebb0eSIngo Weinhold 	// load dependencies (breadth-first)
2450c85bd05SIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
2460c85bd05SIngo Weinhold 			otherImage = otherImage->next) {
24735fa85dbSJérôme Duval 		status_t status = load_immediate_dependencies(otherImage, preload);
2480c85bd05SIngo Weinhold 		if (status != B_OK)
2490c85bd05SIngo Weinhold 			return status;
25035fa85dbSJérôme Duval 		preload = false;
2510c85bd05SIngo Weinhold 	}
2520c85bd05SIngo Weinhold 
253003ebb0eSIngo Weinhold 	// Check the needed versions for the given image and all newly loaded
254003ebb0eSIngo Weinhold 	// dependencies.
255003ebb0eSIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
256003ebb0eSIngo Weinhold 			otherImage = otherImage->next) {
257003ebb0eSIngo Weinhold 		status_t status = check_needed_image_versions(otherImage);
258003ebb0eSIngo Weinhold 		if (status != B_OK)
259003ebb0eSIngo Weinhold 			return status;
260003ebb0eSIngo Weinhold 	}
261003ebb0eSIngo Weinhold 
2620c85bd05SIngo Weinhold 	return B_OK;
2630c85bd05SIngo Weinhold }
2640c85bd05SIngo Weinhold 
2650c85bd05SIngo Weinhold 
26694830eb2SIngo Weinhold static status_t
26794830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
2680c0fea5dSIngo Weinhold {
26925dc253dSIngo Weinhold 	SymbolLookupCache cache(image);
27025dc253dSIngo Weinhold 
27125dc253dSIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image, &cache);
27294830eb2SIngo Weinhold 	if (status < B_OK) {
273c533f813SIngo Weinhold 		FATAL("%s: Troubles relocating: %s\n", image->path, strerror(status));
27494830eb2SIngo Weinhold 		return status;
2750c0fea5dSIngo Weinhold 	}
2760c0fea5dSIngo Weinhold 
27794830eb2SIngo Weinhold 	_kern_image_relocated(image->id);
27894830eb2SIngo Weinhold 	image_event(image, IMAGE_EVENT_RELOCATED);
27994830eb2SIngo Weinhold 	return B_OK;
2800c0fea5dSIngo Weinhold }
2810c0fea5dSIngo Weinhold 
2820c0fea5dSIngo Weinhold 
2830c0fea5dSIngo Weinhold static status_t
2840c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
2850c0fea5dSIngo Weinhold {
286ca618b22SIngo Weinhold 	// get the images that still have to be relocated
287ca618b22SIngo Weinhold 	image_t **list;
288ca618b22SIngo Weinhold 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
2890c0fea5dSIngo Weinhold 	if (count < B_OK)
2900c0fea5dSIngo Weinhold 		return count;
2910c0fea5dSIngo Weinhold 
2920c85bd05SIngo Weinhold 	// relocate
293ca618b22SIngo Weinhold 	for (ssize_t i = 0; i < count; i++) {
29446f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
2950c85bd05SIngo Weinhold 		if (status < B_OK) {
2960c85bd05SIngo Weinhold 			free(list);
2970c0fea5dSIngo Weinhold 			return status;
2980c0fea5dSIngo Weinhold 		}
2990c85bd05SIngo Weinhold 	}
3000c0fea5dSIngo Weinhold 
3010c0fea5dSIngo Weinhold 	free(list);
3020c0fea5dSIngo Weinhold 	return B_OK;
3030c0fea5dSIngo Weinhold }
3040c0fea5dSIngo Weinhold 
3050c0fea5dSIngo Weinhold 
3060c0fea5dSIngo Weinhold static void
3070c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
3080c0fea5dSIngo Weinhold {
309*58dcc29bSAugustin Cavalier 	image_t **initList = NULL;
3100c0fea5dSIngo Weinhold 	ssize_t count, i;
3110c0fea5dSIngo Weinhold 
3123a75ef9aSJérôme Duval 	if (initHead && image->preinit_array) {
3133a75ef9aSJérôme Duval 		uint count_preinit = image->preinit_array_len / sizeof(addr_t);
3143a75ef9aSJérôme Duval 		for (uint j = 0; j < count_preinit; j++)
3153a75ef9aSJérôme Duval 			((initfini_array_function)image->preinit_array[j])();
3163a75ef9aSJérôme Duval 	}
3173a75ef9aSJérôme Duval 
3180c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
319*58dcc29bSAugustin Cavalier 	if (count <= 0) {
320*58dcc29bSAugustin Cavalier 		free(initList);
3210c0fea5dSIngo Weinhold 		return;
322*58dcc29bSAugustin Cavalier 	}
3230c0fea5dSIngo Weinhold 
3240c0fea5dSIngo Weinhold 	if (!initHead) {
3250c0fea5dSIngo Weinhold 		// this removes the "calling" image
3260c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
3270c0fea5dSIngo Weinhold 		initList[--count] = NULL;
3280c0fea5dSIngo Weinhold 	}
3290c0fea5dSIngo Weinhold 
3300c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
3310c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
3320c0fea5dSIngo Weinhold 		image = initList[i];
3330c0fea5dSIngo Weinhold 
3340c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
3350c0fea5dSIngo Weinhold 
336354b60afSAugustin Cavalier 		init_term_function before;
337354b60afSAugustin Cavalier 		if (find_symbol(image,
338354b60afSAugustin Cavalier 				SymbolLookupInfo(B_INIT_BEFORE_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
339354b60afSAugustin Cavalier 				(void**)&before) == B_OK) {
340354b60afSAugustin Cavalier 			before(image->id);
341e340f717SJérôme Duval 		}
342e340f717SJérôme Duval 
343dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
3440c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
34510b4b5d1SIngo Weinhold 
346e340f717SJérôme Duval 		if (image->init_array) {
347e340f717SJérôme Duval 			uint count_init = image->init_array_len / sizeof(addr_t);
348e340f717SJérôme Duval 			for (uint j = 0; j < count_init; j++)
349354b60afSAugustin Cavalier 				((initfini_array_function)image->init_array[j])();
350354b60afSAugustin Cavalier 		}
351354b60afSAugustin Cavalier 
352354b60afSAugustin Cavalier 		init_term_function after;
353354b60afSAugustin Cavalier 		if (find_symbol(image,
354354b60afSAugustin Cavalier 				SymbolLookupInfo(B_INIT_AFTER_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
355354b60afSAugustin Cavalier 				(void**)&after) == B_OK) {
356354b60afSAugustin Cavalier 			after(image->id);
357e340f717SJérôme Duval 		}
358e340f717SJérôme Duval 
35910b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
3600c0fea5dSIngo Weinhold 	}
3610c0fea5dSIngo Weinhold 	TRACE(("%ld: init done.\n", find_thread(NULL)));
3620c0fea5dSIngo Weinhold 
3630c0fea5dSIngo Weinhold 	free(initList);
3640c0fea5dSIngo Weinhold }
3650c0fea5dSIngo Weinhold 
3660c0fea5dSIngo Weinhold 
3670c0fea5dSIngo Weinhold static void
3685d08e3a5SAugustin Cavalier call_term_functions(image_t* image)
3695d08e3a5SAugustin Cavalier {
3705d08e3a5SAugustin Cavalier 	init_term_function before;
3715d08e3a5SAugustin Cavalier 	if (find_symbol(image,
3725d08e3a5SAugustin Cavalier 			SymbolLookupInfo(B_TERM_BEFORE_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
3735d08e3a5SAugustin Cavalier 			(void**)&before) == B_OK) {
3745d08e3a5SAugustin Cavalier 		before(image->id);
3755d08e3a5SAugustin Cavalier 	}
3765d08e3a5SAugustin Cavalier 
3775d08e3a5SAugustin Cavalier 	if (image->term_array) {
3785d08e3a5SAugustin Cavalier 		uint count_term = image->term_array_len / sizeof(addr_t);
3795d08e3a5SAugustin Cavalier 		for (uint i = count_term; i-- > 0;)
3805d08e3a5SAugustin Cavalier 			((initfini_array_function)image->term_array[i])();
3815d08e3a5SAugustin Cavalier 	}
3825d08e3a5SAugustin Cavalier 
3835d08e3a5SAugustin Cavalier 	if (image->term_routine)
3845d08e3a5SAugustin Cavalier 		((init_term_function)image->term_routine)(image->id);
3855d08e3a5SAugustin Cavalier 
3865d08e3a5SAugustin Cavalier 	init_term_function after;
3875d08e3a5SAugustin Cavalier 	if (find_symbol(image,
3885d08e3a5SAugustin Cavalier 			SymbolLookupInfo(B_TERM_AFTER_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
3895d08e3a5SAugustin Cavalier 			(void**)&after) == B_OK) {
3905d08e3a5SAugustin Cavalier 		after(image->id);
3915d08e3a5SAugustin Cavalier 	}
3925d08e3a5SAugustin Cavalier }
3935d08e3a5SAugustin Cavalier 
3945d08e3a5SAugustin Cavalier 
3955d08e3a5SAugustin Cavalier static void
396ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
397ca618b22SIngo Weinhold {
398ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
399ca618b22SIngo Weinhold 	// API.
400ca618b22SIngo Weinhold 	image_t* image;
4010c85bd05SIngo Weinhold 	void* _export;
402003ebb0eSIngo Weinhold 	if (find_symbol_breadth_first(rootImage,
403003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
404003ebb0eSIngo Weinhold 			&_export) == B_OK) {
4050c85bd05SIngo Weinhold 		*(void**)_export = &gRuntimeLoader;
406ca618b22SIngo Weinhold 	}
407ca618b22SIngo Weinhold }
408ca618b22SIngo Weinhold 
409ca618b22SIngo Weinhold 
410ca618b22SIngo Weinhold static status_t
41135fa85dbSJérôme Duval add_preloaded_addon(image_t* image)
412ca618b22SIngo Weinhold {
413ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
41435fa85dbSJérôme Duval 	// small number of preloaded addons.
41535fa85dbSJérôme Duval 	image_t** newArray = (image_t**)realloc(sPreloadedAddons,
41635fa85dbSJérôme Duval 		sizeof(image_t*) * (sPreloadedAddonCount + 1));
417ca618b22SIngo Weinhold 	if (newArray == NULL)
418ca618b22SIngo Weinhold 		return B_NO_MEMORY;
419ca618b22SIngo Weinhold 
42035fa85dbSJérôme Duval 	sPreloadedAddons = newArray;
42135fa85dbSJérôme Duval 	newArray[sPreloadedAddonCount++] = image;
422ca618b22SIngo Weinhold 
423ca618b22SIngo Weinhold 	return B_OK;
424ca618b22SIngo Weinhold }
425ca618b22SIngo Weinhold 
426ca618b22SIngo Weinhold 
427ca618b22SIngo Weinhold image_id
42835fa85dbSJérôme Duval preload_addon(char const* path)
429ca618b22SIngo Weinhold {
430ca618b22SIngo Weinhold 	if (path == NULL)
431ca618b22SIngo Weinhold 		return B_BAD_VALUE;
432ca618b22SIngo Weinhold 
43335fa85dbSJérôme Duval 	KTRACE("rld: preload_addon(\"%s\")", path);
434ca618b22SIngo Weinhold 
435ca618b22SIngo Weinhold 	image_t *image = NULL;
4368d23c440SIngo Weinhold 	status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, &image);
437ca618b22SIngo Weinhold 	if (status < B_OK) {
43835fa85dbSJérôme Duval 		KTRACE("rld: preload_addon(\"%s\") failed to load container: %s", path,
439ca618b22SIngo Weinhold 			strerror(status));
440ca618b22SIngo Weinhold 		return status;
441ca618b22SIngo Weinhold 	}
442ca618b22SIngo Weinhold 
4430c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL)
4440c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_global;
4450c85bd05SIngo Weinhold 
4460c85bd05SIngo Weinhold 	status = load_dependencies(image);
447ca618b22SIngo Weinhold 	if (status < B_OK)
448ca618b22SIngo Weinhold 		goto err;
4490c85bd05SIngo Weinhold 
4500c85bd05SIngo Weinhold 	set_image_flags_recursively(image, RTLD_GLOBAL);
451ca618b22SIngo Weinhold 
452ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
453ca618b22SIngo Weinhold 	if (status < B_OK)
454ca618b22SIngo Weinhold 		goto err;
455ca618b22SIngo Weinhold 
45635fa85dbSJérôme Duval 	status = add_preloaded_addon(image);
457ca618b22SIngo Weinhold 	if (status < B_OK)
458ca618b22SIngo Weinhold 		goto err;
459ca618b22SIngo Weinhold 
460ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
461ca618b22SIngo Weinhold 
462ca618b22SIngo Weinhold 	remap_images();
463ca618b22SIngo Weinhold 	init_dependencies(image, true);
464ca618b22SIngo Weinhold 
46510b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
46610b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
467003ebb0eSIngo Weinhold 	if (find_symbol(image,
468003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
46910b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
47094830eb2SIngo Weinhold 		add_add_on(image, addOnStruct);
47110b4b5d1SIngo Weinhold 	}
47210b4b5d1SIngo Weinhold 
47335fa85dbSJérôme Duval 	KTRACE("rld: preload_addon(\"%s\") done: id: %" B_PRId32, path, image->id);
474ca618b22SIngo Weinhold 
475ca618b22SIngo Weinhold 	return image->id;
476ca618b22SIngo Weinhold 
477ca618b22SIngo Weinhold err:
47835fa85dbSJérôme Duval 	KTRACE("rld: preload_addon(\"%s\") failed: %s", path, strerror(status));
479ca618b22SIngo Weinhold 
48094830eb2SIngo Weinhold 	dequeue_loaded_image(image);
481ca618b22SIngo Weinhold 	delete_image(image);
482ca618b22SIngo Weinhold 	return status;
483ca618b22SIngo Weinhold }
484ca618b22SIngo Weinhold 
485ca618b22SIngo Weinhold 
486ca618b22SIngo Weinhold static void
48735fa85dbSJérôme Duval preload_addons()
488ca618b22SIngo Weinhold {
48935fa85dbSJérôme Duval 	const char* imagePaths = getenv("LD_PRELOAD_ADDONS");
490ca618b22SIngo Weinhold 	if (imagePaths == NULL)
491ca618b22SIngo Weinhold 		return;
492ca618b22SIngo Weinhold 
493ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
494ca618b22SIngo Weinhold 		// find begin of image path
495ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
496ca618b22SIngo Weinhold 			imagePaths++;
497ca618b22SIngo Weinhold 
498ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
499ca618b22SIngo Weinhold 			break;
500ca618b22SIngo Weinhold 
501ca618b22SIngo Weinhold 		// find end of image path
502ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
503ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
504ca618b22SIngo Weinhold 			imagePaths++;
505ca618b22SIngo Weinhold 
506ca618b22SIngo Weinhold 		// extract the path
507ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
508ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
509ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
510ca618b22SIngo Weinhold 			continue;
511ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
512ca618b22SIngo Weinhold 		path[pathLen] = '\0';
513ca618b22SIngo Weinhold 
514ca618b22SIngo Weinhold 		// load the image
51535fa85dbSJérôme Duval 		preload_addon(path);
516ca618b22SIngo Weinhold 	}
517ca618b22SIngo Weinhold }
518ca618b22SIngo Weinhold 
519ca618b22SIngo Weinhold 
52074c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
5210c0fea5dSIngo Weinhold 
5220c0fea5dSIngo Weinhold 
5230c0fea5dSIngo Weinhold image_id
5240c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
5250c0fea5dSIngo Weinhold {
5260c0fea5dSIngo Weinhold 	status_t status;
5270c0fea5dSIngo Weinhold 	image_t *image;
5280c0fea5dSIngo Weinhold 
5297486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
5307486b72dSIngo Weinhold 
531f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
5320c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
5330c0fea5dSIngo Weinhold 
53435fa85dbSJérôme Duval 	preload_addons();
535ca618b22SIngo Weinhold 
5360c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
5370c0fea5dSIngo Weinhold 
5388d23c440SIngo Weinhold 	status = load_image(path, B_APP_IMAGE, NULL, NULL, &gProgramImage);
53974c0424aSAxel Dörfler 	if (status < B_OK)
54074c0424aSAxel Dörfler 		goto err;
5410c0fea5dSIngo Weinhold 
54294830eb2SIngo Weinhold 	if (gProgramImage->find_undefined_symbol == NULL)
54394830eb2SIngo Weinhold 		gProgramImage->find_undefined_symbol = find_undefined_symbol_global;
5440c85bd05SIngo Weinhold 
54535fa85dbSJérôme Duval 	status = load_dependencies(gProgramImage, true);
5460c0fea5dSIngo Weinhold 	if (status < B_OK)
5470c0fea5dSIngo Weinhold 		goto err;
5480c85bd05SIngo Weinhold 
54947bc6663SIngo Weinhold 	// Set RTLD_GLOBAL on all libraries including the program.
5500c85bd05SIngo Weinhold 	// This results in the desired symbol resolution for dlopen()ed libraries.
55194830eb2SIngo Weinhold 	set_image_flags_recursively(gProgramImage, RTLD_GLOBAL);
5520c0fea5dSIngo Weinhold 
55394830eb2SIngo Weinhold 	status = relocate_dependencies(gProgramImage);
5540c0fea5dSIngo Weinhold 	if (status < B_OK)
5550c0fea5dSIngo Weinhold 		goto err;
5560c0fea5dSIngo Weinhold 
55794830eb2SIngo Weinhold 	inject_runtime_loader_api(gProgramImage);
5580c0fea5dSIngo Weinhold 
5590c0fea5dSIngo Weinhold 	remap_images();
56094830eb2SIngo Weinhold 	init_dependencies(gProgramImage, true);
5610c0fea5dSIngo Weinhold 
5620c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
5630c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
56494830eb2SIngo Weinhold 	find_symbol_breadth_first(gProgramImage,
565003ebb0eSIngo Weinhold 		SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
566003ebb0eSIngo Weinhold 		(void**)&gGetEnv);
5670c0fea5dSIngo Weinhold 
56894830eb2SIngo Weinhold 	if (gProgramImage->entry_point == 0) {
5690c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
5700c0fea5dSIngo Weinhold 		goto err;
5710c0fea5dSIngo Weinhold 	}
5720c0fea5dSIngo Weinhold 
57394830eb2SIngo Weinhold 	*_entry = (void *)(gProgramImage->entry_point);
5740c0fea5dSIngo Weinhold 
57594830eb2SIngo Weinhold 	gProgramLoaded = true;
5765d0638bfSIngo Weinhold 
577ded25be1SIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %" B_PRId32 , path,
57894830eb2SIngo Weinhold 		*_entry, gProgramImage->id);
5797486b72dSIngo Weinhold 
58094830eb2SIngo Weinhold 	return gProgramImage->id;
5810c0fea5dSIngo Weinhold 
5820c0fea5dSIngo Weinhold err:
5837486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
5847486b72dSIngo Weinhold 
58594830eb2SIngo Weinhold 	delete_image(gProgramImage);
58674c0424aSAxel Dörfler 
5874bef3723SAxel Dörfler 	if (report_errors()) {
5884bef3723SAxel Dörfler 		// send error message
58994830eb2SIngo Weinhold 		gErrorMessage.AddInt32("error", status);
59094830eb2SIngo Weinhold 		gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
5914bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
5924bef3723SAxel Dörfler 
5934bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
59494830eb2SIngo Weinhold 			gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0);
59574c0424aSAxel Dörfler 	}
59674c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
59774c0424aSAxel Dörfler 
5980c0fea5dSIngo Weinhold 	return status;
5990c0fea5dSIngo Weinhold }
6000c0fea5dSIngo Weinhold 
6010c0fea5dSIngo Weinhold 
6020c0fea5dSIngo Weinhold image_id
6030c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle)
6040c0fea5dSIngo Weinhold {
6050c0fea5dSIngo Weinhold 	image_t *image = NULL;
6060c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
6070c0fea5dSIngo Weinhold 	status_t status;
6080c0fea5dSIngo Weinhold 
6090c85bd05SIngo Weinhold 	if (path == NULL && addOn)
6100c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
6110c0fea5dSIngo Weinhold 
612ded25be1SIngo Weinhold 	KTRACE("rld: load_library(\"%s\", %#" B_PRIx32 ", %d)", path, flags, addOn);
6137486b72dSIngo Weinhold 
614f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
6150c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
6160c0fea5dSIngo Weinhold 
6170c0fea5dSIngo Weinhold 	// have we already loaded this library?
6180c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
6190c0fea5dSIngo Weinhold 	if (!addOn) {
6200c85bd05SIngo Weinhold 		// a NULL path is fine -- it means the global scope shall be opened
6210c85bd05SIngo Weinhold 		if (path == NULL) {
6220c85bd05SIngo Weinhold 			*_handle = RLD_GLOBAL_SCOPE;
6230c85bd05SIngo Weinhold 			return 0;
6240c85bd05SIngo Weinhold 		}
6250c85bd05SIngo Weinhold 
62694830eb2SIngo Weinhold 		image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
6270c85bd05SIngo Weinhold 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
6280c85bd05SIngo Weinhold 			set_image_flags_recursively(image, RTLD_GLOBAL);
6290c85bd05SIngo Weinhold 
6300c0fea5dSIngo Weinhold 		if (image) {
6310c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
632ded25be1SIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %" B_PRId32,
633ded25be1SIngo Weinhold 				path, image->id);
6340c85bd05SIngo Weinhold 			*_handle = image;
6350c0fea5dSIngo Weinhold 			return image->id;
6360c0fea5dSIngo Weinhold 		}
6370c0fea5dSIngo Weinhold 	}
6380c0fea5dSIngo Weinhold 
6398d23c440SIngo Weinhold 	status = load_image(path, type, NULL, NULL, &image);
6400c0fea5dSIngo Weinhold 	if (status < B_OK) {
6417486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
6427486b72dSIngo Weinhold 			strerror(status));
6430c0fea5dSIngo Weinhold 		return status;
6440c0fea5dSIngo Weinhold 	}
6450c0fea5dSIngo Weinhold 
6460c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL) {
6470c85bd05SIngo Weinhold 		if (addOn)
6480c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_add_on;
6490c85bd05SIngo Weinhold 		else
6500c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_global;
6510c85bd05SIngo Weinhold 	}
6520c85bd05SIngo Weinhold 
6530c85bd05SIngo Weinhold 	status = load_dependencies(image);
6540c0fea5dSIngo Weinhold 	if (status < B_OK)
6550c0fea5dSIngo Weinhold 		goto err;
6560c85bd05SIngo Weinhold 
6570c85bd05SIngo Weinhold 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
6580c85bd05SIngo Weinhold 	// dependencies. If not specified, we temporarily set
6590c85bd05SIngo Weinhold 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
6600c85bd05SIngo Weinhold 	// for undefined symbol resolution.
6610c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) != 0)
6620c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RTLD_GLOBAL);
6630c85bd05SIngo Weinhold 	else
6640c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
6650c0fea5dSIngo Weinhold 
6660c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
6670c0fea5dSIngo Weinhold 	if (status < B_OK)
6680c0fea5dSIngo Weinhold 		goto err;
6690c0fea5dSIngo Weinhold 
6700c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) == 0)
6710c85bd05SIngo Weinhold 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
6720c85bd05SIngo Weinhold 
6730c0fea5dSIngo Weinhold 	remap_images();
6740c0fea5dSIngo Weinhold 	init_dependencies(image, true);
6750c0fea5dSIngo Weinhold 
676ded25be1SIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %" B_PRId32, path, image->id);
6777486b72dSIngo Weinhold 
6780c85bd05SIngo Weinhold 	*_handle = image;
6790c0fea5dSIngo Weinhold 	return image->id;
6800c0fea5dSIngo Weinhold 
6810c0fea5dSIngo Weinhold err:
6827486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
6837486b72dSIngo Weinhold 
68494830eb2SIngo Weinhold 	dequeue_loaded_image(image);
6850c0fea5dSIngo Weinhold 	delete_image(image);
6860c0fea5dSIngo Weinhold 	return status;
6870c0fea5dSIngo Weinhold }
6880c0fea5dSIngo Weinhold 
6890c0fea5dSIngo Weinhold 
6900c0fea5dSIngo Weinhold status_t
6910c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
6920c0fea5dSIngo Weinhold {
6930c0fea5dSIngo Weinhold 	image_t *image;
6940c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
6950c0fea5dSIngo Weinhold 
6960c85bd05SIngo Weinhold 	if (handle == NULL && imageID < 0)
6970c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
6980c0fea5dSIngo Weinhold 
6990c85bd05SIngo Weinhold 	if (handle == RLD_GLOBAL_SCOPE)
7000c85bd05SIngo Weinhold 		return B_OK;
7010c85bd05SIngo Weinhold 
702f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
7030c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
7040c0fea5dSIngo Weinhold 
70594830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
7069a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
7079a6072a3SAxel Dörfler 		update_image_ids();
7089a6072a3SAxel Dörfler 	}
7099a6072a3SAxel Dörfler 
7100c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
7110c0fea5dSIngo Weinhold 
712df30098dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
713df30098dSIngo Weinhold 
7140c85bd05SIngo Weinhold 	if (handle != NULL) {
7150c85bd05SIngo Weinhold 		image = (image_t*)handle;
7160c85bd05SIngo Weinhold 		put_image(image);
717df30098dSIngo Weinhold 		status = B_OK;
7180c85bd05SIngo Weinhold 	} else {
71994830eb2SIngo Weinhold 		image = find_loaded_image_by_id(imageID, true);
72094830eb2SIngo Weinhold 		if (image != NULL) {
7210c0fea5dSIngo Weinhold 			// unload image
7220c0fea5dSIngo Weinhold 			if (type == image->type) {
7230c0fea5dSIngo Weinhold 				put_image(image);
7240c0fea5dSIngo Weinhold 				status = B_OK;
7250c0fea5dSIngo Weinhold 			} else
7260c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
7270c0fea5dSIngo Weinhold 		}
7280c85bd05SIngo Weinhold 	}
7290c0fea5dSIngo Weinhold 
7300c0fea5dSIngo Weinhold 	if (status == B_OK) {
73194830eb2SIngo Weinhold 		while ((image = get_disposable_images().head) != NULL) {
732d64f6189SIngo Weinhold 			// Call the exit hooks that live in this image.
733d64f6189SIngo Weinhold 			// Note: With the Itanium ABI this shouldn't really be done this
734d64f6189SIngo Weinhold 			// way anymore, since global destructors are registered via
735d64f6189SIngo Weinhold 			// __cxa_atexit() (the ones that are registered dynamically) and the
736d64f6189SIngo Weinhold 			// termination routine should call __cxa_finalize() for the image.
737d64f6189SIngo Weinhold 			// The reason why we still do it is that hooks registered with
738d64f6189SIngo Weinhold 			// atexit() aren't associated with the image. We could find out
739d64f6189SIngo Weinhold 			// there which image the hooks lives in and register it
740d64f6189SIngo Weinhold 			// respectively, but since that would be done always, that's
741d64f6189SIngo Weinhold 			// probably more expensive than calling
742d64f6189SIngo Weinhold 			// call_atexit_hooks_for_range() only here, which happens only when
743d64f6189SIngo Weinhold 			// libraries are unloaded dynamically.
7448c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
7458c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
7463be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
7478c2a9d74SMichael Lotz 			}
7488c2a9d74SMichael Lotz 
74910b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
75010b4b5d1SIngo Weinhold 
7515d08e3a5SAugustin Cavalier 			call_term_functions(image);
752354b60afSAugustin Cavalier 
75344c0c4d3SPawel Dziepak 			TLSBlockTemplates::Get().Unregister(image->dso_tls_id);
75444c0c4d3SPawel Dziepak 
75594830eb2SIngo Weinhold 			dequeue_disposable_image(image);
7560c0fea5dSIngo Weinhold 			unmap_image(image);
7570c0fea5dSIngo Weinhold 
75810b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
75910b4b5d1SIngo Weinhold 
7600c0fea5dSIngo Weinhold 			delete_image(image);
7610c0fea5dSIngo Weinhold 		}
7620c0fea5dSIngo Weinhold 	}
7630c0fea5dSIngo Weinhold 
7640c0fea5dSIngo Weinhold 	return status;
7650c0fea5dSIngo Weinhold }
7660c0fea5dSIngo Weinhold 
7670c0fea5dSIngo Weinhold 
7680c0fea5dSIngo Weinhold status_t
7699a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
7709a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
7710c0fea5dSIngo Weinhold {
7720c0fea5dSIngo Weinhold 	int32 count = 0, j;
7730c0fea5dSIngo Weinhold 	uint32 i;
7740c0fea5dSIngo Weinhold 	image_t *image;
7750c0fea5dSIngo Weinhold 
776f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
7770c0fea5dSIngo Weinhold 
7780c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
77994830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
780f167d21aSAugustin Cavalier 	if (image == NULL)
7810c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
7820c0fea5dSIngo Weinhold 
7830c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
7840c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
7850c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
786e3ac2588SAlex Smith 			elf_sym *symbol = &image->syms[j];
7870c0fea5dSIngo Weinhold 
7880c0fea5dSIngo Weinhold 			if (count == num) {
78910b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
79010b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
79110b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
7920c0fea5dSIngo Weinhold 
79310b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
79410b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
79510b4b5d1SIngo Weinhold 				int32 type;
796e3ac2588SAlex Smith 				if (symbol->Type() == STT_FUNC)
79710b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
798e3ac2588SAlex Smith 				else if (symbol->Type() == STT_OBJECT)
79910b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
8000c0fea5dSIngo Weinhold 				else
80110b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
80210b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
8030c0fea5dSIngo Weinhold 
80410b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
80510b4b5d1SIngo Weinhold 
80610b4b5d1SIngo Weinhold 				if (_type != NULL)
80710b4b5d1SIngo Weinhold 					*_type = type;
8080c0fea5dSIngo Weinhold 				if (_location != NULL)
80910b4b5d1SIngo Weinhold 					*_location = location;
8100c0fea5dSIngo Weinhold 				goto out;
8110c0fea5dSIngo Weinhold 			}
8120c0fea5dSIngo Weinhold 			count++;
8130c0fea5dSIngo Weinhold 		}
8140c0fea5dSIngo Weinhold 	}
8150c0fea5dSIngo Weinhold out:
8160c0fea5dSIngo Weinhold 	if (num != count)
8170c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
8180c0fea5dSIngo Weinhold 
8190c0fea5dSIngo Weinhold 	return B_OK;
8200c0fea5dSIngo Weinhold }
8210c0fea5dSIngo Weinhold 
8220c0fea5dSIngo Weinhold 
8230c0fea5dSIngo Weinhold status_t
82443e7b1c2SHamish Morrison get_nearest_symbol_at_address(void* address, image_id* _imageID,
825ebdc1d48SMichael Lotz 	char** _imagePath, char** _imageName, char** _symbolName, int32* _type,
826ebdc1d48SMichael Lotz 	void** _location, bool* _exactMatch)
827b6455c08SAxel Dörfler {
828f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
829b6455c08SAxel Dörfler 
830b6455c08SAxel Dörfler 	image_t* image = find_loaded_image_by_address((addr_t)address);
831f167d21aSAugustin Cavalier 	if (image == NULL)
832b6455c08SAxel Dörfler 		return B_BAD_VALUE;
833b6455c08SAxel Dörfler 
834dee722ceSAugustin Cavalier 	if (_imageID != NULL)
835dee722ceSAugustin Cavalier 		*_imageID = image->id;
836dee722ceSAugustin Cavalier 	if (_imagePath != NULL)
837dee722ceSAugustin Cavalier 		*_imagePath = image->path;
838dee722ceSAugustin Cavalier 	if (_imageName != NULL)
839dee722ceSAugustin Cavalier 		*_imageName = image->name;
840dee722ceSAugustin Cavalier 
841dee722ceSAugustin Cavalier 	// If the caller does not want the actual symbol name, only the image,
842dee722ceSAugustin Cavalier 	// we can just return immediately.
843dee722ceSAugustin Cavalier 	if (_symbolName == NULL && _type == NULL && _location == NULL)
844dee722ceSAugustin Cavalier 		return B_OK;
845dee722ceSAugustin Cavalier 
846ebdc1d48SMichael Lotz 	bool exactMatch = false;
847e3ac2588SAlex Smith 	elf_sym* foundSymbol = NULL;
84843e7b1c2SHamish Morrison 	addr_t foundLocation = (addr_t)NULL;
84943e7b1c2SHamish Morrison 
850ebdc1d48SMichael Lotz 	for (uint32 i = 0; i < HASHTABSIZE(image) && !exactMatch; i++) {
851b6455c08SAxel Dörfler 		for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF;
852b6455c08SAxel Dörfler 				j = HASHCHAINS(image)[j]) {
853e3ac2588SAlex Smith 			elf_sym *symbol = &image->syms[j];
854b6455c08SAxel Dörfler 			addr_t location = symbol->st_value + image->regions[0].delta;
855b6455c08SAxel Dörfler 
85643e7b1c2SHamish Morrison 			if (location <= (addr_t)address	&& location >= foundLocation) {
85743e7b1c2SHamish Morrison 				foundSymbol = symbol;
85843e7b1c2SHamish Morrison 				foundLocation = location;
859b6455c08SAxel Dörfler 
86043e7b1c2SHamish Morrison 				// jump out if we have an exact match
861ebdc1d48SMichael Lotz 				if (location + symbol->st_size > (addr_t)address) {
862ebdc1d48SMichael Lotz 					exactMatch = true;
86343e7b1c2SHamish Morrison 					break;
86443e7b1c2SHamish Morrison 				}
86543e7b1c2SHamish Morrison 			}
86643e7b1c2SHamish Morrison 		}
86743e7b1c2SHamish Morrison 	}
868b6455c08SAxel Dörfler 
869ebdc1d48SMichael Lotz 	if (_exactMatch != NULL)
870ebdc1d48SMichael Lotz 		*_exactMatch = exactMatch;
87143e7b1c2SHamish Morrison 
87243e7b1c2SHamish Morrison 	if (foundSymbol != NULL) {
87343e7b1c2SHamish Morrison 		*_symbolName = SYMNAME(image, foundSymbol);
87443e7b1c2SHamish Morrison 
87543e7b1c2SHamish Morrison 		if (_type != NULL) {
876e3ac2588SAlex Smith 			if (foundSymbol->Type() == STT_FUNC)
87743e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_TEXT;
878e3ac2588SAlex Smith 			else if (foundSymbol->Type() == STT_OBJECT)
87943e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_DATA;
88043e7b1c2SHamish Morrison 			else
88143e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_ANY;
88243e7b1c2SHamish Morrison 			// TODO: check with the return types of that BeOS function
88343e7b1c2SHamish Morrison 		}
88443e7b1c2SHamish Morrison 
885b6455c08SAxel Dörfler 		if (_location != NULL)
88643e7b1c2SHamish Morrison 			*_location = (void*)foundLocation;
88743e7b1c2SHamish Morrison 	} else {
88843e7b1c2SHamish Morrison 		*_symbolName = NULL;
88943e7b1c2SHamish Morrison 		if (_location != NULL)
89043e7b1c2SHamish Morrison 			*_location = NULL;
89143e7b1c2SHamish Morrison 	}
892b6455c08SAxel Dörfler 
893b6455c08SAxel Dörfler 	return B_OK;
894b6455c08SAxel Dörfler }
895b6455c08SAxel Dörfler 
896b6455c08SAxel Dörfler 
897b6455c08SAxel Dörfler status_t
8989a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
89980ece785SIngo Weinhold 	bool recursive, image_id *_inImage, void **_location)
9000c0fea5dSIngo Weinhold {
9010c0fea5dSIngo Weinhold 	status_t status = B_OK;
9020c0fea5dSIngo Weinhold 	image_t *image;
9030c0fea5dSIngo Weinhold 
9040c0fea5dSIngo Weinhold 	if (imageID < B_OK)
9050c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
9060c0fea5dSIngo Weinhold 	if (symbolName == NULL)
9070c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
9080c0fea5dSIngo Weinhold 
909354b60afSAugustin Cavalier 	// Previously, these functions were called in __haiku_init_before
910354b60afSAugustin Cavalier 	// and __haiku_init_after. Now we call them inside runtime_loader,
911354b60afSAugustin Cavalier 	// so we prevent applications from fetching them.
912354b60afSAugustin Cavalier 	if (strcmp(symbolName, B_INIT_BEFORE_FUNCTION_NAME) == 0
913354b60afSAugustin Cavalier 		|| strcmp(symbolName, B_INIT_AFTER_FUNCTION_NAME) == 0
914354b60afSAugustin Cavalier 		|| strcmp(symbolName, B_TERM_BEFORE_FUNCTION_NAME) == 0
915354b60afSAugustin Cavalier 		|| strcmp(symbolName, B_TERM_AFTER_FUNCTION_NAME) == 0)
916354b60afSAugustin Cavalier 		return B_BAD_VALUE;
917354b60afSAugustin Cavalier 
918f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
9190c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
9200c0fea5dSIngo Weinhold 
9210c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
92294830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
92380ece785SIngo Weinhold 	if (image != NULL) {
92480ece785SIngo Weinhold 		if (recursive) {
92580ece785SIngo Weinhold 			// breadth-first search in the given image and its dependencies
926003ebb0eSIngo Weinhold 			status = find_symbol_breadth_first(image,
927003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
928003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
92980ece785SIngo Weinhold 				&image, _location);
930003ebb0eSIngo Weinhold 		} else {
931003ebb0eSIngo Weinhold 			status = find_symbol(image,
932003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
933003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
934003ebb0eSIngo Weinhold 				_location);
935003ebb0eSIngo Weinhold 		}
93680ece785SIngo Weinhold 
93780ece785SIngo Weinhold 		if (status == B_OK && _inImage != NULL)
93880ece785SIngo Weinhold 			*_inImage = image->id;
93980ece785SIngo Weinhold 	} else
9400c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
9410c0fea5dSIngo Weinhold 
9420c0fea5dSIngo Weinhold 	return status;
9430c0fea5dSIngo Weinhold }
9440c0fea5dSIngo Weinhold 
9450c0fea5dSIngo Weinhold 
9460c0fea5dSIngo Weinhold status_t
9470c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
9480c85bd05SIngo Weinhold 	void **_location)
9490c85bd05SIngo Weinhold {
9500c85bd05SIngo Weinhold 	status_t status = B_ENTRY_NOT_FOUND;
9510c85bd05SIngo Weinhold 
9520c85bd05SIngo Weinhold 	if (symbolName == NULL)
9530c85bd05SIngo Weinhold 		return B_BAD_VALUE;
9540c85bd05SIngo Weinhold 
955f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
9560c85bd05SIngo Weinhold 		// for now, just do stupid simple global locking
9570c85bd05SIngo Weinhold 
9580c85bd05SIngo Weinhold 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
9590c85bd05SIngo Weinhold 		// look in the default scope
9600c85bd05SIngo Weinhold 		image_t* image;
961e3ac2588SAlex Smith 		elf_sym* symbol = find_undefined_symbol_global(gProgramImage,
96294830eb2SIngo Weinhold 			gProgramImage,
963003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
964003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
965003ebb0eSIngo Weinhold 			&image);
9660c85bd05SIngo Weinhold 		if (symbol != NULL) {
9670c85bd05SIngo Weinhold 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
968e3ac2588SAlex Smith 			int32 symbolType = symbol->Type() == STT_FUNC
9690c85bd05SIngo Weinhold 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
9700c85bd05SIngo Weinhold 			patch_defined_symbol(image, symbolName, _location, &symbolType);
9710c85bd05SIngo Weinhold 			status = B_OK;
9720c85bd05SIngo Weinhold 		}
9730c85bd05SIngo Weinhold 	} else if (handle == RTLD_NEXT) {
9740c85bd05SIngo Weinhold 		// Look in the default scope, but also in the dependencies of the
9750c85bd05SIngo Weinhold 		// calling image. Return the next after the caller symbol.
9760c85bd05SIngo Weinhold 
977a2dad9e1SIngo Weinhold 		// First of all, find the caller image.
97894830eb2SIngo Weinhold 		image_t* callerImage = get_loaded_images().head;
9790c85bd05SIngo Weinhold 		for (; callerImage != NULL; callerImage = callerImage->next) {
9800c85bd05SIngo Weinhold 			elf_region_t& text = callerImage->regions[0];
981a2dad9e1SIngo Weinhold 			if ((addr_t)caller >= text.vmstart
982a2dad9e1SIngo Weinhold 				&& (addr_t)caller < text.vmstart + text.vmsize) {
983a2dad9e1SIngo Weinhold 				// found the image
9840c85bd05SIngo Weinhold 				break;
9850c85bd05SIngo Weinhold 			}
9860c85bd05SIngo Weinhold 		}
9870c85bd05SIngo Weinhold 
988a2dad9e1SIngo Weinhold 		if (callerImage != NULL) {
9890c85bd05SIngo Weinhold 			// found the caller -- now search the global scope until we find
9900c85bd05SIngo Weinhold 			// the next symbol
991a2dad9e1SIngo Weinhold 			bool hitCallerImage = false;
9920c85bd05SIngo Weinhold 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
9930c85bd05SIngo Weinhold 
994e3ac2588SAlex Smith 			elf_sym* candidateSymbol = NULL;
99525dc253dSIngo Weinhold 			image_t* candidateImage = NULL;
99625dc253dSIngo Weinhold 
99794830eb2SIngo Weinhold 			image_t* image = get_loaded_images().head;
9980c85bd05SIngo Weinhold 			for (; image != NULL; image = image->next) {
999a2dad9e1SIngo Weinhold 				// skip the caller image
1000a2dad9e1SIngo Weinhold 				if (image == callerImage) {
1001a2dad9e1SIngo Weinhold 					hitCallerImage = true;
1002a2dad9e1SIngo Weinhold 					continue;
1003a2dad9e1SIngo Weinhold 				}
1004a2dad9e1SIngo Weinhold 
1005a2dad9e1SIngo Weinhold 				// skip all images up to the caller image; also skip add-on
1006a2dad9e1SIngo Weinhold 				// images and those not marked above for resolution
1007a2dad9e1SIngo Weinhold 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
10080c85bd05SIngo Weinhold 					|| (image->flags
1009a2dad9e1SIngo Weinhold 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
10100c85bd05SIngo Weinhold 					continue;
10110c85bd05SIngo Weinhold 				}
10120c85bd05SIngo Weinhold 
1013e3ac2588SAlex Smith 				elf_sym *symbol = find_symbol(image,
1014003ebb0eSIngo Weinhold 					SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
1015003ebb0eSIngo Weinhold 						LOOKUP_FLAG_DEFAULT_VERSION));
10160c85bd05SIngo Weinhold 				if (symbol == NULL)
10170c85bd05SIngo Weinhold 					continue;
10180c85bd05SIngo Weinhold 
101925dc253dSIngo Weinhold 				// found a symbol
1020e3ac2588SAlex Smith 				bool isWeak = symbol->Bind() == STB_WEAK;
102125dc253dSIngo Weinhold 				if (candidateImage == NULL || !isWeak) {
102225dc253dSIngo Weinhold 					candidateSymbol = symbol;
102325dc253dSIngo Weinhold 					candidateImage = image;
102425dc253dSIngo Weinhold 
102525dc253dSIngo Weinhold 					if (!isWeak)
102625dc253dSIngo Weinhold 						break;
102725dc253dSIngo Weinhold 				}
102825dc253dSIngo Weinhold 
102925dc253dSIngo Weinhold 				// symbol is weak, so we need to continue
103025dc253dSIngo Weinhold 			}
103125dc253dSIngo Weinhold 
103225dc253dSIngo Weinhold 			if (candidateSymbol != NULL) {
1033a2dad9e1SIngo Weinhold 				// found the symbol
103425dc253dSIngo Weinhold 				*_location = (void*)(candidateSymbol->st_value
103525dc253dSIngo Weinhold 					+ candidateImage->regions[0].delta);
10360c85bd05SIngo Weinhold 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
103725dc253dSIngo Weinhold 				patch_defined_symbol(candidateImage, symbolName, _location,
10380c85bd05SIngo Weinhold 					&symbolType);
10390c85bd05SIngo Weinhold 				status = B_OK;
10400c85bd05SIngo Weinhold 			}
10410c85bd05SIngo Weinhold 
10420c85bd05SIngo Weinhold 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
10430c85bd05SIngo Weinhold 		}
10440c85bd05SIngo Weinhold 	} else {
10450c85bd05SIngo Weinhold 		// breadth-first search in the given image and its dependencies
10460c85bd05SIngo Weinhold 		image_t* inImage;
1047003ebb0eSIngo Weinhold 		status = find_symbol_breadth_first((image_t*)handle,
1048003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
1049003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
1050003ebb0eSIngo Weinhold 			&inImage, _location);
10510c85bd05SIngo Weinhold 	}
10520c85bd05SIngo Weinhold 
10530c85bd05SIngo Weinhold 	return status;
10540c85bd05SIngo Weinhold }
10550c85bd05SIngo Weinhold 
10560c85bd05SIngo Weinhold 
10570c85bd05SIngo Weinhold status_t
10580c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
10590c0fea5dSIngo Weinhold {
10600c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
1061e3ac2588SAlex Smith 	elf_dyn *dynamicSection;
10620c0fea5dSIngo Weinhold 	image_t *image;
10630c0fea5dSIngo Weinhold 
10640c0fea5dSIngo Weinhold 	if (_name == NULL)
10650c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
10660c0fea5dSIngo Weinhold 
1067f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
10680c0fea5dSIngo Weinhold 
106994830eb2SIngo Weinhold 	image = find_loaded_image_by_id(id, false);
1070f167d21aSAugustin Cavalier 	if (image == NULL)
10710c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
10720c0fea5dSIngo Weinhold 
1073e3ac2588SAlex Smith 	dynamicSection = (elf_dyn *)image->dynamic_ptr;
1074f167d21aSAugustin Cavalier 	if (dynamicSection == NULL || image->num_needed <= searchIndex)
10750c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
10760c0fea5dSIngo Weinhold 
10770c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
10780c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
10790c0fea5dSIngo Weinhold 			continue;
10800c0fea5dSIngo Weinhold 
10810c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
10820c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
10830c0fea5dSIngo Weinhold 
10840c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
10850c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
10860c0fea5dSIngo Weinhold 			return B_OK;
10870c0fea5dSIngo Weinhold 		}
10880c0fea5dSIngo Weinhold 	}
10890c0fea5dSIngo Weinhold 
10900c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
10910c0fea5dSIngo Weinhold }
10920c0fea5dSIngo Weinhold 
10930c0fea5dSIngo Weinhold 
109474c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
10950c0fea5dSIngo Weinhold 
10960c0fea5dSIngo Weinhold 
10979a6072a3SAxel Dörfler /*! Read and verify the ELF header */
10980c0fea5dSIngo Weinhold status_t
1099e3ac2588SAlex Smith elf_verify_header(void *header, size_t length)
11000c0fea5dSIngo Weinhold {
11010c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
11020c0fea5dSIngo Weinhold 
1103e3ac2588SAlex Smith 	if (length < sizeof(elf_ehdr))
11040c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
11050c0fea5dSIngo Weinhold 
1106e3ac2588SAlex Smith 	return parse_elf_header((elf_ehdr *)header, &programSize, &sectionSize);
11070c0fea5dSIngo Weinhold }
11080c0fea5dSIngo Weinhold 
11090c0fea5dSIngo Weinhold 
11102aaad308SJérôme Duval #ifdef _COMPAT_MODE
11112aaad308SJérôme Duval #ifdef __x86_64__
11122aaad308SJérôme Duval status_t
11132aaad308SJérôme Duval elf32_verify_header(void *header, size_t length)
11142aaad308SJérôme Duval {
11152aaad308SJérôme Duval 	int32 programSize, sectionSize;
11162aaad308SJérôme Duval 
11172aaad308SJérôme Duval 	if (length < sizeof(Elf32_Ehdr))
11182aaad308SJérôme Duval 		return B_NOT_AN_EXECUTABLE;
11192aaad308SJérôme Duval 
11202aaad308SJérôme Duval 	return parse_elf32_header((Elf32_Ehdr *)header, &programSize, &sectionSize);
11212aaad308SJérôme Duval }
11222aaad308SJérôme Duval #else
11232aaad308SJérôme Duval status_t
11242aaad308SJérôme Duval elf64_verify_header(void *header, size_t length)
11252aaad308SJérôme Duval {
11262aaad308SJérôme Duval 	int32 programSize, sectionSize;
11272aaad308SJérôme Duval 
11282aaad308SJérôme Duval 	if (length < sizeof(Elf64_Ehdr))
11292aaad308SJérôme Duval 		return B_NOT_AN_EXECUTABLE;
11302aaad308SJérôme Duval 
11312aaad308SJérôme Duval 	return parse_elf64_header((Elf64_Ehdr *)header, &programSize, &sectionSize);
11322aaad308SJérôme Duval }
11332aaad308SJérôme Duval #endif	// __x86_64__
11342aaad308SJérôme Duval #endif	// _COMPAT_MODE
11352aaad308SJérôme Duval 
11362aaad308SJérôme Duval 
11370c0fea5dSIngo Weinhold void
11380c0fea5dSIngo Weinhold terminate_program(void)
11390c0fea5dSIngo Weinhold {
11400c0fea5dSIngo Weinhold 	image_t **termList;
11410c0fea5dSIngo Weinhold 	ssize_t count, i;
11420c0fea5dSIngo Weinhold 
1143aa3507feSIngo Weinhold 	count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED);
11440c0fea5dSIngo Weinhold 	if (count < B_OK)
11450c0fea5dSIngo Weinhold 		return;
11460c0fea5dSIngo Weinhold 
114794830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
11489a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
11499a6072a3SAxel Dörfler 		update_image_ids();
11509a6072a3SAxel Dörfler 	}
11519a6072a3SAxel Dörfler 
11520c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
11530c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
11540c0fea5dSIngo Weinhold 		image_t *image = termList[i];
11550c0fea5dSIngo Weinhold 
11560c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
11570c0fea5dSIngo Weinhold 
115810b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
115910b4b5d1SIngo Weinhold 
11605d08e3a5SAugustin Cavalier 		call_term_functions(image);
116110b4b5d1SIngo Weinhold 
116210b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
11630c0fea5dSIngo Weinhold 	}
11640c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
11650c0fea5dSIngo Weinhold 
11660c0fea5dSIngo Weinhold 	free(termList);
11670c0fea5dSIngo Weinhold }
11680c0fea5dSIngo Weinhold 
11690c0fea5dSIngo Weinhold 
11700c0fea5dSIngo Weinhold void
11710c0fea5dSIngo Weinhold rldelf_init(void)
11720c0fea5dSIngo Weinhold {
117394830eb2SIngo Weinhold 	init_add_ons();
117494830eb2SIngo Weinhold 
11750c0fea5dSIngo Weinhold 	// create the debug area
11760c0fea5dSIngo Weinhold 	{
1177e3ac2588SAlex Smith 		size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
11780c0fea5dSIngo Weinhold 
11790c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
11800c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
11819f3bd497SPawel Dziepak 			(void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK,
118240b0fbbbSAugustin Cavalier 			B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA);
11830c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
11840c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
11850c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
11860c0fea5dSIngo Weinhold 		}
11870c0fea5dSIngo Weinhold 
118894830eb2SIngo Weinhold 		area->loaded_images = &get_loaded_images();
11890c0fea5dSIngo Weinhold 	}
119074c0424aSAxel Dörfler 
119174c0424aSAxel Dörfler 	// initialize error message if needed
11924bef3723SAxel Dörfler 	if (report_errors()) {
119374c0424aSAxel Dörfler 		void *buffer = malloc(1024);
119474c0424aSAxel Dörfler 		if (buffer == NULL)
119574c0424aSAxel Dörfler 			return;
119674c0424aSAxel Dörfler 
119794830eb2SIngo Weinhold 		gErrorMessage.SetTo(buffer, 1024, 'Rler');
119874c0424aSAxel Dörfler 	}
11990c0fea5dSIngo Weinhold }
12001873b4b3SIngo Weinhold 
12011873b4b3SIngo Weinhold 
12021873b4b3SIngo Weinhold status_t
12039a6072a3SAxel Dörfler elf_reinit_after_fork(void)
12041873b4b3SIngo Weinhold {
1205f7127458SIngo Weinhold 	recursive_lock_init(&sLock, kLockName);
12061873b4b3SIngo Weinhold 
12079a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
1208cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
1209cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
12109a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
121194830eb2SIngo Weinhold 	gInvalidImageIDs = true;
1212cbc456deSIngo Weinhold 
12131873b4b3SIngo Weinhold 	return B_OK;
12141873b4b3SIngo Weinhold }
1215