xref: /haiku/src/system/runtime_loader/elf.cpp (revision 23d878482ed22e55dad6d1fca1df7bea42eb157c)
1 /*
2  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2003-2011, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  *
6  * Copyright 2002, Manuel J. Petit. All rights reserved.
7  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
8  * Distributed under the terms of the NewOS License.
9  */
10 
11 #include "runtime_loader_private.h"
12 
13 #include <ctype.h>
14 #include <dlfcn.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include <OS.h>
20 
21 #include <elf32.h>
22 #include <syscalls.h>
23 #include <util/kernel_cpp.h>
24 
25 #include <locks.h>
26 
27 #include "add_ons.h"
28 #include "elf_load_image.h"
29 #include "elf_symbol_lookup.h"
30 #include "elf_versioning.h"
31 #include "errors.h"
32 #include "images.h"
33 
34 
35 // TODO: implement better locking strategy
36 // TODO: implement lazy binding
37 
38 // a handle returned by load_library() (dlopen())
39 #define RLD_GLOBAL_SCOPE	((void*)-2l)
40 
41 static const char* const kLockName = "runtime loader";
42 
43 
44 typedef void (*init_term_function)(image_id);
45 
46 bool gProgramLoaded = false;
47 image_t* gProgramImage;
48 
49 static image_t** sPreloadedImages = NULL;
50 static uint32 sPreloadedImageCount = 0;
51 
52 static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName);
53 
54 
55 static inline void
56 rld_lock()
57 {
58 	recursive_lock_lock(&sLock);
59 }
60 
61 
62 static inline void
63 rld_unlock()
64 {
65 	recursive_lock_unlock(&sLock);
66 }
67 
68 
69 static const char *
70 find_dt_rpath(image_t *image)
71 {
72 	int i;
73 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
74 
75 	for (i = 0; d[i].d_tag != DT_NULL; i++) {
76 		if (d[i].d_tag == DT_RPATH)
77 			return STRING(image, d[i].d_un.d_val);
78 	}
79 
80 	return NULL;
81 }
82 
83 
84 static status_t
85 load_immediate_dependencies(image_t *image)
86 {
87 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
88 	bool reportErrors = report_errors();
89 	status_t status = B_OK;
90 	uint32 i, j;
91 	const char *rpath;
92 
93 	if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
94 		return B_OK;
95 
96 	image->flags |= RFLAG_DEPENDENCIES_LOADED;
97 
98 	if (image->num_needed == 0)
99 		return B_OK;
100 
101 	KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name,
102 		image->id);
103 
104 	image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *));
105 	if (image->needed == NULL) {
106 		FATAL("%s: Failed to allocate needed struct\n", image->path);
107 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory",
108 			image->name, image->id);
109 		return B_NO_MEMORY;
110 	}
111 
112 	memset(image->needed, 0, image->num_needed * sizeof(image_t *));
113 	rpath = find_dt_rpath(image);
114 
115 	for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) {
116 		switch (d[i].d_tag) {
117 			case DT_NEEDED:
118 			{
119 				int32 neededOffset = d[i].d_un.d_val;
120 				const char *name = STRING(image, neededOffset);
121 
122 				status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
123 					rpath, &image->needed[j]);
124 				if (loadStatus < B_OK) {
125 					status = loadStatus;
126 					// correct error code in case the file could not been found
127 					if (status == B_ENTRY_NOT_FOUND) {
128 						status = B_MISSING_LIBRARY;
129 
130 						if (reportErrors)
131 							gErrorMessage.AddString("missing library", name);
132 					}
133 
134 					// Collect all missing libraries in case we report back
135 					if (!reportErrors) {
136 						KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
137 							"failed: %s", image->name, image->id,
138 							strerror(status));
139 						return status;
140 					}
141 				}
142 
143 				j += 1;
144 				break;
145 			}
146 
147 			default:
148 				// ignore any other tag
149 				continue;
150 		}
151 	}
152 
153 	if (status < B_OK) {
154 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
155 			"failed: %s", image->name, image->id,
156 			strerror(status));
157 		return status;
158 	}
159 
160 	if (j != image->num_needed) {
161 		FATAL("Internal error at load_dependencies()");
162 		KTRACE("rld: load_dependencies(\"%s\", id: %ld) "
163 			"failed: internal error", image->name, image->id);
164 		return B_ERROR;
165 	}
166 
167 	KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name,
168 		image->id);
169 
170 	return B_OK;
171 }
172 
173 
174 static status_t
175 load_dependencies(image_t* image)
176 {
177 	// load dependencies (breadth-first)
178 	for (image_t* otherImage = image; otherImage != NULL;
179 			otherImage = otherImage->next) {
180 		status_t status = load_immediate_dependencies(otherImage);
181 		if (status != B_OK)
182 			return status;
183 	}
184 
185 	// Check the needed versions for the given image and all newly loaded
186 	// dependencies.
187 	for (image_t* otherImage = image; otherImage != NULL;
188 			otherImage = otherImage->next) {
189 		status_t status = check_needed_image_versions(otherImage);
190 		if (status != B_OK)
191 			return status;
192 	}
193 
194 	return B_OK;
195 }
196 
197 
198 static status_t
199 relocate_image(image_t *rootImage, image_t *image)
200 {
201 	SymbolLookupCache cache(image);
202 
203 	status_t status = arch_relocate_image(rootImage, image, &cache);
204 	if (status < B_OK) {
205 		FATAL("%s: Troubles relocating: %s\n", image->path, strerror(status));
206 		return status;
207 	}
208 
209 	_kern_image_relocated(image->id);
210 	image_event(image, IMAGE_EVENT_RELOCATED);
211 	return B_OK;
212 }
213 
214 
215 static status_t
216 relocate_dependencies(image_t *image)
217 {
218 	// get the images that still have to be relocated
219 	image_t **list;
220 	ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
221 	if (count < B_OK)
222 		return count;
223 
224 	// relocate
225 	for (ssize_t i = 0; i < count; i++) {
226 		status_t status = relocate_image(image, list[i]);
227 		if (status < B_OK) {
228 			free(list);
229 			return status;
230 		}
231 	}
232 
233 	free(list);
234 	return B_OK;
235 }
236 
237 
238 static void
239 init_dependencies(image_t *image, bool initHead)
240 {
241 	image_t **initList;
242 	ssize_t count, i;
243 
244 	count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED);
245 	if (count <= 0)
246 		return;
247 
248 	if (!initHead) {
249 		// this removes the "calling" image
250 		image->flags &= ~RFLAG_INITIALIZED;
251 		initList[--count] = NULL;
252 	}
253 
254 	TRACE(("%ld: init dependencies\n", find_thread(NULL)));
255 	for (i = 0; i < count; i++) {
256 		image = initList[i];
257 
258 		TRACE(("%ld:  init: %s\n", find_thread(NULL), image->name));
259 
260 		if (image->init_routine != 0)
261 			((init_term_function)image->init_routine)(image->id);
262 
263 		image_event(image, IMAGE_EVENT_INITIALIZED);
264 	}
265 	TRACE(("%ld:  init done.\n", find_thread(NULL)));
266 
267 	free(initList);
268 }
269 
270 
271 static void
272 inject_runtime_loader_api(image_t* rootImage)
273 {
274 	// We patch any exported __gRuntimeLoader symbols to point to our private
275 	// API.
276 	image_t* image;
277 	void* _export;
278 	if (find_symbol_breadth_first(rootImage,
279 			SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
280 			&_export) == B_OK) {
281 		*(void**)_export = &gRuntimeLoader;
282 	}
283 }
284 
285 
286 static status_t
287 add_preloaded_image(image_t* image)
288 {
289 	// We realloc() everytime -- not particularly efficient, but good enough for
290 	// small number of preloaded images.
291 	image_t** newArray = (image_t**)realloc(sPreloadedImages,
292 		sizeof(image_t*) * (sPreloadedImageCount + 1));
293 	if (newArray == NULL)
294 		return B_NO_MEMORY;
295 
296 	sPreloadedImages = newArray;
297 	newArray[sPreloadedImageCount++] = image;
298 
299 	return B_OK;
300 }
301 
302 
303 image_id
304 preload_image(char const* path)
305 {
306 	if (path == NULL)
307 		return B_BAD_VALUE;
308 
309 	KTRACE("rld: preload_image(\"%s\")", path);
310 
311 	image_t *image = NULL;
312 	status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, &image);
313 	if (status < B_OK) {
314 		KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
315 			strerror(status));
316 		return status;
317 	}
318 
319 	if (image->find_undefined_symbol == NULL)
320 		image->find_undefined_symbol = find_undefined_symbol_global;
321 
322 	status = load_dependencies(image);
323 	if (status < B_OK)
324 		goto err;
325 
326 	set_image_flags_recursively(image, RTLD_GLOBAL);
327 
328 	status = relocate_dependencies(image);
329 	if (status < B_OK)
330 		goto err;
331 
332 	status = add_preloaded_image(image);
333 	if (status < B_OK)
334 		goto err;
335 
336 	inject_runtime_loader_api(image);
337 
338 	remap_images();
339 	init_dependencies(image, true);
340 
341 	// if the image contains an add-on, register it
342 	runtime_loader_add_on* addOnStruct;
343 	if (find_symbol(image,
344 			SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
345 			(void**)&addOnStruct) == B_OK) {
346 		add_add_on(image, addOnStruct);
347 	}
348 
349 	KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id);
350 
351 	return image->id;
352 
353 err:
354 	KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status));
355 
356 	dequeue_loaded_image(image);
357 	delete_image(image);
358 	return status;
359 }
360 
361 
362 static void
363 preload_images()
364 {
365 	const char* imagePaths = getenv("LD_PRELOAD");
366 	if (imagePaths == NULL)
367 		return;
368 
369 	while (*imagePaths != '\0') {
370 		// find begin of image path
371 		while (*imagePaths != '\0' && isspace(*imagePaths))
372 			imagePaths++;
373 
374 		if (*imagePaths == '\0')
375 			break;
376 
377 		// find end of image path
378 		const char* imagePath = imagePaths;
379 		while (*imagePaths != '\0' && !isspace(*imagePaths))
380 			imagePaths++;
381 
382 		// extract the path
383 		char path[B_PATH_NAME_LENGTH];
384 		size_t pathLen = imagePaths - imagePath;
385 		if (pathLen > sizeof(path) - 1)
386 			continue;
387 		memcpy(path, imagePath, pathLen);
388 		path[pathLen] = '\0';
389 
390 		// load the image
391 		preload_image(path);
392 	}
393 }
394 
395 
396 //	#pragma mark - libroot.so exported functions
397 
398 
399 image_id
400 load_program(char const *path, void **_entry)
401 {
402 	status_t status;
403 	image_t *image;
404 
405 	KTRACE("rld: load_program(\"%s\")", path);
406 
407 	rld_lock();
408 		// for now, just do stupid simple global locking
409 
410 	preload_images();
411 
412 	TRACE(("rld: load %s\n", path));
413 
414 	status = load_image(path, B_APP_IMAGE, NULL, &gProgramImage);
415 	if (status < B_OK)
416 		goto err;
417 
418 	if (gProgramImage->find_undefined_symbol == NULL)
419 		gProgramImage->find_undefined_symbol = find_undefined_symbol_global;
420 
421 	status = load_dependencies(gProgramImage);
422 	if (status < B_OK)
423 		goto err;
424 
425 	// Set RTLD_GLOBAL on all libraries including the program.
426 	// This results in the desired symbol resolution for dlopen()ed libraries.
427 	set_image_flags_recursively(gProgramImage, RTLD_GLOBAL);
428 
429 	status = relocate_dependencies(gProgramImage);
430 	if (status < B_OK)
431 		goto err;
432 
433 	inject_runtime_loader_api(gProgramImage);
434 
435 	remap_images();
436 	init_dependencies(gProgramImage, true);
437 
438 	// Since the images are initialized now, we no longer should use our
439 	// getenv(), but use the one from libroot.so
440 	find_symbol_breadth_first(gProgramImage,
441 		SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
442 		(void**)&gGetEnv);
443 
444 	if (gProgramImage->entry_point == 0) {
445 		status = B_NOT_AN_EXECUTABLE;
446 		goto err;
447 	}
448 
449 	*_entry = (void *)(gProgramImage->entry_point);
450 
451 	rld_unlock();
452 
453 	gProgramLoaded = true;
454 
455 	KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path,
456 		*_entry, gProgramImage->id);
457 
458 	return gProgramImage->id;
459 
460 err:
461 	KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status));
462 
463 	delete_image(gProgramImage);
464 
465 	if (report_errors()) {
466 		// send error message
467 		gErrorMessage.AddInt32("error", status);
468 		gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token,
469 			-1, 0, find_thread(NULL));
470 
471 		_kern_write_port_etc(gProgramArgs->error_port, 'KMSG',
472 			gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0);
473 	}
474 	_kern_loading_app_failed(status);
475 	rld_unlock();
476 
477 	return status;
478 }
479 
480 
481 image_id
482 load_library(char const *path, uint32 flags, bool addOn, void** _handle)
483 {
484 	image_t *image = NULL;
485 	image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
486 	status_t status;
487 
488 	if (path == NULL && addOn)
489 		return B_BAD_VALUE;
490 
491 	KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
492 
493 	rld_lock();
494 		// for now, just do stupid simple global locking
495 
496 	// have we already loaded this library?
497 	// Checking it at this stage saves loading its dependencies again
498 	if (!addOn) {
499 		// a NULL path is fine -- it means the global scope shall be opened
500 		if (path == NULL) {
501 			*_handle = RLD_GLOBAL_SCOPE;
502 			rld_unlock();
503 			return 0;
504 		}
505 
506 		image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
507 		if (image != NULL && (flags & RTLD_GLOBAL) != 0)
508 			set_image_flags_recursively(image, RTLD_GLOBAL);
509 
510 		if (image) {
511 			atomic_add(&image->ref_count, 1);
512 			rld_unlock();
513 			KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
514 				image->id);
515 			*_handle = image;
516 			return image->id;
517 		}
518 	}
519 
520 	status = load_image(path, type, NULL, &image);
521 	if (status < B_OK) {
522 		rld_unlock();
523 		KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
524 			strerror(status));
525 		return status;
526 	}
527 
528 	if (image->find_undefined_symbol == NULL) {
529 		if (addOn)
530 			image->find_undefined_symbol = find_undefined_symbol_add_on;
531 		else
532 			image->find_undefined_symbol = find_undefined_symbol_global;
533 	}
534 
535 	status = load_dependencies(image);
536 	if (status < B_OK)
537 		goto err;
538 
539 	// If specified, set the RTLD_GLOBAL flag recursively on this image and all
540 	// dependencies. If not specified, we temporarily set
541 	// RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used
542 	// for undefined symbol resolution.
543 	if ((flags & RTLD_GLOBAL) != 0)
544 		set_image_flags_recursively(image, RTLD_GLOBAL);
545 	else
546 		set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
547 
548 	status = relocate_dependencies(image);
549 	if (status < B_OK)
550 		goto err;
551 
552 	if ((flags & RTLD_GLOBAL) == 0)
553 		clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
554 
555 	remap_images();
556 	init_dependencies(image, true);
557 
558 	rld_unlock();
559 
560 	KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
561 
562 	*_handle = image;
563 	return image->id;
564 
565 err:
566 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
567 
568 	dequeue_loaded_image(image);
569 	delete_image(image);
570 	rld_unlock();
571 	return status;
572 }
573 
574 
575 status_t
576 unload_library(void* handle, image_id imageID, bool addOn)
577 {
578 	image_t *image;
579 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
580 
581 	if (handle == NULL && imageID < 0)
582 		return B_BAD_IMAGE_ID;
583 
584 	if (handle == RLD_GLOBAL_SCOPE)
585 		return B_OK;
586 
587 	rld_lock();
588 		// for now, just do stupid simple global locking
589 
590 	if (gInvalidImageIDs) {
591 		// After fork, we lazily rebuild the image IDs of all loaded images
592 		update_image_ids();
593 	}
594 
595 	// we only check images that have been already initialized
596 
597 	status_t status = B_BAD_IMAGE_ID;
598 
599 	if (handle != NULL) {
600 		image = (image_t*)handle;
601 		put_image(image);
602 		status = B_OK;
603 	} else {
604 		image = find_loaded_image_by_id(imageID, true);
605 		if (image != NULL) {
606 			// unload image
607 			if (type == image->type) {
608 				put_image(image);
609 				status = B_OK;
610 			} else
611 				status = B_BAD_VALUE;
612 		}
613 	}
614 
615 	if (status == B_OK) {
616 		while ((image = get_disposable_images().head) != NULL) {
617 			// Call the exit hooks that live in this image.
618 			// Note: With the Itanium ABI this shouldn't really be done this
619 			// way anymore, since global destructors are registered via
620 			// __cxa_atexit() (the ones that are registered dynamically) and the
621 			// termination routine should call __cxa_finalize() for the image.
622 			// The reason why we still do it is that hooks registered with
623 			// atexit() aren't associated with the image. We could find out
624 			// there which image the hooks lives in and register it
625 			// respectively, but since that would be done always, that's
626 			// probably more expensive than calling
627 			// call_atexit_hooks_for_range() only here, which happens only when
628 			// libraries are unloaded dynamically.
629 			if (gRuntimeLoader.call_atexit_hooks_for_range) {
630 				gRuntimeLoader.call_atexit_hooks_for_range(
631 					image->regions[0].vmstart, image->regions[0].vmsize);
632 			}
633 
634 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
635 
636 			if (image->term_routine)
637 				((init_term_function)image->term_routine)(image->id);
638 
639 			dequeue_disposable_image(image);
640 			unmap_image(image);
641 
642 			image_event(image, IMAGE_EVENT_UNLOADING);
643 
644 			delete_image(image);
645 		}
646 	}
647 
648 	rld_unlock();
649 	return status;
650 }
651 
652 
653 status_t
654 get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
655 	int32 *_nameLength, int32 *_type, void **_location)
656 {
657 	int32 count = 0, j;
658 	uint32 i;
659 	image_t *image;
660 
661 	rld_lock();
662 
663 	// get the image from those who have been already initialized
664 	image = find_loaded_image_by_id(imageID, false);
665 	if (image == NULL) {
666 		rld_unlock();
667 		return B_BAD_IMAGE_ID;
668 	}
669 
670 	// iterate through all the hash buckets until we've found the one
671 	for (i = 0; i < HASHTABSIZE(image); i++) {
672 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
673 			struct Elf32_Sym *symbol = &image->syms[j];
674 
675 			if (count == num) {
676 				const char* symbolName = SYMNAME(image, symbol);
677 				strlcpy(nameBuffer, symbolName, *_nameLength);
678 				*_nameLength = strlen(symbolName);
679 
680 				void* location = (void*)(symbol->st_value
681 					+ image->regions[0].delta);
682 				int32 type;
683 				if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
684 					type = B_SYMBOL_TYPE_TEXT;
685 				else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT)
686 					type = B_SYMBOL_TYPE_DATA;
687 				else
688 					type = B_SYMBOL_TYPE_ANY;
689 					// TODO: check with the return types of that BeOS function
690 
691 				patch_defined_symbol(image, symbolName, &location, &type);
692 
693 				if (_type != NULL)
694 					*_type = type;
695 				if (_location != NULL)
696 					*_location = location;
697 				goto out;
698 			}
699 			count++;
700 		}
701 	}
702 out:
703 	rld_unlock();
704 
705 	if (num != count)
706 		return B_BAD_INDEX;
707 
708 	return B_OK;
709 }
710 
711 
712 status_t
713 get_nearest_symbol_at_address(void* address, image_id* _imageID,
714 	char** _imagePath, char** _symbolName, int32* _type, void** _location)
715 {
716 	rld_lock();
717 
718 	image_t* image = find_loaded_image_by_address((addr_t)address);
719 	if (image == NULL) {
720 		rld_unlock();
721 		return B_BAD_VALUE;
722 	}
723 
724 	struct Elf32_Sym* foundSymbol = NULL;
725 	addr_t foundLocation = (addr_t)NULL;
726 
727 	bool found = false;
728 	for (uint32 i = 0; i < HASHTABSIZE(image) && !found; i++) {
729 		for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF;
730 				j = HASHCHAINS(image)[j]) {
731 			struct Elf32_Sym *symbol = &image->syms[j];
732 			addr_t location = symbol->st_value + image->regions[0].delta;
733 
734 			if (location <= (addr_t)address	&& location >= foundLocation) {
735 				foundSymbol = symbol;
736 				foundLocation = location;
737 
738 				// jump out if we have an exact match
739 				if (foundLocation == (addr_t)address) {
740 					found = true;
741 					break;
742 				}
743 			}
744 		}
745 	}
746 
747 	if (_imageID != NULL)
748 		*_imageID = image->id;
749 	if (_imagePath != NULL)
750 		*_imagePath = image->path;
751 
752 	if (foundSymbol != NULL) {
753 		*_symbolName = SYMNAME(image, foundSymbol);
754 
755 		if (_type != NULL) {
756 			if (ELF32_ST_TYPE(foundSymbol->st_info) == STT_FUNC)
757 				*_type = B_SYMBOL_TYPE_TEXT;
758 			else if (ELF32_ST_TYPE(foundSymbol->st_info) == STT_OBJECT)
759 				*_type = B_SYMBOL_TYPE_DATA;
760 			else
761 				*_type = B_SYMBOL_TYPE_ANY;
762 			// TODO: check with the return types of that BeOS function
763 		}
764 
765 		if (_location != NULL)
766 			*_location = (void*)foundLocation;
767 	} else {
768 		*_symbolName = NULL;
769 		if (_location != NULL)
770 			*_location = NULL;
771 	}
772 
773 	rld_unlock();
774 	return B_OK;
775 }
776 
777 
778 status_t
779 get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
780 	bool recursive, image_id *_inImage, void **_location)
781 {
782 	status_t status = B_OK;
783 	image_t *image;
784 
785 	if (imageID < B_OK)
786 		return B_BAD_IMAGE_ID;
787 	if (symbolName == NULL)
788 		return B_BAD_VALUE;
789 
790 	rld_lock();
791 		// for now, just do stupid simple global locking
792 
793 	// get the image from those who have been already initialized
794 	image = find_loaded_image_by_id(imageID, false);
795 	if (image != NULL) {
796 		if (recursive) {
797 			// breadth-first search in the given image and its dependencies
798 			status = find_symbol_breadth_first(image,
799 				SymbolLookupInfo(symbolName, symbolType, NULL,
800 					LOOKUP_FLAG_DEFAULT_VERSION),
801 				&image, _location);
802 		} else {
803 			status = find_symbol(image,
804 				SymbolLookupInfo(symbolName, symbolType, NULL,
805 					LOOKUP_FLAG_DEFAULT_VERSION),
806 				_location);
807 		}
808 
809 		if (status == B_OK && _inImage != NULL)
810 			*_inImage = image->id;
811 	} else
812 		status = B_BAD_IMAGE_ID;
813 
814 	rld_unlock();
815 	return status;
816 }
817 
818 
819 status_t
820 get_library_symbol(void* handle, void* caller, const char* symbolName,
821 	void **_location)
822 {
823 	status_t status = B_ENTRY_NOT_FOUND;
824 
825 	if (symbolName == NULL)
826 		return B_BAD_VALUE;
827 
828 	rld_lock();
829 		// for now, just do stupid simple global locking
830 
831 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
832 		// look in the default scope
833 		image_t* image;
834 		Elf32_Sym* symbol = find_undefined_symbol_global(gProgramImage,
835 			gProgramImage,
836 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
837 				LOOKUP_FLAG_DEFAULT_VERSION),
838 			&image);
839 		if (symbol != NULL) {
840 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
841 			int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
842 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
843 			patch_defined_symbol(image, symbolName, _location, &symbolType);
844 			status = B_OK;
845 		}
846 	} else if (handle == RTLD_NEXT) {
847 		// Look in the default scope, but also in the dependencies of the
848 		// calling image. Return the next after the caller symbol.
849 
850 		// First of all, find the caller image.
851 		image_t* callerImage = get_loaded_images().head;
852 		for (; callerImage != NULL; callerImage = callerImage->next) {
853 			elf_region_t& text = callerImage->regions[0];
854 			if ((addr_t)caller >= text.vmstart
855 				&& (addr_t)caller < text.vmstart + text.vmsize) {
856 				// found the image
857 				break;
858 			}
859 		}
860 
861 		if (callerImage != NULL) {
862 			// found the caller -- now search the global scope until we find
863 			// the next symbol
864 			bool hitCallerImage = false;
865 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
866 
867 			Elf32_Sym* candidateSymbol = NULL;
868 			image_t* candidateImage = NULL;
869 
870 			image_t* image = get_loaded_images().head;
871 			for (; image != NULL; image = image->next) {
872 				// skip the caller image
873 				if (image == callerImage) {
874 					hitCallerImage = true;
875 					continue;
876 				}
877 
878 				// skip all images up to the caller image; also skip add-on
879 				// images and those not marked above for resolution
880 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
881 					|| (image->flags
882 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
883 					continue;
884 				}
885 
886 				struct Elf32_Sym *symbol = find_symbol(image,
887 					SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
888 						LOOKUP_FLAG_DEFAULT_VERSION));
889 				if (symbol == NULL)
890 					continue;
891 
892 				// found a symbol
893 				bool isWeak = ELF32_ST_BIND(symbol->st_info) == STB_WEAK;
894 				if (candidateImage == NULL || !isWeak) {
895 					candidateSymbol = symbol;
896 					candidateImage = image;
897 
898 					if (!isWeak)
899 						break;
900 				}
901 
902 				// symbol is weak, so we need to continue
903 			}
904 
905 			if (candidateSymbol != NULL) {
906 				// found the symbol
907 				*_location = (void*)(candidateSymbol->st_value
908 					+ candidateImage->regions[0].delta);
909 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
910 				patch_defined_symbol(candidateImage, symbolName, _location,
911 					&symbolType);
912 				status = B_OK;
913 			}
914 
915 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
916 		}
917 	} else {
918 		// breadth-first search in the given image and its dependencies
919 		image_t* inImage;
920 		status = find_symbol_breadth_first((image_t*)handle,
921 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
922 				LOOKUP_FLAG_DEFAULT_VERSION),
923 			&inImage, _location);
924 	}
925 
926 	rld_unlock();
927 	return status;
928 }
929 
930 
931 status_t
932 get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
933 {
934 	uint32 i, j, searchIndex = *cookie;
935 	struct Elf32_Dyn *dynamicSection;
936 	image_t *image;
937 
938 	if (_name == NULL)
939 		return B_BAD_VALUE;
940 
941 	rld_lock();
942 
943 	image = find_loaded_image_by_id(id, false);
944 	if (image == NULL) {
945 		rld_unlock();
946 		return B_BAD_IMAGE_ID;
947 	}
948 
949 	dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr;
950 	if (dynamicSection == NULL || image->num_needed <= searchIndex) {
951 		rld_unlock();
952 		return B_ENTRY_NOT_FOUND;
953 	}
954 
955 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
956 		if (dynamicSection[i].d_tag != DT_NEEDED)
957 			continue;
958 
959 		if (j++ == searchIndex) {
960 			int32 neededOffset = dynamicSection[i].d_un.d_val;
961 
962 			*_name = STRING(image, neededOffset);
963 			*cookie = searchIndex + 1;
964 			rld_unlock();
965 			return B_OK;
966 		}
967 	}
968 
969 	rld_unlock();
970 	return B_ENTRY_NOT_FOUND;
971 }
972 
973 
974 //	#pragma mark - runtime_loader private exports
975 
976 
977 /*! Read and verify the ELF header */
978 status_t
979 elf_verify_header(void *header, int32 length)
980 {
981 	int32 programSize, sectionSize;
982 
983 	if (length < (int32)sizeof(struct Elf32_Ehdr))
984 		return B_NOT_AN_EXECUTABLE;
985 
986 	return parse_elf_header((struct Elf32_Ehdr *)header, &programSize,
987 		&sectionSize);
988 }
989 
990 
991 void
992 terminate_program(void)
993 {
994 	image_t **termList;
995 	ssize_t count, i;
996 
997 	count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED);
998 	if (count < B_OK)
999 		return;
1000 
1001 	if (gInvalidImageIDs) {
1002 		// After fork, we lazily rebuild the image IDs of all loaded images
1003 		update_image_ids();
1004 	}
1005 
1006 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
1007 	for (i = count; i-- > 0;) {
1008 		image_t *image = termList[i];
1009 
1010 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
1011 
1012 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
1013 
1014 		if (image->term_routine)
1015 			((init_term_function)image->term_routine)(image->id);
1016 
1017 		image_event(image, IMAGE_EVENT_UNLOADING);
1018 	}
1019 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
1020 
1021 	free(termList);
1022 }
1023 
1024 
1025 void
1026 rldelf_init(void)
1027 {
1028 	init_add_ons();
1029 
1030 	// create the debug area
1031 	{
1032 		int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
1033 
1034 		runtime_loader_debug_area *area;
1035 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
1036 			(void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK,
1037 			B_READ_AREA | B_WRITE_AREA);
1038 		if (areaID < B_OK) {
1039 			FATAL("Failed to create debug area.\n");
1040 			_kern_loading_app_failed(areaID);
1041 		}
1042 
1043 		area->loaded_images = &get_loaded_images();
1044 	}
1045 
1046 	// initialize error message if needed
1047 	if (report_errors()) {
1048 		void *buffer = malloc(1024);
1049 		if (buffer == NULL)
1050 			return;
1051 
1052 		gErrorMessage.SetTo(buffer, 1024, 'Rler');
1053 	}
1054 }
1055 
1056 
1057 status_t
1058 elf_reinit_after_fork(void)
1059 {
1060 	recursive_lock_init(&sLock, kLockName);
1061 
1062 	// We also need to update the IDs of our images. We are the child and
1063 	// and have cloned images with different IDs. Since in most cases (fork()
1064 	// + exec*()) this would just increase the fork() overhead with no one
1065 	// caring, we do that lazily, when first doing something different.
1066 	gInvalidImageIDs = true;
1067 
1068 	return B_OK;
1069 }
1070