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