xref: /haiku/src/system/runtime_loader/elf.cpp (revision 0c0fea5de2f680068bfd2c1d69e09d0c096582e4)
1*0c0fea5dSIngo Weinhold /*
2*0c0fea5dSIngo Weinhold  * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de.
3*0c0fea5dSIngo Weinhold  * Distributed under the terms of the MIT License.
4*0c0fea5dSIngo Weinhold  *
5*0c0fea5dSIngo Weinhold  * Copyright 2002, Manuel J. Petit. All rights reserved.
6*0c0fea5dSIngo Weinhold  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
7*0c0fea5dSIngo Weinhold  * Distributed under the terms of the NewOS License.
8*0c0fea5dSIngo Weinhold  */
9*0c0fea5dSIngo Weinhold 
10*0c0fea5dSIngo Weinhold 
11*0c0fea5dSIngo Weinhold #include "runtime_loader_private.h"
12*0c0fea5dSIngo Weinhold 
13*0c0fea5dSIngo Weinhold #include <OS.h>
14*0c0fea5dSIngo Weinhold 
15*0c0fea5dSIngo Weinhold #include <elf32.h>
16*0c0fea5dSIngo Weinhold #include <user_runtime.h>
17*0c0fea5dSIngo Weinhold #include <syscalls.h>
18*0c0fea5dSIngo Weinhold #include <vm_types.h>
19*0c0fea5dSIngo Weinhold #include <arch/cpu.h>
20*0c0fea5dSIngo Weinhold #include <sem.h>
21*0c0fea5dSIngo Weinhold #include <runtime_loader.h>
22*0c0fea5dSIngo Weinhold 
23*0c0fea5dSIngo Weinhold #include <string.h>
24*0c0fea5dSIngo Weinhold #include <stdio.h>
25*0c0fea5dSIngo Weinhold #include <stdlib.h>
26*0c0fea5dSIngo Weinhold 
27*0c0fea5dSIngo Weinhold 
28*0c0fea5dSIngo Weinhold //#define TRACE_RLD
29*0c0fea5dSIngo Weinhold #ifdef TRACE_RLD
30*0c0fea5dSIngo Weinhold #	define TRACE(x) dprintf x
31*0c0fea5dSIngo Weinhold #else
32*0c0fea5dSIngo Weinhold #	define TRACE(x) ;
33*0c0fea5dSIngo Weinhold #endif
34*0c0fea5dSIngo Weinhold 
35*0c0fea5dSIngo Weinhold 
36*0c0fea5dSIngo Weinhold // ToDo: implement better locking strategy
37*0c0fea5dSIngo Weinhold // ToDo: implement lazy binding
38*0c0fea5dSIngo Weinhold 
39*0c0fea5dSIngo Weinhold #define	PAGE_MASK (B_PAGE_SIZE - 1)
40*0c0fea5dSIngo Weinhold 
41*0c0fea5dSIngo Weinhold #define	PAGE_OFFSET(x) ((x) & (PAGE_MASK))
42*0c0fea5dSIngo Weinhold #define	PAGE_BASE(x) ((x) & ~(PAGE_MASK))
43*0c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
44*0c0fea5dSIngo Weinhold 
45*0c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000
46*0c0fea5dSIngo Weinhold 	/* keep in sync with app ldscript */
47*0c0fea5dSIngo Weinhold 
48*0c0fea5dSIngo Weinhold enum {
49*0c0fea5dSIngo Weinhold 	RFLAG_RW					= 0x0001,
50*0c0fea5dSIngo Weinhold 	RFLAG_ANON					= 0x0002,
51*0c0fea5dSIngo Weinhold 
52*0c0fea5dSIngo Weinhold 	RFLAG_TERMINATED			= 0x0200,
53*0c0fea5dSIngo Weinhold 	RFLAG_INITIALIZED			= 0x0400,
54*0c0fea5dSIngo Weinhold 	RFLAG_SYMBOLIC				= 0x0800,
55*0c0fea5dSIngo Weinhold 	RFLAG_RELOCATED				= 0x1000,
56*0c0fea5dSIngo Weinhold 	RFLAG_PROTECTED				= 0x2000,
57*0c0fea5dSIngo Weinhold 	RFLAG_DEPENDENCIES_LOADED	= 0x4000,
58*0c0fea5dSIngo Weinhold 	RFLAG_REMAPPED				= 0x8000
59*0c0fea5dSIngo Weinhold };
60*0c0fea5dSIngo Weinhold 
61*0c0fea5dSIngo Weinhold 
62*0c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type)	(1 << ((type) - 1))
63*0c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES				(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
64*0c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
65*0c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
66*0c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
67*0c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE			(IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
68*0c0fea5dSIngo Weinhold 									| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
69*0c0fea5dSIngo Weinhold 
70*0c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id);
71*0c0fea5dSIngo Weinhold 
72*0c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0};
73*0c0fea5dSIngo Weinhold static image_queue_t sLoadingImages = {0, 0};
74*0c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0};
75*0c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0;
76*0c0fea5dSIngo Weinhold static image_t *sProgramImage;
77*0c0fea5dSIngo Weinhold 
78*0c0fea5dSIngo Weinhold // a recursive lock
79*0c0fea5dSIngo Weinhold static sem_id rld_sem;
80*0c0fea5dSIngo Weinhold static thread_id rld_sem_owner;
81*0c0fea5dSIngo Weinhold static int32 rld_sem_count;
82*0c0fea5dSIngo Weinhold 
83*0c0fea5dSIngo Weinhold 
84*0c0fea5dSIngo Weinhold #ifdef TRACE_RLD
85*0c0fea5dSIngo Weinhold #	define FATAL(x...) dprintf("runtime_loader: " x);
86*0c0fea5dSIngo Weinhold 
87*0c0fea5dSIngo Weinhold void
88*0c0fea5dSIngo Weinhold dprintf(const char *format, ...)
89*0c0fea5dSIngo Weinhold {
90*0c0fea5dSIngo Weinhold 	char buffer[1024];
91*0c0fea5dSIngo Weinhold 
92*0c0fea5dSIngo Weinhold 	va_list list;
93*0c0fea5dSIngo Weinhold 	va_start(list, format);
94*0c0fea5dSIngo Weinhold 
95*0c0fea5dSIngo Weinhold 	vsnprintf(buffer, sizeof(buffer), format, list);
96*0c0fea5dSIngo Weinhold 	_kern_debug_output(buffer);
97*0c0fea5dSIngo Weinhold 
98*0c0fea5dSIngo Weinhold 	va_end(list);
99*0c0fea5dSIngo Weinhold }
100*0c0fea5dSIngo Weinhold #else
101*0c0fea5dSIngo Weinhold #	define FATAL(x...) printf("runtime_loader: " x);
102*0c0fea5dSIngo Weinhold #endif
103*0c0fea5dSIngo Weinhold 
104*0c0fea5dSIngo Weinhold 
105*0c0fea5dSIngo Weinhold static void
106*0c0fea5dSIngo Weinhold rld_unlock()
107*0c0fea5dSIngo Weinhold {
108*0c0fea5dSIngo Weinhold 	if (rld_sem_count-- == 1) {
109*0c0fea5dSIngo Weinhold 		rld_sem_owner = -1;
110*0c0fea5dSIngo Weinhold 		release_sem(rld_sem);
111*0c0fea5dSIngo Weinhold 	}
112*0c0fea5dSIngo Weinhold }
113*0c0fea5dSIngo Weinhold 
114*0c0fea5dSIngo Weinhold 
115*0c0fea5dSIngo Weinhold static void
116*0c0fea5dSIngo Weinhold rld_lock()
117*0c0fea5dSIngo Weinhold {
118*0c0fea5dSIngo Weinhold 	thread_id self = find_thread(NULL);
119*0c0fea5dSIngo Weinhold 	if (self != rld_sem_owner) {
120*0c0fea5dSIngo Weinhold 		acquire_sem(rld_sem);
121*0c0fea5dSIngo Weinhold 		rld_sem_owner = self;
122*0c0fea5dSIngo Weinhold 	}
123*0c0fea5dSIngo Weinhold 	rld_sem_count++;
124*0c0fea5dSIngo Weinhold }
125*0c0fea5dSIngo Weinhold 
126*0c0fea5dSIngo Weinhold 
127*0c0fea5dSIngo Weinhold static void
128*0c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image)
129*0c0fea5dSIngo Weinhold {
130*0c0fea5dSIngo Weinhold 	image->next = 0;
131*0c0fea5dSIngo Weinhold 
132*0c0fea5dSIngo Weinhold 	image->prev = queue->tail;
133*0c0fea5dSIngo Weinhold 	if (queue->tail)
134*0c0fea5dSIngo Weinhold 		queue->tail->next = image;
135*0c0fea5dSIngo Weinhold 
136*0c0fea5dSIngo Weinhold 	queue->tail = image;
137*0c0fea5dSIngo Weinhold 	if (!queue->head)
138*0c0fea5dSIngo Weinhold 		queue->head = image;
139*0c0fea5dSIngo Weinhold }
140*0c0fea5dSIngo Weinhold 
141*0c0fea5dSIngo Weinhold 
142*0c0fea5dSIngo Weinhold static void
143*0c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image)
144*0c0fea5dSIngo Weinhold {
145*0c0fea5dSIngo Weinhold 	if (image->next)
146*0c0fea5dSIngo Weinhold 		image->next->prev = image->prev;
147*0c0fea5dSIngo Weinhold 	else
148*0c0fea5dSIngo Weinhold 		queue->tail = image->prev;
149*0c0fea5dSIngo Weinhold 
150*0c0fea5dSIngo Weinhold 	if (image->prev)
151*0c0fea5dSIngo Weinhold 		image->prev->next = image->next;
152*0c0fea5dSIngo Weinhold 	else
153*0c0fea5dSIngo Weinhold 		queue->head = image->next;
154*0c0fea5dSIngo Weinhold 
155*0c0fea5dSIngo Weinhold 	image->prev = 0;
156*0c0fea5dSIngo Weinhold 	image->next = 0;
157*0c0fea5dSIngo Weinhold }
158*0c0fea5dSIngo Weinhold 
159*0c0fea5dSIngo Weinhold 
160*0c0fea5dSIngo Weinhold static uint32
161*0c0fea5dSIngo Weinhold elf_hash(const uint8 *name)
162*0c0fea5dSIngo Weinhold {
163*0c0fea5dSIngo Weinhold 	uint32 hash = 0;
164*0c0fea5dSIngo Weinhold 	uint32 temp;
165*0c0fea5dSIngo Weinhold 
166*0c0fea5dSIngo Weinhold 	while (*name) {
167*0c0fea5dSIngo Weinhold 		hash = (hash << 4) + *name++;
168*0c0fea5dSIngo Weinhold 		if ((temp = hash & 0xf0000000)) {
169*0c0fea5dSIngo Weinhold 			hash ^= temp >> 24;
170*0c0fea5dSIngo Weinhold 		}
171*0c0fea5dSIngo Weinhold 		hash &= ~temp;
172*0c0fea5dSIngo Weinhold 	}
173*0c0fea5dSIngo Weinhold 	return hash;
174*0c0fea5dSIngo Weinhold }
175*0c0fea5dSIngo Weinhold 
176*0c0fea5dSIngo Weinhold 
177*0c0fea5dSIngo Weinhold static image_t *
178*0c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath,
179*0c0fea5dSIngo Weinhold 	uint32 typeMask)
180*0c0fea5dSIngo Weinhold {
181*0c0fea5dSIngo Weinhold 	image_t *image;
182*0c0fea5dSIngo Weinhold 
183*0c0fea5dSIngo Weinhold 	for (image = queue->head; image; image = image->next) {
184*0c0fea5dSIngo Weinhold 		const char *imageName = isPath ? image->path : image->name;
185*0c0fea5dSIngo Weinhold 		int length = isPath ? sizeof(image->path) : sizeof(image->name);
186*0c0fea5dSIngo Weinhold 
187*0c0fea5dSIngo Weinhold 		if (!strncmp(imageName, name, length)
188*0c0fea5dSIngo Weinhold 			&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
189*0c0fea5dSIngo Weinhold 			return image;
190*0c0fea5dSIngo Weinhold 		}
191*0c0fea5dSIngo Weinhold 	}
192*0c0fea5dSIngo Weinhold 
193*0c0fea5dSIngo Weinhold 	return NULL;
194*0c0fea5dSIngo Weinhold }
195*0c0fea5dSIngo Weinhold 
196*0c0fea5dSIngo Weinhold 
197*0c0fea5dSIngo Weinhold static image_t *
198*0c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask)
199*0c0fea5dSIngo Weinhold {
200*0c0fea5dSIngo Weinhold 	bool isPath = (strchr(name, '/') != NULL);
201*0c0fea5dSIngo Weinhold 	image_t *image;
202*0c0fea5dSIngo Weinhold 
203*0c0fea5dSIngo Weinhold 	image = find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
204*0c0fea5dSIngo Weinhold 	if (image == NULL)
205*0c0fea5dSIngo Weinhold 		image = find_image_in_queue(&sLoadingImages, name, isPath, typeMask);
206*0c0fea5dSIngo Weinhold 
207*0c0fea5dSIngo Weinhold 	return image;
208*0c0fea5dSIngo Weinhold }
209*0c0fea5dSIngo Weinhold 
210*0c0fea5dSIngo Weinhold 
211*0c0fea5dSIngo Weinhold static image_t *
212*0c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id)
213*0c0fea5dSIngo Weinhold {
214*0c0fea5dSIngo Weinhold 	image_t *image;
215*0c0fea5dSIngo Weinhold 
216*0c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
217*0c0fea5dSIngo Weinhold 		if (image->id == id)
218*0c0fea5dSIngo Weinhold 			return image;
219*0c0fea5dSIngo Weinhold 	}
220*0c0fea5dSIngo Weinhold 
221*0c0fea5dSIngo Weinhold 	// For the termination routine, we need to look into the list of
222*0c0fea5dSIngo Weinhold 	// disposable images as well
223*0c0fea5dSIngo Weinhold 	for (image = sDisposableImages.head; image; image = image->next) {
224*0c0fea5dSIngo Weinhold 		if (image->id == id)
225*0c0fea5dSIngo Weinhold 			return image;
226*0c0fea5dSIngo Weinhold 	}
227*0c0fea5dSIngo Weinhold 
228*0c0fea5dSIngo Weinhold 	return NULL;
229*0c0fea5dSIngo Weinhold }
230*0c0fea5dSIngo Weinhold 
231*0c0fea5dSIngo Weinhold 
232*0c0fea5dSIngo Weinhold static status_t
233*0c0fea5dSIngo Weinhold parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize, int32 *_sheaderSize)
234*0c0fea5dSIngo Weinhold {
235*0c0fea5dSIngo Weinhold 	if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
236*0c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
237*0c0fea5dSIngo Weinhold 
238*0c0fea5dSIngo Weinhold 	if (eheader->e_ident[4] != ELFCLASS32)
239*0c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
240*0c0fea5dSIngo Weinhold 
241*0c0fea5dSIngo Weinhold 	if (eheader->e_phoff == 0)
242*0c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
243*0c0fea5dSIngo Weinhold 
244*0c0fea5dSIngo Weinhold 	if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
245*0c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
246*0c0fea5dSIngo Weinhold 
247*0c0fea5dSIngo Weinhold 	*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
248*0c0fea5dSIngo Weinhold 	*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
249*0c0fea5dSIngo Weinhold 
250*0c0fea5dSIngo Weinhold 	return *_pheaderSize > 0 && *_sheaderSize > 0 ? B_OK : B_NOT_AN_EXECUTABLE;
251*0c0fea5dSIngo Weinhold }
252*0c0fea5dSIngo Weinhold 
253*0c0fea5dSIngo Weinhold 
254*0c0fea5dSIngo Weinhold static int32
255*0c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize)
256*0c0fea5dSIngo Weinhold {
257*0c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheaders;
258*0c0fea5dSIngo Weinhold 	int32 count = 0;
259*0c0fea5dSIngo Weinhold 	int i;
260*0c0fea5dSIngo Weinhold 
261*0c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
262*0c0fea5dSIngo Weinhold 		pheaders = (struct Elf32_Phdr *)(buff + i * phentsize);
263*0c0fea5dSIngo Weinhold 
264*0c0fea5dSIngo Weinhold 		switch (pheaders->p_type) {
265*0c0fea5dSIngo Weinhold 			case PT_NULL:
266*0c0fea5dSIngo Weinhold 				/* NOP header */
267*0c0fea5dSIngo Weinhold 				break;
268*0c0fea5dSIngo Weinhold 			case PT_LOAD:
269*0c0fea5dSIngo Weinhold 				count += 1;
270*0c0fea5dSIngo Weinhold 				if (pheaders->p_memsz != pheaders->p_filesz) {
271*0c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz);
272*0c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz);
273*0c0fea5dSIngo Weinhold 
274*0c0fea5dSIngo Weinhold 					if (A != B)
275*0c0fea5dSIngo Weinhold 						count += 1;
276*0c0fea5dSIngo Weinhold 				}
277*0c0fea5dSIngo Weinhold 				break;
278*0c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
279*0c0fea5dSIngo Weinhold 				/* will be handled at some other place */
280*0c0fea5dSIngo Weinhold 				break;
281*0c0fea5dSIngo Weinhold 			case PT_INTERP:
282*0c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
283*0c0fea5dSIngo Weinhold 				break;
284*0c0fea5dSIngo Weinhold 			case PT_NOTE:
285*0c0fea5dSIngo Weinhold 				/* unsupported */
286*0c0fea5dSIngo Weinhold 				break;
287*0c0fea5dSIngo Weinhold 			case PT_SHLIB:
288*0c0fea5dSIngo Weinhold 				/* undefined semantics */
289*0c0fea5dSIngo Weinhold 				break;
290*0c0fea5dSIngo Weinhold 			case PT_PHDR:
291*0c0fea5dSIngo Weinhold 				/* we don't use it */
292*0c0fea5dSIngo Weinhold 				break;
293*0c0fea5dSIngo Weinhold 			default:
294*0c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type);
295*0c0fea5dSIngo Weinhold 				return B_BAD_DATA;
296*0c0fea5dSIngo Weinhold 		}
297*0c0fea5dSIngo Weinhold 	}
298*0c0fea5dSIngo Weinhold 
299*0c0fea5dSIngo Weinhold 	return count;
300*0c0fea5dSIngo Weinhold }
301*0c0fea5dSIngo Weinhold 
302*0c0fea5dSIngo Weinhold 
303*0c0fea5dSIngo Weinhold /*
304*0c0fea5dSIngo Weinhold  * create_image() & destroy_image()
305*0c0fea5dSIngo Weinhold  *
306*0c0fea5dSIngo Weinhold  * 	Create and destroy image_t structures. The destroyer makes sure that the
307*0c0fea5dSIngo Weinhold  * 	memory buffers are full of garbage before freeing.
308*0c0fea5dSIngo Weinhold  */
309*0c0fea5dSIngo Weinhold 
310*0c0fea5dSIngo Weinhold static image_t *
311*0c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions)
312*0c0fea5dSIngo Weinhold {
313*0c0fea5dSIngo Weinhold 	size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t);
314*0c0fea5dSIngo Weinhold 	const char *lastSlash;
315*0c0fea5dSIngo Weinhold 
316*0c0fea5dSIngo Weinhold 	image_t *image = (image_t*)malloc(allocSize);
317*0c0fea5dSIngo Weinhold 	if (image == NULL) {
318*0c0fea5dSIngo Weinhold 		FATAL("no memory for image %s\n", path);
319*0c0fea5dSIngo Weinhold 		return NULL;
320*0c0fea5dSIngo Weinhold 	}
321*0c0fea5dSIngo Weinhold 
322*0c0fea5dSIngo Weinhold 	memset(image, 0, allocSize);
323*0c0fea5dSIngo Weinhold 
324*0c0fea5dSIngo Weinhold 	strlcpy(image->path, path, sizeof(image->path));
325*0c0fea5dSIngo Weinhold 
326*0c0fea5dSIngo Weinhold 	// Make the last component of the supplied name the image name.
327*0c0fea5dSIngo Weinhold 	// If present, DT_SONAME will replace this name.
328*0c0fea5dSIngo Weinhold 	if ((lastSlash = strrchr(name, '/')))
329*0c0fea5dSIngo Weinhold 		strlcpy(image->name, lastSlash + 1, sizeof(image->name));
330*0c0fea5dSIngo Weinhold 	else
331*0c0fea5dSIngo Weinhold 		strlcpy(image->name, name, sizeof(image->name));
332*0c0fea5dSIngo Weinhold 
333*0c0fea5dSIngo Weinhold 	image->ref_count = 1;
334*0c0fea5dSIngo Weinhold 	image->num_regions = num_regions;
335*0c0fea5dSIngo Weinhold 
336*0c0fea5dSIngo Weinhold 	return image;
337*0c0fea5dSIngo Weinhold }
338*0c0fea5dSIngo Weinhold 
339*0c0fea5dSIngo Weinhold 
340*0c0fea5dSIngo Weinhold static void
341*0c0fea5dSIngo Weinhold delete_image_struct(image_t *image)
342*0c0fea5dSIngo Weinhold {
343*0c0fea5dSIngo Weinhold #ifdef DEBUG
344*0c0fea5dSIngo Weinhold 	size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t);
345*0c0fea5dSIngo Weinhold 	memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
346*0c0fea5dSIngo Weinhold #endif
347*0c0fea5dSIngo Weinhold 	free(image->needed);
348*0c0fea5dSIngo Weinhold 
349*0c0fea5dSIngo Weinhold #ifdef DEBUG
350*0c0fea5dSIngo Weinhold 	memset(image, 0xa5, size);
351*0c0fea5dSIngo Weinhold #endif
352*0c0fea5dSIngo Weinhold 	free(image);
353*0c0fea5dSIngo Weinhold }
354*0c0fea5dSIngo Weinhold 
355*0c0fea5dSIngo Weinhold 
356*0c0fea5dSIngo Weinhold static void
357*0c0fea5dSIngo Weinhold delete_image(image_t *image)
358*0c0fea5dSIngo Weinhold {
359*0c0fea5dSIngo Weinhold 	_kern_unregister_image(image->id);
360*0c0fea5dSIngo Weinhold 		// registered in load_container()
361*0c0fea5dSIngo Weinhold 
362*0c0fea5dSIngo Weinhold 	delete_image_struct(image);
363*0c0fea5dSIngo Weinhold }
364*0c0fea5dSIngo Weinhold 
365*0c0fea5dSIngo Weinhold 
366*0c0fea5dSIngo Weinhold static status_t
367*0c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
368*0c0fea5dSIngo Weinhold {
369*0c0fea5dSIngo Weinhold 	struct Elf32_Phdr *pheader;
370*0c0fea5dSIngo Weinhold 	int regcount;
371*0c0fea5dSIngo Weinhold 	int i;
372*0c0fea5dSIngo Weinhold 
373*0c0fea5dSIngo Weinhold 	regcount = 0;
374*0c0fea5dSIngo Weinhold 	for (i = 0; i < phnum; i++) {
375*0c0fea5dSIngo Weinhold 		pheader = (struct Elf32_Phdr *)(buff + i * phentsize);
376*0c0fea5dSIngo Weinhold 
377*0c0fea5dSIngo Weinhold 		switch (pheader->p_type) {
378*0c0fea5dSIngo Weinhold 			case PT_NULL:
379*0c0fea5dSIngo Weinhold 				/* NOP header */
380*0c0fea5dSIngo Weinhold 				break;
381*0c0fea5dSIngo Weinhold 			case PT_LOAD:
382*0c0fea5dSIngo Weinhold 				if (pheader->p_memsz == pheader->p_filesz) {
383*0c0fea5dSIngo Weinhold 					/*
384*0c0fea5dSIngo Weinhold 					 * everything in one area
385*0c0fea5dSIngo Weinhold 					 */
386*0c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
387*0c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_memsz;
388*0c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
389*0c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz
390*0c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
391*0c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
392*0c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
393*0c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
394*0c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
395*0c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
396*0c0fea5dSIngo Weinhold 						// this is a writable segment
397*0c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
398*0c0fea5dSIngo Weinhold 					}
399*0c0fea5dSIngo Weinhold 				} else {
400*0c0fea5dSIngo Weinhold 					/*
401*0c0fea5dSIngo Weinhold 					 * may require splitting
402*0c0fea5dSIngo Weinhold 					 */
403*0c0fea5dSIngo Weinhold 					addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz);
404*0c0fea5dSIngo Weinhold 					addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz);
405*0c0fea5dSIngo Weinhold 
406*0c0fea5dSIngo Weinhold 					image->regions[regcount].start = pheader->p_vaddr;
407*0c0fea5dSIngo Weinhold 					image->regions[regcount].size = pheader->p_filesz;
408*0c0fea5dSIngo Weinhold 					image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr);
409*0c0fea5dSIngo Weinhold 					image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz
410*0c0fea5dSIngo Weinhold 						+ PAGE_OFFSET(pheader->p_vaddr));
411*0c0fea5dSIngo Weinhold 					image->regions[regcount].fdstart = pheader->p_offset;
412*0c0fea5dSIngo Weinhold 					image->regions[regcount].fdsize = pheader->p_filesz;
413*0c0fea5dSIngo Weinhold 					image->regions[regcount].delta = 0;
414*0c0fea5dSIngo Weinhold 					image->regions[regcount].flags = 0;
415*0c0fea5dSIngo Weinhold 					if (pheader->p_flags & PF_WRITE) {
416*0c0fea5dSIngo Weinhold 						// this is a writable segment
417*0c0fea5dSIngo Weinhold 						image->regions[regcount].flags |= RFLAG_RW;
418*0c0fea5dSIngo Weinhold 					}
419*0c0fea5dSIngo Weinhold 
420*0c0fea5dSIngo Weinhold 					if (A != B) {
421*0c0fea5dSIngo Weinhold 						/*
422*0c0fea5dSIngo Weinhold 						 * yeah, it requires splitting
423*0c0fea5dSIngo Weinhold 						 */
424*0c0fea5dSIngo Weinhold 						regcount += 1;
425*0c0fea5dSIngo Weinhold 						image->regions[regcount].start = pheader->p_vaddr;
426*0c0fea5dSIngo Weinhold 						image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz;
427*0c0fea5dSIngo Weinhold 						image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
428*0c0fea5dSIngo Weinhold 						image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr))
429*0c0fea5dSIngo Weinhold 							- image->regions[regcount-1].vmsize;
430*0c0fea5dSIngo Weinhold 						image->regions[regcount].fdstart = 0;
431*0c0fea5dSIngo Weinhold 						image->regions[regcount].fdsize = 0;
432*0c0fea5dSIngo Weinhold 						image->regions[regcount].delta = 0;
433*0c0fea5dSIngo Weinhold 						image->regions[regcount].flags = RFLAG_ANON;
434*0c0fea5dSIngo Weinhold 						if (pheader->p_flags & PF_WRITE) {
435*0c0fea5dSIngo Weinhold 							// this is a writable segment
436*0c0fea5dSIngo Weinhold 							image->regions[regcount].flags |= RFLAG_RW;
437*0c0fea5dSIngo Weinhold 						}
438*0c0fea5dSIngo Weinhold 					}
439*0c0fea5dSIngo Weinhold 				}
440*0c0fea5dSIngo Weinhold 				regcount += 1;
441*0c0fea5dSIngo Weinhold 				break;
442*0c0fea5dSIngo Weinhold 			case PT_DYNAMIC:
443*0c0fea5dSIngo Weinhold 				image->dynamic_ptr = pheader->p_vaddr;
444*0c0fea5dSIngo Weinhold 				break;
445*0c0fea5dSIngo Weinhold 			case PT_INTERP:
446*0c0fea5dSIngo Weinhold 				/* should check here for appropiate interpreter */
447*0c0fea5dSIngo Weinhold 				break;
448*0c0fea5dSIngo Weinhold 			case PT_NOTE:
449*0c0fea5dSIngo Weinhold 				/* unsupported */
450*0c0fea5dSIngo Weinhold 				break;
451*0c0fea5dSIngo Weinhold 			case PT_SHLIB:
452*0c0fea5dSIngo Weinhold 				/* undefined semantics */
453*0c0fea5dSIngo Weinhold 				break;
454*0c0fea5dSIngo Weinhold 			case PT_PHDR:
455*0c0fea5dSIngo Weinhold 				/* we don't use it */
456*0c0fea5dSIngo Weinhold 				break;
457*0c0fea5dSIngo Weinhold 			default:
458*0c0fea5dSIngo Weinhold 				FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type);
459*0c0fea5dSIngo Weinhold 				return B_BAD_DATA;
460*0c0fea5dSIngo Weinhold 		}
461*0c0fea5dSIngo Weinhold 	}
462*0c0fea5dSIngo Weinhold 
463*0c0fea5dSIngo Weinhold 	return B_OK;
464*0c0fea5dSIngo Weinhold }
465*0c0fea5dSIngo Weinhold 
466*0c0fea5dSIngo Weinhold 
467*0c0fea5dSIngo Weinhold static bool
468*0c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image)
469*0c0fea5dSIngo Weinhold {
470*0c0fea5dSIngo Weinhold 	uint32 i;
471*0c0fea5dSIngo Weinhold 
472*0c0fea5dSIngo Weinhold 	if (!image->dynamic_ptr)
473*0c0fea5dSIngo Weinhold 		return true;
474*0c0fea5dSIngo Weinhold 
475*0c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
476*0c0fea5dSIngo Weinhold 		if (image->dynamic_ptr >= image->regions[i].start
477*0c0fea5dSIngo Weinhold 			&& image->dynamic_ptr < image->regions[i].start + image->regions[i].size)
478*0c0fea5dSIngo Weinhold 			return true;
479*0c0fea5dSIngo Weinhold 	}
480*0c0fea5dSIngo Weinhold 
481*0c0fea5dSIngo Weinhold 	return false;
482*0c0fea5dSIngo Weinhold }
483*0c0fea5dSIngo Weinhold 
484*0c0fea5dSIngo Weinhold 
485*0c0fea5dSIngo Weinhold /**	This function will change the protection of all read-only segments
486*0c0fea5dSIngo Weinhold  *	to really be read-only.
487*0c0fea5dSIngo Weinhold  *	The areas have to be read/write first, so that they can be relocated.
488*0c0fea5dSIngo Weinhold  */
489*0c0fea5dSIngo Weinhold 
490*0c0fea5dSIngo Weinhold static void
491*0c0fea5dSIngo Weinhold remap_images(void)
492*0c0fea5dSIngo Weinhold {
493*0c0fea5dSIngo Weinhold 	image_t *image;
494*0c0fea5dSIngo Weinhold 	uint32 i;
495*0c0fea5dSIngo Weinhold 
496*0c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
497*0c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_regions; i++) {
498*0c0fea5dSIngo Weinhold 			if ((image->regions[i].flags & RFLAG_RW) == 0
499*0c0fea5dSIngo Weinhold 				&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
500*0c0fea5dSIngo Weinhold 				// we only need to do this once, so we remember those we've already mapped
501*0c0fea5dSIngo Weinhold 				if (_kern_set_area_protection(image->regions[i].id,
502*0c0fea5dSIngo Weinhold 						B_READ_AREA | B_EXECUTE_AREA) == B_OK)
503*0c0fea5dSIngo Weinhold 					image->regions[i].flags |= RFLAG_REMAPPED;
504*0c0fea5dSIngo Weinhold 			}
505*0c0fea5dSIngo Weinhold 		}
506*0c0fea5dSIngo Weinhold 	}
507*0c0fea5dSIngo Weinhold }
508*0c0fea5dSIngo Weinhold 
509*0c0fea5dSIngo Weinhold 
510*0c0fea5dSIngo Weinhold static status_t
511*0c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed)
512*0c0fea5dSIngo Weinhold {
513*0c0fea5dSIngo Weinhold 	status_t status = B_OK;
514*0c0fea5dSIngo Weinhold 	const char *baseName;
515*0c0fea5dSIngo Weinhold 	uint32 i;
516*0c0fea5dSIngo Weinhold 
517*0c0fea5dSIngo Weinhold 	(void)(fd);
518*0c0fea5dSIngo Weinhold 
519*0c0fea5dSIngo Weinhold 	// cut the file name from the path as base name for the created areas
520*0c0fea5dSIngo Weinhold 	baseName = strrchr(path, '/');
521*0c0fea5dSIngo Weinhold 	if (baseName != NULL)
522*0c0fea5dSIngo Weinhold 		baseName++;
523*0c0fea5dSIngo Weinhold 	else
524*0c0fea5dSIngo Weinhold 		baseName = path;
525*0c0fea5dSIngo Weinhold 
526*0c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
527*0c0fea5dSIngo Weinhold 		char regionName[B_OS_NAME_LENGTH];
528*0c0fea5dSIngo Weinhold 		addr_t loadAddress;
529*0c0fea5dSIngo Weinhold 		uint32 addressSpecifier;
530*0c0fea5dSIngo Weinhold 
531*0c0fea5dSIngo Weinhold 		// for BeOS compatibility: if we load an old BeOS executable, we
532*0c0fea5dSIngo Weinhold 		// have to relocate it, if possible - we recognize it because the
533*0c0fea5dSIngo Weinhold 		// vmstart is set to 0 (hopefully always)
534*0c0fea5dSIngo Weinhold 		if (fixed && image->regions[i].vmstart == 0)
535*0c0fea5dSIngo Weinhold 			fixed = false;
536*0c0fea5dSIngo Weinhold 
537*0c0fea5dSIngo Weinhold 		snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
538*0c0fea5dSIngo Weinhold 			baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
539*0c0fea5dSIngo Weinhold 
540*0c0fea5dSIngo Weinhold 		if (image->dynamic_ptr && !fixed) {
541*0c0fea5dSIngo Weinhold 			// relocatable image... we can afford to place wherever
542*0c0fea5dSIngo Weinhold 			if (i == 0) {
543*0c0fea5dSIngo Weinhold 				// but only the first segment gets a free ride
544*0c0fea5dSIngo Weinhold 				loadAddress = RLD_PROGRAM_BASE;
545*0c0fea5dSIngo Weinhold 				addressSpecifier = B_BASE_ADDRESS;
546*0c0fea5dSIngo Weinhold 			} else {
547*0c0fea5dSIngo Weinhold 				loadAddress = image->regions[i].vmstart + image->regions[i-1].delta;
548*0c0fea5dSIngo Weinhold 				addressSpecifier = B_EXACT_ADDRESS;
549*0c0fea5dSIngo Weinhold 			}
550*0c0fea5dSIngo Weinhold 		} else {
551*0c0fea5dSIngo Weinhold 			// not relocatable, put it where it asks or die trying
552*0c0fea5dSIngo Weinhold 			loadAddress = image->regions[i].vmstart;
553*0c0fea5dSIngo Weinhold 			addressSpecifier = B_EXACT_ADDRESS;
554*0c0fea5dSIngo Weinhold 		}
555*0c0fea5dSIngo Weinhold 
556*0c0fea5dSIngo Weinhold 		if (image->regions[i].flags & RFLAG_ANON) {
557*0c0fea5dSIngo Weinhold 			image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress,
558*0c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_NO_LOCK,
559*0c0fea5dSIngo Weinhold 				B_READ_AREA | B_WRITE_AREA);
560*0c0fea5dSIngo Weinhold 
561*0c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
562*0c0fea5dSIngo Weinhold 				status = image->regions[i].id;
563*0c0fea5dSIngo Weinhold 				goto error;
564*0c0fea5dSIngo Weinhold 			}
565*0c0fea5dSIngo Weinhold 
566*0c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
567*0c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
568*0c0fea5dSIngo Weinhold 		} else {
569*0c0fea5dSIngo Weinhold 			image->regions[i].id = sys_vm_map_file(regionName, (void **)&loadAddress,
570*0c0fea5dSIngo Weinhold 				addressSpecifier, image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
571*0c0fea5dSIngo Weinhold 				REGION_PRIVATE_MAP, path, PAGE_BASE(image->regions[i].fdstart));
572*0c0fea5dSIngo Weinhold 
573*0c0fea5dSIngo Weinhold 			if (image->regions[i].id < 0) {
574*0c0fea5dSIngo Weinhold 				status = image->regions[i].id;
575*0c0fea5dSIngo Weinhold 				goto error;
576*0c0fea5dSIngo Weinhold 			}
577*0c0fea5dSIngo Weinhold 
578*0c0fea5dSIngo Weinhold 			TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
579*0c0fea5dSIngo Weinhold 				(void *)loadAddress, image->regions[i].vmsize,
580*0c0fea5dSIngo Weinhold 				image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
581*0c0fea5dSIngo Weinhold 
582*0c0fea5dSIngo Weinhold 			image->regions[i].delta = loadAddress - image->regions[i].vmstart;
583*0c0fea5dSIngo Weinhold 			image->regions[i].vmstart = loadAddress;
584*0c0fea5dSIngo Weinhold 
585*0c0fea5dSIngo Weinhold 			// handle trailer bits in data segment
586*0c0fea5dSIngo Weinhold 			if (image->regions[i].flags & RFLAG_RW) {
587*0c0fea5dSIngo Weinhold 				addr_t startClearing;
588*0c0fea5dSIngo Weinhold 				addr_t toClear;
589*0c0fea5dSIngo Weinhold 
590*0c0fea5dSIngo Weinhold 				startClearing = image->regions[i].vmstart
591*0c0fea5dSIngo Weinhold 					+ PAGE_OFFSET(image->regions[i].start)
592*0c0fea5dSIngo Weinhold 					+ image->regions[i].size;
593*0c0fea5dSIngo Weinhold 				toClear = image->regions[i].vmsize
594*0c0fea5dSIngo Weinhold 					- PAGE_OFFSET(image->regions[i].start)
595*0c0fea5dSIngo Weinhold 					- image->regions[i].size;
596*0c0fea5dSIngo Weinhold 
597*0c0fea5dSIngo Weinhold 				TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear));
598*0c0fea5dSIngo Weinhold 				memset((void *)startClearing, 0, toClear);
599*0c0fea5dSIngo Weinhold 			}
600*0c0fea5dSIngo Weinhold 		}
601*0c0fea5dSIngo Weinhold 	}
602*0c0fea5dSIngo Weinhold 
603*0c0fea5dSIngo Weinhold 	if (image->dynamic_ptr)
604*0c0fea5dSIngo Weinhold 		image->dynamic_ptr += image->regions[0].delta;
605*0c0fea5dSIngo Weinhold 
606*0c0fea5dSIngo Weinhold 	return B_OK;
607*0c0fea5dSIngo Weinhold 
608*0c0fea5dSIngo Weinhold error:
609*0c0fea5dSIngo Weinhold 	return status;
610*0c0fea5dSIngo Weinhold }
611*0c0fea5dSIngo Weinhold 
612*0c0fea5dSIngo Weinhold 
613*0c0fea5dSIngo Weinhold static void
614*0c0fea5dSIngo Weinhold unmap_image(image_t *image)
615*0c0fea5dSIngo Weinhold {
616*0c0fea5dSIngo Weinhold 	uint32 i;
617*0c0fea5dSIngo Weinhold 
618*0c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_regions; i++) {
619*0c0fea5dSIngo Weinhold 		_kern_delete_area(image->regions[i].id);
620*0c0fea5dSIngo Weinhold 
621*0c0fea5dSIngo Weinhold 		image->regions[i].id = -1;
622*0c0fea5dSIngo Weinhold 	}
623*0c0fea5dSIngo Weinhold }
624*0c0fea5dSIngo Weinhold 
625*0c0fea5dSIngo Weinhold 
626*0c0fea5dSIngo Weinhold static bool
627*0c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image)
628*0c0fea5dSIngo Weinhold {
629*0c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d;
630*0c0fea5dSIngo Weinhold 	int i;
631*0c0fea5dSIngo Weinhold 	int sonameOffset = -1;
632*0c0fea5dSIngo Weinhold 
633*0c0fea5dSIngo Weinhold 	image->symhash = 0;
634*0c0fea5dSIngo Weinhold 	image->syms = 0;
635*0c0fea5dSIngo Weinhold 	image->strtab = 0;
636*0c0fea5dSIngo Weinhold 
637*0c0fea5dSIngo Weinhold 	d = (struct Elf32_Dyn *)image->dynamic_ptr;
638*0c0fea5dSIngo Weinhold 	if (!d)
639*0c0fea5dSIngo Weinhold 		return true;
640*0c0fea5dSIngo Weinhold 
641*0c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
642*0c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
643*0c0fea5dSIngo Weinhold 			case DT_NEEDED:
644*0c0fea5dSIngo Weinhold 				image->num_needed += 1;
645*0c0fea5dSIngo Weinhold 				break;
646*0c0fea5dSIngo Weinhold 			case DT_HASH:
647*0c0fea5dSIngo Weinhold 				image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta);
648*0c0fea5dSIngo Weinhold 				break;
649*0c0fea5dSIngo Weinhold 			case DT_STRTAB:
650*0c0fea5dSIngo Weinhold 				image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
651*0c0fea5dSIngo Weinhold 				break;
652*0c0fea5dSIngo Weinhold 			case DT_SYMTAB:
653*0c0fea5dSIngo Weinhold 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
654*0c0fea5dSIngo Weinhold 				break;
655*0c0fea5dSIngo Weinhold 			case DT_REL:
656*0c0fea5dSIngo Weinhold 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
657*0c0fea5dSIngo Weinhold 				break;
658*0c0fea5dSIngo Weinhold 			case DT_RELSZ:
659*0c0fea5dSIngo Weinhold 				image->rel_len = d[i].d_un.d_val;
660*0c0fea5dSIngo Weinhold 				break;
661*0c0fea5dSIngo Weinhold 			case DT_RELA:
662*0c0fea5dSIngo Weinhold 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
663*0c0fea5dSIngo Weinhold 				break;
664*0c0fea5dSIngo Weinhold 			case DT_RELASZ:
665*0c0fea5dSIngo Weinhold 				image->rela_len = d[i].d_un.d_val;
666*0c0fea5dSIngo Weinhold 				break;
667*0c0fea5dSIngo Weinhold 			// TK: procedure linkage table
668*0c0fea5dSIngo Weinhold 			case DT_JMPREL:
669*0c0fea5dSIngo Weinhold 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
670*0c0fea5dSIngo Weinhold 				break;
671*0c0fea5dSIngo Weinhold 			case DT_PLTRELSZ:
672*0c0fea5dSIngo Weinhold 				image->pltrel_len = d[i].d_un.d_val;
673*0c0fea5dSIngo Weinhold 				break;
674*0c0fea5dSIngo Weinhold 			case DT_INIT:
675*0c0fea5dSIngo Weinhold 				image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
676*0c0fea5dSIngo Weinhold 				break;
677*0c0fea5dSIngo Weinhold 			case DT_FINI:
678*0c0fea5dSIngo Weinhold 				image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta);
679*0c0fea5dSIngo Weinhold 				break;
680*0c0fea5dSIngo Weinhold 			case DT_SONAME:
681*0c0fea5dSIngo Weinhold 				sonameOffset = d[i].d_un.d_val;
682*0c0fea5dSIngo Weinhold 				break;
683*0c0fea5dSIngo Weinhold 			default:
684*0c0fea5dSIngo Weinhold 				continue;
685*0c0fea5dSIngo Weinhold 		}
686*0c0fea5dSIngo Weinhold 	}
687*0c0fea5dSIngo Weinhold 
688*0c0fea5dSIngo Weinhold 	// lets make sure we found all the required sections
689*0c0fea5dSIngo Weinhold 	if (!image->symhash || !image->syms || !image->strtab)
690*0c0fea5dSIngo Weinhold 		return false;
691*0c0fea5dSIngo Weinhold 
692*0c0fea5dSIngo Weinhold 	if (sonameOffset >= 0)
693*0c0fea5dSIngo Weinhold 		strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
694*0c0fea5dSIngo Weinhold 
695*0c0fea5dSIngo Weinhold 	return true;
696*0c0fea5dSIngo Weinhold }
697*0c0fea5dSIngo Weinhold 
698*0c0fea5dSIngo Weinhold 
699*0c0fea5dSIngo Weinhold static struct Elf32_Sym *
700*0c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type)
701*0c0fea5dSIngo Weinhold {
702*0c0fea5dSIngo Weinhold 	uint32 hash, i;
703*0c0fea5dSIngo Weinhold 
704*0c0fea5dSIngo Weinhold 	// ToDo: "type" is currently ignored!
705*0c0fea5dSIngo Weinhold 	(void)type;
706*0c0fea5dSIngo Weinhold 
707*0c0fea5dSIngo Weinhold 	if (image->dynamic_ptr == NULL)
708*0c0fea5dSIngo Weinhold 		return NULL;
709*0c0fea5dSIngo Weinhold 
710*0c0fea5dSIngo Weinhold 	hash = elf_hash((uint8 *)name) % HASHTABSIZE(image);
711*0c0fea5dSIngo Weinhold 
712*0c0fea5dSIngo Weinhold 	for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
713*0c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = &image->syms[i];
714*0c0fea5dSIngo Weinhold 
715*0c0fea5dSIngo Weinhold 		if (symbol->st_shndx != SHN_UNDEF
716*0c0fea5dSIngo Weinhold 			&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
717*0c0fea5dSIngo Weinhold 				|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
718*0c0fea5dSIngo Weinhold 			&& !strcmp(SYMNAME(image, symbol), name)) {
719*0c0fea5dSIngo Weinhold 			// check if the type matches
720*0c0fea5dSIngo Weinhold 			if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
721*0c0fea5dSIngo Weinhold 				|| (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT))
722*0c0fea5dSIngo Weinhold 				continue;
723*0c0fea5dSIngo Weinhold 
724*0c0fea5dSIngo Weinhold 			return symbol;
725*0c0fea5dSIngo Weinhold 		}
726*0c0fea5dSIngo Weinhold 	}
727*0c0fea5dSIngo Weinhold 
728*0c0fea5dSIngo Weinhold 	return NULL;
729*0c0fea5dSIngo Weinhold }
730*0c0fea5dSIngo Weinhold 
731*0c0fea5dSIngo Weinhold 
732*0c0fea5dSIngo Weinhold static struct Elf32_Sym *
733*0c0fea5dSIngo Weinhold find_symbol_in_loaded_images(image_t **_image, const char *name)
734*0c0fea5dSIngo Weinhold {
735*0c0fea5dSIngo Weinhold 	image_t *image;
736*0c0fea5dSIngo Weinhold 
737*0c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
738*0c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol;
739*0c0fea5dSIngo Weinhold 
740*0c0fea5dSIngo Weinhold 		if (image->dynamic_ptr == NULL)
741*0c0fea5dSIngo Weinhold 			continue;
742*0c0fea5dSIngo Weinhold 
743*0c0fea5dSIngo Weinhold 		symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY);
744*0c0fea5dSIngo Weinhold 		if (symbol) {
745*0c0fea5dSIngo Weinhold 			*_image = image;
746*0c0fea5dSIngo Weinhold 			return symbol;
747*0c0fea5dSIngo Weinhold 		}
748*0c0fea5dSIngo Weinhold 	}
749*0c0fea5dSIngo Weinhold 
750*0c0fea5dSIngo Weinhold 	return NULL;
751*0c0fea5dSIngo Weinhold }
752*0c0fea5dSIngo Weinhold 
753*0c0fea5dSIngo Weinhold 
754*0c0fea5dSIngo Weinhold int
755*0c0fea5dSIngo Weinhold resolve_symbol(image_t *image, struct Elf32_Sym *sym, addr_t *sym_addr)
756*0c0fea5dSIngo Weinhold {
757*0c0fea5dSIngo Weinhold 	struct Elf32_Sym *sym2;
758*0c0fea5dSIngo Weinhold 	char *symname;
759*0c0fea5dSIngo Weinhold 	image_t *shimg;
760*0c0fea5dSIngo Weinhold 
761*0c0fea5dSIngo Weinhold 	switch (sym->st_shndx) {
762*0c0fea5dSIngo Weinhold 		case SHN_UNDEF:
763*0c0fea5dSIngo Weinhold 			// patch the symbol name
764*0c0fea5dSIngo Weinhold 			symname = SYMNAME(image, sym);
765*0c0fea5dSIngo Weinhold 
766*0c0fea5dSIngo Weinhold 			// it's undefined, must be outside this image, try the other image
767*0c0fea5dSIngo Weinhold 			sym2 = find_symbol_in_loaded_images(&shimg, symname);
768*0c0fea5dSIngo Weinhold 			if (!sym2) {
769*0c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: could not resolve symbol '%s'\n", symname);
770*0c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
771*0c0fea5dSIngo Weinhold 			}
772*0c0fea5dSIngo Weinhold 
773*0c0fea5dSIngo Weinhold 			// make sure they're the same type
774*0c0fea5dSIngo Weinhold 			if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
775*0c0fea5dSIngo Weinhold 				&& ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) {
776*0c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", symname);
777*0c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
778*0c0fea5dSIngo Weinhold 			}
779*0c0fea5dSIngo Weinhold 
780*0c0fea5dSIngo Weinhold 			if (ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL
781*0c0fea5dSIngo Weinhold 				&& ELF32_ST_BIND(sym2->st_info) != STB_WEAK) {
782*0c0fea5dSIngo Weinhold 				printf("elf_resolve_symbol: found symbol '%s' but not exported\n", symname);
783*0c0fea5dSIngo Weinhold 				return B_MISSING_SYMBOL;
784*0c0fea5dSIngo Weinhold 			}
785*0c0fea5dSIngo Weinhold 
786*0c0fea5dSIngo Weinhold 			*sym_addr = sym2->st_value + shimg->regions[0].delta;
787*0c0fea5dSIngo Weinhold 			return B_NO_ERROR;
788*0c0fea5dSIngo Weinhold 
789*0c0fea5dSIngo Weinhold 		case SHN_ABS:
790*0c0fea5dSIngo Weinhold 			*sym_addr = sym->st_value + image->regions[0].delta;
791*0c0fea5dSIngo Weinhold 			return B_NO_ERROR;
792*0c0fea5dSIngo Weinhold 
793*0c0fea5dSIngo Weinhold 		case SHN_COMMON:
794*0c0fea5dSIngo Weinhold 			// ToDo: finish this
795*0c0fea5dSIngo Weinhold 			printf("elf_resolve_symbol: COMMON symbol, finish me!\n");
796*0c0fea5dSIngo Weinhold 			return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
797*0c0fea5dSIngo Weinhold 
798*0c0fea5dSIngo Weinhold 		default:
799*0c0fea5dSIngo Weinhold 			// standard symbol
800*0c0fea5dSIngo Weinhold 			*sym_addr = sym->st_value + image->regions[0].delta;
801*0c0fea5dSIngo Weinhold 			return B_NO_ERROR;
802*0c0fea5dSIngo Weinhold 	}
803*0c0fea5dSIngo Weinhold }
804*0c0fea5dSIngo Weinhold 
805*0c0fea5dSIngo Weinhold 
806*0c0fea5dSIngo Weinhold static void
807*0c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path)
808*0c0fea5dSIngo Weinhold {
809*0c0fea5dSIngo Weinhold 	struct stat stat;
810*0c0fea5dSIngo Weinhold 	image_info info;
811*0c0fea5dSIngo Weinhold 
812*0c0fea5dSIngo Weinhold 	// ToDo: set these correctly
813*0c0fea5dSIngo Weinhold 	info.id = 0;
814*0c0fea5dSIngo Weinhold 	info.type = image->type;
815*0c0fea5dSIngo Weinhold 	info.sequence = 0;
816*0c0fea5dSIngo Weinhold 	info.init_order = 0;
817*0c0fea5dSIngo Weinhold 	info.init_routine = (void (*)())image->init_routine;
818*0c0fea5dSIngo Weinhold 	info.term_routine = (void (*)())image->term_routine;
819*0c0fea5dSIngo Weinhold 
820*0c0fea5dSIngo Weinhold 	if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
821*0c0fea5dSIngo Weinhold 		info.device = stat.st_dev;
822*0c0fea5dSIngo Weinhold 		info.node = stat.st_ino;
823*0c0fea5dSIngo Weinhold 	} else {
824*0c0fea5dSIngo Weinhold 		info.device = -1;
825*0c0fea5dSIngo Weinhold 		info.node = -1;
826*0c0fea5dSIngo Weinhold 	}
827*0c0fea5dSIngo Weinhold 
828*0c0fea5dSIngo Weinhold 	strlcpy(info.name, path, sizeof(info.name));
829*0c0fea5dSIngo Weinhold 	info.text = (void *)image->regions[0].vmstart;
830*0c0fea5dSIngo Weinhold 	info.text_size = image->regions[0].vmsize;
831*0c0fea5dSIngo Weinhold 	info.data = (void *)image->regions[1].vmstart;
832*0c0fea5dSIngo Weinhold 	info.data_size = image->regions[1].vmsize;
833*0c0fea5dSIngo Weinhold 	image->id = _kern_register_image(&info, sizeof(image_info));
834*0c0fea5dSIngo Weinhold }
835*0c0fea5dSIngo Weinhold 
836*0c0fea5dSIngo Weinhold 
837*0c0fea5dSIngo Weinhold static status_t
838*0c0fea5dSIngo Weinhold relocate_image(image_t *image)
839*0c0fea5dSIngo Weinhold {
840*0c0fea5dSIngo Weinhold 	status_t status = arch_relocate_image(image);
841*0c0fea5dSIngo Weinhold 	if (status < B_OK) {
842*0c0fea5dSIngo Weinhold 		FATAL("troubles relocating: 0x%lx\n", status);
843*0c0fea5dSIngo Weinhold 		return status;
844*0c0fea5dSIngo Weinhold 	}
845*0c0fea5dSIngo Weinhold 
846*0c0fea5dSIngo Weinhold 	_kern_image_relocated(image->id);
847*0c0fea5dSIngo Weinhold 	return B_OK;
848*0c0fea5dSIngo Weinhold }
849*0c0fea5dSIngo Weinhold 
850*0c0fea5dSIngo Weinhold 
851*0c0fea5dSIngo Weinhold static status_t
852*0c0fea5dSIngo Weinhold load_container(char const *name, image_type type, const char *rpath, image_t **_image)
853*0c0fea5dSIngo Weinhold {
854*0c0fea5dSIngo Weinhold 	int32 pheaderSize, sheaderSize;
855*0c0fea5dSIngo Weinhold 	char path[PATH_MAX];
856*0c0fea5dSIngo Weinhold 	ssize_t length;
857*0c0fea5dSIngo Weinhold 	char ph_buff[4096];
858*0c0fea5dSIngo Weinhold 	int32 numRegions;
859*0c0fea5dSIngo Weinhold 	image_t *found;
860*0c0fea5dSIngo Weinhold 	image_t *image;
861*0c0fea5dSIngo Weinhold 	status_t status;
862*0c0fea5dSIngo Weinhold 	int fd;
863*0c0fea5dSIngo Weinhold 
864*0c0fea5dSIngo Weinhold 	struct Elf32_Ehdr eheader;
865*0c0fea5dSIngo Weinhold 
866*0c0fea5dSIngo Weinhold 	// Have we already loaded that image? Don't check for add-ons -- we always
867*0c0fea5dSIngo Weinhold 	// reload them.
868*0c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
869*0c0fea5dSIngo Weinhold 		found = find_image(name, APP_OR_LIBRARY_TYPE);
870*0c0fea5dSIngo Weinhold 		if (found) {
871*0c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
872*0c0fea5dSIngo Weinhold 			*_image = found;
873*0c0fea5dSIngo Weinhold 			return B_OK;
874*0c0fea5dSIngo Weinhold 		}
875*0c0fea5dSIngo Weinhold 	}
876*0c0fea5dSIngo Weinhold 
877*0c0fea5dSIngo Weinhold 	strlcpy(path, name, sizeof(path));
878*0c0fea5dSIngo Weinhold 
879*0c0fea5dSIngo Weinhold 	// Try to load explicit image path first
880*0c0fea5dSIngo Weinhold 	fd = open_executable(path, type, rpath);
881*0c0fea5dSIngo Weinhold 	if (fd < 0) {
882*0c0fea5dSIngo Weinhold 		FATAL("cannot open file %s\n", path);
883*0c0fea5dSIngo Weinhold 		return fd;
884*0c0fea5dSIngo Weinhold 	}
885*0c0fea5dSIngo Weinhold 
886*0c0fea5dSIngo Weinhold 	// If the path is not absolute, we prepend the CWD to make it one.
887*0c0fea5dSIngo Weinhold 	if (path[0] != '/') {
888*0c0fea5dSIngo Weinhold 		char relativePath[PATH_MAX];
889*0c0fea5dSIngo Weinhold 		if (!strncmp(path, "./", 2))
890*0c0fea5dSIngo Weinhold 			strcpy(relativePath, path + 2);
891*0c0fea5dSIngo Weinhold 		else
892*0c0fea5dSIngo Weinhold 			strcpy(relativePath, path);
893*0c0fea5dSIngo Weinhold 
894*0c0fea5dSIngo Weinhold 		// get the CWD
895*0c0fea5dSIngo Weinhold 		status = _kern_getcwd(path, sizeof(path));
896*0c0fea5dSIngo Weinhold 		if (status < B_OK) {
897*0c0fea5dSIngo Weinhold 			FATAL("_kern_getcwd() failed\n");
898*0c0fea5dSIngo Weinhold 			goto err1;
899*0c0fea5dSIngo Weinhold 		}
900*0c0fea5dSIngo Weinhold 
901*0c0fea5dSIngo Weinhold 		if (strlcat(path, "/", sizeof(path)) >= sizeof(path)
902*0c0fea5dSIngo Weinhold 			|| strlcat(path, relativePath, sizeof(path)) >= sizeof(path)) {
903*0c0fea5dSIngo Weinhold 			status = B_NAME_TOO_LONG;
904*0c0fea5dSIngo Weinhold 			FATAL("Absolute path of image %s is too "
905*0c0fea5dSIngo Weinhold 				"long!\n", relativePath);
906*0c0fea5dSIngo Weinhold 			goto err1;
907*0c0fea5dSIngo Weinhold 		}
908*0c0fea5dSIngo Weinhold 	}
909*0c0fea5dSIngo Weinhold 
910*0c0fea5dSIngo Weinhold 	// Test again if this image has been registered already - this time,
911*0c0fea5dSIngo Weinhold 	// we can check the full path, not just its name as noted.
912*0c0fea5dSIngo Weinhold 	// You could end up loading an image twice with symbolic links, else.
913*0c0fea5dSIngo Weinhold 	if (type != B_ADD_ON_IMAGE) {
914*0c0fea5dSIngo Weinhold 		found = find_image(path, APP_OR_LIBRARY_TYPE);
915*0c0fea5dSIngo Weinhold 		if (found) {
916*0c0fea5dSIngo Weinhold 			atomic_add(&found->ref_count, 1);
917*0c0fea5dSIngo Weinhold 			*_image = found;
918*0c0fea5dSIngo Weinhold 			return B_OK;
919*0c0fea5dSIngo Weinhold 		}
920*0c0fea5dSIngo Weinhold 	}
921*0c0fea5dSIngo Weinhold 
922*0c0fea5dSIngo Weinhold 	length = _kern_read(fd, 0, &eheader, sizeof(eheader));
923*0c0fea5dSIngo Weinhold 	if (length != sizeof(eheader)) {
924*0c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
925*0c0fea5dSIngo Weinhold 		FATAL("troubles reading ELF header\n");
926*0c0fea5dSIngo Weinhold 		goto err1;
927*0c0fea5dSIngo Weinhold 	}
928*0c0fea5dSIngo Weinhold 
929*0c0fea5dSIngo Weinhold 	status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
930*0c0fea5dSIngo Weinhold 	if (status < B_OK) {
931*0c0fea5dSIngo Weinhold 		FATAL("incorrect ELF header\n");
932*0c0fea5dSIngo Weinhold 		goto err1;
933*0c0fea5dSIngo Weinhold 	}
934*0c0fea5dSIngo Weinhold 
935*0c0fea5dSIngo Weinhold 	// ToDo: what to do about this restriction??
936*0c0fea5dSIngo Weinhold 	if (pheaderSize > (int)sizeof(ph_buff)) {
937*0c0fea5dSIngo Weinhold 		FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff));
938*0c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
939*0c0fea5dSIngo Weinhold 		goto err1;
940*0c0fea5dSIngo Weinhold 	}
941*0c0fea5dSIngo Weinhold 
942*0c0fea5dSIngo Weinhold 	length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize);
943*0c0fea5dSIngo Weinhold 	if (length != pheaderSize) {
944*0c0fea5dSIngo Weinhold 		FATAL("Could not read program headers: %s\n", strerror(length));
945*0c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
946*0c0fea5dSIngo Weinhold 		goto err1;
947*0c0fea5dSIngo Weinhold 	}
948*0c0fea5dSIngo Weinhold 
949*0c0fea5dSIngo Weinhold 	numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
950*0c0fea5dSIngo Weinhold 	if (numRegions <= 0) {
951*0c0fea5dSIngo Weinhold 		FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
952*0c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
953*0c0fea5dSIngo Weinhold 		goto err1;
954*0c0fea5dSIngo Weinhold 	}
955*0c0fea5dSIngo Weinhold 
956*0c0fea5dSIngo Weinhold 	image = create_image(name, path, numRegions);
957*0c0fea5dSIngo Weinhold 	if (image == NULL) {
958*0c0fea5dSIngo Weinhold 		FATAL("Failed to allocate image_t object\n");
959*0c0fea5dSIngo Weinhold 		status = B_NO_MEMORY;
960*0c0fea5dSIngo Weinhold 		goto err1;
961*0c0fea5dSIngo Weinhold 	}
962*0c0fea5dSIngo Weinhold 
963*0c0fea5dSIngo Weinhold 	status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
964*0c0fea5dSIngo Weinhold 	if (status < B_OK)
965*0c0fea5dSIngo Weinhold 		goto err2;
966*0c0fea5dSIngo Weinhold 
967*0c0fea5dSIngo Weinhold 	if (!assert_dynamic_loadable(image)) {
968*0c0fea5dSIngo Weinhold 		FATAL("Dynamic segment must be loadable (implementation restriction)\n");
969*0c0fea5dSIngo Weinhold 		status = B_UNSUPPORTED;
970*0c0fea5dSIngo Weinhold 		goto err2;
971*0c0fea5dSIngo Weinhold 	}
972*0c0fea5dSIngo Weinhold 
973*0c0fea5dSIngo Weinhold 	status = map_image(fd, path, image, type == B_APP_IMAGE);
974*0c0fea5dSIngo Weinhold 	if (status < B_OK) {
975*0c0fea5dSIngo Weinhold 		FATAL("Could not map image: %s\n", strerror(status));
976*0c0fea5dSIngo Weinhold 		status = B_ERROR;
977*0c0fea5dSIngo Weinhold 		goto err2;
978*0c0fea5dSIngo Weinhold 	}
979*0c0fea5dSIngo Weinhold 
980*0c0fea5dSIngo Weinhold 	if (!parse_dynamic_segment(image)) {
981*0c0fea5dSIngo Weinhold 		FATAL("Troubles handling dynamic section\n");
982*0c0fea5dSIngo Weinhold 		status = B_BAD_DATA;
983*0c0fea5dSIngo Weinhold 		goto err3;
984*0c0fea5dSIngo Weinhold 	}
985*0c0fea5dSIngo Weinhold 
986*0c0fea5dSIngo Weinhold 	if (eheader.e_entry != NULL)
987*0c0fea5dSIngo Weinhold 		image->entry_point = eheader.e_entry + image->regions[0].delta;
988*0c0fea5dSIngo Weinhold 
989*0c0fea5dSIngo Weinhold 	image->type = type;
990*0c0fea5dSIngo Weinhold 	register_image(image, fd, path);
991*0c0fea5dSIngo Weinhold 
992*0c0fea5dSIngo Weinhold 	_kern_close(fd);
993*0c0fea5dSIngo Weinhold 
994*0c0fea5dSIngo Weinhold 	enqueue_image(&sLoadedImages, image);
995*0c0fea5dSIngo Weinhold 	sLoadedImageCount++;
996*0c0fea5dSIngo Weinhold 
997*0c0fea5dSIngo Weinhold 	*_image = image;
998*0c0fea5dSIngo Weinhold 	return B_OK;
999*0c0fea5dSIngo Weinhold 
1000*0c0fea5dSIngo Weinhold err3:
1001*0c0fea5dSIngo Weinhold 	unmap_image(image);
1002*0c0fea5dSIngo Weinhold err2:
1003*0c0fea5dSIngo Weinhold 	delete_image_struct(image);
1004*0c0fea5dSIngo Weinhold err1:
1005*0c0fea5dSIngo Weinhold 	_kern_close(fd);
1006*0c0fea5dSIngo Weinhold 	return status;
1007*0c0fea5dSIngo Weinhold }
1008*0c0fea5dSIngo Weinhold 
1009*0c0fea5dSIngo Weinhold 
1010*0c0fea5dSIngo Weinhold static const char *
1011*0c0fea5dSIngo Weinhold find_dt_rpath(image_t *image)
1012*0c0fea5dSIngo Weinhold {
1013*0c0fea5dSIngo Weinhold 	int i;
1014*0c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
1015*0c0fea5dSIngo Weinhold 
1016*0c0fea5dSIngo Weinhold 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
1017*0c0fea5dSIngo Weinhold 		if (d[i].d_tag == DT_RPATH)
1018*0c0fea5dSIngo Weinhold 			return STRING(image, d[i].d_un.d_val);
1019*0c0fea5dSIngo Weinhold 	}
1020*0c0fea5dSIngo Weinhold 
1021*0c0fea5dSIngo Weinhold 	return NULL;
1022*0c0fea5dSIngo Weinhold }
1023*0c0fea5dSIngo Weinhold 
1024*0c0fea5dSIngo Weinhold 
1025*0c0fea5dSIngo Weinhold static status_t
1026*0c0fea5dSIngo Weinhold load_dependencies(image_t *image)
1027*0c0fea5dSIngo Weinhold {
1028*0c0fea5dSIngo Weinhold 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
1029*0c0fea5dSIngo Weinhold 	int neededOffset;
1030*0c0fea5dSIngo Weinhold 	status_t status;
1031*0c0fea5dSIngo Weinhold 	uint32 i, j;
1032*0c0fea5dSIngo Weinhold 	const char *rpath;
1033*0c0fea5dSIngo Weinhold 
1034*0c0fea5dSIngo Weinhold 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
1035*0c0fea5dSIngo Weinhold 		return B_OK;
1036*0c0fea5dSIngo Weinhold 
1037*0c0fea5dSIngo Weinhold 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
1038*0c0fea5dSIngo Weinhold 
1039*0c0fea5dSIngo Weinhold 	if (image->num_needed == 0)
1040*0c0fea5dSIngo Weinhold 		return B_OK;
1041*0c0fea5dSIngo Weinhold 
1042*0c0fea5dSIngo Weinhold 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
1043*0c0fea5dSIngo Weinhold 	if (image->needed == NULL) {
1044*0c0fea5dSIngo Weinhold 		FATAL("failed to allocate needed struct\n");
1045*0c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
1046*0c0fea5dSIngo Weinhold 	}
1047*0c0fea5dSIngo Weinhold 
1048*0c0fea5dSIngo Weinhold 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
1049*0c0fea5dSIngo Weinhold 	rpath = find_dt_rpath(image);
1050*0c0fea5dSIngo Weinhold 
1051*0c0fea5dSIngo Weinhold 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
1052*0c0fea5dSIngo Weinhold 		switch (d[i].d_tag) {
1053*0c0fea5dSIngo Weinhold 			case DT_NEEDED:
1054*0c0fea5dSIngo Weinhold 				neededOffset = d[i].d_un.d_val;
1055*0c0fea5dSIngo Weinhold 
1056*0c0fea5dSIngo Weinhold 				status = load_container(STRING(image, neededOffset),
1057*0c0fea5dSIngo Weinhold 					B_LIBRARY_IMAGE, rpath, &image->needed[j]);
1058*0c0fea5dSIngo Weinhold 				if (status < B_OK)
1059*0c0fea5dSIngo Weinhold 					return status;
1060*0c0fea5dSIngo Weinhold 
1061*0c0fea5dSIngo Weinhold 				j += 1;
1062*0c0fea5dSIngo Weinhold 				break;
1063*0c0fea5dSIngo Weinhold 
1064*0c0fea5dSIngo Weinhold 			default:
1065*0c0fea5dSIngo Weinhold 				// ignore any other tag
1066*0c0fea5dSIngo Weinhold 				continue;
1067*0c0fea5dSIngo Weinhold 		}
1068*0c0fea5dSIngo Weinhold 	}
1069*0c0fea5dSIngo Weinhold 
1070*0c0fea5dSIngo Weinhold 	if (j != image->num_needed) {
1071*0c0fea5dSIngo Weinhold 		FATAL("Internal error at load_dependencies()");
1072*0c0fea5dSIngo Weinhold 		return B_ERROR;
1073*0c0fea5dSIngo Weinhold 	}
1074*0c0fea5dSIngo Weinhold 
1075*0c0fea5dSIngo Weinhold 	return B_OK;
1076*0c0fea5dSIngo Weinhold }
1077*0c0fea5dSIngo Weinhold 
1078*0c0fea5dSIngo Weinhold 
1079*0c0fea5dSIngo Weinhold static uint32
1080*0c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList,
1081*0c0fea5dSIngo Weinhold 	uint32 sortFlag)
1082*0c0fea5dSIngo Weinhold {
1083*0c0fea5dSIngo Weinhold 	uint32 i;
1084*0c0fea5dSIngo Weinhold 
1085*0c0fea5dSIngo Weinhold 	if (image->flags & sortFlag)
1086*0c0fea5dSIngo Weinhold 		return slot;
1087*0c0fea5dSIngo Weinhold 
1088*0c0fea5dSIngo Weinhold 	image->flags |= sortFlag; /* make sure we don't visit this one */
1089*0c0fea5dSIngo Weinhold 	for (i = 0; i < image->num_needed; i++)
1090*0c0fea5dSIngo Weinhold 		slot = topological_sort(image->needed[i], slot, initList, sortFlag);
1091*0c0fea5dSIngo Weinhold 
1092*0c0fea5dSIngo Weinhold 	initList[slot] = image;
1093*0c0fea5dSIngo Weinhold 	return slot + 1;
1094*0c0fea5dSIngo Weinhold }
1095*0c0fea5dSIngo Weinhold 
1096*0c0fea5dSIngo Weinhold 
1097*0c0fea5dSIngo Weinhold static ssize_t
1098*0c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
1099*0c0fea5dSIngo Weinhold {
1100*0c0fea5dSIngo Weinhold 	image_t **list;
1101*0c0fea5dSIngo Weinhold 
1102*0c0fea5dSIngo Weinhold 	list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *));
1103*0c0fea5dSIngo Weinhold 	if (list == NULL) {
1104*0c0fea5dSIngo Weinhold 		FATAL("memory shortage in get_sorted_image_list()");
1105*0c0fea5dSIngo Weinhold 		*_list = NULL;
1106*0c0fea5dSIngo Weinhold 		return B_NO_MEMORY;
1107*0c0fea5dSIngo Weinhold 	}
1108*0c0fea5dSIngo Weinhold 
1109*0c0fea5dSIngo Weinhold 	memset(list, 0, sLoadedImageCount * sizeof(image_t *));
1110*0c0fea5dSIngo Weinhold 
1111*0c0fea5dSIngo Weinhold 	*_list = list;
1112*0c0fea5dSIngo Weinhold 	return topological_sort(image, 0, list, sortFlag);
1113*0c0fea5dSIngo Weinhold }
1114*0c0fea5dSIngo Weinhold 
1115*0c0fea5dSIngo Weinhold 
1116*0c0fea5dSIngo Weinhold static status_t
1117*0c0fea5dSIngo Weinhold relocate_dependencies(image_t *image)
1118*0c0fea5dSIngo Weinhold {
1119*0c0fea5dSIngo Weinhold 	ssize_t count, i;
1120*0c0fea5dSIngo Weinhold 	image_t **list;
1121*0c0fea5dSIngo Weinhold 
1122*0c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
1123*0c0fea5dSIngo Weinhold 	if (count < B_OK)
1124*0c0fea5dSIngo Weinhold 		return count;
1125*0c0fea5dSIngo Weinhold 
1126*0c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
1127*0c0fea5dSIngo Weinhold 		status_t status = relocate_image(list[i]);
1128*0c0fea5dSIngo Weinhold 		if (status < B_OK)
1129*0c0fea5dSIngo Weinhold 			return status;
1130*0c0fea5dSIngo Weinhold 	}
1131*0c0fea5dSIngo Weinhold 
1132*0c0fea5dSIngo Weinhold 	free(list);
1133*0c0fea5dSIngo Weinhold 	return B_OK;
1134*0c0fea5dSIngo Weinhold }
1135*0c0fea5dSIngo Weinhold 
1136*0c0fea5dSIngo Weinhold 
1137*0c0fea5dSIngo Weinhold static void
1138*0c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead)
1139*0c0fea5dSIngo Weinhold {
1140*0c0fea5dSIngo Weinhold 	image_t **initList;
1141*0c0fea5dSIngo Weinhold 	ssize_t count, i;
1142*0c0fea5dSIngo Weinhold 
1143*0c0fea5dSIngo Weinhold 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
1144*0c0fea5dSIngo Weinhold 	if (count <= 0)
1145*0c0fea5dSIngo Weinhold 		return;
1146*0c0fea5dSIngo Weinhold 
1147*0c0fea5dSIngo Weinhold 	if (!initHead) {
1148*0c0fea5dSIngo Weinhold 		// this removes the "calling" image
1149*0c0fea5dSIngo Weinhold 		image->flags &= ~RFLAG_INITIALIZED;
1150*0c0fea5dSIngo Weinhold 		initList[--count] = NULL;
1151*0c0fea5dSIngo Weinhold 	}
1152*0c0fea5dSIngo Weinhold 
1153*0c0fea5dSIngo Weinhold 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
1154*0c0fea5dSIngo Weinhold 	for (i = 0; i < count; i++) {
1155*0c0fea5dSIngo Weinhold 		image = initList[i];
1156*0c0fea5dSIngo Weinhold 
1157*0c0fea5dSIngo Weinhold 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
1158*0c0fea5dSIngo Weinhold 
1159*0c0fea5dSIngo Weinhold 		if (image->init_routine != NULL)
1160*0c0fea5dSIngo Weinhold 			((init_term_function)image->init_routine)(image->id);
1161*0c0fea5dSIngo Weinhold 	}
1162*0c0fea5dSIngo Weinhold 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
1163*0c0fea5dSIngo Weinhold 
1164*0c0fea5dSIngo Weinhold 	free(initList);
1165*0c0fea5dSIngo Weinhold }
1166*0c0fea5dSIngo Weinhold 
1167*0c0fea5dSIngo Weinhold 
1168*0c0fea5dSIngo Weinhold static void
1169*0c0fea5dSIngo Weinhold put_image(image_t *image)
1170*0c0fea5dSIngo Weinhold {
1171*0c0fea5dSIngo Weinhold 	// If all references to the image are gone, add it to the disposable list
1172*0c0fea5dSIngo Weinhold 	// and remove all dependencies
1173*0c0fea5dSIngo Weinhold 
1174*0c0fea5dSIngo Weinhold 	if (atomic_add(&image->ref_count, -1) == 1) {
1175*0c0fea5dSIngo Weinhold 		size_t i;
1176*0c0fea5dSIngo Weinhold 
1177*0c0fea5dSIngo Weinhold 		dequeue_image(&sLoadedImages, image);
1178*0c0fea5dSIngo Weinhold 		enqueue_image(&sDisposableImages, image);
1179*0c0fea5dSIngo Weinhold 		sLoadedImageCount--;
1180*0c0fea5dSIngo Weinhold 
1181*0c0fea5dSIngo Weinhold 		for (i = 0; i < image->num_needed; i++) {
1182*0c0fea5dSIngo Weinhold 			put_image(image->needed[i]);
1183*0c0fea5dSIngo Weinhold 		}
1184*0c0fea5dSIngo Weinhold 	}
1185*0c0fea5dSIngo Weinhold }
1186*0c0fea5dSIngo Weinhold 
1187*0c0fea5dSIngo Weinhold 
1188*0c0fea5dSIngo Weinhold //	#pragma mark -
1189*0c0fea5dSIngo Weinhold //	Exported functions (to libroot.so)
1190*0c0fea5dSIngo Weinhold 
1191*0c0fea5dSIngo Weinhold 
1192*0c0fea5dSIngo Weinhold image_id
1193*0c0fea5dSIngo Weinhold load_program(char const *path, void **_entry)
1194*0c0fea5dSIngo Weinhold {
1195*0c0fea5dSIngo Weinhold 	status_t status;
1196*0c0fea5dSIngo Weinhold 	image_t *image;
1197*0c0fea5dSIngo Weinhold 
1198*0c0fea5dSIngo Weinhold 	rld_lock();
1199*0c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
1200*0c0fea5dSIngo Weinhold 
1201*0c0fea5dSIngo Weinhold 	TRACE(("rld: load %s\n", path));
1202*0c0fea5dSIngo Weinhold 
1203*0c0fea5dSIngo Weinhold 	status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage);
1204*0c0fea5dSIngo Weinhold 	if (status < B_OK) {
1205*0c0fea5dSIngo Weinhold 		_kern_loading_app_failed(status);
1206*0c0fea5dSIngo Weinhold 		rld_unlock();
1207*0c0fea5dSIngo Weinhold 		return status;
1208*0c0fea5dSIngo Weinhold 	}
1209*0c0fea5dSIngo Weinhold 
1210*0c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image != NULL; image = image->next) {
1211*0c0fea5dSIngo Weinhold 		status = load_dependencies(image);
1212*0c0fea5dSIngo Weinhold 		if (status < B_OK)
1213*0c0fea5dSIngo Weinhold 			goto err;
1214*0c0fea5dSIngo Weinhold 	}
1215*0c0fea5dSIngo Weinhold 
1216*0c0fea5dSIngo Weinhold 	status = relocate_dependencies(sProgramImage);
1217*0c0fea5dSIngo Weinhold 	if (status < B_OK)
1218*0c0fea5dSIngo Weinhold 		goto err;
1219*0c0fea5dSIngo Weinhold 
1220*0c0fea5dSIngo Weinhold 	// We patch any exported __gRuntimeLoader symbols to point to our private API
1221*0c0fea5dSIngo Weinhold 	{
1222*0c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_loaded_images(&image, "__gRuntimeLoader");
1223*0c0fea5dSIngo Weinhold 		if (symbol != NULL) {
1224*0c0fea5dSIngo Weinhold 			void **_export = (void **)(symbol->st_value + image->regions[0].delta);
1225*0c0fea5dSIngo Weinhold 			*_export = &gRuntimeLoader;
1226*0c0fea5dSIngo Weinhold 		}
1227*0c0fea5dSIngo Weinhold 	}
1228*0c0fea5dSIngo Weinhold 
1229*0c0fea5dSIngo Weinhold 	init_dependencies(sLoadedImages.head, true);
1230*0c0fea5dSIngo Weinhold 	remap_images();
1231*0c0fea5dSIngo Weinhold 		// ToDo: once setup_system_time() is fixed, move this one line higher!
1232*0c0fea5dSIngo Weinhold 
1233*0c0fea5dSIngo Weinhold 	// Since the images are initialized now, we no longer should use our
1234*0c0fea5dSIngo Weinhold 	// getenv(), but use the one from libroot.so
1235*0c0fea5dSIngo Weinhold 	{
1236*0c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol = find_symbol_in_loaded_images(&image, "getenv");
1237*0c0fea5dSIngo Weinhold 		if (symbol != NULL)
1238*0c0fea5dSIngo Weinhold 			gGetEnv = (char* (*)(const char*))
1239*0c0fea5dSIngo Weinhold 				(symbol->st_value + image->regions[0].delta);
1240*0c0fea5dSIngo Weinhold 	}
1241*0c0fea5dSIngo Weinhold 
1242*0c0fea5dSIngo Weinhold 	if (sProgramImage->entry_point == NULL) {
1243*0c0fea5dSIngo Weinhold 		status = B_NOT_AN_EXECUTABLE;
1244*0c0fea5dSIngo Weinhold 		goto err;
1245*0c0fea5dSIngo Weinhold 	}
1246*0c0fea5dSIngo Weinhold 
1247*0c0fea5dSIngo Weinhold 	*_entry = (void *)(sProgramImage->entry_point);
1248*0c0fea5dSIngo Weinhold 
1249*0c0fea5dSIngo Weinhold 	rld_unlock();
1250*0c0fea5dSIngo Weinhold 	return sProgramImage->id;
1251*0c0fea5dSIngo Weinhold 
1252*0c0fea5dSIngo Weinhold err:
1253*0c0fea5dSIngo Weinhold 	_kern_loading_app_failed(status);
1254*0c0fea5dSIngo Weinhold 	delete_image(sProgramImage);
1255*0c0fea5dSIngo Weinhold 	rld_unlock();
1256*0c0fea5dSIngo Weinhold 	return status;
1257*0c0fea5dSIngo Weinhold }
1258*0c0fea5dSIngo Weinhold 
1259*0c0fea5dSIngo Weinhold 
1260*0c0fea5dSIngo Weinhold image_id
1261*0c0fea5dSIngo Weinhold load_library(char const *path, uint32 flags, bool addOn)
1262*0c0fea5dSIngo Weinhold {
1263*0c0fea5dSIngo Weinhold 	image_t *image = NULL;
1264*0c0fea5dSIngo Weinhold 	image_t *iter;
1265*0c0fea5dSIngo Weinhold 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
1266*0c0fea5dSIngo Weinhold 	status_t status;
1267*0c0fea5dSIngo Weinhold 
1268*0c0fea5dSIngo Weinhold 	if (path == NULL)
1269*0c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
1270*0c0fea5dSIngo Weinhold 
1271*0c0fea5dSIngo Weinhold 	// ToDo: implement flags
1272*0c0fea5dSIngo Weinhold 	(void)flags;
1273*0c0fea5dSIngo Weinhold 
1274*0c0fea5dSIngo Weinhold 	rld_lock();
1275*0c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
1276*0c0fea5dSIngo Weinhold 
1277*0c0fea5dSIngo Weinhold 	// have we already loaded this library?
1278*0c0fea5dSIngo Weinhold 	// Checking it at this stage saves loading its dependencies again
1279*0c0fea5dSIngo Weinhold 	if (!addOn) {
1280*0c0fea5dSIngo Weinhold 		image = find_image(path, APP_OR_LIBRARY_TYPE);
1281*0c0fea5dSIngo Weinhold 		if (image) {
1282*0c0fea5dSIngo Weinhold 			atomic_add(&image->ref_count, 1);
1283*0c0fea5dSIngo Weinhold 			rld_unlock();
1284*0c0fea5dSIngo Weinhold 			return image->id;
1285*0c0fea5dSIngo Weinhold 		}
1286*0c0fea5dSIngo Weinhold 	}
1287*0c0fea5dSIngo Weinhold 
1288*0c0fea5dSIngo Weinhold 	status = load_container(path, type, NULL, &image);
1289*0c0fea5dSIngo Weinhold 	if (status < B_OK) {
1290*0c0fea5dSIngo Weinhold 		rld_unlock();
1291*0c0fea5dSIngo Weinhold 		return status;
1292*0c0fea5dSIngo Weinhold 	}
1293*0c0fea5dSIngo Weinhold 
1294*0c0fea5dSIngo Weinhold 	for (iter = sLoadedImages.head; iter; iter = iter->next) {
1295*0c0fea5dSIngo Weinhold 		status = load_dependencies(iter);
1296*0c0fea5dSIngo Weinhold 		if (status < B_OK)
1297*0c0fea5dSIngo Weinhold 			goto err;
1298*0c0fea5dSIngo Weinhold 	}
1299*0c0fea5dSIngo Weinhold 
1300*0c0fea5dSIngo Weinhold 	status = relocate_dependencies(image);
1301*0c0fea5dSIngo Weinhold 	if (status < B_OK)
1302*0c0fea5dSIngo Weinhold 		goto err;
1303*0c0fea5dSIngo Weinhold 
1304*0c0fea5dSIngo Weinhold 	remap_images();
1305*0c0fea5dSIngo Weinhold 	init_dependencies(image, true);
1306*0c0fea5dSIngo Weinhold 
1307*0c0fea5dSIngo Weinhold 	rld_unlock();
1308*0c0fea5dSIngo Weinhold 	return image->id;
1309*0c0fea5dSIngo Weinhold 
1310*0c0fea5dSIngo Weinhold err:
1311*0c0fea5dSIngo Weinhold 	dequeue_image(&sLoadedImages, image);
1312*0c0fea5dSIngo Weinhold 	sLoadedImageCount--;
1313*0c0fea5dSIngo Weinhold 	delete_image(image);
1314*0c0fea5dSIngo Weinhold 	rld_unlock();
1315*0c0fea5dSIngo Weinhold 	return status;
1316*0c0fea5dSIngo Weinhold }
1317*0c0fea5dSIngo Weinhold 
1318*0c0fea5dSIngo Weinhold 
1319*0c0fea5dSIngo Weinhold status_t
1320*0c0fea5dSIngo Weinhold unload_library(image_id imageID, bool addOn)
1321*0c0fea5dSIngo Weinhold {
1322*0c0fea5dSIngo Weinhold 	status_t status = B_BAD_IMAGE_ID;
1323*0c0fea5dSIngo Weinhold 	image_t *image;
1324*0c0fea5dSIngo Weinhold 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
1325*0c0fea5dSIngo Weinhold 
1326*0c0fea5dSIngo Weinhold 	if (imageID < B_OK)
1327*0c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
1328*0c0fea5dSIngo Weinhold 
1329*0c0fea5dSIngo Weinhold 	rld_lock();
1330*0c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
1331*0c0fea5dSIngo Weinhold 
1332*0c0fea5dSIngo Weinhold 	// we only check images that have been already initialized
1333*0c0fea5dSIngo Weinhold 
1334*0c0fea5dSIngo Weinhold 	for (image = sLoadedImages.head; image; image = image->next) {
1335*0c0fea5dSIngo Weinhold 		if (image->id == imageID) {
1336*0c0fea5dSIngo Weinhold 			// unload image
1337*0c0fea5dSIngo Weinhold 			if (type == image->type) {
1338*0c0fea5dSIngo Weinhold 				put_image(image);
1339*0c0fea5dSIngo Weinhold 				status = B_OK;
1340*0c0fea5dSIngo Weinhold 			} else
1341*0c0fea5dSIngo Weinhold 				status = B_BAD_VALUE;
1342*0c0fea5dSIngo Weinhold 			break;
1343*0c0fea5dSIngo Weinhold 		}
1344*0c0fea5dSIngo Weinhold 	}
1345*0c0fea5dSIngo Weinhold 
1346*0c0fea5dSIngo Weinhold 	if (status == B_OK) {
1347*0c0fea5dSIngo Weinhold 		while ((image = sDisposableImages.head) != NULL) {
1348*0c0fea5dSIngo Weinhold 			// call image fini here...
1349*0c0fea5dSIngo Weinhold 			if (image->term_routine)
1350*0c0fea5dSIngo Weinhold 				((init_term_function)image->term_routine)(image->id);
1351*0c0fea5dSIngo Weinhold 
1352*0c0fea5dSIngo Weinhold 			dequeue_image(&sDisposableImages, image);
1353*0c0fea5dSIngo Weinhold 			unmap_image(image);
1354*0c0fea5dSIngo Weinhold 
1355*0c0fea5dSIngo Weinhold 			delete_image(image);
1356*0c0fea5dSIngo Weinhold 		}
1357*0c0fea5dSIngo Weinhold 	}
1358*0c0fea5dSIngo Weinhold 
1359*0c0fea5dSIngo Weinhold 	rld_unlock();
1360*0c0fea5dSIngo Weinhold 	return status;
1361*0c0fea5dSIngo Weinhold }
1362*0c0fea5dSIngo Weinhold 
1363*0c0fea5dSIngo Weinhold 
1364*0c0fea5dSIngo Weinhold status_t
1365*0c0fea5dSIngo Weinhold get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, int32 *_nameLength,
1366*0c0fea5dSIngo Weinhold 	int32 *_type, void **_location)
1367*0c0fea5dSIngo Weinhold {
1368*0c0fea5dSIngo Weinhold 	int32 count = 0, j;
1369*0c0fea5dSIngo Weinhold 	uint32 i;
1370*0c0fea5dSIngo Weinhold 	image_t *image;
1371*0c0fea5dSIngo Weinhold 
1372*0c0fea5dSIngo Weinhold 	rld_lock();
1373*0c0fea5dSIngo Weinhold 
1374*0c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
1375*0c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
1376*0c0fea5dSIngo Weinhold 	if (image == NULL) {
1377*0c0fea5dSIngo Weinhold 		rld_unlock();
1378*0c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
1379*0c0fea5dSIngo Weinhold 	}
1380*0c0fea5dSIngo Weinhold 
1381*0c0fea5dSIngo Weinhold 	// iterate through all the hash buckets until we've found the one
1382*0c0fea5dSIngo Weinhold 	for (i = 0; i < HASHTABSIZE(image); i++) {
1383*0c0fea5dSIngo Weinhold 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
1384*0c0fea5dSIngo Weinhold 			struct Elf32_Sym *symbol = &image->syms[i];
1385*0c0fea5dSIngo Weinhold 
1386*0c0fea5dSIngo Weinhold 			if (count == num) {
1387*0c0fea5dSIngo Weinhold 				strlcpy(nameBuffer, SYMNAME(image, symbol), *_nameLength);
1388*0c0fea5dSIngo Weinhold 				*_nameLength = strlen(SYMNAME(image, symbol));
1389*0c0fea5dSIngo Weinhold 
1390*0c0fea5dSIngo Weinhold 				if (_type != NULL) {
1391*0c0fea5dSIngo Weinhold 					// ToDo: check with the return types of that BeOS function
1392*0c0fea5dSIngo Weinhold 					if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
1393*0c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_TEXT;
1394*0c0fea5dSIngo Weinhold 					else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
1395*0c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_DATA;
1396*0c0fea5dSIngo Weinhold 					else
1397*0c0fea5dSIngo Weinhold 						*_type = B_SYMBOL_TYPE_ANY;
1398*0c0fea5dSIngo Weinhold 				}
1399*0c0fea5dSIngo Weinhold 
1400*0c0fea5dSIngo Weinhold 				if (_location != NULL)
1401*0c0fea5dSIngo Weinhold 					*_location = (void *)(symbol->st_value + image->regions[0].delta);
1402*0c0fea5dSIngo Weinhold 				goto out;
1403*0c0fea5dSIngo Weinhold 			}
1404*0c0fea5dSIngo Weinhold 			count++;
1405*0c0fea5dSIngo Weinhold 		}
1406*0c0fea5dSIngo Weinhold 	}
1407*0c0fea5dSIngo Weinhold out:
1408*0c0fea5dSIngo Weinhold 	rld_unlock();
1409*0c0fea5dSIngo Weinhold 
1410*0c0fea5dSIngo Weinhold 	if (num != count)
1411*0c0fea5dSIngo Weinhold 		return B_BAD_INDEX;
1412*0c0fea5dSIngo Weinhold 
1413*0c0fea5dSIngo Weinhold 	return B_OK;
1414*0c0fea5dSIngo Weinhold }
1415*0c0fea5dSIngo Weinhold 
1416*0c0fea5dSIngo Weinhold 
1417*0c0fea5dSIngo Weinhold status_t
1418*0c0fea5dSIngo Weinhold get_symbol(image_id imageID, char const *symbolName, int32 symbolType, void **_location)
1419*0c0fea5dSIngo Weinhold {
1420*0c0fea5dSIngo Weinhold 	status_t status = B_OK;
1421*0c0fea5dSIngo Weinhold 	image_t *image;
1422*0c0fea5dSIngo Weinhold 
1423*0c0fea5dSIngo Weinhold 	if (imageID < B_OK)
1424*0c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
1425*0c0fea5dSIngo Weinhold 	if (symbolName == NULL)
1426*0c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
1427*0c0fea5dSIngo Weinhold 
1428*0c0fea5dSIngo Weinhold 	rld_lock();
1429*0c0fea5dSIngo Weinhold 		// for now, just do stupid simple global locking
1430*0c0fea5dSIngo Weinhold 
1431*0c0fea5dSIngo Weinhold 	// get the image from those who have been already initialized
1432*0c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(imageID);
1433*0c0fea5dSIngo Weinhold 	if (image != NULL) {
1434*0c0fea5dSIngo Weinhold 		struct Elf32_Sym *symbol;
1435*0c0fea5dSIngo Weinhold 
1436*0c0fea5dSIngo Weinhold 		// get the symbol in the image
1437*0c0fea5dSIngo Weinhold 		symbol = find_symbol(image, symbolName, symbolType);
1438*0c0fea5dSIngo Weinhold 		if (symbol) {
1439*0c0fea5dSIngo Weinhold 			if (_location != NULL)
1440*0c0fea5dSIngo Weinhold 				*_location = (void *)(symbol->st_value + image->regions[0].delta);
1441*0c0fea5dSIngo Weinhold 		} else
1442*0c0fea5dSIngo Weinhold 			status = B_ENTRY_NOT_FOUND;
1443*0c0fea5dSIngo Weinhold 	} else
1444*0c0fea5dSIngo Weinhold 		status = B_BAD_IMAGE_ID;
1445*0c0fea5dSIngo Weinhold 
1446*0c0fea5dSIngo Weinhold 	rld_unlock();
1447*0c0fea5dSIngo Weinhold 	return status;
1448*0c0fea5dSIngo Weinhold }
1449*0c0fea5dSIngo Weinhold 
1450*0c0fea5dSIngo Weinhold 
1451*0c0fea5dSIngo Weinhold status_t
1452*0c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
1453*0c0fea5dSIngo Weinhold {
1454*0c0fea5dSIngo Weinhold 	uint32 i, j, searchIndex = *cookie;
1455*0c0fea5dSIngo Weinhold 	struct Elf32_Dyn *dynamicSection;
1456*0c0fea5dSIngo Weinhold 	image_t *image;
1457*0c0fea5dSIngo Weinhold 
1458*0c0fea5dSIngo Weinhold 	if (_name == NULL)
1459*0c0fea5dSIngo Weinhold 		return B_BAD_VALUE;
1460*0c0fea5dSIngo Weinhold 
1461*0c0fea5dSIngo Weinhold 	rld_lock();
1462*0c0fea5dSIngo Weinhold 
1463*0c0fea5dSIngo Weinhold 	image = find_loaded_image_by_id(id);
1464*0c0fea5dSIngo Weinhold 	if (image == NULL) {
1465*0c0fea5dSIngo Weinhold 		rld_unlock();
1466*0c0fea5dSIngo Weinhold 		return B_BAD_IMAGE_ID;
1467*0c0fea5dSIngo Weinhold 	}
1468*0c0fea5dSIngo Weinhold 
1469*0c0fea5dSIngo Weinhold 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
1470*0c0fea5dSIngo Weinhold 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
1471*0c0fea5dSIngo Weinhold 		rld_unlock();
1472*0c0fea5dSIngo Weinhold 		return B_ENTRY_NOT_FOUND;
1473*0c0fea5dSIngo Weinhold 	}
1474*0c0fea5dSIngo Weinhold 
1475*0c0fea5dSIngo Weinhold 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
1476*0c0fea5dSIngo Weinhold 		if (dynamicSection[i].d_tag != DT_NEEDED)
1477*0c0fea5dSIngo Weinhold 			continue;
1478*0c0fea5dSIngo Weinhold 
1479*0c0fea5dSIngo Weinhold 		if (j++ == searchIndex) {
1480*0c0fea5dSIngo Weinhold 			int32 neededOffset = dynamicSection[i].d_un.d_val;
1481*0c0fea5dSIngo Weinhold 
1482*0c0fea5dSIngo Weinhold 			*_name = STRING(image, neededOffset);
1483*0c0fea5dSIngo Weinhold 			*cookie = searchIndex + 1;
1484*0c0fea5dSIngo Weinhold 			rld_unlock();
1485*0c0fea5dSIngo Weinhold 			return B_OK;
1486*0c0fea5dSIngo Weinhold 		}
1487*0c0fea5dSIngo Weinhold 	}
1488*0c0fea5dSIngo Weinhold 
1489*0c0fea5dSIngo Weinhold 	rld_unlock();
1490*0c0fea5dSIngo Weinhold 	return B_ENTRY_NOT_FOUND;
1491*0c0fea5dSIngo Weinhold }
1492*0c0fea5dSIngo Weinhold 
1493*0c0fea5dSIngo Weinhold 
1494*0c0fea5dSIngo Weinhold //	#pragma mark -
1495*0c0fea5dSIngo Weinhold 
1496*0c0fea5dSIngo Weinhold 
1497*0c0fea5dSIngo Weinhold /** Read and verify the ELF header */
1498*0c0fea5dSIngo Weinhold 
1499*0c0fea5dSIngo Weinhold status_t
1500*0c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length)
1501*0c0fea5dSIngo Weinhold {
1502*0c0fea5dSIngo Weinhold 	int32 programSize, sectionSize;
1503*0c0fea5dSIngo Weinhold 
1504*0c0fea5dSIngo Weinhold 	if (length < (int32)sizeof(struct Elf32_Ehdr))
1505*0c0fea5dSIngo Weinhold 		return B_NOT_AN_EXECUTABLE;
1506*0c0fea5dSIngo Weinhold 
1507*0c0fea5dSIngo Weinhold 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, &sectionSize);
1508*0c0fea5dSIngo Weinhold }
1509*0c0fea5dSIngo Weinhold 
1510*0c0fea5dSIngo Weinhold 
1511*0c0fea5dSIngo Weinhold void
1512*0c0fea5dSIngo Weinhold terminate_program(void)
1513*0c0fea5dSIngo Weinhold {
1514*0c0fea5dSIngo Weinhold 	image_t **termList;
1515*0c0fea5dSIngo Weinhold 	ssize_t count, i;
1516*0c0fea5dSIngo Weinhold 
1517*0c0fea5dSIngo Weinhold 	count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED);
1518*0c0fea5dSIngo Weinhold 	if (count < B_OK)
1519*0c0fea5dSIngo Weinhold 		return;
1520*0c0fea5dSIngo Weinhold 
1521*0c0fea5dSIngo Weinhold 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
1522*0c0fea5dSIngo Weinhold 	for (i = count; i-- > 0;) {
1523*0c0fea5dSIngo Weinhold 		image_t *image = termList[i];
1524*0c0fea5dSIngo Weinhold 
1525*0c0fea5dSIngo Weinhold 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
1526*0c0fea5dSIngo Weinhold 
1527*0c0fea5dSIngo Weinhold 		if (image->term_routine)
1528*0c0fea5dSIngo Weinhold 			((init_term_function)image->term_routine)(image->id);
1529*0c0fea5dSIngo Weinhold 	}
1530*0c0fea5dSIngo Weinhold 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
1531*0c0fea5dSIngo Weinhold 
1532*0c0fea5dSIngo Weinhold 	free(termList);
1533*0c0fea5dSIngo Weinhold }
1534*0c0fea5dSIngo Weinhold 
1535*0c0fea5dSIngo Weinhold 
1536*0c0fea5dSIngo Weinhold void
1537*0c0fea5dSIngo Weinhold rldelf_init(void)
1538*0c0fea5dSIngo Weinhold {
1539*0c0fea5dSIngo Weinhold 	rld_sem = create_sem(1, "rld_lock");
1540*0c0fea5dSIngo Weinhold 	rld_sem_owner = -1;
1541*0c0fea5dSIngo Weinhold 	rld_sem_count = 0;
1542*0c0fea5dSIngo Weinhold 
1543*0c0fea5dSIngo Weinhold 	// create the debug area
1544*0c0fea5dSIngo Weinhold 	{
1545*0c0fea5dSIngo Weinhold 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
1546*0c0fea5dSIngo Weinhold 
1547*0c0fea5dSIngo Weinhold 		runtime_loader_debug_area *area;
1548*0c0fea5dSIngo Weinhold 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
1549*0c0fea5dSIngo Weinhold 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
1550*0c0fea5dSIngo Weinhold 			B_READ_AREA | B_WRITE_AREA);
1551*0c0fea5dSIngo Weinhold 		if (areaID < B_OK) {
1552*0c0fea5dSIngo Weinhold 			FATAL("Failed to create debug area.\n");
1553*0c0fea5dSIngo Weinhold 			_kern_loading_app_failed(areaID);
1554*0c0fea5dSIngo Weinhold 		}
1555*0c0fea5dSIngo Weinhold 
1556*0c0fea5dSIngo Weinhold 		area->loaded_images = &sLoadedImages;
1557*0c0fea5dSIngo Weinhold 	}
1558*0c0fea5dSIngo Weinhold }
1559