xref: /haiku/src/system/runtime_loader/elf.cpp (revision 593ee7bbc334e3ca6ecf6553543ad8037bd7b58a)
10c0fea5dSIngo Weinhold /*
2*593ee7bbSIngo Weinhold  * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
312a5e9a4SAxel Dörfler  * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
40c0fea5dSIngo Weinhold  * Distributed under the terms of the MIT License.
50c0fea5dSIngo Weinhold  *
60c0fea5dSIngo Weinhold  * Copyright 2002, Manuel J. Petit. All rights reserved.
70c0fea5dSIngo Weinhold  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
80c0fea5dSIngo Weinhold  * Distributed under the terms of the NewOS License.
90c0fea5dSIngo Weinhold  */
100c0fea5dSIngo Weinhold 
110c0fea5dSIngo Weinhold #include "runtime_loader_private.h"
120c0fea5dSIngo Weinhold 
13ca618b22SIngo Weinhold #include <ctype.h>
140c85bd05SIngo Weinhold #include <dlfcn.h>
150c0fea5dSIngo Weinhold #include <stdio.h>
160c0fea5dSIngo Weinhold #include <stdlib.h>
1734982809SIngo Weinhold #include <string.h>
180c0fea5dSIngo Weinhold 
19ca618b22SIngo Weinhold #include <OS.h>
20ca618b22SIngo Weinhold 
217486b72dSIngo Weinhold #include <elf32.h>
22*593ee7bbSIngo Weinhold #include <image_defs.h>
237486b72dSIngo Weinhold #include <runtime_loader.h>
247486b72dSIngo Weinhold #include <syscalls.h>
257486b72dSIngo Weinhold #include <user_runtime.h>
2610b4b5d1SIngo Weinhold #include <util/DoublyLinkedList.h>
2710b4b5d1SIngo Weinhold #include <util/kernel_cpp.h>
286b202f4eSIngo Weinhold #include <util/KMessage.h>
296b202f4eSIngo Weinhold #include <vm_defs.h>
307486b72dSIngo Weinhold 
31071f9c3aSIngo Weinhold #include "tracing_config.h"
32071f9c3aSIngo Weinhold 
330c0fea5dSIngo Weinhold 
340c0fea5dSIngo Weinhold //#define TRACE_RLD
350c0fea5dSIngo Weinhold #ifdef TRACE_RLD
360c0fea5dSIngo Weinhold #	define TRACE(x) dprintf x
370c0fea5dSIngo Weinhold #else
380c0fea5dSIngo Weinhold #	define TRACE(x) ;
390c0fea5dSIngo Weinhold #endif
400c0fea5dSIngo Weinhold 
410c0fea5dSIngo Weinhold 
4210b4b5d1SIngo Weinhold // TODO: implement better locking strategy
4310b4b5d1SIngo Weinhold // TODO: implement lazy binding
440c0fea5dSIngo Weinhold 
450c0fea5dSIngo Weinhold #define	PAGE_MASK (B_PAGE_SIZE - 1)
460c0fea5dSIngo Weinhold 
470c0fea5dSIngo Weinhold #define	PAGE_OFFSET(x) ((x) & (PAGE_MASK))
480c0fea5dSIngo Weinhold #define	PAGE_BASE(x) ((x) & ~(PAGE_MASK))
490c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
500c0fea5dSIngo Weinhold 
510c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000
520c0fea5dSIngo Weinhold 	/* keep in sync with app ldscript */
530c0fea5dSIngo Weinhold 
540c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen())
550c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE	((void*)-2l)
560c85bd05SIngo Weinhold 
570c0fea5dSIngo Weinhold enum {
580c85bd05SIngo Weinhold 	// the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL
590c85bd05SIngo Weinhold 
600c85bd05SIngo Weinhold 	RFLAG_RW					= 0x0010,
610c85bd05SIngo Weinhold 	RFLAG_ANON					= 0x0020,
620c0fea5dSIngo Weinhold 
630c0fea5dSIngo Weinhold 	RFLAG_TERMINATED			= 0x0200,
640c0fea5dSIngo Weinhold 	RFLAG_INITIALIZED			= 0x0400,
650c0fea5dSIngo Weinhold 	RFLAG_SYMBOLIC				= 0x0800,
660c0fea5dSIngo Weinhold 	RFLAG_RELOCATED				= 0x1000,
670c0fea5dSIngo Weinhold 	RFLAG_PROTECTED				= 0x2000,
680c0fea5dSIngo Weinhold 	RFLAG_DEPENDENCIES_LOADED	= 0x4000,
6946f4d849SIngo Weinhold 	RFLAG_REMAPPED				= 0x8000,
7046f4d849SIngo Weinhold 
710c85bd05SIngo Weinhold 	RFLAG_VISITED				= 0x10000,
720c85bd05SIngo Weinhold 	RFLAG_USE_FOR_RESOLVING		= 0x20000
7346f4d849SIngo Weinhold 		// temporarily set in the symbol resolution code
740c0fea5dSIngo Weinhold };
750c0fea5dSIngo Weinhold 
760c0fea5dSIngo Weinhold 
770c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type)	(1 << ((type) - 1))
780c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES				(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
790c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
800c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
810c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
820c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE			(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
830c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
840c0fea5dSIngo Weinhold 
850c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
860c0fea5dSIngo Weinhold 
8710b4b5d1SIngo Weinhold 
8810b4b5d1SIngo Weinhold // image events
8910b4b5d1SIngo Weinhold enum {
9010b4b5d1SIngo Weinhold 	IMAGE_EVENT_LOADED,
9110b4b5d1SIngo Weinhold 	IMAGE_EVENT_RELOCATED,
9210b4b5d1SIngo Weinhold 	IMAGE_EVENT_INITIALIZED,
9310b4b5d1SIngo Weinhold 	IMAGE_EVENT_UNINITIALIZING,
9410b4b5d1SIngo Weinhold 	IMAGE_EVENT_UNLOADING
9510b4b5d1SIngo Weinhold };
9610b4b5d1SIngo Weinhold 
9710b4b5d1SIngo Weinhold 
9810b4b5d1SIngo Weinhold struct RuntimeLoaderAddOn
9910b4b5d1SIngo Weinhold 		: public DoublyLinkedListLinkImpl<RuntimeLoaderAddOn> {
10010b4b5d1SIngo Weinhold 	image_t*				image;
10110b4b5d1SIngo Weinhold 	runtime_loader_add_on*	addOn;
10210b4b5d1SIngo Weinhold 
10310b4b5d1SIngo Weinhold 	RuntimeLoaderAddOn(image_t* image, runtime_loader_add_on* addOn)
10410b4b5d1SIngo Weinhold 		:
10510b4b5d1SIngo Weinhold 		image(image),
10610b4b5d1SIngo Weinhold 		addOn(addOn)
10710b4b5d1SIngo Weinhold 	{
10810b4b5d1SIngo Weinhold 	}
10910b4b5d1SIngo Weinhold };
11010b4b5d1SIngo Weinhold 
11110b4b5d1SIngo Weinhold typedef DoublyLinkedList<RuntimeLoaderAddOn> AddOnList;
11210b4b5d1SIngo Weinhold 
11310b4b5d1SIngo Weinhold struct RuntimeLoaderSymbolPatcher {
11410b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher*		next;
11510b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher*	patcher;
11610b4b5d1SIngo Weinhold 	void*							cookie;
11710b4b5d1SIngo Weinhold 
11810b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher(runtime_loader_symbol_patcher* patcher,
11910b4b5d1SIngo Weinhold 			void* cookie)
12010b4b5d1SIngo Weinhold 		:
12110b4b5d1SIngo Weinhold 		patcher(patcher),
12210b4b5d1SIngo Weinhold 		cookie(cookie)
12310b4b5d1SIngo Weinhold 	{
12410b4b5d1SIngo Weinhold 	}
12510b4b5d1SIngo Weinhold };
12610b4b5d1SIngo Weinhold 
12710b4b5d1SIngo Weinhold 
1280c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0};
1290c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0};
1300c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0;
1310c0fea5dSIngo Weinhold static image_t *sProgramImage;
13274c0424aSAxel Dörfler static KMessage sErrorMessage;
1335d0638bfSIngo Weinhold static bool sProgramLoaded = false;
13461b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL;
1359a6072a3SAxel Dörfler static bool sInvalidImageIDs;
136ca618b22SIngo Weinhold static image_t **sPreloadedImages = NULL;
137ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0;
13810b4b5d1SIngo Weinhold static AddOnList sAddOns;
1390c0fea5dSIngo Weinhold 
1400c0fea5dSIngo Weinhold // a recursive lock
141e73923b0SAxel Dörfler static sem_id sSem;
142e73923b0SAxel Dörfler static thread_id sSemOwner;
143e73923b0SAxel Dörfler static int32 sSemCount;
1440c0fea5dSIngo Weinhold 
14510b4b5d1SIngo Weinhold extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport;
14610b4b5d1SIngo Weinhold 
1470c0fea5dSIngo Weinhold 
148*593ee7bbSIngo Weinhold static struct Elf32_Sym* find_symbol(image_t* image, const char* name,
149*593ee7bbSIngo Weinhold 	int32 type);
150*593ee7bbSIngo Weinhold 
151*593ee7bbSIngo Weinhold 
1520c0fea5dSIngo Weinhold void
1530c0fea5dSIngo Weinhold dprintf(const char *format, ...)
1540c0fea5dSIngo Weinhold {
1550c0fea5dSIngo Weinhold 	char buffer[1024];
1560c0fea5dSIngo Weinhold 
1570c0fea5dSIngo Weinhold 	va_list list;
1580c0fea5dSIngo Weinhold 	va_start(list, format);
1590c0fea5dSIngo Weinhold 
1600c0fea5dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1610c0fea5dSIngo Weinhold 	_kern_debug_output(buffer);
1620c0fea5dSIngo Weinhold 
1630c0fea5dSIngo Weinhold 	va_end(list);
1640c0fea5dSIngo Weinhold }
1655d0638bfSIngo Weinhold 
1665d0638bfSIngo Weinhold #define FATAL(x...)							\
1675d0638bfSIngo Weinhold 	do {									\
1685d0638bfSIngo Weinhold 		dprintf("runtime_loader: " x);		\
1695d0638bfSIngo Weinhold 		if (!sProgramLoaded)				\
1705d0638bfSIngo Weinhold 			printf("runtime_loader: " x);	\
1715d0638bfSIngo Weinhold 	} while (false)
1720c0fea5dSIngo Weinhold 
1730c0fea5dSIngo Weinhold 
17434982809SIngo Weinhold /*!	Mini atoi(), so we don't have to include the libroot dependencies.
17534982809SIngo Weinhold  */
17634982809SIngo Weinhold int
17734982809SIngo Weinhold atoi(const char* num)
17834982809SIngo Weinhold {
17934982809SIngo Weinhold 	int result = 0;
18034982809SIngo Weinhold 	while (*num >= '0' && *num <= '9') {
18134982809SIngo Weinhold 		result = (result * 10) + (*num - '0');
18234982809SIngo Weinhold 		num++;
18334982809SIngo Weinhold 	}
18434982809SIngo Weinhold 
18534982809SIngo Weinhold 	return result;
18634982809SIngo Weinhold }
18734982809SIngo Weinhold 
18834982809SIngo Weinhold 
1896bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING
1907486b72dSIngo Weinhold 
1917486b72dSIngo Weinhold void
1927486b72dSIngo Weinhold ktrace_printf(const char *format, ...)
1937486b72dSIngo Weinhold {
1947486b72dSIngo Weinhold 	va_list list;
1957486b72dSIngo Weinhold 	va_start(list, format);
1967486b72dSIngo Weinhold 
1977486b72dSIngo Weinhold 	char buffer[1024];
1987486b72dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1997486b72dSIngo Weinhold 	_kern_ktrace_output(buffer);
2007486b72dSIngo Weinhold 
2017486b72dSIngo Weinhold 	va_end(list);
2027486b72dSIngo Weinhold }
2037486b72dSIngo Weinhold 
2047486b72dSIngo Weinhold #define KTRACE(x...)	ktrace_printf(x)
2057486b72dSIngo Weinhold 
2067486b72dSIngo Weinhold #else
2077486b72dSIngo Weinhold #	define KTRACE(x...)
2087486b72dSIngo Weinhold #endif	// RUNTIME_LOADER_TRACING
2097486b72dSIngo Weinhold 
2107486b72dSIngo Weinhold 
2110c0fea5dSIngo Weinhold static void
2120c0fea5dSIngo Weinhold rld_unlock()
2130c0fea5dSIngo Weinhold {
214e73923b0SAxel Dörfler 	if (sSemCount-- == 1) {
215e73923b0SAxel Dörfler 		sSemOwner = -1;
216e73923b0SAxel Dörfler 		release_sem(sSem);
2170c0fea5dSIngo Weinhold 	}
2180c0fea5dSIngo Weinhold }
2190c0fea5dSIngo Weinhold 
2200c0fea5dSIngo Weinhold 
2210c0fea5dSIngo Weinhold static void
2220c0fea5dSIngo Weinhold rld_lock()
2230c0fea5dSIngo Weinhold {
2240c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
225e73923b0SAxel Dörfler 	if (self != sSemOwner) {
226e73923b0SAxel Dörfler 		acquire_sem(sSem);
227e73923b0SAxel Dörfler 		sSemOwner = self;
2280c0fea5dSIngo Weinhold 	}
229e73923b0SAxel Dörfler 	sSemCount++;
2300c0fea5dSIngo Weinhold }
2310c0fea5dSIngo Weinhold 
2320c0fea5dSIngo Weinhold 
2330c0fea5dSIngo Weinhold static void
2340c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image)
2350c0fea5dSIngo Weinhold {
2360c0fea5dSIngo Weinhold 	image->next = 0;
2370c0fea5dSIngo Weinhold 
2380c0fea5dSIngo Weinhold 	image->prev = queue->tail;
2390c0fea5dSIngo Weinhold 	if (queue->tail)
2400c0fea5dSIngo Weinhold 		queue->tail->next = image;
2410c0fea5dSIngo Weinhold 
2420c0fea5dSIngo Weinhold 	queue->tail = image;
2430c0fea5dSIngo Weinhold 	if (!queue->head)
2440c0fea5dSIngo Weinhold 		queue->head = image;
2450c0fea5dSIngo Weinhold }
2460c0fea5dSIngo Weinhold 
2470c0fea5dSIngo Weinhold 
2480c0fea5dSIngo Weinhold static void
2490c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image)
2500c0fea5dSIngo Weinhold {
2510c0fea5dSIngo Weinhold 	if (image->next)
2520c0fea5dSIngo Weinhold 		image->next->prev = image->prev;
2530c0fea5dSIngo Weinhold 	else
2540c0fea5dSIngo Weinhold 		queue->tail = image->prev;
2550c0fea5dSIngo Weinhold 
2560c0fea5dSIngo Weinhold 	if (image->prev)
2570c0fea5dSIngo Weinhold 		image->prev->next = image->next;
2580c0fea5dSIngo Weinhold 	else
2590c0fea5dSIngo Weinhold 		queue->head = image->next;
2600c0fea5dSIngo Weinhold 
2610c0fea5dSIngo Weinhold 	image->prev = 0;
2620c0fea5dSIngo Weinhold 	image->next = 0;
2630c0fea5dSIngo Weinhold }
2640c0fea5dSIngo Weinhold 
2650c0fea5dSIngo Weinhold 
2660c0fea5dSIngo Weinhold static uint32
2670c0fea5dSIngo Weinhold elf_hash(const uint8 *name)
2680c0fea5dSIngo Weinhold {
2690c0fea5dSIngo Weinhold 	uint32 hash = 0;
2700c0fea5dSIngo Weinhold 	uint32 temp;
2710c0fea5dSIngo Weinhold 
2720c0fea5dSIngo Weinhold 	while (*name) {
2730c0fea5dSIngo Weinhold 		hash = (hash << 4) + *name++;
2740c0fea5dSIngo Weinhold 		if ((temp = hash & 0xf0000000)) {
2750c0fea5dSIngo Weinhold 			hash ^= temp >> 24;
2760c0fea5dSIngo Weinhold 		}
2770c0fea5dSIngo Weinhold 		hash &= ~temp;
2780c0fea5dSIngo Weinhold 	}
2790c0fea5dSIngo Weinhold 	return hash;
2800c0fea5dSIngo Weinhold }
2810c0fea5dSIngo Weinhold 
2820c0fea5dSIngo Weinhold 
2834bef3723SAxel Dörfler static inline bool
2844bef3723SAxel Dörfler report_errors()
2854bef3723SAxel Dörfler {
2864bef3723SAxel Dörfler 	return gProgramArgs->error_port >= 0;
2874bef3723SAxel Dörfler }
2884bef3723SAxel Dörfler 
2894bef3723SAxel Dörfler 
2909a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork.
2919a6072a3SAxel Dörfler static status_t
2929a6072a3SAxel Dörfler update_image_id(image_t *image)
2939a6072a3SAxel Dörfler {
2949a6072a3SAxel Dörfler 	int32 cookie = 0;
2959a6072a3SAxel Dörfler 	image_info info;
2969a6072a3SAxel Dörfler 	while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info,
2979a6072a3SAxel Dörfler 			sizeof(image_info)) == B_OK) {
2989a6072a3SAxel Dörfler 		for (uint32 i = 0; i < image->num_regions; i++) {
2999a6072a3SAxel Dörfler 			if (image->regions[i].vmstart == (addr_t)info.text) {
3009a6072a3SAxel Dörfler 				image->id = info.id;
3019a6072a3SAxel Dörfler 				return B_OK;
3029a6072a3SAxel Dörfler 			}
3039a6072a3SAxel Dörfler 		}
3049a6072a3SAxel Dörfler 	}
3059a6072a3SAxel Dörfler 
3069a6072a3SAxel Dörfler 	FATAL("Could not update image ID %ld after fork()!\n", image->id);
3079a6072a3SAxel Dörfler 	return B_ENTRY_NOT_FOUND;
3089a6072a3SAxel Dörfler }
3099a6072a3SAxel Dörfler 
3109a6072a3SAxel Dörfler 
3119a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images.
3129a6072a3SAxel Dörfler static status_t
3139a6072a3SAxel Dörfler update_image_ids(void)
3149a6072a3SAxel Dörfler {
3159a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.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 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
3219a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
3229a6072a3SAxel Dörfler 		if (status != B_OK)
3239a6072a3SAxel Dörfler 			return status;
3249a6072a3SAxel Dörfler 	}
3259a6072a3SAxel Dörfler 
3269a6072a3SAxel Dörfler 	sInvalidImageIDs = false;
3279a6072a3SAxel Dörfler 	return B_OK;
3289a6072a3SAxel Dörfler }
3299a6072a3SAxel Dörfler 
3309a6072a3SAxel Dörfler 
3310c0fea5dSIngo Weinhold static image_t *
3320c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath,
3330c0fea5dSIngo Weinhold 	uint32 typeMask)
3340c0fea5dSIngo Weinhold {
3359a6072a3SAxel Dörfler 	for (image_t *image = queue->head; image; image = image->next) {
3360c0fea5dSIngo Weinhold 		const char *imageName = isPath ? image->path : image->name;
3370c0fea5dSIngo Weinhold 		int length = isPath ? sizeof(image->path) : sizeof(image->name);
3380c0fea5dSIngo Weinhold 
3390c0fea5dSIngo Weinhold 		if (!strncmp(imageName, name, length)
3400c0fea5dSIngo Weinhold 			&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
3410c0fea5dSIngo Weinhold 			return image;
3420c0fea5dSIngo Weinhold 		}
3430c0fea5dSIngo Weinhold 	}
3440c0fea5dSIngo Weinhold 
3450c0fea5dSIngo Weinhold 	return NULL;
3460c0fea5dSIngo Weinhold }
3470c0fea5dSIngo Weinhold 
3480c0fea5dSIngo Weinhold 
3490c0fea5dSIngo Weinhold static image_t *
3500c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask)
3510c0fea5dSIngo Weinhold {
3529a6072a3SAxel Dörfler 	bool isPath = strchr(name, '/') != NULL;
35346f4d849SIngo Weinhold 	return find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
3540c0fea5dSIngo Weinhold }
3550c0fea5dSIngo Weinhold 
3560c0fea5dSIngo Weinhold 
3570c0fea5dSIngo Weinhold static image_t *
3580c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id)
3590c0fea5dSIngo Weinhold {
3609a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
3619a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
3629a6072a3SAxel Dörfler 		update_image_ids();
3639a6072a3SAxel Dörfler 	}
3640c0fea5dSIngo Weinhold 
3659a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
3660c0fea5dSIngo Weinhold 		if (image->id == id)
3670c0fea5dSIngo Weinhold 			return image;
3680c0fea5dSIngo Weinhold 	}
3690c0fea5dSIngo Weinhold 
3700c0fea5dSIngo Weinhold 	// For the termination routine, we need to look into the list of
3710c0fea5dSIngo Weinhold 	// disposable images as well
3729a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
3730c0fea5dSIngo Weinhold 		if (image->id == id)
3740c0fea5dSIngo Weinhold 			return image;
3750c0fea5dSIngo Weinhold 	}
3760c0fea5dSIngo Weinhold 
3770c0fea5dSIngo Weinhold 	return NULL;
3780c0fea5dSIngo Weinhold }
3790c0fea5dSIngo Weinhold 
3800c0fea5dSIngo Weinhold 
3815fd6637bSIngo Weinhold static image_t*
3825fd6637bSIngo Weinhold get_program_image()
38312a5e9a4SAxel Dörfler {
38412a5e9a4SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
38512a5e9a4SAxel Dörfler 		if (image->type == B_APP_IMAGE)
3865fd6637bSIngo Weinhold 			return image;
38712a5e9a4SAxel Dörfler 	}
38812a5e9a4SAxel Dörfler 
38912a5e9a4SAxel Dörfler 	return NULL;
39012a5e9a4SAxel Dörfler }
39112a5e9a4SAxel Dörfler 
39212a5e9a4SAxel Dörfler 
3935fd6637bSIngo Weinhold static const char *
3945fd6637bSIngo Weinhold get_program_path()
3955fd6637bSIngo Weinhold {
3965fd6637bSIngo Weinhold 	if (image_t* image = get_program_image())
3975fd6637bSIngo Weinhold 		return image->path;
3985fd6637bSIngo Weinhold 
3995fd6637bSIngo Weinhold 	return NULL;
4005fd6637bSIngo Weinhold }
4015fd6637bSIngo Weinhold 
4025fd6637bSIngo Weinhold 
4030c0fea5dSIngo Weinhold static status_t
40412a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize,
40512a5e9a4SAxel Dörfler 	int32 *_sheaderSize)
4060c0fea5dSIngo Weinhold {
4070c0fea5dSIngo Weinhold 	if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
4080c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4090c0fea5dSIngo Weinhold 
4100c0fea5dSIngo Weinhold 	if (eheader->e_ident[4] != ELFCLASS32)
4110c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4120c0fea5dSIngo Weinhold 
4130c0fea5dSIngo Weinhold 	if (eheader->e_phoff == 0)
4140c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4150c0fea5dSIngo Weinhold 
4160c0fea5dSIngo Weinhold 	if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
4170c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4180c0fea5dSIngo Weinhold 
4190c0fea5dSIngo Weinhold 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
4200c0fea5dSIngo Weinhold 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
4210c0fea5dSIngo Weinhold 
4225aa7b7b6SMarcus Overhagen 	if (*_pheaderSize <= 0 || *_sheaderSize <= 0)
4235aa7b7b6SMarcus Overhagen 		return B_NOT_AN_EXECUTABLE;
4245aa7b7b6SMarcus Overhagen 
4255aa7b7b6SMarcus Overhagen 	return B_OK;
4260c0fea5dSIngo Weinhold }
4270c0fea5dSIngo Weinhold 
4280c0fea5dSIngo Weinhold 
4290c0fea5dSIngo Weinhold static int32
4300c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize)
4310c0fea5dSIngo Weinhold {
4320c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheaders;
4330c0fea5dSIngo Weinhold 	int32 count = 0;
4340c0fea5dSIngo Weinhold 	int i;
4350c0fea5dSIngo Weinhold 
4360c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
4370c0fea5dSIngo Weinhold 		pheaders = (struct Elf32_Phdr *)(buff + i * phentsize);
4380c0fea5dSIngo Weinhold 
4390c0fea5dSIngo Weinhold 		switch (pheaders->p_type) {
4400c0fea5dSIngo Weinhold 			case PT_NULL:
4410c0fea5dSIngo Weinhold 				/* NOP header */
4420c0fea5dSIngo Weinhold 				break;
4430c0fea5dSIngo Weinhold 			case PT_LOAD:
4440c0fea5dSIngo Weinhold 				count += 1;
4450c0fea5dSIngo Weinhold 				if (pheaders->p_memsz != pheaders->p_filesz) {
4460c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz);
4470c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz);
4480c0fea5dSIngo Weinhold 
4490c0fea5dSIngo Weinhold 					if (A != B)
4500c0fea5dSIngo Weinhold 						count += 1;
4510c0fea5dSIngo Weinhold 				}
4520c0fea5dSIngo Weinhold 				break;
4530c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
4540c0fea5dSIngo Weinhold 				/* will be handled at some other place */
4550c0fea5dSIngo Weinhold 				break;
4560c0fea5dSIngo Weinhold 			case PT_INTERP:
4570c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
4580c0fea5dSIngo Weinhold 				break;
4590c0fea5dSIngo Weinhold 			case PT_NOTE:
4600c0fea5dSIngo Weinhold 				/* unsupported */
4610c0fea5dSIngo Weinhold 				break;
4620c0fea5dSIngo Weinhold 			case PT_SHLIB:
4630c0fea5dSIngo Weinhold 				/* undefined semantics */
4640c0fea5dSIngo Weinhold 				break;
4650c0fea5dSIngo Weinhold 			case PT_PHDR:
4660c0fea5dSIngo Weinhold 				/* we don't use it */
4670c0fea5dSIngo Weinhold 				break;
4682ecebae1SDavid McPaul 			case PT_STACK:
4692ecebae1SDavid McPaul 				/* we don't use it */
4702ecebae1SDavid McPaul 				break;
4710c0fea5dSIngo Weinhold 			default:
4722ecebae1SDavid McPaul 				FATAL("unhandled pheader type in count 0x%lx\n", pheaders->p_type);
4730c0fea5dSIngo Weinhold 				return B_BAD_DATA;
4740c0fea5dSIngo Weinhold 		}
4750c0fea5dSIngo Weinhold 	}
4760c0fea5dSIngo Weinhold 
4770c0fea5dSIngo Weinhold 	return count;
4780c0fea5dSIngo Weinhold }
4790c0fea5dSIngo Weinhold 
4800c0fea5dSIngo Weinhold 
4810c0fea5dSIngo Weinhold static image_t *
4820c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions)
4830c0fea5dSIngo Weinhold {
4840c0fea5dSIngo Weinhold 	size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t);
4850c0fea5dSIngo Weinhold 	const char *lastSlash;
4860c0fea5dSIngo Weinhold 
4870c0fea5dSIngo Weinhold 	image_t *image = (image_t*)malloc(allocSize);
4880c0fea5dSIngo Weinhold 	if (image == NULL) {
4890c0fea5dSIngo Weinhold 		FATAL("no memory for image %s\n", path);
4900c0fea5dSIngo Weinhold 		return NULL;
4910c0fea5dSIngo Weinhold 	}
4920c0fea5dSIngo Weinhold 
4930c0fea5dSIngo Weinhold 	memset(image, 0, allocSize);
4940c0fea5dSIngo Weinhold 
4950c0fea5dSIngo Weinhold 	strlcpy(image->path, path, sizeof(image->path));
4960c0fea5dSIngo Weinhold 
4970c0fea5dSIngo Weinhold 	// Make the last component of the supplied name the image name.
4980c0fea5dSIngo Weinhold 	// If present, DT_SONAME will replace this name.
4990c0fea5dSIngo Weinhold 	if ((lastSlash = strrchr(name, '/')))
5000c0fea5dSIngo Weinhold 		strlcpy(image->name, lastSlash + 1, sizeof(image->name));
5010c0fea5dSIngo Weinhold 	else
5020c0fea5dSIngo Weinhold 		strlcpy(image->name, name, sizeof(image->name));
5030c0fea5dSIngo Weinhold 
5040c0fea5dSIngo Weinhold 	image->ref_count = 1;
5050c0fea5dSIngo Weinhold 	image->num_regions = num_regions;
5060c0fea5dSIngo Weinhold 
5070c0fea5dSIngo Weinhold 	return image;
5080c0fea5dSIngo Weinhold }
5090c0fea5dSIngo Weinhold 
5100c0fea5dSIngo Weinhold 
5110c0fea5dSIngo Weinhold static void
5120c0fea5dSIngo Weinhold delete_image_struct(image_t *image)
5130c0fea5dSIngo Weinhold {
5140c0fea5dSIngo Weinhold #ifdef DEBUG
5150c0fea5dSIngo Weinhold 	size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t);
5160c0fea5dSIngo Weinhold 	memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
5170c0fea5dSIngo Weinhold #endif
5180c0fea5dSIngo Weinhold 	free(image->needed);
51910b4b5d1SIngo Weinhold 
52010b4b5d1SIngo Weinhold 	while (RuntimeLoaderSymbolPatcher* patcher
52110b4b5d1SIngo Weinhold 			= image->defined_symbol_patchers) {
52210b4b5d1SIngo Weinhold 		image->defined_symbol_patchers = patcher->next;
52310b4b5d1SIngo Weinhold 		delete patcher;
52410b4b5d1SIngo Weinhold 	}
52510b4b5d1SIngo Weinhold 	while (RuntimeLoaderSymbolPatcher* patcher
52610b4b5d1SIngo Weinhold 			= image->undefined_symbol_patchers) {
52710b4b5d1SIngo Weinhold 		image->undefined_symbol_patchers = patcher->next;
52810b4b5d1SIngo Weinhold 		delete patcher;
52910b4b5d1SIngo Weinhold 	}
5300c0fea5dSIngo Weinhold 
5310c0fea5dSIngo Weinhold #ifdef DEBUG
5329a6072a3SAxel Dörfler 	// overwrite images to make sure they aren't accidently reused anywhere
5330c0fea5dSIngo Weinhold 	memset(image, 0xa5, size);
5340c0fea5dSIngo Weinhold #endif
5350c0fea5dSIngo Weinhold 	free(image);
5360c0fea5dSIngo Weinhold }
5370c0fea5dSIngo Weinhold 
5380c0fea5dSIngo Weinhold 
5390c0fea5dSIngo Weinhold static void
5400c0fea5dSIngo Weinhold delete_image(image_t *image)
5410c0fea5dSIngo Weinhold {
5422760c4cdSAxel Dörfler 	if (image == NULL)
5432760c4cdSAxel Dörfler 		return;
5442760c4cdSAxel Dörfler 
5450c0fea5dSIngo Weinhold 	_kern_unregister_image(image->id);
5460c0fea5dSIngo Weinhold 		// registered in load_container()
5470c0fea5dSIngo Weinhold 
5480c0fea5dSIngo Weinhold 	delete_image_struct(image);
5490c0fea5dSIngo Weinhold }
5500c0fea5dSIngo Weinhold 
5510c0fea5dSIngo Weinhold 
5520c85bd05SIngo Weinhold static void
5530c85bd05SIngo Weinhold update_image_flags_recursively(image_t* image, uint32 flagsToSet,
5540c85bd05SIngo Weinhold 	uint32 flagsToClear)
5550c85bd05SIngo Weinhold {
5560c85bd05SIngo Weinhold 	image_t* queue[sLoadedImageCount];
5570c85bd05SIngo Weinhold 	uint32 count = 0;
5580c85bd05SIngo Weinhold 	uint32 index = 0;
5590c85bd05SIngo Weinhold 	queue[count++] = image;
5600c85bd05SIngo Weinhold 	image->flags |= RFLAG_VISITED;
5610c85bd05SIngo Weinhold 
5620c85bd05SIngo Weinhold 	while (index < count) {
5630c85bd05SIngo Weinhold 		// pop next image
5640c85bd05SIngo Weinhold 		image = queue[index++];
5650c85bd05SIngo Weinhold 
5660c85bd05SIngo Weinhold 		// push dependencies
5670c85bd05SIngo Weinhold 		for (uint32 i = 0; i < image->num_needed; i++) {
5680c85bd05SIngo Weinhold 			image_t* needed = image->needed[i];
5690c85bd05SIngo Weinhold 			if ((needed->flags & RFLAG_VISITED) == 0) {
5700c85bd05SIngo Weinhold 				queue[count++] = needed;
5710c85bd05SIngo Weinhold 				needed->flags |= RFLAG_VISITED;
5720c85bd05SIngo Weinhold 			}
5730c85bd05SIngo Weinhold 		}
5740c85bd05SIngo Weinhold 	}
5750c85bd05SIngo Weinhold 
5760c85bd05SIngo Weinhold 	// update flags
5770c85bd05SIngo Weinhold 	for (uint32 i = 0; i < count; i++) {
5780c85bd05SIngo Weinhold 		queue[i]->flags = (queue[i]->flags | flagsToSet)
5790c85bd05SIngo Weinhold 			& ~(flagsToClear | RFLAG_VISITED);
5800c85bd05SIngo Weinhold 	}
5810c85bd05SIngo Weinhold }
5820c85bd05SIngo Weinhold 
5830c85bd05SIngo Weinhold 
5840c85bd05SIngo Weinhold static void
5850c85bd05SIngo Weinhold set_image_flags_recursively(image_t* image, uint32 flags)
5860c85bd05SIngo Weinhold {
5870c85bd05SIngo Weinhold 	update_image_flags_recursively(image, flags, 0);
5880c85bd05SIngo Weinhold }
5890c85bd05SIngo Weinhold 
5900c85bd05SIngo Weinhold 
5910c85bd05SIngo Weinhold static void
5920c85bd05SIngo Weinhold clear_image_flags_recursively(image_t* image, uint32 flags)
5930c85bd05SIngo Weinhold {
5940c85bd05SIngo Weinhold 	update_image_flags_recursively(image, 0, flags);
5950c85bd05SIngo Weinhold }
5960c85bd05SIngo Weinhold 
5970c85bd05SIngo Weinhold 
5980c0fea5dSIngo Weinhold static status_t
5990c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
6000c0fea5dSIngo Weinhold {
6010c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheader;
6020c0fea5dSIngo Weinhold 	int regcount;
6030c0fea5dSIngo Weinhold 	int i;
6040c0fea5dSIngo Weinhold 
6050c0fea5dSIngo Weinhold 	regcount = 0;
6060c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
6070c0fea5dSIngo Weinhold 		pheader = (struct Elf32_Phdr *)(buff + i * phentsize);
6080c0fea5dSIngo Weinhold 
6090c0fea5dSIngo Weinhold 		switch (pheader->p_type) {
6100c0fea5dSIngo Weinhold 			case PT_NULL:
6110c0fea5dSIngo Weinhold 				/* NOP header */
6120c0fea5dSIngo Weinhold 				break;
6130c0fea5dSIngo Weinhold 			case PT_LOAD:
6140c0fea5dSIngo Weinhold 				if (pheader->p_memsz == pheader->p_filesz) {
6150c0fea5dSIngo Weinhold 					/*
6160c0fea5dSIngo Weinhold 					 * everything in one area
6170c0fea5dSIngo Weinhold 					 */
6180c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
6190c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_memsz;
6200c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
6210c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz
6220c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
6230c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
6240c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
6250c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
6260c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
6270c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
6280c0fea5dSIngo Weinhold 						// this is a writable segment
6290c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
6300c0fea5dSIngo Weinhold 					}
6310c0fea5dSIngo Weinhold 				} else {
6320c0fea5dSIngo Weinhold 					/*
6330c0fea5dSIngo Weinhold 					 * may require splitting
6340c0fea5dSIngo Weinhold 					 */
6350c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz);
6360c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz);
6370c0fea5dSIngo Weinhold 
6380c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
6390c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_filesz;
6400c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
6410c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz
6420c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
6430c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
6440c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
6450c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
6460c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
6470c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
6480c0fea5dSIngo Weinhold 						// this is a writable segment
6490c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
6500c0fea5dSIngo Weinhold 					}
6510c0fea5dSIngo Weinhold 
6520c0fea5dSIngo Weinhold 					if (A != B) {
6530c0fea5dSIngo Weinhold 						/*
6540c0fea5dSIngo Weinhold 						 * yeah, it requires splitting
6550c0fea5dSIngo Weinhold 						 */
6560c0fea5dSIngo Weinhold 						regcount += 1;
6570c0fea5dSIngo Weinhold 						image->regions[regcount].start = pheader->p_vaddr;
6580c0fea5dSIngo Weinhold 						image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz;
6590c0fea5dSIngo Weinhold 						image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
6600c0fea5dSIngo Weinhold 						image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr))
6610c0fea5dSIngo Weinhold 							- image->regions[regcount-1].vmsize;
6620c0fea5dSIngo Weinhold 						image->regions[regcount].fdstart = 0;
6630c0fea5dSIngo Weinhold 						image->regions[regcount].fdsize = 0;
6640c0fea5dSIngo Weinhold 						image->regions[regcount].delta = 0;
6650c0fea5dSIngo Weinhold 						image->regions[regcount].flags = RFLAG_ANON;
6660c0fea5dSIngo Weinhold 						if (pheader->p_flags & PF_WRITE) {
6670c0fea5dSIngo Weinhold 							// this is a writable segment
6680c0fea5dSIngo Weinhold 							image->regions[regcount].flags |= RFLAG_RW;
6690c0fea5dSIngo Weinhold 						}
6700c0fea5dSIngo Weinhold 					}
6710c0fea5dSIngo Weinhold 				}
6720c0fea5dSIngo Weinhold 				regcount += 1;
6730c0fea5dSIngo Weinhold 				break;
6740c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
6750c0fea5dSIngo Weinhold 				image->dynamic_ptr = pheader->p_vaddr;
6760c0fea5dSIngo Weinhold 				break;
6770c0fea5dSIngo Weinhold 			case PT_INTERP:
6780c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
6790c0fea5dSIngo Weinhold 				break;
6800c0fea5dSIngo Weinhold 			case PT_NOTE:
6810c0fea5dSIngo Weinhold 				/* unsupported */
6820c0fea5dSIngo Weinhold 				break;
6830c0fea5dSIngo Weinhold 			case PT_SHLIB:
6840c0fea5dSIngo Weinhold 				/* undefined semantics */
6850c0fea5dSIngo Weinhold 				break;
6860c0fea5dSIngo Weinhold 			case PT_PHDR:
6870c0fea5dSIngo Weinhold 				/* we don't use it */
6880c0fea5dSIngo Weinhold 				break;
6892ecebae1SDavid McPaul 			case PT_STACK:
6902ecebae1SDavid McPaul 				/* we don't use it */
6912ecebae1SDavid McPaul 				break;
6920c0fea5dSIngo Weinhold 			default:
6932ecebae1SDavid McPaul 				FATAL("unhandled pheader type in parse 0x%lx\n", pheader->p_type);
6940c0fea5dSIngo Weinhold 				return B_BAD_DATA;
6950c0fea5dSIngo Weinhold 		}
6960c0fea5dSIngo Weinhold 	}
6970c0fea5dSIngo Weinhold 
6980c0fea5dSIngo Weinhold 	return B_OK;
6990c0fea5dSIngo Weinhold }
7000c0fea5dSIngo Weinhold 
7010c0fea5dSIngo Weinhold 
702*593ee7bbSIngo Weinhold static void
703*593ee7bbSIngo Weinhold analyze_image_haiku_version_and_abi(image_t* image)
704*593ee7bbSIngo Weinhold {
705*593ee7bbSIngo Weinhold 	// Haiku API version
706*593ee7bbSIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol(image,
707*593ee7bbSIngo Weinhold 		B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME, B_SYMBOL_TYPE_DATA);
708*593ee7bbSIngo Weinhold 	if (symbol != NULL && symbol->st_shndx != SHN_UNDEF
709*593ee7bbSIngo Weinhold 		&& symbol->st_value > 0
710*593ee7bbSIngo Weinhold 		&& ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT
711*593ee7bbSIngo Weinhold 		&& symbol->st_size >= sizeof(uint32)) {
712*593ee7bbSIngo Weinhold 		image->api_version
713*593ee7bbSIngo Weinhold 			= *(uint32*)(symbol->st_value + image->regions[0].delta);
714*593ee7bbSIngo Weinhold 	} else
715*593ee7bbSIngo Weinhold 		image->api_version = 0;
716*593ee7bbSIngo Weinhold 
717*593ee7bbSIngo Weinhold 	// Haiku ABI
718*593ee7bbSIngo Weinhold 	symbol = find_symbol(image, B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME,
719*593ee7bbSIngo Weinhold 		B_SYMBOL_TYPE_DATA);
720*593ee7bbSIngo Weinhold 	if (symbol != NULL && symbol->st_shndx != SHN_UNDEF
721*593ee7bbSIngo Weinhold 		&& symbol->st_value > 0
722*593ee7bbSIngo Weinhold 		&& ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT
723*593ee7bbSIngo Weinhold 		&& symbol->st_size >= sizeof(uint32)) {
724*593ee7bbSIngo Weinhold 		image->abi = *(uint32*)(symbol->st_value + image->regions[0].delta);
725*593ee7bbSIngo Weinhold 	} else
726*593ee7bbSIngo Weinhold 		image->abi = 0;
727*593ee7bbSIngo Weinhold }
728*593ee7bbSIngo Weinhold 
729*593ee7bbSIngo Weinhold 
7300c0fea5dSIngo Weinhold static bool
73134982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader,
73234982809SIngo Weinhold 	int32 sheaderSize, char* buffer, size_t bufferSize)
73334982809SIngo Weinhold {
73434982809SIngo Weinhold 	image->gcc_version.major = 0;
73534982809SIngo Weinhold 	image->gcc_version.middle = 0;
73634982809SIngo Weinhold 	image->gcc_version.minor = 0;
73734982809SIngo Weinhold 
73834982809SIngo Weinhold 	if (sheaderSize > (int)bufferSize) {
73934982809SIngo Weinhold 		FATAL("Cannot handle section headers bigger than %lu\n", bufferSize);
74034982809SIngo Weinhold 		return false;
74134982809SIngo Weinhold 	}
74234982809SIngo Weinhold 
74334982809SIngo Weinhold 	// read section headers
74434982809SIngo Weinhold 	ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize);
74534982809SIngo Weinhold 	if (length != sheaderSize) {
74634982809SIngo Weinhold 		FATAL("Could not read section headers: %s\n", strerror(length));
74734982809SIngo Weinhold 		return false;
74834982809SIngo Weinhold 	}
74934982809SIngo Weinhold 
75034982809SIngo Weinhold 	// load the string section
75134982809SIngo Weinhold 	Elf32_Shdr* sectionHeader
75234982809SIngo Weinhold 		= (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize);
75334982809SIngo Weinhold 
75434982809SIngo Weinhold 	if (sheaderSize + sectionHeader->sh_size > bufferSize) {
75534982809SIngo Weinhold 		FATAL("Buffer not big enough for section string section\n");
75634982809SIngo Weinhold 		return false;
75734982809SIngo Weinhold 	}
75834982809SIngo Weinhold 
75934982809SIngo Weinhold 	char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size;
76034982809SIngo Weinhold 	length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings,
76134982809SIngo Weinhold 		sectionHeader->sh_size);
76234982809SIngo Weinhold 	if (length != (int)sectionHeader->sh_size) {
76334982809SIngo Weinhold 		FATAL("Could not read section string section: %s\n", strerror(length));
76434982809SIngo Weinhold 		return false;
76534982809SIngo Weinhold 	}
76634982809SIngo Weinhold 
76734982809SIngo Weinhold 	// find the .comment section
76834982809SIngo Weinhold 	off_t commentOffset = 0;
76934982809SIngo Weinhold 	size_t commentSize = 0;
77034982809SIngo Weinhold 	for (uint32 i = 0; i < eheader.e_shnum; i++) {
77134982809SIngo Weinhold 		sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize);
77234982809SIngo Weinhold 		const char* sectionName = sectionStrings + sectionHeader->sh_name;
77334982809SIngo Weinhold 		if (sectionHeader->sh_name != 0
77434982809SIngo Weinhold 			&& strcmp(sectionName, ".comment") == 0) {
77534982809SIngo Weinhold 			commentOffset = sectionHeader->sh_offset;
77634982809SIngo Weinhold 			commentSize = sectionHeader->sh_size;
77734982809SIngo Weinhold 			break;
77834982809SIngo Weinhold 		}
77934982809SIngo Weinhold 	}
78034982809SIngo Weinhold 
78134982809SIngo Weinhold 	if (commentSize == 0) {
78234982809SIngo Weinhold 		FATAL("Could not find .comment section\n");
78334982809SIngo Weinhold 		return false;
78434982809SIngo Weinhold 	}
78534982809SIngo Weinhold 
78634982809SIngo Weinhold 	// read a part of the comment section
78734982809SIngo Weinhold 	if (commentSize > 512)
78834982809SIngo Weinhold 		commentSize = 512;
78934982809SIngo Weinhold 
79034982809SIngo Weinhold 	length = _kern_read(fd, commentOffset, buffer, commentSize);
79134982809SIngo Weinhold 	if (length != (int)commentSize) {
79234982809SIngo Weinhold 		FATAL("Could not read .comment section: %s\n", strerror(length));
79334982809SIngo Weinhold 		return false;
79434982809SIngo Weinhold 	}
79534982809SIngo Weinhold 
79634982809SIngo Weinhold 	// the common prefix of the strings in the .comment section
79734982809SIngo Weinhold 	static const char* kGCCVersionPrefix = "GCC: (GNU) ";
79834982809SIngo Weinhold 	size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix);
79934982809SIngo Weinhold 
80034982809SIngo Weinhold 	size_t index = 0;
80134982809SIngo Weinhold 	int gccMajor = 0;
80234982809SIngo Weinhold 	int gccMiddle = 0;
80334982809SIngo Weinhold 	int gccMinor = 0;
8042716cfd3SAxel Dörfler 	bool isHaiku = true;
80534982809SIngo Weinhold 
80634982809SIngo Weinhold 	// Read up to 10 comments. The first three or four are usually from the
80734982809SIngo Weinhold 	// glue code.
80834982809SIngo Weinhold 	for (int i = 0; i < 10; i++) {
80934982809SIngo Weinhold 		// skip '\0'
81034982809SIngo Weinhold 		while (index < commentSize && buffer[index] == '\0')
81134982809SIngo Weinhold 			index++;
81234982809SIngo Weinhold 		char* stringStart = buffer + index;
81334982809SIngo Weinhold 
81434982809SIngo Weinhold 		// find string end
81534982809SIngo Weinhold 		while (index < commentSize && buffer[index] != '\0')
81634982809SIngo Weinhold 			index++;
81734982809SIngo Weinhold 
81834982809SIngo Weinhold 		// ignore the entry at the end of the buffer
81934982809SIngo Weinhold 		if (index == commentSize)
82034982809SIngo Weinhold 			break;
82134982809SIngo Weinhold 
82234982809SIngo Weinhold 		// We have to analyze string like these:
82334982809SIngo Weinhold 		// GCC: (GNU) 2.9-beos-991026
82434982809SIngo Weinhold 		// GCC: (GNU) 2.95.3-haiku-080322
82534982809SIngo Weinhold 		// GCC: (GNU) 4.1.2
82634982809SIngo Weinhold 
82734982809SIngo Weinhold 		// skip the common prefix
82834982809SIngo Weinhold 		if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0)
82934982809SIngo Weinhold 			continue;
83034982809SIngo Weinhold 
83134982809SIngo Weinhold 		// the rest is the GCC version
83234982809SIngo Weinhold 		char* gccVersion = stringStart + gccVersionPrefixLen;
83334982809SIngo Weinhold 		char* gccPlatform = strchr(gccVersion, '-');
83434982809SIngo Weinhold 		char* patchLevel = NULL;
83534982809SIngo Weinhold 		if (gccPlatform != NULL) {
83634982809SIngo Weinhold 			*gccPlatform = '\0';
83734982809SIngo Weinhold 			gccPlatform++;
83834982809SIngo Weinhold 			patchLevel = strchr(gccPlatform, '-');
83934982809SIngo Weinhold 			if (patchLevel != NULL) {
84034982809SIngo Weinhold 				*patchLevel = '\0';
84134982809SIngo Weinhold 				patchLevel++;
84234982809SIngo Weinhold 			}
84334982809SIngo Weinhold 		}
84434982809SIngo Weinhold 
84534982809SIngo Weinhold 		// split the gcc version into major, middle, and minor
84634982809SIngo Weinhold 		int version[3] = { 0, 0, 0 };
84734982809SIngo Weinhold 
84834982809SIngo Weinhold 		for (int k = 0; gccVersion != NULL && k < 3; k++) {
84934982809SIngo Weinhold 			char* dot = strchr(gccVersion, '.');
85034982809SIngo Weinhold 			if (dot) {
85134982809SIngo Weinhold 				*dot = '\0';
85234982809SIngo Weinhold 				dot++;
85334982809SIngo Weinhold 			}
85434982809SIngo Weinhold 			version[k] = atoi(gccVersion);
85534982809SIngo Weinhold 			gccVersion = dot;
85634982809SIngo Weinhold 		}
85734982809SIngo Weinhold 
85834982809SIngo Weinhold 		// got any version?
85934982809SIngo Weinhold 		if (version[0] == 0)
86034982809SIngo Weinhold 			continue;
86134982809SIngo Weinhold 
86234982809SIngo Weinhold 		// Select the gcc version with the smallest major, but the greatest
86334982809SIngo Weinhold 		// middle/minor. This should usually ignore the glue code version as
86434982809SIngo Weinhold 		// well as cases where e.g. in a gcc 2 program a single C file has
86534982809SIngo Weinhold 		// been compiled with gcc 4.
86634982809SIngo Weinhold 		if (gccMajor == 0 || gccMajor > version[0]
867*593ee7bbSIngo Weinhold 		 	|| (gccMajor == version[0]
86834982809SIngo Weinhold 				&& (gccMiddle < version[1]
869*593ee7bbSIngo Weinhold 					|| (gccMiddle == version[1] && gccMinor < version[2])))) {
87034982809SIngo Weinhold 			gccMajor = version[0];
87134982809SIngo Weinhold 			gccMiddle = version[1];
87234982809SIngo Weinhold 			gccMinor = version[2];
87334982809SIngo Weinhold 		}
8742716cfd3SAxel Dörfler 
87585f9771aSFrançois Revol 		if (gccMajor == 2 && gccPlatform != NULL && strcmp(gccPlatform, "haiku"))
8762716cfd3SAxel Dörfler 			isHaiku = false;
87734982809SIngo Weinhold 	}
87834982809SIngo Weinhold 
87934982809SIngo Weinhold 	image->gcc_version.major = gccMajor;
88034982809SIngo Weinhold 	image->gcc_version.middle = gccMiddle;
88134982809SIngo Weinhold 	image->gcc_version.minor = gccMinor;
8822716cfd3SAxel Dörfler 	image->gcc_version.haiku = isHaiku;
88334982809SIngo Weinhold 
88434982809SIngo Weinhold 	return gccMajor != 0;
88534982809SIngo Weinhold }
88634982809SIngo Weinhold 
88734982809SIngo Weinhold 
88834982809SIngo Weinhold static bool
8890c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image)
8900c0fea5dSIngo Weinhold {
8910c0fea5dSIngo Weinhold 	uint32 i;
8920c0fea5dSIngo Weinhold 
8930c0fea5dSIngo Weinhold 	if (!image->dynamic_ptr)
8940c0fea5dSIngo Weinhold 		return true;
8950c0fea5dSIngo Weinhold 
8960c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
8970c0fea5dSIngo Weinhold 		if (image->dynamic_ptr >= image->regions[i].start
8980c0fea5dSIngo Weinhold 			&& image->dynamic_ptr < image->regions[i].start + image->regions[i].size)
8990c0fea5dSIngo Weinhold 			return true;
9000c0fea5dSIngo Weinhold 	}
9010c0fea5dSIngo Weinhold 
9020c0fea5dSIngo Weinhold 	return false;
9030c0fea5dSIngo Weinhold }
9040c0fea5dSIngo Weinhold 
9050c0fea5dSIngo Weinhold 
9060c0fea5dSIngo Weinhold /**	This function will change the protection of all read-only segments
9070c0fea5dSIngo Weinhold  *	to really be read-only.
9080c0fea5dSIngo Weinhold  *	The areas have to be read/write first, so that they can be relocated.
9090c0fea5dSIngo Weinhold  */
9100c0fea5dSIngo Weinhold 
9110c0fea5dSIngo Weinhold static void
9120c0fea5dSIngo Weinhold remap_images(void)
9130c0fea5dSIngo Weinhold {
9140c0fea5dSIngo Weinhold 	image_t *image;
9150c0fea5dSIngo Weinhold 	uint32 i;
9160c0fea5dSIngo Weinhold 
9170c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
9180c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_regions; i++) {
9190c0fea5dSIngo Weinhold 			if ((image->regions[i].flags & RFLAG_RW) == 0
9200c0fea5dSIngo Weinhold 				&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
9210c0fea5dSIngo Weinhold 				// we only need to do this once, so we remember those we've already mapped
9220c0fea5dSIngo Weinhold 				if (_kern_set_area_protection(image->regions[i].id,
9230c0fea5dSIngo Weinhold 						B_READ_AREA | B_EXECUTE_AREA) == B_OK)
9240c0fea5dSIngo Weinhold 					image->regions[i].flags |= RFLAG_REMAPPED;
9250c0fea5dSIngo Weinhold 			}
9260c0fea5dSIngo Weinhold 		}
9270c0fea5dSIngo Weinhold 	}
9280c0fea5dSIngo Weinhold }
9290c0fea5dSIngo Weinhold 
9300c0fea5dSIngo Weinhold 
9310c0fea5dSIngo Weinhold static status_t
9320c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed)
9330c0fea5dSIngo Weinhold {
9340c0fea5dSIngo Weinhold 	status_t status = B_OK;
9350c0fea5dSIngo Weinhold 	const char *baseName;
9360c0fea5dSIngo Weinhold 	uint32 i;
9370c0fea5dSIngo Weinhold 
9380c0fea5dSIngo Weinhold 	(void)(fd);
9390c0fea5dSIngo Weinhold 
9400c0fea5dSIngo Weinhold 	// cut the file name from the path as base name for the created areas
9410c0fea5dSIngo Weinhold 	baseName = strrchr(path, '/');
9420c0fea5dSIngo Weinhold 	if (baseName != NULL)
9430c0fea5dSIngo Weinhold 		baseName++;
9440c0fea5dSIngo Weinhold 	else
9450c0fea5dSIngo Weinhold 		baseName = path;
9460c0fea5dSIngo Weinhold 
9470c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
9480c0fea5dSIngo Weinhold 		char regionName[B_OS_NAME_LENGTH];
9490c0fea5dSIngo Weinhold 		addr_t loadAddress;
9500c0fea5dSIngo Weinhold 		uint32 addressSpecifier;
9510c0fea5dSIngo Weinhold 
9520c0fea5dSIngo Weinhold 		// for BeOS compatibility: if we load an old BeOS executable, we
9530c0fea5dSIngo Weinhold 		// have to relocate it, if possible - we recognize it because the
9540c0fea5dSIngo Weinhold 		// vmstart is set to 0 (hopefully always)
9550c0fea5dSIngo Weinhold 		if (fixed && image->regions[i].vmstart == 0)
9560c0fea5dSIngo Weinhold 			fixed = false;
9570c0fea5dSIngo Weinhold 
9580c0fea5dSIngo Weinhold 		snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
9590c0fea5dSIngo Weinhold 			baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
9600c0fea5dSIngo Weinhold 
9610c0fea5dSIngo Weinhold 		if (image->dynamic_ptr && !fixed) {
9620c0fea5dSIngo Weinhold 			// relocatable image... we can afford to place wherever
9630c0fea5dSIngo Weinhold 			if (i == 0) {
9640c0fea5dSIngo Weinhold 				// but only the first segment gets a free ride
9650c0fea5dSIngo Weinhold 				loadAddress = RLD_PROGRAM_BASE;
9660c0fea5dSIngo Weinhold 				addressSpecifier = B_BASE_ADDRESS;
9670c0fea5dSIngo Weinhold 			} else {
9680c0fea5dSIngo Weinhold 				loadAddress = image->regions[i].vmstart + image->regions[i-1].delta;
9690c0fea5dSIngo Weinhold 				addressSpecifier = B_EXACT_ADDRESS;
9700c0fea5dSIngo Weinhold 			}
9710c0fea5dSIngo Weinhold 		} else {
9720c0fea5dSIngo Weinhold 			// not relocatable, put it where it asks or die trying
9730c0fea5dSIngo Weinhold 			loadAddress = image->regions[i].vmstart;
9740c0fea5dSIngo Weinhold 			addressSpecifier = B_EXACT_ADDRESS;
9750c0fea5dSIngo Weinhold 		}
9760c0fea5dSIngo Weinhold 
9770c0fea5dSIngo Weinhold 		if (image->regions[i].flags & RFLAG_ANON) {
9780c0fea5dSIngo Weinhold 			image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress,
9790c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_NO_LOCK,
9800c0fea5dSIngo Weinhold 				B_READ_AREA | B_WRITE_AREA);
9810c0fea5dSIngo Weinhold 
9820c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
9830c0fea5dSIngo Weinhold 				status = image->regions[i].id;
9840c0fea5dSIngo Weinhold 				goto error;
9850c0fea5dSIngo Weinhold 			}
9860c0fea5dSIngo Weinhold 
9870c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
9880c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
9890c0fea5dSIngo Weinhold 		} else {
9903cf7ecd1SIngo Weinhold 			image->regions[i].id = _kern_map_file(regionName,
9913cf7ecd1SIngo Weinhold 				(void **)&loadAddress, addressSpecifier,
9923cf7ecd1SIngo Weinhold 				image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
9933cf7ecd1SIngo Weinhold 				REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart));
9940c0fea5dSIngo Weinhold 
9950c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
9960c0fea5dSIngo Weinhold 				status = image->regions[i].id;
9970c0fea5dSIngo Weinhold 				goto error;
9980c0fea5dSIngo Weinhold 			}
9990c0fea5dSIngo Weinhold 
10000c0fea5dSIngo Weinhold 			TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
10010c0fea5dSIngo Weinhold 				(void *)loadAddress, image->regions[i].vmsize,
10020c0fea5dSIngo Weinhold 				image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
10030c0fea5dSIngo Weinhold 
10040c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
10050c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
10060c0fea5dSIngo Weinhold 
10070c0fea5dSIngo Weinhold 			// handle trailer bits in data segment
10080c0fea5dSIngo Weinhold 			if (image->regions[i].flags & RFLAG_RW) {
10090c0fea5dSIngo Weinhold 				addr_t startClearing;
10100c0fea5dSIngo Weinhold 				addr_t toClear;
10110c0fea5dSIngo Weinhold 
10120c0fea5dSIngo Weinhold 				startClearing = image->regions[i].vmstart
10130c0fea5dSIngo Weinhold 					+ PAGE_OFFSET(image->regions[i].start)
10140c0fea5dSIngo Weinhold 					+ image->regions[i].size;
10150c0fea5dSIngo Weinhold 				toClear = image->regions[i].vmsize
10160c0fea5dSIngo Weinhold 					- PAGE_OFFSET(image->regions[i].start)
10170c0fea5dSIngo Weinhold 					- image->regions[i].size;
10180c0fea5dSIngo Weinhold 
10190c0fea5dSIngo Weinhold 				TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear));
10200c0fea5dSIngo Weinhold 				memset((void *)startClearing, 0, toClear);
10210c0fea5dSIngo Weinhold 			}
10220c0fea5dSIngo Weinhold 		}
10230c0fea5dSIngo Weinhold 	}
10240c0fea5dSIngo Weinhold 
10250c0fea5dSIngo Weinhold 	if (image->dynamic_ptr)
10260c0fea5dSIngo Weinhold 		image->dynamic_ptr += image->regions[0].delta;
10270c0fea5dSIngo Weinhold 
10280c0fea5dSIngo Weinhold 	return B_OK;
10290c0fea5dSIngo Weinhold 
10300c0fea5dSIngo Weinhold error:
10310c0fea5dSIngo Weinhold 	return status;
10320c0fea5dSIngo Weinhold }
10330c0fea5dSIngo Weinhold 
10340c0fea5dSIngo Weinhold 
10350c0fea5dSIngo Weinhold static void
10360c0fea5dSIngo Weinhold unmap_image(image_t *image)
10370c0fea5dSIngo Weinhold {
10380c0fea5dSIngo Weinhold 	uint32 i;
10390c0fea5dSIngo Weinhold 
10400c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
10410c0fea5dSIngo Weinhold 		_kern_delete_area(image->regions[i].id);
10420c0fea5dSIngo Weinhold 
10430c0fea5dSIngo Weinhold 		image->regions[i].id = -1;
10440c0fea5dSIngo Weinhold 	}
10450c0fea5dSIngo Weinhold }
10460c0fea5dSIngo Weinhold 
10470c0fea5dSIngo Weinhold 
10480c0fea5dSIngo Weinhold static bool
10490c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image)
10500c0fea5dSIngo Weinhold {
10510c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d;
10520c0fea5dSIngo Weinhold 	int i;
10530c0fea5dSIngo Weinhold 	int sonameOffset = -1;
10540c0fea5dSIngo Weinhold 
10550c0fea5dSIngo Weinhold 	image->symhash = 0;
10560c0fea5dSIngo Weinhold 	image->syms = 0;
10570c0fea5dSIngo Weinhold 	image->strtab = 0;
10580c0fea5dSIngo Weinhold 
10590c0fea5dSIngo Weinhold 	d = (struct Elf32_Dyn *)image->dynamic_ptr;
10600c0fea5dSIngo Weinhold 	if (!d)
10610c0fea5dSIngo Weinhold 		return true;
10620c0fea5dSIngo Weinhold 
10630c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
10640c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
10650c0fea5dSIngo Weinhold 			case DT_NEEDED:
10660c0fea5dSIngo Weinhold 				image->num_needed += 1;
10670c0fea5dSIngo Weinhold 				break;
10680c0fea5dSIngo Weinhold 			case DT_HASH:
10690c0fea5dSIngo Weinhold 				image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta);
10700c0fea5dSIngo Weinhold 				break;
10710c0fea5dSIngo Weinhold 			case DT_STRTAB:
10720c0fea5dSIngo Weinhold 				image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
10730c0fea5dSIngo Weinhold 				break;
10740c0fea5dSIngo Weinhold 			case DT_SYMTAB:
10750c0fea5dSIngo Weinhold 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
10760c0fea5dSIngo Weinhold 				break;
10770c0fea5dSIngo Weinhold 			case DT_REL:
10780c0fea5dSIngo Weinhold 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
10790c0fea5dSIngo Weinhold 				break;
10800c0fea5dSIngo Weinhold 			case DT_RELSZ:
10810c0fea5dSIngo Weinhold 				image->rel_len = d[i].d_un.d_val;
10820c0fea5dSIngo Weinhold 				break;
10830c0fea5dSIngo Weinhold 			case DT_RELA:
10840c0fea5dSIngo Weinhold 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
10850c0fea5dSIngo Weinhold 				break;
10860c0fea5dSIngo Weinhold 			case DT_RELASZ:
10870c0fea5dSIngo Weinhold 				image->rela_len = d[i].d_un.d_val;
10880c0fea5dSIngo Weinhold 				break;
10890c0fea5dSIngo Weinhold 			// TK: procedure linkage table
10900c0fea5dSIngo Weinhold 			case DT_JMPREL:
10910c0fea5dSIngo Weinhold 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
10920c0fea5dSIngo Weinhold 				break;
10930c0fea5dSIngo Weinhold 			case DT_PLTRELSZ:
10940c0fea5dSIngo Weinhold 				image->pltrel_len = d[i].d_un.d_val;
10950c0fea5dSIngo Weinhold 				break;
10960c0fea5dSIngo Weinhold 			case DT_INIT:
10970c0fea5dSIngo Weinhold 				image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
10980c0fea5dSIngo Weinhold 				break;
10990c0fea5dSIngo Weinhold 			case DT_FINI:
11000c0fea5dSIngo Weinhold 				image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
11010c0fea5dSIngo Weinhold 				break;
11020c0fea5dSIngo Weinhold 			case DT_SONAME:
11030c0fea5dSIngo Weinhold 				sonameOffset = d[i].d_un.d_val;
11040c0fea5dSIngo Weinhold 				break;
11050c0fea5dSIngo Weinhold 			default:
11060c0fea5dSIngo Weinhold 				continue;
11070c0fea5dSIngo Weinhold 		}
11080c0fea5dSIngo Weinhold 	}
11090c0fea5dSIngo Weinhold 
11100c0fea5dSIngo Weinhold 	// lets make sure we found all the required sections
11110c0fea5dSIngo Weinhold 	if (!image->symhash || !image->syms || !image->strtab)
11120c0fea5dSIngo Weinhold 		return false;
11130c0fea5dSIngo Weinhold 
11140c0fea5dSIngo Weinhold 	if (sonameOffset >= 0)
11150c0fea5dSIngo Weinhold 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
11160c0fea5dSIngo Weinhold 
11170c0fea5dSIngo Weinhold 	return true;
11180c0fea5dSIngo Weinhold }
11190c0fea5dSIngo Weinhold 
11200c0fea5dSIngo Weinhold 
112110b4b5d1SIngo Weinhold static void
112210b4b5d1SIngo Weinhold patch_defined_symbol(image_t* image, const char* name, void** symbol,
112310b4b5d1SIngo Weinhold 	int32* type)
112410b4b5d1SIngo Weinhold {
112510b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers;
112610b4b5d1SIngo Weinhold 	while (patcher != NULL && *symbol != 0) {
112710b4b5d1SIngo Weinhold 		image_t* inImage = image;
112810b4b5d1SIngo Weinhold 		patcher->patcher(patcher->cookie, NULL, image, name, &inImage,
112910b4b5d1SIngo Weinhold 			symbol, type);
113010b4b5d1SIngo Weinhold 		patcher = patcher->next;
113110b4b5d1SIngo Weinhold 	}
113210b4b5d1SIngo Weinhold }
113310b4b5d1SIngo Weinhold 
113410b4b5d1SIngo Weinhold 
113510b4b5d1SIngo Weinhold static void
113610b4b5d1SIngo Weinhold patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
113710b4b5d1SIngo Weinhold 	image_t** foundInImage, void** symbol, int32* type)
113810b4b5d1SIngo Weinhold {
113910b4b5d1SIngo Weinhold 	if (*foundInImage != NULL)
114010b4b5d1SIngo Weinhold 		patch_defined_symbol(*foundInImage, name, symbol, type);
114110b4b5d1SIngo Weinhold 
114210b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers;
114310b4b5d1SIngo Weinhold 	while (patcher != NULL) {
114410b4b5d1SIngo Weinhold 		patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage,
114510b4b5d1SIngo Weinhold 			symbol, type);
114610b4b5d1SIngo Weinhold 		patcher = patcher->next;
114710b4b5d1SIngo Weinhold 	}
114810b4b5d1SIngo Weinhold }
114910b4b5d1SIngo Weinhold 
115010b4b5d1SIngo Weinhold 
115110b4b5d1SIngo Weinhold status_t
115210b4b5d1SIngo Weinhold register_defined_symbol_patcher(struct image_t* image,
115310b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
115410b4b5d1SIngo Weinhold {
115510b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher
115610b4b5d1SIngo Weinhold 		= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
115710b4b5d1SIngo Weinhold 	if (patcher == NULL)
115810b4b5d1SIngo Weinhold 		return B_NO_MEMORY;
115910b4b5d1SIngo Weinhold 
116010b4b5d1SIngo Weinhold 	patcher->next = image->defined_symbol_patchers;
116110b4b5d1SIngo Weinhold 	image->defined_symbol_patchers = patcher;
116210b4b5d1SIngo Weinhold 
116310b4b5d1SIngo Weinhold 	return B_OK;
116410b4b5d1SIngo Weinhold }
116510b4b5d1SIngo Weinhold 
116610b4b5d1SIngo Weinhold 
116710b4b5d1SIngo Weinhold void
116810b4b5d1SIngo Weinhold unregister_defined_symbol_patcher(struct image_t* image,
116910b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
117010b4b5d1SIngo Weinhold {
117110b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher** patcher = &image->defined_symbol_patchers;
117210b4b5d1SIngo Weinhold 	while (*patcher != NULL) {
117310b4b5d1SIngo Weinhold 		if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
117410b4b5d1SIngo Weinhold 			RuntimeLoaderSymbolPatcher* toDelete = *patcher;
117510b4b5d1SIngo Weinhold 			*patcher = (*patcher)->next;
117610b4b5d1SIngo Weinhold 			delete toDelete;
117710b4b5d1SIngo Weinhold 			return;
117810b4b5d1SIngo Weinhold 		}
117910b4b5d1SIngo Weinhold 		patcher = &(*patcher)->next;
118010b4b5d1SIngo Weinhold 	}
118110b4b5d1SIngo Weinhold }
118210b4b5d1SIngo Weinhold 
118310b4b5d1SIngo Weinhold 
118410b4b5d1SIngo Weinhold status_t
118510b4b5d1SIngo Weinhold register_undefined_symbol_patcher(struct image_t* image,
118610b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
118710b4b5d1SIngo Weinhold {
118810b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher
118910b4b5d1SIngo Weinhold 		= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
119010b4b5d1SIngo Weinhold 	if (patcher == NULL)
119110b4b5d1SIngo Weinhold 		return B_NO_MEMORY;
119210b4b5d1SIngo Weinhold 
119310b4b5d1SIngo Weinhold 	patcher->next = image->undefined_symbol_patchers;
119410b4b5d1SIngo Weinhold 	image->undefined_symbol_patchers = patcher;
119510b4b5d1SIngo Weinhold 
119610b4b5d1SIngo Weinhold 	return B_OK;
119710b4b5d1SIngo Weinhold }
119810b4b5d1SIngo Weinhold 
119910b4b5d1SIngo Weinhold 
120010b4b5d1SIngo Weinhold void
120110b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher(struct image_t* image,
120210b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
120310b4b5d1SIngo Weinhold {
120410b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher** patcher = &image->undefined_symbol_patchers;
120510b4b5d1SIngo Weinhold 	while (*patcher != NULL) {
120610b4b5d1SIngo Weinhold 		if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
120710b4b5d1SIngo Weinhold 			RuntimeLoaderSymbolPatcher* toDelete = *patcher;
120810b4b5d1SIngo Weinhold 			*patcher = (*patcher)->next;
120910b4b5d1SIngo Weinhold 			delete toDelete;
121010b4b5d1SIngo Weinhold 			return;
121110b4b5d1SIngo Weinhold 		}
121210b4b5d1SIngo Weinhold 		patcher = &(*patcher)->next;
121310b4b5d1SIngo Weinhold 	}
121410b4b5d1SIngo Weinhold }
121510b4b5d1SIngo Weinhold 
121610b4b5d1SIngo Weinhold 
121710b4b5d1SIngo Weinhold runtime_loader_add_on_export gRuntimeLoaderAddOnExport = {
121810b4b5d1SIngo Weinhold 	register_defined_symbol_patcher,
121910b4b5d1SIngo Weinhold 	unregister_defined_symbol_patcher,
122010b4b5d1SIngo Weinhold 	register_undefined_symbol_patcher,
122110b4b5d1SIngo Weinhold 	unregister_undefined_symbol_patcher
122210b4b5d1SIngo Weinhold };
122310b4b5d1SIngo Weinhold 
122410b4b5d1SIngo Weinhold 
12250c0fea5dSIngo Weinhold static struct Elf32_Sym *
12260c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type)
12270c0fea5dSIngo Weinhold {
12280c0fea5dSIngo Weinhold 	uint32 hash, i;
12290c0fea5dSIngo Weinhold 
12300c0fea5dSIngo Weinhold 	// ToDo: "type" is currently ignored!
12310c0fea5dSIngo Weinhold 	(void)type;
12320c0fea5dSIngo Weinhold 
1233dd76bc97SIngo Weinhold 	if (image->dynamic_ptr == 0)
12340c0fea5dSIngo Weinhold 		return NULL;
12350c0fea5dSIngo Weinhold 
12360c0fea5dSIngo Weinhold 	hash = elf_hash((uint8 *)name) % HASHTABSIZE(image);
12370c0fea5dSIngo Weinhold 
12380c0fea5dSIngo Weinhold 	for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
12390c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = &image->syms[i];
12400c0fea5dSIngo Weinhold 
12410c0fea5dSIngo Weinhold 		if (symbol->st_shndx != SHN_UNDEF
12420c0fea5dSIngo Weinhold 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
12430c0fea5dSIngo Weinhold 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
12440c0fea5dSIngo Weinhold 			&& !strcmp(SYMNAME(image, symbol), name)) {
12450c0fea5dSIngo Weinhold 			// check if the type matches
12460c0fea5dSIngo Weinhold 			if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
12470c0fea5dSIngo Weinhold 				|| (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT))
12480c0fea5dSIngo Weinhold 				continue;
12490c0fea5dSIngo Weinhold 
12500c0fea5dSIngo Weinhold 			return symbol;
12510c0fea5dSIngo Weinhold 		}
12520c0fea5dSIngo Weinhold 	}
12530c0fea5dSIngo Weinhold 
12540c0fea5dSIngo Weinhold 	return NULL;
12550c0fea5dSIngo Weinhold }
12560c0fea5dSIngo Weinhold 
12570c0fea5dSIngo Weinhold 
125810b4b5d1SIngo Weinhold static status_t
125910b4b5d1SIngo Weinhold find_symbol(image_t* image, char const* symbolName, int32 symbolType,
126010b4b5d1SIngo Weinhold 	void **_location)
126110b4b5d1SIngo Weinhold {
126210b4b5d1SIngo Weinhold 	// get the symbol in the image
126310b4b5d1SIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol(image, symbolName, symbolType);
126410b4b5d1SIngo Weinhold 	if (symbol == NULL)
126510b4b5d1SIngo Weinhold 		return B_ENTRY_NOT_FOUND;
126610b4b5d1SIngo Weinhold 
126710b4b5d1SIngo Weinhold 	void* location = (void*)(symbol->st_value + image->regions[0].delta);
126810b4b5d1SIngo Weinhold 	patch_defined_symbol(image, symbolName, &location, &symbolType);
126910b4b5d1SIngo Weinhold 
127010b4b5d1SIngo Weinhold 	if (_location != NULL)
127110b4b5d1SIngo Weinhold 		*_location = location;
127210b4b5d1SIngo Weinhold 
127310b4b5d1SIngo Weinhold 	return B_OK;
127410b4b5d1SIngo Weinhold }
127510b4b5d1SIngo Weinhold 
127610b4b5d1SIngo Weinhold 
12770c85bd05SIngo Weinhold static status_t
12780c85bd05SIngo Weinhold find_symbol_breadth_first(image_t* image, const char* name, int32 type,
12790c85bd05SIngo Weinhold 	image_t** _foundInImage, void** _location)
12800c0fea5dSIngo Weinhold {
12810c85bd05SIngo Weinhold 	image_t* queue[sLoadedImageCount];
12820c85bd05SIngo Weinhold 	uint32 count = 0;
12830c85bd05SIngo Weinhold 	uint32 index = 0;
12840c85bd05SIngo Weinhold 	queue[count++] = image;
12850c85bd05SIngo Weinhold 	image->flags |= RFLAG_VISITED;
12860c85bd05SIngo Weinhold 
12870c85bd05SIngo Weinhold 	bool found = false;
12880c85bd05SIngo Weinhold 	while (index < count) {
12890c85bd05SIngo Weinhold 		// pop next image
12900c85bd05SIngo Weinhold 		image = queue[index++];
12910c85bd05SIngo Weinhold 
12920c85bd05SIngo Weinhold 		if (find_symbol(image, name, type, _location) == B_OK) {
12930c85bd05SIngo Weinhold 			found = true;
12940c85bd05SIngo Weinhold 			break;
12950c85bd05SIngo Weinhold 		}
12960c85bd05SIngo Weinhold 
12970c85bd05SIngo Weinhold 		// push needed images
12980c85bd05SIngo Weinhold 		for (uint32 i = 0; i < image->num_needed; i++) {
12990c85bd05SIngo Weinhold 			image_t* needed = image->needed[i];
13000c85bd05SIngo Weinhold 			if ((needed->flags & RFLAG_VISITED) == 0) {
13010c85bd05SIngo Weinhold 				queue[count++] = needed;
13020c85bd05SIngo Weinhold 				needed->flags |= RFLAG_VISITED;
130346f4d849SIngo Weinhold 			}
130446f4d849SIngo Weinhold 		}
13050c0fea5dSIngo Weinhold 	}
13060c0fea5dSIngo Weinhold 
13070c85bd05SIngo Weinhold 	// clear visited flags
13080c85bd05SIngo Weinhold 	for (uint32 i = 0; i < count; i++)
13090c85bd05SIngo Weinhold 		queue[i]->flags &= ~RFLAG_VISITED;
13100c85bd05SIngo Weinhold 
13110c85bd05SIngo Weinhold 	return found ? B_OK : B_ENTRY_NOT_FOUND;
13120c0fea5dSIngo Weinhold }
13130c0fea5dSIngo Weinhold 
13140c0fea5dSIngo Weinhold 
131546f4d849SIngo Weinhold static struct Elf32_Sym*
13160c85bd05SIngo Weinhold find_undefined_symbol_beos(image_t* rootImage, image_t* image, const char* name,
131746f4d849SIngo Weinhold 	image_t** foundInImage)
131846f4d849SIngo Weinhold {
131946f4d849SIngo Weinhold 	// BeOS style symbol resolution: It is sufficient to check the direct
132046f4d849SIngo Weinhold 	// dependencies. The linker would have complained, if the symbol wasn't
132146f4d849SIngo Weinhold 	// there.
132246f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
132346f4d849SIngo Weinhold 		if (image->needed[i]->dynamic_ptr) {
132446f4d849SIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(image->needed[i], name,
132546f4d849SIngo Weinhold 				B_SYMBOL_TYPE_ANY);
132646f4d849SIngo Weinhold 			if (symbol) {
132746f4d849SIngo Weinhold 				*foundInImage = image->needed[i];
132846f4d849SIngo Weinhold 				return symbol;
132946f4d849SIngo Weinhold 			}
133046f4d849SIngo Weinhold 		}
133146f4d849SIngo Weinhold 	}
133246f4d849SIngo Weinhold 
133346f4d849SIngo Weinhold 	return NULL;
133446f4d849SIngo Weinhold }
133546f4d849SIngo Weinhold 
133646f4d849SIngo Weinhold 
13370c85bd05SIngo Weinhold static struct Elf32_Sym*
13380c85bd05SIngo Weinhold find_undefined_symbol_global(image_t* rootImage, image_t* image,
13390c85bd05SIngo Weinhold 	const char* name, image_t** foundInImage)
13400c85bd05SIngo Weinhold {
13410c85bd05SIngo Weinhold 	// Global load order symbol resolution: All loaded images are searched for
13420c85bd05SIngo Weinhold 	// the symbol in the order they have been loaded. We skip add-on images and
13430c85bd05SIngo Weinhold 	// RTLD_LOCAL images though.
13440c85bd05SIngo Weinhold 	image_t* otherImage = sLoadedImages.head;
13450c85bd05SIngo Weinhold 	while (otherImage != NULL) {
13460c85bd05SIngo Weinhold 		if (otherImage == rootImage
1347*593ee7bbSIngo Weinhold 			|| (otherImage->type != B_ADD_ON_IMAGE
13480c85bd05SIngo Weinhold 				&& (otherImage->flags
1349*593ee7bbSIngo Weinhold 					& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) {
13500c85bd05SIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(otherImage, name,
13510c85bd05SIngo Weinhold 				B_SYMBOL_TYPE_ANY);
13520c85bd05SIngo Weinhold 			if (symbol) {
13530c85bd05SIngo Weinhold 				*foundInImage = otherImage;
13540c85bd05SIngo Weinhold 				return symbol;
13550c85bd05SIngo Weinhold 			}
13560c85bd05SIngo Weinhold 		}
13570c85bd05SIngo Weinhold 		otherImage = otherImage->next;
13580c85bd05SIngo Weinhold 	}
13590c85bd05SIngo Weinhold 
13600c85bd05SIngo Weinhold 	return NULL;
13610c85bd05SIngo Weinhold }
13620c85bd05SIngo Weinhold 
13630c85bd05SIngo Weinhold 
13640c85bd05SIngo Weinhold static struct Elf32_Sym*
13650c85bd05SIngo Weinhold find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
13660c85bd05SIngo Weinhold 	const char* name, image_t** foundInImage)
13670c85bd05SIngo Weinhold {
13680c85bd05SIngo Weinhold // TODO: How do we want to implement this one? Using global scope resolution
13690c85bd05SIngo Weinhold // might be undesired as it is now, since libraries could refer to symbols in
13700c85bd05SIngo Weinhold // the add-on, which would result in add-on symbols implicitely becoming used
13710c85bd05SIngo Weinhold // outside of the add-on. So the options would be to use the global scope but
13720c85bd05SIngo Weinhold // skip the add-on, or to do breadth-first resolution in the add-on dependency
13730c85bd05SIngo Weinhold // scope, also skipping the add-on itself. BeOS style resolution is safe, too,
13740c85bd05SIngo Weinhold // but we miss out features like undefined symbols and preloading.
13750c85bd05SIngo Weinhold 	return find_undefined_symbol_beos(rootImage, image, name, foundInImage);
13760c85bd05SIngo Weinhold }
13770c85bd05SIngo Weinhold 
13780c85bd05SIngo Weinhold 
137910b4b5d1SIngo Weinhold /*!	This function is called when we run BeOS images on Haiku.
13802716cfd3SAxel Dörfler 	It allows us to redirect functions to ensure compatibility.
13812716cfd3SAxel Dörfler */
13822716cfd3SAxel Dörfler static const char*
13832716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName)
13842716cfd3SAxel Dörfler {
13852716cfd3SAxel Dörfler 	struct symbol_mapping {
13862716cfd3SAxel Dörfler 		const char* from;
13872716cfd3SAxel Dörfler 		const char* to;
13882716cfd3SAxel Dörfler 	};
13892716cfd3SAxel Dörfler 	static const struct symbol_mapping kMappings[] = {
139010b4b5d1SIngo Weinhold 		// TODO: Improve this, and also use it for libnet.so compatibility!
139110b4b5d1SIngo Weinhold 		// Allow an image to provide a function that will be invoked for every
139210b4b5d1SIngo Weinhold 		// (transitively) depending image. The function can return a table to
139310b4b5d1SIngo Weinhold 		// remap symbols (probably better address to address). All the tables
139410b4b5d1SIngo Weinhold 		// for a single image would be combined into a hash table and an
139510b4b5d1SIngo Weinhold 		// undefined symbol patcher using this hash table would be added.
13962716cfd3SAxel Dörfler 		{"fstat", "__be_fstat"},
13972716cfd3SAxel Dörfler 		{"lstat", "__be_lstat"},
13982716cfd3SAxel Dörfler 		{"stat", "__be_stat"},
13992716cfd3SAxel Dörfler 	};
14002716cfd3SAxel Dörfler 	const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]);
14012716cfd3SAxel Dörfler 
14022716cfd3SAxel Dörfler 	for (uint32 i = 0; i < kMappingCount; i++) {
14032716cfd3SAxel Dörfler 		if (!strcmp(symbolName, kMappings[i].from))
14042716cfd3SAxel Dörfler 			return kMappings[i].to;
14052716cfd3SAxel Dörfler 	}
14062716cfd3SAxel Dörfler 
14072716cfd3SAxel Dörfler 	return symbolName;
14082716cfd3SAxel Dörfler }
14092716cfd3SAxel Dörfler 
14102716cfd3SAxel Dörfler 
14110c0fea5dSIngo Weinhold int
141246f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
14132716cfd3SAxel Dörfler 	addr_t *symAddress)
14140c0fea5dSIngo Weinhold {
14150c0fea5dSIngo Weinhold 	switch (sym->st_shndx) {
14160c0fea5dSIngo Weinhold 		case SHN_UNDEF:
14172716cfd3SAxel Dörfler 		{
14182716cfd3SAxel Dörfler 			struct Elf32_Sym *sharedSym;
14192716cfd3SAxel Dörfler 			image_t *sharedImage;
14202716cfd3SAxel Dörfler 			const char *symName;
14212716cfd3SAxel Dörfler 
14220c0fea5dSIngo Weinhold 			// patch the symbol name
14232716cfd3SAxel Dörfler 			symName = SYMNAME(image, sym);
14242716cfd3SAxel Dörfler 			if (!image->gcc_version.haiku) {
14252716cfd3SAxel Dörfler 				// The image has been compiled with a BeOS compiler. This means
14262716cfd3SAxel Dörfler 				// we'll have to redirect some functions for compatibility.
14272716cfd3SAxel Dörfler 				symName = beos_compatibility_map_symbol(symName);
14282716cfd3SAxel Dörfler 			}
14290c0fea5dSIngo Weinhold 
143010b4b5d1SIngo Weinhold 			int32 type = B_SYMBOL_TYPE_ANY;
143110b4b5d1SIngo Weinhold 			if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC)
143210b4b5d1SIngo Weinhold 				type = B_SYMBOL_TYPE_TEXT;
143310b4b5d1SIngo Weinhold 			else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT)
143410b4b5d1SIngo Weinhold 				type = B_SYMBOL_TYPE_DATA;
143510b4b5d1SIngo Weinhold 
143646f4d849SIngo Weinhold 			// it's undefined, must be outside this image, try the other images
14370c85bd05SIngo Weinhold 			sharedSym = rootImage->find_undefined_symbol(rootImage, image,
14380c85bd05SIngo Weinhold 				symName, &sharedImage);
143910b4b5d1SIngo Weinhold 			void* location = NULL;
14400c0fea5dSIngo Weinhold 
144110b4b5d1SIngo Weinhold 			enum {
144210b4b5d1SIngo Weinhold 				ERROR_NO_SYMBOL,
144310b4b5d1SIngo Weinhold 				ERROR_WRONG_TYPE,
144410b4b5d1SIngo Weinhold 				ERROR_NOT_EXPORTED,
144510b4b5d1SIngo Weinhold 				ERROR_UNPATCHED
144610b4b5d1SIngo Weinhold 			};
144710b4b5d1SIngo Weinhold 			uint32 lookupError = ERROR_UNPATCHED;
144810b4b5d1SIngo Weinhold 
144910b4b5d1SIngo Weinhold 			if (sharedSym == NULL) {
145010b4b5d1SIngo Weinhold 				// symbol not found at all
145110b4b5d1SIngo Weinhold 				lookupError = ERROR_NO_SYMBOL;
145210b4b5d1SIngo Weinhold 				sharedImage = NULL;
145310b4b5d1SIngo Weinhold 			} else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
14542716cfd3SAxel Dörfler 				&& ELF32_ST_TYPE(sym->st_info)
14552716cfd3SAxel Dörfler 					!= ELF32_ST_TYPE(sharedSym->st_info)) {
145610b4b5d1SIngo Weinhold 				// symbol not of the requested type
145710b4b5d1SIngo Weinhold 				lookupError = ERROR_WRONG_TYPE;
145810b4b5d1SIngo Weinhold 				sharedImage = NULL;
145910b4b5d1SIngo Weinhold 			} else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL
14602716cfd3SAxel Dörfler 				&& ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) {
146110b4b5d1SIngo Weinhold 				// symbol not exported
146210b4b5d1SIngo Weinhold 				lookupError = ERROR_NOT_EXPORTED;
146310b4b5d1SIngo Weinhold 				sharedImage = NULL;
146410b4b5d1SIngo Weinhold 			} else {
146510b4b5d1SIngo Weinhold 				// symbol is fine, get its location
146610b4b5d1SIngo Weinhold 				location = (void*)(sharedSym->st_value
146710b4b5d1SIngo Weinhold 					+ sharedImage->regions[0].delta);
146810b4b5d1SIngo Weinhold 			}
146910b4b5d1SIngo Weinhold 
147010b4b5d1SIngo Weinhold 			patch_undefined_symbol(rootImage, image, symName, &sharedImage,
147110b4b5d1SIngo Weinhold 				&location, &type);
147210b4b5d1SIngo Weinhold 
147310b4b5d1SIngo Weinhold 			if (location == NULL) {
147410b4b5d1SIngo Weinhold 				switch (lookupError) {
147510b4b5d1SIngo Weinhold 					case ERROR_NO_SYMBOL:
147610b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: could not resolve symbol "
147710b4b5d1SIngo Weinhold 							"'%s'\n", symName);
147810b4b5d1SIngo Weinhold 						break;
147910b4b5d1SIngo Weinhold 					case ERROR_WRONG_TYPE:
148010b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s' in shared "
148110b4b5d1SIngo Weinhold 							"image but wrong type\n", symName);
148210b4b5d1SIngo Weinhold 						break;
148310b4b5d1SIngo Weinhold 					case ERROR_NOT_EXPORTED:
148410b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s', but not "
14852716cfd3SAxel Dörfler 							"exported\n", symName);
148610b4b5d1SIngo Weinhold 						break;
148710b4b5d1SIngo Weinhold 					case ERROR_UNPATCHED:
148810b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s', but was "
148910b4b5d1SIngo Weinhold 							"hidden by symbol patchers\n", symName);
149010b4b5d1SIngo Weinhold 						break;
149110b4b5d1SIngo Weinhold 				}
1492e94d1badSMichael Lotz 
1493e94d1badSMichael Lotz 				if (report_errors())
1494e94d1badSMichael Lotz 					sErrorMessage.AddString("missing symbol", symName);
1495e94d1badSMichael Lotz 
14960c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
14970c0fea5dSIngo Weinhold 			}
14980c0fea5dSIngo Weinhold 
149910b4b5d1SIngo Weinhold 			*symAddress = (addr_t)location;
150010b4b5d1SIngo Weinhold 			return B_OK;
15012716cfd3SAxel Dörfler 		}
15020c0fea5dSIngo Weinhold 
15030c0fea5dSIngo Weinhold 		case SHN_ABS:
15042716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
15050c0fea5dSIngo Weinhold 			return B_NO_ERROR;
15060c0fea5dSIngo Weinhold 
15070c0fea5dSIngo Weinhold 		case SHN_COMMON:
15080c0fea5dSIngo Weinhold 			// ToDo: finish this
15092a33a944SIngo Weinhold 			FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n");
15100c0fea5dSIngo Weinhold 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
15110c0fea5dSIngo Weinhold 
15120c0fea5dSIngo Weinhold 		default:
15130c0fea5dSIngo Weinhold 			// standard symbol
15142716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
15150c0fea5dSIngo Weinhold 			return B_NO_ERROR;
15160c0fea5dSIngo Weinhold 	}
15170c0fea5dSIngo Weinhold }
15180c0fea5dSIngo Weinhold 
15190c0fea5dSIngo Weinhold 
15200c0fea5dSIngo Weinhold static void
152110b4b5d1SIngo Weinhold image_event(image_t* image, uint32 event)
152210b4b5d1SIngo Weinhold {
152310b4b5d1SIngo Weinhold 	AddOnList::Iterator it = sAddOns.GetIterator();
152410b4b5d1SIngo Weinhold 	while (RuntimeLoaderAddOn* addOn = it.Next()) {
152510b4b5d1SIngo Weinhold 		void (*function)(image_t* image) = NULL;
152610b4b5d1SIngo Weinhold 
152710b4b5d1SIngo Weinhold 		switch (event) {
152810b4b5d1SIngo Weinhold 			case IMAGE_EVENT_LOADED:
152910b4b5d1SIngo Weinhold 				function = addOn->addOn->image_loaded;
153010b4b5d1SIngo Weinhold 				break;
153110b4b5d1SIngo Weinhold 			case IMAGE_EVENT_RELOCATED:
153210b4b5d1SIngo Weinhold 				function = addOn->addOn->image_relocated;
153310b4b5d1SIngo Weinhold 				break;
153410b4b5d1SIngo Weinhold 			case IMAGE_EVENT_INITIALIZED:
153510b4b5d1SIngo Weinhold 				function = addOn->addOn->image_initialized;
153610b4b5d1SIngo Weinhold 				break;
153710b4b5d1SIngo Weinhold 			case IMAGE_EVENT_UNINITIALIZING:
153810b4b5d1SIngo Weinhold 				function = addOn->addOn->image_uninitializing;
153910b4b5d1SIngo Weinhold 				break;
154010b4b5d1SIngo Weinhold 			case IMAGE_EVENT_UNLOADING:
154110b4b5d1SIngo Weinhold 				function = addOn->addOn->image_unloading;
154210b4b5d1SIngo Weinhold 				break;
154310b4b5d1SIngo Weinhold 		}
154410b4b5d1SIngo Weinhold 
154510b4b5d1SIngo Weinhold 		if (function != NULL)
154610b4b5d1SIngo Weinhold 			function(image);
154710b4b5d1SIngo Weinhold 	}
154810b4b5d1SIngo Weinhold }
154910b4b5d1SIngo Weinhold 
155010b4b5d1SIngo Weinhold 
155110b4b5d1SIngo Weinhold static void
15520c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path)
15530c0fea5dSIngo Weinhold {
15540c0fea5dSIngo Weinhold 	struct stat stat;
15550c0fea5dSIngo Weinhold 	image_info info;
15560c0fea5dSIngo Weinhold 
15570c0fea5dSIngo Weinhold 	// ToDo: set these correctly
15580c0fea5dSIngo Weinhold 	info.id = 0;
15590c0fea5dSIngo Weinhold 	info.type = image->type;
15600c0fea5dSIngo Weinhold 	info.sequence = 0;
15610c0fea5dSIngo Weinhold 	info.init_order = 0;
15620c0fea5dSIngo Weinhold 	info.init_routine = (void (*)())image->init_routine;
15630c0fea5dSIngo Weinhold 	info.term_routine = (void (*)())image->term_routine;
15640c0fea5dSIngo Weinhold 
15650c0fea5dSIngo Weinhold 	if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
15660c0fea5dSIngo Weinhold 		info.device = stat.st_dev;
15670c0fea5dSIngo Weinhold 		info.node = stat.st_ino;
15680c0fea5dSIngo Weinhold 	} else {
15690c0fea5dSIngo Weinhold 		info.device = -1;
15700c0fea5dSIngo Weinhold 		info.node = -1;
15710c0fea5dSIngo Weinhold 	}
15720c0fea5dSIngo Weinhold 
15730c0fea5dSIngo Weinhold 	strlcpy(info.name, path, sizeof(info.name));
15740c0fea5dSIngo Weinhold 	info.text = (void *)image->regions[0].vmstart;
15750c0fea5dSIngo Weinhold 	info.text_size = image->regions[0].vmsize;
15760c0fea5dSIngo Weinhold 	info.data = (void *)image->regions[1].vmstart;
15770c0fea5dSIngo Weinhold 	info.data_size = image->regions[1].vmsize;
1578*593ee7bbSIngo Weinhold 	info.api_version = image->api_version;
1579*593ee7bbSIngo Weinhold 	info.abi = image->abi;
15800c0fea5dSIngo Weinhold 	image->id = _kern_register_image(&info, sizeof(image_info));
15810c0fea5dSIngo Weinhold }
15820c0fea5dSIngo Weinhold 
15830c0fea5dSIngo Weinhold 
15840c0fea5dSIngo Weinhold static status_t
158546f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
15860c0fea5dSIngo Weinhold {
158746f4d849SIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image);
15880c0fea5dSIngo Weinhold 	if (status < B_OK) {
1589320bd2bdSAxel Dörfler 		FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status,
1590320bd2bdSAxel Dörfler 			image->path, image->name);
15910c0fea5dSIngo Weinhold 		return status;
15920c0fea5dSIngo Weinhold 	}
15930c0fea5dSIngo Weinhold 
15940c0fea5dSIngo Weinhold 	_kern_image_relocated(image->id);
159510b4b5d1SIngo Weinhold 	image_event(image, IMAGE_EVENT_RELOCATED);
15960c0fea5dSIngo Weinhold 	return B_OK;
15970c0fea5dSIngo Weinhold }
15980c0fea5dSIngo Weinhold 
15990c0fea5dSIngo Weinhold 
16000c0fea5dSIngo Weinhold static status_t
16010c85bd05SIngo Weinhold load_container(char const *name, image_type type, const char *rpath,
16020c85bd05SIngo Weinhold 	image_t **_image)
16030c0fea5dSIngo Weinhold {
16040c0fea5dSIngo Weinhold 	int32 pheaderSize, sheaderSize;
16050c0fea5dSIngo Weinhold 	char path[PATH_MAX];
16060c0fea5dSIngo Weinhold 	ssize_t length;
16070c0fea5dSIngo Weinhold 	char ph_buff[4096];
16080c0fea5dSIngo Weinhold 	int32 numRegions;
16090c0fea5dSIngo Weinhold 	image_t *found;
16100c0fea5dSIngo Weinhold 	image_t *image;
16110c0fea5dSIngo Weinhold 	status_t status;
16120c0fea5dSIngo Weinhold 	int fd;
16130c0fea5dSIngo Weinhold 
16140c0fea5dSIngo Weinhold 	struct Elf32_Ehdr eheader;
16150c0fea5dSIngo Weinhold 
16160c0fea5dSIngo Weinhold 	// Have we already loaded that image? Don't check for add-ons -- we always
16170c0fea5dSIngo Weinhold 	// reload them.
16180c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
16190c0fea5dSIngo Weinhold 		found = find_image(name, APP_OR_LIBRARY_TYPE);
162002e577f9SIngo Weinhold 
162102e577f9SIngo Weinhold 		if (found == NULL && type != B_APP_IMAGE) {
162202e577f9SIngo Weinhold 			// Special case for add-ons that link against the application
162302e577f9SIngo Weinhold 			// executable, with the executable not having a soname set.
162402e577f9SIngo Weinhold 			if (const char* lastSlash = strrchr(name, '/')) {
162502e577f9SIngo Weinhold 				image_t* programImage = get_program_image();
162602e577f9SIngo Weinhold 				if (strcmp(programImage->name, lastSlash + 1) == 0)
162702e577f9SIngo Weinhold 					found = programImage;
162802e577f9SIngo Weinhold 			}
162902e577f9SIngo Weinhold 		}
163002e577f9SIngo Weinhold 
16310c0fea5dSIngo Weinhold 		if (found) {
16320c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
16330c0fea5dSIngo Weinhold 			*_image = found;
16347486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") "
16357486b72dSIngo Weinhold 				"already loaded", name, type, rpath);
16360c0fea5dSIngo Weinhold 			return B_OK;
16370c0fea5dSIngo Weinhold 		}
16380c0fea5dSIngo Weinhold 	}
16390c0fea5dSIngo Weinhold 
16407486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type,
16417486b72dSIngo Weinhold 		rpath);
16427486b72dSIngo Weinhold 
16430c0fea5dSIngo Weinhold 	strlcpy(path, name, sizeof(path));
16440c0fea5dSIngo Weinhold 
164561b37794SIngo Weinhold 	// find and open the file
164661b37794SIngo Weinhold 	fd = open_executable(path, type, rpath, get_program_path(),
164761b37794SIngo Weinhold 		sSearchPathSubDir);
16480c0fea5dSIngo Weinhold 	if (fd < 0) {
164902e577f9SIngo Weinhold 		FATAL("cannot open file %s\n", name);
16507486b72dSIngo Weinhold 		KTRACE("rld: load_container(\"%s\"): failed to open file", name);
16510c0fea5dSIngo Weinhold 		return fd;
16520c0fea5dSIngo Weinhold 	}
16530c0fea5dSIngo Weinhold 
16546918dbf4SIngo Weinhold 	// normalize the image path
16556918dbf4SIngo Weinhold 	status = _kern_normalize_path(path, true, path);
16566918dbf4SIngo Weinhold 	if (status != B_OK)
16570c0fea5dSIngo Weinhold 		goto err1;
16580c0fea5dSIngo Weinhold 
16590c0fea5dSIngo Weinhold 	// Test again if this image has been registered already - this time,
16600c0fea5dSIngo Weinhold 	// we can check the full path, not just its name as noted.
16610c0fea5dSIngo Weinhold 	// You could end up loading an image twice with symbolic links, else.
16620c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
16630c0fea5dSIngo Weinhold 		found = find_image(path, APP_OR_LIBRARY_TYPE);
16640c0fea5dSIngo Weinhold 		if (found) {
16650c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
16660c0fea5dSIngo Weinhold 			*_image = found;
1667b2568a30SIngo Weinhold 			_kern_close(fd);
16687486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\"): already loaded after all",
16697486b72dSIngo Weinhold 				name);
16700c0fea5dSIngo Weinhold 			return B_OK;
16710c0fea5dSIngo Weinhold 		}
16720c0fea5dSIngo Weinhold 	}
16730c0fea5dSIngo Weinhold 
16740c0fea5dSIngo Weinhold 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
16750c0fea5dSIngo Weinhold 	if (length != sizeof(eheader)) {
16760c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
16770c0fea5dSIngo Weinhold 		FATAL("troubles reading ELF header\n");
16780c0fea5dSIngo Weinhold 		goto err1;
16790c0fea5dSIngo Weinhold 	}
16800c0fea5dSIngo Weinhold 
16810c0fea5dSIngo Weinhold 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
16820c0fea5dSIngo Weinhold 	if (status < B_OK) {
16830c0fea5dSIngo Weinhold 		FATAL("incorrect ELF header\n");
16840c0fea5dSIngo Weinhold 		goto err1;
16850c0fea5dSIngo Weinhold 	}
16860c0fea5dSIngo Weinhold 
16870c0fea5dSIngo Weinhold 	// ToDo: what to do about this restriction??
16880c0fea5dSIngo Weinhold 	if (pheaderSize > (int)sizeof(ph_buff)) {
16890c0fea5dSIngo Weinhold 		FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff));
16900c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
16910c0fea5dSIngo Weinhold 		goto err1;
16920c0fea5dSIngo Weinhold 	}
16930c0fea5dSIngo Weinhold 
16940c0fea5dSIngo Weinhold 	length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize);
16950c0fea5dSIngo Weinhold 	if (length != pheaderSize) {
16960c0fea5dSIngo Weinhold 		FATAL("Could not read program headers: %s\n", strerror(length));
16970c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
16980c0fea5dSIngo Weinhold 		goto err1;
16990c0fea5dSIngo Weinhold 	}
17000c0fea5dSIngo Weinhold 
17010c0fea5dSIngo Weinhold 	numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
17020c0fea5dSIngo Weinhold 	if (numRegions <= 0) {
17030c0fea5dSIngo Weinhold 		FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
17040c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
17050c0fea5dSIngo Weinhold 		goto err1;
17060c0fea5dSIngo Weinhold 	}
17070c0fea5dSIngo Weinhold 
17080c0fea5dSIngo Weinhold 	image = create_image(name, path, numRegions);
17090c0fea5dSIngo Weinhold 	if (image == NULL) {
17100c0fea5dSIngo Weinhold 		FATAL("Failed to allocate image_t object\n");
17110c0fea5dSIngo Weinhold 		status = B_NO_MEMORY;
17120c0fea5dSIngo Weinhold 		goto err1;
17130c0fea5dSIngo Weinhold 	}
17140c0fea5dSIngo Weinhold 
17150c0fea5dSIngo Weinhold 	status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
17160c0fea5dSIngo Weinhold 	if (status < B_OK)
17170c0fea5dSIngo Weinhold 		goto err2;
17180c0fea5dSIngo Weinhold 
17190c0fea5dSIngo Weinhold 	if (!assert_dynamic_loadable(image)) {
17200c0fea5dSIngo Weinhold 		FATAL("Dynamic segment must be loadable (implementation restriction)\n");
17210c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
17220c0fea5dSIngo Weinhold 		goto err2;
17230c0fea5dSIngo Weinhold 	}
17240c0fea5dSIngo Weinhold 
1725*593ee7bbSIngo Weinhold 	status = map_image(fd, path, image, type == B_APP_IMAGE);
1726*593ee7bbSIngo Weinhold 	if (status < B_OK) {
1727*593ee7bbSIngo Weinhold 		FATAL("Could not map image: %s\n", strerror(status));
1728*593ee7bbSIngo Weinhold 		status = B_ERROR;
1729*593ee7bbSIngo Weinhold 		goto err2;
1730*593ee7bbSIngo Weinhold 	}
1731*593ee7bbSIngo Weinhold 
1732*593ee7bbSIngo Weinhold 	if (!parse_dynamic_segment(image)) {
1733*593ee7bbSIngo Weinhold 		FATAL("Troubles handling dynamic section\n");
1734*593ee7bbSIngo Weinhold 		status = B_BAD_DATA;
1735*593ee7bbSIngo Weinhold 		goto err3;
1736*593ee7bbSIngo Weinhold 	}
1737*593ee7bbSIngo Weinhold 
1738*593ee7bbSIngo Weinhold 	if (eheader.e_entry != 0)
1739*593ee7bbSIngo Weinhold 		image->entry_point = eheader.e_entry + image->regions[0].delta;
1740*593ee7bbSIngo Weinhold 
1741*593ee7bbSIngo Weinhold 	analyze_image_haiku_version_and_abi(image);
1742*593ee7bbSIngo Weinhold 
174361b37794SIngo Weinhold 	if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff,
174434982809SIngo Weinhold 			sizeof(ph_buff))) {
174561b37794SIngo Weinhold 		// If this is the executable image, we init the search path
174661b37794SIngo Weinhold 		// subdir, if the compiler version doesn't match ours.
174761b37794SIngo Weinhold 		if (type == B_APP_IMAGE) {
174861b37794SIngo Weinhold 			#if __GNUC__ == 2
174961b37794SIngo Weinhold 				if (image->gcc_version.major > 2)
175061b37794SIngo Weinhold 					sSearchPathSubDir = "gcc4";
175161b37794SIngo Weinhold 			#elif __GNUC__ == 4
175261b37794SIngo Weinhold 				if (image->gcc_version.major == 2)
175361b37794SIngo Weinhold 					sSearchPathSubDir = "gcc2";
175461b37794SIngo Weinhold 			#endif
175561b37794SIngo Weinhold 		}
175661b37794SIngo Weinhold 	} else {
175734982809SIngo Weinhold 		FATAL("Failed to get gcc version for %s\n", path);
175834982809SIngo Weinhold 		// not really fatal, actually
175934982809SIngo Weinhold 	}
176034982809SIngo Weinhold 
17615fd6637bSIngo Weinhold 	// init gcc version dependent image flags
17625fd6637bSIngo Weinhold 	// symbol resolution strategy (fallback is R5-style, if version is
17635fd6637bSIngo Weinhold 	// unavailable)
17645fd6637bSIngo Weinhold 	if (image->gcc_version.major == 0
1765*593ee7bbSIngo Weinhold 		|| (image->gcc_version.major == 2 && image->gcc_version.middle < 95)) {
17660c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_beos;
17675fd6637bSIngo Weinhold 	}
17685fd6637bSIngo Weinhold 
17690c0fea5dSIngo Weinhold 	image->type = type;
17700c0fea5dSIngo Weinhold 	register_image(image, fd, path);
177110b4b5d1SIngo Weinhold 	image_event(image, IMAGE_EVENT_LOADED);
17720c0fea5dSIngo Weinhold 
17730c0fea5dSIngo Weinhold 	_kern_close(fd);
17740c0fea5dSIngo Weinhold 
17750c0fea5dSIngo Weinhold 	enqueue_image(&sLoadedImages, image);
17760c0fea5dSIngo Weinhold 	sLoadedImageCount++;
17770c0fea5dSIngo Weinhold 
17780c0fea5dSIngo Weinhold 	*_image = image;
17797486b72dSIngo Weinhold 
178034982809SIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): done: id: %ld (gcc: %d.%d.%d)", name,
178134982809SIngo Weinhold 		image->id, image->gcc_version.major, image->gcc_version.middle,
178234982809SIngo Weinhold 		image->gcc_version.minor);
17837486b72dSIngo Weinhold 
17840c0fea5dSIngo Weinhold 	return B_OK;
17850c0fea5dSIngo Weinhold 
17860c0fea5dSIngo Weinhold err3:
17870c0fea5dSIngo Weinhold 	unmap_image(image);
17880c0fea5dSIngo Weinhold err2:
17890c0fea5dSIngo Weinhold 	delete_image_struct(image);
17900c0fea5dSIngo Weinhold err1:
17910c0fea5dSIngo Weinhold 	_kern_close(fd);
17927486b72dSIngo Weinhold 
17937486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): failed: %s", name,
17947486b72dSIngo Weinhold 		strerror(status));
17957486b72dSIngo Weinhold 
17960c0fea5dSIngo Weinhold 	return status;
17970c0fea5dSIngo Weinhold }
17980c0fea5dSIngo Weinhold 
17990c0fea5dSIngo Weinhold 
18000c0fea5dSIngo Weinhold static const char *
18010c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
18020c0fea5dSIngo Weinhold {
18030c0fea5dSIngo Weinhold 	int i;
18040c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
18050c0fea5dSIngo Weinhold 
18060c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
18070c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
18080c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
18090c0fea5dSIngo Weinhold 	}
18100c0fea5dSIngo Weinhold 
18110c0fea5dSIngo Weinhold 	return NULL;
18120c0fea5dSIngo Weinhold }
18130c0fea5dSIngo Weinhold 
18140c0fea5dSIngo Weinhold 
18150c0fea5dSIngo Weinhold static status_t
18160c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image)
18170c0fea5dSIngo Weinhold {
18180c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
18194bef3723SAxel Dörfler 	bool reportErrors = report_errors();
182074c0424aSAxel Dörfler 	status_t status = B_OK;
18210c0fea5dSIngo Weinhold 	uint32 i, j;
18220c0fea5dSIngo Weinhold 	const char *rpath;
18230c0fea5dSIngo Weinhold 
18240c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
18250c0fea5dSIngo Weinhold 		return B_OK;
18260c0fea5dSIngo Weinhold 
18270c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
18280c0fea5dSIngo Weinhold 
18290c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
18300c0fea5dSIngo Weinhold 		return B_OK;
18310c0fea5dSIngo Weinhold 
18327486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
18337486b72dSIngo Weinhold 		image->id);
18347486b72dSIngo Weinhold 
18350c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
18360c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
18370c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
18387486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
18397486b72dSIngo Weinhold 			image->name, image->id);
18400c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
18410c0fea5dSIngo Weinhold 	}
18420c0fea5dSIngo Weinhold 
18430c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
18440c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
18450c0fea5dSIngo Weinhold 
18460c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
18470c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
18480c0fea5dSIngo Weinhold 			case DT_NEEDED:
184974c0424aSAxel Dörfler 			{
185074c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
185174c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
18520c0fea5dSIngo Weinhold 
185374c0424aSAxel Dörfler 				status_t loadStatus = load_container(name, B_LIBRARY_IMAGE,
185474c0424aSAxel Dörfler 					rpath, &image->needed[j]);
185574c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
185674c0424aSAxel Dörfler 					status = loadStatus;
185774c0424aSAxel Dörfler 					// correct error code in case the file could not been found
185874c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
185974c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
186074c0424aSAxel Dörfler 
186174c0424aSAxel Dörfler 						if (reportErrors)
186274c0424aSAxel Dörfler 							sErrorMessage.AddString("missing library", name);
186374c0424aSAxel Dörfler 					}
186474c0424aSAxel Dörfler 
186574c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
18667486b72dSIngo Weinhold 					if (!reportErrors) {
18677486b72dSIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
18687486b72dSIngo Weinhold 							"failed: %s", image->name, image->id,
18697486b72dSIngo Weinhold 							strerror(status));
18700c0fea5dSIngo Weinhold 						return status;
187174c0424aSAxel Dörfler 					}
18727486b72dSIngo Weinhold 				}
18730c0fea5dSIngo Weinhold 
18740c0fea5dSIngo Weinhold 				j += 1;
18750c0fea5dSIngo Weinhold 				break;
187674c0424aSAxel Dörfler 			}
18770c0fea5dSIngo Weinhold 
18780c0fea5dSIngo Weinhold 			default:
18790c0fea5dSIngo Weinhold 				// ignore any other tag
18800c0fea5dSIngo Weinhold 				continue;
18810c0fea5dSIngo Weinhold 		}
18820c0fea5dSIngo Weinhold 	}
18830c0fea5dSIngo Weinhold 
18847486b72dSIngo Weinhold 	if (status < B_OK) {
18857486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
18867486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
18877486b72dSIngo Weinhold 			strerror(status));
188874c0424aSAxel Dörfler 		return status;
18897486b72dSIngo Weinhold 	}
189074c0424aSAxel Dörfler 
18910c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
18920c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
18937486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
18947486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
18950c0fea5dSIngo Weinhold 		return B_ERROR;
18960c0fea5dSIngo Weinhold 	}
18970c0fea5dSIngo Weinhold 
18987486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
18997486b72dSIngo Weinhold 		image->id);
19007486b72dSIngo Weinhold 
19010c0fea5dSIngo Weinhold 	return B_OK;
19020c0fea5dSIngo Weinhold }
19030c0fea5dSIngo Weinhold 
19040c0fea5dSIngo Weinhold 
19050c85bd05SIngo Weinhold static status_t
19060c85bd05SIngo Weinhold load_dependencies(image_t* image)
19070c85bd05SIngo Weinhold {
19080c85bd05SIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
19090c85bd05SIngo Weinhold 			otherImage = otherImage->next) {
19100c85bd05SIngo Weinhold 		status_t status = load_immediate_dependencies(otherImage);
19110c85bd05SIngo Weinhold 		if (status != B_OK)
19120c85bd05SIngo Weinhold 			return status;
19130c85bd05SIngo Weinhold 	}
19140c85bd05SIngo Weinhold 
19150c85bd05SIngo Weinhold 	return B_OK;
19160c85bd05SIngo Weinhold }
19170c85bd05SIngo Weinhold 
19180c85bd05SIngo Weinhold 
19190c0fea5dSIngo Weinhold static uint32
19200c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList,
19210c0fea5dSIngo Weinhold 	uint32 sortFlag)
19220c0fea5dSIngo Weinhold {
19230c0fea5dSIngo Weinhold 	uint32 i;
19240c0fea5dSIngo Weinhold 
19250c0fea5dSIngo Weinhold 	if (image->flags & sortFlag)
19260c0fea5dSIngo Weinhold 		return slot;
19270c0fea5dSIngo Weinhold 
19280c0fea5dSIngo Weinhold 	image->flags |= sortFlag; /* make sure we don't visit this one */
19290c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_needed; i++)
19300c0fea5dSIngo Weinhold 		slot = topological_sort(image->needed[i], slot, initList, sortFlag);
19310c0fea5dSIngo Weinhold 
19320c0fea5dSIngo Weinhold 	initList[slot] = image;
19330c0fea5dSIngo Weinhold 	return slot + 1;
19340c0fea5dSIngo Weinhold }
19350c0fea5dSIngo Weinhold 
19360c0fea5dSIngo Weinhold 
19370c0fea5dSIngo Weinhold static ssize_t
19380c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
19390c0fea5dSIngo Weinhold {
19400c0fea5dSIngo Weinhold 	image_t **list;
19410c0fea5dSIngo Weinhold 
19420c0fea5dSIngo Weinhold 	list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *));
19430c0fea5dSIngo Weinhold 	if (list == NULL) {
19440c0fea5dSIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
19450c0fea5dSIngo Weinhold 		*_list = NULL;
19460c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
19470c0fea5dSIngo Weinhold 	}
19480c0fea5dSIngo Weinhold 
19490c0fea5dSIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
19500c0fea5dSIngo Weinhold 
19510c0fea5dSIngo Weinhold 	*_list = list;
19520c0fea5dSIngo Weinhold 	return topological_sort(image, 0, list, sortFlag);
19530c0fea5dSIngo Weinhold }
19540c0fea5dSIngo Weinhold 
19550c0fea5dSIngo Weinhold 
19560c0fea5dSIngo Weinhold static status_t
19570c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
19580c0fea5dSIngo Weinhold {
1959ca618b22SIngo Weinhold 	// get the images that still have to be relocated
1960ca618b22SIngo Weinhold 	image_t **list;
1961ca618b22SIngo Weinhold 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
19620c0fea5dSIngo Weinhold 	if (count < B_OK)
19630c0fea5dSIngo Weinhold 		return count;
19640c0fea5dSIngo Weinhold 
19650c85bd05SIngo Weinhold 	// relocate
1966ca618b22SIngo Weinhold 	for (ssize_t i = 0; i < count; i++) {
196746f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
19680c85bd05SIngo Weinhold 		if (status < B_OK) {
19690c85bd05SIngo Weinhold 			free(list);
19700c0fea5dSIngo Weinhold 			return status;
19710c0fea5dSIngo Weinhold 		}
19720c85bd05SIngo Weinhold 	}
19730c0fea5dSIngo Weinhold 
19740c0fea5dSIngo Weinhold 	free(list);
19750c0fea5dSIngo Weinhold 	return B_OK;
19760c0fea5dSIngo Weinhold }
19770c0fea5dSIngo Weinhold 
19780c0fea5dSIngo Weinhold 
19790c0fea5dSIngo Weinhold static void
19800c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
19810c0fea5dSIngo Weinhold {
19820c0fea5dSIngo Weinhold 	image_t **initList;
19830c0fea5dSIngo Weinhold 	ssize_t count, i;
19840c0fea5dSIngo Weinhold 
19850c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
19860c0fea5dSIngo Weinhold 	if (count <= 0)
19870c0fea5dSIngo Weinhold 		return;
19880c0fea5dSIngo Weinhold 
19890c0fea5dSIngo Weinhold 	if (!initHead) {
19900c0fea5dSIngo Weinhold 		// this removes the "calling" image
19910c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
19920c0fea5dSIngo Weinhold 		initList[--count] = NULL;
19930c0fea5dSIngo Weinhold 	}
19940c0fea5dSIngo Weinhold 
19950c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
19960c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
19970c0fea5dSIngo Weinhold 		image = initList[i];
19980c0fea5dSIngo Weinhold 
19990c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
20000c0fea5dSIngo Weinhold 
2001dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
20020c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
200310b4b5d1SIngo Weinhold 
200410b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
20050c0fea5dSIngo Weinhold 	}
20060c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
20070c0fea5dSIngo Weinhold 
20080c0fea5dSIngo Weinhold 	free(initList);
20090c0fea5dSIngo Weinhold }
20100c0fea5dSIngo Weinhold 
20110c0fea5dSIngo Weinhold 
20120c0fea5dSIngo Weinhold static void
20130c0fea5dSIngo Weinhold put_image(image_t *image)
20140c0fea5dSIngo Weinhold {
20150c0fea5dSIngo Weinhold 	// If all references to the image are gone, add it to the disposable list
20160c0fea5dSIngo Weinhold 	// and remove all dependencies
20170c0fea5dSIngo Weinhold 
20180c0fea5dSIngo Weinhold 	if (atomic_add(&image->ref_count, -1) == 1) {
20190c0fea5dSIngo Weinhold 		size_t i;
20200c0fea5dSIngo Weinhold 
20210c0fea5dSIngo Weinhold 		dequeue_image(&sLoadedImages, image);
20220c0fea5dSIngo Weinhold 		enqueue_image(&sDisposableImages, image);
20230c0fea5dSIngo Weinhold 		sLoadedImageCount--;
20240c0fea5dSIngo Weinhold 
20250c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_needed; i++) {
20260c0fea5dSIngo Weinhold 			put_image(image->needed[i]);
20270c0fea5dSIngo Weinhold 		}
20280c0fea5dSIngo Weinhold 	}
20290c0fea5dSIngo Weinhold }
20300c0fea5dSIngo Weinhold 
20310c0fea5dSIngo Weinhold 
2032ca618b22SIngo Weinhold void
2033ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
2034ca618b22SIngo Weinhold {
2035ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
2036ca618b22SIngo Weinhold 	// API.
2037ca618b22SIngo Weinhold 	image_t* image;
20380c85bd05SIngo Weinhold 	void* _export;
20390c85bd05SIngo Weinhold 	if (find_symbol_breadth_first(rootImage, "__gRuntimeLoader",
20400c85bd05SIngo Weinhold 			B_SYMBOL_TYPE_DATA, &image, &_export) == B_OK) {
20410c85bd05SIngo Weinhold 		*(void**)_export = &gRuntimeLoader;
2042ca618b22SIngo Weinhold 	}
2043ca618b22SIngo Weinhold }
2044ca618b22SIngo Weinhold 
2045ca618b22SIngo Weinhold 
2046ca618b22SIngo Weinhold static status_t
2047ca618b22SIngo Weinhold add_preloaded_image(image_t* image)
2048ca618b22SIngo Weinhold {
2049ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
2050ca618b22SIngo Weinhold 	// small number of preloaded images.
2051ca618b22SIngo Weinhold 	image_t** newArray = (image_t**)realloc(sPreloadedImages,
2052ca618b22SIngo Weinhold 		sizeof(image_t*) * (sPreloadedImageCount + 1));
2053ca618b22SIngo Weinhold 	if (newArray == NULL)
2054ca618b22SIngo Weinhold 		return B_NO_MEMORY;
2055ca618b22SIngo Weinhold 
2056ca618b22SIngo Weinhold 	sPreloadedImages = newArray;
2057ca618b22SIngo Weinhold 	newArray[sPreloadedImageCount++] = image;
2058ca618b22SIngo Weinhold 
2059ca618b22SIngo Weinhold 	return B_OK;
2060ca618b22SIngo Weinhold }
2061ca618b22SIngo Weinhold 
2062ca618b22SIngo Weinhold 
2063ca618b22SIngo Weinhold image_id
2064ca618b22SIngo Weinhold preload_image(char const* path)
2065ca618b22SIngo Weinhold {
2066ca618b22SIngo Weinhold 	if (path == NULL)
2067ca618b22SIngo Weinhold 		return B_BAD_VALUE;
2068ca618b22SIngo Weinhold 
2069ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\")", path);
2070ca618b22SIngo Weinhold 
2071ca618b22SIngo Weinhold 	image_t *image = NULL;
2072ca618b22SIngo Weinhold 	status_t status = load_container(path, B_ADD_ON_IMAGE, NULL, &image);
2073ca618b22SIngo Weinhold 	if (status < B_OK) {
2074ca618b22SIngo Weinhold 		rld_unlock();
2075ca618b22SIngo Weinhold 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
2076ca618b22SIngo Weinhold 			strerror(status));
2077ca618b22SIngo Weinhold 		return status;
2078ca618b22SIngo Weinhold 	}
2079ca618b22SIngo Weinhold 
20800c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL)
20810c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_global;
20820c85bd05SIngo Weinhold 
20830c85bd05SIngo Weinhold 	status = load_dependencies(image);
2084ca618b22SIngo Weinhold 	if (status < B_OK)
2085ca618b22SIngo Weinhold 		goto err;
20860c85bd05SIngo Weinhold 
20870c85bd05SIngo Weinhold 	set_image_flags_recursively(image, RTLD_GLOBAL);
2088ca618b22SIngo Weinhold 
2089ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
2090ca618b22SIngo Weinhold 	if (status < B_OK)
2091ca618b22SIngo Weinhold 		goto err;
2092ca618b22SIngo Weinhold 
2093ca618b22SIngo Weinhold 	status = add_preloaded_image(image);
2094ca618b22SIngo Weinhold 	if (status < B_OK)
2095ca618b22SIngo Weinhold 		goto err;
2096ca618b22SIngo Weinhold 
2097ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
2098ca618b22SIngo Weinhold 
2099ca618b22SIngo Weinhold 	remap_images();
2100ca618b22SIngo Weinhold 	init_dependencies(image, true);
2101ca618b22SIngo Weinhold 
210210b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
210310b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
210410b4b5d1SIngo Weinhold 	if (find_symbol(image, "__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA,
210510b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
210610b4b5d1SIngo Weinhold 		RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image,
210710b4b5d1SIngo Weinhold 			addOnStruct);
210810b4b5d1SIngo Weinhold 		if (addOn != NULL) {
210910b4b5d1SIngo Weinhold 			sAddOns.Add(addOn);
211010b4b5d1SIngo Weinhold 			addOnStruct->init(&gRuntimeLoader, &gRuntimeLoaderAddOnExport);
211110b4b5d1SIngo Weinhold 		}
211210b4b5d1SIngo Weinhold 	}
211310b4b5d1SIngo Weinhold 
2114ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id);
2115ca618b22SIngo Weinhold 
2116ca618b22SIngo Weinhold 	return image->id;
2117ca618b22SIngo Weinhold 
2118ca618b22SIngo Weinhold err:
2119ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status));
2120ca618b22SIngo Weinhold 
2121ca618b22SIngo Weinhold 	dequeue_image(&sLoadedImages, image);
2122ca618b22SIngo Weinhold 	sLoadedImageCount--;
2123ca618b22SIngo Weinhold 	delete_image(image);
2124ca618b22SIngo Weinhold 	return status;
2125ca618b22SIngo Weinhold }
2126ca618b22SIngo Weinhold 
2127ca618b22SIngo Weinhold 
2128ca618b22SIngo Weinhold static void
2129ca618b22SIngo Weinhold preload_images()
2130ca618b22SIngo Weinhold {
2131ca618b22SIngo Weinhold 	const char* imagePaths = getenv("LD_PRELOAD");
2132ca618b22SIngo Weinhold 	if (imagePaths == NULL)
2133ca618b22SIngo Weinhold 		return;
2134ca618b22SIngo Weinhold 
2135ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
2136ca618b22SIngo Weinhold 		// find begin of image path
2137ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
2138ca618b22SIngo Weinhold 			imagePaths++;
2139ca618b22SIngo Weinhold 
2140ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
2141ca618b22SIngo Weinhold 			break;
2142ca618b22SIngo Weinhold 
2143ca618b22SIngo Weinhold 		// find end of image path
2144ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
2145ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
2146ca618b22SIngo Weinhold 			imagePaths++;
2147ca618b22SIngo Weinhold 
2148ca618b22SIngo Weinhold 		// extract the path
2149ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
2150ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
2151ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
2152ca618b22SIngo Weinhold 			continue;
2153ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
2154ca618b22SIngo Weinhold 		path[pathLen] = '\0';
2155ca618b22SIngo Weinhold 
2156ca618b22SIngo Weinhold 		// load the image
2157ca618b22SIngo Weinhold 		preload_image(path);
2158ca618b22SIngo Weinhold 	}
2159ca618b22SIngo Weinhold }
2160ca618b22SIngo Weinhold 
2161ca618b22SIngo Weinhold 
216274c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
21630c0fea5dSIngo Weinhold 
21640c0fea5dSIngo Weinhold 
21650c0fea5dSIngo Weinhold image_id
21660c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
21670c0fea5dSIngo Weinhold {
21680c0fea5dSIngo Weinhold 	status_t status;
21690c0fea5dSIngo Weinhold 	image_t *image;
21700c0fea5dSIngo Weinhold 
21717486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
21727486b72dSIngo Weinhold 
21730c0fea5dSIngo Weinhold 	rld_lock();
21740c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
21750c0fea5dSIngo Weinhold 
2176ca618b22SIngo Weinhold 	preload_images();
2177ca618b22SIngo Weinhold 
21780c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
21790c0fea5dSIngo Weinhold 
21800c0fea5dSIngo Weinhold 	status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage);
218174c0424aSAxel Dörfler 	if (status < B_OK)
218274c0424aSAxel Dörfler 		goto err;
21830c0fea5dSIngo Weinhold 
21840c85bd05SIngo Weinhold 	if (sProgramImage->find_undefined_symbol == NULL)
21850c85bd05SIngo Weinhold 		sProgramImage->find_undefined_symbol = find_undefined_symbol_global;
21860c85bd05SIngo Weinhold 
21870c85bd05SIngo Weinhold 	status = load_dependencies(sProgramImage);
21880c0fea5dSIngo Weinhold 	if (status < B_OK)
21890c0fea5dSIngo Weinhold 		goto err;
21900c85bd05SIngo Weinhold 
219147bc6663SIngo Weinhold 	// Set RTLD_GLOBAL on all libraries including the program.
21920c85bd05SIngo Weinhold 	// This results in the desired symbol resolution for dlopen()ed libraries.
21930c85bd05SIngo Weinhold 	set_image_flags_recursively(sProgramImage, RTLD_GLOBAL);
21940c0fea5dSIngo Weinhold 
21950c0fea5dSIngo Weinhold 	status = relocate_dependencies(sProgramImage);
21960c0fea5dSIngo Weinhold 	if (status < B_OK)
21970c0fea5dSIngo Weinhold 		goto err;
21980c0fea5dSIngo Weinhold 
2199ca618b22SIngo Weinhold 	inject_runtime_loader_api(sProgramImage);
22000c0fea5dSIngo Weinhold 
22010c0fea5dSIngo Weinhold 	remap_images();
2202ca618b22SIngo Weinhold 	init_dependencies(sProgramImage, true);
22030c0fea5dSIngo Weinhold 
22040c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
22050c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
22060c85bd05SIngo Weinhold 	find_symbol_breadth_first(sProgramImage, "getenv", B_SYMBOL_TYPE_TEXT,
22070c85bd05SIngo Weinhold 		&image, (void**)&gGetEnv);
22080c0fea5dSIngo Weinhold 
2209dd76bc97SIngo Weinhold 	if (sProgramImage->entry_point == 0) {
22100c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
22110c0fea5dSIngo Weinhold 		goto err;
22120c0fea5dSIngo Weinhold 	}
22130c0fea5dSIngo Weinhold 
22140c0fea5dSIngo Weinhold 	*_entry = (void *)(sProgramImage->entry_point);
22150c0fea5dSIngo Weinhold 
22160c0fea5dSIngo Weinhold 	rld_unlock();
22177486b72dSIngo Weinhold 
22185d0638bfSIngo Weinhold 	sProgramLoaded = true;
22195d0638bfSIngo Weinhold 
22207486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
22217486b72dSIngo Weinhold 		*_entry, sProgramImage->id);
22227486b72dSIngo Weinhold 
22230c0fea5dSIngo Weinhold 	return sProgramImage->id;
22240c0fea5dSIngo Weinhold 
22250c0fea5dSIngo Weinhold err:
22267486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
22277486b72dSIngo Weinhold 
22280c0fea5dSIngo Weinhold 	delete_image(sProgramImage);
222974c0424aSAxel Dörfler 
22304bef3723SAxel Dörfler 	if (report_errors()) {
22314bef3723SAxel Dörfler 		// send error message
223274c0424aSAxel Dörfler 		sErrorMessage.AddInt32("error", status);
22334bef3723SAxel Dörfler 		sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
22344bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
22354bef3723SAxel Dörfler 
22364bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
22374bef3723SAxel Dörfler 			sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0);
223874c0424aSAxel Dörfler 	}
223974c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
22400c0fea5dSIngo Weinhold 	rld_unlock();
224174c0424aSAxel Dörfler 
22420c0fea5dSIngo Weinhold 	return status;
22430c0fea5dSIngo Weinhold }
22440c0fea5dSIngo Weinhold 
22450c0fea5dSIngo Weinhold 
22460c0fea5dSIngo Weinhold image_id
22470c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle)
22480c0fea5dSIngo Weinhold {
22490c0fea5dSIngo Weinhold 	image_t *image = NULL;
22500c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
22510c0fea5dSIngo Weinhold 	status_t status;
22520c0fea5dSIngo Weinhold 
22530c85bd05SIngo Weinhold 	if (path == NULL && addOn)
22540c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
22550c0fea5dSIngo Weinhold 
22567486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
22577486b72dSIngo Weinhold 
22580c0fea5dSIngo Weinhold 	rld_lock();
22590c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
22600c0fea5dSIngo Weinhold 
22610c0fea5dSIngo Weinhold 	// have we already loaded this library?
22620c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
22630c0fea5dSIngo Weinhold 	if (!addOn) {
22640c85bd05SIngo Weinhold 		// a NULL path is fine -- it means the global scope shall be opened
22650c85bd05SIngo Weinhold 		if (path == NULL) {
22660c85bd05SIngo Weinhold 			*_handle = RLD_GLOBAL_SCOPE;
22670c85bd05SIngo Weinhold 			rld_unlock();
22680c85bd05SIngo Weinhold 			return 0;
22690c85bd05SIngo Weinhold 		}
22700c85bd05SIngo Weinhold 
22710c0fea5dSIngo Weinhold 		image = find_image(path, APP_OR_LIBRARY_TYPE);
22720c85bd05SIngo Weinhold 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
22730c85bd05SIngo Weinhold 			set_image_flags_recursively(image, RTLD_GLOBAL);
22740c85bd05SIngo Weinhold 
22750c0fea5dSIngo Weinhold 		if (image) {
22760c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
22770c0fea5dSIngo Weinhold 			rld_unlock();
22787486b72dSIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
22797486b72dSIngo Weinhold 				image->id);
22800c85bd05SIngo Weinhold 			*_handle = image;
22810c0fea5dSIngo Weinhold 			return image->id;
22820c0fea5dSIngo Weinhold 		}
22830c0fea5dSIngo Weinhold 	}
22840c0fea5dSIngo Weinhold 
22850c0fea5dSIngo Weinhold 	status = load_container(path, type, NULL, &image);
22860c0fea5dSIngo Weinhold 	if (status < B_OK) {
22870c0fea5dSIngo Weinhold 		rld_unlock();
22887486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
22897486b72dSIngo Weinhold 			strerror(status));
22900c0fea5dSIngo Weinhold 		return status;
22910c0fea5dSIngo Weinhold 	}
22920c0fea5dSIngo Weinhold 
22930c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL) {
22940c85bd05SIngo Weinhold 		if (addOn)
22950c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_add_on;
22960c85bd05SIngo Weinhold 		else
22970c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_global;
22980c85bd05SIngo Weinhold 	}
22990c85bd05SIngo Weinhold 
23000c85bd05SIngo Weinhold 	status = load_dependencies(image);
23010c0fea5dSIngo Weinhold 	if (status < B_OK)
23020c0fea5dSIngo Weinhold 		goto err;
23030c85bd05SIngo Weinhold 
23040c85bd05SIngo Weinhold 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
23050c85bd05SIngo Weinhold 	// dependencies. If not specified, we temporarily set
23060c85bd05SIngo Weinhold 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
23070c85bd05SIngo Weinhold 	// for undefined symbol resolution.
23080c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) != 0)
23090c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RTLD_GLOBAL);
23100c85bd05SIngo Weinhold 	else
23110c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
23120c0fea5dSIngo Weinhold 
23130c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
23140c0fea5dSIngo Weinhold 	if (status < B_OK)
23150c0fea5dSIngo Weinhold 		goto err;
23160c0fea5dSIngo Weinhold 
23170c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) == 0)
23180c85bd05SIngo Weinhold 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
23190c85bd05SIngo Weinhold 
23200c0fea5dSIngo Weinhold 	remap_images();
23210c0fea5dSIngo Weinhold 	init_dependencies(image, true);
23220c0fea5dSIngo Weinhold 
23230c0fea5dSIngo Weinhold 	rld_unlock();
23247486b72dSIngo Weinhold 
23257486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
23267486b72dSIngo Weinhold 
23270c85bd05SIngo Weinhold 	*_handle = image;
23280c0fea5dSIngo Weinhold 	return image->id;
23290c0fea5dSIngo Weinhold 
23300c0fea5dSIngo Weinhold err:
23317486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
23327486b72dSIngo Weinhold 
23330c0fea5dSIngo Weinhold 	dequeue_image(&sLoadedImages, image);
23340c0fea5dSIngo Weinhold 	sLoadedImageCount--;
23350c0fea5dSIngo Weinhold 	delete_image(image);
23360c0fea5dSIngo Weinhold 	rld_unlock();
23370c0fea5dSIngo Weinhold 	return status;
23380c0fea5dSIngo Weinhold }
23390c0fea5dSIngo Weinhold 
23400c0fea5dSIngo Weinhold 
23410c0fea5dSIngo Weinhold status_t
23420c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
23430c0fea5dSIngo Weinhold {
23440c0fea5dSIngo Weinhold 	image_t *image;
23450c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
23460c0fea5dSIngo Weinhold 
23470c85bd05SIngo Weinhold 	if (handle == NULL && imageID < 0)
23480c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
23490c0fea5dSIngo Weinhold 
23500c85bd05SIngo Weinhold 	if (handle == RLD_GLOBAL_SCOPE)
23510c85bd05SIngo Weinhold 		return B_OK;
23520c85bd05SIngo Weinhold 
23530c0fea5dSIngo Weinhold 	rld_lock();
23540c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
23550c0fea5dSIngo Weinhold 
23569a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
23579a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
23589a6072a3SAxel Dörfler 		update_image_ids();
23599a6072a3SAxel Dörfler 	}
23609a6072a3SAxel Dörfler 
23610c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
23620c0fea5dSIngo Weinhold 
2363df30098dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
2364df30098dSIngo Weinhold 
23650c85bd05SIngo Weinhold 	if (handle != NULL) {
23660c85bd05SIngo Weinhold 		image = (image_t*)handle;
23670c85bd05SIngo Weinhold 		put_image(image);
2368df30098dSIngo Weinhold 		status = B_OK;
23690c85bd05SIngo Weinhold 	} else {
23700c0fea5dSIngo Weinhold 		for (image = sLoadedImages.head; image; image = image->next) {
23710c0fea5dSIngo Weinhold 			if (image->id == imageID) {
23720c0fea5dSIngo Weinhold 				// unload image
23730c0fea5dSIngo Weinhold 				if (type == image->type) {
23740c0fea5dSIngo Weinhold 					put_image(image);
23750c0fea5dSIngo Weinhold 					status = B_OK;
23760c0fea5dSIngo Weinhold 				} else
23770c0fea5dSIngo Weinhold 					status = B_BAD_VALUE;
23780c0fea5dSIngo Weinhold 				break;
23790c0fea5dSIngo Weinhold 			}
23800c0fea5dSIngo Weinhold 		}
23810c85bd05SIngo Weinhold 	}
23820c0fea5dSIngo Weinhold 
23830c0fea5dSIngo Weinhold 	if (status == B_OK) {
23840c0fea5dSIngo Weinhold 		while ((image = sDisposableImages.head) != NULL) {
23850c0fea5dSIngo Weinhold 			// call image fini here...
23868c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
23878c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
23883be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
23898c2a9d74SMichael Lotz 			}
23908c2a9d74SMichael Lotz 
239110b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
239210b4b5d1SIngo Weinhold 
23930c0fea5dSIngo Weinhold 			if (image->term_routine)
23940c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
23950c0fea5dSIngo Weinhold 
23960c0fea5dSIngo Weinhold 			dequeue_image(&sDisposableImages, image);
23970c0fea5dSIngo Weinhold 			unmap_image(image);
23980c0fea5dSIngo Weinhold 
239910b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
240010b4b5d1SIngo Weinhold 
24010c0fea5dSIngo Weinhold 			delete_image(image);
24020c0fea5dSIngo Weinhold 		}
24030c0fea5dSIngo Weinhold 	}
24040c0fea5dSIngo Weinhold 
24050c0fea5dSIngo Weinhold 	rld_unlock();
24060c0fea5dSIngo Weinhold 	return status;
24070c0fea5dSIngo Weinhold }
24080c0fea5dSIngo Weinhold 
24090c0fea5dSIngo Weinhold 
24100c0fea5dSIngo Weinhold status_t
24119a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
24129a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
24130c0fea5dSIngo Weinhold {
24140c0fea5dSIngo Weinhold 	int32 count = 0, j;
24150c0fea5dSIngo Weinhold 	uint32 i;
24160c0fea5dSIngo Weinhold 	image_t *image;
24170c0fea5dSIngo Weinhold 
24180c0fea5dSIngo Weinhold 	rld_lock();
24190c0fea5dSIngo Weinhold 
24200c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
24210c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
24220c0fea5dSIngo Weinhold 	if (image == NULL) {
24230c0fea5dSIngo Weinhold 		rld_unlock();
24240c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
24250c0fea5dSIngo Weinhold 	}
24260c0fea5dSIngo Weinhold 
24270c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
24280c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
24290c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
24300555803aSAxel Dörfler 			struct Elf32_Sym *symbol = &image->syms[j];
24310c0fea5dSIngo Weinhold 
24320c0fea5dSIngo Weinhold 			if (count == num) {
243310b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
243410b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
243510b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
24360c0fea5dSIngo Weinhold 
243710b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
243810b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
243910b4b5d1SIngo Weinhold 				int32 type;
24400c0fea5dSIngo Weinhold 				if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
244110b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
24420c0fea5dSIngo Weinhold 				else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
244310b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
24440c0fea5dSIngo Weinhold 				else
244510b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
244610b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
24470c0fea5dSIngo Weinhold 
244810b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
244910b4b5d1SIngo Weinhold 
245010b4b5d1SIngo Weinhold 				if (_type != NULL)
245110b4b5d1SIngo Weinhold 					*_type = type;
24520c0fea5dSIngo Weinhold 				if (_location != NULL)
245310b4b5d1SIngo Weinhold 					*_location = location;
24540c0fea5dSIngo Weinhold 				goto out;
24550c0fea5dSIngo Weinhold 			}
24560c0fea5dSIngo Weinhold 			count++;
24570c0fea5dSIngo Weinhold 		}
24580c0fea5dSIngo Weinhold 	}
24590c0fea5dSIngo Weinhold out:
24600c0fea5dSIngo Weinhold 	rld_unlock();
24610c0fea5dSIngo Weinhold 
24620c0fea5dSIngo Weinhold 	if (num != count)
24630c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
24640c0fea5dSIngo Weinhold 
24650c0fea5dSIngo Weinhold 	return B_OK;
24660c0fea5dSIngo Weinhold }
24670c0fea5dSIngo Weinhold 
24680c0fea5dSIngo Weinhold 
24690c0fea5dSIngo Weinhold status_t
24709a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
247180ece785SIngo Weinhold 	bool recursive, image_id *_inImage, void **_location)
24720c0fea5dSIngo Weinhold {
24730c0fea5dSIngo Weinhold 	status_t status = B_OK;
24740c0fea5dSIngo Weinhold 	image_t *image;
24750c0fea5dSIngo Weinhold 
24760c0fea5dSIngo Weinhold 	if (imageID < B_OK)
24770c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
24780c0fea5dSIngo Weinhold 	if (symbolName == NULL)
24790c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
24800c0fea5dSIngo Weinhold 
24810c0fea5dSIngo Weinhold 	rld_lock();
24820c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
24830c0fea5dSIngo Weinhold 
24840c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
24850c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
248680ece785SIngo Weinhold 	if (image != NULL) {
248780ece785SIngo Weinhold 		if (recursive) {
248880ece785SIngo Weinhold 			// breadth-first search in the given image and its dependencies
248980ece785SIngo Weinhold 			status = find_symbol_breadth_first(image, symbolName, symbolType,
249080ece785SIngo Weinhold 				&image, _location);
249180ece785SIngo Weinhold 		} else
249210b4b5d1SIngo Weinhold 			status = find_symbol(image, symbolName, symbolType, _location);
249380ece785SIngo Weinhold 
249480ece785SIngo Weinhold 		if (status == B_OK && _inImage != NULL)
249580ece785SIngo Weinhold 			*_inImage = image->id;
249680ece785SIngo Weinhold 	} else
24970c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
24980c0fea5dSIngo Weinhold 
24990c0fea5dSIngo Weinhold 	rld_unlock();
25000c0fea5dSIngo Weinhold 	return status;
25010c0fea5dSIngo Weinhold }
25020c0fea5dSIngo Weinhold 
25030c0fea5dSIngo Weinhold 
25040c0fea5dSIngo Weinhold status_t
25050c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
25060c85bd05SIngo Weinhold 	void **_location)
25070c85bd05SIngo Weinhold {
25080c85bd05SIngo Weinhold 	status_t status = B_ENTRY_NOT_FOUND;
25090c85bd05SIngo Weinhold 
25100c85bd05SIngo Weinhold 	if (symbolName == NULL)
25110c85bd05SIngo Weinhold 		return B_BAD_VALUE;
25120c85bd05SIngo Weinhold 
25130c85bd05SIngo Weinhold 	rld_lock();
25140c85bd05SIngo Weinhold 		// for now, just do stupid simple global locking
25150c85bd05SIngo Weinhold 
25160c85bd05SIngo Weinhold 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
25170c85bd05SIngo Weinhold 		// look in the default scope
25180c85bd05SIngo Weinhold 		image_t* image;
25190c85bd05SIngo Weinhold 		Elf32_Sym* symbol = find_undefined_symbol_global(sProgramImage,
25200c85bd05SIngo Weinhold 			sProgramImage, symbolName, &image);
25210c85bd05SIngo Weinhold 		if (symbol != NULL) {
25220c85bd05SIngo Weinhold 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
25230c85bd05SIngo Weinhold 			int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
25240c85bd05SIngo Weinhold 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
25250c85bd05SIngo Weinhold 			patch_defined_symbol(image, symbolName, _location, &symbolType);
25260c85bd05SIngo Weinhold 			status = B_OK;
25270c85bd05SIngo Weinhold 		}
25280c85bd05SIngo Weinhold 	} else if (handle == RTLD_NEXT) {
25290c85bd05SIngo Weinhold 		// Look in the default scope, but also in the dependencies of the
25300c85bd05SIngo Weinhold 		// calling image. Return the next after the caller symbol.
25310c85bd05SIngo Weinhold 
2532a2dad9e1SIngo Weinhold 		// First of all, find the caller image.
25330c85bd05SIngo Weinhold 		image_t* callerImage = sLoadedImages.head;
25340c85bd05SIngo Weinhold 		for (; callerImage != NULL; callerImage = callerImage->next) {
25350c85bd05SIngo Weinhold 			elf_region_t& text = callerImage->regions[0];
2536a2dad9e1SIngo Weinhold 			if ((addr_t)caller >= text.vmstart
2537a2dad9e1SIngo Weinhold 				&& (addr_t)caller < text.vmstart + text.vmsize) {
2538a2dad9e1SIngo Weinhold 				// found the image
25390c85bd05SIngo Weinhold 				break;
25400c85bd05SIngo Weinhold 			}
25410c85bd05SIngo Weinhold 		}
25420c85bd05SIngo Weinhold 
2543a2dad9e1SIngo Weinhold 		if (callerImage != NULL) {
25440c85bd05SIngo Weinhold 			// found the caller -- now search the global scope until we find
25450c85bd05SIngo Weinhold 			// the next symbol
2546a2dad9e1SIngo Weinhold 			bool hitCallerImage = false;
25470c85bd05SIngo Weinhold 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
25480c85bd05SIngo Weinhold 
25490c85bd05SIngo Weinhold 			image_t* image = sLoadedImages.head;
25500c85bd05SIngo Weinhold 			for (; image != NULL; image = image->next) {
2551a2dad9e1SIngo Weinhold 				// skip the caller image
2552a2dad9e1SIngo Weinhold 				if (image == callerImage) {
2553a2dad9e1SIngo Weinhold 					hitCallerImage = true;
2554a2dad9e1SIngo Weinhold 					continue;
2555a2dad9e1SIngo Weinhold 				}
2556a2dad9e1SIngo Weinhold 
2557a2dad9e1SIngo Weinhold 				// skip all images up to the caller image; also skip add-on
2558a2dad9e1SIngo Weinhold 				// images and those not marked above for resolution
2559a2dad9e1SIngo Weinhold 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
25600c85bd05SIngo Weinhold 					|| (image->flags
2561a2dad9e1SIngo Weinhold 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
25620c85bd05SIngo Weinhold 					continue;
25630c85bd05SIngo Weinhold 				}
25640c85bd05SIngo Weinhold 
25650c85bd05SIngo Weinhold 				struct Elf32_Sym *symbol = find_symbol(image, symbolName,
25660c85bd05SIngo Weinhold 					B_SYMBOL_TYPE_TEXT);
25670c85bd05SIngo Weinhold 				if (symbol == NULL)
25680c85bd05SIngo Weinhold 					continue;
25690c85bd05SIngo Weinhold 
2570a2dad9e1SIngo Weinhold 				// found the symbol
25710c85bd05SIngo Weinhold 				*_location = (void*)(symbol->st_value
25720c85bd05SIngo Weinhold 					+ image->regions[0].delta);
25730c85bd05SIngo Weinhold 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
25740c85bd05SIngo Weinhold 				patch_defined_symbol(image, symbolName, _location,
25750c85bd05SIngo Weinhold 					&symbolType);
25760c85bd05SIngo Weinhold 				status = B_OK;
25770c85bd05SIngo Weinhold 				break;
25780c85bd05SIngo Weinhold 			}
25790c85bd05SIngo Weinhold 
25800c85bd05SIngo Weinhold 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
25810c85bd05SIngo Weinhold 		}
25820c85bd05SIngo Weinhold 	} else {
25830c85bd05SIngo Weinhold 		// breadth-first search in the given image and its dependencies
25840c85bd05SIngo Weinhold 		image_t* inImage;
25850c85bd05SIngo Weinhold 		status = find_symbol_breadth_first((image_t*)handle, symbolName,
25860c85bd05SIngo Weinhold 			B_SYMBOL_TYPE_ANY, &inImage, _location);
25870c85bd05SIngo Weinhold 	}
25880c85bd05SIngo Weinhold 
25890c85bd05SIngo Weinhold 	rld_unlock();
25900c85bd05SIngo Weinhold 	return status;
25910c85bd05SIngo Weinhold }
25920c85bd05SIngo Weinhold 
25930c85bd05SIngo Weinhold 
25940c85bd05SIngo Weinhold status_t
25950c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
25960c0fea5dSIngo Weinhold {
25970c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
25980c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
25990c0fea5dSIngo Weinhold 	image_t *image;
26000c0fea5dSIngo Weinhold 
26010c0fea5dSIngo Weinhold 	if (_name == NULL)
26020c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
26030c0fea5dSIngo Weinhold 
26040c0fea5dSIngo Weinhold 	rld_lock();
26050c0fea5dSIngo Weinhold 
26060c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(id);
26070c0fea5dSIngo Weinhold 	if (image == NULL) {
26080c0fea5dSIngo Weinhold 		rld_unlock();
26090c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
26100c0fea5dSIngo Weinhold 	}
26110c0fea5dSIngo Weinhold 
26120c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
26130c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
26140c0fea5dSIngo Weinhold 		rld_unlock();
26150c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
26160c0fea5dSIngo Weinhold 	}
26170c0fea5dSIngo Weinhold 
26180c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
26190c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
26200c0fea5dSIngo Weinhold 			continue;
26210c0fea5dSIngo Weinhold 
26220c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
26230c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
26240c0fea5dSIngo Weinhold 
26250c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
26260c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
26270c0fea5dSIngo Weinhold 			rld_unlock();
26280c0fea5dSIngo Weinhold 			return B_OK;
26290c0fea5dSIngo Weinhold 		}
26300c0fea5dSIngo Weinhold 	}
26310c0fea5dSIngo Weinhold 
26320c0fea5dSIngo Weinhold 	rld_unlock();
26330c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
26340c0fea5dSIngo Weinhold }
26350c0fea5dSIngo Weinhold 
26360c0fea5dSIngo Weinhold 
263774c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
26380c0fea5dSIngo Weinhold 
26390c0fea5dSIngo Weinhold 
26409a6072a3SAxel Dörfler /*! Read and verify the ELF header */
26410c0fea5dSIngo Weinhold status_t
26420c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
26430c0fea5dSIngo Weinhold {
26440c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
26450c0fea5dSIngo Weinhold 
26460c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
26470c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
26480c0fea5dSIngo Weinhold 
26499a6072a3SAxel Dörfler 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize,
26509a6072a3SAxel Dörfler 		&sectionSize);
26510c0fea5dSIngo Weinhold }
26520c0fea5dSIngo Weinhold 
26530c0fea5dSIngo Weinhold 
26540c0fea5dSIngo Weinhold void
26550c0fea5dSIngo Weinhold terminate_program(void)
26560c0fea5dSIngo Weinhold {
26570c0fea5dSIngo Weinhold 	image_t **termList;
26580c0fea5dSIngo Weinhold 	ssize_t count, i;
26590c0fea5dSIngo Weinhold 
26600c0fea5dSIngo Weinhold 	count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED);
26610c0fea5dSIngo Weinhold 	if (count < B_OK)
26620c0fea5dSIngo Weinhold 		return;
26630c0fea5dSIngo Weinhold 
26649a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
26659a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
26669a6072a3SAxel Dörfler 		update_image_ids();
26679a6072a3SAxel Dörfler 	}
26689a6072a3SAxel Dörfler 
26690c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
26700c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
26710c0fea5dSIngo Weinhold 		image_t *image = termList[i];
26720c0fea5dSIngo Weinhold 
26730c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
26740c0fea5dSIngo Weinhold 
267510b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
267610b4b5d1SIngo Weinhold 
26770c0fea5dSIngo Weinhold 		if (image->term_routine)
26780c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
267910b4b5d1SIngo Weinhold 
268010b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
26810c0fea5dSIngo Weinhold 	}
26820c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
26830c0fea5dSIngo Weinhold 
26840c0fea5dSIngo Weinhold 	free(termList);
26850c0fea5dSIngo Weinhold }
26860c0fea5dSIngo Weinhold 
26870c0fea5dSIngo Weinhold 
26880c0fea5dSIngo Weinhold void
26890c0fea5dSIngo Weinhold rldelf_init(void)
26900c0fea5dSIngo Weinhold {
269110b4b5d1SIngo Weinhold 	// invoke static constructors
269210b4b5d1SIngo Weinhold 	new(&sAddOns) AddOnList;
269310b4b5d1SIngo Weinhold 
2694e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
2695e73923b0SAxel Dörfler 	sSemOwner = -1;
2696e73923b0SAxel Dörfler 	sSemCount = 0;
26970c0fea5dSIngo Weinhold 
26980c0fea5dSIngo Weinhold 	// create the debug area
26990c0fea5dSIngo Weinhold 	{
27000c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
27010c0fea5dSIngo Weinhold 
27020c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
27030c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
27040c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
27050c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
27060c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
27070c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
27080c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
27090c0fea5dSIngo Weinhold 		}
27100c0fea5dSIngo Weinhold 
27110c0fea5dSIngo Weinhold 		area->loaded_images = &sLoadedImages;
27120c0fea5dSIngo Weinhold 	}
271374c0424aSAxel Dörfler 
271474c0424aSAxel Dörfler 	// initialize error message if needed
27154bef3723SAxel Dörfler 	if (report_errors()) {
271674c0424aSAxel Dörfler 		void *buffer = malloc(1024);
271774c0424aSAxel Dörfler 		if (buffer == NULL)
271874c0424aSAxel Dörfler 			return;
271974c0424aSAxel Dörfler 
272074c0424aSAxel Dörfler 		sErrorMessage.SetTo(buffer, 1024, 'Rler');
272174c0424aSAxel Dörfler 	}
27220c0fea5dSIngo Weinhold }
27231873b4b3SIngo Weinhold 
27241873b4b3SIngo Weinhold 
27251873b4b3SIngo Weinhold status_t
27269a6072a3SAxel Dörfler elf_reinit_after_fork(void)
27271873b4b3SIngo Weinhold {
2728e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
2729e73923b0SAxel Dörfler 	if (sSem < 0)
2730e73923b0SAxel Dörfler 		return sSem;
27311873b4b3SIngo Weinhold 
27329a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
2733cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
2734cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
27359a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
27369a6072a3SAxel Dörfler 	sInvalidImageIDs = true;
2737cbc456deSIngo Weinhold 
27381873b4b3SIngo Weinhold 	return B_OK;
27391873b4b3SIngo Weinhold }
2740