xref: /haiku/src/system/runtime_loader/elf.cpp (revision 003ebb0e834b8bc6dd69524cc5ffd4860b0466c4)
10c0fea5dSIngo Weinhold /*
2593ee7bbSIngo Weinhold  * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
312a5e9a4SAxel Dörfler  * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
40c0fea5dSIngo Weinhold  * Distributed under the terms of the MIT License.
50c0fea5dSIngo Weinhold  *
60c0fea5dSIngo Weinhold  * Copyright 2002, Manuel J. Petit. All rights reserved.
70c0fea5dSIngo Weinhold  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
80c0fea5dSIngo Weinhold  * Distributed under the terms of the NewOS License.
90c0fea5dSIngo Weinhold  */
100c0fea5dSIngo Weinhold 
110c0fea5dSIngo Weinhold #include "runtime_loader_private.h"
120c0fea5dSIngo Weinhold 
13ca618b22SIngo Weinhold #include <ctype.h>
140c85bd05SIngo Weinhold #include <dlfcn.h>
150c0fea5dSIngo Weinhold #include <stdio.h>
160c0fea5dSIngo Weinhold #include <stdlib.h>
1734982809SIngo Weinhold #include <string.h>
180c0fea5dSIngo Weinhold 
19ca618b22SIngo Weinhold #include <OS.h>
20ca618b22SIngo Weinhold 
217486b72dSIngo Weinhold #include <elf32.h>
22593ee7bbSIngo 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 
45f91194e5SIngo Weinhold // interim Haiku API versions
46f91194e5SIngo Weinhold #define HAIKU_VERSION_PRE_GLUE_CODE		0x00000010
47f91194e5SIngo Weinhold 
480c0fea5dSIngo Weinhold #define	PAGE_MASK (B_PAGE_SIZE - 1)
490c0fea5dSIngo Weinhold 
500c0fea5dSIngo Weinhold #define	PAGE_OFFSET(x) ((x) & (PAGE_MASK))
510c0fea5dSIngo Weinhold #define	PAGE_BASE(x) ((x) & ~(PAGE_MASK))
520c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
530c0fea5dSIngo Weinhold 
540c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000
550c0fea5dSIngo Weinhold 	/* keep in sync with app ldscript */
560c0fea5dSIngo Weinhold 
570c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen())
580c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE	((void*)-2l)
590c85bd05SIngo Weinhold 
600c0fea5dSIngo Weinhold enum {
610c85bd05SIngo Weinhold 	// the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL
620c85bd05SIngo Weinhold 
630c85bd05SIngo Weinhold 	RFLAG_RW					= 0x0010,
640c85bd05SIngo Weinhold 	RFLAG_ANON					= 0x0020,
650c0fea5dSIngo Weinhold 
660c0fea5dSIngo Weinhold 	RFLAG_TERMINATED			= 0x0200,
670c0fea5dSIngo Weinhold 	RFLAG_INITIALIZED			= 0x0400,
680c0fea5dSIngo Weinhold 	RFLAG_SYMBOLIC				= 0x0800,
690c0fea5dSIngo Weinhold 	RFLAG_RELOCATED				= 0x1000,
700c0fea5dSIngo Weinhold 	RFLAG_PROTECTED				= 0x2000,
710c0fea5dSIngo Weinhold 	RFLAG_DEPENDENCIES_LOADED	= 0x4000,
7246f4d849SIngo Weinhold 	RFLAG_REMAPPED				= 0x8000,
7346f4d849SIngo Weinhold 
740c85bd05SIngo Weinhold 	RFLAG_VISITED				= 0x10000,
750c85bd05SIngo Weinhold 	RFLAG_USE_FOR_RESOLVING		= 0x20000
7646f4d849SIngo Weinhold 		// temporarily set in the symbol resolution code
770c0fea5dSIngo Weinhold };
780c0fea5dSIngo Weinhold 
790c0fea5dSIngo Weinhold 
800c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type)	(1 << ((type) - 1))
810c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES				(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
820c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
830c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
840c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
850c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE			(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
860c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
870c0fea5dSIngo Weinhold 
880c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
890c0fea5dSIngo Weinhold 
90*003ebb0eSIngo Weinhold static Elf32_Sym* find_symbol(image_t* image,
91*003ebb0eSIngo Weinhold 	const SymbolLookupInfo& lookupInfo);
92*003ebb0eSIngo Weinhold static uint32 elf_hash(const uint8 *name);
93*003ebb0eSIngo Weinhold 
9410b4b5d1SIngo Weinhold 
9510b4b5d1SIngo Weinhold // image events
9610b4b5d1SIngo Weinhold enum {
9710b4b5d1SIngo Weinhold 	IMAGE_EVENT_LOADED,
9810b4b5d1SIngo Weinhold 	IMAGE_EVENT_RELOCATED,
9910b4b5d1SIngo Weinhold 	IMAGE_EVENT_INITIALIZED,
10010b4b5d1SIngo Weinhold 	IMAGE_EVENT_UNINITIALIZING,
10110b4b5d1SIngo Weinhold 	IMAGE_EVENT_UNLOADING
10210b4b5d1SIngo Weinhold };
10310b4b5d1SIngo Weinhold 
10410b4b5d1SIngo Weinhold 
10510b4b5d1SIngo Weinhold struct RuntimeLoaderAddOn
10610b4b5d1SIngo Weinhold 		: public DoublyLinkedListLinkImpl<RuntimeLoaderAddOn> {
10710b4b5d1SIngo Weinhold 	image_t*				image;
10810b4b5d1SIngo Weinhold 	runtime_loader_add_on*	addOn;
10910b4b5d1SIngo Weinhold 
11010b4b5d1SIngo Weinhold 	RuntimeLoaderAddOn(image_t* image, runtime_loader_add_on* addOn)
11110b4b5d1SIngo Weinhold 		:
11210b4b5d1SIngo Weinhold 		image(image),
11310b4b5d1SIngo Weinhold 		addOn(addOn)
11410b4b5d1SIngo Weinhold 	{
11510b4b5d1SIngo Weinhold 	}
11610b4b5d1SIngo Weinhold };
11710b4b5d1SIngo Weinhold 
11810b4b5d1SIngo Weinhold typedef DoublyLinkedList<RuntimeLoaderAddOn> AddOnList;
11910b4b5d1SIngo Weinhold 
12010b4b5d1SIngo Weinhold struct RuntimeLoaderSymbolPatcher {
12110b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher*		next;
12210b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher*	patcher;
12310b4b5d1SIngo Weinhold 	void*							cookie;
12410b4b5d1SIngo Weinhold 
12510b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher(runtime_loader_symbol_patcher* patcher,
12610b4b5d1SIngo Weinhold 			void* cookie)
12710b4b5d1SIngo Weinhold 		:
12810b4b5d1SIngo Weinhold 		patcher(patcher),
12910b4b5d1SIngo Weinhold 		cookie(cookie)
13010b4b5d1SIngo Weinhold 	{
13110b4b5d1SIngo Weinhold 	}
13210b4b5d1SIngo Weinhold };
13310b4b5d1SIngo Weinhold 
13410b4b5d1SIngo Weinhold 
135*003ebb0eSIngo Weinhold struct SymbolLookupInfo {
136*003ebb0eSIngo Weinhold 	const char*				name;
137*003ebb0eSIngo Weinhold 	int32					type;
138*003ebb0eSIngo Weinhold 	uint32					hash;
139*003ebb0eSIngo Weinhold 	uint32					flags;
140*003ebb0eSIngo Weinhold 	const elf_version_info*	version;
141*003ebb0eSIngo Weinhold 
142*003ebb0eSIngo Weinhold 	SymbolLookupInfo(const char* name, int32 type, uint32 hash,
143*003ebb0eSIngo Weinhold 		const elf_version_info* version = NULL, uint32 flags = 0)
144*003ebb0eSIngo Weinhold 		:
145*003ebb0eSIngo Weinhold 		name(name),
146*003ebb0eSIngo Weinhold 		type(type),
147*003ebb0eSIngo Weinhold 		hash(hash),
148*003ebb0eSIngo Weinhold 		flags(flags),
149*003ebb0eSIngo Weinhold 		version(version)
150*003ebb0eSIngo Weinhold 	{
151*003ebb0eSIngo Weinhold 	}
152*003ebb0eSIngo Weinhold 
153*003ebb0eSIngo Weinhold 	SymbolLookupInfo(const char* name, int32 type,
154*003ebb0eSIngo Weinhold 		const elf_version_info* version = NULL, uint32 flags = 0)
155*003ebb0eSIngo Weinhold 		:
156*003ebb0eSIngo Weinhold 		name(name),
157*003ebb0eSIngo Weinhold 		type(type),
158*003ebb0eSIngo Weinhold 		hash(elf_hash((const uint8*)name)),
159*003ebb0eSIngo Weinhold 		flags(flags),
160*003ebb0eSIngo Weinhold 		version(version)
161*003ebb0eSIngo Weinhold 	{
162*003ebb0eSIngo Weinhold 	}
163*003ebb0eSIngo Weinhold };
164*003ebb0eSIngo Weinhold 
165*003ebb0eSIngo Weinhold 
166*003ebb0eSIngo Weinhold // values for SymbolLookupInfo::flags
167*003ebb0eSIngo Weinhold #define LOOKUP_FLAG_DEFAULT_VERSION	0x01
168*003ebb0eSIngo Weinhold 
169*003ebb0eSIngo Weinhold 
1700c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0};
1710c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0};
1720c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0;
1730c0fea5dSIngo Weinhold static image_t *sProgramImage;
17474c0424aSAxel Dörfler static KMessage sErrorMessage;
1755d0638bfSIngo Weinhold static bool sProgramLoaded = false;
17661b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL;
1779a6072a3SAxel Dörfler static bool sInvalidImageIDs;
178ca618b22SIngo Weinhold static image_t **sPreloadedImages = NULL;
179ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0;
18010b4b5d1SIngo Weinhold static AddOnList sAddOns;
1810c0fea5dSIngo Weinhold 
1820c0fea5dSIngo Weinhold // a recursive lock
183e73923b0SAxel Dörfler static sem_id sSem;
184e73923b0SAxel Dörfler static thread_id sSemOwner;
185e73923b0SAxel Dörfler static int32 sSemCount;
1860c0fea5dSIngo Weinhold 
18710b4b5d1SIngo Weinhold extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport;
18810b4b5d1SIngo Weinhold 
1890c0fea5dSIngo Weinhold 
1900c0fea5dSIngo Weinhold void
1910c0fea5dSIngo Weinhold dprintf(const char *format, ...)
1920c0fea5dSIngo Weinhold {
1930c0fea5dSIngo Weinhold 	char buffer[1024];
1940c0fea5dSIngo Weinhold 
1950c0fea5dSIngo Weinhold 	va_list list;
1960c0fea5dSIngo Weinhold 	va_start(list, format);
1970c0fea5dSIngo Weinhold 
1980c0fea5dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1990c0fea5dSIngo Weinhold 	_kern_debug_output(buffer);
2000c0fea5dSIngo Weinhold 
2010c0fea5dSIngo Weinhold 	va_end(list);
2020c0fea5dSIngo Weinhold }
2035d0638bfSIngo Weinhold 
2045d0638bfSIngo Weinhold #define FATAL(x...)							\
2055d0638bfSIngo Weinhold 	do {									\
2065d0638bfSIngo Weinhold 		dprintf("runtime_loader: " x);		\
2075d0638bfSIngo Weinhold 		if (!sProgramLoaded)				\
2085d0638bfSIngo Weinhold 			printf("runtime_loader: " x);	\
2095d0638bfSIngo Weinhold 	} while (false)
2100c0fea5dSIngo Weinhold 
2110c0fea5dSIngo Weinhold 
21234982809SIngo Weinhold /*!	Mini atoi(), so we don't have to include the libroot dependencies.
21334982809SIngo Weinhold  */
21434982809SIngo Weinhold int
21534982809SIngo Weinhold atoi(const char* num)
21634982809SIngo Weinhold {
21734982809SIngo Weinhold 	int result = 0;
21834982809SIngo Weinhold 	while (*num >= '0' && *num <= '9') {
21934982809SIngo Weinhold 		result = (result * 10) + (*num - '0');
22034982809SIngo Weinhold 		num++;
22134982809SIngo Weinhold 	}
22234982809SIngo Weinhold 
22334982809SIngo Weinhold 	return result;
22434982809SIngo Weinhold }
22534982809SIngo Weinhold 
22634982809SIngo Weinhold 
2276bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING
2287486b72dSIngo Weinhold 
2297486b72dSIngo Weinhold void
2307486b72dSIngo Weinhold ktrace_printf(const char *format, ...)
2317486b72dSIngo Weinhold {
2327486b72dSIngo Weinhold 	va_list list;
2337486b72dSIngo Weinhold 	va_start(list, format);
2347486b72dSIngo Weinhold 
2357486b72dSIngo Weinhold 	char buffer[1024];
2367486b72dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
2377486b72dSIngo Weinhold 	_kern_ktrace_output(buffer);
2387486b72dSIngo Weinhold 
2397486b72dSIngo Weinhold 	va_end(list);
2407486b72dSIngo Weinhold }
2417486b72dSIngo Weinhold 
2427486b72dSIngo Weinhold #define KTRACE(x...)	ktrace_printf(x)
2437486b72dSIngo Weinhold 
2447486b72dSIngo Weinhold #else
2457486b72dSIngo Weinhold #	define KTRACE(x...)
2467486b72dSIngo Weinhold #endif	// RUNTIME_LOADER_TRACING
2477486b72dSIngo Weinhold 
2487486b72dSIngo Weinhold 
2490c0fea5dSIngo Weinhold static void
2500c0fea5dSIngo Weinhold rld_unlock()
2510c0fea5dSIngo Weinhold {
252e73923b0SAxel Dörfler 	if (sSemCount-- == 1) {
253e73923b0SAxel Dörfler 		sSemOwner = -1;
254e73923b0SAxel Dörfler 		release_sem(sSem);
2550c0fea5dSIngo Weinhold 	}
2560c0fea5dSIngo Weinhold }
2570c0fea5dSIngo Weinhold 
2580c0fea5dSIngo Weinhold 
2590c0fea5dSIngo Weinhold static void
2600c0fea5dSIngo Weinhold rld_lock()
2610c0fea5dSIngo Weinhold {
2620c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
263e73923b0SAxel Dörfler 	if (self != sSemOwner) {
264e73923b0SAxel Dörfler 		acquire_sem(sSem);
265e73923b0SAxel Dörfler 		sSemOwner = self;
2660c0fea5dSIngo Weinhold 	}
267e73923b0SAxel Dörfler 	sSemCount++;
2680c0fea5dSIngo Weinhold }
2690c0fea5dSIngo Weinhold 
2700c0fea5dSIngo Weinhold 
2710c0fea5dSIngo Weinhold static void
2720c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image)
2730c0fea5dSIngo Weinhold {
2740c0fea5dSIngo Weinhold 	image->next = 0;
2750c0fea5dSIngo Weinhold 
2760c0fea5dSIngo Weinhold 	image->prev = queue->tail;
2770c0fea5dSIngo Weinhold 	if (queue->tail)
2780c0fea5dSIngo Weinhold 		queue->tail->next = image;
2790c0fea5dSIngo Weinhold 
2800c0fea5dSIngo Weinhold 	queue->tail = image;
2810c0fea5dSIngo Weinhold 	if (!queue->head)
2820c0fea5dSIngo Weinhold 		queue->head = image;
2830c0fea5dSIngo Weinhold }
2840c0fea5dSIngo Weinhold 
2850c0fea5dSIngo Weinhold 
2860c0fea5dSIngo Weinhold static void
2870c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image)
2880c0fea5dSIngo Weinhold {
2890c0fea5dSIngo Weinhold 	if (image->next)
2900c0fea5dSIngo Weinhold 		image->next->prev = image->prev;
2910c0fea5dSIngo Weinhold 	else
2920c0fea5dSIngo Weinhold 		queue->tail = image->prev;
2930c0fea5dSIngo Weinhold 
2940c0fea5dSIngo Weinhold 	if (image->prev)
2950c0fea5dSIngo Weinhold 		image->prev->next = image->next;
2960c0fea5dSIngo Weinhold 	else
2970c0fea5dSIngo Weinhold 		queue->head = image->next;
2980c0fea5dSIngo Weinhold 
2990c0fea5dSIngo Weinhold 	image->prev = 0;
3000c0fea5dSIngo Weinhold 	image->next = 0;
3010c0fea5dSIngo Weinhold }
3020c0fea5dSIngo Weinhold 
3030c0fea5dSIngo Weinhold 
3040c0fea5dSIngo Weinhold static uint32
3050c0fea5dSIngo Weinhold elf_hash(const uint8 *name)
3060c0fea5dSIngo Weinhold {
3070c0fea5dSIngo Weinhold 	uint32 hash = 0;
3080c0fea5dSIngo Weinhold 	uint32 temp;
3090c0fea5dSIngo Weinhold 
3100c0fea5dSIngo Weinhold 	while (*name) {
3110c0fea5dSIngo Weinhold 		hash = (hash << 4) + *name++;
3120c0fea5dSIngo Weinhold 		if ((temp = hash & 0xf0000000)) {
3130c0fea5dSIngo Weinhold 			hash ^= temp >> 24;
3140c0fea5dSIngo Weinhold 		}
3150c0fea5dSIngo Weinhold 		hash &= ~temp;
3160c0fea5dSIngo Weinhold 	}
3170c0fea5dSIngo Weinhold 	return hash;
3180c0fea5dSIngo Weinhold }
3190c0fea5dSIngo Weinhold 
3200c0fea5dSIngo Weinhold 
3214bef3723SAxel Dörfler static inline bool
3224bef3723SAxel Dörfler report_errors()
3234bef3723SAxel Dörfler {
3244bef3723SAxel Dörfler 	return gProgramArgs->error_port >= 0;
3254bef3723SAxel Dörfler }
3264bef3723SAxel Dörfler 
3274bef3723SAxel Dörfler 
3289a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork.
3299a6072a3SAxel Dörfler static status_t
3309a6072a3SAxel Dörfler update_image_id(image_t *image)
3319a6072a3SAxel Dörfler {
3329a6072a3SAxel Dörfler 	int32 cookie = 0;
3339a6072a3SAxel Dörfler 	image_info info;
3349a6072a3SAxel Dörfler 	while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info,
3359a6072a3SAxel Dörfler 			sizeof(image_info)) == B_OK) {
3369a6072a3SAxel Dörfler 		for (uint32 i = 0; i < image->num_regions; i++) {
3379a6072a3SAxel Dörfler 			if (image->regions[i].vmstart == (addr_t)info.text) {
3389a6072a3SAxel Dörfler 				image->id = info.id;
3399a6072a3SAxel Dörfler 				return B_OK;
3409a6072a3SAxel Dörfler 			}
3419a6072a3SAxel Dörfler 		}
3429a6072a3SAxel Dörfler 	}
3439a6072a3SAxel Dörfler 
3449a6072a3SAxel Dörfler 	FATAL("Could not update image ID %ld after fork()!\n", image->id);
3459a6072a3SAxel Dörfler 	return B_ENTRY_NOT_FOUND;
3469a6072a3SAxel Dörfler }
3479a6072a3SAxel Dörfler 
3489a6072a3SAxel Dörfler 
3499a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images.
3509a6072a3SAxel Dörfler static status_t
3519a6072a3SAxel Dörfler update_image_ids(void)
3529a6072a3SAxel Dörfler {
3539a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
3549a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
3559a6072a3SAxel Dörfler 		if (status != B_OK)
3569a6072a3SAxel Dörfler 			return status;
3579a6072a3SAxel Dörfler 	}
3589a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
3599a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
3609a6072a3SAxel Dörfler 		if (status != B_OK)
3619a6072a3SAxel Dörfler 			return status;
3629a6072a3SAxel Dörfler 	}
3639a6072a3SAxel Dörfler 
3649a6072a3SAxel Dörfler 	sInvalidImageIDs = false;
3659a6072a3SAxel Dörfler 	return B_OK;
3669a6072a3SAxel Dörfler }
3679a6072a3SAxel Dörfler 
3689a6072a3SAxel Dörfler 
3690c0fea5dSIngo Weinhold static image_t *
3700c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath,
3710c0fea5dSIngo Weinhold 	uint32 typeMask)
3720c0fea5dSIngo Weinhold {
3739a6072a3SAxel Dörfler 	for (image_t *image = queue->head; image; image = image->next) {
3740c0fea5dSIngo Weinhold 		const char *imageName = isPath ? image->path : image->name;
3750c0fea5dSIngo Weinhold 		int length = isPath ? sizeof(image->path) : sizeof(image->name);
3760c0fea5dSIngo Weinhold 
3770c0fea5dSIngo Weinhold 		if (!strncmp(imageName, name, length)
3780c0fea5dSIngo Weinhold 			&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
3790c0fea5dSIngo Weinhold 			return image;
3800c0fea5dSIngo Weinhold 		}
3810c0fea5dSIngo Weinhold 	}
3820c0fea5dSIngo Weinhold 
3830c0fea5dSIngo Weinhold 	return NULL;
3840c0fea5dSIngo Weinhold }
3850c0fea5dSIngo Weinhold 
3860c0fea5dSIngo Weinhold 
3870c0fea5dSIngo Weinhold static image_t *
3880c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask)
3890c0fea5dSIngo Weinhold {
3909a6072a3SAxel Dörfler 	bool isPath = strchr(name, '/') != NULL;
39146f4d849SIngo Weinhold 	return find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
3920c0fea5dSIngo Weinhold }
3930c0fea5dSIngo Weinhold 
3940c0fea5dSIngo Weinhold 
3950c0fea5dSIngo Weinhold static image_t *
3960c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id)
3970c0fea5dSIngo Weinhold {
3989a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
3999a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
4009a6072a3SAxel Dörfler 		update_image_ids();
4019a6072a3SAxel Dörfler 	}
4020c0fea5dSIngo Weinhold 
4039a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
4040c0fea5dSIngo Weinhold 		if (image->id == id)
4050c0fea5dSIngo Weinhold 			return image;
4060c0fea5dSIngo Weinhold 	}
4070c0fea5dSIngo Weinhold 
4080c0fea5dSIngo Weinhold 	// For the termination routine, we need to look into the list of
4090c0fea5dSIngo Weinhold 	// disposable images as well
4109a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
4110c0fea5dSIngo Weinhold 		if (image->id == id)
4120c0fea5dSIngo Weinhold 			return image;
4130c0fea5dSIngo Weinhold 	}
4140c0fea5dSIngo Weinhold 
4150c0fea5dSIngo Weinhold 	return NULL;
4160c0fea5dSIngo Weinhold }
4170c0fea5dSIngo Weinhold 
4180c0fea5dSIngo Weinhold 
4195fd6637bSIngo Weinhold static image_t*
4205fd6637bSIngo Weinhold get_program_image()
42112a5e9a4SAxel Dörfler {
42212a5e9a4SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
42312a5e9a4SAxel Dörfler 		if (image->type == B_APP_IMAGE)
4245fd6637bSIngo Weinhold 			return image;
42512a5e9a4SAxel Dörfler 	}
42612a5e9a4SAxel Dörfler 
42712a5e9a4SAxel Dörfler 	return NULL;
42812a5e9a4SAxel Dörfler }
42912a5e9a4SAxel Dörfler 
43012a5e9a4SAxel Dörfler 
4315fd6637bSIngo Weinhold static const char *
4325fd6637bSIngo Weinhold get_program_path()
4335fd6637bSIngo Weinhold {
4345fd6637bSIngo Weinhold 	if (image_t* image = get_program_image())
4355fd6637bSIngo Weinhold 		return image->path;
4365fd6637bSIngo Weinhold 
4375fd6637bSIngo Weinhold 	return NULL;
4385fd6637bSIngo Weinhold }
4395fd6637bSIngo Weinhold 
4405fd6637bSIngo Weinhold 
4410c0fea5dSIngo Weinhold static status_t
44212a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize,
44312a5e9a4SAxel Dörfler 	int32 *_sheaderSize)
4440c0fea5dSIngo Weinhold {
4450c0fea5dSIngo Weinhold 	if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
4460c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4470c0fea5dSIngo Weinhold 
4480c0fea5dSIngo Weinhold 	if (eheader->e_ident[4] != ELFCLASS32)
4490c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4500c0fea5dSIngo Weinhold 
4510c0fea5dSIngo Weinhold 	if (eheader->e_phoff == 0)
4520c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4530c0fea5dSIngo Weinhold 
4540c0fea5dSIngo Weinhold 	if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
4550c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4560c0fea5dSIngo Weinhold 
4570c0fea5dSIngo Weinhold 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
4580c0fea5dSIngo Weinhold 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
4590c0fea5dSIngo Weinhold 
4605aa7b7b6SMarcus Overhagen 	if (*_pheaderSize <= 0 || *_sheaderSize <= 0)
4615aa7b7b6SMarcus Overhagen 		return B_NOT_AN_EXECUTABLE;
4625aa7b7b6SMarcus Overhagen 
4635aa7b7b6SMarcus Overhagen 	return B_OK;
4640c0fea5dSIngo Weinhold }
4650c0fea5dSIngo Weinhold 
4660c0fea5dSIngo Weinhold 
4670c0fea5dSIngo Weinhold static int32
4680c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize)
4690c0fea5dSIngo Weinhold {
4700c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheaders;
4710c0fea5dSIngo Weinhold 	int32 count = 0;
4720c0fea5dSIngo Weinhold 	int i;
4730c0fea5dSIngo Weinhold 
4740c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
4750c0fea5dSIngo Weinhold 		pheaders = (struct Elf32_Phdr *)(buff + i * phentsize);
4760c0fea5dSIngo Weinhold 
4770c0fea5dSIngo Weinhold 		switch (pheaders->p_type) {
4780c0fea5dSIngo Weinhold 			case PT_NULL:
4790c0fea5dSIngo Weinhold 				/* NOP header */
4800c0fea5dSIngo Weinhold 				break;
4810c0fea5dSIngo Weinhold 			case PT_LOAD:
4820c0fea5dSIngo Weinhold 				count += 1;
4830c0fea5dSIngo Weinhold 				if (pheaders->p_memsz != pheaders->p_filesz) {
4840c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz);
4850c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz);
4860c0fea5dSIngo Weinhold 
4870c0fea5dSIngo Weinhold 					if (A != B)
4880c0fea5dSIngo Weinhold 						count += 1;
4890c0fea5dSIngo Weinhold 				}
4900c0fea5dSIngo Weinhold 				break;
4910c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
4920c0fea5dSIngo Weinhold 				/* will be handled at some other place */
4930c0fea5dSIngo Weinhold 				break;
4940c0fea5dSIngo Weinhold 			case PT_INTERP:
4950c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
4960c0fea5dSIngo Weinhold 				break;
4970c0fea5dSIngo Weinhold 			case PT_NOTE:
4980c0fea5dSIngo Weinhold 				/* unsupported */
4990c0fea5dSIngo Weinhold 				break;
5000c0fea5dSIngo Weinhold 			case PT_SHLIB:
5010c0fea5dSIngo Weinhold 				/* undefined semantics */
5020c0fea5dSIngo Weinhold 				break;
5030c0fea5dSIngo Weinhold 			case PT_PHDR:
5040c0fea5dSIngo Weinhold 				/* we don't use it */
5050c0fea5dSIngo Weinhold 				break;
5062ecebae1SDavid McPaul 			case PT_STACK:
5072ecebae1SDavid McPaul 				/* we don't use it */
5082ecebae1SDavid McPaul 				break;
5090c0fea5dSIngo Weinhold 			default:
5102ecebae1SDavid McPaul 				FATAL("unhandled pheader type in count 0x%lx\n", pheaders->p_type);
5110c0fea5dSIngo Weinhold 				return B_BAD_DATA;
5120c0fea5dSIngo Weinhold 		}
5130c0fea5dSIngo Weinhold 	}
5140c0fea5dSIngo Weinhold 
5150c0fea5dSIngo Weinhold 	return count;
5160c0fea5dSIngo Weinhold }
5170c0fea5dSIngo Weinhold 
5180c0fea5dSIngo Weinhold 
5190c0fea5dSIngo Weinhold static image_t *
5200c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions)
5210c0fea5dSIngo Weinhold {
5220c0fea5dSIngo Weinhold 	size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t);
5230c0fea5dSIngo Weinhold 	const char *lastSlash;
5240c0fea5dSIngo Weinhold 
5250c0fea5dSIngo Weinhold 	image_t *image = (image_t*)malloc(allocSize);
5260c0fea5dSIngo Weinhold 	if (image == NULL) {
5270c0fea5dSIngo Weinhold 		FATAL("no memory for image %s\n", path);
5280c0fea5dSIngo Weinhold 		return NULL;
5290c0fea5dSIngo Weinhold 	}
5300c0fea5dSIngo Weinhold 
5310c0fea5dSIngo Weinhold 	memset(image, 0, allocSize);
5320c0fea5dSIngo Weinhold 
5330c0fea5dSIngo Weinhold 	strlcpy(image->path, path, sizeof(image->path));
5340c0fea5dSIngo Weinhold 
5350c0fea5dSIngo Weinhold 	// Make the last component of the supplied name the image name.
5360c0fea5dSIngo Weinhold 	// If present, DT_SONAME will replace this name.
5370c0fea5dSIngo Weinhold 	if ((lastSlash = strrchr(name, '/')))
5380c0fea5dSIngo Weinhold 		strlcpy(image->name, lastSlash + 1, sizeof(image->name));
5390c0fea5dSIngo Weinhold 	else
5400c0fea5dSIngo Weinhold 		strlcpy(image->name, name, sizeof(image->name));
5410c0fea5dSIngo Weinhold 
5420c0fea5dSIngo Weinhold 	image->ref_count = 1;
5430c0fea5dSIngo Weinhold 	image->num_regions = num_regions;
5440c0fea5dSIngo Weinhold 
5450c0fea5dSIngo Weinhold 	return image;
5460c0fea5dSIngo Weinhold }
5470c0fea5dSIngo Weinhold 
5480c0fea5dSIngo Weinhold 
5490c0fea5dSIngo Weinhold static void
5500c0fea5dSIngo Weinhold delete_image_struct(image_t *image)
5510c0fea5dSIngo Weinhold {
5520c0fea5dSIngo Weinhold #ifdef DEBUG
5530c0fea5dSIngo Weinhold 	size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t);
5540c0fea5dSIngo Weinhold 	memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
5550c0fea5dSIngo Weinhold #endif
5560c0fea5dSIngo Weinhold 	free(image->needed);
557*003ebb0eSIngo Weinhold 	free(image->versions);
55810b4b5d1SIngo Weinhold 
55910b4b5d1SIngo Weinhold 	while (RuntimeLoaderSymbolPatcher* patcher
56010b4b5d1SIngo Weinhold 			= image->defined_symbol_patchers) {
56110b4b5d1SIngo Weinhold 		image->defined_symbol_patchers = patcher->next;
56210b4b5d1SIngo Weinhold 		delete patcher;
56310b4b5d1SIngo Weinhold 	}
56410b4b5d1SIngo Weinhold 	while (RuntimeLoaderSymbolPatcher* patcher
56510b4b5d1SIngo Weinhold 			= image->undefined_symbol_patchers) {
56610b4b5d1SIngo Weinhold 		image->undefined_symbol_patchers = patcher->next;
56710b4b5d1SIngo Weinhold 		delete patcher;
56810b4b5d1SIngo Weinhold 	}
5690c0fea5dSIngo Weinhold 
5700c0fea5dSIngo Weinhold #ifdef DEBUG
5719a6072a3SAxel Dörfler 	// overwrite images to make sure they aren't accidently reused anywhere
5720c0fea5dSIngo Weinhold 	memset(image, 0xa5, size);
5730c0fea5dSIngo Weinhold #endif
5740c0fea5dSIngo Weinhold 	free(image);
5750c0fea5dSIngo Weinhold }
5760c0fea5dSIngo Weinhold 
5770c0fea5dSIngo Weinhold 
5780c0fea5dSIngo Weinhold static void
5790c0fea5dSIngo Weinhold delete_image(image_t *image)
5800c0fea5dSIngo Weinhold {
5812760c4cdSAxel Dörfler 	if (image == NULL)
5822760c4cdSAxel Dörfler 		return;
5832760c4cdSAxel Dörfler 
5840c0fea5dSIngo Weinhold 	_kern_unregister_image(image->id);
5850c0fea5dSIngo Weinhold 		// registered in load_container()
5860c0fea5dSIngo Weinhold 
5870c0fea5dSIngo Weinhold 	delete_image_struct(image);
5880c0fea5dSIngo Weinhold }
5890c0fea5dSIngo Weinhold 
5900c0fea5dSIngo Weinhold 
5910c85bd05SIngo Weinhold static void
5920c85bd05SIngo Weinhold update_image_flags_recursively(image_t* image, uint32 flagsToSet,
5930c85bd05SIngo Weinhold 	uint32 flagsToClear)
5940c85bd05SIngo Weinhold {
5950c85bd05SIngo Weinhold 	image_t* queue[sLoadedImageCount];
5960c85bd05SIngo Weinhold 	uint32 count = 0;
5970c85bd05SIngo Weinhold 	uint32 index = 0;
5980c85bd05SIngo Weinhold 	queue[count++] = image;
5990c85bd05SIngo Weinhold 	image->flags |= RFLAG_VISITED;
6000c85bd05SIngo Weinhold 
6010c85bd05SIngo Weinhold 	while (index < count) {
6020c85bd05SIngo Weinhold 		// pop next image
6030c85bd05SIngo Weinhold 		image = queue[index++];
6040c85bd05SIngo Weinhold 
6050c85bd05SIngo Weinhold 		// push dependencies
6060c85bd05SIngo Weinhold 		for (uint32 i = 0; i < image->num_needed; i++) {
6070c85bd05SIngo Weinhold 			image_t* needed = image->needed[i];
6080c85bd05SIngo Weinhold 			if ((needed->flags & RFLAG_VISITED) == 0) {
6090c85bd05SIngo Weinhold 				queue[count++] = needed;
6100c85bd05SIngo Weinhold 				needed->flags |= RFLAG_VISITED;
6110c85bd05SIngo Weinhold 			}
6120c85bd05SIngo Weinhold 		}
6130c85bd05SIngo Weinhold 	}
6140c85bd05SIngo Weinhold 
6150c85bd05SIngo Weinhold 	// update flags
6160c85bd05SIngo Weinhold 	for (uint32 i = 0; i < count; i++) {
6170c85bd05SIngo Weinhold 		queue[i]->flags = (queue[i]->flags | flagsToSet)
6180c85bd05SIngo Weinhold 			& ~(flagsToClear | RFLAG_VISITED);
6190c85bd05SIngo Weinhold 	}
6200c85bd05SIngo Weinhold }
6210c85bd05SIngo Weinhold 
6220c85bd05SIngo Weinhold 
6230c85bd05SIngo Weinhold static void
6240c85bd05SIngo Weinhold set_image_flags_recursively(image_t* image, uint32 flags)
6250c85bd05SIngo Weinhold {
6260c85bd05SIngo Weinhold 	update_image_flags_recursively(image, flags, 0);
6270c85bd05SIngo Weinhold }
6280c85bd05SIngo Weinhold 
6290c85bd05SIngo Weinhold 
6300c85bd05SIngo Weinhold static void
6310c85bd05SIngo Weinhold clear_image_flags_recursively(image_t* image, uint32 flags)
6320c85bd05SIngo Weinhold {
6330c85bd05SIngo Weinhold 	update_image_flags_recursively(image, 0, flags);
6340c85bd05SIngo Weinhold }
6350c85bd05SIngo Weinhold 
6360c85bd05SIngo Weinhold 
6370c0fea5dSIngo Weinhold static status_t
6380c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
6390c0fea5dSIngo Weinhold {
6400c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheader;
6410c0fea5dSIngo Weinhold 	int regcount;
6420c0fea5dSIngo Weinhold 	int i;
6430c0fea5dSIngo Weinhold 
6440c0fea5dSIngo Weinhold 	regcount = 0;
6450c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
6460c0fea5dSIngo Weinhold 		pheader = (struct Elf32_Phdr *)(buff + i * phentsize);
6470c0fea5dSIngo Weinhold 
6480c0fea5dSIngo Weinhold 		switch (pheader->p_type) {
6490c0fea5dSIngo Weinhold 			case PT_NULL:
6500c0fea5dSIngo Weinhold 				/* NOP header */
6510c0fea5dSIngo Weinhold 				break;
6520c0fea5dSIngo Weinhold 			case PT_LOAD:
6530c0fea5dSIngo Weinhold 				if (pheader->p_memsz == pheader->p_filesz) {
6540c0fea5dSIngo Weinhold 					/*
6550c0fea5dSIngo Weinhold 					 * everything in one area
6560c0fea5dSIngo Weinhold 					 */
6570c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
6580c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_memsz;
6590c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
6600c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz
6610c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
6620c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
6630c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
6640c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
6650c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
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 				} else {
6710c0fea5dSIngo Weinhold 					/*
6720c0fea5dSIngo Weinhold 					 * may require splitting
6730c0fea5dSIngo Weinhold 					 */
6740c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz);
6750c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz);
6760c0fea5dSIngo Weinhold 
6770c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
6780c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_filesz;
6790c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
6800c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz
6810c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
6820c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
6830c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
6840c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
6850c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
6860c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
6870c0fea5dSIngo Weinhold 						// this is a writable segment
6880c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
6890c0fea5dSIngo Weinhold 					}
6900c0fea5dSIngo Weinhold 
6910c0fea5dSIngo Weinhold 					if (A != B) {
6920c0fea5dSIngo Weinhold 						/*
6930c0fea5dSIngo Weinhold 						 * yeah, it requires splitting
6940c0fea5dSIngo Weinhold 						 */
6950c0fea5dSIngo Weinhold 						regcount += 1;
6960c0fea5dSIngo Weinhold 						image->regions[regcount].start = pheader->p_vaddr;
6970c0fea5dSIngo Weinhold 						image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz;
6980c0fea5dSIngo Weinhold 						image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
6990c0fea5dSIngo Weinhold 						image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr))
7000c0fea5dSIngo Weinhold 							- image->regions[regcount-1].vmsize;
7010c0fea5dSIngo Weinhold 						image->regions[regcount].fdstart = 0;
7020c0fea5dSIngo Weinhold 						image->regions[regcount].fdsize = 0;
7030c0fea5dSIngo Weinhold 						image->regions[regcount].delta = 0;
7040c0fea5dSIngo Weinhold 						image->regions[regcount].flags = RFLAG_ANON;
7050c0fea5dSIngo Weinhold 						if (pheader->p_flags & PF_WRITE) {
7060c0fea5dSIngo Weinhold 							// this is a writable segment
7070c0fea5dSIngo Weinhold 							image->regions[regcount].flags |= RFLAG_RW;
7080c0fea5dSIngo Weinhold 						}
7090c0fea5dSIngo Weinhold 					}
7100c0fea5dSIngo Weinhold 				}
7110c0fea5dSIngo Weinhold 				regcount += 1;
7120c0fea5dSIngo Weinhold 				break;
7130c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
7140c0fea5dSIngo Weinhold 				image->dynamic_ptr = pheader->p_vaddr;
7150c0fea5dSIngo Weinhold 				break;
7160c0fea5dSIngo Weinhold 			case PT_INTERP:
7170c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
7180c0fea5dSIngo Weinhold 				break;
7190c0fea5dSIngo Weinhold 			case PT_NOTE:
7200c0fea5dSIngo Weinhold 				/* unsupported */
7210c0fea5dSIngo Weinhold 				break;
7220c0fea5dSIngo Weinhold 			case PT_SHLIB:
7230c0fea5dSIngo Weinhold 				/* undefined semantics */
7240c0fea5dSIngo Weinhold 				break;
7250c0fea5dSIngo Weinhold 			case PT_PHDR:
7260c0fea5dSIngo Weinhold 				/* we don't use it */
7270c0fea5dSIngo Weinhold 				break;
7282ecebae1SDavid McPaul 			case PT_STACK:
7292ecebae1SDavid McPaul 				/* we don't use it */
7302ecebae1SDavid McPaul 				break;
7310c0fea5dSIngo Weinhold 			default:
7322ecebae1SDavid McPaul 				FATAL("unhandled pheader type in parse 0x%lx\n", pheader->p_type);
7330c0fea5dSIngo Weinhold 				return B_BAD_DATA;
7340c0fea5dSIngo Weinhold 		}
7350c0fea5dSIngo Weinhold 	}
7360c0fea5dSIngo Weinhold 
7370c0fea5dSIngo Weinhold 	return B_OK;
7380c0fea5dSIngo Weinhold }
7390c0fea5dSIngo Weinhold 
7400c0fea5dSIngo Weinhold 
741593ee7bbSIngo Weinhold static void
742593ee7bbSIngo Weinhold analyze_image_haiku_version_and_abi(image_t* image)
743593ee7bbSIngo Weinhold {
744593ee7bbSIngo Weinhold 	// Haiku API version
745593ee7bbSIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol(image,
746*003ebb0eSIngo Weinhold 		SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME,
747*003ebb0eSIngo Weinhold 			B_SYMBOL_TYPE_DATA));
748593ee7bbSIngo Weinhold 	if (symbol != NULL && symbol->st_shndx != SHN_UNDEF
749593ee7bbSIngo Weinhold 		&& symbol->st_value > 0
750593ee7bbSIngo Weinhold 		&& ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT
751593ee7bbSIngo Weinhold 		&& symbol->st_size >= sizeof(uint32)) {
752593ee7bbSIngo Weinhold 		image->api_version
753593ee7bbSIngo Weinhold 			= *(uint32*)(symbol->st_value + image->regions[0].delta);
754593ee7bbSIngo Weinhold 	} else
755593ee7bbSIngo Weinhold 		image->api_version = 0;
756593ee7bbSIngo Weinhold 
757593ee7bbSIngo Weinhold 	// Haiku ABI
758*003ebb0eSIngo Weinhold 	symbol = find_symbol(image,
759*003ebb0eSIngo Weinhold 		SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME,
760*003ebb0eSIngo Weinhold 			B_SYMBOL_TYPE_DATA));
761593ee7bbSIngo Weinhold 	if (symbol != NULL && symbol->st_shndx != SHN_UNDEF
762593ee7bbSIngo Weinhold 		&& symbol->st_value > 0
763593ee7bbSIngo Weinhold 		&& ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT
764593ee7bbSIngo Weinhold 		&& symbol->st_size >= sizeof(uint32)) {
765593ee7bbSIngo Weinhold 		image->abi = *(uint32*)(symbol->st_value + image->regions[0].delta);
766593ee7bbSIngo Weinhold 	} else
767593ee7bbSIngo Weinhold 		image->abi = 0;
768593ee7bbSIngo Weinhold }
769593ee7bbSIngo Weinhold 
770593ee7bbSIngo Weinhold 
7710c0fea5dSIngo Weinhold static bool
77234982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader,
77334982809SIngo Weinhold 	int32 sheaderSize, char* buffer, size_t bufferSize)
77434982809SIngo Weinhold {
77534982809SIngo Weinhold 	if (sheaderSize > (int)bufferSize) {
77634982809SIngo Weinhold 		FATAL("Cannot handle section headers bigger than %lu\n", bufferSize);
77734982809SIngo Weinhold 		return false;
77834982809SIngo Weinhold 	}
77934982809SIngo Weinhold 
78034982809SIngo Weinhold 	// read section headers
78134982809SIngo Weinhold 	ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize);
78234982809SIngo Weinhold 	if (length != sheaderSize) {
78334982809SIngo Weinhold 		FATAL("Could not read section headers: %s\n", strerror(length));
78434982809SIngo Weinhold 		return false;
78534982809SIngo Weinhold 	}
78634982809SIngo Weinhold 
78734982809SIngo Weinhold 	// load the string section
78834982809SIngo Weinhold 	Elf32_Shdr* sectionHeader
78934982809SIngo Weinhold 		= (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize);
79034982809SIngo Weinhold 
79134982809SIngo Weinhold 	if (sheaderSize + sectionHeader->sh_size > bufferSize) {
79234982809SIngo Weinhold 		FATAL("Buffer not big enough for section string section\n");
79334982809SIngo Weinhold 		return false;
79434982809SIngo Weinhold 	}
79534982809SIngo Weinhold 
79634982809SIngo Weinhold 	char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size;
79734982809SIngo Weinhold 	length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings,
79834982809SIngo Weinhold 		sectionHeader->sh_size);
79934982809SIngo Weinhold 	if (length != (int)sectionHeader->sh_size) {
80034982809SIngo Weinhold 		FATAL("Could not read section string section: %s\n", strerror(length));
80134982809SIngo Weinhold 		return false;
80234982809SIngo Weinhold 	}
80334982809SIngo Weinhold 
80434982809SIngo Weinhold 	// find the .comment section
80534982809SIngo Weinhold 	off_t commentOffset = 0;
80634982809SIngo Weinhold 	size_t commentSize = 0;
80734982809SIngo Weinhold 	for (uint32 i = 0; i < eheader.e_shnum; i++) {
80834982809SIngo Weinhold 		sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize);
80934982809SIngo Weinhold 		const char* sectionName = sectionStrings + sectionHeader->sh_name;
81034982809SIngo Weinhold 		if (sectionHeader->sh_name != 0
81134982809SIngo Weinhold 			&& strcmp(sectionName, ".comment") == 0) {
81234982809SIngo Weinhold 			commentOffset = sectionHeader->sh_offset;
81334982809SIngo Weinhold 			commentSize = sectionHeader->sh_size;
81434982809SIngo Weinhold 			break;
81534982809SIngo Weinhold 		}
81634982809SIngo Weinhold 	}
81734982809SIngo Weinhold 
81834982809SIngo Weinhold 	if (commentSize == 0) {
81934982809SIngo Weinhold 		FATAL("Could not find .comment section\n");
82034982809SIngo Weinhold 		return false;
82134982809SIngo Weinhold 	}
82234982809SIngo Weinhold 
82334982809SIngo Weinhold 	// read a part of the comment section
82434982809SIngo Weinhold 	if (commentSize > 512)
82534982809SIngo Weinhold 		commentSize = 512;
82634982809SIngo Weinhold 
82734982809SIngo Weinhold 	length = _kern_read(fd, commentOffset, buffer, commentSize);
82834982809SIngo Weinhold 	if (length != (int)commentSize) {
82934982809SIngo Weinhold 		FATAL("Could not read .comment section: %s\n", strerror(length));
83034982809SIngo Weinhold 		return false;
83134982809SIngo Weinhold 	}
83234982809SIngo Weinhold 
83334982809SIngo Weinhold 	// the common prefix of the strings in the .comment section
83434982809SIngo Weinhold 	static const char* kGCCVersionPrefix = "GCC: (GNU) ";
83534982809SIngo Weinhold 	size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix);
83634982809SIngo Weinhold 
83734982809SIngo Weinhold 	size_t index = 0;
83834982809SIngo Weinhold 	int gccMajor = 0;
83934982809SIngo Weinhold 	int gccMiddle = 0;
84034982809SIngo Weinhold 	int gccMinor = 0;
8412716cfd3SAxel Dörfler 	bool isHaiku = true;
84234982809SIngo Weinhold 
84334982809SIngo Weinhold 	// Read up to 10 comments. The first three or four are usually from the
84434982809SIngo Weinhold 	// glue code.
84534982809SIngo Weinhold 	for (int i = 0; i < 10; i++) {
84634982809SIngo Weinhold 		// skip '\0'
84734982809SIngo Weinhold 		while (index < commentSize && buffer[index] == '\0')
84834982809SIngo Weinhold 			index++;
84934982809SIngo Weinhold 		char* stringStart = buffer + index;
85034982809SIngo Weinhold 
85134982809SIngo Weinhold 		// find string end
85234982809SIngo Weinhold 		while (index < commentSize && buffer[index] != '\0')
85334982809SIngo Weinhold 			index++;
85434982809SIngo Weinhold 
85534982809SIngo Weinhold 		// ignore the entry at the end of the buffer
85634982809SIngo Weinhold 		if (index == commentSize)
85734982809SIngo Weinhold 			break;
85834982809SIngo Weinhold 
85934982809SIngo Weinhold 		// We have to analyze string like these:
86034982809SIngo Weinhold 		// GCC: (GNU) 2.9-beos-991026
86134982809SIngo Weinhold 		// GCC: (GNU) 2.95.3-haiku-080322
86234982809SIngo Weinhold 		// GCC: (GNU) 4.1.2
86334982809SIngo Weinhold 
86434982809SIngo Weinhold 		// skip the common prefix
86534982809SIngo Weinhold 		if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0)
86634982809SIngo Weinhold 			continue;
86734982809SIngo Weinhold 
86834982809SIngo Weinhold 		// the rest is the GCC version
86934982809SIngo Weinhold 		char* gccVersion = stringStart + gccVersionPrefixLen;
87034982809SIngo Weinhold 		char* gccPlatform = strchr(gccVersion, '-');
87134982809SIngo Weinhold 		char* patchLevel = NULL;
87234982809SIngo Weinhold 		if (gccPlatform != NULL) {
87334982809SIngo Weinhold 			*gccPlatform = '\0';
87434982809SIngo Weinhold 			gccPlatform++;
87534982809SIngo Weinhold 			patchLevel = strchr(gccPlatform, '-');
87634982809SIngo Weinhold 			if (patchLevel != NULL) {
87734982809SIngo Weinhold 				*patchLevel = '\0';
87834982809SIngo Weinhold 				patchLevel++;
87934982809SIngo Weinhold 			}
88034982809SIngo Weinhold 		}
88134982809SIngo Weinhold 
88234982809SIngo Weinhold 		// split the gcc version into major, middle, and minor
88334982809SIngo Weinhold 		int version[3] = { 0, 0, 0 };
88434982809SIngo Weinhold 
88534982809SIngo Weinhold 		for (int k = 0; gccVersion != NULL && k < 3; k++) {
88634982809SIngo Weinhold 			char* dot = strchr(gccVersion, '.');
88734982809SIngo Weinhold 			if (dot) {
88834982809SIngo Weinhold 				*dot = '\0';
88934982809SIngo Weinhold 				dot++;
89034982809SIngo Weinhold 			}
89134982809SIngo Weinhold 			version[k] = atoi(gccVersion);
89234982809SIngo Weinhold 			gccVersion = dot;
89334982809SIngo Weinhold 		}
89434982809SIngo Weinhold 
89534982809SIngo Weinhold 		// got any version?
89634982809SIngo Weinhold 		if (version[0] == 0)
89734982809SIngo Weinhold 			continue;
89834982809SIngo Weinhold 
89934982809SIngo Weinhold 		// Select the gcc version with the smallest major, but the greatest
90034982809SIngo Weinhold 		// middle/minor. This should usually ignore the glue code version as
90134982809SIngo Weinhold 		// well as cases where e.g. in a gcc 2 program a single C file has
90234982809SIngo Weinhold 		// been compiled with gcc 4.
90334982809SIngo Weinhold 		if (gccMajor == 0 || gccMajor > version[0]
904593ee7bbSIngo Weinhold 		 	|| (gccMajor == version[0]
90534982809SIngo Weinhold 				&& (gccMiddle < version[1]
906593ee7bbSIngo Weinhold 					|| (gccMiddle == version[1] && gccMinor < version[2])))) {
90734982809SIngo Weinhold 			gccMajor = version[0];
90834982809SIngo Weinhold 			gccMiddle = version[1];
90934982809SIngo Weinhold 			gccMinor = version[2];
91034982809SIngo Weinhold 		}
9112716cfd3SAxel Dörfler 
912f91194e5SIngo Weinhold 		if (gccMajor == 2 && gccPlatform != NULL
913f91194e5SIngo Weinhold 			&& strcmp(gccPlatform, "haiku")) {
9142716cfd3SAxel Dörfler 			isHaiku = false;
91534982809SIngo Weinhold 		}
916f91194e5SIngo Weinhold 	}
91734982809SIngo Weinhold 
918f91194e5SIngo Weinhold 	if (gccMajor == 0)
919f91194e5SIngo Weinhold 		return false;
92034982809SIngo Weinhold 
921f91194e5SIngo Weinhold 	if (gccMajor == 2) {
922f91194e5SIngo Weinhold 		if (gccMiddle < 95)
923f91194e5SIngo Weinhold 			image->abi = B_HAIKU_ABI_GCC_2_ANCIENT;
924f91194e5SIngo Weinhold 		else if (isHaiku)
925f91194e5SIngo Weinhold 			image->abi = B_HAIKU_ABI_GCC_2_HAIKU;
926f91194e5SIngo Weinhold 		else
927f91194e5SIngo Weinhold 			image->abi = B_HAIKU_ABI_GCC_2_BEOS;
928f91194e5SIngo Weinhold 	} else
929f91194e5SIngo Weinhold 		image->abi = gccMajor << 16;
930f91194e5SIngo Weinhold 
931f91194e5SIngo Weinhold 	return true;
93234982809SIngo Weinhold }
93334982809SIngo Weinhold 
93434982809SIngo Weinhold 
93534982809SIngo Weinhold static bool
9360c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image)
9370c0fea5dSIngo Weinhold {
9380c0fea5dSIngo Weinhold 	uint32 i;
9390c0fea5dSIngo Weinhold 
9400c0fea5dSIngo Weinhold 	if (!image->dynamic_ptr)
9410c0fea5dSIngo Weinhold 		return true;
9420c0fea5dSIngo Weinhold 
9430c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
9440c0fea5dSIngo Weinhold 		if (image->dynamic_ptr >= image->regions[i].start
9450c0fea5dSIngo Weinhold 			&& image->dynamic_ptr < image->regions[i].start + image->regions[i].size)
9460c0fea5dSIngo Weinhold 			return true;
9470c0fea5dSIngo Weinhold 	}
9480c0fea5dSIngo Weinhold 
9490c0fea5dSIngo Weinhold 	return false;
9500c0fea5dSIngo Weinhold }
9510c0fea5dSIngo Weinhold 
9520c0fea5dSIngo Weinhold 
9530c0fea5dSIngo Weinhold /**	This function will change the protection of all read-only segments
9540c0fea5dSIngo Weinhold  *	to really be read-only.
9550c0fea5dSIngo Weinhold  *	The areas have to be read/write first, so that they can be relocated.
9560c0fea5dSIngo Weinhold  */
9570c0fea5dSIngo Weinhold 
9580c0fea5dSIngo Weinhold static void
9590c0fea5dSIngo Weinhold remap_images(void)
9600c0fea5dSIngo Weinhold {
9610c0fea5dSIngo Weinhold 	image_t *image;
9620c0fea5dSIngo Weinhold 	uint32 i;
9630c0fea5dSIngo Weinhold 
9640c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
9650c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_regions; i++) {
9660c0fea5dSIngo Weinhold 			if ((image->regions[i].flags & RFLAG_RW) == 0
9670c0fea5dSIngo Weinhold 				&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
9680c0fea5dSIngo Weinhold 				// we only need to do this once, so we remember those we've already mapped
9690c0fea5dSIngo Weinhold 				if (_kern_set_area_protection(image->regions[i].id,
9700c0fea5dSIngo Weinhold 						B_READ_AREA | B_EXECUTE_AREA) == B_OK)
9710c0fea5dSIngo Weinhold 					image->regions[i].flags |= RFLAG_REMAPPED;
9720c0fea5dSIngo Weinhold 			}
9730c0fea5dSIngo Weinhold 		}
9740c0fea5dSIngo Weinhold 	}
9750c0fea5dSIngo Weinhold }
9760c0fea5dSIngo Weinhold 
9770c0fea5dSIngo Weinhold 
9780c0fea5dSIngo Weinhold static status_t
9790c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed)
9800c0fea5dSIngo Weinhold {
9810c0fea5dSIngo Weinhold 	status_t status = B_OK;
9820c0fea5dSIngo Weinhold 	const char *baseName;
9830c0fea5dSIngo Weinhold 	uint32 i;
9840c0fea5dSIngo Weinhold 
9850c0fea5dSIngo Weinhold 	(void)(fd);
9860c0fea5dSIngo Weinhold 
9870c0fea5dSIngo Weinhold 	// cut the file name from the path as base name for the created areas
9880c0fea5dSIngo Weinhold 	baseName = strrchr(path, '/');
9890c0fea5dSIngo Weinhold 	if (baseName != NULL)
9900c0fea5dSIngo Weinhold 		baseName++;
9910c0fea5dSIngo Weinhold 	else
9920c0fea5dSIngo Weinhold 		baseName = path;
9930c0fea5dSIngo Weinhold 
9940c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
9950c0fea5dSIngo Weinhold 		char regionName[B_OS_NAME_LENGTH];
9960c0fea5dSIngo Weinhold 		addr_t loadAddress;
9970c0fea5dSIngo Weinhold 		uint32 addressSpecifier;
9980c0fea5dSIngo Weinhold 
9990c0fea5dSIngo Weinhold 		// for BeOS compatibility: if we load an old BeOS executable, we
10000c0fea5dSIngo Weinhold 		// have to relocate it, if possible - we recognize it because the
10010c0fea5dSIngo Weinhold 		// vmstart is set to 0 (hopefully always)
10020c0fea5dSIngo Weinhold 		if (fixed && image->regions[i].vmstart == 0)
10030c0fea5dSIngo Weinhold 			fixed = false;
10040c0fea5dSIngo Weinhold 
10050c0fea5dSIngo Weinhold 		snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
10060c0fea5dSIngo Weinhold 			baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
10070c0fea5dSIngo Weinhold 
10080c0fea5dSIngo Weinhold 		if (image->dynamic_ptr && !fixed) {
10090c0fea5dSIngo Weinhold 			// relocatable image... we can afford to place wherever
10100c0fea5dSIngo Weinhold 			if (i == 0) {
10110c0fea5dSIngo Weinhold 				// but only the first segment gets a free ride
10120c0fea5dSIngo Weinhold 				loadAddress = RLD_PROGRAM_BASE;
10130c0fea5dSIngo Weinhold 				addressSpecifier = B_BASE_ADDRESS;
10140c0fea5dSIngo Weinhold 			} else {
10150c0fea5dSIngo Weinhold 				loadAddress = image->regions[i].vmstart + image->regions[i-1].delta;
10160c0fea5dSIngo Weinhold 				addressSpecifier = B_EXACT_ADDRESS;
10170c0fea5dSIngo Weinhold 			}
10180c0fea5dSIngo Weinhold 		} else {
10190c0fea5dSIngo Weinhold 			// not relocatable, put it where it asks or die trying
10200c0fea5dSIngo Weinhold 			loadAddress = image->regions[i].vmstart;
10210c0fea5dSIngo Weinhold 			addressSpecifier = B_EXACT_ADDRESS;
10220c0fea5dSIngo Weinhold 		}
10230c0fea5dSIngo Weinhold 
10240c0fea5dSIngo Weinhold 		if (image->regions[i].flags & RFLAG_ANON) {
10250c0fea5dSIngo Weinhold 			image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress,
10260c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_NO_LOCK,
10270c0fea5dSIngo Weinhold 				B_READ_AREA | B_WRITE_AREA);
10280c0fea5dSIngo Weinhold 
10290c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
10300c0fea5dSIngo Weinhold 				status = image->regions[i].id;
10310c0fea5dSIngo Weinhold 				goto error;
10320c0fea5dSIngo Weinhold 			}
10330c0fea5dSIngo Weinhold 
10340c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
10350c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
10360c0fea5dSIngo Weinhold 		} else {
10373cf7ecd1SIngo Weinhold 			image->regions[i].id = _kern_map_file(regionName,
10383cf7ecd1SIngo Weinhold 				(void **)&loadAddress, addressSpecifier,
10393cf7ecd1SIngo Weinhold 				image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
10403cf7ecd1SIngo Weinhold 				REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart));
10410c0fea5dSIngo Weinhold 
10420c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
10430c0fea5dSIngo Weinhold 				status = image->regions[i].id;
10440c0fea5dSIngo Weinhold 				goto error;
10450c0fea5dSIngo Weinhold 			}
10460c0fea5dSIngo Weinhold 
10470c0fea5dSIngo Weinhold 			TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
10480c0fea5dSIngo Weinhold 				(void *)loadAddress, image->regions[i].vmsize,
10490c0fea5dSIngo Weinhold 				image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
10500c0fea5dSIngo Weinhold 
10510c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
10520c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
10530c0fea5dSIngo Weinhold 
10540c0fea5dSIngo Weinhold 			// handle trailer bits in data segment
10550c0fea5dSIngo Weinhold 			if (image->regions[i].flags & RFLAG_RW) {
10560c0fea5dSIngo Weinhold 				addr_t startClearing;
10570c0fea5dSIngo Weinhold 				addr_t toClear;
10580c0fea5dSIngo Weinhold 
10590c0fea5dSIngo Weinhold 				startClearing = image->regions[i].vmstart
10600c0fea5dSIngo Weinhold 					+ PAGE_OFFSET(image->regions[i].start)
10610c0fea5dSIngo Weinhold 					+ image->regions[i].size;
10620c0fea5dSIngo Weinhold 				toClear = image->regions[i].vmsize
10630c0fea5dSIngo Weinhold 					- PAGE_OFFSET(image->regions[i].start)
10640c0fea5dSIngo Weinhold 					- image->regions[i].size;
10650c0fea5dSIngo Weinhold 
10660c0fea5dSIngo Weinhold 				TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear));
10670c0fea5dSIngo Weinhold 				memset((void *)startClearing, 0, toClear);
10680c0fea5dSIngo Weinhold 			}
10690c0fea5dSIngo Weinhold 		}
10700c0fea5dSIngo Weinhold 	}
10710c0fea5dSIngo Weinhold 
10720c0fea5dSIngo Weinhold 	if (image->dynamic_ptr)
10730c0fea5dSIngo Weinhold 		image->dynamic_ptr += image->regions[0].delta;
10740c0fea5dSIngo Weinhold 
10750c0fea5dSIngo Weinhold 	return B_OK;
10760c0fea5dSIngo Weinhold 
10770c0fea5dSIngo Weinhold error:
10780c0fea5dSIngo Weinhold 	return status;
10790c0fea5dSIngo Weinhold }
10800c0fea5dSIngo Weinhold 
10810c0fea5dSIngo Weinhold 
10820c0fea5dSIngo Weinhold static void
10830c0fea5dSIngo Weinhold unmap_image(image_t *image)
10840c0fea5dSIngo Weinhold {
10850c0fea5dSIngo Weinhold 	uint32 i;
10860c0fea5dSIngo Weinhold 
10870c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
10880c0fea5dSIngo Weinhold 		_kern_delete_area(image->regions[i].id);
10890c0fea5dSIngo Weinhold 
10900c0fea5dSIngo Weinhold 		image->regions[i].id = -1;
10910c0fea5dSIngo Weinhold 	}
10920c0fea5dSIngo Weinhold }
10930c0fea5dSIngo Weinhold 
10940c0fea5dSIngo Weinhold 
10950c0fea5dSIngo Weinhold static bool
10960c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image)
10970c0fea5dSIngo Weinhold {
10980c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d;
10990c0fea5dSIngo Weinhold 	int i;
11000c0fea5dSIngo Weinhold 	int sonameOffset = -1;
11010c0fea5dSIngo Weinhold 
11020c0fea5dSIngo Weinhold 	image->symhash = 0;
11030c0fea5dSIngo Weinhold 	image->syms = 0;
11040c0fea5dSIngo Weinhold 	image->strtab = 0;
11050c0fea5dSIngo Weinhold 
11060c0fea5dSIngo Weinhold 	d = (struct Elf32_Dyn *)image->dynamic_ptr;
11070c0fea5dSIngo Weinhold 	if (!d)
11080c0fea5dSIngo Weinhold 		return true;
11090c0fea5dSIngo Weinhold 
11100c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
11110c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
11120c0fea5dSIngo Weinhold 			case DT_NEEDED:
11130c0fea5dSIngo Weinhold 				image->num_needed += 1;
11140c0fea5dSIngo Weinhold 				break;
11150c0fea5dSIngo Weinhold 			case DT_HASH:
11160c0fea5dSIngo Weinhold 				image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta);
11170c0fea5dSIngo Weinhold 				break;
11180c0fea5dSIngo Weinhold 			case DT_STRTAB:
11190c0fea5dSIngo Weinhold 				image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
11200c0fea5dSIngo Weinhold 				break;
11210c0fea5dSIngo Weinhold 			case DT_SYMTAB:
11220c0fea5dSIngo Weinhold 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
11230c0fea5dSIngo Weinhold 				break;
11240c0fea5dSIngo Weinhold 			case DT_REL:
11250c0fea5dSIngo Weinhold 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
11260c0fea5dSIngo Weinhold 				break;
11270c0fea5dSIngo Weinhold 			case DT_RELSZ:
11280c0fea5dSIngo Weinhold 				image->rel_len = d[i].d_un.d_val;
11290c0fea5dSIngo Weinhold 				break;
11300c0fea5dSIngo Weinhold 			case DT_RELA:
11310c0fea5dSIngo Weinhold 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
11320c0fea5dSIngo Weinhold 				break;
11330c0fea5dSIngo Weinhold 			case DT_RELASZ:
11340c0fea5dSIngo Weinhold 				image->rela_len = d[i].d_un.d_val;
11350c0fea5dSIngo Weinhold 				break;
11360c0fea5dSIngo Weinhold 			// TK: procedure linkage table
11370c0fea5dSIngo Weinhold 			case DT_JMPREL:
11380c0fea5dSIngo Weinhold 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
11390c0fea5dSIngo Weinhold 				break;
11400c0fea5dSIngo Weinhold 			case DT_PLTRELSZ:
11410c0fea5dSIngo Weinhold 				image->pltrel_len = d[i].d_un.d_val;
11420c0fea5dSIngo Weinhold 				break;
11430c0fea5dSIngo Weinhold 			case DT_INIT:
11440c0fea5dSIngo Weinhold 				image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
11450c0fea5dSIngo Weinhold 				break;
11460c0fea5dSIngo Weinhold 			case DT_FINI:
11470c0fea5dSIngo Weinhold 				image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
11480c0fea5dSIngo Weinhold 				break;
11490c0fea5dSIngo Weinhold 			case DT_SONAME:
11500c0fea5dSIngo Weinhold 				sonameOffset = d[i].d_un.d_val;
11510c0fea5dSIngo Weinhold 				break;
1152*003ebb0eSIngo Weinhold 			case DT_VERSYM:
1153*003ebb0eSIngo Weinhold 				image->symbol_versions = (Elf32_Versym*)
1154*003ebb0eSIngo Weinhold 					(d[i].d_un.d_ptr + image->regions[0].delta);
1155*003ebb0eSIngo Weinhold 				break;
1156*003ebb0eSIngo Weinhold 			case DT_VERDEF:
1157*003ebb0eSIngo Weinhold 				image->version_definitions = (Elf32_Verdef*)
1158*003ebb0eSIngo Weinhold 					(d[i].d_un.d_ptr + image->regions[0].delta);
1159*003ebb0eSIngo Weinhold 				break;
1160*003ebb0eSIngo Weinhold 			case DT_VERDEFNUM:
1161*003ebb0eSIngo Weinhold 				image->num_version_definitions = d[i].d_un.d_val;
1162*003ebb0eSIngo Weinhold 				break;
1163*003ebb0eSIngo Weinhold 			case DT_VERNEED:
1164*003ebb0eSIngo Weinhold 				image->needed_versions = (Elf32_Verneed*)
1165*003ebb0eSIngo Weinhold 					(d[i].d_un.d_ptr + image->regions[0].delta);
1166*003ebb0eSIngo Weinhold 				break;
1167*003ebb0eSIngo Weinhold 			case DT_VERNEEDNUM:
1168*003ebb0eSIngo Weinhold 				image->num_needed_versions = d[i].d_un.d_val;
1169*003ebb0eSIngo Weinhold 				break;
11700c0fea5dSIngo Weinhold 			default:
11710c0fea5dSIngo Weinhold 				continue;
11720c0fea5dSIngo Weinhold 		}
11730c0fea5dSIngo Weinhold 	}
11740c0fea5dSIngo Weinhold 
11750c0fea5dSIngo Weinhold 	// lets make sure we found all the required sections
11760c0fea5dSIngo Weinhold 	if (!image->symhash || !image->syms || !image->strtab)
11770c0fea5dSIngo Weinhold 		return false;
11780c0fea5dSIngo Weinhold 
11790c0fea5dSIngo Weinhold 	if (sonameOffset >= 0)
11800c0fea5dSIngo Weinhold 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
11810c0fea5dSIngo Weinhold 
11820c0fea5dSIngo Weinhold 	return true;
11830c0fea5dSIngo Weinhold }
11840c0fea5dSIngo Weinhold 
11850c0fea5dSIngo Weinhold 
118610b4b5d1SIngo Weinhold static void
118710b4b5d1SIngo Weinhold patch_defined_symbol(image_t* image, const char* name, void** symbol,
118810b4b5d1SIngo Weinhold 	int32* type)
118910b4b5d1SIngo Weinhold {
119010b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers;
119110b4b5d1SIngo Weinhold 	while (patcher != NULL && *symbol != 0) {
119210b4b5d1SIngo Weinhold 		image_t* inImage = image;
119310b4b5d1SIngo Weinhold 		patcher->patcher(patcher->cookie, NULL, image, name, &inImage,
119410b4b5d1SIngo Weinhold 			symbol, type);
119510b4b5d1SIngo Weinhold 		patcher = patcher->next;
119610b4b5d1SIngo Weinhold 	}
119710b4b5d1SIngo Weinhold }
119810b4b5d1SIngo Weinhold 
119910b4b5d1SIngo Weinhold 
120010b4b5d1SIngo Weinhold static void
120110b4b5d1SIngo Weinhold patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
120210b4b5d1SIngo Weinhold 	image_t** foundInImage, void** symbol, int32* type)
120310b4b5d1SIngo Weinhold {
120410b4b5d1SIngo Weinhold 	if (*foundInImage != NULL)
120510b4b5d1SIngo Weinhold 		patch_defined_symbol(*foundInImage, name, symbol, type);
120610b4b5d1SIngo Weinhold 
120710b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers;
120810b4b5d1SIngo Weinhold 	while (patcher != NULL) {
120910b4b5d1SIngo Weinhold 		patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage,
121010b4b5d1SIngo Weinhold 			symbol, type);
121110b4b5d1SIngo Weinhold 		patcher = patcher->next;
121210b4b5d1SIngo Weinhold 	}
121310b4b5d1SIngo Weinhold }
121410b4b5d1SIngo Weinhold 
121510b4b5d1SIngo Weinhold 
121610b4b5d1SIngo Weinhold status_t
121710b4b5d1SIngo Weinhold register_defined_symbol_patcher(struct image_t* image,
121810b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
121910b4b5d1SIngo Weinhold {
122010b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher
122110b4b5d1SIngo Weinhold 		= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
122210b4b5d1SIngo Weinhold 	if (patcher == NULL)
122310b4b5d1SIngo Weinhold 		return B_NO_MEMORY;
122410b4b5d1SIngo Weinhold 
122510b4b5d1SIngo Weinhold 	patcher->next = image->defined_symbol_patchers;
122610b4b5d1SIngo Weinhold 	image->defined_symbol_patchers = patcher;
122710b4b5d1SIngo Weinhold 
122810b4b5d1SIngo Weinhold 	return B_OK;
122910b4b5d1SIngo Weinhold }
123010b4b5d1SIngo Weinhold 
123110b4b5d1SIngo Weinhold 
123210b4b5d1SIngo Weinhold void
123310b4b5d1SIngo Weinhold unregister_defined_symbol_patcher(struct image_t* image,
123410b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
123510b4b5d1SIngo Weinhold {
123610b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher** patcher = &image->defined_symbol_patchers;
123710b4b5d1SIngo Weinhold 	while (*patcher != NULL) {
123810b4b5d1SIngo Weinhold 		if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
123910b4b5d1SIngo Weinhold 			RuntimeLoaderSymbolPatcher* toDelete = *patcher;
124010b4b5d1SIngo Weinhold 			*patcher = (*patcher)->next;
124110b4b5d1SIngo Weinhold 			delete toDelete;
124210b4b5d1SIngo Weinhold 			return;
124310b4b5d1SIngo Weinhold 		}
124410b4b5d1SIngo Weinhold 		patcher = &(*patcher)->next;
124510b4b5d1SIngo Weinhold 	}
124610b4b5d1SIngo Weinhold }
124710b4b5d1SIngo Weinhold 
124810b4b5d1SIngo Weinhold 
124910b4b5d1SIngo Weinhold status_t
125010b4b5d1SIngo Weinhold register_undefined_symbol_patcher(struct image_t* image,
125110b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
125210b4b5d1SIngo Weinhold {
125310b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher
125410b4b5d1SIngo Weinhold 		= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
125510b4b5d1SIngo Weinhold 	if (patcher == NULL)
125610b4b5d1SIngo Weinhold 		return B_NO_MEMORY;
125710b4b5d1SIngo Weinhold 
125810b4b5d1SIngo Weinhold 	patcher->next = image->undefined_symbol_patchers;
125910b4b5d1SIngo Weinhold 	image->undefined_symbol_patchers = patcher;
126010b4b5d1SIngo Weinhold 
126110b4b5d1SIngo Weinhold 	return B_OK;
126210b4b5d1SIngo Weinhold }
126310b4b5d1SIngo Weinhold 
126410b4b5d1SIngo Weinhold 
126510b4b5d1SIngo Weinhold void
126610b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher(struct image_t* image,
126710b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
126810b4b5d1SIngo Weinhold {
126910b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher** patcher = &image->undefined_symbol_patchers;
127010b4b5d1SIngo Weinhold 	while (*patcher != NULL) {
127110b4b5d1SIngo Weinhold 		if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
127210b4b5d1SIngo Weinhold 			RuntimeLoaderSymbolPatcher* toDelete = *patcher;
127310b4b5d1SIngo Weinhold 			*patcher = (*patcher)->next;
127410b4b5d1SIngo Weinhold 			delete toDelete;
127510b4b5d1SIngo Weinhold 			return;
127610b4b5d1SIngo Weinhold 		}
127710b4b5d1SIngo Weinhold 		patcher = &(*patcher)->next;
127810b4b5d1SIngo Weinhold 	}
127910b4b5d1SIngo Weinhold }
128010b4b5d1SIngo Weinhold 
128110b4b5d1SIngo Weinhold 
128210b4b5d1SIngo Weinhold runtime_loader_add_on_export gRuntimeLoaderAddOnExport = {
128310b4b5d1SIngo Weinhold 	register_defined_symbol_patcher,
128410b4b5d1SIngo Weinhold 	unregister_defined_symbol_patcher,
128510b4b5d1SIngo Weinhold 	register_undefined_symbol_patcher,
128610b4b5d1SIngo Weinhold 	unregister_undefined_symbol_patcher
128710b4b5d1SIngo Weinhold };
128810b4b5d1SIngo Weinhold 
128910b4b5d1SIngo Weinhold 
1290*003ebb0eSIngo Weinhold static bool
1291*003ebb0eSIngo Weinhold equals_image_name(image_t* image, const char* name)
12920c0fea5dSIngo Weinhold {
1293*003ebb0eSIngo Weinhold 	const char* lastSlash = strrchr(name, '/');
1294*003ebb0eSIngo Weinhold 	return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0;
1295*003ebb0eSIngo Weinhold }
12960c0fea5dSIngo Weinhold 
12970c0fea5dSIngo Weinhold 
1298*003ebb0eSIngo Weinhold static Elf32_Sym*
1299*003ebb0eSIngo Weinhold find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo)
1300*003ebb0eSIngo Weinhold {
1301dd76bc97SIngo Weinhold 	if (image->dynamic_ptr == 0)
13020c0fea5dSIngo Weinhold 		return NULL;
13030c0fea5dSIngo Weinhold 
1304*003ebb0eSIngo Weinhold 	Elf32_Sym* versionedSymbol = NULL;
1305*003ebb0eSIngo Weinhold 	uint32 versionedSymbolCount = 0;
13060c0fea5dSIngo Weinhold 
1307*003ebb0eSIngo Weinhold 	uint32 bucket = lookupInfo.hash % HASHTABSIZE(image);
1308*003ebb0eSIngo Weinhold 
1309*003ebb0eSIngo Weinhold 	for (uint32 i = HASHBUCKETS(image)[bucket]; i != STN_UNDEF;
1310*003ebb0eSIngo Weinhold 			i = HASHCHAINS(image)[i]) {
13110c0fea5dSIngo Weinhold 		struct Elf32_Sym* symbol = &image->syms[i];
13120c0fea5dSIngo Weinhold 
13130c0fea5dSIngo Weinhold 		if (symbol->st_shndx != SHN_UNDEF
13140c0fea5dSIngo Weinhold 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
13150c0fea5dSIngo Weinhold 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
1316*003ebb0eSIngo Weinhold 			&& !strcmp(SYMNAME(image, symbol), lookupInfo.name)) {
13170c0fea5dSIngo Weinhold 
1318*003ebb0eSIngo Weinhold 			// check if the type matches
1319*003ebb0eSIngo Weinhold 			uint32 type = ELF32_ST_TYPE(symbol->st_info);
1320*003ebb0eSIngo Weinhold 			if ((lookupInfo.type == B_SYMBOL_TYPE_TEXT && type != STT_FUNC)
1321*003ebb0eSIngo Weinhold 				|| (lookupInfo.type == B_SYMBOL_TYPE_DATA
1322*003ebb0eSIngo Weinhold 					&& type != STT_OBJECT)) {
1323*003ebb0eSIngo Weinhold 				continue;
1324*003ebb0eSIngo Weinhold 			}
1325*003ebb0eSIngo Weinhold 
1326*003ebb0eSIngo Weinhold 			// check the version
1327*003ebb0eSIngo Weinhold 
1328*003ebb0eSIngo Weinhold 			// Handle the simple cases -- the image doesn't have version
1329*003ebb0eSIngo Weinhold 			// information -- first.
1330*003ebb0eSIngo Weinhold 			if (image->symbol_versions == NULL) {
1331*003ebb0eSIngo Weinhold 				if (lookupInfo.version == NULL) {
1332*003ebb0eSIngo Weinhold 					// No specific symbol version was requested either, so the
1333*003ebb0eSIngo Weinhold 					// symbol is just fine.
13340c0fea5dSIngo Weinhold 					return symbol;
13350c0fea5dSIngo Weinhold 				}
1336*003ebb0eSIngo Weinhold 
1337*003ebb0eSIngo Weinhold 				// A specific version is requested. If it's the dependency
1338*003ebb0eSIngo Weinhold 				// referred to by the requested version, it's apparently an
1339*003ebb0eSIngo Weinhold 				// older version of the dependency and we're not happy.
1340*003ebb0eSIngo Weinhold 				if (equals_image_name(image, lookupInfo.version->file_name)) {
1341*003ebb0eSIngo Weinhold 					// TODO: That should actually be kind of fatal!
1342*003ebb0eSIngo Weinhold 					return NULL;
13430c0fea5dSIngo Weinhold 				}
13440c0fea5dSIngo Weinhold 
1345*003ebb0eSIngo Weinhold 				// This is some other image. We accept the symbol.
1346*003ebb0eSIngo Weinhold 				return symbol;
1347*003ebb0eSIngo Weinhold 			}
1348*003ebb0eSIngo Weinhold 
1349*003ebb0eSIngo Weinhold 			// The image has version information. Let's see what we've got.
1350*003ebb0eSIngo Weinhold 			uint32 versionID = image->symbol_versions[i];
1351*003ebb0eSIngo Weinhold 			uint32 versionIndex = VER_NDX(versionID);
1352*003ebb0eSIngo Weinhold 			elf_version_info& version = image->versions[versionIndex];
1353*003ebb0eSIngo Weinhold 
1354*003ebb0eSIngo Weinhold 			// skip local versions
1355*003ebb0eSIngo Weinhold 			if (versionIndex == VER_NDX_LOCAL)
1356*003ebb0eSIngo Weinhold 				continue;
1357*003ebb0eSIngo Weinhold 
1358*003ebb0eSIngo Weinhold 			if (lookupInfo.version != NULL) {
1359*003ebb0eSIngo Weinhold 				// a specific version is requested
1360*003ebb0eSIngo Weinhold 
1361*003ebb0eSIngo Weinhold 				// compare the versions
1362*003ebb0eSIngo Weinhold 				if (version.hash == lookupInfo.version->hash
1363*003ebb0eSIngo Weinhold 					&& strcmp(version.name, lookupInfo.version->name) == 0) {
1364*003ebb0eSIngo Weinhold 					// versions match
1365*003ebb0eSIngo Weinhold 					return symbol;
1366*003ebb0eSIngo Weinhold 				}
1367*003ebb0eSIngo Weinhold 
1368*003ebb0eSIngo Weinhold 				// The versions don't match. We're still fine with the
1369*003ebb0eSIngo Weinhold 				// base version, if it is public and we're not looking for
1370*003ebb0eSIngo Weinhold 				// the default version.
1371*003ebb0eSIngo Weinhold 				if ((versionID & VER_NDX_FLAG_HIDDEN) == 0
1372*003ebb0eSIngo Weinhold 					&& versionIndex == VER_NDX_GLOBAL
1373*003ebb0eSIngo Weinhold 					&& (lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION)
1374*003ebb0eSIngo Weinhold 						== 0) {
1375*003ebb0eSIngo Weinhold 					// TODO: Revise the default version case! That's how
1376*003ebb0eSIngo Weinhold 					// FreeBSD implements it, but glibc doesn't handle it
1377*003ebb0eSIngo Weinhold 					// specially.
1378*003ebb0eSIngo Weinhold 					return symbol;
1379*003ebb0eSIngo Weinhold 				}
1380*003ebb0eSIngo Weinhold 			} else {
1381*003ebb0eSIngo Weinhold 				// No specific version requested, but the image has version
1382*003ebb0eSIngo Weinhold 				// information. This can happen in either of these cases:
1383*003ebb0eSIngo Weinhold 				//
1384*003ebb0eSIngo Weinhold 				// * The dependent object was linked against an older version
1385*003ebb0eSIngo Weinhold 				//   of the now versioned dependency.
1386*003ebb0eSIngo Weinhold 				// * The symbol is looked up via find_image_symbol() or dlsym().
1387*003ebb0eSIngo Weinhold 				//
1388*003ebb0eSIngo Weinhold 				// In the first case we return the base version of the symbol
1389*003ebb0eSIngo Weinhold 				// (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't
1390*003ebb0eSIngo Weinhold 				// exist, the unique, non-hidden versioned symbol.
1391*003ebb0eSIngo Weinhold 				//
1392*003ebb0eSIngo Weinhold 				// In the second case we want to return the public default
1393*003ebb0eSIngo Weinhold 				// version of the symbol. The handling is pretty similar to the
1394*003ebb0eSIngo Weinhold 				// first case, with the exception that we treat VER_NDX_INITIAL
1395*003ebb0eSIngo Weinhold 				// as regular version.
1396*003ebb0eSIngo Weinhold 
1397*003ebb0eSIngo Weinhold 				// VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if
1398*003ebb0eSIngo Weinhold 				// we don't look for the default version.
1399*003ebb0eSIngo Weinhold 				if (versionIndex == VER_NDX_GLOBAL
1400*003ebb0eSIngo Weinhold 					|| ((lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) == 0
1401*003ebb0eSIngo Weinhold 						&& versionIndex == VER_NDX_INITIAL)) {
1402*003ebb0eSIngo Weinhold 					return symbol;
1403*003ebb0eSIngo Weinhold 				}
1404*003ebb0eSIngo Weinhold 
1405*003ebb0eSIngo Weinhold 				// If not hidden, remember the version -- we'll return it, if
1406*003ebb0eSIngo Weinhold 				// it is the only one.
1407*003ebb0eSIngo Weinhold 				if ((versionID & VER_NDX_FLAG_HIDDEN) == 0) {
1408*003ebb0eSIngo Weinhold 					versionedSymbolCount++;
1409*003ebb0eSIngo Weinhold 					versionedSymbol = symbol;
1410*003ebb0eSIngo Weinhold 				}
1411*003ebb0eSIngo Weinhold 			}
1412*003ebb0eSIngo Weinhold 		}
1413*003ebb0eSIngo Weinhold 	}
1414*003ebb0eSIngo Weinhold 
1415*003ebb0eSIngo Weinhold 	return versionedSymbolCount == 1 ? versionedSymbol : NULL;
14160c0fea5dSIngo Weinhold }
14170c0fea5dSIngo Weinhold 
14180c0fea5dSIngo Weinhold 
141910b4b5d1SIngo Weinhold static status_t
1420*003ebb0eSIngo Weinhold find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo,
142110b4b5d1SIngo Weinhold 	void **_location)
142210b4b5d1SIngo Weinhold {
142310b4b5d1SIngo Weinhold 	// get the symbol in the image
1424*003ebb0eSIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol(image, lookupInfo);
142510b4b5d1SIngo Weinhold 	if (symbol == NULL)
142610b4b5d1SIngo Weinhold 		return B_ENTRY_NOT_FOUND;
142710b4b5d1SIngo Weinhold 
142810b4b5d1SIngo Weinhold 	void* location = (void*)(symbol->st_value + image->regions[0].delta);
1429*003ebb0eSIngo Weinhold 	int32 symbolType = lookupInfo.type;
1430*003ebb0eSIngo Weinhold 	patch_defined_symbol(image, lookupInfo.name, &location, &symbolType);
143110b4b5d1SIngo Weinhold 
143210b4b5d1SIngo Weinhold 	if (_location != NULL)
143310b4b5d1SIngo Weinhold 		*_location = location;
143410b4b5d1SIngo Weinhold 
143510b4b5d1SIngo Weinhold 	return B_OK;
143610b4b5d1SIngo Weinhold }
143710b4b5d1SIngo Weinhold 
143810b4b5d1SIngo Weinhold 
14390c85bd05SIngo Weinhold static status_t
1440*003ebb0eSIngo Weinhold find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo,
14410c85bd05SIngo Weinhold 	image_t** _foundInImage, void** _location)
14420c0fea5dSIngo Weinhold {
14430c85bd05SIngo Weinhold 	image_t* queue[sLoadedImageCount];
14440c85bd05SIngo Weinhold 	uint32 count = 0;
14450c85bd05SIngo Weinhold 	uint32 index = 0;
14460c85bd05SIngo Weinhold 	queue[count++] = image;
14470c85bd05SIngo Weinhold 	image->flags |= RFLAG_VISITED;
14480c85bd05SIngo Weinhold 
14490c85bd05SIngo Weinhold 	bool found = false;
14500c85bd05SIngo Weinhold 	while (index < count) {
14510c85bd05SIngo Weinhold 		// pop next image
14520c85bd05SIngo Weinhold 		image = queue[index++];
14530c85bd05SIngo Weinhold 
1454*003ebb0eSIngo Weinhold 		if (find_symbol(image, lookupInfo, _location) == B_OK) {
14550c85bd05SIngo Weinhold 			found = true;
14560c85bd05SIngo Weinhold 			break;
14570c85bd05SIngo Weinhold 		}
14580c85bd05SIngo Weinhold 
14590c85bd05SIngo Weinhold 		// push needed images
14600c85bd05SIngo Weinhold 		for (uint32 i = 0; i < image->num_needed; i++) {
14610c85bd05SIngo Weinhold 			image_t* needed = image->needed[i];
14620c85bd05SIngo Weinhold 			if ((needed->flags & RFLAG_VISITED) == 0) {
14630c85bd05SIngo Weinhold 				queue[count++] = needed;
14640c85bd05SIngo Weinhold 				needed->flags |= RFLAG_VISITED;
146546f4d849SIngo Weinhold 			}
146646f4d849SIngo Weinhold 		}
14670c0fea5dSIngo Weinhold 	}
14680c0fea5dSIngo Weinhold 
14690c85bd05SIngo Weinhold 	// clear visited flags
14700c85bd05SIngo Weinhold 	for (uint32 i = 0; i < count; i++)
14710c85bd05SIngo Weinhold 		queue[i]->flags &= ~RFLAG_VISITED;
14720c85bd05SIngo Weinhold 
14730c85bd05SIngo Weinhold 	return found ? B_OK : B_ENTRY_NOT_FOUND;
14740c0fea5dSIngo Weinhold }
14750c0fea5dSIngo Weinhold 
14760c0fea5dSIngo Weinhold 
147746f4d849SIngo Weinhold static struct Elf32_Sym*
1478*003ebb0eSIngo Weinhold find_undefined_symbol_beos(image_t* rootImage, image_t* image,
1479*003ebb0eSIngo Weinhold 	const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
148046f4d849SIngo Weinhold {
148146f4d849SIngo Weinhold 	// BeOS style symbol resolution: It is sufficient to check the direct
148246f4d849SIngo Weinhold 	// dependencies. The linker would have complained, if the symbol wasn't
148346f4d849SIngo Weinhold 	// there.
148446f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
148546f4d849SIngo Weinhold 		if (image->needed[i]->dynamic_ptr) {
1486*003ebb0eSIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(image->needed[i],
1487*003ebb0eSIngo Weinhold 				lookupInfo);
148846f4d849SIngo Weinhold 			if (symbol) {
148946f4d849SIngo Weinhold 				*foundInImage = image->needed[i];
149046f4d849SIngo Weinhold 				return symbol;
149146f4d849SIngo Weinhold 			}
149246f4d849SIngo Weinhold 		}
149346f4d849SIngo Weinhold 	}
149446f4d849SIngo Weinhold 
149546f4d849SIngo Weinhold 	return NULL;
149646f4d849SIngo Weinhold }
149746f4d849SIngo Weinhold 
149846f4d849SIngo Weinhold 
14990c85bd05SIngo Weinhold static struct Elf32_Sym*
15000c85bd05SIngo Weinhold find_undefined_symbol_global(image_t* rootImage, image_t* image,
1501*003ebb0eSIngo Weinhold 	const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
15020c85bd05SIngo Weinhold {
15030c85bd05SIngo Weinhold 	// Global load order symbol resolution: All loaded images are searched for
15040c85bd05SIngo Weinhold 	// the symbol in the order they have been loaded. We skip add-on images and
15050c85bd05SIngo Weinhold 	// RTLD_LOCAL images though.
15060c85bd05SIngo Weinhold 	image_t* otherImage = sLoadedImages.head;
15070c85bd05SIngo Weinhold 	while (otherImage != NULL) {
15080c85bd05SIngo Weinhold 		if (otherImage == rootImage
1509593ee7bbSIngo Weinhold 			|| (otherImage->type != B_ADD_ON_IMAGE
15100c85bd05SIngo Weinhold 				&& (otherImage->flags
1511593ee7bbSIngo Weinhold 					& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) {
1512*003ebb0eSIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(otherImage, lookupInfo);
15130c85bd05SIngo Weinhold 			if (symbol) {
15140c85bd05SIngo Weinhold 				*foundInImage = otherImage;
15150c85bd05SIngo Weinhold 				return symbol;
15160c85bd05SIngo Weinhold 			}
15170c85bd05SIngo Weinhold 		}
15180c85bd05SIngo Weinhold 		otherImage = otherImage->next;
15190c85bd05SIngo Weinhold 	}
15200c85bd05SIngo Weinhold 
15210c85bd05SIngo Weinhold 	return NULL;
15220c85bd05SIngo Weinhold }
15230c85bd05SIngo Weinhold 
15240c85bd05SIngo Weinhold 
15250c85bd05SIngo Weinhold static struct Elf32_Sym*
15260c85bd05SIngo Weinhold find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
1527*003ebb0eSIngo Weinhold 	const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
15280c85bd05SIngo Weinhold {
15290c85bd05SIngo Weinhold // TODO: How do we want to implement this one? Using global scope resolution
15300c85bd05SIngo Weinhold // might be undesired as it is now, since libraries could refer to symbols in
15310c85bd05SIngo Weinhold // the add-on, which would result in add-on symbols implicitely becoming used
15320c85bd05SIngo Weinhold // outside of the add-on. So the options would be to use the global scope but
15330c85bd05SIngo Weinhold // skip the add-on, or to do breadth-first resolution in the add-on dependency
15340c85bd05SIngo Weinhold // scope, also skipping the add-on itself. BeOS style resolution is safe, too,
15350c85bd05SIngo Weinhold // but we miss out features like undefined symbols and preloading.
1536*003ebb0eSIngo Weinhold 	return find_undefined_symbol_beos(rootImage, image, lookupInfo,
1537*003ebb0eSIngo Weinhold 		foundInImage);
15380c85bd05SIngo Weinhold }
15390c85bd05SIngo Weinhold 
15400c85bd05SIngo Weinhold 
154110b4b5d1SIngo Weinhold /*!	This function is called when we run BeOS images on Haiku.
15422716cfd3SAxel Dörfler 	It allows us to redirect functions to ensure compatibility.
15432716cfd3SAxel Dörfler */
15442716cfd3SAxel Dörfler static const char*
15452716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName)
15462716cfd3SAxel Dörfler {
15472716cfd3SAxel Dörfler 	struct symbol_mapping {
15482716cfd3SAxel Dörfler 		const char* from;
15492716cfd3SAxel Dörfler 		const char* to;
15502716cfd3SAxel Dörfler 	};
15512716cfd3SAxel Dörfler 	static const struct symbol_mapping kMappings[] = {
155210b4b5d1SIngo Weinhold 		// TODO: Improve this, and also use it for libnet.so compatibility!
155310b4b5d1SIngo Weinhold 		// Allow an image to provide a function that will be invoked for every
155410b4b5d1SIngo Weinhold 		// (transitively) depending image. The function can return a table to
155510b4b5d1SIngo Weinhold 		// remap symbols (probably better address to address). All the tables
155610b4b5d1SIngo Weinhold 		// for a single image would be combined into a hash table and an
155710b4b5d1SIngo Weinhold 		// undefined symbol patcher using this hash table would be added.
15582716cfd3SAxel Dörfler 		{"fstat", "__be_fstat"},
15592716cfd3SAxel Dörfler 		{"lstat", "__be_lstat"},
15602716cfd3SAxel Dörfler 		{"stat", "__be_stat"},
15612716cfd3SAxel Dörfler 	};
15622716cfd3SAxel Dörfler 	const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]);
15632716cfd3SAxel Dörfler 
15642716cfd3SAxel Dörfler 	for (uint32 i = 0; i < kMappingCount; i++) {
15652716cfd3SAxel Dörfler 		if (!strcmp(symbolName, kMappings[i].from))
15662716cfd3SAxel Dörfler 			return kMappings[i].to;
15672716cfd3SAxel Dörfler 	}
15682716cfd3SAxel Dörfler 
15692716cfd3SAxel Dörfler 	return symbolName;
15702716cfd3SAxel Dörfler }
15712716cfd3SAxel Dörfler 
15722716cfd3SAxel Dörfler 
15730c0fea5dSIngo Weinhold int
157446f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
15752716cfd3SAxel Dörfler 	addr_t *symAddress)
15760c0fea5dSIngo Weinhold {
15770c0fea5dSIngo Weinhold 	switch (sym->st_shndx) {
15780c0fea5dSIngo Weinhold 		case SHN_UNDEF:
15792716cfd3SAxel Dörfler 		{
15802716cfd3SAxel Dörfler 			struct Elf32_Sym *sharedSym;
15812716cfd3SAxel Dörfler 			image_t *sharedImage;
1582*003ebb0eSIngo Weinhold 			const char *symName = SYMNAME(image, sym);
15832716cfd3SAxel Dörfler 
15840c0fea5dSIngo Weinhold 			// patch the symbol name
1585f91194e5SIngo Weinhold 			if (image->abi < B_HAIKU_ABI_GCC_2_HAIKU) {
15862716cfd3SAxel Dörfler 				// The image has been compiled with a BeOS compiler. This means
15872716cfd3SAxel Dörfler 				// we'll have to redirect some functions for compatibility.
15882716cfd3SAxel Dörfler 				symName = beos_compatibility_map_symbol(symName);
15892716cfd3SAxel Dörfler 			}
15900c0fea5dSIngo Weinhold 
1591*003ebb0eSIngo Weinhold 			// get the version info
1592*003ebb0eSIngo Weinhold 			const elf_version_info* versionInfo = NULL;
1593*003ebb0eSIngo Weinhold 			if (image->symbol_versions != NULL) {
1594*003ebb0eSIngo Weinhold 				uint32 index = sym - image->syms;
1595*003ebb0eSIngo Weinhold 				uint32 versionIndex = VER_NDX(image->symbol_versions[index]);
1596*003ebb0eSIngo Weinhold 				if (versionIndex >= VER_NDX_INITIAL)
1597*003ebb0eSIngo Weinhold 					versionInfo = image->versions + versionIndex;
1598*003ebb0eSIngo Weinhold 			}
1599*003ebb0eSIngo Weinhold 
160010b4b5d1SIngo Weinhold 			int32 type = B_SYMBOL_TYPE_ANY;
160110b4b5d1SIngo Weinhold 			if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC)
160210b4b5d1SIngo Weinhold 				type = B_SYMBOL_TYPE_TEXT;
160310b4b5d1SIngo Weinhold 			else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT)
160410b4b5d1SIngo Weinhold 				type = B_SYMBOL_TYPE_DATA;
160510b4b5d1SIngo Weinhold 
160646f4d849SIngo Weinhold 			// it's undefined, must be outside this image, try the other images
16070c85bd05SIngo Weinhold 			sharedSym = rootImage->find_undefined_symbol(rootImage, image,
1608*003ebb0eSIngo Weinhold 				SymbolLookupInfo(symName, type, versionInfo), &sharedImage);
160910b4b5d1SIngo Weinhold 			void* location = NULL;
16100c0fea5dSIngo Weinhold 
161110b4b5d1SIngo Weinhold 			enum {
161210b4b5d1SIngo Weinhold 				ERROR_NO_SYMBOL,
161310b4b5d1SIngo Weinhold 				ERROR_WRONG_TYPE,
161410b4b5d1SIngo Weinhold 				ERROR_NOT_EXPORTED,
161510b4b5d1SIngo Weinhold 				ERROR_UNPATCHED
161610b4b5d1SIngo Weinhold 			};
161710b4b5d1SIngo Weinhold 			uint32 lookupError = ERROR_UNPATCHED;
161810b4b5d1SIngo Weinhold 
161910b4b5d1SIngo Weinhold 			if (sharedSym == NULL) {
162010b4b5d1SIngo Weinhold 				// symbol not found at all
162110b4b5d1SIngo Weinhold 				lookupError = ERROR_NO_SYMBOL;
162210b4b5d1SIngo Weinhold 				sharedImage = NULL;
162310b4b5d1SIngo Weinhold 			} else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
16242716cfd3SAxel Dörfler 				&& ELF32_ST_TYPE(sym->st_info)
16252716cfd3SAxel Dörfler 					!= ELF32_ST_TYPE(sharedSym->st_info)) {
162610b4b5d1SIngo Weinhold 				// symbol not of the requested type
162710b4b5d1SIngo Weinhold 				lookupError = ERROR_WRONG_TYPE;
162810b4b5d1SIngo Weinhold 				sharedImage = NULL;
162910b4b5d1SIngo Weinhold 			} else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL
16302716cfd3SAxel Dörfler 				&& ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) {
163110b4b5d1SIngo Weinhold 				// symbol not exported
163210b4b5d1SIngo Weinhold 				lookupError = ERROR_NOT_EXPORTED;
163310b4b5d1SIngo Weinhold 				sharedImage = NULL;
163410b4b5d1SIngo Weinhold 			} else {
163510b4b5d1SIngo Weinhold 				// symbol is fine, get its location
163610b4b5d1SIngo Weinhold 				location = (void*)(sharedSym->st_value
163710b4b5d1SIngo Weinhold 					+ sharedImage->regions[0].delta);
163810b4b5d1SIngo Weinhold 			}
163910b4b5d1SIngo Weinhold 
164010b4b5d1SIngo Weinhold 			patch_undefined_symbol(rootImage, image, symName, &sharedImage,
164110b4b5d1SIngo Weinhold 				&location, &type);
164210b4b5d1SIngo Weinhold 
164310b4b5d1SIngo Weinhold 			if (location == NULL) {
164410b4b5d1SIngo Weinhold 				switch (lookupError) {
164510b4b5d1SIngo Weinhold 					case ERROR_NO_SYMBOL:
164610b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: could not resolve symbol "
164710b4b5d1SIngo Weinhold 							"'%s'\n", symName);
164810b4b5d1SIngo Weinhold 						break;
164910b4b5d1SIngo Weinhold 					case ERROR_WRONG_TYPE:
165010b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s' in shared "
165110b4b5d1SIngo Weinhold 							"image but wrong type\n", symName);
165210b4b5d1SIngo Weinhold 						break;
165310b4b5d1SIngo Weinhold 					case ERROR_NOT_EXPORTED:
165410b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s', but not "
16552716cfd3SAxel Dörfler 							"exported\n", symName);
165610b4b5d1SIngo Weinhold 						break;
165710b4b5d1SIngo Weinhold 					case ERROR_UNPATCHED:
165810b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s', but was "
165910b4b5d1SIngo Weinhold 							"hidden by symbol patchers\n", symName);
166010b4b5d1SIngo Weinhold 						break;
166110b4b5d1SIngo Weinhold 				}
1662e94d1badSMichael Lotz 
1663e94d1badSMichael Lotz 				if (report_errors())
1664e94d1badSMichael Lotz 					sErrorMessage.AddString("missing symbol", symName);
1665e94d1badSMichael Lotz 
16660c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
16670c0fea5dSIngo Weinhold 			}
16680c0fea5dSIngo Weinhold 
166910b4b5d1SIngo Weinhold 			*symAddress = (addr_t)location;
167010b4b5d1SIngo Weinhold 			return B_OK;
16712716cfd3SAxel Dörfler 		}
16720c0fea5dSIngo Weinhold 
16730c0fea5dSIngo Weinhold 		case SHN_ABS:
16742716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
16750c0fea5dSIngo Weinhold 			return B_NO_ERROR;
16760c0fea5dSIngo Weinhold 
16770c0fea5dSIngo Weinhold 		case SHN_COMMON:
16780c0fea5dSIngo Weinhold 			// ToDo: finish this
16792a33a944SIngo Weinhold 			FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n");
16800c0fea5dSIngo Weinhold 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
16810c0fea5dSIngo Weinhold 
16820c0fea5dSIngo Weinhold 		default:
16830c0fea5dSIngo Weinhold 			// standard symbol
16842716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
16850c0fea5dSIngo Weinhold 			return B_NO_ERROR;
16860c0fea5dSIngo Weinhold 	}
16870c0fea5dSIngo Weinhold }
16880c0fea5dSIngo Weinhold 
16890c0fea5dSIngo Weinhold 
16900c0fea5dSIngo Weinhold static void
169110b4b5d1SIngo Weinhold image_event(image_t* image, uint32 event)
169210b4b5d1SIngo Weinhold {
169310b4b5d1SIngo Weinhold 	AddOnList::Iterator it = sAddOns.GetIterator();
169410b4b5d1SIngo Weinhold 	while (RuntimeLoaderAddOn* addOn = it.Next()) {
169510b4b5d1SIngo Weinhold 		void (*function)(image_t* image) = NULL;
169610b4b5d1SIngo Weinhold 
169710b4b5d1SIngo Weinhold 		switch (event) {
169810b4b5d1SIngo Weinhold 			case IMAGE_EVENT_LOADED:
169910b4b5d1SIngo Weinhold 				function = addOn->addOn->image_loaded;
170010b4b5d1SIngo Weinhold 				break;
170110b4b5d1SIngo Weinhold 			case IMAGE_EVENT_RELOCATED:
170210b4b5d1SIngo Weinhold 				function = addOn->addOn->image_relocated;
170310b4b5d1SIngo Weinhold 				break;
170410b4b5d1SIngo Weinhold 			case IMAGE_EVENT_INITIALIZED:
170510b4b5d1SIngo Weinhold 				function = addOn->addOn->image_initialized;
170610b4b5d1SIngo Weinhold 				break;
170710b4b5d1SIngo Weinhold 			case IMAGE_EVENT_UNINITIALIZING:
170810b4b5d1SIngo Weinhold 				function = addOn->addOn->image_uninitializing;
170910b4b5d1SIngo Weinhold 				break;
171010b4b5d1SIngo Weinhold 			case IMAGE_EVENT_UNLOADING:
171110b4b5d1SIngo Weinhold 				function = addOn->addOn->image_unloading;
171210b4b5d1SIngo Weinhold 				break;
171310b4b5d1SIngo Weinhold 		}
171410b4b5d1SIngo Weinhold 
171510b4b5d1SIngo Weinhold 		if (function != NULL)
171610b4b5d1SIngo Weinhold 			function(image);
171710b4b5d1SIngo Weinhold 	}
171810b4b5d1SIngo Weinhold }
171910b4b5d1SIngo Weinhold 
172010b4b5d1SIngo Weinhold 
1721*003ebb0eSIngo Weinhold static status_t
1722*003ebb0eSIngo Weinhold init_image_version_infos(image_t* image)
1723*003ebb0eSIngo Weinhold {
1724*003ebb0eSIngo Weinhold 	// First find out how many version infos we need -- i.e. get the greatest
1725*003ebb0eSIngo Weinhold 	// version index from the defined and needed versions (they use the same
1726*003ebb0eSIngo Weinhold 	// index namespace).
1727*003ebb0eSIngo Weinhold 	uint32 maxIndex = 0;
1728*003ebb0eSIngo Weinhold 
1729*003ebb0eSIngo Weinhold 	if (image->version_definitions != NULL) {
1730*003ebb0eSIngo Weinhold 		Elf32_Verdef* definition = image->version_definitions;
1731*003ebb0eSIngo Weinhold 		for (uint32 i = 0; i < image->num_version_definitions; i++) {
1732*003ebb0eSIngo Weinhold 			if (definition->vd_version != 1) {
1733*003ebb0eSIngo Weinhold 				FATAL("Unsupported version definition revision: %u\n",
1734*003ebb0eSIngo Weinhold 					definition->vd_version);
1735*003ebb0eSIngo Weinhold 				return B_BAD_VALUE;
1736*003ebb0eSIngo Weinhold 			}
1737*003ebb0eSIngo Weinhold 
1738*003ebb0eSIngo Weinhold 			uint32 versionIndex = VER_NDX(definition->vd_ndx);
1739*003ebb0eSIngo Weinhold 			if (versionIndex > maxIndex)
1740*003ebb0eSIngo Weinhold 				maxIndex = versionIndex;
1741*003ebb0eSIngo Weinhold 
1742*003ebb0eSIngo Weinhold 			definition = (Elf32_Verdef*)
1743*003ebb0eSIngo Weinhold 				((uint8*)definition	+ definition->vd_next);
1744*003ebb0eSIngo Weinhold 		}
1745*003ebb0eSIngo Weinhold 	}
1746*003ebb0eSIngo Weinhold 
1747*003ebb0eSIngo Weinhold 	if (image->needed_versions != NULL) {
1748*003ebb0eSIngo Weinhold 		Elf32_Verneed* needed = image->needed_versions;
1749*003ebb0eSIngo Weinhold 		for (uint32 i = 0; i < image->num_needed_versions; i++) {
1750*003ebb0eSIngo Weinhold 			if (needed->vn_version != 1) {
1751*003ebb0eSIngo Weinhold 				FATAL("Unsupported version needed revision: %u\n",
1752*003ebb0eSIngo Weinhold 					needed->vn_version);
1753*003ebb0eSIngo Weinhold 				return B_BAD_VALUE;
1754*003ebb0eSIngo Weinhold 			}
1755*003ebb0eSIngo Weinhold 
1756*003ebb0eSIngo Weinhold 			Elf32_Vernaux* vernaux
1757*003ebb0eSIngo Weinhold 				= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
1758*003ebb0eSIngo Weinhold 			for (uint32 k = 0; k < needed->vn_cnt; k++) {
1759*003ebb0eSIngo Weinhold 				uint32 versionIndex = VER_NDX(vernaux->vna_other);
1760*003ebb0eSIngo Weinhold 				if (versionIndex > maxIndex)
1761*003ebb0eSIngo Weinhold 					maxIndex = versionIndex;
1762*003ebb0eSIngo Weinhold 
1763*003ebb0eSIngo Weinhold 				vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
1764*003ebb0eSIngo Weinhold 			}
1765*003ebb0eSIngo Weinhold 
1766*003ebb0eSIngo Weinhold 			needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
1767*003ebb0eSIngo Weinhold 		}
1768*003ebb0eSIngo Weinhold 	}
1769*003ebb0eSIngo Weinhold 
1770*003ebb0eSIngo Weinhold 	if (maxIndex == 0)
1771*003ebb0eSIngo Weinhold 		return B_OK;
1772*003ebb0eSIngo Weinhold 
1773*003ebb0eSIngo Weinhold 	// allocate the version infos
1774*003ebb0eSIngo Weinhold 	image->versions
1775*003ebb0eSIngo Weinhold 		= (elf_version_info*)malloc(sizeof(elf_version_info) * (maxIndex + 1));
1776*003ebb0eSIngo Weinhold 	if (image->versions == NULL) {
1777*003ebb0eSIngo Weinhold 		FATAL("Memory shortage in init_image_version_infos()");
1778*003ebb0eSIngo Weinhold 		return B_NO_MEMORY;
1779*003ebb0eSIngo Weinhold 	}
1780*003ebb0eSIngo Weinhold 	image->num_versions = maxIndex + 1;
1781*003ebb0eSIngo Weinhold 
1782*003ebb0eSIngo Weinhold 	// init the version infos
1783*003ebb0eSIngo Weinhold 
1784*003ebb0eSIngo Weinhold 	// version definitions
1785*003ebb0eSIngo Weinhold 	if (image->version_definitions != NULL) {
1786*003ebb0eSIngo Weinhold 		Elf32_Verdef* definition = image->version_definitions;
1787*003ebb0eSIngo Weinhold 		for (uint32 i = 0; i < image->num_version_definitions; i++) {
1788*003ebb0eSIngo Weinhold 			if (definition->vd_cnt > 0
1789*003ebb0eSIngo Weinhold 				&& (definition->vd_flags & VER_FLG_BASE) == 0) {
1790*003ebb0eSIngo Weinhold 				Elf32_Verdaux* verdaux
1791*003ebb0eSIngo Weinhold 					= (Elf32_Verdaux*)((uint8*)definition + definition->vd_aux);
1792*003ebb0eSIngo Weinhold 
1793*003ebb0eSIngo Weinhold 				uint32 versionIndex = VER_NDX(definition->vd_ndx);
1794*003ebb0eSIngo Weinhold 				elf_version_info& info = image->versions[versionIndex];
1795*003ebb0eSIngo Weinhold 				info.hash = definition->vd_hash;
1796*003ebb0eSIngo Weinhold 				info.name = STRING(image, verdaux->vda_name);
1797*003ebb0eSIngo Weinhold 			}
1798*003ebb0eSIngo Weinhold 
1799*003ebb0eSIngo Weinhold 			definition = (Elf32_Verdef*)
1800*003ebb0eSIngo Weinhold 				((uint8*)definition + definition->vd_next);
1801*003ebb0eSIngo Weinhold 		}
1802*003ebb0eSIngo Weinhold 	}
1803*003ebb0eSIngo Weinhold 
1804*003ebb0eSIngo Weinhold 	// needed versions
1805*003ebb0eSIngo Weinhold 	if (image->needed_versions != NULL) {
1806*003ebb0eSIngo Weinhold 		Elf32_Verneed* needed = image->needed_versions;
1807*003ebb0eSIngo Weinhold 		for (uint32 i = 0; i < image->num_needed_versions; i++) {
1808*003ebb0eSIngo Weinhold 			const char* fileName = STRING(image, needed->vn_file);
1809*003ebb0eSIngo Weinhold 
1810*003ebb0eSIngo Weinhold 			Elf32_Vernaux* vernaux
1811*003ebb0eSIngo Weinhold 				= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
1812*003ebb0eSIngo Weinhold 			for (uint32 k = 0; k < needed->vn_cnt; k++) {
1813*003ebb0eSIngo Weinhold 				uint32 versionIndex = VER_NDX(vernaux->vna_other);
1814*003ebb0eSIngo Weinhold 				elf_version_info& info = image->versions[versionIndex];
1815*003ebb0eSIngo Weinhold 				info.hash = vernaux->vna_hash;
1816*003ebb0eSIngo Weinhold 				info.name = STRING(image, vernaux->vna_name);
1817*003ebb0eSIngo Weinhold 				info.file_name = fileName;
1818*003ebb0eSIngo Weinhold 				info.hidden = (vernaux->vna_other & VER_NDX_FLAG_HIDDEN) != 0;
1819*003ebb0eSIngo Weinhold 
1820*003ebb0eSIngo Weinhold 				vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
1821*003ebb0eSIngo Weinhold 			}
1822*003ebb0eSIngo Weinhold 
1823*003ebb0eSIngo Weinhold 			needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
1824*003ebb0eSIngo Weinhold 		}
1825*003ebb0eSIngo Weinhold 	}
1826*003ebb0eSIngo Weinhold 
1827*003ebb0eSIngo Weinhold 	return B_OK;
1828*003ebb0eSIngo Weinhold }
1829*003ebb0eSIngo Weinhold 
1830*003ebb0eSIngo Weinhold 
1831*003ebb0eSIngo Weinhold static status_t
1832*003ebb0eSIngo Weinhold assert_defined_image_version(image_t* dependentImage, image_t* image,
1833*003ebb0eSIngo Weinhold 	const elf_version_info& neededVersion, bool weak)
1834*003ebb0eSIngo Weinhold {
1835*003ebb0eSIngo Weinhold 	// If the image doesn't have version definitions, we print a warning and
1836*003ebb0eSIngo Weinhold 	// succeed. Weird, but that's how glibc does it. Not unlikely we'll fail
1837*003ebb0eSIngo Weinhold 	// later when resolving versioned symbols.
1838*003ebb0eSIngo Weinhold 	if (image->version_definitions == NULL) {
1839*003ebb0eSIngo Weinhold 		FATAL("%s: No version information available (required by %s)\n",
1840*003ebb0eSIngo Weinhold 			image->name, dependentImage->name);
1841*003ebb0eSIngo Weinhold 		return B_OK;
1842*003ebb0eSIngo Weinhold 	}
1843*003ebb0eSIngo Weinhold 
1844*003ebb0eSIngo Weinhold 	// iterate through the defined versions to find the given one
1845*003ebb0eSIngo Weinhold 	Elf32_Verdef* definition = image->version_definitions;
1846*003ebb0eSIngo Weinhold 	for (uint32 i = 0; i < image->num_version_definitions; i++) {
1847*003ebb0eSIngo Weinhold 		uint32 versionIndex = VER_NDX(definition->vd_ndx);
1848*003ebb0eSIngo Weinhold 		elf_version_info& info = image->versions[versionIndex];
1849*003ebb0eSIngo Weinhold 
1850*003ebb0eSIngo Weinhold 		if (neededVersion.hash == info.hash
1851*003ebb0eSIngo Weinhold 			&& strcmp(neededVersion.name, info.name) == 0) {
1852*003ebb0eSIngo Weinhold 			return B_OK;
1853*003ebb0eSIngo Weinhold 		}
1854*003ebb0eSIngo Weinhold 
1855*003ebb0eSIngo Weinhold 		definition = (Elf32_Verdef*)
1856*003ebb0eSIngo Weinhold 			((uint8*)definition + definition->vd_next);
1857*003ebb0eSIngo Weinhold 	}
1858*003ebb0eSIngo Weinhold 
1859*003ebb0eSIngo Weinhold 	// version not found -- fail, if not weak
1860*003ebb0eSIngo Weinhold 	if (!weak) {
1861*003ebb0eSIngo Weinhold 		FATAL("%s: version \"%s\" not found (required by %s)\n", image->name,
1862*003ebb0eSIngo Weinhold 			neededVersion.name, dependentImage->name);
1863*003ebb0eSIngo Weinhold 		return B_MISSING_SYMBOL;
1864*003ebb0eSIngo Weinhold 	}
1865*003ebb0eSIngo Weinhold 
1866*003ebb0eSIngo Weinhold 	return B_OK;
1867*003ebb0eSIngo Weinhold }
1868*003ebb0eSIngo Weinhold 
1869*003ebb0eSIngo Weinhold 
1870*003ebb0eSIngo Weinhold static status_t
1871*003ebb0eSIngo Weinhold check_needed_image_versions(image_t* image)
1872*003ebb0eSIngo Weinhold {
1873*003ebb0eSIngo Weinhold 	if (image->needed_versions == NULL)
1874*003ebb0eSIngo Weinhold 		return B_OK;
1875*003ebb0eSIngo Weinhold 
1876*003ebb0eSIngo Weinhold 	Elf32_Verneed* needed = image->needed_versions;
1877*003ebb0eSIngo Weinhold 	for (uint32 i = 0; i < image->num_needed_versions; i++) {
1878*003ebb0eSIngo Weinhold 		const char* fileName = STRING(image, needed->vn_file);
1879*003ebb0eSIngo Weinhold 		image_t* dependency = find_image(fileName, ALL_IMAGE_TYPES);
1880*003ebb0eSIngo Weinhold 		if (dependency == NULL) {
1881*003ebb0eSIngo Weinhold 			// This can't really happen, unless the object file is broken, since
1882*003ebb0eSIngo Weinhold 			// the file should also appear in DT_NEEDED.
1883*003ebb0eSIngo Weinhold 			FATAL("Version dependency \"%s\" not found", fileName);
1884*003ebb0eSIngo Weinhold 			return B_FILE_NOT_FOUND;
1885*003ebb0eSIngo Weinhold 		}
1886*003ebb0eSIngo Weinhold 
1887*003ebb0eSIngo Weinhold 		Elf32_Vernaux* vernaux
1888*003ebb0eSIngo Weinhold 			= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
1889*003ebb0eSIngo Weinhold 		for (uint32 k = 0; k < needed->vn_cnt; k++) {
1890*003ebb0eSIngo Weinhold 			uint32 versionIndex = VER_NDX(vernaux->vna_other);
1891*003ebb0eSIngo Weinhold 			elf_version_info& info = image->versions[versionIndex];
1892*003ebb0eSIngo Weinhold 
1893*003ebb0eSIngo Weinhold 			status_t error = assert_defined_image_version(image, dependency,
1894*003ebb0eSIngo Weinhold 				info, (vernaux->vna_flags & VER_FLG_WEAK) != 0);
1895*003ebb0eSIngo Weinhold 			if (error != B_OK)
1896*003ebb0eSIngo Weinhold 				return error;
1897*003ebb0eSIngo Weinhold 
1898*003ebb0eSIngo Weinhold 			vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
1899*003ebb0eSIngo Weinhold 		}
1900*003ebb0eSIngo Weinhold 
1901*003ebb0eSIngo Weinhold 		needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
1902*003ebb0eSIngo Weinhold 	}
1903*003ebb0eSIngo Weinhold 
1904*003ebb0eSIngo Weinhold 	return B_OK;
1905*003ebb0eSIngo Weinhold }
1906*003ebb0eSIngo Weinhold 
1907*003ebb0eSIngo Weinhold 
190810b4b5d1SIngo Weinhold static void
19090c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path)
19100c0fea5dSIngo Weinhold {
19110c0fea5dSIngo Weinhold 	struct stat stat;
19120c0fea5dSIngo Weinhold 	image_info info;
19130c0fea5dSIngo Weinhold 
19140c0fea5dSIngo Weinhold 	// ToDo: set these correctly
19150c0fea5dSIngo Weinhold 	info.id = 0;
19160c0fea5dSIngo Weinhold 	info.type = image->type;
19170c0fea5dSIngo Weinhold 	info.sequence = 0;
19180c0fea5dSIngo Weinhold 	info.init_order = 0;
19190c0fea5dSIngo Weinhold 	info.init_routine = (void (*)())image->init_routine;
19200c0fea5dSIngo Weinhold 	info.term_routine = (void (*)())image->term_routine;
19210c0fea5dSIngo Weinhold 
19220c0fea5dSIngo Weinhold 	if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
19230c0fea5dSIngo Weinhold 		info.device = stat.st_dev;
19240c0fea5dSIngo Weinhold 		info.node = stat.st_ino;
19250c0fea5dSIngo Weinhold 	} else {
19260c0fea5dSIngo Weinhold 		info.device = -1;
19270c0fea5dSIngo Weinhold 		info.node = -1;
19280c0fea5dSIngo Weinhold 	}
19290c0fea5dSIngo Weinhold 
19300c0fea5dSIngo Weinhold 	strlcpy(info.name, path, sizeof(info.name));
19310c0fea5dSIngo Weinhold 	info.text = (void *)image->regions[0].vmstart;
19320c0fea5dSIngo Weinhold 	info.text_size = image->regions[0].vmsize;
19330c0fea5dSIngo Weinhold 	info.data = (void *)image->regions[1].vmstart;
19340c0fea5dSIngo Weinhold 	info.data_size = image->regions[1].vmsize;
1935593ee7bbSIngo Weinhold 	info.api_version = image->api_version;
1936593ee7bbSIngo Weinhold 	info.abi = image->abi;
19370c0fea5dSIngo Weinhold 	image->id = _kern_register_image(&info, sizeof(image_info));
19380c0fea5dSIngo Weinhold }
19390c0fea5dSIngo Weinhold 
19400c0fea5dSIngo Weinhold 
19410c0fea5dSIngo Weinhold static status_t
194246f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
19430c0fea5dSIngo Weinhold {
194446f4d849SIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image);
19450c0fea5dSIngo Weinhold 	if (status < B_OK) {
1946320bd2bdSAxel Dörfler 		FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status,
1947320bd2bdSAxel Dörfler 			image->path, image->name);
19480c0fea5dSIngo Weinhold 		return status;
19490c0fea5dSIngo Weinhold 	}
19500c0fea5dSIngo Weinhold 
19510c0fea5dSIngo Weinhold 	_kern_image_relocated(image->id);
195210b4b5d1SIngo Weinhold 	image_event(image, IMAGE_EVENT_RELOCATED);
19530c0fea5dSIngo Weinhold 	return B_OK;
19540c0fea5dSIngo Weinhold }
19550c0fea5dSIngo Weinhold 
19560c0fea5dSIngo Weinhold 
19570c0fea5dSIngo Weinhold static status_t
19580c85bd05SIngo Weinhold load_container(char const *name, image_type type, const char *rpath,
19590c85bd05SIngo Weinhold 	image_t **_image)
19600c0fea5dSIngo Weinhold {
19610c0fea5dSIngo Weinhold 	int32 pheaderSize, sheaderSize;
19620c0fea5dSIngo Weinhold 	char path[PATH_MAX];
19630c0fea5dSIngo Weinhold 	ssize_t length;
19640c0fea5dSIngo Weinhold 	char ph_buff[4096];
19650c0fea5dSIngo Weinhold 	int32 numRegions;
19660c0fea5dSIngo Weinhold 	image_t *found;
19670c0fea5dSIngo Weinhold 	image_t *image;
19680c0fea5dSIngo Weinhold 	status_t status;
19690c0fea5dSIngo Weinhold 	int fd;
19700c0fea5dSIngo Weinhold 
19710c0fea5dSIngo Weinhold 	struct Elf32_Ehdr eheader;
19720c0fea5dSIngo Weinhold 
19730c0fea5dSIngo Weinhold 	// Have we already loaded that image? Don't check for add-ons -- we always
19740c0fea5dSIngo Weinhold 	// reload them.
19750c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
19760c0fea5dSIngo Weinhold 		found = find_image(name, APP_OR_LIBRARY_TYPE);
197702e577f9SIngo Weinhold 
197802e577f9SIngo Weinhold 		if (found == NULL && type != B_APP_IMAGE) {
197902e577f9SIngo Weinhold 			// Special case for add-ons that link against the application
198002e577f9SIngo Weinhold 			// executable, with the executable not having a soname set.
198102e577f9SIngo Weinhold 			if (const char* lastSlash = strrchr(name, '/')) {
198202e577f9SIngo Weinhold 				image_t* programImage = get_program_image();
198302e577f9SIngo Weinhold 				if (strcmp(programImage->name, lastSlash + 1) == 0)
198402e577f9SIngo Weinhold 					found = programImage;
198502e577f9SIngo Weinhold 			}
198602e577f9SIngo Weinhold 		}
198702e577f9SIngo Weinhold 
19880c0fea5dSIngo Weinhold 		if (found) {
19890c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
19900c0fea5dSIngo Weinhold 			*_image = found;
19917486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") "
19927486b72dSIngo Weinhold 				"already loaded", name, type, rpath);
19930c0fea5dSIngo Weinhold 			return B_OK;
19940c0fea5dSIngo Weinhold 		}
19950c0fea5dSIngo Weinhold 	}
19960c0fea5dSIngo Weinhold 
19977486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type,
19987486b72dSIngo Weinhold 		rpath);
19997486b72dSIngo Weinhold 
20000c0fea5dSIngo Weinhold 	strlcpy(path, name, sizeof(path));
20010c0fea5dSIngo Weinhold 
200261b37794SIngo Weinhold 	// find and open the file
200361b37794SIngo Weinhold 	fd = open_executable(path, type, rpath, get_program_path(),
200461b37794SIngo Weinhold 		sSearchPathSubDir);
20050c0fea5dSIngo Weinhold 	if (fd < 0) {
200602e577f9SIngo Weinhold 		FATAL("cannot open file %s\n", name);
20077486b72dSIngo Weinhold 		KTRACE("rld: load_container(\"%s\"): failed to open file", name);
20080c0fea5dSIngo Weinhold 		return fd;
20090c0fea5dSIngo Weinhold 	}
20100c0fea5dSIngo Weinhold 
20116918dbf4SIngo Weinhold 	// normalize the image path
20126918dbf4SIngo Weinhold 	status = _kern_normalize_path(path, true, path);
20136918dbf4SIngo Weinhold 	if (status != B_OK)
20140c0fea5dSIngo Weinhold 		goto err1;
20150c0fea5dSIngo Weinhold 
20160c0fea5dSIngo Weinhold 	// Test again if this image has been registered already - this time,
20170c0fea5dSIngo Weinhold 	// we can check the full path, not just its name as noted.
20180c0fea5dSIngo Weinhold 	// You could end up loading an image twice with symbolic links, else.
20190c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
20200c0fea5dSIngo Weinhold 		found = find_image(path, APP_OR_LIBRARY_TYPE);
20210c0fea5dSIngo Weinhold 		if (found) {
20220c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
20230c0fea5dSIngo Weinhold 			*_image = found;
2024b2568a30SIngo Weinhold 			_kern_close(fd);
20257486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\"): already loaded after all",
20267486b72dSIngo Weinhold 				name);
20270c0fea5dSIngo Weinhold 			return B_OK;
20280c0fea5dSIngo Weinhold 		}
20290c0fea5dSIngo Weinhold 	}
20300c0fea5dSIngo Weinhold 
20310c0fea5dSIngo Weinhold 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
20320c0fea5dSIngo Weinhold 	if (length != sizeof(eheader)) {
20330c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
20340c0fea5dSIngo Weinhold 		FATAL("troubles reading ELF header\n");
20350c0fea5dSIngo Weinhold 		goto err1;
20360c0fea5dSIngo Weinhold 	}
20370c0fea5dSIngo Weinhold 
20380c0fea5dSIngo Weinhold 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
20390c0fea5dSIngo Weinhold 	if (status < B_OK) {
20400c0fea5dSIngo Weinhold 		FATAL("incorrect ELF header\n");
20410c0fea5dSIngo Weinhold 		goto err1;
20420c0fea5dSIngo Weinhold 	}
20430c0fea5dSIngo Weinhold 
20440c0fea5dSIngo Weinhold 	// ToDo: what to do about this restriction??
20450c0fea5dSIngo Weinhold 	if (pheaderSize > (int)sizeof(ph_buff)) {
20460c0fea5dSIngo Weinhold 		FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff));
20470c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
20480c0fea5dSIngo Weinhold 		goto err1;
20490c0fea5dSIngo Weinhold 	}
20500c0fea5dSIngo Weinhold 
20510c0fea5dSIngo Weinhold 	length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize);
20520c0fea5dSIngo Weinhold 	if (length != pheaderSize) {
20530c0fea5dSIngo Weinhold 		FATAL("Could not read program headers: %s\n", strerror(length));
20540c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
20550c0fea5dSIngo Weinhold 		goto err1;
20560c0fea5dSIngo Weinhold 	}
20570c0fea5dSIngo Weinhold 
20580c0fea5dSIngo Weinhold 	numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
20590c0fea5dSIngo Weinhold 	if (numRegions <= 0) {
20600c0fea5dSIngo Weinhold 		FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
20610c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
20620c0fea5dSIngo Weinhold 		goto err1;
20630c0fea5dSIngo Weinhold 	}
20640c0fea5dSIngo Weinhold 
20650c0fea5dSIngo Weinhold 	image = create_image(name, path, numRegions);
20660c0fea5dSIngo Weinhold 	if (image == NULL) {
20670c0fea5dSIngo Weinhold 		FATAL("Failed to allocate image_t object\n");
20680c0fea5dSIngo Weinhold 		status = B_NO_MEMORY;
20690c0fea5dSIngo Weinhold 		goto err1;
20700c0fea5dSIngo Weinhold 	}
20710c0fea5dSIngo Weinhold 
20720c0fea5dSIngo Weinhold 	status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
20730c0fea5dSIngo Weinhold 	if (status < B_OK)
20740c0fea5dSIngo Weinhold 		goto err2;
20750c0fea5dSIngo Weinhold 
20760c0fea5dSIngo Weinhold 	if (!assert_dynamic_loadable(image)) {
20770c0fea5dSIngo Weinhold 		FATAL("Dynamic segment must be loadable (implementation restriction)\n");
20780c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
20790c0fea5dSIngo Weinhold 		goto err2;
20800c0fea5dSIngo Weinhold 	}
20810c0fea5dSIngo Weinhold 
2082593ee7bbSIngo Weinhold 	status = map_image(fd, path, image, type == B_APP_IMAGE);
2083593ee7bbSIngo Weinhold 	if (status < B_OK) {
2084593ee7bbSIngo Weinhold 		FATAL("Could not map image: %s\n", strerror(status));
2085593ee7bbSIngo Weinhold 		status = B_ERROR;
2086593ee7bbSIngo Weinhold 		goto err2;
2087593ee7bbSIngo Weinhold 	}
2088593ee7bbSIngo Weinhold 
2089593ee7bbSIngo Weinhold 	if (!parse_dynamic_segment(image)) {
2090593ee7bbSIngo Weinhold 		FATAL("Troubles handling dynamic section\n");
2091593ee7bbSIngo Weinhold 		status = B_BAD_DATA;
2092593ee7bbSIngo Weinhold 		goto err3;
2093593ee7bbSIngo Weinhold 	}
2094593ee7bbSIngo Weinhold 
2095593ee7bbSIngo Weinhold 	if (eheader.e_entry != 0)
2096593ee7bbSIngo Weinhold 		image->entry_point = eheader.e_entry + image->regions[0].delta;
2097593ee7bbSIngo Weinhold 
2098593ee7bbSIngo Weinhold 	analyze_image_haiku_version_and_abi(image);
2099593ee7bbSIngo Weinhold 
2100f91194e5SIngo Weinhold 	if (image->abi == 0) {
2101f91194e5SIngo Weinhold 		// No ABI version in the shared object, i.e. it has been built before
2102f91194e5SIngo Weinhold 		// that was introduced in Haiku. We have to try and analyze the gcc
2103f91194e5SIngo Weinhold 		// version.
2104f91194e5SIngo Weinhold 		if (!analyze_object_gcc_version(fd, image, eheader, sheaderSize,
2105f91194e5SIngo Weinhold 				ph_buff, sizeof(ph_buff))) {
2106f91194e5SIngo Weinhold 			FATAL("Failed to get gcc version for %s\n", path);
2107f91194e5SIngo Weinhold 				// not really fatal, actually
2108f91194e5SIngo Weinhold 
2109f91194e5SIngo Weinhold 			// assume ancient BeOS
2110f91194e5SIngo Weinhold 			image->abi = B_HAIKU_ABI_GCC_2_ANCIENT;
2111f91194e5SIngo Weinhold 		}
2112f91194e5SIngo Weinhold 	}
2113f91194e5SIngo Weinhold 
2114f91194e5SIngo Weinhold 	// guess the API version, if we couldn't figure it out yet
2115f91194e5SIngo Weinhold 	if (image->api_version == 0) {
2116f91194e5SIngo Weinhold 		image->api_version = image->abi > B_HAIKU_ABI_GCC_2_BEOS
2117f91194e5SIngo Weinhold 			? HAIKU_VERSION_PRE_GLUE_CODE : B_HAIKU_VERSION_BEOS;
2118f91194e5SIngo Weinhold 	}
2119f91194e5SIngo Weinhold 
212061b37794SIngo Weinhold 	// If this is the executable image, we init the search path
212161b37794SIngo Weinhold 	// subdir, if the compiler version doesn't match ours.
212261b37794SIngo Weinhold 	if (type == B_APP_IMAGE) {
212361b37794SIngo Weinhold 		#if __GNUC__ == 2
2124f91194e5SIngo Weinhold 			if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_4)
212561b37794SIngo Weinhold 				sSearchPathSubDir = "gcc4";
212661b37794SIngo Weinhold 		#elif __GNUC__ == 4
2127f91194e5SIngo Weinhold 			if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2)
212861b37794SIngo Weinhold 				sSearchPathSubDir = "gcc2";
212961b37794SIngo Weinhold 		#endif
213061b37794SIngo Weinhold 	}
213134982809SIngo Weinhold 
21325fd6637bSIngo Weinhold 	// init gcc version dependent image flags
2133f91194e5SIngo Weinhold 	// symbol resolution strategy
2134f91194e5SIngo Weinhold 	if (image->abi == B_HAIKU_ABI_GCC_2_ANCIENT)
21350c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_beos;
21365fd6637bSIngo Weinhold 
2137*003ebb0eSIngo Weinhold 	// init version infos
2138*003ebb0eSIngo Weinhold 	status = init_image_version_infos(image);
2139*003ebb0eSIngo Weinhold 
21400c0fea5dSIngo Weinhold 	image->type = type;
21410c0fea5dSIngo Weinhold 	register_image(image, fd, path);
214210b4b5d1SIngo Weinhold 	image_event(image, IMAGE_EVENT_LOADED);
21430c0fea5dSIngo Weinhold 
21440c0fea5dSIngo Weinhold 	_kern_close(fd);
21450c0fea5dSIngo Weinhold 
21460c0fea5dSIngo Weinhold 	enqueue_image(&sLoadedImages, image);
21470c0fea5dSIngo Weinhold 	sLoadedImageCount++;
21480c0fea5dSIngo Weinhold 
21490c0fea5dSIngo Weinhold 	*_image = image;
21507486b72dSIngo Weinhold 
2151f91194e5SIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): done: id: %ld (ABI: %#lx)", name,
2152f91194e5SIngo Weinhold 		image->id, image->abi);
21537486b72dSIngo Weinhold 
21540c0fea5dSIngo Weinhold 	return B_OK;
21550c0fea5dSIngo Weinhold 
21560c0fea5dSIngo Weinhold err3:
21570c0fea5dSIngo Weinhold 	unmap_image(image);
21580c0fea5dSIngo Weinhold err2:
21590c0fea5dSIngo Weinhold 	delete_image_struct(image);
21600c0fea5dSIngo Weinhold err1:
21610c0fea5dSIngo Weinhold 	_kern_close(fd);
21627486b72dSIngo Weinhold 
21637486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): failed: %s", name,
21647486b72dSIngo Weinhold 		strerror(status));
21657486b72dSIngo Weinhold 
21660c0fea5dSIngo Weinhold 	return status;
21670c0fea5dSIngo Weinhold }
21680c0fea5dSIngo Weinhold 
21690c0fea5dSIngo Weinhold 
21700c0fea5dSIngo Weinhold static const char *
21710c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
21720c0fea5dSIngo Weinhold {
21730c0fea5dSIngo Weinhold 	int i;
21740c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
21750c0fea5dSIngo Weinhold 
21760c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
21770c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
21780c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
21790c0fea5dSIngo Weinhold 	}
21800c0fea5dSIngo Weinhold 
21810c0fea5dSIngo Weinhold 	return NULL;
21820c0fea5dSIngo Weinhold }
21830c0fea5dSIngo Weinhold 
21840c0fea5dSIngo Weinhold 
21850c0fea5dSIngo Weinhold static status_t
21860c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image)
21870c0fea5dSIngo Weinhold {
21880c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
21894bef3723SAxel Dörfler 	bool reportErrors = report_errors();
219074c0424aSAxel Dörfler 	status_t status = B_OK;
21910c0fea5dSIngo Weinhold 	uint32 i, j;
21920c0fea5dSIngo Weinhold 	const char *rpath;
21930c0fea5dSIngo Weinhold 
21940c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
21950c0fea5dSIngo Weinhold 		return B_OK;
21960c0fea5dSIngo Weinhold 
21970c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
21980c0fea5dSIngo Weinhold 
21990c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
22000c0fea5dSIngo Weinhold 		return B_OK;
22010c0fea5dSIngo Weinhold 
22027486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
22037486b72dSIngo Weinhold 		image->id);
22047486b72dSIngo Weinhold 
22050c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
22060c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
22070c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
22087486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
22097486b72dSIngo Weinhold 			image->name, image->id);
22100c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
22110c0fea5dSIngo Weinhold 	}
22120c0fea5dSIngo Weinhold 
22130c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
22140c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
22150c0fea5dSIngo Weinhold 
22160c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
22170c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
22180c0fea5dSIngo Weinhold 			case DT_NEEDED:
221974c0424aSAxel Dörfler 			{
222074c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
222174c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
22220c0fea5dSIngo Weinhold 
222374c0424aSAxel Dörfler 				status_t loadStatus = load_container(name, B_LIBRARY_IMAGE,
222474c0424aSAxel Dörfler 					rpath, &image->needed[j]);
222574c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
222674c0424aSAxel Dörfler 					status = loadStatus;
222774c0424aSAxel Dörfler 					// correct error code in case the file could not been found
222874c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
222974c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
223074c0424aSAxel Dörfler 
223174c0424aSAxel Dörfler 						if (reportErrors)
223274c0424aSAxel Dörfler 							sErrorMessage.AddString("missing library", name);
223374c0424aSAxel Dörfler 					}
223474c0424aSAxel Dörfler 
223574c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
22367486b72dSIngo Weinhold 					if (!reportErrors) {
22377486b72dSIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
22387486b72dSIngo Weinhold 							"failed: %s", image->name, image->id,
22397486b72dSIngo Weinhold 							strerror(status));
22400c0fea5dSIngo Weinhold 						return status;
224174c0424aSAxel Dörfler 					}
22427486b72dSIngo Weinhold 				}
22430c0fea5dSIngo Weinhold 
22440c0fea5dSIngo Weinhold 				j += 1;
22450c0fea5dSIngo Weinhold 				break;
224674c0424aSAxel Dörfler 			}
22470c0fea5dSIngo Weinhold 
22480c0fea5dSIngo Weinhold 			default:
22490c0fea5dSIngo Weinhold 				// ignore any other tag
22500c0fea5dSIngo Weinhold 				continue;
22510c0fea5dSIngo Weinhold 		}
22520c0fea5dSIngo Weinhold 	}
22530c0fea5dSIngo Weinhold 
22547486b72dSIngo Weinhold 	if (status < B_OK) {
22557486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
22567486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
22577486b72dSIngo Weinhold 			strerror(status));
225874c0424aSAxel Dörfler 		return status;
22597486b72dSIngo Weinhold 	}
226074c0424aSAxel Dörfler 
22610c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
22620c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
22637486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
22647486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
22650c0fea5dSIngo Weinhold 		return B_ERROR;
22660c0fea5dSIngo Weinhold 	}
22670c0fea5dSIngo Weinhold 
22687486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
22697486b72dSIngo Weinhold 		image->id);
22707486b72dSIngo Weinhold 
22710c0fea5dSIngo Weinhold 	return B_OK;
22720c0fea5dSIngo Weinhold }
22730c0fea5dSIngo Weinhold 
22740c0fea5dSIngo Weinhold 
22750c85bd05SIngo Weinhold static status_t
22760c85bd05SIngo Weinhold load_dependencies(image_t* image)
22770c85bd05SIngo Weinhold {
2278*003ebb0eSIngo Weinhold 	// load dependencies (breadth-first)
22790c85bd05SIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
22800c85bd05SIngo Weinhold 			otherImage = otherImage->next) {
22810c85bd05SIngo Weinhold 		status_t status = load_immediate_dependencies(otherImage);
22820c85bd05SIngo Weinhold 		if (status != B_OK)
22830c85bd05SIngo Weinhold 			return status;
22840c85bd05SIngo Weinhold 	}
22850c85bd05SIngo Weinhold 
2286*003ebb0eSIngo Weinhold 	// Check the needed versions for the given image and all newly loaded
2287*003ebb0eSIngo Weinhold 	// dependencies.
2288*003ebb0eSIngo Weinhold 	for (image_t* otherImage = image; otherImage != NULL;
2289*003ebb0eSIngo Weinhold 			otherImage = otherImage->next) {
2290*003ebb0eSIngo Weinhold 		status_t status = check_needed_image_versions(otherImage);
2291*003ebb0eSIngo Weinhold 		if (status != B_OK)
2292*003ebb0eSIngo Weinhold 			return status;
2293*003ebb0eSIngo Weinhold 	}
2294*003ebb0eSIngo Weinhold 
22950c85bd05SIngo Weinhold 	return B_OK;
22960c85bd05SIngo Weinhold }
22970c85bd05SIngo Weinhold 
22980c85bd05SIngo Weinhold 
22990c0fea5dSIngo Weinhold static uint32
23000c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList,
23010c0fea5dSIngo Weinhold 	uint32 sortFlag)
23020c0fea5dSIngo Weinhold {
23030c0fea5dSIngo Weinhold 	uint32 i;
23040c0fea5dSIngo Weinhold 
23050c0fea5dSIngo Weinhold 	if (image->flags & sortFlag)
23060c0fea5dSIngo Weinhold 		return slot;
23070c0fea5dSIngo Weinhold 
23080c0fea5dSIngo Weinhold 	image->flags |= sortFlag; /* make sure we don't visit this one */
23090c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_needed; i++)
23100c0fea5dSIngo Weinhold 		slot = topological_sort(image->needed[i], slot, initList, sortFlag);
23110c0fea5dSIngo Weinhold 
23120c0fea5dSIngo Weinhold 	initList[slot] = image;
23130c0fea5dSIngo Weinhold 	return slot + 1;
23140c0fea5dSIngo Weinhold }
23150c0fea5dSIngo Weinhold 
23160c0fea5dSIngo Weinhold 
23170c0fea5dSIngo Weinhold static ssize_t
23180c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
23190c0fea5dSIngo Weinhold {
23200c0fea5dSIngo Weinhold 	image_t **list;
23210c0fea5dSIngo Weinhold 
23220c0fea5dSIngo Weinhold 	list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *));
23230c0fea5dSIngo Weinhold 	if (list == NULL) {
23240c0fea5dSIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
23250c0fea5dSIngo Weinhold 		*_list = NULL;
23260c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
23270c0fea5dSIngo Weinhold 	}
23280c0fea5dSIngo Weinhold 
23290c0fea5dSIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
23300c0fea5dSIngo Weinhold 
23310c0fea5dSIngo Weinhold 	*_list = list;
23320c0fea5dSIngo Weinhold 	return topological_sort(image, 0, list, sortFlag);
23330c0fea5dSIngo Weinhold }
23340c0fea5dSIngo Weinhold 
23350c0fea5dSIngo Weinhold 
23360c0fea5dSIngo Weinhold static status_t
23370c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
23380c0fea5dSIngo Weinhold {
2339ca618b22SIngo Weinhold 	// get the images that still have to be relocated
2340ca618b22SIngo Weinhold 	image_t **list;
2341ca618b22SIngo Weinhold 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
23420c0fea5dSIngo Weinhold 	if (count < B_OK)
23430c0fea5dSIngo Weinhold 		return count;
23440c0fea5dSIngo Weinhold 
23450c85bd05SIngo Weinhold 	// relocate
2346ca618b22SIngo Weinhold 	for (ssize_t i = 0; i < count; i++) {
234746f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
23480c85bd05SIngo Weinhold 		if (status < B_OK) {
23490c85bd05SIngo Weinhold 			free(list);
23500c0fea5dSIngo Weinhold 			return status;
23510c0fea5dSIngo Weinhold 		}
23520c85bd05SIngo Weinhold 	}
23530c0fea5dSIngo Weinhold 
23540c0fea5dSIngo Weinhold 	free(list);
23550c0fea5dSIngo Weinhold 	return B_OK;
23560c0fea5dSIngo Weinhold }
23570c0fea5dSIngo Weinhold 
23580c0fea5dSIngo Weinhold 
23590c0fea5dSIngo Weinhold static void
23600c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
23610c0fea5dSIngo Weinhold {
23620c0fea5dSIngo Weinhold 	image_t **initList;
23630c0fea5dSIngo Weinhold 	ssize_t count, i;
23640c0fea5dSIngo Weinhold 
23650c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
23660c0fea5dSIngo Weinhold 	if (count <= 0)
23670c0fea5dSIngo Weinhold 		return;
23680c0fea5dSIngo Weinhold 
23690c0fea5dSIngo Weinhold 	if (!initHead) {
23700c0fea5dSIngo Weinhold 		// this removes the "calling" image
23710c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
23720c0fea5dSIngo Weinhold 		initList[--count] = NULL;
23730c0fea5dSIngo Weinhold 	}
23740c0fea5dSIngo Weinhold 
23750c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
23760c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
23770c0fea5dSIngo Weinhold 		image = initList[i];
23780c0fea5dSIngo Weinhold 
23790c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
23800c0fea5dSIngo Weinhold 
2381dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
23820c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
238310b4b5d1SIngo Weinhold 
238410b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
23850c0fea5dSIngo Weinhold 	}
23860c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
23870c0fea5dSIngo Weinhold 
23880c0fea5dSIngo Weinhold 	free(initList);
23890c0fea5dSIngo Weinhold }
23900c0fea5dSIngo Weinhold 
23910c0fea5dSIngo Weinhold 
23920c0fea5dSIngo Weinhold static void
23930c0fea5dSIngo Weinhold put_image(image_t *image)
23940c0fea5dSIngo Weinhold {
23950c0fea5dSIngo Weinhold 	// If all references to the image are gone, add it to the disposable list
23960c0fea5dSIngo Weinhold 	// and remove all dependencies
23970c0fea5dSIngo Weinhold 
23980c0fea5dSIngo Weinhold 	if (atomic_add(&image->ref_count, -1) == 1) {
23990c0fea5dSIngo Weinhold 		size_t i;
24000c0fea5dSIngo Weinhold 
24010c0fea5dSIngo Weinhold 		dequeue_image(&sLoadedImages, image);
24020c0fea5dSIngo Weinhold 		enqueue_image(&sDisposableImages, image);
24030c0fea5dSIngo Weinhold 		sLoadedImageCount--;
24040c0fea5dSIngo Weinhold 
24050c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_needed; i++) {
24060c0fea5dSIngo Weinhold 			put_image(image->needed[i]);
24070c0fea5dSIngo Weinhold 		}
24080c0fea5dSIngo Weinhold 	}
24090c0fea5dSIngo Weinhold }
24100c0fea5dSIngo Weinhold 
24110c0fea5dSIngo Weinhold 
2412ca618b22SIngo Weinhold void
2413ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
2414ca618b22SIngo Weinhold {
2415ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
2416ca618b22SIngo Weinhold 	// API.
2417ca618b22SIngo Weinhold 	image_t* image;
24180c85bd05SIngo Weinhold 	void* _export;
2419*003ebb0eSIngo Weinhold 	if (find_symbol_breadth_first(rootImage,
2420*003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
2421*003ebb0eSIngo Weinhold 			&_export) == B_OK) {
24220c85bd05SIngo Weinhold 		*(void**)_export = &gRuntimeLoader;
2423ca618b22SIngo Weinhold 	}
2424ca618b22SIngo Weinhold }
2425ca618b22SIngo Weinhold 
2426ca618b22SIngo Weinhold 
2427ca618b22SIngo Weinhold static status_t
2428ca618b22SIngo Weinhold add_preloaded_image(image_t* image)
2429ca618b22SIngo Weinhold {
2430ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
2431ca618b22SIngo Weinhold 	// small number of preloaded images.
2432ca618b22SIngo Weinhold 	image_t** newArray = (image_t**)realloc(sPreloadedImages,
2433ca618b22SIngo Weinhold 		sizeof(image_t*) * (sPreloadedImageCount + 1));
2434ca618b22SIngo Weinhold 	if (newArray == NULL)
2435ca618b22SIngo Weinhold 		return B_NO_MEMORY;
2436ca618b22SIngo Weinhold 
2437ca618b22SIngo Weinhold 	sPreloadedImages = newArray;
2438ca618b22SIngo Weinhold 	newArray[sPreloadedImageCount++] = image;
2439ca618b22SIngo Weinhold 
2440ca618b22SIngo Weinhold 	return B_OK;
2441ca618b22SIngo Weinhold }
2442ca618b22SIngo Weinhold 
2443ca618b22SIngo Weinhold 
2444ca618b22SIngo Weinhold image_id
2445ca618b22SIngo Weinhold preload_image(char const* path)
2446ca618b22SIngo Weinhold {
2447ca618b22SIngo Weinhold 	if (path == NULL)
2448ca618b22SIngo Weinhold 		return B_BAD_VALUE;
2449ca618b22SIngo Weinhold 
2450ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\")", path);
2451ca618b22SIngo Weinhold 
2452ca618b22SIngo Weinhold 	image_t *image = NULL;
2453ca618b22SIngo Weinhold 	status_t status = load_container(path, B_ADD_ON_IMAGE, NULL, &image);
2454ca618b22SIngo Weinhold 	if (status < B_OK) {
2455ca618b22SIngo Weinhold 		rld_unlock();
2456ca618b22SIngo Weinhold 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
2457ca618b22SIngo Weinhold 			strerror(status));
2458ca618b22SIngo Weinhold 		return status;
2459ca618b22SIngo Weinhold 	}
2460ca618b22SIngo Weinhold 
24610c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL)
24620c85bd05SIngo Weinhold 		image->find_undefined_symbol = find_undefined_symbol_global;
24630c85bd05SIngo Weinhold 
24640c85bd05SIngo Weinhold 	status = load_dependencies(image);
2465ca618b22SIngo Weinhold 	if (status < B_OK)
2466ca618b22SIngo Weinhold 		goto err;
24670c85bd05SIngo Weinhold 
24680c85bd05SIngo Weinhold 	set_image_flags_recursively(image, RTLD_GLOBAL);
2469ca618b22SIngo Weinhold 
2470ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
2471ca618b22SIngo Weinhold 	if (status < B_OK)
2472ca618b22SIngo Weinhold 		goto err;
2473ca618b22SIngo Weinhold 
2474ca618b22SIngo Weinhold 	status = add_preloaded_image(image);
2475ca618b22SIngo Weinhold 	if (status < B_OK)
2476ca618b22SIngo Weinhold 		goto err;
2477ca618b22SIngo Weinhold 
2478ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
2479ca618b22SIngo Weinhold 
2480ca618b22SIngo Weinhold 	remap_images();
2481ca618b22SIngo Weinhold 	init_dependencies(image, true);
2482ca618b22SIngo Weinhold 
248310b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
248410b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
2485*003ebb0eSIngo Weinhold 	if (find_symbol(image,
2486*003ebb0eSIngo Weinhold 			SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
248710b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
248810b4b5d1SIngo Weinhold 		RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image,
248910b4b5d1SIngo Weinhold 			addOnStruct);
249010b4b5d1SIngo Weinhold 		if (addOn != NULL) {
249110b4b5d1SIngo Weinhold 			sAddOns.Add(addOn);
249210b4b5d1SIngo Weinhold 			addOnStruct->init(&gRuntimeLoader, &gRuntimeLoaderAddOnExport);
249310b4b5d1SIngo Weinhold 		}
249410b4b5d1SIngo Weinhold 	}
249510b4b5d1SIngo Weinhold 
2496ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id);
2497ca618b22SIngo Weinhold 
2498ca618b22SIngo Weinhold 	return image->id;
2499ca618b22SIngo Weinhold 
2500ca618b22SIngo Weinhold err:
2501ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status));
2502ca618b22SIngo Weinhold 
2503ca618b22SIngo Weinhold 	dequeue_image(&sLoadedImages, image);
2504ca618b22SIngo Weinhold 	sLoadedImageCount--;
2505ca618b22SIngo Weinhold 	delete_image(image);
2506ca618b22SIngo Weinhold 	return status;
2507ca618b22SIngo Weinhold }
2508ca618b22SIngo Weinhold 
2509ca618b22SIngo Weinhold 
2510ca618b22SIngo Weinhold static void
2511ca618b22SIngo Weinhold preload_images()
2512ca618b22SIngo Weinhold {
2513ca618b22SIngo Weinhold 	const char* imagePaths = getenv("LD_PRELOAD");
2514ca618b22SIngo Weinhold 	if (imagePaths == NULL)
2515ca618b22SIngo Weinhold 		return;
2516ca618b22SIngo Weinhold 
2517ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
2518ca618b22SIngo Weinhold 		// find begin of image path
2519ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
2520ca618b22SIngo Weinhold 			imagePaths++;
2521ca618b22SIngo Weinhold 
2522ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
2523ca618b22SIngo Weinhold 			break;
2524ca618b22SIngo Weinhold 
2525ca618b22SIngo Weinhold 		// find end of image path
2526ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
2527ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
2528ca618b22SIngo Weinhold 			imagePaths++;
2529ca618b22SIngo Weinhold 
2530ca618b22SIngo Weinhold 		// extract the path
2531ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
2532ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
2533ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
2534ca618b22SIngo Weinhold 			continue;
2535ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
2536ca618b22SIngo Weinhold 		path[pathLen] = '\0';
2537ca618b22SIngo Weinhold 
2538ca618b22SIngo Weinhold 		// load the image
2539ca618b22SIngo Weinhold 		preload_image(path);
2540ca618b22SIngo Weinhold 	}
2541ca618b22SIngo Weinhold }
2542ca618b22SIngo Weinhold 
2543ca618b22SIngo Weinhold 
254474c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
25450c0fea5dSIngo Weinhold 
25460c0fea5dSIngo Weinhold 
25470c0fea5dSIngo Weinhold image_id
25480c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
25490c0fea5dSIngo Weinhold {
25500c0fea5dSIngo Weinhold 	status_t status;
25510c0fea5dSIngo Weinhold 	image_t *image;
25520c0fea5dSIngo Weinhold 
25537486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
25547486b72dSIngo Weinhold 
25550c0fea5dSIngo Weinhold 	rld_lock();
25560c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
25570c0fea5dSIngo Weinhold 
2558ca618b22SIngo Weinhold 	preload_images();
2559ca618b22SIngo Weinhold 
25600c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
25610c0fea5dSIngo Weinhold 
25620c0fea5dSIngo Weinhold 	status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage);
256374c0424aSAxel Dörfler 	if (status < B_OK)
256474c0424aSAxel Dörfler 		goto err;
25650c0fea5dSIngo Weinhold 
25660c85bd05SIngo Weinhold 	if (sProgramImage->find_undefined_symbol == NULL)
25670c85bd05SIngo Weinhold 		sProgramImage->find_undefined_symbol = find_undefined_symbol_global;
25680c85bd05SIngo Weinhold 
25690c85bd05SIngo Weinhold 	status = load_dependencies(sProgramImage);
25700c0fea5dSIngo Weinhold 	if (status < B_OK)
25710c0fea5dSIngo Weinhold 		goto err;
25720c85bd05SIngo Weinhold 
257347bc6663SIngo Weinhold 	// Set RTLD_GLOBAL on all libraries including the program.
25740c85bd05SIngo Weinhold 	// This results in the desired symbol resolution for dlopen()ed libraries.
25750c85bd05SIngo Weinhold 	set_image_flags_recursively(sProgramImage, RTLD_GLOBAL);
25760c0fea5dSIngo Weinhold 
25770c0fea5dSIngo Weinhold 	status = relocate_dependencies(sProgramImage);
25780c0fea5dSIngo Weinhold 	if (status < B_OK)
25790c0fea5dSIngo Weinhold 		goto err;
25800c0fea5dSIngo Weinhold 
2581ca618b22SIngo Weinhold 	inject_runtime_loader_api(sProgramImage);
25820c0fea5dSIngo Weinhold 
25830c0fea5dSIngo Weinhold 	remap_images();
2584ca618b22SIngo Weinhold 	init_dependencies(sProgramImage, true);
25850c0fea5dSIngo Weinhold 
25860c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
25870c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
2588*003ebb0eSIngo Weinhold 	find_symbol_breadth_first(sProgramImage,
2589*003ebb0eSIngo Weinhold 		SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
2590*003ebb0eSIngo Weinhold 		(void**)&gGetEnv);
25910c0fea5dSIngo Weinhold 
2592dd76bc97SIngo Weinhold 	if (sProgramImage->entry_point == 0) {
25930c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
25940c0fea5dSIngo Weinhold 		goto err;
25950c0fea5dSIngo Weinhold 	}
25960c0fea5dSIngo Weinhold 
25970c0fea5dSIngo Weinhold 	*_entry = (void *)(sProgramImage->entry_point);
25980c0fea5dSIngo Weinhold 
25990c0fea5dSIngo Weinhold 	rld_unlock();
26007486b72dSIngo Weinhold 
26015d0638bfSIngo Weinhold 	sProgramLoaded = true;
26025d0638bfSIngo Weinhold 
26037486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
26047486b72dSIngo Weinhold 		*_entry, sProgramImage->id);
26057486b72dSIngo Weinhold 
26060c0fea5dSIngo Weinhold 	return sProgramImage->id;
26070c0fea5dSIngo Weinhold 
26080c0fea5dSIngo Weinhold err:
26097486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
26107486b72dSIngo Weinhold 
26110c0fea5dSIngo Weinhold 	delete_image(sProgramImage);
261274c0424aSAxel Dörfler 
26134bef3723SAxel Dörfler 	if (report_errors()) {
26144bef3723SAxel Dörfler 		// send error message
261574c0424aSAxel Dörfler 		sErrorMessage.AddInt32("error", status);
26164bef3723SAxel Dörfler 		sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
26174bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
26184bef3723SAxel Dörfler 
26194bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
26204bef3723SAxel Dörfler 			sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0);
262174c0424aSAxel Dörfler 	}
262274c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
26230c0fea5dSIngo Weinhold 	rld_unlock();
262474c0424aSAxel Dörfler 
26250c0fea5dSIngo Weinhold 	return status;
26260c0fea5dSIngo Weinhold }
26270c0fea5dSIngo Weinhold 
26280c0fea5dSIngo Weinhold 
26290c0fea5dSIngo Weinhold image_id
26300c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle)
26310c0fea5dSIngo Weinhold {
26320c0fea5dSIngo Weinhold 	image_t *image = NULL;
26330c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
26340c0fea5dSIngo Weinhold 	status_t status;
26350c0fea5dSIngo Weinhold 
26360c85bd05SIngo Weinhold 	if (path == NULL && addOn)
26370c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
26380c0fea5dSIngo Weinhold 
26397486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
26407486b72dSIngo Weinhold 
26410c0fea5dSIngo Weinhold 	rld_lock();
26420c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
26430c0fea5dSIngo Weinhold 
26440c0fea5dSIngo Weinhold 	// have we already loaded this library?
26450c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
26460c0fea5dSIngo Weinhold 	if (!addOn) {
26470c85bd05SIngo Weinhold 		// a NULL path is fine -- it means the global scope shall be opened
26480c85bd05SIngo Weinhold 		if (path == NULL) {
26490c85bd05SIngo Weinhold 			*_handle = RLD_GLOBAL_SCOPE;
26500c85bd05SIngo Weinhold 			rld_unlock();
26510c85bd05SIngo Weinhold 			return 0;
26520c85bd05SIngo Weinhold 		}
26530c85bd05SIngo Weinhold 
26540c0fea5dSIngo Weinhold 		image = find_image(path, APP_OR_LIBRARY_TYPE);
26550c85bd05SIngo Weinhold 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
26560c85bd05SIngo Weinhold 			set_image_flags_recursively(image, RTLD_GLOBAL);
26570c85bd05SIngo Weinhold 
26580c0fea5dSIngo Weinhold 		if (image) {
26590c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
26600c0fea5dSIngo Weinhold 			rld_unlock();
26617486b72dSIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
26627486b72dSIngo Weinhold 				image->id);
26630c85bd05SIngo Weinhold 			*_handle = image;
26640c0fea5dSIngo Weinhold 			return image->id;
26650c0fea5dSIngo Weinhold 		}
26660c0fea5dSIngo Weinhold 	}
26670c0fea5dSIngo Weinhold 
26680c0fea5dSIngo Weinhold 	status = load_container(path, type, NULL, &image);
26690c0fea5dSIngo Weinhold 	if (status < B_OK) {
26700c0fea5dSIngo Weinhold 		rld_unlock();
26717486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
26727486b72dSIngo Weinhold 			strerror(status));
26730c0fea5dSIngo Weinhold 		return status;
26740c0fea5dSIngo Weinhold 	}
26750c0fea5dSIngo Weinhold 
26760c85bd05SIngo Weinhold 	if (image->find_undefined_symbol == NULL) {
26770c85bd05SIngo Weinhold 		if (addOn)
26780c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_add_on;
26790c85bd05SIngo Weinhold 		else
26800c85bd05SIngo Weinhold 			image->find_undefined_symbol = find_undefined_symbol_global;
26810c85bd05SIngo Weinhold 	}
26820c85bd05SIngo Weinhold 
26830c85bd05SIngo Weinhold 	status = load_dependencies(image);
26840c0fea5dSIngo Weinhold 	if (status < B_OK)
26850c0fea5dSIngo Weinhold 		goto err;
26860c85bd05SIngo Weinhold 
26870c85bd05SIngo Weinhold 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
26880c85bd05SIngo Weinhold 	// dependencies. If not specified, we temporarily set
26890c85bd05SIngo Weinhold 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
26900c85bd05SIngo Weinhold 	// for undefined symbol resolution.
26910c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) != 0)
26920c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RTLD_GLOBAL);
26930c85bd05SIngo Weinhold 	else
26940c85bd05SIngo Weinhold 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
26950c0fea5dSIngo Weinhold 
26960c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
26970c0fea5dSIngo Weinhold 	if (status < B_OK)
26980c0fea5dSIngo Weinhold 		goto err;
26990c0fea5dSIngo Weinhold 
27000c85bd05SIngo Weinhold 	if ((flags & RTLD_GLOBAL) == 0)
27010c85bd05SIngo Weinhold 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
27020c85bd05SIngo Weinhold 
27030c0fea5dSIngo Weinhold 	remap_images();
27040c0fea5dSIngo Weinhold 	init_dependencies(image, true);
27050c0fea5dSIngo Weinhold 
27060c0fea5dSIngo Weinhold 	rld_unlock();
27077486b72dSIngo Weinhold 
27087486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
27097486b72dSIngo Weinhold 
27100c85bd05SIngo Weinhold 	*_handle = image;
27110c0fea5dSIngo Weinhold 	return image->id;
27120c0fea5dSIngo Weinhold 
27130c0fea5dSIngo Weinhold err:
27147486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
27157486b72dSIngo Weinhold 
27160c0fea5dSIngo Weinhold 	dequeue_image(&sLoadedImages, image);
27170c0fea5dSIngo Weinhold 	sLoadedImageCount--;
27180c0fea5dSIngo Weinhold 	delete_image(image);
27190c0fea5dSIngo Weinhold 	rld_unlock();
27200c0fea5dSIngo Weinhold 	return status;
27210c0fea5dSIngo Weinhold }
27220c0fea5dSIngo Weinhold 
27230c0fea5dSIngo Weinhold 
27240c0fea5dSIngo Weinhold status_t
27250c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn)
27260c0fea5dSIngo Weinhold {
27270c0fea5dSIngo Weinhold 	image_t *image;
27280c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
27290c0fea5dSIngo Weinhold 
27300c85bd05SIngo Weinhold 	if (handle == NULL && imageID < 0)
27310c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
27320c0fea5dSIngo Weinhold 
27330c85bd05SIngo Weinhold 	if (handle == RLD_GLOBAL_SCOPE)
27340c85bd05SIngo Weinhold 		return B_OK;
27350c85bd05SIngo Weinhold 
27360c0fea5dSIngo Weinhold 	rld_lock();
27370c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
27380c0fea5dSIngo Weinhold 
27399a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
27409a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
27419a6072a3SAxel Dörfler 		update_image_ids();
27429a6072a3SAxel Dörfler 	}
27439a6072a3SAxel Dörfler 
27440c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
27450c0fea5dSIngo Weinhold 
2746df30098dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
2747df30098dSIngo Weinhold 
27480c85bd05SIngo Weinhold 	if (handle != NULL) {
27490c85bd05SIngo Weinhold 		image = (image_t*)handle;
27500c85bd05SIngo Weinhold 		put_image(image);
2751df30098dSIngo Weinhold 		status = B_OK;
27520c85bd05SIngo Weinhold 	} else {
27530c0fea5dSIngo Weinhold 		for (image = sLoadedImages.head; image; image = image->next) {
27540c0fea5dSIngo Weinhold 			if (image->id == imageID) {
27550c0fea5dSIngo Weinhold 				// unload image
27560c0fea5dSIngo Weinhold 				if (type == image->type) {
27570c0fea5dSIngo Weinhold 					put_image(image);
27580c0fea5dSIngo Weinhold 					status = B_OK;
27590c0fea5dSIngo Weinhold 				} else
27600c0fea5dSIngo Weinhold 					status = B_BAD_VALUE;
27610c0fea5dSIngo Weinhold 				break;
27620c0fea5dSIngo Weinhold 			}
27630c0fea5dSIngo Weinhold 		}
27640c85bd05SIngo Weinhold 	}
27650c0fea5dSIngo Weinhold 
27660c0fea5dSIngo Weinhold 	if (status == B_OK) {
27670c0fea5dSIngo Weinhold 		while ((image = sDisposableImages.head) != NULL) {
27680c0fea5dSIngo Weinhold 			// call image fini here...
27698c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
27708c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
27713be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
27728c2a9d74SMichael Lotz 			}
27738c2a9d74SMichael Lotz 
277410b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
277510b4b5d1SIngo Weinhold 
27760c0fea5dSIngo Weinhold 			if (image->term_routine)
27770c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
27780c0fea5dSIngo Weinhold 
27790c0fea5dSIngo Weinhold 			dequeue_image(&sDisposableImages, image);
27800c0fea5dSIngo Weinhold 			unmap_image(image);
27810c0fea5dSIngo Weinhold 
278210b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
278310b4b5d1SIngo Weinhold 
27840c0fea5dSIngo Weinhold 			delete_image(image);
27850c0fea5dSIngo Weinhold 		}
27860c0fea5dSIngo Weinhold 	}
27870c0fea5dSIngo Weinhold 
27880c0fea5dSIngo Weinhold 	rld_unlock();
27890c0fea5dSIngo Weinhold 	return status;
27900c0fea5dSIngo Weinhold }
27910c0fea5dSIngo Weinhold 
27920c0fea5dSIngo Weinhold 
27930c0fea5dSIngo Weinhold status_t
27949a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
27959a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
27960c0fea5dSIngo Weinhold {
27970c0fea5dSIngo Weinhold 	int32 count = 0, j;
27980c0fea5dSIngo Weinhold 	uint32 i;
27990c0fea5dSIngo Weinhold 	image_t *image;
28000c0fea5dSIngo Weinhold 
28010c0fea5dSIngo Weinhold 	rld_lock();
28020c0fea5dSIngo Weinhold 
28030c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
28040c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
28050c0fea5dSIngo Weinhold 	if (image == NULL) {
28060c0fea5dSIngo Weinhold 		rld_unlock();
28070c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
28080c0fea5dSIngo Weinhold 	}
28090c0fea5dSIngo Weinhold 
28100c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
28110c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
28120c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
28130555803aSAxel Dörfler 			struct Elf32_Sym *symbol = &image->syms[j];
28140c0fea5dSIngo Weinhold 
28150c0fea5dSIngo Weinhold 			if (count == num) {
281610b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
281710b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
281810b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
28190c0fea5dSIngo Weinhold 
282010b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
282110b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
282210b4b5d1SIngo Weinhold 				int32 type;
28230c0fea5dSIngo Weinhold 				if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
282410b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
28250c0fea5dSIngo Weinhold 				else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
282610b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
28270c0fea5dSIngo Weinhold 				else
282810b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
282910b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
28300c0fea5dSIngo Weinhold 
283110b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
283210b4b5d1SIngo Weinhold 
283310b4b5d1SIngo Weinhold 				if (_type != NULL)
283410b4b5d1SIngo Weinhold 					*_type = type;
28350c0fea5dSIngo Weinhold 				if (_location != NULL)
283610b4b5d1SIngo Weinhold 					*_location = location;
28370c0fea5dSIngo Weinhold 				goto out;
28380c0fea5dSIngo Weinhold 			}
28390c0fea5dSIngo Weinhold 			count++;
28400c0fea5dSIngo Weinhold 		}
28410c0fea5dSIngo Weinhold 	}
28420c0fea5dSIngo Weinhold out:
28430c0fea5dSIngo Weinhold 	rld_unlock();
28440c0fea5dSIngo Weinhold 
28450c0fea5dSIngo Weinhold 	if (num != count)
28460c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
28470c0fea5dSIngo Weinhold 
28480c0fea5dSIngo Weinhold 	return B_OK;
28490c0fea5dSIngo Weinhold }
28500c0fea5dSIngo Weinhold 
28510c0fea5dSIngo Weinhold 
28520c0fea5dSIngo Weinhold status_t
28539a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
285480ece785SIngo Weinhold 	bool recursive, image_id *_inImage, void **_location)
28550c0fea5dSIngo Weinhold {
28560c0fea5dSIngo Weinhold 	status_t status = B_OK;
28570c0fea5dSIngo Weinhold 	image_t *image;
28580c0fea5dSIngo Weinhold 
28590c0fea5dSIngo Weinhold 	if (imageID < B_OK)
28600c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
28610c0fea5dSIngo Weinhold 	if (symbolName == NULL)
28620c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
28630c0fea5dSIngo Weinhold 
28640c0fea5dSIngo Weinhold 	rld_lock();
28650c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
28660c0fea5dSIngo Weinhold 
28670c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
28680c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
286980ece785SIngo Weinhold 	if (image != NULL) {
287080ece785SIngo Weinhold 		if (recursive) {
287180ece785SIngo Weinhold 			// breadth-first search in the given image and its dependencies
2872*003ebb0eSIngo Weinhold 			status = find_symbol_breadth_first(image,
2873*003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
2874*003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
287580ece785SIngo Weinhold 				&image, _location);
2876*003ebb0eSIngo Weinhold 		} else {
2877*003ebb0eSIngo Weinhold 			status = find_symbol(image,
2878*003ebb0eSIngo Weinhold 				SymbolLookupInfo(symbolName, symbolType, NULL,
2879*003ebb0eSIngo Weinhold 					LOOKUP_FLAG_DEFAULT_VERSION),
2880*003ebb0eSIngo Weinhold 				_location);
2881*003ebb0eSIngo Weinhold 		}
288280ece785SIngo Weinhold 
288380ece785SIngo Weinhold 		if (status == B_OK && _inImage != NULL)
288480ece785SIngo Weinhold 			*_inImage = image->id;
288580ece785SIngo Weinhold 	} else
28860c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
28870c0fea5dSIngo Weinhold 
28880c0fea5dSIngo Weinhold 	rld_unlock();
28890c0fea5dSIngo Weinhold 	return status;
28900c0fea5dSIngo Weinhold }
28910c0fea5dSIngo Weinhold 
28920c0fea5dSIngo Weinhold 
28930c0fea5dSIngo Weinhold status_t
28940c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName,
28950c85bd05SIngo Weinhold 	void **_location)
28960c85bd05SIngo Weinhold {
28970c85bd05SIngo Weinhold 	status_t status = B_ENTRY_NOT_FOUND;
28980c85bd05SIngo Weinhold 
28990c85bd05SIngo Weinhold 	if (symbolName == NULL)
29000c85bd05SIngo Weinhold 		return B_BAD_VALUE;
29010c85bd05SIngo Weinhold 
29020c85bd05SIngo Weinhold 	rld_lock();
29030c85bd05SIngo Weinhold 		// for now, just do stupid simple global locking
29040c85bd05SIngo Weinhold 
29050c85bd05SIngo Weinhold 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
29060c85bd05SIngo Weinhold 		// look in the default scope
29070c85bd05SIngo Weinhold 		image_t* image;
29080c85bd05SIngo Weinhold 		Elf32_Sym* symbol = find_undefined_symbol_global(sProgramImage,
2909*003ebb0eSIngo Weinhold 			sProgramImage,
2910*003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
2911*003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
2912*003ebb0eSIngo Weinhold 			&image);
29130c85bd05SIngo Weinhold 		if (symbol != NULL) {
29140c85bd05SIngo Weinhold 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
29150c85bd05SIngo Weinhold 			int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
29160c85bd05SIngo Weinhold 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
29170c85bd05SIngo Weinhold 			patch_defined_symbol(image, symbolName, _location, &symbolType);
29180c85bd05SIngo Weinhold 			status = B_OK;
29190c85bd05SIngo Weinhold 		}
29200c85bd05SIngo Weinhold 	} else if (handle == RTLD_NEXT) {
29210c85bd05SIngo Weinhold 		// Look in the default scope, but also in the dependencies of the
29220c85bd05SIngo Weinhold 		// calling image. Return the next after the caller symbol.
29230c85bd05SIngo Weinhold 
2924a2dad9e1SIngo Weinhold 		// First of all, find the caller image.
29250c85bd05SIngo Weinhold 		image_t* callerImage = sLoadedImages.head;
29260c85bd05SIngo Weinhold 		for (; callerImage != NULL; callerImage = callerImage->next) {
29270c85bd05SIngo Weinhold 			elf_region_t& text = callerImage->regions[0];
2928a2dad9e1SIngo Weinhold 			if ((addr_t)caller >= text.vmstart
2929a2dad9e1SIngo Weinhold 				&& (addr_t)caller < text.vmstart + text.vmsize) {
2930a2dad9e1SIngo Weinhold 				// found the image
29310c85bd05SIngo Weinhold 				break;
29320c85bd05SIngo Weinhold 			}
29330c85bd05SIngo Weinhold 		}
29340c85bd05SIngo Weinhold 
2935a2dad9e1SIngo Weinhold 		if (callerImage != NULL) {
29360c85bd05SIngo Weinhold 			// found the caller -- now search the global scope until we find
29370c85bd05SIngo Weinhold 			// the next symbol
2938a2dad9e1SIngo Weinhold 			bool hitCallerImage = false;
29390c85bd05SIngo Weinhold 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
29400c85bd05SIngo Weinhold 
29410c85bd05SIngo Weinhold 			image_t* image = sLoadedImages.head;
29420c85bd05SIngo Weinhold 			for (; image != NULL; image = image->next) {
2943a2dad9e1SIngo Weinhold 				// skip the caller image
2944a2dad9e1SIngo Weinhold 				if (image == callerImage) {
2945a2dad9e1SIngo Weinhold 					hitCallerImage = true;
2946a2dad9e1SIngo Weinhold 					continue;
2947a2dad9e1SIngo Weinhold 				}
2948a2dad9e1SIngo Weinhold 
2949a2dad9e1SIngo Weinhold 				// skip all images up to the caller image; also skip add-on
2950a2dad9e1SIngo Weinhold 				// images and those not marked above for resolution
2951a2dad9e1SIngo Weinhold 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
29520c85bd05SIngo Weinhold 					|| (image->flags
2953a2dad9e1SIngo Weinhold 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
29540c85bd05SIngo Weinhold 					continue;
29550c85bd05SIngo Weinhold 				}
29560c85bd05SIngo Weinhold 
2957*003ebb0eSIngo Weinhold 				struct Elf32_Sym *symbol = find_symbol(image,
2958*003ebb0eSIngo Weinhold 					SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
2959*003ebb0eSIngo Weinhold 						LOOKUP_FLAG_DEFAULT_VERSION));
29600c85bd05SIngo Weinhold 				if (symbol == NULL)
29610c85bd05SIngo Weinhold 					continue;
29620c85bd05SIngo Weinhold 
2963a2dad9e1SIngo Weinhold 				// found the symbol
29640c85bd05SIngo Weinhold 				*_location = (void*)(symbol->st_value
29650c85bd05SIngo Weinhold 					+ image->regions[0].delta);
29660c85bd05SIngo Weinhold 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
29670c85bd05SIngo Weinhold 				patch_defined_symbol(image, symbolName, _location,
29680c85bd05SIngo Weinhold 					&symbolType);
29690c85bd05SIngo Weinhold 				status = B_OK;
29700c85bd05SIngo Weinhold 				break;
29710c85bd05SIngo Weinhold 			}
29720c85bd05SIngo Weinhold 
29730c85bd05SIngo Weinhold 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
29740c85bd05SIngo Weinhold 		}
29750c85bd05SIngo Weinhold 	} else {
29760c85bd05SIngo Weinhold 		// breadth-first search in the given image and its dependencies
29770c85bd05SIngo Weinhold 		image_t* inImage;
2978*003ebb0eSIngo Weinhold 		status = find_symbol_breadth_first((image_t*)handle,
2979*003ebb0eSIngo Weinhold 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
2980*003ebb0eSIngo Weinhold 				LOOKUP_FLAG_DEFAULT_VERSION),
2981*003ebb0eSIngo Weinhold 			&inImage, _location);
29820c85bd05SIngo Weinhold 	}
29830c85bd05SIngo Weinhold 
29840c85bd05SIngo Weinhold 	rld_unlock();
29850c85bd05SIngo Weinhold 	return status;
29860c85bd05SIngo Weinhold }
29870c85bd05SIngo Weinhold 
29880c85bd05SIngo Weinhold 
29890c85bd05SIngo Weinhold status_t
29900c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
29910c0fea5dSIngo Weinhold {
29920c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
29930c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
29940c0fea5dSIngo Weinhold 	image_t *image;
29950c0fea5dSIngo Weinhold 
29960c0fea5dSIngo Weinhold 	if (_name == NULL)
29970c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
29980c0fea5dSIngo Weinhold 
29990c0fea5dSIngo Weinhold 	rld_lock();
30000c0fea5dSIngo Weinhold 
30010c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(id);
30020c0fea5dSIngo Weinhold 	if (image == NULL) {
30030c0fea5dSIngo Weinhold 		rld_unlock();
30040c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
30050c0fea5dSIngo Weinhold 	}
30060c0fea5dSIngo Weinhold 
30070c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
30080c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
30090c0fea5dSIngo Weinhold 		rld_unlock();
30100c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
30110c0fea5dSIngo Weinhold 	}
30120c0fea5dSIngo Weinhold 
30130c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
30140c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
30150c0fea5dSIngo Weinhold 			continue;
30160c0fea5dSIngo Weinhold 
30170c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
30180c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
30190c0fea5dSIngo Weinhold 
30200c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
30210c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
30220c0fea5dSIngo Weinhold 			rld_unlock();
30230c0fea5dSIngo Weinhold 			return B_OK;
30240c0fea5dSIngo Weinhold 		}
30250c0fea5dSIngo Weinhold 	}
30260c0fea5dSIngo Weinhold 
30270c0fea5dSIngo Weinhold 	rld_unlock();
30280c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
30290c0fea5dSIngo Weinhold }
30300c0fea5dSIngo Weinhold 
30310c0fea5dSIngo Weinhold 
303274c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
30330c0fea5dSIngo Weinhold 
30340c0fea5dSIngo Weinhold 
30359a6072a3SAxel Dörfler /*! Read and verify the ELF header */
30360c0fea5dSIngo Weinhold status_t
30370c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
30380c0fea5dSIngo Weinhold {
30390c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
30400c0fea5dSIngo Weinhold 
30410c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
30420c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
30430c0fea5dSIngo Weinhold 
30449a6072a3SAxel Dörfler 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize,
30459a6072a3SAxel Dörfler 		&sectionSize);
30460c0fea5dSIngo Weinhold }
30470c0fea5dSIngo Weinhold 
30480c0fea5dSIngo Weinhold 
30490c0fea5dSIngo Weinhold void
30500c0fea5dSIngo Weinhold terminate_program(void)
30510c0fea5dSIngo Weinhold {
30520c0fea5dSIngo Weinhold 	image_t **termList;
30530c0fea5dSIngo Weinhold 	ssize_t count, i;
30540c0fea5dSIngo Weinhold 
30550c0fea5dSIngo Weinhold 	count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED);
30560c0fea5dSIngo Weinhold 	if (count < B_OK)
30570c0fea5dSIngo Weinhold 		return;
30580c0fea5dSIngo Weinhold 
30599a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
30609a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
30619a6072a3SAxel Dörfler 		update_image_ids();
30629a6072a3SAxel Dörfler 	}
30639a6072a3SAxel Dörfler 
30640c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
30650c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
30660c0fea5dSIngo Weinhold 		image_t *image = termList[i];
30670c0fea5dSIngo Weinhold 
30680c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
30690c0fea5dSIngo Weinhold 
307010b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
307110b4b5d1SIngo Weinhold 
30720c0fea5dSIngo Weinhold 		if (image->term_routine)
30730c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
307410b4b5d1SIngo Weinhold 
307510b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
30760c0fea5dSIngo Weinhold 	}
30770c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
30780c0fea5dSIngo Weinhold 
30790c0fea5dSIngo Weinhold 	free(termList);
30800c0fea5dSIngo Weinhold }
30810c0fea5dSIngo Weinhold 
30820c0fea5dSIngo Weinhold 
30830c0fea5dSIngo Weinhold void
30840c0fea5dSIngo Weinhold rldelf_init(void)
30850c0fea5dSIngo Weinhold {
308610b4b5d1SIngo Weinhold 	// invoke static constructors
308710b4b5d1SIngo Weinhold 	new(&sAddOns) AddOnList;
308810b4b5d1SIngo Weinhold 
3089e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
3090e73923b0SAxel Dörfler 	sSemOwner = -1;
3091e73923b0SAxel Dörfler 	sSemCount = 0;
30920c0fea5dSIngo Weinhold 
30930c0fea5dSIngo Weinhold 	// create the debug area
30940c0fea5dSIngo Weinhold 	{
30950c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
30960c0fea5dSIngo Weinhold 
30970c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
30980c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
30990c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
31000c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
31010c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
31020c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
31030c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
31040c0fea5dSIngo Weinhold 		}
31050c0fea5dSIngo Weinhold 
31060c0fea5dSIngo Weinhold 		area->loaded_images = &sLoadedImages;
31070c0fea5dSIngo Weinhold 	}
310874c0424aSAxel Dörfler 
310974c0424aSAxel Dörfler 	// initialize error message if needed
31104bef3723SAxel Dörfler 	if (report_errors()) {
311174c0424aSAxel Dörfler 		void *buffer = malloc(1024);
311274c0424aSAxel Dörfler 		if (buffer == NULL)
311374c0424aSAxel Dörfler 			return;
311474c0424aSAxel Dörfler 
311574c0424aSAxel Dörfler 		sErrorMessage.SetTo(buffer, 1024, 'Rler');
311674c0424aSAxel Dörfler 	}
31170c0fea5dSIngo Weinhold }
31181873b4b3SIngo Weinhold 
31191873b4b3SIngo Weinhold 
31201873b4b3SIngo Weinhold status_t
31219a6072a3SAxel Dörfler elf_reinit_after_fork(void)
31221873b4b3SIngo Weinhold {
3123e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
3124e73923b0SAxel Dörfler 	if (sSem < 0)
3125e73923b0SAxel Dörfler 		return sSem;
31261873b4b3SIngo Weinhold 
31279a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
3128cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
3129cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
31309a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
31319a6072a3SAxel Dörfler 	sInvalidImageIDs = true;
3132cbc456deSIngo Weinhold 
31331873b4b3SIngo Weinhold 	return B_OK;
31341873b4b3SIngo Weinhold }
3135