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