xref: /haiku/src/system/runtime_loader/elf.cpp (revision ebdc1d480e809b6ab0b1ad58822a21395706be25)
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);
450c0fea5dSIngo Weinhold 
4694830eb2SIngo Weinhold bool gProgramLoaded = false;
4794830eb2SIngo Weinhold image_t* gProgramImage;
48003ebb0eSIngo Weinhold 
49ca618b22SIngo Weinhold static image_t** sPreloadedImages = NULL;
50ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0;
510c0fea5dSIngo Weinhold 
52f7127458SIngo Weinhold static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName);
530c0fea5dSIngo Weinhold 
547486b72dSIngo Weinhold 
55f2bb2575SIngo Weinhold static inline void
560c0fea5dSIngo Weinhold rld_lock()
570c0fea5dSIngo Weinhold {
58f2bb2575SIngo Weinhold 	recursive_lock_lock(&sLock);
590c0fea5dSIngo Weinhold }
60f2bb2575SIngo Weinhold 
61f2bb2575SIngo Weinhold 
62f2bb2575SIngo Weinhold static inline void
63f2bb2575SIngo Weinhold rld_unlock()
64f2bb2575SIngo Weinhold {
65f2bb2575SIngo Weinhold 	recursive_lock_unlock(&sLock);
660c0fea5dSIngo Weinhold }
670c0fea5dSIngo Weinhold 
680c0fea5dSIngo Weinhold 
690c0fea5dSIngo Weinhold static const char *
700c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
710c0fea5dSIngo Weinhold {
720c0fea5dSIngo Weinhold 	int i;
73e3ac2588SAlex Smith 	elf_dyn *d = (elf_dyn *)image->dynamic_ptr;
740c0fea5dSIngo Weinhold 
750c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
760c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
770c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
780c0fea5dSIngo Weinhold 	}
790c0fea5dSIngo Weinhold 
800c0fea5dSIngo Weinhold 	return NULL;
810c0fea5dSIngo Weinhold }
820c0fea5dSIngo Weinhold 
830c0fea5dSIngo Weinhold 
840c0fea5dSIngo Weinhold static status_t
850c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image)
860c0fea5dSIngo Weinhold {
87e3ac2588SAlex Smith 	elf_dyn *d = (elf_dyn *)image->dynamic_ptr;
884bef3723SAxel Dörfler 	bool reportErrors = report_errors();
8974c0424aSAxel Dörfler 	status_t status = B_OK;
900c0fea5dSIngo Weinhold 	uint32 i, j;
910c0fea5dSIngo Weinhold 	const char *rpath;
920c0fea5dSIngo Weinhold 
930c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
940c0fea5dSIngo Weinhold 		return B_OK;
950c0fea5dSIngo Weinhold 
960c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
970c0fea5dSIngo Weinhold 
980c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
990c0fea5dSIngo Weinhold 		return B_OK;
1000c0fea5dSIngo Weinhold 
101ded25be1SIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ")", image->name,
1027486b72dSIngo Weinhold 		image->id);
1037486b72dSIngo Weinhold 
1040c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
1050c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
106c533f813SIngo Weinhold 		FATAL("%s: Failed to allocate needed struct\n", image->path);
107ded25be1SIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32
108ded25be1SIngo Weinhold 			") failed: no memory", image->name, image->id);
1090c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
1100c0fea5dSIngo Weinhold 	}
1110c0fea5dSIngo Weinhold 
1120c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
1130c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
1140c0fea5dSIngo Weinhold 
1150c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
1160c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
1170c0fea5dSIngo Weinhold 			case DT_NEEDED:
11874c0424aSAxel Dörfler 			{
11974c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
12074c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
1210c0fea5dSIngo Weinhold 
12294830eb2SIngo Weinhold 				status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
1238d23c440SIngo Weinhold 					rpath, image->path, &image->needed[j]);
12474c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
12574c0424aSAxel Dörfler 					status = loadStatus;
12674c0424aSAxel Dörfler 					// correct error code in case the file could not been found
12774c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
12874c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
12974c0424aSAxel Dörfler 
13074c0424aSAxel Dörfler 						if (reportErrors)
13194830eb2SIngo Weinhold 							gErrorMessage.AddString("missing library", name);
13274c0424aSAxel Dörfler 					}
13374c0424aSAxel Dörfler 
13474c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
1357486b72dSIngo Weinhold 					if (!reportErrors) {
136ded25be1SIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32
137ded25be1SIngo Weinhold 							") failed: %s", image->name, image->id,
1387486b72dSIngo Weinhold 							strerror(status));
1390c0fea5dSIngo Weinhold 						return status;
14074c0424aSAxel Dörfler 					}
1417486b72dSIngo Weinhold 				}
1420c0fea5dSIngo Weinhold 
1430c0fea5dSIngo Weinhold 				j += 1;
1440c0fea5dSIngo Weinhold 				break;
14574c0424aSAxel Dörfler 			}
1460c0fea5dSIngo Weinhold 
1470c0fea5dSIngo Weinhold 			default:
1480c0fea5dSIngo Weinhold 				// ignore any other tag
1490c0fea5dSIngo Weinhold 				continue;
1500c0fea5dSIngo Weinhold 		}
1510c0fea5dSIngo Weinhold 	}
1520c0fea5dSIngo Weinhold 
1537486b72dSIngo Weinhold 	if (status < B_OK) {
154ded25be1SIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") "
1557486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
1567486b72dSIngo Weinhold 			strerror(status));
15774c0424aSAxel Dörfler 		return status;
1587486b72dSIngo Weinhold 	}
15974c0424aSAxel Dörfler 
1600c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
1610c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
162ded25be1SIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") "
1637486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
1640c0fea5dSIngo Weinhold 		return B_ERROR;
1650c0fea5dSIngo Weinhold 	}
1660c0fea5dSIngo Weinhold 
167ded25be1SIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") done",
168ded25be1SIngo Weinhold 		image->name, image->id);
1697486b72dSIngo Weinhold 
1700c0fea5dSIngo Weinhold 	return B_OK;
1710c0fea5dSIngo Weinhold }
1720c0fea5dSIngo Weinhold 
1730c0fea5dSIngo Weinhold 
1740c85bd05SIngo Weinhold static status_t
1750c85bd05SIngo Weinhold load_dependencies(image_t* image)
1760c85bd05SIngo Weinhold {
177003ebb0eSIngo Weinhold 	// load dependencies (breadth-first)
1780c85bd05SIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
1790c85bd05SIngo Weinhold 			otherImage = otherImage->next) {
1800c85bd05SIngo Weinhold 		status_t status = load_immediate_dependencies(otherImage);
1810c85bd05SIngo Weinhold 		if (status != B_OK)
1820c85bd05SIngo Weinhold 			return status;
1830c85bd05SIngo Weinhold 	}
1840c85bd05SIngo Weinhold 
185003ebb0eSIngo Weinhold 	// Check the needed versions for the given image and all newly loaded
186003ebb0eSIngo Weinhold 	// dependencies.
187003ebb0eSIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
188003ebb0eSIngo Weinhold 			otherImage = otherImage->next) {
189003ebb0eSIngo Weinhold 		status_t status = check_needed_image_versions(otherImage);
190003ebb0eSIngo Weinhold 		if (status != B_OK)
191003ebb0eSIngo Weinhold 			return status;
192003ebb0eSIngo Weinhold 	}
193003ebb0eSIngo Weinhold 
1940c85bd05SIngo Weinhold 	return B_OK;
1950c85bd05SIngo Weinhold }
1960c85bd05SIngo Weinhold 
1970c85bd05SIngo Weinhold 
19894830eb2SIngo Weinhold static status_t
19994830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
2000c0fea5dSIngo Weinhold {
20125dc253dSIngo Weinhold 	SymbolLookupCache cache(image);
20225dc253dSIngo Weinhold 
20325dc253dSIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image, &cache);
20494830eb2SIngo Weinhold 	if (status < B_OK) {
205c533f813SIngo Weinhold 		FATAL("%s: Troubles relocating: %s\n", image->path, strerror(status));
20694830eb2SIngo Weinhold 		return status;
2070c0fea5dSIngo Weinhold 	}
2080c0fea5dSIngo Weinhold 
20994830eb2SIngo Weinhold 	_kern_image_relocated(image->id);
21094830eb2SIngo Weinhold 	image_event(image, IMAGE_EVENT_RELOCATED);
21194830eb2SIngo Weinhold 	return B_OK;
2120c0fea5dSIngo Weinhold }
2130c0fea5dSIngo Weinhold 
2140c0fea5dSIngo Weinhold 
2150c0fea5dSIngo Weinhold static status_t
2160c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
2170c0fea5dSIngo Weinhold {
218ca618b22SIngo Weinhold 	// get the images that still have to be relocated
219ca618b22SIngo Weinhold 	image_t **list;
220ca618b22SIngo Weinhold 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
2210c0fea5dSIngo Weinhold 	if (count < B_OK)
2220c0fea5dSIngo Weinhold 		return count;
2230c0fea5dSIngo Weinhold 
2240c85bd05SIngo Weinhold 	// relocate
225ca618b22SIngo Weinhold 	for (ssize_t i = 0; i < count; i++) {
22646f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
2270c85bd05SIngo Weinhold 		if (status < B_OK) {
2280c85bd05SIngo Weinhold 			free(list);
2290c0fea5dSIngo Weinhold 			return status;
2300c0fea5dSIngo Weinhold 		}
2310c85bd05SIngo Weinhold 	}
2320c0fea5dSIngo Weinhold 
2330c0fea5dSIngo Weinhold 	free(list);
2340c0fea5dSIngo Weinhold 	return B_OK;
2350c0fea5dSIngo Weinhold }
2360c0fea5dSIngo Weinhold 
2370c0fea5dSIngo Weinhold 
2380c0fea5dSIngo Weinhold static void
2390c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
2400c0fea5dSIngo Weinhold {
2410c0fea5dSIngo Weinhold 	image_t **initList;
2420c0fea5dSIngo Weinhold 	ssize_t count, i;
2430c0fea5dSIngo Weinhold 
2440c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
2450c0fea5dSIngo Weinhold 	if (count <= 0)
2460c0fea5dSIngo Weinhold 		return;
2470c0fea5dSIngo Weinhold 
2480c0fea5dSIngo Weinhold 	if (!initHead) {
2490c0fea5dSIngo Weinhold 		// this removes the "calling" image
2500c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
2510c0fea5dSIngo Weinhold 		initList[--count] = NULL;
2520c0fea5dSIngo Weinhold 	}
2530c0fea5dSIngo Weinhold 
2540c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
2550c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
2560c0fea5dSIngo Weinhold 		image = initList[i];
2570c0fea5dSIngo Weinhold 
2580c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
2590c0fea5dSIngo Weinhold 
260dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
2610c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
26210b4b5d1SIngo Weinhold 
26310b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
2640c0fea5dSIngo Weinhold 	}
2650c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
2660c0fea5dSIngo Weinhold 
2670c0fea5dSIngo Weinhold 	free(initList);
2680c0fea5dSIngo Weinhold }
2690c0fea5dSIngo Weinhold 
2700c0fea5dSIngo Weinhold 
2710c0fea5dSIngo Weinhold static void
272ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
273ca618b22SIngo Weinhold {
274ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
275ca618b22SIngo Weinhold 	// API.
276ca618b22SIngo Weinhold 	image_t* image;
2770c85bd05SIngo Weinhold 	void* _export;
278003ebb0eSIngo Weinhold 	if (find_symbol_breadth_first(rootImage,
279003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
280003ebb0eSIngo Weinhold 			&_export) == B_OK) {
2810c85bd05SIngo Weinhold 		*(void**)_export = &gRuntimeLoader;
282ca618b22SIngo Weinhold 	}
283ca618b22SIngo Weinhold }
284ca618b22SIngo Weinhold 
285ca618b22SIngo Weinhold 
286ca618b22SIngo Weinhold static status_t
287ca618b22SIngo Weinhold add_preloaded_image(image_t* image)
288ca618b22SIngo Weinhold {
289ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
290ca618b22SIngo Weinhold 	// small number of preloaded images.
291ca618b22SIngo Weinhold 	image_t** newArray = (image_t**)realloc(sPreloadedImages,
292ca618b22SIngo Weinhold 		sizeof(image_t*) * (sPreloadedImageCount + 1));
293ca618b22SIngo Weinhold 	if (newArray == NULL)
294ca618b22SIngo Weinhold 		return B_NO_MEMORY;
295ca618b22SIngo Weinhold 
296ca618b22SIngo Weinhold 	sPreloadedImages = newArray;
297ca618b22SIngo Weinhold 	newArray[sPreloadedImageCount++] = image;
298ca618b22SIngo Weinhold 
299ca618b22SIngo Weinhold 	return B_OK;
300ca618b22SIngo Weinhold }
301ca618b22SIngo Weinhold 
302ca618b22SIngo Weinhold 
303ca618b22SIngo Weinhold image_id
304ca618b22SIngo Weinhold preload_image(char const* path)
305ca618b22SIngo Weinhold {
306ca618b22SIngo Weinhold 	if (path == NULL)
307ca618b22SIngo Weinhold 		return B_BAD_VALUE;
308ca618b22SIngo Weinhold 
309ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\")", path);
310ca618b22SIngo Weinhold 
311ca618b22SIngo Weinhold 	image_t *image = NULL;
3128d23c440SIngo Weinhold 	status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, &image);
313ca618b22SIngo Weinhold 	if (status < B_OK) {
314ca618b22SIngo Weinhold 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
315ca618b22SIngo Weinhold 			strerror(status));
316ca618b22SIngo Weinhold 		return status;
317ca618b22SIngo Weinhold 	}
318ca618b22SIngo Weinhold 
3190c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL)
3200c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_global;
3210c85bd05SIngo Weinhold 
3220c85bd05SIngo Weinhold 	status = load_dependencies(image);
323ca618b22SIngo Weinhold 	if (status < B_OK)
324ca618b22SIngo Weinhold 		goto err;
3250c85bd05SIngo Weinhold 
3260c85bd05SIngo Weinhold 	set_image_flags_recursively(image, RTLD_GLOBAL);
327ca618b22SIngo Weinhold 
328ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
329ca618b22SIngo Weinhold 	if (status < B_OK)
330ca618b22SIngo Weinhold 		goto err;
331ca618b22SIngo Weinhold 
332ca618b22SIngo Weinhold 	status = add_preloaded_image(image);
333ca618b22SIngo Weinhold 	if (status < B_OK)
334ca618b22SIngo Weinhold 		goto err;
335ca618b22SIngo Weinhold 
336ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
337ca618b22SIngo Weinhold 
338ca618b22SIngo Weinhold 	remap_images();
339ca618b22SIngo Weinhold 	init_dependencies(image, true);
340ca618b22SIngo Weinhold 
34110b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
34210b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
343003ebb0eSIngo Weinhold 	if (find_symbol(image,
344003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
34510b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
34694830eb2SIngo Weinhold 		add_add_on(image, addOnStruct);
34710b4b5d1SIngo Weinhold 	}
34810b4b5d1SIngo Weinhold 
349ded25be1SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") done: id: %" B_PRId32, path, image->id);
350ca618b22SIngo Weinhold 
351ca618b22SIngo Weinhold 	return image->id;
352ca618b22SIngo Weinhold 
353ca618b22SIngo Weinhold err:
354ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status));
355ca618b22SIngo Weinhold 
35694830eb2SIngo Weinhold 	dequeue_loaded_image(image);
357ca618b22SIngo Weinhold 	delete_image(image);
358ca618b22SIngo Weinhold 	return status;
359ca618b22SIngo Weinhold }
360ca618b22SIngo Weinhold 
361ca618b22SIngo Weinhold 
362ca618b22SIngo Weinhold static void
363ca618b22SIngo Weinhold preload_images()
364ca618b22SIngo Weinhold {
365ca618b22SIngo Weinhold 	const char* imagePaths = getenv("LD_PRELOAD");
366ca618b22SIngo Weinhold 	if (imagePaths == NULL)
367ca618b22SIngo Weinhold 		return;
368ca618b22SIngo Weinhold 
369ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
370ca618b22SIngo Weinhold 		// find begin of image path
371ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
372ca618b22SIngo Weinhold 			imagePaths++;
373ca618b22SIngo Weinhold 
374ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
375ca618b22SIngo Weinhold 			break;
376ca618b22SIngo Weinhold 
377ca618b22SIngo Weinhold 		// find end of image path
378ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
379ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
380ca618b22SIngo Weinhold 			imagePaths++;
381ca618b22SIngo Weinhold 
382ca618b22SIngo Weinhold 		// extract the path
383ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
384ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
385ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
386ca618b22SIngo Weinhold 			continue;
387ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
388ca618b22SIngo Weinhold 		path[pathLen] = '\0';
389ca618b22SIngo Weinhold 
390ca618b22SIngo Weinhold 		// load the image
391ca618b22SIngo Weinhold 		preload_image(path);
392ca618b22SIngo Weinhold 	}
393ca618b22SIngo Weinhold }
394ca618b22SIngo Weinhold 
395ca618b22SIngo Weinhold 
39674c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
3970c0fea5dSIngo Weinhold 
3980c0fea5dSIngo Weinhold 
3990c0fea5dSIngo Weinhold image_id
4000c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
4010c0fea5dSIngo Weinhold {
4020c0fea5dSIngo Weinhold 	status_t status;
4030c0fea5dSIngo Weinhold 	image_t *image;
4040c0fea5dSIngo Weinhold 
4057486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
4067486b72dSIngo Weinhold 
4070c0fea5dSIngo Weinhold 	rld_lock();
4080c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
4090c0fea5dSIngo Weinhold 
410ca618b22SIngo Weinhold 	preload_images();
411ca618b22SIngo Weinhold 
4120c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
4130c0fea5dSIngo Weinhold 
4148d23c440SIngo Weinhold 	status = load_image(path, B_APP_IMAGE, NULL, NULL, &gProgramImage);
41574c0424aSAxel Dörfler 	if (status < B_OK)
41674c0424aSAxel Dörfler 		goto err;
4170c0fea5dSIngo Weinhold 
41894830eb2SIngo Weinhold 	if (gProgramImage->find_undefined_symbol == NULL)
41994830eb2SIngo Weinhold 		gProgramImage->find_undefined_symbol = find_undefined_symbol_global;
4200c85bd05SIngo Weinhold 
42194830eb2SIngo Weinhold 	status = load_dependencies(gProgramImage);
4220c0fea5dSIngo Weinhold 	if (status < B_OK)
4230c0fea5dSIngo Weinhold 		goto err;
4240c85bd05SIngo Weinhold 
42547bc6663SIngo Weinhold 	// Set RTLD_GLOBAL on all libraries including the program.
4260c85bd05SIngo Weinhold 	// This results in the desired symbol resolution for dlopen()ed libraries.
42794830eb2SIngo Weinhold 	set_image_flags_recursively(gProgramImage, RTLD_GLOBAL);
4280c0fea5dSIngo Weinhold 
42994830eb2SIngo Weinhold 	status = relocate_dependencies(gProgramImage);
4300c0fea5dSIngo Weinhold 	if (status < B_OK)
4310c0fea5dSIngo Weinhold 		goto err;
4320c0fea5dSIngo Weinhold 
43394830eb2SIngo Weinhold 	inject_runtime_loader_api(gProgramImage);
4340c0fea5dSIngo Weinhold 
4350c0fea5dSIngo Weinhold 	remap_images();
43694830eb2SIngo Weinhold 	init_dependencies(gProgramImage, true);
4370c0fea5dSIngo Weinhold 
4380c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
4390c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
44094830eb2SIngo Weinhold 	find_symbol_breadth_first(gProgramImage,
441003ebb0eSIngo Weinhold 		SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
442003ebb0eSIngo Weinhold 		(void**)&gGetEnv);
4430c0fea5dSIngo Weinhold 
44494830eb2SIngo Weinhold 	if (gProgramImage->entry_point == 0) {
4450c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
4460c0fea5dSIngo Weinhold 		goto err;
4470c0fea5dSIngo Weinhold 	}
4480c0fea5dSIngo Weinhold 
44994830eb2SIngo Weinhold 	*_entry = (void *)(gProgramImage->entry_point);
4500c0fea5dSIngo Weinhold 
4510c0fea5dSIngo Weinhold 	rld_unlock();
4527486b72dSIngo Weinhold 
45394830eb2SIngo Weinhold 	gProgramLoaded = true;
4545d0638bfSIngo Weinhold 
455ded25be1SIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %" B_PRId32 , path,
45694830eb2SIngo Weinhold 		*_entry, gProgramImage->id);
4577486b72dSIngo Weinhold 
45894830eb2SIngo Weinhold 	return gProgramImage->id;
4590c0fea5dSIngo Weinhold 
4600c0fea5dSIngo Weinhold err:
4617486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
4627486b72dSIngo Weinhold 
46394830eb2SIngo Weinhold 	delete_image(gProgramImage);
46474c0424aSAxel Dörfler 
4654bef3723SAxel Dörfler 	if (report_errors()) {
4664bef3723SAxel Dörfler 		// send error message
46794830eb2SIngo Weinhold 		gErrorMessage.AddInt32("error", status);
46894830eb2SIngo Weinhold 		gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
4694bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
4704bef3723SAxel Dörfler 
4714bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
47294830eb2SIngo Weinhold 			gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0);
47374c0424aSAxel Dörfler 	}
47474c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
4750c0fea5dSIngo Weinhold 	rld_unlock();
47674c0424aSAxel Dörfler 
4770c0fea5dSIngo Weinhold 	return status;
4780c0fea5dSIngo Weinhold }
4790c0fea5dSIngo Weinhold 
4800c0fea5dSIngo Weinhold 
4810c0fea5dSIngo Weinhold image_id
4820c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle)
4830c0fea5dSIngo Weinhold {
4840c0fea5dSIngo Weinhold 	image_t *image = NULL;
4850c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
4860c0fea5dSIngo Weinhold 	status_t status;
4870c0fea5dSIngo Weinhold 
4880c85bd05SIngo Weinhold 	if (path == NULL && addOn)
4890c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
4900c0fea5dSIngo Weinhold 
491ded25be1SIngo Weinhold 	KTRACE("rld: load_library(\"%s\", %#" B_PRIx32 ", %d)", path, flags, addOn);
4927486b72dSIngo Weinhold 
4930c0fea5dSIngo Weinhold 	rld_lock();
4940c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
4950c0fea5dSIngo Weinhold 
4960c0fea5dSIngo Weinhold 	// have we already loaded this library?
4970c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
4980c0fea5dSIngo Weinhold 	if (!addOn) {
4990c85bd05SIngo Weinhold 		// a NULL path is fine -- it means the global scope shall be opened
5000c85bd05SIngo Weinhold 		if (path == NULL) {
5010c85bd05SIngo Weinhold 			*_handle = RLD_GLOBAL_SCOPE;
5020c85bd05SIngo Weinhold 			rld_unlock();
5030c85bd05SIngo Weinhold 			return 0;
5040c85bd05SIngo Weinhold 		}
5050c85bd05SIngo Weinhold 
50694830eb2SIngo Weinhold 		image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
5070c85bd05SIngo Weinhold 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
5080c85bd05SIngo Weinhold 			set_image_flags_recursively(image, RTLD_GLOBAL);
5090c85bd05SIngo Weinhold 
5100c0fea5dSIngo Weinhold 		if (image) {
5110c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
5120c0fea5dSIngo Weinhold 			rld_unlock();
513ded25be1SIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %" B_PRId32,
514ded25be1SIngo Weinhold 				path, image->id);
5150c85bd05SIngo Weinhold 			*_handle = image;
5160c0fea5dSIngo Weinhold 			return image->id;
5170c0fea5dSIngo Weinhold 		}
5180c0fea5dSIngo Weinhold 	}
5190c0fea5dSIngo Weinhold 
5208d23c440SIngo Weinhold 	status = load_image(path, type, NULL, NULL, &image);
5210c0fea5dSIngo Weinhold 	if (status < B_OK) {
5220c0fea5dSIngo Weinhold 		rld_unlock();
5237486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
5247486b72dSIngo Weinhold 			strerror(status));
5250c0fea5dSIngo Weinhold 		return status;
5260c0fea5dSIngo Weinhold 	}
5270c0fea5dSIngo Weinhold 
5280c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL) {
5290c85bd05SIngo Weinhold 		if (addOn)
5300c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_add_on;
5310c85bd05SIngo Weinhold 		else
5320c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_global;
5330c85bd05SIngo Weinhold 	}
5340c85bd05SIngo Weinhold 
5350c85bd05SIngo Weinhold 	status = load_dependencies(image);
5360c0fea5dSIngo Weinhold 	if (status < B_OK)
5370c0fea5dSIngo Weinhold 		goto err;
5380c85bd05SIngo Weinhold 
5390c85bd05SIngo Weinhold 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
5400c85bd05SIngo Weinhold 	// dependencies. If not specified, we temporarily set
5410c85bd05SIngo Weinhold 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
5420c85bd05SIngo Weinhold 	// for undefined symbol resolution.
5430c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) != 0)
5440c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RTLD_GLOBAL);
5450c85bd05SIngo Weinhold 	else
5460c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
5470c0fea5dSIngo Weinhold 
5480c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
5490c0fea5dSIngo Weinhold 	if (status < B_OK)
5500c0fea5dSIngo Weinhold 		goto err;
5510c0fea5dSIngo Weinhold 
5520c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) == 0)
5530c85bd05SIngo Weinhold 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
5540c85bd05SIngo Weinhold 
5550c0fea5dSIngo Weinhold 	remap_images();
5560c0fea5dSIngo Weinhold 	init_dependencies(image, true);
5570c0fea5dSIngo Weinhold 
5580c0fea5dSIngo Weinhold 	rld_unlock();
5597486b72dSIngo Weinhold 
560ded25be1SIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %" B_PRId32, path, image->id);
5617486b72dSIngo Weinhold 
5620c85bd05SIngo Weinhold 	*_handle = image;
5630c0fea5dSIngo Weinhold 	return image->id;
5640c0fea5dSIngo Weinhold 
5650c0fea5dSIngo Weinhold err:
5667486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
5677486b72dSIngo Weinhold 
56894830eb2SIngo Weinhold 	dequeue_loaded_image(image);
5690c0fea5dSIngo Weinhold 	delete_image(image);
5700c0fea5dSIngo Weinhold 	rld_unlock();
5710c0fea5dSIngo Weinhold 	return status;
5720c0fea5dSIngo Weinhold }
5730c0fea5dSIngo Weinhold 
5740c0fea5dSIngo Weinhold 
5750c0fea5dSIngo Weinhold status_t
5760c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
5770c0fea5dSIngo Weinhold {
5780c0fea5dSIngo Weinhold 	image_t *image;
5790c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
5800c0fea5dSIngo Weinhold 
5810c85bd05SIngo Weinhold 	if (handle == NULL && imageID < 0)
5820c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
5830c0fea5dSIngo Weinhold 
5840c85bd05SIngo Weinhold 	if (handle == RLD_GLOBAL_SCOPE)
5850c85bd05SIngo Weinhold 		return B_OK;
5860c85bd05SIngo Weinhold 
5870c0fea5dSIngo Weinhold 	rld_lock();
5880c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
5890c0fea5dSIngo Weinhold 
59094830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
5919a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
5929a6072a3SAxel Dörfler 		update_image_ids();
5939a6072a3SAxel Dörfler 	}
5949a6072a3SAxel Dörfler 
5950c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
5960c0fea5dSIngo Weinhold 
597df30098dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
598df30098dSIngo Weinhold 
5990c85bd05SIngo Weinhold 	if (handle != NULL) {
6000c85bd05SIngo Weinhold 		image = (image_t*)handle;
6010c85bd05SIngo Weinhold 		put_image(image);
602df30098dSIngo Weinhold 		status = B_OK;
6030c85bd05SIngo Weinhold 	} else {
60494830eb2SIngo Weinhold 		image = find_loaded_image_by_id(imageID, true);
60594830eb2SIngo Weinhold 		if (image != NULL) {
6060c0fea5dSIngo Weinhold 			// unload image
6070c0fea5dSIngo Weinhold 			if (type == image->type) {
6080c0fea5dSIngo Weinhold 				put_image(image);
6090c0fea5dSIngo Weinhold 				status = B_OK;
6100c0fea5dSIngo Weinhold 			} else
6110c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
6120c0fea5dSIngo Weinhold 		}
6130c85bd05SIngo Weinhold 	}
6140c0fea5dSIngo Weinhold 
6150c0fea5dSIngo Weinhold 	if (status == B_OK) {
61694830eb2SIngo Weinhold 		while ((image = get_disposable_images().head) != NULL) {
617d64f6189SIngo Weinhold 			// Call the exit hooks that live in this image.
618d64f6189SIngo Weinhold 			// Note: With the Itanium ABI this shouldn't really be done this
619d64f6189SIngo Weinhold 			// way anymore, since global destructors are registered via
620d64f6189SIngo Weinhold 			// __cxa_atexit() (the ones that are registered dynamically) and the
621d64f6189SIngo Weinhold 			// termination routine should call __cxa_finalize() for the image.
622d64f6189SIngo Weinhold 			// The reason why we still do it is that hooks registered with
623d64f6189SIngo Weinhold 			// atexit() aren't associated with the image. We could find out
624d64f6189SIngo Weinhold 			// there which image the hooks lives in and register it
625d64f6189SIngo Weinhold 			// respectively, but since that would be done always, that's
626d64f6189SIngo Weinhold 			// probably more expensive than calling
627d64f6189SIngo Weinhold 			// call_atexit_hooks_for_range() only here, which happens only when
628d64f6189SIngo Weinhold 			// libraries are unloaded dynamically.
6298c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
6308c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
6313be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
6328c2a9d74SMichael Lotz 			}
6338c2a9d74SMichael Lotz 
63410b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
63510b4b5d1SIngo Weinhold 
6360c0fea5dSIngo Weinhold 			if (image->term_routine)
6370c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
6380c0fea5dSIngo Weinhold 
63944c0c4d3SPawel Dziepak 			TLSBlockTemplates::Get().Unregister(image->dso_tls_id);
64044c0c4d3SPawel Dziepak 
64194830eb2SIngo Weinhold 			dequeue_disposable_image(image);
6420c0fea5dSIngo Weinhold 			unmap_image(image);
6430c0fea5dSIngo Weinhold 
64410b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
64510b4b5d1SIngo Weinhold 
6460c0fea5dSIngo Weinhold 			delete_image(image);
6470c0fea5dSIngo Weinhold 		}
6480c0fea5dSIngo Weinhold 	}
6490c0fea5dSIngo Weinhold 
6500c0fea5dSIngo Weinhold 	rld_unlock();
6510c0fea5dSIngo Weinhold 	return status;
6520c0fea5dSIngo Weinhold }
6530c0fea5dSIngo Weinhold 
6540c0fea5dSIngo Weinhold 
6550c0fea5dSIngo Weinhold status_t
6569a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
6579a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
6580c0fea5dSIngo Weinhold {
6590c0fea5dSIngo Weinhold 	int32 count = 0, j;
6600c0fea5dSIngo Weinhold 	uint32 i;
6610c0fea5dSIngo Weinhold 	image_t *image;
6620c0fea5dSIngo Weinhold 
6630c0fea5dSIngo Weinhold 	rld_lock();
6640c0fea5dSIngo Weinhold 
6650c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
66694830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
6670c0fea5dSIngo Weinhold 	if (image == NULL) {
6680c0fea5dSIngo Weinhold 		rld_unlock();
6690c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
6700c0fea5dSIngo Weinhold 	}
6710c0fea5dSIngo Weinhold 
6720c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
6730c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
6740c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
675e3ac2588SAlex Smith 			elf_sym *symbol = &image->syms[j];
6760c0fea5dSIngo Weinhold 
6770c0fea5dSIngo Weinhold 			if (count == num) {
67810b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
67910b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
68010b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
6810c0fea5dSIngo Weinhold 
68210b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
68310b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
68410b4b5d1SIngo Weinhold 				int32 type;
685e3ac2588SAlex Smith 				if (symbol->Type() == STT_FUNC)
68610b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
687e3ac2588SAlex Smith 				else if (symbol->Type() == STT_OBJECT)
68810b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
6890c0fea5dSIngo Weinhold 				else
69010b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
69110b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
6920c0fea5dSIngo Weinhold 
69310b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
69410b4b5d1SIngo Weinhold 
69510b4b5d1SIngo Weinhold 				if (_type != NULL)
69610b4b5d1SIngo Weinhold 					*_type = type;
6970c0fea5dSIngo Weinhold 				if (_location != NULL)
69810b4b5d1SIngo Weinhold 					*_location = location;
6990c0fea5dSIngo Weinhold 				goto out;
7000c0fea5dSIngo Weinhold 			}
7010c0fea5dSIngo Weinhold 			count++;
7020c0fea5dSIngo Weinhold 		}
7030c0fea5dSIngo Weinhold 	}
7040c0fea5dSIngo Weinhold out:
7050c0fea5dSIngo Weinhold 	rld_unlock();
7060c0fea5dSIngo Weinhold 
7070c0fea5dSIngo Weinhold 	if (num != count)
7080c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
7090c0fea5dSIngo Weinhold 
7100c0fea5dSIngo Weinhold 	return B_OK;
7110c0fea5dSIngo Weinhold }
7120c0fea5dSIngo Weinhold 
7130c0fea5dSIngo Weinhold 
7140c0fea5dSIngo Weinhold status_t
71543e7b1c2SHamish Morrison get_nearest_symbol_at_address(void* address, image_id* _imageID,
716*ebdc1d48SMichael Lotz 	char** _imagePath, char** _imageName, char** _symbolName, int32* _type,
717*ebdc1d48SMichael Lotz 	void** _location, bool* _exactMatch)
718b6455c08SAxel Dörfler {
719b6455c08SAxel Dörfler 	rld_lock();
720b6455c08SAxel Dörfler 
721b6455c08SAxel Dörfler 	image_t* image = find_loaded_image_by_address((addr_t)address);
722b6455c08SAxel Dörfler 	if (image == NULL) {
723b6455c08SAxel Dörfler 		rld_unlock();
724b6455c08SAxel Dörfler 		return B_BAD_VALUE;
725b6455c08SAxel Dörfler 	}
726b6455c08SAxel Dörfler 
727*ebdc1d48SMichael Lotz 	bool exactMatch = false;
728e3ac2588SAlex Smith 	elf_sym* foundSymbol = NULL;
72943e7b1c2SHamish Morrison 	addr_t foundLocation = (addr_t)NULL;
73043e7b1c2SHamish Morrison 
731*ebdc1d48SMichael Lotz 	for (uint32 i = 0; i < HASHTABSIZE(image) && !exactMatch; i++) {
732b6455c08SAxel Dörfler 		for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF;
733b6455c08SAxel Dörfler 				j = HASHCHAINS(image)[j]) {
734e3ac2588SAlex Smith 			elf_sym *symbol = &image->syms[j];
735b6455c08SAxel Dörfler 			addr_t location = symbol->st_value + image->regions[0].delta;
736b6455c08SAxel Dörfler 
73743e7b1c2SHamish Morrison 			if (location <= (addr_t)address	&& location >= foundLocation) {
73843e7b1c2SHamish Morrison 				foundSymbol = symbol;
73943e7b1c2SHamish Morrison 				foundLocation = location;
740b6455c08SAxel Dörfler 
74143e7b1c2SHamish Morrison 				// jump out if we have an exact match
742*ebdc1d48SMichael Lotz 				if (location + symbol->st_size > (addr_t)address) {
743*ebdc1d48SMichael Lotz 					exactMatch = true;
74443e7b1c2SHamish Morrison 					break;
74543e7b1c2SHamish Morrison 				}
74643e7b1c2SHamish Morrison 			}
74743e7b1c2SHamish Morrison 		}
74843e7b1c2SHamish Morrison 	}
749b6455c08SAxel Dörfler 
750b6455c08SAxel Dörfler 	if (_imageID != NULL)
751b6455c08SAxel Dörfler 		*_imageID = image->id;
75243e7b1c2SHamish Morrison 	if (_imagePath != NULL)
75343e7b1c2SHamish Morrison 		*_imagePath = image->path;
754*ebdc1d48SMichael Lotz 	if (_imageName != NULL)
755*ebdc1d48SMichael Lotz 		*_imageName = image->name;
756*ebdc1d48SMichael Lotz 	if (_exactMatch != NULL)
757*ebdc1d48SMichael Lotz 		*_exactMatch = exactMatch;
75843e7b1c2SHamish Morrison 
75943e7b1c2SHamish Morrison 	if (foundSymbol != NULL) {
76043e7b1c2SHamish Morrison 		*_symbolName = SYMNAME(image, foundSymbol);
76143e7b1c2SHamish Morrison 
76243e7b1c2SHamish Morrison 		if (_type != NULL) {
763e3ac2588SAlex Smith 			if (foundSymbol->Type() == STT_FUNC)
76443e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_TEXT;
765e3ac2588SAlex Smith 			else if (foundSymbol->Type() == STT_OBJECT)
76643e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_DATA;
76743e7b1c2SHamish Morrison 			else
76843e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_ANY;
76943e7b1c2SHamish Morrison 			// TODO: check with the return types of that BeOS function
77043e7b1c2SHamish Morrison 		}
77143e7b1c2SHamish Morrison 
772b6455c08SAxel Dörfler 		if (_location != NULL)
77343e7b1c2SHamish Morrison 			*_location = (void*)foundLocation;
77443e7b1c2SHamish Morrison 	} else {
77543e7b1c2SHamish Morrison 		*_symbolName = NULL;
77643e7b1c2SHamish Morrison 		if (_location != NULL)
77743e7b1c2SHamish Morrison 			*_location = NULL;
77843e7b1c2SHamish Morrison 	}
779b6455c08SAxel Dörfler 
780b6455c08SAxel Dörfler 	rld_unlock();
781b6455c08SAxel Dörfler 	return B_OK;
782b6455c08SAxel Dörfler }
783b6455c08SAxel Dörfler 
784b6455c08SAxel Dörfler 
785b6455c08SAxel Dörfler status_t
7869a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
78780ece785SIngo Weinhold 	bool recursive, image_id *_inImage, void **_location)
7880c0fea5dSIngo Weinhold {
7890c0fea5dSIngo Weinhold 	status_t status = B_OK;
7900c0fea5dSIngo Weinhold 	image_t *image;
7910c0fea5dSIngo Weinhold 
7920c0fea5dSIngo Weinhold 	if (imageID < B_OK)
7930c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
7940c0fea5dSIngo Weinhold 	if (symbolName == NULL)
7950c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
7960c0fea5dSIngo Weinhold 
7970c0fea5dSIngo Weinhold 	rld_lock();
7980c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
7990c0fea5dSIngo Weinhold 
8000c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
80194830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
80280ece785SIngo Weinhold 	if (image != NULL) {
80380ece785SIngo Weinhold 		if (recursive) {
80480ece785SIngo Weinhold 			// breadth-first search in the given image and its dependencies
805003ebb0eSIngo Weinhold 			status = find_symbol_breadth_first(image,
806003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
807003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
80880ece785SIngo Weinhold 				&image, _location);
809003ebb0eSIngo Weinhold 		} else {
810003ebb0eSIngo Weinhold 			status = find_symbol(image,
811003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
812003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
813003ebb0eSIngo Weinhold 				_location);
814003ebb0eSIngo Weinhold 		}
81580ece785SIngo Weinhold 
81680ece785SIngo Weinhold 		if (status == B_OK && _inImage != NULL)
81780ece785SIngo Weinhold 			*_inImage = image->id;
81880ece785SIngo Weinhold 	} else
8190c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
8200c0fea5dSIngo Weinhold 
8210c0fea5dSIngo Weinhold 	rld_unlock();
8220c0fea5dSIngo Weinhold 	return status;
8230c0fea5dSIngo Weinhold }
8240c0fea5dSIngo Weinhold 
8250c0fea5dSIngo Weinhold 
8260c0fea5dSIngo Weinhold status_t
8270c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
8280c85bd05SIngo Weinhold 	void **_location)
8290c85bd05SIngo Weinhold {
8300c85bd05SIngo Weinhold 	status_t status = B_ENTRY_NOT_FOUND;
8310c85bd05SIngo Weinhold 
8320c85bd05SIngo Weinhold 	if (symbolName == NULL)
8330c85bd05SIngo Weinhold 		return B_BAD_VALUE;
8340c85bd05SIngo Weinhold 
8350c85bd05SIngo Weinhold 	rld_lock();
8360c85bd05SIngo Weinhold 		// for now, just do stupid simple global locking
8370c85bd05SIngo Weinhold 
8380c85bd05SIngo Weinhold 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
8390c85bd05SIngo Weinhold 		// look in the default scope
8400c85bd05SIngo Weinhold 		image_t* image;
841e3ac2588SAlex Smith 		elf_sym* symbol = find_undefined_symbol_global(gProgramImage,
84294830eb2SIngo Weinhold 			gProgramImage,
843003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
844003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
845003ebb0eSIngo Weinhold 			&image);
8460c85bd05SIngo Weinhold 		if (symbol != NULL) {
8470c85bd05SIngo Weinhold 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
848e3ac2588SAlex Smith 			int32 symbolType = symbol->Type() == STT_FUNC
8490c85bd05SIngo Weinhold 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
8500c85bd05SIngo Weinhold 			patch_defined_symbol(image, symbolName, _location, &symbolType);
8510c85bd05SIngo Weinhold 			status = B_OK;
8520c85bd05SIngo Weinhold 		}
8530c85bd05SIngo Weinhold 	} else if (handle == RTLD_NEXT) {
8540c85bd05SIngo Weinhold 		// Look in the default scope, but also in the dependencies of the
8550c85bd05SIngo Weinhold 		// calling image. Return the next after the caller symbol.
8560c85bd05SIngo Weinhold 
857a2dad9e1SIngo Weinhold 		// First of all, find the caller image.
85894830eb2SIngo Weinhold 		image_t* callerImage = get_loaded_images().head;
8590c85bd05SIngo Weinhold 		for (; callerImage != NULL; callerImage = callerImage->next) {
8600c85bd05SIngo Weinhold 			elf_region_t& text = callerImage->regions[0];
861a2dad9e1SIngo Weinhold 			if ((addr_t)caller >= text.vmstart
862a2dad9e1SIngo Weinhold 				&& (addr_t)caller < text.vmstart + text.vmsize) {
863a2dad9e1SIngo Weinhold 				// found the image
8640c85bd05SIngo Weinhold 				break;
8650c85bd05SIngo Weinhold 			}
8660c85bd05SIngo Weinhold 		}
8670c85bd05SIngo Weinhold 
868a2dad9e1SIngo Weinhold 		if (callerImage != NULL) {
8690c85bd05SIngo Weinhold 			// found the caller -- now search the global scope until we find
8700c85bd05SIngo Weinhold 			// the next symbol
871a2dad9e1SIngo Weinhold 			bool hitCallerImage = false;
8720c85bd05SIngo Weinhold 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
8730c85bd05SIngo Weinhold 
874e3ac2588SAlex Smith 			elf_sym* candidateSymbol = NULL;
87525dc253dSIngo Weinhold 			image_t* candidateImage = NULL;
87625dc253dSIngo Weinhold 
87794830eb2SIngo Weinhold 			image_t* image = get_loaded_images().head;
8780c85bd05SIngo Weinhold 			for (; image != NULL; image = image->next) {
879a2dad9e1SIngo Weinhold 				// skip the caller image
880a2dad9e1SIngo Weinhold 				if (image == callerImage) {
881a2dad9e1SIngo Weinhold 					hitCallerImage = true;
882a2dad9e1SIngo Weinhold 					continue;
883a2dad9e1SIngo Weinhold 				}
884a2dad9e1SIngo Weinhold 
885a2dad9e1SIngo Weinhold 				// skip all images up to the caller image; also skip add-on
886a2dad9e1SIngo Weinhold 				// images and those not marked above for resolution
887a2dad9e1SIngo Weinhold 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
8880c85bd05SIngo Weinhold 					|| (image->flags
889a2dad9e1SIngo Weinhold 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
8900c85bd05SIngo Weinhold 					continue;
8910c85bd05SIngo Weinhold 				}
8920c85bd05SIngo Weinhold 
893e3ac2588SAlex Smith 				elf_sym *symbol = find_symbol(image,
894003ebb0eSIngo Weinhold 					SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
895003ebb0eSIngo Weinhold 						LOOKUP_FLAG_DEFAULT_VERSION));
8960c85bd05SIngo Weinhold 				if (symbol == NULL)
8970c85bd05SIngo Weinhold 					continue;
8980c85bd05SIngo Weinhold 
89925dc253dSIngo Weinhold 				// found a symbol
900e3ac2588SAlex Smith 				bool isWeak = symbol->Bind() == STB_WEAK;
90125dc253dSIngo Weinhold 				if (candidateImage == NULL || !isWeak) {
90225dc253dSIngo Weinhold 					candidateSymbol = symbol;
90325dc253dSIngo Weinhold 					candidateImage = image;
90425dc253dSIngo Weinhold 
90525dc253dSIngo Weinhold 					if (!isWeak)
90625dc253dSIngo Weinhold 						break;
90725dc253dSIngo Weinhold 				}
90825dc253dSIngo Weinhold 
90925dc253dSIngo Weinhold 				// symbol is weak, so we need to continue
91025dc253dSIngo Weinhold 			}
91125dc253dSIngo Weinhold 
91225dc253dSIngo Weinhold 			if (candidateSymbol != NULL) {
913a2dad9e1SIngo Weinhold 				// found the symbol
91425dc253dSIngo Weinhold 				*_location = (void*)(candidateSymbol->st_value
91525dc253dSIngo Weinhold 					+ candidateImage->regions[0].delta);
9160c85bd05SIngo Weinhold 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
91725dc253dSIngo Weinhold 				patch_defined_symbol(candidateImage, symbolName, _location,
9180c85bd05SIngo Weinhold 					&symbolType);
9190c85bd05SIngo Weinhold 				status = B_OK;
9200c85bd05SIngo Weinhold 			}
9210c85bd05SIngo Weinhold 
9220c85bd05SIngo Weinhold 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
9230c85bd05SIngo Weinhold 		}
9240c85bd05SIngo Weinhold 	} else {
9250c85bd05SIngo Weinhold 		// breadth-first search in the given image and its dependencies
9260c85bd05SIngo Weinhold 		image_t* inImage;
927003ebb0eSIngo Weinhold 		status = find_symbol_breadth_first((image_t*)handle,
928003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
929003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
930003ebb0eSIngo Weinhold 			&inImage, _location);
9310c85bd05SIngo Weinhold 	}
9320c85bd05SIngo Weinhold 
9330c85bd05SIngo Weinhold 	rld_unlock();
9340c85bd05SIngo Weinhold 	return status;
9350c85bd05SIngo Weinhold }
9360c85bd05SIngo Weinhold 
9370c85bd05SIngo Weinhold 
9380c85bd05SIngo Weinhold status_t
9390c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
9400c0fea5dSIngo Weinhold {
9410c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
942e3ac2588SAlex Smith 	elf_dyn *dynamicSection;
9430c0fea5dSIngo Weinhold 	image_t *image;
9440c0fea5dSIngo Weinhold 
9450c0fea5dSIngo Weinhold 	if (_name == NULL)
9460c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
9470c0fea5dSIngo Weinhold 
9480c0fea5dSIngo Weinhold 	rld_lock();
9490c0fea5dSIngo Weinhold 
95094830eb2SIngo Weinhold 	image = find_loaded_image_by_id(id, false);
9510c0fea5dSIngo Weinhold 	if (image == NULL) {
9520c0fea5dSIngo Weinhold 		rld_unlock();
9530c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
9540c0fea5dSIngo Weinhold 	}
9550c0fea5dSIngo Weinhold 
956e3ac2588SAlex Smith 	dynamicSection = (elf_dyn *)image->dynamic_ptr;
9570c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
9580c0fea5dSIngo Weinhold 		rld_unlock();
9590c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
9600c0fea5dSIngo Weinhold 	}
9610c0fea5dSIngo Weinhold 
9620c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
9630c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
9640c0fea5dSIngo Weinhold 			continue;
9650c0fea5dSIngo Weinhold 
9660c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
9670c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
9680c0fea5dSIngo Weinhold 
9690c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
9700c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
9710c0fea5dSIngo Weinhold 			rld_unlock();
9720c0fea5dSIngo Weinhold 			return B_OK;
9730c0fea5dSIngo Weinhold 		}
9740c0fea5dSIngo Weinhold 	}
9750c0fea5dSIngo Weinhold 
9760c0fea5dSIngo Weinhold 	rld_unlock();
9770c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
9780c0fea5dSIngo Weinhold }
9790c0fea5dSIngo Weinhold 
9800c0fea5dSIngo Weinhold 
98174c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
9820c0fea5dSIngo Weinhold 
9830c0fea5dSIngo Weinhold 
9849a6072a3SAxel Dörfler /*! Read and verify the ELF header */
9850c0fea5dSIngo Weinhold status_t
986e3ac2588SAlex Smith elf_verify_header(void *header, size_t length)
9870c0fea5dSIngo Weinhold {
9880c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
9890c0fea5dSIngo Weinhold 
990e3ac2588SAlex Smith 	if (length < sizeof(elf_ehdr))
9910c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
9920c0fea5dSIngo Weinhold 
993e3ac2588SAlex Smith 	return parse_elf_header((elf_ehdr *)header, &programSize, &sectionSize);
9940c0fea5dSIngo Weinhold }
9950c0fea5dSIngo Weinhold 
9960c0fea5dSIngo Weinhold 
9970c0fea5dSIngo Weinhold void
9980c0fea5dSIngo Weinhold terminate_program(void)
9990c0fea5dSIngo Weinhold {
10000c0fea5dSIngo Weinhold 	image_t **termList;
10010c0fea5dSIngo Weinhold 	ssize_t count, i;
10020c0fea5dSIngo Weinhold 
1003aa3507feSIngo Weinhold 	count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED);
10040c0fea5dSIngo Weinhold 	if (count < B_OK)
10050c0fea5dSIngo Weinhold 		return;
10060c0fea5dSIngo Weinhold 
100794830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
10089a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
10099a6072a3SAxel Dörfler 		update_image_ids();
10109a6072a3SAxel Dörfler 	}
10119a6072a3SAxel Dörfler 
10120c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
10130c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
10140c0fea5dSIngo Weinhold 		image_t *image = termList[i];
10150c0fea5dSIngo Weinhold 
10160c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
10170c0fea5dSIngo Weinhold 
101810b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
101910b4b5d1SIngo Weinhold 
10200c0fea5dSIngo Weinhold 		if (image->term_routine)
10210c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
102210b4b5d1SIngo Weinhold 
102310b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
10240c0fea5dSIngo Weinhold 	}
10250c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
10260c0fea5dSIngo Weinhold 
10270c0fea5dSIngo Weinhold 	free(termList);
10280c0fea5dSIngo Weinhold }
10290c0fea5dSIngo Weinhold 
10300c0fea5dSIngo Weinhold 
10310c0fea5dSIngo Weinhold void
10320c0fea5dSIngo Weinhold rldelf_init(void)
10330c0fea5dSIngo Weinhold {
103494830eb2SIngo Weinhold 	init_add_ons();
103594830eb2SIngo Weinhold 
10360c0fea5dSIngo Weinhold 	// create the debug area
10370c0fea5dSIngo Weinhold 	{
1038e3ac2588SAlex Smith 		size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
10390c0fea5dSIngo Weinhold 
10400c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
10410c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
10429f3bd497SPawel Dziepak 			(void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK,
10430c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
10440c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
10450c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
10460c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
10470c0fea5dSIngo Weinhold 		}
10480c0fea5dSIngo Weinhold 
104994830eb2SIngo Weinhold 		area->loaded_images = &get_loaded_images();
10500c0fea5dSIngo Weinhold 	}
105174c0424aSAxel Dörfler 
105274c0424aSAxel Dörfler 	// initialize error message if needed
10534bef3723SAxel Dörfler 	if (report_errors()) {
105474c0424aSAxel Dörfler 		void *buffer = malloc(1024);
105574c0424aSAxel Dörfler 		if (buffer == NULL)
105674c0424aSAxel Dörfler 			return;
105774c0424aSAxel Dörfler 
105894830eb2SIngo Weinhold 		gErrorMessage.SetTo(buffer, 1024, 'Rler');
105974c0424aSAxel Dörfler 	}
10600c0fea5dSIngo Weinhold }
10611873b4b3SIngo Weinhold 
10621873b4b3SIngo Weinhold 
10631873b4b3SIngo Weinhold status_t
10649a6072a3SAxel Dörfler elf_reinit_after_fork(void)
10651873b4b3SIngo Weinhold {
1066f7127458SIngo Weinhold 	recursive_lock_init(&sLock, kLockName);
10671873b4b3SIngo Weinhold 
10689a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
1069cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
1070cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
10719a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
107294830eb2SIngo Weinhold 	gInvalidImageIDs = true;
1073cbc456deSIngo Weinhold 
10741873b4b3SIngo Weinhold 	return B_OK;
10751873b4b3SIngo Weinhold }
1076