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