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