xref: /haiku/src/system/runtime_loader/elf.cpp (revision 071f9c3aa2c2215feaa56a8ff59557dd00b27f37)
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"
135aa7b7b6SMarcus Overhagen #include "vm.h"
140c0fea5dSIngo Weinhold 
150c0fea5dSIngo Weinhold #include <OS.h>
160c0fea5dSIngo Weinhold 
170c0fea5dSIngo Weinhold #include <string.h>
180c0fea5dSIngo Weinhold #include <stdio.h>
190c0fea5dSIngo Weinhold #include <stdlib.h>
2034982809SIngo Weinhold #include <string.h>
210c0fea5dSIngo Weinhold 
227486b72dSIngo Weinhold #include <arch/cpu.h>
237486b72dSIngo Weinhold #include <elf32.h>
247486b72dSIngo Weinhold #include <runtime_loader.h>
257486b72dSIngo Weinhold #include <sem.h>
267486b72dSIngo Weinhold #include <syscalls.h>
277486b72dSIngo Weinhold #include <user_runtime.h>
287486b72dSIngo Weinhold #include <vm_types.h>
297486b72dSIngo Weinhold 
30*071f9c3aSIngo Weinhold #include "tracing_config.h"
31*071f9c3aSIngo Weinhold 
320c0fea5dSIngo Weinhold 
330c0fea5dSIngo Weinhold //#define TRACE_RLD
340c0fea5dSIngo Weinhold #ifdef TRACE_RLD
350c0fea5dSIngo Weinhold #	define TRACE(x) dprintf x
360c0fea5dSIngo Weinhold #else
370c0fea5dSIngo Weinhold #	define TRACE(x) ;
380c0fea5dSIngo Weinhold #endif
390c0fea5dSIngo Weinhold 
400c0fea5dSIngo Weinhold 
410c0fea5dSIngo Weinhold // ToDo: implement better locking strategy
420c0fea5dSIngo Weinhold // ToDo: implement lazy binding
430c0fea5dSIngo Weinhold 
440c0fea5dSIngo Weinhold #define	PAGE_MASK (B_PAGE_SIZE - 1)
450c0fea5dSIngo Weinhold 
460c0fea5dSIngo Weinhold #define	PAGE_OFFSET(x) ((x) & (PAGE_MASK))
470c0fea5dSIngo Weinhold #define	PAGE_BASE(x) ((x) & ~(PAGE_MASK))
480c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
490c0fea5dSIngo Weinhold 
500c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000
510c0fea5dSIngo Weinhold 	/* keep in sync with app ldscript */
520c0fea5dSIngo Weinhold 
530c0fea5dSIngo Weinhold enum {
540c0fea5dSIngo Weinhold 	RFLAG_RW					= 0x0001,
550c0fea5dSIngo Weinhold 	RFLAG_ANON					= 0x0002,
560c0fea5dSIngo Weinhold 
570c0fea5dSIngo Weinhold 	RFLAG_TERMINATED			= 0x0200,
580c0fea5dSIngo Weinhold 	RFLAG_INITIALIZED			= 0x0400,
590c0fea5dSIngo Weinhold 	RFLAG_SYMBOLIC				= 0x0800,
600c0fea5dSIngo Weinhold 	RFLAG_RELOCATED				= 0x1000,
610c0fea5dSIngo Weinhold 	RFLAG_PROTECTED				= 0x2000,
620c0fea5dSIngo Weinhold 	RFLAG_DEPENDENCIES_LOADED	= 0x4000,
6346f4d849SIngo Weinhold 	RFLAG_REMAPPED				= 0x8000,
6446f4d849SIngo Weinhold 
6546f4d849SIngo Weinhold 	RFLAG_VISITED				= 0x10000
6646f4d849SIngo Weinhold 		// temporarily set in the symbol resolution code
670c0fea5dSIngo Weinhold };
680c0fea5dSIngo Weinhold 
690c0fea5dSIngo Weinhold 
700c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type)	(1 << ((type) - 1))
710c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES				(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
720c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
730c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
740c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
750c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE			(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
760c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
770c0fea5dSIngo Weinhold 
780c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
790c0fea5dSIngo Weinhold 
800c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0};
810c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0};
820c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0;
830c0fea5dSIngo Weinhold static image_t *sProgramImage;
8474c0424aSAxel Dörfler static KMessage sErrorMessage;
850c0fea5dSIngo Weinhold 
860c0fea5dSIngo Weinhold // a recursive lock
870c0fea5dSIngo Weinhold static sem_id rld_sem;
880c0fea5dSIngo Weinhold static thread_id rld_sem_owner;
890c0fea5dSIngo Weinhold static int32 rld_sem_count;
900c0fea5dSIngo Weinhold 
910c0fea5dSIngo Weinhold 
920c0fea5dSIngo Weinhold #ifdef TRACE_RLD
930c0fea5dSIngo Weinhold #	define FATAL(x...) dprintf("runtime_loader: " x);
940c0fea5dSIngo Weinhold 
950c0fea5dSIngo Weinhold void
960c0fea5dSIngo Weinhold dprintf(const char *format, ...)
970c0fea5dSIngo Weinhold {
980c0fea5dSIngo Weinhold 	char buffer[1024];
990c0fea5dSIngo Weinhold 
1000c0fea5dSIngo Weinhold 	va_list list;
1010c0fea5dSIngo Weinhold 	va_start(list, format);
1020c0fea5dSIngo Weinhold 
1030c0fea5dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1040c0fea5dSIngo Weinhold 	_kern_debug_output(buffer);
1050c0fea5dSIngo Weinhold 
1060c0fea5dSIngo Weinhold 	va_end(list);
1070c0fea5dSIngo Weinhold }
1080c0fea5dSIngo Weinhold #else
1090c0fea5dSIngo Weinhold #	define FATAL(x...) printf("runtime_loader: " x);
1100c0fea5dSIngo Weinhold #endif
1110c0fea5dSIngo Weinhold 
1120c0fea5dSIngo Weinhold 
11334982809SIngo Weinhold /*!	Mini atoi(), so we don't have to include the libroot dependencies.
11434982809SIngo Weinhold  */
11534982809SIngo Weinhold int
11634982809SIngo Weinhold atoi(const char* num)
11734982809SIngo Weinhold {
11834982809SIngo Weinhold 	int result = 0;
11934982809SIngo Weinhold 	while (*num >= '0' && *num <= '9') {
12034982809SIngo Weinhold 		result = (result * 10) + (*num - '0');
12134982809SIngo Weinhold 		num++;
12234982809SIngo Weinhold 	}
12334982809SIngo Weinhold 
12434982809SIngo Weinhold 	return result;
12534982809SIngo Weinhold }
12634982809SIngo Weinhold 
12734982809SIngo Weinhold 
1287486b72dSIngo Weinhold #ifdef RUNTIME_LOADER_TRACING
1297486b72dSIngo Weinhold 
1307486b72dSIngo Weinhold void
1317486b72dSIngo Weinhold ktrace_printf(const char *format, ...)
1327486b72dSIngo Weinhold {
1337486b72dSIngo Weinhold 	va_list list;
1347486b72dSIngo Weinhold 	va_start(list, format);
1357486b72dSIngo Weinhold 
1367486b72dSIngo Weinhold 	char buffer[1024];
1377486b72dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
1387486b72dSIngo Weinhold 	_kern_ktrace_output(buffer);
1397486b72dSIngo Weinhold 
1407486b72dSIngo Weinhold 	va_end(list);
1417486b72dSIngo Weinhold }
1427486b72dSIngo Weinhold 
1437486b72dSIngo Weinhold #define KTRACE(x...)	ktrace_printf(x)
1447486b72dSIngo Weinhold 
1457486b72dSIngo Weinhold #else
1467486b72dSIngo Weinhold #	define KTRACE(x...)
1477486b72dSIngo Weinhold #endif	// RUNTIME_LOADER_TRACING
1487486b72dSIngo Weinhold 
1497486b72dSIngo Weinhold 
1500c0fea5dSIngo Weinhold static void
1510c0fea5dSIngo Weinhold rld_unlock()
1520c0fea5dSIngo Weinhold {
1530c0fea5dSIngo Weinhold 	if (rld_sem_count-- == 1) {
1540c0fea5dSIngo Weinhold 		rld_sem_owner = -1;
1550c0fea5dSIngo Weinhold 		release_sem(rld_sem);
1560c0fea5dSIngo Weinhold 	}
1570c0fea5dSIngo Weinhold }
1580c0fea5dSIngo Weinhold 
1590c0fea5dSIngo Weinhold 
1600c0fea5dSIngo Weinhold static void
1610c0fea5dSIngo Weinhold rld_lock()
1620c0fea5dSIngo Weinhold {
1630c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
1640c0fea5dSIngo Weinhold 	if (self != rld_sem_owner) {
1650c0fea5dSIngo Weinhold 		acquire_sem(rld_sem);
1660c0fea5dSIngo Weinhold 		rld_sem_owner = self;
1670c0fea5dSIngo Weinhold 	}
1680c0fea5dSIngo Weinhold 	rld_sem_count++;
1690c0fea5dSIngo Weinhold }
1700c0fea5dSIngo Weinhold 
1710c0fea5dSIngo Weinhold 
1720c0fea5dSIngo Weinhold static void
1730c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image)
1740c0fea5dSIngo Weinhold {
1750c0fea5dSIngo Weinhold 	image->next = 0;
1760c0fea5dSIngo Weinhold 
1770c0fea5dSIngo Weinhold 	image->prev = queue->tail;
1780c0fea5dSIngo Weinhold 	if (queue->tail)
1790c0fea5dSIngo Weinhold 		queue->tail->next = image;
1800c0fea5dSIngo Weinhold 
1810c0fea5dSIngo Weinhold 	queue->tail = image;
1820c0fea5dSIngo Weinhold 	if (!queue->head)
1830c0fea5dSIngo Weinhold 		queue->head = image;
1840c0fea5dSIngo Weinhold }
1850c0fea5dSIngo Weinhold 
1860c0fea5dSIngo Weinhold 
1870c0fea5dSIngo Weinhold static void
1880c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image)
1890c0fea5dSIngo Weinhold {
1900c0fea5dSIngo Weinhold 	if (image->next)
1910c0fea5dSIngo Weinhold 		image->next->prev = image->prev;
1920c0fea5dSIngo Weinhold 	else
1930c0fea5dSIngo Weinhold 		queue->tail = image->prev;
1940c0fea5dSIngo Weinhold 
1950c0fea5dSIngo Weinhold 	if (image->prev)
1960c0fea5dSIngo Weinhold 		image->prev->next = image->next;
1970c0fea5dSIngo Weinhold 	else
1980c0fea5dSIngo Weinhold 		queue->head = image->next;
1990c0fea5dSIngo Weinhold 
2000c0fea5dSIngo Weinhold 	image->prev = 0;
2010c0fea5dSIngo Weinhold 	image->next = 0;
2020c0fea5dSIngo Weinhold }
2030c0fea5dSIngo Weinhold 
2040c0fea5dSIngo Weinhold 
2050c0fea5dSIngo Weinhold static uint32
2060c0fea5dSIngo Weinhold elf_hash(const uint8 *name)
2070c0fea5dSIngo Weinhold {
2080c0fea5dSIngo Weinhold 	uint32 hash = 0;
2090c0fea5dSIngo Weinhold 	uint32 temp;
2100c0fea5dSIngo Weinhold 
2110c0fea5dSIngo Weinhold 	while (*name) {
2120c0fea5dSIngo Weinhold 		hash = (hash << 4) + *name++;
2130c0fea5dSIngo Weinhold 		if ((temp = hash & 0xf0000000)) {
2140c0fea5dSIngo Weinhold 			hash ^= temp >> 24;
2150c0fea5dSIngo Weinhold 		}
2160c0fea5dSIngo Weinhold 		hash &= ~temp;
2170c0fea5dSIngo Weinhold 	}
2180c0fea5dSIngo Weinhold 	return hash;
2190c0fea5dSIngo Weinhold }
2200c0fea5dSIngo Weinhold 
2210c0fea5dSIngo Weinhold 
2224bef3723SAxel Dörfler static inline bool
2234bef3723SAxel Dörfler report_errors()
2244bef3723SAxel Dörfler {
2254bef3723SAxel Dörfler 	return gProgramArgs->error_port >= 0;
2264bef3723SAxel Dörfler }
2274bef3723SAxel Dörfler 
2284bef3723SAxel Dörfler 
2290c0fea5dSIngo Weinhold static image_t *
2300c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath,
2310c0fea5dSIngo Weinhold 	uint32 typeMask)
2320c0fea5dSIngo Weinhold {
2330c0fea5dSIngo Weinhold 	image_t *image;
2340c0fea5dSIngo Weinhold 
2350c0fea5dSIngo Weinhold 	for (image = queue->head; image; image = image->next) {
2360c0fea5dSIngo Weinhold 		const char *imageName = isPath ? image->path : image->name;
2370c0fea5dSIngo Weinhold 		int length = isPath ? sizeof(image->path) : sizeof(image->name);
2380c0fea5dSIngo Weinhold 
2390c0fea5dSIngo Weinhold 		if (!strncmp(imageName, name, length)
2400c0fea5dSIngo Weinhold 			&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
2410c0fea5dSIngo Weinhold 			return image;
2420c0fea5dSIngo Weinhold 		}
2430c0fea5dSIngo Weinhold 	}
2440c0fea5dSIngo Weinhold 
2450c0fea5dSIngo Weinhold 	return NULL;
2460c0fea5dSIngo Weinhold }
2470c0fea5dSIngo Weinhold 
2480c0fea5dSIngo Weinhold 
2490c0fea5dSIngo Weinhold static image_t *
2500c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask)
2510c0fea5dSIngo Weinhold {
2520c0fea5dSIngo Weinhold 	bool isPath = (strchr(name, '/') != NULL);
25346f4d849SIngo Weinhold 	return find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
2540c0fea5dSIngo Weinhold }
2550c0fea5dSIngo Weinhold 
2560c0fea5dSIngo Weinhold 
2570c0fea5dSIngo Weinhold static image_t *
2580c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id)
2590c0fea5dSIngo Weinhold {
2600c0fea5dSIngo Weinhold 	image_t *image;
2610c0fea5dSIngo Weinhold 
2620c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
2630c0fea5dSIngo Weinhold 		if (image->id == id)
2640c0fea5dSIngo Weinhold 			return image;
2650c0fea5dSIngo Weinhold 	}
2660c0fea5dSIngo Weinhold 
2670c0fea5dSIngo Weinhold 	// For the termination routine, we need to look into the list of
2680c0fea5dSIngo Weinhold 	// disposable images as well
2690c0fea5dSIngo Weinhold 	for (image = sDisposableImages.head; image; image = image->next) {
2700c0fea5dSIngo Weinhold 		if (image->id == id)
2710c0fea5dSIngo Weinhold 			return image;
2720c0fea5dSIngo Weinhold 	}
2730c0fea5dSIngo Weinhold 
2740c0fea5dSIngo Weinhold 	return NULL;
2750c0fea5dSIngo Weinhold }
2760c0fea5dSIngo Weinhold 
2770c0fea5dSIngo Weinhold 
2785fd6637bSIngo Weinhold static image_t*
2795fd6637bSIngo Weinhold get_program_image()
28012a5e9a4SAxel Dörfler {
28112a5e9a4SAxel Dörfler 	for (image_t *image = sLoadedImages.head; image; image = image->next) {
28212a5e9a4SAxel Dörfler 		if (image->type == B_APP_IMAGE)
2835fd6637bSIngo Weinhold 			return image;
28412a5e9a4SAxel Dörfler 	}
28512a5e9a4SAxel Dörfler 
28612a5e9a4SAxel Dörfler 	return NULL;
28712a5e9a4SAxel Dörfler }
28812a5e9a4SAxel Dörfler 
28912a5e9a4SAxel Dörfler 
2905fd6637bSIngo Weinhold static const char *
2915fd6637bSIngo Weinhold get_program_path()
2925fd6637bSIngo Weinhold {
2935fd6637bSIngo Weinhold 	if (image_t* image = get_program_image())
2945fd6637bSIngo Weinhold 		return image->path;
2955fd6637bSIngo Weinhold 
2965fd6637bSIngo Weinhold 	return NULL;
2975fd6637bSIngo Weinhold }
2985fd6637bSIngo Weinhold 
2995fd6637bSIngo Weinhold 
3000c0fea5dSIngo Weinhold static status_t
30112a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize,
30212a5e9a4SAxel Dörfler 	int32 *_sheaderSize)
3030c0fea5dSIngo Weinhold {
3040c0fea5dSIngo Weinhold 	if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
3050c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3060c0fea5dSIngo Weinhold 
3070c0fea5dSIngo Weinhold 	if (eheader->e_ident[4] != ELFCLASS32)
3080c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3090c0fea5dSIngo Weinhold 
3100c0fea5dSIngo Weinhold 	if (eheader->e_phoff == 0)
3110c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3120c0fea5dSIngo Weinhold 
3130c0fea5dSIngo Weinhold 	if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
3140c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
3150c0fea5dSIngo Weinhold 
3160c0fea5dSIngo Weinhold 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
3170c0fea5dSIngo Weinhold 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
3180c0fea5dSIngo Weinhold 
3195aa7b7b6SMarcus Overhagen 	if (*_pheaderSize <= 0 || *_sheaderSize <= 0)
3205aa7b7b6SMarcus Overhagen 		return B_NOT_AN_EXECUTABLE;
3215aa7b7b6SMarcus Overhagen 
3225aa7b7b6SMarcus Overhagen 	return B_OK;
3230c0fea5dSIngo Weinhold }
3240c0fea5dSIngo Weinhold 
3250c0fea5dSIngo Weinhold 
3260c0fea5dSIngo Weinhold static int32
3270c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize)
3280c0fea5dSIngo Weinhold {
3290c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheaders;
3300c0fea5dSIngo Weinhold 	int32 count = 0;
3310c0fea5dSIngo Weinhold 	int i;
3320c0fea5dSIngo Weinhold 
3330c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
3340c0fea5dSIngo Weinhold 		pheaders = (struct Elf32_Phdr *)(buff + i * phentsize);
3350c0fea5dSIngo Weinhold 
3360c0fea5dSIngo Weinhold 		switch (pheaders->p_type) {
3370c0fea5dSIngo Weinhold 			case PT_NULL:
3380c0fea5dSIngo Weinhold 				/* NOP header */
3390c0fea5dSIngo Weinhold 				break;
3400c0fea5dSIngo Weinhold 			case PT_LOAD:
3410c0fea5dSIngo Weinhold 				count += 1;
3420c0fea5dSIngo Weinhold 				if (pheaders->p_memsz != pheaders->p_filesz) {
3430c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz);
3440c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz);
3450c0fea5dSIngo Weinhold 
3460c0fea5dSIngo Weinhold 					if (A != B)
3470c0fea5dSIngo Weinhold 						count += 1;
3480c0fea5dSIngo Weinhold 				}
3490c0fea5dSIngo Weinhold 				break;
3500c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
3510c0fea5dSIngo Weinhold 				/* will be handled at some other place */
3520c0fea5dSIngo Weinhold 				break;
3530c0fea5dSIngo Weinhold 			case PT_INTERP:
3540c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
3550c0fea5dSIngo Weinhold 				break;
3560c0fea5dSIngo Weinhold 			case PT_NOTE:
3570c0fea5dSIngo Weinhold 				/* unsupported */
3580c0fea5dSIngo Weinhold 				break;
3590c0fea5dSIngo Weinhold 			case PT_SHLIB:
3600c0fea5dSIngo Weinhold 				/* undefined semantics */
3610c0fea5dSIngo Weinhold 				break;
3620c0fea5dSIngo Weinhold 			case PT_PHDR:
3630c0fea5dSIngo Weinhold 				/* we don't use it */
3640c0fea5dSIngo Weinhold 				break;
3650c0fea5dSIngo Weinhold 			default:
3660c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type);
3670c0fea5dSIngo Weinhold 				return B_BAD_DATA;
3680c0fea5dSIngo Weinhold 		}
3690c0fea5dSIngo Weinhold 	}
3700c0fea5dSIngo Weinhold 
3710c0fea5dSIngo Weinhold 	return count;
3720c0fea5dSIngo Weinhold }
3730c0fea5dSIngo Weinhold 
3740c0fea5dSIngo Weinhold 
3750c0fea5dSIngo Weinhold /*
3760c0fea5dSIngo Weinhold  * create_image() & destroy_image()
3770c0fea5dSIngo Weinhold  *
3780c0fea5dSIngo Weinhold  * 	Create and destroy image_t structures. The destroyer makes sure that the
3790c0fea5dSIngo Weinhold  * 	memory buffers are full of garbage before freeing.
3800c0fea5dSIngo Weinhold  */
3810c0fea5dSIngo Weinhold 
3820c0fea5dSIngo Weinhold static image_t *
3830c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions)
3840c0fea5dSIngo Weinhold {
3850c0fea5dSIngo Weinhold 	size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t);
3860c0fea5dSIngo Weinhold 	const char *lastSlash;
3870c0fea5dSIngo Weinhold 
3880c0fea5dSIngo Weinhold 	image_t *image = (image_t*)malloc(allocSize);
3890c0fea5dSIngo Weinhold 	if (image == NULL) {
3900c0fea5dSIngo Weinhold 		FATAL("no memory for image %s\n", path);
3910c0fea5dSIngo Weinhold 		return NULL;
3920c0fea5dSIngo Weinhold 	}
3930c0fea5dSIngo Weinhold 
3940c0fea5dSIngo Weinhold 	memset(image, 0, allocSize);
3950c0fea5dSIngo Weinhold 
3960c0fea5dSIngo Weinhold 	strlcpy(image->path, path, sizeof(image->path));
3970c0fea5dSIngo Weinhold 
3980c0fea5dSIngo Weinhold 	// Make the last component of the supplied name the image name.
3990c0fea5dSIngo Weinhold 	// If present, DT_SONAME will replace this name.
4000c0fea5dSIngo Weinhold 	if ((lastSlash = strrchr(name, '/')))
4010c0fea5dSIngo Weinhold 		strlcpy(image->name, lastSlash + 1, sizeof(image->name));
4020c0fea5dSIngo Weinhold 	else
4030c0fea5dSIngo Weinhold 		strlcpy(image->name, name, sizeof(image->name));
4040c0fea5dSIngo Weinhold 
4050c0fea5dSIngo Weinhold 	image->ref_count = 1;
4060c0fea5dSIngo Weinhold 	image->num_regions = num_regions;
4070c0fea5dSIngo Weinhold 
4080c0fea5dSIngo Weinhold 	return image;
4090c0fea5dSIngo Weinhold }
4100c0fea5dSIngo Weinhold 
4110c0fea5dSIngo Weinhold 
4120c0fea5dSIngo Weinhold static void
4130c0fea5dSIngo Weinhold delete_image_struct(image_t *image)
4140c0fea5dSIngo Weinhold {
4150c0fea5dSIngo Weinhold #ifdef DEBUG
4160c0fea5dSIngo Weinhold 	size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t);
4170c0fea5dSIngo Weinhold 	memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
4180c0fea5dSIngo Weinhold #endif
4190c0fea5dSIngo Weinhold 	free(image->needed);
4200c0fea5dSIngo Weinhold 
4210c0fea5dSIngo Weinhold #ifdef DEBUG
4220c0fea5dSIngo Weinhold 	memset(image, 0xa5, size);
4230c0fea5dSIngo Weinhold #endif
4240c0fea5dSIngo Weinhold 	free(image);
4250c0fea5dSIngo Weinhold }
4260c0fea5dSIngo Weinhold 
4270c0fea5dSIngo Weinhold 
4280c0fea5dSIngo Weinhold static void
4290c0fea5dSIngo Weinhold delete_image(image_t *image)
4300c0fea5dSIngo Weinhold {
4312760c4cdSAxel Dörfler 	if (image == NULL)
4322760c4cdSAxel Dörfler 		return;
4332760c4cdSAxel Dörfler 
4340c0fea5dSIngo Weinhold 	_kern_unregister_image(image->id);
4350c0fea5dSIngo Weinhold 		// registered in load_container()
4360c0fea5dSIngo Weinhold 
4370c0fea5dSIngo Weinhold 	delete_image_struct(image);
4380c0fea5dSIngo Weinhold }
4390c0fea5dSIngo Weinhold 
4400c0fea5dSIngo Weinhold 
4410c0fea5dSIngo Weinhold static status_t
4420c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
4430c0fea5dSIngo Weinhold {
4440c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheader;
4450c0fea5dSIngo Weinhold 	int regcount;
4460c0fea5dSIngo Weinhold 	int i;
4470c0fea5dSIngo Weinhold 
4480c0fea5dSIngo Weinhold 	regcount = 0;
4490c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
4500c0fea5dSIngo Weinhold 		pheader = (struct Elf32_Phdr *)(buff + i * phentsize);
4510c0fea5dSIngo Weinhold 
4520c0fea5dSIngo Weinhold 		switch (pheader->p_type) {
4530c0fea5dSIngo Weinhold 			case PT_NULL:
4540c0fea5dSIngo Weinhold 				/* NOP header */
4550c0fea5dSIngo Weinhold 				break;
4560c0fea5dSIngo Weinhold 			case PT_LOAD:
4570c0fea5dSIngo Weinhold 				if (pheader->p_memsz == pheader->p_filesz) {
4580c0fea5dSIngo Weinhold 					/*
4590c0fea5dSIngo Weinhold 					 * everything in one area
4600c0fea5dSIngo Weinhold 					 */
4610c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
4620c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_memsz;
4630c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
4640c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz
4650c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
4660c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
4670c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
4680c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
4690c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
4700c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
4710c0fea5dSIngo Weinhold 						// this is a writable segment
4720c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
4730c0fea5dSIngo Weinhold 					}
4740c0fea5dSIngo Weinhold 				} else {
4750c0fea5dSIngo Weinhold 					/*
4760c0fea5dSIngo Weinhold 					 * may require splitting
4770c0fea5dSIngo Weinhold 					 */
4780c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz);
4790c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz);
4800c0fea5dSIngo Weinhold 
4810c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
4820c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_filesz;
4830c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
4840c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz
4850c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
4860c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
4870c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
4880c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
4890c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
4900c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
4910c0fea5dSIngo Weinhold 						// this is a writable segment
4920c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
4930c0fea5dSIngo Weinhold 					}
4940c0fea5dSIngo Weinhold 
4950c0fea5dSIngo Weinhold 					if (A != B) {
4960c0fea5dSIngo Weinhold 						/*
4970c0fea5dSIngo Weinhold 						 * yeah, it requires splitting
4980c0fea5dSIngo Weinhold 						 */
4990c0fea5dSIngo Weinhold 						regcount += 1;
5000c0fea5dSIngo Weinhold 						image->regions[regcount].start = pheader->p_vaddr;
5010c0fea5dSIngo Weinhold 						image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz;
5020c0fea5dSIngo Weinhold 						image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
5030c0fea5dSIngo Weinhold 						image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr))
5040c0fea5dSIngo Weinhold 							- image->regions[regcount-1].vmsize;
5050c0fea5dSIngo Weinhold 						image->regions[regcount].fdstart = 0;
5060c0fea5dSIngo Weinhold 						image->regions[regcount].fdsize = 0;
5070c0fea5dSIngo Weinhold 						image->regions[regcount].delta = 0;
5080c0fea5dSIngo Weinhold 						image->regions[regcount].flags = RFLAG_ANON;
5090c0fea5dSIngo Weinhold 						if (pheader->p_flags & PF_WRITE) {
5100c0fea5dSIngo Weinhold 							// this is a writable segment
5110c0fea5dSIngo Weinhold 							image->regions[regcount].flags |= RFLAG_RW;
5120c0fea5dSIngo Weinhold 						}
5130c0fea5dSIngo Weinhold 					}
5140c0fea5dSIngo Weinhold 				}
5150c0fea5dSIngo Weinhold 				regcount += 1;
5160c0fea5dSIngo Weinhold 				break;
5170c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
5180c0fea5dSIngo Weinhold 				image->dynamic_ptr = pheader->p_vaddr;
5190c0fea5dSIngo Weinhold 				break;
5200c0fea5dSIngo Weinhold 			case PT_INTERP:
5210c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
5220c0fea5dSIngo Weinhold 				break;
5230c0fea5dSIngo Weinhold 			case PT_NOTE:
5240c0fea5dSIngo Weinhold 				/* unsupported */
5250c0fea5dSIngo Weinhold 				break;
5260c0fea5dSIngo Weinhold 			case PT_SHLIB:
5270c0fea5dSIngo Weinhold 				/* undefined semantics */
5280c0fea5dSIngo Weinhold 				break;
5290c0fea5dSIngo Weinhold 			case PT_PHDR:
5300c0fea5dSIngo Weinhold 				/* we don't use it */
5310c0fea5dSIngo Weinhold 				break;
5320c0fea5dSIngo Weinhold 			default:
5330c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type);
5340c0fea5dSIngo Weinhold 				return B_BAD_DATA;
5350c0fea5dSIngo Weinhold 		}
5360c0fea5dSIngo Weinhold 	}
5370c0fea5dSIngo Weinhold 
5380c0fea5dSIngo Weinhold 	return B_OK;
5390c0fea5dSIngo Weinhold }
5400c0fea5dSIngo Weinhold 
5410c0fea5dSIngo Weinhold 
5420c0fea5dSIngo Weinhold static bool
54334982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader,
54434982809SIngo Weinhold 	int32 sheaderSize, char* buffer, size_t bufferSize)
54534982809SIngo Weinhold {
54634982809SIngo Weinhold 	image->gcc_version.major = 0;
54734982809SIngo Weinhold 	image->gcc_version.middle = 0;
54834982809SIngo Weinhold 	image->gcc_version.minor = 0;
54934982809SIngo Weinhold 
55034982809SIngo Weinhold 	if (sheaderSize > (int)bufferSize) {
55134982809SIngo Weinhold 		FATAL("Cannot handle section headers bigger than %lu\n", bufferSize);
55234982809SIngo Weinhold 		return false;
55334982809SIngo Weinhold 	}
55434982809SIngo Weinhold 
55534982809SIngo Weinhold 	// read section headers
55634982809SIngo Weinhold 	ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize);
55734982809SIngo Weinhold 	if (length != sheaderSize) {
55834982809SIngo Weinhold 		FATAL("Could not read section headers: %s\n", strerror(length));
55934982809SIngo Weinhold 		return false;
56034982809SIngo Weinhold 	}
56134982809SIngo Weinhold 
56234982809SIngo Weinhold 	// load the string section
56334982809SIngo Weinhold 	Elf32_Shdr* sectionHeader
56434982809SIngo Weinhold 		= (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize);
56534982809SIngo Weinhold 
56634982809SIngo Weinhold 	if (sheaderSize + sectionHeader->sh_size > bufferSize) {
56734982809SIngo Weinhold 		FATAL("Buffer not big enough for section string section\n");
56834982809SIngo Weinhold 		return false;
56934982809SIngo Weinhold 	}
57034982809SIngo Weinhold 
57134982809SIngo Weinhold 	char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size;
57234982809SIngo Weinhold 	length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings,
57334982809SIngo Weinhold 		sectionHeader->sh_size);
57434982809SIngo Weinhold 	if (length != (int)sectionHeader->sh_size) {
57534982809SIngo Weinhold 		FATAL("Could not read section string section: %s\n", strerror(length));
57634982809SIngo Weinhold 		return false;
57734982809SIngo Weinhold 	}
57834982809SIngo Weinhold 
57934982809SIngo Weinhold 	// find the .comment section
58034982809SIngo Weinhold 	off_t commentOffset = 0;
58134982809SIngo Weinhold 	size_t commentSize = 0;
58234982809SIngo Weinhold 	for (uint32 i = 0; i < eheader.e_shnum; i++) {
58334982809SIngo Weinhold 		sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize);
58434982809SIngo Weinhold 		const char* sectionName = sectionStrings + sectionHeader->sh_name;
58534982809SIngo Weinhold 		if (sectionHeader->sh_name != 0
58634982809SIngo Weinhold 			&& strcmp(sectionName, ".comment") == 0) {
58734982809SIngo Weinhold 			commentOffset = sectionHeader->sh_offset;
58834982809SIngo Weinhold 			commentSize = sectionHeader->sh_size;
58934982809SIngo Weinhold 			break;
59034982809SIngo Weinhold 		}
59134982809SIngo Weinhold 	}
59234982809SIngo Weinhold 
59334982809SIngo Weinhold 	if (commentSize == 0) {
59434982809SIngo Weinhold 		FATAL("Could not find .comment section\n");
59534982809SIngo Weinhold 		return false;
59634982809SIngo Weinhold 	}
59734982809SIngo Weinhold 
59834982809SIngo Weinhold 	// read a part of the comment section
59934982809SIngo Weinhold 	if (commentSize > 512)
60034982809SIngo Weinhold 		commentSize = 512;
60134982809SIngo Weinhold 
60234982809SIngo Weinhold 	length = _kern_read(fd, commentOffset, buffer, commentSize);
60334982809SIngo Weinhold 	if (length != (int)commentSize) {
60434982809SIngo Weinhold 		FATAL("Could not read .comment section: %s\n", strerror(length));
60534982809SIngo Weinhold 		return false;
60634982809SIngo Weinhold 	}
60734982809SIngo Weinhold 
60834982809SIngo Weinhold 	// the common prefix of the strings in the .comment section
60934982809SIngo Weinhold 	static const char* kGCCVersionPrefix = "GCC: (GNU) ";
61034982809SIngo Weinhold 	size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix);
61134982809SIngo Weinhold 
61234982809SIngo Weinhold 	size_t index = 0;
61334982809SIngo Weinhold 	int gccMajor = 0;
61434982809SIngo Weinhold 	int gccMiddle = 0;
61534982809SIngo Weinhold 	int gccMinor = 0;
61634982809SIngo Weinhold 
61734982809SIngo Weinhold 	// Read up to 10 comments. The first three or four are usually from the
61834982809SIngo Weinhold 	// glue code.
61934982809SIngo Weinhold 	for (int i = 0; i < 10; i++) {
62034982809SIngo Weinhold 		// skip '\0'
62134982809SIngo Weinhold 		while (index < commentSize && buffer[index] == '\0')
62234982809SIngo Weinhold 			index++;
62334982809SIngo Weinhold 		char* stringStart = buffer + index;
62434982809SIngo Weinhold 
62534982809SIngo Weinhold 		// find string end
62634982809SIngo Weinhold 		while (index < commentSize && buffer[index] != '\0')
62734982809SIngo Weinhold 			index++;
62834982809SIngo Weinhold 
62934982809SIngo Weinhold 		// ignore the entry at the end of the buffer
63034982809SIngo Weinhold 		if (index == commentSize)
63134982809SIngo Weinhold 			break;
63234982809SIngo Weinhold 
63334982809SIngo Weinhold 		// We have to analyze string like these:
63434982809SIngo Weinhold 		// GCC: (GNU) 2.9-beos-991026
63534982809SIngo Weinhold 		// GCC: (GNU) 2.95.3-haiku-080322
63634982809SIngo Weinhold 		// GCC: (GNU) 4.1.2
63734982809SIngo Weinhold 
63834982809SIngo Weinhold 		// skip the common prefix
63934982809SIngo Weinhold 		if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0)
64034982809SIngo Weinhold 			continue;
64134982809SIngo Weinhold 
64234982809SIngo Weinhold 		// the rest is the GCC version
64334982809SIngo Weinhold 		char* gccVersion = stringStart + gccVersionPrefixLen;
64434982809SIngo Weinhold 		char* gccPlatform = strchr(gccVersion, '-');
64534982809SIngo Weinhold 		char* patchLevel = NULL;
64634982809SIngo Weinhold 		if (gccPlatform != NULL) {
64734982809SIngo Weinhold 			*gccPlatform = '\0';
64834982809SIngo Weinhold 			gccPlatform++;
64934982809SIngo Weinhold 			patchLevel = strchr(gccPlatform, '-');
65034982809SIngo Weinhold 			if (patchLevel != NULL) {
65134982809SIngo Weinhold 				*patchLevel = '\0';
65234982809SIngo Weinhold 				patchLevel++;
65334982809SIngo Weinhold 			}
65434982809SIngo Weinhold 		}
65534982809SIngo Weinhold 
65634982809SIngo Weinhold 		// split the gcc version into major, middle, and minor
65734982809SIngo Weinhold 		int version[3] = { 0, 0, 0 };
65834982809SIngo Weinhold 
65934982809SIngo Weinhold 		for (int k = 0; gccVersion != NULL && k < 3; k++) {
66034982809SIngo Weinhold 			char* dot = strchr(gccVersion, '.');
66134982809SIngo Weinhold 			if (dot) {
66234982809SIngo Weinhold 				*dot = '\0';
66334982809SIngo Weinhold 				dot++;
66434982809SIngo Weinhold 			}
66534982809SIngo Weinhold 			version[k] = atoi(gccVersion);
66634982809SIngo Weinhold 			gccVersion = dot;
66734982809SIngo Weinhold 		}
66834982809SIngo Weinhold 
66934982809SIngo Weinhold 		// got any version?
67034982809SIngo Weinhold 		if (version[0] == 0)
67134982809SIngo Weinhold 			continue;
67234982809SIngo Weinhold 
67334982809SIngo Weinhold 		// Select the gcc version with the smallest major, but the greatest
67434982809SIngo Weinhold 		// middle/minor. This should usually ignore the glue code version as
67534982809SIngo Weinhold 		// well as cases where e.g. in a gcc 2 program a single C file has
67634982809SIngo Weinhold 		// been compiled with gcc 4.
67734982809SIngo Weinhold 		if (gccMajor == 0 || gccMajor > version[0]
67834982809SIngo Weinhold 		 	|| gccMajor == version[0]
67934982809SIngo Weinhold 				&& (gccMiddle < version[1]
68034982809SIngo Weinhold 					|| gccMiddle == version[1] && gccMinor < version[2])) {
68134982809SIngo Weinhold 			gccMajor = version[0];
68234982809SIngo Weinhold 			gccMiddle = version[1];
68334982809SIngo Weinhold 			gccMinor = version[2];
68434982809SIngo Weinhold 		}
68534982809SIngo Weinhold 	}
68634982809SIngo Weinhold 
68734982809SIngo Weinhold 	image->gcc_version.major = gccMajor;
68834982809SIngo Weinhold 	image->gcc_version.middle = gccMiddle;
68934982809SIngo Weinhold 	image->gcc_version.minor = gccMinor;
69034982809SIngo Weinhold 
69134982809SIngo Weinhold 	return gccMajor != 0;
69234982809SIngo Weinhold }
69334982809SIngo Weinhold 
69434982809SIngo Weinhold 
69534982809SIngo Weinhold static bool
6960c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image)
6970c0fea5dSIngo Weinhold {
6980c0fea5dSIngo Weinhold 	uint32 i;
6990c0fea5dSIngo Weinhold 
7000c0fea5dSIngo Weinhold 	if (!image->dynamic_ptr)
7010c0fea5dSIngo Weinhold 		return true;
7020c0fea5dSIngo Weinhold 
7030c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
7040c0fea5dSIngo Weinhold 		if (image->dynamic_ptr >= image->regions[i].start
7050c0fea5dSIngo Weinhold 			&& image->dynamic_ptr < image->regions[i].start + image->regions[i].size)
7060c0fea5dSIngo Weinhold 			return true;
7070c0fea5dSIngo Weinhold 	}
7080c0fea5dSIngo Weinhold 
7090c0fea5dSIngo Weinhold 	return false;
7100c0fea5dSIngo Weinhold }
7110c0fea5dSIngo Weinhold 
7120c0fea5dSIngo Weinhold 
7130c0fea5dSIngo Weinhold /**	This function will change the protection of all read-only segments
7140c0fea5dSIngo Weinhold  *	to really be read-only.
7150c0fea5dSIngo Weinhold  *	The areas have to be read/write first, so that they can be relocated.
7160c0fea5dSIngo Weinhold  */
7170c0fea5dSIngo Weinhold 
7180c0fea5dSIngo Weinhold static void
7190c0fea5dSIngo Weinhold remap_images(void)
7200c0fea5dSIngo Weinhold {
7210c0fea5dSIngo Weinhold 	image_t *image;
7220c0fea5dSIngo Weinhold 	uint32 i;
7230c0fea5dSIngo Weinhold 
7240c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
7250c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_regions; i++) {
7260c0fea5dSIngo Weinhold 			if ((image->regions[i].flags & RFLAG_RW) == 0
7270c0fea5dSIngo Weinhold 				&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
7280c0fea5dSIngo Weinhold 				// we only need to do this once, so we remember those we've already mapped
7290c0fea5dSIngo Weinhold 				if (_kern_set_area_protection(image->regions[i].id,
7300c0fea5dSIngo Weinhold 						B_READ_AREA | B_EXECUTE_AREA) == B_OK)
7310c0fea5dSIngo Weinhold 					image->regions[i].flags |= RFLAG_REMAPPED;
7320c0fea5dSIngo Weinhold 			}
7330c0fea5dSIngo Weinhold 		}
7340c0fea5dSIngo Weinhold 	}
7350c0fea5dSIngo Weinhold }
7360c0fea5dSIngo Weinhold 
7370c0fea5dSIngo Weinhold 
7380c0fea5dSIngo Weinhold static status_t
7390c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed)
7400c0fea5dSIngo Weinhold {
7410c0fea5dSIngo Weinhold 	status_t status = B_OK;
7420c0fea5dSIngo Weinhold 	const char *baseName;
7430c0fea5dSIngo Weinhold 	uint32 i;
7440c0fea5dSIngo Weinhold 
7450c0fea5dSIngo Weinhold 	(void)(fd);
7460c0fea5dSIngo Weinhold 
7470c0fea5dSIngo Weinhold 	// cut the file name from the path as base name for the created areas
7480c0fea5dSIngo Weinhold 	baseName = strrchr(path, '/');
7490c0fea5dSIngo Weinhold 	if (baseName != NULL)
7500c0fea5dSIngo Weinhold 		baseName++;
7510c0fea5dSIngo Weinhold 	else
7520c0fea5dSIngo Weinhold 		baseName = path;
7530c0fea5dSIngo Weinhold 
7540c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
7550c0fea5dSIngo Weinhold 		char regionName[B_OS_NAME_LENGTH];
7560c0fea5dSIngo Weinhold 		addr_t loadAddress;
7570c0fea5dSIngo Weinhold 		uint32 addressSpecifier;
7580c0fea5dSIngo Weinhold 
7590c0fea5dSIngo Weinhold 		// for BeOS compatibility: if we load an old BeOS executable, we
7600c0fea5dSIngo Weinhold 		// have to relocate it, if possible - we recognize it because the
7610c0fea5dSIngo Weinhold 		// vmstart is set to 0 (hopefully always)
7620c0fea5dSIngo Weinhold 		if (fixed && image->regions[i].vmstart == 0)
7630c0fea5dSIngo Weinhold 			fixed = false;
7640c0fea5dSIngo Weinhold 
7650c0fea5dSIngo Weinhold 		snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
7660c0fea5dSIngo Weinhold 			baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
7670c0fea5dSIngo Weinhold 
7680c0fea5dSIngo Weinhold 		if (image->dynamic_ptr && !fixed) {
7690c0fea5dSIngo Weinhold 			// relocatable image... we can afford to place wherever
7700c0fea5dSIngo Weinhold 			if (i == 0) {
7710c0fea5dSIngo Weinhold 				// but only the first segment gets a free ride
7720c0fea5dSIngo Weinhold 				loadAddress = RLD_PROGRAM_BASE;
7730c0fea5dSIngo Weinhold 				addressSpecifier = B_BASE_ADDRESS;
7740c0fea5dSIngo Weinhold 			} else {
7750c0fea5dSIngo Weinhold 				loadAddress = image->regions[i].vmstart + image->regions[i-1].delta;
7760c0fea5dSIngo Weinhold 				addressSpecifier = B_EXACT_ADDRESS;
7770c0fea5dSIngo Weinhold 			}
7780c0fea5dSIngo Weinhold 		} else {
7790c0fea5dSIngo Weinhold 			// not relocatable, put it where it asks or die trying
7800c0fea5dSIngo Weinhold 			loadAddress = image->regions[i].vmstart;
7810c0fea5dSIngo Weinhold 			addressSpecifier = B_EXACT_ADDRESS;
7820c0fea5dSIngo Weinhold 		}
7830c0fea5dSIngo Weinhold 
7840c0fea5dSIngo Weinhold 		if (image->regions[i].flags & RFLAG_ANON) {
7850c0fea5dSIngo Weinhold 			image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress,
7860c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_NO_LOCK,
7870c0fea5dSIngo Weinhold 				B_READ_AREA | B_WRITE_AREA);
7880c0fea5dSIngo Weinhold 
7890c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
7900c0fea5dSIngo Weinhold 				status = image->regions[i].id;
7910c0fea5dSIngo Weinhold 				goto error;
7920c0fea5dSIngo Weinhold 			}
7930c0fea5dSIngo Weinhold 
7940c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
7950c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
7960c0fea5dSIngo Weinhold 		} else {
7970c0fea5dSIngo Weinhold 			image->regions[i].id = sys_vm_map_file(regionName, (void **)&loadAddress,
7980c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
7990c0fea5dSIngo Weinhold 				REGION_PRIVATE_MAP, path, PAGE_BASE(image->regions[i].fdstart));
8000c0fea5dSIngo Weinhold 
8010c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
8020c0fea5dSIngo Weinhold 				status = image->regions[i].id;
8030c0fea5dSIngo Weinhold 				goto error;
8040c0fea5dSIngo Weinhold 			}
8050c0fea5dSIngo Weinhold 
8060c0fea5dSIngo Weinhold 			TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
8070c0fea5dSIngo Weinhold 				(void *)loadAddress, image->regions[i].vmsize,
8080c0fea5dSIngo Weinhold 				image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
8090c0fea5dSIngo Weinhold 
8100c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
8110c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
8120c0fea5dSIngo Weinhold 
8130c0fea5dSIngo Weinhold 			// handle trailer bits in data segment
8140c0fea5dSIngo Weinhold 			if (image->regions[i].flags & RFLAG_RW) {
8150c0fea5dSIngo Weinhold 				addr_t startClearing;
8160c0fea5dSIngo Weinhold 				addr_t toClear;
8170c0fea5dSIngo Weinhold 
8180c0fea5dSIngo Weinhold 				startClearing = image->regions[i].vmstart
8190c0fea5dSIngo Weinhold 					+ PAGE_OFFSET(image->regions[i].start)
8200c0fea5dSIngo Weinhold 					+ image->regions[i].size;
8210c0fea5dSIngo Weinhold 				toClear = image->regions[i].vmsize
8220c0fea5dSIngo Weinhold 					- PAGE_OFFSET(image->regions[i].start)
8230c0fea5dSIngo Weinhold 					- image->regions[i].size;
8240c0fea5dSIngo Weinhold 
8250c0fea5dSIngo Weinhold 				TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear));
8260c0fea5dSIngo Weinhold 				memset((void *)startClearing, 0, toClear);
8270c0fea5dSIngo Weinhold 			}
8280c0fea5dSIngo Weinhold 		}
8290c0fea5dSIngo Weinhold 	}
8300c0fea5dSIngo Weinhold 
8310c0fea5dSIngo Weinhold 	if (image->dynamic_ptr)
8320c0fea5dSIngo Weinhold 		image->dynamic_ptr += image->regions[0].delta;
8330c0fea5dSIngo Weinhold 
8340c0fea5dSIngo Weinhold 	return B_OK;
8350c0fea5dSIngo Weinhold 
8360c0fea5dSIngo Weinhold error:
8370c0fea5dSIngo Weinhold 	return status;
8380c0fea5dSIngo Weinhold }
8390c0fea5dSIngo Weinhold 
8400c0fea5dSIngo Weinhold 
8410c0fea5dSIngo Weinhold static void
8420c0fea5dSIngo Weinhold unmap_image(image_t *image)
8430c0fea5dSIngo Weinhold {
8440c0fea5dSIngo Weinhold 	uint32 i;
8450c0fea5dSIngo Weinhold 
8460c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
8470c0fea5dSIngo Weinhold 		_kern_delete_area(image->regions[i].id);
8480c0fea5dSIngo Weinhold 
8490c0fea5dSIngo Weinhold 		image->regions[i].id = -1;
8500c0fea5dSIngo Weinhold 	}
8510c0fea5dSIngo Weinhold }
8520c0fea5dSIngo Weinhold 
8530c0fea5dSIngo Weinhold 
8540c0fea5dSIngo Weinhold static bool
8550c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image)
8560c0fea5dSIngo Weinhold {
8570c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d;
8580c0fea5dSIngo Weinhold 	int i;
8590c0fea5dSIngo Weinhold 	int sonameOffset = -1;
8600c0fea5dSIngo Weinhold 
8610c0fea5dSIngo Weinhold 	image->symhash = 0;
8620c0fea5dSIngo Weinhold 	image->syms = 0;
8630c0fea5dSIngo Weinhold 	image->strtab = 0;
8640c0fea5dSIngo Weinhold 
8650c0fea5dSIngo Weinhold 	d = (struct Elf32_Dyn *)image->dynamic_ptr;
8660c0fea5dSIngo Weinhold 	if (!d)
8670c0fea5dSIngo Weinhold 		return true;
8680c0fea5dSIngo Weinhold 
8690c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
8700c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
8710c0fea5dSIngo Weinhold 			case DT_NEEDED:
8720c0fea5dSIngo Weinhold 				image->num_needed += 1;
8730c0fea5dSIngo Weinhold 				break;
8740c0fea5dSIngo Weinhold 			case DT_HASH:
8750c0fea5dSIngo Weinhold 				image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta);
8760c0fea5dSIngo Weinhold 				break;
8770c0fea5dSIngo Weinhold 			case DT_STRTAB:
8780c0fea5dSIngo Weinhold 				image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
8790c0fea5dSIngo Weinhold 				break;
8800c0fea5dSIngo Weinhold 			case DT_SYMTAB:
8810c0fea5dSIngo Weinhold 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
8820c0fea5dSIngo Weinhold 				break;
8830c0fea5dSIngo Weinhold 			case DT_REL:
8840c0fea5dSIngo Weinhold 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
8850c0fea5dSIngo Weinhold 				break;
8860c0fea5dSIngo Weinhold 			case DT_RELSZ:
8870c0fea5dSIngo Weinhold 				image->rel_len = d[i].d_un.d_val;
8880c0fea5dSIngo Weinhold 				break;
8890c0fea5dSIngo Weinhold 			case DT_RELA:
8900c0fea5dSIngo Weinhold 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
8910c0fea5dSIngo Weinhold 				break;
8920c0fea5dSIngo Weinhold 			case DT_RELASZ:
8930c0fea5dSIngo Weinhold 				image->rela_len = d[i].d_un.d_val;
8940c0fea5dSIngo Weinhold 				break;
8950c0fea5dSIngo Weinhold 			// TK: procedure linkage table
8960c0fea5dSIngo Weinhold 			case DT_JMPREL:
8970c0fea5dSIngo Weinhold 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
8980c0fea5dSIngo Weinhold 				break;
8990c0fea5dSIngo Weinhold 			case DT_PLTRELSZ:
9000c0fea5dSIngo Weinhold 				image->pltrel_len = d[i].d_un.d_val;
9010c0fea5dSIngo Weinhold 				break;
9020c0fea5dSIngo Weinhold 			case DT_INIT:
9030c0fea5dSIngo Weinhold 				image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
9040c0fea5dSIngo Weinhold 				break;
9050c0fea5dSIngo Weinhold 			case DT_FINI:
9060c0fea5dSIngo Weinhold 				image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
9070c0fea5dSIngo Weinhold 				break;
9080c0fea5dSIngo Weinhold 			case DT_SONAME:
9090c0fea5dSIngo Weinhold 				sonameOffset = d[i].d_un.d_val;
9100c0fea5dSIngo Weinhold 				break;
9110c0fea5dSIngo Weinhold 			default:
9120c0fea5dSIngo Weinhold 				continue;
9130c0fea5dSIngo Weinhold 		}
9140c0fea5dSIngo Weinhold 	}
9150c0fea5dSIngo Weinhold 
9160c0fea5dSIngo Weinhold 	// lets make sure we found all the required sections
9170c0fea5dSIngo Weinhold 	if (!image->symhash || !image->syms || !image->strtab)
9180c0fea5dSIngo Weinhold 		return false;
9190c0fea5dSIngo Weinhold 
9200c0fea5dSIngo Weinhold 	if (sonameOffset >= 0)
9210c0fea5dSIngo Weinhold 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
9220c0fea5dSIngo Weinhold 
9230c0fea5dSIngo Weinhold 	return true;
9240c0fea5dSIngo Weinhold }
9250c0fea5dSIngo Weinhold 
9260c0fea5dSIngo Weinhold 
9270c0fea5dSIngo Weinhold static struct Elf32_Sym *
9280c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type)
9290c0fea5dSIngo Weinhold {
9300c0fea5dSIngo Weinhold 	uint32 hash, i;
9310c0fea5dSIngo Weinhold 
9320c0fea5dSIngo Weinhold 	// ToDo: "type" is currently ignored!
9330c0fea5dSIngo Weinhold 	(void)type;
9340c0fea5dSIngo Weinhold 
935dd76bc97SIngo Weinhold 	if (image->dynamic_ptr == 0)
9360c0fea5dSIngo Weinhold 		return NULL;
9370c0fea5dSIngo Weinhold 
9380c0fea5dSIngo Weinhold 	hash = elf_hash((uint8 *)name) % HASHTABSIZE(image);
9390c0fea5dSIngo Weinhold 
9400c0fea5dSIngo Weinhold 	for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
9410c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = &image->syms[i];
9420c0fea5dSIngo Weinhold 
9430c0fea5dSIngo Weinhold 		if (symbol->st_shndx != SHN_UNDEF
9440c0fea5dSIngo Weinhold 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
9450c0fea5dSIngo Weinhold 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
9460c0fea5dSIngo Weinhold 			&& !strcmp(SYMNAME(image, symbol), name)) {
9470c0fea5dSIngo Weinhold 			// check if the type matches
9480c0fea5dSIngo Weinhold 			if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
9490c0fea5dSIngo Weinhold 				|| (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT))
9500c0fea5dSIngo Weinhold 				continue;
9510c0fea5dSIngo Weinhold 
9520c0fea5dSIngo Weinhold 			return symbol;
9530c0fea5dSIngo Weinhold 		}
9540c0fea5dSIngo Weinhold 	}
9550c0fea5dSIngo Weinhold 
9560c0fea5dSIngo Weinhold 	return NULL;
9570c0fea5dSIngo Weinhold }
9580c0fea5dSIngo Weinhold 
9590c0fea5dSIngo Weinhold 
9600c0fea5dSIngo Weinhold static struct Elf32_Sym*
96146f4d849SIngo Weinhold find_symbol_recursively_impl(image_t* image, const char* name,
96246f4d849SIngo Weinhold 	image_t** foundInImage)
9630c0fea5dSIngo Weinhold {
96446f4d849SIngo Weinhold 	image->flags |= RFLAG_VISITED;
9650c0fea5dSIngo Weinhold 
9660c0fea5dSIngo Weinhold 	struct Elf32_Sym *symbol;
9670c0fea5dSIngo Weinhold 
96846f4d849SIngo Weinhold 	// look up the symbol in this image
96946f4d849SIngo Weinhold 	if (image->dynamic_ptr) {
9700c0fea5dSIngo Weinhold 		symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY);
9710c0fea5dSIngo Weinhold 		if (symbol) {
97246f4d849SIngo Weinhold 			*foundInImage = image;
97346f4d849SIngo Weinhold 			return symbol;
97446f4d849SIngo Weinhold 		}
97546f4d849SIngo Weinhold 	}
97646f4d849SIngo Weinhold 
97746f4d849SIngo Weinhold 	// recursively search dependencies
97846f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
97946f4d849SIngo Weinhold 		if (!(image->needed[i]->flags & RFLAG_VISITED)) {
98046f4d849SIngo Weinhold 			symbol = find_symbol_recursively_impl(image->needed[i], name,
98146f4d849SIngo Weinhold 				foundInImage);
98246f4d849SIngo Weinhold 			if (symbol)
9830c0fea5dSIngo Weinhold 				return symbol;
9840c0fea5dSIngo Weinhold 		}
9850c0fea5dSIngo Weinhold 	}
9860c0fea5dSIngo Weinhold 
9870c0fea5dSIngo Weinhold 	return NULL;
9880c0fea5dSIngo Weinhold }
9890c0fea5dSIngo Weinhold 
9900c0fea5dSIngo Weinhold 
99146f4d849SIngo Weinhold static void
99246f4d849SIngo Weinhold clear_image_flag_recursively(image_t* image, uint32 flag)
99346f4d849SIngo Weinhold {
99446f4d849SIngo Weinhold 	image->flags &= ~flag;
99546f4d849SIngo Weinhold 
99646f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
99746f4d849SIngo Weinhold 		if (image->needed[i]->flags & flag)
99846f4d849SIngo Weinhold 			clear_image_flag_recursively(image->needed[i], flag);
99946f4d849SIngo Weinhold 	}
100046f4d849SIngo Weinhold }
100146f4d849SIngo Weinhold 
100246f4d849SIngo Weinhold 
100346f4d849SIngo Weinhold static struct Elf32_Sym*
100446f4d849SIngo Weinhold find_symbol_recursively(image_t* image, const char* name,
100546f4d849SIngo Weinhold 	image_t** foundInImage)
100646f4d849SIngo Weinhold {
100746f4d849SIngo Weinhold 	struct Elf32_Sym* symbol = find_symbol_recursively_impl(image, name,
100846f4d849SIngo Weinhold 		foundInImage);
100946f4d849SIngo Weinhold 	clear_image_flag_recursively(image, RFLAG_VISITED);
101046f4d849SIngo Weinhold 	return symbol;
101146f4d849SIngo Weinhold }
101246f4d849SIngo Weinhold 
101346f4d849SIngo Weinhold 
101446f4d849SIngo Weinhold static struct Elf32_Sym*
101546f4d849SIngo Weinhold find_symbol_in_loaded_images(const char* name, image_t** foundInImage)
101646f4d849SIngo Weinhold {
101746f4d849SIngo Weinhold 	return find_symbol_recursively(sLoadedImages.head, name, foundInImage);
101846f4d849SIngo Weinhold }
101946f4d849SIngo Weinhold 
102046f4d849SIngo Weinhold 
102146f4d849SIngo Weinhold static struct Elf32_Sym*
102246f4d849SIngo Weinhold find_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
102346f4d849SIngo Weinhold 	image_t** foundInImage)
102446f4d849SIngo Weinhold {
102546f4d849SIngo Weinhold 	// If not simulating BeOS style symbol resolution, undefined symbols are
102692af28dfSIngo Weinhold 	// searched recursively starting from the root image.
102792af28dfSIngo Weinhold 	// TODO: Breadth first might be better than the depth first strategy used
102892af28dfSIngo Weinhold 	// here. We're also visiting images multiple times. Consider building a
102992af28dfSIngo Weinhold 	// breadth-first sorted array of images for each root image.
10305fd6637bSIngo Weinhold 	if ((rootImage->flags & IMAGE_FLAG_R5_SYMBOL_RESOLUTION) == 0) {
10315fd6637bSIngo Weinhold 		Elf32_Sym* symbol = find_symbol_recursively(rootImage, name,
10325fd6637bSIngo Weinhold 			foundInImage);
10335fd6637bSIngo Weinhold 		if (symbol != NULL)
10345fd6637bSIngo Weinhold 			return symbol;
10355fd6637bSIngo Weinhold 
10365fd6637bSIngo Weinhold 		// If the root image is not the program image (i.e. it is a dynamically
10375fd6637bSIngo Weinhold 		// loaded add-on or library), we try the program image hierarchy too.
10385fd6637bSIngo Weinhold 		image_t* programImage = get_program_image();
10395fd6637bSIngo Weinhold 		if (rootImage != programImage)
10405fd6637bSIngo Weinhold 			return find_symbol_recursively(programImage, name, foundInImage);
10415fd6637bSIngo Weinhold 
10425fd6637bSIngo Weinhold 		return NULL;
10435fd6637bSIngo Weinhold 	}
104446f4d849SIngo Weinhold 
104546f4d849SIngo Weinhold 	// BeOS style symbol resolution: It is sufficient to check the direct
104646f4d849SIngo Weinhold 	// dependencies. The linker would have complained, if the symbol wasn't
104746f4d849SIngo Weinhold 	// there.
104846f4d849SIngo Weinhold 	for (uint32 i = 0; i < image->num_needed; i++) {
104946f4d849SIngo Weinhold 		if (image->needed[i]->dynamic_ptr) {
105046f4d849SIngo Weinhold 			struct Elf32_Sym *symbol = find_symbol(image->needed[i], name,
105146f4d849SIngo Weinhold 				B_SYMBOL_TYPE_ANY);
105246f4d849SIngo Weinhold 			if (symbol) {
105346f4d849SIngo Weinhold 				*foundInImage = image->needed[i];
105446f4d849SIngo Weinhold 				return symbol;
105546f4d849SIngo Weinhold 			}
105646f4d849SIngo Weinhold 		}
105746f4d849SIngo Weinhold 	}
105846f4d849SIngo Weinhold 
105946f4d849SIngo Weinhold 	return NULL;
106046f4d849SIngo Weinhold }
106146f4d849SIngo Weinhold 
106246f4d849SIngo Weinhold 
10630c0fea5dSIngo Weinhold int
106446f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
106546f4d849SIngo Weinhold 	addr_t *sym_addr)
10660c0fea5dSIngo Weinhold {
10670c0fea5dSIngo Weinhold 	struct Elf32_Sym *sym2;
10680c0fea5dSIngo Weinhold 	char *symname;
10690c0fea5dSIngo Weinhold 	image_t *shimg;
10700c0fea5dSIngo Weinhold 
10710c0fea5dSIngo Weinhold 	switch (sym->st_shndx) {
10720c0fea5dSIngo Weinhold 		case SHN_UNDEF:
10730c0fea5dSIngo Weinhold 			// patch the symbol name
10740c0fea5dSIngo Weinhold 			symname = SYMNAME(image, sym);
10750c0fea5dSIngo Weinhold 
107646f4d849SIngo Weinhold 			// it's undefined, must be outside this image, try the other images
107746f4d849SIngo Weinhold 			sym2 = find_undefined_symbol(rootImage, image, symname, &shimg);
10780c0fea5dSIngo Weinhold 			if (!sym2) {
10790c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: could not resolve symbol '%s'\n", symname);
10800c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
10810c0fea5dSIngo Weinhold 			}
10820c0fea5dSIngo Weinhold 
10830c0fea5dSIngo Weinhold 			// make sure they're the same type
10840c0fea5dSIngo Weinhold 			if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
10850c0fea5dSIngo Weinhold 				&& ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) {
10860c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", symname);
10870c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
10880c0fea5dSIngo Weinhold 			}
10890c0fea5dSIngo Weinhold 
10900c0fea5dSIngo Weinhold 			if (ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL
10910c0fea5dSIngo Weinhold 				&& ELF32_ST_BIND(sym2->st_info) != STB_WEAK) {
10920c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: found symbol '%s' but not exported\n", symname);
10930c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
10940c0fea5dSIngo Weinhold 			}
10950c0fea5dSIngo Weinhold 
10960c0fea5dSIngo Weinhold 			*sym_addr = sym2->st_value + shimg->regions[0].delta;
10970c0fea5dSIngo Weinhold 			return B_NO_ERROR;
10980c0fea5dSIngo Weinhold 
10990c0fea5dSIngo Weinhold 		case SHN_ABS:
11000c0fea5dSIngo Weinhold 			*sym_addr = sym->st_value + image->regions[0].delta;
11010c0fea5dSIngo Weinhold 			return B_NO_ERROR;
11020c0fea5dSIngo Weinhold 
11030c0fea5dSIngo Weinhold 		case SHN_COMMON:
11040c0fea5dSIngo Weinhold 			// ToDo: finish this
11050c0fea5dSIngo Weinhold 			printf("elf_resolve_symbol: COMMON symbol, finish me!\n");
11060c0fea5dSIngo Weinhold 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
11070c0fea5dSIngo Weinhold 
11080c0fea5dSIngo Weinhold 		default:
11090c0fea5dSIngo Weinhold 			// standard symbol
11100c0fea5dSIngo Weinhold 			*sym_addr = sym->st_value + image->regions[0].delta;
11110c0fea5dSIngo Weinhold 			return B_NO_ERROR;
11120c0fea5dSIngo Weinhold 	}
11130c0fea5dSIngo Weinhold }
11140c0fea5dSIngo Weinhold 
11150c0fea5dSIngo Weinhold 
11160c0fea5dSIngo Weinhold static void
11170c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path)
11180c0fea5dSIngo Weinhold {
11190c0fea5dSIngo Weinhold 	struct stat stat;
11200c0fea5dSIngo Weinhold 	image_info info;
11210c0fea5dSIngo Weinhold 
11220c0fea5dSIngo Weinhold 	// ToDo: set these correctly
11230c0fea5dSIngo Weinhold 	info.id = 0;
11240c0fea5dSIngo Weinhold 	info.type = image->type;
11250c0fea5dSIngo Weinhold 	info.sequence = 0;
11260c0fea5dSIngo Weinhold 	info.init_order = 0;
11270c0fea5dSIngo Weinhold 	info.init_routine = (void (*)())image->init_routine;
11280c0fea5dSIngo Weinhold 	info.term_routine = (void (*)())image->term_routine;
11290c0fea5dSIngo Weinhold 
11300c0fea5dSIngo Weinhold 	if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
11310c0fea5dSIngo Weinhold 		info.device = stat.st_dev;
11320c0fea5dSIngo Weinhold 		info.node = stat.st_ino;
11330c0fea5dSIngo Weinhold 	} else {
11340c0fea5dSIngo Weinhold 		info.device = -1;
11350c0fea5dSIngo Weinhold 		info.node = -1;
11360c0fea5dSIngo Weinhold 	}
11370c0fea5dSIngo Weinhold 
11380c0fea5dSIngo Weinhold 	strlcpy(info.name, path, sizeof(info.name));
11390c0fea5dSIngo Weinhold 	info.text = (void *)image->regions[0].vmstart;
11400c0fea5dSIngo Weinhold 	info.text_size = image->regions[0].vmsize;
11410c0fea5dSIngo Weinhold 	info.data = (void *)image->regions[1].vmstart;
11420c0fea5dSIngo Weinhold 	info.data_size = image->regions[1].vmsize;
11430c0fea5dSIngo Weinhold 	image->id = _kern_register_image(&info, sizeof(image_info));
11440c0fea5dSIngo Weinhold }
11450c0fea5dSIngo Weinhold 
11460c0fea5dSIngo Weinhold 
11470c0fea5dSIngo Weinhold static status_t
114846f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image)
11490c0fea5dSIngo Weinhold {
115046f4d849SIngo Weinhold 	status_t status = arch_relocate_image(rootImage, image);
11510c0fea5dSIngo Weinhold 	if (status < B_OK) {
115246f4d849SIngo Weinhold 		FATAL("troubles relocating: 0x%lx (image: %s)\n", status, image->name);
11530c0fea5dSIngo Weinhold 		return status;
11540c0fea5dSIngo Weinhold 	}
11550c0fea5dSIngo Weinhold 
11560c0fea5dSIngo Weinhold 	_kern_image_relocated(image->id);
11570c0fea5dSIngo Weinhold 	return B_OK;
11580c0fea5dSIngo Weinhold }
11590c0fea5dSIngo Weinhold 
11600c0fea5dSIngo Weinhold 
11610c0fea5dSIngo Weinhold static status_t
11620c0fea5dSIngo Weinhold load_container(char const *name, image_type type, const char *rpath, image_t **_image)
11630c0fea5dSIngo Weinhold {
11640c0fea5dSIngo Weinhold 	int32 pheaderSize, sheaderSize;
11650c0fea5dSIngo Weinhold 	char path[PATH_MAX];
11660c0fea5dSIngo Weinhold 	ssize_t length;
11670c0fea5dSIngo Weinhold 	char ph_buff[4096];
11680c0fea5dSIngo Weinhold 	int32 numRegions;
11690c0fea5dSIngo Weinhold 	image_t *found;
11700c0fea5dSIngo Weinhold 	image_t *image;
11710c0fea5dSIngo Weinhold 	status_t status;
11720c0fea5dSIngo Weinhold 	int fd;
11730c0fea5dSIngo Weinhold 
11740c0fea5dSIngo Weinhold 	struct Elf32_Ehdr eheader;
11750c0fea5dSIngo Weinhold 
11760c0fea5dSIngo Weinhold 	// Have we already loaded that image? Don't check for add-ons -- we always
11770c0fea5dSIngo Weinhold 	// reload them.
11780c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
11790c0fea5dSIngo Weinhold 		found = find_image(name, APP_OR_LIBRARY_TYPE);
11800c0fea5dSIngo Weinhold 		if (found) {
11810c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
11820c0fea5dSIngo Weinhold 			*_image = found;
11837486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") "
11847486b72dSIngo Weinhold 				"already loaded", name, type, rpath);
11850c0fea5dSIngo Weinhold 			return B_OK;
11860c0fea5dSIngo Weinhold 		}
11870c0fea5dSIngo Weinhold 	}
11880c0fea5dSIngo Weinhold 
11897486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type,
11907486b72dSIngo Weinhold 		rpath);
11917486b72dSIngo Weinhold 
11920c0fea5dSIngo Weinhold 	strlcpy(path, name, sizeof(path));
11930c0fea5dSIngo Weinhold 
11940c0fea5dSIngo Weinhold 	// Try to load explicit image path first
119512a5e9a4SAxel Dörfler 	fd = open_executable(path, type, rpath, get_program_path());
11960c0fea5dSIngo Weinhold 	if (fd < 0) {
11970c0fea5dSIngo Weinhold 		FATAL("cannot open file %s\n", path);
11987486b72dSIngo Weinhold 		KTRACE("rld: load_container(\"%s\"): failed to open file", name);
11990c0fea5dSIngo Weinhold 		return fd;
12000c0fea5dSIngo Weinhold 	}
12010c0fea5dSIngo Weinhold 
12026918dbf4SIngo Weinhold 	// normalize the image path
12036918dbf4SIngo Weinhold 	status = _kern_normalize_path(path, true, path);
12046918dbf4SIngo Weinhold 	if (status != B_OK)
12050c0fea5dSIngo Weinhold 		goto err1;
12060c0fea5dSIngo Weinhold 
12070c0fea5dSIngo Weinhold 	// Test again if this image has been registered already - this time,
12080c0fea5dSIngo Weinhold 	// we can check the full path, not just its name as noted.
12090c0fea5dSIngo Weinhold 	// You could end up loading an image twice with symbolic links, else.
12100c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
12110c0fea5dSIngo Weinhold 		found = find_image(path, APP_OR_LIBRARY_TYPE);
12120c0fea5dSIngo Weinhold 		if (found) {
12130c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
12140c0fea5dSIngo Weinhold 			*_image = found;
12157486b72dSIngo Weinhold 			KTRACE("rld: load_container(\"%s\"): already loaded after all",
12167486b72dSIngo Weinhold 				name);
12170c0fea5dSIngo Weinhold 			return B_OK;
12180c0fea5dSIngo Weinhold 		}
12190c0fea5dSIngo Weinhold 	}
12200c0fea5dSIngo Weinhold 
12210c0fea5dSIngo Weinhold 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
12220c0fea5dSIngo Weinhold 	if (length != sizeof(eheader)) {
12230c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
12240c0fea5dSIngo Weinhold 		FATAL("troubles reading ELF header\n");
12250c0fea5dSIngo Weinhold 		goto err1;
12260c0fea5dSIngo Weinhold 	}
12270c0fea5dSIngo Weinhold 
12280c0fea5dSIngo Weinhold 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
12290c0fea5dSIngo Weinhold 	if (status < B_OK) {
12300c0fea5dSIngo Weinhold 		FATAL("incorrect ELF header\n");
12310c0fea5dSIngo Weinhold 		goto err1;
12320c0fea5dSIngo Weinhold 	}
12330c0fea5dSIngo Weinhold 
12340c0fea5dSIngo Weinhold 	// ToDo: what to do about this restriction??
12350c0fea5dSIngo Weinhold 	if (pheaderSize > (int)sizeof(ph_buff)) {
12360c0fea5dSIngo Weinhold 		FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff));
12370c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
12380c0fea5dSIngo Weinhold 		goto err1;
12390c0fea5dSIngo Weinhold 	}
12400c0fea5dSIngo Weinhold 
12410c0fea5dSIngo Weinhold 	length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize);
12420c0fea5dSIngo Weinhold 	if (length != pheaderSize) {
12430c0fea5dSIngo Weinhold 		FATAL("Could not read program headers: %s\n", strerror(length));
12440c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
12450c0fea5dSIngo Weinhold 		goto err1;
12460c0fea5dSIngo Weinhold 	}
12470c0fea5dSIngo Weinhold 
12480c0fea5dSIngo Weinhold 	numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
12490c0fea5dSIngo Weinhold 	if (numRegions <= 0) {
12500c0fea5dSIngo Weinhold 		FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
12510c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
12520c0fea5dSIngo Weinhold 		goto err1;
12530c0fea5dSIngo Weinhold 	}
12540c0fea5dSIngo Weinhold 
12550c0fea5dSIngo Weinhold 	image = create_image(name, path, numRegions);
12560c0fea5dSIngo Weinhold 	if (image == NULL) {
12570c0fea5dSIngo Weinhold 		FATAL("Failed to allocate image_t object\n");
12580c0fea5dSIngo Weinhold 		status = B_NO_MEMORY;
12590c0fea5dSIngo Weinhold 		goto err1;
12600c0fea5dSIngo Weinhold 	}
12610c0fea5dSIngo Weinhold 
12620c0fea5dSIngo Weinhold 	status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
12630c0fea5dSIngo Weinhold 	if (status < B_OK)
12640c0fea5dSIngo Weinhold 		goto err2;
12650c0fea5dSIngo Weinhold 
12660c0fea5dSIngo Weinhold 	if (!assert_dynamic_loadable(image)) {
12670c0fea5dSIngo Weinhold 		FATAL("Dynamic segment must be loadable (implementation restriction)\n");
12680c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
12690c0fea5dSIngo Weinhold 		goto err2;
12700c0fea5dSIngo Weinhold 	}
12710c0fea5dSIngo Weinhold 
127234982809SIngo Weinhold 	if (!analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff,
127334982809SIngo Weinhold 			sizeof(ph_buff))) {
127434982809SIngo Weinhold 		FATAL("Failed to get gcc version for %s\n", path);
127534982809SIngo Weinhold 		// not really fatal, actually
127634982809SIngo Weinhold 	}
127734982809SIngo Weinhold 
12785fd6637bSIngo Weinhold 	// init gcc version dependent image flags
12795fd6637bSIngo Weinhold 	// symbol resolution strategy (fallback is R5-style, if version is
12805fd6637bSIngo Weinhold 	// unavailable)
12815fd6637bSIngo Weinhold 	if (image->gcc_version.major == 0
12825fd6637bSIngo Weinhold 		|| image->gcc_version.major == 2 && image->gcc_version.middle < 95) {
12835fd6637bSIngo Weinhold 		image->flags |= IMAGE_FLAG_R5_SYMBOL_RESOLUTION;
12845fd6637bSIngo Weinhold 	}
12855fd6637bSIngo Weinhold 
12860c0fea5dSIngo Weinhold 	status = map_image(fd, path, image, type == B_APP_IMAGE);
12870c0fea5dSIngo Weinhold 	if (status < B_OK) {
12880c0fea5dSIngo Weinhold 		FATAL("Could not map image: %s\n", strerror(status));
12890c0fea5dSIngo Weinhold 		status = B_ERROR;
12900c0fea5dSIngo Weinhold 		goto err2;
12910c0fea5dSIngo Weinhold 	}
12920c0fea5dSIngo Weinhold 
12930c0fea5dSIngo Weinhold 	if (!parse_dynamic_segment(image)) {
12940c0fea5dSIngo Weinhold 		FATAL("Troubles handling dynamic section\n");
12950c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
12960c0fea5dSIngo Weinhold 		goto err3;
12970c0fea5dSIngo Weinhold 	}
12980c0fea5dSIngo Weinhold 
1299dd76bc97SIngo Weinhold 	if (eheader.e_entry != 0)
13000c0fea5dSIngo Weinhold 		image->entry_point = eheader.e_entry + image->regions[0].delta;
13010c0fea5dSIngo Weinhold 
13020c0fea5dSIngo Weinhold 	image->type = type;
13030c0fea5dSIngo Weinhold 	register_image(image, fd, path);
13040c0fea5dSIngo Weinhold 
13050c0fea5dSIngo Weinhold 	_kern_close(fd);
13060c0fea5dSIngo Weinhold 
13070c0fea5dSIngo Weinhold 	enqueue_image(&sLoadedImages, image);
13080c0fea5dSIngo Weinhold 	sLoadedImageCount++;
13090c0fea5dSIngo Weinhold 
13100c0fea5dSIngo Weinhold 	*_image = image;
13117486b72dSIngo Weinhold 
131234982809SIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): done: id: %ld (gcc: %d.%d.%d)", name,
131334982809SIngo Weinhold 		image->id, image->gcc_version.major, image->gcc_version.middle,
131434982809SIngo Weinhold 		image->gcc_version.minor);
13157486b72dSIngo Weinhold 
13160c0fea5dSIngo Weinhold 	return B_OK;
13170c0fea5dSIngo Weinhold 
13180c0fea5dSIngo Weinhold err3:
13190c0fea5dSIngo Weinhold 	unmap_image(image);
13200c0fea5dSIngo Weinhold err2:
13210c0fea5dSIngo Weinhold 	delete_image_struct(image);
13220c0fea5dSIngo Weinhold err1:
13230c0fea5dSIngo Weinhold 	_kern_close(fd);
13247486b72dSIngo Weinhold 
13257486b72dSIngo Weinhold 	KTRACE("rld: load_container(\"%s\"): failed: %s", name,
13267486b72dSIngo Weinhold 		strerror(status));
13277486b72dSIngo Weinhold 
13280c0fea5dSIngo Weinhold 	return status;
13290c0fea5dSIngo Weinhold }
13300c0fea5dSIngo Weinhold 
13310c0fea5dSIngo Weinhold 
13320c0fea5dSIngo Weinhold static const char *
13330c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
13340c0fea5dSIngo Weinhold {
13350c0fea5dSIngo Weinhold 	int i;
13360c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
13370c0fea5dSIngo Weinhold 
13380c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
13390c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
13400c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
13410c0fea5dSIngo Weinhold 	}
13420c0fea5dSIngo Weinhold 
13430c0fea5dSIngo Weinhold 	return NULL;
13440c0fea5dSIngo Weinhold }
13450c0fea5dSIngo Weinhold 
13460c0fea5dSIngo Weinhold 
13470c0fea5dSIngo Weinhold static status_t
13480c0fea5dSIngo Weinhold load_dependencies(image_t *image)
13490c0fea5dSIngo Weinhold {
13500c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
13514bef3723SAxel Dörfler 	bool reportErrors = report_errors();
135274c0424aSAxel Dörfler 	status_t status = B_OK;
13530c0fea5dSIngo Weinhold 	uint32 i, j;
13540c0fea5dSIngo Weinhold 	const char *rpath;
13550c0fea5dSIngo Weinhold 
13560c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
13570c0fea5dSIngo Weinhold 		return B_OK;
13580c0fea5dSIngo Weinhold 
13590c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
13600c0fea5dSIngo Weinhold 
13610c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
13620c0fea5dSIngo Weinhold 		return B_OK;
13630c0fea5dSIngo Weinhold 
13647486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
13657486b72dSIngo Weinhold 		image->id);
13667486b72dSIngo Weinhold 
13670c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
13680c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
13690c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
13707486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
13717486b72dSIngo Weinhold 			image->name, image->id);
13720c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
13730c0fea5dSIngo Weinhold 	}
13740c0fea5dSIngo Weinhold 
13750c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
13760c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
13770c0fea5dSIngo Weinhold 
13780c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
13790c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
13800c0fea5dSIngo Weinhold 			case DT_NEEDED:
138174c0424aSAxel Dörfler 			{
138274c0424aSAxel Dörfler 				int32 neededOffset = d[i].d_un.d_val;
138374c0424aSAxel Dörfler 				const char *name = STRING(image, neededOffset);
13840c0fea5dSIngo Weinhold 
138574c0424aSAxel Dörfler 				status_t loadStatus = load_container(name, B_LIBRARY_IMAGE,
138674c0424aSAxel Dörfler 					rpath, &image->needed[j]);
138774c0424aSAxel Dörfler 				if (loadStatus < B_OK) {
138874c0424aSAxel Dörfler 					status = loadStatus;
138974c0424aSAxel Dörfler 					// correct error code in case the file could not been found
139074c0424aSAxel Dörfler 					if (status == B_ENTRY_NOT_FOUND) {
139174c0424aSAxel Dörfler 						status = B_MISSING_LIBRARY;
139274c0424aSAxel Dörfler 
139374c0424aSAxel Dörfler 						if (reportErrors)
139474c0424aSAxel Dörfler 							sErrorMessage.AddString("missing library", name);
139574c0424aSAxel Dörfler 					}
139674c0424aSAxel Dörfler 
139774c0424aSAxel Dörfler 					// Collect all missing libraries in case we report back
13987486b72dSIngo Weinhold 					if (!reportErrors) {
13997486b72dSIngo Weinhold 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
14007486b72dSIngo Weinhold 							"failed: %s", image->name, image->id,
14017486b72dSIngo Weinhold 							strerror(status));
14020c0fea5dSIngo Weinhold 						return status;
140374c0424aSAxel Dörfler 					}
14047486b72dSIngo Weinhold 				}
14050c0fea5dSIngo Weinhold 
14060c0fea5dSIngo Weinhold 				j += 1;
14070c0fea5dSIngo Weinhold 				break;
140874c0424aSAxel Dörfler 			}
14090c0fea5dSIngo Weinhold 
14100c0fea5dSIngo Weinhold 			default:
14110c0fea5dSIngo Weinhold 				// ignore any other tag
14120c0fea5dSIngo Weinhold 				continue;
14130c0fea5dSIngo Weinhold 		}
14140c0fea5dSIngo Weinhold 	}
14150c0fea5dSIngo Weinhold 
14167486b72dSIngo Weinhold 	if (status < B_OK) {
14177486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
14187486b72dSIngo Weinhold 			"failed: %s", image->name, image->id,
14197486b72dSIngo Weinhold 			strerror(status));
142074c0424aSAxel Dörfler 		return status;
14217486b72dSIngo Weinhold 	}
142274c0424aSAxel Dörfler 
14230c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
14240c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
14257486b72dSIngo Weinhold 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
14267486b72dSIngo Weinhold 			"failed: internal error", image->name, image->id);
14270c0fea5dSIngo Weinhold 		return B_ERROR;
14280c0fea5dSIngo Weinhold 	}
14290c0fea5dSIngo Weinhold 
14307486b72dSIngo Weinhold 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
14317486b72dSIngo Weinhold 		image->id);
14327486b72dSIngo Weinhold 
14330c0fea5dSIngo Weinhold 	return B_OK;
14340c0fea5dSIngo Weinhold }
14350c0fea5dSIngo Weinhold 
14360c0fea5dSIngo Weinhold 
14370c0fea5dSIngo Weinhold static uint32
14380c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList,
14390c0fea5dSIngo Weinhold 	uint32 sortFlag)
14400c0fea5dSIngo Weinhold {
14410c0fea5dSIngo Weinhold 	uint32 i;
14420c0fea5dSIngo Weinhold 
14430c0fea5dSIngo Weinhold 	if (image->flags & sortFlag)
14440c0fea5dSIngo Weinhold 		return slot;
14450c0fea5dSIngo Weinhold 
14460c0fea5dSIngo Weinhold 	image->flags |= sortFlag; /* make sure we don't visit this one */
14470c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_needed; i++)
14480c0fea5dSIngo Weinhold 		slot = topological_sort(image->needed[i], slot, initList, sortFlag);
14490c0fea5dSIngo Weinhold 
14500c0fea5dSIngo Weinhold 	initList[slot] = image;
14510c0fea5dSIngo Weinhold 	return slot + 1;
14520c0fea5dSIngo Weinhold }
14530c0fea5dSIngo Weinhold 
14540c0fea5dSIngo Weinhold 
14550c0fea5dSIngo Weinhold static ssize_t
14560c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
14570c0fea5dSIngo Weinhold {
14580c0fea5dSIngo Weinhold 	image_t **list;
14590c0fea5dSIngo Weinhold 
14600c0fea5dSIngo Weinhold 	list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *));
14610c0fea5dSIngo Weinhold 	if (list == NULL) {
14620c0fea5dSIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
14630c0fea5dSIngo Weinhold 		*_list = NULL;
14640c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
14650c0fea5dSIngo Weinhold 	}
14660c0fea5dSIngo Weinhold 
14670c0fea5dSIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
14680c0fea5dSIngo Weinhold 
14690c0fea5dSIngo Weinhold 	*_list = list;
14700c0fea5dSIngo Weinhold 	return topological_sort(image, 0, list, sortFlag);
14710c0fea5dSIngo Weinhold }
14720c0fea5dSIngo Weinhold 
14730c0fea5dSIngo Weinhold 
14740c0fea5dSIngo Weinhold static status_t
14750c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
14760c0fea5dSIngo Weinhold {
14770c0fea5dSIngo Weinhold 	ssize_t count, i;
14780c0fea5dSIngo Weinhold 	image_t **list;
14790c0fea5dSIngo Weinhold 
14800c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
14810c0fea5dSIngo Weinhold 	if (count < B_OK)
14820c0fea5dSIngo Weinhold 		return count;
14830c0fea5dSIngo Weinhold 
14840c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
148546f4d849SIngo Weinhold 		status_t status = relocate_image(image, list[i]);
14860c0fea5dSIngo Weinhold 		if (status < B_OK)
14870c0fea5dSIngo Weinhold 			return status;
14880c0fea5dSIngo Weinhold 	}
14890c0fea5dSIngo Weinhold 
14900c0fea5dSIngo Weinhold 	free(list);
14910c0fea5dSIngo Weinhold 	return B_OK;
14920c0fea5dSIngo Weinhold }
14930c0fea5dSIngo Weinhold 
14940c0fea5dSIngo Weinhold 
14950c0fea5dSIngo Weinhold static void
14960c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
14970c0fea5dSIngo Weinhold {
14980c0fea5dSIngo Weinhold 	image_t **initList;
14990c0fea5dSIngo Weinhold 	ssize_t count, i;
15000c0fea5dSIngo Weinhold 
15010c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
15020c0fea5dSIngo Weinhold 	if (count <= 0)
15030c0fea5dSIngo Weinhold 		return;
15040c0fea5dSIngo Weinhold 
15050c0fea5dSIngo Weinhold 	if (!initHead) {
15060c0fea5dSIngo Weinhold 		// this removes the "calling" image
15070c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
15080c0fea5dSIngo Weinhold 		initList[--count] = NULL;
15090c0fea5dSIngo Weinhold 	}
15100c0fea5dSIngo Weinhold 
15110c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
15120c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
15130c0fea5dSIngo Weinhold 		image = initList[i];
15140c0fea5dSIngo Weinhold 
15150c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
15160c0fea5dSIngo Weinhold 
1517dd76bc97SIngo Weinhold 		if (image->init_routine != 0)
15180c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
15190c0fea5dSIngo Weinhold 	}
15200c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
15210c0fea5dSIngo Weinhold 
15220c0fea5dSIngo Weinhold 	free(initList);
15230c0fea5dSIngo Weinhold }
15240c0fea5dSIngo Weinhold 
15250c0fea5dSIngo Weinhold 
15260c0fea5dSIngo Weinhold static void
15270c0fea5dSIngo Weinhold put_image(image_t *image)
15280c0fea5dSIngo Weinhold {
15290c0fea5dSIngo Weinhold 	// If all references to the image are gone, add it to the disposable list
15300c0fea5dSIngo Weinhold 	// and remove all dependencies
15310c0fea5dSIngo Weinhold 
15320c0fea5dSIngo Weinhold 	if (atomic_add(&image->ref_count, -1) == 1) {
15330c0fea5dSIngo Weinhold 		size_t i;
15340c0fea5dSIngo Weinhold 
15350c0fea5dSIngo Weinhold 		dequeue_image(&sLoadedImages, image);
15360c0fea5dSIngo Weinhold 		enqueue_image(&sDisposableImages, image);
15370c0fea5dSIngo Weinhold 		sLoadedImageCount--;
15380c0fea5dSIngo Weinhold 
15390c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_needed; i++) {
15400c0fea5dSIngo Weinhold 			put_image(image->needed[i]);
15410c0fea5dSIngo Weinhold 		}
15420c0fea5dSIngo Weinhold 	}
15430c0fea5dSIngo Weinhold }
15440c0fea5dSIngo Weinhold 
15450c0fea5dSIngo Weinhold 
154674c0424aSAxel Dörfler //	#pragma mark - libroot.so exported functions
15470c0fea5dSIngo Weinhold 
15480c0fea5dSIngo Weinhold 
15490c0fea5dSIngo Weinhold image_id
15500c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
15510c0fea5dSIngo Weinhold {
15520c0fea5dSIngo Weinhold 	status_t status;
15530c0fea5dSIngo Weinhold 	image_t *image;
15540c0fea5dSIngo Weinhold 
15557486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\")", path);
15567486b72dSIngo Weinhold 
15570c0fea5dSIngo Weinhold 	rld_lock();
15580c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
15590c0fea5dSIngo Weinhold 
15600c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
15610c0fea5dSIngo Weinhold 
15620c0fea5dSIngo Weinhold 	status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage);
156374c0424aSAxel Dörfler 	if (status < B_OK)
156474c0424aSAxel Dörfler 		goto err;
15650c0fea5dSIngo Weinhold 
15660c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
15670c0fea5dSIngo Weinhold 		status = load_dependencies(image);
15680c0fea5dSIngo Weinhold 		if (status < B_OK)
15690c0fea5dSIngo Weinhold 			goto err;
15700c0fea5dSIngo Weinhold 	}
15710c0fea5dSIngo Weinhold 
15720c0fea5dSIngo Weinhold 	status = relocate_dependencies(sProgramImage);
15730c0fea5dSIngo Weinhold 	if (status < B_OK)
15740c0fea5dSIngo Weinhold 		goto err;
15750c0fea5dSIngo Weinhold 
15760c0fea5dSIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private API
15770c0fea5dSIngo Weinhold 	{
157846f4d849SIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_loaded_images(
157946f4d849SIngo Weinhold 			"__gRuntimeLoader", &image);
15800c0fea5dSIngo Weinhold 		if (symbol != NULL) {
15810c0fea5dSIngo Weinhold 			void **_export = (void **)(symbol->st_value + image->regions[0].delta);
15820c0fea5dSIngo Weinhold 			*_export = &gRuntimeLoader;
15830c0fea5dSIngo Weinhold 		}
15840c0fea5dSIngo Weinhold 	}
15850c0fea5dSIngo Weinhold 
15860c0fea5dSIngo Weinhold 	init_dependencies(sLoadedImages.head, true);
15870c0fea5dSIngo Weinhold 	remap_images();
15880c0fea5dSIngo Weinhold 		// ToDo: once setup_system_time() is fixed, move this one line higher!
15890c0fea5dSIngo Weinhold 
15900c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
15910c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
15920c0fea5dSIngo Weinhold 	{
159346f4d849SIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_loaded_images("getenv",
159446f4d849SIngo Weinhold 			&image);
15950c0fea5dSIngo Weinhold 		if (symbol != NULL)
15960c0fea5dSIngo Weinhold 			gGetEnv = (char* (*)(const char*))
15970c0fea5dSIngo Weinhold 				(symbol->st_value + image->regions[0].delta);
15980c0fea5dSIngo Weinhold 	}
15990c0fea5dSIngo Weinhold 
1600dd76bc97SIngo Weinhold 	if (sProgramImage->entry_point == 0) {
16010c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
16020c0fea5dSIngo Weinhold 		goto err;
16030c0fea5dSIngo Weinhold 	}
16040c0fea5dSIngo Weinhold 
16050c0fea5dSIngo Weinhold 	*_entry = (void *)(sProgramImage->entry_point);
16060c0fea5dSIngo Weinhold 
16070c0fea5dSIngo Weinhold 	rld_unlock();
16087486b72dSIngo Weinhold 
16097486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
16107486b72dSIngo Weinhold 		*_entry, sProgramImage->id);
16117486b72dSIngo Weinhold 
16120c0fea5dSIngo Weinhold 	return sProgramImage->id;
16130c0fea5dSIngo Weinhold 
16140c0fea5dSIngo Weinhold err:
16157486b72dSIngo Weinhold 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
16167486b72dSIngo Weinhold 
16170c0fea5dSIngo Weinhold 	delete_image(sProgramImage);
161874c0424aSAxel Dörfler 
16194bef3723SAxel Dörfler 	if (report_errors()) {
16204bef3723SAxel Dörfler 		// send error message
162174c0424aSAxel Dörfler 		sErrorMessage.AddInt32("error", status);
16224bef3723SAxel Dörfler 		sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
16234bef3723SAxel Dörfler 			-1, 0, find_thread(NULL));
16244bef3723SAxel Dörfler 
16254bef3723SAxel Dörfler 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
16264bef3723SAxel Dörfler 			sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0);
162774c0424aSAxel Dörfler 	}
162874c0424aSAxel Dörfler 	_kern_loading_app_failed(status);
16290c0fea5dSIngo Weinhold 	rld_unlock();
163074c0424aSAxel Dörfler 
16310c0fea5dSIngo Weinhold 	return status;
16320c0fea5dSIngo Weinhold }
16330c0fea5dSIngo Weinhold 
16340c0fea5dSIngo Weinhold 
16350c0fea5dSIngo Weinhold image_id
16360c0fea5dSIngo Weinhold load_library(char const *path, uint32 flags, bool addOn)
16370c0fea5dSIngo Weinhold {
16380c0fea5dSIngo Weinhold 	image_t *image = NULL;
16390c0fea5dSIngo Weinhold 	image_t *iter;
16400c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
16410c0fea5dSIngo Weinhold 	status_t status;
16420c0fea5dSIngo Weinhold 
16430c0fea5dSIngo Weinhold 	if (path == NULL)
16440c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
16450c0fea5dSIngo Weinhold 
16460c0fea5dSIngo Weinhold 	// ToDo: implement flags
16470c0fea5dSIngo Weinhold 	(void)flags;
16480c0fea5dSIngo Weinhold 
16497486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
16507486b72dSIngo Weinhold 
16510c0fea5dSIngo Weinhold 	rld_lock();
16520c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
16530c0fea5dSIngo Weinhold 
16540c0fea5dSIngo Weinhold 	// have we already loaded this library?
16550c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
16560c0fea5dSIngo Weinhold 	if (!addOn) {
16570c0fea5dSIngo Weinhold 		image = find_image(path, APP_OR_LIBRARY_TYPE);
16580c0fea5dSIngo Weinhold 		if (image) {
16590c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
16600c0fea5dSIngo Weinhold 			rld_unlock();
16617486b72dSIngo Weinhold 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
16627486b72dSIngo Weinhold 				image->id);
16630c0fea5dSIngo Weinhold 			return image->id;
16640c0fea5dSIngo Weinhold 		}
16650c0fea5dSIngo Weinhold 	}
16660c0fea5dSIngo Weinhold 
16670c0fea5dSIngo Weinhold 	status = load_container(path, type, NULL, &image);
16680c0fea5dSIngo Weinhold 	if (status < B_OK) {
16690c0fea5dSIngo Weinhold 		rld_unlock();
16707486b72dSIngo Weinhold 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
16717486b72dSIngo Weinhold 			strerror(status));
16720c0fea5dSIngo Weinhold 		return status;
16730c0fea5dSIngo Weinhold 	}
16740c0fea5dSIngo Weinhold 
16750c0fea5dSIngo Weinhold 	for (iter = sLoadedImages.head; iter; iter = iter->next) {
16760c0fea5dSIngo Weinhold 		status = load_dependencies(iter);
16770c0fea5dSIngo Weinhold 		if (status < B_OK)
16780c0fea5dSIngo Weinhold 			goto err;
16790c0fea5dSIngo Weinhold 	}
16800c0fea5dSIngo Weinhold 
16810c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
16820c0fea5dSIngo Weinhold 	if (status < B_OK)
16830c0fea5dSIngo Weinhold 		goto err;
16840c0fea5dSIngo Weinhold 
16850c0fea5dSIngo Weinhold 	remap_images();
16860c0fea5dSIngo Weinhold 	init_dependencies(image, true);
16870c0fea5dSIngo Weinhold 
16880c0fea5dSIngo Weinhold 	rld_unlock();
16897486b72dSIngo Weinhold 
16907486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
16917486b72dSIngo Weinhold 
16920c0fea5dSIngo Weinhold 	return image->id;
16930c0fea5dSIngo Weinhold 
16940c0fea5dSIngo Weinhold err:
16957486b72dSIngo Weinhold 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
16967486b72dSIngo Weinhold 
16970c0fea5dSIngo Weinhold 	dequeue_image(&sLoadedImages, image);
16980c0fea5dSIngo Weinhold 	sLoadedImageCount--;
16990c0fea5dSIngo Weinhold 	delete_image(image);
17000c0fea5dSIngo Weinhold 	rld_unlock();
17010c0fea5dSIngo Weinhold 	return status;
17020c0fea5dSIngo Weinhold }
17030c0fea5dSIngo Weinhold 
17040c0fea5dSIngo Weinhold 
17050c0fea5dSIngo Weinhold status_t
17060c0fea5dSIngo Weinhold unload_library(image_id imageID, bool addOn)
17070c0fea5dSIngo Weinhold {
17080c0fea5dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
17090c0fea5dSIngo Weinhold 	image_t *image;
17100c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
17110c0fea5dSIngo Weinhold 
17120c0fea5dSIngo Weinhold 	if (imageID < B_OK)
17130c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
17140c0fea5dSIngo Weinhold 
17150c0fea5dSIngo Weinhold 	rld_lock();
17160c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
17170c0fea5dSIngo Weinhold 
17180c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
17190c0fea5dSIngo Weinhold 
17200c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
17210c0fea5dSIngo Weinhold 		if (image->id == imageID) {
17220c0fea5dSIngo Weinhold 			// unload image
17230c0fea5dSIngo Weinhold 			if (type == image->type) {
17240c0fea5dSIngo Weinhold 				put_image(image);
17250c0fea5dSIngo Weinhold 				status = B_OK;
17260c0fea5dSIngo Weinhold 			} else
17270c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
17280c0fea5dSIngo Weinhold 			break;
17290c0fea5dSIngo Weinhold 		}
17300c0fea5dSIngo Weinhold 	}
17310c0fea5dSIngo Weinhold 
17320c0fea5dSIngo Weinhold 	if (status == B_OK) {
17330c0fea5dSIngo Weinhold 		while ((image = sDisposableImages.head) != NULL) {
17340c0fea5dSIngo Weinhold 			// call image fini here...
17358c2a9d74SMichael Lotz 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
17368c2a9d74SMichael Lotz 				gRuntimeLoader.call_atexit_hooks_for_range(
17373be509a2SMichael Lotz 					image->regions[0].vmstart, image->regions[0].vmsize);
17388c2a9d74SMichael Lotz 			}
17398c2a9d74SMichael Lotz 
17400c0fea5dSIngo Weinhold 			if (image->term_routine)
17410c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
17420c0fea5dSIngo Weinhold 
17430c0fea5dSIngo Weinhold 			dequeue_image(&sDisposableImages, image);
17440c0fea5dSIngo Weinhold 			unmap_image(image);
17450c0fea5dSIngo Weinhold 
17460c0fea5dSIngo Weinhold 			delete_image(image);
17470c0fea5dSIngo Weinhold 		}
17480c0fea5dSIngo Weinhold 	}
17490c0fea5dSIngo Weinhold 
17500c0fea5dSIngo Weinhold 	rld_unlock();
17510c0fea5dSIngo Weinhold 	return status;
17520c0fea5dSIngo Weinhold }
17530c0fea5dSIngo Weinhold 
17540c0fea5dSIngo Weinhold 
17550c0fea5dSIngo Weinhold status_t
17560c0fea5dSIngo Weinhold get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, int32 *_nameLength,
17570c0fea5dSIngo Weinhold 	int32 *_type, void **_location)
17580c0fea5dSIngo Weinhold {
17590c0fea5dSIngo Weinhold 	int32 count = 0, j;
17600c0fea5dSIngo Weinhold 	uint32 i;
17610c0fea5dSIngo Weinhold 	image_t *image;
17620c0fea5dSIngo Weinhold 
17630c0fea5dSIngo Weinhold 	rld_lock();
17640c0fea5dSIngo Weinhold 
17650c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
17660c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
17670c0fea5dSIngo Weinhold 	if (image == NULL) {
17680c0fea5dSIngo Weinhold 		rld_unlock();
17690c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
17700c0fea5dSIngo Weinhold 	}
17710c0fea5dSIngo Weinhold 
17720c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
17730c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
17740c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
17750c0fea5dSIngo Weinhold 			struct Elf32_Sym *symbol = &image->syms[i];
17760c0fea5dSIngo Weinhold 
17770c0fea5dSIngo Weinhold 			if (count == num) {
17780c0fea5dSIngo Weinhold 				strlcpy(nameBuffer, SYMNAME(image, symbol), *_nameLength);
17790c0fea5dSIngo Weinhold 				*_nameLength = strlen(SYMNAME(image, symbol));
17800c0fea5dSIngo Weinhold 
17810c0fea5dSIngo Weinhold 				if (_type != NULL) {
17820c0fea5dSIngo Weinhold 					// ToDo: check with the return types of that BeOS function
17830c0fea5dSIngo Weinhold 					if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
17840c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_TEXT;
17850c0fea5dSIngo Weinhold 					else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
17860c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_DATA;
17870c0fea5dSIngo Weinhold 					else
17880c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_ANY;
17890c0fea5dSIngo Weinhold 				}
17900c0fea5dSIngo Weinhold 
17910c0fea5dSIngo Weinhold 				if (_location != NULL)
17920c0fea5dSIngo Weinhold 					*_location = (void *)(symbol->st_value + image->regions[0].delta);
17930c0fea5dSIngo Weinhold 				goto out;
17940c0fea5dSIngo Weinhold 			}
17950c0fea5dSIngo Weinhold 			count++;
17960c0fea5dSIngo Weinhold 		}
17970c0fea5dSIngo Weinhold 	}
17980c0fea5dSIngo Weinhold out:
17990c0fea5dSIngo Weinhold 	rld_unlock();
18000c0fea5dSIngo Weinhold 
18010c0fea5dSIngo Weinhold 	if (num != count)
18020c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
18030c0fea5dSIngo Weinhold 
18040c0fea5dSIngo Weinhold 	return B_OK;
18050c0fea5dSIngo Weinhold }
18060c0fea5dSIngo Weinhold 
18070c0fea5dSIngo Weinhold 
18080c0fea5dSIngo Weinhold status_t
18090c0fea5dSIngo Weinhold get_symbol(image_id imageID, char const *symbolName, int32 symbolType, void **_location)
18100c0fea5dSIngo Weinhold {
18110c0fea5dSIngo Weinhold 	status_t status = B_OK;
18120c0fea5dSIngo Weinhold 	image_t *image;
18130c0fea5dSIngo Weinhold 
18140c0fea5dSIngo Weinhold 	if (imageID < B_OK)
18150c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
18160c0fea5dSIngo Weinhold 	if (symbolName == NULL)
18170c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
18180c0fea5dSIngo Weinhold 
18190c0fea5dSIngo Weinhold 	rld_lock();
18200c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
18210c0fea5dSIngo Weinhold 
18220c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
18230c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
18240c0fea5dSIngo Weinhold 	if (image != NULL) {
18250c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol;
18260c0fea5dSIngo Weinhold 
18270c0fea5dSIngo Weinhold 		// get the symbol in the image
18280c0fea5dSIngo Weinhold 		symbol = find_symbol(image, symbolName, symbolType);
18290c0fea5dSIngo Weinhold 		if (symbol) {
18300c0fea5dSIngo Weinhold 			if (_location != NULL)
18310c0fea5dSIngo Weinhold 				*_location = (void *)(symbol->st_value + image->regions[0].delta);
18320c0fea5dSIngo Weinhold 		} else
18330c0fea5dSIngo Weinhold 			status = B_ENTRY_NOT_FOUND;
18340c0fea5dSIngo Weinhold 	} else
18350c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
18360c0fea5dSIngo Weinhold 
18370c0fea5dSIngo Weinhold 	rld_unlock();
18380c0fea5dSIngo Weinhold 	return status;
18390c0fea5dSIngo Weinhold }
18400c0fea5dSIngo Weinhold 
18410c0fea5dSIngo Weinhold 
18420c0fea5dSIngo Weinhold status_t
18430c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
18440c0fea5dSIngo Weinhold {
18450c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
18460c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
18470c0fea5dSIngo Weinhold 	image_t *image;
18480c0fea5dSIngo Weinhold 
18490c0fea5dSIngo Weinhold 	if (_name == NULL)
18500c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
18510c0fea5dSIngo Weinhold 
18520c0fea5dSIngo Weinhold 	rld_lock();
18530c0fea5dSIngo Weinhold 
18540c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(id);
18550c0fea5dSIngo Weinhold 	if (image == NULL) {
18560c0fea5dSIngo Weinhold 		rld_unlock();
18570c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
18580c0fea5dSIngo Weinhold 	}
18590c0fea5dSIngo Weinhold 
18600c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
18610c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
18620c0fea5dSIngo Weinhold 		rld_unlock();
18630c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
18640c0fea5dSIngo Weinhold 	}
18650c0fea5dSIngo Weinhold 
18660c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
18670c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
18680c0fea5dSIngo Weinhold 			continue;
18690c0fea5dSIngo Weinhold 
18700c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
18710c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
18720c0fea5dSIngo Weinhold 
18730c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
18740c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
18750c0fea5dSIngo Weinhold 			rld_unlock();
18760c0fea5dSIngo Weinhold 			return B_OK;
18770c0fea5dSIngo Weinhold 		}
18780c0fea5dSIngo Weinhold 	}
18790c0fea5dSIngo Weinhold 
18800c0fea5dSIngo Weinhold 	rld_unlock();
18810c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
18820c0fea5dSIngo Weinhold }
18830c0fea5dSIngo Weinhold 
18840c0fea5dSIngo Weinhold 
188574c0424aSAxel Dörfler //	#pragma mark - runtime_loader private exports
18860c0fea5dSIngo Weinhold 
18870c0fea5dSIngo Weinhold 
18880c0fea5dSIngo Weinhold /** Read and verify the ELF header */
18890c0fea5dSIngo Weinhold 
18900c0fea5dSIngo Weinhold status_t
18910c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
18920c0fea5dSIngo Weinhold {
18930c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
18940c0fea5dSIngo Weinhold 
18950c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
18960c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
18970c0fea5dSIngo Weinhold 
18980c0fea5dSIngo Weinhold 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, &sectionSize);
18990c0fea5dSIngo Weinhold }
19000c0fea5dSIngo Weinhold 
19010c0fea5dSIngo Weinhold 
19020c0fea5dSIngo Weinhold void
19030c0fea5dSIngo Weinhold terminate_program(void)
19040c0fea5dSIngo Weinhold {
19050c0fea5dSIngo Weinhold 	image_t **termList;
19060c0fea5dSIngo Weinhold 	ssize_t count, i;
19070c0fea5dSIngo Weinhold 
19080c0fea5dSIngo Weinhold 	count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED);
19090c0fea5dSIngo Weinhold 	if (count < B_OK)
19100c0fea5dSIngo Weinhold 		return;
19110c0fea5dSIngo Weinhold 
19120c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
19130c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
19140c0fea5dSIngo Weinhold 		image_t *image = termList[i];
19150c0fea5dSIngo Weinhold 
19160c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
19170c0fea5dSIngo Weinhold 
19180c0fea5dSIngo Weinhold 		if (image->term_routine)
19190c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
19200c0fea5dSIngo Weinhold 	}
19210c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
19220c0fea5dSIngo Weinhold 
19230c0fea5dSIngo Weinhold 	free(termList);
19240c0fea5dSIngo Weinhold }
19250c0fea5dSIngo Weinhold 
19260c0fea5dSIngo Weinhold 
19270c0fea5dSIngo Weinhold void
19280c0fea5dSIngo Weinhold rldelf_init(void)
19290c0fea5dSIngo Weinhold {
19300c0fea5dSIngo Weinhold 	rld_sem = create_sem(1, "rld_lock");
19310c0fea5dSIngo Weinhold 	rld_sem_owner = -1;
19320c0fea5dSIngo Weinhold 	rld_sem_count = 0;
19330c0fea5dSIngo Weinhold 
19340c0fea5dSIngo Weinhold 	// create the debug area
19350c0fea5dSIngo Weinhold 	{
19360c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
19370c0fea5dSIngo Weinhold 
19380c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
19390c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
19400c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
19410c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
19420c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
19430c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
19440c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
19450c0fea5dSIngo Weinhold 		}
19460c0fea5dSIngo Weinhold 
19470c0fea5dSIngo Weinhold 		area->loaded_images = &sLoadedImages;
19480c0fea5dSIngo Weinhold 	}
194974c0424aSAxel Dörfler 
195074c0424aSAxel Dörfler 	// initialize error message if needed
19514bef3723SAxel Dörfler 	if (report_errors()) {
195274c0424aSAxel Dörfler 		void *buffer = malloc(1024);
195374c0424aSAxel Dörfler 		if (buffer == NULL)
195474c0424aSAxel Dörfler 			return;
195574c0424aSAxel Dörfler 
195674c0424aSAxel Dörfler 		sErrorMessage.SetTo(buffer, 1024, 'Rler');
195774c0424aSAxel Dörfler 	}
19580c0fea5dSIngo Weinhold }
19591873b4b3SIngo Weinhold 
19601873b4b3SIngo Weinhold 
19611873b4b3SIngo Weinhold status_t
19621873b4b3SIngo Weinhold elf_reinit_after_fork()
19631873b4b3SIngo Weinhold {
19641873b4b3SIngo Weinhold 	rld_sem = create_sem(1, "rld_lock");
19651873b4b3SIngo Weinhold 	if (rld_sem < 0)
19661873b4b3SIngo Weinhold 		return rld_sem;
19671873b4b3SIngo Weinhold 
19681873b4b3SIngo Weinhold 	return B_OK;
19691873b4b3SIngo Weinhold }
1970