xref: /haiku/src/system/runtime_loader/elf.cpp (revision 94830eb226ce51bd1fd0143bad2538f788883e85)
10c0fea5dSIngo Weinhold /*
2593ee7bbSIngo Weinhold  * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
312a5e9a4SAxel Dörfler  * Copyright 2003-2008, 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 <elf32.h>
227486b72dSIngo Weinhold #include <syscalls.h>
2310b4b5d1SIngo Weinhold #include <util/kernel_cpp.h>
247486b72dSIngo Weinhold 
25*94830eb2SIngo Weinhold #include "add_ons.h"
26*94830eb2SIngo Weinhold #include "elf_load_image.h"
27*94830eb2SIngo Weinhold #include "elf_symbol_lookup.h"
28*94830eb2SIngo Weinhold #include "elf_versioning.h"
29*94830eb2SIngo Weinhold #include "errors.h"
30*94830eb2SIngo Weinhold #include "images.h"
310c0fea5dSIngo Weinhold 
320c0fea5dSIngo Weinhold 
3310b4b5d1SIngo Weinhold // TODO: implement better locking strategy
3410b4b5d1SIngo Weinhold // TODO: implement lazy binding
350c0fea5dSIngo Weinhold 
360c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen())
370c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE	((void*)-2l)
380c85bd05SIngo Weinhold 
390c0fea5dSIngo Weinhold 
400c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
410c0fea5dSIngo Weinhold 
42*94830eb2SIngo Weinhold bool gProgramLoaded = false;
43*94830eb2SIngo Weinhold image_t* gProgramImage;
44003ebb0eSIngo Weinhold 
45ca618b22SIngo Weinhold static image_t** sPreloadedImages = NULL;
46ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0;
470c0fea5dSIngo Weinhold 
480c0fea5dSIngo Weinhold // a recursive lock
49e73923b0SAxel Dörfler static sem_id sSem;
50e73923b0SAxel Dörfler static thread_id sSemOwner;
51e73923b0SAxel Dörfler static int32 sSemCount;
520c0fea5dSIngo Weinhold 
537486b72dSIngo Weinhold 
540c0fea5dSIngo Weinhold static void
550c0fea5dSIngo Weinhold rld_unlock()
560c0fea5dSIngo Weinhold {
57e73923b0SAxel Dörfler 	if (sSemCount-- == 1) {
58e73923b0SAxel Dörfler 		sSemOwner = -1;
59e73923b0SAxel Dörfler 		release_sem(sSem);
600c0fea5dSIngo Weinhold 	}
610c0fea5dSIngo Weinhold }
620c0fea5dSIngo Weinhold 
630c0fea5dSIngo Weinhold 
640c0fea5dSIngo Weinhold static void
650c0fea5dSIngo Weinhold rld_lock()
660c0fea5dSIngo Weinhold {
670c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
68e73923b0SAxel Dörfler 	if (self != sSemOwner) {
69e73923b0SAxel Dörfler 		acquire_sem(sSem);
70e73923b0SAxel Dörfler 		sSemOwner = self;
710c0fea5dSIngo Weinhold 	}
72e73923b0SAxel Dörfler 	sSemCount++;
730c0fea5dSIngo Weinhold }
740c0fea5dSIngo Weinhold 
750c0fea5dSIngo Weinhold 
760c0fea5dSIngo Weinhold static const char *
770c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
780c0fea5dSIngo Weinhold {
790c0fea5dSIngo Weinhold 	int i;
800c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
810c0fea5dSIngo Weinhold 
820c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
830c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
840c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
850c0fea5dSIngo Weinhold 	}
860c0fea5dSIngo Weinhold 
870c0fea5dSIngo Weinhold 	return NULL;
880c0fea5dSIngo Weinhold }
890c0fea5dSIngo Weinhold 
900c0fea5dSIngo Weinhold 
910c0fea5dSIngo Weinhold static status_t
920c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image)
930c0fea5dSIngo Weinhold {
940c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
954bef3723SAxel Dörfler 	bool reportErrors = report_errors();
9674c0424aSAxel Dörfler 	status_t status = B_OK;
970c0fea5dSIngo Weinhold 	uint32 i, j;
980c0fea5dSIngo Weinhold 	const char *rpath;
990c0fea5dSIngo Weinhold 
1000c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
1010c0fea5dSIngo Weinhold 		return B_OK;
1020c0fea5dSIngo Weinhold 
1030c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
1040c0fea5dSIngo Weinhold 
1050c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
1060c0fea5dSIngo Weinhold 		return B_OK;
1070c0fea5dSIngo Weinhold 
1087486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
1097486b72dSIngo Weinhold 		image->id);
1107486b72dSIngo Weinhold 
1110c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
1120c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
1130c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
1147486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
1157486b72dSIngo Weinhold 			image->name, image->id);
1160c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
1170c0fea5dSIngo Weinhold 	}
1180c0fea5dSIngo Weinhold 
1190c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
1200c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
1210c0fea5dSIngo Weinhold 
1220c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
1230c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
1240c0fea5dSIngo Weinhold 			case DT_NEEDED:
12574c0424aSAxel Dörfler 			{
12674c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
12774c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
1280c0fea5dSIngo Weinhold 
129*94830eb2SIngo Weinhold 				status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
13074c0424aSAxel Dörfler 					rpath, &image->needed[j]);
13174c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
13274c0424aSAxel Dörfler 					status = loadStatus;
13374c0424aSAxel Dörfler 					// correct error code in case the file could not been found
13474c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
13574c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
13674c0424aSAxel Dörfler 
13774c0424aSAxel Dörfler 						if (reportErrors)
138*94830eb2SIngo Weinhold 							gErrorMessage.AddString("missing library", name);
13974c0424aSAxel Dörfler 					}
14074c0424aSAxel Dörfler 
14174c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
1427486b72dSIngo Weinhold 					if (!reportErrors) {
1437486b72dSIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
1447486b72dSIngo Weinhold 							"failed: %s", image->name, image->id,
1457486b72dSIngo Weinhold 							strerror(status));
1460c0fea5dSIngo Weinhold 						return status;
14774c0424aSAxel Dörfler 					}
1487486b72dSIngo Weinhold 				}
1490c0fea5dSIngo Weinhold 
1500c0fea5dSIngo Weinhold 				j += 1;
1510c0fea5dSIngo Weinhold 				break;
15274c0424aSAxel Dörfler 			}
1530c0fea5dSIngo Weinhold 
1540c0fea5dSIngo Weinhold 			default:
1550c0fea5dSIngo Weinhold 				// ignore any other tag
1560c0fea5dSIngo Weinhold 				continue;
1570c0fea5dSIngo Weinhold 		}
1580c0fea5dSIngo Weinhold 	}
1590c0fea5dSIngo Weinhold 
1607486b72dSIngo Weinhold 	if (status < B_OK) {
1617486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
1627486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
1637486b72dSIngo Weinhold 			strerror(status));
16474c0424aSAxel Dörfler 		return status;
1657486b72dSIngo Weinhold 	}
16674c0424aSAxel Dörfler 
1670c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
1680c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
1697486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
1707486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
1710c0fea5dSIngo Weinhold 		return B_ERROR;
1720c0fea5dSIngo Weinhold 	}
1730c0fea5dSIngo Weinhold 
1747486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
1757486b72dSIngo Weinhold 		image->id);
1767486b72dSIngo Weinhold 
1770c0fea5dSIngo Weinhold 	return B_OK;
1780c0fea5dSIngo Weinhold }
1790c0fea5dSIngo Weinhold 
1800c0fea5dSIngo Weinhold 
1810c85bd05SIngo Weinhold static status_t
1820c85bd05SIngo Weinhold load_dependencies(image_t* image)
1830c85bd05SIngo Weinhold {
184003ebb0eSIngo Weinhold 	// load dependencies (breadth-first)
1850c85bd05SIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
1860c85bd05SIngo Weinhold 			otherImage = otherImage->next) {
1870c85bd05SIngo Weinhold 		status_t status = load_immediate_dependencies(otherImage);
1880c85bd05SIngo Weinhold 		if (status != B_OK)
1890c85bd05SIngo Weinhold 			return status;
1900c85bd05SIngo Weinhold 	}
1910c85bd05SIngo Weinhold 
192003ebb0eSIngo Weinhold 	// Check the needed versions for the given image and all newly loaded
193003ebb0eSIngo Weinhold 	// dependencies.
194003ebb0eSIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
195003ebb0eSIngo Weinhold 			otherImage = otherImage->next) {
196003ebb0eSIngo Weinhold 		status_t status = check_needed_image_versions(otherImage);
197003ebb0eSIngo Weinhold 		if (status != B_OK)
198003ebb0eSIngo Weinhold 			return status;
199003ebb0eSIngo Weinhold 	}
200003ebb0eSIngo Weinhold 
2010c85bd05SIngo Weinhold 	return B_OK;
2020c85bd05SIngo Weinhold }
2030c85bd05SIngo Weinhold 
2040c85bd05SIngo Weinhold 
205*94830eb2SIngo Weinhold static status_t
206*94830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
2070c0fea5dSIngo Weinhold {
208*94830eb2SIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image);
209*94830eb2SIngo Weinhold 	if (status < B_OK) {
210*94830eb2SIngo Weinhold 		FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status,
211*94830eb2SIngo Weinhold 			image->path, image->name);
212*94830eb2SIngo Weinhold 		return status;
2130c0fea5dSIngo Weinhold 	}
2140c0fea5dSIngo Weinhold 
215*94830eb2SIngo Weinhold 	_kern_image_relocated(image->id);
216*94830eb2SIngo Weinhold 	image_event(image, IMAGE_EVENT_RELOCATED);
217*94830eb2SIngo Weinhold 	return B_OK;
2180c0fea5dSIngo Weinhold }
2190c0fea5dSIngo Weinhold 
2200c0fea5dSIngo Weinhold 
2210c0fea5dSIngo Weinhold static status_t
2220c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
2230c0fea5dSIngo Weinhold {
224ca618b22SIngo Weinhold 	// get the images that still have to be relocated
225ca618b22SIngo Weinhold 	image_t **list;
226ca618b22SIngo Weinhold 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
2270c0fea5dSIngo Weinhold 	if (count < B_OK)
2280c0fea5dSIngo Weinhold 		return count;
2290c0fea5dSIngo Weinhold 
2300c85bd05SIngo Weinhold 	// relocate
231ca618b22SIngo Weinhold 	for (ssize_t i = 0; i < count; i++) {
23246f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
2330c85bd05SIngo Weinhold 		if (status < B_OK) {
2340c85bd05SIngo Weinhold 			free(list);
2350c0fea5dSIngo Weinhold 			return status;
2360c0fea5dSIngo Weinhold 		}
2370c85bd05SIngo Weinhold 	}
2380c0fea5dSIngo Weinhold 
2390c0fea5dSIngo Weinhold 	free(list);
2400c0fea5dSIngo Weinhold 	return B_OK;
2410c0fea5dSIngo Weinhold }
2420c0fea5dSIngo Weinhold 
2430c0fea5dSIngo Weinhold 
2440c0fea5dSIngo Weinhold static void
2450c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
2460c0fea5dSIngo Weinhold {
2470c0fea5dSIngo Weinhold 	image_t **initList;
2480c0fea5dSIngo Weinhold 	ssize_t count, i;
2490c0fea5dSIngo Weinhold 
2500c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
2510c0fea5dSIngo Weinhold 	if (count <= 0)
2520c0fea5dSIngo Weinhold 		return;
2530c0fea5dSIngo Weinhold 
2540c0fea5dSIngo Weinhold 	if (!initHead) {
2550c0fea5dSIngo Weinhold 		// this removes the "calling" image
2560c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
2570c0fea5dSIngo Weinhold 		initList[--count] = NULL;
2580c0fea5dSIngo Weinhold 	}
2590c0fea5dSIngo Weinhold 
2600c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
2610c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
2620c0fea5dSIngo Weinhold 		image = initList[i];
2630c0fea5dSIngo Weinhold 
2640c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
2650c0fea5dSIngo Weinhold 
266dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
2670c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
26810b4b5d1SIngo Weinhold 
26910b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
2700c0fea5dSIngo Weinhold 	}
2710c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
2720c0fea5dSIngo Weinhold 
2730c0fea5dSIngo Weinhold 	free(initList);
2740c0fea5dSIngo Weinhold }
2750c0fea5dSIngo Weinhold 
2760c0fea5dSIngo Weinhold 
2770c0fea5dSIngo Weinhold static void
278ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
279ca618b22SIngo Weinhold {
280ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
281ca618b22SIngo Weinhold 	// API.
282ca618b22SIngo Weinhold 	image_t* image;
2830c85bd05SIngo Weinhold 	void* _export;
284003ebb0eSIngo Weinhold 	if (find_symbol_breadth_first(rootImage,
285003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
286003ebb0eSIngo Weinhold 			&_export) == B_OK) {
2870c85bd05SIngo Weinhold 		*(void**)_export = &gRuntimeLoader;
288ca618b22SIngo Weinhold 	}
289ca618b22SIngo Weinhold }
290ca618b22SIngo Weinhold 
291ca618b22SIngo Weinhold 
292ca618b22SIngo Weinhold static status_t
293ca618b22SIngo Weinhold add_preloaded_image(image_t* image)
294ca618b22SIngo Weinhold {
295ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
296ca618b22SIngo Weinhold 	// small number of preloaded images.
297ca618b22SIngo Weinhold 	image_t** newArray = (image_t**)realloc(sPreloadedImages,
298ca618b22SIngo Weinhold 		sizeof(image_t*) * (sPreloadedImageCount + 1));
299ca618b22SIngo Weinhold 	if (newArray == NULL)
300ca618b22SIngo Weinhold 		return B_NO_MEMORY;
301ca618b22SIngo Weinhold 
302ca618b22SIngo Weinhold 	sPreloadedImages = newArray;
303ca618b22SIngo Weinhold 	newArray[sPreloadedImageCount++] = image;
304ca618b22SIngo Weinhold 
305ca618b22SIngo Weinhold 	return B_OK;
306ca618b22SIngo Weinhold }
307ca618b22SIngo Weinhold 
308ca618b22SIngo Weinhold 
309ca618b22SIngo Weinhold image_id
310ca618b22SIngo Weinhold preload_image(char const* path)
311ca618b22SIngo Weinhold {
312ca618b22SIngo Weinhold 	if (path == NULL)
313ca618b22SIngo Weinhold 		return B_BAD_VALUE;
314ca618b22SIngo Weinhold 
315ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\")", path);
316ca618b22SIngo Weinhold 
317ca618b22SIngo Weinhold 	image_t *image = NULL;
318*94830eb2SIngo Weinhold 	status_t status = load_image(path, B_ADD_ON_IMAGE, NULL, &image);
319ca618b22SIngo Weinhold 	if (status < B_OK) {
320ca618b22SIngo Weinhold 		rld_unlock();
321ca618b22SIngo Weinhold 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
322ca618b22SIngo Weinhold 			strerror(status));
323ca618b22SIngo Weinhold 		return status;
324ca618b22SIngo Weinhold 	}
325ca618b22SIngo Weinhold 
3260c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL)
3270c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_global;
3280c85bd05SIngo Weinhold 
3290c85bd05SIngo Weinhold 	status = load_dependencies(image);
330ca618b22SIngo Weinhold 	if (status < B_OK)
331ca618b22SIngo Weinhold 		goto err;
3320c85bd05SIngo Weinhold 
3330c85bd05SIngo Weinhold 	set_image_flags_recursively(image, RTLD_GLOBAL);
334ca618b22SIngo Weinhold 
335ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
336ca618b22SIngo Weinhold 	if (status < B_OK)
337ca618b22SIngo Weinhold 		goto err;
338ca618b22SIngo Weinhold 
339ca618b22SIngo Weinhold 	status = add_preloaded_image(image);
340ca618b22SIngo Weinhold 	if (status < B_OK)
341ca618b22SIngo Weinhold 		goto err;
342ca618b22SIngo Weinhold 
343ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
344ca618b22SIngo Weinhold 
345ca618b22SIngo Weinhold 	remap_images();
346ca618b22SIngo Weinhold 	init_dependencies(image, true);
347ca618b22SIngo Weinhold 
34810b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
34910b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
350003ebb0eSIngo Weinhold 	if (find_symbol(image,
351003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
35210b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
353*94830eb2SIngo Weinhold 		add_add_on(image, addOnStruct);
35410b4b5d1SIngo Weinhold 	}
35510b4b5d1SIngo Weinhold 
356ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id);
357ca618b22SIngo Weinhold 
358ca618b22SIngo Weinhold 	return image->id;
359ca618b22SIngo Weinhold 
360ca618b22SIngo Weinhold err:
361ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status));
362ca618b22SIngo Weinhold 
363*94830eb2SIngo Weinhold 	dequeue_loaded_image(image);
364ca618b22SIngo Weinhold 	delete_image(image);
365ca618b22SIngo Weinhold 	return status;
366ca618b22SIngo Weinhold }
367ca618b22SIngo Weinhold 
368ca618b22SIngo Weinhold 
369ca618b22SIngo Weinhold static void
370ca618b22SIngo Weinhold preload_images()
371ca618b22SIngo Weinhold {
372ca618b22SIngo Weinhold 	const char* imagePaths = getenv("LD_PRELOAD");
373ca618b22SIngo Weinhold 	if (imagePaths == NULL)
374ca618b22SIngo Weinhold 		return;
375ca618b22SIngo Weinhold 
376ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
377ca618b22SIngo Weinhold 		// find begin of image path
378ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
379ca618b22SIngo Weinhold 			imagePaths++;
380ca618b22SIngo Weinhold 
381ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
382ca618b22SIngo Weinhold 			break;
383ca618b22SIngo Weinhold 
384ca618b22SIngo Weinhold 		// find end of image path
385ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
386ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
387ca618b22SIngo Weinhold 			imagePaths++;
388ca618b22SIngo Weinhold 
389ca618b22SIngo Weinhold 		// extract the path
390ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
391ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
392ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
393ca618b22SIngo Weinhold 			continue;
394ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
395ca618b22SIngo Weinhold 		path[pathLen] = '\0';
396ca618b22SIngo Weinhold 
397ca618b22SIngo Weinhold 		// load the image
398ca618b22SIngo Weinhold 		preload_image(path);
399ca618b22SIngo Weinhold 	}
400ca618b22SIngo Weinhold }
401ca618b22SIngo Weinhold 
402ca618b22SIngo Weinhold 
40374c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
4040c0fea5dSIngo Weinhold 
4050c0fea5dSIngo Weinhold 
4060c0fea5dSIngo Weinhold image_id
4070c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
4080c0fea5dSIngo Weinhold {
4090c0fea5dSIngo Weinhold 	status_t status;
4100c0fea5dSIngo Weinhold 	image_t *image;
4110c0fea5dSIngo Weinhold 
4127486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
4137486b72dSIngo Weinhold 
4140c0fea5dSIngo Weinhold 	rld_lock();
4150c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
4160c0fea5dSIngo Weinhold 
417ca618b22SIngo Weinhold 	preload_images();
418ca618b22SIngo Weinhold 
4190c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
4200c0fea5dSIngo Weinhold 
421*94830eb2SIngo Weinhold 	status = load_image(path, B_APP_IMAGE, NULL, &gProgramImage);
42274c0424aSAxel Dörfler 	if (status < B_OK)
42374c0424aSAxel Dörfler 		goto err;
4240c0fea5dSIngo Weinhold 
425*94830eb2SIngo Weinhold 	if (gProgramImage->find_undefined_symbol == NULL)
426*94830eb2SIngo Weinhold 		gProgramImage->find_undefined_symbol = find_undefined_symbol_global;
4270c85bd05SIngo Weinhold 
428*94830eb2SIngo Weinhold 	status = load_dependencies(gProgramImage);
4290c0fea5dSIngo Weinhold 	if (status < B_OK)
4300c0fea5dSIngo Weinhold 		goto err;
4310c85bd05SIngo Weinhold 
43247bc6663SIngo Weinhold 	// Set RTLD_GLOBAL on all libraries including the program.
4330c85bd05SIngo Weinhold 	// This results in the desired symbol resolution for dlopen()ed libraries.
434*94830eb2SIngo Weinhold 	set_image_flags_recursively(gProgramImage, RTLD_GLOBAL);
4350c0fea5dSIngo Weinhold 
436*94830eb2SIngo Weinhold 	status = relocate_dependencies(gProgramImage);
4370c0fea5dSIngo Weinhold 	if (status < B_OK)
4380c0fea5dSIngo Weinhold 		goto err;
4390c0fea5dSIngo Weinhold 
440*94830eb2SIngo Weinhold 	inject_runtime_loader_api(gProgramImage);
4410c0fea5dSIngo Weinhold 
4420c0fea5dSIngo Weinhold 	remap_images();
443*94830eb2SIngo Weinhold 	init_dependencies(gProgramImage, true);
4440c0fea5dSIngo Weinhold 
4450c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
4460c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
447*94830eb2SIngo Weinhold 	find_symbol_breadth_first(gProgramImage,
448003ebb0eSIngo Weinhold 		SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
449003ebb0eSIngo Weinhold 		(void**)&gGetEnv);
4500c0fea5dSIngo Weinhold 
451*94830eb2SIngo Weinhold 	if (gProgramImage->entry_point == 0) {
4520c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
4530c0fea5dSIngo Weinhold 		goto err;
4540c0fea5dSIngo Weinhold 	}
4550c0fea5dSIngo Weinhold 
456*94830eb2SIngo Weinhold 	*_entry = (void *)(gProgramImage->entry_point);
4570c0fea5dSIngo Weinhold 
4580c0fea5dSIngo Weinhold 	rld_unlock();
4597486b72dSIngo Weinhold 
460*94830eb2SIngo Weinhold 	gProgramLoaded = true;
4615d0638bfSIngo Weinhold 
4627486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
463*94830eb2SIngo Weinhold 		*_entry, gProgramImage->id);
4647486b72dSIngo Weinhold 
465*94830eb2SIngo Weinhold 	return gProgramImage->id;
4660c0fea5dSIngo Weinhold 
4670c0fea5dSIngo Weinhold err:
4687486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
4697486b72dSIngo Weinhold 
470*94830eb2SIngo Weinhold 	delete_image(gProgramImage);
47174c0424aSAxel Dörfler 
4724bef3723SAxel Dörfler 	if (report_errors()) {
4734bef3723SAxel Dörfler 		// send error message
474*94830eb2SIngo Weinhold 		gErrorMessage.AddInt32("error", status);
475*94830eb2SIngo Weinhold 		gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
4764bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
4774bef3723SAxel Dörfler 
4784bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
479*94830eb2SIngo Weinhold 			gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0);
48074c0424aSAxel Dörfler 	}
48174c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
4820c0fea5dSIngo Weinhold 	rld_unlock();
48374c0424aSAxel Dörfler 
4840c0fea5dSIngo Weinhold 	return status;
4850c0fea5dSIngo Weinhold }
4860c0fea5dSIngo Weinhold 
4870c0fea5dSIngo Weinhold 
4880c0fea5dSIngo Weinhold image_id
4890c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle)
4900c0fea5dSIngo Weinhold {
4910c0fea5dSIngo Weinhold 	image_t *image = NULL;
4920c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
4930c0fea5dSIngo Weinhold 	status_t status;
4940c0fea5dSIngo Weinhold 
4950c85bd05SIngo Weinhold 	if (path == NULL && addOn)
4960c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
4970c0fea5dSIngo Weinhold 
4987486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
4997486b72dSIngo Weinhold 
5000c0fea5dSIngo Weinhold 	rld_lock();
5010c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
5020c0fea5dSIngo Weinhold 
5030c0fea5dSIngo Weinhold 	// have we already loaded this library?
5040c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
5050c0fea5dSIngo Weinhold 	if (!addOn) {
5060c85bd05SIngo Weinhold 		// a NULL path is fine -- it means the global scope shall be opened
5070c85bd05SIngo Weinhold 		if (path == NULL) {
5080c85bd05SIngo Weinhold 			*_handle = RLD_GLOBAL_SCOPE;
5090c85bd05SIngo Weinhold 			rld_unlock();
5100c85bd05SIngo Weinhold 			return 0;
5110c85bd05SIngo Weinhold 		}
5120c85bd05SIngo Weinhold 
513*94830eb2SIngo Weinhold 		image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
5140c85bd05SIngo Weinhold 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
5150c85bd05SIngo Weinhold 			set_image_flags_recursively(image, RTLD_GLOBAL);
5160c85bd05SIngo Weinhold 
5170c0fea5dSIngo Weinhold 		if (image) {
5180c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
5190c0fea5dSIngo Weinhold 			rld_unlock();
5207486b72dSIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
5217486b72dSIngo Weinhold 				image->id);
5220c85bd05SIngo Weinhold 			*_handle = image;
5230c0fea5dSIngo Weinhold 			return image->id;
5240c0fea5dSIngo Weinhold 		}
5250c0fea5dSIngo Weinhold 	}
5260c0fea5dSIngo Weinhold 
527*94830eb2SIngo Weinhold 	status = load_image(path, type, NULL, &image);
5280c0fea5dSIngo Weinhold 	if (status < B_OK) {
5290c0fea5dSIngo Weinhold 		rld_unlock();
5307486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
5317486b72dSIngo Weinhold 			strerror(status));
5320c0fea5dSIngo Weinhold 		return status;
5330c0fea5dSIngo Weinhold 	}
5340c0fea5dSIngo Weinhold 
5350c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL) {
5360c85bd05SIngo Weinhold 		if (addOn)
5370c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_add_on;
5380c85bd05SIngo Weinhold 		else
5390c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_global;
5400c85bd05SIngo Weinhold 	}
5410c85bd05SIngo Weinhold 
5420c85bd05SIngo Weinhold 	status = load_dependencies(image);
5430c0fea5dSIngo Weinhold 	if (status < B_OK)
5440c0fea5dSIngo Weinhold 		goto err;
5450c85bd05SIngo Weinhold 
5460c85bd05SIngo Weinhold 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
5470c85bd05SIngo Weinhold 	// dependencies. If not specified, we temporarily set
5480c85bd05SIngo Weinhold 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
5490c85bd05SIngo Weinhold 	// for undefined symbol resolution.
5500c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) != 0)
5510c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RTLD_GLOBAL);
5520c85bd05SIngo Weinhold 	else
5530c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
5540c0fea5dSIngo Weinhold 
5550c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
5560c0fea5dSIngo Weinhold 	if (status < B_OK)
5570c0fea5dSIngo Weinhold 		goto err;
5580c0fea5dSIngo Weinhold 
5590c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) == 0)
5600c85bd05SIngo Weinhold 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
5610c85bd05SIngo Weinhold 
5620c0fea5dSIngo Weinhold 	remap_images();
5630c0fea5dSIngo Weinhold 	init_dependencies(image, true);
5640c0fea5dSIngo Weinhold 
5650c0fea5dSIngo Weinhold 	rld_unlock();
5667486b72dSIngo Weinhold 
5677486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
5687486b72dSIngo Weinhold 
5690c85bd05SIngo Weinhold 	*_handle = image;
5700c0fea5dSIngo Weinhold 	return image->id;
5710c0fea5dSIngo Weinhold 
5720c0fea5dSIngo Weinhold err:
5737486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
5747486b72dSIngo Weinhold 
575*94830eb2SIngo Weinhold 	dequeue_loaded_image(image);
5760c0fea5dSIngo Weinhold 	delete_image(image);
5770c0fea5dSIngo Weinhold 	rld_unlock();
5780c0fea5dSIngo Weinhold 	return status;
5790c0fea5dSIngo Weinhold }
5800c0fea5dSIngo Weinhold 
5810c0fea5dSIngo Weinhold 
5820c0fea5dSIngo Weinhold status_t
5830c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
5840c0fea5dSIngo Weinhold {
5850c0fea5dSIngo Weinhold 	image_t *image;
5860c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
5870c0fea5dSIngo Weinhold 
5880c85bd05SIngo Weinhold 	if (handle == NULL && imageID < 0)
5890c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
5900c0fea5dSIngo Weinhold 
5910c85bd05SIngo Weinhold 	if (handle == RLD_GLOBAL_SCOPE)
5920c85bd05SIngo Weinhold 		return B_OK;
5930c85bd05SIngo Weinhold 
5940c0fea5dSIngo Weinhold 	rld_lock();
5950c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
5960c0fea5dSIngo Weinhold 
597*94830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
5989a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
5999a6072a3SAxel Dörfler 		update_image_ids();
6009a6072a3SAxel Dörfler 	}
6019a6072a3SAxel Dörfler 
6020c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
6030c0fea5dSIngo Weinhold 
604df30098dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
605df30098dSIngo Weinhold 
6060c85bd05SIngo Weinhold 	if (handle != NULL) {
6070c85bd05SIngo Weinhold 		image = (image_t*)handle;
6080c85bd05SIngo Weinhold 		put_image(image);
609df30098dSIngo Weinhold 		status = B_OK;
6100c85bd05SIngo Weinhold 	} else {
611*94830eb2SIngo Weinhold 		image = find_loaded_image_by_id(imageID, true);
612*94830eb2SIngo Weinhold 		if (image != NULL) {
6130c0fea5dSIngo Weinhold 			// unload image
6140c0fea5dSIngo Weinhold 			if (type == image->type) {
6150c0fea5dSIngo Weinhold 				put_image(image);
6160c0fea5dSIngo Weinhold 				status = B_OK;
6170c0fea5dSIngo Weinhold 			} else
6180c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
6190c0fea5dSIngo Weinhold 		}
6200c85bd05SIngo Weinhold 	}
6210c0fea5dSIngo Weinhold 
6220c0fea5dSIngo Weinhold 	if (status == B_OK) {
623*94830eb2SIngo Weinhold 		while ((image = get_disposable_images().head) != NULL) {
6240c0fea5dSIngo Weinhold 			// call image fini here...
6258c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
6268c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
6273be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
6288c2a9d74SMichael Lotz 			}
6298c2a9d74SMichael Lotz 
63010b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
63110b4b5d1SIngo Weinhold 
6320c0fea5dSIngo Weinhold 			if (image->term_routine)
6330c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
6340c0fea5dSIngo Weinhold 
635*94830eb2SIngo Weinhold 			dequeue_disposable_image(image);
6360c0fea5dSIngo Weinhold 			unmap_image(image);
6370c0fea5dSIngo Weinhold 
63810b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
63910b4b5d1SIngo Weinhold 
6400c0fea5dSIngo Weinhold 			delete_image(image);
6410c0fea5dSIngo Weinhold 		}
6420c0fea5dSIngo Weinhold 	}
6430c0fea5dSIngo Weinhold 
6440c0fea5dSIngo Weinhold 	rld_unlock();
6450c0fea5dSIngo Weinhold 	return status;
6460c0fea5dSIngo Weinhold }
6470c0fea5dSIngo Weinhold 
6480c0fea5dSIngo Weinhold 
6490c0fea5dSIngo Weinhold status_t
6509a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
6519a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
6520c0fea5dSIngo Weinhold {
6530c0fea5dSIngo Weinhold 	int32 count = 0, j;
6540c0fea5dSIngo Weinhold 	uint32 i;
6550c0fea5dSIngo Weinhold 	image_t *image;
6560c0fea5dSIngo Weinhold 
6570c0fea5dSIngo Weinhold 	rld_lock();
6580c0fea5dSIngo Weinhold 
6590c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
660*94830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
6610c0fea5dSIngo Weinhold 	if (image == NULL) {
6620c0fea5dSIngo Weinhold 		rld_unlock();
6630c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
6640c0fea5dSIngo Weinhold 	}
6650c0fea5dSIngo Weinhold 
6660c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
6670c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
6680c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
6690555803aSAxel Dörfler 			struct Elf32_Sym *symbol = &image->syms[j];
6700c0fea5dSIngo Weinhold 
6710c0fea5dSIngo Weinhold 			if (count == num) {
67210b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
67310b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
67410b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
6750c0fea5dSIngo Weinhold 
67610b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
67710b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
67810b4b5d1SIngo Weinhold 				int32 type;
6790c0fea5dSIngo Weinhold 				if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
68010b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
6810c0fea5dSIngo Weinhold 				else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
68210b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
6830c0fea5dSIngo Weinhold 				else
68410b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
68510b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
6860c0fea5dSIngo Weinhold 
68710b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
68810b4b5d1SIngo Weinhold 
68910b4b5d1SIngo Weinhold 				if (_type != NULL)
69010b4b5d1SIngo Weinhold 					*_type = type;
6910c0fea5dSIngo Weinhold 				if (_location != NULL)
69210b4b5d1SIngo Weinhold 					*_location = location;
6930c0fea5dSIngo Weinhold 				goto out;
6940c0fea5dSIngo Weinhold 			}
6950c0fea5dSIngo Weinhold 			count++;
6960c0fea5dSIngo Weinhold 		}
6970c0fea5dSIngo Weinhold 	}
6980c0fea5dSIngo Weinhold out:
6990c0fea5dSIngo Weinhold 	rld_unlock();
7000c0fea5dSIngo Weinhold 
7010c0fea5dSIngo Weinhold 	if (num != count)
7020c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
7030c0fea5dSIngo Weinhold 
7040c0fea5dSIngo Weinhold 	return B_OK;
7050c0fea5dSIngo Weinhold }
7060c0fea5dSIngo Weinhold 
7070c0fea5dSIngo Weinhold 
7080c0fea5dSIngo Weinhold status_t
7099a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
71080ece785SIngo Weinhold 	bool recursive, image_id *_inImage, void **_location)
7110c0fea5dSIngo Weinhold {
7120c0fea5dSIngo Weinhold 	status_t status = B_OK;
7130c0fea5dSIngo Weinhold 	image_t *image;
7140c0fea5dSIngo Weinhold 
7150c0fea5dSIngo Weinhold 	if (imageID < B_OK)
7160c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
7170c0fea5dSIngo Weinhold 	if (symbolName == NULL)
7180c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
7190c0fea5dSIngo Weinhold 
7200c0fea5dSIngo Weinhold 	rld_lock();
7210c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
7220c0fea5dSIngo Weinhold 
7230c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
724*94830eb2SIngo Weinhold 	image = find_loaded_image_by_id(imageID, false);
72580ece785SIngo Weinhold 	if (image != NULL) {
72680ece785SIngo Weinhold 		if (recursive) {
72780ece785SIngo Weinhold 			// breadth-first search in the given image and its dependencies
728003ebb0eSIngo Weinhold 			status = find_symbol_breadth_first(image,
729003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
730003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
73180ece785SIngo Weinhold 				&image, _location);
732003ebb0eSIngo Weinhold 		} else {
733003ebb0eSIngo Weinhold 			status = find_symbol(image,
734003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
735003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
736003ebb0eSIngo Weinhold 				_location);
737003ebb0eSIngo Weinhold 		}
73880ece785SIngo Weinhold 
73980ece785SIngo Weinhold 		if (status == B_OK && _inImage != NULL)
74080ece785SIngo Weinhold 			*_inImage = image->id;
74180ece785SIngo Weinhold 	} else
7420c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
7430c0fea5dSIngo Weinhold 
7440c0fea5dSIngo Weinhold 	rld_unlock();
7450c0fea5dSIngo Weinhold 	return status;
7460c0fea5dSIngo Weinhold }
7470c0fea5dSIngo Weinhold 
7480c0fea5dSIngo Weinhold 
7490c0fea5dSIngo Weinhold status_t
7500c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
7510c85bd05SIngo Weinhold 	void **_location)
7520c85bd05SIngo Weinhold {
7530c85bd05SIngo Weinhold 	status_t status = B_ENTRY_NOT_FOUND;
7540c85bd05SIngo Weinhold 
7550c85bd05SIngo Weinhold 	if (symbolName == NULL)
7560c85bd05SIngo Weinhold 		return B_BAD_VALUE;
7570c85bd05SIngo Weinhold 
7580c85bd05SIngo Weinhold 	rld_lock();
7590c85bd05SIngo Weinhold 		// for now, just do stupid simple global locking
7600c85bd05SIngo Weinhold 
7610c85bd05SIngo Weinhold 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
7620c85bd05SIngo Weinhold 		// look in the default scope
7630c85bd05SIngo Weinhold 		image_t* image;
764*94830eb2SIngo Weinhold 		Elf32_Sym* symbol = find_undefined_symbol_global(gProgramImage,
765*94830eb2SIngo Weinhold 			gProgramImage,
766003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
767003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
768003ebb0eSIngo Weinhold 			&image);
7690c85bd05SIngo Weinhold 		if (symbol != NULL) {
7700c85bd05SIngo Weinhold 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
7710c85bd05SIngo Weinhold 			int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
7720c85bd05SIngo Weinhold 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
7730c85bd05SIngo Weinhold 			patch_defined_symbol(image, symbolName, _location, &symbolType);
7740c85bd05SIngo Weinhold 			status = B_OK;
7750c85bd05SIngo Weinhold 		}
7760c85bd05SIngo Weinhold 	} else if (handle == RTLD_NEXT) {
7770c85bd05SIngo Weinhold 		// Look in the default scope, but also in the dependencies of the
7780c85bd05SIngo Weinhold 		// calling image. Return the next after the caller symbol.
7790c85bd05SIngo Weinhold 
780a2dad9e1SIngo Weinhold 		// First of all, find the caller image.
781*94830eb2SIngo Weinhold 		image_t* callerImage = get_loaded_images().head;
7820c85bd05SIngo Weinhold 		for (; callerImage != NULL; callerImage = callerImage->next) {
7830c85bd05SIngo Weinhold 			elf_region_t& text = callerImage->regions[0];
784a2dad9e1SIngo Weinhold 			if ((addr_t)caller >= text.vmstart
785a2dad9e1SIngo Weinhold 				&& (addr_t)caller < text.vmstart + text.vmsize) {
786a2dad9e1SIngo Weinhold 				// found the image
7870c85bd05SIngo Weinhold 				break;
7880c85bd05SIngo Weinhold 			}
7890c85bd05SIngo Weinhold 		}
7900c85bd05SIngo Weinhold 
791a2dad9e1SIngo Weinhold 		if (callerImage != NULL) {
7920c85bd05SIngo Weinhold 			// found the caller -- now search the global scope until we find
7930c85bd05SIngo Weinhold 			// the next symbol
794a2dad9e1SIngo Weinhold 			bool hitCallerImage = false;
7950c85bd05SIngo Weinhold 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
7960c85bd05SIngo Weinhold 
797*94830eb2SIngo Weinhold 			image_t* image = get_loaded_images().head;
7980c85bd05SIngo Weinhold 			for (; image != NULL; image = image->next) {
799a2dad9e1SIngo Weinhold 				// skip the caller image
800a2dad9e1SIngo Weinhold 				if (image == callerImage) {
801a2dad9e1SIngo Weinhold 					hitCallerImage = true;
802a2dad9e1SIngo Weinhold 					continue;
803a2dad9e1SIngo Weinhold 				}
804a2dad9e1SIngo Weinhold 
805a2dad9e1SIngo Weinhold 				// skip all images up to the caller image; also skip add-on
806a2dad9e1SIngo Weinhold 				// images and those not marked above for resolution
807a2dad9e1SIngo Weinhold 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
8080c85bd05SIngo Weinhold 					|| (image->flags
809a2dad9e1SIngo Weinhold 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
8100c85bd05SIngo Weinhold 					continue;
8110c85bd05SIngo Weinhold 				}
8120c85bd05SIngo Weinhold 
813003ebb0eSIngo Weinhold 				struct Elf32_Sym *symbol = find_symbol(image,
814003ebb0eSIngo Weinhold 					SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
815003ebb0eSIngo Weinhold 						LOOKUP_FLAG_DEFAULT_VERSION));
8160c85bd05SIngo Weinhold 				if (symbol == NULL)
8170c85bd05SIngo Weinhold 					continue;
8180c85bd05SIngo Weinhold 
819a2dad9e1SIngo Weinhold 				// found the symbol
8200c85bd05SIngo Weinhold 				*_location = (void*)(symbol->st_value
8210c85bd05SIngo Weinhold 					+ image->regions[0].delta);
8220c85bd05SIngo Weinhold 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
8230c85bd05SIngo Weinhold 				patch_defined_symbol(image, symbolName, _location,
8240c85bd05SIngo Weinhold 					&symbolType);
8250c85bd05SIngo Weinhold 				status = B_OK;
8260c85bd05SIngo Weinhold 				break;
8270c85bd05SIngo Weinhold 			}
8280c85bd05SIngo Weinhold 
8290c85bd05SIngo Weinhold 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
8300c85bd05SIngo Weinhold 		}
8310c85bd05SIngo Weinhold 	} else {
8320c85bd05SIngo Weinhold 		// breadth-first search in the given image and its dependencies
8330c85bd05SIngo Weinhold 		image_t* inImage;
834003ebb0eSIngo Weinhold 		status = find_symbol_breadth_first((image_t*)handle,
835003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
836003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
837003ebb0eSIngo Weinhold 			&inImage, _location);
8380c85bd05SIngo Weinhold 	}
8390c85bd05SIngo Weinhold 
8400c85bd05SIngo Weinhold 	rld_unlock();
8410c85bd05SIngo Weinhold 	return status;
8420c85bd05SIngo Weinhold }
8430c85bd05SIngo Weinhold 
8440c85bd05SIngo Weinhold 
8450c85bd05SIngo Weinhold status_t
8460c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
8470c0fea5dSIngo Weinhold {
8480c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
8490c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
8500c0fea5dSIngo Weinhold 	image_t *image;
8510c0fea5dSIngo Weinhold 
8520c0fea5dSIngo Weinhold 	if (_name == NULL)
8530c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
8540c0fea5dSIngo Weinhold 
8550c0fea5dSIngo Weinhold 	rld_lock();
8560c0fea5dSIngo Weinhold 
857*94830eb2SIngo Weinhold 	image = find_loaded_image_by_id(id, false);
8580c0fea5dSIngo Weinhold 	if (image == NULL) {
8590c0fea5dSIngo Weinhold 		rld_unlock();
8600c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
8610c0fea5dSIngo Weinhold 	}
8620c0fea5dSIngo Weinhold 
8630c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
8640c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
8650c0fea5dSIngo Weinhold 		rld_unlock();
8660c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
8670c0fea5dSIngo Weinhold 	}
8680c0fea5dSIngo Weinhold 
8690c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
8700c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
8710c0fea5dSIngo Weinhold 			continue;
8720c0fea5dSIngo Weinhold 
8730c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
8740c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
8750c0fea5dSIngo Weinhold 
8760c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
8770c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
8780c0fea5dSIngo Weinhold 			rld_unlock();
8790c0fea5dSIngo Weinhold 			return B_OK;
8800c0fea5dSIngo Weinhold 		}
8810c0fea5dSIngo Weinhold 	}
8820c0fea5dSIngo Weinhold 
8830c0fea5dSIngo Weinhold 	rld_unlock();
8840c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
8850c0fea5dSIngo Weinhold }
8860c0fea5dSIngo Weinhold 
8870c0fea5dSIngo Weinhold 
88874c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
8890c0fea5dSIngo Weinhold 
8900c0fea5dSIngo Weinhold 
8919a6072a3SAxel Dörfler /*! Read and verify the ELF header */
8920c0fea5dSIngo Weinhold status_t
8930c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
8940c0fea5dSIngo Weinhold {
8950c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
8960c0fea5dSIngo Weinhold 
8970c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
8980c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
8990c0fea5dSIngo Weinhold 
9009a6072a3SAxel Dörfler 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize,
9019a6072a3SAxel Dörfler 		&sectionSize);
9020c0fea5dSIngo Weinhold }
9030c0fea5dSIngo Weinhold 
9040c0fea5dSIngo Weinhold 
9050c0fea5dSIngo Weinhold void
9060c0fea5dSIngo Weinhold terminate_program(void)
9070c0fea5dSIngo Weinhold {
9080c0fea5dSIngo Weinhold 	image_t **termList;
9090c0fea5dSIngo Weinhold 	ssize_t count, i;
9100c0fea5dSIngo Weinhold 
911*94830eb2SIngo Weinhold 	count = get_sorted_image_list(gProgramImage, &termList, RFLAG_TERMINATED);
9120c0fea5dSIngo Weinhold 	if (count < B_OK)
9130c0fea5dSIngo Weinhold 		return;
9140c0fea5dSIngo Weinhold 
915*94830eb2SIngo Weinhold 	if (gInvalidImageIDs) {
9169a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
9179a6072a3SAxel Dörfler 		update_image_ids();
9189a6072a3SAxel Dörfler 	}
9199a6072a3SAxel Dörfler 
9200c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
9210c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
9220c0fea5dSIngo Weinhold 		image_t *image = termList[i];
9230c0fea5dSIngo Weinhold 
9240c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
9250c0fea5dSIngo Weinhold 
92610b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
92710b4b5d1SIngo Weinhold 
9280c0fea5dSIngo Weinhold 		if (image->term_routine)
9290c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
93010b4b5d1SIngo Weinhold 
93110b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
9320c0fea5dSIngo Weinhold 	}
9330c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
9340c0fea5dSIngo Weinhold 
9350c0fea5dSIngo Weinhold 	free(termList);
9360c0fea5dSIngo Weinhold }
9370c0fea5dSIngo Weinhold 
9380c0fea5dSIngo Weinhold 
9390c0fea5dSIngo Weinhold void
9400c0fea5dSIngo Weinhold rldelf_init(void)
9410c0fea5dSIngo Weinhold {
942e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
943e73923b0SAxel Dörfler 	sSemOwner = -1;
944e73923b0SAxel Dörfler 	sSemCount = 0;
9450c0fea5dSIngo Weinhold 
946*94830eb2SIngo Weinhold 	init_add_ons();
947*94830eb2SIngo Weinhold 
9480c0fea5dSIngo Weinhold 	// create the debug area
9490c0fea5dSIngo Weinhold 	{
9500c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
9510c0fea5dSIngo Weinhold 
9520c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
9530c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
9540c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
9550c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
9560c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
9570c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
9580c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
9590c0fea5dSIngo Weinhold 		}
9600c0fea5dSIngo Weinhold 
961*94830eb2SIngo Weinhold 		area->loaded_images = &get_loaded_images();
9620c0fea5dSIngo Weinhold 	}
96374c0424aSAxel Dörfler 
96474c0424aSAxel Dörfler 	// initialize error message if needed
9654bef3723SAxel Dörfler 	if (report_errors()) {
96674c0424aSAxel Dörfler 		void *buffer = malloc(1024);
96774c0424aSAxel Dörfler 		if (buffer == NULL)
96874c0424aSAxel Dörfler 			return;
96974c0424aSAxel Dörfler 
970*94830eb2SIngo Weinhold 		gErrorMessage.SetTo(buffer, 1024, 'Rler');
97174c0424aSAxel Dörfler 	}
9720c0fea5dSIngo Weinhold }
9731873b4b3SIngo Weinhold 
9741873b4b3SIngo Weinhold 
9751873b4b3SIngo Weinhold status_t
9769a6072a3SAxel Dörfler elf_reinit_after_fork(void)
9771873b4b3SIngo Weinhold {
978e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
979e73923b0SAxel Dörfler 	if (sSem < 0)
980e73923b0SAxel Dörfler 		return sSem;
9811873b4b3SIngo Weinhold 
9829a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
983cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
984cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
9859a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
986*94830eb2SIngo Weinhold 	gInvalidImageIDs = true;
987cbc456deSIngo Weinhold 
9881873b4b3SIngo Weinhold 	return B_OK;
9891873b4b3SIngo Weinhold }
990