xref: /haiku/src/system/runtime_loader/elf.cpp (revision 8c2a9d743392241b067a471f7835a625b6a57dba)
10c0fea5dSIngo Weinhold /*
20c0fea5dSIngo Weinhold  * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de.
30c0fea5dSIngo Weinhold  * Distributed under the terms of the MIT License.
40c0fea5dSIngo Weinhold  *
50c0fea5dSIngo Weinhold  * Copyright 2002, Manuel J. Petit. All rights reserved.
60c0fea5dSIngo Weinhold  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
70c0fea5dSIngo Weinhold  * Distributed under the terms of the NewOS License.
80c0fea5dSIngo Weinhold  */
90c0fea5dSIngo Weinhold 
100c0fea5dSIngo Weinhold 
110c0fea5dSIngo Weinhold #include "runtime_loader_private.h"
125aa7b7b6SMarcus Overhagen #include "vm.h"
130c0fea5dSIngo Weinhold 
140c0fea5dSIngo Weinhold #include <OS.h>
150c0fea5dSIngo Weinhold 
160c0fea5dSIngo Weinhold #include <elf32.h>
170c0fea5dSIngo Weinhold #include <user_runtime.h>
180c0fea5dSIngo Weinhold #include <syscalls.h>
190c0fea5dSIngo Weinhold #include <vm_types.h>
200c0fea5dSIngo Weinhold #include <arch/cpu.h>
210c0fea5dSIngo Weinhold #include <sem.h>
220c0fea5dSIngo Weinhold #include <runtime_loader.h>
230c0fea5dSIngo Weinhold 
240c0fea5dSIngo Weinhold #include <string.h>
250c0fea5dSIngo Weinhold #include <stdio.h>
260c0fea5dSIngo Weinhold #include <stdlib.h>
270c0fea5dSIngo Weinhold 
280c0fea5dSIngo Weinhold 
290c0fea5dSIngo Weinhold //#define TRACE_RLD
300c0fea5dSIngo Weinhold #ifdef TRACE_RLD
310c0fea5dSIngo Weinhold #	define TRACE(x) dprintf x
320c0fea5dSIngo Weinhold #else
330c0fea5dSIngo Weinhold #	define TRACE(x) ;
340c0fea5dSIngo Weinhold #endif
350c0fea5dSIngo Weinhold 
360c0fea5dSIngo Weinhold 
370c0fea5dSIngo Weinhold // ToDo: implement better locking strategy
380c0fea5dSIngo Weinhold // ToDo: implement lazy binding
390c0fea5dSIngo Weinhold 
400c0fea5dSIngo Weinhold #define	PAGE_MASK (B_PAGE_SIZE - 1)
410c0fea5dSIngo Weinhold 
420c0fea5dSIngo Weinhold #define	PAGE_OFFSET(x) ((x) & (PAGE_MASK))
430c0fea5dSIngo Weinhold #define	PAGE_BASE(x) ((x) & ~(PAGE_MASK))
440c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
450c0fea5dSIngo Weinhold 
460c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000
470c0fea5dSIngo Weinhold 	/* keep in sync with app ldscript */
480c0fea5dSIngo Weinhold 
490c0fea5dSIngo Weinhold enum {
500c0fea5dSIngo Weinhold 	RFLAG_RW					= 0x0001,
510c0fea5dSIngo Weinhold 	RFLAG_ANON					= 0x0002,
520c0fea5dSIngo Weinhold 
530c0fea5dSIngo Weinhold 	RFLAG_TERMINATED			= 0x0200,
540c0fea5dSIngo Weinhold 	RFLAG_INITIALIZED			= 0x0400,
550c0fea5dSIngo Weinhold 	RFLAG_SYMBOLIC				= 0x0800,
560c0fea5dSIngo Weinhold 	RFLAG_RELOCATED				= 0x1000,
570c0fea5dSIngo Weinhold 	RFLAG_PROTECTED				= 0x2000,
580c0fea5dSIngo Weinhold 	RFLAG_DEPENDENCIES_LOADED	= 0x4000,
5946f4d849SIngo Weinhold 	RFLAG_REMAPPED				= 0x8000,
6046f4d849SIngo Weinhold 
6146f4d849SIngo Weinhold 	RFLAG_VISITED				= 0x10000
6246f4d849SIngo Weinhold 		// temporarily set in the symbol resolution code
630c0fea5dSIngo Weinhold };
640c0fea5dSIngo Weinhold 
650c0fea5dSIngo Weinhold 
660c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type)	(1 << ((type) - 1))
670c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES				(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
680c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
690c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
700c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
710c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE			(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
720c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
730c0fea5dSIngo Weinhold 
740c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
750c0fea5dSIngo Weinhold 
760c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0};
770c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0};
780c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0;
790c0fea5dSIngo Weinhold static image_t *sProgramImage;
8074c0424aSAxel Dörfler static KMessage sErrorMessage;
810c0fea5dSIngo Weinhold 
8246f4d849SIngo Weinhold #ifdef BEOS_STYLE_SYMBOLS_RESOLUTION
8346f4d849SIngo Weinhold static bool sResolveSymbolsBeOSStyle = true;
8446f4d849SIngo Weinhold #else
8546f4d849SIngo Weinhold static bool sResolveSymbolsBeOSStyle = false;
8646f4d849SIngo Weinhold #endif
8746f4d849SIngo Weinhold 
880c0fea5dSIngo Weinhold // a recursive lock
890c0fea5dSIngo Weinhold static sem_id rld_sem;
900c0fea5dSIngo Weinhold static thread_id rld_sem_owner;
910c0fea5dSIngo Weinhold static int32 rld_sem_count;
920c0fea5dSIngo Weinhold 
930c0fea5dSIngo Weinhold 
940c0fea5dSIngo Weinhold #ifdef TRACE_RLD
950c0fea5dSIngo Weinhold #	define FATAL(x...) dprintf("runtime_loader: " x);
960c0fea5dSIngo Weinhold 
970c0fea5dSIngo Weinhold void
980c0fea5dSIngo Weinhold dprintf(const char *format, ...)
990c0fea5dSIngo Weinhold {
1000c0fea5dSIngo Weinhold 	char buffer[1024];
1010c0fea5dSIngo Weinhold 
1020c0fea5dSIngo Weinhold 	va_list list;
1030c0fea5dSIngo Weinhold 	va_start(list, format);
1040c0fea5dSIngo Weinhold 
1050c0fea5dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1060c0fea5dSIngo Weinhold 	_kern_debug_output(buffer);
1070c0fea5dSIngo Weinhold 
1080c0fea5dSIngo Weinhold 	va_end(list);
1090c0fea5dSIngo Weinhold }
1100c0fea5dSIngo Weinhold #else
1110c0fea5dSIngo Weinhold #	define FATAL(x...) printf("runtime_loader: " x);
1120c0fea5dSIngo Weinhold #endif
1130c0fea5dSIngo Weinhold 
1140c0fea5dSIngo Weinhold 
1150c0fea5dSIngo Weinhold static void
1160c0fea5dSIngo Weinhold rld_unlock()
1170c0fea5dSIngo Weinhold {
1180c0fea5dSIngo Weinhold 	if (rld_sem_count-- == 1) {
1190c0fea5dSIngo Weinhold 		rld_sem_owner = -1;
1200c0fea5dSIngo Weinhold 		release_sem(rld_sem);
1210c0fea5dSIngo Weinhold 	}
1220c0fea5dSIngo Weinhold }
1230c0fea5dSIngo Weinhold 
1240c0fea5dSIngo Weinhold 
1250c0fea5dSIngo Weinhold static void
1260c0fea5dSIngo Weinhold rld_lock()
1270c0fea5dSIngo Weinhold {
1280c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
1290c0fea5dSIngo Weinhold 	if (self != rld_sem_owner) {
1300c0fea5dSIngo Weinhold 		acquire_sem(rld_sem);
1310c0fea5dSIngo Weinhold 		rld_sem_owner = self;
1320c0fea5dSIngo Weinhold 	}
1330c0fea5dSIngo Weinhold 	rld_sem_count++;
1340c0fea5dSIngo Weinhold }
1350c0fea5dSIngo Weinhold 
1360c0fea5dSIngo Weinhold 
1370c0fea5dSIngo Weinhold static void
1380c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image)
1390c0fea5dSIngo Weinhold {
1400c0fea5dSIngo Weinhold 	image->next = 0;
1410c0fea5dSIngo Weinhold 
1420c0fea5dSIngo Weinhold 	image->prev = queue->tail;
1430c0fea5dSIngo Weinhold 	if (queue->tail)
1440c0fea5dSIngo Weinhold 		queue->tail->next = image;
1450c0fea5dSIngo Weinhold 
1460c0fea5dSIngo Weinhold 	queue->tail = image;
1470c0fea5dSIngo Weinhold 	if (!queue->head)
1480c0fea5dSIngo Weinhold 		queue->head = image;
1490c0fea5dSIngo Weinhold }
1500c0fea5dSIngo Weinhold 
1510c0fea5dSIngo Weinhold 
1520c0fea5dSIngo Weinhold static void
1530c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image)
1540c0fea5dSIngo Weinhold {
1550c0fea5dSIngo Weinhold 	if (image->next)
1560c0fea5dSIngo Weinhold 		image->next->prev = image->prev;
1570c0fea5dSIngo Weinhold 	else
1580c0fea5dSIngo Weinhold 		queue->tail = image->prev;
1590c0fea5dSIngo Weinhold 
1600c0fea5dSIngo Weinhold 	if (image->prev)
1610c0fea5dSIngo Weinhold 		image->prev->next = image->next;
1620c0fea5dSIngo Weinhold 	else
1630c0fea5dSIngo Weinhold 		queue->head = image->next;
1640c0fea5dSIngo Weinhold 
1650c0fea5dSIngo Weinhold 	image->prev = 0;
1660c0fea5dSIngo Weinhold 	image->next = 0;
1670c0fea5dSIngo Weinhold }
1680c0fea5dSIngo Weinhold 
1690c0fea5dSIngo Weinhold 
1700c0fea5dSIngo Weinhold static uint32
1710c0fea5dSIngo Weinhold elf_hash(const uint8 *name)
1720c0fea5dSIngo Weinhold {
1730c0fea5dSIngo Weinhold 	uint32 hash = 0;
1740c0fea5dSIngo Weinhold 	uint32 temp;
1750c0fea5dSIngo Weinhold 
1760c0fea5dSIngo Weinhold 	while (*name) {
1770c0fea5dSIngo Weinhold 		hash = (hash << 4) + *name++;
1780c0fea5dSIngo Weinhold 		if ((temp = hash & 0xf0000000)) {
1790c0fea5dSIngo Weinhold 			hash ^= temp >> 24;
1800c0fea5dSIngo Weinhold 		}
1810c0fea5dSIngo Weinhold 		hash &= ~temp;
1820c0fea5dSIngo Weinhold 	}
1830c0fea5dSIngo Weinhold 	return hash;
1840c0fea5dSIngo Weinhold }
1850c0fea5dSIngo Weinhold 
1860c0fea5dSIngo Weinhold 
1874bef3723SAxel Dörfler static inline bool
1884bef3723SAxel Dörfler report_errors()
1894bef3723SAxel Dörfler {
1904bef3723SAxel Dörfler 	return gProgramArgs->error_port >= 0;
1914bef3723SAxel Dörfler }
1924bef3723SAxel Dörfler 
1934bef3723SAxel Dörfler 
1940c0fea5dSIngo Weinhold static image_t *
1950c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath,
1960c0fea5dSIngo Weinhold 	uint32 typeMask)
1970c0fea5dSIngo Weinhold {
1980c0fea5dSIngo Weinhold 	image_t *image;
1990c0fea5dSIngo Weinhold 
2000c0fea5dSIngo Weinhold 	for (image = queue->head; image; image = image->next) {
2010c0fea5dSIngo Weinhold 		const char *imageName = isPath ? image->path : image->name;
2020c0fea5dSIngo Weinhold 		int length = isPath ? sizeof(image->path) : sizeof(image->name);
2030c0fea5dSIngo Weinhold 
2040c0fea5dSIngo Weinhold 		if (!strncmp(imageName, name, length)
2050c0fea5dSIngo Weinhold 			&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
2060c0fea5dSIngo Weinhold 			return image;
2070c0fea5dSIngo Weinhold 		}
2080c0fea5dSIngo Weinhold 	}
2090c0fea5dSIngo Weinhold 
2100c0fea5dSIngo Weinhold 	return NULL;
2110c0fea5dSIngo Weinhold }
2120c0fea5dSIngo Weinhold 
2130c0fea5dSIngo Weinhold 
2140c0fea5dSIngo Weinhold static image_t *
2150c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask)
2160c0fea5dSIngo Weinhold {
2170c0fea5dSIngo Weinhold 	bool isPath = (strchr(name, '/') != NULL);
21846f4d849SIngo Weinhold 	return find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
2190c0fea5dSIngo Weinhold }
2200c0fea5dSIngo Weinhold 
2210c0fea5dSIngo Weinhold 
2220c0fea5dSIngo Weinhold static image_t *
2230c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id)
2240c0fea5dSIngo Weinhold {
2250c0fea5dSIngo Weinhold 	image_t *image;
2260c0fea5dSIngo Weinhold 
2270c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
2280c0fea5dSIngo Weinhold 		if (image->id == id)
2290c0fea5dSIngo Weinhold 			return image;
2300c0fea5dSIngo Weinhold 	}
2310c0fea5dSIngo Weinhold 
2320c0fea5dSIngo Weinhold 	// For the termination routine, we need to look into the list of
2330c0fea5dSIngo Weinhold 	// disposable images as well
2340c0fea5dSIngo Weinhold 	for (image = sDisposableImages.head; image; image = image->next) {
2350c0fea5dSIngo Weinhold 		if (image->id == id)
2360c0fea5dSIngo Weinhold 			return image;
2370c0fea5dSIngo Weinhold 	}
2380c0fea5dSIngo Weinhold 
2390c0fea5dSIngo Weinhold 	return NULL;
2400c0fea5dSIngo Weinhold }
2410c0fea5dSIngo Weinhold 
2420c0fea5dSIngo Weinhold 
2430c0fea5dSIngo Weinhold static status_t
2440c0fea5dSIngo Weinhold parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize, int32 *_sheaderSize)
2450c0fea5dSIngo Weinhold {
2460c0fea5dSIngo Weinhold 	if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
2470c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
2480c0fea5dSIngo Weinhold 
2490c0fea5dSIngo Weinhold 	if (eheader->e_ident[4] != ELFCLASS32)
2500c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
2510c0fea5dSIngo Weinhold 
2520c0fea5dSIngo Weinhold 	if (eheader->e_phoff == 0)
2530c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
2540c0fea5dSIngo Weinhold 
2550c0fea5dSIngo Weinhold 	if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
2560c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
2570c0fea5dSIngo Weinhold 
2580c0fea5dSIngo Weinhold 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
2590c0fea5dSIngo Weinhold 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
2600c0fea5dSIngo Weinhold 
2615aa7b7b6SMarcus Overhagen 	if (*_pheaderSize <= 0 || *_sheaderSize <= 0)
2625aa7b7b6SMarcus Overhagen 		return B_NOT_AN_EXECUTABLE;
2635aa7b7b6SMarcus Overhagen 
2645aa7b7b6SMarcus Overhagen 	return B_OK;
2650c0fea5dSIngo Weinhold }
2660c0fea5dSIngo Weinhold 
2670c0fea5dSIngo Weinhold 
2680c0fea5dSIngo Weinhold static int32
2690c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize)
2700c0fea5dSIngo Weinhold {
2710c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheaders;
2720c0fea5dSIngo Weinhold 	int32 count = 0;
2730c0fea5dSIngo Weinhold 	int i;
2740c0fea5dSIngo Weinhold 
2750c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
2760c0fea5dSIngo Weinhold 		pheaders = (struct Elf32_Phdr *)(buff + i * phentsize);
2770c0fea5dSIngo Weinhold 
2780c0fea5dSIngo Weinhold 		switch (pheaders->p_type) {
2790c0fea5dSIngo Weinhold 			case PT_NULL:
2800c0fea5dSIngo Weinhold 				/* NOP header */
2810c0fea5dSIngo Weinhold 				break;
2820c0fea5dSIngo Weinhold 			case PT_LOAD:
2830c0fea5dSIngo Weinhold 				count += 1;
2840c0fea5dSIngo Weinhold 				if (pheaders->p_memsz != pheaders->p_filesz) {
2850c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz);
2860c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz);
2870c0fea5dSIngo Weinhold 
2880c0fea5dSIngo Weinhold 					if (A != B)
2890c0fea5dSIngo Weinhold 						count += 1;
2900c0fea5dSIngo Weinhold 				}
2910c0fea5dSIngo Weinhold 				break;
2920c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
2930c0fea5dSIngo Weinhold 				/* will be handled at some other place */
2940c0fea5dSIngo Weinhold 				break;
2950c0fea5dSIngo Weinhold 			case PT_INTERP:
2960c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
2970c0fea5dSIngo Weinhold 				break;
2980c0fea5dSIngo Weinhold 			case PT_NOTE:
2990c0fea5dSIngo Weinhold 				/* unsupported */
3000c0fea5dSIngo Weinhold 				break;
3010c0fea5dSIngo Weinhold 			case PT_SHLIB:
3020c0fea5dSIngo Weinhold 				/* undefined semantics */
3030c0fea5dSIngo Weinhold 				break;
3040c0fea5dSIngo Weinhold 			case PT_PHDR:
3050c0fea5dSIngo Weinhold 				/* we don't use it */
3060c0fea5dSIngo Weinhold 				break;
3070c0fea5dSIngo Weinhold 			default:
3080c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type);
3090c0fea5dSIngo Weinhold 				return B_BAD_DATA;
3100c0fea5dSIngo Weinhold 		}
3110c0fea5dSIngo Weinhold 	}
3120c0fea5dSIngo Weinhold 
3130c0fea5dSIngo Weinhold 	return count;
3140c0fea5dSIngo Weinhold }
3150c0fea5dSIngo Weinhold 
3160c0fea5dSIngo Weinhold 
3170c0fea5dSIngo Weinhold /*
3180c0fea5dSIngo Weinhold  * create_image() & destroy_image()
3190c0fea5dSIngo Weinhold  *
3200c0fea5dSIngo Weinhold  * 	Create and destroy image_t structures. The destroyer makes sure that the
3210c0fea5dSIngo Weinhold  * 	memory buffers are full of garbage before freeing.
3220c0fea5dSIngo Weinhold  */
3230c0fea5dSIngo Weinhold 
3240c0fea5dSIngo Weinhold static image_t *
3250c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions)
3260c0fea5dSIngo Weinhold {
3270c0fea5dSIngo Weinhold 	size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t);
3280c0fea5dSIngo Weinhold 	const char *lastSlash;
3290c0fea5dSIngo Weinhold 
3300c0fea5dSIngo Weinhold 	image_t *image = (image_t*)malloc(allocSize);
3310c0fea5dSIngo Weinhold 	if (image == NULL) {
3320c0fea5dSIngo Weinhold 		FATAL("no memory for image %s\n", path);
3330c0fea5dSIngo Weinhold 		return NULL;
3340c0fea5dSIngo Weinhold 	}
3350c0fea5dSIngo Weinhold 
3360c0fea5dSIngo Weinhold 	memset(image, 0, allocSize);
3370c0fea5dSIngo Weinhold 
3380c0fea5dSIngo Weinhold 	strlcpy(image->path, path, sizeof(image->path));
3390c0fea5dSIngo Weinhold 
3400c0fea5dSIngo Weinhold 	// Make the last component of the supplied name the image name.
3410c0fea5dSIngo Weinhold 	// If present, DT_SONAME will replace this name.
3420c0fea5dSIngo Weinhold 	if ((lastSlash = strrchr(name, '/')))
3430c0fea5dSIngo Weinhold 		strlcpy(image->name, lastSlash + 1, sizeof(image->name));
3440c0fea5dSIngo Weinhold 	else
3450c0fea5dSIngo Weinhold 		strlcpy(image->name, name, sizeof(image->name));
3460c0fea5dSIngo Weinhold 
3470c0fea5dSIngo Weinhold 	image->ref_count = 1;
3480c0fea5dSIngo Weinhold 	image->num_regions = num_regions;
3490c0fea5dSIngo Weinhold 
3500c0fea5dSIngo Weinhold 	return image;
3510c0fea5dSIngo Weinhold }
3520c0fea5dSIngo Weinhold 
3530c0fea5dSIngo Weinhold 
3540c0fea5dSIngo Weinhold static void
3550c0fea5dSIngo Weinhold delete_image_struct(image_t *image)
3560c0fea5dSIngo Weinhold {
3570c0fea5dSIngo Weinhold #ifdef DEBUG
3580c0fea5dSIngo Weinhold 	size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t);
3590c0fea5dSIngo Weinhold 	memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
3600c0fea5dSIngo Weinhold #endif
3610c0fea5dSIngo Weinhold 	free(image->needed);
3620c0fea5dSIngo Weinhold 
3630c0fea5dSIngo Weinhold #ifdef DEBUG
3640c0fea5dSIngo Weinhold 	memset(image, 0xa5, size);
3650c0fea5dSIngo Weinhold #endif
3660c0fea5dSIngo Weinhold 	free(image);
3670c0fea5dSIngo Weinhold }
3680c0fea5dSIngo Weinhold 
3690c0fea5dSIngo Weinhold 
3700c0fea5dSIngo Weinhold static void
3710c0fea5dSIngo Weinhold delete_image(image_t *image)
3720c0fea5dSIngo Weinhold {
3732760c4cdSAxel Dörfler 	if (image == NULL)
3742760c4cdSAxel Dörfler 		return;
3752760c4cdSAxel Dörfler 
3760c0fea5dSIngo Weinhold 	_kern_unregister_image(image->id);
3770c0fea5dSIngo Weinhold 		// registered in load_container()
3780c0fea5dSIngo Weinhold 
3790c0fea5dSIngo Weinhold 	delete_image_struct(image);
3800c0fea5dSIngo Weinhold }
3810c0fea5dSIngo Weinhold 
3820c0fea5dSIngo Weinhold 
3830c0fea5dSIngo Weinhold static status_t
3840c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
3850c0fea5dSIngo Weinhold {
3860c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheader;
3870c0fea5dSIngo Weinhold 	int regcount;
3880c0fea5dSIngo Weinhold 	int i;
3890c0fea5dSIngo Weinhold 
3900c0fea5dSIngo Weinhold 	regcount = 0;
3910c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
3920c0fea5dSIngo Weinhold 		pheader = (struct Elf32_Phdr *)(buff + i * phentsize);
3930c0fea5dSIngo Weinhold 
3940c0fea5dSIngo Weinhold 		switch (pheader->p_type) {
3950c0fea5dSIngo Weinhold 			case PT_NULL:
3960c0fea5dSIngo Weinhold 				/* NOP header */
3970c0fea5dSIngo Weinhold 				break;
3980c0fea5dSIngo Weinhold 			case PT_LOAD:
3990c0fea5dSIngo Weinhold 				if (pheader->p_memsz == pheader->p_filesz) {
4000c0fea5dSIngo Weinhold 					/*
4010c0fea5dSIngo Weinhold 					 * everything in one area
4020c0fea5dSIngo Weinhold 					 */
4030c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
4040c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_memsz;
4050c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
4060c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz
4070c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
4080c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
4090c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
4100c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
4110c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
4120c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
4130c0fea5dSIngo Weinhold 						// this is a writable segment
4140c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
4150c0fea5dSIngo Weinhold 					}
4160c0fea5dSIngo Weinhold 				} else {
4170c0fea5dSIngo Weinhold 					/*
4180c0fea5dSIngo Weinhold 					 * may require splitting
4190c0fea5dSIngo Weinhold 					 */
4200c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz);
4210c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz);
4220c0fea5dSIngo Weinhold 
4230c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
4240c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_filesz;
4250c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
4260c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz
4270c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
4280c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
4290c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
4300c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
4310c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
4320c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
4330c0fea5dSIngo Weinhold 						// this is a writable segment
4340c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
4350c0fea5dSIngo Weinhold 					}
4360c0fea5dSIngo Weinhold 
4370c0fea5dSIngo Weinhold 					if (A != B) {
4380c0fea5dSIngo Weinhold 						/*
4390c0fea5dSIngo Weinhold 						 * yeah, it requires splitting
4400c0fea5dSIngo Weinhold 						 */
4410c0fea5dSIngo Weinhold 						regcount += 1;
4420c0fea5dSIngo Weinhold 						image->regions[regcount].start = pheader->p_vaddr;
4430c0fea5dSIngo Weinhold 						image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz;
4440c0fea5dSIngo Weinhold 						image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
4450c0fea5dSIngo Weinhold 						image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr))
4460c0fea5dSIngo Weinhold 							- image->regions[regcount-1].vmsize;
4470c0fea5dSIngo Weinhold 						image->regions[regcount].fdstart = 0;
4480c0fea5dSIngo Weinhold 						image->regions[regcount].fdsize = 0;
4490c0fea5dSIngo Weinhold 						image->regions[regcount].delta = 0;
4500c0fea5dSIngo Weinhold 						image->regions[regcount].flags = RFLAG_ANON;
4510c0fea5dSIngo Weinhold 						if (pheader->p_flags & PF_WRITE) {
4520c0fea5dSIngo Weinhold 							// this is a writable segment
4530c0fea5dSIngo Weinhold 							image->regions[regcount].flags |= RFLAG_RW;
4540c0fea5dSIngo Weinhold 						}
4550c0fea5dSIngo Weinhold 					}
4560c0fea5dSIngo Weinhold 				}
4570c0fea5dSIngo Weinhold 				regcount += 1;
4580c0fea5dSIngo Weinhold 				break;
4590c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
4600c0fea5dSIngo Weinhold 				image->dynamic_ptr = pheader->p_vaddr;
4610c0fea5dSIngo Weinhold 				break;
4620c0fea5dSIngo Weinhold 			case PT_INTERP:
4630c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
4640c0fea5dSIngo Weinhold 				break;
4650c0fea5dSIngo Weinhold 			case PT_NOTE:
4660c0fea5dSIngo Weinhold 				/* unsupported */
4670c0fea5dSIngo Weinhold 				break;
4680c0fea5dSIngo Weinhold 			case PT_SHLIB:
4690c0fea5dSIngo Weinhold 				/* undefined semantics */
4700c0fea5dSIngo Weinhold 				break;
4710c0fea5dSIngo Weinhold 			case PT_PHDR:
4720c0fea5dSIngo Weinhold 				/* we don't use it */
4730c0fea5dSIngo Weinhold 				break;
4740c0fea5dSIngo Weinhold 			default:
4750c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type);
4760c0fea5dSIngo Weinhold 				return B_BAD_DATA;
4770c0fea5dSIngo Weinhold 		}
4780c0fea5dSIngo Weinhold 	}
4790c0fea5dSIngo Weinhold 
4800c0fea5dSIngo Weinhold 	return B_OK;
4810c0fea5dSIngo Weinhold }
4820c0fea5dSIngo Weinhold 
4830c0fea5dSIngo Weinhold 
4840c0fea5dSIngo Weinhold static bool
4850c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image)
4860c0fea5dSIngo Weinhold {
4870c0fea5dSIngo Weinhold 	uint32 i;
4880c0fea5dSIngo Weinhold 
4890c0fea5dSIngo Weinhold 	if (!image->dynamic_ptr)
4900c0fea5dSIngo Weinhold 		return true;
4910c0fea5dSIngo Weinhold 
4920c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
4930c0fea5dSIngo Weinhold 		if (image->dynamic_ptr >= image->regions[i].start
4940c0fea5dSIngo Weinhold 			&& image->dynamic_ptr < image->regions[i].start + image->regions[i].size)
4950c0fea5dSIngo Weinhold 			return true;
4960c0fea5dSIngo Weinhold 	}
4970c0fea5dSIngo Weinhold 
4980c0fea5dSIngo Weinhold 	return false;
4990c0fea5dSIngo Weinhold }
5000c0fea5dSIngo Weinhold 
5010c0fea5dSIngo Weinhold 
5020c0fea5dSIngo Weinhold /**	This function will change the protection of all read-only segments
5030c0fea5dSIngo Weinhold  *	to really be read-only.
5040c0fea5dSIngo Weinhold  *	The areas have to be read/write first, so that they can be relocated.
5050c0fea5dSIngo Weinhold  */
5060c0fea5dSIngo Weinhold 
5070c0fea5dSIngo Weinhold static void
5080c0fea5dSIngo Weinhold remap_images(void)
5090c0fea5dSIngo Weinhold {
5100c0fea5dSIngo Weinhold 	image_t *image;
5110c0fea5dSIngo Weinhold 	uint32 i;
5120c0fea5dSIngo Weinhold 
5130c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
5140c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_regions; i++) {
5150c0fea5dSIngo Weinhold 			if ((image->regions[i].flags & RFLAG_RW) == 0
5160c0fea5dSIngo Weinhold 				&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
5170c0fea5dSIngo Weinhold 				// we only need to do this once, so we remember those we've already mapped
5180c0fea5dSIngo Weinhold 				if (_kern_set_area_protection(image->regions[i].id,
5190c0fea5dSIngo Weinhold 						B_READ_AREA | B_EXECUTE_AREA) == B_OK)
5200c0fea5dSIngo Weinhold 					image->regions[i].flags |= RFLAG_REMAPPED;
5210c0fea5dSIngo Weinhold 			}
5220c0fea5dSIngo Weinhold 		}
5230c0fea5dSIngo Weinhold 	}
5240c0fea5dSIngo Weinhold }
5250c0fea5dSIngo Weinhold 
5260c0fea5dSIngo Weinhold 
5270c0fea5dSIngo Weinhold static status_t
5280c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed)
5290c0fea5dSIngo Weinhold {
5300c0fea5dSIngo Weinhold 	status_t status = B_OK;
5310c0fea5dSIngo Weinhold 	const char *baseName;
5320c0fea5dSIngo Weinhold 	uint32 i;
5330c0fea5dSIngo Weinhold 
5340c0fea5dSIngo Weinhold 	(void)(fd);
5350c0fea5dSIngo Weinhold 
5360c0fea5dSIngo Weinhold 	// cut the file name from the path as base name for the created areas
5370c0fea5dSIngo Weinhold 	baseName = strrchr(path, '/');
5380c0fea5dSIngo Weinhold 	if (baseName != NULL)
5390c0fea5dSIngo Weinhold 		baseName++;
5400c0fea5dSIngo Weinhold 	else
5410c0fea5dSIngo Weinhold 		baseName = path;
5420c0fea5dSIngo Weinhold 
5430c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
5440c0fea5dSIngo Weinhold 		char regionName[B_OS_NAME_LENGTH];
5450c0fea5dSIngo Weinhold 		addr_t loadAddress;
5460c0fea5dSIngo Weinhold 		uint32 addressSpecifier;
5470c0fea5dSIngo Weinhold 
5480c0fea5dSIngo Weinhold 		// for BeOS compatibility: if we load an old BeOS executable, we
5490c0fea5dSIngo Weinhold 		// have to relocate it, if possible - we recognize it because the
5500c0fea5dSIngo Weinhold 		// vmstart is set to 0 (hopefully always)
5510c0fea5dSIngo Weinhold 		if (fixed && image->regions[i].vmstart == 0)
5520c0fea5dSIngo Weinhold 			fixed = false;
5530c0fea5dSIngo Weinhold 
5540c0fea5dSIngo Weinhold 		snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
5550c0fea5dSIngo Weinhold 			baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
5560c0fea5dSIngo Weinhold 
5570c0fea5dSIngo Weinhold 		if (image->dynamic_ptr && !fixed) {
5580c0fea5dSIngo Weinhold 			// relocatable image... we can afford to place wherever
5590c0fea5dSIngo Weinhold 			if (i == 0) {
5600c0fea5dSIngo Weinhold 				// but only the first segment gets a free ride
5610c0fea5dSIngo Weinhold 				loadAddress = RLD_PROGRAM_BASE;
5620c0fea5dSIngo Weinhold 				addressSpecifier = B_BASE_ADDRESS;
5630c0fea5dSIngo Weinhold 			} else {
5640c0fea5dSIngo Weinhold 				loadAddress = image->regions[i].vmstart + image->regions[i-1].delta;
5650c0fea5dSIngo Weinhold 				addressSpecifier = B_EXACT_ADDRESS;
5660c0fea5dSIngo Weinhold 			}
5670c0fea5dSIngo Weinhold 		} else {
5680c0fea5dSIngo Weinhold 			// not relocatable, put it where it asks or die trying
5690c0fea5dSIngo Weinhold 			loadAddress = image->regions[i].vmstart;
5700c0fea5dSIngo Weinhold 			addressSpecifier = B_EXACT_ADDRESS;
5710c0fea5dSIngo Weinhold 		}
5720c0fea5dSIngo Weinhold 
5730c0fea5dSIngo Weinhold 		if (image->regions[i].flags & RFLAG_ANON) {
5740c0fea5dSIngo Weinhold 			image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress,
5750c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_NO_LOCK,
5760c0fea5dSIngo Weinhold 				B_READ_AREA | B_WRITE_AREA);
5770c0fea5dSIngo Weinhold 
5780c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
5790c0fea5dSIngo Weinhold 				status = image->regions[i].id;
5800c0fea5dSIngo Weinhold 				goto error;
5810c0fea5dSIngo Weinhold 			}
5820c0fea5dSIngo Weinhold 
5830c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
5840c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
5850c0fea5dSIngo Weinhold 		} else {
5860c0fea5dSIngo Weinhold 			image->regions[i].id = sys_vm_map_file(regionName, (void **)&loadAddress,
5870c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
5880c0fea5dSIngo Weinhold 				REGION_PRIVATE_MAP, path, PAGE_BASE(image->regions[i].fdstart));
5890c0fea5dSIngo Weinhold 
5900c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
5910c0fea5dSIngo Weinhold 				status = image->regions[i].id;
5920c0fea5dSIngo Weinhold 				goto error;
5930c0fea5dSIngo Weinhold 			}
5940c0fea5dSIngo Weinhold 
5950c0fea5dSIngo Weinhold 			TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
5960c0fea5dSIngo Weinhold 				(void *)loadAddress, image->regions[i].vmsize,
5970c0fea5dSIngo Weinhold 				image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
5980c0fea5dSIngo Weinhold 
5990c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
6000c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
6010c0fea5dSIngo Weinhold 
6020c0fea5dSIngo Weinhold 			// handle trailer bits in data segment
6030c0fea5dSIngo Weinhold 			if (image->regions[i].flags & RFLAG_RW) {
6040c0fea5dSIngo Weinhold 				addr_t startClearing;
6050c0fea5dSIngo Weinhold 				addr_t toClear;
6060c0fea5dSIngo Weinhold 
6070c0fea5dSIngo Weinhold 				startClearing = image->regions[i].vmstart
6080c0fea5dSIngo Weinhold 					+ PAGE_OFFSET(image->regions[i].start)
6090c0fea5dSIngo Weinhold 					+ image->regions[i].size;
6100c0fea5dSIngo Weinhold 				toClear = image->regions[i].vmsize
6110c0fea5dSIngo Weinhold 					- PAGE_OFFSET(image->regions[i].start)
6120c0fea5dSIngo Weinhold 					- image->regions[i].size;
6130c0fea5dSIngo Weinhold 
6140c0fea5dSIngo Weinhold 				TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear));
6150c0fea5dSIngo Weinhold 				memset((void *)startClearing, 0, toClear);
6160c0fea5dSIngo Weinhold 			}
6170c0fea5dSIngo Weinhold 		}
6180c0fea5dSIngo Weinhold 	}
6190c0fea5dSIngo Weinhold 
6200c0fea5dSIngo Weinhold 	if (image->dynamic_ptr)
6210c0fea5dSIngo Weinhold 		image->dynamic_ptr += image->regions[0].delta;
6220c0fea5dSIngo Weinhold 
6230c0fea5dSIngo Weinhold 	return B_OK;
6240c0fea5dSIngo Weinhold 
6250c0fea5dSIngo Weinhold error:
6260c0fea5dSIngo Weinhold 	return status;
6270c0fea5dSIngo Weinhold }
6280c0fea5dSIngo Weinhold 
6290c0fea5dSIngo Weinhold 
6300c0fea5dSIngo Weinhold static void
6310c0fea5dSIngo Weinhold unmap_image(image_t *image)
6320c0fea5dSIngo Weinhold {
6330c0fea5dSIngo Weinhold 	uint32 i;
6340c0fea5dSIngo Weinhold 
6350c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
6360c0fea5dSIngo Weinhold 		_kern_delete_area(image->regions[i].id);
6370c0fea5dSIngo Weinhold 
6380c0fea5dSIngo Weinhold 		image->regions[i].id = -1;
6390c0fea5dSIngo Weinhold 	}
6400c0fea5dSIngo Weinhold }
6410c0fea5dSIngo Weinhold 
6420c0fea5dSIngo Weinhold 
6430c0fea5dSIngo Weinhold static bool
6440c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image)
6450c0fea5dSIngo Weinhold {
6460c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d;
6470c0fea5dSIngo Weinhold 	int i;
6480c0fea5dSIngo Weinhold 	int sonameOffset = -1;
6490c0fea5dSIngo Weinhold 
6500c0fea5dSIngo Weinhold 	image->symhash = 0;
6510c0fea5dSIngo Weinhold 	image->syms = 0;
6520c0fea5dSIngo Weinhold 	image->strtab = 0;
6530c0fea5dSIngo Weinhold 
6540c0fea5dSIngo Weinhold 	d = (struct Elf32_Dyn *)image->dynamic_ptr;
6550c0fea5dSIngo Weinhold 	if (!d)
6560c0fea5dSIngo Weinhold 		return true;
6570c0fea5dSIngo Weinhold 
6580c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
6590c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
6600c0fea5dSIngo Weinhold 			case DT_NEEDED:
6610c0fea5dSIngo Weinhold 				image->num_needed += 1;
6620c0fea5dSIngo Weinhold 				break;
6630c0fea5dSIngo Weinhold 			case DT_HASH:
6640c0fea5dSIngo Weinhold 				image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta);
6650c0fea5dSIngo Weinhold 				break;
6660c0fea5dSIngo Weinhold 			case DT_STRTAB:
6670c0fea5dSIngo Weinhold 				image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
6680c0fea5dSIngo Weinhold 				break;
6690c0fea5dSIngo Weinhold 			case DT_SYMTAB:
6700c0fea5dSIngo Weinhold 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
6710c0fea5dSIngo Weinhold 				break;
6720c0fea5dSIngo Weinhold 			case DT_REL:
6730c0fea5dSIngo Weinhold 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
6740c0fea5dSIngo Weinhold 				break;
6750c0fea5dSIngo Weinhold 			case DT_RELSZ:
6760c0fea5dSIngo Weinhold 				image->rel_len = d[i].d_un.d_val;
6770c0fea5dSIngo Weinhold 				break;
6780c0fea5dSIngo Weinhold 			case DT_RELA:
6790c0fea5dSIngo Weinhold 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
6800c0fea5dSIngo Weinhold 				break;
6810c0fea5dSIngo Weinhold 			case DT_RELASZ:
6820c0fea5dSIngo Weinhold 				image->rela_len = d[i].d_un.d_val;
6830c0fea5dSIngo Weinhold 				break;
6840c0fea5dSIngo Weinhold 			// TK: procedure linkage table
6850c0fea5dSIngo Weinhold 			case DT_JMPREL:
6860c0fea5dSIngo Weinhold 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
6870c0fea5dSIngo Weinhold 				break;
6880c0fea5dSIngo Weinhold 			case DT_PLTRELSZ:
6890c0fea5dSIngo Weinhold 				image->pltrel_len = d[i].d_un.d_val;
6900c0fea5dSIngo Weinhold 				break;
6910c0fea5dSIngo Weinhold 			case DT_INIT:
6920c0fea5dSIngo Weinhold 				image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
6930c0fea5dSIngo Weinhold 				break;
6940c0fea5dSIngo Weinhold 			case DT_FINI:
6950c0fea5dSIngo Weinhold 				image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
6960c0fea5dSIngo Weinhold 				break;
6970c0fea5dSIngo Weinhold 			case DT_SONAME:
6980c0fea5dSIngo Weinhold 				sonameOffset = d[i].d_un.d_val;
6990c0fea5dSIngo Weinhold 				break;
7000c0fea5dSIngo Weinhold 			default:
7010c0fea5dSIngo Weinhold 				continue;
7020c0fea5dSIngo Weinhold 		}
7030c0fea5dSIngo Weinhold 	}
7040c0fea5dSIngo Weinhold 
7050c0fea5dSIngo Weinhold 	// lets make sure we found all the required sections
7060c0fea5dSIngo Weinhold 	if (!image->symhash || !image->syms || !image->strtab)
7070c0fea5dSIngo Weinhold 		return false;
7080c0fea5dSIngo Weinhold 
7090c0fea5dSIngo Weinhold 	if (sonameOffset >= 0)
7100c0fea5dSIngo Weinhold 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
7110c0fea5dSIngo Weinhold 
7120c0fea5dSIngo Weinhold 	return true;
7130c0fea5dSIngo Weinhold }
7140c0fea5dSIngo Weinhold 
7150c0fea5dSIngo Weinhold 
7160c0fea5dSIngo Weinhold static struct Elf32_Sym *
7170c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type)
7180c0fea5dSIngo Weinhold {
7190c0fea5dSIngo Weinhold 	uint32 hash, i;
7200c0fea5dSIngo Weinhold 
7210c0fea5dSIngo Weinhold 	// ToDo: "type" is currently ignored!
7220c0fea5dSIngo Weinhold 	(void)type;
7230c0fea5dSIngo Weinhold 
7240c0fea5dSIngo Weinhold 	if (image->dynamic_ptr == NULL)
7250c0fea5dSIngo Weinhold 		return NULL;
7260c0fea5dSIngo Weinhold 
7270c0fea5dSIngo Weinhold 	hash = elf_hash((uint8 *)name) % HASHTABSIZE(image);
7280c0fea5dSIngo Weinhold 
7290c0fea5dSIngo Weinhold 	for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
7300c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = &image->syms[i];
7310c0fea5dSIngo Weinhold 
7320c0fea5dSIngo Weinhold 		if (symbol->st_shndx != SHN_UNDEF
7330c0fea5dSIngo Weinhold 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
7340c0fea5dSIngo Weinhold 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
7350c0fea5dSIngo Weinhold 			&& !strcmp(SYMNAME(image, symbol), name)) {
7360c0fea5dSIngo Weinhold 			// check if the type matches
7370c0fea5dSIngo Weinhold 			if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
7380c0fea5dSIngo Weinhold 				|| (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT))
7390c0fea5dSIngo Weinhold 				continue;
7400c0fea5dSIngo Weinhold 
7410c0fea5dSIngo Weinhold 			return symbol;
7420c0fea5dSIngo Weinhold 		}
7430c0fea5dSIngo Weinhold 	}
7440c0fea5dSIngo Weinhold 
7450c0fea5dSIngo Weinhold 	return NULL;
7460c0fea5dSIngo Weinhold }
7470c0fea5dSIngo Weinhold 
7480c0fea5dSIngo Weinhold 
7490c0fea5dSIngo Weinhold static struct Elf32_Sym*
75046f4d849SIngo Weinhold find_symbol_recursively_impl(image_t* image, const char* name,
75146f4d849SIngo Weinhold 	image_t** foundInImage)
7520c0fea5dSIngo Weinhold {
75346f4d849SIngo Weinhold 	image->flags |= RFLAG_VISITED;
7540c0fea5dSIngo Weinhold 
7550c0fea5dSIngo Weinhold 	struct Elf32_Sym *symbol;
7560c0fea5dSIngo Weinhold 
75746f4d849SIngo Weinhold 	// look up the symbol in this image
75846f4d849SIngo Weinhold 	if (image->dynamic_ptr) {
7590c0fea5dSIngo Weinhold 		symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY);
7600c0fea5dSIngo Weinhold 		if (symbol) {
76146f4d849SIngo Weinhold 			*foundInImage = image;
76246f4d849SIngo Weinhold 			return symbol;
76346f4d849SIngo Weinhold 		}
76446f4d849SIngo Weinhold 	}
76546f4d849SIngo Weinhold 
76646f4d849SIngo Weinhold 	// recursively search dependencies
76746f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
76846f4d849SIngo Weinhold 		if (!(image->needed[i]->flags & RFLAG_VISITED)) {
76946f4d849SIngo Weinhold 			symbol = find_symbol_recursively_impl(image->needed[i], name,
77046f4d849SIngo Weinhold 				foundInImage);
77146f4d849SIngo Weinhold 			if (symbol)
7720c0fea5dSIngo Weinhold 				return symbol;
7730c0fea5dSIngo Weinhold 		}
7740c0fea5dSIngo Weinhold 	}
7750c0fea5dSIngo Weinhold 
7760c0fea5dSIngo Weinhold 	return NULL;
7770c0fea5dSIngo Weinhold }
7780c0fea5dSIngo Weinhold 
7790c0fea5dSIngo Weinhold 
78046f4d849SIngo Weinhold static void
78146f4d849SIngo Weinhold clear_image_flag_recursively(image_t* image, uint32 flag)
78246f4d849SIngo Weinhold {
78346f4d849SIngo Weinhold 	image->flags &= ~flag;
78446f4d849SIngo Weinhold 
78546f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
78646f4d849SIngo Weinhold 		if (image->needed[i]->flags & flag)
78746f4d849SIngo Weinhold 			clear_image_flag_recursively(image->needed[i], flag);
78846f4d849SIngo Weinhold 	}
78946f4d849SIngo Weinhold }
79046f4d849SIngo Weinhold 
79146f4d849SIngo Weinhold 
79246f4d849SIngo Weinhold static struct Elf32_Sym*
79346f4d849SIngo Weinhold find_symbol_recursively(image_t* image, const char* name,
79446f4d849SIngo Weinhold 	image_t** foundInImage)
79546f4d849SIngo Weinhold {
79646f4d849SIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol_recursively_impl(image, name,
79746f4d849SIngo Weinhold 		foundInImage);
79846f4d849SIngo Weinhold 	clear_image_flag_recursively(image, RFLAG_VISITED);
79946f4d849SIngo Weinhold 	return symbol;
80046f4d849SIngo Weinhold }
80146f4d849SIngo Weinhold 
80246f4d849SIngo Weinhold 
80346f4d849SIngo Weinhold static struct Elf32_Sym*
80446f4d849SIngo Weinhold find_symbol_in_loaded_images(const char* name, image_t** foundInImage)
80546f4d849SIngo Weinhold {
80646f4d849SIngo Weinhold 	return find_symbol_recursively(sLoadedImages.head, name, foundInImage);
80746f4d849SIngo Weinhold }
80846f4d849SIngo Weinhold 
80946f4d849SIngo Weinhold 
81046f4d849SIngo Weinhold static struct Elf32_Sym*
81146f4d849SIngo Weinhold find_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
81246f4d849SIngo Weinhold 	image_t** foundInImage)
81346f4d849SIngo Weinhold {
81446f4d849SIngo Weinhold 	// If not simulating BeOS style symbol resolution, undefined symbols are
81546f4d849SIngo Weinhold 	// search recursively starting from the root image. (Note, breadth first
81646f4d849SIngo Weinhold 	// might be better than the depth first use here.)
81746f4d849SIngo Weinhold 	if (!sResolveSymbolsBeOSStyle)
81846f4d849SIngo Weinhold 		return find_symbol_recursively(rootImage, name, foundInImage);
81946f4d849SIngo Weinhold 
82046f4d849SIngo Weinhold 	// BeOS style symbol resolution: It is sufficient to check the direct
82146f4d849SIngo Weinhold 	// dependencies. The linker would have complained, if the symbol wasn't
82246f4d849SIngo Weinhold 	// there.
82346f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
82446f4d849SIngo Weinhold 		if (image->needed[i]->dynamic_ptr) {
82546f4d849SIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(image->needed[i], name,
82646f4d849SIngo Weinhold 				B_SYMBOL_TYPE_ANY);
82746f4d849SIngo Weinhold 			if (symbol) {
82846f4d849SIngo Weinhold 				*foundInImage = image->needed[i];
82946f4d849SIngo Weinhold 				return symbol;
83046f4d849SIngo Weinhold 			}
83146f4d849SIngo Weinhold 		}
83246f4d849SIngo Weinhold 	}
83346f4d849SIngo Weinhold 
83446f4d849SIngo Weinhold 	return NULL;
83546f4d849SIngo Weinhold }
83646f4d849SIngo Weinhold 
83746f4d849SIngo Weinhold 
8380c0fea5dSIngo Weinhold int
83946f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
84046f4d849SIngo Weinhold 	addr_t *sym_addr)
8410c0fea5dSIngo Weinhold {
8420c0fea5dSIngo Weinhold 	struct Elf32_Sym *sym2;
8430c0fea5dSIngo Weinhold 	char *symname;
8440c0fea5dSIngo Weinhold 	image_t *shimg;
8450c0fea5dSIngo Weinhold 
8460c0fea5dSIngo Weinhold 	switch (sym->st_shndx) {
8470c0fea5dSIngo Weinhold 		case SHN_UNDEF:
8480c0fea5dSIngo Weinhold 			// patch the symbol name
8490c0fea5dSIngo Weinhold 			symname = SYMNAME(image, sym);
8500c0fea5dSIngo Weinhold 
85146f4d849SIngo Weinhold 			// it's undefined, must be outside this image, try the other images
85246f4d849SIngo Weinhold 			sym2 = find_undefined_symbol(rootImage, image, symname, &shimg);
8530c0fea5dSIngo Weinhold 			if (!sym2) {
8540c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: could not resolve symbol '%s'\n", symname);
8550c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
8560c0fea5dSIngo Weinhold 			}
8570c0fea5dSIngo Weinhold 
8580c0fea5dSIngo Weinhold 			// make sure they're the same type
8590c0fea5dSIngo Weinhold 			if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
8600c0fea5dSIngo Weinhold 				&& ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) {
8610c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", symname);
8620c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
8630c0fea5dSIngo Weinhold 			}
8640c0fea5dSIngo Weinhold 
8650c0fea5dSIngo Weinhold 			if (ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL
8660c0fea5dSIngo Weinhold 				&& ELF32_ST_BIND(sym2->st_info) != STB_WEAK) {
8670c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: found symbol '%s' but not exported\n", symname);
8680c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
8690c0fea5dSIngo Weinhold 			}
8700c0fea5dSIngo Weinhold 
8710c0fea5dSIngo Weinhold 			*sym_addr = sym2->st_value + shimg->regions[0].delta;
8720c0fea5dSIngo Weinhold 			return B_NO_ERROR;
8730c0fea5dSIngo Weinhold 
8740c0fea5dSIngo Weinhold 		case SHN_ABS:
8750c0fea5dSIngo Weinhold 			*sym_addr = sym->st_value + image->regions[0].delta;
8760c0fea5dSIngo Weinhold 			return B_NO_ERROR;
8770c0fea5dSIngo Weinhold 
8780c0fea5dSIngo Weinhold 		case SHN_COMMON:
8790c0fea5dSIngo Weinhold 			// ToDo: finish this
8800c0fea5dSIngo Weinhold 			printf("elf_resolve_symbol: COMMON symbol, finish me!\n");
8810c0fea5dSIngo Weinhold 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
8820c0fea5dSIngo Weinhold 
8830c0fea5dSIngo Weinhold 		default:
8840c0fea5dSIngo Weinhold 			// standard symbol
8850c0fea5dSIngo Weinhold 			*sym_addr = sym->st_value + image->regions[0].delta;
8860c0fea5dSIngo Weinhold 			return B_NO_ERROR;
8870c0fea5dSIngo Weinhold 	}
8880c0fea5dSIngo Weinhold }
8890c0fea5dSIngo Weinhold 
8900c0fea5dSIngo Weinhold 
8910c0fea5dSIngo Weinhold static void
8920c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path)
8930c0fea5dSIngo Weinhold {
8940c0fea5dSIngo Weinhold 	struct stat stat;
8950c0fea5dSIngo Weinhold 	image_info info;
8960c0fea5dSIngo Weinhold 
8970c0fea5dSIngo Weinhold 	// ToDo: set these correctly
8980c0fea5dSIngo Weinhold 	info.id = 0;
8990c0fea5dSIngo Weinhold 	info.type = image->type;
9000c0fea5dSIngo Weinhold 	info.sequence = 0;
9010c0fea5dSIngo Weinhold 	info.init_order = 0;
9020c0fea5dSIngo Weinhold 	info.init_routine = (void (*)())image->init_routine;
9030c0fea5dSIngo Weinhold 	info.term_routine = (void (*)())image->term_routine;
9040c0fea5dSIngo Weinhold 
9050c0fea5dSIngo Weinhold 	if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
9060c0fea5dSIngo Weinhold 		info.device = stat.st_dev;
9070c0fea5dSIngo Weinhold 		info.node = stat.st_ino;
9080c0fea5dSIngo Weinhold 	} else {
9090c0fea5dSIngo Weinhold 		info.device = -1;
9100c0fea5dSIngo Weinhold 		info.node = -1;
9110c0fea5dSIngo Weinhold 	}
9120c0fea5dSIngo Weinhold 
9130c0fea5dSIngo Weinhold 	strlcpy(info.name, path, sizeof(info.name));
9140c0fea5dSIngo Weinhold 	info.text = (void *)image->regions[0].vmstart;
9150c0fea5dSIngo Weinhold 	info.text_size = image->regions[0].vmsize;
9160c0fea5dSIngo Weinhold 	info.data = (void *)image->regions[1].vmstart;
9170c0fea5dSIngo Weinhold 	info.data_size = image->regions[1].vmsize;
9180c0fea5dSIngo Weinhold 	image->id = _kern_register_image(&info, sizeof(image_info));
9190c0fea5dSIngo Weinhold }
9200c0fea5dSIngo Weinhold 
9210c0fea5dSIngo Weinhold 
9220c0fea5dSIngo Weinhold static status_t
92346f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
9240c0fea5dSIngo Weinhold {
92546f4d849SIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image);
9260c0fea5dSIngo Weinhold 	if (status < B_OK) {
92746f4d849SIngo Weinhold 		FATAL("troubles relocating: 0x%lx (image: %s)\n", status, image->name);
9280c0fea5dSIngo Weinhold 		return status;
9290c0fea5dSIngo Weinhold 	}
9300c0fea5dSIngo Weinhold 
9310c0fea5dSIngo Weinhold 	_kern_image_relocated(image->id);
9320c0fea5dSIngo Weinhold 	return B_OK;
9330c0fea5dSIngo Weinhold }
9340c0fea5dSIngo Weinhold 
9350c0fea5dSIngo Weinhold 
9360c0fea5dSIngo Weinhold static status_t
9370c0fea5dSIngo Weinhold load_container(char const *name, image_type type, const char *rpath, image_t **_image)
9380c0fea5dSIngo Weinhold {
9390c0fea5dSIngo Weinhold 	int32 pheaderSize, sheaderSize;
9400c0fea5dSIngo Weinhold 	char path[PATH_MAX];
9410c0fea5dSIngo Weinhold 	ssize_t length;
9420c0fea5dSIngo Weinhold 	char ph_buff[4096];
9430c0fea5dSIngo Weinhold 	int32 numRegions;
9440c0fea5dSIngo Weinhold 	image_t *found;
9450c0fea5dSIngo Weinhold 	image_t *image;
9460c0fea5dSIngo Weinhold 	status_t status;
9470c0fea5dSIngo Weinhold 	int fd;
9480c0fea5dSIngo Weinhold 
9490c0fea5dSIngo Weinhold 	struct Elf32_Ehdr eheader;
9500c0fea5dSIngo Weinhold 
9510c0fea5dSIngo Weinhold 	// Have we already loaded that image? Don't check for add-ons -- we always
9520c0fea5dSIngo Weinhold 	// reload them.
9530c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
9540c0fea5dSIngo Weinhold 		found = find_image(name, APP_OR_LIBRARY_TYPE);
9550c0fea5dSIngo Weinhold 		if (found) {
9560c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
9570c0fea5dSIngo Weinhold 			*_image = found;
9580c0fea5dSIngo Weinhold 			return B_OK;
9590c0fea5dSIngo Weinhold 		}
9600c0fea5dSIngo Weinhold 	}
9610c0fea5dSIngo Weinhold 
9620c0fea5dSIngo Weinhold 	strlcpy(path, name, sizeof(path));
9630c0fea5dSIngo Weinhold 
9640c0fea5dSIngo Weinhold 	// Try to load explicit image path first
9650c0fea5dSIngo Weinhold 	fd = open_executable(path, type, rpath);
9660c0fea5dSIngo Weinhold 	if (fd < 0) {
9670c0fea5dSIngo Weinhold 		FATAL("cannot open file %s\n", path);
9680c0fea5dSIngo Weinhold 		return fd;
9690c0fea5dSIngo Weinhold 	}
9700c0fea5dSIngo Weinhold 
9710c0fea5dSIngo Weinhold 	// If the path is not absolute, we prepend the CWD to make it one.
9720c0fea5dSIngo Weinhold 	if (path[0] != '/') {
9730c0fea5dSIngo Weinhold 		char relativePath[PATH_MAX];
9740c0fea5dSIngo Weinhold 		if (!strncmp(path, "./", 2))
9750c0fea5dSIngo Weinhold 			strcpy(relativePath, path + 2);
9760c0fea5dSIngo Weinhold 		else
9770c0fea5dSIngo Weinhold 			strcpy(relativePath, path);
9780c0fea5dSIngo Weinhold 
9790c0fea5dSIngo Weinhold 		// get the CWD
9800c0fea5dSIngo Weinhold 		status = _kern_getcwd(path, sizeof(path));
9810c0fea5dSIngo Weinhold 		if (status < B_OK) {
9820c0fea5dSIngo Weinhold 			FATAL("_kern_getcwd() failed\n");
9830c0fea5dSIngo Weinhold 			goto err1;
9840c0fea5dSIngo Weinhold 		}
9850c0fea5dSIngo Weinhold 
9860c0fea5dSIngo Weinhold 		if (strlcat(path, "/", sizeof(path)) >= sizeof(path)
9870c0fea5dSIngo Weinhold 			|| strlcat(path, relativePath, sizeof(path)) >= sizeof(path)) {
9880c0fea5dSIngo Weinhold 			status = B_NAME_TOO_LONG;
9890c0fea5dSIngo Weinhold 			FATAL("Absolute path of image %s is too "
9900c0fea5dSIngo Weinhold 				"long!\n", relativePath);
9910c0fea5dSIngo Weinhold 			goto err1;
9920c0fea5dSIngo Weinhold 		}
9930c0fea5dSIngo Weinhold 	}
9940c0fea5dSIngo Weinhold 
9950c0fea5dSIngo Weinhold 	// Test again if this image has been registered already - this time,
9960c0fea5dSIngo Weinhold 	// we can check the full path, not just its name as noted.
9970c0fea5dSIngo Weinhold 	// You could end up loading an image twice with symbolic links, else.
9980c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
9990c0fea5dSIngo Weinhold 		found = find_image(path, APP_OR_LIBRARY_TYPE);
10000c0fea5dSIngo Weinhold 		if (found) {
10010c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
10020c0fea5dSIngo Weinhold 			*_image = found;
10030c0fea5dSIngo Weinhold 			return B_OK;
10040c0fea5dSIngo Weinhold 		}
10050c0fea5dSIngo Weinhold 	}
10060c0fea5dSIngo Weinhold 
10070c0fea5dSIngo Weinhold 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
10080c0fea5dSIngo Weinhold 	if (length != sizeof(eheader)) {
10090c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
10100c0fea5dSIngo Weinhold 		FATAL("troubles reading ELF header\n");
10110c0fea5dSIngo Weinhold 		goto err1;
10120c0fea5dSIngo Weinhold 	}
10130c0fea5dSIngo Weinhold 
10140c0fea5dSIngo Weinhold 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
10150c0fea5dSIngo Weinhold 	if (status < B_OK) {
10160c0fea5dSIngo Weinhold 		FATAL("incorrect ELF header\n");
10170c0fea5dSIngo Weinhold 		goto err1;
10180c0fea5dSIngo Weinhold 	}
10190c0fea5dSIngo Weinhold 
10200c0fea5dSIngo Weinhold 	// ToDo: what to do about this restriction??
10210c0fea5dSIngo Weinhold 	if (pheaderSize > (int)sizeof(ph_buff)) {
10220c0fea5dSIngo Weinhold 		FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff));
10230c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
10240c0fea5dSIngo Weinhold 		goto err1;
10250c0fea5dSIngo Weinhold 	}
10260c0fea5dSIngo Weinhold 
10270c0fea5dSIngo Weinhold 	length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize);
10280c0fea5dSIngo Weinhold 	if (length != pheaderSize) {
10290c0fea5dSIngo Weinhold 		FATAL("Could not read program headers: %s\n", strerror(length));
10300c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
10310c0fea5dSIngo Weinhold 		goto err1;
10320c0fea5dSIngo Weinhold 	}
10330c0fea5dSIngo Weinhold 
10340c0fea5dSIngo Weinhold 	numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
10350c0fea5dSIngo Weinhold 	if (numRegions <= 0) {
10360c0fea5dSIngo Weinhold 		FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
10370c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
10380c0fea5dSIngo Weinhold 		goto err1;
10390c0fea5dSIngo Weinhold 	}
10400c0fea5dSIngo Weinhold 
10410c0fea5dSIngo Weinhold 	image = create_image(name, path, numRegions);
10420c0fea5dSIngo Weinhold 	if (image == NULL) {
10430c0fea5dSIngo Weinhold 		FATAL("Failed to allocate image_t object\n");
10440c0fea5dSIngo Weinhold 		status = B_NO_MEMORY;
10450c0fea5dSIngo Weinhold 		goto err1;
10460c0fea5dSIngo Weinhold 	}
10470c0fea5dSIngo Weinhold 
10480c0fea5dSIngo Weinhold 	status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
10490c0fea5dSIngo Weinhold 	if (status < B_OK)
10500c0fea5dSIngo Weinhold 		goto err2;
10510c0fea5dSIngo Weinhold 
10520c0fea5dSIngo Weinhold 	if (!assert_dynamic_loadable(image)) {
10530c0fea5dSIngo Weinhold 		FATAL("Dynamic segment must be loadable (implementation restriction)\n");
10540c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
10550c0fea5dSIngo Weinhold 		goto err2;
10560c0fea5dSIngo Weinhold 	}
10570c0fea5dSIngo Weinhold 
10580c0fea5dSIngo Weinhold 	status = map_image(fd, path, image, type == B_APP_IMAGE);
10590c0fea5dSIngo Weinhold 	if (status < B_OK) {
10600c0fea5dSIngo Weinhold 		FATAL("Could not map image: %s\n", strerror(status));
10610c0fea5dSIngo Weinhold 		status = B_ERROR;
10620c0fea5dSIngo Weinhold 		goto err2;
10630c0fea5dSIngo Weinhold 	}
10640c0fea5dSIngo Weinhold 
10650c0fea5dSIngo Weinhold 	if (!parse_dynamic_segment(image)) {
10660c0fea5dSIngo Weinhold 		FATAL("Troubles handling dynamic section\n");
10670c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
10680c0fea5dSIngo Weinhold 		goto err3;
10690c0fea5dSIngo Weinhold 	}
10700c0fea5dSIngo Weinhold 
10710c0fea5dSIngo Weinhold 	if (eheader.e_entry != NULL)
10720c0fea5dSIngo Weinhold 		image->entry_point = eheader.e_entry + image->regions[0].delta;
10730c0fea5dSIngo Weinhold 
10740c0fea5dSIngo Weinhold 	image->type = type;
10750c0fea5dSIngo Weinhold 	register_image(image, fd, path);
10760c0fea5dSIngo Weinhold 
10770c0fea5dSIngo Weinhold 	_kern_close(fd);
10780c0fea5dSIngo Weinhold 
10790c0fea5dSIngo Weinhold 	enqueue_image(&sLoadedImages, image);
10800c0fea5dSIngo Weinhold 	sLoadedImageCount++;
10810c0fea5dSIngo Weinhold 
10820c0fea5dSIngo Weinhold 	*_image = image;
10830c0fea5dSIngo Weinhold 	return B_OK;
10840c0fea5dSIngo Weinhold 
10850c0fea5dSIngo Weinhold err3:
10860c0fea5dSIngo Weinhold 	unmap_image(image);
10870c0fea5dSIngo Weinhold err2:
10880c0fea5dSIngo Weinhold 	delete_image_struct(image);
10890c0fea5dSIngo Weinhold err1:
10900c0fea5dSIngo Weinhold 	_kern_close(fd);
10910c0fea5dSIngo Weinhold 	return status;
10920c0fea5dSIngo Weinhold }
10930c0fea5dSIngo Weinhold 
10940c0fea5dSIngo Weinhold 
10950c0fea5dSIngo Weinhold static const char *
10960c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
10970c0fea5dSIngo Weinhold {
10980c0fea5dSIngo Weinhold 	int i;
10990c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
11000c0fea5dSIngo Weinhold 
11010c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
11020c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
11030c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
11040c0fea5dSIngo Weinhold 	}
11050c0fea5dSIngo Weinhold 
11060c0fea5dSIngo Weinhold 	return NULL;
11070c0fea5dSIngo Weinhold }
11080c0fea5dSIngo Weinhold 
11090c0fea5dSIngo Weinhold 
11100c0fea5dSIngo Weinhold static status_t
11110c0fea5dSIngo Weinhold load_dependencies(image_t *image)
11120c0fea5dSIngo Weinhold {
11130c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
11144bef3723SAxel Dörfler 	bool reportErrors = report_errors();
111574c0424aSAxel Dörfler 	status_t status = B_OK;
11160c0fea5dSIngo Weinhold 	uint32 i, j;
11170c0fea5dSIngo Weinhold 	const char *rpath;
11180c0fea5dSIngo Weinhold 
11190c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
11200c0fea5dSIngo Weinhold 		return B_OK;
11210c0fea5dSIngo Weinhold 
11220c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
11230c0fea5dSIngo Weinhold 
11240c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
11250c0fea5dSIngo Weinhold 		return B_OK;
11260c0fea5dSIngo Weinhold 
11270c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
11280c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
11290c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
11300c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
11310c0fea5dSIngo Weinhold 	}
11320c0fea5dSIngo Weinhold 
11330c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
11340c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
11350c0fea5dSIngo Weinhold 
11360c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
11370c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
11380c0fea5dSIngo Weinhold 			case DT_NEEDED:
113974c0424aSAxel Dörfler 			{
114074c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
114174c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
11420c0fea5dSIngo Weinhold 
114374c0424aSAxel Dörfler 				status_t loadStatus = load_container(name, B_LIBRARY_IMAGE,
114474c0424aSAxel Dörfler 					rpath, &image->needed[j]);
114574c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
114674c0424aSAxel Dörfler 					status = loadStatus;
114774c0424aSAxel Dörfler 					// correct error code in case the file could not been found
114874c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
114974c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
115074c0424aSAxel Dörfler 
115174c0424aSAxel Dörfler 						if (reportErrors)
115274c0424aSAxel Dörfler 							sErrorMessage.AddString("missing library", name);
115374c0424aSAxel Dörfler 					}
115474c0424aSAxel Dörfler 
115574c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
115674c0424aSAxel Dörfler 					if (!reportErrors)
11570c0fea5dSIngo Weinhold 						return status;
115874c0424aSAxel Dörfler 				}
11590c0fea5dSIngo Weinhold 
11600c0fea5dSIngo Weinhold 				j += 1;
11610c0fea5dSIngo Weinhold 				break;
116274c0424aSAxel Dörfler 			}
11630c0fea5dSIngo Weinhold 
11640c0fea5dSIngo Weinhold 			default:
11650c0fea5dSIngo Weinhold 				// ignore any other tag
11660c0fea5dSIngo Weinhold 				continue;
11670c0fea5dSIngo Weinhold 		}
11680c0fea5dSIngo Weinhold 	}
11690c0fea5dSIngo Weinhold 
117074c0424aSAxel Dörfler 	if (status < B_OK)
117174c0424aSAxel Dörfler 		return status;
117274c0424aSAxel Dörfler 
11730c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
11740c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
11750c0fea5dSIngo Weinhold 		return B_ERROR;
11760c0fea5dSIngo Weinhold 	}
11770c0fea5dSIngo Weinhold 
11780c0fea5dSIngo Weinhold 	return B_OK;
11790c0fea5dSIngo Weinhold }
11800c0fea5dSIngo Weinhold 
11810c0fea5dSIngo Weinhold 
11820c0fea5dSIngo Weinhold static uint32
11830c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList,
11840c0fea5dSIngo Weinhold 	uint32 sortFlag)
11850c0fea5dSIngo Weinhold {
11860c0fea5dSIngo Weinhold 	uint32 i;
11870c0fea5dSIngo Weinhold 
11880c0fea5dSIngo Weinhold 	if (image->flags & sortFlag)
11890c0fea5dSIngo Weinhold 		return slot;
11900c0fea5dSIngo Weinhold 
11910c0fea5dSIngo Weinhold 	image->flags |= sortFlag; /* make sure we don't visit this one */
11920c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_needed; i++)
11930c0fea5dSIngo Weinhold 		slot = topological_sort(image->needed[i], slot, initList, sortFlag);
11940c0fea5dSIngo Weinhold 
11950c0fea5dSIngo Weinhold 	initList[slot] = image;
11960c0fea5dSIngo Weinhold 	return slot + 1;
11970c0fea5dSIngo Weinhold }
11980c0fea5dSIngo Weinhold 
11990c0fea5dSIngo Weinhold 
12000c0fea5dSIngo Weinhold static ssize_t
12010c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
12020c0fea5dSIngo Weinhold {
12030c0fea5dSIngo Weinhold 	image_t **list;
12040c0fea5dSIngo Weinhold 
12050c0fea5dSIngo Weinhold 	list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *));
12060c0fea5dSIngo Weinhold 	if (list == NULL) {
12070c0fea5dSIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
12080c0fea5dSIngo Weinhold 		*_list = NULL;
12090c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
12100c0fea5dSIngo Weinhold 	}
12110c0fea5dSIngo Weinhold 
12120c0fea5dSIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
12130c0fea5dSIngo Weinhold 
12140c0fea5dSIngo Weinhold 	*_list = list;
12150c0fea5dSIngo Weinhold 	return topological_sort(image, 0, list, sortFlag);
12160c0fea5dSIngo Weinhold }
12170c0fea5dSIngo Weinhold 
12180c0fea5dSIngo Weinhold 
12190c0fea5dSIngo Weinhold static status_t
12200c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
12210c0fea5dSIngo Weinhold {
12220c0fea5dSIngo Weinhold 	ssize_t count, i;
12230c0fea5dSIngo Weinhold 	image_t **list;
12240c0fea5dSIngo Weinhold 
12250c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
12260c0fea5dSIngo Weinhold 	if (count < B_OK)
12270c0fea5dSIngo Weinhold 		return count;
12280c0fea5dSIngo Weinhold 
12290c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
123046f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
12310c0fea5dSIngo Weinhold 		if (status < B_OK)
12320c0fea5dSIngo Weinhold 			return status;
12330c0fea5dSIngo Weinhold 	}
12340c0fea5dSIngo Weinhold 
12350c0fea5dSIngo Weinhold 	free(list);
12360c0fea5dSIngo Weinhold 	return B_OK;
12370c0fea5dSIngo Weinhold }
12380c0fea5dSIngo Weinhold 
12390c0fea5dSIngo Weinhold 
12400c0fea5dSIngo Weinhold static void
12410c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
12420c0fea5dSIngo Weinhold {
12430c0fea5dSIngo Weinhold 	image_t **initList;
12440c0fea5dSIngo Weinhold 	ssize_t count, i;
12450c0fea5dSIngo Weinhold 
12460c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
12470c0fea5dSIngo Weinhold 	if (count <= 0)
12480c0fea5dSIngo Weinhold 		return;
12490c0fea5dSIngo Weinhold 
12500c0fea5dSIngo Weinhold 	if (!initHead) {
12510c0fea5dSIngo Weinhold 		// this removes the "calling" image
12520c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
12530c0fea5dSIngo Weinhold 		initList[--count] = NULL;
12540c0fea5dSIngo Weinhold 	}
12550c0fea5dSIngo Weinhold 
12560c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
12570c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
12580c0fea5dSIngo Weinhold 		image = initList[i];
12590c0fea5dSIngo Weinhold 
12600c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
12610c0fea5dSIngo Weinhold 
12620c0fea5dSIngo Weinhold 		if (image->init_routine != NULL)
12630c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
12640c0fea5dSIngo Weinhold 	}
12650c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
12660c0fea5dSIngo Weinhold 
12670c0fea5dSIngo Weinhold 	free(initList);
12680c0fea5dSIngo Weinhold }
12690c0fea5dSIngo Weinhold 
12700c0fea5dSIngo Weinhold 
12710c0fea5dSIngo Weinhold static void
12720c0fea5dSIngo Weinhold put_image(image_t *image)
12730c0fea5dSIngo Weinhold {
12740c0fea5dSIngo Weinhold 	// If all references to the image are gone, add it to the disposable list
12750c0fea5dSIngo Weinhold 	// and remove all dependencies
12760c0fea5dSIngo Weinhold 
12770c0fea5dSIngo Weinhold 	if (atomic_add(&image->ref_count, -1) == 1) {
12780c0fea5dSIngo Weinhold 		size_t i;
12790c0fea5dSIngo Weinhold 
12800c0fea5dSIngo Weinhold 		dequeue_image(&sLoadedImages, image);
12810c0fea5dSIngo Weinhold 		enqueue_image(&sDisposableImages, image);
12820c0fea5dSIngo Weinhold 		sLoadedImageCount--;
12830c0fea5dSIngo Weinhold 
12840c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_needed; i++) {
12850c0fea5dSIngo Weinhold 			put_image(image->needed[i]);
12860c0fea5dSIngo Weinhold 		}
12870c0fea5dSIngo Weinhold 	}
12880c0fea5dSIngo Weinhold }
12890c0fea5dSIngo Weinhold 
12900c0fea5dSIngo Weinhold 
129174c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
12920c0fea5dSIngo Weinhold 
12930c0fea5dSIngo Weinhold 
12940c0fea5dSIngo Weinhold image_id
12950c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
12960c0fea5dSIngo Weinhold {
12970c0fea5dSIngo Weinhold 	status_t status;
12980c0fea5dSIngo Weinhold 	image_t *image;
12990c0fea5dSIngo Weinhold 
13000c0fea5dSIngo Weinhold 	rld_lock();
13010c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
13020c0fea5dSIngo Weinhold 
13030c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
13040c0fea5dSIngo Weinhold 
13050c0fea5dSIngo Weinhold 	status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage);
130674c0424aSAxel Dörfler 	if (status < B_OK)
130774c0424aSAxel Dörfler 		goto err;
13080c0fea5dSIngo Weinhold 
13090c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
13100c0fea5dSIngo Weinhold 		status = load_dependencies(image);
13110c0fea5dSIngo Weinhold 		if (status < B_OK)
13120c0fea5dSIngo Weinhold 			goto err;
13130c0fea5dSIngo Weinhold 	}
13140c0fea5dSIngo Weinhold 
13150c0fea5dSIngo Weinhold 	status = relocate_dependencies(sProgramImage);
13160c0fea5dSIngo Weinhold 	if (status < B_OK)
13170c0fea5dSIngo Weinhold 		goto err;
13180c0fea5dSIngo Weinhold 
13190c0fea5dSIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private API
13200c0fea5dSIngo Weinhold 	{
132146f4d849SIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_loaded_images(
132246f4d849SIngo Weinhold 			"__gRuntimeLoader", &image);
13230c0fea5dSIngo Weinhold 		if (symbol != NULL) {
13240c0fea5dSIngo Weinhold 			void **_export = (void **)(symbol->st_value + image->regions[0].delta);
13250c0fea5dSIngo Weinhold 			*_export = &gRuntimeLoader;
13260c0fea5dSIngo Weinhold 		}
13270c0fea5dSIngo Weinhold 	}
13280c0fea5dSIngo Weinhold 
13290c0fea5dSIngo Weinhold 	init_dependencies(sLoadedImages.head, true);
13300c0fea5dSIngo Weinhold 	remap_images();
13310c0fea5dSIngo Weinhold 		// ToDo: once setup_system_time() is fixed, move this one line higher!
13320c0fea5dSIngo Weinhold 
13330c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
13340c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
13350c0fea5dSIngo Weinhold 	{
133646f4d849SIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_loaded_images("getenv",
133746f4d849SIngo Weinhold 			&image);
13380c0fea5dSIngo Weinhold 		if (symbol != NULL)
13390c0fea5dSIngo Weinhold 			gGetEnv = (char* (*)(const char*))
13400c0fea5dSIngo Weinhold 				(symbol->st_value + image->regions[0].delta);
13410c0fea5dSIngo Weinhold 	}
13420c0fea5dSIngo Weinhold 
13430c0fea5dSIngo Weinhold 	if (sProgramImage->entry_point == NULL) {
13440c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
13450c0fea5dSIngo Weinhold 		goto err;
13460c0fea5dSIngo Weinhold 	}
13470c0fea5dSIngo Weinhold 
13480c0fea5dSIngo Weinhold 	*_entry = (void *)(sProgramImage->entry_point);
13490c0fea5dSIngo Weinhold 
13500c0fea5dSIngo Weinhold 	rld_unlock();
13510c0fea5dSIngo Weinhold 	return sProgramImage->id;
13520c0fea5dSIngo Weinhold 
13530c0fea5dSIngo Weinhold err:
13540c0fea5dSIngo Weinhold 	delete_image(sProgramImage);
135574c0424aSAxel Dörfler 
13564bef3723SAxel Dörfler 	if (report_errors()) {
13574bef3723SAxel Dörfler 		// send error message
135874c0424aSAxel Dörfler 		sErrorMessage.AddInt32("error", status);
13594bef3723SAxel Dörfler 		sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
13604bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
13614bef3723SAxel Dörfler 
13624bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
13634bef3723SAxel Dörfler 			sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0);
136474c0424aSAxel Dörfler 	}
136574c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
13660c0fea5dSIngo Weinhold 	rld_unlock();
136774c0424aSAxel Dörfler 
13680c0fea5dSIngo Weinhold 	return status;
13690c0fea5dSIngo Weinhold }
13700c0fea5dSIngo Weinhold 
13710c0fea5dSIngo Weinhold 
13720c0fea5dSIngo Weinhold image_id
13730c0fea5dSIngo Weinhold load_library(char const *path, uint32 flags, bool addOn)
13740c0fea5dSIngo Weinhold {
13750c0fea5dSIngo Weinhold 	image_t *image = NULL;
13760c0fea5dSIngo Weinhold 	image_t *iter;
13770c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
13780c0fea5dSIngo Weinhold 	status_t status;
13790c0fea5dSIngo Weinhold 
13800c0fea5dSIngo Weinhold 	if (path == NULL)
13810c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
13820c0fea5dSIngo Weinhold 
13830c0fea5dSIngo Weinhold 	// ToDo: implement flags
13840c0fea5dSIngo Weinhold 	(void)flags;
13850c0fea5dSIngo Weinhold 
13860c0fea5dSIngo Weinhold 	rld_lock();
13870c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
13880c0fea5dSIngo Weinhold 
13890c0fea5dSIngo Weinhold 	// have we already loaded this library?
13900c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
13910c0fea5dSIngo Weinhold 	if (!addOn) {
13920c0fea5dSIngo Weinhold 		image = find_image(path, APP_OR_LIBRARY_TYPE);
13930c0fea5dSIngo Weinhold 		if (image) {
13940c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
13950c0fea5dSIngo Weinhold 			rld_unlock();
13960c0fea5dSIngo Weinhold 			return image->id;
13970c0fea5dSIngo Weinhold 		}
13980c0fea5dSIngo Weinhold 	}
13990c0fea5dSIngo Weinhold 
14000c0fea5dSIngo Weinhold 	status = load_container(path, type, NULL, &image);
14010c0fea5dSIngo Weinhold 	if (status < B_OK) {
14020c0fea5dSIngo Weinhold 		rld_unlock();
14030c0fea5dSIngo Weinhold 		return status;
14040c0fea5dSIngo Weinhold 	}
14050c0fea5dSIngo Weinhold 
14060c0fea5dSIngo Weinhold 	for (iter = sLoadedImages.head; iter; iter = iter->next) {
14070c0fea5dSIngo Weinhold 		status = load_dependencies(iter);
14080c0fea5dSIngo Weinhold 		if (status < B_OK)
14090c0fea5dSIngo Weinhold 			goto err;
14100c0fea5dSIngo Weinhold 	}
14110c0fea5dSIngo Weinhold 
14120c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
14130c0fea5dSIngo Weinhold 	if (status < B_OK)
14140c0fea5dSIngo Weinhold 		goto err;
14150c0fea5dSIngo Weinhold 
14160c0fea5dSIngo Weinhold 	remap_images();
14170c0fea5dSIngo Weinhold 	init_dependencies(image, true);
14180c0fea5dSIngo Weinhold 
14190c0fea5dSIngo Weinhold 	rld_unlock();
14200c0fea5dSIngo Weinhold 	return image->id;
14210c0fea5dSIngo Weinhold 
14220c0fea5dSIngo Weinhold err:
14230c0fea5dSIngo Weinhold 	dequeue_image(&sLoadedImages, image);
14240c0fea5dSIngo Weinhold 	sLoadedImageCount--;
14250c0fea5dSIngo Weinhold 	delete_image(image);
14260c0fea5dSIngo Weinhold 	rld_unlock();
14270c0fea5dSIngo Weinhold 	return status;
14280c0fea5dSIngo Weinhold }
14290c0fea5dSIngo Weinhold 
14300c0fea5dSIngo Weinhold 
14310c0fea5dSIngo Weinhold status_t
14320c0fea5dSIngo Weinhold unload_library(image_id imageID, bool addOn)
14330c0fea5dSIngo Weinhold {
14340c0fea5dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
14350c0fea5dSIngo Weinhold 	image_t *image;
14360c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
14370c0fea5dSIngo Weinhold 
14380c0fea5dSIngo Weinhold 	if (imageID < B_OK)
14390c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
14400c0fea5dSIngo Weinhold 
14410c0fea5dSIngo Weinhold 	rld_lock();
14420c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
14430c0fea5dSIngo Weinhold 
14440c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
14450c0fea5dSIngo Weinhold 
14460c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
14470c0fea5dSIngo Weinhold 		if (image->id == imageID) {
14480c0fea5dSIngo Weinhold 			// unload image
14490c0fea5dSIngo Weinhold 			if (type == image->type) {
14500c0fea5dSIngo Weinhold 				put_image(image);
14510c0fea5dSIngo Weinhold 				status = B_OK;
14520c0fea5dSIngo Weinhold 			} else
14530c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
14540c0fea5dSIngo Weinhold 			break;
14550c0fea5dSIngo Weinhold 		}
14560c0fea5dSIngo Weinhold 	}
14570c0fea5dSIngo Weinhold 
14580c0fea5dSIngo Weinhold 	if (status == B_OK) {
14590c0fea5dSIngo Weinhold 		while ((image = sDisposableImages.head) != NULL) {
14600c0fea5dSIngo Weinhold 			// call image fini here...
1461*8c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
1462*8c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
1463*8c2a9d74SMichael Lotz 					image->regions[0].start, image->regions[0].size);
1464*8c2a9d74SMichael Lotz 			}
1465*8c2a9d74SMichael Lotz 
14660c0fea5dSIngo Weinhold 			if (image->term_routine)
14670c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
14680c0fea5dSIngo Weinhold 
14690c0fea5dSIngo Weinhold 			dequeue_image(&sDisposableImages, image);
14700c0fea5dSIngo Weinhold 			unmap_image(image);
14710c0fea5dSIngo Weinhold 
14720c0fea5dSIngo Weinhold 			delete_image(image);
14730c0fea5dSIngo Weinhold 		}
14740c0fea5dSIngo Weinhold 	}
14750c0fea5dSIngo Weinhold 
14760c0fea5dSIngo Weinhold 	rld_unlock();
14770c0fea5dSIngo Weinhold 	return status;
14780c0fea5dSIngo Weinhold }
14790c0fea5dSIngo Weinhold 
14800c0fea5dSIngo Weinhold 
14810c0fea5dSIngo Weinhold status_t
14820c0fea5dSIngo Weinhold get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, int32 *_nameLength,
14830c0fea5dSIngo Weinhold 	int32 *_type, void **_location)
14840c0fea5dSIngo Weinhold {
14850c0fea5dSIngo Weinhold 	int32 count = 0, j;
14860c0fea5dSIngo Weinhold 	uint32 i;
14870c0fea5dSIngo Weinhold 	image_t *image;
14880c0fea5dSIngo Weinhold 
14890c0fea5dSIngo Weinhold 	rld_lock();
14900c0fea5dSIngo Weinhold 
14910c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
14920c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
14930c0fea5dSIngo Weinhold 	if (image == NULL) {
14940c0fea5dSIngo Weinhold 		rld_unlock();
14950c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
14960c0fea5dSIngo Weinhold 	}
14970c0fea5dSIngo Weinhold 
14980c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
14990c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
15000c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
15010c0fea5dSIngo Weinhold 			struct Elf32_Sym *symbol = &image->syms[i];
15020c0fea5dSIngo Weinhold 
15030c0fea5dSIngo Weinhold 			if (count == num) {
15040c0fea5dSIngo Weinhold 				strlcpy(nameBuffer, SYMNAME(image, symbol), *_nameLength);
15050c0fea5dSIngo Weinhold 				*_nameLength = strlen(SYMNAME(image, symbol));
15060c0fea5dSIngo Weinhold 
15070c0fea5dSIngo Weinhold 				if (_type != NULL) {
15080c0fea5dSIngo Weinhold 					// ToDo: check with the return types of that BeOS function
15090c0fea5dSIngo Weinhold 					if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
15100c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_TEXT;
15110c0fea5dSIngo Weinhold 					else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
15120c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_DATA;
15130c0fea5dSIngo Weinhold 					else
15140c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_ANY;
15150c0fea5dSIngo Weinhold 				}
15160c0fea5dSIngo Weinhold 
15170c0fea5dSIngo Weinhold 				if (_location != NULL)
15180c0fea5dSIngo Weinhold 					*_location = (void *)(symbol->st_value + image->regions[0].delta);
15190c0fea5dSIngo Weinhold 				goto out;
15200c0fea5dSIngo Weinhold 			}
15210c0fea5dSIngo Weinhold 			count++;
15220c0fea5dSIngo Weinhold 		}
15230c0fea5dSIngo Weinhold 	}
15240c0fea5dSIngo Weinhold out:
15250c0fea5dSIngo Weinhold 	rld_unlock();
15260c0fea5dSIngo Weinhold 
15270c0fea5dSIngo Weinhold 	if (num != count)
15280c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
15290c0fea5dSIngo Weinhold 
15300c0fea5dSIngo Weinhold 	return B_OK;
15310c0fea5dSIngo Weinhold }
15320c0fea5dSIngo Weinhold 
15330c0fea5dSIngo Weinhold 
15340c0fea5dSIngo Weinhold status_t
15350c0fea5dSIngo Weinhold get_symbol(image_id imageID, char const *symbolName, int32 symbolType, void **_location)
15360c0fea5dSIngo Weinhold {
15370c0fea5dSIngo Weinhold 	status_t status = B_OK;
15380c0fea5dSIngo Weinhold 	image_t *image;
15390c0fea5dSIngo Weinhold 
15400c0fea5dSIngo Weinhold 	if (imageID < B_OK)
15410c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
15420c0fea5dSIngo Weinhold 	if (symbolName == NULL)
15430c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
15440c0fea5dSIngo Weinhold 
15450c0fea5dSIngo Weinhold 	rld_lock();
15460c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
15470c0fea5dSIngo Weinhold 
15480c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
15490c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
15500c0fea5dSIngo Weinhold 	if (image != NULL) {
15510c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol;
15520c0fea5dSIngo Weinhold 
15530c0fea5dSIngo Weinhold 		// get the symbol in the image
15540c0fea5dSIngo Weinhold 		symbol = find_symbol(image, symbolName, symbolType);
15550c0fea5dSIngo Weinhold 		if (symbol) {
15560c0fea5dSIngo Weinhold 			if (_location != NULL)
15570c0fea5dSIngo Weinhold 				*_location = (void *)(symbol->st_value + image->regions[0].delta);
15580c0fea5dSIngo Weinhold 		} else
15590c0fea5dSIngo Weinhold 			status = B_ENTRY_NOT_FOUND;
15600c0fea5dSIngo Weinhold 	} else
15610c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
15620c0fea5dSIngo Weinhold 
15630c0fea5dSIngo Weinhold 	rld_unlock();
15640c0fea5dSIngo Weinhold 	return status;
15650c0fea5dSIngo Weinhold }
15660c0fea5dSIngo Weinhold 
15670c0fea5dSIngo Weinhold 
15680c0fea5dSIngo Weinhold status_t
15690c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
15700c0fea5dSIngo Weinhold {
15710c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
15720c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
15730c0fea5dSIngo Weinhold 	image_t *image;
15740c0fea5dSIngo Weinhold 
15750c0fea5dSIngo Weinhold 	if (_name == NULL)
15760c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
15770c0fea5dSIngo Weinhold 
15780c0fea5dSIngo Weinhold 	rld_lock();
15790c0fea5dSIngo Weinhold 
15800c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(id);
15810c0fea5dSIngo Weinhold 	if (image == NULL) {
15820c0fea5dSIngo Weinhold 		rld_unlock();
15830c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
15840c0fea5dSIngo Weinhold 	}
15850c0fea5dSIngo Weinhold 
15860c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
15870c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
15880c0fea5dSIngo Weinhold 		rld_unlock();
15890c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
15900c0fea5dSIngo Weinhold 	}
15910c0fea5dSIngo Weinhold 
15920c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
15930c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
15940c0fea5dSIngo Weinhold 			continue;
15950c0fea5dSIngo Weinhold 
15960c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
15970c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
15980c0fea5dSIngo Weinhold 
15990c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
16000c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
16010c0fea5dSIngo Weinhold 			rld_unlock();
16020c0fea5dSIngo Weinhold 			return B_OK;
16030c0fea5dSIngo Weinhold 		}
16040c0fea5dSIngo Weinhold 	}
16050c0fea5dSIngo Weinhold 
16060c0fea5dSIngo Weinhold 	rld_unlock();
16070c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
16080c0fea5dSIngo Weinhold }
16090c0fea5dSIngo Weinhold 
16100c0fea5dSIngo Weinhold 
161174c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
16120c0fea5dSIngo Weinhold 
16130c0fea5dSIngo Weinhold 
16140c0fea5dSIngo Weinhold /** Read and verify the ELF header */
16150c0fea5dSIngo Weinhold 
16160c0fea5dSIngo Weinhold status_t
16170c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
16180c0fea5dSIngo Weinhold {
16190c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
16200c0fea5dSIngo Weinhold 
16210c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
16220c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
16230c0fea5dSIngo Weinhold 
16240c0fea5dSIngo Weinhold 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, &sectionSize);
16250c0fea5dSIngo Weinhold }
16260c0fea5dSIngo Weinhold 
16270c0fea5dSIngo Weinhold 
16280c0fea5dSIngo Weinhold void
16290c0fea5dSIngo Weinhold terminate_program(void)
16300c0fea5dSIngo Weinhold {
16310c0fea5dSIngo Weinhold 	image_t **termList;
16320c0fea5dSIngo Weinhold 	ssize_t count, i;
16330c0fea5dSIngo Weinhold 
16340c0fea5dSIngo Weinhold 	count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED);
16350c0fea5dSIngo Weinhold 	if (count < B_OK)
16360c0fea5dSIngo Weinhold 		return;
16370c0fea5dSIngo Weinhold 
16380c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
16390c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
16400c0fea5dSIngo Weinhold 		image_t *image = termList[i];
16410c0fea5dSIngo Weinhold 
16420c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
16430c0fea5dSIngo Weinhold 
16440c0fea5dSIngo Weinhold 		if (image->term_routine)
16450c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
16460c0fea5dSIngo Weinhold 	}
16470c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
16480c0fea5dSIngo Weinhold 
16490c0fea5dSIngo Weinhold 	free(termList);
16500c0fea5dSIngo Weinhold }
16510c0fea5dSIngo Weinhold 
16520c0fea5dSIngo Weinhold 
16530c0fea5dSIngo Weinhold void
16540c0fea5dSIngo Weinhold rldelf_init(void)
16550c0fea5dSIngo Weinhold {
16560c0fea5dSIngo Weinhold 	rld_sem = create_sem(1, "rld_lock");
16570c0fea5dSIngo Weinhold 	rld_sem_owner = -1;
16580c0fea5dSIngo Weinhold 	rld_sem_count = 0;
16590c0fea5dSIngo Weinhold 
16600c0fea5dSIngo Weinhold 	// create the debug area
16610c0fea5dSIngo Weinhold 	{
16620c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
16630c0fea5dSIngo Weinhold 
16640c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
16650c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
16660c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
16670c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
16680c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
16690c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
16700c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
16710c0fea5dSIngo Weinhold 		}
16720c0fea5dSIngo Weinhold 
16730c0fea5dSIngo Weinhold 		area->loaded_images = &sLoadedImages;
16740c0fea5dSIngo Weinhold 	}
167574c0424aSAxel Dörfler 
167674c0424aSAxel Dörfler 	// initialize error message if needed
16774bef3723SAxel Dörfler 	if (report_errors()) {
167874c0424aSAxel Dörfler 		void *buffer = malloc(1024);
167974c0424aSAxel Dörfler 		if (buffer == NULL)
168074c0424aSAxel Dörfler 			return;
168174c0424aSAxel Dörfler 
168274c0424aSAxel Dörfler 		sErrorMessage.SetTo(buffer, 1024, 'Rler');
168374c0424aSAxel Dörfler 	}
16840c0fea5dSIngo Weinhold }
16851873b4b3SIngo Weinhold 
16861873b4b3SIngo Weinhold 
16871873b4b3SIngo Weinhold status_t
16881873b4b3SIngo Weinhold elf_reinit_after_fork()
16891873b4b3SIngo Weinhold {
16901873b4b3SIngo Weinhold 	rld_sem = create_sem(1, "rld_lock");
16911873b4b3SIngo Weinhold 	if (rld_sem < 0)
16921873b4b3SIngo Weinhold 		return rld_sem;
16931873b4b3SIngo Weinhold 
16941873b4b3SIngo Weinhold 	return B_OK;
16951873b4b3SIngo Weinhold }
1696