xref: /haiku/src/system/runtime_loader/elf.cpp (revision 2716cfd3d79e5e71870527afc66de278430cc8d9)
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 
120c0fea5dSIngo Weinhold #include "runtime_loader_private.h"
130c0fea5dSIngo Weinhold 
140c0fea5dSIngo Weinhold #include <OS.h>
150c0fea5dSIngo Weinhold 
160c0fea5dSIngo Weinhold #include <string.h>
170c0fea5dSIngo Weinhold #include <stdio.h>
180c0fea5dSIngo Weinhold #include <stdlib.h>
1934982809SIngo Weinhold #include <string.h>
200c0fea5dSIngo Weinhold 
217486b72dSIngo Weinhold #include <elf32.h>
227486b72dSIngo Weinhold #include <runtime_loader.h>
237486b72dSIngo Weinhold #include <syscalls.h>
247486b72dSIngo Weinhold #include <user_runtime.h>
256b202f4eSIngo Weinhold #include <util/KMessage.h>
266b202f4eSIngo Weinhold #include <vm_defs.h>
277486b72dSIngo Weinhold 
28071f9c3aSIngo Weinhold #include "tracing_config.h"
29071f9c3aSIngo Weinhold 
300c0fea5dSIngo Weinhold 
310c0fea5dSIngo Weinhold //#define TRACE_RLD
320c0fea5dSIngo Weinhold #ifdef TRACE_RLD
330c0fea5dSIngo Weinhold #	define TRACE(x) dprintf x
340c0fea5dSIngo Weinhold #else
350c0fea5dSIngo Weinhold #	define TRACE(x) ;
360c0fea5dSIngo Weinhold #endif
370c0fea5dSIngo Weinhold 
380c0fea5dSIngo Weinhold 
390c0fea5dSIngo Weinhold // ToDo: implement better locking strategy
400c0fea5dSIngo Weinhold // ToDo: implement lazy binding
410c0fea5dSIngo Weinhold 
420c0fea5dSIngo Weinhold #define	PAGE_MASK (B_PAGE_SIZE - 1)
430c0fea5dSIngo Weinhold 
440c0fea5dSIngo Weinhold #define	PAGE_OFFSET(x) ((x) & (PAGE_MASK))
450c0fea5dSIngo Weinhold #define	PAGE_BASE(x) ((x) & ~(PAGE_MASK))
460c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
470c0fea5dSIngo Weinhold 
480c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000
490c0fea5dSIngo Weinhold 	/* keep in sync with app ldscript */
500c0fea5dSIngo Weinhold 
510c0fea5dSIngo Weinhold enum {
520c0fea5dSIngo Weinhold 	RFLAG_RW					= 0x0001,
530c0fea5dSIngo Weinhold 	RFLAG_ANON					= 0x0002,
540c0fea5dSIngo Weinhold 
550c0fea5dSIngo Weinhold 	RFLAG_TERMINATED			= 0x0200,
560c0fea5dSIngo Weinhold 	RFLAG_INITIALIZED			= 0x0400,
570c0fea5dSIngo Weinhold 	RFLAG_SYMBOLIC				= 0x0800,
580c0fea5dSIngo Weinhold 	RFLAG_RELOCATED				= 0x1000,
590c0fea5dSIngo Weinhold 	RFLAG_PROTECTED				= 0x2000,
600c0fea5dSIngo Weinhold 	RFLAG_DEPENDENCIES_LOADED	= 0x4000,
6146f4d849SIngo Weinhold 	RFLAG_REMAPPED				= 0x8000,
6246f4d849SIngo Weinhold 
6346f4d849SIngo Weinhold 	RFLAG_VISITED				= 0x10000
6446f4d849SIngo Weinhold 		// temporarily set in the symbol resolution code
650c0fea5dSIngo Weinhold };
660c0fea5dSIngo Weinhold 
670c0fea5dSIngo Weinhold 
680c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type)	(1 << ((type) - 1))
690c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES				(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
700c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
710c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
720c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
730c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE			(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
740c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
750c0fea5dSIngo Weinhold 
760c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
770c0fea5dSIngo Weinhold 
780c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0};
790c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0};
800c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0;
810c0fea5dSIngo Weinhold static image_t *sProgramImage;
8274c0424aSAxel Dörfler static KMessage sErrorMessage;
835d0638bfSIngo Weinhold static bool sProgramLoaded = false;
8461b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL;
859a6072a3SAxel Dörfler static bool sInvalidImageIDs;
860c0fea5dSIngo Weinhold 
870c0fea5dSIngo Weinhold // a recursive lock
88e73923b0SAxel Dörfler static sem_id sSem;
89e73923b0SAxel Dörfler static thread_id sSemOwner;
90e73923b0SAxel Dörfler static int32 sSemCount;
910c0fea5dSIngo Weinhold 
920c0fea5dSIngo Weinhold 
930c0fea5dSIngo Weinhold void
940c0fea5dSIngo Weinhold dprintf(const char *format, ...)
950c0fea5dSIngo Weinhold {
960c0fea5dSIngo Weinhold 	char buffer[1024];
970c0fea5dSIngo Weinhold 
980c0fea5dSIngo Weinhold 	va_list list;
990c0fea5dSIngo Weinhold 	va_start(list, format);
1000c0fea5dSIngo Weinhold 
1010c0fea5dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1020c0fea5dSIngo Weinhold 	_kern_debug_output(buffer);
1030c0fea5dSIngo Weinhold 
1040c0fea5dSIngo Weinhold 	va_end(list);
1050c0fea5dSIngo Weinhold }
1065d0638bfSIngo Weinhold 
1075d0638bfSIngo Weinhold #define FATAL(x...)							\
1085d0638bfSIngo Weinhold 	do {									\
1095d0638bfSIngo Weinhold 		dprintf("runtime_loader: " x);		\
1105d0638bfSIngo Weinhold 		if (!sProgramLoaded)				\
1115d0638bfSIngo Weinhold 			printf("runtime_loader: " x);	\
1125d0638bfSIngo Weinhold 	} while (false)
1130c0fea5dSIngo Weinhold 
1140c0fea5dSIngo Weinhold 
11534982809SIngo Weinhold /*!	Mini atoi(), so we don't have to include the libroot dependencies.
11634982809SIngo Weinhold  */
11734982809SIngo Weinhold int
11834982809SIngo Weinhold atoi(const char* num)
11934982809SIngo Weinhold {
12034982809SIngo Weinhold 	int result = 0;
12134982809SIngo Weinhold 	while (*num >= '0' && *num <= '9') {
12234982809SIngo Weinhold 		result = (result * 10) + (*num - '0');
12334982809SIngo Weinhold 		num++;
12434982809SIngo Weinhold 	}
12534982809SIngo Weinhold 
12634982809SIngo Weinhold 	return result;
12734982809SIngo Weinhold }
12834982809SIngo Weinhold 
12934982809SIngo Weinhold 
1306bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING
1317486b72dSIngo Weinhold 
1327486b72dSIngo Weinhold void
1337486b72dSIngo Weinhold ktrace_printf(const char *format, ...)
1347486b72dSIngo Weinhold {
1357486b72dSIngo Weinhold 	va_list list;
1367486b72dSIngo Weinhold 	va_start(list, format);
1377486b72dSIngo Weinhold 
1387486b72dSIngo Weinhold 	char buffer[1024];
1397486b72dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1407486b72dSIngo Weinhold 	_kern_ktrace_output(buffer);
1417486b72dSIngo Weinhold 
1427486b72dSIngo Weinhold 	va_end(list);
1437486b72dSIngo Weinhold }
1447486b72dSIngo Weinhold 
1457486b72dSIngo Weinhold #define KTRACE(x...)	ktrace_printf(x)
1467486b72dSIngo Weinhold 
1477486b72dSIngo Weinhold #else
1487486b72dSIngo Weinhold #	define KTRACE(x...)
1497486b72dSIngo Weinhold #endif	// RUNTIME_LOADER_TRACING
1507486b72dSIngo Weinhold 
1517486b72dSIngo Weinhold 
1520c0fea5dSIngo Weinhold static void
1530c0fea5dSIngo Weinhold rld_unlock()
1540c0fea5dSIngo Weinhold {
155e73923b0SAxel Dörfler 	if (sSemCount-- == 1) {
156e73923b0SAxel Dörfler 		sSemOwner = -1;
157e73923b0SAxel Dörfler 		release_sem(sSem);
1580c0fea5dSIngo Weinhold 	}
1590c0fea5dSIngo Weinhold }
1600c0fea5dSIngo Weinhold 
1610c0fea5dSIngo Weinhold 
1620c0fea5dSIngo Weinhold static void
1630c0fea5dSIngo Weinhold rld_lock()
1640c0fea5dSIngo Weinhold {
1650c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
166e73923b0SAxel Dörfler 	if (self != sSemOwner) {
167e73923b0SAxel Dörfler 		acquire_sem(sSem);
168e73923b0SAxel Dörfler 		sSemOwner = self;
1690c0fea5dSIngo Weinhold 	}
170e73923b0SAxel Dörfler 	sSemCount++;
1710c0fea5dSIngo Weinhold }
1720c0fea5dSIngo Weinhold 
1730c0fea5dSIngo Weinhold 
1740c0fea5dSIngo Weinhold static void
1750c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image)
1760c0fea5dSIngo Weinhold {
1770c0fea5dSIngo Weinhold 	image->next = 0;
1780c0fea5dSIngo Weinhold 
1790c0fea5dSIngo Weinhold 	image->prev = queue->tail;
1800c0fea5dSIngo Weinhold 	if (queue->tail)
1810c0fea5dSIngo Weinhold 		queue->tail->next = image;
1820c0fea5dSIngo Weinhold 
1830c0fea5dSIngo Weinhold 	queue->tail = image;
1840c0fea5dSIngo Weinhold 	if (!queue->head)
1850c0fea5dSIngo Weinhold 		queue->head = image;
1860c0fea5dSIngo Weinhold }
1870c0fea5dSIngo Weinhold 
1880c0fea5dSIngo Weinhold 
1890c0fea5dSIngo Weinhold static void
1900c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image)
1910c0fea5dSIngo Weinhold {
1920c0fea5dSIngo Weinhold 	if (image->next)
1930c0fea5dSIngo Weinhold 		image->next->prev = image->prev;
1940c0fea5dSIngo Weinhold 	else
1950c0fea5dSIngo Weinhold 		queue->tail = image->prev;
1960c0fea5dSIngo Weinhold 
1970c0fea5dSIngo Weinhold 	if (image->prev)
1980c0fea5dSIngo Weinhold 		image->prev->next = image->next;
1990c0fea5dSIngo Weinhold 	else
2000c0fea5dSIngo Weinhold 		queue->head = image->next;
2010c0fea5dSIngo Weinhold 
2020c0fea5dSIngo Weinhold 	image->prev = 0;
2030c0fea5dSIngo Weinhold 	image->next = 0;
2040c0fea5dSIngo Weinhold }
2050c0fea5dSIngo Weinhold 
2060c0fea5dSIngo Weinhold 
2070c0fea5dSIngo Weinhold static uint32
2080c0fea5dSIngo Weinhold elf_hash(const uint8 *name)
2090c0fea5dSIngo Weinhold {
2100c0fea5dSIngo Weinhold 	uint32 hash = 0;
2110c0fea5dSIngo Weinhold 	uint32 temp;
2120c0fea5dSIngo Weinhold 
2130c0fea5dSIngo Weinhold 	while (*name) {
2140c0fea5dSIngo Weinhold 		hash = (hash << 4) + *name++;
2150c0fea5dSIngo Weinhold 		if ((temp = hash & 0xf0000000)) {
2160c0fea5dSIngo Weinhold 			hash ^= temp >> 24;
2170c0fea5dSIngo Weinhold 		}
2180c0fea5dSIngo Weinhold 		hash &= ~temp;
2190c0fea5dSIngo Weinhold 	}
2200c0fea5dSIngo Weinhold 	return hash;
2210c0fea5dSIngo Weinhold }
2220c0fea5dSIngo Weinhold 
2230c0fea5dSIngo Weinhold 
2244bef3723SAxel Dörfler static inline bool
2254bef3723SAxel Dörfler report_errors()
2264bef3723SAxel Dörfler {
2274bef3723SAxel Dörfler 	return gProgramArgs->error_port >= 0;
2284bef3723SAxel Dörfler }
2294bef3723SAxel Dörfler 
2304bef3723SAxel Dörfler 
2319a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork.
2329a6072a3SAxel Dörfler static status_t
2339a6072a3SAxel Dörfler update_image_id(image_t *image)
2349a6072a3SAxel Dörfler {
2359a6072a3SAxel Dörfler 	int32 cookie = 0;
2369a6072a3SAxel Dörfler 	image_info info;
2379a6072a3SAxel Dörfler 	while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info,
2389a6072a3SAxel Dörfler 			sizeof(image_info)) == B_OK) {
2399a6072a3SAxel Dörfler 		for (uint32 i = 0; i < image->num_regions; i++) {
2409a6072a3SAxel Dörfler 			if (image->regions[i].vmstart == (addr_t)info.text) {
2419a6072a3SAxel Dörfler 				image->id = info.id;
2429a6072a3SAxel Dörfler 				return B_OK;
2439a6072a3SAxel Dörfler 			}
2449a6072a3SAxel Dörfler 		}
2459a6072a3SAxel Dörfler 	}
2469a6072a3SAxel Dörfler 
2479a6072a3SAxel Dörfler 	FATAL("Could not update image ID %ld after fork()!\n", image->id);
2489a6072a3SAxel Dörfler 	return B_ENTRY_NOT_FOUND;
2499a6072a3SAxel Dörfler }
2509a6072a3SAxel Dörfler 
2519a6072a3SAxel Dörfler 
2529a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images.
2539a6072a3SAxel Dörfler static status_t
2549a6072a3SAxel Dörfler update_image_ids(void)
2559a6072a3SAxel Dörfler {
2569a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
2579a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
2589a6072a3SAxel Dörfler 		if (status != B_OK)
2599a6072a3SAxel Dörfler 			return status;
2609a6072a3SAxel Dörfler 	}
2619a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
2629a6072a3SAxel Dörfler 		status_t status = update_image_id(image);
2639a6072a3SAxel Dörfler 		if (status != B_OK)
2649a6072a3SAxel Dörfler 			return status;
2659a6072a3SAxel Dörfler 	}
2669a6072a3SAxel Dörfler 
2679a6072a3SAxel Dörfler 	sInvalidImageIDs = false;
2689a6072a3SAxel Dörfler 	return B_OK;
2699a6072a3SAxel Dörfler }
2709a6072a3SAxel Dörfler 
2719a6072a3SAxel Dörfler 
2720c0fea5dSIngo Weinhold static image_t *
2730c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath,
2740c0fea5dSIngo Weinhold 	uint32 typeMask)
2750c0fea5dSIngo Weinhold {
2769a6072a3SAxel Dörfler 	for (image_t *image = queue->head; image; image = image->next) {
2770c0fea5dSIngo Weinhold 		const char *imageName = isPath ? image->path : image->name;
2780c0fea5dSIngo Weinhold 		int length = isPath ? sizeof(image->path) : sizeof(image->name);
2790c0fea5dSIngo Weinhold 
2800c0fea5dSIngo Weinhold 		if (!strncmp(imageName, name, length)
2810c0fea5dSIngo Weinhold 			&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
2820c0fea5dSIngo Weinhold 			return image;
2830c0fea5dSIngo Weinhold 		}
2840c0fea5dSIngo Weinhold 	}
2850c0fea5dSIngo Weinhold 
2860c0fea5dSIngo Weinhold 	return NULL;
2870c0fea5dSIngo Weinhold }
2880c0fea5dSIngo Weinhold 
2890c0fea5dSIngo Weinhold 
2900c0fea5dSIngo Weinhold static image_t *
2910c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask)
2920c0fea5dSIngo Weinhold {
2939a6072a3SAxel Dörfler 	bool isPath = strchr(name, '/') != NULL;
29446f4d849SIngo Weinhold 	return find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
2950c0fea5dSIngo Weinhold }
2960c0fea5dSIngo Weinhold 
2970c0fea5dSIngo Weinhold 
2980c0fea5dSIngo Weinhold static image_t *
2990c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id)
3000c0fea5dSIngo Weinhold {
3019a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
3029a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
3039a6072a3SAxel Dörfler 		update_image_ids();
3049a6072a3SAxel Dörfler 	}
3050c0fea5dSIngo Weinhold 
3069a6072a3SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
3070c0fea5dSIngo Weinhold 		if (image->id == id)
3080c0fea5dSIngo Weinhold 			return image;
3090c0fea5dSIngo Weinhold 	}
3100c0fea5dSIngo Weinhold 
3110c0fea5dSIngo Weinhold 	// For the termination routine, we need to look into the list of
3120c0fea5dSIngo Weinhold 	// disposable images as well
3139a6072a3SAxel Dörfler 	for (image_t *image = sDisposableImages.head; image; image = image->next) {
3140c0fea5dSIngo Weinhold 		if (image->id == id)
3150c0fea5dSIngo Weinhold 			return image;
3160c0fea5dSIngo Weinhold 	}
3170c0fea5dSIngo Weinhold 
3180c0fea5dSIngo Weinhold 	return NULL;
3190c0fea5dSIngo Weinhold }
3200c0fea5dSIngo Weinhold 
3210c0fea5dSIngo Weinhold 
3225fd6637bSIngo Weinhold static image_t*
3235fd6637bSIngo Weinhold get_program_image()
32412a5e9a4SAxel Dörfler {
32512a5e9a4SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
32612a5e9a4SAxel Dörfler 		if (image->type == B_APP_IMAGE)
3275fd6637bSIngo Weinhold 			return image;
32812a5e9a4SAxel Dörfler 	}
32912a5e9a4SAxel Dörfler 
33012a5e9a4SAxel Dörfler 	return NULL;
33112a5e9a4SAxel Dörfler }
33212a5e9a4SAxel Dörfler 
33312a5e9a4SAxel Dörfler 
3345fd6637bSIngo Weinhold static const char *
3355fd6637bSIngo Weinhold get_program_path()
3365fd6637bSIngo Weinhold {
3375fd6637bSIngo Weinhold 	if (image_t* image = get_program_image())
3385fd6637bSIngo Weinhold 		return image->path;
3395fd6637bSIngo Weinhold 
3405fd6637bSIngo Weinhold 	return NULL;
3415fd6637bSIngo Weinhold }
3425fd6637bSIngo Weinhold 
3435fd6637bSIngo Weinhold 
3440c0fea5dSIngo Weinhold static status_t
34512a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize,
34612a5e9a4SAxel Dörfler 	int32 *_sheaderSize)
3470c0fea5dSIngo Weinhold {
3480c0fea5dSIngo Weinhold 	if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
3490c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3500c0fea5dSIngo Weinhold 
3510c0fea5dSIngo Weinhold 	if (eheader->e_ident[4] != ELFCLASS32)
3520c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3530c0fea5dSIngo Weinhold 
3540c0fea5dSIngo Weinhold 	if (eheader->e_phoff == 0)
3550c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3560c0fea5dSIngo Weinhold 
3570c0fea5dSIngo Weinhold 	if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
3580c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3590c0fea5dSIngo Weinhold 
3600c0fea5dSIngo Weinhold 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
3610c0fea5dSIngo Weinhold 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
3620c0fea5dSIngo Weinhold 
3635aa7b7b6SMarcus Overhagen 	if (*_pheaderSize <= 0 || *_sheaderSize <= 0)
3645aa7b7b6SMarcus Overhagen 		return B_NOT_AN_EXECUTABLE;
3655aa7b7b6SMarcus Overhagen 
3665aa7b7b6SMarcus Overhagen 	return B_OK;
3670c0fea5dSIngo Weinhold }
3680c0fea5dSIngo Weinhold 
3690c0fea5dSIngo Weinhold 
3700c0fea5dSIngo Weinhold static int32
3710c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize)
3720c0fea5dSIngo Weinhold {
3730c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheaders;
3740c0fea5dSIngo Weinhold 	int32 count = 0;
3750c0fea5dSIngo Weinhold 	int i;
3760c0fea5dSIngo Weinhold 
3770c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
3780c0fea5dSIngo Weinhold 		pheaders = (struct Elf32_Phdr *)(buff + i * phentsize);
3790c0fea5dSIngo Weinhold 
3800c0fea5dSIngo Weinhold 		switch (pheaders->p_type) {
3810c0fea5dSIngo Weinhold 			case PT_NULL:
3820c0fea5dSIngo Weinhold 				/* NOP header */
3830c0fea5dSIngo Weinhold 				break;
3840c0fea5dSIngo Weinhold 			case PT_LOAD:
3850c0fea5dSIngo Weinhold 				count += 1;
3860c0fea5dSIngo Weinhold 				if (pheaders->p_memsz != pheaders->p_filesz) {
3870c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz);
3880c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz);
3890c0fea5dSIngo Weinhold 
3900c0fea5dSIngo Weinhold 					if (A != B)
3910c0fea5dSIngo Weinhold 						count += 1;
3920c0fea5dSIngo Weinhold 				}
3930c0fea5dSIngo Weinhold 				break;
3940c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
3950c0fea5dSIngo Weinhold 				/* will be handled at some other place */
3960c0fea5dSIngo Weinhold 				break;
3970c0fea5dSIngo Weinhold 			case PT_INTERP:
3980c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
3990c0fea5dSIngo Weinhold 				break;
4000c0fea5dSIngo Weinhold 			case PT_NOTE:
4010c0fea5dSIngo Weinhold 				/* unsupported */
4020c0fea5dSIngo Weinhold 				break;
4030c0fea5dSIngo Weinhold 			case PT_SHLIB:
4040c0fea5dSIngo Weinhold 				/* undefined semantics */
4050c0fea5dSIngo Weinhold 				break;
4060c0fea5dSIngo Weinhold 			case PT_PHDR:
4070c0fea5dSIngo Weinhold 				/* we don't use it */
4080c0fea5dSIngo Weinhold 				break;
4090c0fea5dSIngo Weinhold 			default:
4100c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type);
4110c0fea5dSIngo Weinhold 				return B_BAD_DATA;
4120c0fea5dSIngo Weinhold 		}
4130c0fea5dSIngo Weinhold 	}
4140c0fea5dSIngo Weinhold 
4150c0fea5dSIngo Weinhold 	return count;
4160c0fea5dSIngo Weinhold }
4170c0fea5dSIngo Weinhold 
4180c0fea5dSIngo Weinhold 
4190c0fea5dSIngo Weinhold static image_t *
4200c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions)
4210c0fea5dSIngo Weinhold {
4220c0fea5dSIngo Weinhold 	size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t);
4230c0fea5dSIngo Weinhold 	const char *lastSlash;
4240c0fea5dSIngo Weinhold 
4250c0fea5dSIngo Weinhold 	image_t *image = (image_t*)malloc(allocSize);
4260c0fea5dSIngo Weinhold 	if (image == NULL) {
4270c0fea5dSIngo Weinhold 		FATAL("no memory for image %s\n", path);
4280c0fea5dSIngo Weinhold 		return NULL;
4290c0fea5dSIngo Weinhold 	}
4300c0fea5dSIngo Weinhold 
4310c0fea5dSIngo Weinhold 	memset(image, 0, allocSize);
4320c0fea5dSIngo Weinhold 
4330c0fea5dSIngo Weinhold 	strlcpy(image->path, path, sizeof(image->path));
4340c0fea5dSIngo Weinhold 
4350c0fea5dSIngo Weinhold 	// Make the last component of the supplied name the image name.
4360c0fea5dSIngo Weinhold 	// If present, DT_SONAME will replace this name.
4370c0fea5dSIngo Weinhold 	if ((lastSlash = strrchr(name, '/')))
4380c0fea5dSIngo Weinhold 		strlcpy(image->name, lastSlash + 1, sizeof(image->name));
4390c0fea5dSIngo Weinhold 	else
4400c0fea5dSIngo Weinhold 		strlcpy(image->name, name, sizeof(image->name));
4410c0fea5dSIngo Weinhold 
4420c0fea5dSIngo Weinhold 	image->ref_count = 1;
4430c0fea5dSIngo Weinhold 	image->num_regions = num_regions;
4440c0fea5dSIngo Weinhold 
4450c0fea5dSIngo Weinhold 	return image;
4460c0fea5dSIngo Weinhold }
4470c0fea5dSIngo Weinhold 
4480c0fea5dSIngo Weinhold 
4490c0fea5dSIngo Weinhold static void
4500c0fea5dSIngo Weinhold delete_image_struct(image_t *image)
4510c0fea5dSIngo Weinhold {
4520c0fea5dSIngo Weinhold #ifdef DEBUG
4530c0fea5dSIngo Weinhold 	size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t);
4540c0fea5dSIngo Weinhold 	memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
4550c0fea5dSIngo Weinhold #endif
4560c0fea5dSIngo Weinhold 	free(image->needed);
4570c0fea5dSIngo Weinhold 
4580c0fea5dSIngo Weinhold #ifdef DEBUG
4599a6072a3SAxel Dörfler 	// overwrite images to make sure they aren't accidently reused anywhere
4600c0fea5dSIngo Weinhold 	memset(image, 0xa5, size);
4610c0fea5dSIngo Weinhold #endif
4620c0fea5dSIngo Weinhold 	free(image);
4630c0fea5dSIngo Weinhold }
4640c0fea5dSIngo Weinhold 
4650c0fea5dSIngo Weinhold 
4660c0fea5dSIngo Weinhold static void
4670c0fea5dSIngo Weinhold delete_image(image_t *image)
4680c0fea5dSIngo Weinhold {
4692760c4cdSAxel Dörfler 	if (image == NULL)
4702760c4cdSAxel Dörfler 		return;
4712760c4cdSAxel Dörfler 
4720c0fea5dSIngo Weinhold 	_kern_unregister_image(image->id);
4730c0fea5dSIngo Weinhold 		// registered in load_container()
4740c0fea5dSIngo Weinhold 
4750c0fea5dSIngo Weinhold 	delete_image_struct(image);
4760c0fea5dSIngo Weinhold }
4770c0fea5dSIngo Weinhold 
4780c0fea5dSIngo Weinhold 
4790c0fea5dSIngo Weinhold static status_t
4800c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
4810c0fea5dSIngo Weinhold {
4820c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheader;
4830c0fea5dSIngo Weinhold 	int regcount;
4840c0fea5dSIngo Weinhold 	int i;
4850c0fea5dSIngo Weinhold 
4860c0fea5dSIngo Weinhold 	regcount = 0;
4870c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
4880c0fea5dSIngo Weinhold 		pheader = (struct Elf32_Phdr *)(buff + i * phentsize);
4890c0fea5dSIngo Weinhold 
4900c0fea5dSIngo Weinhold 		switch (pheader->p_type) {
4910c0fea5dSIngo Weinhold 			case PT_NULL:
4920c0fea5dSIngo Weinhold 				/* NOP header */
4930c0fea5dSIngo Weinhold 				break;
4940c0fea5dSIngo Weinhold 			case PT_LOAD:
4950c0fea5dSIngo Weinhold 				if (pheader->p_memsz == pheader->p_filesz) {
4960c0fea5dSIngo Weinhold 					/*
4970c0fea5dSIngo Weinhold 					 * everything in one area
4980c0fea5dSIngo Weinhold 					 */
4990c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
5000c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_memsz;
5010c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
5020c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz
5030c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
5040c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
5050c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
5060c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
5070c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
5080c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
5090c0fea5dSIngo Weinhold 						// this is a writable segment
5100c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
5110c0fea5dSIngo Weinhold 					}
5120c0fea5dSIngo Weinhold 				} else {
5130c0fea5dSIngo Weinhold 					/*
5140c0fea5dSIngo Weinhold 					 * may require splitting
5150c0fea5dSIngo Weinhold 					 */
5160c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz);
5170c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz);
5180c0fea5dSIngo Weinhold 
5190c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
5200c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_filesz;
5210c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
5220c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz
5230c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
5240c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
5250c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
5260c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
5270c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
5280c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
5290c0fea5dSIngo Weinhold 						// this is a writable segment
5300c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
5310c0fea5dSIngo Weinhold 					}
5320c0fea5dSIngo Weinhold 
5330c0fea5dSIngo Weinhold 					if (A != B) {
5340c0fea5dSIngo Weinhold 						/*
5350c0fea5dSIngo Weinhold 						 * yeah, it requires splitting
5360c0fea5dSIngo Weinhold 						 */
5370c0fea5dSIngo Weinhold 						regcount += 1;
5380c0fea5dSIngo Weinhold 						image->regions[regcount].start = pheader->p_vaddr;
5390c0fea5dSIngo Weinhold 						image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz;
5400c0fea5dSIngo Weinhold 						image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
5410c0fea5dSIngo Weinhold 						image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr))
5420c0fea5dSIngo Weinhold 							- image->regions[regcount-1].vmsize;
5430c0fea5dSIngo Weinhold 						image->regions[regcount].fdstart = 0;
5440c0fea5dSIngo Weinhold 						image->regions[regcount].fdsize = 0;
5450c0fea5dSIngo Weinhold 						image->regions[regcount].delta = 0;
5460c0fea5dSIngo Weinhold 						image->regions[regcount].flags = RFLAG_ANON;
5470c0fea5dSIngo Weinhold 						if (pheader->p_flags & PF_WRITE) {
5480c0fea5dSIngo Weinhold 							// this is a writable segment
5490c0fea5dSIngo Weinhold 							image->regions[regcount].flags |= RFLAG_RW;
5500c0fea5dSIngo Weinhold 						}
5510c0fea5dSIngo Weinhold 					}
5520c0fea5dSIngo Weinhold 				}
5530c0fea5dSIngo Weinhold 				regcount += 1;
5540c0fea5dSIngo Weinhold 				break;
5550c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
5560c0fea5dSIngo Weinhold 				image->dynamic_ptr = pheader->p_vaddr;
5570c0fea5dSIngo Weinhold 				break;
5580c0fea5dSIngo Weinhold 			case PT_INTERP:
5590c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
5600c0fea5dSIngo Weinhold 				break;
5610c0fea5dSIngo Weinhold 			case PT_NOTE:
5620c0fea5dSIngo Weinhold 				/* unsupported */
5630c0fea5dSIngo Weinhold 				break;
5640c0fea5dSIngo Weinhold 			case PT_SHLIB:
5650c0fea5dSIngo Weinhold 				/* undefined semantics */
5660c0fea5dSIngo Weinhold 				break;
5670c0fea5dSIngo Weinhold 			case PT_PHDR:
5680c0fea5dSIngo Weinhold 				/* we don't use it */
5690c0fea5dSIngo Weinhold 				break;
5700c0fea5dSIngo Weinhold 			default:
5710c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type);
5720c0fea5dSIngo Weinhold 				return B_BAD_DATA;
5730c0fea5dSIngo Weinhold 		}
5740c0fea5dSIngo Weinhold 	}
5750c0fea5dSIngo Weinhold 
5760c0fea5dSIngo Weinhold 	return B_OK;
5770c0fea5dSIngo Weinhold }
5780c0fea5dSIngo Weinhold 
5790c0fea5dSIngo Weinhold 
5800c0fea5dSIngo Weinhold static bool
58134982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader,
58234982809SIngo Weinhold 	int32 sheaderSize, char* buffer, size_t bufferSize)
58334982809SIngo Weinhold {
58434982809SIngo Weinhold 	image->gcc_version.major = 0;
58534982809SIngo Weinhold 	image->gcc_version.middle = 0;
58634982809SIngo Weinhold 	image->gcc_version.minor = 0;
58734982809SIngo Weinhold 
58834982809SIngo Weinhold 	if (sheaderSize > (int)bufferSize) {
58934982809SIngo Weinhold 		FATAL("Cannot handle section headers bigger than %lu\n", bufferSize);
59034982809SIngo Weinhold 		return false;
59134982809SIngo Weinhold 	}
59234982809SIngo Weinhold 
59334982809SIngo Weinhold 	// read section headers
59434982809SIngo Weinhold 	ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize);
59534982809SIngo Weinhold 	if (length != sheaderSize) {
59634982809SIngo Weinhold 		FATAL("Could not read section headers: %s\n", strerror(length));
59734982809SIngo Weinhold 		return false;
59834982809SIngo Weinhold 	}
59934982809SIngo Weinhold 
60034982809SIngo Weinhold 	// load the string section
60134982809SIngo Weinhold 	Elf32_Shdr* sectionHeader
60234982809SIngo Weinhold 		= (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize);
60334982809SIngo Weinhold 
60434982809SIngo Weinhold 	if (sheaderSize + sectionHeader->sh_size > bufferSize) {
60534982809SIngo Weinhold 		FATAL("Buffer not big enough for section string section\n");
60634982809SIngo Weinhold 		return false;
60734982809SIngo Weinhold 	}
60834982809SIngo Weinhold 
60934982809SIngo Weinhold 	char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size;
61034982809SIngo Weinhold 	length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings,
61134982809SIngo Weinhold 		sectionHeader->sh_size);
61234982809SIngo Weinhold 	if (length != (int)sectionHeader->sh_size) {
61334982809SIngo Weinhold 		FATAL("Could not read section string section: %s\n", strerror(length));
61434982809SIngo Weinhold 		return false;
61534982809SIngo Weinhold 	}
61634982809SIngo Weinhold 
61734982809SIngo Weinhold 	// find the .comment section
61834982809SIngo Weinhold 	off_t commentOffset = 0;
61934982809SIngo Weinhold 	size_t commentSize = 0;
62034982809SIngo Weinhold 	for (uint32 i = 0; i < eheader.e_shnum; i++) {
62134982809SIngo Weinhold 		sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize);
62234982809SIngo Weinhold 		const char* sectionName = sectionStrings + sectionHeader->sh_name;
62334982809SIngo Weinhold 		if (sectionHeader->sh_name != 0
62434982809SIngo Weinhold 			&& strcmp(sectionName, ".comment") == 0) {
62534982809SIngo Weinhold 			commentOffset = sectionHeader->sh_offset;
62634982809SIngo Weinhold 			commentSize = sectionHeader->sh_size;
62734982809SIngo Weinhold 			break;
62834982809SIngo Weinhold 		}
62934982809SIngo Weinhold 	}
63034982809SIngo Weinhold 
63134982809SIngo Weinhold 	if (commentSize == 0) {
63234982809SIngo Weinhold 		FATAL("Could not find .comment section\n");
63334982809SIngo Weinhold 		return false;
63434982809SIngo Weinhold 	}
63534982809SIngo Weinhold 
63634982809SIngo Weinhold 	// read a part of the comment section
63734982809SIngo Weinhold 	if (commentSize > 512)
63834982809SIngo Weinhold 		commentSize = 512;
63934982809SIngo Weinhold 
64034982809SIngo Weinhold 	length = _kern_read(fd, commentOffset, buffer, commentSize);
64134982809SIngo Weinhold 	if (length != (int)commentSize) {
64234982809SIngo Weinhold 		FATAL("Could not read .comment section: %s\n", strerror(length));
64334982809SIngo Weinhold 		return false;
64434982809SIngo Weinhold 	}
64534982809SIngo Weinhold 
64634982809SIngo Weinhold 	// the common prefix of the strings in the .comment section
64734982809SIngo Weinhold 	static const char* kGCCVersionPrefix = "GCC: (GNU) ";
64834982809SIngo Weinhold 	size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix);
64934982809SIngo Weinhold 
65034982809SIngo Weinhold 	size_t index = 0;
65134982809SIngo Weinhold 	int gccMajor = 0;
65234982809SIngo Weinhold 	int gccMiddle = 0;
65334982809SIngo Weinhold 	int gccMinor = 0;
654*2716cfd3SAxel Dörfler 	bool isHaiku = true;
65534982809SIngo Weinhold 
65634982809SIngo Weinhold 	// Read up to 10 comments. The first three or four are usually from the
65734982809SIngo Weinhold 	// glue code.
65834982809SIngo Weinhold 	for (int i = 0; i < 10; i++) {
65934982809SIngo Weinhold 		// skip '\0'
66034982809SIngo Weinhold 		while (index < commentSize && buffer[index] == '\0')
66134982809SIngo Weinhold 			index++;
66234982809SIngo Weinhold 		char* stringStart = buffer + index;
66334982809SIngo Weinhold 
66434982809SIngo Weinhold 		// find string end
66534982809SIngo Weinhold 		while (index < commentSize && buffer[index] != '\0')
66634982809SIngo Weinhold 			index++;
66734982809SIngo Weinhold 
66834982809SIngo Weinhold 		// ignore the entry at the end of the buffer
66934982809SIngo Weinhold 		if (index == commentSize)
67034982809SIngo Weinhold 			break;
67134982809SIngo Weinhold 
67234982809SIngo Weinhold 		// We have to analyze string like these:
67334982809SIngo Weinhold 		// GCC: (GNU) 2.9-beos-991026
67434982809SIngo Weinhold 		// GCC: (GNU) 2.95.3-haiku-080322
67534982809SIngo Weinhold 		// GCC: (GNU) 4.1.2
67634982809SIngo Weinhold 
67734982809SIngo Weinhold 		// skip the common prefix
67834982809SIngo Weinhold 		if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0)
67934982809SIngo Weinhold 			continue;
68034982809SIngo Weinhold 
68134982809SIngo Weinhold 		// the rest is the GCC version
68234982809SIngo Weinhold 		char* gccVersion = stringStart + gccVersionPrefixLen;
68334982809SIngo Weinhold 		char* gccPlatform = strchr(gccVersion, '-');
68434982809SIngo Weinhold 		char* patchLevel = NULL;
68534982809SIngo Weinhold 		if (gccPlatform != NULL) {
68634982809SIngo Weinhold 			*gccPlatform = '\0';
68734982809SIngo Weinhold 			gccPlatform++;
68834982809SIngo Weinhold 			patchLevel = strchr(gccPlatform, '-');
68934982809SIngo Weinhold 			if (patchLevel != NULL) {
69034982809SIngo Weinhold 				*patchLevel = '\0';
69134982809SIngo Weinhold 				patchLevel++;
69234982809SIngo Weinhold 			}
69334982809SIngo Weinhold 		}
69434982809SIngo Weinhold 
69534982809SIngo Weinhold 		// split the gcc version into major, middle, and minor
69634982809SIngo Weinhold 		int version[3] = { 0, 0, 0 };
69734982809SIngo Weinhold 
69834982809SIngo Weinhold 		for (int k = 0; gccVersion != NULL && k < 3; k++) {
69934982809SIngo Weinhold 			char* dot = strchr(gccVersion, '.');
70034982809SIngo Weinhold 			if (dot) {
70134982809SIngo Weinhold 				*dot = '\0';
70234982809SIngo Weinhold 				dot++;
70334982809SIngo Weinhold 			}
70434982809SIngo Weinhold 			version[k] = atoi(gccVersion);
70534982809SIngo Weinhold 			gccVersion = dot;
70634982809SIngo Weinhold 		}
70734982809SIngo Weinhold 
70834982809SIngo Weinhold 		// got any version?
70934982809SIngo Weinhold 		if (version[0] == 0)
71034982809SIngo Weinhold 			continue;
71134982809SIngo Weinhold 
71234982809SIngo Weinhold 		// Select the gcc version with the smallest major, but the greatest
71334982809SIngo Weinhold 		// middle/minor. This should usually ignore the glue code version as
71434982809SIngo Weinhold 		// well as cases where e.g. in a gcc 2 program a single C file has
71534982809SIngo Weinhold 		// been compiled with gcc 4.
71634982809SIngo Weinhold 		if (gccMajor == 0 || gccMajor > version[0]
71734982809SIngo Weinhold 		 	|| gccMajor == version[0]
71834982809SIngo Weinhold 				&& (gccMiddle < version[1]
71934982809SIngo Weinhold 					|| gccMiddle == version[1] && gccMinor < version[2])) {
72034982809SIngo Weinhold 			gccMajor = version[0];
72134982809SIngo Weinhold 			gccMiddle = version[1];
72234982809SIngo Weinhold 			gccMinor = version[2];
72334982809SIngo Weinhold 		}
724*2716cfd3SAxel Dörfler 
725*2716cfd3SAxel Dörfler 		if (gccMajor == 2 && strcmp(gccPlatform, "haiku"))
726*2716cfd3SAxel Dörfler 			isHaiku = false;
72734982809SIngo Weinhold 	}
72834982809SIngo Weinhold 
72934982809SIngo Weinhold 	image->gcc_version.major = gccMajor;
73034982809SIngo Weinhold 	image->gcc_version.middle = gccMiddle;
73134982809SIngo Weinhold 	image->gcc_version.minor = gccMinor;
732*2716cfd3SAxel Dörfler 	image->gcc_version.haiku = isHaiku;
73334982809SIngo Weinhold 
73434982809SIngo Weinhold 	return gccMajor != 0;
73534982809SIngo Weinhold }
73634982809SIngo Weinhold 
73734982809SIngo Weinhold 
73834982809SIngo Weinhold static bool
7390c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image)
7400c0fea5dSIngo Weinhold {
7410c0fea5dSIngo Weinhold 	uint32 i;
7420c0fea5dSIngo Weinhold 
7430c0fea5dSIngo Weinhold 	if (!image->dynamic_ptr)
7440c0fea5dSIngo Weinhold 		return true;
7450c0fea5dSIngo Weinhold 
7460c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
7470c0fea5dSIngo Weinhold 		if (image->dynamic_ptr >= image->regions[i].start
7480c0fea5dSIngo Weinhold 			&& image->dynamic_ptr < image->regions[i].start + image->regions[i].size)
7490c0fea5dSIngo Weinhold 			return true;
7500c0fea5dSIngo Weinhold 	}
7510c0fea5dSIngo Weinhold 
7520c0fea5dSIngo Weinhold 	return false;
7530c0fea5dSIngo Weinhold }
7540c0fea5dSIngo Weinhold 
7550c0fea5dSIngo Weinhold 
7560c0fea5dSIngo Weinhold /**	This function will change the protection of all read-only segments
7570c0fea5dSIngo Weinhold  *	to really be read-only.
7580c0fea5dSIngo Weinhold  *	The areas have to be read/write first, so that they can be relocated.
7590c0fea5dSIngo Weinhold  */
7600c0fea5dSIngo Weinhold 
7610c0fea5dSIngo Weinhold static void
7620c0fea5dSIngo Weinhold remap_images(void)
7630c0fea5dSIngo Weinhold {
7640c0fea5dSIngo Weinhold 	image_t *image;
7650c0fea5dSIngo Weinhold 	uint32 i;
7660c0fea5dSIngo Weinhold 
7670c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
7680c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_regions; i++) {
7690c0fea5dSIngo Weinhold 			if ((image->regions[i].flags & RFLAG_RW) == 0
7700c0fea5dSIngo Weinhold 				&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
7710c0fea5dSIngo Weinhold 				// we only need to do this once, so we remember those we've already mapped
7720c0fea5dSIngo Weinhold 				if (_kern_set_area_protection(image->regions[i].id,
7730c0fea5dSIngo Weinhold 						B_READ_AREA | B_EXECUTE_AREA) == B_OK)
7740c0fea5dSIngo Weinhold 					image->regions[i].flags |= RFLAG_REMAPPED;
7750c0fea5dSIngo Weinhold 			}
7760c0fea5dSIngo Weinhold 		}
7770c0fea5dSIngo Weinhold 	}
7780c0fea5dSIngo Weinhold }
7790c0fea5dSIngo Weinhold 
7800c0fea5dSIngo Weinhold 
7810c0fea5dSIngo Weinhold static status_t
7820c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed)
7830c0fea5dSIngo Weinhold {
7840c0fea5dSIngo Weinhold 	status_t status = B_OK;
7850c0fea5dSIngo Weinhold 	const char *baseName;
7860c0fea5dSIngo Weinhold 	uint32 i;
7870c0fea5dSIngo Weinhold 
7880c0fea5dSIngo Weinhold 	(void)(fd);
7890c0fea5dSIngo Weinhold 
7900c0fea5dSIngo Weinhold 	// cut the file name from the path as base name for the created areas
7910c0fea5dSIngo Weinhold 	baseName = strrchr(path, '/');
7920c0fea5dSIngo Weinhold 	if (baseName != NULL)
7930c0fea5dSIngo Weinhold 		baseName++;
7940c0fea5dSIngo Weinhold 	else
7950c0fea5dSIngo Weinhold 		baseName = path;
7960c0fea5dSIngo Weinhold 
7970c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
7980c0fea5dSIngo Weinhold 		char regionName[B_OS_NAME_LENGTH];
7990c0fea5dSIngo Weinhold 		addr_t loadAddress;
8000c0fea5dSIngo Weinhold 		uint32 addressSpecifier;
8010c0fea5dSIngo Weinhold 
8020c0fea5dSIngo Weinhold 		// for BeOS compatibility: if we load an old BeOS executable, we
8030c0fea5dSIngo Weinhold 		// have to relocate it, if possible - we recognize it because the
8040c0fea5dSIngo Weinhold 		// vmstart is set to 0 (hopefully always)
8050c0fea5dSIngo Weinhold 		if (fixed && image->regions[i].vmstart == 0)
8060c0fea5dSIngo Weinhold 			fixed = false;
8070c0fea5dSIngo Weinhold 
8080c0fea5dSIngo Weinhold 		snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
8090c0fea5dSIngo Weinhold 			baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
8100c0fea5dSIngo Weinhold 
8110c0fea5dSIngo Weinhold 		if (image->dynamic_ptr && !fixed) {
8120c0fea5dSIngo Weinhold 			// relocatable image... we can afford to place wherever
8130c0fea5dSIngo Weinhold 			if (i == 0) {
8140c0fea5dSIngo Weinhold 				// but only the first segment gets a free ride
8150c0fea5dSIngo Weinhold 				loadAddress = RLD_PROGRAM_BASE;
8160c0fea5dSIngo Weinhold 				addressSpecifier = B_BASE_ADDRESS;
8170c0fea5dSIngo Weinhold 			} else {
8180c0fea5dSIngo Weinhold 				loadAddress = image->regions[i].vmstart + image->regions[i-1].delta;
8190c0fea5dSIngo Weinhold 				addressSpecifier = B_EXACT_ADDRESS;
8200c0fea5dSIngo Weinhold 			}
8210c0fea5dSIngo Weinhold 		} else {
8220c0fea5dSIngo Weinhold 			// not relocatable, put it where it asks or die trying
8230c0fea5dSIngo Weinhold 			loadAddress = image->regions[i].vmstart;
8240c0fea5dSIngo Weinhold 			addressSpecifier = B_EXACT_ADDRESS;
8250c0fea5dSIngo Weinhold 		}
8260c0fea5dSIngo Weinhold 
8270c0fea5dSIngo Weinhold 		if (image->regions[i].flags & RFLAG_ANON) {
8280c0fea5dSIngo Weinhold 			image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress,
8290c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_NO_LOCK,
8300c0fea5dSIngo Weinhold 				B_READ_AREA | B_WRITE_AREA);
8310c0fea5dSIngo Weinhold 
8320c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
8330c0fea5dSIngo Weinhold 				status = image->regions[i].id;
8340c0fea5dSIngo Weinhold 				goto error;
8350c0fea5dSIngo Weinhold 			}
8360c0fea5dSIngo Weinhold 
8370c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
8380c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
8390c0fea5dSIngo Weinhold 		} else {
8403cf7ecd1SIngo Weinhold 			image->regions[i].id = _kern_map_file(regionName,
8413cf7ecd1SIngo Weinhold 				(void **)&loadAddress, addressSpecifier,
8423cf7ecd1SIngo Weinhold 				image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
8433cf7ecd1SIngo Weinhold 				REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart));
8440c0fea5dSIngo Weinhold 
8450c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
8460c0fea5dSIngo Weinhold 				status = image->regions[i].id;
8470c0fea5dSIngo Weinhold 				goto error;
8480c0fea5dSIngo Weinhold 			}
8490c0fea5dSIngo Weinhold 
8500c0fea5dSIngo Weinhold 			TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
8510c0fea5dSIngo Weinhold 				(void *)loadAddress, image->regions[i].vmsize,
8520c0fea5dSIngo Weinhold 				image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
8530c0fea5dSIngo Weinhold 
8540c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
8550c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
8560c0fea5dSIngo Weinhold 
8570c0fea5dSIngo Weinhold 			// handle trailer bits in data segment
8580c0fea5dSIngo Weinhold 			if (image->regions[i].flags & RFLAG_RW) {
8590c0fea5dSIngo Weinhold 				addr_t startClearing;
8600c0fea5dSIngo Weinhold 				addr_t toClear;
8610c0fea5dSIngo Weinhold 
8620c0fea5dSIngo Weinhold 				startClearing = image->regions[i].vmstart
8630c0fea5dSIngo Weinhold 					+ PAGE_OFFSET(image->regions[i].start)
8640c0fea5dSIngo Weinhold 					+ image->regions[i].size;
8650c0fea5dSIngo Weinhold 				toClear = image->regions[i].vmsize
8660c0fea5dSIngo Weinhold 					- PAGE_OFFSET(image->regions[i].start)
8670c0fea5dSIngo Weinhold 					- image->regions[i].size;
8680c0fea5dSIngo Weinhold 
8690c0fea5dSIngo Weinhold 				TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear));
8700c0fea5dSIngo Weinhold 				memset((void *)startClearing, 0, toClear);
8710c0fea5dSIngo Weinhold 			}
8720c0fea5dSIngo Weinhold 		}
8730c0fea5dSIngo Weinhold 	}
8740c0fea5dSIngo Weinhold 
8750c0fea5dSIngo Weinhold 	if (image->dynamic_ptr)
8760c0fea5dSIngo Weinhold 		image->dynamic_ptr += image->regions[0].delta;
8770c0fea5dSIngo Weinhold 
8780c0fea5dSIngo Weinhold 	return B_OK;
8790c0fea5dSIngo Weinhold 
8800c0fea5dSIngo Weinhold error:
8810c0fea5dSIngo Weinhold 	return status;
8820c0fea5dSIngo Weinhold }
8830c0fea5dSIngo Weinhold 
8840c0fea5dSIngo Weinhold 
8850c0fea5dSIngo Weinhold static void
8860c0fea5dSIngo Weinhold unmap_image(image_t *image)
8870c0fea5dSIngo Weinhold {
8880c0fea5dSIngo Weinhold 	uint32 i;
8890c0fea5dSIngo Weinhold 
8900c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
8910c0fea5dSIngo Weinhold 		_kern_delete_area(image->regions[i].id);
8920c0fea5dSIngo Weinhold 
8930c0fea5dSIngo Weinhold 		image->regions[i].id = -1;
8940c0fea5dSIngo Weinhold 	}
8950c0fea5dSIngo Weinhold }
8960c0fea5dSIngo Weinhold 
8970c0fea5dSIngo Weinhold 
8980c0fea5dSIngo Weinhold static bool
8990c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image)
9000c0fea5dSIngo Weinhold {
9010c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d;
9020c0fea5dSIngo Weinhold 	int i;
9030c0fea5dSIngo Weinhold 	int sonameOffset = -1;
9040c0fea5dSIngo Weinhold 
9050c0fea5dSIngo Weinhold 	image->symhash = 0;
9060c0fea5dSIngo Weinhold 	image->syms = 0;
9070c0fea5dSIngo Weinhold 	image->strtab = 0;
9080c0fea5dSIngo Weinhold 
9090c0fea5dSIngo Weinhold 	d = (struct Elf32_Dyn *)image->dynamic_ptr;
9100c0fea5dSIngo Weinhold 	if (!d)
9110c0fea5dSIngo Weinhold 		return true;
9120c0fea5dSIngo Weinhold 
9130c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
9140c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
9150c0fea5dSIngo Weinhold 			case DT_NEEDED:
9160c0fea5dSIngo Weinhold 				image->num_needed += 1;
9170c0fea5dSIngo Weinhold 				break;
9180c0fea5dSIngo Weinhold 			case DT_HASH:
9190c0fea5dSIngo Weinhold 				image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta);
9200c0fea5dSIngo Weinhold 				break;
9210c0fea5dSIngo Weinhold 			case DT_STRTAB:
9220c0fea5dSIngo Weinhold 				image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
9230c0fea5dSIngo Weinhold 				break;
9240c0fea5dSIngo Weinhold 			case DT_SYMTAB:
9250c0fea5dSIngo Weinhold 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
9260c0fea5dSIngo Weinhold 				break;
9270c0fea5dSIngo Weinhold 			case DT_REL:
9280c0fea5dSIngo Weinhold 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
9290c0fea5dSIngo Weinhold 				break;
9300c0fea5dSIngo Weinhold 			case DT_RELSZ:
9310c0fea5dSIngo Weinhold 				image->rel_len = d[i].d_un.d_val;
9320c0fea5dSIngo Weinhold 				break;
9330c0fea5dSIngo Weinhold 			case DT_RELA:
9340c0fea5dSIngo Weinhold 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
9350c0fea5dSIngo Weinhold 				break;
9360c0fea5dSIngo Weinhold 			case DT_RELASZ:
9370c0fea5dSIngo Weinhold 				image->rela_len = d[i].d_un.d_val;
9380c0fea5dSIngo Weinhold 				break;
9390c0fea5dSIngo Weinhold 			// TK: procedure linkage table
9400c0fea5dSIngo Weinhold 			case DT_JMPREL:
9410c0fea5dSIngo Weinhold 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
9420c0fea5dSIngo Weinhold 				break;
9430c0fea5dSIngo Weinhold 			case DT_PLTRELSZ:
9440c0fea5dSIngo Weinhold 				image->pltrel_len = d[i].d_un.d_val;
9450c0fea5dSIngo Weinhold 				break;
9460c0fea5dSIngo Weinhold 			case DT_INIT:
9470c0fea5dSIngo Weinhold 				image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
9480c0fea5dSIngo Weinhold 				break;
9490c0fea5dSIngo Weinhold 			case DT_FINI:
9500c0fea5dSIngo Weinhold 				image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
9510c0fea5dSIngo Weinhold 				break;
9520c0fea5dSIngo Weinhold 			case DT_SONAME:
9530c0fea5dSIngo Weinhold 				sonameOffset = d[i].d_un.d_val;
9540c0fea5dSIngo Weinhold 				break;
9550c0fea5dSIngo Weinhold 			default:
9560c0fea5dSIngo Weinhold 				continue;
9570c0fea5dSIngo Weinhold 		}
9580c0fea5dSIngo Weinhold 	}
9590c0fea5dSIngo Weinhold 
9600c0fea5dSIngo Weinhold 	// lets make sure we found all the required sections
9610c0fea5dSIngo Weinhold 	if (!image->symhash || !image->syms || !image->strtab)
9620c0fea5dSIngo Weinhold 		return false;
9630c0fea5dSIngo Weinhold 
9640c0fea5dSIngo Weinhold 	if (sonameOffset >= 0)
9650c0fea5dSIngo Weinhold 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
9660c0fea5dSIngo Weinhold 
9670c0fea5dSIngo Weinhold 	return true;
9680c0fea5dSIngo Weinhold }
9690c0fea5dSIngo Weinhold 
9700c0fea5dSIngo Weinhold 
9710c0fea5dSIngo Weinhold static struct Elf32_Sym *
9720c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type)
9730c0fea5dSIngo Weinhold {
9740c0fea5dSIngo Weinhold 	uint32 hash, i;
9750c0fea5dSIngo Weinhold 
9760c0fea5dSIngo Weinhold 	// ToDo: "type" is currently ignored!
9770c0fea5dSIngo Weinhold 	(void)type;
9780c0fea5dSIngo Weinhold 
979dd76bc97SIngo Weinhold 	if (image->dynamic_ptr == 0)
9800c0fea5dSIngo Weinhold 		return NULL;
9810c0fea5dSIngo Weinhold 
9820c0fea5dSIngo Weinhold 	hash = elf_hash((uint8 *)name) % HASHTABSIZE(image);
9830c0fea5dSIngo Weinhold 
9840c0fea5dSIngo Weinhold 	for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
9850c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = &image->syms[i];
9860c0fea5dSIngo Weinhold 
9870c0fea5dSIngo Weinhold 		if (symbol->st_shndx != SHN_UNDEF
9880c0fea5dSIngo Weinhold 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
9890c0fea5dSIngo Weinhold 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
9900c0fea5dSIngo Weinhold 			&& !strcmp(SYMNAME(image, symbol), name)) {
9910c0fea5dSIngo Weinhold 			// check if the type matches
9920c0fea5dSIngo Weinhold 			if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
9930c0fea5dSIngo Weinhold 				|| (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT))
9940c0fea5dSIngo Weinhold 				continue;
9950c0fea5dSIngo Weinhold 
9960c0fea5dSIngo Weinhold 			return symbol;
9970c0fea5dSIngo Weinhold 		}
9980c0fea5dSIngo Weinhold 	}
9990c0fea5dSIngo Weinhold 
10000c0fea5dSIngo Weinhold 	return NULL;
10010c0fea5dSIngo Weinhold }
10020c0fea5dSIngo Weinhold 
10030c0fea5dSIngo Weinhold 
10040c0fea5dSIngo Weinhold static struct Elf32_Sym*
100546f4d849SIngo Weinhold find_symbol_recursively_impl(image_t* image, const char* name,
100646f4d849SIngo Weinhold 	image_t** foundInImage)
10070c0fea5dSIngo Weinhold {
100846f4d849SIngo Weinhold 	image->flags |= RFLAG_VISITED;
10090c0fea5dSIngo Weinhold 
10100c0fea5dSIngo Weinhold 	struct Elf32_Sym *symbol;
10110c0fea5dSIngo Weinhold 
101246f4d849SIngo Weinhold 	// look up the symbol in this image
101346f4d849SIngo Weinhold 	if (image->dynamic_ptr) {
10140c0fea5dSIngo Weinhold 		symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY);
10150c0fea5dSIngo Weinhold 		if (symbol) {
101646f4d849SIngo Weinhold 			*foundInImage = image;
101746f4d849SIngo Weinhold 			return symbol;
101846f4d849SIngo Weinhold 		}
101946f4d849SIngo Weinhold 	}
102046f4d849SIngo Weinhold 
102146f4d849SIngo Weinhold 	// recursively search dependencies
102246f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
102346f4d849SIngo Weinhold 		if (!(image->needed[i]->flags & RFLAG_VISITED)) {
102446f4d849SIngo Weinhold 			symbol = find_symbol_recursively_impl(image->needed[i], name,
102546f4d849SIngo Weinhold 				foundInImage);
102646f4d849SIngo Weinhold 			if (symbol)
10270c0fea5dSIngo Weinhold 				return symbol;
10280c0fea5dSIngo Weinhold 		}
10290c0fea5dSIngo Weinhold 	}
10300c0fea5dSIngo Weinhold 
10310c0fea5dSIngo Weinhold 	return NULL;
10320c0fea5dSIngo Weinhold }
10330c0fea5dSIngo Weinhold 
10340c0fea5dSIngo Weinhold 
103546f4d849SIngo Weinhold static void
103646f4d849SIngo Weinhold clear_image_flag_recursively(image_t* image, uint32 flag)
103746f4d849SIngo Weinhold {
103846f4d849SIngo Weinhold 	image->flags &= ~flag;
103946f4d849SIngo Weinhold 
104046f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
104146f4d849SIngo Weinhold 		if (image->needed[i]->flags & flag)
104246f4d849SIngo Weinhold 			clear_image_flag_recursively(image->needed[i], flag);
104346f4d849SIngo Weinhold 	}
104446f4d849SIngo Weinhold }
104546f4d849SIngo Weinhold 
104646f4d849SIngo Weinhold 
104746f4d849SIngo Weinhold static struct Elf32_Sym*
104846f4d849SIngo Weinhold find_symbol_recursively(image_t* image, const char* name,
104946f4d849SIngo Weinhold 	image_t** foundInImage)
105046f4d849SIngo Weinhold {
105146f4d849SIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol_recursively_impl(image, name,
105246f4d849SIngo Weinhold 		foundInImage);
105346f4d849SIngo Weinhold 	clear_image_flag_recursively(image, RFLAG_VISITED);
105446f4d849SIngo Weinhold 	return symbol;
105546f4d849SIngo Weinhold }
105646f4d849SIngo Weinhold 
105746f4d849SIngo Weinhold 
105846f4d849SIngo Weinhold static struct Elf32_Sym*
105946f4d849SIngo Weinhold find_symbol_in_loaded_images(const char* name, image_t** foundInImage)
106046f4d849SIngo Weinhold {
106146f4d849SIngo Weinhold 	return find_symbol_recursively(sLoadedImages.head, name, foundInImage);
106246f4d849SIngo Weinhold }
106346f4d849SIngo Weinhold 
106446f4d849SIngo Weinhold 
106546f4d849SIngo Weinhold static struct Elf32_Sym*
106646f4d849SIngo Weinhold find_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
106746f4d849SIngo Weinhold 	image_t** foundInImage)
106846f4d849SIngo Weinhold {
106946f4d849SIngo Weinhold 	// If not simulating BeOS style symbol resolution, undefined symbols are
107092af28dfSIngo Weinhold 	// searched recursively starting from the root image.
107192af28dfSIngo Weinhold 	// TODO: Breadth first might be better than the depth first strategy used
107292af28dfSIngo Weinhold 	// here. We're also visiting images multiple times. Consider building a
107392af28dfSIngo Weinhold 	// breadth-first sorted array of images for each root image.
10745fd6637bSIngo Weinhold 	if ((rootImage->flags & IMAGE_FLAG_R5_SYMBOL_RESOLUTION) == 0) {
10755fd6637bSIngo Weinhold 		Elf32_Sym* symbol = find_symbol_recursively(rootImage, name,
10765fd6637bSIngo Weinhold 			foundInImage);
10775fd6637bSIngo Weinhold 		if (symbol != NULL)
10785fd6637bSIngo Weinhold 			return symbol;
10795fd6637bSIngo Weinhold 
10805fd6637bSIngo Weinhold 		// If the root image is not the program image (i.e. it is a dynamically
10815fd6637bSIngo Weinhold 		// loaded add-on or library), we try the program image hierarchy too.
10825fd6637bSIngo Weinhold 		image_t* programImage = get_program_image();
10835fd6637bSIngo Weinhold 		if (rootImage != programImage)
10845fd6637bSIngo Weinhold 			return find_symbol_recursively(programImage, name, foundInImage);
10855fd6637bSIngo Weinhold 
10865fd6637bSIngo Weinhold 		return NULL;
10875fd6637bSIngo Weinhold 	}
108846f4d849SIngo Weinhold 
108946f4d849SIngo Weinhold 	// BeOS style symbol resolution: It is sufficient to check the direct
109046f4d849SIngo Weinhold 	// dependencies. The linker would have complained, if the symbol wasn't
109146f4d849SIngo Weinhold 	// there.
109246f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
109346f4d849SIngo Weinhold 		if (image->needed[i]->dynamic_ptr) {
109446f4d849SIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(image->needed[i], name,
109546f4d849SIngo Weinhold 				B_SYMBOL_TYPE_ANY);
109646f4d849SIngo Weinhold 			if (symbol) {
109746f4d849SIngo Weinhold 				*foundInImage = image->needed[i];
109846f4d849SIngo Weinhold 				return symbol;
109946f4d849SIngo Weinhold 			}
110046f4d849SIngo Weinhold 		}
110146f4d849SIngo Weinhold 	}
110246f4d849SIngo Weinhold 
110346f4d849SIngo Weinhold 	return NULL;
110446f4d849SIngo Weinhold }
110546f4d849SIngo Weinhold 
110646f4d849SIngo Weinhold 
1107*2716cfd3SAxel Dörfler /*!	This functions is called when we run BeOS images on Haiku.
1108*2716cfd3SAxel Dörfler 	It allows us to redirect functions to ensure compatibility.
1109*2716cfd3SAxel Dörfler */
1110*2716cfd3SAxel Dörfler static const char*
1111*2716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName)
1112*2716cfd3SAxel Dörfler {
1113*2716cfd3SAxel Dörfler 	struct symbol_mapping {
1114*2716cfd3SAxel Dörfler 		const char* from;
1115*2716cfd3SAxel Dörfler 		const char* to;
1116*2716cfd3SAxel Dörfler 	};
1117*2716cfd3SAxel Dörfler 	static const struct symbol_mapping kMappings[] = {
1118*2716cfd3SAxel Dörfler 		// TODO: improve this, and also use it for libnet.so compatibility!
1119*2716cfd3SAxel Dörfler 		{"fstat", "__be_fstat"},
1120*2716cfd3SAxel Dörfler 		{"lstat", "__be_lstat"},
1121*2716cfd3SAxel Dörfler 		{"stat", "__be_stat"},
1122*2716cfd3SAxel Dörfler 	};
1123*2716cfd3SAxel Dörfler 	const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]);
1124*2716cfd3SAxel Dörfler 
1125*2716cfd3SAxel Dörfler 	for (uint32 i = 0; i < kMappingCount; i++) {
1126*2716cfd3SAxel Dörfler 		if (!strcmp(symbolName, kMappings[i].from))
1127*2716cfd3SAxel Dörfler 			return kMappings[i].to;
1128*2716cfd3SAxel Dörfler 	}
1129*2716cfd3SAxel Dörfler 
1130*2716cfd3SAxel Dörfler 	return symbolName;
1131*2716cfd3SAxel Dörfler }
1132*2716cfd3SAxel Dörfler 
1133*2716cfd3SAxel Dörfler 
11340c0fea5dSIngo Weinhold int
113546f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
1136*2716cfd3SAxel Dörfler 	addr_t *symAddress)
11370c0fea5dSIngo Weinhold {
11380c0fea5dSIngo Weinhold 	switch (sym->st_shndx) {
11390c0fea5dSIngo Weinhold 		case SHN_UNDEF:
1140*2716cfd3SAxel Dörfler 		{
1141*2716cfd3SAxel Dörfler 			struct Elf32_Sym *sharedSym;
1142*2716cfd3SAxel Dörfler 			image_t *sharedImage;
1143*2716cfd3SAxel Dörfler 			const char *symName;
1144*2716cfd3SAxel Dörfler 
11450c0fea5dSIngo Weinhold 			// patch the symbol name
1146*2716cfd3SAxel Dörfler 			symName = SYMNAME(image, sym);
1147*2716cfd3SAxel Dörfler 			if (!image->gcc_version.haiku) {
1148*2716cfd3SAxel Dörfler 				// The image has been compiled with a BeOS compiler. This means
1149*2716cfd3SAxel Dörfler 				// we'll have to redirect some functions for compatibility.
1150*2716cfd3SAxel Dörfler 				symName = beos_compatibility_map_symbol(symName);
1151*2716cfd3SAxel Dörfler 			}
11520c0fea5dSIngo Weinhold 
115346f4d849SIngo Weinhold 			// it's undefined, must be outside this image, try the other images
1154*2716cfd3SAxel Dörfler 			sharedSym = find_undefined_symbol(rootImage, image, symName,
1155*2716cfd3SAxel Dörfler 				&sharedImage);
1156*2716cfd3SAxel Dörfler 			if (sharedSym == NULL) {
11572a33a944SIngo Weinhold 				FATAL("elf_resolve_symbol: could not resolve symbol '%s'\n",
1158*2716cfd3SAxel Dörfler 					symName);
11590c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
11600c0fea5dSIngo Weinhold 			}
11610c0fea5dSIngo Weinhold 
11620c0fea5dSIngo Weinhold 			// make sure they're the same type
11630c0fea5dSIngo Weinhold 			if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
1164*2716cfd3SAxel Dörfler 				&& ELF32_ST_TYPE(sym->st_info)
1165*2716cfd3SAxel Dörfler 					!= ELF32_ST_TYPE(sharedSym->st_info)) {
11662a33a944SIngo Weinhold 				FATAL("elf_resolve_symbol: found symbol '%s' in shared image "
1167*2716cfd3SAxel Dörfler 					"but wrong type\n", symName);
11680c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
11690c0fea5dSIngo Weinhold 			}
11700c0fea5dSIngo Weinhold 
1171*2716cfd3SAxel Dörfler 			if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL
1172*2716cfd3SAxel Dörfler 				&& ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) {
11732a33a944SIngo Weinhold 				FATAL("elf_resolve_symbol: found symbol '%s' but not "
1174*2716cfd3SAxel Dörfler 					"exported\n", symName);
11750c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
11760c0fea5dSIngo Weinhold 			}
11770c0fea5dSIngo Weinhold 
1178*2716cfd3SAxel Dörfler 			*symAddress = sharedSym->st_value + sharedImage->regions[0].delta;
11790c0fea5dSIngo Weinhold 			return B_NO_ERROR;
1180*2716cfd3SAxel Dörfler 		}
11810c0fea5dSIngo Weinhold 
11820c0fea5dSIngo Weinhold 		case SHN_ABS:
1183*2716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
11840c0fea5dSIngo Weinhold 			return B_NO_ERROR;
11850c0fea5dSIngo Weinhold 
11860c0fea5dSIngo Weinhold 		case SHN_COMMON:
11870c0fea5dSIngo Weinhold 			// ToDo: finish this
11882a33a944SIngo Weinhold 			FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n");
11890c0fea5dSIngo Weinhold 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
11900c0fea5dSIngo Weinhold 
11910c0fea5dSIngo Weinhold 		default:
11920c0fea5dSIngo Weinhold 			// standard symbol
1193*2716cfd3SAxel Dörfler 			*symAddress = sym->st_value + image->regions[0].delta;
11940c0fea5dSIngo Weinhold 			return B_NO_ERROR;
11950c0fea5dSIngo Weinhold 	}
11960c0fea5dSIngo Weinhold }
11970c0fea5dSIngo Weinhold 
11980c0fea5dSIngo Weinhold 
11990c0fea5dSIngo Weinhold static void
12000c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path)
12010c0fea5dSIngo Weinhold {
12020c0fea5dSIngo Weinhold 	struct stat stat;
12030c0fea5dSIngo Weinhold 	image_info info;
12040c0fea5dSIngo Weinhold 
12050c0fea5dSIngo Weinhold 	// ToDo: set these correctly
12060c0fea5dSIngo Weinhold 	info.id = 0;
12070c0fea5dSIngo Weinhold 	info.type = image->type;
12080c0fea5dSIngo Weinhold 	info.sequence = 0;
12090c0fea5dSIngo Weinhold 	info.init_order = 0;
12100c0fea5dSIngo Weinhold 	info.init_routine = (void (*)())image->init_routine;
12110c0fea5dSIngo Weinhold 	info.term_routine = (void (*)())image->term_routine;
12120c0fea5dSIngo Weinhold 
12130c0fea5dSIngo Weinhold 	if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
12140c0fea5dSIngo Weinhold 		info.device = stat.st_dev;
12150c0fea5dSIngo Weinhold 		info.node = stat.st_ino;
12160c0fea5dSIngo Weinhold 	} else {
12170c0fea5dSIngo Weinhold 		info.device = -1;
12180c0fea5dSIngo Weinhold 		info.node = -1;
12190c0fea5dSIngo Weinhold 	}
12200c0fea5dSIngo Weinhold 
12210c0fea5dSIngo Weinhold 	strlcpy(info.name, path, sizeof(info.name));
12220c0fea5dSIngo Weinhold 	info.text = (void *)image->regions[0].vmstart;
12230c0fea5dSIngo Weinhold 	info.text_size = image->regions[0].vmsize;
12240c0fea5dSIngo Weinhold 	info.data = (void *)image->regions[1].vmstart;
12250c0fea5dSIngo Weinhold 	info.data_size = image->regions[1].vmsize;
12260c0fea5dSIngo Weinhold 	image->id = _kern_register_image(&info, sizeof(image_info));
12270c0fea5dSIngo Weinhold }
12280c0fea5dSIngo Weinhold 
12290c0fea5dSIngo Weinhold 
12300c0fea5dSIngo Weinhold static status_t
123146f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
12320c0fea5dSIngo Weinhold {
123346f4d849SIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image);
12340c0fea5dSIngo Weinhold 	if (status < B_OK) {
1235320bd2bdSAxel Dörfler 		FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status,
1236320bd2bdSAxel Dörfler 			image->path, image->name);
12370c0fea5dSIngo Weinhold 		return status;
12380c0fea5dSIngo Weinhold 	}
12390c0fea5dSIngo Weinhold 
12400c0fea5dSIngo Weinhold 	_kern_image_relocated(image->id);
12410c0fea5dSIngo Weinhold 	return B_OK;
12420c0fea5dSIngo Weinhold }
12430c0fea5dSIngo Weinhold 
12440c0fea5dSIngo Weinhold 
12450c0fea5dSIngo Weinhold static status_t
12460c0fea5dSIngo Weinhold load_container(char const *name, image_type type, const char *rpath, image_t **_image)
12470c0fea5dSIngo Weinhold {
12480c0fea5dSIngo Weinhold 	int32 pheaderSize, sheaderSize;
12490c0fea5dSIngo Weinhold 	char path[PATH_MAX];
12500c0fea5dSIngo Weinhold 	ssize_t length;
12510c0fea5dSIngo Weinhold 	char ph_buff[4096];
12520c0fea5dSIngo Weinhold 	int32 numRegions;
12530c0fea5dSIngo Weinhold 	image_t *found;
12540c0fea5dSIngo Weinhold 	image_t *image;
12550c0fea5dSIngo Weinhold 	status_t status;
12560c0fea5dSIngo Weinhold 	int fd;
12570c0fea5dSIngo Weinhold 
12580c0fea5dSIngo Weinhold 	struct Elf32_Ehdr eheader;
12590c0fea5dSIngo Weinhold 
12600c0fea5dSIngo Weinhold 	// Have we already loaded that image? Don't check for add-ons -- we always
12610c0fea5dSIngo Weinhold 	// reload them.
12620c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
12630c0fea5dSIngo Weinhold 		found = find_image(name, APP_OR_LIBRARY_TYPE);
12640c0fea5dSIngo Weinhold 		if (found) {
12650c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
12660c0fea5dSIngo Weinhold 			*_image = found;
12677486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") "
12687486b72dSIngo Weinhold 				"already loaded", name, type, rpath);
12690c0fea5dSIngo Weinhold 			return B_OK;
12700c0fea5dSIngo Weinhold 		}
12710c0fea5dSIngo Weinhold 	}
12720c0fea5dSIngo Weinhold 
12737486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type,
12747486b72dSIngo Weinhold 		rpath);
12757486b72dSIngo Weinhold 
12760c0fea5dSIngo Weinhold 	strlcpy(path, name, sizeof(path));
12770c0fea5dSIngo Weinhold 
127861b37794SIngo Weinhold 	// find and open the file
127961b37794SIngo Weinhold 	fd = open_executable(path, type, rpath, get_program_path(),
128061b37794SIngo Weinhold 		sSearchPathSubDir);
12810c0fea5dSIngo Weinhold 	if (fd < 0) {
12820c0fea5dSIngo Weinhold 		FATAL("cannot open file %s\n", path);
12837486b72dSIngo Weinhold 		KTRACE("rld: load_container(\"%s\"): failed to open file", name);
12840c0fea5dSIngo Weinhold 		return fd;
12850c0fea5dSIngo Weinhold 	}
12860c0fea5dSIngo Weinhold 
12876918dbf4SIngo Weinhold 	// normalize the image path
12886918dbf4SIngo Weinhold 	status = _kern_normalize_path(path, true, path);
12896918dbf4SIngo Weinhold 	if (status != B_OK)
12900c0fea5dSIngo Weinhold 		goto err1;
12910c0fea5dSIngo Weinhold 
12920c0fea5dSIngo Weinhold 	// Test again if this image has been registered already - this time,
12930c0fea5dSIngo Weinhold 	// we can check the full path, not just its name as noted.
12940c0fea5dSIngo Weinhold 	// You could end up loading an image twice with symbolic links, else.
12950c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
12960c0fea5dSIngo Weinhold 		found = find_image(path, APP_OR_LIBRARY_TYPE);
12970c0fea5dSIngo Weinhold 		if (found) {
12980c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
12990c0fea5dSIngo Weinhold 			*_image = found;
13007486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\"): already loaded after all",
13017486b72dSIngo Weinhold 				name);
13020c0fea5dSIngo Weinhold 			return B_OK;
13030c0fea5dSIngo Weinhold 		}
13040c0fea5dSIngo Weinhold 	}
13050c0fea5dSIngo Weinhold 
13060c0fea5dSIngo Weinhold 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
13070c0fea5dSIngo Weinhold 	if (length != sizeof(eheader)) {
13080c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
13090c0fea5dSIngo Weinhold 		FATAL("troubles reading ELF header\n");
13100c0fea5dSIngo Weinhold 		goto err1;
13110c0fea5dSIngo Weinhold 	}
13120c0fea5dSIngo Weinhold 
13130c0fea5dSIngo Weinhold 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
13140c0fea5dSIngo Weinhold 	if (status < B_OK) {
13150c0fea5dSIngo Weinhold 		FATAL("incorrect ELF header\n");
13160c0fea5dSIngo Weinhold 		goto err1;
13170c0fea5dSIngo Weinhold 	}
13180c0fea5dSIngo Weinhold 
13190c0fea5dSIngo Weinhold 	// ToDo: what to do about this restriction??
13200c0fea5dSIngo Weinhold 	if (pheaderSize > (int)sizeof(ph_buff)) {
13210c0fea5dSIngo Weinhold 		FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff));
13220c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
13230c0fea5dSIngo Weinhold 		goto err1;
13240c0fea5dSIngo Weinhold 	}
13250c0fea5dSIngo Weinhold 
13260c0fea5dSIngo Weinhold 	length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize);
13270c0fea5dSIngo Weinhold 	if (length != pheaderSize) {
13280c0fea5dSIngo Weinhold 		FATAL("Could not read program headers: %s\n", strerror(length));
13290c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
13300c0fea5dSIngo Weinhold 		goto err1;
13310c0fea5dSIngo Weinhold 	}
13320c0fea5dSIngo Weinhold 
13330c0fea5dSIngo Weinhold 	numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
13340c0fea5dSIngo Weinhold 	if (numRegions <= 0) {
13350c0fea5dSIngo Weinhold 		FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
13360c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
13370c0fea5dSIngo Weinhold 		goto err1;
13380c0fea5dSIngo Weinhold 	}
13390c0fea5dSIngo Weinhold 
13400c0fea5dSIngo Weinhold 	image = create_image(name, path, numRegions);
13410c0fea5dSIngo Weinhold 	if (image == NULL) {
13420c0fea5dSIngo Weinhold 		FATAL("Failed to allocate image_t object\n");
13430c0fea5dSIngo Weinhold 		status = B_NO_MEMORY;
13440c0fea5dSIngo Weinhold 		goto err1;
13450c0fea5dSIngo Weinhold 	}
13460c0fea5dSIngo Weinhold 
13470c0fea5dSIngo Weinhold 	status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
13480c0fea5dSIngo Weinhold 	if (status < B_OK)
13490c0fea5dSIngo Weinhold 		goto err2;
13500c0fea5dSIngo Weinhold 
13510c0fea5dSIngo Weinhold 	if (!assert_dynamic_loadable(image)) {
13520c0fea5dSIngo Weinhold 		FATAL("Dynamic segment must be loadable (implementation restriction)\n");
13530c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
13540c0fea5dSIngo Weinhold 		goto err2;
13550c0fea5dSIngo Weinhold 	}
13560c0fea5dSIngo Weinhold 
135761b37794SIngo Weinhold 	if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff,
135834982809SIngo Weinhold 			sizeof(ph_buff))) {
135961b37794SIngo Weinhold 		// If this is the executable image, we init the search path
136061b37794SIngo Weinhold 		// subdir, if the compiler version doesn't match ours.
136161b37794SIngo Weinhold 		if (type == B_APP_IMAGE) {
136261b37794SIngo Weinhold 			#if __GNUC__ == 2
136361b37794SIngo Weinhold 				if (image->gcc_version.major > 2)
136461b37794SIngo Weinhold 					sSearchPathSubDir = "gcc4";
136561b37794SIngo Weinhold 			#elif __GNUC__ == 4
136661b37794SIngo Weinhold 				if (image->gcc_version.major == 2)
136761b37794SIngo Weinhold 					sSearchPathSubDir = "gcc2";
136861b37794SIngo Weinhold 			#endif
136961b37794SIngo Weinhold 		}
137061b37794SIngo Weinhold 	} else {
137134982809SIngo Weinhold 		FATAL("Failed to get gcc version for %s\n", path);
137234982809SIngo Weinhold 		// not really fatal, actually
137334982809SIngo Weinhold 	}
137434982809SIngo Weinhold 
13755fd6637bSIngo Weinhold 	// init gcc version dependent image flags
13765fd6637bSIngo Weinhold 	// symbol resolution strategy (fallback is R5-style, if version is
13775fd6637bSIngo Weinhold 	// unavailable)
13785fd6637bSIngo Weinhold 	if (image->gcc_version.major == 0
13795fd6637bSIngo Weinhold 		|| image->gcc_version.major == 2 && image->gcc_version.middle < 95) {
13805fd6637bSIngo Weinhold 		image->flags |= IMAGE_FLAG_R5_SYMBOL_RESOLUTION;
13815fd6637bSIngo Weinhold 	}
13825fd6637bSIngo Weinhold 
13830c0fea5dSIngo Weinhold 	status = map_image(fd, path, image, type == B_APP_IMAGE);
13840c0fea5dSIngo Weinhold 	if (status < B_OK) {
13850c0fea5dSIngo Weinhold 		FATAL("Could not map image: %s\n", strerror(status));
13860c0fea5dSIngo Weinhold 		status = B_ERROR;
13870c0fea5dSIngo Weinhold 		goto err2;
13880c0fea5dSIngo Weinhold 	}
13890c0fea5dSIngo Weinhold 
13900c0fea5dSIngo Weinhold 	if (!parse_dynamic_segment(image)) {
13910c0fea5dSIngo Weinhold 		FATAL("Troubles handling dynamic section\n");
13920c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
13930c0fea5dSIngo Weinhold 		goto err3;
13940c0fea5dSIngo Weinhold 	}
13950c0fea5dSIngo Weinhold 
1396dd76bc97SIngo Weinhold 	if (eheader.e_entry != 0)
13970c0fea5dSIngo Weinhold 		image->entry_point = eheader.e_entry + image->regions[0].delta;
13980c0fea5dSIngo Weinhold 
13990c0fea5dSIngo Weinhold 	image->type = type;
14000c0fea5dSIngo Weinhold 	register_image(image, fd, path);
14010c0fea5dSIngo Weinhold 
14020c0fea5dSIngo Weinhold 	_kern_close(fd);
14030c0fea5dSIngo Weinhold 
14040c0fea5dSIngo Weinhold 	enqueue_image(&sLoadedImages, image);
14050c0fea5dSIngo Weinhold 	sLoadedImageCount++;
14060c0fea5dSIngo Weinhold 
14070c0fea5dSIngo Weinhold 	*_image = image;
14087486b72dSIngo Weinhold 
140934982809SIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): done: id: %ld (gcc: %d.%d.%d)", name,
141034982809SIngo Weinhold 		image->id, image->gcc_version.major, image->gcc_version.middle,
141134982809SIngo Weinhold 		image->gcc_version.minor);
14127486b72dSIngo Weinhold 
14130c0fea5dSIngo Weinhold 	return B_OK;
14140c0fea5dSIngo Weinhold 
14150c0fea5dSIngo Weinhold err3:
14160c0fea5dSIngo Weinhold 	unmap_image(image);
14170c0fea5dSIngo Weinhold err2:
14180c0fea5dSIngo Weinhold 	delete_image_struct(image);
14190c0fea5dSIngo Weinhold err1:
14200c0fea5dSIngo Weinhold 	_kern_close(fd);
14217486b72dSIngo Weinhold 
14227486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): failed: %s", name,
14237486b72dSIngo Weinhold 		strerror(status));
14247486b72dSIngo Weinhold 
14250c0fea5dSIngo Weinhold 	return status;
14260c0fea5dSIngo Weinhold }
14270c0fea5dSIngo Weinhold 
14280c0fea5dSIngo Weinhold 
14290c0fea5dSIngo Weinhold static const char *
14300c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
14310c0fea5dSIngo Weinhold {
14320c0fea5dSIngo Weinhold 	int i;
14330c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
14340c0fea5dSIngo Weinhold 
14350c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
14360c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
14370c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
14380c0fea5dSIngo Weinhold 	}
14390c0fea5dSIngo Weinhold 
14400c0fea5dSIngo Weinhold 	return NULL;
14410c0fea5dSIngo Weinhold }
14420c0fea5dSIngo Weinhold 
14430c0fea5dSIngo Weinhold 
14440c0fea5dSIngo Weinhold static status_t
14450c0fea5dSIngo Weinhold load_dependencies(image_t *image)
14460c0fea5dSIngo Weinhold {
14470c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
14484bef3723SAxel Dörfler 	bool reportErrors = report_errors();
144974c0424aSAxel Dörfler 	status_t status = B_OK;
14500c0fea5dSIngo Weinhold 	uint32 i, j;
14510c0fea5dSIngo Weinhold 	const char *rpath;
14520c0fea5dSIngo Weinhold 
14530c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
14540c0fea5dSIngo Weinhold 		return B_OK;
14550c0fea5dSIngo Weinhold 
14560c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
14570c0fea5dSIngo Weinhold 
14580c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
14590c0fea5dSIngo Weinhold 		return B_OK;
14600c0fea5dSIngo Weinhold 
14617486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
14627486b72dSIngo Weinhold 		image->id);
14637486b72dSIngo Weinhold 
14640c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
14650c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
14660c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
14677486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
14687486b72dSIngo Weinhold 			image->name, image->id);
14690c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
14700c0fea5dSIngo Weinhold 	}
14710c0fea5dSIngo Weinhold 
14720c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
14730c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
14740c0fea5dSIngo Weinhold 
14750c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
14760c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
14770c0fea5dSIngo Weinhold 			case DT_NEEDED:
147874c0424aSAxel Dörfler 			{
147974c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
148074c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
14810c0fea5dSIngo Weinhold 
148274c0424aSAxel Dörfler 				status_t loadStatus = load_container(name, B_LIBRARY_IMAGE,
148374c0424aSAxel Dörfler 					rpath, &image->needed[j]);
148474c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
148574c0424aSAxel Dörfler 					status = loadStatus;
148674c0424aSAxel Dörfler 					// correct error code in case the file could not been found
148774c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
148874c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
148974c0424aSAxel Dörfler 
149074c0424aSAxel Dörfler 						if (reportErrors)
149174c0424aSAxel Dörfler 							sErrorMessage.AddString("missing library", name);
149274c0424aSAxel Dörfler 					}
149374c0424aSAxel Dörfler 
149474c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
14957486b72dSIngo Weinhold 					if (!reportErrors) {
14967486b72dSIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
14977486b72dSIngo Weinhold 							"failed: %s", image->name, image->id,
14987486b72dSIngo Weinhold 							strerror(status));
14990c0fea5dSIngo Weinhold 						return status;
150074c0424aSAxel Dörfler 					}
15017486b72dSIngo Weinhold 				}
15020c0fea5dSIngo Weinhold 
15030c0fea5dSIngo Weinhold 				j += 1;
15040c0fea5dSIngo Weinhold 				break;
150574c0424aSAxel Dörfler 			}
15060c0fea5dSIngo Weinhold 
15070c0fea5dSIngo Weinhold 			default:
15080c0fea5dSIngo Weinhold 				// ignore any other tag
15090c0fea5dSIngo Weinhold 				continue;
15100c0fea5dSIngo Weinhold 		}
15110c0fea5dSIngo Weinhold 	}
15120c0fea5dSIngo Weinhold 
15137486b72dSIngo Weinhold 	if (status < B_OK) {
15147486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
15157486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
15167486b72dSIngo Weinhold 			strerror(status));
151774c0424aSAxel Dörfler 		return status;
15187486b72dSIngo Weinhold 	}
151974c0424aSAxel Dörfler 
15200c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
15210c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
15227486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
15237486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
15240c0fea5dSIngo Weinhold 		return B_ERROR;
15250c0fea5dSIngo Weinhold 	}
15260c0fea5dSIngo Weinhold 
15277486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
15287486b72dSIngo Weinhold 		image->id);
15297486b72dSIngo Weinhold 
15300c0fea5dSIngo Weinhold 	return B_OK;
15310c0fea5dSIngo Weinhold }
15320c0fea5dSIngo Weinhold 
15330c0fea5dSIngo Weinhold 
15340c0fea5dSIngo Weinhold static uint32
15350c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList,
15360c0fea5dSIngo Weinhold 	uint32 sortFlag)
15370c0fea5dSIngo Weinhold {
15380c0fea5dSIngo Weinhold 	uint32 i;
15390c0fea5dSIngo Weinhold 
15400c0fea5dSIngo Weinhold 	if (image->flags & sortFlag)
15410c0fea5dSIngo Weinhold 		return slot;
15420c0fea5dSIngo Weinhold 
15430c0fea5dSIngo Weinhold 	image->flags |= sortFlag; /* make sure we don't visit this one */
15440c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_needed; i++)
15450c0fea5dSIngo Weinhold 		slot = topological_sort(image->needed[i], slot, initList, sortFlag);
15460c0fea5dSIngo Weinhold 
15470c0fea5dSIngo Weinhold 	initList[slot] = image;
15480c0fea5dSIngo Weinhold 	return slot + 1;
15490c0fea5dSIngo Weinhold }
15500c0fea5dSIngo Weinhold 
15510c0fea5dSIngo Weinhold 
15520c0fea5dSIngo Weinhold static ssize_t
15530c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
15540c0fea5dSIngo Weinhold {
15550c0fea5dSIngo Weinhold 	image_t **list;
15560c0fea5dSIngo Weinhold 
15570c0fea5dSIngo Weinhold 	list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *));
15580c0fea5dSIngo Weinhold 	if (list == NULL) {
15590c0fea5dSIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
15600c0fea5dSIngo Weinhold 		*_list = NULL;
15610c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
15620c0fea5dSIngo Weinhold 	}
15630c0fea5dSIngo Weinhold 
15640c0fea5dSIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
15650c0fea5dSIngo Weinhold 
15660c0fea5dSIngo Weinhold 	*_list = list;
15670c0fea5dSIngo Weinhold 	return topological_sort(image, 0, list, sortFlag);
15680c0fea5dSIngo Weinhold }
15690c0fea5dSIngo Weinhold 
15700c0fea5dSIngo Weinhold 
15710c0fea5dSIngo Weinhold static status_t
15720c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
15730c0fea5dSIngo Weinhold {
15740c0fea5dSIngo Weinhold 	ssize_t count, i;
15750c0fea5dSIngo Weinhold 	image_t **list;
15760c0fea5dSIngo Weinhold 
15770c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
15780c0fea5dSIngo Weinhold 	if (count < B_OK)
15790c0fea5dSIngo Weinhold 		return count;
15800c0fea5dSIngo Weinhold 
15810c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
158246f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
15830c0fea5dSIngo Weinhold 		if (status < B_OK)
15840c0fea5dSIngo Weinhold 			return status;
15850c0fea5dSIngo Weinhold 	}
15860c0fea5dSIngo Weinhold 
15870c0fea5dSIngo Weinhold 	free(list);
15880c0fea5dSIngo Weinhold 	return B_OK;
15890c0fea5dSIngo Weinhold }
15900c0fea5dSIngo Weinhold 
15910c0fea5dSIngo Weinhold 
15920c0fea5dSIngo Weinhold static void
15930c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
15940c0fea5dSIngo Weinhold {
15950c0fea5dSIngo Weinhold 	image_t **initList;
15960c0fea5dSIngo Weinhold 	ssize_t count, i;
15970c0fea5dSIngo Weinhold 
15980c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
15990c0fea5dSIngo Weinhold 	if (count <= 0)
16000c0fea5dSIngo Weinhold 		return;
16010c0fea5dSIngo Weinhold 
16020c0fea5dSIngo Weinhold 	if (!initHead) {
16030c0fea5dSIngo Weinhold 		// this removes the "calling" image
16040c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
16050c0fea5dSIngo Weinhold 		initList[--count] = NULL;
16060c0fea5dSIngo Weinhold 	}
16070c0fea5dSIngo Weinhold 
16080c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
16090c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
16100c0fea5dSIngo Weinhold 		image = initList[i];
16110c0fea5dSIngo Weinhold 
16120c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
16130c0fea5dSIngo Weinhold 
1614dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
16150c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
16160c0fea5dSIngo Weinhold 	}
16170c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
16180c0fea5dSIngo Weinhold 
16190c0fea5dSIngo Weinhold 	free(initList);
16200c0fea5dSIngo Weinhold }
16210c0fea5dSIngo Weinhold 
16220c0fea5dSIngo Weinhold 
16230c0fea5dSIngo Weinhold static void
16240c0fea5dSIngo Weinhold put_image(image_t *image)
16250c0fea5dSIngo Weinhold {
16260c0fea5dSIngo Weinhold 	// If all references to the image are gone, add it to the disposable list
16270c0fea5dSIngo Weinhold 	// and remove all dependencies
16280c0fea5dSIngo Weinhold 
16290c0fea5dSIngo Weinhold 	if (atomic_add(&image->ref_count, -1) == 1) {
16300c0fea5dSIngo Weinhold 		size_t i;
16310c0fea5dSIngo Weinhold 
16320c0fea5dSIngo Weinhold 		dequeue_image(&sLoadedImages, image);
16330c0fea5dSIngo Weinhold 		enqueue_image(&sDisposableImages, image);
16340c0fea5dSIngo Weinhold 		sLoadedImageCount--;
16350c0fea5dSIngo Weinhold 
16360c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_needed; i++) {
16370c0fea5dSIngo Weinhold 			put_image(image->needed[i]);
16380c0fea5dSIngo Weinhold 		}
16390c0fea5dSIngo Weinhold 	}
16400c0fea5dSIngo Weinhold }
16410c0fea5dSIngo Weinhold 
16420c0fea5dSIngo Weinhold 
164374c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
16440c0fea5dSIngo Weinhold 
16450c0fea5dSIngo Weinhold 
16460c0fea5dSIngo Weinhold image_id
16470c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
16480c0fea5dSIngo Weinhold {
16490c0fea5dSIngo Weinhold 	status_t status;
16500c0fea5dSIngo Weinhold 	image_t *image;
16510c0fea5dSIngo Weinhold 
16527486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
16537486b72dSIngo Weinhold 
16540c0fea5dSIngo Weinhold 	rld_lock();
16550c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
16560c0fea5dSIngo Weinhold 
16570c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
16580c0fea5dSIngo Weinhold 
16590c0fea5dSIngo Weinhold 	status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage);
166074c0424aSAxel Dörfler 	if (status < B_OK)
166174c0424aSAxel Dörfler 		goto err;
16620c0fea5dSIngo Weinhold 
16630c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
16640c0fea5dSIngo Weinhold 		status = load_dependencies(image);
16650c0fea5dSIngo Weinhold 		if (status < B_OK)
16660c0fea5dSIngo Weinhold 			goto err;
16670c0fea5dSIngo Weinhold 	}
16680c0fea5dSIngo Weinhold 
16690c0fea5dSIngo Weinhold 	status = relocate_dependencies(sProgramImage);
16700c0fea5dSIngo Weinhold 	if (status < B_OK)
16710c0fea5dSIngo Weinhold 		goto err;
16720c0fea5dSIngo Weinhold 
16730c0fea5dSIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private API
16740c0fea5dSIngo Weinhold 	{
167546f4d849SIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_loaded_images(
167646f4d849SIngo Weinhold 			"__gRuntimeLoader", &image);
16770c0fea5dSIngo Weinhold 		if (symbol != NULL) {
16780c0fea5dSIngo Weinhold 			void **_export = (void **)(symbol->st_value + image->regions[0].delta);
16790c0fea5dSIngo Weinhold 			*_export = &gRuntimeLoader;
16800c0fea5dSIngo Weinhold 		}
16810c0fea5dSIngo Weinhold 	}
16820c0fea5dSIngo Weinhold 
16830c0fea5dSIngo Weinhold 	init_dependencies(sLoadedImages.head, true);
16840c0fea5dSIngo Weinhold 	remap_images();
16850c0fea5dSIngo Weinhold 		// ToDo: once setup_system_time() is fixed, move this one line higher!
16860c0fea5dSIngo Weinhold 
16870c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
16880c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
16890c0fea5dSIngo Weinhold 	{
169046f4d849SIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_loaded_images("getenv",
169146f4d849SIngo Weinhold 			&image);
16920c0fea5dSIngo Weinhold 		if (symbol != NULL)
16930c0fea5dSIngo Weinhold 			gGetEnv = (char* (*)(const char*))
16940c0fea5dSIngo Weinhold 				(symbol->st_value + image->regions[0].delta);
16950c0fea5dSIngo Weinhold 	}
16960c0fea5dSIngo Weinhold 
1697dd76bc97SIngo Weinhold 	if (sProgramImage->entry_point == 0) {
16980c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
16990c0fea5dSIngo Weinhold 		goto err;
17000c0fea5dSIngo Weinhold 	}
17010c0fea5dSIngo Weinhold 
17020c0fea5dSIngo Weinhold 	*_entry = (void *)(sProgramImage->entry_point);
17030c0fea5dSIngo Weinhold 
17040c0fea5dSIngo Weinhold 	rld_unlock();
17057486b72dSIngo Weinhold 
17065d0638bfSIngo Weinhold 	sProgramLoaded = true;
17075d0638bfSIngo Weinhold 
17087486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
17097486b72dSIngo Weinhold 		*_entry, sProgramImage->id);
17107486b72dSIngo Weinhold 
17110c0fea5dSIngo Weinhold 	return sProgramImage->id;
17120c0fea5dSIngo Weinhold 
17130c0fea5dSIngo Weinhold err:
17147486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
17157486b72dSIngo Weinhold 
17160c0fea5dSIngo Weinhold 	delete_image(sProgramImage);
171774c0424aSAxel Dörfler 
17184bef3723SAxel Dörfler 	if (report_errors()) {
17194bef3723SAxel Dörfler 		// send error message
172074c0424aSAxel Dörfler 		sErrorMessage.AddInt32("error", status);
17214bef3723SAxel Dörfler 		sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
17224bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
17234bef3723SAxel Dörfler 
17244bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
17254bef3723SAxel Dörfler 			sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0);
172674c0424aSAxel Dörfler 	}
172774c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
17280c0fea5dSIngo Weinhold 	rld_unlock();
172974c0424aSAxel Dörfler 
17300c0fea5dSIngo Weinhold 	return status;
17310c0fea5dSIngo Weinhold }
17320c0fea5dSIngo Weinhold 
17330c0fea5dSIngo Weinhold 
17340c0fea5dSIngo Weinhold image_id
17350c0fea5dSIngo Weinhold load_library(char const *path, uint32 flags, bool addOn)
17360c0fea5dSIngo Weinhold {
17370c0fea5dSIngo Weinhold 	image_t *image = NULL;
17380c0fea5dSIngo Weinhold 	image_t *iter;
17390c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
17400c0fea5dSIngo Weinhold 	status_t status;
17410c0fea5dSIngo Weinhold 
17420c0fea5dSIngo Weinhold 	if (path == NULL)
17430c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
17440c0fea5dSIngo Weinhold 
17450c0fea5dSIngo Weinhold 	// ToDo: implement flags
17460c0fea5dSIngo Weinhold 	(void)flags;
17470c0fea5dSIngo Weinhold 
17487486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
17497486b72dSIngo Weinhold 
17500c0fea5dSIngo Weinhold 	rld_lock();
17510c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
17520c0fea5dSIngo Weinhold 
17530c0fea5dSIngo Weinhold 	// have we already loaded this library?
17540c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
17550c0fea5dSIngo Weinhold 	if (!addOn) {
17560c0fea5dSIngo Weinhold 		image = find_image(path, APP_OR_LIBRARY_TYPE);
17570c0fea5dSIngo Weinhold 		if (image) {
17580c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
17590c0fea5dSIngo Weinhold 			rld_unlock();
17607486b72dSIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
17617486b72dSIngo Weinhold 				image->id);
17620c0fea5dSIngo Weinhold 			return image->id;
17630c0fea5dSIngo Weinhold 		}
17640c0fea5dSIngo Weinhold 	}
17650c0fea5dSIngo Weinhold 
17660c0fea5dSIngo Weinhold 	status = load_container(path, type, NULL, &image);
17670c0fea5dSIngo Weinhold 	if (status < B_OK) {
17680c0fea5dSIngo Weinhold 		rld_unlock();
17697486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
17707486b72dSIngo Weinhold 			strerror(status));
17710c0fea5dSIngo Weinhold 		return status;
17720c0fea5dSIngo Weinhold 	}
17730c0fea5dSIngo Weinhold 
17740c0fea5dSIngo Weinhold 	for (iter = sLoadedImages.head; iter; iter = iter->next) {
17750c0fea5dSIngo Weinhold 		status = load_dependencies(iter);
17760c0fea5dSIngo Weinhold 		if (status < B_OK)
17770c0fea5dSIngo Weinhold 			goto err;
17780c0fea5dSIngo Weinhold 	}
17790c0fea5dSIngo Weinhold 
17800c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
17810c0fea5dSIngo Weinhold 	if (status < B_OK)
17820c0fea5dSIngo Weinhold 		goto err;
17830c0fea5dSIngo Weinhold 
17840c0fea5dSIngo Weinhold 	remap_images();
17850c0fea5dSIngo Weinhold 	init_dependencies(image, true);
17860c0fea5dSIngo Weinhold 
17870c0fea5dSIngo Weinhold 	rld_unlock();
17887486b72dSIngo Weinhold 
17897486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
17907486b72dSIngo Weinhold 
17910c0fea5dSIngo Weinhold 	return image->id;
17920c0fea5dSIngo Weinhold 
17930c0fea5dSIngo Weinhold err:
17947486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
17957486b72dSIngo Weinhold 
17960c0fea5dSIngo Weinhold 	dequeue_image(&sLoadedImages, image);
17970c0fea5dSIngo Weinhold 	sLoadedImageCount--;
17980c0fea5dSIngo Weinhold 	delete_image(image);
17990c0fea5dSIngo Weinhold 	rld_unlock();
18000c0fea5dSIngo Weinhold 	return status;
18010c0fea5dSIngo Weinhold }
18020c0fea5dSIngo Weinhold 
18030c0fea5dSIngo Weinhold 
18040c0fea5dSIngo Weinhold status_t
18050c0fea5dSIngo Weinhold unload_library(image_id imageID, bool addOn)
18060c0fea5dSIngo Weinhold {
18070c0fea5dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
18080c0fea5dSIngo Weinhold 	image_t *image;
18090c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
18100c0fea5dSIngo Weinhold 
18110c0fea5dSIngo Weinhold 	if (imageID < B_OK)
18120c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
18130c0fea5dSIngo Weinhold 
18140c0fea5dSIngo Weinhold 	rld_lock();
18150c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
18160c0fea5dSIngo Weinhold 
18179a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
18189a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
18199a6072a3SAxel Dörfler 		update_image_ids();
18209a6072a3SAxel Dörfler 	}
18219a6072a3SAxel Dörfler 
18220c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
18230c0fea5dSIngo Weinhold 
18240c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
18250c0fea5dSIngo Weinhold 		if (image->id == imageID) {
18260c0fea5dSIngo Weinhold 			// unload image
18270c0fea5dSIngo Weinhold 			if (type == image->type) {
18280c0fea5dSIngo Weinhold 				put_image(image);
18290c0fea5dSIngo Weinhold 				status = B_OK;
18300c0fea5dSIngo Weinhold 			} else
18310c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
18320c0fea5dSIngo Weinhold 			break;
18330c0fea5dSIngo Weinhold 		}
18340c0fea5dSIngo Weinhold 	}
18350c0fea5dSIngo Weinhold 
18360c0fea5dSIngo Weinhold 	if (status == B_OK) {
18370c0fea5dSIngo Weinhold 		while ((image = sDisposableImages.head) != NULL) {
18380c0fea5dSIngo Weinhold 			// call image fini here...
18398c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
18408c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
18413be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
18428c2a9d74SMichael Lotz 			}
18438c2a9d74SMichael Lotz 
18440c0fea5dSIngo Weinhold 			if (image->term_routine)
18450c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
18460c0fea5dSIngo Weinhold 
18470c0fea5dSIngo Weinhold 			dequeue_image(&sDisposableImages, image);
18480c0fea5dSIngo Weinhold 			unmap_image(image);
18490c0fea5dSIngo Weinhold 
18500c0fea5dSIngo Weinhold 			delete_image(image);
18510c0fea5dSIngo Weinhold 		}
18520c0fea5dSIngo Weinhold 	}
18530c0fea5dSIngo Weinhold 
18540c0fea5dSIngo Weinhold 	rld_unlock();
18550c0fea5dSIngo Weinhold 	return status;
18560c0fea5dSIngo Weinhold }
18570c0fea5dSIngo Weinhold 
18580c0fea5dSIngo Weinhold 
18590c0fea5dSIngo Weinhold status_t
18609a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
18619a6072a3SAxel Dörfler 	int32 *_nameLength, int32 *_type, void **_location)
18620c0fea5dSIngo Weinhold {
18630c0fea5dSIngo Weinhold 	int32 count = 0, j;
18640c0fea5dSIngo Weinhold 	uint32 i;
18650c0fea5dSIngo Weinhold 	image_t *image;
18660c0fea5dSIngo Weinhold 
18670c0fea5dSIngo Weinhold 	rld_lock();
18680c0fea5dSIngo Weinhold 
18690c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
18700c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
18710c0fea5dSIngo Weinhold 	if (image == NULL) {
18720c0fea5dSIngo Weinhold 		rld_unlock();
18730c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
18740c0fea5dSIngo Weinhold 	}
18750c0fea5dSIngo Weinhold 
18760c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
18770c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
18780c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
18790555803aSAxel Dörfler 			struct Elf32_Sym *symbol = &image->syms[j];
18800c0fea5dSIngo Weinhold 
18810c0fea5dSIngo Weinhold 			if (count == num) {
18820c0fea5dSIngo Weinhold 				strlcpy(nameBuffer, SYMNAME(image, symbol), *_nameLength);
18830c0fea5dSIngo Weinhold 				*_nameLength = strlen(SYMNAME(image, symbol));
18840c0fea5dSIngo Weinhold 
18850c0fea5dSIngo Weinhold 				if (_type != NULL) {
18860c0fea5dSIngo Weinhold 					// ToDo: check with the return types of that BeOS function
18870c0fea5dSIngo Weinhold 					if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
18880c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_TEXT;
18890c0fea5dSIngo Weinhold 					else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
18900c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_DATA;
18910c0fea5dSIngo Weinhold 					else
18920c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_ANY;
18930c0fea5dSIngo Weinhold 				}
18940c0fea5dSIngo Weinhold 
18950c0fea5dSIngo Weinhold 				if (_location != NULL)
18960c0fea5dSIngo Weinhold 					*_location = (void *)(symbol->st_value + image->regions[0].delta);
18970c0fea5dSIngo Weinhold 				goto out;
18980c0fea5dSIngo Weinhold 			}
18990c0fea5dSIngo Weinhold 			count++;
19000c0fea5dSIngo Weinhold 		}
19010c0fea5dSIngo Weinhold 	}
19020c0fea5dSIngo Weinhold out:
19030c0fea5dSIngo Weinhold 	rld_unlock();
19040c0fea5dSIngo Weinhold 
19050c0fea5dSIngo Weinhold 	if (num != count)
19060c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
19070c0fea5dSIngo Weinhold 
19080c0fea5dSIngo Weinhold 	return B_OK;
19090c0fea5dSIngo Weinhold }
19100c0fea5dSIngo Weinhold 
19110c0fea5dSIngo Weinhold 
19120c0fea5dSIngo Weinhold status_t
19139a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
19149a6072a3SAxel Dörfler 	void **_location)
19150c0fea5dSIngo Weinhold {
19160c0fea5dSIngo Weinhold 	status_t status = B_OK;
19170c0fea5dSIngo Weinhold 	image_t *image;
19180c0fea5dSIngo Weinhold 
19190c0fea5dSIngo Weinhold 	if (imageID < B_OK)
19200c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
19210c0fea5dSIngo Weinhold 	if (symbolName == NULL)
19220c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
19230c0fea5dSIngo Weinhold 
19240c0fea5dSIngo Weinhold 	rld_lock();
19250c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
19260c0fea5dSIngo Weinhold 
19270c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
19280c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
19290c0fea5dSIngo Weinhold 	if (image != NULL) {
19300c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol;
19310c0fea5dSIngo Weinhold 
19320c0fea5dSIngo Weinhold 		// get the symbol in the image
19330c0fea5dSIngo Weinhold 		symbol = find_symbol(image, symbolName, symbolType);
19340c0fea5dSIngo Weinhold 		if (symbol) {
19350c0fea5dSIngo Weinhold 			if (_location != NULL)
19360c0fea5dSIngo Weinhold 				*_location = (void *)(symbol->st_value + image->regions[0].delta);
19370c0fea5dSIngo Weinhold 		} else
19380c0fea5dSIngo Weinhold 			status = B_ENTRY_NOT_FOUND;
19390c0fea5dSIngo Weinhold 	} else
19400c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
19410c0fea5dSIngo Weinhold 
19420c0fea5dSIngo Weinhold 	rld_unlock();
19430c0fea5dSIngo Weinhold 	return status;
19440c0fea5dSIngo Weinhold }
19450c0fea5dSIngo Weinhold 
19460c0fea5dSIngo Weinhold 
19470c0fea5dSIngo Weinhold status_t
19480c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
19490c0fea5dSIngo Weinhold {
19500c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
19510c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
19520c0fea5dSIngo Weinhold 	image_t *image;
19530c0fea5dSIngo Weinhold 
19540c0fea5dSIngo Weinhold 	if (_name == NULL)
19550c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
19560c0fea5dSIngo Weinhold 
19570c0fea5dSIngo Weinhold 	rld_lock();
19580c0fea5dSIngo Weinhold 
19590c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(id);
19600c0fea5dSIngo Weinhold 	if (image == NULL) {
19610c0fea5dSIngo Weinhold 		rld_unlock();
19620c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
19630c0fea5dSIngo Weinhold 	}
19640c0fea5dSIngo Weinhold 
19650c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
19660c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
19670c0fea5dSIngo Weinhold 		rld_unlock();
19680c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
19690c0fea5dSIngo Weinhold 	}
19700c0fea5dSIngo Weinhold 
19710c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
19720c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
19730c0fea5dSIngo Weinhold 			continue;
19740c0fea5dSIngo Weinhold 
19750c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
19760c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
19770c0fea5dSIngo Weinhold 
19780c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
19790c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
19800c0fea5dSIngo Weinhold 			rld_unlock();
19810c0fea5dSIngo Weinhold 			return B_OK;
19820c0fea5dSIngo Weinhold 		}
19830c0fea5dSIngo Weinhold 	}
19840c0fea5dSIngo Weinhold 
19850c0fea5dSIngo Weinhold 	rld_unlock();
19860c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
19870c0fea5dSIngo Weinhold }
19880c0fea5dSIngo Weinhold 
19890c0fea5dSIngo Weinhold 
199074c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
19910c0fea5dSIngo Weinhold 
19920c0fea5dSIngo Weinhold 
19939a6072a3SAxel Dörfler /*! Read and verify the ELF header */
19940c0fea5dSIngo Weinhold status_t
19950c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
19960c0fea5dSIngo Weinhold {
19970c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
19980c0fea5dSIngo Weinhold 
19990c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
20000c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
20010c0fea5dSIngo Weinhold 
20029a6072a3SAxel Dörfler 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize,
20039a6072a3SAxel Dörfler 		&sectionSize);
20040c0fea5dSIngo Weinhold }
20050c0fea5dSIngo Weinhold 
20060c0fea5dSIngo Weinhold 
20070c0fea5dSIngo Weinhold void
20080c0fea5dSIngo Weinhold terminate_program(void)
20090c0fea5dSIngo Weinhold {
20100c0fea5dSIngo Weinhold 	image_t **termList;
20110c0fea5dSIngo Weinhold 	ssize_t count, i;
20120c0fea5dSIngo Weinhold 
20130c0fea5dSIngo Weinhold 	count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED);
20140c0fea5dSIngo Weinhold 	if (count < B_OK)
20150c0fea5dSIngo Weinhold 		return;
20160c0fea5dSIngo Weinhold 
20179a6072a3SAxel Dörfler 	if (sInvalidImageIDs) {
20189a6072a3SAxel Dörfler 		// After fork, we lazily rebuild the image IDs of all loaded images
20199a6072a3SAxel Dörfler 		update_image_ids();
20209a6072a3SAxel Dörfler 	}
20219a6072a3SAxel Dörfler 
20220c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
20230c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
20240c0fea5dSIngo Weinhold 		image_t *image = termList[i];
20250c0fea5dSIngo Weinhold 
20260c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
20270c0fea5dSIngo Weinhold 
20280c0fea5dSIngo Weinhold 		if (image->term_routine)
20290c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
20300c0fea5dSIngo Weinhold 	}
20310c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
20320c0fea5dSIngo Weinhold 
20330c0fea5dSIngo Weinhold 	free(termList);
20340c0fea5dSIngo Weinhold }
20350c0fea5dSIngo Weinhold 
20360c0fea5dSIngo Weinhold 
20370c0fea5dSIngo Weinhold void
20380c0fea5dSIngo Weinhold rldelf_init(void)
20390c0fea5dSIngo Weinhold {
2040e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
2041e73923b0SAxel Dörfler 	sSemOwner = -1;
2042e73923b0SAxel Dörfler 	sSemCount = 0;
20430c0fea5dSIngo Weinhold 
20440c0fea5dSIngo Weinhold 	// create the debug area
20450c0fea5dSIngo Weinhold 	{
20460c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
20470c0fea5dSIngo Weinhold 
20480c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
20490c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
20500c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
20510c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
20520c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
20530c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
20540c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
20550c0fea5dSIngo Weinhold 		}
20560c0fea5dSIngo Weinhold 
20570c0fea5dSIngo Weinhold 		area->loaded_images = &sLoadedImages;
20580c0fea5dSIngo Weinhold 	}
205974c0424aSAxel Dörfler 
206074c0424aSAxel Dörfler 	// initialize error message if needed
20614bef3723SAxel Dörfler 	if (report_errors()) {
206274c0424aSAxel Dörfler 		void *buffer = malloc(1024);
206374c0424aSAxel Dörfler 		if (buffer == NULL)
206474c0424aSAxel Dörfler 			return;
206574c0424aSAxel Dörfler 
206674c0424aSAxel Dörfler 		sErrorMessage.SetTo(buffer, 1024, 'Rler');
206774c0424aSAxel Dörfler 	}
20680c0fea5dSIngo Weinhold }
20691873b4b3SIngo Weinhold 
20701873b4b3SIngo Weinhold 
20711873b4b3SIngo Weinhold status_t
20729a6072a3SAxel Dörfler elf_reinit_after_fork(void)
20731873b4b3SIngo Weinhold {
2074e73923b0SAxel Dörfler 	sSem = create_sem(1, "runtime loader");
2075e73923b0SAxel Dörfler 	if (sSem < 0)
2076e73923b0SAxel Dörfler 		return sSem;
20771873b4b3SIngo Weinhold 
20789a6072a3SAxel Dörfler 	// We also need to update the IDs of our images. We are the child and
2079cbc456deSIngo Weinhold 	// and have cloned images with different IDs. Since in most cases (fork()
2080cbc456deSIngo Weinhold 	// + exec*()) this would just increase the fork() overhead with no one
20819a6072a3SAxel Dörfler 	// caring, we do that lazily, when first doing something different.
20829a6072a3SAxel Dörfler 	sInvalidImageIDs = true;
2083cbc456deSIngo Weinhold 
20841873b4b3SIngo Weinhold 	return B_OK;
20851873b4b3SIngo Weinhold }
2086