xref: /haiku/src/system/runtime_loader/elf.cpp (revision 35fa85dba5398fd6f00a25f2ec1afb9cba4d15ed)
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 
50*35fa85dbSJérôme Duval static image_t** sPreloadedAddons = NULL;
51*35fa85dbSJé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 
71*35fa85dbSJérôme Duval image_id
72*35fa85dbSJérôme Duval preload_image(char const* path, image_t **image)
73*35fa85dbSJérôme Duval {
74*35fa85dbSJérôme Duval 	if (path == NULL)
75*35fa85dbSJérôme Duval 		return B_BAD_VALUE;
76*35fa85dbSJérôme Duval 
77*35fa85dbSJérôme Duval 	KTRACE("rld: preload_image(\"%s\")", path);
78*35fa85dbSJérôme Duval 
79*35fa85dbSJérôme Duval 	status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, image);
80*35fa85dbSJérôme Duval 	if (status < B_OK) {
81*35fa85dbSJérôme Duval 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
82*35fa85dbSJérôme Duval 			strerror(status));
83*35fa85dbSJérôme Duval 		return status;
84*35fa85dbSJérôme Duval 	}
85*35fa85dbSJérôme Duval 
86*35fa85dbSJérôme Duval 	if ((*image)->find_undefined_symbol == NULL)
87*35fa85dbSJérôme Duval 		(*image)->find_undefined_symbol = find_undefined_symbol_global;
88*35fa85dbSJérôme Duval 
89*35fa85dbSJérôme Duval 	KTRACE("rld: preload_image(\"%s\") done: id: %" B_PRId32, path, (*image)->id);
90*35fa85dbSJérôme Duval 
91*35fa85dbSJérôme Duval 	return (*image)->id;
92*35fa85dbSJérôme Duval }
93*35fa85dbSJérôme Duval 
94*35fa85dbSJérôme Duval 
95*35fa85dbSJérôme Duval static void
96*35fa85dbSJérôme Duval preload_images(image_t **image, int32 *_count = NULL)
97*35fa85dbSJérôme Duval {
98*35fa85dbSJérôme Duval 	const char* imagePaths = getenv("LD_PRELOAD");
99*35fa85dbSJérôme Duval 	if (imagePaths == NULL) {
100*35fa85dbSJérôme Duval 		if (_count != NULL)
101*35fa85dbSJérôme Duval 			*_count = 0;
102*35fa85dbSJérôme Duval 		return;
103*35fa85dbSJérôme Duval 	}
104*35fa85dbSJérôme Duval 
105*35fa85dbSJérôme Duval 	int32 count = 0;
106*35fa85dbSJérôme Duval 
107*35fa85dbSJérôme Duval 	while (*imagePaths != '\0') {
108*35fa85dbSJérôme Duval 		// find begin of image path
109*35fa85dbSJérôme Duval 		while (*imagePaths != '\0' && isspace(*imagePaths))
110*35fa85dbSJérôme Duval 			imagePaths++;
111*35fa85dbSJérôme Duval 
112*35fa85dbSJérôme Duval 		if (*imagePaths == '\0')
113*35fa85dbSJérôme Duval 			break;
114*35fa85dbSJérôme Duval 
115*35fa85dbSJérôme Duval 		// find end of image path
116*35fa85dbSJérôme Duval 		const char* imagePath = imagePaths;
117*35fa85dbSJérôme Duval 		while (*imagePaths != '\0' && !isspace(*imagePaths))
118*35fa85dbSJérôme Duval 			imagePaths++;
119*35fa85dbSJérôme Duval 
120*35fa85dbSJérôme Duval 		// extract the path
121*35fa85dbSJérôme Duval 		char path[B_PATH_NAME_LENGTH];
122*35fa85dbSJérôme Duval 		size_t pathLen = imagePaths - imagePath;
123*35fa85dbSJérôme Duval 		if (pathLen > sizeof(path) - 1)
124*35fa85dbSJérôme Duval 			continue;
125*35fa85dbSJérôme Duval 
126*35fa85dbSJérôme Duval 		if (image == NULL) {
127*35fa85dbSJérôme Duval 			count++;
128*35fa85dbSJérôme Duval 			continue;
129*35fa85dbSJérôme Duval 		}
130*35fa85dbSJérôme Duval 		memcpy(path, imagePath, pathLen);
131*35fa85dbSJérôme Duval 		path[pathLen] = '\0';
132*35fa85dbSJérôme Duval 
133*35fa85dbSJérôme Duval 		// load the image
134*35fa85dbSJérôme Duval 		preload_image(path, &image[count++]);
135*35fa85dbSJérôme Duval 	}
136*35fa85dbSJérôme Duval 
137*35fa85dbSJérôme Duval 	KTRACE("rld: preload_images count: %d", count);
138*35fa85dbSJérôme Duval 
139*35fa85dbSJérôme Duval 	if (_count != NULL)
140*35fa85dbSJérôme Duval 		*_count = count;
141*35fa85dbSJérôme Duval }
142*35fa85dbSJérôme Duval 
143*35fa85dbSJérôme Duval 
1440c0fea5dSIngo Weinhold static status_t
145*35fa85dbSJé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 
158*35fa85dbSJérôme Duval 	int32 preloadedCount = 0;
159*35fa85dbSJérôme Duval 	if (preload) {
160*35fa85dbSJérôme Duval 		preload_images(NULL, &preloadedCount);
161*35fa85dbSJérôme Duval 		image->num_needed += preloadedCount;
162*35fa85dbSJé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 *));
178*35fa85dbSJérôme Duval 	if (preload)
179*35fa85dbSJérôme Duval 		preload_images(image->needed);
1800c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
1810c0fea5dSIngo Weinhold 
182*35fa85dbSJé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
242*35fa85dbSJé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) {
247*35fa85dbSJérôme Duval 		status_t status = load_immediate_dependencies(otherImage, preload);
2480c85bd05SIngo Weinhold 		if (status != B_OK)
2490c85bd05SIngo Weinhold 			return status;
250*35fa85dbSJé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 {
3090c0fea5dSIngo Weinhold 	image_t **initList;
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);
3190c0fea5dSIngo Weinhold 	if (count <= 0)
3200c0fea5dSIngo Weinhold 		return;
3210c0fea5dSIngo Weinhold 
3220c0fea5dSIngo Weinhold 	if (!initHead) {
3230c0fea5dSIngo Weinhold 		// this removes the "calling" image
3240c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
3250c0fea5dSIngo Weinhold 		initList[--count] = NULL;
3260c0fea5dSIngo Weinhold 	}
3270c0fea5dSIngo Weinhold 
3280c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
3290c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
3300c0fea5dSIngo Weinhold 		image = initList[i];
3310c0fea5dSIngo Weinhold 
3320c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
3330c0fea5dSIngo Weinhold 
334354b60afSAugustin Cavalier 		init_term_function before;
335354b60afSAugustin Cavalier 		if (find_symbol(image,
336354b60afSAugustin Cavalier 				SymbolLookupInfo(B_INIT_BEFORE_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
337354b60afSAugustin Cavalier 				(void**)&before) == B_OK) {
338354b60afSAugustin Cavalier 			before(image->id);
339e340f717SJérôme Duval 		}
340e340f717SJérôme Duval 
341dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
3420c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
34310b4b5d1SIngo Weinhold 
344e340f717SJérôme Duval 		if (image->init_array) {
345e340f717SJérôme Duval 			uint count_init = image->init_array_len / sizeof(addr_t);
346e340f717SJérôme Duval 			for (uint j = 0; j < count_init; j++)
347354b60afSAugustin Cavalier 				((initfini_array_function)image->init_array[j])();
348354b60afSAugustin Cavalier 		}
349354b60afSAugustin Cavalier 
350354b60afSAugustin Cavalier 		init_term_function after;
351354b60afSAugustin Cavalier 		if (find_symbol(image,
352354b60afSAugustin Cavalier 				SymbolLookupInfo(B_INIT_AFTER_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
353354b60afSAugustin Cavalier 				(void**)&after) == B_OK) {
354354b60afSAugustin Cavalier 			after(image->id);
355e340f717SJérôme Duval 		}
356e340f717SJérôme Duval 
35710b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
3580c0fea5dSIngo Weinhold 	}
3590c0fea5dSIngo Weinhold 	TRACE(("%ld: init done.\n", find_thread(NULL)));
3600c0fea5dSIngo Weinhold 
3610c0fea5dSIngo Weinhold 	free(initList);
3620c0fea5dSIngo Weinhold }
3630c0fea5dSIngo Weinhold 
3640c0fea5dSIngo Weinhold 
3650c0fea5dSIngo Weinhold static void
366ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
367ca618b22SIngo Weinhold {
368ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
369ca618b22SIngo Weinhold 	// API.
370ca618b22SIngo Weinhold 	image_t* image;
3710c85bd05SIngo Weinhold 	void* _export;
372003ebb0eSIngo Weinhold 	if (find_symbol_breadth_first(rootImage,
373003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
374003ebb0eSIngo Weinhold 			&_export) == B_OK) {
3750c85bd05SIngo Weinhold 		*(void**)_export = &gRuntimeLoader;
376ca618b22SIngo Weinhold 	}
377ca618b22SIngo Weinhold }
378ca618b22SIngo Weinhold 
379ca618b22SIngo Weinhold 
380ca618b22SIngo Weinhold static status_t
381*35fa85dbSJérôme Duval add_preloaded_addon(image_t* image)
382ca618b22SIngo Weinhold {
383ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
384*35fa85dbSJérôme Duval 	// small number of preloaded addons.
385*35fa85dbSJérôme Duval 	image_t** newArray = (image_t**)realloc(sPreloadedAddons,
386*35fa85dbSJérôme Duval 		sizeof(image_t*) * (sPreloadedAddonCount + 1));
387ca618b22SIngo Weinhold 	if (newArray == NULL)
388ca618b22SIngo Weinhold 		return B_NO_MEMORY;
389ca618b22SIngo Weinhold 
390*35fa85dbSJérôme Duval 	sPreloadedAddons = newArray;
391*35fa85dbSJérôme Duval 	newArray[sPreloadedAddonCount++] = image;
392ca618b22SIngo Weinhold 
393ca618b22SIngo Weinhold 	return B_OK;
394ca618b22SIngo Weinhold }
395ca618b22SIngo Weinhold 
396ca618b22SIngo Weinhold 
397ca618b22SIngo Weinhold image_id
398*35fa85dbSJérôme Duval preload_addon(char const* path)
399ca618b22SIngo Weinhold {
400ca618b22SIngo Weinhold 	if (path == NULL)
401ca618b22SIngo Weinhold 		return B_BAD_VALUE;
402ca618b22SIngo Weinhold 
403*35fa85dbSJérôme Duval 	KTRACE("rld: preload_addon(\"%s\")", path);
404ca618b22SIngo Weinhold 
405ca618b22SIngo Weinhold 	image_t *image = NULL;
4068d23c440SIngo Weinhold 	status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, &image);
407ca618b22SIngo Weinhold 	if (status < B_OK) {
408*35fa85dbSJérôme Duval 		KTRACE("rld: preload_addon(\"%s\") failed to load container: %s", path,
409ca618b22SIngo Weinhold 			strerror(status));
410ca618b22SIngo Weinhold 		return status;
411ca618b22SIngo Weinhold 	}
412ca618b22SIngo Weinhold 
4130c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL)
4140c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_global;
4150c85bd05SIngo Weinhold 
4160c85bd05SIngo Weinhold 	status = load_dependencies(image);
417ca618b22SIngo Weinhold 	if (status < B_OK)
418ca618b22SIngo Weinhold 		goto err;
4190c85bd05SIngo Weinhold 
4200c85bd05SIngo Weinhold 	set_image_flags_recursively(image, RTLD_GLOBAL);
421ca618b22SIngo Weinhold 
422ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
423ca618b22SIngo Weinhold 	if (status < B_OK)
424ca618b22SIngo Weinhold 		goto err;
425ca618b22SIngo Weinhold 
426*35fa85dbSJérôme Duval 	status = add_preloaded_addon(image);
427ca618b22SIngo Weinhold 	if (status < B_OK)
428ca618b22SIngo Weinhold 		goto err;
429ca618b22SIngo Weinhold 
430ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
431ca618b22SIngo Weinhold 
432ca618b22SIngo Weinhold 	remap_images();
433ca618b22SIngo Weinhold 	init_dependencies(image, true);
434ca618b22SIngo Weinhold 
43510b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
43610b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
437003ebb0eSIngo Weinhold 	if (find_symbol(image,
438003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
43910b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
44094830eb2SIngo Weinhold 		add_add_on(image, addOnStruct);
44110b4b5d1SIngo Weinhold 	}
44210b4b5d1SIngo Weinhold 
443*35fa85dbSJérôme Duval 	KTRACE("rld: preload_addon(\"%s\") done: id: %" B_PRId32, path, image->id);
444ca618b22SIngo Weinhold 
445ca618b22SIngo Weinhold 	return image->id;
446ca618b22SIngo Weinhold 
447ca618b22SIngo Weinhold err:
448*35fa85dbSJérôme Duval 	KTRACE("rld: preload_addon(\"%s\") failed: %s", path, strerror(status));
449ca618b22SIngo Weinhold 
45094830eb2SIngo Weinhold 	dequeue_loaded_image(image);
451ca618b22SIngo Weinhold 	delete_image(image);
452ca618b22SIngo Weinhold 	return status;
453ca618b22SIngo Weinhold }
454ca618b22SIngo Weinhold 
455ca618b22SIngo Weinhold 
456ca618b22SIngo Weinhold static void
457*35fa85dbSJérôme Duval preload_addons()
458ca618b22SIngo Weinhold {
459*35fa85dbSJérôme Duval 	const char* imagePaths = getenv("LD_PRELOAD_ADDONS");
460ca618b22SIngo Weinhold 	if (imagePaths == NULL)
461ca618b22SIngo Weinhold 		return;
462ca618b22SIngo Weinhold 
463ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
464ca618b22SIngo Weinhold 		// find begin of image path
465ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
466ca618b22SIngo Weinhold 			imagePaths++;
467ca618b22SIngo Weinhold 
468ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
469ca618b22SIngo Weinhold 			break;
470ca618b22SIngo Weinhold 
471ca618b22SIngo Weinhold 		// find end of image path
472ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
473ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
474ca618b22SIngo Weinhold 			imagePaths++;
475ca618b22SIngo Weinhold 
476ca618b22SIngo Weinhold 		// extract the path
477ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
478ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
479ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
480ca618b22SIngo Weinhold 			continue;
481ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
482ca618b22SIngo Weinhold 		path[pathLen] = '\0';
483ca618b22SIngo Weinhold 
484ca618b22SIngo Weinhold 		// load the image
485*35fa85dbSJérôme Duval 		preload_addon(path);
486ca618b22SIngo Weinhold 	}
487ca618b22SIngo Weinhold }
488ca618b22SIngo Weinhold 
489ca618b22SIngo Weinhold 
49074c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
4910c0fea5dSIngo Weinhold 
4920c0fea5dSIngo Weinhold 
4930c0fea5dSIngo Weinhold image_id
4940c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
4950c0fea5dSIngo Weinhold {
4960c0fea5dSIngo Weinhold 	status_t status;
4970c0fea5dSIngo Weinhold 	image_t *image;
4980c0fea5dSIngo Weinhold 
4997486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
5007486b72dSIngo Weinhold 
501f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
5020c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
5030c0fea5dSIngo Weinhold 
504*35fa85dbSJérôme Duval 	preload_addons();
505ca618b22SIngo Weinhold 
5060c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
5070c0fea5dSIngo Weinhold 
5088d23c440SIngo Weinhold 	status = load_image(path, B_APP_IMAGE, NULL, NULL, &gProgramImage);
50974c0424aSAxel Dörfler 	if (status < B_OK)
51074c0424aSAxel Dörfler 		goto err;
5110c0fea5dSIngo Weinhold 
51294830eb2SIngo Weinhold 	if (gProgramImage->find_undefined_symbol == NULL)
51394830eb2SIngo Weinhold 		gProgramImage->find_undefined_symbol = find_undefined_symbol_global;
5140c85bd05SIngo Weinhold 
515*35fa85dbSJérôme Duval 	status = load_dependencies(gProgramImage, true);
5160c0fea5dSIngo Weinhold 	if (status < B_OK)
5170c0fea5dSIngo Weinhold 		goto err;
5180c85bd05SIngo Weinhold 
51947bc6663SIngo Weinhold 	// Set RTLD_GLOBAL on all libraries including the program.
5200c85bd05SIngo Weinhold 	// This results in the desired symbol resolution for dlopen()ed libraries.
52194830eb2SIngo Weinhold 	set_image_flags_recursively(gProgramImage, RTLD_GLOBAL);
5220c0fea5dSIngo Weinhold 
52394830eb2SIngo Weinhold 	status = relocate_dependencies(gProgramImage);
5240c0fea5dSIngo Weinhold 	if (status < B_OK)
5250c0fea5dSIngo Weinhold 		goto err;
5260c0fea5dSIngo Weinhold 
52794830eb2SIngo Weinhold 	inject_runtime_loader_api(gProgramImage);
5280c0fea5dSIngo Weinhold 
5290c0fea5dSIngo Weinhold 	remap_images();
53094830eb2SIngo Weinhold 	init_dependencies(gProgramImage, true);
5310c0fea5dSIngo Weinhold 
5320c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
5330c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
53494830eb2SIngo Weinhold 	find_symbol_breadth_first(gProgramImage,
535003ebb0eSIngo Weinhold 		SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
536003ebb0eSIngo Weinhold 		(void**)&gGetEnv);
5370c0fea5dSIngo Weinhold 
53894830eb2SIngo Weinhold 	if (gProgramImage->entry_point == 0) {
5390c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
5400c0fea5dSIngo Weinhold 		goto err;
5410c0fea5dSIngo Weinhold 	}
5420c0fea5dSIngo Weinhold 
54394830eb2SIngo Weinhold 	*_entry = (void *)(gProgramImage->entry_point);
5440c0fea5dSIngo Weinhold 
54594830eb2SIngo Weinhold 	gProgramLoaded = true;
5465d0638bfSIngo Weinhold 
547ded25be1SIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %" B_PRId32 , path,
54894830eb2SIngo Weinhold 		*_entry, gProgramImage->id);
5497486b72dSIngo Weinhold 
55094830eb2SIngo Weinhold 	return gProgramImage->id;
5510c0fea5dSIngo Weinhold 
5520c0fea5dSIngo Weinhold err:
5537486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
5547486b72dSIngo Weinhold 
55594830eb2SIngo Weinhold 	delete_image(gProgramImage);
55674c0424aSAxel Dörfler 
5574bef3723SAxel Dörfler 	if (report_errors()) {
5584bef3723SAxel Dörfler 		// send error message
55994830eb2SIngo Weinhold 		gErrorMessage.AddInt32("error", status);
56094830eb2SIngo Weinhold 		gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
5614bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
5624bef3723SAxel Dörfler 
5634bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
56494830eb2SIngo Weinhold 			gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0);
56574c0424aSAxel Dörfler 	}
56674c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
56774c0424aSAxel Dörfler 
5680c0fea5dSIngo Weinhold 	return status;
5690c0fea5dSIngo Weinhold }
5700c0fea5dSIngo Weinhold 
5710c0fea5dSIngo Weinhold 
5720c0fea5dSIngo Weinhold image_id
5730c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle)
5740c0fea5dSIngo Weinhold {
5750c0fea5dSIngo Weinhold 	image_t *image = NULL;
5760c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
5770c0fea5dSIngo Weinhold 	status_t status;
5780c0fea5dSIngo Weinhold 
5790c85bd05SIngo Weinhold 	if (path == NULL && addOn)
5800c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
5810c0fea5dSIngo Weinhold 
582ded25be1SIngo Weinhold 	KTRACE("rld: load_library(\"%s\", %#" B_PRIx32 ", %d)", path, flags, addOn);
5837486b72dSIngo Weinhold 
584f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
5850c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
5860c0fea5dSIngo Weinhold 
5870c0fea5dSIngo Weinhold 	// have we already loaded this library?
5880c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
5890c0fea5dSIngo Weinhold 	if (!addOn) {
5900c85bd05SIngo Weinhold 		// a NULL path is fine -- it means the global scope shall be opened
5910c85bd05SIngo Weinhold 		if (path == NULL) {
5920c85bd05SIngo Weinhold 			*_handle = RLD_GLOBAL_SCOPE;
5930c85bd05SIngo Weinhold 			return 0;
5940c85bd05SIngo Weinhold 		}
5950c85bd05SIngo Weinhold 
59694830eb2SIngo Weinhold 		image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
5970c85bd05SIngo Weinhold 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
5980c85bd05SIngo Weinhold 			set_image_flags_recursively(image, RTLD_GLOBAL);
5990c85bd05SIngo Weinhold 
6000c0fea5dSIngo Weinhold 		if (image) {
6010c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
602ded25be1SIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %" B_PRId32,
603ded25be1SIngo Weinhold 				path, image->id);
6040c85bd05SIngo Weinhold 			*_handle = image;
6050c0fea5dSIngo Weinhold 			return image->id;
6060c0fea5dSIngo Weinhold 		}
6070c0fea5dSIngo Weinhold 	}
6080c0fea5dSIngo Weinhold 
6098d23c440SIngo Weinhold 	status = load_image(path, type, NULL, NULL, &image);
6100c0fea5dSIngo Weinhold 	if (status < B_OK) {
6117486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
6127486b72dSIngo Weinhold 			strerror(status));
6130c0fea5dSIngo Weinhold 		return status;
6140c0fea5dSIngo Weinhold 	}
6150c0fea5dSIngo Weinhold 
6160c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL) {
6170c85bd05SIngo Weinhold 		if (addOn)
6180c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_add_on;
6190c85bd05SIngo Weinhold 		else
6200c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_global;
6210c85bd05SIngo Weinhold 	}
6220c85bd05SIngo Weinhold 
6230c85bd05SIngo Weinhold 	status = load_dependencies(image);
6240c0fea5dSIngo Weinhold 	if (status < B_OK)
6250c0fea5dSIngo Weinhold 		goto err;
6260c85bd05SIngo Weinhold 
6270c85bd05SIngo Weinhold 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
6280c85bd05SIngo Weinhold 	// dependencies. If not specified, we temporarily set
6290c85bd05SIngo Weinhold 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
6300c85bd05SIngo Weinhold 	// for undefined symbol resolution.
6310c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) != 0)
6320c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RTLD_GLOBAL);
6330c85bd05SIngo Weinhold 	else
6340c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
6350c0fea5dSIngo Weinhold 
6360c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
6370c0fea5dSIngo Weinhold 	if (status < B_OK)
6380c0fea5dSIngo Weinhold 		goto err;
6390c0fea5dSIngo Weinhold 
6400c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) == 0)
6410c85bd05SIngo Weinhold 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
6420c85bd05SIngo Weinhold 
6430c0fea5dSIngo Weinhold 	remap_images();
6440c0fea5dSIngo Weinhold 	init_dependencies(image, true);
6450c0fea5dSIngo Weinhold 
646ded25be1SIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %" B_PRId32, path, image->id);
6477486b72dSIngo Weinhold 
6480c85bd05SIngo Weinhold 	*_handle = image;
6490c0fea5dSIngo Weinhold 	return image->id;
6500c0fea5dSIngo Weinhold 
6510c0fea5dSIngo Weinhold err:
6527486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
6537486b72dSIngo Weinhold 
65494830eb2SIngo Weinhold 	dequeue_loaded_image(image);
6550c0fea5dSIngo Weinhold 	delete_image(image);
6560c0fea5dSIngo Weinhold 	return status;
6570c0fea5dSIngo Weinhold }
6580c0fea5dSIngo Weinhold 
6590c0fea5dSIngo Weinhold 
6600c0fea5dSIngo Weinhold status_t
6610c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
6620c0fea5dSIngo Weinhold {
6630c0fea5dSIngo Weinhold 	image_t *image;
6640c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
6650c0fea5dSIngo Weinhold 
6660c85bd05SIngo Weinhold 	if (handle == NULL && imageID < 0)
6670c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
6680c0fea5dSIngo Weinhold 
6690c85bd05SIngo Weinhold 	if (handle == RLD_GLOBAL_SCOPE)
6700c85bd05SIngo Weinhold 		return B_OK;
6710c85bd05SIngo Weinhold 
672f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
6730c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
6740c0fea5dSIngo Weinhold 
67594830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
6769a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
6779a6072a3SAxel Dörfler 		update_image_ids();
6789a6072a3SAxel Dörfler 	}
6799a6072a3SAxel Dörfler 
6800c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
6810c0fea5dSIngo Weinhold 
682df30098dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
683df30098dSIngo Weinhold 
6840c85bd05SIngo Weinhold 	if (handle != NULL) {
6850c85bd05SIngo Weinhold 		image = (image_t*)handle;
6860c85bd05SIngo Weinhold 		put_image(image);
687df30098dSIngo Weinhold 		status = B_OK;
6880c85bd05SIngo Weinhold 	} else {
68994830eb2SIngo Weinhold 		image = find_loaded_image_by_id(imageID, true);
69094830eb2SIngo Weinhold 		if (image != NULL) {
6910c0fea5dSIngo Weinhold 			// unload image
6920c0fea5dSIngo Weinhold 			if (type == image->type) {
6930c0fea5dSIngo Weinhold 				put_image(image);
6940c0fea5dSIngo Weinhold 				status = B_OK;
6950c0fea5dSIngo Weinhold 			} else
6960c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
6970c0fea5dSIngo Weinhold 		}
6980c85bd05SIngo Weinhold 	}
6990c0fea5dSIngo Weinhold 
7000c0fea5dSIngo Weinhold 	if (status == B_OK) {
70194830eb2SIngo Weinhold 		while ((image = get_disposable_images().head) != NULL) {
702d64f6189SIngo Weinhold 			// Call the exit hooks that live in this image.
703d64f6189SIngo Weinhold 			// Note: With the Itanium ABI this shouldn't really be done this
704d64f6189SIngo Weinhold 			// way anymore, since global destructors are registered via
705d64f6189SIngo Weinhold 			// __cxa_atexit() (the ones that are registered dynamically) and the
706d64f6189SIngo Weinhold 			// termination routine should call __cxa_finalize() for the image.
707d64f6189SIngo Weinhold 			// The reason why we still do it is that hooks registered with
708d64f6189SIngo Weinhold 			// atexit() aren't associated with the image. We could find out
709d64f6189SIngo Weinhold 			// there which image the hooks lives in and register it
710d64f6189SIngo Weinhold 			// respectively, but since that would be done always, that's
711d64f6189SIngo Weinhold 			// probably more expensive than calling
712d64f6189SIngo Weinhold 			// call_atexit_hooks_for_range() only here, which happens only when
713d64f6189SIngo Weinhold 			// libraries are unloaded dynamically.
7148c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
7158c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
7163be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
7178c2a9d74SMichael Lotz 			}
7188c2a9d74SMichael Lotz 
71910b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
72010b4b5d1SIngo Weinhold 
721354b60afSAugustin Cavalier 			init_term_function before;
722354b60afSAugustin Cavalier 			if (find_symbol(image,
723354b60afSAugustin Cavalier 					SymbolLookupInfo(B_TERM_BEFORE_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
724354b60afSAugustin Cavalier 					(void**)&before) == B_OK) {
725354b60afSAugustin Cavalier 				before(image->id);
726354b60afSAugustin Cavalier 			}
727354b60afSAugustin Cavalier 
728e340f717SJérôme Duval 			if (image->term_array) {
729e340f717SJérôme Duval 				uint count_term = image->term_array_len / sizeof(addr_t);
730e340f717SJérôme Duval 				for (uint i = count_term; i-- > 0;)
731354b60afSAugustin Cavalier 					((initfini_array_function)image->term_array[i])();
732e340f717SJérôme Duval 			}
733e340f717SJérôme Duval 
7340c0fea5dSIngo Weinhold 			if (image->term_routine)
7350c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
7360c0fea5dSIngo Weinhold 
737354b60afSAugustin Cavalier 			init_term_function after;
738354b60afSAugustin Cavalier 			if (find_symbol(image,
739354b60afSAugustin Cavalier 					SymbolLookupInfo(B_TERM_AFTER_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT),
740354b60afSAugustin Cavalier 					(void**)&after) == B_OK) {
741354b60afSAugustin Cavalier 				after(image->id);
742354b60afSAugustin Cavalier 			}
743354b60afSAugustin Cavalier 
74444c0c4d3SPawel Dziepak 			TLSBlockTemplates::Get().Unregister(image->dso_tls_id);
74544c0c4d3SPawel Dziepak 
74694830eb2SIngo Weinhold 			dequeue_disposable_image(image);
7470c0fea5dSIngo Weinhold 			unmap_image(image);
7480c0fea5dSIngo Weinhold 
74910b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
75010b4b5d1SIngo Weinhold 
7510c0fea5dSIngo Weinhold 			delete_image(image);
7520c0fea5dSIngo Weinhold 		}
7530c0fea5dSIngo Weinhold 	}
7540c0fea5dSIngo Weinhold 
7550c0fea5dSIngo Weinhold 	return status;
7560c0fea5dSIngo Weinhold }
7570c0fea5dSIngo Weinhold 
7580c0fea5dSIngo Weinhold 
7590c0fea5dSIngo Weinhold status_t
7609a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
7619a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
7620c0fea5dSIngo Weinhold {
7630c0fea5dSIngo Weinhold 	int32 count = 0, j;
7640c0fea5dSIngo Weinhold 	uint32 i;
7650c0fea5dSIngo Weinhold 	image_t *image;
7660c0fea5dSIngo Weinhold 
767f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
7680c0fea5dSIngo Weinhold 
7690c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
77094830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
771f167d21aSAugustin Cavalier 	if (image == NULL)
7720c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
7730c0fea5dSIngo Weinhold 
7740c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
7750c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
7760c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
777e3ac2588SAlex Smith 			elf_sym *symbol = &image->syms[j];
7780c0fea5dSIngo Weinhold 
7790c0fea5dSIngo Weinhold 			if (count == num) {
78010b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
78110b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
78210b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
7830c0fea5dSIngo Weinhold 
78410b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
78510b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
78610b4b5d1SIngo Weinhold 				int32 type;
787e3ac2588SAlex Smith 				if (symbol->Type() == STT_FUNC)
78810b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
789e3ac2588SAlex Smith 				else if (symbol->Type() == STT_OBJECT)
79010b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
7910c0fea5dSIngo Weinhold 				else
79210b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
79310b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
7940c0fea5dSIngo Weinhold 
79510b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
79610b4b5d1SIngo Weinhold 
79710b4b5d1SIngo Weinhold 				if (_type != NULL)
79810b4b5d1SIngo Weinhold 					*_type = type;
7990c0fea5dSIngo Weinhold 				if (_location != NULL)
80010b4b5d1SIngo Weinhold 					*_location = location;
8010c0fea5dSIngo Weinhold 				goto out;
8020c0fea5dSIngo Weinhold 			}
8030c0fea5dSIngo Weinhold 			count++;
8040c0fea5dSIngo Weinhold 		}
8050c0fea5dSIngo Weinhold 	}
8060c0fea5dSIngo Weinhold out:
8070c0fea5dSIngo Weinhold 	if (num != count)
8080c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
8090c0fea5dSIngo Weinhold 
8100c0fea5dSIngo Weinhold 	return B_OK;
8110c0fea5dSIngo Weinhold }
8120c0fea5dSIngo Weinhold 
8130c0fea5dSIngo Weinhold 
8140c0fea5dSIngo Weinhold status_t
81543e7b1c2SHamish Morrison get_nearest_symbol_at_address(void* address, image_id* _imageID,
816ebdc1d48SMichael Lotz 	char** _imagePath, char** _imageName, char** _symbolName, int32* _type,
817ebdc1d48SMichael Lotz 	void** _location, bool* _exactMatch)
818b6455c08SAxel Dörfler {
819f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
820b6455c08SAxel Dörfler 
821b6455c08SAxel Dörfler 	image_t* image = find_loaded_image_by_address((addr_t)address);
822f167d21aSAugustin Cavalier 	if (image == NULL)
823b6455c08SAxel Dörfler 		return B_BAD_VALUE;
824b6455c08SAxel Dörfler 
825ebdc1d48SMichael Lotz 	bool exactMatch = false;
826e3ac2588SAlex Smith 	elf_sym* foundSymbol = NULL;
82743e7b1c2SHamish Morrison 	addr_t foundLocation = (addr_t)NULL;
82843e7b1c2SHamish Morrison 
829ebdc1d48SMichael Lotz 	for (uint32 i = 0; i < HASHTABSIZE(image) && !exactMatch; i++) {
830b6455c08SAxel Dörfler 		for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF;
831b6455c08SAxel Dörfler 				j = HASHCHAINS(image)[j]) {
832e3ac2588SAlex Smith 			elf_sym *symbol = &image->syms[j];
833b6455c08SAxel Dörfler 			addr_t location = symbol->st_value + image->regions[0].delta;
834b6455c08SAxel Dörfler 
83543e7b1c2SHamish Morrison 			if (location <= (addr_t)address	&& location >= foundLocation) {
83643e7b1c2SHamish Morrison 				foundSymbol = symbol;
83743e7b1c2SHamish Morrison 				foundLocation = location;
838b6455c08SAxel Dörfler 
83943e7b1c2SHamish Morrison 				// jump out if we have an exact match
840ebdc1d48SMichael Lotz 				if (location + symbol->st_size > (addr_t)address) {
841ebdc1d48SMichael Lotz 					exactMatch = true;
84243e7b1c2SHamish Morrison 					break;
84343e7b1c2SHamish Morrison 				}
84443e7b1c2SHamish Morrison 			}
84543e7b1c2SHamish Morrison 		}
84643e7b1c2SHamish Morrison 	}
847b6455c08SAxel Dörfler 
848b6455c08SAxel Dörfler 	if (_imageID != NULL)
849b6455c08SAxel Dörfler 		*_imageID = image->id;
85043e7b1c2SHamish Morrison 	if (_imagePath != NULL)
85143e7b1c2SHamish Morrison 		*_imagePath = image->path;
852ebdc1d48SMichael Lotz 	if (_imageName != NULL)
853ebdc1d48SMichael Lotz 		*_imageName = image->name;
854ebdc1d48SMichael Lotz 	if (_exactMatch != NULL)
855ebdc1d48SMichael Lotz 		*_exactMatch = exactMatch;
85643e7b1c2SHamish Morrison 
85743e7b1c2SHamish Morrison 	if (foundSymbol != NULL) {
85843e7b1c2SHamish Morrison 		*_symbolName = SYMNAME(image, foundSymbol);
85943e7b1c2SHamish Morrison 
86043e7b1c2SHamish Morrison 		if (_type != NULL) {
861e3ac2588SAlex Smith 			if (foundSymbol->Type() == STT_FUNC)
86243e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_TEXT;
863e3ac2588SAlex Smith 			else if (foundSymbol->Type() == STT_OBJECT)
86443e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_DATA;
86543e7b1c2SHamish Morrison 			else
86643e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_ANY;
86743e7b1c2SHamish Morrison 			// TODO: check with the return types of that BeOS function
86843e7b1c2SHamish Morrison 		}
86943e7b1c2SHamish Morrison 
870b6455c08SAxel Dörfler 		if (_location != NULL)
87143e7b1c2SHamish Morrison 			*_location = (void*)foundLocation;
87243e7b1c2SHamish Morrison 	} else {
87343e7b1c2SHamish Morrison 		*_symbolName = NULL;
87443e7b1c2SHamish Morrison 		if (_location != NULL)
87543e7b1c2SHamish Morrison 			*_location = NULL;
87643e7b1c2SHamish Morrison 	}
877b6455c08SAxel Dörfler 
878b6455c08SAxel Dörfler 	return B_OK;
879b6455c08SAxel Dörfler }
880b6455c08SAxel Dörfler 
881b6455c08SAxel Dörfler 
882b6455c08SAxel Dörfler status_t
8839a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
88480ece785SIngo Weinhold 	bool recursive, image_id *_inImage, void **_location)
8850c0fea5dSIngo Weinhold {
8860c0fea5dSIngo Weinhold 	status_t status = B_OK;
8870c0fea5dSIngo Weinhold 	image_t *image;
8880c0fea5dSIngo Weinhold 
8890c0fea5dSIngo Weinhold 	if (imageID < B_OK)
8900c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
8910c0fea5dSIngo Weinhold 	if (symbolName == NULL)
8920c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
8930c0fea5dSIngo Weinhold 
894354b60afSAugustin Cavalier 	// Previously, these functions were called in __haiku_init_before
895354b60afSAugustin Cavalier 	// and __haiku_init_after. Now we call them inside runtime_loader,
896354b60afSAugustin Cavalier 	// so we prevent applications from fetching them.
897354b60afSAugustin Cavalier 	if (strcmp(symbolName, B_INIT_BEFORE_FUNCTION_NAME) == 0
898354b60afSAugustin Cavalier 		|| strcmp(symbolName, B_INIT_AFTER_FUNCTION_NAME) == 0
899354b60afSAugustin Cavalier 		|| strcmp(symbolName, B_TERM_BEFORE_FUNCTION_NAME) == 0
900354b60afSAugustin Cavalier 		|| strcmp(symbolName, B_TERM_AFTER_FUNCTION_NAME) == 0)
901354b60afSAugustin Cavalier 		return B_BAD_VALUE;
902354b60afSAugustin Cavalier 
903f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
9040c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
9050c0fea5dSIngo Weinhold 
9060c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
90794830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
90880ece785SIngo Weinhold 	if (image != NULL) {
90980ece785SIngo Weinhold 		if (recursive) {
91080ece785SIngo Weinhold 			// breadth-first search in the given image and its dependencies
911003ebb0eSIngo Weinhold 			status = find_symbol_breadth_first(image,
912003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
913003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
91480ece785SIngo Weinhold 				&image, _location);
915003ebb0eSIngo Weinhold 		} else {
916003ebb0eSIngo Weinhold 			status = find_symbol(image,
917003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
918003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
919003ebb0eSIngo Weinhold 				_location);
920003ebb0eSIngo Weinhold 		}
92180ece785SIngo Weinhold 
92280ece785SIngo Weinhold 		if (status == B_OK && _inImage != NULL)
92380ece785SIngo Weinhold 			*_inImage = image->id;
92480ece785SIngo Weinhold 	} else
9250c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
9260c0fea5dSIngo Weinhold 
9270c0fea5dSIngo Weinhold 	return status;
9280c0fea5dSIngo Weinhold }
9290c0fea5dSIngo Weinhold 
9300c0fea5dSIngo Weinhold 
9310c0fea5dSIngo Weinhold status_t
9320c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
9330c85bd05SIngo Weinhold 	void **_location)
9340c85bd05SIngo Weinhold {
9350c85bd05SIngo Weinhold 	status_t status = B_ENTRY_NOT_FOUND;
9360c85bd05SIngo Weinhold 
9370c85bd05SIngo Weinhold 	if (symbolName == NULL)
9380c85bd05SIngo Weinhold 		return B_BAD_VALUE;
9390c85bd05SIngo Weinhold 
940f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
9410c85bd05SIngo Weinhold 		// for now, just do stupid simple global locking
9420c85bd05SIngo Weinhold 
9430c85bd05SIngo Weinhold 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
9440c85bd05SIngo Weinhold 		// look in the default scope
9450c85bd05SIngo Weinhold 		image_t* image;
946e3ac2588SAlex Smith 		elf_sym* symbol = find_undefined_symbol_global(gProgramImage,
94794830eb2SIngo Weinhold 			gProgramImage,
948003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
949003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
950003ebb0eSIngo Weinhold 			&image);
9510c85bd05SIngo Weinhold 		if (symbol != NULL) {
9520c85bd05SIngo Weinhold 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
953e3ac2588SAlex Smith 			int32 symbolType = symbol->Type() == STT_FUNC
9540c85bd05SIngo Weinhold 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
9550c85bd05SIngo Weinhold 			patch_defined_symbol(image, symbolName, _location, &symbolType);
9560c85bd05SIngo Weinhold 			status = B_OK;
9570c85bd05SIngo Weinhold 		}
9580c85bd05SIngo Weinhold 	} else if (handle == RTLD_NEXT) {
9590c85bd05SIngo Weinhold 		// Look in the default scope, but also in the dependencies of the
9600c85bd05SIngo Weinhold 		// calling image. Return the next after the caller symbol.
9610c85bd05SIngo Weinhold 
962a2dad9e1SIngo Weinhold 		// First of all, find the caller image.
96394830eb2SIngo Weinhold 		image_t* callerImage = get_loaded_images().head;
9640c85bd05SIngo Weinhold 		for (; callerImage != NULL; callerImage = callerImage->next) {
9650c85bd05SIngo Weinhold 			elf_region_t& text = callerImage->regions[0];
966a2dad9e1SIngo Weinhold 			if ((addr_t)caller >= text.vmstart
967a2dad9e1SIngo Weinhold 				&& (addr_t)caller < text.vmstart + text.vmsize) {
968a2dad9e1SIngo Weinhold 				// found the image
9690c85bd05SIngo Weinhold 				break;
9700c85bd05SIngo Weinhold 			}
9710c85bd05SIngo Weinhold 		}
9720c85bd05SIngo Weinhold 
973a2dad9e1SIngo Weinhold 		if (callerImage != NULL) {
9740c85bd05SIngo Weinhold 			// found the caller -- now search the global scope until we find
9750c85bd05SIngo Weinhold 			// the next symbol
976a2dad9e1SIngo Weinhold 			bool hitCallerImage = false;
9770c85bd05SIngo Weinhold 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
9780c85bd05SIngo Weinhold 
979e3ac2588SAlex Smith 			elf_sym* candidateSymbol = NULL;
98025dc253dSIngo Weinhold 			image_t* candidateImage = NULL;
98125dc253dSIngo Weinhold 
98294830eb2SIngo Weinhold 			image_t* image = get_loaded_images().head;
9830c85bd05SIngo Weinhold 			for (; image != NULL; image = image->next) {
984a2dad9e1SIngo Weinhold 				// skip the caller image
985a2dad9e1SIngo Weinhold 				if (image == callerImage) {
986a2dad9e1SIngo Weinhold 					hitCallerImage = true;
987a2dad9e1SIngo Weinhold 					continue;
988a2dad9e1SIngo Weinhold 				}
989a2dad9e1SIngo Weinhold 
990a2dad9e1SIngo Weinhold 				// skip all images up to the caller image; also skip add-on
991a2dad9e1SIngo Weinhold 				// images and those not marked above for resolution
992a2dad9e1SIngo Weinhold 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
9930c85bd05SIngo Weinhold 					|| (image->flags
994a2dad9e1SIngo Weinhold 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
9950c85bd05SIngo Weinhold 					continue;
9960c85bd05SIngo Weinhold 				}
9970c85bd05SIngo Weinhold 
998e3ac2588SAlex Smith 				elf_sym *symbol = find_symbol(image,
999003ebb0eSIngo Weinhold 					SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
1000003ebb0eSIngo Weinhold 						LOOKUP_FLAG_DEFAULT_VERSION));
10010c85bd05SIngo Weinhold 				if (symbol == NULL)
10020c85bd05SIngo Weinhold 					continue;
10030c85bd05SIngo Weinhold 
100425dc253dSIngo Weinhold 				// found a symbol
1005e3ac2588SAlex Smith 				bool isWeak = symbol->Bind() == STB_WEAK;
100625dc253dSIngo Weinhold 				if (candidateImage == NULL || !isWeak) {
100725dc253dSIngo Weinhold 					candidateSymbol = symbol;
100825dc253dSIngo Weinhold 					candidateImage = image;
100925dc253dSIngo Weinhold 
101025dc253dSIngo Weinhold 					if (!isWeak)
101125dc253dSIngo Weinhold 						break;
101225dc253dSIngo Weinhold 				}
101325dc253dSIngo Weinhold 
101425dc253dSIngo Weinhold 				// symbol is weak, so we need to continue
101525dc253dSIngo Weinhold 			}
101625dc253dSIngo Weinhold 
101725dc253dSIngo Weinhold 			if (candidateSymbol != NULL) {
1018a2dad9e1SIngo Weinhold 				// found the symbol
101925dc253dSIngo Weinhold 				*_location = (void*)(candidateSymbol->st_value
102025dc253dSIngo Weinhold 					+ candidateImage->regions[0].delta);
10210c85bd05SIngo Weinhold 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
102225dc253dSIngo Weinhold 				patch_defined_symbol(candidateImage, symbolName, _location,
10230c85bd05SIngo Weinhold 					&symbolType);
10240c85bd05SIngo Weinhold 				status = B_OK;
10250c85bd05SIngo Weinhold 			}
10260c85bd05SIngo Weinhold 
10270c85bd05SIngo Weinhold 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
10280c85bd05SIngo Weinhold 		}
10290c85bd05SIngo Weinhold 	} else {
10300c85bd05SIngo Weinhold 		// breadth-first search in the given image and its dependencies
10310c85bd05SIngo Weinhold 		image_t* inImage;
1032003ebb0eSIngo Weinhold 		status = find_symbol_breadth_first((image_t*)handle,
1033003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
1034003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
1035003ebb0eSIngo Weinhold 			&inImage, _location);
10360c85bd05SIngo Weinhold 	}
10370c85bd05SIngo Weinhold 
10380c85bd05SIngo Weinhold 	return status;
10390c85bd05SIngo Weinhold }
10400c85bd05SIngo Weinhold 
10410c85bd05SIngo Weinhold 
10420c85bd05SIngo Weinhold status_t
10430c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
10440c0fea5dSIngo Weinhold {
10450c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
1046e3ac2588SAlex Smith 	elf_dyn *dynamicSection;
10470c0fea5dSIngo Weinhold 	image_t *image;
10480c0fea5dSIngo Weinhold 
10490c0fea5dSIngo Weinhold 	if (_name == NULL)
10500c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
10510c0fea5dSIngo Weinhold 
1052f167d21aSAugustin Cavalier 	RecursiveLocker _(sLock);
10530c0fea5dSIngo Weinhold 
105494830eb2SIngo Weinhold 	image = find_loaded_image_by_id(id, false);
1055f167d21aSAugustin Cavalier 	if (image == NULL)
10560c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
10570c0fea5dSIngo Weinhold 
1058e3ac2588SAlex Smith 	dynamicSection = (elf_dyn *)image->dynamic_ptr;
1059f167d21aSAugustin Cavalier 	if (dynamicSection == NULL || image->num_needed <= searchIndex)
10600c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
10610c0fea5dSIngo Weinhold 
10620c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
10630c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
10640c0fea5dSIngo Weinhold 			continue;
10650c0fea5dSIngo Weinhold 
10660c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
10670c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
10680c0fea5dSIngo Weinhold 
10690c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
10700c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
10710c0fea5dSIngo Weinhold 			return B_OK;
10720c0fea5dSIngo Weinhold 		}
10730c0fea5dSIngo Weinhold 	}
10740c0fea5dSIngo Weinhold 
10750c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
10760c0fea5dSIngo Weinhold }
10770c0fea5dSIngo Weinhold 
10780c0fea5dSIngo Weinhold 
107974c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
10800c0fea5dSIngo Weinhold 
10810c0fea5dSIngo Weinhold 
10829a6072a3SAxel Dörfler /*! Read and verify the ELF header */
10830c0fea5dSIngo Weinhold status_t
1084e3ac2588SAlex Smith elf_verify_header(void *header, size_t length)
10850c0fea5dSIngo Weinhold {
10860c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
10870c0fea5dSIngo Weinhold 
1088e3ac2588SAlex Smith 	if (length < sizeof(elf_ehdr))
10890c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
10900c0fea5dSIngo Weinhold 
1091e3ac2588SAlex Smith 	return parse_elf_header((elf_ehdr *)header, &programSize, &sectionSize);
10920c0fea5dSIngo Weinhold }
10930c0fea5dSIngo Weinhold 
10940c0fea5dSIngo Weinhold 
10952aaad308SJérôme Duval #ifdef _COMPAT_MODE
10962aaad308SJérôme Duval #ifdef __x86_64__
10972aaad308SJérôme Duval status_t
10982aaad308SJérôme Duval elf32_verify_header(void *header, size_t length)
10992aaad308SJérôme Duval {
11002aaad308SJérôme Duval 	int32 programSize, sectionSize;
11012aaad308SJérôme Duval 
11022aaad308SJérôme Duval 	if (length < sizeof(Elf32_Ehdr))
11032aaad308SJérôme Duval 		return B_NOT_AN_EXECUTABLE;
11042aaad308SJérôme Duval 
11052aaad308SJérôme Duval 	return parse_elf32_header((Elf32_Ehdr *)header, &programSize, &sectionSize);
11062aaad308SJérôme Duval }
11072aaad308SJérôme Duval #else
11082aaad308SJérôme Duval status_t
11092aaad308SJérôme Duval elf64_verify_header(void *header, size_t length)
11102aaad308SJérôme Duval {
11112aaad308SJérôme Duval 	int32 programSize, sectionSize;
11122aaad308SJérôme Duval 
11132aaad308SJérôme Duval 	if (length < sizeof(Elf64_Ehdr))
11142aaad308SJérôme Duval 		return B_NOT_AN_EXECUTABLE;
11152aaad308SJérôme Duval 
11162aaad308SJérôme Duval 	return parse_elf64_header((Elf64_Ehdr *)header, &programSize, &sectionSize);
11172aaad308SJérôme Duval }
11182aaad308SJérôme Duval #endif	// __x86_64__
11192aaad308SJérôme Duval #endif	// _COMPAT_MODE
11202aaad308SJérôme Duval 
11212aaad308SJérôme Duval 
11220c0fea5dSIngo Weinhold void
11230c0fea5dSIngo Weinhold terminate_program(void)
11240c0fea5dSIngo Weinhold {
11250c0fea5dSIngo Weinhold 	image_t **termList;
11260c0fea5dSIngo Weinhold 	ssize_t count, i;
11270c0fea5dSIngo Weinhold 
1128aa3507feSIngo Weinhold 	count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED);
11290c0fea5dSIngo Weinhold 	if (count < B_OK)
11300c0fea5dSIngo Weinhold 		return;
11310c0fea5dSIngo Weinhold 
113294830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
11339a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
11349a6072a3SAxel Dörfler 		update_image_ids();
11359a6072a3SAxel Dörfler 	}
11369a6072a3SAxel Dörfler 
11370c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
11380c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
11390c0fea5dSIngo Weinhold 		image_t *image = termList[i];
11400c0fea5dSIngo Weinhold 
11410c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
11420c0fea5dSIngo Weinhold 
114310b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
114410b4b5d1SIngo Weinhold 
1145e340f717SJérôme Duval 		if (image->term_array) {
1146e340f717SJérôme Duval 			uint count_term = image->term_array_len / sizeof(addr_t);
1147e340f717SJérôme Duval 			for (uint j = count_term; j-- > 0;)
1148e340f717SJérôme Duval 				((init_term_function)image->term_array[j])(image->id);
1149e340f717SJérôme Duval 		}
1150e340f717SJérôme Duval 
11510c0fea5dSIngo Weinhold 		if (image->term_routine)
11520c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
115310b4b5d1SIngo Weinhold 
115410b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
11550c0fea5dSIngo Weinhold 	}
11560c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
11570c0fea5dSIngo Weinhold 
11580c0fea5dSIngo Weinhold 	free(termList);
11590c0fea5dSIngo Weinhold }
11600c0fea5dSIngo Weinhold 
11610c0fea5dSIngo Weinhold 
11620c0fea5dSIngo Weinhold void
11630c0fea5dSIngo Weinhold rldelf_init(void)
11640c0fea5dSIngo Weinhold {
116594830eb2SIngo Weinhold 	init_add_ons();
116694830eb2SIngo Weinhold 
11670c0fea5dSIngo Weinhold 	// create the debug area
11680c0fea5dSIngo Weinhold 	{
1169e3ac2588SAlex Smith 		size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
11700c0fea5dSIngo Weinhold 
11710c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
11720c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
11739f3bd497SPawel Dziepak 			(void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK,
11740c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
11750c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
11760c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
11770c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
11780c0fea5dSIngo Weinhold 		}
11790c0fea5dSIngo Weinhold 
118094830eb2SIngo Weinhold 		area->loaded_images = &get_loaded_images();
11810c0fea5dSIngo Weinhold 	}
118274c0424aSAxel Dörfler 
118374c0424aSAxel Dörfler 	// initialize error message if needed
11844bef3723SAxel Dörfler 	if (report_errors()) {
118574c0424aSAxel Dörfler 		void *buffer = malloc(1024);
118674c0424aSAxel Dörfler 		if (buffer == NULL)
118774c0424aSAxel Dörfler 			return;
118874c0424aSAxel Dörfler 
118994830eb2SIngo Weinhold 		gErrorMessage.SetTo(buffer, 1024, 'Rler');
119074c0424aSAxel Dörfler 	}
11910c0fea5dSIngo Weinhold }
11921873b4b3SIngo Weinhold 
11931873b4b3SIngo Weinhold 
11941873b4b3SIngo Weinhold status_t
11959a6072a3SAxel Dörfler elf_reinit_after_fork(void)
11961873b4b3SIngo Weinhold {
1197f7127458SIngo Weinhold 	recursive_lock_init(&sLock, kLockName);
11981873b4b3SIngo Weinhold 
11999a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
1200cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
1201cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
12029a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
120394830eb2SIngo Weinhold 	gInvalidImageIDs = true;
1204cbc456deSIngo Weinhold 
12051873b4b3SIngo Weinhold 	return B_OK;
12061873b4b3SIngo Weinhold }
1207