xref: /haiku/src/system/runtime_loader/elf.cpp (revision 1f1be520070165ce402b46d17a44a2941c0dda2f)
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 *
find_dt_string(image_t * image,int32 d_tag)57 find_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 
71 static const char *
find_dt_rpath(image_t * image)72 find_dt_rpath(image_t *image)
73 {
74 	return find_dt_string(image, DT_RPATH);
75 }
76 
77 
78 static const char *
find_dt_runpath(image_t * image)79 find_dt_runpath(image_t *image)
80 {
81 	return find_dt_string(image, DT_RUNPATH);
82 }
83 
84 
85 image_id
preload_image(char const * path,image_t ** image)86 preload_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 
109 static void
preload_images(image_t ** image,int32 * _count=NULL)110 preload_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 
158 static status_t
load_immediate_dependencies(image_t * image,bool preload)159 load_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 
256 static status_t
load_dependencies(image_t * image,bool preload=false)257 load_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 
281 static status_t
relocate_image(image_t * rootImage,image_t * image)282 relocate_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 
298 static status_t
relocate_dependencies(image_t * image)299 relocate_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 
321 static void
init_dependencies(image_t * image,bool initHead)322 init_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 
382 static void
call_term_functions(image_t * image)383 call_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 
410 static void
inject_runtime_loader_api(image_t * rootImage)411 inject_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 
425 static status_t
add_preloaded_addon(image_t * image)426 add_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 
442 image_id
preload_addon(char const * path)443 preload_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 
492 err:
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 
501 static void
preload_addons()502 preload_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 
538 image_id
load_program(char const * path,void ** _entry)539 load_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 
597 err:
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 
617 image_id
load_library(char const * path,uint32 flags,bool addOn,void * caller,void ** _handle)618 load_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 
716 err:
717 	KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status));
718 
719 	unload_library(image, -1, addOn);
720 	return status;
721 }
722 
723 
724 status_t
unload_library(void * handle,image_id imageID,bool addOn)725 unload_library(void* handle, image_id imageID, bool addOn)
726 {
727 	image_t *image;
728 	image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE;
729 
730 	if (handle == NULL && imageID < 0)
731 		return B_BAD_IMAGE_ID;
732 
733 	if (handle == RLD_GLOBAL_SCOPE)
734 		return B_OK;
735 
736 	RecursiveLocker _(sLock);
737 		// for now, just do stupid simple global locking
738 
739 	if (gInvalidImageIDs) {
740 		// After fork, we lazily rebuild the image IDs of all loaded images
741 		update_image_ids();
742 	}
743 
744 	// we only check images that have been already initialized
745 
746 	if (handle != NULL) {
747 		image = (image_t*)handle;
748 		put_image(image);
749 	} else {
750 		image = find_loaded_image_by_id(imageID, true);
751 		if (image == NULL)
752 			return B_BAD_IMAGE_ID;
753 
754 		// unload image
755 		if (type != image->type)
756 			return B_BAD_VALUE;
757 		put_image(image);
758 	}
759 
760 	while ((image = get_disposable_images().head) != NULL) {
761 		dequeue_disposable_image(image);
762 
763 		if ((image->flags & RFLAG_INITIALIZED) != 0) {
764 			// Call the exit hooks that live in this image.
765 			// Note: With the Itanium ABI this shouldn't really be done this
766 			// way anymore, since global destructors are registered via
767 			// __cxa_atexit() (the ones that are registered dynamically) and the
768 			// termination routine should call __cxa_finalize() for the image.
769 			// The reason why we still do it is that hooks registered with
770 			// atexit() aren't associated with the image. We could find out
771 			// there which image the hooks lives in and register it
772 			// respectively, but since that would be done always, that's
773 			// probably more expensive than calling
774 			// call_atexit_hooks_for_range() only here, which happens only when
775 			// libraries are unloaded dynamically.
776 			if (gRuntimeLoader.call_atexit_hooks_for_range != NULL) {
777 				gRuntimeLoader.call_atexit_hooks_for_range(
778 					image->regions[0].vmstart, image->regions[0].vmsize);
779 			}
780 
781 			image_event(image, IMAGE_EVENT_UNINITIALIZING);
782 
783 			call_term_functions(image);
784 		}
785 
786 		TLSBlockTemplates::Get().Unregister(image->dso_tls_id);
787 
788 		unmap_image(image);
789 
790 		image_event(image, IMAGE_EVENT_UNLOADING);
791 
792 		delete_image(image);
793 	}
794 
795 	return B_OK;
796 }
797 
798 
799 status_t
get_nth_symbol(image_id imageID,int32 num,char * nameBuffer,int32 * _nameLength,int32 * _type,void ** _location)800 get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
801 	int32 *_nameLength, int32 *_type, void **_location)
802 {
803 	int32 count = 0, j;
804 	uint32 i;
805 	image_t *image;
806 
807 	RecursiveLocker _(sLock);
808 
809 	// get the image from those who have been already initialized
810 	image = find_loaded_image_by_id(imageID, false);
811 	if (image == NULL)
812 		return B_BAD_IMAGE_ID;
813 
814 	// iterate through all the hash buckets until we've found the one
815 	for (i = 0; i < HASHTABSIZE(image); i++) {
816 		for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
817 			elf_sym *symbol = &image->syms[j];
818 
819 			if (count == num) {
820 				const char* symbolName = SYMNAME(image, symbol);
821 				strlcpy(nameBuffer, symbolName, *_nameLength);
822 				*_nameLength = strlen(symbolName);
823 
824 				void* location = (void*)(symbol->st_value
825 					+ image->regions[0].delta);
826 				int32 type;
827 				if (symbol->Type() == STT_FUNC)
828 					type = B_SYMBOL_TYPE_TEXT;
829 				else if (symbol->Type() == STT_OBJECT)
830 					type = B_SYMBOL_TYPE_DATA;
831 				else
832 					type = B_SYMBOL_TYPE_ANY;
833 					// TODO: check with the return types of that BeOS function
834 
835 				patch_defined_symbol(image, symbolName, &location, &type);
836 
837 				if (_type != NULL)
838 					*_type = type;
839 				if (_location != NULL)
840 					*_location = location;
841 				goto out;
842 			}
843 			count++;
844 		}
845 	}
846 out:
847 	if (num != count)
848 		return B_BAD_INDEX;
849 
850 	return B_OK;
851 }
852 
853 
854 status_t
get_nearest_symbol_at_address(void * address,image_id * _imageID,char ** _imagePath,char ** _imageName,char ** _symbolName,int32 * _type,void ** _location,bool * _exactMatch)855 get_nearest_symbol_at_address(void* address, image_id* _imageID,
856 	char** _imagePath, char** _imageName, char** _symbolName, int32* _type,
857 	void** _location, bool* _exactMatch)
858 {
859 	RecursiveLocker _(sLock);
860 
861 	image_t* image = find_loaded_image_by_address((addr_t)address);
862 	if (image == NULL)
863 		return B_BAD_VALUE;
864 
865 	if (_imageID != NULL)
866 		*_imageID = image->id;
867 	if (_imagePath != NULL)
868 		*_imagePath = image->path;
869 	if (_imageName != NULL)
870 		*_imageName = image->name;
871 
872 	// If the caller does not want the actual symbol name, only the image,
873 	// we can just return immediately.
874 	if (_symbolName == NULL && _type == NULL && _location == NULL)
875 		return B_OK;
876 
877 	bool exactMatch = false;
878 	elf_sym* foundSymbol = NULL;
879 	addr_t foundLocation = (addr_t)NULL;
880 
881 	for (uint32 i = 0; i < HASHTABSIZE(image) && !exactMatch; i++) {
882 		for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF;
883 				j = HASHCHAINS(image)[j]) {
884 			elf_sym *symbol = &image->syms[j];
885 			addr_t location = symbol->st_value + image->regions[0].delta;
886 
887 			if (location <= (addr_t)address	&& location >= foundLocation) {
888 				foundSymbol = symbol;
889 				foundLocation = location;
890 
891 				// jump out if we have an exact match
892 				if (location + symbol->st_size > (addr_t)address) {
893 					exactMatch = true;
894 					break;
895 				}
896 			}
897 		}
898 	}
899 
900 	if (_exactMatch != NULL)
901 		*_exactMatch = exactMatch;
902 
903 	if (foundSymbol != NULL) {
904 		*_symbolName = SYMNAME(image, foundSymbol);
905 
906 		if (_type != NULL) {
907 			if (foundSymbol->Type() == STT_FUNC)
908 				*_type = B_SYMBOL_TYPE_TEXT;
909 			else if (foundSymbol->Type() == STT_OBJECT)
910 				*_type = B_SYMBOL_TYPE_DATA;
911 			else
912 				*_type = B_SYMBOL_TYPE_ANY;
913 			// TODO: check with the return types of that BeOS function
914 		}
915 
916 		if (_location != NULL)
917 			*_location = (void*)foundLocation;
918 	} else {
919 		*_symbolName = NULL;
920 		if (_location != NULL)
921 			*_location = NULL;
922 	}
923 
924 	return B_OK;
925 }
926 
927 
928 status_t
get_symbol(image_id imageID,char const * symbolName,int32 symbolType,bool recursive,image_id * _inImage,void ** _location)929 get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
930 	bool recursive, image_id *_inImage, void **_location)
931 {
932 	status_t status = B_OK;
933 	image_t *image;
934 
935 	if (imageID < B_OK)
936 		return B_BAD_IMAGE_ID;
937 	if (symbolName == NULL)
938 		return B_BAD_VALUE;
939 
940 	// Previously, these functions were called in __haiku_init_before
941 	// and __haiku_init_after. Now we call them inside runtime_loader,
942 	// so we prevent applications from fetching them.
943 	if (strcmp(symbolName, B_INIT_BEFORE_FUNCTION_NAME) == 0
944 		|| strcmp(symbolName, B_INIT_AFTER_FUNCTION_NAME) == 0
945 		|| strcmp(symbolName, B_TERM_BEFORE_FUNCTION_NAME) == 0
946 		|| strcmp(symbolName, B_TERM_AFTER_FUNCTION_NAME) == 0)
947 		return B_BAD_VALUE;
948 
949 	RecursiveLocker _(sLock);
950 		// for now, just do stupid simple global locking
951 
952 	// get the image from those who have been already initialized
953 	image = find_loaded_image_by_id(imageID, false);
954 	if (image != NULL) {
955 		if (recursive) {
956 			// breadth-first search in the given image and its dependencies
957 			status = find_symbol_breadth_first(image,
958 				SymbolLookupInfo(symbolName, symbolType, NULL,
959 					LOOKUP_FLAG_DEFAULT_VERSION),
960 				&image, _location);
961 		} else {
962 			status = find_symbol(image,
963 				SymbolLookupInfo(symbolName, symbolType, NULL,
964 					LOOKUP_FLAG_DEFAULT_VERSION),
965 				_location);
966 		}
967 
968 		if (status == B_OK && _inImage != NULL)
969 			*_inImage = image->id;
970 	} else
971 		status = B_BAD_IMAGE_ID;
972 
973 	return status;
974 }
975 
976 
977 status_t
get_library_symbol(void * handle,void * caller,const char * symbolName,void ** _location)978 get_library_symbol(void* handle, void* caller, const char* symbolName,
979 	void **_location)
980 {
981 	status_t status = B_ENTRY_NOT_FOUND;
982 
983 	if (symbolName == NULL)
984 		return B_BAD_VALUE;
985 
986 	RecursiveLocker _(sLock);
987 		// for now, just do stupid simple global locking
988 
989 	if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) {
990 		// look in the default scope
991 		image_t* image;
992 		elf_sym* symbol = find_undefined_symbol_global(gProgramImage,
993 			gProgramImage,
994 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
995 				LOOKUP_FLAG_DEFAULT_VERSION),
996 			&image);
997 		if (symbol != NULL) {
998 			*_location = (void*)(symbol->st_value + image->regions[0].delta);
999 			int32 symbolType = symbol->Type() == STT_FUNC
1000 				? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
1001 			patch_defined_symbol(image, symbolName, _location, &symbolType);
1002 			status = B_OK;
1003 		}
1004 	} else if (handle == RTLD_NEXT) {
1005 		// Look in the default scope, but also in the dependencies of the
1006 		// calling image. Return the next after the caller symbol.
1007 
1008 		// First of all, find the caller image.
1009 		image_t* callerImage = get_loaded_images().head;
1010 		for (; callerImage != NULL; callerImage = callerImage->next) {
1011 			elf_region_t& text = callerImage->regions[0];
1012 			if ((addr_t)caller >= text.vmstart
1013 				&& (addr_t)caller < text.vmstart + text.vmsize) {
1014 				// found the image
1015 				break;
1016 			}
1017 		}
1018 
1019 		if (callerImage != NULL) {
1020 			// found the caller -- now search the global scope until we find
1021 			// the next symbol
1022 			bool hitCallerImage = false;
1023 			set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
1024 
1025 			elf_sym* candidateSymbol = NULL;
1026 			image_t* candidateImage = NULL;
1027 
1028 			image_t* image = get_loaded_images().head;
1029 			for (; image != NULL; image = image->next) {
1030 				// skip the caller image
1031 				if (image == callerImage) {
1032 					hitCallerImage = true;
1033 					continue;
1034 				}
1035 
1036 				// skip all images up to the caller image; also skip add-on
1037 				// images and those not marked above for resolution
1038 				if (!hitCallerImage || image->type == B_ADD_ON_IMAGE
1039 					|| (image->flags
1040 						& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) {
1041 					continue;
1042 				}
1043 
1044 				elf_sym *symbol = find_symbol(image,
1045 					SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
1046 						LOOKUP_FLAG_DEFAULT_VERSION));
1047 				if (symbol == NULL)
1048 					continue;
1049 
1050 				// found a symbol
1051 				bool isWeak = symbol->Bind() == STB_WEAK;
1052 				if (candidateImage == NULL || !isWeak) {
1053 					candidateSymbol = symbol;
1054 					candidateImage = image;
1055 
1056 					if (!isWeak)
1057 						break;
1058 				}
1059 
1060 				// symbol is weak, so we need to continue
1061 			}
1062 
1063 			if (candidateSymbol != NULL) {
1064 				// found the symbol
1065 				*_location = (void*)(candidateSymbol->st_value
1066 					+ candidateImage->regions[0].delta);
1067 				int32 symbolType = B_SYMBOL_TYPE_TEXT;
1068 				patch_defined_symbol(candidateImage, symbolName, _location,
1069 					&symbolType);
1070 				status = B_OK;
1071 			}
1072 
1073 			clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING);
1074 		}
1075 	} else {
1076 		// breadth-first search in the given image and its dependencies
1077 		image_t* inImage;
1078 		status = find_symbol_breadth_first((image_t*)handle,
1079 			SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
1080 				LOOKUP_FLAG_DEFAULT_VERSION),
1081 			&inImage, _location);
1082 	}
1083 
1084 	return status;
1085 }
1086 
1087 
1088 status_t
get_next_image_dependency(image_id id,uint32 * cookie,const char ** _name)1089 get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
1090 {
1091 	uint32 i, j, searchIndex = *cookie;
1092 	elf_dyn *dynamicSection;
1093 	image_t *image;
1094 
1095 	if (_name == NULL)
1096 		return B_BAD_VALUE;
1097 
1098 	RecursiveLocker _(sLock);
1099 
1100 	image = find_loaded_image_by_id(id, false);
1101 	if (image == NULL)
1102 		return B_BAD_IMAGE_ID;
1103 
1104 	dynamicSection = (elf_dyn *)image->dynamic_ptr;
1105 	if (dynamicSection == NULL || image->num_needed <= searchIndex)
1106 		return B_ENTRY_NOT_FOUND;
1107 
1108 	for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) {
1109 		if (dynamicSection[i].d_tag != DT_NEEDED)
1110 			continue;
1111 
1112 		if (j++ == searchIndex) {
1113 			int32 neededOffset = dynamicSection[i].d_un.d_val;
1114 
1115 			*_name = STRING(image, neededOffset);
1116 			*cookie = searchIndex + 1;
1117 			return B_OK;
1118 		}
1119 	}
1120 
1121 	return B_ENTRY_NOT_FOUND;
1122 }
1123 
1124 
1125 //	#pragma mark - runtime_loader private exports
1126 
1127 
1128 /*! Read and verify the ELF header */
1129 status_t
elf_verify_header(void * header,size_t length)1130 elf_verify_header(void *header, size_t length)
1131 {
1132 	int32 programSize, sectionSize;
1133 
1134 	if (length < sizeof(elf_ehdr))
1135 		return B_NOT_AN_EXECUTABLE;
1136 
1137 	return parse_elf_header((elf_ehdr *)header, &programSize, &sectionSize);
1138 }
1139 
1140 
1141 #ifdef _COMPAT_MODE
1142 #ifdef __x86_64__
1143 status_t
elf32_verify_header(void * header,size_t length)1144 elf32_verify_header(void *header, size_t length)
1145 {
1146 	int32 programSize, sectionSize;
1147 
1148 	if (length < sizeof(Elf32_Ehdr))
1149 		return B_NOT_AN_EXECUTABLE;
1150 
1151 	return parse_elf32_header((Elf32_Ehdr *)header, &programSize, &sectionSize);
1152 }
1153 #else
1154 status_t
elf64_verify_header(void * header,size_t length)1155 elf64_verify_header(void *header, size_t length)
1156 {
1157 	int32 programSize, sectionSize;
1158 
1159 	if (length < sizeof(Elf64_Ehdr))
1160 		return B_NOT_AN_EXECUTABLE;
1161 
1162 	return parse_elf64_header((Elf64_Ehdr *)header, &programSize, &sectionSize);
1163 }
1164 #endif	// __x86_64__
1165 #endif	// _COMPAT_MODE
1166 
1167 
1168 void
terminate_program(void)1169 terminate_program(void)
1170 {
1171 	image_t **termList;
1172 	ssize_t count, i;
1173 
1174 	count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED);
1175 	if (count < B_OK)
1176 		return;
1177 
1178 	if (gInvalidImageIDs) {
1179 		// After fork, we lazily rebuild the image IDs of all loaded images
1180 		update_image_ids();
1181 	}
1182 
1183 	TRACE(("%ld: terminate dependencies\n", find_thread(NULL)));
1184 	for (i = count; i-- > 0;) {
1185 		image_t *image = termList[i];
1186 
1187 		TRACE(("%ld:  term: %s\n", find_thread(NULL), image->name));
1188 
1189 		image_event(image, IMAGE_EVENT_UNINITIALIZING);
1190 
1191 		call_term_functions(image);
1192 
1193 		image_event(image, IMAGE_EVENT_UNLOADING);
1194 	}
1195 	TRACE(("%ld:  term done.\n", find_thread(NULL)));
1196 
1197 	free(termList);
1198 }
1199 
1200 
1201 void
rldelf_init(void)1202 rldelf_init(void)
1203 {
1204 	init_add_ons();
1205 
1206 	// create the debug area
1207 	{
1208 		size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area));
1209 
1210 		runtime_loader_debug_area *area;
1211 		area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME,
1212 			(void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK,
1213 			B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA);
1214 		if (areaID < B_OK) {
1215 			FATAL("Failed to create debug area.\n");
1216 			_kern_loading_app_failed(areaID);
1217 		}
1218 
1219 		area->loaded_images = &get_loaded_images();
1220 	}
1221 
1222 	// initialize error message if needed
1223 	if (report_errors()) {
1224 		void *buffer = malloc(1024);
1225 		if (buffer == NULL)
1226 			return;
1227 
1228 		gErrorMessage.SetTo(buffer, 1024, 'Rler');
1229 	}
1230 }
1231 
1232 
1233 status_t
elf_reinit_after_fork(void)1234 elf_reinit_after_fork(void)
1235 {
1236 	recursive_lock_init(&sLock, kLockName);
1237 
1238 	// We also need to update the IDs of our images. We are the child and
1239 	// and have cloned images with different IDs. Since in most cases (fork()
1240 	// + exec*()) this would just increase the fork() overhead with no one
1241 	// caring, we do that lazily, when first doing something different.
1242 	gInvalidImageIDs = true;
1243 
1244 	return B_OK;
1245 }
1246