10c0fea5dSIngo Weinhold /* 2593ee7bbSIngo Weinhold * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 312a5e9a4SAxel Dörfler * Copyright 2003-2008, 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 <elf32.h> 227486b72dSIngo Weinhold #include <syscalls.h> 2310b4b5d1SIngo Weinhold #include <util/kernel_cpp.h> 247486b72dSIngo Weinhold 25*94830eb2SIngo Weinhold #include "add_ons.h" 26*94830eb2SIngo Weinhold #include "elf_load_image.h" 27*94830eb2SIngo Weinhold #include "elf_symbol_lookup.h" 28*94830eb2SIngo Weinhold #include "elf_versioning.h" 29*94830eb2SIngo Weinhold #include "errors.h" 30*94830eb2SIngo Weinhold #include "images.h" 310c0fea5dSIngo Weinhold 320c0fea5dSIngo Weinhold 3310b4b5d1SIngo Weinhold // TODO: implement better locking strategy 3410b4b5d1SIngo Weinhold // TODO: implement lazy binding 350c0fea5dSIngo Weinhold 360c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen()) 370c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE ((void*)-2l) 380c85bd05SIngo Weinhold 390c0fea5dSIngo Weinhold 400c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 410c0fea5dSIngo Weinhold 42*94830eb2SIngo Weinhold bool gProgramLoaded = false; 43*94830eb2SIngo Weinhold image_t* gProgramImage; 44003ebb0eSIngo Weinhold 45ca618b22SIngo Weinhold static image_t** sPreloadedImages = NULL; 46ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0; 470c0fea5dSIngo Weinhold 480c0fea5dSIngo Weinhold // a recursive lock 49e73923b0SAxel Dörfler static sem_id sSem; 50e73923b0SAxel Dörfler static thread_id sSemOwner; 51e73923b0SAxel Dörfler static int32 sSemCount; 520c0fea5dSIngo Weinhold 537486b72dSIngo Weinhold 540c0fea5dSIngo Weinhold static void 550c0fea5dSIngo Weinhold rld_unlock() 560c0fea5dSIngo Weinhold { 57e73923b0SAxel Dörfler if (sSemCount-- == 1) { 58e73923b0SAxel Dörfler sSemOwner = -1; 59e73923b0SAxel Dörfler release_sem(sSem); 600c0fea5dSIngo Weinhold } 610c0fea5dSIngo Weinhold } 620c0fea5dSIngo Weinhold 630c0fea5dSIngo Weinhold 640c0fea5dSIngo Weinhold static void 650c0fea5dSIngo Weinhold rld_lock() 660c0fea5dSIngo Weinhold { 670c0fea5dSIngo Weinhold thread_id self = find_thread(NULL); 68e73923b0SAxel Dörfler if (self != sSemOwner) { 69e73923b0SAxel Dörfler acquire_sem(sSem); 70e73923b0SAxel Dörfler sSemOwner = self; 710c0fea5dSIngo Weinhold } 72e73923b0SAxel Dörfler sSemCount++; 730c0fea5dSIngo Weinhold } 740c0fea5dSIngo Weinhold 750c0fea5dSIngo Weinhold 760c0fea5dSIngo Weinhold static const char * 770c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 780c0fea5dSIngo Weinhold { 790c0fea5dSIngo Weinhold int i; 800c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 810c0fea5dSIngo Weinhold 820c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 830c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 840c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 850c0fea5dSIngo Weinhold } 860c0fea5dSIngo Weinhold 870c0fea5dSIngo Weinhold return NULL; 880c0fea5dSIngo Weinhold } 890c0fea5dSIngo Weinhold 900c0fea5dSIngo Weinhold 910c0fea5dSIngo Weinhold static status_t 920c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image) 930c0fea5dSIngo Weinhold { 940c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 954bef3723SAxel Dörfler bool reportErrors = report_errors(); 9674c0424aSAxel Dörfler status_t status = B_OK; 970c0fea5dSIngo Weinhold uint32 i, j; 980c0fea5dSIngo Weinhold const char *rpath; 990c0fea5dSIngo Weinhold 1000c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 1010c0fea5dSIngo Weinhold return B_OK; 1020c0fea5dSIngo Weinhold 1030c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 1040c0fea5dSIngo Weinhold 1050c0fea5dSIngo Weinhold if (image->num_needed == 0) 1060c0fea5dSIngo Weinhold return B_OK; 1070c0fea5dSIngo Weinhold 1087486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name, 1097486b72dSIngo Weinhold image->id); 1107486b72dSIngo Weinhold 1110c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 1120c0fea5dSIngo Weinhold if (image->needed == NULL) { 1130c0fea5dSIngo Weinhold FATAL("failed to allocate needed struct\n"); 1147486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory", 1157486b72dSIngo Weinhold image->name, image->id); 1160c0fea5dSIngo Weinhold return B_NO_MEMORY; 1170c0fea5dSIngo Weinhold } 1180c0fea5dSIngo Weinhold 1190c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 1200c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 1210c0fea5dSIngo Weinhold 1220c0fea5dSIngo Weinhold for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { 1230c0fea5dSIngo Weinhold switch (d[i].d_tag) { 1240c0fea5dSIngo Weinhold case DT_NEEDED: 12574c0424aSAxel Dörfler { 12674c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 12774c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 1280c0fea5dSIngo Weinhold 129*94830eb2SIngo Weinhold status_t loadStatus = load_image(name, B_LIBRARY_IMAGE, 13074c0424aSAxel Dörfler rpath, &image->needed[j]); 13174c0424aSAxel Dörfler if (loadStatus < B_OK) { 13274c0424aSAxel Dörfler status = loadStatus; 13374c0424aSAxel Dörfler // correct error code in case the file could not been found 13474c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 13574c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 13674c0424aSAxel Dörfler 13774c0424aSAxel Dörfler if (reportErrors) 138*94830eb2SIngo Weinhold gErrorMessage.AddString("missing library", name); 13974c0424aSAxel Dörfler } 14074c0424aSAxel Dörfler 14174c0424aSAxel Dörfler // Collect all missing libraries in case we report back 1427486b72dSIngo Weinhold if (!reportErrors) { 1437486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 1447486b72dSIngo Weinhold "failed: %s", image->name, image->id, 1457486b72dSIngo Weinhold strerror(status)); 1460c0fea5dSIngo Weinhold return status; 14774c0424aSAxel Dörfler } 1487486b72dSIngo Weinhold } 1490c0fea5dSIngo Weinhold 1500c0fea5dSIngo Weinhold j += 1; 1510c0fea5dSIngo Weinhold break; 15274c0424aSAxel Dörfler } 1530c0fea5dSIngo Weinhold 1540c0fea5dSIngo Weinhold default: 1550c0fea5dSIngo Weinhold // ignore any other tag 1560c0fea5dSIngo Weinhold continue; 1570c0fea5dSIngo Weinhold } 1580c0fea5dSIngo Weinhold } 1590c0fea5dSIngo Weinhold 1607486b72dSIngo Weinhold if (status < B_OK) { 1617486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 1627486b72dSIngo Weinhold "failed: %s", image->name, image->id, 1637486b72dSIngo Weinhold strerror(status)); 16474c0424aSAxel Dörfler return status; 1657486b72dSIngo Weinhold } 16674c0424aSAxel Dörfler 1670c0fea5dSIngo Weinhold if (j != image->num_needed) { 1680c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 1697486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 1707486b72dSIngo Weinhold "failed: internal error", image->name, image->id); 1710c0fea5dSIngo Weinhold return B_ERROR; 1720c0fea5dSIngo Weinhold } 1730c0fea5dSIngo Weinhold 1747486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name, 1757486b72dSIngo Weinhold image->id); 1767486b72dSIngo Weinhold 1770c0fea5dSIngo Weinhold return B_OK; 1780c0fea5dSIngo Weinhold } 1790c0fea5dSIngo Weinhold 1800c0fea5dSIngo Weinhold 1810c85bd05SIngo Weinhold static status_t 1820c85bd05SIngo Weinhold load_dependencies(image_t* image) 1830c85bd05SIngo Weinhold { 184003ebb0eSIngo Weinhold // load dependencies (breadth-first) 1850c85bd05SIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 1860c85bd05SIngo Weinhold otherImage = otherImage->next) { 1870c85bd05SIngo Weinhold status_t status = load_immediate_dependencies(otherImage); 1880c85bd05SIngo Weinhold if (status != B_OK) 1890c85bd05SIngo Weinhold return status; 1900c85bd05SIngo Weinhold } 1910c85bd05SIngo Weinhold 192003ebb0eSIngo Weinhold // Check the needed versions for the given image and all newly loaded 193003ebb0eSIngo Weinhold // dependencies. 194003ebb0eSIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 195003ebb0eSIngo Weinhold otherImage = otherImage->next) { 196003ebb0eSIngo Weinhold status_t status = check_needed_image_versions(otherImage); 197003ebb0eSIngo Weinhold if (status != B_OK) 198003ebb0eSIngo Weinhold return status; 199003ebb0eSIngo Weinhold } 200003ebb0eSIngo Weinhold 2010c85bd05SIngo Weinhold return B_OK; 2020c85bd05SIngo Weinhold } 2030c85bd05SIngo Weinhold 2040c85bd05SIngo Weinhold 205*94830eb2SIngo Weinhold static status_t 206*94830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 2070c0fea5dSIngo Weinhold { 208*94830eb2SIngo Weinhold status_t status = arch_relocate_image(rootImage, image); 209*94830eb2SIngo Weinhold if (status < B_OK) { 210*94830eb2SIngo Weinhold FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status, 211*94830eb2SIngo Weinhold image->path, image->name); 212*94830eb2SIngo Weinhold return status; 2130c0fea5dSIngo Weinhold } 2140c0fea5dSIngo Weinhold 215*94830eb2SIngo Weinhold _kern_image_relocated(image->id); 216*94830eb2SIngo Weinhold image_event(image, IMAGE_EVENT_RELOCATED); 217*94830eb2SIngo Weinhold return B_OK; 2180c0fea5dSIngo Weinhold } 2190c0fea5dSIngo Weinhold 2200c0fea5dSIngo Weinhold 2210c0fea5dSIngo Weinhold static status_t 2220c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 2230c0fea5dSIngo Weinhold { 224ca618b22SIngo Weinhold // get the images that still have to be relocated 225ca618b22SIngo Weinhold image_t **list; 226ca618b22SIngo Weinhold ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 2270c0fea5dSIngo Weinhold if (count < B_OK) 2280c0fea5dSIngo Weinhold return count; 2290c0fea5dSIngo Weinhold 2300c85bd05SIngo Weinhold // relocate 231ca618b22SIngo Weinhold for (ssize_t i = 0; i < count; i++) { 23246f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 2330c85bd05SIngo Weinhold if (status < B_OK) { 2340c85bd05SIngo Weinhold free(list); 2350c0fea5dSIngo Weinhold return status; 2360c0fea5dSIngo Weinhold } 2370c85bd05SIngo Weinhold } 2380c0fea5dSIngo Weinhold 2390c0fea5dSIngo Weinhold free(list); 2400c0fea5dSIngo Weinhold return B_OK; 2410c0fea5dSIngo Weinhold } 2420c0fea5dSIngo Weinhold 2430c0fea5dSIngo Weinhold 2440c0fea5dSIngo Weinhold static void 2450c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 2460c0fea5dSIngo Weinhold { 2470c0fea5dSIngo Weinhold image_t **initList; 2480c0fea5dSIngo Weinhold ssize_t count, i; 2490c0fea5dSIngo Weinhold 2500c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 2510c0fea5dSIngo Weinhold if (count <= 0) 2520c0fea5dSIngo Weinhold return; 2530c0fea5dSIngo Weinhold 2540c0fea5dSIngo Weinhold if (!initHead) { 2550c0fea5dSIngo Weinhold // this removes the "calling" image 2560c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 2570c0fea5dSIngo Weinhold initList[--count] = NULL; 2580c0fea5dSIngo Weinhold } 2590c0fea5dSIngo Weinhold 2600c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 2610c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 2620c0fea5dSIngo Weinhold image = initList[i]; 2630c0fea5dSIngo Weinhold 2640c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 2650c0fea5dSIngo Weinhold 266dd76bc97SIngo Weinhold if (image->init_routine != 0) 2670c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 26810b4b5d1SIngo Weinhold 26910b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_INITIALIZED); 2700c0fea5dSIngo Weinhold } 2710c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 2720c0fea5dSIngo Weinhold 2730c0fea5dSIngo Weinhold free(initList); 2740c0fea5dSIngo Weinhold } 2750c0fea5dSIngo Weinhold 2760c0fea5dSIngo Weinhold 2770c0fea5dSIngo Weinhold static void 278ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage) 279ca618b22SIngo Weinhold { 280ca618b22SIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private 281ca618b22SIngo Weinhold // API. 282ca618b22SIngo Weinhold image_t* image; 2830c85bd05SIngo Weinhold void* _export; 284003ebb0eSIngo Weinhold if (find_symbol_breadth_first(rootImage, 285003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image, 286003ebb0eSIngo Weinhold &_export) == B_OK) { 2870c85bd05SIngo Weinhold *(void**)_export = &gRuntimeLoader; 288ca618b22SIngo Weinhold } 289ca618b22SIngo Weinhold } 290ca618b22SIngo Weinhold 291ca618b22SIngo Weinhold 292ca618b22SIngo Weinhold static status_t 293ca618b22SIngo Weinhold add_preloaded_image(image_t* image) 294ca618b22SIngo Weinhold { 295ca618b22SIngo Weinhold // We realloc() everytime -- not particularly efficient, but good enough for 296ca618b22SIngo Weinhold // small number of preloaded images. 297ca618b22SIngo Weinhold image_t** newArray = (image_t**)realloc(sPreloadedImages, 298ca618b22SIngo Weinhold sizeof(image_t*) * (sPreloadedImageCount + 1)); 299ca618b22SIngo Weinhold if (newArray == NULL) 300ca618b22SIngo Weinhold return B_NO_MEMORY; 301ca618b22SIngo Weinhold 302ca618b22SIngo Weinhold sPreloadedImages = newArray; 303ca618b22SIngo Weinhold newArray[sPreloadedImageCount++] = image; 304ca618b22SIngo Weinhold 305ca618b22SIngo Weinhold return B_OK; 306ca618b22SIngo Weinhold } 307ca618b22SIngo Weinhold 308ca618b22SIngo Weinhold 309ca618b22SIngo Weinhold image_id 310ca618b22SIngo Weinhold preload_image(char const* path) 311ca618b22SIngo Weinhold { 312ca618b22SIngo Weinhold if (path == NULL) 313ca618b22SIngo Weinhold return B_BAD_VALUE; 314ca618b22SIngo Weinhold 315ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\")", path); 316ca618b22SIngo Weinhold 317ca618b22SIngo Weinhold image_t *image = NULL; 318*94830eb2SIngo Weinhold status_t status = load_image(path, B_ADD_ON_IMAGE, NULL, &image); 319ca618b22SIngo Weinhold if (status < B_OK) { 320ca618b22SIngo Weinhold rld_unlock(); 321ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, 322ca618b22SIngo Weinhold strerror(status)); 323ca618b22SIngo Weinhold return status; 324ca618b22SIngo Weinhold } 325ca618b22SIngo Weinhold 3260c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) 3270c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 3280c85bd05SIngo Weinhold 3290c85bd05SIngo Weinhold status = load_dependencies(image); 330ca618b22SIngo Weinhold if (status < B_OK) 331ca618b22SIngo Weinhold goto err; 3320c85bd05SIngo Weinhold 3330c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 334ca618b22SIngo Weinhold 335ca618b22SIngo Weinhold status = relocate_dependencies(image); 336ca618b22SIngo Weinhold if (status < B_OK) 337ca618b22SIngo Weinhold goto err; 338ca618b22SIngo Weinhold 339ca618b22SIngo Weinhold status = add_preloaded_image(image); 340ca618b22SIngo Weinhold if (status < B_OK) 341ca618b22SIngo Weinhold goto err; 342ca618b22SIngo Weinhold 343ca618b22SIngo Weinhold inject_runtime_loader_api(image); 344ca618b22SIngo Weinhold 345ca618b22SIngo Weinhold remap_images(); 346ca618b22SIngo Weinhold init_dependencies(image, true); 347ca618b22SIngo Weinhold 34810b4b5d1SIngo Weinhold // if the image contains an add-on, register it 34910b4b5d1SIngo Weinhold runtime_loader_add_on* addOnStruct; 350003ebb0eSIngo Weinhold if (find_symbol(image, 351003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA), 35210b4b5d1SIngo Weinhold (void**)&addOnStruct) == B_OK) { 353*94830eb2SIngo Weinhold add_add_on(image, addOnStruct); 35410b4b5d1SIngo Weinhold } 35510b4b5d1SIngo Weinhold 356ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id); 357ca618b22SIngo Weinhold 358ca618b22SIngo Weinhold return image->id; 359ca618b22SIngo Weinhold 360ca618b22SIngo Weinhold err: 361ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status)); 362ca618b22SIngo Weinhold 363*94830eb2SIngo Weinhold dequeue_loaded_image(image); 364ca618b22SIngo Weinhold delete_image(image); 365ca618b22SIngo Weinhold return status; 366ca618b22SIngo Weinhold } 367ca618b22SIngo Weinhold 368ca618b22SIngo Weinhold 369ca618b22SIngo Weinhold static void 370ca618b22SIngo Weinhold preload_images() 371ca618b22SIngo Weinhold { 372ca618b22SIngo Weinhold const char* imagePaths = getenv("LD_PRELOAD"); 373ca618b22SIngo Weinhold if (imagePaths == NULL) 374ca618b22SIngo Weinhold return; 375ca618b22SIngo Weinhold 376ca618b22SIngo Weinhold while (*imagePaths != '\0') { 377ca618b22SIngo Weinhold // find begin of image path 378ca618b22SIngo Weinhold while (*imagePaths != '\0' && isspace(*imagePaths)) 379ca618b22SIngo Weinhold imagePaths++; 380ca618b22SIngo Weinhold 381ca618b22SIngo Weinhold if (*imagePaths == '\0') 382ca618b22SIngo Weinhold break; 383ca618b22SIngo Weinhold 384ca618b22SIngo Weinhold // find end of image path 385ca618b22SIngo Weinhold const char* imagePath = imagePaths; 386ca618b22SIngo Weinhold while (*imagePaths != '\0' && !isspace(*imagePaths)) 387ca618b22SIngo Weinhold imagePaths++; 388ca618b22SIngo Weinhold 389ca618b22SIngo Weinhold // extract the path 390ca618b22SIngo Weinhold char path[B_PATH_NAME_LENGTH]; 391ca618b22SIngo Weinhold size_t pathLen = imagePaths - imagePath; 392ca618b22SIngo Weinhold if (pathLen > sizeof(path) - 1) 393ca618b22SIngo Weinhold continue; 394ca618b22SIngo Weinhold memcpy(path, imagePath, pathLen); 395ca618b22SIngo Weinhold path[pathLen] = '\0'; 396ca618b22SIngo Weinhold 397ca618b22SIngo Weinhold // load the image 398ca618b22SIngo Weinhold preload_image(path); 399ca618b22SIngo Weinhold } 400ca618b22SIngo Weinhold } 401ca618b22SIngo Weinhold 402ca618b22SIngo Weinhold 40374c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 4040c0fea5dSIngo Weinhold 4050c0fea5dSIngo Weinhold 4060c0fea5dSIngo Weinhold image_id 4070c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 4080c0fea5dSIngo Weinhold { 4090c0fea5dSIngo Weinhold status_t status; 4100c0fea5dSIngo Weinhold image_t *image; 4110c0fea5dSIngo Weinhold 4127486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path); 4137486b72dSIngo Weinhold 4140c0fea5dSIngo Weinhold rld_lock(); 4150c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 4160c0fea5dSIngo Weinhold 417ca618b22SIngo Weinhold preload_images(); 418ca618b22SIngo Weinhold 4190c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 4200c0fea5dSIngo Weinhold 421*94830eb2SIngo Weinhold status = load_image(path, B_APP_IMAGE, NULL, &gProgramImage); 42274c0424aSAxel Dörfler if (status < B_OK) 42374c0424aSAxel Dörfler goto err; 4240c0fea5dSIngo Weinhold 425*94830eb2SIngo Weinhold if (gProgramImage->find_undefined_symbol == NULL) 426*94830eb2SIngo Weinhold gProgramImage->find_undefined_symbol = find_undefined_symbol_global; 4270c85bd05SIngo Weinhold 428*94830eb2SIngo Weinhold status = load_dependencies(gProgramImage); 4290c0fea5dSIngo Weinhold if (status < B_OK) 4300c0fea5dSIngo Weinhold goto err; 4310c85bd05SIngo Weinhold 43247bc6663SIngo Weinhold // Set RTLD_GLOBAL on all libraries including the program. 4330c85bd05SIngo Weinhold // This results in the desired symbol resolution for dlopen()ed libraries. 434*94830eb2SIngo Weinhold set_image_flags_recursively(gProgramImage, RTLD_GLOBAL); 4350c0fea5dSIngo Weinhold 436*94830eb2SIngo Weinhold status = relocate_dependencies(gProgramImage); 4370c0fea5dSIngo Weinhold if (status < B_OK) 4380c0fea5dSIngo Weinhold goto err; 4390c0fea5dSIngo Weinhold 440*94830eb2SIngo Weinhold inject_runtime_loader_api(gProgramImage); 4410c0fea5dSIngo Weinhold 4420c0fea5dSIngo Weinhold remap_images(); 443*94830eb2SIngo Weinhold init_dependencies(gProgramImage, true); 4440c0fea5dSIngo Weinhold 4450c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 4460c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 447*94830eb2SIngo Weinhold find_symbol_breadth_first(gProgramImage, 448003ebb0eSIngo Weinhold SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image, 449003ebb0eSIngo Weinhold (void**)&gGetEnv); 4500c0fea5dSIngo Weinhold 451*94830eb2SIngo Weinhold if (gProgramImage->entry_point == 0) { 4520c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 4530c0fea5dSIngo Weinhold goto err; 4540c0fea5dSIngo Weinhold } 4550c0fea5dSIngo Weinhold 456*94830eb2SIngo Weinhold *_entry = (void *)(gProgramImage->entry_point); 4570c0fea5dSIngo Weinhold 4580c0fea5dSIngo Weinhold rld_unlock(); 4597486b72dSIngo Weinhold 460*94830eb2SIngo Weinhold gProgramLoaded = true; 4615d0638bfSIngo Weinhold 4627486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path, 463*94830eb2SIngo Weinhold *_entry, gProgramImage->id); 4647486b72dSIngo Weinhold 465*94830eb2SIngo Weinhold return gProgramImage->id; 4660c0fea5dSIngo Weinhold 4670c0fea5dSIngo Weinhold err: 4687486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); 4697486b72dSIngo Weinhold 470*94830eb2SIngo Weinhold delete_image(gProgramImage); 47174c0424aSAxel Dörfler 4724bef3723SAxel Dörfler if (report_errors()) { 4734bef3723SAxel Dörfler // send error message 474*94830eb2SIngo Weinhold gErrorMessage.AddInt32("error", status); 475*94830eb2SIngo Weinhold gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 4764bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 4774bef3723SAxel Dörfler 4784bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 479*94830eb2SIngo Weinhold gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0); 48074c0424aSAxel Dörfler } 48174c0424aSAxel Dörfler _kern_loading_app_failed(status); 4820c0fea5dSIngo Weinhold rld_unlock(); 48374c0424aSAxel Dörfler 4840c0fea5dSIngo Weinhold return status; 4850c0fea5dSIngo Weinhold } 4860c0fea5dSIngo Weinhold 4870c0fea5dSIngo Weinhold 4880c0fea5dSIngo Weinhold image_id 4890c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle) 4900c0fea5dSIngo Weinhold { 4910c0fea5dSIngo Weinhold image_t *image = NULL; 4920c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 4930c0fea5dSIngo Weinhold status_t status; 4940c0fea5dSIngo Weinhold 4950c85bd05SIngo Weinhold if (path == NULL && addOn) 4960c0fea5dSIngo Weinhold return B_BAD_VALUE; 4970c0fea5dSIngo Weinhold 4987486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn); 4997486b72dSIngo Weinhold 5000c0fea5dSIngo Weinhold rld_lock(); 5010c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 5020c0fea5dSIngo Weinhold 5030c0fea5dSIngo Weinhold // have we already loaded this library? 5040c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 5050c0fea5dSIngo Weinhold if (!addOn) { 5060c85bd05SIngo Weinhold // a NULL path is fine -- it means the global scope shall be opened 5070c85bd05SIngo Weinhold if (path == NULL) { 5080c85bd05SIngo Weinhold *_handle = RLD_GLOBAL_SCOPE; 5090c85bd05SIngo Weinhold rld_unlock(); 5100c85bd05SIngo Weinhold return 0; 5110c85bd05SIngo Weinhold } 5120c85bd05SIngo Weinhold 513*94830eb2SIngo Weinhold image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE); 5140c85bd05SIngo Weinhold if (image != NULL && (flags & RTLD_GLOBAL) != 0) 5150c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 5160c85bd05SIngo Weinhold 5170c0fea5dSIngo Weinhold if (image) { 5180c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 5190c0fea5dSIngo Weinhold rld_unlock(); 5207486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path, 5217486b72dSIngo Weinhold image->id); 5220c85bd05SIngo Weinhold *_handle = image; 5230c0fea5dSIngo Weinhold return image->id; 5240c0fea5dSIngo Weinhold } 5250c0fea5dSIngo Weinhold } 5260c0fea5dSIngo Weinhold 527*94830eb2SIngo Weinhold status = load_image(path, type, NULL, &image); 5280c0fea5dSIngo Weinhold if (status < B_OK) { 5290c0fea5dSIngo Weinhold rld_unlock(); 5307486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, 5317486b72dSIngo Weinhold strerror(status)); 5320c0fea5dSIngo Weinhold return status; 5330c0fea5dSIngo Weinhold } 5340c0fea5dSIngo Weinhold 5350c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) { 5360c85bd05SIngo Weinhold if (addOn) 5370c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_add_on; 5380c85bd05SIngo Weinhold else 5390c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 5400c85bd05SIngo Weinhold } 5410c85bd05SIngo Weinhold 5420c85bd05SIngo Weinhold status = load_dependencies(image); 5430c0fea5dSIngo Weinhold if (status < B_OK) 5440c0fea5dSIngo Weinhold goto err; 5450c85bd05SIngo Weinhold 5460c85bd05SIngo Weinhold // If specified, set the RTLD_GLOBAL flag recursively on this image and all 5470c85bd05SIngo Weinhold // dependencies. If not specified, we temporarily set 5480c85bd05SIngo Weinhold // RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used 5490c85bd05SIngo Weinhold // for undefined symbol resolution. 5500c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) != 0) 5510c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 5520c85bd05SIngo Weinhold else 5530c85bd05SIngo Weinhold set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 5540c0fea5dSIngo Weinhold 5550c0fea5dSIngo Weinhold status = relocate_dependencies(image); 5560c0fea5dSIngo Weinhold if (status < B_OK) 5570c0fea5dSIngo Weinhold goto err; 5580c0fea5dSIngo Weinhold 5590c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) == 0) 5600c85bd05SIngo Weinhold clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 5610c85bd05SIngo Weinhold 5620c0fea5dSIngo Weinhold remap_images(); 5630c0fea5dSIngo Weinhold init_dependencies(image, true); 5640c0fea5dSIngo Weinhold 5650c0fea5dSIngo Weinhold rld_unlock(); 5667486b72dSIngo Weinhold 5677486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id); 5687486b72dSIngo Weinhold 5690c85bd05SIngo Weinhold *_handle = image; 5700c0fea5dSIngo Weinhold return image->id; 5710c0fea5dSIngo Weinhold 5720c0fea5dSIngo Weinhold err: 5737486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status)); 5747486b72dSIngo Weinhold 575*94830eb2SIngo Weinhold dequeue_loaded_image(image); 5760c0fea5dSIngo Weinhold delete_image(image); 5770c0fea5dSIngo Weinhold rld_unlock(); 5780c0fea5dSIngo Weinhold return status; 5790c0fea5dSIngo Weinhold } 5800c0fea5dSIngo Weinhold 5810c0fea5dSIngo Weinhold 5820c0fea5dSIngo Weinhold status_t 5830c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn) 5840c0fea5dSIngo Weinhold { 5850c0fea5dSIngo Weinhold image_t *image; 5860c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 5870c0fea5dSIngo Weinhold 5880c85bd05SIngo Weinhold if (handle == NULL && imageID < 0) 5890c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 5900c0fea5dSIngo Weinhold 5910c85bd05SIngo Weinhold if (handle == RLD_GLOBAL_SCOPE) 5920c85bd05SIngo Weinhold return B_OK; 5930c85bd05SIngo Weinhold 5940c0fea5dSIngo Weinhold rld_lock(); 5950c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 5960c0fea5dSIngo Weinhold 597*94830eb2SIngo Weinhold if (gInvalidImageIDs) { 5989a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 5999a6072a3SAxel Dörfler update_image_ids(); 6009a6072a3SAxel Dörfler } 6019a6072a3SAxel Dörfler 6020c0fea5dSIngo Weinhold // we only check images that have been already initialized 6030c0fea5dSIngo Weinhold 604df30098dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 605df30098dSIngo Weinhold 6060c85bd05SIngo Weinhold if (handle != NULL) { 6070c85bd05SIngo Weinhold image = (image_t*)handle; 6080c85bd05SIngo Weinhold put_image(image); 609df30098dSIngo Weinhold status = B_OK; 6100c85bd05SIngo Weinhold } else { 611*94830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, true); 612*94830eb2SIngo Weinhold if (image != NULL) { 6130c0fea5dSIngo Weinhold // unload image 6140c0fea5dSIngo Weinhold if (type == image->type) { 6150c0fea5dSIngo Weinhold put_image(image); 6160c0fea5dSIngo Weinhold status = B_OK; 6170c0fea5dSIngo Weinhold } else 6180c0fea5dSIngo Weinhold status = B_BAD_VALUE; 6190c0fea5dSIngo Weinhold } 6200c85bd05SIngo Weinhold } 6210c0fea5dSIngo Weinhold 6220c0fea5dSIngo Weinhold if (status == B_OK) { 623*94830eb2SIngo Weinhold while ((image = get_disposable_images().head) != NULL) { 6240c0fea5dSIngo Weinhold // call image fini here... 6258c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 6268c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 6273be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize); 6288c2a9d74SMichael Lotz } 6298c2a9d74SMichael Lotz 63010b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 63110b4b5d1SIngo Weinhold 6320c0fea5dSIngo Weinhold if (image->term_routine) 6330c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 6340c0fea5dSIngo Weinhold 635*94830eb2SIngo Weinhold dequeue_disposable_image(image); 6360c0fea5dSIngo Weinhold unmap_image(image); 6370c0fea5dSIngo Weinhold 63810b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 63910b4b5d1SIngo Weinhold 6400c0fea5dSIngo Weinhold delete_image(image); 6410c0fea5dSIngo Weinhold } 6420c0fea5dSIngo Weinhold } 6430c0fea5dSIngo Weinhold 6440c0fea5dSIngo Weinhold rld_unlock(); 6450c0fea5dSIngo Weinhold return status; 6460c0fea5dSIngo Weinhold } 6470c0fea5dSIngo Weinhold 6480c0fea5dSIngo Weinhold 6490c0fea5dSIngo Weinhold status_t 6509a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, 6519a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location) 6520c0fea5dSIngo Weinhold { 6530c0fea5dSIngo Weinhold int32 count = 0, j; 6540c0fea5dSIngo Weinhold uint32 i; 6550c0fea5dSIngo Weinhold image_t *image; 6560c0fea5dSIngo Weinhold 6570c0fea5dSIngo Weinhold rld_lock(); 6580c0fea5dSIngo Weinhold 6590c0fea5dSIngo Weinhold // get the image from those who have been already initialized 660*94830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false); 6610c0fea5dSIngo Weinhold if (image == NULL) { 6620c0fea5dSIngo Weinhold rld_unlock(); 6630c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 6640c0fea5dSIngo Weinhold } 6650c0fea5dSIngo Weinhold 6660c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 6670c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 6680c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 6690555803aSAxel Dörfler struct Elf32_Sym *symbol = &image->syms[j]; 6700c0fea5dSIngo Weinhold 6710c0fea5dSIngo Weinhold if (count == num) { 67210b4b5d1SIngo Weinhold const char* symbolName = SYMNAME(image, symbol); 67310b4b5d1SIngo Weinhold strlcpy(nameBuffer, symbolName, *_nameLength); 67410b4b5d1SIngo Weinhold *_nameLength = strlen(symbolName); 6750c0fea5dSIngo Weinhold 67610b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value 67710b4b5d1SIngo Weinhold + image->regions[0].delta); 67810b4b5d1SIngo Weinhold int32 type; 6790c0fea5dSIngo Weinhold if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) 68010b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 6810c0fea5dSIngo Weinhold else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) 68210b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 6830c0fea5dSIngo Weinhold else 68410b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_ANY; 68510b4b5d1SIngo Weinhold // TODO: check with the return types of that BeOS function 6860c0fea5dSIngo Weinhold 68710b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &type); 68810b4b5d1SIngo Weinhold 68910b4b5d1SIngo Weinhold if (_type != NULL) 69010b4b5d1SIngo Weinhold *_type = type; 6910c0fea5dSIngo Weinhold if (_location != NULL) 69210b4b5d1SIngo Weinhold *_location = location; 6930c0fea5dSIngo Weinhold goto out; 6940c0fea5dSIngo Weinhold } 6950c0fea5dSIngo Weinhold count++; 6960c0fea5dSIngo Weinhold } 6970c0fea5dSIngo Weinhold } 6980c0fea5dSIngo Weinhold out: 6990c0fea5dSIngo Weinhold rld_unlock(); 7000c0fea5dSIngo Weinhold 7010c0fea5dSIngo Weinhold if (num != count) 7020c0fea5dSIngo Weinhold return B_BAD_INDEX; 7030c0fea5dSIngo Weinhold 7040c0fea5dSIngo Weinhold return B_OK; 7050c0fea5dSIngo Weinhold } 7060c0fea5dSIngo Weinhold 7070c0fea5dSIngo Weinhold 7080c0fea5dSIngo Weinhold status_t 7099a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType, 71080ece785SIngo Weinhold bool recursive, image_id *_inImage, void **_location) 7110c0fea5dSIngo Weinhold { 7120c0fea5dSIngo Weinhold status_t status = B_OK; 7130c0fea5dSIngo Weinhold image_t *image; 7140c0fea5dSIngo Weinhold 7150c0fea5dSIngo Weinhold if (imageID < B_OK) 7160c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 7170c0fea5dSIngo Weinhold if (symbolName == NULL) 7180c0fea5dSIngo Weinhold return B_BAD_VALUE; 7190c0fea5dSIngo Weinhold 7200c0fea5dSIngo Weinhold rld_lock(); 7210c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 7220c0fea5dSIngo Weinhold 7230c0fea5dSIngo Weinhold // get the image from those who have been already initialized 724*94830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false); 72580ece785SIngo Weinhold if (image != NULL) { 72680ece785SIngo Weinhold if (recursive) { 72780ece785SIngo Weinhold // breadth-first search in the given image and its dependencies 728003ebb0eSIngo Weinhold status = find_symbol_breadth_first(image, 729003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 730003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 73180ece785SIngo Weinhold &image, _location); 732003ebb0eSIngo Weinhold } else { 733003ebb0eSIngo Weinhold status = find_symbol(image, 734003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 735003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 736003ebb0eSIngo Weinhold _location); 737003ebb0eSIngo Weinhold } 73880ece785SIngo Weinhold 73980ece785SIngo Weinhold if (status == B_OK && _inImage != NULL) 74080ece785SIngo Weinhold *_inImage = image->id; 74180ece785SIngo Weinhold } else 7420c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 7430c0fea5dSIngo Weinhold 7440c0fea5dSIngo Weinhold rld_unlock(); 7450c0fea5dSIngo Weinhold return status; 7460c0fea5dSIngo Weinhold } 7470c0fea5dSIngo Weinhold 7480c0fea5dSIngo Weinhold 7490c0fea5dSIngo Weinhold status_t 7500c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName, 7510c85bd05SIngo Weinhold void **_location) 7520c85bd05SIngo Weinhold { 7530c85bd05SIngo Weinhold status_t status = B_ENTRY_NOT_FOUND; 7540c85bd05SIngo Weinhold 7550c85bd05SIngo Weinhold if (symbolName == NULL) 7560c85bd05SIngo Weinhold return B_BAD_VALUE; 7570c85bd05SIngo Weinhold 7580c85bd05SIngo Weinhold rld_lock(); 7590c85bd05SIngo Weinhold // for now, just do stupid simple global locking 7600c85bd05SIngo Weinhold 7610c85bd05SIngo Weinhold if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) { 7620c85bd05SIngo Weinhold // look in the default scope 7630c85bd05SIngo Weinhold image_t* image; 764*94830eb2SIngo Weinhold Elf32_Sym* symbol = find_undefined_symbol_global(gProgramImage, 765*94830eb2SIngo Weinhold gProgramImage, 766003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 767003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 768003ebb0eSIngo Weinhold &image); 7690c85bd05SIngo Weinhold if (symbol != NULL) { 7700c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value + image->regions[0].delta); 7710c85bd05SIngo Weinhold int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC 7720c85bd05SIngo Weinhold ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 7730c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, &symbolType); 7740c85bd05SIngo Weinhold status = B_OK; 7750c85bd05SIngo Weinhold } 7760c85bd05SIngo Weinhold } else if (handle == RTLD_NEXT) { 7770c85bd05SIngo Weinhold // Look in the default scope, but also in the dependencies of the 7780c85bd05SIngo Weinhold // calling image. Return the next after the caller symbol. 7790c85bd05SIngo Weinhold 780a2dad9e1SIngo Weinhold // First of all, find the caller image. 781*94830eb2SIngo Weinhold image_t* callerImage = get_loaded_images().head; 7820c85bd05SIngo Weinhold for (; callerImage != NULL; callerImage = callerImage->next) { 7830c85bd05SIngo Weinhold elf_region_t& text = callerImage->regions[0]; 784a2dad9e1SIngo Weinhold if ((addr_t)caller >= text.vmstart 785a2dad9e1SIngo Weinhold && (addr_t)caller < text.vmstart + text.vmsize) { 786a2dad9e1SIngo Weinhold // found the image 7870c85bd05SIngo Weinhold break; 7880c85bd05SIngo Weinhold } 7890c85bd05SIngo Weinhold } 7900c85bd05SIngo Weinhold 791a2dad9e1SIngo Weinhold if (callerImage != NULL) { 7920c85bd05SIngo Weinhold // found the caller -- now search the global scope until we find 7930c85bd05SIngo Weinhold // the next symbol 794a2dad9e1SIngo Weinhold bool hitCallerImage = false; 7950c85bd05SIngo Weinhold set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 7960c85bd05SIngo Weinhold 797*94830eb2SIngo Weinhold image_t* image = get_loaded_images().head; 7980c85bd05SIngo Weinhold for (; image != NULL; image = image->next) { 799a2dad9e1SIngo Weinhold // skip the caller image 800a2dad9e1SIngo Weinhold if (image == callerImage) { 801a2dad9e1SIngo Weinhold hitCallerImage = true; 802a2dad9e1SIngo Weinhold continue; 803a2dad9e1SIngo Weinhold } 804a2dad9e1SIngo Weinhold 805a2dad9e1SIngo Weinhold // skip all images up to the caller image; also skip add-on 806a2dad9e1SIngo Weinhold // images and those not marked above for resolution 807a2dad9e1SIngo Weinhold if (!hitCallerImage || image->type == B_ADD_ON_IMAGE 8080c85bd05SIngo Weinhold || (image->flags 809a2dad9e1SIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) { 8100c85bd05SIngo Weinhold continue; 8110c85bd05SIngo Weinhold } 8120c85bd05SIngo Weinhold 813003ebb0eSIngo Weinhold struct Elf32_Sym *symbol = find_symbol(image, 814003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL, 815003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION)); 8160c85bd05SIngo Weinhold if (symbol == NULL) 8170c85bd05SIngo Weinhold continue; 8180c85bd05SIngo Weinhold 819a2dad9e1SIngo Weinhold // found the symbol 8200c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value 8210c85bd05SIngo Weinhold + image->regions[0].delta); 8220c85bd05SIngo Weinhold int32 symbolType = B_SYMBOL_TYPE_TEXT; 8230c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, 8240c85bd05SIngo Weinhold &symbolType); 8250c85bd05SIngo Weinhold status = B_OK; 8260c85bd05SIngo Weinhold break; 8270c85bd05SIngo Weinhold } 8280c85bd05SIngo Weinhold 8290c85bd05SIngo Weinhold clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 8300c85bd05SIngo Weinhold } 8310c85bd05SIngo Weinhold } else { 8320c85bd05SIngo Weinhold // breadth-first search in the given image and its dependencies 8330c85bd05SIngo Weinhold image_t* inImage; 834003ebb0eSIngo Weinhold status = find_symbol_breadth_first((image_t*)handle, 835003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 836003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 837003ebb0eSIngo Weinhold &inImage, _location); 8380c85bd05SIngo Weinhold } 8390c85bd05SIngo Weinhold 8400c85bd05SIngo Weinhold rld_unlock(); 8410c85bd05SIngo Weinhold return status; 8420c85bd05SIngo Weinhold } 8430c85bd05SIngo Weinhold 8440c85bd05SIngo Weinhold 8450c85bd05SIngo Weinhold status_t 8460c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 8470c0fea5dSIngo Weinhold { 8480c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 8490c0fea5dSIngo Weinhold struct Elf32_Dyn *dynamicSection; 8500c0fea5dSIngo Weinhold image_t *image; 8510c0fea5dSIngo Weinhold 8520c0fea5dSIngo Weinhold if (_name == NULL) 8530c0fea5dSIngo Weinhold return B_BAD_VALUE; 8540c0fea5dSIngo Weinhold 8550c0fea5dSIngo Weinhold rld_lock(); 8560c0fea5dSIngo Weinhold 857*94830eb2SIngo Weinhold image = find_loaded_image_by_id(id, false); 8580c0fea5dSIngo Weinhold if (image == NULL) { 8590c0fea5dSIngo Weinhold rld_unlock(); 8600c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 8610c0fea5dSIngo Weinhold } 8620c0fea5dSIngo Weinhold 8630c0fea5dSIngo Weinhold dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr; 8640c0fea5dSIngo Weinhold if (dynamicSection == NULL || image->num_needed <= searchIndex) { 8650c0fea5dSIngo Weinhold rld_unlock(); 8660c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 8670c0fea5dSIngo Weinhold } 8680c0fea5dSIngo Weinhold 8690c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 8700c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 8710c0fea5dSIngo Weinhold continue; 8720c0fea5dSIngo Weinhold 8730c0fea5dSIngo Weinhold if (j++ == searchIndex) { 8740c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 8750c0fea5dSIngo Weinhold 8760c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 8770c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 8780c0fea5dSIngo Weinhold rld_unlock(); 8790c0fea5dSIngo Weinhold return B_OK; 8800c0fea5dSIngo Weinhold } 8810c0fea5dSIngo Weinhold } 8820c0fea5dSIngo Weinhold 8830c0fea5dSIngo Weinhold rld_unlock(); 8840c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 8850c0fea5dSIngo Weinhold } 8860c0fea5dSIngo Weinhold 8870c0fea5dSIngo Weinhold 88874c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 8890c0fea5dSIngo Weinhold 8900c0fea5dSIngo Weinhold 8919a6072a3SAxel Dörfler /*! Read and verify the ELF header */ 8920c0fea5dSIngo Weinhold status_t 8930c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length) 8940c0fea5dSIngo Weinhold { 8950c0fea5dSIngo Weinhold int32 programSize, sectionSize; 8960c0fea5dSIngo Weinhold 8970c0fea5dSIngo Weinhold if (length < (int32)sizeof(struct Elf32_Ehdr)) 8980c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 8990c0fea5dSIngo Weinhold 9009a6072a3SAxel Dörfler return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, 9019a6072a3SAxel Dörfler §ionSize); 9020c0fea5dSIngo Weinhold } 9030c0fea5dSIngo Weinhold 9040c0fea5dSIngo Weinhold 9050c0fea5dSIngo Weinhold void 9060c0fea5dSIngo Weinhold terminate_program(void) 9070c0fea5dSIngo Weinhold { 9080c0fea5dSIngo Weinhold image_t **termList; 9090c0fea5dSIngo Weinhold ssize_t count, i; 9100c0fea5dSIngo Weinhold 911*94830eb2SIngo Weinhold count = get_sorted_image_list(gProgramImage, &termList, RFLAG_TERMINATED); 9120c0fea5dSIngo Weinhold if (count < B_OK) 9130c0fea5dSIngo Weinhold return; 9140c0fea5dSIngo Weinhold 915*94830eb2SIngo Weinhold if (gInvalidImageIDs) { 9169a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 9179a6072a3SAxel Dörfler update_image_ids(); 9189a6072a3SAxel Dörfler } 9199a6072a3SAxel Dörfler 9200c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 9210c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 9220c0fea5dSIngo Weinhold image_t *image = termList[i]; 9230c0fea5dSIngo Weinhold 9240c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 9250c0fea5dSIngo Weinhold 92610b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 92710b4b5d1SIngo Weinhold 9280c0fea5dSIngo Weinhold if (image->term_routine) 9290c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 93010b4b5d1SIngo Weinhold 93110b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 9320c0fea5dSIngo Weinhold } 9330c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 9340c0fea5dSIngo Weinhold 9350c0fea5dSIngo Weinhold free(termList); 9360c0fea5dSIngo Weinhold } 9370c0fea5dSIngo Weinhold 9380c0fea5dSIngo Weinhold 9390c0fea5dSIngo Weinhold void 9400c0fea5dSIngo Weinhold rldelf_init(void) 9410c0fea5dSIngo Weinhold { 942e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 943e73923b0SAxel Dörfler sSemOwner = -1; 944e73923b0SAxel Dörfler sSemCount = 0; 9450c0fea5dSIngo Weinhold 946*94830eb2SIngo Weinhold init_add_ons(); 947*94830eb2SIngo Weinhold 9480c0fea5dSIngo Weinhold // create the debug area 9490c0fea5dSIngo Weinhold { 9500c0fea5dSIngo Weinhold int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 9510c0fea5dSIngo Weinhold 9520c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 9530c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 9540c0fea5dSIngo Weinhold (void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK, 9550c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 9560c0fea5dSIngo Weinhold if (areaID < B_OK) { 9570c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 9580c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 9590c0fea5dSIngo Weinhold } 9600c0fea5dSIngo Weinhold 961*94830eb2SIngo Weinhold area->loaded_images = &get_loaded_images(); 9620c0fea5dSIngo Weinhold } 96374c0424aSAxel Dörfler 96474c0424aSAxel Dörfler // initialize error message if needed 9654bef3723SAxel Dörfler if (report_errors()) { 96674c0424aSAxel Dörfler void *buffer = malloc(1024); 96774c0424aSAxel Dörfler if (buffer == NULL) 96874c0424aSAxel Dörfler return; 96974c0424aSAxel Dörfler 970*94830eb2SIngo Weinhold gErrorMessage.SetTo(buffer, 1024, 'Rler'); 97174c0424aSAxel Dörfler } 9720c0fea5dSIngo Weinhold } 9731873b4b3SIngo Weinhold 9741873b4b3SIngo Weinhold 9751873b4b3SIngo Weinhold status_t 9769a6072a3SAxel Dörfler elf_reinit_after_fork(void) 9771873b4b3SIngo Weinhold { 978e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 979e73923b0SAxel Dörfler if (sSem < 0) 980e73923b0SAxel Dörfler return sSem; 9811873b4b3SIngo Weinhold 9829a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and 983cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork() 984cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one 9859a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different. 986*94830eb2SIngo Weinhold gInvalidImageIDs = true; 987cbc456deSIngo Weinhold 9881873b4b3SIngo Weinhold return B_OK; 9891873b4b3SIngo Weinhold } 990