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" 2994830eb2SIngo Weinhold #include "elf_versioning.h" 3094830eb2SIngo Weinhold #include "errors.h" 3194830eb2SIngo Weinhold #include "images.h" 320c0fea5dSIngo Weinhold 330c0fea5dSIngo Weinhold 3410b4b5d1SIngo Weinhold // TODO: implement better locking strategy 3510b4b5d1SIngo Weinhold // TODO: implement lazy binding 360c0fea5dSIngo Weinhold 370c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen()) 380c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE ((void*)-2l) 390c85bd05SIngo Weinhold 40f7127458SIngo Weinhold static const char* const kLockName = "runtime loader"; 41f7127458SIngo Weinhold 420c0fea5dSIngo Weinhold 430c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 440c0fea5dSIngo Weinhold 4594830eb2SIngo Weinhold bool gProgramLoaded = false; 4694830eb2SIngo Weinhold image_t* gProgramImage; 47003ebb0eSIngo Weinhold 48ca618b22SIngo Weinhold static image_t** sPreloadedImages = NULL; 49ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0; 500c0fea5dSIngo Weinhold 51f7127458SIngo Weinhold static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName); 520c0fea5dSIngo Weinhold 537486b72dSIngo Weinhold 54f2bb2575SIngo Weinhold static inline void 550c0fea5dSIngo Weinhold rld_lock() 560c0fea5dSIngo Weinhold { 57f2bb2575SIngo Weinhold recursive_lock_lock(&sLock); 580c0fea5dSIngo Weinhold } 59f2bb2575SIngo Weinhold 60f2bb2575SIngo Weinhold 61f2bb2575SIngo Weinhold static inline void 62f2bb2575SIngo Weinhold rld_unlock() 63f2bb2575SIngo Weinhold { 64f2bb2575SIngo Weinhold recursive_lock_unlock(&sLock); 650c0fea5dSIngo Weinhold } 660c0fea5dSIngo Weinhold 670c0fea5dSIngo Weinhold 680c0fea5dSIngo Weinhold static const char * 690c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 700c0fea5dSIngo Weinhold { 710c0fea5dSIngo Weinhold int i; 72e3ac2588SAlex Smith elf_dyn *d = (elf_dyn *)image->dynamic_ptr; 730c0fea5dSIngo Weinhold 740c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 750c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 760c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 770c0fea5dSIngo Weinhold } 780c0fea5dSIngo Weinhold 790c0fea5dSIngo Weinhold return NULL; 800c0fea5dSIngo Weinhold } 810c0fea5dSIngo Weinhold 820c0fea5dSIngo Weinhold 830c0fea5dSIngo Weinhold static status_t 840c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image) 850c0fea5dSIngo Weinhold { 86e3ac2588SAlex Smith elf_dyn *d = (elf_dyn *)image->dynamic_ptr; 874bef3723SAxel Dörfler bool reportErrors = report_errors(); 8874c0424aSAxel Dörfler status_t status = B_OK; 890c0fea5dSIngo Weinhold uint32 i, j; 900c0fea5dSIngo Weinhold const char *rpath; 910c0fea5dSIngo Weinhold 920c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 930c0fea5dSIngo Weinhold return B_OK; 940c0fea5dSIngo Weinhold 950c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 960c0fea5dSIngo Weinhold 970c0fea5dSIngo Weinhold if (image->num_needed == 0) 980c0fea5dSIngo Weinhold return B_OK; 990c0fea5dSIngo Weinhold 1007486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name, 1017486b72dSIngo Weinhold image->id); 1027486b72dSIngo Weinhold 1030c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 1040c0fea5dSIngo Weinhold if (image->needed == NULL) { 105c533f813SIngo Weinhold FATAL("%s: Failed to allocate needed struct\n", image->path); 1067486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory", 1077486b72dSIngo Weinhold image->name, image->id); 1080c0fea5dSIngo Weinhold return B_NO_MEMORY; 1090c0fea5dSIngo Weinhold } 1100c0fea5dSIngo Weinhold 1110c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 1120c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 1130c0fea5dSIngo Weinhold 1140c0fea5dSIngo Weinhold for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { 1150c0fea5dSIngo Weinhold switch (d[i].d_tag) { 1160c0fea5dSIngo Weinhold case DT_NEEDED: 11774c0424aSAxel Dörfler { 11874c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 11974c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 1200c0fea5dSIngo Weinhold 12194830eb2SIngo Weinhold status_t loadStatus = load_image(name, B_LIBRARY_IMAGE, 12274c0424aSAxel Dörfler rpath, &image->needed[j]); 12374c0424aSAxel Dörfler if (loadStatus < B_OK) { 12474c0424aSAxel Dörfler status = loadStatus; 12574c0424aSAxel Dörfler // correct error code in case the file could not been found 12674c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 12774c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 12874c0424aSAxel Dörfler 12974c0424aSAxel Dörfler if (reportErrors) 13094830eb2SIngo Weinhold gErrorMessage.AddString("missing library", name); 13174c0424aSAxel Dörfler } 13274c0424aSAxel Dörfler 13374c0424aSAxel Dörfler // Collect all missing libraries in case we report back 1347486b72dSIngo Weinhold if (!reportErrors) { 1357486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 1367486b72dSIngo Weinhold "failed: %s", image->name, image->id, 1377486b72dSIngo Weinhold strerror(status)); 1380c0fea5dSIngo Weinhold return status; 13974c0424aSAxel Dörfler } 1407486b72dSIngo Weinhold } 1410c0fea5dSIngo Weinhold 1420c0fea5dSIngo Weinhold j += 1; 1430c0fea5dSIngo Weinhold break; 14474c0424aSAxel Dörfler } 1450c0fea5dSIngo Weinhold 1460c0fea5dSIngo Weinhold default: 1470c0fea5dSIngo Weinhold // ignore any other tag 1480c0fea5dSIngo Weinhold continue; 1490c0fea5dSIngo Weinhold } 1500c0fea5dSIngo Weinhold } 1510c0fea5dSIngo Weinhold 1527486b72dSIngo Weinhold if (status < B_OK) { 1537486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 1547486b72dSIngo Weinhold "failed: %s", image->name, image->id, 1557486b72dSIngo Weinhold strerror(status)); 15674c0424aSAxel Dörfler return status; 1577486b72dSIngo Weinhold } 15874c0424aSAxel Dörfler 1590c0fea5dSIngo Weinhold if (j != image->num_needed) { 1600c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 1617486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 1627486b72dSIngo Weinhold "failed: internal error", image->name, image->id); 1630c0fea5dSIngo Weinhold return B_ERROR; 1640c0fea5dSIngo Weinhold } 1650c0fea5dSIngo Weinhold 1667486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name, 1677486b72dSIngo Weinhold image->id); 1687486b72dSIngo Weinhold 1690c0fea5dSIngo Weinhold return B_OK; 1700c0fea5dSIngo Weinhold } 1710c0fea5dSIngo Weinhold 1720c0fea5dSIngo Weinhold 1730c85bd05SIngo Weinhold static status_t 1740c85bd05SIngo Weinhold load_dependencies(image_t* image) 1750c85bd05SIngo Weinhold { 176003ebb0eSIngo Weinhold // load dependencies (breadth-first) 1770c85bd05SIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 1780c85bd05SIngo Weinhold otherImage = otherImage->next) { 1790c85bd05SIngo Weinhold status_t status = load_immediate_dependencies(otherImage); 1800c85bd05SIngo Weinhold if (status != B_OK) 1810c85bd05SIngo Weinhold return status; 1820c85bd05SIngo Weinhold } 1830c85bd05SIngo Weinhold 184003ebb0eSIngo Weinhold // Check the needed versions for the given image and all newly loaded 185003ebb0eSIngo Weinhold // dependencies. 186003ebb0eSIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 187003ebb0eSIngo Weinhold otherImage = otherImage->next) { 188003ebb0eSIngo Weinhold status_t status = check_needed_image_versions(otherImage); 189003ebb0eSIngo Weinhold if (status != B_OK) 190003ebb0eSIngo Weinhold return status; 191003ebb0eSIngo Weinhold } 192003ebb0eSIngo Weinhold 1930c85bd05SIngo Weinhold return B_OK; 1940c85bd05SIngo Weinhold } 1950c85bd05SIngo Weinhold 1960c85bd05SIngo Weinhold 19794830eb2SIngo Weinhold static status_t 19894830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 1990c0fea5dSIngo Weinhold { 20025dc253dSIngo Weinhold SymbolLookupCache cache(image); 20125dc253dSIngo Weinhold 20225dc253dSIngo Weinhold status_t status = arch_relocate_image(rootImage, image, &cache); 20394830eb2SIngo Weinhold if (status < B_OK) { 204c533f813SIngo Weinhold FATAL("%s: Troubles relocating: %s\n", image->path, strerror(status)); 20594830eb2SIngo Weinhold return status; 2060c0fea5dSIngo Weinhold } 2070c0fea5dSIngo Weinhold 20894830eb2SIngo Weinhold _kern_image_relocated(image->id); 20994830eb2SIngo Weinhold image_event(image, IMAGE_EVENT_RELOCATED); 21094830eb2SIngo Weinhold return B_OK; 2110c0fea5dSIngo Weinhold } 2120c0fea5dSIngo Weinhold 2130c0fea5dSIngo Weinhold 2140c0fea5dSIngo Weinhold static status_t 2150c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 2160c0fea5dSIngo Weinhold { 217ca618b22SIngo Weinhold // get the images that still have to be relocated 218ca618b22SIngo Weinhold image_t **list; 219ca618b22SIngo Weinhold ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 2200c0fea5dSIngo Weinhold if (count < B_OK) 2210c0fea5dSIngo Weinhold return count; 2220c0fea5dSIngo Weinhold 2230c85bd05SIngo Weinhold // relocate 224ca618b22SIngo Weinhold for (ssize_t i = 0; i < count; i++) { 22546f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 2260c85bd05SIngo Weinhold if (status < B_OK) { 2270c85bd05SIngo Weinhold free(list); 2280c0fea5dSIngo Weinhold return status; 2290c0fea5dSIngo Weinhold } 2300c85bd05SIngo Weinhold } 2310c0fea5dSIngo Weinhold 2320c0fea5dSIngo Weinhold free(list); 2330c0fea5dSIngo Weinhold return B_OK; 2340c0fea5dSIngo Weinhold } 2350c0fea5dSIngo Weinhold 2360c0fea5dSIngo Weinhold 2370c0fea5dSIngo Weinhold static void 2380c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 2390c0fea5dSIngo Weinhold { 2400c0fea5dSIngo Weinhold image_t **initList; 2410c0fea5dSIngo Weinhold ssize_t count, i; 2420c0fea5dSIngo Weinhold 2430c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 2440c0fea5dSIngo Weinhold if (count <= 0) 2450c0fea5dSIngo Weinhold return; 2460c0fea5dSIngo Weinhold 2470c0fea5dSIngo Weinhold if (!initHead) { 2480c0fea5dSIngo Weinhold // this removes the "calling" image 2490c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 2500c0fea5dSIngo Weinhold initList[--count] = NULL; 2510c0fea5dSIngo Weinhold } 2520c0fea5dSIngo Weinhold 2530c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 2540c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 2550c0fea5dSIngo Weinhold image = initList[i]; 2560c0fea5dSIngo Weinhold 2570c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 2580c0fea5dSIngo Weinhold 259dd76bc97SIngo Weinhold if (image->init_routine != 0) 2600c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 26110b4b5d1SIngo Weinhold 26210b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_INITIALIZED); 2630c0fea5dSIngo Weinhold } 2640c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 2650c0fea5dSIngo Weinhold 2660c0fea5dSIngo Weinhold free(initList); 2670c0fea5dSIngo Weinhold } 2680c0fea5dSIngo Weinhold 2690c0fea5dSIngo Weinhold 2700c0fea5dSIngo Weinhold static void 271ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage) 272ca618b22SIngo Weinhold { 273ca618b22SIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private 274ca618b22SIngo Weinhold // API. 275ca618b22SIngo Weinhold image_t* image; 2760c85bd05SIngo Weinhold void* _export; 277003ebb0eSIngo Weinhold if (find_symbol_breadth_first(rootImage, 278003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image, 279003ebb0eSIngo Weinhold &_export) == B_OK) { 2800c85bd05SIngo Weinhold *(void**)_export = &gRuntimeLoader; 281ca618b22SIngo Weinhold } 282ca618b22SIngo Weinhold } 283ca618b22SIngo Weinhold 284ca618b22SIngo Weinhold 285ca618b22SIngo Weinhold static status_t 286ca618b22SIngo Weinhold add_preloaded_image(image_t* image) 287ca618b22SIngo Weinhold { 288ca618b22SIngo Weinhold // We realloc() everytime -- not particularly efficient, but good enough for 289ca618b22SIngo Weinhold // small number of preloaded images. 290ca618b22SIngo Weinhold image_t** newArray = (image_t**)realloc(sPreloadedImages, 291ca618b22SIngo Weinhold sizeof(image_t*) * (sPreloadedImageCount + 1)); 292ca618b22SIngo Weinhold if (newArray == NULL) 293ca618b22SIngo Weinhold return B_NO_MEMORY; 294ca618b22SIngo Weinhold 295ca618b22SIngo Weinhold sPreloadedImages = newArray; 296ca618b22SIngo Weinhold newArray[sPreloadedImageCount++] = image; 297ca618b22SIngo Weinhold 298ca618b22SIngo Weinhold return B_OK; 299ca618b22SIngo Weinhold } 300ca618b22SIngo Weinhold 301ca618b22SIngo Weinhold 302ca618b22SIngo Weinhold image_id 303ca618b22SIngo Weinhold preload_image(char const* path) 304ca618b22SIngo Weinhold { 305ca618b22SIngo Weinhold if (path == NULL) 306ca618b22SIngo Weinhold return B_BAD_VALUE; 307ca618b22SIngo Weinhold 308ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\")", path); 309ca618b22SIngo Weinhold 310ca618b22SIngo Weinhold image_t *image = NULL; 311765a039dSIngo Weinhold status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, &image); 312ca618b22SIngo Weinhold if (status < B_OK) { 313ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, 314ca618b22SIngo Weinhold strerror(status)); 315ca618b22SIngo Weinhold return status; 316ca618b22SIngo Weinhold } 317ca618b22SIngo Weinhold 3180c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) 3190c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 3200c85bd05SIngo Weinhold 3210c85bd05SIngo Weinhold status = load_dependencies(image); 322ca618b22SIngo Weinhold if (status < B_OK) 323ca618b22SIngo Weinhold goto err; 3240c85bd05SIngo Weinhold 3250c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 326ca618b22SIngo Weinhold 327ca618b22SIngo Weinhold status = relocate_dependencies(image); 328ca618b22SIngo Weinhold if (status < B_OK) 329ca618b22SIngo Weinhold goto err; 330ca618b22SIngo Weinhold 331ca618b22SIngo Weinhold status = add_preloaded_image(image); 332ca618b22SIngo Weinhold if (status < B_OK) 333ca618b22SIngo Weinhold goto err; 334ca618b22SIngo Weinhold 335ca618b22SIngo Weinhold inject_runtime_loader_api(image); 336ca618b22SIngo Weinhold 337ca618b22SIngo Weinhold remap_images(); 338ca618b22SIngo Weinhold init_dependencies(image, true); 339ca618b22SIngo Weinhold 34010b4b5d1SIngo Weinhold // if the image contains an add-on, register it 34110b4b5d1SIngo Weinhold runtime_loader_add_on* addOnStruct; 342003ebb0eSIngo Weinhold if (find_symbol(image, 343003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA), 34410b4b5d1SIngo Weinhold (void**)&addOnStruct) == B_OK) { 34594830eb2SIngo Weinhold add_add_on(image, addOnStruct); 34610b4b5d1SIngo Weinhold } 34710b4b5d1SIngo Weinhold 348ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id); 349ca618b22SIngo Weinhold 350ca618b22SIngo Weinhold return image->id; 351ca618b22SIngo Weinhold 352ca618b22SIngo Weinhold err: 353ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status)); 354ca618b22SIngo Weinhold 35594830eb2SIngo Weinhold dequeue_loaded_image(image); 356ca618b22SIngo Weinhold delete_image(image); 357ca618b22SIngo Weinhold return status; 358ca618b22SIngo Weinhold } 359ca618b22SIngo Weinhold 360ca618b22SIngo Weinhold 361ca618b22SIngo Weinhold static void 362ca618b22SIngo Weinhold preload_images() 363ca618b22SIngo Weinhold { 364ca618b22SIngo Weinhold const char* imagePaths = getenv("LD_PRELOAD"); 365ca618b22SIngo Weinhold if (imagePaths == NULL) 366ca618b22SIngo Weinhold return; 367ca618b22SIngo Weinhold 368ca618b22SIngo Weinhold while (*imagePaths != '\0') { 369ca618b22SIngo Weinhold // find begin of image path 370ca618b22SIngo Weinhold while (*imagePaths != '\0' && isspace(*imagePaths)) 371ca618b22SIngo Weinhold imagePaths++; 372ca618b22SIngo Weinhold 373ca618b22SIngo Weinhold if (*imagePaths == '\0') 374ca618b22SIngo Weinhold break; 375ca618b22SIngo Weinhold 376ca618b22SIngo Weinhold // find end of image path 377ca618b22SIngo Weinhold const char* imagePath = imagePaths; 378ca618b22SIngo Weinhold while (*imagePaths != '\0' && !isspace(*imagePaths)) 379ca618b22SIngo Weinhold imagePaths++; 380ca618b22SIngo Weinhold 381ca618b22SIngo Weinhold // extract the path 382ca618b22SIngo Weinhold char path[B_PATH_NAME_LENGTH]; 383ca618b22SIngo Weinhold size_t pathLen = imagePaths - imagePath; 384ca618b22SIngo Weinhold if (pathLen > sizeof(path) - 1) 385ca618b22SIngo Weinhold continue; 386ca618b22SIngo Weinhold memcpy(path, imagePath, pathLen); 387ca618b22SIngo Weinhold path[pathLen] = '\0'; 388ca618b22SIngo Weinhold 389ca618b22SIngo Weinhold // load the image 390ca618b22SIngo Weinhold preload_image(path); 391ca618b22SIngo Weinhold } 392ca618b22SIngo Weinhold } 393ca618b22SIngo Weinhold 394ca618b22SIngo Weinhold 39574c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 3960c0fea5dSIngo Weinhold 3970c0fea5dSIngo Weinhold 3980c0fea5dSIngo Weinhold image_id 3990c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 4000c0fea5dSIngo Weinhold { 4010c0fea5dSIngo Weinhold status_t status; 4020c0fea5dSIngo Weinhold image_t *image; 4030c0fea5dSIngo Weinhold 4047486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path); 4057486b72dSIngo Weinhold 4060c0fea5dSIngo Weinhold rld_lock(); 4070c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 4080c0fea5dSIngo Weinhold 409ca618b22SIngo Weinhold preload_images(); 410ca618b22SIngo Weinhold 4110c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 4120c0fea5dSIngo Weinhold 41394830eb2SIngo Weinhold status = load_image(path, B_APP_IMAGE, NULL, &gProgramImage); 41474c0424aSAxel Dörfler if (status < B_OK) 41574c0424aSAxel Dörfler goto err; 4160c0fea5dSIngo Weinhold 41794830eb2SIngo Weinhold if (gProgramImage->find_undefined_symbol == NULL) 41894830eb2SIngo Weinhold gProgramImage->find_undefined_symbol = find_undefined_symbol_global; 4190c85bd05SIngo Weinhold 42094830eb2SIngo Weinhold status = load_dependencies(gProgramImage); 4210c0fea5dSIngo Weinhold if (status < B_OK) 4220c0fea5dSIngo Weinhold goto err; 4230c85bd05SIngo Weinhold 42447bc6663SIngo Weinhold // Set RTLD_GLOBAL on all libraries including the program. 4250c85bd05SIngo Weinhold // This results in the desired symbol resolution for dlopen()ed libraries. 42694830eb2SIngo Weinhold set_image_flags_recursively(gProgramImage, RTLD_GLOBAL); 4270c0fea5dSIngo Weinhold 42894830eb2SIngo Weinhold status = relocate_dependencies(gProgramImage); 4290c0fea5dSIngo Weinhold if (status < B_OK) 4300c0fea5dSIngo Weinhold goto err; 4310c0fea5dSIngo Weinhold 43294830eb2SIngo Weinhold inject_runtime_loader_api(gProgramImage); 4330c0fea5dSIngo Weinhold 4340c0fea5dSIngo Weinhold remap_images(); 43594830eb2SIngo Weinhold init_dependencies(gProgramImage, true); 4360c0fea5dSIngo Weinhold 4370c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 4380c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 43994830eb2SIngo Weinhold find_symbol_breadth_first(gProgramImage, 440003ebb0eSIngo Weinhold SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image, 441003ebb0eSIngo Weinhold (void**)&gGetEnv); 4420c0fea5dSIngo Weinhold 44394830eb2SIngo Weinhold if (gProgramImage->entry_point == 0) { 4440c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 4450c0fea5dSIngo Weinhold goto err; 4460c0fea5dSIngo Weinhold } 4470c0fea5dSIngo Weinhold 44894830eb2SIngo Weinhold *_entry = (void *)(gProgramImage->entry_point); 4490c0fea5dSIngo Weinhold 4500c0fea5dSIngo Weinhold rld_unlock(); 4517486b72dSIngo Weinhold 45294830eb2SIngo Weinhold gProgramLoaded = true; 4535d0638bfSIngo Weinhold 4547486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path, 45594830eb2SIngo Weinhold *_entry, gProgramImage->id); 4567486b72dSIngo Weinhold 45794830eb2SIngo Weinhold return gProgramImage->id; 4580c0fea5dSIngo Weinhold 4590c0fea5dSIngo Weinhold err: 4607486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); 4617486b72dSIngo Weinhold 46294830eb2SIngo Weinhold delete_image(gProgramImage); 46374c0424aSAxel Dörfler 4644bef3723SAxel Dörfler if (report_errors()) { 4654bef3723SAxel Dörfler // send error message 46694830eb2SIngo Weinhold gErrorMessage.AddInt32("error", status); 46794830eb2SIngo Weinhold gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 4684bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 4694bef3723SAxel Dörfler 4704bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 47194830eb2SIngo Weinhold gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0); 47274c0424aSAxel Dörfler } 47374c0424aSAxel Dörfler _kern_loading_app_failed(status); 4740c0fea5dSIngo Weinhold rld_unlock(); 47574c0424aSAxel Dörfler 4760c0fea5dSIngo Weinhold return status; 4770c0fea5dSIngo Weinhold } 4780c0fea5dSIngo Weinhold 4790c0fea5dSIngo Weinhold 4800c0fea5dSIngo Weinhold image_id 4810c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle) 4820c0fea5dSIngo Weinhold { 4830c0fea5dSIngo Weinhold image_t *image = NULL; 4840c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 4850c0fea5dSIngo Weinhold status_t status; 4860c0fea5dSIngo Weinhold 4870c85bd05SIngo Weinhold if (path == NULL && addOn) 4880c0fea5dSIngo Weinhold return B_BAD_VALUE; 4890c0fea5dSIngo Weinhold 4907486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn); 4917486b72dSIngo Weinhold 4920c0fea5dSIngo Weinhold rld_lock(); 4930c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 4940c0fea5dSIngo Weinhold 4950c0fea5dSIngo Weinhold // have we already loaded this library? 4960c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 4970c0fea5dSIngo Weinhold if (!addOn) { 4980c85bd05SIngo Weinhold // a NULL path is fine -- it means the global scope shall be opened 4990c85bd05SIngo Weinhold if (path == NULL) { 5000c85bd05SIngo Weinhold *_handle = RLD_GLOBAL_SCOPE; 5010c85bd05SIngo Weinhold rld_unlock(); 5020c85bd05SIngo Weinhold return 0; 5030c85bd05SIngo Weinhold } 5040c85bd05SIngo Weinhold 50594830eb2SIngo Weinhold image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE); 5060c85bd05SIngo Weinhold if (image != NULL && (flags & RTLD_GLOBAL) != 0) 5070c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 5080c85bd05SIngo Weinhold 5090c0fea5dSIngo Weinhold if (image) { 5100c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 5110c0fea5dSIngo Weinhold rld_unlock(); 5127486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path, 5137486b72dSIngo Weinhold image->id); 5140c85bd05SIngo Weinhold *_handle = image; 5150c0fea5dSIngo Weinhold return image->id; 5160c0fea5dSIngo Weinhold } 5170c0fea5dSIngo Weinhold } 5180c0fea5dSIngo Weinhold 51994830eb2SIngo Weinhold status = load_image(path, type, NULL, &image); 5200c0fea5dSIngo Weinhold if (status < B_OK) { 5210c0fea5dSIngo Weinhold rld_unlock(); 5227486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, 5237486b72dSIngo Weinhold strerror(status)); 5240c0fea5dSIngo Weinhold return status; 5250c0fea5dSIngo Weinhold } 5260c0fea5dSIngo Weinhold 5270c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) { 5280c85bd05SIngo Weinhold if (addOn) 5290c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_add_on; 5300c85bd05SIngo Weinhold else 5310c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 5320c85bd05SIngo Weinhold } 5330c85bd05SIngo Weinhold 5340c85bd05SIngo Weinhold status = load_dependencies(image); 5350c0fea5dSIngo Weinhold if (status < B_OK) 5360c0fea5dSIngo Weinhold goto err; 5370c85bd05SIngo Weinhold 5380c85bd05SIngo Weinhold // If specified, set the RTLD_GLOBAL flag recursively on this image and all 5390c85bd05SIngo Weinhold // dependencies. If not specified, we temporarily set 5400c85bd05SIngo Weinhold // RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used 5410c85bd05SIngo Weinhold // for undefined symbol resolution. 5420c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) != 0) 5430c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 5440c85bd05SIngo Weinhold else 5450c85bd05SIngo Weinhold set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 5460c0fea5dSIngo Weinhold 5470c0fea5dSIngo Weinhold status = relocate_dependencies(image); 5480c0fea5dSIngo Weinhold if (status < B_OK) 5490c0fea5dSIngo Weinhold goto err; 5500c0fea5dSIngo Weinhold 5510c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) == 0) 5520c85bd05SIngo Weinhold clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 5530c85bd05SIngo Weinhold 5540c0fea5dSIngo Weinhold remap_images(); 5550c0fea5dSIngo Weinhold init_dependencies(image, true); 5560c0fea5dSIngo Weinhold 5570c0fea5dSIngo Weinhold rld_unlock(); 5587486b72dSIngo Weinhold 5597486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id); 5607486b72dSIngo Weinhold 5610c85bd05SIngo Weinhold *_handle = image; 5620c0fea5dSIngo Weinhold return image->id; 5630c0fea5dSIngo Weinhold 5640c0fea5dSIngo Weinhold err: 5657486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status)); 5667486b72dSIngo Weinhold 56794830eb2SIngo Weinhold dequeue_loaded_image(image); 5680c0fea5dSIngo Weinhold delete_image(image); 5690c0fea5dSIngo Weinhold rld_unlock(); 5700c0fea5dSIngo Weinhold return status; 5710c0fea5dSIngo Weinhold } 5720c0fea5dSIngo Weinhold 5730c0fea5dSIngo Weinhold 5740c0fea5dSIngo Weinhold status_t 5750c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn) 5760c0fea5dSIngo Weinhold { 5770c0fea5dSIngo Weinhold image_t *image; 5780c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 5790c0fea5dSIngo Weinhold 5800c85bd05SIngo Weinhold if (handle == NULL && imageID < 0) 5810c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 5820c0fea5dSIngo Weinhold 5830c85bd05SIngo Weinhold if (handle == RLD_GLOBAL_SCOPE) 5840c85bd05SIngo Weinhold return B_OK; 5850c85bd05SIngo Weinhold 5860c0fea5dSIngo Weinhold rld_lock(); 5870c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 5880c0fea5dSIngo Weinhold 58994830eb2SIngo Weinhold if (gInvalidImageIDs) { 5909a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 5919a6072a3SAxel Dörfler update_image_ids(); 5929a6072a3SAxel Dörfler } 5939a6072a3SAxel Dörfler 5940c0fea5dSIngo Weinhold // we only check images that have been already initialized 5950c0fea5dSIngo Weinhold 596df30098dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 597df30098dSIngo Weinhold 5980c85bd05SIngo Weinhold if (handle != NULL) { 5990c85bd05SIngo Weinhold image = (image_t*)handle; 6000c85bd05SIngo Weinhold put_image(image); 601df30098dSIngo Weinhold status = B_OK; 6020c85bd05SIngo Weinhold } else { 60394830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, true); 60494830eb2SIngo Weinhold if (image != NULL) { 6050c0fea5dSIngo Weinhold // unload image 6060c0fea5dSIngo Weinhold if (type == image->type) { 6070c0fea5dSIngo Weinhold put_image(image); 6080c0fea5dSIngo Weinhold status = B_OK; 6090c0fea5dSIngo Weinhold } else 6100c0fea5dSIngo Weinhold status = B_BAD_VALUE; 6110c0fea5dSIngo Weinhold } 6120c85bd05SIngo Weinhold } 6130c0fea5dSIngo Weinhold 6140c0fea5dSIngo Weinhold if (status == B_OK) { 61594830eb2SIngo Weinhold while ((image = get_disposable_images().head) != NULL) { 616d64f6189SIngo Weinhold // Call the exit hooks that live in this image. 617d64f6189SIngo Weinhold // Note: With the Itanium ABI this shouldn't really be done this 618d64f6189SIngo Weinhold // way anymore, since global destructors are registered via 619d64f6189SIngo Weinhold // __cxa_atexit() (the ones that are registered dynamically) and the 620d64f6189SIngo Weinhold // termination routine should call __cxa_finalize() for the image. 621d64f6189SIngo Weinhold // The reason why we still do it is that hooks registered with 622d64f6189SIngo Weinhold // atexit() aren't associated with the image. We could find out 623d64f6189SIngo Weinhold // there which image the hooks lives in and register it 624d64f6189SIngo Weinhold // respectively, but since that would be done always, that's 625d64f6189SIngo Weinhold // probably more expensive than calling 626d64f6189SIngo Weinhold // call_atexit_hooks_for_range() only here, which happens only when 627d64f6189SIngo Weinhold // libraries are unloaded dynamically. 6288c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 6298c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 6303be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize); 6318c2a9d74SMichael Lotz } 6328c2a9d74SMichael Lotz 63310b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 63410b4b5d1SIngo Weinhold 6350c0fea5dSIngo Weinhold if (image->term_routine) 6360c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 6370c0fea5dSIngo Weinhold 63894830eb2SIngo Weinhold dequeue_disposable_image(image); 6390c0fea5dSIngo Weinhold unmap_image(image); 6400c0fea5dSIngo Weinhold 64110b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 64210b4b5d1SIngo Weinhold 6430c0fea5dSIngo Weinhold delete_image(image); 6440c0fea5dSIngo Weinhold } 6450c0fea5dSIngo Weinhold } 6460c0fea5dSIngo Weinhold 6470c0fea5dSIngo Weinhold rld_unlock(); 6480c0fea5dSIngo Weinhold return status; 6490c0fea5dSIngo Weinhold } 6500c0fea5dSIngo Weinhold 6510c0fea5dSIngo Weinhold 6520c0fea5dSIngo Weinhold status_t 6539a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, 6549a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location) 6550c0fea5dSIngo Weinhold { 6560c0fea5dSIngo Weinhold int32 count = 0, j; 6570c0fea5dSIngo Weinhold uint32 i; 6580c0fea5dSIngo Weinhold image_t *image; 6590c0fea5dSIngo Weinhold 6600c0fea5dSIngo Weinhold rld_lock(); 6610c0fea5dSIngo Weinhold 6620c0fea5dSIngo Weinhold // get the image from those who have been already initialized 66394830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false); 6640c0fea5dSIngo Weinhold if (image == NULL) { 6650c0fea5dSIngo Weinhold rld_unlock(); 6660c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 6670c0fea5dSIngo Weinhold } 6680c0fea5dSIngo Weinhold 6690c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 6700c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 6710c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 672e3ac2588SAlex Smith elf_sym *symbol = &image->syms[j]; 6730c0fea5dSIngo Weinhold 6740c0fea5dSIngo Weinhold if (count == num) { 67510b4b5d1SIngo Weinhold const char* symbolName = SYMNAME(image, symbol); 67610b4b5d1SIngo Weinhold strlcpy(nameBuffer, symbolName, *_nameLength); 67710b4b5d1SIngo Weinhold *_nameLength = strlen(symbolName); 6780c0fea5dSIngo Weinhold 67910b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value 68010b4b5d1SIngo Weinhold + image->regions[0].delta); 68110b4b5d1SIngo Weinhold int32 type; 682e3ac2588SAlex Smith if (symbol->Type() == STT_FUNC) 68310b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 684e3ac2588SAlex Smith else if (symbol->Type() == STT_OBJECT) 68510b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 6860c0fea5dSIngo Weinhold else 68710b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_ANY; 68810b4b5d1SIngo Weinhold // TODO: check with the return types of that BeOS function 6890c0fea5dSIngo Weinhold 69010b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &type); 69110b4b5d1SIngo Weinhold 69210b4b5d1SIngo Weinhold if (_type != NULL) 69310b4b5d1SIngo Weinhold *_type = type; 6940c0fea5dSIngo Weinhold if (_location != NULL) 69510b4b5d1SIngo Weinhold *_location = location; 6960c0fea5dSIngo Weinhold goto out; 6970c0fea5dSIngo Weinhold } 6980c0fea5dSIngo Weinhold count++; 6990c0fea5dSIngo Weinhold } 7000c0fea5dSIngo Weinhold } 7010c0fea5dSIngo Weinhold out: 7020c0fea5dSIngo Weinhold rld_unlock(); 7030c0fea5dSIngo Weinhold 7040c0fea5dSIngo Weinhold if (num != count) 7050c0fea5dSIngo Weinhold return B_BAD_INDEX; 7060c0fea5dSIngo Weinhold 7070c0fea5dSIngo Weinhold return B_OK; 7080c0fea5dSIngo Weinhold } 7090c0fea5dSIngo Weinhold 7100c0fea5dSIngo Weinhold 7110c0fea5dSIngo Weinhold status_t 71243e7b1c2SHamish Morrison get_nearest_symbol_at_address(void* address, image_id* _imageID, 71343e7b1c2SHamish Morrison char** _imagePath, char** _symbolName, int32* _type, void** _location) 714b6455c08SAxel Dörfler { 715b6455c08SAxel Dörfler rld_lock(); 716b6455c08SAxel Dörfler 717b6455c08SAxel Dörfler image_t* image = find_loaded_image_by_address((addr_t)address); 718b6455c08SAxel Dörfler if (image == NULL) { 719b6455c08SAxel Dörfler rld_unlock(); 720b6455c08SAxel Dörfler return B_BAD_VALUE; 721b6455c08SAxel Dörfler } 722b6455c08SAxel Dörfler 723e3ac2588SAlex Smith elf_sym* foundSymbol = NULL; 72443e7b1c2SHamish Morrison addr_t foundLocation = (addr_t)NULL; 72543e7b1c2SHamish Morrison 72643e7b1c2SHamish Morrison bool found = false; 72743e7b1c2SHamish Morrison for (uint32 i = 0; i < HASHTABSIZE(image) && !found; i++) { 728b6455c08SAxel Dörfler for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF; 729b6455c08SAxel Dörfler j = HASHCHAINS(image)[j]) { 730e3ac2588SAlex Smith elf_sym *symbol = &image->syms[j]; 731b6455c08SAxel Dörfler addr_t location = symbol->st_value + image->regions[0].delta; 732b6455c08SAxel Dörfler 73343e7b1c2SHamish Morrison if (location <= (addr_t)address && location >= foundLocation) { 73443e7b1c2SHamish Morrison foundSymbol = symbol; 73543e7b1c2SHamish Morrison foundLocation = location; 736b6455c08SAxel Dörfler 73743e7b1c2SHamish Morrison // jump out if we have an exact match 73843e7b1c2SHamish Morrison if (foundLocation == (addr_t)address) { 73943e7b1c2SHamish Morrison found = true; 74043e7b1c2SHamish Morrison break; 74143e7b1c2SHamish Morrison } 74243e7b1c2SHamish Morrison } 74343e7b1c2SHamish Morrison } 74443e7b1c2SHamish Morrison } 745b6455c08SAxel Dörfler 746b6455c08SAxel Dörfler if (_imageID != NULL) 747b6455c08SAxel Dörfler *_imageID = image->id; 74843e7b1c2SHamish Morrison if (_imagePath != NULL) 74943e7b1c2SHamish Morrison *_imagePath = image->path; 75043e7b1c2SHamish Morrison 75143e7b1c2SHamish Morrison if (foundSymbol != NULL) { 75243e7b1c2SHamish Morrison *_symbolName = SYMNAME(image, foundSymbol); 75343e7b1c2SHamish Morrison 75443e7b1c2SHamish Morrison if (_type != NULL) { 755e3ac2588SAlex Smith if (foundSymbol->Type() == STT_FUNC) 75643e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_TEXT; 757e3ac2588SAlex Smith else if (foundSymbol->Type() == STT_OBJECT) 75843e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_DATA; 75943e7b1c2SHamish Morrison else 76043e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_ANY; 76143e7b1c2SHamish Morrison // TODO: check with the return types of that BeOS function 76243e7b1c2SHamish Morrison } 76343e7b1c2SHamish Morrison 764b6455c08SAxel Dörfler if (_location != NULL) 76543e7b1c2SHamish Morrison *_location = (void*)foundLocation; 76643e7b1c2SHamish Morrison } else { 76743e7b1c2SHamish Morrison *_symbolName = NULL; 76843e7b1c2SHamish Morrison if (_location != NULL) 76943e7b1c2SHamish Morrison *_location = NULL; 77043e7b1c2SHamish Morrison } 771b6455c08SAxel Dörfler 772b6455c08SAxel Dörfler rld_unlock(); 773b6455c08SAxel Dörfler return B_OK; 774b6455c08SAxel Dörfler } 775b6455c08SAxel Dörfler 776b6455c08SAxel Dörfler 777b6455c08SAxel Dörfler status_t 7789a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType, 77980ece785SIngo Weinhold bool recursive, image_id *_inImage, void **_location) 7800c0fea5dSIngo Weinhold { 7810c0fea5dSIngo Weinhold status_t status = B_OK; 7820c0fea5dSIngo Weinhold image_t *image; 7830c0fea5dSIngo Weinhold 7840c0fea5dSIngo Weinhold if (imageID < B_OK) 7850c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 7860c0fea5dSIngo Weinhold if (symbolName == NULL) 7870c0fea5dSIngo Weinhold return B_BAD_VALUE; 7880c0fea5dSIngo Weinhold 7890c0fea5dSIngo Weinhold rld_lock(); 7900c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 7910c0fea5dSIngo Weinhold 7920c0fea5dSIngo Weinhold // get the image from those who have been already initialized 79394830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false); 79480ece785SIngo Weinhold if (image != NULL) { 79580ece785SIngo Weinhold if (recursive) { 79680ece785SIngo Weinhold // breadth-first search in the given image and its dependencies 797003ebb0eSIngo Weinhold status = find_symbol_breadth_first(image, 798003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 799003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 80080ece785SIngo Weinhold &image, _location); 801003ebb0eSIngo Weinhold } else { 802003ebb0eSIngo Weinhold status = find_symbol(image, 803003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 804003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 805003ebb0eSIngo Weinhold _location); 806003ebb0eSIngo Weinhold } 80780ece785SIngo Weinhold 80880ece785SIngo Weinhold if (status == B_OK && _inImage != NULL) 80980ece785SIngo Weinhold *_inImage = image->id; 81080ece785SIngo Weinhold } else 8110c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 8120c0fea5dSIngo Weinhold 8130c0fea5dSIngo Weinhold rld_unlock(); 8140c0fea5dSIngo Weinhold return status; 8150c0fea5dSIngo Weinhold } 8160c0fea5dSIngo Weinhold 8170c0fea5dSIngo Weinhold 8180c0fea5dSIngo Weinhold status_t 8190c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName, 8200c85bd05SIngo Weinhold void **_location) 8210c85bd05SIngo Weinhold { 8220c85bd05SIngo Weinhold status_t status = B_ENTRY_NOT_FOUND; 8230c85bd05SIngo Weinhold 8240c85bd05SIngo Weinhold if (symbolName == NULL) 8250c85bd05SIngo Weinhold return B_BAD_VALUE; 8260c85bd05SIngo Weinhold 8270c85bd05SIngo Weinhold rld_lock(); 8280c85bd05SIngo Weinhold // for now, just do stupid simple global locking 8290c85bd05SIngo Weinhold 8300c85bd05SIngo Weinhold if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) { 8310c85bd05SIngo Weinhold // look in the default scope 8320c85bd05SIngo Weinhold image_t* image; 833e3ac2588SAlex Smith elf_sym* symbol = find_undefined_symbol_global(gProgramImage, 83494830eb2SIngo Weinhold gProgramImage, 835003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 836003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 837003ebb0eSIngo Weinhold &image); 8380c85bd05SIngo Weinhold if (symbol != NULL) { 8390c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value + image->regions[0].delta); 840e3ac2588SAlex Smith int32 symbolType = symbol->Type() == STT_FUNC 8410c85bd05SIngo Weinhold ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 8420c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, &symbolType); 8430c85bd05SIngo Weinhold status = B_OK; 8440c85bd05SIngo Weinhold } 8450c85bd05SIngo Weinhold } else if (handle == RTLD_NEXT) { 8460c85bd05SIngo Weinhold // Look in the default scope, but also in the dependencies of the 8470c85bd05SIngo Weinhold // calling image. Return the next after the caller symbol. 8480c85bd05SIngo Weinhold 849a2dad9e1SIngo Weinhold // First of all, find the caller image. 85094830eb2SIngo Weinhold image_t* callerImage = get_loaded_images().head; 8510c85bd05SIngo Weinhold for (; callerImage != NULL; callerImage = callerImage->next) { 8520c85bd05SIngo Weinhold elf_region_t& text = callerImage->regions[0]; 853a2dad9e1SIngo Weinhold if ((addr_t)caller >= text.vmstart 854a2dad9e1SIngo Weinhold && (addr_t)caller < text.vmstart + text.vmsize) { 855a2dad9e1SIngo Weinhold // found the image 8560c85bd05SIngo Weinhold break; 8570c85bd05SIngo Weinhold } 8580c85bd05SIngo Weinhold } 8590c85bd05SIngo Weinhold 860a2dad9e1SIngo Weinhold if (callerImage != NULL) { 8610c85bd05SIngo Weinhold // found the caller -- now search the global scope until we find 8620c85bd05SIngo Weinhold // the next symbol 863a2dad9e1SIngo Weinhold bool hitCallerImage = false; 8640c85bd05SIngo Weinhold set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 8650c85bd05SIngo Weinhold 866e3ac2588SAlex Smith elf_sym* candidateSymbol = NULL; 86725dc253dSIngo Weinhold image_t* candidateImage = NULL; 86825dc253dSIngo Weinhold 86994830eb2SIngo Weinhold image_t* image = get_loaded_images().head; 8700c85bd05SIngo Weinhold for (; image != NULL; image = image->next) { 871a2dad9e1SIngo Weinhold // skip the caller image 872a2dad9e1SIngo Weinhold if (image == callerImage) { 873a2dad9e1SIngo Weinhold hitCallerImage = true; 874a2dad9e1SIngo Weinhold continue; 875a2dad9e1SIngo Weinhold } 876a2dad9e1SIngo Weinhold 877a2dad9e1SIngo Weinhold // skip all images up to the caller image; also skip add-on 878a2dad9e1SIngo Weinhold // images and those not marked above for resolution 879a2dad9e1SIngo Weinhold if (!hitCallerImage || image->type == B_ADD_ON_IMAGE 8800c85bd05SIngo Weinhold || (image->flags 881a2dad9e1SIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) { 8820c85bd05SIngo Weinhold continue; 8830c85bd05SIngo Weinhold } 8840c85bd05SIngo Weinhold 885e3ac2588SAlex Smith elf_sym *symbol = find_symbol(image, 886003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL, 887003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION)); 8880c85bd05SIngo Weinhold if (symbol == NULL) 8890c85bd05SIngo Weinhold continue; 8900c85bd05SIngo Weinhold 89125dc253dSIngo Weinhold // found a symbol 892e3ac2588SAlex Smith bool isWeak = symbol->Bind() == STB_WEAK; 89325dc253dSIngo Weinhold if (candidateImage == NULL || !isWeak) { 89425dc253dSIngo Weinhold candidateSymbol = symbol; 89525dc253dSIngo Weinhold candidateImage = image; 89625dc253dSIngo Weinhold 89725dc253dSIngo Weinhold if (!isWeak) 89825dc253dSIngo Weinhold break; 89925dc253dSIngo Weinhold } 90025dc253dSIngo Weinhold 90125dc253dSIngo Weinhold // symbol is weak, so we need to continue 90225dc253dSIngo Weinhold } 90325dc253dSIngo Weinhold 90425dc253dSIngo Weinhold if (candidateSymbol != NULL) { 905a2dad9e1SIngo Weinhold // found the symbol 90625dc253dSIngo Weinhold *_location = (void*)(candidateSymbol->st_value 90725dc253dSIngo Weinhold + candidateImage->regions[0].delta); 9080c85bd05SIngo Weinhold int32 symbolType = B_SYMBOL_TYPE_TEXT; 90925dc253dSIngo Weinhold patch_defined_symbol(candidateImage, symbolName, _location, 9100c85bd05SIngo Weinhold &symbolType); 9110c85bd05SIngo Weinhold status = B_OK; 9120c85bd05SIngo Weinhold } 9130c85bd05SIngo Weinhold 9140c85bd05SIngo Weinhold clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 9150c85bd05SIngo Weinhold } 9160c85bd05SIngo Weinhold } else { 9170c85bd05SIngo Weinhold // breadth-first search in the given image and its dependencies 9180c85bd05SIngo Weinhold image_t* inImage; 919003ebb0eSIngo Weinhold status = find_symbol_breadth_first((image_t*)handle, 920003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 921003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 922003ebb0eSIngo Weinhold &inImage, _location); 9230c85bd05SIngo Weinhold } 9240c85bd05SIngo Weinhold 9250c85bd05SIngo Weinhold rld_unlock(); 9260c85bd05SIngo Weinhold return status; 9270c85bd05SIngo Weinhold } 9280c85bd05SIngo Weinhold 9290c85bd05SIngo Weinhold 9300c85bd05SIngo Weinhold status_t 9310c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 9320c0fea5dSIngo Weinhold { 9330c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 934e3ac2588SAlex Smith elf_dyn *dynamicSection; 9350c0fea5dSIngo Weinhold image_t *image; 9360c0fea5dSIngo Weinhold 9370c0fea5dSIngo Weinhold if (_name == NULL) 9380c0fea5dSIngo Weinhold return B_BAD_VALUE; 9390c0fea5dSIngo Weinhold 9400c0fea5dSIngo Weinhold rld_lock(); 9410c0fea5dSIngo Weinhold 94294830eb2SIngo Weinhold image = find_loaded_image_by_id(id, false); 9430c0fea5dSIngo Weinhold if (image == NULL) { 9440c0fea5dSIngo Weinhold rld_unlock(); 9450c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 9460c0fea5dSIngo Weinhold } 9470c0fea5dSIngo Weinhold 948e3ac2588SAlex Smith dynamicSection = (elf_dyn *)image->dynamic_ptr; 9490c0fea5dSIngo Weinhold if (dynamicSection == NULL || image->num_needed <= searchIndex) { 9500c0fea5dSIngo Weinhold rld_unlock(); 9510c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 9520c0fea5dSIngo Weinhold } 9530c0fea5dSIngo Weinhold 9540c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 9550c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 9560c0fea5dSIngo Weinhold continue; 9570c0fea5dSIngo Weinhold 9580c0fea5dSIngo Weinhold if (j++ == searchIndex) { 9590c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 9600c0fea5dSIngo Weinhold 9610c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 9620c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 9630c0fea5dSIngo Weinhold rld_unlock(); 9640c0fea5dSIngo Weinhold return B_OK; 9650c0fea5dSIngo Weinhold } 9660c0fea5dSIngo Weinhold } 9670c0fea5dSIngo Weinhold 9680c0fea5dSIngo Weinhold rld_unlock(); 9690c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 9700c0fea5dSIngo Weinhold } 9710c0fea5dSIngo Weinhold 9720c0fea5dSIngo Weinhold 97374c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 9740c0fea5dSIngo Weinhold 9750c0fea5dSIngo Weinhold 9769a6072a3SAxel Dörfler /*! Read and verify the ELF header */ 9770c0fea5dSIngo Weinhold status_t 978e3ac2588SAlex Smith elf_verify_header(void *header, size_t length) 9790c0fea5dSIngo Weinhold { 9800c0fea5dSIngo Weinhold int32 programSize, sectionSize; 9810c0fea5dSIngo Weinhold 982e3ac2588SAlex Smith if (length < sizeof(elf_ehdr)) 9830c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 9840c0fea5dSIngo Weinhold 985e3ac2588SAlex Smith return parse_elf_header((elf_ehdr *)header, &programSize, §ionSize); 9860c0fea5dSIngo Weinhold } 9870c0fea5dSIngo Weinhold 9880c0fea5dSIngo Weinhold 9890c0fea5dSIngo Weinhold void 9900c0fea5dSIngo Weinhold terminate_program(void) 9910c0fea5dSIngo Weinhold { 9920c0fea5dSIngo Weinhold image_t **termList; 9930c0fea5dSIngo Weinhold ssize_t count, i; 9940c0fea5dSIngo Weinhold 995aa3507feSIngo Weinhold count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED); 9960c0fea5dSIngo Weinhold if (count < B_OK) 9970c0fea5dSIngo Weinhold return; 9980c0fea5dSIngo Weinhold 99994830eb2SIngo Weinhold if (gInvalidImageIDs) { 10009a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 10019a6072a3SAxel Dörfler update_image_ids(); 10029a6072a3SAxel Dörfler } 10039a6072a3SAxel Dörfler 10040c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 10050c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 10060c0fea5dSIngo Weinhold image_t *image = termList[i]; 10070c0fea5dSIngo Weinhold 10080c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 10090c0fea5dSIngo Weinhold 101010b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 101110b4b5d1SIngo Weinhold 10120c0fea5dSIngo Weinhold if (image->term_routine) 10130c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 101410b4b5d1SIngo Weinhold 101510b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 10160c0fea5dSIngo Weinhold } 10170c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 10180c0fea5dSIngo Weinhold 10190c0fea5dSIngo Weinhold free(termList); 10200c0fea5dSIngo Weinhold } 10210c0fea5dSIngo Weinhold 10220c0fea5dSIngo Weinhold 10230c0fea5dSIngo Weinhold void 10240c0fea5dSIngo Weinhold rldelf_init(void) 10250c0fea5dSIngo Weinhold { 102694830eb2SIngo Weinhold init_add_ons(); 102794830eb2SIngo Weinhold 10280c0fea5dSIngo Weinhold // create the debug area 10290c0fea5dSIngo Weinhold { 1030e3ac2588SAlex Smith size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 10310c0fea5dSIngo Weinhold 10320c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 10330c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 1034*9f3bd497SPawel Dziepak (void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK, 10350c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 10360c0fea5dSIngo Weinhold if (areaID < B_OK) { 10370c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 10380c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 10390c0fea5dSIngo Weinhold } 10400c0fea5dSIngo Weinhold 104194830eb2SIngo Weinhold area->loaded_images = &get_loaded_images(); 10420c0fea5dSIngo Weinhold } 104374c0424aSAxel Dörfler 104474c0424aSAxel Dörfler // initialize error message if needed 10454bef3723SAxel Dörfler if (report_errors()) { 104674c0424aSAxel Dörfler void *buffer = malloc(1024); 104774c0424aSAxel Dörfler if (buffer == NULL) 104874c0424aSAxel Dörfler return; 104974c0424aSAxel Dörfler 105094830eb2SIngo Weinhold gErrorMessage.SetTo(buffer, 1024, 'Rler'); 105174c0424aSAxel Dörfler } 10520c0fea5dSIngo Weinhold } 10531873b4b3SIngo Weinhold 10541873b4b3SIngo Weinhold 10551873b4b3SIngo Weinhold status_t 10569a6072a3SAxel Dörfler elf_reinit_after_fork(void) 10571873b4b3SIngo Weinhold { 1058f7127458SIngo Weinhold recursive_lock_init(&sLock, kLockName); 10591873b4b3SIngo Weinhold 10609a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and 1061cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork() 1062cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one 10639a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different. 106494830eb2SIngo Weinhold gInvalidImageIDs = true; 1065cbc456deSIngo Weinhold 10661873b4b3SIngo Weinhold return B_OK; 10671873b4b3SIngo Weinhold } 1068