10c0fea5dSIngo Weinhold /* 2aa3507feSIngo Weinhold * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3b6455c08SAxel Dörfler * Copyright 2003-2011, Axel Dörfler, axeld@pinc-software.de. 40c0fea5dSIngo Weinhold * Distributed under the terms of the MIT License. 50c0fea5dSIngo Weinhold * 60c0fea5dSIngo Weinhold * Copyright 2002, Manuel J. Petit. All rights reserved. 70c0fea5dSIngo Weinhold * Copyright 2001, Travis Geiselbrecht. All rights reserved. 80c0fea5dSIngo Weinhold * Distributed under the terms of the NewOS License. 90c0fea5dSIngo Weinhold */ 100c0fea5dSIngo Weinhold 110c0fea5dSIngo Weinhold #include "runtime_loader_private.h" 120c0fea5dSIngo Weinhold 13ca618b22SIngo Weinhold #include <ctype.h> 140c85bd05SIngo Weinhold #include <dlfcn.h> 150c0fea5dSIngo Weinhold #include <stdio.h> 160c0fea5dSIngo Weinhold #include <stdlib.h> 1734982809SIngo Weinhold #include <string.h> 180c0fea5dSIngo Weinhold 19ca618b22SIngo Weinhold #include <OS.h> 20ca618b22SIngo Weinhold 217486b72dSIngo Weinhold #include <syscalls.h> 2210b4b5d1SIngo Weinhold #include <util/kernel_cpp.h> 237486b72dSIngo Weinhold 24f2bb2575SIngo Weinhold #include <locks.h> 25f2bb2575SIngo Weinhold 2694830eb2SIngo Weinhold #include "add_ons.h" 2794830eb2SIngo Weinhold #include "elf_load_image.h" 2894830eb2SIngo Weinhold #include "elf_symbol_lookup.h" 2944c0c4d3SPawel Dziepak #include "elf_tls.h" 3094830eb2SIngo Weinhold #include "elf_versioning.h" 3194830eb2SIngo Weinhold #include "errors.h" 3294830eb2SIngo Weinhold #include "images.h" 330c0fea5dSIngo Weinhold 340c0fea5dSIngo Weinhold 3510b4b5d1SIngo Weinhold // TODO: implement better locking strategy 3610b4b5d1SIngo Weinhold // TODO: implement lazy binding 370c0fea5dSIngo Weinhold 380c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen()) 390c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE ((void*)-2l) 400c85bd05SIngo Weinhold 41f7127458SIngo Weinhold static const char* const kLockName = "runtime loader"; 42f7127458SIngo Weinhold 430c0fea5dSIngo Weinhold 440c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 450c0fea5dSIngo Weinhold 4694830eb2SIngo Weinhold bool gProgramLoaded = false; 4794830eb2SIngo Weinhold image_t* gProgramImage; 48003ebb0eSIngo Weinhold 49ca618b22SIngo Weinhold static image_t** sPreloadedImages = NULL; 50ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0; 510c0fea5dSIngo Weinhold 52f7127458SIngo Weinhold static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName); 530c0fea5dSIngo Weinhold 547486b72dSIngo Weinhold 55f2bb2575SIngo Weinhold static inline void 560c0fea5dSIngo Weinhold rld_lock() 570c0fea5dSIngo Weinhold { 58f2bb2575SIngo Weinhold recursive_lock_lock(&sLock); 590c0fea5dSIngo Weinhold } 60f2bb2575SIngo Weinhold 61f2bb2575SIngo Weinhold 62f2bb2575SIngo Weinhold static inline void 63f2bb2575SIngo Weinhold rld_unlock() 64f2bb2575SIngo Weinhold { 65f2bb2575SIngo Weinhold recursive_lock_unlock(&sLock); 660c0fea5dSIngo Weinhold } 670c0fea5dSIngo Weinhold 680c0fea5dSIngo Weinhold 690c0fea5dSIngo Weinhold static const char * 700c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 710c0fea5dSIngo Weinhold { 720c0fea5dSIngo Weinhold int i; 73e3ac2588SAlex Smith elf_dyn *d = (elf_dyn *)image->dynamic_ptr; 740c0fea5dSIngo Weinhold 750c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 760c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 770c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 780c0fea5dSIngo Weinhold } 790c0fea5dSIngo Weinhold 800c0fea5dSIngo Weinhold return NULL; 810c0fea5dSIngo Weinhold } 820c0fea5dSIngo Weinhold 830c0fea5dSIngo Weinhold 840c0fea5dSIngo Weinhold static status_t 850c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image) 860c0fea5dSIngo Weinhold { 87e3ac2588SAlex Smith elf_dyn *d = (elf_dyn *)image->dynamic_ptr; 884bef3723SAxel Dörfler bool reportErrors = report_errors(); 8974c0424aSAxel Dörfler status_t status = B_OK; 900c0fea5dSIngo Weinhold uint32 i, j; 910c0fea5dSIngo Weinhold const char *rpath; 920c0fea5dSIngo Weinhold 930c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 940c0fea5dSIngo Weinhold return B_OK; 950c0fea5dSIngo Weinhold 960c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 970c0fea5dSIngo Weinhold 980c0fea5dSIngo Weinhold if (image->num_needed == 0) 990c0fea5dSIngo Weinhold return B_OK; 1000c0fea5dSIngo Weinhold 101ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ")", image->name, 1027486b72dSIngo Weinhold image->id); 1037486b72dSIngo Weinhold 1040c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 1050c0fea5dSIngo Weinhold if (image->needed == NULL) { 106c533f813SIngo Weinhold FATAL("%s: Failed to allocate needed struct\n", image->path); 107ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 108ded25be1SIngo Weinhold ") failed: no memory", image->name, image->id); 1090c0fea5dSIngo Weinhold return B_NO_MEMORY; 1100c0fea5dSIngo Weinhold } 1110c0fea5dSIngo Weinhold 1120c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 1130c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 1140c0fea5dSIngo Weinhold 1150c0fea5dSIngo Weinhold for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { 1160c0fea5dSIngo Weinhold switch (d[i].d_tag) { 1170c0fea5dSIngo Weinhold case DT_NEEDED: 11874c0424aSAxel Dörfler { 11974c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 12074c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 1210c0fea5dSIngo Weinhold 12294830eb2SIngo Weinhold status_t loadStatus = load_image(name, B_LIBRARY_IMAGE, 1238d23c440SIngo Weinhold rpath, image->path, &image->needed[j]); 12474c0424aSAxel Dörfler if (loadStatus < B_OK) { 12574c0424aSAxel Dörfler status = loadStatus; 12674c0424aSAxel Dörfler // correct error code in case the file could not been found 12774c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 12874c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 12974c0424aSAxel Dörfler 13074c0424aSAxel Dörfler if (reportErrors) 13194830eb2SIngo Weinhold gErrorMessage.AddString("missing library", name); 13274c0424aSAxel Dörfler } 13374c0424aSAxel Dörfler 13474c0424aSAxel Dörfler // Collect all missing libraries in case we report back 1357486b72dSIngo Weinhold if (!reportErrors) { 136ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 137ded25be1SIngo Weinhold ") failed: %s", image->name, image->id, 1387486b72dSIngo Weinhold strerror(status)); 1390c0fea5dSIngo Weinhold return status; 14074c0424aSAxel Dörfler } 1417486b72dSIngo Weinhold } 1420c0fea5dSIngo Weinhold 1430c0fea5dSIngo Weinhold j += 1; 1440c0fea5dSIngo Weinhold break; 14574c0424aSAxel Dörfler } 1460c0fea5dSIngo Weinhold 1470c0fea5dSIngo Weinhold default: 1480c0fea5dSIngo Weinhold // ignore any other tag 1490c0fea5dSIngo Weinhold continue; 1500c0fea5dSIngo Weinhold } 1510c0fea5dSIngo Weinhold } 1520c0fea5dSIngo Weinhold 1537486b72dSIngo Weinhold if (status < B_OK) { 154ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") " 1557486b72dSIngo Weinhold "failed: %s", image->name, image->id, 1567486b72dSIngo Weinhold strerror(status)); 15774c0424aSAxel Dörfler return status; 1587486b72dSIngo Weinhold } 15974c0424aSAxel Dörfler 1600c0fea5dSIngo Weinhold if (j != image->num_needed) { 1610c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 162ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") " 1637486b72dSIngo Weinhold "failed: internal error", image->name, image->id); 1640c0fea5dSIngo Weinhold return B_ERROR; 1650c0fea5dSIngo Weinhold } 1660c0fea5dSIngo Weinhold 167ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") done", 168ded25be1SIngo Weinhold image->name, image->id); 1697486b72dSIngo Weinhold 1700c0fea5dSIngo Weinhold return B_OK; 1710c0fea5dSIngo Weinhold } 1720c0fea5dSIngo Weinhold 1730c0fea5dSIngo Weinhold 1740c85bd05SIngo Weinhold static status_t 1750c85bd05SIngo Weinhold load_dependencies(image_t* image) 1760c85bd05SIngo Weinhold { 177003ebb0eSIngo Weinhold // load dependencies (breadth-first) 1780c85bd05SIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 1790c85bd05SIngo Weinhold otherImage = otherImage->next) { 1800c85bd05SIngo Weinhold status_t status = load_immediate_dependencies(otherImage); 1810c85bd05SIngo Weinhold if (status != B_OK) 1820c85bd05SIngo Weinhold return status; 1830c85bd05SIngo Weinhold } 1840c85bd05SIngo Weinhold 185003ebb0eSIngo Weinhold // Check the needed versions for the given image and all newly loaded 186003ebb0eSIngo Weinhold // dependencies. 187003ebb0eSIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 188003ebb0eSIngo Weinhold otherImage = otherImage->next) { 189003ebb0eSIngo Weinhold status_t status = check_needed_image_versions(otherImage); 190003ebb0eSIngo Weinhold if (status != B_OK) 191003ebb0eSIngo Weinhold return status; 192003ebb0eSIngo Weinhold } 193003ebb0eSIngo Weinhold 1940c85bd05SIngo Weinhold return B_OK; 1950c85bd05SIngo Weinhold } 1960c85bd05SIngo Weinhold 1970c85bd05SIngo Weinhold 19894830eb2SIngo Weinhold static status_t 19994830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 2000c0fea5dSIngo Weinhold { 20125dc253dSIngo Weinhold SymbolLookupCache cache(image); 20225dc253dSIngo Weinhold 20325dc253dSIngo Weinhold status_t status = arch_relocate_image(rootImage, image, &cache); 20494830eb2SIngo Weinhold if (status < B_OK) { 205c533f813SIngo Weinhold FATAL("%s: Troubles relocating: %s\n", image->path, strerror(status)); 20694830eb2SIngo Weinhold return status; 2070c0fea5dSIngo Weinhold } 2080c0fea5dSIngo Weinhold 20994830eb2SIngo Weinhold _kern_image_relocated(image->id); 21094830eb2SIngo Weinhold image_event(image, IMAGE_EVENT_RELOCATED); 21194830eb2SIngo Weinhold return B_OK; 2120c0fea5dSIngo Weinhold } 2130c0fea5dSIngo Weinhold 2140c0fea5dSIngo Weinhold 2150c0fea5dSIngo Weinhold static status_t 2160c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 2170c0fea5dSIngo Weinhold { 218ca618b22SIngo Weinhold // get the images that still have to be relocated 219ca618b22SIngo Weinhold image_t **list; 220ca618b22SIngo Weinhold ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 2210c0fea5dSIngo Weinhold if (count < B_OK) 2220c0fea5dSIngo Weinhold return count; 2230c0fea5dSIngo Weinhold 2240c85bd05SIngo Weinhold // relocate 225ca618b22SIngo Weinhold for (ssize_t i = 0; i < count; i++) { 22646f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 2270c85bd05SIngo Weinhold if (status < B_OK) { 2280c85bd05SIngo Weinhold free(list); 2290c0fea5dSIngo Weinhold return status; 2300c0fea5dSIngo Weinhold } 2310c85bd05SIngo Weinhold } 2320c0fea5dSIngo Weinhold 2330c0fea5dSIngo Weinhold free(list); 2340c0fea5dSIngo Weinhold return B_OK; 2350c0fea5dSIngo Weinhold } 2360c0fea5dSIngo Weinhold 2370c0fea5dSIngo Weinhold 2380c0fea5dSIngo Weinhold static void 2390c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 2400c0fea5dSIngo Weinhold { 2410c0fea5dSIngo Weinhold image_t **initList; 2420c0fea5dSIngo Weinhold ssize_t count, i; 2430c0fea5dSIngo Weinhold 2440c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 2450c0fea5dSIngo Weinhold if (count <= 0) 2460c0fea5dSIngo Weinhold return; 2470c0fea5dSIngo Weinhold 2480c0fea5dSIngo Weinhold if (!initHead) { 2490c0fea5dSIngo Weinhold // this removes the "calling" image 2500c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 2510c0fea5dSIngo Weinhold initList[--count] = NULL; 2520c0fea5dSIngo Weinhold } 2530c0fea5dSIngo Weinhold 2540c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 2550c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 2560c0fea5dSIngo Weinhold image = initList[i]; 2570c0fea5dSIngo Weinhold 2580c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 2590c0fea5dSIngo Weinhold 260dd76bc97SIngo Weinhold if (image->init_routine != 0) 2610c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 26210b4b5d1SIngo Weinhold 26310b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_INITIALIZED); 2640c0fea5dSIngo Weinhold } 2650c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 2660c0fea5dSIngo Weinhold 2670c0fea5dSIngo Weinhold free(initList); 2680c0fea5dSIngo Weinhold } 2690c0fea5dSIngo Weinhold 2700c0fea5dSIngo Weinhold 2710c0fea5dSIngo Weinhold static void 272ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage) 273ca618b22SIngo Weinhold { 274ca618b22SIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private 275ca618b22SIngo Weinhold // API. 276ca618b22SIngo Weinhold image_t* image; 2770c85bd05SIngo Weinhold void* _export; 278003ebb0eSIngo Weinhold if (find_symbol_breadth_first(rootImage, 279003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image, 280003ebb0eSIngo Weinhold &_export) == B_OK) { 2810c85bd05SIngo Weinhold *(void**)_export = &gRuntimeLoader; 282ca618b22SIngo Weinhold } 283ca618b22SIngo Weinhold } 284ca618b22SIngo Weinhold 285ca618b22SIngo Weinhold 286ca618b22SIngo Weinhold static status_t 287ca618b22SIngo Weinhold add_preloaded_image(image_t* image) 288ca618b22SIngo Weinhold { 289ca618b22SIngo Weinhold // We realloc() everytime -- not particularly efficient, but good enough for 290ca618b22SIngo Weinhold // small number of preloaded images. 291ca618b22SIngo Weinhold image_t** newArray = (image_t**)realloc(sPreloadedImages, 292ca618b22SIngo Weinhold sizeof(image_t*) * (sPreloadedImageCount + 1)); 293ca618b22SIngo Weinhold if (newArray == NULL) 294ca618b22SIngo Weinhold return B_NO_MEMORY; 295ca618b22SIngo Weinhold 296ca618b22SIngo Weinhold sPreloadedImages = newArray; 297ca618b22SIngo Weinhold newArray[sPreloadedImageCount++] = image; 298ca618b22SIngo Weinhold 299ca618b22SIngo Weinhold return B_OK; 300ca618b22SIngo Weinhold } 301ca618b22SIngo Weinhold 302ca618b22SIngo Weinhold 303ca618b22SIngo Weinhold image_id 304ca618b22SIngo Weinhold preload_image(char const* path) 305ca618b22SIngo Weinhold { 306ca618b22SIngo Weinhold if (path == NULL) 307ca618b22SIngo Weinhold return B_BAD_VALUE; 308ca618b22SIngo Weinhold 309ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\")", path); 310ca618b22SIngo Weinhold 311ca618b22SIngo Weinhold image_t *image = NULL; 3128d23c440SIngo Weinhold status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, &image); 313ca618b22SIngo Weinhold if (status < B_OK) { 314ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, 315ca618b22SIngo Weinhold strerror(status)); 316ca618b22SIngo Weinhold return status; 317ca618b22SIngo Weinhold } 318ca618b22SIngo Weinhold 3190c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) 3200c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 3210c85bd05SIngo Weinhold 3220c85bd05SIngo Weinhold status = load_dependencies(image); 323ca618b22SIngo Weinhold if (status < B_OK) 324ca618b22SIngo Weinhold goto err; 3250c85bd05SIngo Weinhold 3260c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 327ca618b22SIngo Weinhold 328ca618b22SIngo Weinhold status = relocate_dependencies(image); 329ca618b22SIngo Weinhold if (status < B_OK) 330ca618b22SIngo Weinhold goto err; 331ca618b22SIngo Weinhold 332ca618b22SIngo Weinhold status = add_preloaded_image(image); 333ca618b22SIngo Weinhold if (status < B_OK) 334ca618b22SIngo Weinhold goto err; 335ca618b22SIngo Weinhold 336ca618b22SIngo Weinhold inject_runtime_loader_api(image); 337ca618b22SIngo Weinhold 338ca618b22SIngo Weinhold remap_images(); 339ca618b22SIngo Weinhold init_dependencies(image, true); 340ca618b22SIngo Weinhold 34110b4b5d1SIngo Weinhold // if the image contains an add-on, register it 34210b4b5d1SIngo Weinhold runtime_loader_add_on* addOnStruct; 343003ebb0eSIngo Weinhold if (find_symbol(image, 344003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA), 34510b4b5d1SIngo Weinhold (void**)&addOnStruct) == B_OK) { 34694830eb2SIngo Weinhold add_add_on(image, addOnStruct); 34710b4b5d1SIngo Weinhold } 34810b4b5d1SIngo Weinhold 349ded25be1SIngo Weinhold KTRACE("rld: preload_image(\"%s\") done: id: %" B_PRId32, path, image->id); 350ca618b22SIngo Weinhold 351ca618b22SIngo Weinhold return image->id; 352ca618b22SIngo Weinhold 353ca618b22SIngo Weinhold err: 354ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status)); 355ca618b22SIngo Weinhold 35694830eb2SIngo Weinhold dequeue_loaded_image(image); 357ca618b22SIngo Weinhold delete_image(image); 358ca618b22SIngo Weinhold return status; 359ca618b22SIngo Weinhold } 360ca618b22SIngo Weinhold 361ca618b22SIngo Weinhold 362ca618b22SIngo Weinhold static void 363ca618b22SIngo Weinhold preload_images() 364ca618b22SIngo Weinhold { 365ca618b22SIngo Weinhold const char* imagePaths = getenv("LD_PRELOAD"); 366ca618b22SIngo Weinhold if (imagePaths == NULL) 367ca618b22SIngo Weinhold return; 368ca618b22SIngo Weinhold 369ca618b22SIngo Weinhold while (*imagePaths != '\0') { 370ca618b22SIngo Weinhold // find begin of image path 371ca618b22SIngo Weinhold while (*imagePaths != '\0' && isspace(*imagePaths)) 372ca618b22SIngo Weinhold imagePaths++; 373ca618b22SIngo Weinhold 374ca618b22SIngo Weinhold if (*imagePaths == '\0') 375ca618b22SIngo Weinhold break; 376ca618b22SIngo Weinhold 377ca618b22SIngo Weinhold // find end of image path 378ca618b22SIngo Weinhold const char* imagePath = imagePaths; 379ca618b22SIngo Weinhold while (*imagePaths != '\0' && !isspace(*imagePaths)) 380ca618b22SIngo Weinhold imagePaths++; 381ca618b22SIngo Weinhold 382ca618b22SIngo Weinhold // extract the path 383ca618b22SIngo Weinhold char path[B_PATH_NAME_LENGTH]; 384ca618b22SIngo Weinhold size_t pathLen = imagePaths - imagePath; 385ca618b22SIngo Weinhold if (pathLen > sizeof(path) - 1) 386ca618b22SIngo Weinhold continue; 387ca618b22SIngo Weinhold memcpy(path, imagePath, pathLen); 388ca618b22SIngo Weinhold path[pathLen] = '\0'; 389ca618b22SIngo Weinhold 390ca618b22SIngo Weinhold // load the image 391ca618b22SIngo Weinhold preload_image(path); 392ca618b22SIngo Weinhold } 393ca618b22SIngo Weinhold } 394ca618b22SIngo Weinhold 395ca618b22SIngo Weinhold 39674c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 3970c0fea5dSIngo Weinhold 3980c0fea5dSIngo Weinhold 3990c0fea5dSIngo Weinhold image_id 4000c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 4010c0fea5dSIngo Weinhold { 4020c0fea5dSIngo Weinhold status_t status; 4030c0fea5dSIngo Weinhold image_t *image; 4040c0fea5dSIngo Weinhold 4057486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path); 4067486b72dSIngo Weinhold 4070c0fea5dSIngo Weinhold rld_lock(); 4080c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 4090c0fea5dSIngo Weinhold 410ca618b22SIngo Weinhold preload_images(); 411ca618b22SIngo Weinhold 4120c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 4130c0fea5dSIngo Weinhold 4148d23c440SIngo Weinhold status = load_image(path, B_APP_IMAGE, NULL, NULL, &gProgramImage); 41574c0424aSAxel Dörfler if (status < B_OK) 41674c0424aSAxel Dörfler goto err; 4170c0fea5dSIngo Weinhold 41894830eb2SIngo Weinhold if (gProgramImage->find_undefined_symbol == NULL) 41994830eb2SIngo Weinhold gProgramImage->find_undefined_symbol = find_undefined_symbol_global; 4200c85bd05SIngo Weinhold 42194830eb2SIngo Weinhold status = load_dependencies(gProgramImage); 4220c0fea5dSIngo Weinhold if (status < B_OK) 4230c0fea5dSIngo Weinhold goto err; 4240c85bd05SIngo Weinhold 42547bc6663SIngo Weinhold // Set RTLD_GLOBAL on all libraries including the program. 4260c85bd05SIngo Weinhold // This results in the desired symbol resolution for dlopen()ed libraries. 42794830eb2SIngo Weinhold set_image_flags_recursively(gProgramImage, RTLD_GLOBAL); 4280c0fea5dSIngo Weinhold 42994830eb2SIngo Weinhold status = relocate_dependencies(gProgramImage); 4300c0fea5dSIngo Weinhold if (status < B_OK) 4310c0fea5dSIngo Weinhold goto err; 4320c0fea5dSIngo Weinhold 43394830eb2SIngo Weinhold inject_runtime_loader_api(gProgramImage); 4340c0fea5dSIngo Weinhold 4350c0fea5dSIngo Weinhold remap_images(); 43694830eb2SIngo Weinhold init_dependencies(gProgramImage, true); 4370c0fea5dSIngo Weinhold 4380c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 4390c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 44094830eb2SIngo Weinhold find_symbol_breadth_first(gProgramImage, 441003ebb0eSIngo Weinhold SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image, 442003ebb0eSIngo Weinhold (void**)&gGetEnv); 4430c0fea5dSIngo Weinhold 44494830eb2SIngo Weinhold if (gProgramImage->entry_point == 0) { 4450c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 4460c0fea5dSIngo Weinhold goto err; 4470c0fea5dSIngo Weinhold } 4480c0fea5dSIngo Weinhold 44994830eb2SIngo Weinhold *_entry = (void *)(gProgramImage->entry_point); 4500c0fea5dSIngo Weinhold 4510c0fea5dSIngo Weinhold rld_unlock(); 4527486b72dSIngo Weinhold 45394830eb2SIngo Weinhold gProgramLoaded = true; 4545d0638bfSIngo Weinhold 455ded25be1SIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %" B_PRId32 , path, 45694830eb2SIngo Weinhold *_entry, gProgramImage->id); 4577486b72dSIngo Weinhold 45894830eb2SIngo Weinhold return gProgramImage->id; 4590c0fea5dSIngo Weinhold 4600c0fea5dSIngo Weinhold err: 4617486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); 4627486b72dSIngo Weinhold 46394830eb2SIngo Weinhold delete_image(gProgramImage); 46474c0424aSAxel Dörfler 4654bef3723SAxel Dörfler if (report_errors()) { 4664bef3723SAxel Dörfler // send error message 46794830eb2SIngo Weinhold gErrorMessage.AddInt32("error", status); 46894830eb2SIngo Weinhold gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 4694bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 4704bef3723SAxel Dörfler 4714bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 47294830eb2SIngo Weinhold gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0); 47374c0424aSAxel Dörfler } 47474c0424aSAxel Dörfler _kern_loading_app_failed(status); 4750c0fea5dSIngo Weinhold rld_unlock(); 47674c0424aSAxel Dörfler 4770c0fea5dSIngo Weinhold return status; 4780c0fea5dSIngo Weinhold } 4790c0fea5dSIngo Weinhold 4800c0fea5dSIngo Weinhold 4810c0fea5dSIngo Weinhold image_id 4820c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle) 4830c0fea5dSIngo Weinhold { 4840c0fea5dSIngo Weinhold image_t *image = NULL; 4850c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 4860c0fea5dSIngo Weinhold status_t status; 4870c0fea5dSIngo Weinhold 4880c85bd05SIngo Weinhold if (path == NULL && addOn) 4890c0fea5dSIngo Weinhold return B_BAD_VALUE; 4900c0fea5dSIngo Weinhold 491ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\", %#" B_PRIx32 ", %d)", path, flags, addOn); 4927486b72dSIngo Weinhold 4930c0fea5dSIngo Weinhold rld_lock(); 4940c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 4950c0fea5dSIngo Weinhold 4960c0fea5dSIngo Weinhold // have we already loaded this library? 4970c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 4980c0fea5dSIngo Weinhold if (!addOn) { 4990c85bd05SIngo Weinhold // a NULL path is fine -- it means the global scope shall be opened 5000c85bd05SIngo Weinhold if (path == NULL) { 5010c85bd05SIngo Weinhold *_handle = RLD_GLOBAL_SCOPE; 5020c85bd05SIngo Weinhold rld_unlock(); 5030c85bd05SIngo Weinhold return 0; 5040c85bd05SIngo Weinhold } 5050c85bd05SIngo Weinhold 50694830eb2SIngo Weinhold image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE); 5070c85bd05SIngo Weinhold if (image != NULL && (flags & RTLD_GLOBAL) != 0) 5080c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 5090c85bd05SIngo Weinhold 5100c0fea5dSIngo Weinhold if (image) { 5110c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 5120c0fea5dSIngo Weinhold rld_unlock(); 513ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %" B_PRId32, 514ded25be1SIngo Weinhold path, image->id); 5150c85bd05SIngo Weinhold *_handle = image; 5160c0fea5dSIngo Weinhold return image->id; 5170c0fea5dSIngo Weinhold } 5180c0fea5dSIngo Weinhold } 5190c0fea5dSIngo Weinhold 5208d23c440SIngo Weinhold status = load_image(path, type, NULL, NULL, &image); 5210c0fea5dSIngo Weinhold if (status < B_OK) { 5220c0fea5dSIngo Weinhold rld_unlock(); 5237486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, 5247486b72dSIngo Weinhold strerror(status)); 5250c0fea5dSIngo Weinhold return status; 5260c0fea5dSIngo Weinhold } 5270c0fea5dSIngo Weinhold 5280c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) { 5290c85bd05SIngo Weinhold if (addOn) 5300c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_add_on; 5310c85bd05SIngo Weinhold else 5320c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 5330c85bd05SIngo Weinhold } 5340c85bd05SIngo Weinhold 5350c85bd05SIngo Weinhold status = load_dependencies(image); 5360c0fea5dSIngo Weinhold if (status < B_OK) 5370c0fea5dSIngo Weinhold goto err; 5380c85bd05SIngo Weinhold 5390c85bd05SIngo Weinhold // If specified, set the RTLD_GLOBAL flag recursively on this image and all 5400c85bd05SIngo Weinhold // dependencies. If not specified, we temporarily set 5410c85bd05SIngo Weinhold // RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used 5420c85bd05SIngo Weinhold // for undefined symbol resolution. 5430c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) != 0) 5440c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 5450c85bd05SIngo Weinhold else 5460c85bd05SIngo Weinhold set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 5470c0fea5dSIngo Weinhold 5480c0fea5dSIngo Weinhold status = relocate_dependencies(image); 5490c0fea5dSIngo Weinhold if (status < B_OK) 5500c0fea5dSIngo Weinhold goto err; 5510c0fea5dSIngo Weinhold 5520c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) == 0) 5530c85bd05SIngo Weinhold clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 5540c85bd05SIngo Weinhold 5550c0fea5dSIngo Weinhold remap_images(); 5560c0fea5dSIngo Weinhold init_dependencies(image, true); 5570c0fea5dSIngo Weinhold 5580c0fea5dSIngo Weinhold rld_unlock(); 5597486b72dSIngo Weinhold 560ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %" B_PRId32, path, image->id); 5617486b72dSIngo Weinhold 5620c85bd05SIngo Weinhold *_handle = image; 5630c0fea5dSIngo Weinhold return image->id; 5640c0fea5dSIngo Weinhold 5650c0fea5dSIngo Weinhold err: 5667486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status)); 5677486b72dSIngo Weinhold 56894830eb2SIngo Weinhold dequeue_loaded_image(image); 5690c0fea5dSIngo Weinhold delete_image(image); 5700c0fea5dSIngo Weinhold rld_unlock(); 5710c0fea5dSIngo Weinhold return status; 5720c0fea5dSIngo Weinhold } 5730c0fea5dSIngo Weinhold 5740c0fea5dSIngo Weinhold 5750c0fea5dSIngo Weinhold status_t 5760c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn) 5770c0fea5dSIngo Weinhold { 5780c0fea5dSIngo Weinhold image_t *image; 5790c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 5800c0fea5dSIngo Weinhold 5810c85bd05SIngo Weinhold if (handle == NULL && imageID < 0) 5820c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 5830c0fea5dSIngo Weinhold 5840c85bd05SIngo Weinhold if (handle == RLD_GLOBAL_SCOPE) 5850c85bd05SIngo Weinhold return B_OK; 5860c85bd05SIngo Weinhold 5870c0fea5dSIngo Weinhold rld_lock(); 5880c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 5890c0fea5dSIngo Weinhold 59094830eb2SIngo Weinhold if (gInvalidImageIDs) { 5919a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 5929a6072a3SAxel Dörfler update_image_ids(); 5939a6072a3SAxel Dörfler } 5949a6072a3SAxel Dörfler 5950c0fea5dSIngo Weinhold // we only check images that have been already initialized 5960c0fea5dSIngo Weinhold 597df30098dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 598df30098dSIngo Weinhold 5990c85bd05SIngo Weinhold if (handle != NULL) { 6000c85bd05SIngo Weinhold image = (image_t*)handle; 6010c85bd05SIngo Weinhold put_image(image); 602df30098dSIngo Weinhold status = B_OK; 6030c85bd05SIngo Weinhold } else { 60494830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, true); 60594830eb2SIngo Weinhold if (image != NULL) { 6060c0fea5dSIngo Weinhold // unload image 6070c0fea5dSIngo Weinhold if (type == image->type) { 6080c0fea5dSIngo Weinhold put_image(image); 6090c0fea5dSIngo Weinhold status = B_OK; 6100c0fea5dSIngo Weinhold } else 6110c0fea5dSIngo Weinhold status = B_BAD_VALUE; 6120c0fea5dSIngo Weinhold } 6130c85bd05SIngo Weinhold } 6140c0fea5dSIngo Weinhold 6150c0fea5dSIngo Weinhold if (status == B_OK) { 61694830eb2SIngo Weinhold while ((image = get_disposable_images().head) != NULL) { 617d64f6189SIngo Weinhold // Call the exit hooks that live in this image. 618d64f6189SIngo Weinhold // Note: With the Itanium ABI this shouldn't really be done this 619d64f6189SIngo Weinhold // way anymore, since global destructors are registered via 620d64f6189SIngo Weinhold // __cxa_atexit() (the ones that are registered dynamically) and the 621d64f6189SIngo Weinhold // termination routine should call __cxa_finalize() for the image. 622d64f6189SIngo Weinhold // The reason why we still do it is that hooks registered with 623d64f6189SIngo Weinhold // atexit() aren't associated with the image. We could find out 624d64f6189SIngo Weinhold // there which image the hooks lives in and register it 625d64f6189SIngo Weinhold // respectively, but since that would be done always, that's 626d64f6189SIngo Weinhold // probably more expensive than calling 627d64f6189SIngo Weinhold // call_atexit_hooks_for_range() only here, which happens only when 628d64f6189SIngo Weinhold // libraries are unloaded dynamically. 6298c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 6308c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 6313be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize); 6328c2a9d74SMichael Lotz } 6338c2a9d74SMichael Lotz 63410b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 63510b4b5d1SIngo Weinhold 6360c0fea5dSIngo Weinhold if (image->term_routine) 6370c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 6380c0fea5dSIngo Weinhold 63944c0c4d3SPawel Dziepak TLSBlockTemplates::Get().Unregister(image->dso_tls_id); 64044c0c4d3SPawel Dziepak 64194830eb2SIngo Weinhold dequeue_disposable_image(image); 6420c0fea5dSIngo Weinhold unmap_image(image); 6430c0fea5dSIngo Weinhold 64410b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 64510b4b5d1SIngo Weinhold 6460c0fea5dSIngo Weinhold delete_image(image); 6470c0fea5dSIngo Weinhold } 6480c0fea5dSIngo Weinhold } 6490c0fea5dSIngo Weinhold 6500c0fea5dSIngo Weinhold rld_unlock(); 6510c0fea5dSIngo Weinhold return status; 6520c0fea5dSIngo Weinhold } 6530c0fea5dSIngo Weinhold 6540c0fea5dSIngo Weinhold 6550c0fea5dSIngo Weinhold status_t 6569a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, 6579a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location) 6580c0fea5dSIngo Weinhold { 6590c0fea5dSIngo Weinhold int32 count = 0, j; 6600c0fea5dSIngo Weinhold uint32 i; 6610c0fea5dSIngo Weinhold image_t *image; 6620c0fea5dSIngo Weinhold 6630c0fea5dSIngo Weinhold rld_lock(); 6640c0fea5dSIngo Weinhold 6650c0fea5dSIngo Weinhold // get the image from those who have been already initialized 66694830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false); 6670c0fea5dSIngo Weinhold if (image == NULL) { 6680c0fea5dSIngo Weinhold rld_unlock(); 6690c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 6700c0fea5dSIngo Weinhold } 6710c0fea5dSIngo Weinhold 6720c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 6730c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 6740c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 675e3ac2588SAlex Smith elf_sym *symbol = &image->syms[j]; 6760c0fea5dSIngo Weinhold 6770c0fea5dSIngo Weinhold if (count == num) { 67810b4b5d1SIngo Weinhold const char* symbolName = SYMNAME(image, symbol); 67910b4b5d1SIngo Weinhold strlcpy(nameBuffer, symbolName, *_nameLength); 68010b4b5d1SIngo Weinhold *_nameLength = strlen(symbolName); 6810c0fea5dSIngo Weinhold 68210b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value 68310b4b5d1SIngo Weinhold + image->regions[0].delta); 68410b4b5d1SIngo Weinhold int32 type; 685e3ac2588SAlex Smith if (symbol->Type() == STT_FUNC) 68610b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 687e3ac2588SAlex Smith else if (symbol->Type() == STT_OBJECT) 68810b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 6890c0fea5dSIngo Weinhold else 69010b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_ANY; 69110b4b5d1SIngo Weinhold // TODO: check with the return types of that BeOS function 6920c0fea5dSIngo Weinhold 69310b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &type); 69410b4b5d1SIngo Weinhold 69510b4b5d1SIngo Weinhold if (_type != NULL) 69610b4b5d1SIngo Weinhold *_type = type; 6970c0fea5dSIngo Weinhold if (_location != NULL) 69810b4b5d1SIngo Weinhold *_location = location; 6990c0fea5dSIngo Weinhold goto out; 7000c0fea5dSIngo Weinhold } 7010c0fea5dSIngo Weinhold count++; 7020c0fea5dSIngo Weinhold } 7030c0fea5dSIngo Weinhold } 7040c0fea5dSIngo Weinhold out: 7050c0fea5dSIngo Weinhold rld_unlock(); 7060c0fea5dSIngo Weinhold 7070c0fea5dSIngo Weinhold if (num != count) 7080c0fea5dSIngo Weinhold return B_BAD_INDEX; 7090c0fea5dSIngo Weinhold 7100c0fea5dSIngo Weinhold return B_OK; 7110c0fea5dSIngo Weinhold } 7120c0fea5dSIngo Weinhold 7130c0fea5dSIngo Weinhold 7140c0fea5dSIngo Weinhold status_t 71543e7b1c2SHamish Morrison get_nearest_symbol_at_address(void* address, image_id* _imageID, 716*ebdc1d48SMichael Lotz char** _imagePath, char** _imageName, char** _symbolName, int32* _type, 717*ebdc1d48SMichael Lotz void** _location, bool* _exactMatch) 718b6455c08SAxel Dörfler { 719b6455c08SAxel Dörfler rld_lock(); 720b6455c08SAxel Dörfler 721b6455c08SAxel Dörfler image_t* image = find_loaded_image_by_address((addr_t)address); 722b6455c08SAxel Dörfler if (image == NULL) { 723b6455c08SAxel Dörfler rld_unlock(); 724b6455c08SAxel Dörfler return B_BAD_VALUE; 725b6455c08SAxel Dörfler } 726b6455c08SAxel Dörfler 727*ebdc1d48SMichael Lotz bool exactMatch = false; 728e3ac2588SAlex Smith elf_sym* foundSymbol = NULL; 72943e7b1c2SHamish Morrison addr_t foundLocation = (addr_t)NULL; 73043e7b1c2SHamish Morrison 731*ebdc1d48SMichael Lotz for (uint32 i = 0; i < HASHTABSIZE(image) && !exactMatch; i++) { 732b6455c08SAxel Dörfler for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF; 733b6455c08SAxel Dörfler j = HASHCHAINS(image)[j]) { 734e3ac2588SAlex Smith elf_sym *symbol = &image->syms[j]; 735b6455c08SAxel Dörfler addr_t location = symbol->st_value + image->regions[0].delta; 736b6455c08SAxel Dörfler 73743e7b1c2SHamish Morrison if (location <= (addr_t)address && location >= foundLocation) { 73843e7b1c2SHamish Morrison foundSymbol = symbol; 73943e7b1c2SHamish Morrison foundLocation = location; 740b6455c08SAxel Dörfler 74143e7b1c2SHamish Morrison // jump out if we have an exact match 742*ebdc1d48SMichael Lotz if (location + symbol->st_size > (addr_t)address) { 743*ebdc1d48SMichael Lotz exactMatch = true; 74443e7b1c2SHamish Morrison break; 74543e7b1c2SHamish Morrison } 74643e7b1c2SHamish Morrison } 74743e7b1c2SHamish Morrison } 74843e7b1c2SHamish Morrison } 749b6455c08SAxel Dörfler 750b6455c08SAxel Dörfler if (_imageID != NULL) 751b6455c08SAxel Dörfler *_imageID = image->id; 75243e7b1c2SHamish Morrison if (_imagePath != NULL) 75343e7b1c2SHamish Morrison *_imagePath = image->path; 754*ebdc1d48SMichael Lotz if (_imageName != NULL) 755*ebdc1d48SMichael Lotz *_imageName = image->name; 756*ebdc1d48SMichael Lotz if (_exactMatch != NULL) 757*ebdc1d48SMichael Lotz *_exactMatch = exactMatch; 75843e7b1c2SHamish Morrison 75943e7b1c2SHamish Morrison if (foundSymbol != NULL) { 76043e7b1c2SHamish Morrison *_symbolName = SYMNAME(image, foundSymbol); 76143e7b1c2SHamish Morrison 76243e7b1c2SHamish Morrison if (_type != NULL) { 763e3ac2588SAlex Smith if (foundSymbol->Type() == STT_FUNC) 76443e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_TEXT; 765e3ac2588SAlex Smith else if (foundSymbol->Type() == STT_OBJECT) 76643e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_DATA; 76743e7b1c2SHamish Morrison else 76843e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_ANY; 76943e7b1c2SHamish Morrison // TODO: check with the return types of that BeOS function 77043e7b1c2SHamish Morrison } 77143e7b1c2SHamish Morrison 772b6455c08SAxel Dörfler if (_location != NULL) 77343e7b1c2SHamish Morrison *_location = (void*)foundLocation; 77443e7b1c2SHamish Morrison } else { 77543e7b1c2SHamish Morrison *_symbolName = NULL; 77643e7b1c2SHamish Morrison if (_location != NULL) 77743e7b1c2SHamish Morrison *_location = NULL; 77843e7b1c2SHamish Morrison } 779b6455c08SAxel Dörfler 780b6455c08SAxel Dörfler rld_unlock(); 781b6455c08SAxel Dörfler return B_OK; 782b6455c08SAxel Dörfler } 783b6455c08SAxel Dörfler 784b6455c08SAxel Dörfler 785b6455c08SAxel Dörfler status_t 7869a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType, 78780ece785SIngo Weinhold bool recursive, image_id *_inImage, void **_location) 7880c0fea5dSIngo Weinhold { 7890c0fea5dSIngo Weinhold status_t status = B_OK; 7900c0fea5dSIngo Weinhold image_t *image; 7910c0fea5dSIngo Weinhold 7920c0fea5dSIngo Weinhold if (imageID < B_OK) 7930c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 7940c0fea5dSIngo Weinhold if (symbolName == NULL) 7950c0fea5dSIngo Weinhold return B_BAD_VALUE; 7960c0fea5dSIngo Weinhold 7970c0fea5dSIngo Weinhold rld_lock(); 7980c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 7990c0fea5dSIngo Weinhold 8000c0fea5dSIngo Weinhold // get the image from those who have been already initialized 80194830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false); 80280ece785SIngo Weinhold if (image != NULL) { 80380ece785SIngo Weinhold if (recursive) { 80480ece785SIngo Weinhold // breadth-first search in the given image and its dependencies 805003ebb0eSIngo Weinhold status = find_symbol_breadth_first(image, 806003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 807003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 80880ece785SIngo Weinhold &image, _location); 809003ebb0eSIngo Weinhold } else { 810003ebb0eSIngo Weinhold status = find_symbol(image, 811003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 812003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 813003ebb0eSIngo Weinhold _location); 814003ebb0eSIngo Weinhold } 81580ece785SIngo Weinhold 81680ece785SIngo Weinhold if (status == B_OK && _inImage != NULL) 81780ece785SIngo Weinhold *_inImage = image->id; 81880ece785SIngo Weinhold } else 8190c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 8200c0fea5dSIngo Weinhold 8210c0fea5dSIngo Weinhold rld_unlock(); 8220c0fea5dSIngo Weinhold return status; 8230c0fea5dSIngo Weinhold } 8240c0fea5dSIngo Weinhold 8250c0fea5dSIngo Weinhold 8260c0fea5dSIngo Weinhold status_t 8270c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName, 8280c85bd05SIngo Weinhold void **_location) 8290c85bd05SIngo Weinhold { 8300c85bd05SIngo Weinhold status_t status = B_ENTRY_NOT_FOUND; 8310c85bd05SIngo Weinhold 8320c85bd05SIngo Weinhold if (symbolName == NULL) 8330c85bd05SIngo Weinhold return B_BAD_VALUE; 8340c85bd05SIngo Weinhold 8350c85bd05SIngo Weinhold rld_lock(); 8360c85bd05SIngo Weinhold // for now, just do stupid simple global locking 8370c85bd05SIngo Weinhold 8380c85bd05SIngo Weinhold if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) { 8390c85bd05SIngo Weinhold // look in the default scope 8400c85bd05SIngo Weinhold image_t* image; 841e3ac2588SAlex Smith elf_sym* symbol = find_undefined_symbol_global(gProgramImage, 84294830eb2SIngo Weinhold gProgramImage, 843003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 844003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 845003ebb0eSIngo Weinhold &image); 8460c85bd05SIngo Weinhold if (symbol != NULL) { 8470c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value + image->regions[0].delta); 848e3ac2588SAlex Smith int32 symbolType = symbol->Type() == STT_FUNC 8490c85bd05SIngo Weinhold ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 8500c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, &symbolType); 8510c85bd05SIngo Weinhold status = B_OK; 8520c85bd05SIngo Weinhold } 8530c85bd05SIngo Weinhold } else if (handle == RTLD_NEXT) { 8540c85bd05SIngo Weinhold // Look in the default scope, but also in the dependencies of the 8550c85bd05SIngo Weinhold // calling image. Return the next after the caller symbol. 8560c85bd05SIngo Weinhold 857a2dad9e1SIngo Weinhold // First of all, find the caller image. 85894830eb2SIngo Weinhold image_t* callerImage = get_loaded_images().head; 8590c85bd05SIngo Weinhold for (; callerImage != NULL; callerImage = callerImage->next) { 8600c85bd05SIngo Weinhold elf_region_t& text = callerImage->regions[0]; 861a2dad9e1SIngo Weinhold if ((addr_t)caller >= text.vmstart 862a2dad9e1SIngo Weinhold && (addr_t)caller < text.vmstart + text.vmsize) { 863a2dad9e1SIngo Weinhold // found the image 8640c85bd05SIngo Weinhold break; 8650c85bd05SIngo Weinhold } 8660c85bd05SIngo Weinhold } 8670c85bd05SIngo Weinhold 868a2dad9e1SIngo Weinhold if (callerImage != NULL) { 8690c85bd05SIngo Weinhold // found the caller -- now search the global scope until we find 8700c85bd05SIngo Weinhold // the next symbol 871a2dad9e1SIngo Weinhold bool hitCallerImage = false; 8720c85bd05SIngo Weinhold set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 8730c85bd05SIngo Weinhold 874e3ac2588SAlex Smith elf_sym* candidateSymbol = NULL; 87525dc253dSIngo Weinhold image_t* candidateImage = NULL; 87625dc253dSIngo Weinhold 87794830eb2SIngo Weinhold image_t* image = get_loaded_images().head; 8780c85bd05SIngo Weinhold for (; image != NULL; image = image->next) { 879a2dad9e1SIngo Weinhold // skip the caller image 880a2dad9e1SIngo Weinhold if (image == callerImage) { 881a2dad9e1SIngo Weinhold hitCallerImage = true; 882a2dad9e1SIngo Weinhold continue; 883a2dad9e1SIngo Weinhold } 884a2dad9e1SIngo Weinhold 885a2dad9e1SIngo Weinhold // skip all images up to the caller image; also skip add-on 886a2dad9e1SIngo Weinhold // images and those not marked above for resolution 887a2dad9e1SIngo Weinhold if (!hitCallerImage || image->type == B_ADD_ON_IMAGE 8880c85bd05SIngo Weinhold || (image->flags 889a2dad9e1SIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) { 8900c85bd05SIngo Weinhold continue; 8910c85bd05SIngo Weinhold } 8920c85bd05SIngo Weinhold 893e3ac2588SAlex Smith elf_sym *symbol = find_symbol(image, 894003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL, 895003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION)); 8960c85bd05SIngo Weinhold if (symbol == NULL) 8970c85bd05SIngo Weinhold continue; 8980c85bd05SIngo Weinhold 89925dc253dSIngo Weinhold // found a symbol 900e3ac2588SAlex Smith bool isWeak = symbol->Bind() == STB_WEAK; 90125dc253dSIngo Weinhold if (candidateImage == NULL || !isWeak) { 90225dc253dSIngo Weinhold candidateSymbol = symbol; 90325dc253dSIngo Weinhold candidateImage = image; 90425dc253dSIngo Weinhold 90525dc253dSIngo Weinhold if (!isWeak) 90625dc253dSIngo Weinhold break; 90725dc253dSIngo Weinhold } 90825dc253dSIngo Weinhold 90925dc253dSIngo Weinhold // symbol is weak, so we need to continue 91025dc253dSIngo Weinhold } 91125dc253dSIngo Weinhold 91225dc253dSIngo Weinhold if (candidateSymbol != NULL) { 913a2dad9e1SIngo Weinhold // found the symbol 91425dc253dSIngo Weinhold *_location = (void*)(candidateSymbol->st_value 91525dc253dSIngo Weinhold + candidateImage->regions[0].delta); 9160c85bd05SIngo Weinhold int32 symbolType = B_SYMBOL_TYPE_TEXT; 91725dc253dSIngo Weinhold patch_defined_symbol(candidateImage, symbolName, _location, 9180c85bd05SIngo Weinhold &symbolType); 9190c85bd05SIngo Weinhold status = B_OK; 9200c85bd05SIngo Weinhold } 9210c85bd05SIngo Weinhold 9220c85bd05SIngo Weinhold clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 9230c85bd05SIngo Weinhold } 9240c85bd05SIngo Weinhold } else { 9250c85bd05SIngo Weinhold // breadth-first search in the given image and its dependencies 9260c85bd05SIngo Weinhold image_t* inImage; 927003ebb0eSIngo Weinhold status = find_symbol_breadth_first((image_t*)handle, 928003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 929003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 930003ebb0eSIngo Weinhold &inImage, _location); 9310c85bd05SIngo Weinhold } 9320c85bd05SIngo Weinhold 9330c85bd05SIngo Weinhold rld_unlock(); 9340c85bd05SIngo Weinhold return status; 9350c85bd05SIngo Weinhold } 9360c85bd05SIngo Weinhold 9370c85bd05SIngo Weinhold 9380c85bd05SIngo Weinhold status_t 9390c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 9400c0fea5dSIngo Weinhold { 9410c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 942e3ac2588SAlex Smith elf_dyn *dynamicSection; 9430c0fea5dSIngo Weinhold image_t *image; 9440c0fea5dSIngo Weinhold 9450c0fea5dSIngo Weinhold if (_name == NULL) 9460c0fea5dSIngo Weinhold return B_BAD_VALUE; 9470c0fea5dSIngo Weinhold 9480c0fea5dSIngo Weinhold rld_lock(); 9490c0fea5dSIngo Weinhold 95094830eb2SIngo Weinhold image = find_loaded_image_by_id(id, false); 9510c0fea5dSIngo Weinhold if (image == NULL) { 9520c0fea5dSIngo Weinhold rld_unlock(); 9530c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 9540c0fea5dSIngo Weinhold } 9550c0fea5dSIngo Weinhold 956e3ac2588SAlex Smith dynamicSection = (elf_dyn *)image->dynamic_ptr; 9570c0fea5dSIngo Weinhold if (dynamicSection == NULL || image->num_needed <= searchIndex) { 9580c0fea5dSIngo Weinhold rld_unlock(); 9590c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 9600c0fea5dSIngo Weinhold } 9610c0fea5dSIngo Weinhold 9620c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 9630c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 9640c0fea5dSIngo Weinhold continue; 9650c0fea5dSIngo Weinhold 9660c0fea5dSIngo Weinhold if (j++ == searchIndex) { 9670c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 9680c0fea5dSIngo Weinhold 9690c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 9700c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 9710c0fea5dSIngo Weinhold rld_unlock(); 9720c0fea5dSIngo Weinhold return B_OK; 9730c0fea5dSIngo Weinhold } 9740c0fea5dSIngo Weinhold } 9750c0fea5dSIngo Weinhold 9760c0fea5dSIngo Weinhold rld_unlock(); 9770c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 9780c0fea5dSIngo Weinhold } 9790c0fea5dSIngo Weinhold 9800c0fea5dSIngo Weinhold 98174c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 9820c0fea5dSIngo Weinhold 9830c0fea5dSIngo Weinhold 9849a6072a3SAxel Dörfler /*! Read and verify the ELF header */ 9850c0fea5dSIngo Weinhold status_t 986e3ac2588SAlex Smith elf_verify_header(void *header, size_t length) 9870c0fea5dSIngo Weinhold { 9880c0fea5dSIngo Weinhold int32 programSize, sectionSize; 9890c0fea5dSIngo Weinhold 990e3ac2588SAlex Smith if (length < sizeof(elf_ehdr)) 9910c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 9920c0fea5dSIngo Weinhold 993e3ac2588SAlex Smith return parse_elf_header((elf_ehdr *)header, &programSize, §ionSize); 9940c0fea5dSIngo Weinhold } 9950c0fea5dSIngo Weinhold 9960c0fea5dSIngo Weinhold 9970c0fea5dSIngo Weinhold void 9980c0fea5dSIngo Weinhold terminate_program(void) 9990c0fea5dSIngo Weinhold { 10000c0fea5dSIngo Weinhold image_t **termList; 10010c0fea5dSIngo Weinhold ssize_t count, i; 10020c0fea5dSIngo Weinhold 1003aa3507feSIngo Weinhold count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED); 10040c0fea5dSIngo Weinhold if (count < B_OK) 10050c0fea5dSIngo Weinhold return; 10060c0fea5dSIngo Weinhold 100794830eb2SIngo Weinhold if (gInvalidImageIDs) { 10089a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 10099a6072a3SAxel Dörfler update_image_ids(); 10109a6072a3SAxel Dörfler } 10119a6072a3SAxel Dörfler 10120c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 10130c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 10140c0fea5dSIngo Weinhold image_t *image = termList[i]; 10150c0fea5dSIngo Weinhold 10160c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 10170c0fea5dSIngo Weinhold 101810b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 101910b4b5d1SIngo Weinhold 10200c0fea5dSIngo Weinhold if (image->term_routine) 10210c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 102210b4b5d1SIngo Weinhold 102310b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 10240c0fea5dSIngo Weinhold } 10250c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 10260c0fea5dSIngo Weinhold 10270c0fea5dSIngo Weinhold free(termList); 10280c0fea5dSIngo Weinhold } 10290c0fea5dSIngo Weinhold 10300c0fea5dSIngo Weinhold 10310c0fea5dSIngo Weinhold void 10320c0fea5dSIngo Weinhold rldelf_init(void) 10330c0fea5dSIngo Weinhold { 103494830eb2SIngo Weinhold init_add_ons(); 103594830eb2SIngo Weinhold 10360c0fea5dSIngo Weinhold // create the debug area 10370c0fea5dSIngo Weinhold { 1038e3ac2588SAlex Smith size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 10390c0fea5dSIngo Weinhold 10400c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 10410c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 10429f3bd497SPawel Dziepak (void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK, 10430c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 10440c0fea5dSIngo Weinhold if (areaID < B_OK) { 10450c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 10460c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 10470c0fea5dSIngo Weinhold } 10480c0fea5dSIngo Weinhold 104994830eb2SIngo Weinhold area->loaded_images = &get_loaded_images(); 10500c0fea5dSIngo Weinhold } 105174c0424aSAxel Dörfler 105274c0424aSAxel Dörfler // initialize error message if needed 10534bef3723SAxel Dörfler if (report_errors()) { 105474c0424aSAxel Dörfler void *buffer = malloc(1024); 105574c0424aSAxel Dörfler if (buffer == NULL) 105674c0424aSAxel Dörfler return; 105774c0424aSAxel Dörfler 105894830eb2SIngo Weinhold gErrorMessage.SetTo(buffer, 1024, 'Rler'); 105974c0424aSAxel Dörfler } 10600c0fea5dSIngo Weinhold } 10611873b4b3SIngo Weinhold 10621873b4b3SIngo Weinhold 10631873b4b3SIngo Weinhold status_t 10649a6072a3SAxel Dörfler elf_reinit_after_fork(void) 10651873b4b3SIngo Weinhold { 1066f7127458SIngo Weinhold recursive_lock_init(&sLock, kLockName); 10671873b4b3SIngo Weinhold 10689a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and 1069cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork() 1070cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one 10719a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different. 107294830eb2SIngo Weinhold gInvalidImageIDs = true; 1073cbc456deSIngo Weinhold 10741873b4b3SIngo Weinhold return B_OK; 10751873b4b3SIngo Weinhold } 1076