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