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