xref: /haiku/src/system/runtime_loader/elf.cpp (revision 9f3bd49737df7fedbf89ed90570ac1a965814c2b)
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"
2994830eb2SIngo Weinhold #include "elf_versioning.h"
3094830eb2SIngo Weinhold #include "errors.h"
3194830eb2SIngo Weinhold #include "images.h"
320c0fea5dSIngo Weinhold 
330c0fea5dSIngo Weinhold 
3410b4b5d1SIngo Weinhold // TODO: implement better locking strategy
3510b4b5d1SIngo Weinhold // TODO: implement lazy binding
360c0fea5dSIngo Weinhold 
370c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen())
380c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE	((void*)-2l)
390c85bd05SIngo Weinhold 
40f7127458SIngo Weinhold static const char* const kLockName = "runtime loader";
41f7127458SIngo Weinhold 
420c0fea5dSIngo Weinhold 
430c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
440c0fea5dSIngo Weinhold 
4594830eb2SIngo Weinhold bool gProgramLoaded = false;
4694830eb2SIngo Weinhold image_t* gProgramImage;
47003ebb0eSIngo Weinhold 
48ca618b22SIngo Weinhold static image_t** sPreloadedImages = NULL;
49ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0;
500c0fea5dSIngo Weinhold 
51f7127458SIngo Weinhold static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName);
520c0fea5dSIngo Weinhold 
537486b72dSIngo Weinhold 
54f2bb2575SIngo Weinhold static inline void
550c0fea5dSIngo Weinhold rld_lock()
560c0fea5dSIngo Weinhold {
57f2bb2575SIngo Weinhold 	recursive_lock_lock(&sLock);
580c0fea5dSIngo Weinhold }
59f2bb2575SIngo Weinhold 
60f2bb2575SIngo Weinhold 
61f2bb2575SIngo Weinhold static inline void
62f2bb2575SIngo Weinhold rld_unlock()
63f2bb2575SIngo Weinhold {
64f2bb2575SIngo Weinhold 	recursive_lock_unlock(&sLock);
650c0fea5dSIngo Weinhold }
660c0fea5dSIngo Weinhold 
670c0fea5dSIngo Weinhold 
680c0fea5dSIngo Weinhold static const char *
690c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
700c0fea5dSIngo Weinhold {
710c0fea5dSIngo Weinhold 	int i;
72e3ac2588SAlex Smith 	elf_dyn *d = (elf_dyn *)image->dynamic_ptr;
730c0fea5dSIngo Weinhold 
740c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
750c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
760c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
770c0fea5dSIngo Weinhold 	}
780c0fea5dSIngo Weinhold 
790c0fea5dSIngo Weinhold 	return NULL;
800c0fea5dSIngo Weinhold }
810c0fea5dSIngo Weinhold 
820c0fea5dSIngo Weinhold 
830c0fea5dSIngo Weinhold static status_t
840c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image)
850c0fea5dSIngo Weinhold {
86e3ac2588SAlex Smith 	elf_dyn *d = (elf_dyn *)image->dynamic_ptr;
874bef3723SAxel Dörfler 	bool reportErrors = report_errors();
8874c0424aSAxel Dörfler 	status_t status = B_OK;
890c0fea5dSIngo Weinhold 	uint32 i, j;
900c0fea5dSIngo Weinhold 	const char *rpath;
910c0fea5dSIngo Weinhold 
920c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
930c0fea5dSIngo Weinhold 		return B_OK;
940c0fea5dSIngo Weinhold 
950c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
960c0fea5dSIngo Weinhold 
970c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
980c0fea5dSIngo Weinhold 		return B_OK;
990c0fea5dSIngo Weinhold 
1007486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
1017486b72dSIngo Weinhold 		image->id);
1027486b72dSIngo Weinhold 
1030c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
1040c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
105c533f813SIngo Weinhold 		FATAL("%s: Failed to allocate needed struct\n", image->path);
1067486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
1077486b72dSIngo Weinhold 			image->name, image->id);
1080c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
1090c0fea5dSIngo Weinhold 	}
1100c0fea5dSIngo Weinhold 
1110c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
1120c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
1130c0fea5dSIngo Weinhold 
1140c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
1150c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
1160c0fea5dSIngo Weinhold 			case DT_NEEDED:
11774c0424aSAxel Dörfler 			{
11874c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
11974c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
1200c0fea5dSIngo Weinhold 
12194830eb2SIngo Weinhold 				status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
12274c0424aSAxel Dörfler 					rpath, &image->needed[j]);
12374c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
12474c0424aSAxel Dörfler 					status = loadStatus;
12574c0424aSAxel Dörfler 					// correct error code in case the file could not been found
12674c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
12774c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
12874c0424aSAxel Dörfler 
12974c0424aSAxel Dörfler 						if (reportErrors)
13094830eb2SIngo Weinhold 							gErrorMessage.AddString("missing library", name);
13174c0424aSAxel Dörfler 					}
13274c0424aSAxel Dörfler 
13374c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
1347486b72dSIngo Weinhold 					if (!reportErrors) {
1357486b72dSIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
1367486b72dSIngo Weinhold 							"failed: %s", image->name, image->id,
1377486b72dSIngo Weinhold 							strerror(status));
1380c0fea5dSIngo Weinhold 						return status;
13974c0424aSAxel Dörfler 					}
1407486b72dSIngo Weinhold 				}
1410c0fea5dSIngo Weinhold 
1420c0fea5dSIngo Weinhold 				j += 1;
1430c0fea5dSIngo Weinhold 				break;
14474c0424aSAxel Dörfler 			}
1450c0fea5dSIngo Weinhold 
1460c0fea5dSIngo Weinhold 			default:
1470c0fea5dSIngo Weinhold 				// ignore any other tag
1480c0fea5dSIngo Weinhold 				continue;
1490c0fea5dSIngo Weinhold 		}
1500c0fea5dSIngo Weinhold 	}
1510c0fea5dSIngo Weinhold 
1527486b72dSIngo Weinhold 	if (status < B_OK) {
1537486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
1547486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
1557486b72dSIngo Weinhold 			strerror(status));
15674c0424aSAxel Dörfler 		return status;
1577486b72dSIngo Weinhold 	}
15874c0424aSAxel Dörfler 
1590c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
1600c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
1617486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
1627486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
1630c0fea5dSIngo Weinhold 		return B_ERROR;
1640c0fea5dSIngo Weinhold 	}
1650c0fea5dSIngo Weinhold 
1667486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
1677486b72dSIngo Weinhold 		image->id);
1687486b72dSIngo Weinhold 
1690c0fea5dSIngo Weinhold 	return B_OK;
1700c0fea5dSIngo Weinhold }
1710c0fea5dSIngo Weinhold 
1720c0fea5dSIngo Weinhold 
1730c85bd05SIngo Weinhold static status_t
1740c85bd05SIngo Weinhold load_dependencies(image_t* image)
1750c85bd05SIngo Weinhold {
176003ebb0eSIngo Weinhold 	// load dependencies (breadth-first)
1770c85bd05SIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
1780c85bd05SIngo Weinhold 			otherImage = otherImage->next) {
1790c85bd05SIngo Weinhold 		status_t status = load_immediate_dependencies(otherImage);
1800c85bd05SIngo Weinhold 		if (status != B_OK)
1810c85bd05SIngo Weinhold 			return status;
1820c85bd05SIngo Weinhold 	}
1830c85bd05SIngo Weinhold 
184003ebb0eSIngo Weinhold 	// Check the needed versions for the given image and all newly loaded
185003ebb0eSIngo Weinhold 	// dependencies.
186003ebb0eSIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
187003ebb0eSIngo Weinhold 			otherImage = otherImage->next) {
188003ebb0eSIngo Weinhold 		status_t status = check_needed_image_versions(otherImage);
189003ebb0eSIngo Weinhold 		if (status != B_OK)
190003ebb0eSIngo Weinhold 			return status;
191003ebb0eSIngo Weinhold 	}
192003ebb0eSIngo Weinhold 
1930c85bd05SIngo Weinhold 	return B_OK;
1940c85bd05SIngo Weinhold }
1950c85bd05SIngo Weinhold 
1960c85bd05SIngo Weinhold 
19794830eb2SIngo Weinhold static status_t
19894830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
1990c0fea5dSIngo Weinhold {
20025dc253dSIngo Weinhold 	SymbolLookupCache cache(image);
20125dc253dSIngo Weinhold 
20225dc253dSIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image, &cache);
20394830eb2SIngo Weinhold 	if (status < B_OK) {
204c533f813SIngo Weinhold 		FATAL("%s: Troubles relocating: %s\n", image->path, strerror(status));
20594830eb2SIngo Weinhold 		return status;
2060c0fea5dSIngo Weinhold 	}
2070c0fea5dSIngo Weinhold 
20894830eb2SIngo Weinhold 	_kern_image_relocated(image->id);
20994830eb2SIngo Weinhold 	image_event(image, IMAGE_EVENT_RELOCATED);
21094830eb2SIngo Weinhold 	return B_OK;
2110c0fea5dSIngo Weinhold }
2120c0fea5dSIngo Weinhold 
2130c0fea5dSIngo Weinhold 
2140c0fea5dSIngo Weinhold static status_t
2150c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
2160c0fea5dSIngo Weinhold {
217ca618b22SIngo Weinhold 	// get the images that still have to be relocated
218ca618b22SIngo Weinhold 	image_t **list;
219ca618b22SIngo Weinhold 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
2200c0fea5dSIngo Weinhold 	if (count < B_OK)
2210c0fea5dSIngo Weinhold 		return count;
2220c0fea5dSIngo Weinhold 
2230c85bd05SIngo Weinhold 	// relocate
224ca618b22SIngo Weinhold 	for (ssize_t i = 0; i < count; i++) {
22546f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
2260c85bd05SIngo Weinhold 		if (status < B_OK) {
2270c85bd05SIngo Weinhold 			free(list);
2280c0fea5dSIngo Weinhold 			return status;
2290c0fea5dSIngo Weinhold 		}
2300c85bd05SIngo Weinhold 	}
2310c0fea5dSIngo Weinhold 
2320c0fea5dSIngo Weinhold 	free(list);
2330c0fea5dSIngo Weinhold 	return B_OK;
2340c0fea5dSIngo Weinhold }
2350c0fea5dSIngo Weinhold 
2360c0fea5dSIngo Weinhold 
2370c0fea5dSIngo Weinhold static void
2380c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
2390c0fea5dSIngo Weinhold {
2400c0fea5dSIngo Weinhold 	image_t **initList;
2410c0fea5dSIngo Weinhold 	ssize_t count, i;
2420c0fea5dSIngo Weinhold 
2430c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
2440c0fea5dSIngo Weinhold 	if (count <= 0)
2450c0fea5dSIngo Weinhold 		return;
2460c0fea5dSIngo Weinhold 
2470c0fea5dSIngo Weinhold 	if (!initHead) {
2480c0fea5dSIngo Weinhold 		// this removes the "calling" image
2490c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
2500c0fea5dSIngo Weinhold 		initList[--count] = NULL;
2510c0fea5dSIngo Weinhold 	}
2520c0fea5dSIngo Weinhold 
2530c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
2540c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
2550c0fea5dSIngo Weinhold 		image = initList[i];
2560c0fea5dSIngo Weinhold 
2570c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
2580c0fea5dSIngo Weinhold 
259dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
2600c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
26110b4b5d1SIngo Weinhold 
26210b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
2630c0fea5dSIngo Weinhold 	}
2640c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
2650c0fea5dSIngo Weinhold 
2660c0fea5dSIngo Weinhold 	free(initList);
2670c0fea5dSIngo Weinhold }
2680c0fea5dSIngo Weinhold 
2690c0fea5dSIngo Weinhold 
2700c0fea5dSIngo Weinhold static void
271ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
272ca618b22SIngo Weinhold {
273ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
274ca618b22SIngo Weinhold 	// API.
275ca618b22SIngo Weinhold 	image_t* image;
2760c85bd05SIngo Weinhold 	void* _export;
277003ebb0eSIngo Weinhold 	if (find_symbol_breadth_first(rootImage,
278003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
279003ebb0eSIngo Weinhold 			&_export) == B_OK) {
2800c85bd05SIngo Weinhold 		*(void**)_export = &gRuntimeLoader;
281ca618b22SIngo Weinhold 	}
282ca618b22SIngo Weinhold }
283ca618b22SIngo Weinhold 
284ca618b22SIngo Weinhold 
285ca618b22SIngo Weinhold static status_t
286ca618b22SIngo Weinhold add_preloaded_image(image_t* image)
287ca618b22SIngo Weinhold {
288ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
289ca618b22SIngo Weinhold 	// small number of preloaded images.
290ca618b22SIngo Weinhold 	image_t** newArray = (image_t**)realloc(sPreloadedImages,
291ca618b22SIngo Weinhold 		sizeof(image_t*) * (sPreloadedImageCount + 1));
292ca618b22SIngo Weinhold 	if (newArray == NULL)
293ca618b22SIngo Weinhold 		return B_NO_MEMORY;
294ca618b22SIngo Weinhold 
295ca618b22SIngo Weinhold 	sPreloadedImages = newArray;
296ca618b22SIngo Weinhold 	newArray[sPreloadedImageCount++] = image;
297ca618b22SIngo Weinhold 
298ca618b22SIngo Weinhold 	return B_OK;
299ca618b22SIngo Weinhold }
300ca618b22SIngo Weinhold 
301ca618b22SIngo Weinhold 
302ca618b22SIngo Weinhold image_id
303ca618b22SIngo Weinhold preload_image(char const* path)
304ca618b22SIngo Weinhold {
305ca618b22SIngo Weinhold 	if (path == NULL)
306ca618b22SIngo Weinhold 		return B_BAD_VALUE;
307ca618b22SIngo Weinhold 
308ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\")", path);
309ca618b22SIngo Weinhold 
310ca618b22SIngo Weinhold 	image_t *image = NULL;
311765a039dSIngo Weinhold 	status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, &image);
312ca618b22SIngo Weinhold 	if (status < B_OK) {
313ca618b22SIngo Weinhold 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
314ca618b22SIngo Weinhold 			strerror(status));
315ca618b22SIngo Weinhold 		return status;
316ca618b22SIngo Weinhold 	}
317ca618b22SIngo Weinhold 
3180c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL)
3190c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_global;
3200c85bd05SIngo Weinhold 
3210c85bd05SIngo Weinhold 	status = load_dependencies(image);
322ca618b22SIngo Weinhold 	if (status < B_OK)
323ca618b22SIngo Weinhold 		goto err;
3240c85bd05SIngo Weinhold 
3250c85bd05SIngo Weinhold 	set_image_flags_recursively(image, RTLD_GLOBAL);
326ca618b22SIngo Weinhold 
327ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
328ca618b22SIngo Weinhold 	if (status < B_OK)
329ca618b22SIngo Weinhold 		goto err;
330ca618b22SIngo Weinhold 
331ca618b22SIngo Weinhold 	status = add_preloaded_image(image);
332ca618b22SIngo Weinhold 	if (status < B_OK)
333ca618b22SIngo Weinhold 		goto err;
334ca618b22SIngo Weinhold 
335ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
336ca618b22SIngo Weinhold 
337ca618b22SIngo Weinhold 	remap_images();
338ca618b22SIngo Weinhold 	init_dependencies(image, true);
339ca618b22SIngo Weinhold 
34010b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
34110b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
342003ebb0eSIngo Weinhold 	if (find_symbol(image,
343003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
34410b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
34594830eb2SIngo Weinhold 		add_add_on(image, addOnStruct);
34610b4b5d1SIngo Weinhold 	}
34710b4b5d1SIngo Weinhold 
348ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id);
349ca618b22SIngo Weinhold 
350ca618b22SIngo Weinhold 	return image->id;
351ca618b22SIngo Weinhold 
352ca618b22SIngo Weinhold err:
353ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status));
354ca618b22SIngo Weinhold 
35594830eb2SIngo Weinhold 	dequeue_loaded_image(image);
356ca618b22SIngo Weinhold 	delete_image(image);
357ca618b22SIngo Weinhold 	return status;
358ca618b22SIngo Weinhold }
359ca618b22SIngo Weinhold 
360ca618b22SIngo Weinhold 
361ca618b22SIngo Weinhold static void
362ca618b22SIngo Weinhold preload_images()
363ca618b22SIngo Weinhold {
364ca618b22SIngo Weinhold 	const char* imagePaths = getenv("LD_PRELOAD");
365ca618b22SIngo Weinhold 	if (imagePaths == NULL)
366ca618b22SIngo Weinhold 		return;
367ca618b22SIngo Weinhold 
368ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
369ca618b22SIngo Weinhold 		// find begin of image path
370ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
371ca618b22SIngo Weinhold 			imagePaths++;
372ca618b22SIngo Weinhold 
373ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
374ca618b22SIngo Weinhold 			break;
375ca618b22SIngo Weinhold 
376ca618b22SIngo Weinhold 		// find end of image path
377ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
378ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
379ca618b22SIngo Weinhold 			imagePaths++;
380ca618b22SIngo Weinhold 
381ca618b22SIngo Weinhold 		// extract the path
382ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
383ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
384ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
385ca618b22SIngo Weinhold 			continue;
386ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
387ca618b22SIngo Weinhold 		path[pathLen] = '\0';
388ca618b22SIngo Weinhold 
389ca618b22SIngo Weinhold 		// load the image
390ca618b22SIngo Weinhold 		preload_image(path);
391ca618b22SIngo Weinhold 	}
392ca618b22SIngo Weinhold }
393ca618b22SIngo Weinhold 
394ca618b22SIngo Weinhold 
39574c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
3960c0fea5dSIngo Weinhold 
3970c0fea5dSIngo Weinhold 
3980c0fea5dSIngo Weinhold image_id
3990c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
4000c0fea5dSIngo Weinhold {
4010c0fea5dSIngo Weinhold 	status_t status;
4020c0fea5dSIngo Weinhold 	image_t *image;
4030c0fea5dSIngo Weinhold 
4047486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
4057486b72dSIngo Weinhold 
4060c0fea5dSIngo Weinhold 	rld_lock();
4070c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
4080c0fea5dSIngo Weinhold 
409ca618b22SIngo Weinhold 	preload_images();
410ca618b22SIngo Weinhold 
4110c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
4120c0fea5dSIngo Weinhold 
41394830eb2SIngo Weinhold 	status = load_image(path, B_APP_IMAGE, NULL, &gProgramImage);
41474c0424aSAxel Dörfler 	if (status < B_OK)
41574c0424aSAxel Dörfler 		goto err;
4160c0fea5dSIngo Weinhold 
41794830eb2SIngo Weinhold 	if (gProgramImage->find_undefined_symbol == NULL)
41894830eb2SIngo Weinhold 		gProgramImage->find_undefined_symbol = find_undefined_symbol_global;
4190c85bd05SIngo Weinhold 
42094830eb2SIngo Weinhold 	status = load_dependencies(gProgramImage);
4210c0fea5dSIngo Weinhold 	if (status < B_OK)
4220c0fea5dSIngo Weinhold 		goto err;
4230c85bd05SIngo Weinhold 
42447bc6663SIngo Weinhold 	// Set RTLD_GLOBAL on all libraries including the program.
4250c85bd05SIngo Weinhold 	// This results in the desired symbol resolution for dlopen()ed libraries.
42694830eb2SIngo Weinhold 	set_image_flags_recursively(gProgramImage, RTLD_GLOBAL);
4270c0fea5dSIngo Weinhold 
42894830eb2SIngo Weinhold 	status = relocate_dependencies(gProgramImage);
4290c0fea5dSIngo Weinhold 	if (status < B_OK)
4300c0fea5dSIngo Weinhold 		goto err;
4310c0fea5dSIngo Weinhold 
43294830eb2SIngo Weinhold 	inject_runtime_loader_api(gProgramImage);
4330c0fea5dSIngo Weinhold 
4340c0fea5dSIngo Weinhold 	remap_images();
43594830eb2SIngo Weinhold 	init_dependencies(gProgramImage, true);
4360c0fea5dSIngo Weinhold 
4370c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
4380c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
43994830eb2SIngo Weinhold 	find_symbol_breadth_first(gProgramImage,
440003ebb0eSIngo Weinhold 		SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
441003ebb0eSIngo Weinhold 		(void**)&gGetEnv);
4420c0fea5dSIngo Weinhold 
44394830eb2SIngo Weinhold 	if (gProgramImage->entry_point == 0) {
4440c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
4450c0fea5dSIngo Weinhold 		goto err;
4460c0fea5dSIngo Weinhold 	}
4470c0fea5dSIngo Weinhold 
44894830eb2SIngo Weinhold 	*_entry = (void *)(gProgramImage->entry_point);
4490c0fea5dSIngo Weinhold 
4500c0fea5dSIngo Weinhold 	rld_unlock();
4517486b72dSIngo Weinhold 
45294830eb2SIngo Weinhold 	gProgramLoaded = true;
4535d0638bfSIngo Weinhold 
4547486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
45594830eb2SIngo Weinhold 		*_entry, gProgramImage->id);
4567486b72dSIngo Weinhold 
45794830eb2SIngo Weinhold 	return gProgramImage->id;
4580c0fea5dSIngo Weinhold 
4590c0fea5dSIngo Weinhold err:
4607486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
4617486b72dSIngo Weinhold 
46294830eb2SIngo Weinhold 	delete_image(gProgramImage);
46374c0424aSAxel Dörfler 
4644bef3723SAxel Dörfler 	if (report_errors()) {
4654bef3723SAxel Dörfler 		// send error message
46694830eb2SIngo Weinhold 		gErrorMessage.AddInt32("error", status);
46794830eb2SIngo Weinhold 		gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
4684bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
4694bef3723SAxel Dörfler 
4704bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
47194830eb2SIngo Weinhold 			gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0);
47274c0424aSAxel Dörfler 	}
47374c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
4740c0fea5dSIngo Weinhold 	rld_unlock();
47574c0424aSAxel Dörfler 
4760c0fea5dSIngo Weinhold 	return status;
4770c0fea5dSIngo Weinhold }
4780c0fea5dSIngo Weinhold 
4790c0fea5dSIngo Weinhold 
4800c0fea5dSIngo Weinhold image_id
4810c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle)
4820c0fea5dSIngo Weinhold {
4830c0fea5dSIngo Weinhold 	image_t *image = NULL;
4840c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
4850c0fea5dSIngo Weinhold 	status_t status;
4860c0fea5dSIngo Weinhold 
4870c85bd05SIngo Weinhold 	if (path == NULL && addOn)
4880c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
4890c0fea5dSIngo Weinhold 
4907486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
4917486b72dSIngo Weinhold 
4920c0fea5dSIngo Weinhold 	rld_lock();
4930c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
4940c0fea5dSIngo Weinhold 
4950c0fea5dSIngo Weinhold 	// have we already loaded this library?
4960c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
4970c0fea5dSIngo Weinhold 	if (!addOn) {
4980c85bd05SIngo Weinhold 		// a NULL path is fine -- it means the global scope shall be opened
4990c85bd05SIngo Weinhold 		if (path == NULL) {
5000c85bd05SIngo Weinhold 			*_handle = RLD_GLOBAL_SCOPE;
5010c85bd05SIngo Weinhold 			rld_unlock();
5020c85bd05SIngo Weinhold 			return 0;
5030c85bd05SIngo Weinhold 		}
5040c85bd05SIngo Weinhold 
50594830eb2SIngo Weinhold 		image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
5060c85bd05SIngo Weinhold 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
5070c85bd05SIngo Weinhold 			set_image_flags_recursively(image, RTLD_GLOBAL);
5080c85bd05SIngo Weinhold 
5090c0fea5dSIngo Weinhold 		if (image) {
5100c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
5110c0fea5dSIngo Weinhold 			rld_unlock();
5127486b72dSIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
5137486b72dSIngo Weinhold 				image->id);
5140c85bd05SIngo Weinhold 			*_handle = image;
5150c0fea5dSIngo Weinhold 			return image->id;
5160c0fea5dSIngo Weinhold 		}
5170c0fea5dSIngo Weinhold 	}
5180c0fea5dSIngo Weinhold 
51994830eb2SIngo Weinhold 	status = load_image(path, type, NULL, &image);
5200c0fea5dSIngo Weinhold 	if (status < B_OK) {
5210c0fea5dSIngo Weinhold 		rld_unlock();
5227486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
5237486b72dSIngo Weinhold 			strerror(status));
5240c0fea5dSIngo Weinhold 		return status;
5250c0fea5dSIngo Weinhold 	}
5260c0fea5dSIngo Weinhold 
5270c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL) {
5280c85bd05SIngo Weinhold 		if (addOn)
5290c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_add_on;
5300c85bd05SIngo Weinhold 		else
5310c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_global;
5320c85bd05SIngo Weinhold 	}
5330c85bd05SIngo Weinhold 
5340c85bd05SIngo Weinhold 	status = load_dependencies(image);
5350c0fea5dSIngo Weinhold 	if (status < B_OK)
5360c0fea5dSIngo Weinhold 		goto err;
5370c85bd05SIngo Weinhold 
5380c85bd05SIngo Weinhold 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
5390c85bd05SIngo Weinhold 	// dependencies. If not specified, we temporarily set
5400c85bd05SIngo Weinhold 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
5410c85bd05SIngo Weinhold 	// for undefined symbol resolution.
5420c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) != 0)
5430c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RTLD_GLOBAL);
5440c85bd05SIngo Weinhold 	else
5450c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
5460c0fea5dSIngo Weinhold 
5470c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
5480c0fea5dSIngo Weinhold 	if (status < B_OK)
5490c0fea5dSIngo Weinhold 		goto err;
5500c0fea5dSIngo Weinhold 
5510c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) == 0)
5520c85bd05SIngo Weinhold 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
5530c85bd05SIngo Weinhold 
5540c0fea5dSIngo Weinhold 	remap_images();
5550c0fea5dSIngo Weinhold 	init_dependencies(image, true);
5560c0fea5dSIngo Weinhold 
5570c0fea5dSIngo Weinhold 	rld_unlock();
5587486b72dSIngo Weinhold 
5597486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
5607486b72dSIngo Weinhold 
5610c85bd05SIngo Weinhold 	*_handle = image;
5620c0fea5dSIngo Weinhold 	return image->id;
5630c0fea5dSIngo Weinhold 
5640c0fea5dSIngo Weinhold err:
5657486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
5667486b72dSIngo Weinhold 
56794830eb2SIngo Weinhold 	dequeue_loaded_image(image);
5680c0fea5dSIngo Weinhold 	delete_image(image);
5690c0fea5dSIngo Weinhold 	rld_unlock();
5700c0fea5dSIngo Weinhold 	return status;
5710c0fea5dSIngo Weinhold }
5720c0fea5dSIngo Weinhold 
5730c0fea5dSIngo Weinhold 
5740c0fea5dSIngo Weinhold status_t
5750c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
5760c0fea5dSIngo Weinhold {
5770c0fea5dSIngo Weinhold 	image_t *image;
5780c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
5790c0fea5dSIngo Weinhold 
5800c85bd05SIngo Weinhold 	if (handle == NULL && imageID < 0)
5810c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
5820c0fea5dSIngo Weinhold 
5830c85bd05SIngo Weinhold 	if (handle == RLD_GLOBAL_SCOPE)
5840c85bd05SIngo Weinhold 		return B_OK;
5850c85bd05SIngo Weinhold 
5860c0fea5dSIngo Weinhold 	rld_lock();
5870c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
5880c0fea5dSIngo Weinhold 
58994830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
5909a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
5919a6072a3SAxel Dörfler 		update_image_ids();
5929a6072a3SAxel Dörfler 	}
5939a6072a3SAxel Dörfler 
5940c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
5950c0fea5dSIngo Weinhold 
596df30098dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
597df30098dSIngo Weinhold 
5980c85bd05SIngo Weinhold 	if (handle != NULL) {
5990c85bd05SIngo Weinhold 		image = (image_t*)handle;
6000c85bd05SIngo Weinhold 		put_image(image);
601df30098dSIngo Weinhold 		status = B_OK;
6020c85bd05SIngo Weinhold 	} else {
60394830eb2SIngo Weinhold 		image = find_loaded_image_by_id(imageID, true);
60494830eb2SIngo Weinhold 		if (image != NULL) {
6050c0fea5dSIngo Weinhold 			// unload image
6060c0fea5dSIngo Weinhold 			if (type == image->type) {
6070c0fea5dSIngo Weinhold 				put_image(image);
6080c0fea5dSIngo Weinhold 				status = B_OK;
6090c0fea5dSIngo Weinhold 			} else
6100c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
6110c0fea5dSIngo Weinhold 		}
6120c85bd05SIngo Weinhold 	}
6130c0fea5dSIngo Weinhold 
6140c0fea5dSIngo Weinhold 	if (status == B_OK) {
61594830eb2SIngo Weinhold 		while ((image = get_disposable_images().head) != NULL) {
616d64f6189SIngo Weinhold 			// Call the exit hooks that live in this image.
617d64f6189SIngo Weinhold 			// Note: With the Itanium ABI this shouldn't really be done this
618d64f6189SIngo Weinhold 			// way anymore, since global destructors are registered via
619d64f6189SIngo Weinhold 			// __cxa_atexit() (the ones that are registered dynamically) and the
620d64f6189SIngo Weinhold 			// termination routine should call __cxa_finalize() for the image.
621d64f6189SIngo Weinhold 			// The reason why we still do it is that hooks registered with
622d64f6189SIngo Weinhold 			// atexit() aren't associated with the image. We could find out
623d64f6189SIngo Weinhold 			// there which image the hooks lives in and register it
624d64f6189SIngo Weinhold 			// respectively, but since that would be done always, that's
625d64f6189SIngo Weinhold 			// probably more expensive than calling
626d64f6189SIngo Weinhold 			// call_atexit_hooks_for_range() only here, which happens only when
627d64f6189SIngo Weinhold 			// libraries are unloaded dynamically.
6288c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
6298c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
6303be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
6318c2a9d74SMichael Lotz 			}
6328c2a9d74SMichael Lotz 
63310b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
63410b4b5d1SIngo Weinhold 
6350c0fea5dSIngo Weinhold 			if (image->term_routine)
6360c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
6370c0fea5dSIngo Weinhold 
63894830eb2SIngo Weinhold 			dequeue_disposable_image(image);
6390c0fea5dSIngo Weinhold 			unmap_image(image);
6400c0fea5dSIngo Weinhold 
64110b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
64210b4b5d1SIngo Weinhold 
6430c0fea5dSIngo Weinhold 			delete_image(image);
6440c0fea5dSIngo Weinhold 		}
6450c0fea5dSIngo Weinhold 	}
6460c0fea5dSIngo Weinhold 
6470c0fea5dSIngo Weinhold 	rld_unlock();
6480c0fea5dSIngo Weinhold 	return status;
6490c0fea5dSIngo Weinhold }
6500c0fea5dSIngo Weinhold 
6510c0fea5dSIngo Weinhold 
6520c0fea5dSIngo Weinhold status_t
6539a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
6549a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
6550c0fea5dSIngo Weinhold {
6560c0fea5dSIngo Weinhold 	int32 count = 0, j;
6570c0fea5dSIngo Weinhold 	uint32 i;
6580c0fea5dSIngo Weinhold 	image_t *image;
6590c0fea5dSIngo Weinhold 
6600c0fea5dSIngo Weinhold 	rld_lock();
6610c0fea5dSIngo Weinhold 
6620c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
66394830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
6640c0fea5dSIngo Weinhold 	if (image == NULL) {
6650c0fea5dSIngo Weinhold 		rld_unlock();
6660c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
6670c0fea5dSIngo Weinhold 	}
6680c0fea5dSIngo Weinhold 
6690c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
6700c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
6710c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
672e3ac2588SAlex Smith 			elf_sym *symbol = &image->syms[j];
6730c0fea5dSIngo Weinhold 
6740c0fea5dSIngo Weinhold 			if (count == num) {
67510b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
67610b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
67710b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
6780c0fea5dSIngo Weinhold 
67910b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
68010b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
68110b4b5d1SIngo Weinhold 				int32 type;
682e3ac2588SAlex Smith 				if (symbol->Type() == STT_FUNC)
68310b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
684e3ac2588SAlex Smith 				else if (symbol->Type() == STT_OBJECT)
68510b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
6860c0fea5dSIngo Weinhold 				else
68710b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
68810b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
6890c0fea5dSIngo Weinhold 
69010b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
69110b4b5d1SIngo Weinhold 
69210b4b5d1SIngo Weinhold 				if (_type != NULL)
69310b4b5d1SIngo Weinhold 					*_type = type;
6940c0fea5dSIngo Weinhold 				if (_location != NULL)
69510b4b5d1SIngo Weinhold 					*_location = location;
6960c0fea5dSIngo Weinhold 				goto out;
6970c0fea5dSIngo Weinhold 			}
6980c0fea5dSIngo Weinhold 			count++;
6990c0fea5dSIngo Weinhold 		}
7000c0fea5dSIngo Weinhold 	}
7010c0fea5dSIngo Weinhold out:
7020c0fea5dSIngo Weinhold 	rld_unlock();
7030c0fea5dSIngo Weinhold 
7040c0fea5dSIngo Weinhold 	if (num != count)
7050c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
7060c0fea5dSIngo Weinhold 
7070c0fea5dSIngo Weinhold 	return B_OK;
7080c0fea5dSIngo Weinhold }
7090c0fea5dSIngo Weinhold 
7100c0fea5dSIngo Weinhold 
7110c0fea5dSIngo Weinhold status_t
71243e7b1c2SHamish Morrison get_nearest_symbol_at_address(void* address, image_id* _imageID,
71343e7b1c2SHamish Morrison 	char** _imagePath, char** _symbolName, int32* _type, void** _location)
714b6455c08SAxel Dörfler {
715b6455c08SAxel Dörfler 	rld_lock();
716b6455c08SAxel Dörfler 
717b6455c08SAxel Dörfler 	image_t* image = find_loaded_image_by_address((addr_t)address);
718b6455c08SAxel Dörfler 	if (image == NULL) {
719b6455c08SAxel Dörfler 		rld_unlock();
720b6455c08SAxel Dörfler 		return B_BAD_VALUE;
721b6455c08SAxel Dörfler 	}
722b6455c08SAxel Dörfler 
723e3ac2588SAlex Smith 	elf_sym* foundSymbol = NULL;
72443e7b1c2SHamish Morrison 	addr_t foundLocation = (addr_t)NULL;
72543e7b1c2SHamish Morrison 
72643e7b1c2SHamish Morrison 	bool found = false;
72743e7b1c2SHamish Morrison 	for (uint32 i = 0; i < HASHTABSIZE(image) && !found; i++) {
728b6455c08SAxel Dörfler 		for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF;
729b6455c08SAxel Dörfler 				j = HASHCHAINS(image)[j]) {
730e3ac2588SAlex Smith 			elf_sym *symbol = &image->syms[j];
731b6455c08SAxel Dörfler 			addr_t location = symbol->st_value + image->regions[0].delta;
732b6455c08SAxel Dörfler 
73343e7b1c2SHamish Morrison 			if (location <= (addr_t)address	&& location >= foundLocation) {
73443e7b1c2SHamish Morrison 				foundSymbol = symbol;
73543e7b1c2SHamish Morrison 				foundLocation = location;
736b6455c08SAxel Dörfler 
73743e7b1c2SHamish Morrison 				// jump out if we have an exact match
73843e7b1c2SHamish Morrison 				if (foundLocation == (addr_t)address) {
73943e7b1c2SHamish Morrison 					found = true;
74043e7b1c2SHamish Morrison 					break;
74143e7b1c2SHamish Morrison 				}
74243e7b1c2SHamish Morrison 			}
74343e7b1c2SHamish Morrison 		}
74443e7b1c2SHamish Morrison 	}
745b6455c08SAxel Dörfler 
746b6455c08SAxel Dörfler 	if (_imageID != NULL)
747b6455c08SAxel Dörfler 		*_imageID = image->id;
74843e7b1c2SHamish Morrison 	if (_imagePath != NULL)
74943e7b1c2SHamish Morrison 		*_imagePath = image->path;
75043e7b1c2SHamish Morrison 
75143e7b1c2SHamish Morrison 	if (foundSymbol != NULL) {
75243e7b1c2SHamish Morrison 		*_symbolName = SYMNAME(image, foundSymbol);
75343e7b1c2SHamish Morrison 
75443e7b1c2SHamish Morrison 		if (_type != NULL) {
755e3ac2588SAlex Smith 			if (foundSymbol->Type() == STT_FUNC)
75643e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_TEXT;
757e3ac2588SAlex Smith 			else if (foundSymbol->Type() == STT_OBJECT)
75843e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_DATA;
75943e7b1c2SHamish Morrison 			else
76043e7b1c2SHamish Morrison 				*_type = B_SYMBOL_TYPE_ANY;
76143e7b1c2SHamish Morrison 			// TODO: check with the return types of that BeOS function
76243e7b1c2SHamish Morrison 		}
76343e7b1c2SHamish Morrison 
764b6455c08SAxel Dörfler 		if (_location != NULL)
76543e7b1c2SHamish Morrison 			*_location = (void*)foundLocation;
76643e7b1c2SHamish Morrison 	} else {
76743e7b1c2SHamish Morrison 		*_symbolName = NULL;
76843e7b1c2SHamish Morrison 		if (_location != NULL)
76943e7b1c2SHamish Morrison 			*_location = NULL;
77043e7b1c2SHamish Morrison 	}
771b6455c08SAxel Dörfler 
772b6455c08SAxel Dörfler 	rld_unlock();
773b6455c08SAxel Dörfler 	return B_OK;
774b6455c08SAxel Dörfler }
775b6455c08SAxel Dörfler 
776b6455c08SAxel Dörfler 
777b6455c08SAxel Dörfler status_t
7789a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
77980ece785SIngo Weinhold 	bool recursive, image_id *_inImage, void **_location)
7800c0fea5dSIngo Weinhold {
7810c0fea5dSIngo Weinhold 	status_t status = B_OK;
7820c0fea5dSIngo Weinhold 	image_t *image;
7830c0fea5dSIngo Weinhold 
7840c0fea5dSIngo Weinhold 	if (imageID < B_OK)
7850c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
7860c0fea5dSIngo Weinhold 	if (symbolName == NULL)
7870c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
7880c0fea5dSIngo Weinhold 
7890c0fea5dSIngo Weinhold 	rld_lock();
7900c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
7910c0fea5dSIngo Weinhold 
7920c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
79394830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
79480ece785SIngo Weinhold 	if (image != NULL) {
79580ece785SIngo Weinhold 		if (recursive) {
79680ece785SIngo Weinhold 			// breadth-first search in the given image and its dependencies
797003ebb0eSIngo Weinhold 			status = find_symbol_breadth_first(image,
798003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
799003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
80080ece785SIngo Weinhold 				&image, _location);
801003ebb0eSIngo Weinhold 		} else {
802003ebb0eSIngo Weinhold 			status = find_symbol(image,
803003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
804003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
805003ebb0eSIngo Weinhold 				_location);
806003ebb0eSIngo Weinhold 		}
80780ece785SIngo Weinhold 
80880ece785SIngo Weinhold 		if (status == B_OK && _inImage != NULL)
80980ece785SIngo Weinhold 			*_inImage = image->id;
81080ece785SIngo Weinhold 	} else
8110c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
8120c0fea5dSIngo Weinhold 
8130c0fea5dSIngo Weinhold 	rld_unlock();
8140c0fea5dSIngo Weinhold 	return status;
8150c0fea5dSIngo Weinhold }
8160c0fea5dSIngo Weinhold 
8170c0fea5dSIngo Weinhold 
8180c0fea5dSIngo Weinhold status_t
8190c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
8200c85bd05SIngo Weinhold 	void **_location)
8210c85bd05SIngo Weinhold {
8220c85bd05SIngo Weinhold 	status_t status = B_ENTRY_NOT_FOUND;
8230c85bd05SIngo Weinhold 
8240c85bd05SIngo Weinhold 	if (symbolName == NULL)
8250c85bd05SIngo Weinhold 		return B_BAD_VALUE;
8260c85bd05SIngo Weinhold 
8270c85bd05SIngo Weinhold 	rld_lock();
8280c85bd05SIngo Weinhold 		// for now, just do stupid simple global locking
8290c85bd05SIngo Weinhold 
8300c85bd05SIngo Weinhold 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
8310c85bd05SIngo Weinhold 		// look in the default scope
8320c85bd05SIngo Weinhold 		image_t* image;
833e3ac2588SAlex Smith 		elf_sym* symbol = find_undefined_symbol_global(gProgramImage,
83494830eb2SIngo Weinhold 			gProgramImage,
835003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
836003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
837003ebb0eSIngo Weinhold 			&image);
8380c85bd05SIngo Weinhold 		if (symbol != NULL) {
8390c85bd05SIngo Weinhold 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
840e3ac2588SAlex Smith 			int32 symbolType = symbol->Type() == STT_FUNC
8410c85bd05SIngo Weinhold 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
8420c85bd05SIngo Weinhold 			patch_defined_symbol(image, symbolName, _location, &symbolType);
8430c85bd05SIngo Weinhold 			status = B_OK;
8440c85bd05SIngo Weinhold 		}
8450c85bd05SIngo Weinhold 	} else if (handle == RTLD_NEXT) {
8460c85bd05SIngo Weinhold 		// Look in the default scope, but also in the dependencies of the
8470c85bd05SIngo Weinhold 		// calling image. Return the next after the caller symbol.
8480c85bd05SIngo Weinhold 
849a2dad9e1SIngo Weinhold 		// First of all, find the caller image.
85094830eb2SIngo Weinhold 		image_t* callerImage = get_loaded_images().head;
8510c85bd05SIngo Weinhold 		for (; callerImage != NULL; callerImage = callerImage->next) {
8520c85bd05SIngo Weinhold 			elf_region_t& text = callerImage->regions[0];
853a2dad9e1SIngo Weinhold 			if ((addr_t)caller >= text.vmstart
854a2dad9e1SIngo Weinhold 				&& (addr_t)caller < text.vmstart + text.vmsize) {
855a2dad9e1SIngo Weinhold 				// found the image
8560c85bd05SIngo Weinhold 				break;
8570c85bd05SIngo Weinhold 			}
8580c85bd05SIngo Weinhold 		}
8590c85bd05SIngo Weinhold 
860a2dad9e1SIngo Weinhold 		if (callerImage != NULL) {
8610c85bd05SIngo Weinhold 			// found the caller -- now search the global scope until we find
8620c85bd05SIngo Weinhold 			// the next symbol
863a2dad9e1SIngo Weinhold 			bool hitCallerImage = false;
8640c85bd05SIngo Weinhold 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
8650c85bd05SIngo Weinhold 
866e3ac2588SAlex Smith 			elf_sym* candidateSymbol = NULL;
86725dc253dSIngo Weinhold 			image_t* candidateImage = NULL;
86825dc253dSIngo Weinhold 
86994830eb2SIngo Weinhold 			image_t* image = get_loaded_images().head;
8700c85bd05SIngo Weinhold 			for (; image != NULL; image = image->next) {
871a2dad9e1SIngo Weinhold 				// skip the caller image
872a2dad9e1SIngo Weinhold 				if (image == callerImage) {
873a2dad9e1SIngo Weinhold 					hitCallerImage = true;
874a2dad9e1SIngo Weinhold 					continue;
875a2dad9e1SIngo Weinhold 				}
876a2dad9e1SIngo Weinhold 
877a2dad9e1SIngo Weinhold 				// skip all images up to the caller image; also skip add-on
878a2dad9e1SIngo Weinhold 				// images and those not marked above for resolution
879a2dad9e1SIngo Weinhold 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
8800c85bd05SIngo Weinhold 					|| (image->flags
881a2dad9e1SIngo Weinhold 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
8820c85bd05SIngo Weinhold 					continue;
8830c85bd05SIngo Weinhold 				}
8840c85bd05SIngo Weinhold 
885e3ac2588SAlex Smith 				elf_sym *symbol = find_symbol(image,
886003ebb0eSIngo Weinhold 					SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
887003ebb0eSIngo Weinhold 						LOOKUP_FLAG_DEFAULT_VERSION));
8880c85bd05SIngo Weinhold 				if (symbol == NULL)
8890c85bd05SIngo Weinhold 					continue;
8900c85bd05SIngo Weinhold 
89125dc253dSIngo Weinhold 				// found a symbol
892e3ac2588SAlex Smith 				bool isWeak = symbol->Bind() == STB_WEAK;
89325dc253dSIngo Weinhold 				if (candidateImage == NULL || !isWeak) {
89425dc253dSIngo Weinhold 					candidateSymbol = symbol;
89525dc253dSIngo Weinhold 					candidateImage = image;
89625dc253dSIngo Weinhold 
89725dc253dSIngo Weinhold 					if (!isWeak)
89825dc253dSIngo Weinhold 						break;
89925dc253dSIngo Weinhold 				}
90025dc253dSIngo Weinhold 
90125dc253dSIngo Weinhold 				// symbol is weak, so we need to continue
90225dc253dSIngo Weinhold 			}
90325dc253dSIngo Weinhold 
90425dc253dSIngo Weinhold 			if (candidateSymbol != NULL) {
905a2dad9e1SIngo Weinhold 				// found the symbol
90625dc253dSIngo Weinhold 				*_location = (void*)(candidateSymbol->st_value
90725dc253dSIngo Weinhold 					+ candidateImage->regions[0].delta);
9080c85bd05SIngo Weinhold 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
90925dc253dSIngo Weinhold 				patch_defined_symbol(candidateImage, symbolName, _location,
9100c85bd05SIngo Weinhold 					&symbolType);
9110c85bd05SIngo Weinhold 				status = B_OK;
9120c85bd05SIngo Weinhold 			}
9130c85bd05SIngo Weinhold 
9140c85bd05SIngo Weinhold 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
9150c85bd05SIngo Weinhold 		}
9160c85bd05SIngo Weinhold 	} else {
9170c85bd05SIngo Weinhold 		// breadth-first search in the given image and its dependencies
9180c85bd05SIngo Weinhold 		image_t* inImage;
919003ebb0eSIngo Weinhold 		status = find_symbol_breadth_first((image_t*)handle,
920003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
921003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
922003ebb0eSIngo Weinhold 			&inImage, _location);
9230c85bd05SIngo Weinhold 	}
9240c85bd05SIngo Weinhold 
9250c85bd05SIngo Weinhold 	rld_unlock();
9260c85bd05SIngo Weinhold 	return status;
9270c85bd05SIngo Weinhold }
9280c85bd05SIngo Weinhold 
9290c85bd05SIngo Weinhold 
9300c85bd05SIngo Weinhold status_t
9310c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
9320c0fea5dSIngo Weinhold {
9330c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
934e3ac2588SAlex Smith 	elf_dyn *dynamicSection;
9350c0fea5dSIngo Weinhold 	image_t *image;
9360c0fea5dSIngo Weinhold 
9370c0fea5dSIngo Weinhold 	if (_name == NULL)
9380c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
9390c0fea5dSIngo Weinhold 
9400c0fea5dSIngo Weinhold 	rld_lock();
9410c0fea5dSIngo Weinhold 
94294830eb2SIngo Weinhold 	image = find_loaded_image_by_id(id, false);
9430c0fea5dSIngo Weinhold 	if (image == NULL) {
9440c0fea5dSIngo Weinhold 		rld_unlock();
9450c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
9460c0fea5dSIngo Weinhold 	}
9470c0fea5dSIngo Weinhold 
948e3ac2588SAlex Smith 	dynamicSection = (elf_dyn *)image->dynamic_ptr;
9490c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
9500c0fea5dSIngo Weinhold 		rld_unlock();
9510c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
9520c0fea5dSIngo Weinhold 	}
9530c0fea5dSIngo Weinhold 
9540c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
9550c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
9560c0fea5dSIngo Weinhold 			continue;
9570c0fea5dSIngo Weinhold 
9580c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
9590c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
9600c0fea5dSIngo Weinhold 
9610c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
9620c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
9630c0fea5dSIngo Weinhold 			rld_unlock();
9640c0fea5dSIngo Weinhold 			return B_OK;
9650c0fea5dSIngo Weinhold 		}
9660c0fea5dSIngo Weinhold 	}
9670c0fea5dSIngo Weinhold 
9680c0fea5dSIngo Weinhold 	rld_unlock();
9690c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
9700c0fea5dSIngo Weinhold }
9710c0fea5dSIngo Weinhold 
9720c0fea5dSIngo Weinhold 
97374c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
9740c0fea5dSIngo Weinhold 
9750c0fea5dSIngo Weinhold 
9769a6072a3SAxel Dörfler /*! Read and verify the ELF header */
9770c0fea5dSIngo Weinhold status_t
978e3ac2588SAlex Smith elf_verify_header(void *header, size_t length)
9790c0fea5dSIngo Weinhold {
9800c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
9810c0fea5dSIngo Weinhold 
982e3ac2588SAlex Smith 	if (length < sizeof(elf_ehdr))
9830c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
9840c0fea5dSIngo Weinhold 
985e3ac2588SAlex Smith 	return parse_elf_header((elf_ehdr *)header, &programSize, &sectionSize);
9860c0fea5dSIngo Weinhold }
9870c0fea5dSIngo Weinhold 
9880c0fea5dSIngo Weinhold 
9890c0fea5dSIngo Weinhold void
9900c0fea5dSIngo Weinhold terminate_program(void)
9910c0fea5dSIngo Weinhold {
9920c0fea5dSIngo Weinhold 	image_t **termList;
9930c0fea5dSIngo Weinhold 	ssize_t count, i;
9940c0fea5dSIngo Weinhold 
995aa3507feSIngo Weinhold 	count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED);
9960c0fea5dSIngo Weinhold 	if (count < B_OK)
9970c0fea5dSIngo Weinhold 		return;
9980c0fea5dSIngo Weinhold 
99994830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
10009a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
10019a6072a3SAxel Dörfler 		update_image_ids();
10029a6072a3SAxel Dörfler 	}
10039a6072a3SAxel Dörfler 
10040c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
10050c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
10060c0fea5dSIngo Weinhold 		image_t *image = termList[i];
10070c0fea5dSIngo Weinhold 
10080c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
10090c0fea5dSIngo Weinhold 
101010b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
101110b4b5d1SIngo Weinhold 
10120c0fea5dSIngo Weinhold 		if (image->term_routine)
10130c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
101410b4b5d1SIngo Weinhold 
101510b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
10160c0fea5dSIngo Weinhold 	}
10170c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
10180c0fea5dSIngo Weinhold 
10190c0fea5dSIngo Weinhold 	free(termList);
10200c0fea5dSIngo Weinhold }
10210c0fea5dSIngo Weinhold 
10220c0fea5dSIngo Weinhold 
10230c0fea5dSIngo Weinhold void
10240c0fea5dSIngo Weinhold rldelf_init(void)
10250c0fea5dSIngo Weinhold {
102694830eb2SIngo Weinhold 	init_add_ons();
102794830eb2SIngo Weinhold 
10280c0fea5dSIngo Weinhold 	// create the debug area
10290c0fea5dSIngo Weinhold 	{
1030e3ac2588SAlex Smith 		size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
10310c0fea5dSIngo Weinhold 
10320c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
10330c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
1034*9f3bd497SPawel Dziepak 			(void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK,
10350c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
10360c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
10370c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
10380c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
10390c0fea5dSIngo Weinhold 		}
10400c0fea5dSIngo Weinhold 
104194830eb2SIngo Weinhold 		area->loaded_images = &get_loaded_images();
10420c0fea5dSIngo Weinhold 	}
104374c0424aSAxel Dörfler 
104474c0424aSAxel Dörfler 	// initialize error message if needed
10454bef3723SAxel Dörfler 	if (report_errors()) {
104674c0424aSAxel Dörfler 		void *buffer = malloc(1024);
104774c0424aSAxel Dörfler 		if (buffer == NULL)
104874c0424aSAxel Dörfler 			return;
104974c0424aSAxel Dörfler 
105094830eb2SIngo Weinhold 		gErrorMessage.SetTo(buffer, 1024, 'Rler');
105174c0424aSAxel Dörfler 	}
10520c0fea5dSIngo Weinhold }
10531873b4b3SIngo Weinhold 
10541873b4b3SIngo Weinhold 
10551873b4b3SIngo Weinhold status_t
10569a6072a3SAxel Dörfler elf_reinit_after_fork(void)
10571873b4b3SIngo Weinhold {
1058f7127458SIngo Weinhold 	recursive_lock_init(&sLock, kLockName);
10591873b4b3SIngo Weinhold 
10609a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
1061cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
1062cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
10639a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
106494830eb2SIngo Weinhold 	gInvalidImageIDs = true;
1065cbc456deSIngo Weinhold 
10661873b4b3SIngo Weinhold 	return B_OK;
10671873b4b3SIngo Weinhold }
1068