xref: /haiku/src/system/runtime_loader/elf.cpp (revision 10b4b5d1755c3d2b4d405321c8c30bc609dd635d)
10c0fea5dSIngo Weinhold /*
234982809SIngo Weinhold  * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
312a5e9a4SAxel Dörfler  * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
40c0fea5dSIngo Weinhold  * Distributed under the terms of the MIT License.
50c0fea5dSIngo Weinhold  *
60c0fea5dSIngo Weinhold  * Copyright 2002, Manuel J. Petit. All rights reserved.
70c0fea5dSIngo Weinhold  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
80c0fea5dSIngo Weinhold  * Distributed under the terms of the NewOS License.
90c0fea5dSIngo Weinhold  */
100c0fea5dSIngo Weinhold 
110c0fea5dSIngo Weinhold #include "runtime_loader_private.h"
120c0fea5dSIngo Weinhold 
13ca618b22SIngo Weinhold #include <ctype.h>
140c0fea5dSIngo Weinhold #include <stdio.h>
150c0fea5dSIngo Weinhold #include <stdlib.h>
1634982809SIngo Weinhold #include <string.h>
170c0fea5dSIngo Weinhold 
18ca618b22SIngo Weinhold #include <OS.h>
19ca618b22SIngo Weinhold 
207486b72dSIngo Weinhold #include <elf32.h>
217486b72dSIngo Weinhold #include <runtime_loader.h>
227486b72dSIngo Weinhold #include <syscalls.h>
237486b72dSIngo Weinhold #include <user_runtime.h>
24*10b4b5d1SIngo Weinhold #include <util/DoublyLinkedList.h>
25*10b4b5d1SIngo Weinhold #include <util/kernel_cpp.h>
266b202f4eSIngo Weinhold #include <util/KMessage.h>
276b202f4eSIngo Weinhold #include <vm_defs.h>
287486b72dSIngo Weinhold 
29071f9c3aSIngo Weinhold #include "tracing_config.h"
30071f9c3aSIngo Weinhold 
310c0fea5dSIngo Weinhold 
320c0fea5dSIngo Weinhold //#define TRACE_RLD
330c0fea5dSIngo Weinhold #ifdef TRACE_RLD
340c0fea5dSIngo Weinhold #	define TRACE(x) dprintf x
350c0fea5dSIngo Weinhold #else
360c0fea5dSIngo Weinhold #	define TRACE(x) ;
370c0fea5dSIngo Weinhold #endif
380c0fea5dSIngo Weinhold 
390c0fea5dSIngo Weinhold 
40*10b4b5d1SIngo Weinhold // TODO: implement better locking strategy
41*10b4b5d1SIngo Weinhold // TODO: implement lazy binding
420c0fea5dSIngo Weinhold 
430c0fea5dSIngo Weinhold #define	PAGE_MASK (B_PAGE_SIZE - 1)
440c0fea5dSIngo Weinhold 
450c0fea5dSIngo Weinhold #define	PAGE_OFFSET(x) ((x) & (PAGE_MASK))
460c0fea5dSIngo Weinhold #define	PAGE_BASE(x) ((x) & ~(PAGE_MASK))
470c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
480c0fea5dSIngo Weinhold 
490c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000
500c0fea5dSIngo Weinhold 	/* keep in sync with app ldscript */
510c0fea5dSIngo Weinhold 
520c0fea5dSIngo Weinhold enum {
530c0fea5dSIngo Weinhold 	RFLAG_RW					= 0x0001,
540c0fea5dSIngo Weinhold 	RFLAG_ANON					= 0x0002,
550c0fea5dSIngo Weinhold 
560c0fea5dSIngo Weinhold 	RFLAG_TERMINATED			= 0x0200,
570c0fea5dSIngo Weinhold 	RFLAG_INITIALIZED			= 0x0400,
580c0fea5dSIngo Weinhold 	RFLAG_SYMBOLIC				= 0x0800,
590c0fea5dSIngo Weinhold 	RFLAG_RELOCATED				= 0x1000,
600c0fea5dSIngo Weinhold 	RFLAG_PROTECTED				= 0x2000,
610c0fea5dSIngo Weinhold 	RFLAG_DEPENDENCIES_LOADED	= 0x4000,
6246f4d849SIngo Weinhold 	RFLAG_REMAPPED				= 0x8000,
6346f4d849SIngo Weinhold 
6446f4d849SIngo Weinhold 	RFLAG_VISITED				= 0x10000
6546f4d849SIngo Weinhold 		// temporarily set in the symbol resolution code
660c0fea5dSIngo Weinhold };
670c0fea5dSIngo Weinhold 
680c0fea5dSIngo Weinhold 
690c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type)	(1 << ((type) - 1))
700c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES				(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
710c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
720c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
730c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
740c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE			(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
750c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
760c0fea5dSIngo Weinhold 
770c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
780c0fea5dSIngo Weinhold 
79*10b4b5d1SIngo Weinhold 
80*10b4b5d1SIngo Weinhold // image events
81*10b4b5d1SIngo Weinhold enum {
82*10b4b5d1SIngo Weinhold 	IMAGE_EVENT_LOADED,
83*10b4b5d1SIngo Weinhold 	IMAGE_EVENT_RELOCATED,
84*10b4b5d1SIngo Weinhold 	IMAGE_EVENT_INITIALIZED,
85*10b4b5d1SIngo Weinhold 	IMAGE_EVENT_UNINITIALIZING,
86*10b4b5d1SIngo Weinhold 	IMAGE_EVENT_UNLOADING
87*10b4b5d1SIngo Weinhold };
88*10b4b5d1SIngo Weinhold 
89*10b4b5d1SIngo Weinhold 
90*10b4b5d1SIngo Weinhold struct RuntimeLoaderAddOn
91*10b4b5d1SIngo Weinhold 		: public DoublyLinkedListLinkImpl<RuntimeLoaderAddOn> {
92*10b4b5d1SIngo Weinhold 	image_t*				image;
93*10b4b5d1SIngo Weinhold 	runtime_loader_add_on*	addOn;
94*10b4b5d1SIngo Weinhold 
95*10b4b5d1SIngo Weinhold 	RuntimeLoaderAddOn(image_t* image, runtime_loader_add_on* addOn)
96*10b4b5d1SIngo Weinhold 		:
97*10b4b5d1SIngo Weinhold 		image(image),
98*10b4b5d1SIngo Weinhold 		addOn(addOn)
99*10b4b5d1SIngo Weinhold 	{
100*10b4b5d1SIngo Weinhold 	}
101*10b4b5d1SIngo Weinhold };
102*10b4b5d1SIngo Weinhold 
103*10b4b5d1SIngo Weinhold typedef DoublyLinkedList<RuntimeLoaderAddOn> AddOnList;
104*10b4b5d1SIngo Weinhold 
105*10b4b5d1SIngo Weinhold struct RuntimeLoaderSymbolPatcher {
106*10b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher*		next;
107*10b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher*	patcher;
108*10b4b5d1SIngo Weinhold 	void*							cookie;
109*10b4b5d1SIngo Weinhold 
110*10b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher(runtime_loader_symbol_patcher* patcher,
111*10b4b5d1SIngo Weinhold 			void* cookie)
112*10b4b5d1SIngo Weinhold 		:
113*10b4b5d1SIngo Weinhold 		patcher(patcher),
114*10b4b5d1SIngo Weinhold 		cookie(cookie)
115*10b4b5d1SIngo Weinhold 	{
116*10b4b5d1SIngo Weinhold 	}
117*10b4b5d1SIngo Weinhold };
118*10b4b5d1SIngo Weinhold 
119*10b4b5d1SIngo Weinhold 
1200c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0};
1210c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0};
1220c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0;
1230c0fea5dSIngo Weinhold static image_t *sProgramImage;
12474c0424aSAxel Dörfler static KMessage sErrorMessage;
1255d0638bfSIngo Weinhold static bool sProgramLoaded = false;
12661b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL;
1279a6072a3SAxel Dörfler static bool sInvalidImageIDs;
128ca618b22SIngo Weinhold static image_t **sPreloadedImages = NULL;
129ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0;
130*10b4b5d1SIngo Weinhold static AddOnList sAddOns;
1310c0fea5dSIngo Weinhold 
1320c0fea5dSIngo Weinhold // a recursive lock
133e73923b0SAxel Dörfler static sem_id sSem;
134e73923b0SAxel Dörfler static thread_id sSemOwner;
135e73923b0SAxel Dörfler static int32 sSemCount;
1360c0fea5dSIngo Weinhold 
137*10b4b5d1SIngo Weinhold extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport;
138*10b4b5d1SIngo Weinhold 
1390c0fea5dSIngo Weinhold 
1400c0fea5dSIngo Weinhold void
1410c0fea5dSIngo Weinhold dprintf(const char *format, ...)
1420c0fea5dSIngo Weinhold {
1430c0fea5dSIngo Weinhold 	char buffer[1024];
1440c0fea5dSIngo Weinhold 
1450c0fea5dSIngo Weinhold 	va_list list;
1460c0fea5dSIngo Weinhold 	va_start(list, format);
1470c0fea5dSIngo Weinhold 
1480c0fea5dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1490c0fea5dSIngo Weinhold 	_kern_debug_output(buffer);
1500c0fea5dSIngo Weinhold 
1510c0fea5dSIngo Weinhold 	va_end(list);
1520c0fea5dSIngo Weinhold }
1535d0638bfSIngo Weinhold 
1545d0638bfSIngo Weinhold #define FATAL(x...)							\
1555d0638bfSIngo Weinhold 	do {									\
1565d0638bfSIngo Weinhold 		dprintf("runtime_loader: " x);		\
1575d0638bfSIngo Weinhold 		if (!sProgramLoaded)				\
1585d0638bfSIngo Weinhold 			printf("runtime_loader: " x);	\
1595d0638bfSIngo Weinhold 	} while (false)
1600c0fea5dSIngo Weinhold 
1610c0fea5dSIngo Weinhold 
16234982809SIngo Weinhold /*!	Mini atoi(), so we don't have to include the libroot dependencies.
16334982809SIngo Weinhold  */
16434982809SIngo Weinhold int
16534982809SIngo Weinhold atoi(const char* num)
16634982809SIngo Weinhold {
16734982809SIngo Weinhold 	int result = 0;
16834982809SIngo Weinhold 	while (*num >= '0' && *num <= '9') {
16934982809SIngo Weinhold 		result = (result * 10) + (*num - '0');
17034982809SIngo Weinhold 		num++;
17134982809SIngo Weinhold 	}
17234982809SIngo Weinhold 
17334982809SIngo Weinhold 	return result;
17434982809SIngo Weinhold }
17534982809SIngo Weinhold 
17634982809SIngo Weinhold 
1776bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING
1787486b72dSIngo Weinhold 
1797486b72dSIngo Weinhold void
1807486b72dSIngo Weinhold ktrace_printf(const char *format, ...)
1817486b72dSIngo Weinhold {
1827486b72dSIngo Weinhold 	va_list list;
1837486b72dSIngo Weinhold 	va_start(list, format);
1847486b72dSIngo Weinhold 
1857486b72dSIngo Weinhold 	char buffer[1024];
1867486b72dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1877486b72dSIngo Weinhold 	_kern_ktrace_output(buffer);
1887486b72dSIngo Weinhold 
1897486b72dSIngo Weinhold 	va_end(list);
1907486b72dSIngo Weinhold }
1917486b72dSIngo Weinhold 
1927486b72dSIngo Weinhold #define KTRACE(x...)	ktrace_printf(x)
1937486b72dSIngo Weinhold 
1947486b72dSIngo Weinhold #else
1957486b72dSIngo Weinhold #	define KTRACE(x...)
1967486b72dSIngo Weinhold #endif	// RUNTIME_LOADER_TRACING
1977486b72dSIngo Weinhold 
1987486b72dSIngo Weinhold 
1990c0fea5dSIngo Weinhold static void
2000c0fea5dSIngo Weinhold rld_unlock()
2010c0fea5dSIngo Weinhold {
202e73923b0SAxel Dörfler 	if (sSemCount-- == 1) {
203e73923b0SAxel Dörfler 		sSemOwner = -1;
204e73923b0SAxel Dörfler 		release_sem(sSem);
2050c0fea5dSIngo Weinhold 	}
2060c0fea5dSIngo Weinhold }
2070c0fea5dSIngo Weinhold 
2080c0fea5dSIngo Weinhold 
2090c0fea5dSIngo Weinhold static void
2100c0fea5dSIngo Weinhold rld_lock()
2110c0fea5dSIngo Weinhold {
2120c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
213e73923b0SAxel Dörfler 	if (self != sSemOwner) {
214e73923b0SAxel Dörfler 		acquire_sem(sSem);
215e73923b0SAxel Dörfler 		sSemOwner = self;
2160c0fea5dSIngo Weinhold 	}
217e73923b0SAxel Dörfler 	sSemCount++;
2180c0fea5dSIngo Weinhold }
2190c0fea5dSIngo Weinhold 
2200c0fea5dSIngo Weinhold 
2210c0fea5dSIngo Weinhold static void
2220c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image)
2230c0fea5dSIngo Weinhold {
2240c0fea5dSIngo Weinhold 	image->next = 0;
2250c0fea5dSIngo Weinhold 
2260c0fea5dSIngo Weinhold 	image->prev = queue->tail;
2270c0fea5dSIngo Weinhold 	if (queue->tail)
2280c0fea5dSIngo Weinhold 		queue->tail->next = image;
2290c0fea5dSIngo Weinhold 
2300c0fea5dSIngo Weinhold 	queue->tail = image;
2310c0fea5dSIngo Weinhold 	if (!queue->head)
2320c0fea5dSIngo Weinhold 		queue->head = image;
2330c0fea5dSIngo Weinhold }
2340c0fea5dSIngo Weinhold 
2350c0fea5dSIngo Weinhold 
2360c0fea5dSIngo Weinhold static void
2370c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image)
2380c0fea5dSIngo Weinhold {
2390c0fea5dSIngo Weinhold 	if (image->next)
2400c0fea5dSIngo Weinhold 		image->next->prev = image->prev;
2410c0fea5dSIngo Weinhold 	else
2420c0fea5dSIngo Weinhold 		queue->tail = image->prev;
2430c0fea5dSIngo Weinhold 
2440c0fea5dSIngo Weinhold 	if (image->prev)
2450c0fea5dSIngo Weinhold 		image->prev->next = image->next;
2460c0fea5dSIngo Weinhold 	else
2470c0fea5dSIngo Weinhold 		queue->head = image->next;
2480c0fea5dSIngo Weinhold 
2490c0fea5dSIngo Weinhold 	image->prev = 0;
2500c0fea5dSIngo Weinhold 	image->next = 0;
2510c0fea5dSIngo Weinhold }
2520c0fea5dSIngo Weinhold 
2530c0fea5dSIngo Weinhold 
2540c0fea5dSIngo Weinhold static uint32
2550c0fea5dSIngo Weinhold elf_hash(const uint8 *name)
2560c0fea5dSIngo Weinhold {
2570c0fea5dSIngo Weinhold 	uint32 hash = 0;
2580c0fea5dSIngo Weinhold 	uint32 temp;
2590c0fea5dSIngo Weinhold 
2600c0fea5dSIngo Weinhold 	while (*name) {
2610c0fea5dSIngo Weinhold 		hash = (hash << 4) + *name++;
2620c0fea5dSIngo Weinhold 		if ((temp = hash & 0xf0000000)) {
2630c0fea5dSIngo Weinhold 			hash ^= temp >> 24;
2640c0fea5dSIngo Weinhold 		}
2650c0fea5dSIngo Weinhold 		hash &= ~temp;
2660c0fea5dSIngo Weinhold 	}
2670c0fea5dSIngo Weinhold 	return hash;
2680c0fea5dSIngo Weinhold }
2690c0fea5dSIngo Weinhold 
2700c0fea5dSIngo Weinhold 
2714bef3723SAxel Dörfler static inline bool
2724bef3723SAxel Dörfler report_errors()
2734bef3723SAxel Dörfler {
2744bef3723SAxel Dörfler 	return gProgramArgs->error_port >= 0;
2754bef3723SAxel Dörfler }
2764bef3723SAxel Dörfler 
2774bef3723SAxel Dörfler 
2789a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork.
2799a6072a3SAxel Dörfler static status_t
2809a6072a3SAxel Dörfler update_image_id(image_t *image)
2819a6072a3SAxel Dörfler {
2829a6072a3SAxel Dörfler 	int32 cookie = 0;
2839a6072a3SAxel Dörfler 	image_info info;
2849a6072a3SAxel Dörfler 	while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info,
2859a6072a3SAxel Dörfler 			sizeof(image_info)) == B_OK) {
2869a6072a3SAxel Dörfler 		for (uint32 i = 0; i < image->num_regions; i++) {
2879a6072a3SAxel Dörfler 			if (image->regions[i].vmstart == (addr_t)info.text) {
2889a6072a3SAxel Dörfler 				image->id = info.id;
2899a6072a3SAxel Dörfler 				return B_OK;
2909a6072a3SAxel Dörfler 			}
2919a6072a3SAxel Dörfler 		}
2929a6072a3SAxel Dörfler 	}
2939a6072a3SAxel Dörfler 
2949a6072a3SAxel Dörfler 	FATAL("Could not update image ID %ld after fork()!\n", image->id);
2959a6072a3SAxel Dörfler 	return B_ENTRY_NOT_FOUND;
2969a6072a3SAxel Dörfler }
2979a6072a3SAxel Dörfler 
2989a6072a3SAxel Dörfler 
2999a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images.
3009a6072a3SAxel Dörfler static status_t
3019a6072a3SAxel Dörfler update_image_ids(void)
3029a6072a3SAxel Dörfler {
3039a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
3049a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
3059a6072a3SAxel Dörfler 		if (status != B_OK)
3069a6072a3SAxel Dörfler 			return status;
3079a6072a3SAxel Dörfler 	}
3089a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
3099a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
3109a6072a3SAxel Dörfler 		if (status != B_OK)
3119a6072a3SAxel Dörfler 			return status;
3129a6072a3SAxel Dörfler 	}
3139a6072a3SAxel Dörfler 
3149a6072a3SAxel Dörfler 	sInvalidImageIDs = false;
3159a6072a3SAxel Dörfler 	return B_OK;
3169a6072a3SAxel Dörfler }
3179a6072a3SAxel Dörfler 
3189a6072a3SAxel Dörfler 
3190c0fea5dSIngo Weinhold static image_t *
3200c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath,
3210c0fea5dSIngo Weinhold 	uint32 typeMask)
3220c0fea5dSIngo Weinhold {
3239a6072a3SAxel Dörfler 	for (image_t *image = queue->head; image; image = image->next) {
3240c0fea5dSIngo Weinhold 		const char *imageName = isPath ? image->path : image->name;
3250c0fea5dSIngo Weinhold 		int length = isPath ? sizeof(image->path) : sizeof(image->name);
3260c0fea5dSIngo Weinhold 
3270c0fea5dSIngo Weinhold 		if (!strncmp(imageName, name, length)
3280c0fea5dSIngo Weinhold 			&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
3290c0fea5dSIngo Weinhold 			return image;
3300c0fea5dSIngo Weinhold 		}
3310c0fea5dSIngo Weinhold 	}
3320c0fea5dSIngo Weinhold 
3330c0fea5dSIngo Weinhold 	return NULL;
3340c0fea5dSIngo Weinhold }
3350c0fea5dSIngo Weinhold 
3360c0fea5dSIngo Weinhold 
3370c0fea5dSIngo Weinhold static image_t *
3380c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask)
3390c0fea5dSIngo Weinhold {
3409a6072a3SAxel Dörfler 	bool isPath = strchr(name, '/') != NULL;
34146f4d849SIngo Weinhold 	return find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
3420c0fea5dSIngo Weinhold }
3430c0fea5dSIngo Weinhold 
3440c0fea5dSIngo Weinhold 
3450c0fea5dSIngo Weinhold static image_t *
3460c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id)
3470c0fea5dSIngo Weinhold {
3489a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
3499a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
3509a6072a3SAxel Dörfler 		update_image_ids();
3519a6072a3SAxel Dörfler 	}
3520c0fea5dSIngo Weinhold 
3539a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
3540c0fea5dSIngo Weinhold 		if (image->id == id)
3550c0fea5dSIngo Weinhold 			return image;
3560c0fea5dSIngo Weinhold 	}
3570c0fea5dSIngo Weinhold 
3580c0fea5dSIngo Weinhold 	// For the termination routine, we need to look into the list of
3590c0fea5dSIngo Weinhold 	// disposable images as well
3609a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
3610c0fea5dSIngo Weinhold 		if (image->id == id)
3620c0fea5dSIngo Weinhold 			return image;
3630c0fea5dSIngo Weinhold 	}
3640c0fea5dSIngo Weinhold 
3650c0fea5dSIngo Weinhold 	return NULL;
3660c0fea5dSIngo Weinhold }
3670c0fea5dSIngo Weinhold 
3680c0fea5dSIngo Weinhold 
3695fd6637bSIngo Weinhold static image_t*
3705fd6637bSIngo Weinhold get_program_image()
37112a5e9a4SAxel Dörfler {
37212a5e9a4SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
37312a5e9a4SAxel Dörfler 		if (image->type == B_APP_IMAGE)
3745fd6637bSIngo Weinhold 			return image;
37512a5e9a4SAxel Dörfler 	}
37612a5e9a4SAxel Dörfler 
37712a5e9a4SAxel Dörfler 	return NULL;
37812a5e9a4SAxel Dörfler }
37912a5e9a4SAxel Dörfler 
38012a5e9a4SAxel Dörfler 
3815fd6637bSIngo Weinhold static const char *
3825fd6637bSIngo Weinhold get_program_path()
3835fd6637bSIngo Weinhold {
3845fd6637bSIngo Weinhold 	if (image_t* image = get_program_image())
3855fd6637bSIngo Weinhold 		return image->path;
3865fd6637bSIngo Weinhold 
3875fd6637bSIngo Weinhold 	return NULL;
3885fd6637bSIngo Weinhold }
3895fd6637bSIngo Weinhold 
3905fd6637bSIngo Weinhold 
3910c0fea5dSIngo Weinhold static status_t
39212a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize,
39312a5e9a4SAxel Dörfler 	int32 *_sheaderSize)
3940c0fea5dSIngo Weinhold {
3950c0fea5dSIngo Weinhold 	if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
3960c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3970c0fea5dSIngo Weinhold 
3980c0fea5dSIngo Weinhold 	if (eheader->e_ident[4] != ELFCLASS32)
3990c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4000c0fea5dSIngo Weinhold 
4010c0fea5dSIngo Weinhold 	if (eheader->e_phoff == 0)
4020c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4030c0fea5dSIngo Weinhold 
4040c0fea5dSIngo Weinhold 	if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
4050c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
4060c0fea5dSIngo Weinhold 
4070c0fea5dSIngo Weinhold 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
4080c0fea5dSIngo Weinhold 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
4090c0fea5dSIngo Weinhold 
4105aa7b7b6SMarcus Overhagen 	if (*_pheaderSize <= 0 || *_sheaderSize <= 0)
4115aa7b7b6SMarcus Overhagen 		return B_NOT_AN_EXECUTABLE;
4125aa7b7b6SMarcus Overhagen 
4135aa7b7b6SMarcus Overhagen 	return B_OK;
4140c0fea5dSIngo Weinhold }
4150c0fea5dSIngo Weinhold 
4160c0fea5dSIngo Weinhold 
4170c0fea5dSIngo Weinhold static int32
4180c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize)
4190c0fea5dSIngo Weinhold {
4200c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheaders;
4210c0fea5dSIngo Weinhold 	int32 count = 0;
4220c0fea5dSIngo Weinhold 	int i;
4230c0fea5dSIngo Weinhold 
4240c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
4250c0fea5dSIngo Weinhold 		pheaders = (struct Elf32_Phdr *)(buff + i * phentsize);
4260c0fea5dSIngo Weinhold 
4270c0fea5dSIngo Weinhold 		switch (pheaders->p_type) {
4280c0fea5dSIngo Weinhold 			case PT_NULL:
4290c0fea5dSIngo Weinhold 				/* NOP header */
4300c0fea5dSIngo Weinhold 				break;
4310c0fea5dSIngo Weinhold 			case PT_LOAD:
4320c0fea5dSIngo Weinhold 				count += 1;
4330c0fea5dSIngo Weinhold 				if (pheaders->p_memsz != pheaders->p_filesz) {
4340c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz);
4350c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz);
4360c0fea5dSIngo Weinhold 
4370c0fea5dSIngo Weinhold 					if (A != B)
4380c0fea5dSIngo Weinhold 						count += 1;
4390c0fea5dSIngo Weinhold 				}
4400c0fea5dSIngo Weinhold 				break;
4410c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
4420c0fea5dSIngo Weinhold 				/* will be handled at some other place */
4430c0fea5dSIngo Weinhold 				break;
4440c0fea5dSIngo Weinhold 			case PT_INTERP:
4450c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
4460c0fea5dSIngo Weinhold 				break;
4470c0fea5dSIngo Weinhold 			case PT_NOTE:
4480c0fea5dSIngo Weinhold 				/* unsupported */
4490c0fea5dSIngo Weinhold 				break;
4500c0fea5dSIngo Weinhold 			case PT_SHLIB:
4510c0fea5dSIngo Weinhold 				/* undefined semantics */
4520c0fea5dSIngo Weinhold 				break;
4530c0fea5dSIngo Weinhold 			case PT_PHDR:
4540c0fea5dSIngo Weinhold 				/* we don't use it */
4550c0fea5dSIngo Weinhold 				break;
4560c0fea5dSIngo Weinhold 			default:
4570c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type);
4580c0fea5dSIngo Weinhold 				return B_BAD_DATA;
4590c0fea5dSIngo Weinhold 		}
4600c0fea5dSIngo Weinhold 	}
4610c0fea5dSIngo Weinhold 
4620c0fea5dSIngo Weinhold 	return count;
4630c0fea5dSIngo Weinhold }
4640c0fea5dSIngo Weinhold 
4650c0fea5dSIngo Weinhold 
4660c0fea5dSIngo Weinhold static image_t *
4670c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions)
4680c0fea5dSIngo Weinhold {
4690c0fea5dSIngo Weinhold 	size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t);
4700c0fea5dSIngo Weinhold 	const char *lastSlash;
4710c0fea5dSIngo Weinhold 
4720c0fea5dSIngo Weinhold 	image_t *image = (image_t*)malloc(allocSize);
4730c0fea5dSIngo Weinhold 	if (image == NULL) {
4740c0fea5dSIngo Weinhold 		FATAL("no memory for image %s\n", path);
4750c0fea5dSIngo Weinhold 		return NULL;
4760c0fea5dSIngo Weinhold 	}
4770c0fea5dSIngo Weinhold 
4780c0fea5dSIngo Weinhold 	memset(image, 0, allocSize);
4790c0fea5dSIngo Weinhold 
4800c0fea5dSIngo Weinhold 	strlcpy(image->path, path, sizeof(image->path));
4810c0fea5dSIngo Weinhold 
4820c0fea5dSIngo Weinhold 	// Make the last component of the supplied name the image name.
4830c0fea5dSIngo Weinhold 	// If present, DT_SONAME will replace this name.
4840c0fea5dSIngo Weinhold 	if ((lastSlash = strrchr(name, '/')))
4850c0fea5dSIngo Weinhold 		strlcpy(image->name, lastSlash + 1, sizeof(image->name));
4860c0fea5dSIngo Weinhold 	else
4870c0fea5dSIngo Weinhold 		strlcpy(image->name, name, sizeof(image->name));
4880c0fea5dSIngo Weinhold 
4890c0fea5dSIngo Weinhold 	image->ref_count = 1;
4900c0fea5dSIngo Weinhold 	image->num_regions = num_regions;
4910c0fea5dSIngo Weinhold 
4920c0fea5dSIngo Weinhold 	return image;
4930c0fea5dSIngo Weinhold }
4940c0fea5dSIngo Weinhold 
4950c0fea5dSIngo Weinhold 
4960c0fea5dSIngo Weinhold static void
4970c0fea5dSIngo Weinhold delete_image_struct(image_t *image)
4980c0fea5dSIngo Weinhold {
4990c0fea5dSIngo Weinhold #ifdef DEBUG
5000c0fea5dSIngo Weinhold 	size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t);
5010c0fea5dSIngo Weinhold 	memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
5020c0fea5dSIngo Weinhold #endif
5030c0fea5dSIngo Weinhold 	free(image->needed);
504*10b4b5d1SIngo Weinhold 	free(image->symbol_resolution_images);
505*10b4b5d1SIngo Weinhold 
506*10b4b5d1SIngo Weinhold 	while (RuntimeLoaderSymbolPatcher* patcher
507*10b4b5d1SIngo Weinhold 			= image->defined_symbol_patchers) {
508*10b4b5d1SIngo Weinhold 		image->defined_symbol_patchers = patcher->next;
509*10b4b5d1SIngo Weinhold 		delete patcher;
510*10b4b5d1SIngo Weinhold 	}
511*10b4b5d1SIngo Weinhold 	while (RuntimeLoaderSymbolPatcher* patcher
512*10b4b5d1SIngo Weinhold 			= image->undefined_symbol_patchers) {
513*10b4b5d1SIngo Weinhold 		image->undefined_symbol_patchers = patcher->next;
514*10b4b5d1SIngo Weinhold 		delete patcher;
515*10b4b5d1SIngo Weinhold 	}
5160c0fea5dSIngo Weinhold 
5170c0fea5dSIngo Weinhold #ifdef DEBUG
5189a6072a3SAxel Dörfler 	// overwrite images to make sure they aren't accidently reused anywhere
5190c0fea5dSIngo Weinhold 	memset(image, 0xa5, size);
5200c0fea5dSIngo Weinhold #endif
5210c0fea5dSIngo Weinhold 	free(image);
5220c0fea5dSIngo Weinhold }
5230c0fea5dSIngo Weinhold 
5240c0fea5dSIngo Weinhold 
5250c0fea5dSIngo Weinhold static void
5260c0fea5dSIngo Weinhold delete_image(image_t *image)
5270c0fea5dSIngo Weinhold {
5282760c4cdSAxel Dörfler 	if (image == NULL)
5292760c4cdSAxel Dörfler 		return;
5302760c4cdSAxel Dörfler 
5310c0fea5dSIngo Weinhold 	_kern_unregister_image(image->id);
5320c0fea5dSIngo Weinhold 		// registered in load_container()
5330c0fea5dSIngo Weinhold 
5340c0fea5dSIngo Weinhold 	delete_image_struct(image);
5350c0fea5dSIngo Weinhold }
5360c0fea5dSIngo Weinhold 
5370c0fea5dSIngo Weinhold 
5380c0fea5dSIngo Weinhold static status_t
5390c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
5400c0fea5dSIngo Weinhold {
5410c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheader;
5420c0fea5dSIngo Weinhold 	int regcount;
5430c0fea5dSIngo Weinhold 	int i;
5440c0fea5dSIngo Weinhold 
5450c0fea5dSIngo Weinhold 	regcount = 0;
5460c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
5470c0fea5dSIngo Weinhold 		pheader = (struct Elf32_Phdr *)(buff + i * phentsize);
5480c0fea5dSIngo Weinhold 
5490c0fea5dSIngo Weinhold 		switch (pheader->p_type) {
5500c0fea5dSIngo Weinhold 			case PT_NULL:
5510c0fea5dSIngo Weinhold 				/* NOP header */
5520c0fea5dSIngo Weinhold 				break;
5530c0fea5dSIngo Weinhold 			case PT_LOAD:
5540c0fea5dSIngo Weinhold 				if (pheader->p_memsz == pheader->p_filesz) {
5550c0fea5dSIngo Weinhold 					/*
5560c0fea5dSIngo Weinhold 					 * everything in one area
5570c0fea5dSIngo Weinhold 					 */
5580c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
5590c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_memsz;
5600c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
5610c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz
5620c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
5630c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
5640c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
5650c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
5660c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
5670c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
5680c0fea5dSIngo Weinhold 						// this is a writable segment
5690c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
5700c0fea5dSIngo Weinhold 					}
5710c0fea5dSIngo Weinhold 				} else {
5720c0fea5dSIngo Weinhold 					/*
5730c0fea5dSIngo Weinhold 					 * may require splitting
5740c0fea5dSIngo Weinhold 					 */
5750c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz);
5760c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz);
5770c0fea5dSIngo Weinhold 
5780c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
5790c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_filesz;
5800c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
5810c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz
5820c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
5830c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
5840c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
5850c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
5860c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
5870c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
5880c0fea5dSIngo Weinhold 						// this is a writable segment
5890c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
5900c0fea5dSIngo Weinhold 					}
5910c0fea5dSIngo Weinhold 
5920c0fea5dSIngo Weinhold 					if (A != B) {
5930c0fea5dSIngo Weinhold 						/*
5940c0fea5dSIngo Weinhold 						 * yeah, it requires splitting
5950c0fea5dSIngo Weinhold 						 */
5960c0fea5dSIngo Weinhold 						regcount += 1;
5970c0fea5dSIngo Weinhold 						image->regions[regcount].start = pheader->p_vaddr;
5980c0fea5dSIngo Weinhold 						image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz;
5990c0fea5dSIngo Weinhold 						image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
6000c0fea5dSIngo Weinhold 						image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr))
6010c0fea5dSIngo Weinhold 							- image->regions[regcount-1].vmsize;
6020c0fea5dSIngo Weinhold 						image->regions[regcount].fdstart = 0;
6030c0fea5dSIngo Weinhold 						image->regions[regcount].fdsize = 0;
6040c0fea5dSIngo Weinhold 						image->regions[regcount].delta = 0;
6050c0fea5dSIngo Weinhold 						image->regions[regcount].flags = RFLAG_ANON;
6060c0fea5dSIngo Weinhold 						if (pheader->p_flags & PF_WRITE) {
6070c0fea5dSIngo Weinhold 							// this is a writable segment
6080c0fea5dSIngo Weinhold 							image->regions[regcount].flags |= RFLAG_RW;
6090c0fea5dSIngo Weinhold 						}
6100c0fea5dSIngo Weinhold 					}
6110c0fea5dSIngo Weinhold 				}
6120c0fea5dSIngo Weinhold 				regcount += 1;
6130c0fea5dSIngo Weinhold 				break;
6140c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
6150c0fea5dSIngo Weinhold 				image->dynamic_ptr = pheader->p_vaddr;
6160c0fea5dSIngo Weinhold 				break;
6170c0fea5dSIngo Weinhold 			case PT_INTERP:
6180c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
6190c0fea5dSIngo Weinhold 				break;
6200c0fea5dSIngo Weinhold 			case PT_NOTE:
6210c0fea5dSIngo Weinhold 				/* unsupported */
6220c0fea5dSIngo Weinhold 				break;
6230c0fea5dSIngo Weinhold 			case PT_SHLIB:
6240c0fea5dSIngo Weinhold 				/* undefined semantics */
6250c0fea5dSIngo Weinhold 				break;
6260c0fea5dSIngo Weinhold 			case PT_PHDR:
6270c0fea5dSIngo Weinhold 				/* we don't use it */
6280c0fea5dSIngo Weinhold 				break;
6290c0fea5dSIngo Weinhold 			default:
6300c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type);
6310c0fea5dSIngo Weinhold 				return B_BAD_DATA;
6320c0fea5dSIngo Weinhold 		}
6330c0fea5dSIngo Weinhold 	}
6340c0fea5dSIngo Weinhold 
6350c0fea5dSIngo Weinhold 	return B_OK;
6360c0fea5dSIngo Weinhold }
6370c0fea5dSIngo Weinhold 
6380c0fea5dSIngo Weinhold 
6390c0fea5dSIngo Weinhold static bool
64034982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader,
64134982809SIngo Weinhold 	int32 sheaderSize, char* buffer, size_t bufferSize)
64234982809SIngo Weinhold {
64334982809SIngo Weinhold 	image->gcc_version.major = 0;
64434982809SIngo Weinhold 	image->gcc_version.middle = 0;
64534982809SIngo Weinhold 	image->gcc_version.minor = 0;
64634982809SIngo Weinhold 
64734982809SIngo Weinhold 	if (sheaderSize > (int)bufferSize) {
64834982809SIngo Weinhold 		FATAL("Cannot handle section headers bigger than %lu\n", bufferSize);
64934982809SIngo Weinhold 		return false;
65034982809SIngo Weinhold 	}
65134982809SIngo Weinhold 
65234982809SIngo Weinhold 	// read section headers
65334982809SIngo Weinhold 	ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize);
65434982809SIngo Weinhold 	if (length != sheaderSize) {
65534982809SIngo Weinhold 		FATAL("Could not read section headers: %s\n", strerror(length));
65634982809SIngo Weinhold 		return false;
65734982809SIngo Weinhold 	}
65834982809SIngo Weinhold 
65934982809SIngo Weinhold 	// load the string section
66034982809SIngo Weinhold 	Elf32_Shdr* sectionHeader
66134982809SIngo Weinhold 		= (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize);
66234982809SIngo Weinhold 
66334982809SIngo Weinhold 	if (sheaderSize + sectionHeader->sh_size > bufferSize) {
66434982809SIngo Weinhold 		FATAL("Buffer not big enough for section string section\n");
66534982809SIngo Weinhold 		return false;
66634982809SIngo Weinhold 	}
66734982809SIngo Weinhold 
66834982809SIngo Weinhold 	char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size;
66934982809SIngo Weinhold 	length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings,
67034982809SIngo Weinhold 		sectionHeader->sh_size);
67134982809SIngo Weinhold 	if (length != (int)sectionHeader->sh_size) {
67234982809SIngo Weinhold 		FATAL("Could not read section string section: %s\n", strerror(length));
67334982809SIngo Weinhold 		return false;
67434982809SIngo Weinhold 	}
67534982809SIngo Weinhold 
67634982809SIngo Weinhold 	// find the .comment section
67734982809SIngo Weinhold 	off_t commentOffset = 0;
67834982809SIngo Weinhold 	size_t commentSize = 0;
67934982809SIngo Weinhold 	for (uint32 i = 0; i < eheader.e_shnum; i++) {
68034982809SIngo Weinhold 		sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize);
68134982809SIngo Weinhold 		const char* sectionName = sectionStrings + sectionHeader->sh_name;
68234982809SIngo Weinhold 		if (sectionHeader->sh_name != 0
68334982809SIngo Weinhold 			&& strcmp(sectionName, ".comment") == 0) {
68434982809SIngo Weinhold 			commentOffset = sectionHeader->sh_offset;
68534982809SIngo Weinhold 			commentSize = sectionHeader->sh_size;
68634982809SIngo Weinhold 			break;
68734982809SIngo Weinhold 		}
68834982809SIngo Weinhold 	}
68934982809SIngo Weinhold 
69034982809SIngo Weinhold 	if (commentSize == 0) {
69134982809SIngo Weinhold 		FATAL("Could not find .comment section\n");
69234982809SIngo Weinhold 		return false;
69334982809SIngo Weinhold 	}
69434982809SIngo Weinhold 
69534982809SIngo Weinhold 	// read a part of the comment section
69634982809SIngo Weinhold 	if (commentSize > 512)
69734982809SIngo Weinhold 		commentSize = 512;
69834982809SIngo Weinhold 
69934982809SIngo Weinhold 	length = _kern_read(fd, commentOffset, buffer, commentSize);
70034982809SIngo Weinhold 	if (length != (int)commentSize) {
70134982809SIngo Weinhold 		FATAL("Could not read .comment section: %s\n", strerror(length));
70234982809SIngo Weinhold 		return false;
70334982809SIngo Weinhold 	}
70434982809SIngo Weinhold 
70534982809SIngo Weinhold 	// the common prefix of the strings in the .comment section
70634982809SIngo Weinhold 	static const char* kGCCVersionPrefix = "GCC: (GNU) ";
70734982809SIngo Weinhold 	size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix);
70834982809SIngo Weinhold 
70934982809SIngo Weinhold 	size_t index = 0;
71034982809SIngo Weinhold 	int gccMajor = 0;
71134982809SIngo Weinhold 	int gccMiddle = 0;
71234982809SIngo Weinhold 	int gccMinor = 0;
7132716cfd3SAxel Dörfler 	bool isHaiku = true;
71434982809SIngo Weinhold 
71534982809SIngo Weinhold 	// Read up to 10 comments. The first three or four are usually from the
71634982809SIngo Weinhold 	// glue code.
71734982809SIngo Weinhold 	for (int i = 0; i < 10; i++) {
71834982809SIngo Weinhold 		// skip '\0'
71934982809SIngo Weinhold 		while (index < commentSize && buffer[index] == '\0')
72034982809SIngo Weinhold 			index++;
72134982809SIngo Weinhold 		char* stringStart = buffer + index;
72234982809SIngo Weinhold 
72334982809SIngo Weinhold 		// find string end
72434982809SIngo Weinhold 		while (index < commentSize && buffer[index] != '\0')
72534982809SIngo Weinhold 			index++;
72634982809SIngo Weinhold 
72734982809SIngo Weinhold 		// ignore the entry at the end of the buffer
72834982809SIngo Weinhold 		if (index == commentSize)
72934982809SIngo Weinhold 			break;
73034982809SIngo Weinhold 
73134982809SIngo Weinhold 		// We have to analyze string like these:
73234982809SIngo Weinhold 		// GCC: (GNU) 2.9-beos-991026
73334982809SIngo Weinhold 		// GCC: (GNU) 2.95.3-haiku-080322
73434982809SIngo Weinhold 		// GCC: (GNU) 4.1.2
73534982809SIngo Weinhold 
73634982809SIngo Weinhold 		// skip the common prefix
73734982809SIngo Weinhold 		if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0)
73834982809SIngo Weinhold 			continue;
73934982809SIngo Weinhold 
74034982809SIngo Weinhold 		// the rest is the GCC version
74134982809SIngo Weinhold 		char* gccVersion = stringStart + gccVersionPrefixLen;
74234982809SIngo Weinhold 		char* gccPlatform = strchr(gccVersion, '-');
74334982809SIngo Weinhold 		char* patchLevel = NULL;
74434982809SIngo Weinhold 		if (gccPlatform != NULL) {
74534982809SIngo Weinhold 			*gccPlatform = '\0';
74634982809SIngo Weinhold 			gccPlatform++;
74734982809SIngo Weinhold 			patchLevel = strchr(gccPlatform, '-');
74834982809SIngo Weinhold 			if (patchLevel != NULL) {
74934982809SIngo Weinhold 				*patchLevel = '\0';
75034982809SIngo Weinhold 				patchLevel++;
75134982809SIngo Weinhold 			}
75234982809SIngo Weinhold 		}
75334982809SIngo Weinhold 
75434982809SIngo Weinhold 		// split the gcc version into major, middle, and minor
75534982809SIngo Weinhold 		int version[3] = { 0, 0, 0 };
75634982809SIngo Weinhold 
75734982809SIngo Weinhold 		for (int k = 0; gccVersion != NULL && k < 3; k++) {
75834982809SIngo Weinhold 			char* dot = strchr(gccVersion, '.');
75934982809SIngo Weinhold 			if (dot) {
76034982809SIngo Weinhold 				*dot = '\0';
76134982809SIngo Weinhold 				dot++;
76234982809SIngo Weinhold 			}
76334982809SIngo Weinhold 			version[k] = atoi(gccVersion);
76434982809SIngo Weinhold 			gccVersion = dot;
76534982809SIngo Weinhold 		}
76634982809SIngo Weinhold 
76734982809SIngo Weinhold 		// got any version?
76834982809SIngo Weinhold 		if (version[0] == 0)
76934982809SIngo Weinhold 			continue;
77034982809SIngo Weinhold 
77134982809SIngo Weinhold 		// Select the gcc version with the smallest major, but the greatest
77234982809SIngo Weinhold 		// middle/minor. This should usually ignore the glue code version as
77334982809SIngo Weinhold 		// well as cases where e.g. in a gcc 2 program a single C file has
77434982809SIngo Weinhold 		// been compiled with gcc 4.
77534982809SIngo Weinhold 		if (gccMajor == 0 || gccMajor > version[0]
77634982809SIngo Weinhold 		 	|| gccMajor == version[0]
77734982809SIngo Weinhold 				&& (gccMiddle < version[1]
77834982809SIngo Weinhold 					|| gccMiddle == version[1] && gccMinor < version[2])) {
77934982809SIngo Weinhold 			gccMajor = version[0];
78034982809SIngo Weinhold 			gccMiddle = version[1];
78134982809SIngo Weinhold 			gccMinor = version[2];
78234982809SIngo Weinhold 		}
7832716cfd3SAxel Dörfler 
78485f9771aSFrançois Revol 		if (gccMajor == 2 && gccPlatform != NULL && strcmp(gccPlatform, "haiku"))
7852716cfd3SAxel Dörfler 			isHaiku = false;
78634982809SIngo Weinhold 	}
78734982809SIngo Weinhold 
78834982809SIngo Weinhold 	image->gcc_version.major = gccMajor;
78934982809SIngo Weinhold 	image->gcc_version.middle = gccMiddle;
79034982809SIngo Weinhold 	image->gcc_version.minor = gccMinor;
7912716cfd3SAxel Dörfler 	image->gcc_version.haiku = isHaiku;
79234982809SIngo Weinhold 
79334982809SIngo Weinhold 	return gccMajor != 0;
79434982809SIngo Weinhold }
79534982809SIngo Weinhold 
79634982809SIngo Weinhold 
79734982809SIngo Weinhold static bool
7980c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image)
7990c0fea5dSIngo Weinhold {
8000c0fea5dSIngo Weinhold 	uint32 i;
8010c0fea5dSIngo Weinhold 
8020c0fea5dSIngo Weinhold 	if (!image->dynamic_ptr)
8030c0fea5dSIngo Weinhold 		return true;
8040c0fea5dSIngo Weinhold 
8050c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
8060c0fea5dSIngo Weinhold 		if (image->dynamic_ptr >= image->regions[i].start
8070c0fea5dSIngo Weinhold 			&& image->dynamic_ptr < image->regions[i].start + image->regions[i].size)
8080c0fea5dSIngo Weinhold 			return true;
8090c0fea5dSIngo Weinhold 	}
8100c0fea5dSIngo Weinhold 
8110c0fea5dSIngo Weinhold 	return false;
8120c0fea5dSIngo Weinhold }
8130c0fea5dSIngo Weinhold 
8140c0fea5dSIngo Weinhold 
8150c0fea5dSIngo Weinhold /**	This function will change the protection of all read-only segments
8160c0fea5dSIngo Weinhold  *	to really be read-only.
8170c0fea5dSIngo Weinhold  *	The areas have to be read/write first, so that they can be relocated.
8180c0fea5dSIngo Weinhold  */
8190c0fea5dSIngo Weinhold 
8200c0fea5dSIngo Weinhold static void
8210c0fea5dSIngo Weinhold remap_images(void)
8220c0fea5dSIngo Weinhold {
8230c0fea5dSIngo Weinhold 	image_t *image;
8240c0fea5dSIngo Weinhold 	uint32 i;
8250c0fea5dSIngo Weinhold 
8260c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
8270c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_regions; i++) {
8280c0fea5dSIngo Weinhold 			if ((image->regions[i].flags & RFLAG_RW) == 0
8290c0fea5dSIngo Weinhold 				&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
8300c0fea5dSIngo Weinhold 				// we only need to do this once, so we remember those we've already mapped
8310c0fea5dSIngo Weinhold 				if (_kern_set_area_protection(image->regions[i].id,
8320c0fea5dSIngo Weinhold 						B_READ_AREA | B_EXECUTE_AREA) == B_OK)
8330c0fea5dSIngo Weinhold 					image->regions[i].flags |= RFLAG_REMAPPED;
8340c0fea5dSIngo Weinhold 			}
8350c0fea5dSIngo Weinhold 		}
8360c0fea5dSIngo Weinhold 	}
8370c0fea5dSIngo Weinhold }
8380c0fea5dSIngo Weinhold 
8390c0fea5dSIngo Weinhold 
8400c0fea5dSIngo Weinhold static status_t
8410c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed)
8420c0fea5dSIngo Weinhold {
8430c0fea5dSIngo Weinhold 	status_t status = B_OK;
8440c0fea5dSIngo Weinhold 	const char *baseName;
8450c0fea5dSIngo Weinhold 	uint32 i;
8460c0fea5dSIngo Weinhold 
8470c0fea5dSIngo Weinhold 	(void)(fd);
8480c0fea5dSIngo Weinhold 
8490c0fea5dSIngo Weinhold 	// cut the file name from the path as base name for the created areas
8500c0fea5dSIngo Weinhold 	baseName = strrchr(path, '/');
8510c0fea5dSIngo Weinhold 	if (baseName != NULL)
8520c0fea5dSIngo Weinhold 		baseName++;
8530c0fea5dSIngo Weinhold 	else
8540c0fea5dSIngo Weinhold 		baseName = path;
8550c0fea5dSIngo Weinhold 
8560c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
8570c0fea5dSIngo Weinhold 		char regionName[B_OS_NAME_LENGTH];
8580c0fea5dSIngo Weinhold 		addr_t loadAddress;
8590c0fea5dSIngo Weinhold 		uint32 addressSpecifier;
8600c0fea5dSIngo Weinhold 
8610c0fea5dSIngo Weinhold 		// for BeOS compatibility: if we load an old BeOS executable, we
8620c0fea5dSIngo Weinhold 		// have to relocate it, if possible - we recognize it because the
8630c0fea5dSIngo Weinhold 		// vmstart is set to 0 (hopefully always)
8640c0fea5dSIngo Weinhold 		if (fixed && image->regions[i].vmstart == 0)
8650c0fea5dSIngo Weinhold 			fixed = false;
8660c0fea5dSIngo Weinhold 
8670c0fea5dSIngo Weinhold 		snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
8680c0fea5dSIngo Weinhold 			baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
8690c0fea5dSIngo Weinhold 
8700c0fea5dSIngo Weinhold 		if (image->dynamic_ptr && !fixed) {
8710c0fea5dSIngo Weinhold 			// relocatable image... we can afford to place wherever
8720c0fea5dSIngo Weinhold 			if (i == 0) {
8730c0fea5dSIngo Weinhold 				// but only the first segment gets a free ride
8740c0fea5dSIngo Weinhold 				loadAddress = RLD_PROGRAM_BASE;
8750c0fea5dSIngo Weinhold 				addressSpecifier = B_BASE_ADDRESS;
8760c0fea5dSIngo Weinhold 			} else {
8770c0fea5dSIngo Weinhold 				loadAddress = image->regions[i].vmstart + image->regions[i-1].delta;
8780c0fea5dSIngo Weinhold 				addressSpecifier = B_EXACT_ADDRESS;
8790c0fea5dSIngo Weinhold 			}
8800c0fea5dSIngo Weinhold 		} else {
8810c0fea5dSIngo Weinhold 			// not relocatable, put it where it asks or die trying
8820c0fea5dSIngo Weinhold 			loadAddress = image->regions[i].vmstart;
8830c0fea5dSIngo Weinhold 			addressSpecifier = B_EXACT_ADDRESS;
8840c0fea5dSIngo Weinhold 		}
8850c0fea5dSIngo Weinhold 
8860c0fea5dSIngo Weinhold 		if (image->regions[i].flags & RFLAG_ANON) {
8870c0fea5dSIngo Weinhold 			image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress,
8880c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_NO_LOCK,
8890c0fea5dSIngo Weinhold 				B_READ_AREA | B_WRITE_AREA);
8900c0fea5dSIngo Weinhold 
8910c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
8920c0fea5dSIngo Weinhold 				status = image->regions[i].id;
8930c0fea5dSIngo Weinhold 				goto error;
8940c0fea5dSIngo Weinhold 			}
8950c0fea5dSIngo Weinhold 
8960c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
8970c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
8980c0fea5dSIngo Weinhold 		} else {
8993cf7ecd1SIngo Weinhold 			image->regions[i].id = _kern_map_file(regionName,
9003cf7ecd1SIngo Weinhold 				(void **)&loadAddress, addressSpecifier,
9013cf7ecd1SIngo Weinhold 				image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
9023cf7ecd1SIngo Weinhold 				REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart));
9030c0fea5dSIngo Weinhold 
9040c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
9050c0fea5dSIngo Weinhold 				status = image->regions[i].id;
9060c0fea5dSIngo Weinhold 				goto error;
9070c0fea5dSIngo Weinhold 			}
9080c0fea5dSIngo Weinhold 
9090c0fea5dSIngo Weinhold 			TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
9100c0fea5dSIngo Weinhold 				(void *)loadAddress, image->regions[i].vmsize,
9110c0fea5dSIngo Weinhold 				image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
9120c0fea5dSIngo Weinhold 
9130c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
9140c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
9150c0fea5dSIngo Weinhold 
9160c0fea5dSIngo Weinhold 			// handle trailer bits in data segment
9170c0fea5dSIngo Weinhold 			if (image->regions[i].flags & RFLAG_RW) {
9180c0fea5dSIngo Weinhold 				addr_t startClearing;
9190c0fea5dSIngo Weinhold 				addr_t toClear;
9200c0fea5dSIngo Weinhold 
9210c0fea5dSIngo Weinhold 				startClearing = image->regions[i].vmstart
9220c0fea5dSIngo Weinhold 					+ PAGE_OFFSET(image->regions[i].start)
9230c0fea5dSIngo Weinhold 					+ image->regions[i].size;
9240c0fea5dSIngo Weinhold 				toClear = image->regions[i].vmsize
9250c0fea5dSIngo Weinhold 					- PAGE_OFFSET(image->regions[i].start)
9260c0fea5dSIngo Weinhold 					- image->regions[i].size;
9270c0fea5dSIngo Weinhold 
9280c0fea5dSIngo Weinhold 				TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear));
9290c0fea5dSIngo Weinhold 				memset((void *)startClearing, 0, toClear);
9300c0fea5dSIngo Weinhold 			}
9310c0fea5dSIngo Weinhold 		}
9320c0fea5dSIngo Weinhold 	}
9330c0fea5dSIngo Weinhold 
9340c0fea5dSIngo Weinhold 	if (image->dynamic_ptr)
9350c0fea5dSIngo Weinhold 		image->dynamic_ptr += image->regions[0].delta;
9360c0fea5dSIngo Weinhold 
9370c0fea5dSIngo Weinhold 	return B_OK;
9380c0fea5dSIngo Weinhold 
9390c0fea5dSIngo Weinhold error:
9400c0fea5dSIngo Weinhold 	return status;
9410c0fea5dSIngo Weinhold }
9420c0fea5dSIngo Weinhold 
9430c0fea5dSIngo Weinhold 
9440c0fea5dSIngo Weinhold static void
9450c0fea5dSIngo Weinhold unmap_image(image_t *image)
9460c0fea5dSIngo Weinhold {
9470c0fea5dSIngo Weinhold 	uint32 i;
9480c0fea5dSIngo Weinhold 
9490c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
9500c0fea5dSIngo Weinhold 		_kern_delete_area(image->regions[i].id);
9510c0fea5dSIngo Weinhold 
9520c0fea5dSIngo Weinhold 		image->regions[i].id = -1;
9530c0fea5dSIngo Weinhold 	}
9540c0fea5dSIngo Weinhold }
9550c0fea5dSIngo Weinhold 
9560c0fea5dSIngo Weinhold 
9570c0fea5dSIngo Weinhold static bool
9580c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image)
9590c0fea5dSIngo Weinhold {
9600c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d;
9610c0fea5dSIngo Weinhold 	int i;
9620c0fea5dSIngo Weinhold 	int sonameOffset = -1;
9630c0fea5dSIngo Weinhold 
9640c0fea5dSIngo Weinhold 	image->symhash = 0;
9650c0fea5dSIngo Weinhold 	image->syms = 0;
9660c0fea5dSIngo Weinhold 	image->strtab = 0;
9670c0fea5dSIngo Weinhold 
9680c0fea5dSIngo Weinhold 	d = (struct Elf32_Dyn *)image->dynamic_ptr;
9690c0fea5dSIngo Weinhold 	if (!d)
9700c0fea5dSIngo Weinhold 		return true;
9710c0fea5dSIngo Weinhold 
9720c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
9730c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
9740c0fea5dSIngo Weinhold 			case DT_NEEDED:
9750c0fea5dSIngo Weinhold 				image->num_needed += 1;
9760c0fea5dSIngo Weinhold 				break;
9770c0fea5dSIngo Weinhold 			case DT_HASH:
9780c0fea5dSIngo Weinhold 				image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta);
9790c0fea5dSIngo Weinhold 				break;
9800c0fea5dSIngo Weinhold 			case DT_STRTAB:
9810c0fea5dSIngo Weinhold 				image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
9820c0fea5dSIngo Weinhold 				break;
9830c0fea5dSIngo Weinhold 			case DT_SYMTAB:
9840c0fea5dSIngo Weinhold 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
9850c0fea5dSIngo Weinhold 				break;
9860c0fea5dSIngo Weinhold 			case DT_REL:
9870c0fea5dSIngo Weinhold 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
9880c0fea5dSIngo Weinhold 				break;
9890c0fea5dSIngo Weinhold 			case DT_RELSZ:
9900c0fea5dSIngo Weinhold 				image->rel_len = d[i].d_un.d_val;
9910c0fea5dSIngo Weinhold 				break;
9920c0fea5dSIngo Weinhold 			case DT_RELA:
9930c0fea5dSIngo Weinhold 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
9940c0fea5dSIngo Weinhold 				break;
9950c0fea5dSIngo Weinhold 			case DT_RELASZ:
9960c0fea5dSIngo Weinhold 				image->rela_len = d[i].d_un.d_val;
9970c0fea5dSIngo Weinhold 				break;
9980c0fea5dSIngo Weinhold 			// TK: procedure linkage table
9990c0fea5dSIngo Weinhold 			case DT_JMPREL:
10000c0fea5dSIngo Weinhold 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
10010c0fea5dSIngo Weinhold 				break;
10020c0fea5dSIngo Weinhold 			case DT_PLTRELSZ:
10030c0fea5dSIngo Weinhold 				image->pltrel_len = d[i].d_un.d_val;
10040c0fea5dSIngo Weinhold 				break;
10050c0fea5dSIngo Weinhold 			case DT_INIT:
10060c0fea5dSIngo Weinhold 				image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
10070c0fea5dSIngo Weinhold 				break;
10080c0fea5dSIngo Weinhold 			case DT_FINI:
10090c0fea5dSIngo Weinhold 				image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
10100c0fea5dSIngo Weinhold 				break;
10110c0fea5dSIngo Weinhold 			case DT_SONAME:
10120c0fea5dSIngo Weinhold 				sonameOffset = d[i].d_un.d_val;
10130c0fea5dSIngo Weinhold 				break;
10140c0fea5dSIngo Weinhold 			default:
10150c0fea5dSIngo Weinhold 				continue;
10160c0fea5dSIngo Weinhold 		}
10170c0fea5dSIngo Weinhold 	}
10180c0fea5dSIngo Weinhold 
10190c0fea5dSIngo Weinhold 	// lets make sure we found all the required sections
10200c0fea5dSIngo Weinhold 	if (!image->symhash || !image->syms || !image->strtab)
10210c0fea5dSIngo Weinhold 		return false;
10220c0fea5dSIngo Weinhold 
10230c0fea5dSIngo Weinhold 	if (sonameOffset >= 0)
10240c0fea5dSIngo Weinhold 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
10250c0fea5dSIngo Weinhold 
10260c0fea5dSIngo Weinhold 	return true;
10270c0fea5dSIngo Weinhold }
10280c0fea5dSIngo Weinhold 
10290c0fea5dSIngo Weinhold 
1030*10b4b5d1SIngo Weinhold static void
1031*10b4b5d1SIngo Weinhold patch_defined_symbol(image_t* image, const char* name, void** symbol,
1032*10b4b5d1SIngo Weinhold 	int32* type)
1033*10b4b5d1SIngo Weinhold {
1034*10b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers;
1035*10b4b5d1SIngo Weinhold 	while (patcher != NULL && *symbol != 0) {
1036*10b4b5d1SIngo Weinhold 		image_t* inImage = image;
1037*10b4b5d1SIngo Weinhold 		patcher->patcher(patcher->cookie, NULL, image, name, &inImage,
1038*10b4b5d1SIngo Weinhold 			symbol, type);
1039*10b4b5d1SIngo Weinhold 		patcher = patcher->next;
1040*10b4b5d1SIngo Weinhold 	}
1041*10b4b5d1SIngo Weinhold }
1042*10b4b5d1SIngo Weinhold 
1043*10b4b5d1SIngo Weinhold 
1044*10b4b5d1SIngo Weinhold static void
1045*10b4b5d1SIngo Weinhold patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
1046*10b4b5d1SIngo Weinhold 	image_t** foundInImage, void** symbol, int32* type)
1047*10b4b5d1SIngo Weinhold {
1048*10b4b5d1SIngo Weinhold 	if (*foundInImage != NULL)
1049*10b4b5d1SIngo Weinhold 		patch_defined_symbol(*foundInImage, name, symbol, type);
1050*10b4b5d1SIngo Weinhold 
1051*10b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers;
1052*10b4b5d1SIngo Weinhold 	while (patcher != NULL) {
1053*10b4b5d1SIngo Weinhold 		patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage,
1054*10b4b5d1SIngo Weinhold 			symbol, type);
1055*10b4b5d1SIngo Weinhold 		patcher = patcher->next;
1056*10b4b5d1SIngo Weinhold 	}
1057*10b4b5d1SIngo Weinhold }
1058*10b4b5d1SIngo Weinhold 
1059*10b4b5d1SIngo Weinhold 
1060*10b4b5d1SIngo Weinhold status_t
1061*10b4b5d1SIngo Weinhold register_defined_symbol_patcher(struct image_t* image,
1062*10b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
1063*10b4b5d1SIngo Weinhold {
1064*10b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher
1065*10b4b5d1SIngo Weinhold 		= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
1066*10b4b5d1SIngo Weinhold 	if (patcher == NULL)
1067*10b4b5d1SIngo Weinhold 		return B_NO_MEMORY;
1068*10b4b5d1SIngo Weinhold 
1069*10b4b5d1SIngo Weinhold 	patcher->next = image->defined_symbol_patchers;
1070*10b4b5d1SIngo Weinhold 	image->defined_symbol_patchers = patcher;
1071*10b4b5d1SIngo Weinhold 
1072*10b4b5d1SIngo Weinhold 	return B_OK;
1073*10b4b5d1SIngo Weinhold }
1074*10b4b5d1SIngo Weinhold 
1075*10b4b5d1SIngo Weinhold 
1076*10b4b5d1SIngo Weinhold void
1077*10b4b5d1SIngo Weinhold unregister_defined_symbol_patcher(struct image_t* image,
1078*10b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
1079*10b4b5d1SIngo Weinhold {
1080*10b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher** patcher = &image->defined_symbol_patchers;
1081*10b4b5d1SIngo Weinhold 	while (*patcher != NULL) {
1082*10b4b5d1SIngo Weinhold 		if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
1083*10b4b5d1SIngo Weinhold 			RuntimeLoaderSymbolPatcher* toDelete = *patcher;
1084*10b4b5d1SIngo Weinhold 			*patcher = (*patcher)->next;
1085*10b4b5d1SIngo Weinhold 			delete toDelete;
1086*10b4b5d1SIngo Weinhold 			return;
1087*10b4b5d1SIngo Weinhold 		}
1088*10b4b5d1SIngo Weinhold 		patcher = &(*patcher)->next;
1089*10b4b5d1SIngo Weinhold 	}
1090*10b4b5d1SIngo Weinhold }
1091*10b4b5d1SIngo Weinhold 
1092*10b4b5d1SIngo Weinhold 
1093*10b4b5d1SIngo Weinhold status_t
1094*10b4b5d1SIngo Weinhold register_undefined_symbol_patcher(struct image_t* image,
1095*10b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
1096*10b4b5d1SIngo Weinhold {
1097*10b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher* patcher
1098*10b4b5d1SIngo Weinhold 		= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
1099*10b4b5d1SIngo Weinhold 	if (patcher == NULL)
1100*10b4b5d1SIngo Weinhold 		return B_NO_MEMORY;
1101*10b4b5d1SIngo Weinhold 
1102*10b4b5d1SIngo Weinhold 	patcher->next = image->undefined_symbol_patchers;
1103*10b4b5d1SIngo Weinhold 	image->undefined_symbol_patchers = patcher;
1104*10b4b5d1SIngo Weinhold 
1105*10b4b5d1SIngo Weinhold 	return B_OK;
1106*10b4b5d1SIngo Weinhold }
1107*10b4b5d1SIngo Weinhold 
1108*10b4b5d1SIngo Weinhold 
1109*10b4b5d1SIngo Weinhold void
1110*10b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher(struct image_t* image,
1111*10b4b5d1SIngo Weinhold 	runtime_loader_symbol_patcher* _patcher, void* cookie)
1112*10b4b5d1SIngo Weinhold {
1113*10b4b5d1SIngo Weinhold 	RuntimeLoaderSymbolPatcher** patcher = &image->undefined_symbol_patchers;
1114*10b4b5d1SIngo Weinhold 	while (*patcher != NULL) {
1115*10b4b5d1SIngo Weinhold 		if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
1116*10b4b5d1SIngo Weinhold 			RuntimeLoaderSymbolPatcher* toDelete = *patcher;
1117*10b4b5d1SIngo Weinhold 			*patcher = (*patcher)->next;
1118*10b4b5d1SIngo Weinhold 			delete toDelete;
1119*10b4b5d1SIngo Weinhold 			return;
1120*10b4b5d1SIngo Weinhold 		}
1121*10b4b5d1SIngo Weinhold 		patcher = &(*patcher)->next;
1122*10b4b5d1SIngo Weinhold 	}
1123*10b4b5d1SIngo Weinhold }
1124*10b4b5d1SIngo Weinhold 
1125*10b4b5d1SIngo Weinhold 
1126*10b4b5d1SIngo Weinhold runtime_loader_add_on_export gRuntimeLoaderAddOnExport = {
1127*10b4b5d1SIngo Weinhold 	register_defined_symbol_patcher,
1128*10b4b5d1SIngo Weinhold 	unregister_defined_symbol_patcher,
1129*10b4b5d1SIngo Weinhold 	register_undefined_symbol_patcher,
1130*10b4b5d1SIngo Weinhold 	unregister_undefined_symbol_patcher
1131*10b4b5d1SIngo Weinhold };
1132*10b4b5d1SIngo Weinhold 
1133*10b4b5d1SIngo Weinhold 
11340c0fea5dSIngo Weinhold static struct Elf32_Sym *
11350c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type)
11360c0fea5dSIngo Weinhold {
11370c0fea5dSIngo Weinhold 	uint32 hash, i;
11380c0fea5dSIngo Weinhold 
11390c0fea5dSIngo Weinhold 	// ToDo: "type" is currently ignored!
11400c0fea5dSIngo Weinhold 	(void)type;
11410c0fea5dSIngo Weinhold 
1142dd76bc97SIngo Weinhold 	if (image->dynamic_ptr == 0)
11430c0fea5dSIngo Weinhold 		return NULL;
11440c0fea5dSIngo Weinhold 
11450c0fea5dSIngo Weinhold 	hash = elf_hash((uint8 *)name) % HASHTABSIZE(image);
11460c0fea5dSIngo Weinhold 
11470c0fea5dSIngo Weinhold 	for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
11480c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = &image->syms[i];
11490c0fea5dSIngo Weinhold 
11500c0fea5dSIngo Weinhold 		if (symbol->st_shndx != SHN_UNDEF
11510c0fea5dSIngo Weinhold 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
11520c0fea5dSIngo Weinhold 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
11530c0fea5dSIngo Weinhold 			&& !strcmp(SYMNAME(image, symbol), name)) {
11540c0fea5dSIngo Weinhold 			// check if the type matches
11550c0fea5dSIngo Weinhold 			if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
11560c0fea5dSIngo Weinhold 				|| (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT))
11570c0fea5dSIngo Weinhold 				continue;
11580c0fea5dSIngo Weinhold 
11590c0fea5dSIngo Weinhold 			return symbol;
11600c0fea5dSIngo Weinhold 		}
11610c0fea5dSIngo Weinhold 	}
11620c0fea5dSIngo Weinhold 
11630c0fea5dSIngo Weinhold 	return NULL;
11640c0fea5dSIngo Weinhold }
11650c0fea5dSIngo Weinhold 
11660c0fea5dSIngo Weinhold 
1167*10b4b5d1SIngo Weinhold static status_t
1168*10b4b5d1SIngo Weinhold find_symbol(image_t* image, char const* symbolName, int32 symbolType,
1169*10b4b5d1SIngo Weinhold 	void **_location)
1170*10b4b5d1SIngo Weinhold {
1171*10b4b5d1SIngo Weinhold 	// get the symbol in the image
1172*10b4b5d1SIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol(image, symbolName, symbolType);
1173*10b4b5d1SIngo Weinhold 	if (symbol == NULL)
1174*10b4b5d1SIngo Weinhold 		return B_ENTRY_NOT_FOUND;
1175*10b4b5d1SIngo Weinhold 
1176*10b4b5d1SIngo Weinhold 	void* location = (void*)(symbol->st_value + image->regions[0].delta);
1177*10b4b5d1SIngo Weinhold 	patch_defined_symbol(image, symbolName, &location, &symbolType);
1178*10b4b5d1SIngo Weinhold 
1179*10b4b5d1SIngo Weinhold 	if (_location != NULL)
1180*10b4b5d1SIngo Weinhold 		*_location = location;
1181*10b4b5d1SIngo Weinhold 
1182*10b4b5d1SIngo Weinhold 	return B_OK;
1183*10b4b5d1SIngo Weinhold }
1184*10b4b5d1SIngo Weinhold 
1185*10b4b5d1SIngo Weinhold 
11860c0fea5dSIngo Weinhold static struct Elf32_Sym*
1187ca618b22SIngo Weinhold find_symbol_in_root_image_list(image_t* rootImage, const char* name,
118846f4d849SIngo Weinhold 	image_t** foundInImage)
11890c0fea5dSIngo Weinhold {
1190ca618b22SIngo Weinhold 	int32 count = rootImage->symbol_resolution_image_count;
1191ca618b22SIngo Weinhold 	image_t** images = rootImage->symbol_resolution_images;
1192ca618b22SIngo Weinhold 	for (int32 i = 0; i < count; i++) {
1193ca618b22SIngo Weinhold 		image_t* image = images[i];
119446f4d849SIngo Weinhold 		if (image->dynamic_ptr) {
1195ca618b22SIngo Weinhold 			Elf32_Sym* symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY);
11960c0fea5dSIngo Weinhold 			if (symbol) {
119746f4d849SIngo Weinhold 				*foundInImage = image;
119846f4d849SIngo Weinhold 				return symbol;
119946f4d849SIngo Weinhold 			}
120046f4d849SIngo Weinhold 		}
12010c0fea5dSIngo Weinhold 	}
12020c0fea5dSIngo Weinhold 
12030c0fea5dSIngo Weinhold 	return NULL;
12040c0fea5dSIngo Weinhold }
12050c0fea5dSIngo Weinhold 
12060c0fea5dSIngo Weinhold 
120746f4d849SIngo Weinhold static struct Elf32_Sym*
120846f4d849SIngo Weinhold find_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
120946f4d849SIngo Weinhold 	image_t** foundInImage)
121046f4d849SIngo Weinhold {
121146f4d849SIngo Weinhold 	// If not simulating BeOS style symbol resolution, undefined symbols are
121292af28dfSIngo Weinhold 	// searched recursively starting from the root image.
1213ca618b22SIngo Weinhold 	if ((rootImage->flags & IMAGE_FLAG_R5_SYMBOL_RESOLUTION) == 0)
1214ca618b22SIngo Weinhold 		return find_symbol_in_root_image_list(rootImage, name, foundInImage);
121546f4d849SIngo Weinhold 
121646f4d849SIngo Weinhold 	// BeOS style symbol resolution: It is sufficient to check the direct
121746f4d849SIngo Weinhold 	// dependencies. The linker would have complained, if the symbol wasn't
121846f4d849SIngo Weinhold 	// there.
121946f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
122046f4d849SIngo Weinhold 		if (image->needed[i]->dynamic_ptr) {
122146f4d849SIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(image->needed[i], name,
122246f4d849SIngo Weinhold 				B_SYMBOL_TYPE_ANY);
122346f4d849SIngo Weinhold 			if (symbol) {
122446f4d849SIngo Weinhold 				*foundInImage = image->needed[i];
122546f4d849SIngo Weinhold 				return symbol;
122646f4d849SIngo Weinhold 			}
122746f4d849SIngo Weinhold 		}
122846f4d849SIngo Weinhold 	}
122946f4d849SIngo Weinhold 
123046f4d849SIngo Weinhold 	return NULL;
123146f4d849SIngo Weinhold }
123246f4d849SIngo Weinhold 
123346f4d849SIngo Weinhold 
1234*10b4b5d1SIngo Weinhold /*!	This function is called when we run BeOS images on Haiku.
12352716cfd3SAxel Dörfler 	It allows us to redirect functions to ensure compatibility.
12362716cfd3SAxel Dörfler */
12372716cfd3SAxel Dörfler static const char*
12382716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName)
12392716cfd3SAxel Dörfler {
12402716cfd3SAxel Dörfler 	struct symbol_mapping {
12412716cfd3SAxel Dörfler 		const char* from;
12422716cfd3SAxel Dörfler 		const char* to;
12432716cfd3SAxel Dörfler 	};
12442716cfd3SAxel Dörfler 	static const struct symbol_mapping kMappings[] = {
1245*10b4b5d1SIngo Weinhold 		// TODO: Improve this, and also use it for libnet.so compatibility!
1246*10b4b5d1SIngo Weinhold 		// Allow an image to provide a function that will be invoked for every
1247*10b4b5d1SIngo Weinhold 		// (transitively) depending image. The function can return a table to
1248*10b4b5d1SIngo Weinhold 		// remap symbols (probably better address to address). All the tables
1249*10b4b5d1SIngo Weinhold 		// for a single image would be combined into a hash table and an
1250*10b4b5d1SIngo Weinhold 		// undefined symbol patcher using this hash table would be added.
12512716cfd3SAxel Dörfler 		{"fstat", "__be_fstat"},
12522716cfd3SAxel Dörfler 		{"lstat", "__be_lstat"},
12532716cfd3SAxel Dörfler 		{"stat", "__be_stat"},
12542716cfd3SAxel Dörfler 	};
12552716cfd3SAxel Dörfler 	const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]);
12562716cfd3SAxel Dörfler 
12572716cfd3SAxel Dörfler 	for (uint32 i = 0; i < kMappingCount; i++) {
12582716cfd3SAxel Dörfler 		if (!strcmp(symbolName, kMappings[i].from))
12592716cfd3SAxel Dörfler 			return kMappings[i].to;
12602716cfd3SAxel Dörfler 	}
12612716cfd3SAxel Dörfler 
12622716cfd3SAxel Dörfler 	return symbolName;
12632716cfd3SAxel Dörfler }
12642716cfd3SAxel Dörfler 
12652716cfd3SAxel Dörfler 
12660c0fea5dSIngo Weinhold int
126746f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
12682716cfd3SAxel Dörfler 	addr_t *symAddress)
12690c0fea5dSIngo Weinhold {
12700c0fea5dSIngo Weinhold 	switch (sym->st_shndx) {
12710c0fea5dSIngo Weinhold 		case SHN_UNDEF:
12722716cfd3SAxel Dörfler 		{
12732716cfd3SAxel Dörfler 			struct Elf32_Sym *sharedSym;
12742716cfd3SAxel Dörfler 			image_t *sharedImage;
12752716cfd3SAxel Dörfler 			const char *symName;
12762716cfd3SAxel Dörfler 
12770c0fea5dSIngo Weinhold 			// patch the symbol name
12782716cfd3SAxel Dörfler 			symName = SYMNAME(image, sym);
12792716cfd3SAxel Dörfler 			if (!image->gcc_version.haiku) {
12802716cfd3SAxel Dörfler 				// The image has been compiled with a BeOS compiler. This means
12812716cfd3SAxel Dörfler 				// we'll have to redirect some functions for compatibility.
12822716cfd3SAxel Dörfler 				symName = beos_compatibility_map_symbol(symName);
12832716cfd3SAxel Dörfler 			}
12840c0fea5dSIngo Weinhold 
1285*10b4b5d1SIngo Weinhold 			int32 type = B_SYMBOL_TYPE_ANY;
1286*10b4b5d1SIngo Weinhold 			if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC)
1287*10b4b5d1SIngo Weinhold 				type = B_SYMBOL_TYPE_TEXT;
1288*10b4b5d1SIngo Weinhold 			else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT)
1289*10b4b5d1SIngo Weinhold 				type = B_SYMBOL_TYPE_DATA;
1290*10b4b5d1SIngo Weinhold 
129146f4d849SIngo Weinhold 			// it's undefined, must be outside this image, try the other images
12922716cfd3SAxel Dörfler 			sharedSym = find_undefined_symbol(rootImage, image, symName,
12932716cfd3SAxel Dörfler 				&sharedImage);
1294*10b4b5d1SIngo Weinhold 			void* location = NULL;
12950c0fea5dSIngo Weinhold 
1296*10b4b5d1SIngo Weinhold 			enum {
1297*10b4b5d1SIngo Weinhold 				ERROR_NO_SYMBOL,
1298*10b4b5d1SIngo Weinhold 				ERROR_WRONG_TYPE,
1299*10b4b5d1SIngo Weinhold 				ERROR_NOT_EXPORTED,
1300*10b4b5d1SIngo Weinhold 				ERROR_UNPATCHED
1301*10b4b5d1SIngo Weinhold 			};
1302*10b4b5d1SIngo Weinhold 			uint32 lookupError = ERROR_UNPATCHED;
1303*10b4b5d1SIngo Weinhold 
1304*10b4b5d1SIngo Weinhold 			if (sharedSym == NULL) {
1305*10b4b5d1SIngo Weinhold 				// symbol not found at all
1306*10b4b5d1SIngo Weinhold 				lookupError = ERROR_NO_SYMBOL;
1307*10b4b5d1SIngo Weinhold 				sharedImage = NULL;
1308*10b4b5d1SIngo Weinhold 			} else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
13092716cfd3SAxel Dörfler 				&& ELF32_ST_TYPE(sym->st_info)
13102716cfd3SAxel Dörfler 					!= ELF32_ST_TYPE(sharedSym->st_info)) {
1311*10b4b5d1SIngo Weinhold 				// symbol not of the requested type
1312*10b4b5d1SIngo Weinhold 				lookupError = ERROR_WRONG_TYPE;
1313*10b4b5d1SIngo Weinhold 				sharedImage = NULL;
1314*10b4b5d1SIngo Weinhold 			} else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL
13152716cfd3SAxel Dörfler 				&& ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) {
1316*10b4b5d1SIngo Weinhold 				// symbol not exported
1317*10b4b5d1SIngo Weinhold 				lookupError = ERROR_NOT_EXPORTED;
1318*10b4b5d1SIngo Weinhold 				sharedImage = NULL;
1319*10b4b5d1SIngo Weinhold 			} else {
1320*10b4b5d1SIngo Weinhold 				// symbol is fine, get its location
1321*10b4b5d1SIngo Weinhold 				location = (void*)(sharedSym->st_value
1322*10b4b5d1SIngo Weinhold 					+ sharedImage->regions[0].delta);
1323*10b4b5d1SIngo Weinhold 			}
1324*10b4b5d1SIngo Weinhold 
1325*10b4b5d1SIngo Weinhold 			patch_undefined_symbol(rootImage, image, symName, &sharedImage,
1326*10b4b5d1SIngo Weinhold 				&location, &type);
1327*10b4b5d1SIngo Weinhold 
1328*10b4b5d1SIngo Weinhold 			if (location == NULL) {
1329*10b4b5d1SIngo Weinhold 				switch (lookupError) {
1330*10b4b5d1SIngo Weinhold 					case ERROR_NO_SYMBOL:
1331*10b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: could not resolve symbol "
1332*10b4b5d1SIngo Weinhold 							"'%s'\n", symName);
1333*10b4b5d1SIngo Weinhold 						break;
1334*10b4b5d1SIngo Weinhold 					case ERROR_WRONG_TYPE:
1335*10b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s' in shared "
1336*10b4b5d1SIngo Weinhold 							"image but wrong type\n", symName);
1337*10b4b5d1SIngo Weinhold 						break;
1338*10b4b5d1SIngo Weinhold 					case ERROR_NOT_EXPORTED:
1339*10b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s', but not "
13402716cfd3SAxel Dörfler 							"exported\n", symName);
1341*10b4b5d1SIngo Weinhold 						break;
1342*10b4b5d1SIngo Weinhold 					case ERROR_UNPATCHED:
1343*10b4b5d1SIngo Weinhold 						FATAL("elf_resolve_symbol: found symbol '%s', but was "
1344*10b4b5d1SIngo Weinhold 							"hidden by symbol patchers\n", symName);
1345*10b4b5d1SIngo Weinhold 						break;
1346*10b4b5d1SIngo Weinhold 				}
13470c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
13480c0fea5dSIngo Weinhold 			}
13490c0fea5dSIngo Weinhold 
1350*10b4b5d1SIngo Weinhold 			*symAddress = (addr_t)location;
1351*10b4b5d1SIngo Weinhold 			return B_OK;
13522716cfd3SAxel Dörfler 		}
13530c0fea5dSIngo Weinhold 
13540c0fea5dSIngo Weinhold 		case SHN_ABS:
13552716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
13560c0fea5dSIngo Weinhold 			return B_NO_ERROR;
13570c0fea5dSIngo Weinhold 
13580c0fea5dSIngo Weinhold 		case SHN_COMMON:
13590c0fea5dSIngo Weinhold 			// ToDo: finish this
13602a33a944SIngo Weinhold 			FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n");
13610c0fea5dSIngo Weinhold 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
13620c0fea5dSIngo Weinhold 
13630c0fea5dSIngo Weinhold 		default:
13640c0fea5dSIngo Weinhold 			// standard symbol
13652716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
13660c0fea5dSIngo Weinhold 			return B_NO_ERROR;
13670c0fea5dSIngo Weinhold 	}
13680c0fea5dSIngo Weinhold }
13690c0fea5dSIngo Weinhold 
13700c0fea5dSIngo Weinhold 
13710c0fea5dSIngo Weinhold static void
1372*10b4b5d1SIngo Weinhold image_event(image_t* image, uint32 event)
1373*10b4b5d1SIngo Weinhold {
1374*10b4b5d1SIngo Weinhold 	AddOnList::Iterator it = sAddOns.GetIterator();
1375*10b4b5d1SIngo Weinhold 	while (RuntimeLoaderAddOn* addOn = it.Next()) {
1376*10b4b5d1SIngo Weinhold 		void (*function)(image_t* image) = NULL;
1377*10b4b5d1SIngo Weinhold 
1378*10b4b5d1SIngo Weinhold 		switch (event) {
1379*10b4b5d1SIngo Weinhold 			case IMAGE_EVENT_LOADED:
1380*10b4b5d1SIngo Weinhold 				function = addOn->addOn->image_loaded;
1381*10b4b5d1SIngo Weinhold 				break;
1382*10b4b5d1SIngo Weinhold 			case IMAGE_EVENT_RELOCATED:
1383*10b4b5d1SIngo Weinhold 				function = addOn->addOn->image_relocated;
1384*10b4b5d1SIngo Weinhold 				break;
1385*10b4b5d1SIngo Weinhold 			case IMAGE_EVENT_INITIALIZED:
1386*10b4b5d1SIngo Weinhold 				function = addOn->addOn->image_initialized;
1387*10b4b5d1SIngo Weinhold 				break;
1388*10b4b5d1SIngo Weinhold 			case IMAGE_EVENT_UNINITIALIZING:
1389*10b4b5d1SIngo Weinhold 				function = addOn->addOn->image_uninitializing;
1390*10b4b5d1SIngo Weinhold 				break;
1391*10b4b5d1SIngo Weinhold 			case IMAGE_EVENT_UNLOADING:
1392*10b4b5d1SIngo Weinhold 				function = addOn->addOn->image_unloading;
1393*10b4b5d1SIngo Weinhold 				break;
1394*10b4b5d1SIngo Weinhold 		}
1395*10b4b5d1SIngo Weinhold 
1396*10b4b5d1SIngo Weinhold 		if (function != NULL)
1397*10b4b5d1SIngo Weinhold 			function(image);
1398*10b4b5d1SIngo Weinhold 	}
1399*10b4b5d1SIngo Weinhold }
1400*10b4b5d1SIngo Weinhold 
1401*10b4b5d1SIngo Weinhold 
1402*10b4b5d1SIngo Weinhold static void
14030c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path)
14040c0fea5dSIngo Weinhold {
14050c0fea5dSIngo Weinhold 	struct stat stat;
14060c0fea5dSIngo Weinhold 	image_info info;
14070c0fea5dSIngo Weinhold 
14080c0fea5dSIngo Weinhold 	// ToDo: set these correctly
14090c0fea5dSIngo Weinhold 	info.id = 0;
14100c0fea5dSIngo Weinhold 	info.type = image->type;
14110c0fea5dSIngo Weinhold 	info.sequence = 0;
14120c0fea5dSIngo Weinhold 	info.init_order = 0;
14130c0fea5dSIngo Weinhold 	info.init_routine = (void (*)())image->init_routine;
14140c0fea5dSIngo Weinhold 	info.term_routine = (void (*)())image->term_routine;
14150c0fea5dSIngo Weinhold 
14160c0fea5dSIngo Weinhold 	if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
14170c0fea5dSIngo Weinhold 		info.device = stat.st_dev;
14180c0fea5dSIngo Weinhold 		info.node = stat.st_ino;
14190c0fea5dSIngo Weinhold 	} else {
14200c0fea5dSIngo Weinhold 		info.device = -1;
14210c0fea5dSIngo Weinhold 		info.node = -1;
14220c0fea5dSIngo Weinhold 	}
14230c0fea5dSIngo Weinhold 
14240c0fea5dSIngo Weinhold 	strlcpy(info.name, path, sizeof(info.name));
14250c0fea5dSIngo Weinhold 	info.text = (void *)image->regions[0].vmstart;
14260c0fea5dSIngo Weinhold 	info.text_size = image->regions[0].vmsize;
14270c0fea5dSIngo Weinhold 	info.data = (void *)image->regions[1].vmstart;
14280c0fea5dSIngo Weinhold 	info.data_size = image->regions[1].vmsize;
14290c0fea5dSIngo Weinhold 	image->id = _kern_register_image(&info, sizeof(image_info));
14300c0fea5dSIngo Weinhold }
14310c0fea5dSIngo Weinhold 
14320c0fea5dSIngo Weinhold 
14330c0fea5dSIngo Weinhold static status_t
143446f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
14350c0fea5dSIngo Weinhold {
143646f4d849SIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image);
14370c0fea5dSIngo Weinhold 	if (status < B_OK) {
1438320bd2bdSAxel Dörfler 		FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status,
1439320bd2bdSAxel Dörfler 			image->path, image->name);
14400c0fea5dSIngo Weinhold 		return status;
14410c0fea5dSIngo Weinhold 	}
14420c0fea5dSIngo Weinhold 
14430c0fea5dSIngo Weinhold 	_kern_image_relocated(image->id);
1444*10b4b5d1SIngo Weinhold 	image_event(image, IMAGE_EVENT_RELOCATED);
14450c0fea5dSIngo Weinhold 	return B_OK;
14460c0fea5dSIngo Weinhold }
14470c0fea5dSIngo Weinhold 
14480c0fea5dSIngo Weinhold 
14490c0fea5dSIngo Weinhold static status_t
14500c0fea5dSIngo Weinhold load_container(char const *name, image_type type, const char *rpath, image_t **_image)
14510c0fea5dSIngo Weinhold {
14520c0fea5dSIngo Weinhold 	int32 pheaderSize, sheaderSize;
14530c0fea5dSIngo Weinhold 	char path[PATH_MAX];
14540c0fea5dSIngo Weinhold 	ssize_t length;
14550c0fea5dSIngo Weinhold 	char ph_buff[4096];
14560c0fea5dSIngo Weinhold 	int32 numRegions;
14570c0fea5dSIngo Weinhold 	image_t *found;
14580c0fea5dSIngo Weinhold 	image_t *image;
14590c0fea5dSIngo Weinhold 	status_t status;
14600c0fea5dSIngo Weinhold 	int fd;
14610c0fea5dSIngo Weinhold 
14620c0fea5dSIngo Weinhold 	struct Elf32_Ehdr eheader;
14630c0fea5dSIngo Weinhold 
14640c0fea5dSIngo Weinhold 	// Have we already loaded that image? Don't check for add-ons -- we always
14650c0fea5dSIngo Weinhold 	// reload them.
14660c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
14670c0fea5dSIngo Weinhold 		found = find_image(name, APP_OR_LIBRARY_TYPE);
146802e577f9SIngo Weinhold 
146902e577f9SIngo Weinhold 		if (found == NULL && type != B_APP_IMAGE) {
147002e577f9SIngo Weinhold 			// Special case for add-ons that link against the application
147102e577f9SIngo Weinhold 			// executable, with the executable not having a soname set.
147202e577f9SIngo Weinhold 			if (const char* lastSlash = strrchr(name, '/')) {
147302e577f9SIngo Weinhold 				image_t* programImage = get_program_image();
147402e577f9SIngo Weinhold 				if (strcmp(programImage->name, lastSlash + 1) == 0)
147502e577f9SIngo Weinhold 					found = programImage;
147602e577f9SIngo Weinhold 			}
147702e577f9SIngo Weinhold 		}
147802e577f9SIngo Weinhold 
14790c0fea5dSIngo Weinhold 		if (found) {
14800c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
14810c0fea5dSIngo Weinhold 			*_image = found;
14827486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") "
14837486b72dSIngo Weinhold 				"already loaded", name, type, rpath);
14840c0fea5dSIngo Weinhold 			return B_OK;
14850c0fea5dSIngo Weinhold 		}
14860c0fea5dSIngo Weinhold 	}
14870c0fea5dSIngo Weinhold 
14887486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type,
14897486b72dSIngo Weinhold 		rpath);
14907486b72dSIngo Weinhold 
14910c0fea5dSIngo Weinhold 	strlcpy(path, name, sizeof(path));
14920c0fea5dSIngo Weinhold 
149361b37794SIngo Weinhold 	// find and open the file
149461b37794SIngo Weinhold 	fd = open_executable(path, type, rpath, get_program_path(),
149561b37794SIngo Weinhold 		sSearchPathSubDir);
14960c0fea5dSIngo Weinhold 	if (fd < 0) {
149702e577f9SIngo Weinhold 		FATAL("cannot open file %s\n", name);
14987486b72dSIngo Weinhold 		KTRACE("rld: load_container(\"%s\"): failed to open file", name);
14990c0fea5dSIngo Weinhold 		return fd;
15000c0fea5dSIngo Weinhold 	}
15010c0fea5dSIngo Weinhold 
15026918dbf4SIngo Weinhold 	// normalize the image path
15036918dbf4SIngo Weinhold 	status = _kern_normalize_path(path, true, path);
15046918dbf4SIngo Weinhold 	if (status != B_OK)
15050c0fea5dSIngo Weinhold 		goto err1;
15060c0fea5dSIngo Weinhold 
15070c0fea5dSIngo Weinhold 	// Test again if this image has been registered already - this time,
15080c0fea5dSIngo Weinhold 	// we can check the full path, not just its name as noted.
15090c0fea5dSIngo Weinhold 	// You could end up loading an image twice with symbolic links, else.
15100c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
15110c0fea5dSIngo Weinhold 		found = find_image(path, APP_OR_LIBRARY_TYPE);
15120c0fea5dSIngo Weinhold 		if (found) {
15130c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
15140c0fea5dSIngo Weinhold 			*_image = found;
1515b2568a30SIngo Weinhold 			_kern_close(fd);
15167486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\"): already loaded after all",
15177486b72dSIngo Weinhold 				name);
15180c0fea5dSIngo Weinhold 			return B_OK;
15190c0fea5dSIngo Weinhold 		}
15200c0fea5dSIngo Weinhold 	}
15210c0fea5dSIngo Weinhold 
15220c0fea5dSIngo Weinhold 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
15230c0fea5dSIngo Weinhold 	if (length != sizeof(eheader)) {
15240c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
15250c0fea5dSIngo Weinhold 		FATAL("troubles reading ELF header\n");
15260c0fea5dSIngo Weinhold 		goto err1;
15270c0fea5dSIngo Weinhold 	}
15280c0fea5dSIngo Weinhold 
15290c0fea5dSIngo Weinhold 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
15300c0fea5dSIngo Weinhold 	if (status < B_OK) {
15310c0fea5dSIngo Weinhold 		FATAL("incorrect ELF header\n");
15320c0fea5dSIngo Weinhold 		goto err1;
15330c0fea5dSIngo Weinhold 	}
15340c0fea5dSIngo Weinhold 
15350c0fea5dSIngo Weinhold 	// ToDo: what to do about this restriction??
15360c0fea5dSIngo Weinhold 	if (pheaderSize > (int)sizeof(ph_buff)) {
15370c0fea5dSIngo Weinhold 		FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff));
15380c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
15390c0fea5dSIngo Weinhold 		goto err1;
15400c0fea5dSIngo Weinhold 	}
15410c0fea5dSIngo Weinhold 
15420c0fea5dSIngo Weinhold 	length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize);
15430c0fea5dSIngo Weinhold 	if (length != pheaderSize) {
15440c0fea5dSIngo Weinhold 		FATAL("Could not read program headers: %s\n", strerror(length));
15450c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
15460c0fea5dSIngo Weinhold 		goto err1;
15470c0fea5dSIngo Weinhold 	}
15480c0fea5dSIngo Weinhold 
15490c0fea5dSIngo Weinhold 	numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
15500c0fea5dSIngo Weinhold 	if (numRegions <= 0) {
15510c0fea5dSIngo Weinhold 		FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
15520c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
15530c0fea5dSIngo Weinhold 		goto err1;
15540c0fea5dSIngo Weinhold 	}
15550c0fea5dSIngo Weinhold 
15560c0fea5dSIngo Weinhold 	image = create_image(name, path, numRegions);
15570c0fea5dSIngo Weinhold 	if (image == NULL) {
15580c0fea5dSIngo Weinhold 		FATAL("Failed to allocate image_t object\n");
15590c0fea5dSIngo Weinhold 		status = B_NO_MEMORY;
15600c0fea5dSIngo Weinhold 		goto err1;
15610c0fea5dSIngo Weinhold 	}
15620c0fea5dSIngo Weinhold 
15630c0fea5dSIngo Weinhold 	status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
15640c0fea5dSIngo Weinhold 	if (status < B_OK)
15650c0fea5dSIngo Weinhold 		goto err2;
15660c0fea5dSIngo Weinhold 
15670c0fea5dSIngo Weinhold 	if (!assert_dynamic_loadable(image)) {
15680c0fea5dSIngo Weinhold 		FATAL("Dynamic segment must be loadable (implementation restriction)\n");
15690c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
15700c0fea5dSIngo Weinhold 		goto err2;
15710c0fea5dSIngo Weinhold 	}
15720c0fea5dSIngo Weinhold 
157361b37794SIngo Weinhold 	if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff,
157434982809SIngo Weinhold 			sizeof(ph_buff))) {
157561b37794SIngo Weinhold 		// If this is the executable image, we init the search path
157661b37794SIngo Weinhold 		// subdir, if the compiler version doesn't match ours.
157761b37794SIngo Weinhold 		if (type == B_APP_IMAGE) {
157861b37794SIngo Weinhold 			#if __GNUC__ == 2
157961b37794SIngo Weinhold 				if (image->gcc_version.major > 2)
158061b37794SIngo Weinhold 					sSearchPathSubDir = "gcc4";
158161b37794SIngo Weinhold 			#elif __GNUC__ == 4
158261b37794SIngo Weinhold 				if (image->gcc_version.major == 2)
158361b37794SIngo Weinhold 					sSearchPathSubDir = "gcc2";
158461b37794SIngo Weinhold 			#endif
158561b37794SIngo Weinhold 		}
158661b37794SIngo Weinhold 	} else {
158734982809SIngo Weinhold 		FATAL("Failed to get gcc version for %s\n", path);
158834982809SIngo Weinhold 		// not really fatal, actually
158934982809SIngo Weinhold 	}
159034982809SIngo Weinhold 
15915fd6637bSIngo Weinhold 	// init gcc version dependent image flags
15925fd6637bSIngo Weinhold 	// symbol resolution strategy (fallback is R5-style, if version is
15935fd6637bSIngo Weinhold 	// unavailable)
15945fd6637bSIngo Weinhold 	if (image->gcc_version.major == 0
15955fd6637bSIngo Weinhold 		|| image->gcc_version.major == 2 && image->gcc_version.middle < 95) {
15965fd6637bSIngo Weinhold 		image->flags |= IMAGE_FLAG_R5_SYMBOL_RESOLUTION;
15975fd6637bSIngo Weinhold 	}
15985fd6637bSIngo Weinhold 
15990c0fea5dSIngo Weinhold 	status = map_image(fd, path, image, type == B_APP_IMAGE);
16000c0fea5dSIngo Weinhold 	if (status < B_OK) {
16010c0fea5dSIngo Weinhold 		FATAL("Could not map image: %s\n", strerror(status));
16020c0fea5dSIngo Weinhold 		status = B_ERROR;
16030c0fea5dSIngo Weinhold 		goto err2;
16040c0fea5dSIngo Weinhold 	}
16050c0fea5dSIngo Weinhold 
16060c0fea5dSIngo Weinhold 	if (!parse_dynamic_segment(image)) {
16070c0fea5dSIngo Weinhold 		FATAL("Troubles handling dynamic section\n");
16080c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
16090c0fea5dSIngo Weinhold 		goto err3;
16100c0fea5dSIngo Weinhold 	}
16110c0fea5dSIngo Weinhold 
1612dd76bc97SIngo Weinhold 	if (eheader.e_entry != 0)
16130c0fea5dSIngo Weinhold 		image->entry_point = eheader.e_entry + image->regions[0].delta;
16140c0fea5dSIngo Weinhold 
16150c0fea5dSIngo Weinhold 	image->type = type;
16160c0fea5dSIngo Weinhold 	register_image(image, fd, path);
1617*10b4b5d1SIngo Weinhold 	image_event(image, IMAGE_EVENT_LOADED);
16180c0fea5dSIngo Weinhold 
16190c0fea5dSIngo Weinhold 	_kern_close(fd);
16200c0fea5dSIngo Weinhold 
16210c0fea5dSIngo Weinhold 	enqueue_image(&sLoadedImages, image);
16220c0fea5dSIngo Weinhold 	sLoadedImageCount++;
16230c0fea5dSIngo Weinhold 
16240c0fea5dSIngo Weinhold 	*_image = image;
16257486b72dSIngo Weinhold 
162634982809SIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): done: id: %ld (gcc: %d.%d.%d)", name,
162734982809SIngo Weinhold 		image->id, image->gcc_version.major, image->gcc_version.middle,
162834982809SIngo Weinhold 		image->gcc_version.minor);
16297486b72dSIngo Weinhold 
16300c0fea5dSIngo Weinhold 	return B_OK;
16310c0fea5dSIngo Weinhold 
16320c0fea5dSIngo Weinhold err3:
16330c0fea5dSIngo Weinhold 	unmap_image(image);
16340c0fea5dSIngo Weinhold err2:
16350c0fea5dSIngo Weinhold 	delete_image_struct(image);
16360c0fea5dSIngo Weinhold err1:
16370c0fea5dSIngo Weinhold 	_kern_close(fd);
16387486b72dSIngo Weinhold 
16397486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): failed: %s", name,
16407486b72dSIngo Weinhold 		strerror(status));
16417486b72dSIngo Weinhold 
16420c0fea5dSIngo Weinhold 	return status;
16430c0fea5dSIngo Weinhold }
16440c0fea5dSIngo Weinhold 
16450c0fea5dSIngo Weinhold 
16460c0fea5dSIngo Weinhold static const char *
16470c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
16480c0fea5dSIngo Weinhold {
16490c0fea5dSIngo Weinhold 	int i;
16500c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
16510c0fea5dSIngo Weinhold 
16520c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
16530c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
16540c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
16550c0fea5dSIngo Weinhold 	}
16560c0fea5dSIngo Weinhold 
16570c0fea5dSIngo Weinhold 	return NULL;
16580c0fea5dSIngo Weinhold }
16590c0fea5dSIngo Weinhold 
16600c0fea5dSIngo Weinhold 
16610c0fea5dSIngo Weinhold static status_t
16620c0fea5dSIngo Weinhold load_dependencies(image_t *image)
16630c0fea5dSIngo Weinhold {
16640c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
16654bef3723SAxel Dörfler 	bool reportErrors = report_errors();
166674c0424aSAxel Dörfler 	status_t status = B_OK;
16670c0fea5dSIngo Weinhold 	uint32 i, j;
16680c0fea5dSIngo Weinhold 	const char *rpath;
16690c0fea5dSIngo Weinhold 
16700c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
16710c0fea5dSIngo Weinhold 		return B_OK;
16720c0fea5dSIngo Weinhold 
16730c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
16740c0fea5dSIngo Weinhold 
16750c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
16760c0fea5dSIngo Weinhold 		return B_OK;
16770c0fea5dSIngo Weinhold 
16787486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
16797486b72dSIngo Weinhold 		image->id);
16807486b72dSIngo Weinhold 
16810c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
16820c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
16830c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
16847486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
16857486b72dSIngo Weinhold 			image->name, image->id);
16860c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
16870c0fea5dSIngo Weinhold 	}
16880c0fea5dSIngo Weinhold 
16890c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
16900c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
16910c0fea5dSIngo Weinhold 
16920c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
16930c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
16940c0fea5dSIngo Weinhold 			case DT_NEEDED:
169574c0424aSAxel Dörfler 			{
169674c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
169774c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
16980c0fea5dSIngo Weinhold 
169974c0424aSAxel Dörfler 				status_t loadStatus = load_container(name, B_LIBRARY_IMAGE,
170074c0424aSAxel Dörfler 					rpath, &image->needed[j]);
170174c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
170274c0424aSAxel Dörfler 					status = loadStatus;
170374c0424aSAxel Dörfler 					// correct error code in case the file could not been found
170474c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
170574c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
170674c0424aSAxel Dörfler 
170774c0424aSAxel Dörfler 						if (reportErrors)
170874c0424aSAxel Dörfler 							sErrorMessage.AddString("missing library", name);
170974c0424aSAxel Dörfler 					}
171074c0424aSAxel Dörfler 
171174c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
17127486b72dSIngo Weinhold 					if (!reportErrors) {
17137486b72dSIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
17147486b72dSIngo Weinhold 							"failed: %s", image->name, image->id,
17157486b72dSIngo Weinhold 							strerror(status));
17160c0fea5dSIngo Weinhold 						return status;
171774c0424aSAxel Dörfler 					}
17187486b72dSIngo Weinhold 				}
17190c0fea5dSIngo Weinhold 
17200c0fea5dSIngo Weinhold 				j += 1;
17210c0fea5dSIngo Weinhold 				break;
172274c0424aSAxel Dörfler 			}
17230c0fea5dSIngo Weinhold 
17240c0fea5dSIngo Weinhold 			default:
17250c0fea5dSIngo Weinhold 				// ignore any other tag
17260c0fea5dSIngo Weinhold 				continue;
17270c0fea5dSIngo Weinhold 		}
17280c0fea5dSIngo Weinhold 	}
17290c0fea5dSIngo Weinhold 
17307486b72dSIngo Weinhold 	if (status < B_OK) {
17317486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
17327486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
17337486b72dSIngo Weinhold 			strerror(status));
173474c0424aSAxel Dörfler 		return status;
17357486b72dSIngo Weinhold 	}
173674c0424aSAxel Dörfler 
17370c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
17380c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
17397486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
17407486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
17410c0fea5dSIngo Weinhold 		return B_ERROR;
17420c0fea5dSIngo Weinhold 	}
17430c0fea5dSIngo Weinhold 
17447486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
17457486b72dSIngo Weinhold 		image->id);
17467486b72dSIngo Weinhold 
17470c0fea5dSIngo Weinhold 	return B_OK;
17480c0fea5dSIngo Weinhold }
17490c0fea5dSIngo Weinhold 
17500c0fea5dSIngo Weinhold 
17510c0fea5dSIngo Weinhold static uint32
17520c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList,
17530c0fea5dSIngo Weinhold 	uint32 sortFlag)
17540c0fea5dSIngo Weinhold {
17550c0fea5dSIngo Weinhold 	uint32 i;
17560c0fea5dSIngo Weinhold 
17570c0fea5dSIngo Weinhold 	if (image->flags & sortFlag)
17580c0fea5dSIngo Weinhold 		return slot;
17590c0fea5dSIngo Weinhold 
17600c0fea5dSIngo Weinhold 	image->flags |= sortFlag; /* make sure we don't visit this one */
17610c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_needed; i++)
17620c0fea5dSIngo Weinhold 		slot = topological_sort(image->needed[i], slot, initList, sortFlag);
17630c0fea5dSIngo Weinhold 
17640c0fea5dSIngo Weinhold 	initList[slot] = image;
17650c0fea5dSIngo Weinhold 	return slot + 1;
17660c0fea5dSIngo Weinhold }
17670c0fea5dSIngo Weinhold 
17680c0fea5dSIngo Weinhold 
1769ca618b22SIngo Weinhold static uint32
1770ca618b22SIngo Weinhold topological_sort_breadth_first(image_t* image, image_t** list, uint32 sortFlag)
1771ca618b22SIngo Weinhold {
1772ca618b22SIngo Weinhold 	if ((image->flags & sortFlag) != 0)
1773ca618b22SIngo Weinhold 		return 0;
1774ca618b22SIngo Weinhold 
1775ca618b22SIngo Weinhold 	// We directly use the result list as queue for the breadth first search.
1776ca618b22SIngo Weinhold 	list[0] = image;
1777ca618b22SIngo Weinhold 	image->flags |= sortFlag;
1778ca618b22SIngo Weinhold 
1779ca618b22SIngo Weinhold 	int32 index = 0;
1780ca618b22SIngo Weinhold 	int32 count = 1;
1781ca618b22SIngo Weinhold 
1782ca618b22SIngo Weinhold 	while (index < count) {
1783ca618b22SIngo Weinhold 		image = list[index++];
1784ca618b22SIngo Weinhold 
1785ca618b22SIngo Weinhold 		for (uint32 i = 0; i < image->num_needed; i++) {
1786ca618b22SIngo Weinhold 			image_t* neededImage = image->needed[i];
1787ca618b22SIngo Weinhold 			if ((neededImage->flags & sortFlag) == 0) {
1788ca618b22SIngo Weinhold 				// dependency not yet visited -- add to queue
1789ca618b22SIngo Weinhold 				list[count++] = neededImage;
1790ca618b22SIngo Weinhold 				neededImage->flags |= sortFlag;
1791ca618b22SIngo Weinhold 			}
1792ca618b22SIngo Weinhold 		}
1793ca618b22SIngo Weinhold 	}
1794ca618b22SIngo Weinhold 
1795ca618b22SIngo Weinhold 	return count;
1796ca618b22SIngo Weinhold }
1797ca618b22SIngo Weinhold 
1798ca618b22SIngo Weinhold 
17990c0fea5dSIngo Weinhold static ssize_t
18000c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
18010c0fea5dSIngo Weinhold {
18020c0fea5dSIngo Weinhold 	image_t **list;
18030c0fea5dSIngo Weinhold 
18040c0fea5dSIngo Weinhold 	list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *));
18050c0fea5dSIngo Weinhold 	if (list == NULL) {
18060c0fea5dSIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
18070c0fea5dSIngo Weinhold 		*_list = NULL;
18080c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
18090c0fea5dSIngo Weinhold 	}
18100c0fea5dSIngo Weinhold 
18110c0fea5dSIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
18120c0fea5dSIngo Weinhold 
18130c0fea5dSIngo Weinhold 	*_list = list;
18140c0fea5dSIngo Weinhold 	return topological_sort(image, 0, list, sortFlag);
18150c0fea5dSIngo Weinhold }
18160c0fea5dSIngo Weinhold 
18170c0fea5dSIngo Weinhold 
1818ca618b22SIngo Weinhold static ssize_t
1819ca618b22SIngo Weinhold get_sorted_image_list_breadth_first(image_t* image, image_t*** _list,
1820ca618b22SIngo Weinhold 	uint32 sortFlag)
1821ca618b22SIngo Weinhold {
1822ca618b22SIngo Weinhold 	image_t** list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t*));
1823ca618b22SIngo Weinhold 	if (list == NULL) {
1824ca618b22SIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
1825ca618b22SIngo Weinhold 		*_list = NULL;
1826ca618b22SIngo Weinhold 		return B_NO_MEMORY;
1827ca618b22SIngo Weinhold 	}
1828ca618b22SIngo Weinhold 
1829ca618b22SIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
1830ca618b22SIngo Weinhold 
1831ca618b22SIngo Weinhold 	*_list = list;
1832ca618b22SIngo Weinhold 
1833ca618b22SIngo Weinhold 	return topological_sort_breadth_first(image, list, sortFlag);
1834ca618b22SIngo Weinhold }
1835ca618b22SIngo Weinhold 
1836ca618b22SIngo Weinhold 
18370c0fea5dSIngo Weinhold static status_t
18380c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
18390c0fea5dSIngo Weinhold {
1840ca618b22SIngo Weinhold 	// build an array of images in the order we want to lookup symbols
1841ca618b22SIngo Weinhold 	image_t** lookupList;
1842ca618b22SIngo Weinhold 	ssize_t lookupCount = get_sorted_image_list_breadth_first(image,
1843ca618b22SIngo Weinhold 		&lookupList, RFLAG_VISITED);
1844ca618b22SIngo Weinhold 	if (lookupCount < 0)
1845ca618b22SIngo Weinhold 		return lookupCount;
18460c0fea5dSIngo Weinhold 
1847ca618b22SIngo Weinhold 	// If the image is not the program image, add it and its dependencies, too.
1848ca618b22SIngo Weinhold 	if (sProgramImage != NULL && image != sProgramImage) {
1849ca618b22SIngo Weinhold 		lookupCount += topological_sort_breadth_first(sProgramImage,
1850ca618b22SIngo Weinhold 			lookupList + lookupCount, RFLAG_VISITED);
1851ca618b22SIngo Weinhold 	}
1852ca618b22SIngo Weinhold 
1853ca618b22SIngo Weinhold 	// If we have pre-loaded images, prepend them.
1854ca618b22SIngo Weinhold 	if (sPreloadedImageCount > 0) {
1855ca618b22SIngo Weinhold 		// Count the ones that have to be added -- normally all, but one never
1856ca618b22SIngo Weinhold 		// knows.
1857ca618b22SIngo Weinhold 		uint32 preloadedCount = 0;
1858ca618b22SIngo Weinhold 		for (uint32 i = 0; i < sPreloadedImageCount; i++) {
1859ca618b22SIngo Weinhold 			image_t* preloadedImage = sPreloadedImages[i];
1860ca618b22SIngo Weinhold 			if ((preloadedImage->flags & RFLAG_VISITED) == 0)
1861ca618b22SIngo Weinhold 				preloadedCount++;
1862ca618b22SIngo Weinhold 		}
1863ca618b22SIngo Weinhold 
1864ca618b22SIngo Weinhold 		// add them
1865ca618b22SIngo Weinhold 		if (preloadedCount > 0) {
1866ca618b22SIngo Weinhold 			memmove(lookupList + preloadedCount, lookupList,
1867ca618b22SIngo Weinhold 				lookupCount * sizeof(image_t*));
1868ca618b22SIngo Weinhold 			lookupCount += preloadedCount;
1869ca618b22SIngo Weinhold 
1870ca618b22SIngo Weinhold 			preloadedCount = 0;
1871ca618b22SIngo Weinhold 			for (uint32 i = 0; i < sPreloadedImageCount; i++) {
1872ca618b22SIngo Weinhold 				image_t* preloadedImage = sPreloadedImages[i];
1873ca618b22SIngo Weinhold 				if ((preloadedImage->flags & RFLAG_VISITED) == 0)
1874ca618b22SIngo Weinhold 					lookupList[preloadedCount++] = preloadedImage;
1875ca618b22SIngo Weinhold 			}
1876ca618b22SIngo Weinhold 		}
1877ca618b22SIngo Weinhold 	}
1878ca618b22SIngo Weinhold 
1879ca618b22SIngo Weinhold 	// clear the "visited" flag
1880ca618b22SIngo Weinhold 	for (int32 i = 0; i < lookupCount; i++)
1881ca618b22SIngo Weinhold 		lookupList[i]->flags &= ~RFLAG_VISITED;
1882ca618b22SIngo Weinhold 
1883ca618b22SIngo Weinhold 	image->symbol_resolution_images = lookupList;
1884ca618b22SIngo Weinhold 	image->symbol_resolution_image_count = lookupCount;
1885ca618b22SIngo Weinhold 
1886ca618b22SIngo Weinhold 	// get the images that still have to be relocated
1887ca618b22SIngo Weinhold 	image_t **list;
1888ca618b22SIngo Weinhold 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
18890c0fea5dSIngo Weinhold 	if (count < B_OK)
18900c0fea5dSIngo Weinhold 		return count;
18910c0fea5dSIngo Weinhold 
1892ca618b22SIngo Weinhold 	for (ssize_t i = 0; i < count; i++) {
189346f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
18940c0fea5dSIngo Weinhold 		if (status < B_OK)
18950c0fea5dSIngo Weinhold 			return status;
18960c0fea5dSIngo Weinhold 	}
18970c0fea5dSIngo Weinhold 
18980c0fea5dSIngo Weinhold 	free(list);
18990c0fea5dSIngo Weinhold 	return B_OK;
19000c0fea5dSIngo Weinhold }
19010c0fea5dSIngo Weinhold 
19020c0fea5dSIngo Weinhold 
19030c0fea5dSIngo Weinhold static void
19040c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
19050c0fea5dSIngo Weinhold {
19060c0fea5dSIngo Weinhold 	image_t **initList;
19070c0fea5dSIngo Weinhold 	ssize_t count, i;
19080c0fea5dSIngo Weinhold 
19090c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
19100c0fea5dSIngo Weinhold 	if (count <= 0)
19110c0fea5dSIngo Weinhold 		return;
19120c0fea5dSIngo Weinhold 
19130c0fea5dSIngo Weinhold 	if (!initHead) {
19140c0fea5dSIngo Weinhold 		// this removes the "calling" image
19150c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
19160c0fea5dSIngo Weinhold 		initList[--count] = NULL;
19170c0fea5dSIngo Weinhold 	}
19180c0fea5dSIngo Weinhold 
19190c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
19200c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
19210c0fea5dSIngo Weinhold 		image = initList[i];
19220c0fea5dSIngo Weinhold 
19230c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
19240c0fea5dSIngo Weinhold 
1925dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
19260c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
1927*10b4b5d1SIngo Weinhold 
1928*10b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_INITIALIZED);
19290c0fea5dSIngo Weinhold 	}
19300c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
19310c0fea5dSIngo Weinhold 
19320c0fea5dSIngo Weinhold 	free(initList);
19330c0fea5dSIngo Weinhold }
19340c0fea5dSIngo Weinhold 
19350c0fea5dSIngo Weinhold 
19360c0fea5dSIngo Weinhold static void
19370c0fea5dSIngo Weinhold put_image(image_t *image)
19380c0fea5dSIngo Weinhold {
19390c0fea5dSIngo Weinhold 	// If all references to the image are gone, add it to the disposable list
19400c0fea5dSIngo Weinhold 	// and remove all dependencies
19410c0fea5dSIngo Weinhold 
19420c0fea5dSIngo Weinhold 	if (atomic_add(&image->ref_count, -1) == 1) {
19430c0fea5dSIngo Weinhold 		size_t i;
19440c0fea5dSIngo Weinhold 
19450c0fea5dSIngo Weinhold 		dequeue_image(&sLoadedImages, image);
19460c0fea5dSIngo Weinhold 		enqueue_image(&sDisposableImages, image);
19470c0fea5dSIngo Weinhold 		sLoadedImageCount--;
19480c0fea5dSIngo Weinhold 
19490c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_needed; i++) {
19500c0fea5dSIngo Weinhold 			put_image(image->needed[i]);
19510c0fea5dSIngo Weinhold 		}
19520c0fea5dSIngo Weinhold 	}
19530c0fea5dSIngo Weinhold }
19540c0fea5dSIngo Weinhold 
19550c0fea5dSIngo Weinhold 
1956ca618b22SIngo Weinhold void
1957ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage)
1958ca618b22SIngo Weinhold {
1959ca618b22SIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private
1960ca618b22SIngo Weinhold 	// API.
1961ca618b22SIngo Weinhold 	image_t* image;
1962ca618b22SIngo Weinhold 	Elf32_Sym* symbol = find_symbol_in_root_image_list(rootImage,
1963ca618b22SIngo Weinhold 		"__gRuntimeLoader", &image);
1964ca618b22SIngo Weinhold 
1965ca618b22SIngo Weinhold 	if (symbol != NULL) {
1966ca618b22SIngo Weinhold 		void** _export = (void**)(symbol->st_value + image->regions[0].delta);
1967ca618b22SIngo Weinhold 		*_export = &gRuntimeLoader;
1968ca618b22SIngo Weinhold 	}
1969ca618b22SIngo Weinhold }
1970ca618b22SIngo Weinhold 
1971ca618b22SIngo Weinhold 
1972ca618b22SIngo Weinhold static status_t
1973ca618b22SIngo Weinhold add_preloaded_image(image_t* image)
1974ca618b22SIngo Weinhold {
1975ca618b22SIngo Weinhold 	// We realloc() everytime -- not particularly efficient, but good enough for
1976ca618b22SIngo Weinhold 	// small number of preloaded images.
1977ca618b22SIngo Weinhold 	image_t** newArray = (image_t**)realloc(sPreloadedImages,
1978ca618b22SIngo Weinhold 		sizeof(image_t*) * (sPreloadedImageCount + 1));
1979ca618b22SIngo Weinhold 	if (newArray == NULL)
1980ca618b22SIngo Weinhold 		return B_NO_MEMORY;
1981ca618b22SIngo Weinhold 
1982ca618b22SIngo Weinhold 	sPreloadedImages = newArray;
1983ca618b22SIngo Weinhold 	newArray[sPreloadedImageCount++] = image;
1984ca618b22SIngo Weinhold 
1985ca618b22SIngo Weinhold 	return B_OK;
1986ca618b22SIngo Weinhold }
1987ca618b22SIngo Weinhold 
1988ca618b22SIngo Weinhold 
1989ca618b22SIngo Weinhold image_id
1990ca618b22SIngo Weinhold preload_image(char const* path)
1991ca618b22SIngo Weinhold {
1992ca618b22SIngo Weinhold 	if (path == NULL)
1993ca618b22SIngo Weinhold 		return B_BAD_VALUE;
1994ca618b22SIngo Weinhold 
1995ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\")", path);
1996ca618b22SIngo Weinhold 
1997ca618b22SIngo Weinhold 	image_t *image = NULL;
1998ca618b22SIngo Weinhold 	status_t status = load_container(path, B_ADD_ON_IMAGE, NULL, &image);
1999ca618b22SIngo Weinhold 	if (status < B_OK) {
2000ca618b22SIngo Weinhold 		rld_unlock();
2001ca618b22SIngo Weinhold 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
2002ca618b22SIngo Weinhold 			strerror(status));
2003ca618b22SIngo Weinhold 		return status;
2004ca618b22SIngo Weinhold 	}
2005ca618b22SIngo Weinhold 
2006ca618b22SIngo Weinhold 	for (image_t* otherImage = sLoadedImages.head; otherImage != NULL;
2007ca618b22SIngo Weinhold 			otherImage = otherImage->next) {
2008ca618b22SIngo Weinhold 		status = load_dependencies(otherImage);
2009ca618b22SIngo Weinhold 		if (status < B_OK)
2010ca618b22SIngo Weinhold 			goto err;
2011ca618b22SIngo Weinhold 	}
2012ca618b22SIngo Weinhold 
2013ca618b22SIngo Weinhold 	status = relocate_dependencies(image);
2014ca618b22SIngo Weinhold 	if (status < B_OK)
2015ca618b22SIngo Weinhold 		goto err;
2016ca618b22SIngo Weinhold 
2017ca618b22SIngo Weinhold 	status = add_preloaded_image(image);
2018ca618b22SIngo Weinhold 	if (status < B_OK)
2019ca618b22SIngo Weinhold 		goto err;
2020ca618b22SIngo Weinhold 
2021ca618b22SIngo Weinhold 	inject_runtime_loader_api(image);
2022ca618b22SIngo Weinhold 
2023ca618b22SIngo Weinhold 	remap_images();
2024ca618b22SIngo Weinhold 	init_dependencies(image, true);
2025ca618b22SIngo Weinhold 
2026*10b4b5d1SIngo Weinhold 	// if the image contains an add-on, register it
2027*10b4b5d1SIngo Weinhold 	runtime_loader_add_on* addOnStruct;
2028*10b4b5d1SIngo Weinhold 	if (find_symbol(image, "__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA,
2029*10b4b5d1SIngo Weinhold 			(void**)&addOnStruct) == B_OK) {
2030*10b4b5d1SIngo Weinhold 		RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image,
2031*10b4b5d1SIngo Weinhold 			addOnStruct);
2032*10b4b5d1SIngo Weinhold 		if (addOn != NULL) {
2033*10b4b5d1SIngo Weinhold 			sAddOns.Add(addOn);
2034*10b4b5d1SIngo Weinhold 			addOnStruct->init(&gRuntimeLoader, &gRuntimeLoaderAddOnExport);
2035*10b4b5d1SIngo Weinhold 		}
2036*10b4b5d1SIngo Weinhold 	}
2037*10b4b5d1SIngo Weinhold 
2038ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id);
2039ca618b22SIngo Weinhold 
2040ca618b22SIngo Weinhold 	return image->id;
2041ca618b22SIngo Weinhold 
2042ca618b22SIngo Weinhold err:
2043ca618b22SIngo Weinhold 	KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status));
2044ca618b22SIngo Weinhold 
2045ca618b22SIngo Weinhold 	dequeue_image(&sLoadedImages, image);
2046ca618b22SIngo Weinhold 	sLoadedImageCount--;
2047ca618b22SIngo Weinhold 	delete_image(image);
2048ca618b22SIngo Weinhold 	return status;
2049ca618b22SIngo Weinhold }
2050ca618b22SIngo Weinhold 
2051ca618b22SIngo Weinhold 
2052ca618b22SIngo Weinhold static void
2053ca618b22SIngo Weinhold preload_images()
2054ca618b22SIngo Weinhold {
2055ca618b22SIngo Weinhold 	const char* imagePaths = getenv("LD_PRELOAD");
2056ca618b22SIngo Weinhold 	if (imagePaths == NULL)
2057ca618b22SIngo Weinhold 		return;
2058ca618b22SIngo Weinhold 
2059ca618b22SIngo Weinhold 	while (*imagePaths != '\0') {
2060ca618b22SIngo Weinhold 		// find begin of image path
2061ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && isspace(*imagePaths))
2062ca618b22SIngo Weinhold 			imagePaths++;
2063ca618b22SIngo Weinhold 
2064ca618b22SIngo Weinhold 		if (*imagePaths == '\0')
2065ca618b22SIngo Weinhold 			break;
2066ca618b22SIngo Weinhold 
2067ca618b22SIngo Weinhold 		// find end of image path
2068ca618b22SIngo Weinhold 		const char* imagePath = imagePaths;
2069ca618b22SIngo Weinhold 		while (*imagePaths != '\0' && !isspace(*imagePaths))
2070ca618b22SIngo Weinhold 			imagePaths++;
2071ca618b22SIngo Weinhold 
2072ca618b22SIngo Weinhold 		// extract the path
2073ca618b22SIngo Weinhold 		char path[B_PATH_NAME_LENGTH];
2074ca618b22SIngo Weinhold 		size_t pathLen = imagePaths - imagePath;
2075ca618b22SIngo Weinhold 		if (pathLen > sizeof(path) - 1)
2076ca618b22SIngo Weinhold 			continue;
2077ca618b22SIngo Weinhold 		memcpy(path, imagePath, pathLen);
2078ca618b22SIngo Weinhold 		path[pathLen] = '\0';
2079ca618b22SIngo Weinhold 
2080ca618b22SIngo Weinhold 		// load the image
2081ca618b22SIngo Weinhold 		preload_image(path);
2082ca618b22SIngo Weinhold 	}
2083ca618b22SIngo Weinhold }
2084ca618b22SIngo Weinhold 
2085ca618b22SIngo Weinhold 
208674c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
20870c0fea5dSIngo Weinhold 
20880c0fea5dSIngo Weinhold 
20890c0fea5dSIngo Weinhold image_id
20900c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
20910c0fea5dSIngo Weinhold {
20920c0fea5dSIngo Weinhold 	status_t status;
20930c0fea5dSIngo Weinhold 	image_t *image;
20940c0fea5dSIngo Weinhold 
20957486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
20967486b72dSIngo Weinhold 
20970c0fea5dSIngo Weinhold 	rld_lock();
20980c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
20990c0fea5dSIngo Weinhold 
2100ca618b22SIngo Weinhold 	preload_images();
2101ca618b22SIngo Weinhold 
21020c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
21030c0fea5dSIngo Weinhold 
21040c0fea5dSIngo Weinhold 	status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage);
210574c0424aSAxel Dörfler 	if (status < B_OK)
210674c0424aSAxel Dörfler 		goto err;
21070c0fea5dSIngo Weinhold 
21080c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
21090c0fea5dSIngo Weinhold 		status = load_dependencies(image);
21100c0fea5dSIngo Weinhold 		if (status < B_OK)
21110c0fea5dSIngo Weinhold 			goto err;
21120c0fea5dSIngo Weinhold 	}
21130c0fea5dSIngo Weinhold 
21140c0fea5dSIngo Weinhold 	status = relocate_dependencies(sProgramImage);
21150c0fea5dSIngo Weinhold 	if (status < B_OK)
21160c0fea5dSIngo Weinhold 		goto err;
21170c0fea5dSIngo Weinhold 
2118ca618b22SIngo Weinhold 	inject_runtime_loader_api(sProgramImage);
21190c0fea5dSIngo Weinhold 
21200c0fea5dSIngo Weinhold 	remap_images();
2121ca618b22SIngo Weinhold 	init_dependencies(sProgramImage, true);
21220c0fea5dSIngo Weinhold 
21230c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
21240c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
21250c0fea5dSIngo Weinhold 	{
2126ca618b22SIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_root_image_list(sProgramImage,
2127ca618b22SIngo Weinhold 			"getenv", &image);
2128ca618b22SIngo Weinhold 
21290c0fea5dSIngo Weinhold 		if (symbol != NULL)
21300c0fea5dSIngo Weinhold 			gGetEnv = (char* (*)(const char*))
21310c0fea5dSIngo Weinhold 				(symbol->st_value + image->regions[0].delta);
21320c0fea5dSIngo Weinhold 	}
21330c0fea5dSIngo Weinhold 
2134dd76bc97SIngo Weinhold 	if (sProgramImage->entry_point == 0) {
21350c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
21360c0fea5dSIngo Weinhold 		goto err;
21370c0fea5dSIngo Weinhold 	}
21380c0fea5dSIngo Weinhold 
21390c0fea5dSIngo Weinhold 	*_entry = (void *)(sProgramImage->entry_point);
21400c0fea5dSIngo Weinhold 
21410c0fea5dSIngo Weinhold 	rld_unlock();
21427486b72dSIngo Weinhold 
21435d0638bfSIngo Weinhold 	sProgramLoaded = true;
21445d0638bfSIngo Weinhold 
21457486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
21467486b72dSIngo Weinhold 		*_entry, sProgramImage->id);
21477486b72dSIngo Weinhold 
21480c0fea5dSIngo Weinhold 	return sProgramImage->id;
21490c0fea5dSIngo Weinhold 
21500c0fea5dSIngo Weinhold err:
21517486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
21527486b72dSIngo Weinhold 
21530c0fea5dSIngo Weinhold 	delete_image(sProgramImage);
215474c0424aSAxel Dörfler 
21554bef3723SAxel Dörfler 	if (report_errors()) {
21564bef3723SAxel Dörfler 		// send error message
215774c0424aSAxel Dörfler 		sErrorMessage.AddInt32("error", status);
21584bef3723SAxel Dörfler 		sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
21594bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
21604bef3723SAxel Dörfler 
21614bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
21624bef3723SAxel Dörfler 			sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0);
216374c0424aSAxel Dörfler 	}
216474c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
21650c0fea5dSIngo Weinhold 	rld_unlock();
216674c0424aSAxel Dörfler 
21670c0fea5dSIngo Weinhold 	return status;
21680c0fea5dSIngo Weinhold }
21690c0fea5dSIngo Weinhold 
21700c0fea5dSIngo Weinhold 
21710c0fea5dSIngo Weinhold image_id
21720c0fea5dSIngo Weinhold load_library(char const *path, uint32 flags, bool addOn)
21730c0fea5dSIngo Weinhold {
21740c0fea5dSIngo Weinhold 	image_t *image = NULL;
21750c0fea5dSIngo Weinhold 	image_t *iter;
21760c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
21770c0fea5dSIngo Weinhold 	status_t status;
21780c0fea5dSIngo Weinhold 
21790c0fea5dSIngo Weinhold 	if (path == NULL)
21800c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
21810c0fea5dSIngo Weinhold 
21820c0fea5dSIngo Weinhold 	// ToDo: implement flags
21830c0fea5dSIngo Weinhold 	(void)flags;
21840c0fea5dSIngo Weinhold 
21857486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
21867486b72dSIngo Weinhold 
21870c0fea5dSIngo Weinhold 	rld_lock();
21880c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
21890c0fea5dSIngo Weinhold 
21900c0fea5dSIngo Weinhold 	// have we already loaded this library?
21910c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
21920c0fea5dSIngo Weinhold 	if (!addOn) {
21930c0fea5dSIngo Weinhold 		image = find_image(path, APP_OR_LIBRARY_TYPE);
21940c0fea5dSIngo Weinhold 		if (image) {
21950c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
21960c0fea5dSIngo Weinhold 			rld_unlock();
21977486b72dSIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
21987486b72dSIngo Weinhold 				image->id);
21990c0fea5dSIngo Weinhold 			return image->id;
22000c0fea5dSIngo Weinhold 		}
22010c0fea5dSIngo Weinhold 	}
22020c0fea5dSIngo Weinhold 
22030c0fea5dSIngo Weinhold 	status = load_container(path, type, NULL, &image);
22040c0fea5dSIngo Weinhold 	if (status < B_OK) {
22050c0fea5dSIngo Weinhold 		rld_unlock();
22067486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
22077486b72dSIngo Weinhold 			strerror(status));
22080c0fea5dSIngo Weinhold 		return status;
22090c0fea5dSIngo Weinhold 	}
22100c0fea5dSIngo Weinhold 
22110c0fea5dSIngo Weinhold 	for (iter = sLoadedImages.head; iter; iter = iter->next) {
22120c0fea5dSIngo Weinhold 		status = load_dependencies(iter);
22130c0fea5dSIngo Weinhold 		if (status < B_OK)
22140c0fea5dSIngo Weinhold 			goto err;
22150c0fea5dSIngo Weinhold 	}
22160c0fea5dSIngo Weinhold 
22170c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
22180c0fea5dSIngo Weinhold 	if (status < B_OK)
22190c0fea5dSIngo Weinhold 		goto err;
22200c0fea5dSIngo Weinhold 
22210c0fea5dSIngo Weinhold 	remap_images();
22220c0fea5dSIngo Weinhold 	init_dependencies(image, true);
22230c0fea5dSIngo Weinhold 
22240c0fea5dSIngo Weinhold 	rld_unlock();
22257486b72dSIngo Weinhold 
22267486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
22277486b72dSIngo Weinhold 
22280c0fea5dSIngo Weinhold 	return image->id;
22290c0fea5dSIngo Weinhold 
22300c0fea5dSIngo Weinhold err:
22317486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
22327486b72dSIngo Weinhold 
22330c0fea5dSIngo Weinhold 	dequeue_image(&sLoadedImages, image);
22340c0fea5dSIngo Weinhold 	sLoadedImageCount--;
22350c0fea5dSIngo Weinhold 	delete_image(image);
22360c0fea5dSIngo Weinhold 	rld_unlock();
22370c0fea5dSIngo Weinhold 	return status;
22380c0fea5dSIngo Weinhold }
22390c0fea5dSIngo Weinhold 
22400c0fea5dSIngo Weinhold 
22410c0fea5dSIngo Weinhold status_t
22420c0fea5dSIngo Weinhold unload_library(image_id imageID, bool addOn)
22430c0fea5dSIngo Weinhold {
22440c0fea5dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
22450c0fea5dSIngo Weinhold 	image_t *image;
22460c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
22470c0fea5dSIngo Weinhold 
22480c0fea5dSIngo Weinhold 	if (imageID < B_OK)
22490c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
22500c0fea5dSIngo Weinhold 
22510c0fea5dSIngo Weinhold 	rld_lock();
22520c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
22530c0fea5dSIngo Weinhold 
22549a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
22559a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
22569a6072a3SAxel Dörfler 		update_image_ids();
22579a6072a3SAxel Dörfler 	}
22589a6072a3SAxel Dörfler 
22590c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
22600c0fea5dSIngo Weinhold 
22610c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
22620c0fea5dSIngo Weinhold 		if (image->id == imageID) {
22630c0fea5dSIngo Weinhold 			// unload image
22640c0fea5dSIngo Weinhold 			if (type == image->type) {
22650c0fea5dSIngo Weinhold 				put_image(image);
22660c0fea5dSIngo Weinhold 				status = B_OK;
22670c0fea5dSIngo Weinhold 			} else
22680c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
22690c0fea5dSIngo Weinhold 			break;
22700c0fea5dSIngo Weinhold 		}
22710c0fea5dSIngo Weinhold 	}
22720c0fea5dSIngo Weinhold 
22730c0fea5dSIngo Weinhold 	if (status == B_OK) {
22740c0fea5dSIngo Weinhold 		while ((image = sDisposableImages.head) != NULL) {
22750c0fea5dSIngo Weinhold 			// call image fini here...
22768c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
22778c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
22783be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
22798c2a9d74SMichael Lotz 			}
22808c2a9d74SMichael Lotz 
2281*10b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
2282*10b4b5d1SIngo Weinhold 
22830c0fea5dSIngo Weinhold 			if (image->term_routine)
22840c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
22850c0fea5dSIngo Weinhold 
22860c0fea5dSIngo Weinhold 			dequeue_image(&sDisposableImages, image);
22870c0fea5dSIngo Weinhold 			unmap_image(image);
22880c0fea5dSIngo Weinhold 
2289*10b4b5d1SIngo Weinhold 			image_event(image, IMAGE_EVENT_UNLOADING);
2290*10b4b5d1SIngo Weinhold 
22910c0fea5dSIngo Weinhold 			delete_image(image);
22920c0fea5dSIngo Weinhold 		}
22930c0fea5dSIngo Weinhold 	}
22940c0fea5dSIngo Weinhold 
22950c0fea5dSIngo Weinhold 	rld_unlock();
22960c0fea5dSIngo Weinhold 	return status;
22970c0fea5dSIngo Weinhold }
22980c0fea5dSIngo Weinhold 
22990c0fea5dSIngo Weinhold 
23000c0fea5dSIngo Weinhold status_t
23019a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
23029a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
23030c0fea5dSIngo Weinhold {
23040c0fea5dSIngo Weinhold 	int32 count = 0, j;
23050c0fea5dSIngo Weinhold 	uint32 i;
23060c0fea5dSIngo Weinhold 	image_t *image;
23070c0fea5dSIngo Weinhold 
23080c0fea5dSIngo Weinhold 	rld_lock();
23090c0fea5dSIngo Weinhold 
23100c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
23110c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
23120c0fea5dSIngo Weinhold 	if (image == NULL) {
23130c0fea5dSIngo Weinhold 		rld_unlock();
23140c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
23150c0fea5dSIngo Weinhold 	}
23160c0fea5dSIngo Weinhold 
23170c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
23180c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
23190c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
23200555803aSAxel Dörfler 			struct Elf32_Sym *symbol = &image->syms[j];
23210c0fea5dSIngo Weinhold 
23220c0fea5dSIngo Weinhold 			if (count == num) {
2323*10b4b5d1SIngo Weinhold 				const char* symbolName = SYMNAME(image, symbol);
2324*10b4b5d1SIngo Weinhold 				strlcpy(nameBuffer, symbolName, *_nameLength);
2325*10b4b5d1SIngo Weinhold 				*_nameLength = strlen(symbolName);
23260c0fea5dSIngo Weinhold 
2327*10b4b5d1SIngo Weinhold 				void* location = (void*)(symbol->st_value
2328*10b4b5d1SIngo Weinhold 					+ image->regions[0].delta);
2329*10b4b5d1SIngo Weinhold 				int32 type;
23300c0fea5dSIngo Weinhold 				if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
2331*10b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_TEXT;
23320c0fea5dSIngo Weinhold 				else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
2333*10b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_DATA;
23340c0fea5dSIngo Weinhold 				else
2335*10b4b5d1SIngo Weinhold 					type = B_SYMBOL_TYPE_ANY;
2336*10b4b5d1SIngo Weinhold 					// TODO: check with the return types of that BeOS function
23370c0fea5dSIngo Weinhold 
2338*10b4b5d1SIngo Weinhold 				patch_defined_symbol(image, symbolName, &location, &type);
2339*10b4b5d1SIngo Weinhold 
2340*10b4b5d1SIngo Weinhold 				if (_type != NULL)
2341*10b4b5d1SIngo Weinhold 					*_type = type;
23420c0fea5dSIngo Weinhold 				if (_location != NULL)
2343*10b4b5d1SIngo Weinhold 					*_location = location;
23440c0fea5dSIngo Weinhold 				goto out;
23450c0fea5dSIngo Weinhold 			}
23460c0fea5dSIngo Weinhold 			count++;
23470c0fea5dSIngo Weinhold 		}
23480c0fea5dSIngo Weinhold 	}
23490c0fea5dSIngo Weinhold out:
23500c0fea5dSIngo Weinhold 	rld_unlock();
23510c0fea5dSIngo Weinhold 
23520c0fea5dSIngo Weinhold 	if (num != count)
23530c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
23540c0fea5dSIngo Weinhold 
23550c0fea5dSIngo Weinhold 	return B_OK;
23560c0fea5dSIngo Weinhold }
23570c0fea5dSIngo Weinhold 
23580c0fea5dSIngo Weinhold 
23590c0fea5dSIngo Weinhold status_t
23609a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
23619a6072a3SAxel Dörfler 	void **_location)
23620c0fea5dSIngo Weinhold {
23630c0fea5dSIngo Weinhold 	status_t status = B_OK;
23640c0fea5dSIngo Weinhold 	image_t *image;
23650c0fea5dSIngo Weinhold 
23660c0fea5dSIngo Weinhold 	if (imageID < B_OK)
23670c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
23680c0fea5dSIngo Weinhold 	if (symbolName == NULL)
23690c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
23700c0fea5dSIngo Weinhold 
23710c0fea5dSIngo Weinhold 	rld_lock();
23720c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
23730c0fea5dSIngo Weinhold 
23740c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
23750c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
2376*10b4b5d1SIngo Weinhold 	if (image != NULL)
2377*10b4b5d1SIngo Weinhold 		status = find_symbol(image, symbolName, symbolType, _location);
2378*10b4b5d1SIngo Weinhold 	else
23790c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
23800c0fea5dSIngo Weinhold 
23810c0fea5dSIngo Weinhold 	rld_unlock();
23820c0fea5dSIngo Weinhold 	return status;
23830c0fea5dSIngo Weinhold }
23840c0fea5dSIngo Weinhold 
23850c0fea5dSIngo Weinhold 
23860c0fea5dSIngo Weinhold status_t
23870c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
23880c0fea5dSIngo Weinhold {
23890c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
23900c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
23910c0fea5dSIngo Weinhold 	image_t *image;
23920c0fea5dSIngo Weinhold 
23930c0fea5dSIngo Weinhold 	if (_name == NULL)
23940c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
23950c0fea5dSIngo Weinhold 
23960c0fea5dSIngo Weinhold 	rld_lock();
23970c0fea5dSIngo Weinhold 
23980c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(id);
23990c0fea5dSIngo Weinhold 	if (image == NULL) {
24000c0fea5dSIngo Weinhold 		rld_unlock();
24010c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
24020c0fea5dSIngo Weinhold 	}
24030c0fea5dSIngo Weinhold 
24040c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
24050c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
24060c0fea5dSIngo Weinhold 		rld_unlock();
24070c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
24080c0fea5dSIngo Weinhold 	}
24090c0fea5dSIngo Weinhold 
24100c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
24110c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
24120c0fea5dSIngo Weinhold 			continue;
24130c0fea5dSIngo Weinhold 
24140c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
24150c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
24160c0fea5dSIngo Weinhold 
24170c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
24180c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
24190c0fea5dSIngo Weinhold 			rld_unlock();
24200c0fea5dSIngo Weinhold 			return B_OK;
24210c0fea5dSIngo Weinhold 		}
24220c0fea5dSIngo Weinhold 	}
24230c0fea5dSIngo Weinhold 
24240c0fea5dSIngo Weinhold 	rld_unlock();
24250c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
24260c0fea5dSIngo Weinhold }
24270c0fea5dSIngo Weinhold 
24280c0fea5dSIngo Weinhold 
242974c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
24300c0fea5dSIngo Weinhold 
24310c0fea5dSIngo Weinhold 
24329a6072a3SAxel Dörfler /*! Read and verify the ELF header */
24330c0fea5dSIngo Weinhold status_t
24340c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
24350c0fea5dSIngo Weinhold {
24360c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
24370c0fea5dSIngo Weinhold 
24380c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
24390c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
24400c0fea5dSIngo Weinhold 
24419a6072a3SAxel Dörfler 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize,
24429a6072a3SAxel Dörfler 		&sectionSize);
24430c0fea5dSIngo Weinhold }
24440c0fea5dSIngo Weinhold 
24450c0fea5dSIngo Weinhold 
24460c0fea5dSIngo Weinhold void
24470c0fea5dSIngo Weinhold terminate_program(void)
24480c0fea5dSIngo Weinhold {
24490c0fea5dSIngo Weinhold 	image_t **termList;
24500c0fea5dSIngo Weinhold 	ssize_t count, i;
24510c0fea5dSIngo Weinhold 
24520c0fea5dSIngo Weinhold 	count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED);
24530c0fea5dSIngo Weinhold 	if (count < B_OK)
24540c0fea5dSIngo Weinhold 		return;
24550c0fea5dSIngo Weinhold 
24569a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
24579a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
24589a6072a3SAxel Dörfler 		update_image_ids();
24599a6072a3SAxel Dörfler 	}
24609a6072a3SAxel Dörfler 
24610c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
24620c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
24630c0fea5dSIngo Weinhold 		image_t *image = termList[i];
24640c0fea5dSIngo Weinhold 
24650c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
24660c0fea5dSIngo Weinhold 
2467*10b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
2468*10b4b5d1SIngo Weinhold 
24690c0fea5dSIngo Weinhold 		if (image->term_routine)
24700c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
2471*10b4b5d1SIngo Weinhold 
2472*10b4b5d1SIngo Weinhold 		image_event(image, IMAGE_EVENT_UNLOADING);
24730c0fea5dSIngo Weinhold 	}
24740c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
24750c0fea5dSIngo Weinhold 
24760c0fea5dSIngo Weinhold 	free(termList);
24770c0fea5dSIngo Weinhold }
24780c0fea5dSIngo Weinhold 
24790c0fea5dSIngo Weinhold 
24800c0fea5dSIngo Weinhold void
24810c0fea5dSIngo Weinhold rldelf_init(void)
24820c0fea5dSIngo Weinhold {
2483*10b4b5d1SIngo Weinhold 	// invoke static constructors
2484*10b4b5d1SIngo Weinhold 	new(&sAddOns) AddOnList;
2485*10b4b5d1SIngo Weinhold 
2486e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
2487e73923b0SAxel Dörfler 	sSemOwner = -1;
2488e73923b0SAxel Dörfler 	sSemCount = 0;
24890c0fea5dSIngo Weinhold 
24900c0fea5dSIngo Weinhold 	// create the debug area
24910c0fea5dSIngo Weinhold 	{
24920c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
24930c0fea5dSIngo Weinhold 
24940c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
24950c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
24960c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
24970c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
24980c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
24990c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
25000c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
25010c0fea5dSIngo Weinhold 		}
25020c0fea5dSIngo Weinhold 
25030c0fea5dSIngo Weinhold 		area->loaded_images = &sLoadedImages;
25040c0fea5dSIngo Weinhold 	}
250574c0424aSAxel Dörfler 
250674c0424aSAxel Dörfler 	// initialize error message if needed
25074bef3723SAxel Dörfler 	if (report_errors()) {
250874c0424aSAxel Dörfler 		void *buffer = malloc(1024);
250974c0424aSAxel Dörfler 		if (buffer == NULL)
251074c0424aSAxel Dörfler 			return;
251174c0424aSAxel Dörfler 
251274c0424aSAxel Dörfler 		sErrorMessage.SetTo(buffer, 1024, 'Rler');
251374c0424aSAxel Dörfler 	}
25140c0fea5dSIngo Weinhold }
25151873b4b3SIngo Weinhold 
25161873b4b3SIngo Weinhold 
25171873b4b3SIngo Weinhold status_t
25189a6072a3SAxel Dörfler elf_reinit_after_fork(void)
25191873b4b3SIngo Weinhold {
2520e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
2521e73923b0SAxel Dörfler 	if (sSem < 0)
2522e73923b0SAxel Dörfler 		return sSem;
25231873b4b3SIngo Weinhold 
25249a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
2525cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
2526cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
25279a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
25289a6072a3SAxel Dörfler 	sInvalidImageIDs = true;
2529cbc456deSIngo Weinhold 
25301873b4b3SIngo Weinhold 	return B_OK;
25311873b4b3SIngo Weinhold }
2532