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