xref: /haiku/src/system/runtime_loader/elf.cpp (revision e94d1badf539e0e265f2ca42865a11ee1c8535f3)
10c0fea5dSIngo Weinhold /*
234982809SIngo Weinhold  * Copyright 2008, 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 <runtime_loader.h>
237486b72dSIngo Weinhold #include <syscalls.h>
247486b72dSIngo Weinhold #include <user_runtime.h>
2510b4b5d1SIngo Weinhold #include <util/DoublyLinkedList.h>
2610b4b5d1SIngo Weinhold #include <util/kernel_cpp.h>
276b202f4eSIngo Weinhold #include <util/KMessage.h>
286b202f4eSIngo Weinhold #include <vm_defs.h>
297486b72dSIngo Weinhold 
30071f9c3aSIngo Weinhold #include "tracing_config.h"
31071f9c3aSIngo Weinhold 
320c0fea5dSIngo Weinhold 
330c0fea5dSIngo Weinhold //#define TRACE_RLD
340c0fea5dSIngo Weinhold #ifdef TRACE_RLD
350c0fea5dSIngo Weinhold #	define TRACE(x) dprintf x
360c0fea5dSIngo Weinhold #else
370c0fea5dSIngo Weinhold #	define TRACE(x) ;
380c0fea5dSIngo Weinhold #endif
390c0fea5dSIngo Weinhold 
400c0fea5dSIngo Weinhold 
4110b4b5d1SIngo Weinhold // TODO: implement better locking strategy
4210b4b5d1SIngo Weinhold // TODO: implement lazy binding
430c0fea5dSIngo Weinhold 
440c0fea5dSIngo Weinhold #define	PAGE_MASK (B_PAGE_SIZE - 1)
450c0fea5dSIngo Weinhold 
460c0fea5dSIngo Weinhold #define	PAGE_OFFSET(x) ((x) & (PAGE_MASK))
470c0fea5dSIngo Weinhold #define	PAGE_BASE(x) ((x) & ~(PAGE_MASK))
480c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
490c0fea5dSIngo Weinhold 
500c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000
510c0fea5dSIngo Weinhold 	/* keep in sync with app ldscript */
520c0fea5dSIngo Weinhold 
530c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen())
540c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE	((void*)-2l)
550c85bd05SIngo Weinhold 
560c0fea5dSIngo Weinhold enum {
570c85bd05SIngo Weinhold 	// the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL
580c85bd05SIngo Weinhold 
590c85bd05SIngo Weinhold 	RFLAG_RW					= 0x0010,
600c85bd05SIngo Weinhold 	RFLAG_ANON					= 0x0020,
610c0fea5dSIngo Weinhold 
620c0fea5dSIngo Weinhold 	RFLAG_TERMINATED			= 0x0200,
630c0fea5dSIngo Weinhold 	RFLAG_INITIALIZED			= 0x0400,
640c0fea5dSIngo Weinhold 	RFLAG_SYMBOLIC				= 0x0800,
650c0fea5dSIngo Weinhold 	RFLAG_RELOCATED				= 0x1000,
660c0fea5dSIngo Weinhold 	RFLAG_PROTECTED				= 0x2000,
670c0fea5dSIngo Weinhold 	RFLAG_DEPENDENCIES_LOADED	= 0x4000,
6846f4d849SIngo Weinhold 	RFLAG_REMAPPED				= 0x8000,
6946f4d849SIngo Weinhold 
700c85bd05SIngo Weinhold 	RFLAG_VISITED				= 0x10000,
710c85bd05SIngo Weinhold 	RFLAG_USE_FOR_RESOLVING		= 0x20000
7246f4d849SIngo Weinhold 		// temporarily set in the symbol resolution code
730c0fea5dSIngo Weinhold };
740c0fea5dSIngo Weinhold 
750c0fea5dSIngo Weinhold 
760c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type)	(1 << ((type) - 1))
770c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES				(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
780c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
790c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
800c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
810c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE			(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
820c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
830c0fea5dSIngo Weinhold 
840c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
850c0fea5dSIngo Weinhold 
8610b4b5d1SIngo Weinhold 
8710b4b5d1SIngo Weinhold // image events
8810b4b5d1SIngo Weinhold enum {
8910b4b5d1SIngo Weinhold 	IMAGE_EVENT_LOADED,
9010b4b5d1SIngo Weinhold 	IMAGE_EVENT_RELOCATED,
9110b4b5d1SIngo Weinhold 	IMAGE_EVENT_INITIALIZED,
9210b4b5d1SIngo Weinhold 	IMAGE_EVENT_UNINITIALIZING,
9310b4b5d1SIngo Weinhold 	IMAGE_EVENT_UNLOADING
9410b4b5d1SIngo Weinhold };
9510b4b5d1SIngo Weinhold 
9610b4b5d1SIngo Weinhold 
9710b4b5d1SIngo Weinhold struct RuntimeLoaderAddOn
9810b4b5d1SIngo Weinhold 		: public DoublyLinkedListLinkImpl<RuntimeLoaderAddOn> {
9910b4b5d1SIngo Weinhold 	image_t*				image;
10010b4b5d1SIngo Weinhold 	runtime_loader_add_on*	addOn;
10110b4b5d1SIngo Weinhold 
10210b4b5d1SIngo Weinhold 	RuntimeLoaderAddOn(image_t* image, runtime_loader_add_on* addOn)
10310b4b5d1SIngo Weinhold 		:
10410b4b5d1SIngo Weinhold 		image(image),
10510b4b5d1SIngo Weinhold 		addOn(addOn)
10610b4b5d1SIngo Weinhold 	{
10710b4b5d1SIngo Weinhold 	}
10810b4b5d1SIngo Weinhold };
10910b4b5d1SIngo Weinhold 
11010b4b5d1SIngo Weinhold typedef DoublyLinkedList<RuntimeLoaderAddOn> AddOnList;
11110b4b5d1SIngo Weinhold 
11210b4b5d1SIngo Weinhold struct RuntimeLoaderSymbolPatcher {
11310b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher*		next;
11410b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher*	patcher;
11510b4b5d1SIngo Weinhold 	void*							cookie;
11610b4b5d1SIngo Weinhold 
11710b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher(runtime_loader_symbol_patcher* patcher,
11810b4b5d1SIngo Weinhold 			void* cookie)
11910b4b5d1SIngo Weinhold 		:
12010b4b5d1SIngo Weinhold 		patcher(patcher),
12110b4b5d1SIngo Weinhold 		cookie(cookie)
12210b4b5d1SIngo Weinhold 	{
12310b4b5d1SIngo Weinhold 	}
12410b4b5d1SIngo Weinhold };
12510b4b5d1SIngo Weinhold 
12610b4b5d1SIngo Weinhold 
1270c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0};
1280c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0};
1290c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0;
1300c0fea5dSIngo Weinhold static image_t *sProgramImage;
13174c0424aSAxel Dörfler static KMessage sErrorMessage;
1325d0638bfSIngo Weinhold static bool sProgramLoaded = false;
13361b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL;
1349a6072a3SAxel Dörfler static bool sInvalidImageIDs;
135ca618b22SIngo Weinhold static image_t **sPreloadedImages = NULL;
136ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0;
13710b4b5d1SIngo Weinhold static AddOnList sAddOns;
1380c0fea5dSIngo Weinhold 
1390c0fea5dSIngo Weinhold // a recursive lock
140e73923b0SAxel Dörfler static sem_id sSem;
141e73923b0SAxel Dörfler static thread_id sSemOwner;
142e73923b0SAxel Dörfler static int32 sSemCount;
1430c0fea5dSIngo Weinhold 
14410b4b5d1SIngo Weinhold extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport;
14510b4b5d1SIngo Weinhold 
1460c0fea5dSIngo Weinhold 
1470c0fea5dSIngo Weinhold void
1480c0fea5dSIngo Weinhold dprintf(const char *format, ...)
1490c0fea5dSIngo Weinhold {
1500c0fea5dSIngo Weinhold 	char buffer[1024];
1510c0fea5dSIngo Weinhold 
1520c0fea5dSIngo Weinhold 	va_list list;
1530c0fea5dSIngo Weinhold 	va_start(list, format);
1540c0fea5dSIngo Weinhold 
1550c0fea5dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1560c0fea5dSIngo Weinhold 	_kern_debug_output(buffer);
1570c0fea5dSIngo Weinhold 
1580c0fea5dSIngo Weinhold 	va_end(list);
1590c0fea5dSIngo Weinhold }
1605d0638bfSIngo Weinhold 
1615d0638bfSIngo Weinhold #define FATAL(x...)							\
1625d0638bfSIngo Weinhold 	do {									\
1635d0638bfSIngo Weinhold 		dprintf("runtime_loader: " x);		\
1645d0638bfSIngo Weinhold 		if (!sProgramLoaded)				\
1655d0638bfSIngo Weinhold 			printf("runtime_loader: " x);	\
1665d0638bfSIngo Weinhold 	} while (false)
1670c0fea5dSIngo Weinhold 
1680c0fea5dSIngo Weinhold 
16934982809SIngo Weinhold /*!	Mini atoi(), so we don't have to include the libroot dependencies.
17034982809SIngo Weinhold  */
17134982809SIngo Weinhold int
17234982809SIngo Weinhold atoi(const char* num)
17334982809SIngo Weinhold {
17434982809SIngo Weinhold 	int result = 0;
17534982809SIngo Weinhold 	while (*num >= '0' && *num <= '9') {
17634982809SIngo Weinhold 		result = (result * 10) + (*num - '0');
17734982809SIngo Weinhold 		num++;
17834982809SIngo Weinhold 	}
17934982809SIngo Weinhold 
18034982809SIngo Weinhold 	return result;
18134982809SIngo Weinhold }
18234982809SIngo Weinhold 
18334982809SIngo Weinhold 
1846bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING
1857486b72dSIngo Weinhold 
1867486b72dSIngo Weinhold void
1877486b72dSIngo Weinhold ktrace_printf(const char *format, ...)
1887486b72dSIngo Weinhold {
1897486b72dSIngo Weinhold 	va_list list;
1907486b72dSIngo Weinhold 	va_start(list, format);
1917486b72dSIngo Weinhold 
1927486b72dSIngo Weinhold 	char buffer[1024];
1937486b72dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1947486b72dSIngo Weinhold 	_kern_ktrace_output(buffer);
1957486b72dSIngo Weinhold 
1967486b72dSIngo Weinhold 	va_end(list);
1977486b72dSIngo Weinhold }
1987486b72dSIngo Weinhold 
1997486b72dSIngo Weinhold #define KTRACE(x...)	ktrace_printf(x)
2007486b72dSIngo Weinhold 
2017486b72dSIngo Weinhold #else
2027486b72dSIngo Weinhold #	define KTRACE(x...)
2037486b72dSIngo Weinhold #endif	// RUNTIME_LOADER_TRACING
2047486b72dSIngo Weinhold 
2057486b72dSIngo Weinhold 
2060c0fea5dSIngo Weinhold static void
2070c0fea5dSIngo Weinhold rld_unlock()
2080c0fea5dSIngo Weinhold {
209e73923b0SAxel Dörfler 	if (sSemCount-- == 1) {
210e73923b0SAxel Dörfler 		sSemOwner = -1;
211e73923b0SAxel Dörfler 		release_sem(sSem);
2120c0fea5dSIngo Weinhold 	}
2130c0fea5dSIngo Weinhold }
2140c0fea5dSIngo Weinhold 
2150c0fea5dSIngo Weinhold 
2160c0fea5dSIngo Weinhold static void
2170c0fea5dSIngo Weinhold rld_lock()
2180c0fea5dSIngo Weinhold {
2190c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
220e73923b0SAxel Dörfler 	if (self != sSemOwner) {
221e73923b0SAxel Dörfler 		acquire_sem(sSem);
222e73923b0SAxel Dörfler 		sSemOwner = self;
2230c0fea5dSIngo Weinhold 	}
224e73923b0SAxel Dörfler 	sSemCount++;
2250c0fea5dSIngo Weinhold }
2260c0fea5dSIngo Weinhold 
2270c0fea5dSIngo Weinhold 
2280c0fea5dSIngo Weinhold static void
2290c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image)
2300c0fea5dSIngo Weinhold {
2310c0fea5dSIngo Weinhold 	image->next = 0;
2320c0fea5dSIngo Weinhold 
2330c0fea5dSIngo Weinhold 	image->prev = queue->tail;
2340c0fea5dSIngo Weinhold 	if (queue->tail)
2350c0fea5dSIngo Weinhold 		queue->tail->next = image;
2360c0fea5dSIngo Weinhold 
2370c0fea5dSIngo Weinhold 	queue->tail = image;
2380c0fea5dSIngo Weinhold 	if (!queue->head)
2390c0fea5dSIngo Weinhold 		queue->head = image;
2400c0fea5dSIngo Weinhold }
2410c0fea5dSIngo Weinhold 
2420c0fea5dSIngo Weinhold 
2430c0fea5dSIngo Weinhold static void
2440c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image)
2450c0fea5dSIngo Weinhold {
2460c0fea5dSIngo Weinhold 	if (image->next)
2470c0fea5dSIngo Weinhold 		image->next->prev = image->prev;
2480c0fea5dSIngo Weinhold 	else
2490c0fea5dSIngo Weinhold 		queue->tail = image->prev;
2500c0fea5dSIngo Weinhold 
2510c0fea5dSIngo Weinhold 	if (image->prev)
2520c0fea5dSIngo Weinhold 		image->prev->next = image->next;
2530c0fea5dSIngo Weinhold 	else
2540c0fea5dSIngo Weinhold 		queue->head = image->next;
2550c0fea5dSIngo Weinhold 
2560c0fea5dSIngo Weinhold 	image->prev = 0;
2570c0fea5dSIngo Weinhold 	image->next = 0;
2580c0fea5dSIngo Weinhold }
2590c0fea5dSIngo Weinhold 
2600c0fea5dSIngo Weinhold 
2610c0fea5dSIngo Weinhold static uint32
2620c0fea5dSIngo Weinhold elf_hash(const uint8 *name)
2630c0fea5dSIngo Weinhold {
2640c0fea5dSIngo Weinhold 	uint32 hash = 0;
2650c0fea5dSIngo Weinhold 	uint32 temp;
2660c0fea5dSIngo Weinhold 
2670c0fea5dSIngo Weinhold 	while (*name) {
2680c0fea5dSIngo Weinhold 		hash = (hash << 4) + *name++;
2690c0fea5dSIngo Weinhold 		if ((temp = hash & 0xf0000000)) {
2700c0fea5dSIngo Weinhold 			hash ^= temp >> 24;
2710c0fea5dSIngo Weinhold 		}
2720c0fea5dSIngo Weinhold 		hash &= ~temp;
2730c0fea5dSIngo Weinhold 	}
2740c0fea5dSIngo Weinhold 	return hash;
2750c0fea5dSIngo Weinhold }
2760c0fea5dSIngo Weinhold 
2770c0fea5dSIngo Weinhold 
2784bef3723SAxel Dörfler static inline bool
2794bef3723SAxel Dörfler report_errors()
2804bef3723SAxel Dörfler {
2814bef3723SAxel Dörfler 	return gProgramArgs->error_port >= 0;
2824bef3723SAxel Dörfler }
2834bef3723SAxel Dörfler 
2844bef3723SAxel Dörfler 
2859a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork.
2869a6072a3SAxel Dörfler static status_t
2879a6072a3SAxel Dörfler update_image_id(image_t *image)
2889a6072a3SAxel Dörfler {
2899a6072a3SAxel Dörfler 	int32 cookie = 0;
2909a6072a3SAxel Dörfler 	image_info info;
2919a6072a3SAxel Dörfler 	while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info,
2929a6072a3SAxel Dörfler 			sizeof(image_info)) == B_OK) {
2939a6072a3SAxel Dörfler 		for (uint32 i = 0; i < image->num_regions; i++) {
2949a6072a3SAxel Dörfler 			if (image->regions[i].vmstart == (addr_t)info.text) {
2959a6072a3SAxel Dörfler 				image->id = info.id;
2969a6072a3SAxel Dörfler 				return B_OK;
2979a6072a3SAxel Dörfler 			}
2989a6072a3SAxel Dörfler 		}
2999a6072a3SAxel Dörfler 	}
3009a6072a3SAxel Dörfler 
3019a6072a3SAxel Dörfler 	FATAL("Could not update image ID %ld after fork()!\n", image->id);
3029a6072a3SAxel Dörfler 	return B_ENTRY_NOT_FOUND;
3039a6072a3SAxel Dörfler }
3049a6072a3SAxel Dörfler 
3059a6072a3SAxel Dörfler 
3069a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images.
3079a6072a3SAxel Dörfler static status_t
3089a6072a3SAxel Dörfler update_image_ids(void)
3099a6072a3SAxel Dörfler {
3109a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
3119a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
3129a6072a3SAxel Dörfler 		if (status != B_OK)
3139a6072a3SAxel Dörfler 			return status;
3149a6072a3SAxel Dörfler 	}
3159a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
3169a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
3179a6072a3SAxel Dörfler 		if (status != B_OK)
3189a6072a3SAxel Dörfler 			return status;
3199a6072a3SAxel Dörfler 	}
3209a6072a3SAxel Dörfler 
3219a6072a3SAxel Dörfler 	sInvalidImageIDs = false;
3229a6072a3SAxel Dörfler 	return B_OK;
3239a6072a3SAxel Dörfler }
3249a6072a3SAxel Dörfler 
3259a6072a3SAxel Dörfler 
3260c0fea5dSIngo Weinhold static image_t *
3270c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath,
3280c0fea5dSIngo Weinhold 	uint32 typeMask)
3290c0fea5dSIngo Weinhold {
3309a6072a3SAxel Dörfler 	for (image_t *image = queue->head; image; image = image->next) {
3310c0fea5dSIngo Weinhold 		const char *imageName = isPath ? image->path : image->name;
3320c0fea5dSIngo Weinhold 		int length = isPath ? sizeof(image->path) : sizeof(image->name);
3330c0fea5dSIngo Weinhold 
3340c0fea5dSIngo Weinhold 		if (!strncmp(imageName, name, length)
3350c0fea5dSIngo Weinhold 			&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
3360c0fea5dSIngo Weinhold 			return image;
3370c0fea5dSIngo Weinhold 		}
3380c0fea5dSIngo Weinhold 	}
3390c0fea5dSIngo Weinhold 
3400c0fea5dSIngo Weinhold 	return NULL;
3410c0fea5dSIngo Weinhold }
3420c0fea5dSIngo Weinhold 
3430c0fea5dSIngo Weinhold 
3440c0fea5dSIngo Weinhold static image_t *
3450c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask)
3460c0fea5dSIngo Weinhold {
3479a6072a3SAxel Dörfler 	bool isPath = strchr(name, '/') != NULL;
34846f4d849SIngo Weinhold 	return find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
3490c0fea5dSIngo Weinhold }
3500c0fea5dSIngo Weinhold 
3510c0fea5dSIngo Weinhold 
3520c0fea5dSIngo Weinhold static image_t *
3530c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id)
3540c0fea5dSIngo Weinhold {
3559a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
3569a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
3579a6072a3SAxel Dörfler 		update_image_ids();
3589a6072a3SAxel Dörfler 	}
3590c0fea5dSIngo Weinhold 
3609a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
3610c0fea5dSIngo Weinhold 		if (image->id == id)
3620c0fea5dSIngo Weinhold 			return image;
3630c0fea5dSIngo Weinhold 	}
3640c0fea5dSIngo Weinhold 
3650c0fea5dSIngo Weinhold 	// For the termination routine, we need to look into the list of
3660c0fea5dSIngo Weinhold 	// disposable images as well
3679a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
3680c0fea5dSIngo Weinhold 		if (image->id == id)
3690c0fea5dSIngo Weinhold 			return image;
3700c0fea5dSIngo Weinhold 	}
3710c0fea5dSIngo Weinhold 
3720c0fea5dSIngo Weinhold 	return NULL;
3730c0fea5dSIngo Weinhold }
3740c0fea5dSIngo Weinhold 
3750c0fea5dSIngo Weinhold 
3765fd6637bSIngo Weinhold static image_t*
3775fd6637bSIngo Weinhold get_program_image()
37812a5e9a4SAxel Dörfler {
37912a5e9a4SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
38012a5e9a4SAxel Dörfler 		if (image->type == B_APP_IMAGE)
3815fd6637bSIngo Weinhold 			return image;
38212a5e9a4SAxel Dörfler 	}
38312a5e9a4SAxel Dörfler 
38412a5e9a4SAxel Dörfler 	return NULL;
38512a5e9a4SAxel Dörfler }
38612a5e9a4SAxel Dörfler 
38712a5e9a4SAxel Dörfler 
3885fd6637bSIngo Weinhold static const char *
3895fd6637bSIngo Weinhold get_program_path()
3905fd6637bSIngo Weinhold {
3915fd6637bSIngo Weinhold 	if (image_t* image = get_program_image())
3925fd6637bSIngo Weinhold 		return image->path;
3935fd6637bSIngo Weinhold 
3945fd6637bSIngo Weinhold 	return NULL;
3955fd6637bSIngo Weinhold }
3965fd6637bSIngo Weinhold 
3975fd6637bSIngo Weinhold 
3980c0fea5dSIngo Weinhold static status_t
39912a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize,
40012a5e9a4SAxel Dörfler 	int32 *_sheaderSize)
4010c0fea5dSIngo Weinhold {
4020c0fea5dSIngo Weinhold 	if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
4030c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4040c0fea5dSIngo Weinhold 
4050c0fea5dSIngo Weinhold 	if (eheader->e_ident[4] != ELFCLASS32)
4060c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4070c0fea5dSIngo Weinhold 
4080c0fea5dSIngo Weinhold 	if (eheader->e_phoff == 0)
4090c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4100c0fea5dSIngo Weinhold 
4110c0fea5dSIngo Weinhold 	if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
4120c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4130c0fea5dSIngo Weinhold 
4140c0fea5dSIngo Weinhold 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
4150c0fea5dSIngo Weinhold 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
4160c0fea5dSIngo Weinhold 
4175aa7b7b6SMarcus Overhagen 	if (*_pheaderSize <= 0 || *_sheaderSize <= 0)
4185aa7b7b6SMarcus Overhagen 		return B_NOT_AN_EXECUTABLE;
4195aa7b7b6SMarcus Overhagen 
4205aa7b7b6SMarcus Overhagen 	return B_OK;
4210c0fea5dSIngo Weinhold }
4220c0fea5dSIngo Weinhold 
4230c0fea5dSIngo Weinhold 
4240c0fea5dSIngo Weinhold static int32
4250c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize)
4260c0fea5dSIngo Weinhold {
4270c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheaders;
4280c0fea5dSIngo Weinhold 	int32 count = 0;
4290c0fea5dSIngo Weinhold 	int i;
4300c0fea5dSIngo Weinhold 
4310c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
4320c0fea5dSIngo Weinhold 		pheaders = (struct Elf32_Phdr *)(buff + i * phentsize);
4330c0fea5dSIngo Weinhold 
4340c0fea5dSIngo Weinhold 		switch (pheaders->p_type) {
4350c0fea5dSIngo Weinhold 			case PT_NULL:
4360c0fea5dSIngo Weinhold 				/* NOP header */
4370c0fea5dSIngo Weinhold 				break;
4380c0fea5dSIngo Weinhold 			case PT_LOAD:
4390c0fea5dSIngo Weinhold 				count += 1;
4400c0fea5dSIngo Weinhold 				if (pheaders->p_memsz != pheaders->p_filesz) {
4410c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz);
4420c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz);
4430c0fea5dSIngo Weinhold 
4440c0fea5dSIngo Weinhold 					if (A != B)
4450c0fea5dSIngo Weinhold 						count += 1;
4460c0fea5dSIngo Weinhold 				}
4470c0fea5dSIngo Weinhold 				break;
4480c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
4490c0fea5dSIngo Weinhold 				/* will be handled at some other place */
4500c0fea5dSIngo Weinhold 				break;
4510c0fea5dSIngo Weinhold 			case PT_INTERP:
4520c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
4530c0fea5dSIngo Weinhold 				break;
4540c0fea5dSIngo Weinhold 			case PT_NOTE:
4550c0fea5dSIngo Weinhold 				/* unsupported */
4560c0fea5dSIngo Weinhold 				break;
4570c0fea5dSIngo Weinhold 			case PT_SHLIB:
4580c0fea5dSIngo Weinhold 				/* undefined semantics */
4590c0fea5dSIngo Weinhold 				break;
4600c0fea5dSIngo Weinhold 			case PT_PHDR:
4610c0fea5dSIngo Weinhold 				/* we don't use it */
4620c0fea5dSIngo Weinhold 				break;
4630c0fea5dSIngo Weinhold 			default:
4640c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type);
4650c0fea5dSIngo Weinhold 				return B_BAD_DATA;
4660c0fea5dSIngo Weinhold 		}
4670c0fea5dSIngo Weinhold 	}
4680c0fea5dSIngo Weinhold 
4690c0fea5dSIngo Weinhold 	return count;
4700c0fea5dSIngo Weinhold }
4710c0fea5dSIngo Weinhold 
4720c0fea5dSIngo Weinhold 
4730c0fea5dSIngo Weinhold static image_t *
4740c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions)
4750c0fea5dSIngo Weinhold {
4760c0fea5dSIngo Weinhold 	size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t);
4770c0fea5dSIngo Weinhold 	const char *lastSlash;
4780c0fea5dSIngo Weinhold 
4790c0fea5dSIngo Weinhold 	image_t *image = (image_t*)malloc(allocSize);
4800c0fea5dSIngo Weinhold 	if (image == NULL) {
4810c0fea5dSIngo Weinhold 		FATAL("no memory for image %s\n", path);
4820c0fea5dSIngo Weinhold 		return NULL;
4830c0fea5dSIngo Weinhold 	}
4840c0fea5dSIngo Weinhold 
4850c0fea5dSIngo Weinhold 	memset(image, 0, allocSize);
4860c0fea5dSIngo Weinhold 
4870c0fea5dSIngo Weinhold 	strlcpy(image->path, path, sizeof(image->path));
4880c0fea5dSIngo Weinhold 
4890c0fea5dSIngo Weinhold 	// Make the last component of the supplied name the image name.
4900c0fea5dSIngo Weinhold 	// If present, DT_SONAME will replace this name.
4910c0fea5dSIngo Weinhold 	if ((lastSlash = strrchr(name, '/')))
4920c0fea5dSIngo Weinhold 		strlcpy(image->name, lastSlash + 1, sizeof(image->name));
4930c0fea5dSIngo Weinhold 	else
4940c0fea5dSIngo Weinhold 		strlcpy(image->name, name, sizeof(image->name));
4950c0fea5dSIngo Weinhold 
4960c0fea5dSIngo Weinhold 	image->ref_count = 1;
4970c0fea5dSIngo Weinhold 	image->num_regions = num_regions;
4980c0fea5dSIngo Weinhold 
4990c0fea5dSIngo Weinhold 	return image;
5000c0fea5dSIngo Weinhold }
5010c0fea5dSIngo Weinhold 
5020c0fea5dSIngo Weinhold 
5030c0fea5dSIngo Weinhold static void
5040c0fea5dSIngo Weinhold delete_image_struct(image_t *image)
5050c0fea5dSIngo Weinhold {
5060c0fea5dSIngo Weinhold #ifdef DEBUG
5070c0fea5dSIngo Weinhold 	size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t);
5080c0fea5dSIngo Weinhold 	memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
5090c0fea5dSIngo Weinhold #endif
5100c0fea5dSIngo Weinhold 	free(image->needed);
51110b4b5d1SIngo Weinhold 
51210b4b5d1SIngo Weinhold 	while (RuntimeLoaderSymbolPatcher* patcher
51310b4b5d1SIngo Weinhold 			= image->defined_symbol_patchers) {
51410b4b5d1SIngo Weinhold 		image->defined_symbol_patchers = patcher->next;
51510b4b5d1SIngo Weinhold 		delete patcher;
51610b4b5d1SIngo Weinhold 	}
51710b4b5d1SIngo Weinhold 	while (RuntimeLoaderSymbolPatcher* patcher
51810b4b5d1SIngo Weinhold 			= image->undefined_symbol_patchers) {
51910b4b5d1SIngo Weinhold 		image->undefined_symbol_patchers = patcher->next;
52010b4b5d1SIngo Weinhold 		delete patcher;
52110b4b5d1SIngo Weinhold 	}
5220c0fea5dSIngo Weinhold 
5230c0fea5dSIngo Weinhold #ifdef DEBUG
5249a6072a3SAxel Dörfler 	// overwrite images to make sure they aren't accidently reused anywhere
5250c0fea5dSIngo Weinhold 	memset(image, 0xa5, size);
5260c0fea5dSIngo Weinhold #endif
5270c0fea5dSIngo Weinhold 	free(image);
5280c0fea5dSIngo Weinhold }
5290c0fea5dSIngo Weinhold 
5300c0fea5dSIngo Weinhold 
5310c0fea5dSIngo Weinhold static void
5320c0fea5dSIngo Weinhold delete_image(image_t *image)
5330c0fea5dSIngo Weinhold {
5342760c4cdSAxel Dörfler 	if (image == NULL)
5352760c4cdSAxel Dörfler 		return;
5362760c4cdSAxel Dörfler 
5370c0fea5dSIngo Weinhold 	_kern_unregister_image(image->id);
5380c0fea5dSIngo Weinhold 		// registered in load_container()
5390c0fea5dSIngo Weinhold 
5400c0fea5dSIngo Weinhold 	delete_image_struct(image);
5410c0fea5dSIngo Weinhold }
5420c0fea5dSIngo Weinhold 
5430c0fea5dSIngo Weinhold 
5440c85bd05SIngo Weinhold static void
5450c85bd05SIngo Weinhold update_image_flags_recursively(image_t* image, uint32 flagsToSet,
5460c85bd05SIngo Weinhold 	uint32 flagsToClear)
5470c85bd05SIngo Weinhold {
5480c85bd05SIngo Weinhold 	image_t* queue[sLoadedImageCount];
5490c85bd05SIngo Weinhold 	uint32 count = 0;
5500c85bd05SIngo Weinhold 	uint32 index = 0;
5510c85bd05SIngo Weinhold 	queue[count++] = image;
5520c85bd05SIngo Weinhold 	image->flags |= RFLAG_VISITED;
5530c85bd05SIngo Weinhold 
5540c85bd05SIngo Weinhold 	while (index < count) {
5550c85bd05SIngo Weinhold 		// pop next image
5560c85bd05SIngo Weinhold 		image = queue[index++];
5570c85bd05SIngo Weinhold 
5580c85bd05SIngo Weinhold 		// push dependencies
5590c85bd05SIngo Weinhold 		for (uint32 i = 0; i < image->num_needed; i++) {
5600c85bd05SIngo Weinhold 			image_t* needed = image->needed[i];
5610c85bd05SIngo Weinhold 			if ((needed->flags & RFLAG_VISITED) == 0) {
5620c85bd05SIngo Weinhold 				queue[count++] = needed;
5630c85bd05SIngo Weinhold 				needed->flags |= RFLAG_VISITED;
5640c85bd05SIngo Weinhold 			}
5650c85bd05SIngo Weinhold 		}
5660c85bd05SIngo Weinhold 	}
5670c85bd05SIngo Weinhold 
5680c85bd05SIngo Weinhold 	// update flags
5690c85bd05SIngo Weinhold 	for (uint32 i = 0; i < count; i++) {
5700c85bd05SIngo Weinhold 		queue[i]->flags = (queue[i]->flags | flagsToSet)
5710c85bd05SIngo Weinhold 			& ~(flagsToClear | RFLAG_VISITED);
5720c85bd05SIngo Weinhold 	}
5730c85bd05SIngo Weinhold }
5740c85bd05SIngo Weinhold 
5750c85bd05SIngo Weinhold 
5760c85bd05SIngo Weinhold static void
5770c85bd05SIngo Weinhold set_image_flags_recursively(image_t* image, uint32 flags)
5780c85bd05SIngo Weinhold {
5790c85bd05SIngo Weinhold 	update_image_flags_recursively(image, flags, 0);
5800c85bd05SIngo Weinhold }
5810c85bd05SIngo Weinhold 
5820c85bd05SIngo Weinhold 
5830c85bd05SIngo Weinhold static void
5840c85bd05SIngo Weinhold clear_image_flags_recursively(image_t* image, uint32 flags)
5850c85bd05SIngo Weinhold {
5860c85bd05SIngo Weinhold 	update_image_flags_recursively(image, 0, flags);
5870c85bd05SIngo Weinhold }
5880c85bd05SIngo Weinhold 
5890c85bd05SIngo Weinhold 
5900c0fea5dSIngo Weinhold static status_t
5910c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
5920c0fea5dSIngo Weinhold {
5930c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheader;
5940c0fea5dSIngo Weinhold 	int regcount;
5950c0fea5dSIngo Weinhold 	int i;
5960c0fea5dSIngo Weinhold 
5970c0fea5dSIngo Weinhold 	regcount = 0;
5980c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
5990c0fea5dSIngo Weinhold 		pheader = (struct Elf32_Phdr *)(buff + i * phentsize);
6000c0fea5dSIngo Weinhold 
6010c0fea5dSIngo Weinhold 		switch (pheader->p_type) {
6020c0fea5dSIngo Weinhold 			case PT_NULL:
6030c0fea5dSIngo Weinhold 				/* NOP header */
6040c0fea5dSIngo Weinhold 				break;
6050c0fea5dSIngo Weinhold 			case PT_LOAD:
6060c0fea5dSIngo Weinhold 				if (pheader->p_memsz == pheader->p_filesz) {
6070c0fea5dSIngo Weinhold 					/*
6080c0fea5dSIngo Weinhold 					 * everything in one area
6090c0fea5dSIngo Weinhold 					 */
6100c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
6110c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_memsz;
6120c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
6130c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz
6140c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
6150c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
6160c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
6170c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
6180c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
6190c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
6200c0fea5dSIngo Weinhold 						// this is a writable segment
6210c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
6220c0fea5dSIngo Weinhold 					}
6230c0fea5dSIngo Weinhold 				} else {
6240c0fea5dSIngo Weinhold 					/*
6250c0fea5dSIngo Weinhold 					 * may require splitting
6260c0fea5dSIngo Weinhold 					 */
6270c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz);
6280c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz);
6290c0fea5dSIngo Weinhold 
6300c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
6310c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_filesz;
6320c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
6330c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz
6340c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
6350c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
6360c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
6370c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
6380c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
6390c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
6400c0fea5dSIngo Weinhold 						// this is a writable segment
6410c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
6420c0fea5dSIngo Weinhold 					}
6430c0fea5dSIngo Weinhold 
6440c0fea5dSIngo Weinhold 					if (A != B) {
6450c0fea5dSIngo Weinhold 						/*
6460c0fea5dSIngo Weinhold 						 * yeah, it requires splitting
6470c0fea5dSIngo Weinhold 						 */
6480c0fea5dSIngo Weinhold 						regcount += 1;
6490c0fea5dSIngo Weinhold 						image->regions[regcount].start = pheader->p_vaddr;
6500c0fea5dSIngo Weinhold 						image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz;
6510c0fea5dSIngo Weinhold 						image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
6520c0fea5dSIngo Weinhold 						image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr))
6530c0fea5dSIngo Weinhold 							- image->regions[regcount-1].vmsize;
6540c0fea5dSIngo Weinhold 						image->regions[regcount].fdstart = 0;
6550c0fea5dSIngo Weinhold 						image->regions[regcount].fdsize = 0;
6560c0fea5dSIngo Weinhold 						image->regions[regcount].delta = 0;
6570c0fea5dSIngo Weinhold 						image->regions[regcount].flags = RFLAG_ANON;
6580c0fea5dSIngo Weinhold 						if (pheader->p_flags & PF_WRITE) {
6590c0fea5dSIngo Weinhold 							// this is a writable segment
6600c0fea5dSIngo Weinhold 							image->regions[regcount].flags |= RFLAG_RW;
6610c0fea5dSIngo Weinhold 						}
6620c0fea5dSIngo Weinhold 					}
6630c0fea5dSIngo Weinhold 				}
6640c0fea5dSIngo Weinhold 				regcount += 1;
6650c0fea5dSIngo Weinhold 				break;
6660c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
6670c0fea5dSIngo Weinhold 				image->dynamic_ptr = pheader->p_vaddr;
6680c0fea5dSIngo Weinhold 				break;
6690c0fea5dSIngo Weinhold 			case PT_INTERP:
6700c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
6710c0fea5dSIngo Weinhold 				break;
6720c0fea5dSIngo Weinhold 			case PT_NOTE:
6730c0fea5dSIngo Weinhold 				/* unsupported */
6740c0fea5dSIngo Weinhold 				break;
6750c0fea5dSIngo Weinhold 			case PT_SHLIB:
6760c0fea5dSIngo Weinhold 				/* undefined semantics */
6770c0fea5dSIngo Weinhold 				break;
6780c0fea5dSIngo Weinhold 			case PT_PHDR:
6790c0fea5dSIngo Weinhold 				/* we don't use it */
6800c0fea5dSIngo Weinhold 				break;
6810c0fea5dSIngo Weinhold 			default:
6820c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type);
6830c0fea5dSIngo Weinhold 				return B_BAD_DATA;
6840c0fea5dSIngo Weinhold 		}
6850c0fea5dSIngo Weinhold 	}
6860c0fea5dSIngo Weinhold 
6870c0fea5dSIngo Weinhold 	return B_OK;
6880c0fea5dSIngo Weinhold }
6890c0fea5dSIngo Weinhold 
6900c0fea5dSIngo Weinhold 
6910c0fea5dSIngo Weinhold static bool
69234982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader,
69334982809SIngo Weinhold 	int32 sheaderSize, char* buffer, size_t bufferSize)
69434982809SIngo Weinhold {
69534982809SIngo Weinhold 	image->gcc_version.major = 0;
69634982809SIngo Weinhold 	image->gcc_version.middle = 0;
69734982809SIngo Weinhold 	image->gcc_version.minor = 0;
69834982809SIngo Weinhold 
69934982809SIngo Weinhold 	if (sheaderSize > (int)bufferSize) {
70034982809SIngo Weinhold 		FATAL("Cannot handle section headers bigger than %lu\n", bufferSize);
70134982809SIngo Weinhold 		return false;
70234982809SIngo Weinhold 	}
70334982809SIngo Weinhold 
70434982809SIngo Weinhold 	// read section headers
70534982809SIngo Weinhold 	ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize);
70634982809SIngo Weinhold 	if (length != sheaderSize) {
70734982809SIngo Weinhold 		FATAL("Could not read section headers: %s\n", strerror(length));
70834982809SIngo Weinhold 		return false;
70934982809SIngo Weinhold 	}
71034982809SIngo Weinhold 
71134982809SIngo Weinhold 	// load the string section
71234982809SIngo Weinhold 	Elf32_Shdr* sectionHeader
71334982809SIngo Weinhold 		= (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize);
71434982809SIngo Weinhold 
71534982809SIngo Weinhold 	if (sheaderSize + sectionHeader->sh_size > bufferSize) {
71634982809SIngo Weinhold 		FATAL("Buffer not big enough for section string section\n");
71734982809SIngo Weinhold 		return false;
71834982809SIngo Weinhold 	}
71934982809SIngo Weinhold 
72034982809SIngo Weinhold 	char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size;
72134982809SIngo Weinhold 	length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings,
72234982809SIngo Weinhold 		sectionHeader->sh_size);
72334982809SIngo Weinhold 	if (length != (int)sectionHeader->sh_size) {
72434982809SIngo Weinhold 		FATAL("Could not read section string section: %s\n", strerror(length));
72534982809SIngo Weinhold 		return false;
72634982809SIngo Weinhold 	}
72734982809SIngo Weinhold 
72834982809SIngo Weinhold 	// find the .comment section
72934982809SIngo Weinhold 	off_t commentOffset = 0;
73034982809SIngo Weinhold 	size_t commentSize = 0;
73134982809SIngo Weinhold 	for (uint32 i = 0; i < eheader.e_shnum; i++) {
73234982809SIngo Weinhold 		sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize);
73334982809SIngo Weinhold 		const char* sectionName = sectionStrings + sectionHeader->sh_name;
73434982809SIngo Weinhold 		if (sectionHeader->sh_name != 0
73534982809SIngo Weinhold 			&& strcmp(sectionName, ".comment") == 0) {
73634982809SIngo Weinhold 			commentOffset = sectionHeader->sh_offset;
73734982809SIngo Weinhold 			commentSize = sectionHeader->sh_size;
73834982809SIngo Weinhold 			break;
73934982809SIngo Weinhold 		}
74034982809SIngo Weinhold 	}
74134982809SIngo Weinhold 
74234982809SIngo Weinhold 	if (commentSize == 0) {
74334982809SIngo Weinhold 		FATAL("Could not find .comment section\n");
74434982809SIngo Weinhold 		return false;
74534982809SIngo Weinhold 	}
74634982809SIngo Weinhold 
74734982809SIngo Weinhold 	// read a part of the comment section
74834982809SIngo Weinhold 	if (commentSize > 512)
74934982809SIngo Weinhold 		commentSize = 512;
75034982809SIngo Weinhold 
75134982809SIngo Weinhold 	length = _kern_read(fd, commentOffset, buffer, commentSize);
75234982809SIngo Weinhold 	if (length != (int)commentSize) {
75334982809SIngo Weinhold 		FATAL("Could not read .comment section: %s\n", strerror(length));
75434982809SIngo Weinhold 		return false;
75534982809SIngo Weinhold 	}
75634982809SIngo Weinhold 
75734982809SIngo Weinhold 	// the common prefix of the strings in the .comment section
75834982809SIngo Weinhold 	static const char* kGCCVersionPrefix = "GCC: (GNU) ";
75934982809SIngo Weinhold 	size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix);
76034982809SIngo Weinhold 
76134982809SIngo Weinhold 	size_t index = 0;
76234982809SIngo Weinhold 	int gccMajor = 0;
76334982809SIngo Weinhold 	int gccMiddle = 0;
76434982809SIngo Weinhold 	int gccMinor = 0;
7652716cfd3SAxel Dörfler 	bool isHaiku = true;
76634982809SIngo Weinhold 
76734982809SIngo Weinhold 	// Read up to 10 comments. The first three or four are usually from the
76834982809SIngo Weinhold 	// glue code.
76934982809SIngo Weinhold 	for (int i = 0; i < 10; i++) {
77034982809SIngo Weinhold 		// skip '\0'
77134982809SIngo Weinhold 		while (index < commentSize && buffer[index] == '\0')
77234982809SIngo Weinhold 			index++;
77334982809SIngo Weinhold 		char* stringStart = buffer + index;
77434982809SIngo Weinhold 
77534982809SIngo Weinhold 		// find string end
77634982809SIngo Weinhold 		while (index < commentSize && buffer[index] != '\0')
77734982809SIngo Weinhold 			index++;
77834982809SIngo Weinhold 
77934982809SIngo Weinhold 		// ignore the entry at the end of the buffer
78034982809SIngo Weinhold 		if (index == commentSize)
78134982809SIngo Weinhold 			break;
78234982809SIngo Weinhold 
78334982809SIngo Weinhold 		// We have to analyze string like these:
78434982809SIngo Weinhold 		// GCC: (GNU) 2.9-beos-991026
78534982809SIngo Weinhold 		// GCC: (GNU) 2.95.3-haiku-080322
78634982809SIngo Weinhold 		// GCC: (GNU) 4.1.2
78734982809SIngo Weinhold 
78834982809SIngo Weinhold 		// skip the common prefix
78934982809SIngo Weinhold 		if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0)
79034982809SIngo Weinhold 			continue;
79134982809SIngo Weinhold 
79234982809SIngo Weinhold 		// the rest is the GCC version
79334982809SIngo Weinhold 		char* gccVersion = stringStart + gccVersionPrefixLen;
79434982809SIngo Weinhold 		char* gccPlatform = strchr(gccVersion, '-');
79534982809SIngo Weinhold 		char* patchLevel = NULL;
79634982809SIngo Weinhold 		if (gccPlatform != NULL) {
79734982809SIngo Weinhold 			*gccPlatform = '\0';
79834982809SIngo Weinhold 			gccPlatform++;
79934982809SIngo Weinhold 			patchLevel = strchr(gccPlatform, '-');
80034982809SIngo Weinhold 			if (patchLevel != NULL) {
80134982809SIngo Weinhold 				*patchLevel = '\0';
80234982809SIngo Weinhold 				patchLevel++;
80334982809SIngo Weinhold 			}
80434982809SIngo Weinhold 		}
80534982809SIngo Weinhold 
80634982809SIngo Weinhold 		// split the gcc version into major, middle, and minor
80734982809SIngo Weinhold 		int version[3] = { 0, 0, 0 };
80834982809SIngo Weinhold 
80934982809SIngo Weinhold 		for (int k = 0; gccVersion != NULL && k < 3; k++) {
81034982809SIngo Weinhold 			char* dot = strchr(gccVersion, '.');
81134982809SIngo Weinhold 			if (dot) {
81234982809SIngo Weinhold 				*dot = '\0';
81334982809SIngo Weinhold 				dot++;
81434982809SIngo Weinhold 			}
81534982809SIngo Weinhold 			version[k] = atoi(gccVersion);
81634982809SIngo Weinhold 			gccVersion = dot;
81734982809SIngo Weinhold 		}
81834982809SIngo Weinhold 
81934982809SIngo Weinhold 		// got any version?
82034982809SIngo Weinhold 		if (version[0] == 0)
82134982809SIngo Weinhold 			continue;
82234982809SIngo Weinhold 
82334982809SIngo Weinhold 		// Select the gcc version with the smallest major, but the greatest
82434982809SIngo Weinhold 		// middle/minor. This should usually ignore the glue code version as
82534982809SIngo Weinhold 		// well as cases where e.g. in a gcc 2 program a single C file has
82634982809SIngo Weinhold 		// been compiled with gcc 4.
82734982809SIngo Weinhold 		if (gccMajor == 0 || gccMajor > version[0]
82834982809SIngo Weinhold 		 	|| gccMajor == version[0]
82934982809SIngo Weinhold 				&& (gccMiddle < version[1]
83034982809SIngo Weinhold 					|| gccMiddle == version[1] && gccMinor < version[2])) {
83134982809SIngo Weinhold 			gccMajor = version[0];
83234982809SIngo Weinhold 			gccMiddle = version[1];
83334982809SIngo Weinhold 			gccMinor = version[2];
83434982809SIngo Weinhold 		}
8352716cfd3SAxel Dörfler 
83685f9771aSFrançois Revol 		if (gccMajor == 2 && gccPlatform != NULL && strcmp(gccPlatform, "haiku"))
8372716cfd3SAxel Dörfler 			isHaiku = false;
83834982809SIngo Weinhold 	}
83934982809SIngo Weinhold 
84034982809SIngo Weinhold 	image->gcc_version.major = gccMajor;
84134982809SIngo Weinhold 	image->gcc_version.middle = gccMiddle;
84234982809SIngo Weinhold 	image->gcc_version.minor = gccMinor;
8432716cfd3SAxel Dörfler 	image->gcc_version.haiku = isHaiku;
84434982809SIngo Weinhold 
84534982809SIngo Weinhold 	return gccMajor != 0;
84634982809SIngo Weinhold }
84734982809SIngo Weinhold 
84834982809SIngo Weinhold 
84934982809SIngo Weinhold static bool
8500c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image)
8510c0fea5dSIngo Weinhold {
8520c0fea5dSIngo Weinhold 	uint32 i;
8530c0fea5dSIngo Weinhold 
8540c0fea5dSIngo Weinhold 	if (!image->dynamic_ptr)
8550c0fea5dSIngo Weinhold 		return true;
8560c0fea5dSIngo Weinhold 
8570c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
8580c0fea5dSIngo Weinhold 		if (image->dynamic_ptr >= image->regions[i].start
8590c0fea5dSIngo Weinhold 			&& image->dynamic_ptr < image->regions[i].start + image->regions[i].size)
8600c0fea5dSIngo Weinhold 			return true;
8610c0fea5dSIngo Weinhold 	}
8620c0fea5dSIngo Weinhold 
8630c0fea5dSIngo Weinhold 	return false;
8640c0fea5dSIngo Weinhold }
8650c0fea5dSIngo Weinhold 
8660c0fea5dSIngo Weinhold 
8670c0fea5dSIngo Weinhold /**	This function will change the protection of all read-only segments
8680c0fea5dSIngo Weinhold  *	to really be read-only.
8690c0fea5dSIngo Weinhold  *	The areas have to be read/write first, so that they can be relocated.
8700c0fea5dSIngo Weinhold  */
8710c0fea5dSIngo Weinhold 
8720c0fea5dSIngo Weinhold static void
8730c0fea5dSIngo Weinhold remap_images(void)
8740c0fea5dSIngo Weinhold {
8750c0fea5dSIngo Weinhold 	image_t *image;
8760c0fea5dSIngo Weinhold 	uint32 i;
8770c0fea5dSIngo Weinhold 
8780c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
8790c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_regions; i++) {
8800c0fea5dSIngo Weinhold 			if ((image->regions[i].flags & RFLAG_RW) == 0
8810c0fea5dSIngo Weinhold 				&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
8820c0fea5dSIngo Weinhold 				// we only need to do this once, so we remember those we've already mapped
8830c0fea5dSIngo Weinhold 				if (_kern_set_area_protection(image->regions[i].id,
8840c0fea5dSIngo Weinhold 						B_READ_AREA | B_EXECUTE_AREA) == B_OK)
8850c0fea5dSIngo Weinhold 					image->regions[i].flags |= RFLAG_REMAPPED;
8860c0fea5dSIngo Weinhold 			}
8870c0fea5dSIngo Weinhold 		}
8880c0fea5dSIngo Weinhold 	}
8890c0fea5dSIngo Weinhold }
8900c0fea5dSIngo Weinhold 
8910c0fea5dSIngo Weinhold 
8920c0fea5dSIngo Weinhold static status_t
8930c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed)
8940c0fea5dSIngo Weinhold {
8950c0fea5dSIngo Weinhold 	status_t status = B_OK;
8960c0fea5dSIngo Weinhold 	const char *baseName;
8970c0fea5dSIngo Weinhold 	uint32 i;
8980c0fea5dSIngo Weinhold 
8990c0fea5dSIngo Weinhold 	(void)(fd);
9000c0fea5dSIngo Weinhold 
9010c0fea5dSIngo Weinhold 	// cut the file name from the path as base name for the created areas
9020c0fea5dSIngo Weinhold 	baseName = strrchr(path, '/');
9030c0fea5dSIngo Weinhold 	if (baseName != NULL)
9040c0fea5dSIngo Weinhold 		baseName++;
9050c0fea5dSIngo Weinhold 	else
9060c0fea5dSIngo Weinhold 		baseName = path;
9070c0fea5dSIngo Weinhold 
9080c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
9090c0fea5dSIngo Weinhold 		char regionName[B_OS_NAME_LENGTH];
9100c0fea5dSIngo Weinhold 		addr_t loadAddress;
9110c0fea5dSIngo Weinhold 		uint32 addressSpecifier;
9120c0fea5dSIngo Weinhold 
9130c0fea5dSIngo Weinhold 		// for BeOS compatibility: if we load an old BeOS executable, we
9140c0fea5dSIngo Weinhold 		// have to relocate it, if possible - we recognize it because the
9150c0fea5dSIngo Weinhold 		// vmstart is set to 0 (hopefully always)
9160c0fea5dSIngo Weinhold 		if (fixed && image->regions[i].vmstart == 0)
9170c0fea5dSIngo Weinhold 			fixed = false;
9180c0fea5dSIngo Weinhold 
9190c0fea5dSIngo Weinhold 		snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
9200c0fea5dSIngo Weinhold 			baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
9210c0fea5dSIngo Weinhold 
9220c0fea5dSIngo Weinhold 		if (image->dynamic_ptr && !fixed) {
9230c0fea5dSIngo Weinhold 			// relocatable image... we can afford to place wherever
9240c0fea5dSIngo Weinhold 			if (i == 0) {
9250c0fea5dSIngo Weinhold 				// but only the first segment gets a free ride
9260c0fea5dSIngo Weinhold 				loadAddress = RLD_PROGRAM_BASE;
9270c0fea5dSIngo Weinhold 				addressSpecifier = B_BASE_ADDRESS;
9280c0fea5dSIngo Weinhold 			} else {
9290c0fea5dSIngo Weinhold 				loadAddress = image->regions[i].vmstart + image->regions[i-1].delta;
9300c0fea5dSIngo Weinhold 				addressSpecifier = B_EXACT_ADDRESS;
9310c0fea5dSIngo Weinhold 			}
9320c0fea5dSIngo Weinhold 		} else {
9330c0fea5dSIngo Weinhold 			// not relocatable, put it where it asks or die trying
9340c0fea5dSIngo Weinhold 			loadAddress = image->regions[i].vmstart;
9350c0fea5dSIngo Weinhold 			addressSpecifier = B_EXACT_ADDRESS;
9360c0fea5dSIngo Weinhold 		}
9370c0fea5dSIngo Weinhold 
9380c0fea5dSIngo Weinhold 		if (image->regions[i].flags & RFLAG_ANON) {
9390c0fea5dSIngo Weinhold 			image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress,
9400c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_NO_LOCK,
9410c0fea5dSIngo Weinhold 				B_READ_AREA | B_WRITE_AREA);
9420c0fea5dSIngo Weinhold 
9430c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
9440c0fea5dSIngo Weinhold 				status = image->regions[i].id;
9450c0fea5dSIngo Weinhold 				goto error;
9460c0fea5dSIngo Weinhold 			}
9470c0fea5dSIngo Weinhold 
9480c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
9490c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
9500c0fea5dSIngo Weinhold 		} else {
9513cf7ecd1SIngo Weinhold 			image->regions[i].id = _kern_map_file(regionName,
9523cf7ecd1SIngo Weinhold 				(void **)&loadAddress, addressSpecifier,
9533cf7ecd1SIngo Weinhold 				image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
9543cf7ecd1SIngo Weinhold 				REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart));
9550c0fea5dSIngo Weinhold 
9560c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
9570c0fea5dSIngo Weinhold 				status = image->regions[i].id;
9580c0fea5dSIngo Weinhold 				goto error;
9590c0fea5dSIngo Weinhold 			}
9600c0fea5dSIngo Weinhold 
9610c0fea5dSIngo Weinhold 			TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
9620c0fea5dSIngo Weinhold 				(void *)loadAddress, image->regions[i].vmsize,
9630c0fea5dSIngo Weinhold 				image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
9640c0fea5dSIngo Weinhold 
9650c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
9660c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
9670c0fea5dSIngo Weinhold 
9680c0fea5dSIngo Weinhold 			// handle trailer bits in data segment
9690c0fea5dSIngo Weinhold 			if (image->regions[i].flags & RFLAG_RW) {
9700c0fea5dSIngo Weinhold 				addr_t startClearing;
9710c0fea5dSIngo Weinhold 				addr_t toClear;
9720c0fea5dSIngo Weinhold 
9730c0fea5dSIngo Weinhold 				startClearing = image->regions[i].vmstart
9740c0fea5dSIngo Weinhold 					+ PAGE_OFFSET(image->regions[i].start)
9750c0fea5dSIngo Weinhold 					+ image->regions[i].size;
9760c0fea5dSIngo Weinhold 				toClear = image->regions[i].vmsize
9770c0fea5dSIngo Weinhold 					- PAGE_OFFSET(image->regions[i].start)
9780c0fea5dSIngo Weinhold 					- image->regions[i].size;
9790c0fea5dSIngo Weinhold 
9800c0fea5dSIngo Weinhold 				TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear));
9810c0fea5dSIngo Weinhold 				memset((void *)startClearing, 0, toClear);
9820c0fea5dSIngo Weinhold 			}
9830c0fea5dSIngo Weinhold 		}
9840c0fea5dSIngo Weinhold 	}
9850c0fea5dSIngo Weinhold 
9860c0fea5dSIngo Weinhold 	if (image->dynamic_ptr)
9870c0fea5dSIngo Weinhold 		image->dynamic_ptr += image->regions[0].delta;
9880c0fea5dSIngo Weinhold 
9890c0fea5dSIngo Weinhold 	return B_OK;
9900c0fea5dSIngo Weinhold 
9910c0fea5dSIngo Weinhold error:
9920c0fea5dSIngo Weinhold 	return status;
9930c0fea5dSIngo Weinhold }
9940c0fea5dSIngo Weinhold 
9950c0fea5dSIngo Weinhold 
9960c0fea5dSIngo Weinhold static void
9970c0fea5dSIngo Weinhold unmap_image(image_t *image)
9980c0fea5dSIngo Weinhold {
9990c0fea5dSIngo Weinhold 	uint32 i;
10000c0fea5dSIngo Weinhold 
10010c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
10020c0fea5dSIngo Weinhold 		_kern_delete_area(image->regions[i].id);
10030c0fea5dSIngo Weinhold 
10040c0fea5dSIngo Weinhold 		image->regions[i].id = -1;
10050c0fea5dSIngo Weinhold 	}
10060c0fea5dSIngo Weinhold }
10070c0fea5dSIngo Weinhold 
10080c0fea5dSIngo Weinhold 
10090c0fea5dSIngo Weinhold static bool
10100c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image)
10110c0fea5dSIngo Weinhold {
10120c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d;
10130c0fea5dSIngo Weinhold 	int i;
10140c0fea5dSIngo Weinhold 	int sonameOffset = -1;
10150c0fea5dSIngo Weinhold 
10160c0fea5dSIngo Weinhold 	image->symhash = 0;
10170c0fea5dSIngo Weinhold 	image->syms = 0;
10180c0fea5dSIngo Weinhold 	image->strtab = 0;
10190c0fea5dSIngo Weinhold 
10200c0fea5dSIngo Weinhold 	d = (struct Elf32_Dyn *)image->dynamic_ptr;
10210c0fea5dSIngo Weinhold 	if (!d)
10220c0fea5dSIngo Weinhold 		return true;
10230c0fea5dSIngo Weinhold 
10240c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
10250c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
10260c0fea5dSIngo Weinhold 			case DT_NEEDED:
10270c0fea5dSIngo Weinhold 				image->num_needed += 1;
10280c0fea5dSIngo Weinhold 				break;
10290c0fea5dSIngo Weinhold 			case DT_HASH:
10300c0fea5dSIngo Weinhold 				image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta);
10310c0fea5dSIngo Weinhold 				break;
10320c0fea5dSIngo Weinhold 			case DT_STRTAB:
10330c0fea5dSIngo Weinhold 				image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
10340c0fea5dSIngo Weinhold 				break;
10350c0fea5dSIngo Weinhold 			case DT_SYMTAB:
10360c0fea5dSIngo Weinhold 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
10370c0fea5dSIngo Weinhold 				break;
10380c0fea5dSIngo Weinhold 			case DT_REL:
10390c0fea5dSIngo Weinhold 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
10400c0fea5dSIngo Weinhold 				break;
10410c0fea5dSIngo Weinhold 			case DT_RELSZ:
10420c0fea5dSIngo Weinhold 				image->rel_len = d[i].d_un.d_val;
10430c0fea5dSIngo Weinhold 				break;
10440c0fea5dSIngo Weinhold 			case DT_RELA:
10450c0fea5dSIngo Weinhold 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
10460c0fea5dSIngo Weinhold 				break;
10470c0fea5dSIngo Weinhold 			case DT_RELASZ:
10480c0fea5dSIngo Weinhold 				image->rela_len = d[i].d_un.d_val;
10490c0fea5dSIngo Weinhold 				break;
10500c0fea5dSIngo Weinhold 			// TK: procedure linkage table
10510c0fea5dSIngo Weinhold 			case DT_JMPREL:
10520c0fea5dSIngo Weinhold 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
10530c0fea5dSIngo Weinhold 				break;
10540c0fea5dSIngo Weinhold 			case DT_PLTRELSZ:
10550c0fea5dSIngo Weinhold 				image->pltrel_len = d[i].d_un.d_val;
10560c0fea5dSIngo Weinhold 				break;
10570c0fea5dSIngo Weinhold 			case DT_INIT:
10580c0fea5dSIngo Weinhold 				image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
10590c0fea5dSIngo Weinhold 				break;
10600c0fea5dSIngo Weinhold 			case DT_FINI:
10610c0fea5dSIngo Weinhold 				image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
10620c0fea5dSIngo Weinhold 				break;
10630c0fea5dSIngo Weinhold 			case DT_SONAME:
10640c0fea5dSIngo Weinhold 				sonameOffset = d[i].d_un.d_val;
10650c0fea5dSIngo Weinhold 				break;
10660c0fea5dSIngo Weinhold 			default:
10670c0fea5dSIngo Weinhold 				continue;
10680c0fea5dSIngo Weinhold 		}
10690c0fea5dSIngo Weinhold 	}
10700c0fea5dSIngo Weinhold 
10710c0fea5dSIngo Weinhold 	// lets make sure we found all the required sections
10720c0fea5dSIngo Weinhold 	if (!image->symhash || !image->syms || !image->strtab)
10730c0fea5dSIngo Weinhold 		return false;
10740c0fea5dSIngo Weinhold 
10750c0fea5dSIngo Weinhold 	if (sonameOffset >= 0)
10760c0fea5dSIngo Weinhold 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
10770c0fea5dSIngo Weinhold 
10780c0fea5dSIngo Weinhold 	return true;
10790c0fea5dSIngo Weinhold }
10800c0fea5dSIngo Weinhold 
10810c0fea5dSIngo Weinhold 
108210b4b5d1SIngo Weinhold static void
108310b4b5d1SIngo Weinhold patch_defined_symbol(image_t* image, const char* name, void** symbol,
108410b4b5d1SIngo Weinhold 	int32* type)
108510b4b5d1SIngo Weinhold {
108610b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers;
108710b4b5d1SIngo Weinhold 	while (patcher != NULL && *symbol != 0) {
108810b4b5d1SIngo Weinhold 		image_t* inImage = image;
108910b4b5d1SIngo Weinhold 		patcher->patcher(patcher->cookie, NULL, image, name, &inImage,
109010b4b5d1SIngo Weinhold 			symbol, type);
109110b4b5d1SIngo Weinhold 		patcher = patcher->next;
109210b4b5d1SIngo Weinhold 	}
109310b4b5d1SIngo Weinhold }
109410b4b5d1SIngo Weinhold 
109510b4b5d1SIngo Weinhold 
109610b4b5d1SIngo Weinhold static void
109710b4b5d1SIngo Weinhold patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
109810b4b5d1SIngo Weinhold 	image_t** foundInImage, void** symbol, int32* type)
109910b4b5d1SIngo Weinhold {
110010b4b5d1SIngo Weinhold 	if (*foundInImage != NULL)
110110b4b5d1SIngo Weinhold 		patch_defined_symbol(*foundInImage, name, symbol, type);
110210b4b5d1SIngo Weinhold 
110310b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers;
110410b4b5d1SIngo Weinhold 	while (patcher != NULL) {
110510b4b5d1SIngo Weinhold 		patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage,
110610b4b5d1SIngo Weinhold 			symbol, type);
110710b4b5d1SIngo Weinhold 		patcher = patcher->next;
110810b4b5d1SIngo Weinhold 	}
110910b4b5d1SIngo Weinhold }
111010b4b5d1SIngo Weinhold 
111110b4b5d1SIngo Weinhold 
111210b4b5d1SIngo Weinhold status_t
111310b4b5d1SIngo Weinhold register_defined_symbol_patcher(struct image_t* image,
111410b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
111510b4b5d1SIngo Weinhold {
111610b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher
111710b4b5d1SIngo Weinhold 		= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
111810b4b5d1SIngo Weinhold 	if (patcher == NULL)
111910b4b5d1SIngo Weinhold 		return B_NO_MEMORY;
112010b4b5d1SIngo Weinhold 
112110b4b5d1SIngo Weinhold 	patcher->next = image->defined_symbol_patchers;
112210b4b5d1SIngo Weinhold 	image->defined_symbol_patchers = patcher;
112310b4b5d1SIngo Weinhold 
112410b4b5d1SIngo Weinhold 	return B_OK;
112510b4b5d1SIngo Weinhold }
112610b4b5d1SIngo Weinhold 
112710b4b5d1SIngo Weinhold 
112810b4b5d1SIngo Weinhold void
112910b4b5d1SIngo Weinhold unregister_defined_symbol_patcher(struct image_t* image,
113010b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
113110b4b5d1SIngo Weinhold {
113210b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher** patcher = &image->defined_symbol_patchers;
113310b4b5d1SIngo Weinhold 	while (*patcher != NULL) {
113410b4b5d1SIngo Weinhold 		if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
113510b4b5d1SIngo Weinhold 			RuntimeLoaderSymbolPatcher* toDelete = *patcher;
113610b4b5d1SIngo Weinhold 			*patcher = (*patcher)->next;
113710b4b5d1SIngo Weinhold 			delete toDelete;
113810b4b5d1SIngo Weinhold 			return;
113910b4b5d1SIngo Weinhold 		}
114010b4b5d1SIngo Weinhold 		patcher = &(*patcher)->next;
114110b4b5d1SIngo Weinhold 	}
114210b4b5d1SIngo Weinhold }
114310b4b5d1SIngo Weinhold 
114410b4b5d1SIngo Weinhold 
114510b4b5d1SIngo Weinhold status_t
114610b4b5d1SIngo Weinhold register_undefined_symbol_patcher(struct image_t* image,
114710b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
114810b4b5d1SIngo Weinhold {
114910b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher
115010b4b5d1SIngo Weinhold 		= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
115110b4b5d1SIngo Weinhold 	if (patcher == NULL)
115210b4b5d1SIngo Weinhold 		return B_NO_MEMORY;
115310b4b5d1SIngo Weinhold 
115410b4b5d1SIngo Weinhold 	patcher->next = image->undefined_symbol_patchers;
115510b4b5d1SIngo Weinhold 	image->undefined_symbol_patchers = patcher;
115610b4b5d1SIngo Weinhold 
115710b4b5d1SIngo Weinhold 	return B_OK;
115810b4b5d1SIngo Weinhold }
115910b4b5d1SIngo Weinhold 
116010b4b5d1SIngo Weinhold 
116110b4b5d1SIngo Weinhold void
116210b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher(struct image_t* image,
116310b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
116410b4b5d1SIngo Weinhold {
116510b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher** patcher = &image->undefined_symbol_patchers;
116610b4b5d1SIngo Weinhold 	while (*patcher != NULL) {
116710b4b5d1SIngo Weinhold 		if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
116810b4b5d1SIngo Weinhold 			RuntimeLoaderSymbolPatcher* toDelete = *patcher;
116910b4b5d1SIngo Weinhold 			*patcher = (*patcher)->next;
117010b4b5d1SIngo Weinhold 			delete toDelete;
117110b4b5d1SIngo Weinhold 			return;
117210b4b5d1SIngo Weinhold 		}
117310b4b5d1SIngo Weinhold 		patcher = &(*patcher)->next;
117410b4b5d1SIngo Weinhold 	}
117510b4b5d1SIngo Weinhold }
117610b4b5d1SIngo Weinhold 
117710b4b5d1SIngo Weinhold 
117810b4b5d1SIngo Weinhold runtime_loader_add_on_export gRuntimeLoaderAddOnExport = {
117910b4b5d1SIngo Weinhold 	register_defined_symbol_patcher,
118010b4b5d1SIngo Weinhold 	unregister_defined_symbol_patcher,
118110b4b5d1SIngo Weinhold 	register_undefined_symbol_patcher,
118210b4b5d1SIngo Weinhold 	unregister_undefined_symbol_patcher
118310b4b5d1SIngo Weinhold };
118410b4b5d1SIngo Weinhold 
118510b4b5d1SIngo Weinhold 
11860c0fea5dSIngo Weinhold static struct Elf32_Sym *
11870c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type)
11880c0fea5dSIngo Weinhold {
11890c0fea5dSIngo Weinhold 	uint32 hash, i;
11900c0fea5dSIngo Weinhold 
11910c0fea5dSIngo Weinhold 	// ToDo: "type" is currently ignored!
11920c0fea5dSIngo Weinhold 	(void)type;
11930c0fea5dSIngo Weinhold 
1194dd76bc97SIngo Weinhold 	if (image->dynamic_ptr == 0)
11950c0fea5dSIngo Weinhold 		return NULL;
11960c0fea5dSIngo Weinhold 
11970c0fea5dSIngo Weinhold 	hash = elf_hash((uint8 *)name) % HASHTABSIZE(image);
11980c0fea5dSIngo Weinhold 
11990c0fea5dSIngo Weinhold 	for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
12000c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = &image->syms[i];
12010c0fea5dSIngo Weinhold 
12020c0fea5dSIngo Weinhold 		if (symbol->st_shndx != SHN_UNDEF
12030c0fea5dSIngo Weinhold 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
12040c0fea5dSIngo Weinhold 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
12050c0fea5dSIngo Weinhold 			&& !strcmp(SYMNAME(image, symbol), name)) {
12060c0fea5dSIngo Weinhold 			// check if the type matches
12070c0fea5dSIngo Weinhold 			if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
12080c0fea5dSIngo Weinhold 				|| (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT))
12090c0fea5dSIngo Weinhold 				continue;
12100c0fea5dSIngo Weinhold 
12110c0fea5dSIngo Weinhold 			return symbol;
12120c0fea5dSIngo Weinhold 		}
12130c0fea5dSIngo Weinhold 	}
12140c0fea5dSIngo Weinhold 
12150c0fea5dSIngo Weinhold 	return NULL;
12160c0fea5dSIngo Weinhold }
12170c0fea5dSIngo Weinhold 
12180c0fea5dSIngo Weinhold 
121910b4b5d1SIngo Weinhold static status_t
122010b4b5d1SIngo Weinhold find_symbol(image_t* image, char const* symbolName, int32 symbolType,
122110b4b5d1SIngo Weinhold 	void **_location)
122210b4b5d1SIngo Weinhold {
122310b4b5d1SIngo Weinhold 	// get the symbol in the image
122410b4b5d1SIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol(image, symbolName, symbolType);
122510b4b5d1SIngo Weinhold 	if (symbol == NULL)
122610b4b5d1SIngo Weinhold 		return B_ENTRY_NOT_FOUND;
122710b4b5d1SIngo Weinhold 
122810b4b5d1SIngo Weinhold 	void* location = (void*)(symbol->st_value + image->regions[0].delta);
122910b4b5d1SIngo Weinhold 	patch_defined_symbol(image, symbolName, &location, &symbolType);
123010b4b5d1SIngo Weinhold 
123110b4b5d1SIngo Weinhold 	if (_location != NULL)
123210b4b5d1SIngo Weinhold 		*_location = location;
123310b4b5d1SIngo Weinhold 
123410b4b5d1SIngo Weinhold 	return B_OK;
123510b4b5d1SIngo Weinhold }
123610b4b5d1SIngo Weinhold 
123710b4b5d1SIngo Weinhold 
12380c85bd05SIngo Weinhold static status_t
12390c85bd05SIngo Weinhold find_symbol_breadth_first(image_t* image, const char* name, int32 type,
12400c85bd05SIngo Weinhold 	image_t** _foundInImage, void** _location)
12410c0fea5dSIngo Weinhold {
12420c85bd05SIngo Weinhold 	image_t* queue[sLoadedImageCount];
12430c85bd05SIngo Weinhold 	uint32 count = 0;
12440c85bd05SIngo Weinhold 	uint32 index = 0;
12450c85bd05SIngo Weinhold 	queue[count++] = image;
12460c85bd05SIngo Weinhold 	image->flags |= RFLAG_VISITED;
12470c85bd05SIngo Weinhold 
12480c85bd05SIngo Weinhold 	bool found = false;
12490c85bd05SIngo Weinhold 	while (index < count) {
12500c85bd05SIngo Weinhold 		// pop next image
12510c85bd05SIngo Weinhold 		image = queue[index++];
12520c85bd05SIngo Weinhold 
12530c85bd05SIngo Weinhold 		if (find_symbol(image, name, type, _location) == B_OK) {
12540c85bd05SIngo Weinhold 			found = true;
12550c85bd05SIngo Weinhold 			break;
12560c85bd05SIngo Weinhold 		}
12570c85bd05SIngo Weinhold 
12580c85bd05SIngo Weinhold 		// push needed images
12590c85bd05SIngo Weinhold 		for (uint32 i = 0; i < image->num_needed; i++) {
12600c85bd05SIngo Weinhold 			image_t* needed = image->needed[i];
12610c85bd05SIngo Weinhold 			if ((needed->flags & RFLAG_VISITED) == 0) {
12620c85bd05SIngo Weinhold 				queue[count++] = needed;
12630c85bd05SIngo Weinhold 				needed->flags |= RFLAG_VISITED;
126446f4d849SIngo Weinhold 			}
126546f4d849SIngo Weinhold 		}
12660c0fea5dSIngo Weinhold 	}
12670c0fea5dSIngo Weinhold 
12680c85bd05SIngo Weinhold 	// clear visited flags
12690c85bd05SIngo Weinhold 	for (uint32 i = 0; i < count; i++)
12700c85bd05SIngo Weinhold 		queue[i]->flags &= ~RFLAG_VISITED;
12710c85bd05SIngo Weinhold 
12720c85bd05SIngo Weinhold 	return found ? B_OK : B_ENTRY_NOT_FOUND;
12730c0fea5dSIngo Weinhold }
12740c0fea5dSIngo Weinhold 
12750c0fea5dSIngo Weinhold 
127646f4d849SIngo Weinhold static struct Elf32_Sym*
12770c85bd05SIngo Weinhold find_undefined_symbol_beos(image_t* rootImage, image_t* image, const char* name,
127846f4d849SIngo Weinhold 	image_t** foundInImage)
127946f4d849SIngo Weinhold {
128046f4d849SIngo Weinhold 	// BeOS style symbol resolution: It is sufficient to check the direct
128146f4d849SIngo Weinhold 	// dependencies. The linker would have complained, if the symbol wasn't
128246f4d849SIngo Weinhold 	// there.
128346f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
128446f4d849SIngo Weinhold 		if (image->needed[i]->dynamic_ptr) {
128546f4d849SIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(image->needed[i], name,
128646f4d849SIngo Weinhold 				B_SYMBOL_TYPE_ANY);
128746f4d849SIngo Weinhold 			if (symbol) {
128846f4d849SIngo Weinhold 				*foundInImage = image->needed[i];
128946f4d849SIngo Weinhold 				return symbol;
129046f4d849SIngo Weinhold 			}
129146f4d849SIngo Weinhold 		}
129246f4d849SIngo Weinhold 	}
129346f4d849SIngo Weinhold 
129446f4d849SIngo Weinhold 	return NULL;
129546f4d849SIngo Weinhold }
129646f4d849SIngo Weinhold 
129746f4d849SIngo Weinhold 
12980c85bd05SIngo Weinhold static struct Elf32_Sym*
12990c85bd05SIngo Weinhold find_undefined_symbol_global(image_t* rootImage, image_t* image,
13000c85bd05SIngo Weinhold 	const char* name, image_t** foundInImage)
13010c85bd05SIngo Weinhold {
13020c85bd05SIngo Weinhold 	// Global load order symbol resolution: All loaded images are searched for
13030c85bd05SIngo Weinhold 	// the symbol in the order they have been loaded. We skip add-on images and
13040c85bd05SIngo Weinhold 	// RTLD_LOCAL images though.
13050c85bd05SIngo Weinhold 	image_t* otherImage = sLoadedImages.head;
13060c85bd05SIngo Weinhold 	while (otherImage != NULL) {
13070c85bd05SIngo Weinhold 		if (otherImage == rootImage
13080c85bd05SIngo Weinhold 			|| otherImage->type != B_ADD_ON_IMAGE
13090c85bd05SIngo Weinhold 				&& (otherImage->flags
13100c85bd05SIngo Weinhold 					& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0) {
13110c85bd05SIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(otherImage, name,
13120c85bd05SIngo Weinhold 				B_SYMBOL_TYPE_ANY);
13130c85bd05SIngo Weinhold 			if (symbol) {
13140c85bd05SIngo Weinhold 				*foundInImage = otherImage;
13150c85bd05SIngo Weinhold 				return symbol;
13160c85bd05SIngo Weinhold 			}
13170c85bd05SIngo Weinhold 		}
13180c85bd05SIngo Weinhold 		otherImage = otherImage->next;
13190c85bd05SIngo Weinhold 	}
13200c85bd05SIngo Weinhold 
13210c85bd05SIngo Weinhold 	return NULL;
13220c85bd05SIngo Weinhold }
13230c85bd05SIngo Weinhold 
13240c85bd05SIngo Weinhold 
13250c85bd05SIngo Weinhold static struct Elf32_Sym*
13260c85bd05SIngo Weinhold find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
13270c85bd05SIngo Weinhold 	const char* name, image_t** foundInImage)
13280c85bd05SIngo Weinhold {
13290c85bd05SIngo Weinhold // TODO: How do we want to implement this one? Using global scope resolution
13300c85bd05SIngo Weinhold // might be undesired as it is now, since libraries could refer to symbols in
13310c85bd05SIngo Weinhold // the add-on, which would result in add-on symbols implicitely becoming used
13320c85bd05SIngo Weinhold // outside of the add-on. So the options would be to use the global scope but
13330c85bd05SIngo Weinhold // skip the add-on, or to do breadth-first resolution in the add-on dependency
13340c85bd05SIngo Weinhold // scope, also skipping the add-on itself. BeOS style resolution is safe, too,
13350c85bd05SIngo Weinhold // but we miss out features like undefined symbols and preloading.
13360c85bd05SIngo Weinhold 	return find_undefined_symbol_beos(rootImage, image, name, foundInImage);
13370c85bd05SIngo Weinhold }
13380c85bd05SIngo Weinhold 
13390c85bd05SIngo Weinhold 
134010b4b5d1SIngo Weinhold /*!	This function is called when we run BeOS images on Haiku.
13412716cfd3SAxel Dörfler 	It allows us to redirect functions to ensure compatibility.
13422716cfd3SAxel Dörfler */
13432716cfd3SAxel Dörfler static const char*
13442716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName)
13452716cfd3SAxel Dörfler {
13462716cfd3SAxel Dörfler 	struct symbol_mapping {
13472716cfd3SAxel Dörfler 		const char* from;
13482716cfd3SAxel Dörfler 		const char* to;
13492716cfd3SAxel Dörfler 	};
13502716cfd3SAxel Dörfler 	static const struct symbol_mapping kMappings[] = {
135110b4b5d1SIngo Weinhold 		// TODO: Improve this, and also use it for libnet.so compatibility!
135210b4b5d1SIngo Weinhold 		// Allow an image to provide a function that will be invoked for every
135310b4b5d1SIngo Weinhold 		// (transitively) depending image. The function can return a table to
135410b4b5d1SIngo Weinhold 		// remap symbols (probably better address to address). All the tables
135510b4b5d1SIngo Weinhold 		// for a single image would be combined into a hash table and an
135610b4b5d1SIngo Weinhold 		// undefined symbol patcher using this hash table would be added.
13572716cfd3SAxel Dörfler 		{"fstat", "__be_fstat"},
13582716cfd3SAxel Dörfler 		{"lstat", "__be_lstat"},
13592716cfd3SAxel Dörfler 		{"stat", "__be_stat"},
13602716cfd3SAxel Dörfler 	};
13612716cfd3SAxel Dörfler 	const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]);
13622716cfd3SAxel Dörfler 
13632716cfd3SAxel Dörfler 	for (uint32 i = 0; i < kMappingCount; i++) {
13642716cfd3SAxel Dörfler 		if (!strcmp(symbolName, kMappings[i].from))
13652716cfd3SAxel Dörfler 			return kMappings[i].to;
13662716cfd3SAxel Dörfler 	}
13672716cfd3SAxel Dörfler 
13682716cfd3SAxel Dörfler 	return symbolName;
13692716cfd3SAxel Dörfler }
13702716cfd3SAxel Dörfler 
13712716cfd3SAxel Dörfler 
13720c0fea5dSIngo Weinhold int
137346f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
13742716cfd3SAxel Dörfler 	addr_t *symAddress)
13750c0fea5dSIngo Weinhold {
13760c0fea5dSIngo Weinhold 	switch (sym->st_shndx) {
13770c0fea5dSIngo Weinhold 		case SHN_UNDEF:
13782716cfd3SAxel Dörfler 		{
13792716cfd3SAxel Dörfler 			struct Elf32_Sym *sharedSym;
13802716cfd3SAxel Dörfler 			image_t *sharedImage;
13812716cfd3SAxel Dörfler 			const char *symName;
13822716cfd3SAxel Dörfler 
13830c0fea5dSIngo Weinhold 			// patch the symbol name
13842716cfd3SAxel Dörfler 			symName = SYMNAME(image, sym);
13852716cfd3SAxel Dörfler 			if (!image->gcc_version.haiku) {
13862716cfd3SAxel Dörfler 				// The image has been compiled with a BeOS compiler. This means
13872716cfd3SAxel Dörfler 				// we'll have to redirect some functions for compatibility.
13882716cfd3SAxel Dörfler 				symName = beos_compatibility_map_symbol(symName);
13892716cfd3SAxel Dörfler 			}
13900c0fea5dSIngo Weinhold 
139110b4b5d1SIngo Weinhold 			int32 type = B_SYMBOL_TYPE_ANY;
139210b4b5d1SIngo Weinhold 			if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC)
139310b4b5d1SIngo Weinhold 				type = B_SYMBOL_TYPE_TEXT;
139410b4b5d1SIngo Weinhold 			else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT)
139510b4b5d1SIngo Weinhold 				type = B_SYMBOL_TYPE_DATA;
139610b4b5d1SIngo Weinhold 
139746f4d849SIngo Weinhold 			// it's undefined, must be outside this image, try the other images
13980c85bd05SIngo Weinhold 			sharedSym = rootImage->find_undefined_symbol(rootImage, image,
13990c85bd05SIngo Weinhold 				symName, &sharedImage);
140010b4b5d1SIngo Weinhold 			void* location = NULL;
14010c0fea5dSIngo Weinhold 
140210b4b5d1SIngo Weinhold 			enum {
140310b4b5d1SIngo Weinhold 				ERROR_NO_SYMBOL,
140410b4b5d1SIngo Weinhold 				ERROR_WRONG_TYPE,
140510b4b5d1SIngo Weinhold 				ERROR_NOT_EXPORTED,
140610b4b5d1SIngo Weinhold 				ERROR_UNPATCHED
140710b4b5d1SIngo Weinhold 			};
140810b4b5d1SIngo Weinhold 			uint32 lookupError = ERROR_UNPATCHED;
140910b4b5d1SIngo Weinhold 
141010b4b5d1SIngo Weinhold 			if (sharedSym == NULL) {
141110b4b5d1SIngo Weinhold 				// symbol not found at all
141210b4b5d1SIngo Weinhold 				lookupError = ERROR_NO_SYMBOL;
141310b4b5d1SIngo Weinhold 				sharedImage = NULL;
141410b4b5d1SIngo Weinhold 			} else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
14152716cfd3SAxel Dörfler 				&& ELF32_ST_TYPE(sym->st_info)
14162716cfd3SAxel Dörfler 					!= ELF32_ST_TYPE(sharedSym->st_info)) {
141710b4b5d1SIngo Weinhold 				// symbol not of the requested type
141810b4b5d1SIngo Weinhold 				lookupError = ERROR_WRONG_TYPE;
141910b4b5d1SIngo Weinhold 				sharedImage = NULL;
142010b4b5d1SIngo Weinhold 			} else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL
14212716cfd3SAxel Dörfler 				&& ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) {
142210b4b5d1SIngo Weinhold 				// symbol not exported
142310b4b5d1SIngo Weinhold 				lookupError = ERROR_NOT_EXPORTED;
142410b4b5d1SIngo Weinhold 				sharedImage = NULL;
142510b4b5d1SIngo Weinhold 			} else {
142610b4b5d1SIngo Weinhold 				// symbol is fine, get its location
142710b4b5d1SIngo Weinhold 				location = (void*)(sharedSym->st_value
142810b4b5d1SIngo Weinhold 					+ sharedImage->regions[0].delta);
142910b4b5d1SIngo Weinhold 			}
143010b4b5d1SIngo Weinhold 
143110b4b5d1SIngo Weinhold 			patch_undefined_symbol(rootImage, image, symName, &sharedImage,
143210b4b5d1SIngo Weinhold 				&location, &type);
143310b4b5d1SIngo Weinhold 
143410b4b5d1SIngo Weinhold 			if (location == NULL) {
143510b4b5d1SIngo Weinhold 				switch (lookupError) {
143610b4b5d1SIngo Weinhold 					case ERROR_NO_SYMBOL:
143710b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: could not resolve symbol "
143810b4b5d1SIngo Weinhold 							"'%s'\n", symName);
143910b4b5d1SIngo Weinhold 						break;
144010b4b5d1SIngo Weinhold 					case ERROR_WRONG_TYPE:
144110b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s' in shared "
144210b4b5d1SIngo Weinhold 							"image but wrong type\n", symName);
144310b4b5d1SIngo Weinhold 						break;
144410b4b5d1SIngo Weinhold 					case ERROR_NOT_EXPORTED:
144510b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s', but not "
14462716cfd3SAxel Dörfler 							"exported\n", symName);
144710b4b5d1SIngo Weinhold 						break;
144810b4b5d1SIngo Weinhold 					case ERROR_UNPATCHED:
144910b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s', but was "
145010b4b5d1SIngo Weinhold 							"hidden by symbol patchers\n", symName);
145110b4b5d1SIngo Weinhold 						break;
145210b4b5d1SIngo Weinhold 				}
1453*e94d1badSMichael Lotz 
1454*e94d1badSMichael Lotz 				if (report_errors())
1455*e94d1badSMichael Lotz 					sErrorMessage.AddString("missing symbol", symName);
1456*e94d1badSMichael Lotz 
14570c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
14580c0fea5dSIngo Weinhold 			}
14590c0fea5dSIngo Weinhold 
146010b4b5d1SIngo Weinhold 			*symAddress = (addr_t)location;
146110b4b5d1SIngo Weinhold 			return B_OK;
14622716cfd3SAxel Dörfler 		}
14630c0fea5dSIngo Weinhold 
14640c0fea5dSIngo Weinhold 		case SHN_ABS:
14652716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
14660c0fea5dSIngo Weinhold 			return B_NO_ERROR;
14670c0fea5dSIngo Weinhold 
14680c0fea5dSIngo Weinhold 		case SHN_COMMON:
14690c0fea5dSIngo Weinhold 			// ToDo: finish this
14702a33a944SIngo Weinhold 			FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n");
14710c0fea5dSIngo Weinhold 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
14720c0fea5dSIngo Weinhold 
14730c0fea5dSIngo Weinhold 		default:
14740c0fea5dSIngo Weinhold 			// standard symbol
14752716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
14760c0fea5dSIngo Weinhold 			return B_NO_ERROR;
14770c0fea5dSIngo Weinhold 	}
14780c0fea5dSIngo Weinhold }
14790c0fea5dSIngo Weinhold 
14800c0fea5dSIngo Weinhold 
14810c0fea5dSIngo Weinhold static void
148210b4b5d1SIngo Weinhold image_event(image_t* image, uint32 event)
148310b4b5d1SIngo Weinhold {
148410b4b5d1SIngo Weinhold 	AddOnList::Iterator it = sAddOns.GetIterator();
148510b4b5d1SIngo Weinhold 	while (RuntimeLoaderAddOn* addOn = it.Next()) {
148610b4b5d1SIngo Weinhold 		void (*function)(image_t* image) = NULL;
148710b4b5d1SIngo Weinhold 
148810b4b5d1SIngo Weinhold 		switch (event) {
148910b4b5d1SIngo Weinhold 			case IMAGE_EVENT_LOADED:
149010b4b5d1SIngo Weinhold 				function = addOn->addOn->image_loaded;
149110b4b5d1SIngo Weinhold 				break;
149210b4b5d1SIngo Weinhold 			case IMAGE_EVENT_RELOCATED:
149310b4b5d1SIngo Weinhold 				function = addOn->addOn->image_relocated;
149410b4b5d1SIngo Weinhold 				break;
149510b4b5d1SIngo Weinhold 			case IMAGE_EVENT_INITIALIZED:
149610b4b5d1SIngo Weinhold 				function = addOn->addOn->image_initialized;
149710b4b5d1SIngo Weinhold 				break;
149810b4b5d1SIngo Weinhold 			case IMAGE_EVENT_UNINITIALIZING:
149910b4b5d1SIngo Weinhold 				function = addOn->addOn->image_uninitializing;
150010b4b5d1SIngo Weinhold 				break;
150110b4b5d1SIngo Weinhold 			case IMAGE_EVENT_UNLOADING:
150210b4b5d1SIngo Weinhold 				function = addOn->addOn->image_unloading;
150310b4b5d1SIngo Weinhold 				break;
150410b4b5d1SIngo Weinhold 		}
150510b4b5d1SIngo Weinhold 
150610b4b5d1SIngo Weinhold 		if (function != NULL)
150710b4b5d1SIngo Weinhold 			function(image);
150810b4b5d1SIngo Weinhold 	}
150910b4b5d1SIngo Weinhold }
151010b4b5d1SIngo Weinhold 
151110b4b5d1SIngo Weinhold 
151210b4b5d1SIngo Weinhold static void
15130c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path)
15140c0fea5dSIngo Weinhold {
15150c0fea5dSIngo Weinhold 	struct stat stat;
15160c0fea5dSIngo Weinhold 	image_info info;
15170c0fea5dSIngo Weinhold 
15180c0fea5dSIngo Weinhold 	// ToDo: set these correctly
15190c0fea5dSIngo Weinhold 	info.id = 0;
15200c0fea5dSIngo Weinhold 	info.type = image->type;
15210c0fea5dSIngo Weinhold 	info.sequence = 0;
15220c0fea5dSIngo Weinhold 	info.init_order = 0;
15230c0fea5dSIngo Weinhold 	info.init_routine = (void (*)())image->init_routine;
15240c0fea5dSIngo Weinhold 	info.term_routine = (void (*)())image->term_routine;
15250c0fea5dSIngo Weinhold 
15260c0fea5dSIngo Weinhold 	if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
15270c0fea5dSIngo Weinhold 		info.device = stat.st_dev;
15280c0fea5dSIngo Weinhold 		info.node = stat.st_ino;
15290c0fea5dSIngo Weinhold 	} else {
15300c0fea5dSIngo Weinhold 		info.device = -1;
15310c0fea5dSIngo Weinhold 		info.node = -1;
15320c0fea5dSIngo Weinhold 	}
15330c0fea5dSIngo Weinhold 
15340c0fea5dSIngo Weinhold 	strlcpy(info.name, path, sizeof(info.name));
15350c0fea5dSIngo Weinhold 	info.text = (void *)image->regions[0].vmstart;
15360c0fea5dSIngo Weinhold 	info.text_size = image->regions[0].vmsize;
15370c0fea5dSIngo Weinhold 	info.data = (void *)image->regions[1].vmstart;
15380c0fea5dSIngo Weinhold 	info.data_size = image->regions[1].vmsize;
15390c0fea5dSIngo Weinhold 	image->id = _kern_register_image(&info, sizeof(image_info));
15400c0fea5dSIngo Weinhold }
15410c0fea5dSIngo Weinhold 
15420c0fea5dSIngo Weinhold 
15430c0fea5dSIngo Weinhold static status_t
154446f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
15450c0fea5dSIngo Weinhold {
154646f4d849SIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image);
15470c0fea5dSIngo Weinhold 	if (status < B_OK) {
1548320bd2bdSAxel Dörfler 		FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status,
1549320bd2bdSAxel Dörfler 			image->path, image->name);
15500c0fea5dSIngo Weinhold 		return status;
15510c0fea5dSIngo Weinhold 	}
15520c0fea5dSIngo Weinhold 
15530c0fea5dSIngo Weinhold 	_kern_image_relocated(image->id);
155410b4b5d1SIngo Weinhold 	image_event(image, IMAGE_EVENT_RELOCATED);
15550c0fea5dSIngo Weinhold 	return B_OK;
15560c0fea5dSIngo Weinhold }
15570c0fea5dSIngo Weinhold 
15580c0fea5dSIngo Weinhold 
15590c0fea5dSIngo Weinhold static status_t
15600c85bd05SIngo Weinhold load_container(char const *name, image_type type, const char *rpath,
15610c85bd05SIngo Weinhold 	image_t **_image)
15620c0fea5dSIngo Weinhold {
15630c0fea5dSIngo Weinhold 	int32 pheaderSize, sheaderSize;
15640c0fea5dSIngo Weinhold 	char path[PATH_MAX];
15650c0fea5dSIngo Weinhold 	ssize_t length;
15660c0fea5dSIngo Weinhold 	char ph_buff[4096];
15670c0fea5dSIngo Weinhold 	int32 numRegions;
15680c0fea5dSIngo Weinhold 	image_t *found;
15690c0fea5dSIngo Weinhold 	image_t *image;
15700c0fea5dSIngo Weinhold 	status_t status;
15710c0fea5dSIngo Weinhold 	int fd;
15720c0fea5dSIngo Weinhold 
15730c0fea5dSIngo Weinhold 	struct Elf32_Ehdr eheader;
15740c0fea5dSIngo Weinhold 
15750c0fea5dSIngo Weinhold 	// Have we already loaded that image? Don't check for add-ons -- we always
15760c0fea5dSIngo Weinhold 	// reload them.
15770c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
15780c0fea5dSIngo Weinhold 		found = find_image(name, APP_OR_LIBRARY_TYPE);
157902e577f9SIngo Weinhold 
158002e577f9SIngo Weinhold 		if (found == NULL && type != B_APP_IMAGE) {
158102e577f9SIngo Weinhold 			// Special case for add-ons that link against the application
158202e577f9SIngo Weinhold 			// executable, with the executable not having a soname set.
158302e577f9SIngo Weinhold 			if (const char* lastSlash = strrchr(name, '/')) {
158402e577f9SIngo Weinhold 				image_t* programImage = get_program_image();
158502e577f9SIngo Weinhold 				if (strcmp(programImage->name, lastSlash + 1) == 0)
158602e577f9SIngo Weinhold 					found = programImage;
158702e577f9SIngo Weinhold 			}
158802e577f9SIngo Weinhold 		}
158902e577f9SIngo Weinhold 
15900c0fea5dSIngo Weinhold 		if (found) {
15910c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
15920c0fea5dSIngo Weinhold 			*_image = found;
15937486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") "
15947486b72dSIngo Weinhold 				"already loaded", name, type, rpath);
15950c0fea5dSIngo Weinhold 			return B_OK;
15960c0fea5dSIngo Weinhold 		}
15970c0fea5dSIngo Weinhold 	}
15980c0fea5dSIngo Weinhold 
15997486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type,
16007486b72dSIngo Weinhold 		rpath);
16017486b72dSIngo Weinhold 
16020c0fea5dSIngo Weinhold 	strlcpy(path, name, sizeof(path));
16030c0fea5dSIngo Weinhold 
160461b37794SIngo Weinhold 	// find and open the file
160561b37794SIngo Weinhold 	fd = open_executable(path, type, rpath, get_program_path(),
160661b37794SIngo Weinhold 		sSearchPathSubDir);
16070c0fea5dSIngo Weinhold 	if (fd < 0) {
160802e577f9SIngo Weinhold 		FATAL("cannot open file %s\n", name);
16097486b72dSIngo Weinhold 		KTRACE("rld: load_container(\"%s\"): failed to open file", name);
16100c0fea5dSIngo Weinhold 		return fd;
16110c0fea5dSIngo Weinhold 	}
16120c0fea5dSIngo Weinhold 
16136918dbf4SIngo Weinhold 	// normalize the image path
16146918dbf4SIngo Weinhold 	status = _kern_normalize_path(path, true, path);
16156918dbf4SIngo Weinhold 	if (status != B_OK)
16160c0fea5dSIngo Weinhold 		goto err1;
16170c0fea5dSIngo Weinhold 
16180c0fea5dSIngo Weinhold 	// Test again if this image has been registered already - this time,
16190c0fea5dSIngo Weinhold 	// we can check the full path, not just its name as noted.
16200c0fea5dSIngo Weinhold 	// You could end up loading an image twice with symbolic links, else.
16210c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
16220c0fea5dSIngo Weinhold 		found = find_image(path, APP_OR_LIBRARY_TYPE);
16230c0fea5dSIngo Weinhold 		if (found) {
16240c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
16250c0fea5dSIngo Weinhold 			*_image = found;
1626b2568a30SIngo Weinhold 			_kern_close(fd);
16277486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\"): already loaded after all",
16287486b72dSIngo Weinhold 				name);
16290c0fea5dSIngo Weinhold 			return B_OK;
16300c0fea5dSIngo Weinhold 		}
16310c0fea5dSIngo Weinhold 	}
16320c0fea5dSIngo Weinhold 
16330c0fea5dSIngo Weinhold 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
16340c0fea5dSIngo Weinhold 	if (length != sizeof(eheader)) {
16350c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
16360c0fea5dSIngo Weinhold 		FATAL("troubles reading ELF header\n");
16370c0fea5dSIngo Weinhold 		goto err1;
16380c0fea5dSIngo Weinhold 	}
16390c0fea5dSIngo Weinhold 
16400c0fea5dSIngo Weinhold 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
16410c0fea5dSIngo Weinhold 	if (status < B_OK) {
16420c0fea5dSIngo Weinhold 		FATAL("incorrect ELF header\n");
16430c0fea5dSIngo Weinhold 		goto err1;
16440c0fea5dSIngo Weinhold 	}
16450c0fea5dSIngo Weinhold 
16460c0fea5dSIngo Weinhold 	// ToDo: what to do about this restriction??
16470c0fea5dSIngo Weinhold 	if (pheaderSize > (int)sizeof(ph_buff)) {
16480c0fea5dSIngo Weinhold 		FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff));
16490c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
16500c0fea5dSIngo Weinhold 		goto err1;
16510c0fea5dSIngo Weinhold 	}
16520c0fea5dSIngo Weinhold 
16530c0fea5dSIngo Weinhold 	length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize);
16540c0fea5dSIngo Weinhold 	if (length != pheaderSize) {
16550c0fea5dSIngo Weinhold 		FATAL("Could not read program headers: %s\n", strerror(length));
16560c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
16570c0fea5dSIngo Weinhold 		goto err1;
16580c0fea5dSIngo Weinhold 	}
16590c0fea5dSIngo Weinhold 
16600c0fea5dSIngo Weinhold 	numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
16610c0fea5dSIngo Weinhold 	if (numRegions <= 0) {
16620c0fea5dSIngo Weinhold 		FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
16630c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
16640c0fea5dSIngo Weinhold 		goto err1;
16650c0fea5dSIngo Weinhold 	}
16660c0fea5dSIngo Weinhold 
16670c0fea5dSIngo Weinhold 	image = create_image(name, path, numRegions);
16680c0fea5dSIngo Weinhold 	if (image == NULL) {
16690c0fea5dSIngo Weinhold 		FATAL("Failed to allocate image_t object\n");
16700c0fea5dSIngo Weinhold 		status = B_NO_MEMORY;
16710c0fea5dSIngo Weinhold 		goto err1;
16720c0fea5dSIngo Weinhold 	}
16730c0fea5dSIngo Weinhold 
16740c0fea5dSIngo Weinhold 	status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
16750c0fea5dSIngo Weinhold 	if (status < B_OK)
16760c0fea5dSIngo Weinhold 		goto err2;
16770c0fea5dSIngo Weinhold 
16780c0fea5dSIngo Weinhold 	if (!assert_dynamic_loadable(image)) {
16790c0fea5dSIngo Weinhold 		FATAL("Dynamic segment must be loadable (implementation restriction)\n");
16800c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
16810c0fea5dSIngo Weinhold 		goto err2;
16820c0fea5dSIngo Weinhold 	}
16830c0fea5dSIngo Weinhold 
168461b37794SIngo Weinhold 	if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff,
168534982809SIngo Weinhold 			sizeof(ph_buff))) {
168661b37794SIngo Weinhold 		// If this is the executable image, we init the search path
168761b37794SIngo Weinhold 		// subdir, if the compiler version doesn't match ours.
168861b37794SIngo Weinhold 		if (type == B_APP_IMAGE) {
168961b37794SIngo Weinhold 			#if __GNUC__ == 2
169061b37794SIngo Weinhold 				if (image->gcc_version.major > 2)
169161b37794SIngo Weinhold 					sSearchPathSubDir = "gcc4";
169261b37794SIngo Weinhold 			#elif __GNUC__ == 4
169361b37794SIngo Weinhold 				if (image->gcc_version.major == 2)
169461b37794SIngo Weinhold 					sSearchPathSubDir = "gcc2";
169561b37794SIngo Weinhold 			#endif
169661b37794SIngo Weinhold 		}
169761b37794SIngo Weinhold 	} else {
169834982809SIngo Weinhold 		FATAL("Failed to get gcc version for %s\n", path);
169934982809SIngo Weinhold 		// not really fatal, actually
170034982809SIngo Weinhold 	}
170134982809SIngo Weinhold 
17025fd6637bSIngo Weinhold 	// init gcc version dependent image flags
17035fd6637bSIngo Weinhold 	// symbol resolution strategy (fallback is R5-style, if version is
17045fd6637bSIngo Weinhold 	// unavailable)
17055fd6637bSIngo Weinhold 	if (image->gcc_version.major == 0
17065fd6637bSIngo Weinhold 		|| image->gcc_version.major == 2 && image->gcc_version.middle < 95) {
17070c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_beos;
17085fd6637bSIngo Weinhold 	}
17095fd6637bSIngo Weinhold 
17100c0fea5dSIngo Weinhold 	status = map_image(fd, path, image, type == B_APP_IMAGE);
17110c0fea5dSIngo Weinhold 	if (status < B_OK) {
17120c0fea5dSIngo Weinhold 		FATAL("Could not map image: %s\n", strerror(status));
17130c0fea5dSIngo Weinhold 		status = B_ERROR;
17140c0fea5dSIngo Weinhold 		goto err2;
17150c0fea5dSIngo Weinhold 	}
17160c0fea5dSIngo Weinhold 
17170c0fea5dSIngo Weinhold 	if (!parse_dynamic_segment(image)) {
17180c0fea5dSIngo Weinhold 		FATAL("Troubles handling dynamic section\n");
17190c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
17200c0fea5dSIngo Weinhold 		goto err3;
17210c0fea5dSIngo Weinhold 	}
17220c0fea5dSIngo Weinhold 
1723dd76bc97SIngo Weinhold 	if (eheader.e_entry != 0)
17240c0fea5dSIngo Weinhold 		image->entry_point = eheader.e_entry + image->regions[0].delta;
17250c0fea5dSIngo Weinhold 
17260c0fea5dSIngo Weinhold 	image->type = type;
17270c0fea5dSIngo Weinhold 	register_image(image, fd, path);
172810b4b5d1SIngo Weinhold 	image_event(image, IMAGE_EVENT_LOADED);
17290c0fea5dSIngo Weinhold 
17300c0fea5dSIngo Weinhold 	_kern_close(fd);
17310c0fea5dSIngo Weinhold 
17320c0fea5dSIngo Weinhold 	enqueue_image(&sLoadedImages, image);
17330c0fea5dSIngo Weinhold 	sLoadedImageCount++;
17340c0fea5dSIngo Weinhold 
17350c0fea5dSIngo Weinhold 	*_image = image;
17367486b72dSIngo Weinhold 
173734982809SIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): done: id: %ld (gcc: %d.%d.%d)", name,
173834982809SIngo Weinhold 		image->id, image->gcc_version.major, image->gcc_version.middle,
173934982809SIngo Weinhold 		image->gcc_version.minor);
17407486b72dSIngo Weinhold 
17410c0fea5dSIngo Weinhold 	return B_OK;
17420c0fea5dSIngo Weinhold 
17430c0fea5dSIngo Weinhold err3:
17440c0fea5dSIngo Weinhold 	unmap_image(image);
17450c0fea5dSIngo Weinhold err2:
17460c0fea5dSIngo Weinhold 	delete_image_struct(image);
17470c0fea5dSIngo Weinhold err1:
17480c0fea5dSIngo Weinhold 	_kern_close(fd);
17497486b72dSIngo Weinhold 
17507486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): failed: %s", name,
17517486b72dSIngo Weinhold 		strerror(status));
17527486b72dSIngo Weinhold 
17530c0fea5dSIngo Weinhold 	return status;
17540c0fea5dSIngo Weinhold }
17550c0fea5dSIngo Weinhold 
17560c0fea5dSIngo Weinhold 
17570c0fea5dSIngo Weinhold static const char *
17580c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
17590c0fea5dSIngo Weinhold {
17600c0fea5dSIngo Weinhold 	int i;
17610c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
17620c0fea5dSIngo Weinhold 
17630c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
17640c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
17650c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
17660c0fea5dSIngo Weinhold 	}
17670c0fea5dSIngo Weinhold 
17680c0fea5dSIngo Weinhold 	return NULL;
17690c0fea5dSIngo Weinhold }
17700c0fea5dSIngo Weinhold 
17710c0fea5dSIngo Weinhold 
17720c0fea5dSIngo Weinhold static status_t
17730c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image)
17740c0fea5dSIngo Weinhold {
17750c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
17764bef3723SAxel Dörfler 	bool reportErrors = report_errors();
177774c0424aSAxel Dörfler 	status_t status = B_OK;
17780c0fea5dSIngo Weinhold 	uint32 i, j;
17790c0fea5dSIngo Weinhold 	const char *rpath;
17800c0fea5dSIngo Weinhold 
17810c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
17820c0fea5dSIngo Weinhold 		return B_OK;
17830c0fea5dSIngo Weinhold 
17840c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
17850c0fea5dSIngo Weinhold 
17860c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
17870c0fea5dSIngo Weinhold 		return B_OK;
17880c0fea5dSIngo Weinhold 
17897486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
17907486b72dSIngo Weinhold 		image->id);
17917486b72dSIngo Weinhold 
17920c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
17930c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
17940c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
17957486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
17967486b72dSIngo Weinhold 			image->name, image->id);
17970c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
17980c0fea5dSIngo Weinhold 	}
17990c0fea5dSIngo Weinhold 
18000c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
18010c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
18020c0fea5dSIngo Weinhold 
18030c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
18040c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
18050c0fea5dSIngo Weinhold 			case DT_NEEDED:
180674c0424aSAxel Dörfler 			{
180774c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
180874c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
18090c0fea5dSIngo Weinhold 
181074c0424aSAxel Dörfler 				status_t loadStatus = load_container(name, B_LIBRARY_IMAGE,
181174c0424aSAxel Dörfler 					rpath, &image->needed[j]);
181274c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
181374c0424aSAxel Dörfler 					status = loadStatus;
181474c0424aSAxel Dörfler 					// correct error code in case the file could not been found
181574c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
181674c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
181774c0424aSAxel Dörfler 
181874c0424aSAxel Dörfler 						if (reportErrors)
181974c0424aSAxel Dörfler 							sErrorMessage.AddString("missing library", name);
182074c0424aSAxel Dörfler 					}
182174c0424aSAxel Dörfler 
182274c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
18237486b72dSIngo Weinhold 					if (!reportErrors) {
18247486b72dSIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
18257486b72dSIngo Weinhold 							"failed: %s", image->name, image->id,
18267486b72dSIngo Weinhold 							strerror(status));
18270c0fea5dSIngo Weinhold 						return status;
182874c0424aSAxel Dörfler 					}
18297486b72dSIngo Weinhold 				}
18300c0fea5dSIngo Weinhold 
18310c0fea5dSIngo Weinhold 				j += 1;
18320c0fea5dSIngo Weinhold 				break;
183374c0424aSAxel Dörfler 			}
18340c0fea5dSIngo Weinhold 
18350c0fea5dSIngo Weinhold 			default:
18360c0fea5dSIngo Weinhold 				// ignore any other tag
18370c0fea5dSIngo Weinhold 				continue;
18380c0fea5dSIngo Weinhold 		}
18390c0fea5dSIngo Weinhold 	}
18400c0fea5dSIngo Weinhold 
18417486b72dSIngo Weinhold 	if (status < B_OK) {
18427486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
18437486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
18447486b72dSIngo Weinhold 			strerror(status));
184574c0424aSAxel Dörfler 		return status;
18467486b72dSIngo Weinhold 	}
184774c0424aSAxel Dörfler 
18480c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
18490c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
18507486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
18517486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
18520c0fea5dSIngo Weinhold 		return B_ERROR;
18530c0fea5dSIngo Weinhold 	}
18540c0fea5dSIngo Weinhold 
18557486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
18567486b72dSIngo Weinhold 		image->id);
18577486b72dSIngo Weinhold 
18580c0fea5dSIngo Weinhold 	return B_OK;
18590c0fea5dSIngo Weinhold }
18600c0fea5dSIngo Weinhold 
18610c0fea5dSIngo Weinhold 
18620c85bd05SIngo Weinhold static status_t
18630c85bd05SIngo Weinhold load_dependencies(image_t* image)
18640c85bd05SIngo Weinhold {
18650c85bd05SIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
18660c85bd05SIngo Weinhold 			otherImage = otherImage->next) {
18670c85bd05SIngo Weinhold 		status_t status = load_immediate_dependencies(otherImage);
18680c85bd05SIngo Weinhold 		if (status != B_OK)
18690c85bd05SIngo Weinhold 			return status;
18700c85bd05SIngo Weinhold 	}
18710c85bd05SIngo Weinhold 
18720c85bd05SIngo Weinhold 	return B_OK;
18730c85bd05SIngo Weinhold }
18740c85bd05SIngo Weinhold 
18750c85bd05SIngo Weinhold 
18760c0fea5dSIngo Weinhold static uint32
18770c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList,
18780c0fea5dSIngo Weinhold 	uint32 sortFlag)
18790c0fea5dSIngo Weinhold {
18800c0fea5dSIngo Weinhold 	uint32 i;
18810c0fea5dSIngo Weinhold 
18820c0fea5dSIngo Weinhold 	if (image->flags & sortFlag)
18830c0fea5dSIngo Weinhold 		return slot;
18840c0fea5dSIngo Weinhold 
18850c0fea5dSIngo Weinhold 	image->flags |= sortFlag; /* make sure we don't visit this one */
18860c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_needed; i++)
18870c0fea5dSIngo Weinhold 		slot = topological_sort(image->needed[i], slot, initList, sortFlag);
18880c0fea5dSIngo Weinhold 
18890c0fea5dSIngo Weinhold 	initList[slot] = image;
18900c0fea5dSIngo Weinhold 	return slot + 1;
18910c0fea5dSIngo Weinhold }
18920c0fea5dSIngo Weinhold 
18930c0fea5dSIngo Weinhold 
18940c0fea5dSIngo Weinhold static ssize_t
18950c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
18960c0fea5dSIngo Weinhold {
18970c0fea5dSIngo Weinhold 	image_t **list;
18980c0fea5dSIngo Weinhold 
18990c0fea5dSIngo Weinhold 	list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *));
19000c0fea5dSIngo Weinhold 	if (list == NULL) {
19010c0fea5dSIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
19020c0fea5dSIngo Weinhold 		*_list = NULL;
19030c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
19040c0fea5dSIngo Weinhold 	}
19050c0fea5dSIngo Weinhold 
19060c0fea5dSIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
19070c0fea5dSIngo Weinhold 
19080c0fea5dSIngo Weinhold 	*_list = list;
19090c0fea5dSIngo Weinhold 	return topological_sort(image, 0, list, sortFlag);
19100c0fea5dSIngo Weinhold }
19110c0fea5dSIngo Weinhold 
19120c0fea5dSIngo Weinhold 
19130c0fea5dSIngo Weinhold static status_t
19140c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
19150c0fea5dSIngo Weinhold {
1916ca618b22SIngo Weinhold 	// get the images that still have to be relocated
1917ca618b22SIngo Weinhold 	image_t **list;
1918ca618b22SIngo Weinhold 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
19190c0fea5dSIngo Weinhold 	if (count < B_OK)
19200c0fea5dSIngo Weinhold 		return count;
19210c0fea5dSIngo Weinhold 
19220c85bd05SIngo Weinhold 	// relocate
1923ca618b22SIngo Weinhold 	for (ssize_t i = 0; i < count; i++) {
192446f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
19250c85bd05SIngo Weinhold 		if (status < B_OK) {
19260c85bd05SIngo Weinhold 			free(list);
19270c0fea5dSIngo Weinhold 			return status;
19280c0fea5dSIngo Weinhold 		}
19290c85bd05SIngo Weinhold 	}
19300c0fea5dSIngo Weinhold 
19310c0fea5dSIngo Weinhold 	free(list);
19320c0fea5dSIngo Weinhold 	return B_OK;
19330c0fea5dSIngo Weinhold }
19340c0fea5dSIngo Weinhold 
19350c0fea5dSIngo Weinhold 
19360c0fea5dSIngo Weinhold static void
19370c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
19380c0fea5dSIngo Weinhold {
19390c0fea5dSIngo Weinhold 	image_t **initList;
19400c0fea5dSIngo Weinhold 	ssize_t count, i;
19410c0fea5dSIngo Weinhold 
19420c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
19430c0fea5dSIngo Weinhold 	if (count <= 0)
19440c0fea5dSIngo Weinhold 		return;
19450c0fea5dSIngo Weinhold 
19460c0fea5dSIngo Weinhold 	if (!initHead) {
19470c0fea5dSIngo Weinhold 		// this removes the "calling" image
19480c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
19490c0fea5dSIngo Weinhold 		initList[--count] = NULL;
19500c0fea5dSIngo Weinhold 	}
19510c0fea5dSIngo Weinhold 
19520c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
19530c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
19540c0fea5dSIngo Weinhold 		image = initList[i];
19550c0fea5dSIngo Weinhold 
19560c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
19570c0fea5dSIngo Weinhold 
1958dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
19590c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
196010b4b5d1SIngo Weinhold 
196110b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
19620c0fea5dSIngo Weinhold 	}
19630c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
19640c0fea5dSIngo Weinhold 
19650c0fea5dSIngo Weinhold 	free(initList);
19660c0fea5dSIngo Weinhold }
19670c0fea5dSIngo Weinhold 
19680c0fea5dSIngo Weinhold 
19690c0fea5dSIngo Weinhold static void
19700c0fea5dSIngo Weinhold put_image(image_t *image)
19710c0fea5dSIngo Weinhold {
19720c0fea5dSIngo Weinhold 	// If all references to the image are gone, add it to the disposable list
19730c0fea5dSIngo Weinhold 	// and remove all dependencies
19740c0fea5dSIngo Weinhold 
19750c0fea5dSIngo Weinhold 	if (atomic_add(&image->ref_count, -1) == 1) {
19760c0fea5dSIngo Weinhold 		size_t i;
19770c0fea5dSIngo Weinhold 
19780c0fea5dSIngo Weinhold 		dequeue_image(&sLoadedImages, image);
19790c0fea5dSIngo Weinhold 		enqueue_image(&sDisposableImages, image);
19800c0fea5dSIngo Weinhold 		sLoadedImageCount--;
19810c0fea5dSIngo Weinhold 
19820c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_needed; i++) {
19830c0fea5dSIngo Weinhold 			put_image(image->needed[i]);
19840c0fea5dSIngo Weinhold 		}
19850c0fea5dSIngo Weinhold 	}
19860c0fea5dSIngo Weinhold }
19870c0fea5dSIngo Weinhold 
19880c0fea5dSIngo Weinhold 
1989ca618b22SIngo Weinhold void
1990ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
1991ca618b22SIngo Weinhold {
1992ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
1993ca618b22SIngo Weinhold 	// API.
1994ca618b22SIngo Weinhold 	image_t* image;
19950c85bd05SIngo Weinhold 	void* _export;
19960c85bd05SIngo Weinhold 	if (find_symbol_breadth_first(rootImage, "__gRuntimeLoader",
19970c85bd05SIngo Weinhold 			B_SYMBOL_TYPE_DATA, &image, &_export) == B_OK) {
19980c85bd05SIngo Weinhold 		*(void**)_export = &gRuntimeLoader;
1999ca618b22SIngo Weinhold 	}
2000ca618b22SIngo Weinhold }
2001ca618b22SIngo Weinhold 
2002ca618b22SIngo Weinhold 
2003ca618b22SIngo Weinhold static status_t
2004ca618b22SIngo Weinhold add_preloaded_image(image_t* image)
2005ca618b22SIngo Weinhold {
2006ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
2007ca618b22SIngo Weinhold 	// small number of preloaded images.
2008ca618b22SIngo Weinhold 	image_t** newArray = (image_t**)realloc(sPreloadedImages,
2009ca618b22SIngo Weinhold 		sizeof(image_t*) * (sPreloadedImageCount + 1));
2010ca618b22SIngo Weinhold 	if (newArray == NULL)
2011ca618b22SIngo Weinhold 		return B_NO_MEMORY;
2012ca618b22SIngo Weinhold 
2013ca618b22SIngo Weinhold 	sPreloadedImages = newArray;
2014ca618b22SIngo Weinhold 	newArray[sPreloadedImageCount++] = image;
2015ca618b22SIngo Weinhold 
2016ca618b22SIngo Weinhold 	return B_OK;
2017ca618b22SIngo Weinhold }
2018ca618b22SIngo Weinhold 
2019ca618b22SIngo Weinhold 
2020ca618b22SIngo Weinhold image_id
2021ca618b22SIngo Weinhold preload_image(char const* path)
2022ca618b22SIngo Weinhold {
2023ca618b22SIngo Weinhold 	if (path == NULL)
2024ca618b22SIngo Weinhold 		return B_BAD_VALUE;
2025ca618b22SIngo Weinhold 
2026ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\")", path);
2027ca618b22SIngo Weinhold 
2028ca618b22SIngo Weinhold 	image_t *image = NULL;
2029ca618b22SIngo Weinhold 	status_t status = load_container(path, B_ADD_ON_IMAGE, NULL, &image);
2030ca618b22SIngo Weinhold 	if (status < B_OK) {
2031ca618b22SIngo Weinhold 		rld_unlock();
2032ca618b22SIngo Weinhold 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
2033ca618b22SIngo Weinhold 			strerror(status));
2034ca618b22SIngo Weinhold 		return status;
2035ca618b22SIngo Weinhold 	}
2036ca618b22SIngo Weinhold 
20370c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL)
20380c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_global;
20390c85bd05SIngo Weinhold 
20400c85bd05SIngo Weinhold 	status = load_dependencies(image);
2041ca618b22SIngo Weinhold 	if (status < B_OK)
2042ca618b22SIngo Weinhold 		goto err;
20430c85bd05SIngo Weinhold 
20440c85bd05SIngo Weinhold 	set_image_flags_recursively(image, RTLD_GLOBAL);
2045ca618b22SIngo Weinhold 
2046ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
2047ca618b22SIngo Weinhold 	if (status < B_OK)
2048ca618b22SIngo Weinhold 		goto err;
2049ca618b22SIngo Weinhold 
2050ca618b22SIngo Weinhold 	status = add_preloaded_image(image);
2051ca618b22SIngo Weinhold 	if (status < B_OK)
2052ca618b22SIngo Weinhold 		goto err;
2053ca618b22SIngo Weinhold 
2054ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
2055ca618b22SIngo Weinhold 
2056ca618b22SIngo Weinhold 	remap_images();
2057ca618b22SIngo Weinhold 	init_dependencies(image, true);
2058ca618b22SIngo Weinhold 
205910b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
206010b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
206110b4b5d1SIngo Weinhold 	if (find_symbol(image, "__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA,
206210b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
206310b4b5d1SIngo Weinhold 		RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image,
206410b4b5d1SIngo Weinhold 			addOnStruct);
206510b4b5d1SIngo Weinhold 		if (addOn != NULL) {
206610b4b5d1SIngo Weinhold 			sAddOns.Add(addOn);
206710b4b5d1SIngo Weinhold 			addOnStruct->init(&gRuntimeLoader, &gRuntimeLoaderAddOnExport);
206810b4b5d1SIngo Weinhold 		}
206910b4b5d1SIngo Weinhold 	}
207010b4b5d1SIngo Weinhold 
2071ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id);
2072ca618b22SIngo Weinhold 
2073ca618b22SIngo Weinhold 	return image->id;
2074ca618b22SIngo Weinhold 
2075ca618b22SIngo Weinhold err:
2076ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status));
2077ca618b22SIngo Weinhold 
2078ca618b22SIngo Weinhold 	dequeue_image(&sLoadedImages, image);
2079ca618b22SIngo Weinhold 	sLoadedImageCount--;
2080ca618b22SIngo Weinhold 	delete_image(image);
2081ca618b22SIngo Weinhold 	return status;
2082ca618b22SIngo Weinhold }
2083ca618b22SIngo Weinhold 
2084ca618b22SIngo Weinhold 
2085ca618b22SIngo Weinhold static void
2086ca618b22SIngo Weinhold preload_images()
2087ca618b22SIngo Weinhold {
2088ca618b22SIngo Weinhold 	const char* imagePaths = getenv("LD_PRELOAD");
2089ca618b22SIngo Weinhold 	if (imagePaths == NULL)
2090ca618b22SIngo Weinhold 		return;
2091ca618b22SIngo Weinhold 
2092ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
2093ca618b22SIngo Weinhold 		// find begin of image path
2094ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
2095ca618b22SIngo Weinhold 			imagePaths++;
2096ca618b22SIngo Weinhold 
2097ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
2098ca618b22SIngo Weinhold 			break;
2099ca618b22SIngo Weinhold 
2100ca618b22SIngo Weinhold 		// find end of image path
2101ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
2102ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
2103ca618b22SIngo Weinhold 			imagePaths++;
2104ca618b22SIngo Weinhold 
2105ca618b22SIngo Weinhold 		// extract the path
2106ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
2107ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
2108ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
2109ca618b22SIngo Weinhold 			continue;
2110ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
2111ca618b22SIngo Weinhold 		path[pathLen] = '\0';
2112ca618b22SIngo Weinhold 
2113ca618b22SIngo Weinhold 		// load the image
2114ca618b22SIngo Weinhold 		preload_image(path);
2115ca618b22SIngo Weinhold 	}
2116ca618b22SIngo Weinhold }
2117ca618b22SIngo Weinhold 
2118ca618b22SIngo Weinhold 
211974c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
21200c0fea5dSIngo Weinhold 
21210c0fea5dSIngo Weinhold 
21220c0fea5dSIngo Weinhold image_id
21230c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
21240c0fea5dSIngo Weinhold {
21250c0fea5dSIngo Weinhold 	status_t status;
21260c0fea5dSIngo Weinhold 	image_t *image;
21270c0fea5dSIngo Weinhold 
21287486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
21297486b72dSIngo Weinhold 
21300c0fea5dSIngo Weinhold 	rld_lock();
21310c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
21320c0fea5dSIngo Weinhold 
2133ca618b22SIngo Weinhold 	preload_images();
2134ca618b22SIngo Weinhold 
21350c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
21360c0fea5dSIngo Weinhold 
21370c0fea5dSIngo Weinhold 	status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage);
213874c0424aSAxel Dörfler 	if (status < B_OK)
213974c0424aSAxel Dörfler 		goto err;
21400c0fea5dSIngo Weinhold 
21410c85bd05SIngo Weinhold 	if (sProgramImage->find_undefined_symbol == NULL)
21420c85bd05SIngo Weinhold 		sProgramImage->find_undefined_symbol = find_undefined_symbol_global;
21430c85bd05SIngo Weinhold 
21440c85bd05SIngo Weinhold 	status = load_dependencies(sProgramImage);
21450c0fea5dSIngo Weinhold 	if (status < B_OK)
21460c0fea5dSIngo Weinhold 		goto err;
21470c85bd05SIngo Weinhold 
214847bc6663SIngo Weinhold 	// Set RTLD_GLOBAL on all libraries including the program.
21490c85bd05SIngo Weinhold 	// This results in the desired symbol resolution for dlopen()ed libraries.
21500c85bd05SIngo Weinhold 	set_image_flags_recursively(sProgramImage, RTLD_GLOBAL);
21510c0fea5dSIngo Weinhold 
21520c0fea5dSIngo Weinhold 	status = relocate_dependencies(sProgramImage);
21530c0fea5dSIngo Weinhold 	if (status < B_OK)
21540c0fea5dSIngo Weinhold 		goto err;
21550c0fea5dSIngo Weinhold 
2156ca618b22SIngo Weinhold 	inject_runtime_loader_api(sProgramImage);
21570c0fea5dSIngo Weinhold 
21580c0fea5dSIngo Weinhold 	remap_images();
2159ca618b22SIngo Weinhold 	init_dependencies(sProgramImage, true);
21600c0fea5dSIngo Weinhold 
21610c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
21620c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
21630c85bd05SIngo Weinhold 	find_symbol_breadth_first(sProgramImage, "getenv", B_SYMBOL_TYPE_TEXT,
21640c85bd05SIngo Weinhold 		&image, (void**)&gGetEnv);
21650c0fea5dSIngo Weinhold 
2166dd76bc97SIngo Weinhold 	if (sProgramImage->entry_point == 0) {
21670c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
21680c0fea5dSIngo Weinhold 		goto err;
21690c0fea5dSIngo Weinhold 	}
21700c0fea5dSIngo Weinhold 
21710c0fea5dSIngo Weinhold 	*_entry = (void *)(sProgramImage->entry_point);
21720c0fea5dSIngo Weinhold 
21730c0fea5dSIngo Weinhold 	rld_unlock();
21747486b72dSIngo Weinhold 
21755d0638bfSIngo Weinhold 	sProgramLoaded = true;
21765d0638bfSIngo Weinhold 
21777486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
21787486b72dSIngo Weinhold 		*_entry, sProgramImage->id);
21797486b72dSIngo Weinhold 
21800c0fea5dSIngo Weinhold 	return sProgramImage->id;
21810c0fea5dSIngo Weinhold 
21820c0fea5dSIngo Weinhold err:
21837486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
21847486b72dSIngo Weinhold 
21850c0fea5dSIngo Weinhold 	delete_image(sProgramImage);
218674c0424aSAxel Dörfler 
21874bef3723SAxel Dörfler 	if (report_errors()) {
21884bef3723SAxel Dörfler 		// send error message
218974c0424aSAxel Dörfler 		sErrorMessage.AddInt32("error", status);
21904bef3723SAxel Dörfler 		sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
21914bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
21924bef3723SAxel Dörfler 
21934bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
21944bef3723SAxel Dörfler 			sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0);
219574c0424aSAxel Dörfler 	}
219674c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
21970c0fea5dSIngo Weinhold 	rld_unlock();
219874c0424aSAxel Dörfler 
21990c0fea5dSIngo Weinhold 	return status;
22000c0fea5dSIngo Weinhold }
22010c0fea5dSIngo Weinhold 
22020c0fea5dSIngo Weinhold 
22030c0fea5dSIngo Weinhold image_id
22040c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle)
22050c0fea5dSIngo Weinhold {
22060c0fea5dSIngo Weinhold 	image_t *image = NULL;
22070c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
22080c0fea5dSIngo Weinhold 	status_t status;
22090c0fea5dSIngo Weinhold 
22100c85bd05SIngo Weinhold 	if (path == NULL && addOn)
22110c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
22120c0fea5dSIngo Weinhold 
22137486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
22147486b72dSIngo Weinhold 
22150c0fea5dSIngo Weinhold 	rld_lock();
22160c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
22170c0fea5dSIngo Weinhold 
22180c0fea5dSIngo Weinhold 	// have we already loaded this library?
22190c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
22200c0fea5dSIngo Weinhold 	if (!addOn) {
22210c85bd05SIngo Weinhold 		// a NULL path is fine -- it means the global scope shall be opened
22220c85bd05SIngo Weinhold 		if (path == NULL) {
22230c85bd05SIngo Weinhold 			*_handle = RLD_GLOBAL_SCOPE;
22240c85bd05SIngo Weinhold 			rld_unlock();
22250c85bd05SIngo Weinhold 			return 0;
22260c85bd05SIngo Weinhold 		}
22270c85bd05SIngo Weinhold 
22280c0fea5dSIngo Weinhold 		image = find_image(path, APP_OR_LIBRARY_TYPE);
22290c85bd05SIngo Weinhold 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
22300c85bd05SIngo Weinhold 			set_image_flags_recursively(image, RTLD_GLOBAL);
22310c85bd05SIngo Weinhold 
22320c0fea5dSIngo Weinhold 		if (image) {
22330c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
22340c0fea5dSIngo Weinhold 			rld_unlock();
22357486b72dSIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
22367486b72dSIngo Weinhold 				image->id);
22370c85bd05SIngo Weinhold 			*_handle = image;
22380c0fea5dSIngo Weinhold 			return image->id;
22390c0fea5dSIngo Weinhold 		}
22400c0fea5dSIngo Weinhold 	}
22410c0fea5dSIngo Weinhold 
22420c0fea5dSIngo Weinhold 	status = load_container(path, type, NULL, &image);
22430c0fea5dSIngo Weinhold 	if (status < B_OK) {
22440c0fea5dSIngo Weinhold 		rld_unlock();
22457486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
22467486b72dSIngo Weinhold 			strerror(status));
22470c0fea5dSIngo Weinhold 		return status;
22480c0fea5dSIngo Weinhold 	}
22490c0fea5dSIngo Weinhold 
22500c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL) {
22510c85bd05SIngo Weinhold 		if (addOn)
22520c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_add_on;
22530c85bd05SIngo Weinhold 		else
22540c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_global;
22550c85bd05SIngo Weinhold 	}
22560c85bd05SIngo Weinhold 
22570c85bd05SIngo Weinhold 	status = load_dependencies(image);
22580c0fea5dSIngo Weinhold 	if (status < B_OK)
22590c0fea5dSIngo Weinhold 		goto err;
22600c85bd05SIngo Weinhold 
22610c85bd05SIngo Weinhold 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
22620c85bd05SIngo Weinhold 	// dependencies. If not specified, we temporarily set
22630c85bd05SIngo Weinhold 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
22640c85bd05SIngo Weinhold 	// for undefined symbol resolution.
22650c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) != 0)
22660c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RTLD_GLOBAL);
22670c85bd05SIngo Weinhold 	else
22680c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
22690c0fea5dSIngo Weinhold 
22700c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
22710c0fea5dSIngo Weinhold 	if (status < B_OK)
22720c0fea5dSIngo Weinhold 		goto err;
22730c0fea5dSIngo Weinhold 
22740c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) == 0)
22750c85bd05SIngo Weinhold 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
22760c85bd05SIngo Weinhold 
22770c0fea5dSIngo Weinhold 	remap_images();
22780c0fea5dSIngo Weinhold 	init_dependencies(image, true);
22790c0fea5dSIngo Weinhold 
22800c0fea5dSIngo Weinhold 	rld_unlock();
22817486b72dSIngo Weinhold 
22827486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
22837486b72dSIngo Weinhold 
22840c85bd05SIngo Weinhold 	*_handle = image;
22850c0fea5dSIngo Weinhold 	return image->id;
22860c0fea5dSIngo Weinhold 
22870c0fea5dSIngo Weinhold err:
22887486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
22897486b72dSIngo Weinhold 
22900c0fea5dSIngo Weinhold 	dequeue_image(&sLoadedImages, image);
22910c0fea5dSIngo Weinhold 	sLoadedImageCount--;
22920c0fea5dSIngo Weinhold 	delete_image(image);
22930c0fea5dSIngo Weinhold 	rld_unlock();
22940c0fea5dSIngo Weinhold 	return status;
22950c0fea5dSIngo Weinhold }
22960c0fea5dSIngo Weinhold 
22970c0fea5dSIngo Weinhold 
22980c0fea5dSIngo Weinhold status_t
22990c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
23000c0fea5dSIngo Weinhold {
23010c0fea5dSIngo Weinhold 	image_t *image;
23020c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
23030c0fea5dSIngo Weinhold 
23040c85bd05SIngo Weinhold 	if (handle == NULL && imageID < 0)
23050c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
23060c0fea5dSIngo Weinhold 
23070c85bd05SIngo Weinhold 	if (handle == RLD_GLOBAL_SCOPE)
23080c85bd05SIngo Weinhold 		return B_OK;
23090c85bd05SIngo Weinhold 
23100c0fea5dSIngo Weinhold 	rld_lock();
23110c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
23120c0fea5dSIngo Weinhold 
23139a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
23149a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
23159a6072a3SAxel Dörfler 		update_image_ids();
23169a6072a3SAxel Dörfler 	}
23179a6072a3SAxel Dörfler 
23180c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
23190c0fea5dSIngo Weinhold 
2320df30098dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
2321df30098dSIngo Weinhold 
23220c85bd05SIngo Weinhold 	if (handle != NULL) {
23230c85bd05SIngo Weinhold 		image = (image_t*)handle;
23240c85bd05SIngo Weinhold 		put_image(image);
2325df30098dSIngo Weinhold 		status = B_OK;
23260c85bd05SIngo Weinhold 	} else {
23270c0fea5dSIngo Weinhold 		for (image = sLoadedImages.head; image; image = image->next) {
23280c0fea5dSIngo Weinhold 			if (image->id == imageID) {
23290c0fea5dSIngo Weinhold 				// unload image
23300c0fea5dSIngo Weinhold 				if (type == image->type) {
23310c0fea5dSIngo Weinhold 					put_image(image);
23320c0fea5dSIngo Weinhold 					status = B_OK;
23330c0fea5dSIngo Weinhold 				} else
23340c0fea5dSIngo Weinhold 					status = B_BAD_VALUE;
23350c0fea5dSIngo Weinhold 				break;
23360c0fea5dSIngo Weinhold 			}
23370c0fea5dSIngo Weinhold 		}
23380c85bd05SIngo Weinhold 	}
23390c0fea5dSIngo Weinhold 
23400c0fea5dSIngo Weinhold 	if (status == B_OK) {
23410c0fea5dSIngo Weinhold 		while ((image = sDisposableImages.head) != NULL) {
23420c0fea5dSIngo Weinhold 			// call image fini here...
23438c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
23448c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
23453be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
23468c2a9d74SMichael Lotz 			}
23478c2a9d74SMichael Lotz 
234810b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
234910b4b5d1SIngo Weinhold 
23500c0fea5dSIngo Weinhold 			if (image->term_routine)
23510c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
23520c0fea5dSIngo Weinhold 
23530c0fea5dSIngo Weinhold 			dequeue_image(&sDisposableImages, image);
23540c0fea5dSIngo Weinhold 			unmap_image(image);
23550c0fea5dSIngo Weinhold 
235610b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
235710b4b5d1SIngo Weinhold 
23580c0fea5dSIngo Weinhold 			delete_image(image);
23590c0fea5dSIngo Weinhold 		}
23600c0fea5dSIngo Weinhold 	}
23610c0fea5dSIngo Weinhold 
23620c0fea5dSIngo Weinhold 	rld_unlock();
23630c0fea5dSIngo Weinhold 	return status;
23640c0fea5dSIngo Weinhold }
23650c0fea5dSIngo Weinhold 
23660c0fea5dSIngo Weinhold 
23670c0fea5dSIngo Weinhold status_t
23689a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
23699a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
23700c0fea5dSIngo Weinhold {
23710c0fea5dSIngo Weinhold 	int32 count = 0, j;
23720c0fea5dSIngo Weinhold 	uint32 i;
23730c0fea5dSIngo Weinhold 	image_t *image;
23740c0fea5dSIngo Weinhold 
23750c0fea5dSIngo Weinhold 	rld_lock();
23760c0fea5dSIngo Weinhold 
23770c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
23780c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
23790c0fea5dSIngo Weinhold 	if (image == NULL) {
23800c0fea5dSIngo Weinhold 		rld_unlock();
23810c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
23820c0fea5dSIngo Weinhold 	}
23830c0fea5dSIngo Weinhold 
23840c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
23850c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
23860c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
23870555803aSAxel Dörfler 			struct Elf32_Sym *symbol = &image->syms[j];
23880c0fea5dSIngo Weinhold 
23890c0fea5dSIngo Weinhold 			if (count == num) {
239010b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
239110b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
239210b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
23930c0fea5dSIngo Weinhold 
239410b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
239510b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
239610b4b5d1SIngo Weinhold 				int32 type;
23970c0fea5dSIngo Weinhold 				if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
239810b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
23990c0fea5dSIngo Weinhold 				else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
240010b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
24010c0fea5dSIngo Weinhold 				else
240210b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
240310b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
24040c0fea5dSIngo Weinhold 
240510b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
240610b4b5d1SIngo Weinhold 
240710b4b5d1SIngo Weinhold 				if (_type != NULL)
240810b4b5d1SIngo Weinhold 					*_type = type;
24090c0fea5dSIngo Weinhold 				if (_location != NULL)
241010b4b5d1SIngo Weinhold 					*_location = location;
24110c0fea5dSIngo Weinhold 				goto out;
24120c0fea5dSIngo Weinhold 			}
24130c0fea5dSIngo Weinhold 			count++;
24140c0fea5dSIngo Weinhold 		}
24150c0fea5dSIngo Weinhold 	}
24160c0fea5dSIngo Weinhold out:
24170c0fea5dSIngo Weinhold 	rld_unlock();
24180c0fea5dSIngo Weinhold 
24190c0fea5dSIngo Weinhold 	if (num != count)
24200c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
24210c0fea5dSIngo Weinhold 
24220c0fea5dSIngo Weinhold 	return B_OK;
24230c0fea5dSIngo Weinhold }
24240c0fea5dSIngo Weinhold 
24250c0fea5dSIngo Weinhold 
24260c0fea5dSIngo Weinhold status_t
24279a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
242880ece785SIngo Weinhold 	bool recursive, image_id *_inImage, void **_location)
24290c0fea5dSIngo Weinhold {
24300c0fea5dSIngo Weinhold 	status_t status = B_OK;
24310c0fea5dSIngo Weinhold 	image_t *image;
24320c0fea5dSIngo Weinhold 
24330c0fea5dSIngo Weinhold 	if (imageID < B_OK)
24340c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
24350c0fea5dSIngo Weinhold 	if (symbolName == NULL)
24360c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
24370c0fea5dSIngo Weinhold 
24380c0fea5dSIngo Weinhold 	rld_lock();
24390c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
24400c0fea5dSIngo Weinhold 
24410c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
24420c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
244380ece785SIngo Weinhold 	if (image != NULL) {
244480ece785SIngo Weinhold 		if (recursive) {
244580ece785SIngo Weinhold 			// breadth-first search in the given image and its dependencies
244680ece785SIngo Weinhold 			status = find_symbol_breadth_first(image, symbolName, symbolType,
244780ece785SIngo Weinhold 				&image, _location);
244880ece785SIngo Weinhold 		} else
244910b4b5d1SIngo Weinhold 			status = find_symbol(image, symbolName, symbolType, _location);
245080ece785SIngo Weinhold 
245180ece785SIngo Weinhold 		if (status == B_OK && _inImage != NULL)
245280ece785SIngo Weinhold 			*_inImage = image->id;
245380ece785SIngo Weinhold 	} else
24540c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
24550c0fea5dSIngo Weinhold 
24560c0fea5dSIngo Weinhold 	rld_unlock();
24570c0fea5dSIngo Weinhold 	return status;
24580c0fea5dSIngo Weinhold }
24590c0fea5dSIngo Weinhold 
24600c0fea5dSIngo Weinhold 
24610c0fea5dSIngo Weinhold status_t
24620c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
24630c85bd05SIngo Weinhold 	void **_location)
24640c85bd05SIngo Weinhold {
24650c85bd05SIngo Weinhold 	status_t status = B_ENTRY_NOT_FOUND;
24660c85bd05SIngo Weinhold 
24670c85bd05SIngo Weinhold 	if (symbolName == NULL)
24680c85bd05SIngo Weinhold 		return B_BAD_VALUE;
24690c85bd05SIngo Weinhold 
24700c85bd05SIngo Weinhold 	rld_lock();
24710c85bd05SIngo Weinhold 		// for now, just do stupid simple global locking
24720c85bd05SIngo Weinhold 
24730c85bd05SIngo Weinhold 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
24740c85bd05SIngo Weinhold 		// look in the default scope
24750c85bd05SIngo Weinhold 		image_t* image;
24760c85bd05SIngo Weinhold 		Elf32_Sym* symbol = find_undefined_symbol_global(sProgramImage,
24770c85bd05SIngo Weinhold 			sProgramImage, symbolName, &image);
24780c85bd05SIngo Weinhold 		if (symbol != NULL) {
24790c85bd05SIngo Weinhold 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
24800c85bd05SIngo Weinhold 			int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
24810c85bd05SIngo Weinhold 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
24820c85bd05SIngo Weinhold 			patch_defined_symbol(image, symbolName, _location, &symbolType);
24830c85bd05SIngo Weinhold 			status = B_OK;
24840c85bd05SIngo Weinhold 		}
24850c85bd05SIngo Weinhold 	} else if (handle == RTLD_NEXT) {
24860c85bd05SIngo Weinhold 		// Look in the default scope, but also in the dependencies of the
24870c85bd05SIngo Weinhold 		// calling image. Return the next after the caller symbol.
24880c85bd05SIngo Weinhold 
24890c85bd05SIngo Weinhold 		// First of all, find the caller symbol and its image.
24900c85bd05SIngo Weinhold 		Elf32_Sym* callerSymbol = NULL;
24910c85bd05SIngo Weinhold 		image_t* callerImage = sLoadedImages.head;
24920c85bd05SIngo Weinhold 		for (; callerImage != NULL; callerImage = callerImage->next) {
24930c85bd05SIngo Weinhold 			elf_region_t& text = callerImage->regions[0];
24940c85bd05SIngo Weinhold 			if ((addr_t)caller < text.vmstart
24950c85bd05SIngo Weinhold 				|| (addr_t)caller >= text.vmstart + text.vmsize) {
24960c85bd05SIngo Weinhold 				continue;
24970c85bd05SIngo Weinhold 			}
24980c85bd05SIngo Weinhold 
24990c85bd05SIngo Weinhold 			// found the image -- now find the symbol
25000c85bd05SIngo Weinhold 			for (uint32 i = 0; i < callerImage->symhash[1]; i++) {
25010c85bd05SIngo Weinhold 				Elf32_Sym& symbol = callerImage->syms[i];
25020c85bd05SIngo Weinhold 				if ((ELF32_ST_TYPE(symbol.st_info) != STT_FUNC)
25030c85bd05SIngo Weinhold 					|| symbol.st_value == 0) {
25040c85bd05SIngo Weinhold 					continue;
25050c85bd05SIngo Weinhold 				}
25060c85bd05SIngo Weinhold 
25070c85bd05SIngo Weinhold 				addr_t address = symbol.st_value
25080c85bd05SIngo Weinhold 					+ callerImage->regions[0].delta;
25090c85bd05SIngo Weinhold 				if ((addr_t)caller >= address
25100c85bd05SIngo Weinhold 					&& (addr_t)caller < address + symbol.st_size) {
25110c85bd05SIngo Weinhold 					callerSymbol = &symbol;
25120c85bd05SIngo Weinhold 					break;
25130c85bd05SIngo Weinhold 				}
25140c85bd05SIngo Weinhold 			}
25150c85bd05SIngo Weinhold 
25160c85bd05SIngo Weinhold 			break;
25170c85bd05SIngo Weinhold 		}
25180c85bd05SIngo Weinhold 
25190c85bd05SIngo Weinhold 		if (callerSymbol != NULL) {
25200c85bd05SIngo Weinhold 			// found the caller -- now search the global scope until we find
25210c85bd05SIngo Weinhold 			// the next symbol
25220c85bd05SIngo Weinhold 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
25230c85bd05SIngo Weinhold 
25240c85bd05SIngo Weinhold 			image_t* image = sLoadedImages.head;
25250c85bd05SIngo Weinhold 			for (; image != NULL; image = image->next) {
25260c85bd05SIngo Weinhold 				if (image != callerImage
25270c85bd05SIngo Weinhold 					&& (image->type == B_ADD_ON_IMAGE
25280c85bd05SIngo Weinhold 						|| (image->flags
25290c85bd05SIngo Weinhold 							& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0)) {
25300c85bd05SIngo Weinhold 					continue;
25310c85bd05SIngo Weinhold 				}
25320c85bd05SIngo Weinhold 
25330c85bd05SIngo Weinhold 				struct Elf32_Sym *symbol = find_symbol(image, symbolName,
25340c85bd05SIngo Weinhold 					B_SYMBOL_TYPE_TEXT);
25350c85bd05SIngo Weinhold 				if (symbol == NULL)
25360c85bd05SIngo Weinhold 					continue;
25370c85bd05SIngo Weinhold 
25380c85bd05SIngo Weinhold 				if (callerSymbol == NULL) {
25390c85bd05SIngo Weinhold 					// already skipped the caller symbol -- so this is
25400c85bd05SIngo Weinhold 					// the one we're looking for
25410c85bd05SIngo Weinhold 					*_location = (void*)(symbol->st_value
25420c85bd05SIngo Weinhold 						+ image->regions[0].delta);
25430c85bd05SIngo Weinhold 					int32 symbolType = B_SYMBOL_TYPE_TEXT;
25440c85bd05SIngo Weinhold 					patch_defined_symbol(image, symbolName, _location,
25450c85bd05SIngo Weinhold 						&symbolType);
25460c85bd05SIngo Weinhold 					status = B_OK;
25470c85bd05SIngo Weinhold 					break;
25480c85bd05SIngo Weinhold 				}
25490c85bd05SIngo Weinhold 				if (symbol == callerSymbol) {
25500c85bd05SIngo Weinhold 					// found the caller symbol
25510c85bd05SIngo Weinhold 					callerSymbol = NULL;
25520c85bd05SIngo Weinhold 				}
25530c85bd05SIngo Weinhold 			}
25540c85bd05SIngo Weinhold 
25550c85bd05SIngo Weinhold 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
25560c85bd05SIngo Weinhold 		}
25570c85bd05SIngo Weinhold 
25580c85bd05SIngo Weinhold 	} else {
25590c85bd05SIngo Weinhold 		// breadth-first search in the given image and its dependencies
25600c85bd05SIngo Weinhold 		image_t* inImage;
25610c85bd05SIngo Weinhold 		status = find_symbol_breadth_first((image_t*)handle, symbolName,
25620c85bd05SIngo Weinhold 			B_SYMBOL_TYPE_ANY, &inImage, _location);
25630c85bd05SIngo Weinhold 	}
25640c85bd05SIngo Weinhold 
25650c85bd05SIngo Weinhold 	rld_unlock();
25660c85bd05SIngo Weinhold 	return status;
25670c85bd05SIngo Weinhold }
25680c85bd05SIngo Weinhold 
25690c85bd05SIngo Weinhold 
25700c85bd05SIngo Weinhold status_t
25710c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
25720c0fea5dSIngo Weinhold {
25730c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
25740c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
25750c0fea5dSIngo Weinhold 	image_t *image;
25760c0fea5dSIngo Weinhold 
25770c0fea5dSIngo Weinhold 	if (_name == NULL)
25780c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
25790c0fea5dSIngo Weinhold 
25800c0fea5dSIngo Weinhold 	rld_lock();
25810c0fea5dSIngo Weinhold 
25820c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(id);
25830c0fea5dSIngo Weinhold 	if (image == NULL) {
25840c0fea5dSIngo Weinhold 		rld_unlock();
25850c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
25860c0fea5dSIngo Weinhold 	}
25870c0fea5dSIngo Weinhold 
25880c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
25890c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
25900c0fea5dSIngo Weinhold 		rld_unlock();
25910c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
25920c0fea5dSIngo Weinhold 	}
25930c0fea5dSIngo Weinhold 
25940c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
25950c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
25960c0fea5dSIngo Weinhold 			continue;
25970c0fea5dSIngo Weinhold 
25980c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
25990c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
26000c0fea5dSIngo Weinhold 
26010c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
26020c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
26030c0fea5dSIngo Weinhold 			rld_unlock();
26040c0fea5dSIngo Weinhold 			return B_OK;
26050c0fea5dSIngo Weinhold 		}
26060c0fea5dSIngo Weinhold 	}
26070c0fea5dSIngo Weinhold 
26080c0fea5dSIngo Weinhold 	rld_unlock();
26090c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
26100c0fea5dSIngo Weinhold }
26110c0fea5dSIngo Weinhold 
26120c0fea5dSIngo Weinhold 
261374c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
26140c0fea5dSIngo Weinhold 
26150c0fea5dSIngo Weinhold 
26169a6072a3SAxel Dörfler /*! Read and verify the ELF header */
26170c0fea5dSIngo Weinhold status_t
26180c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
26190c0fea5dSIngo Weinhold {
26200c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
26210c0fea5dSIngo Weinhold 
26220c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
26230c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
26240c0fea5dSIngo Weinhold 
26259a6072a3SAxel Dörfler 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize,
26269a6072a3SAxel Dörfler 		&sectionSize);
26270c0fea5dSIngo Weinhold }
26280c0fea5dSIngo Weinhold 
26290c0fea5dSIngo Weinhold 
26300c0fea5dSIngo Weinhold void
26310c0fea5dSIngo Weinhold terminate_program(void)
26320c0fea5dSIngo Weinhold {
26330c0fea5dSIngo Weinhold 	image_t **termList;
26340c0fea5dSIngo Weinhold 	ssize_t count, i;
26350c0fea5dSIngo Weinhold 
26360c0fea5dSIngo Weinhold 	count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED);
26370c0fea5dSIngo Weinhold 	if (count < B_OK)
26380c0fea5dSIngo Weinhold 		return;
26390c0fea5dSIngo Weinhold 
26409a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
26419a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
26429a6072a3SAxel Dörfler 		update_image_ids();
26439a6072a3SAxel Dörfler 	}
26449a6072a3SAxel Dörfler 
26450c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
26460c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
26470c0fea5dSIngo Weinhold 		image_t *image = termList[i];
26480c0fea5dSIngo Weinhold 
26490c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
26500c0fea5dSIngo Weinhold 
265110b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
265210b4b5d1SIngo Weinhold 
26530c0fea5dSIngo Weinhold 		if (image->term_routine)
26540c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
265510b4b5d1SIngo Weinhold 
265610b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
26570c0fea5dSIngo Weinhold 	}
26580c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
26590c0fea5dSIngo Weinhold 
26600c0fea5dSIngo Weinhold 	free(termList);
26610c0fea5dSIngo Weinhold }
26620c0fea5dSIngo Weinhold 
26630c0fea5dSIngo Weinhold 
26640c0fea5dSIngo Weinhold void
26650c0fea5dSIngo Weinhold rldelf_init(void)
26660c0fea5dSIngo Weinhold {
266710b4b5d1SIngo Weinhold 	// invoke static constructors
266810b4b5d1SIngo Weinhold 	new(&sAddOns) AddOnList;
266910b4b5d1SIngo Weinhold 
2670e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
2671e73923b0SAxel Dörfler 	sSemOwner = -1;
2672e73923b0SAxel Dörfler 	sSemCount = 0;
26730c0fea5dSIngo Weinhold 
26740c0fea5dSIngo Weinhold 	// create the debug area
26750c0fea5dSIngo Weinhold 	{
26760c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
26770c0fea5dSIngo Weinhold 
26780c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
26790c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
26800c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
26810c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
26820c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
26830c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
26840c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
26850c0fea5dSIngo Weinhold 		}
26860c0fea5dSIngo Weinhold 
26870c0fea5dSIngo Weinhold 		area->loaded_images = &sLoadedImages;
26880c0fea5dSIngo Weinhold 	}
268974c0424aSAxel Dörfler 
269074c0424aSAxel Dörfler 	// initialize error message if needed
26914bef3723SAxel Dörfler 	if (report_errors()) {
269274c0424aSAxel Dörfler 		void *buffer = malloc(1024);
269374c0424aSAxel Dörfler 		if (buffer == NULL)
269474c0424aSAxel Dörfler 			return;
269574c0424aSAxel Dörfler 
269674c0424aSAxel Dörfler 		sErrorMessage.SetTo(buffer, 1024, 'Rler');
269774c0424aSAxel Dörfler 	}
26980c0fea5dSIngo Weinhold }
26991873b4b3SIngo Weinhold 
27001873b4b3SIngo Weinhold 
27011873b4b3SIngo Weinhold status_t
27029a6072a3SAxel Dörfler elf_reinit_after_fork(void)
27031873b4b3SIngo Weinhold {
2704e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
2705e73923b0SAxel Dörfler 	if (sSem < 0)
2706e73923b0SAxel Dörfler 		return sSem;
27071873b4b3SIngo Weinhold 
27089a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
2709cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
2710cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
27119a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
27129a6072a3SAxel Dörfler 	sInvalidImageIDs = true;
2713cbc456deSIngo Weinhold 
27141873b4b3SIngo Weinhold 	return B_OK;
27151873b4b3SIngo Weinhold }
2716