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, §ionSize);
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, §ionSize);
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, §ionSize);
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