10c0fea5dSIngo Weinhold /* 2aa3507feSIngo Weinhold * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3b6455c08SAxel Dörfler * Copyright 2003-2011, Axel Dörfler, axeld@pinc-software.de. 40c0fea5dSIngo Weinhold * Distributed under the terms of the MIT License. 50c0fea5dSIngo Weinhold * 60c0fea5dSIngo Weinhold * Copyright 2002, Manuel J. Petit. All rights reserved. 70c0fea5dSIngo Weinhold * Copyright 2001, Travis Geiselbrecht. All rights reserved. 80c0fea5dSIngo Weinhold * Distributed under the terms of the NewOS License. 90c0fea5dSIngo Weinhold */ 100c0fea5dSIngo Weinhold 110c0fea5dSIngo Weinhold #include "runtime_loader_private.h" 120c0fea5dSIngo Weinhold 13ca618b22SIngo Weinhold #include <ctype.h> 140c85bd05SIngo Weinhold #include <dlfcn.h> 150c0fea5dSIngo Weinhold #include <stdio.h> 160c0fea5dSIngo Weinhold #include <stdlib.h> 1734982809SIngo Weinhold #include <string.h> 180c0fea5dSIngo Weinhold 19ca618b22SIngo Weinhold #include <OS.h> 20ca618b22SIngo Weinhold 217486b72dSIngo Weinhold #include <syscalls.h> 2210b4b5d1SIngo Weinhold #include <util/kernel_cpp.h> 237486b72dSIngo Weinhold 24f2bb2575SIngo Weinhold #include <locks.h> 25f2bb2575SIngo Weinhold 2694830eb2SIngo Weinhold #include "add_ons.h" 2794830eb2SIngo Weinhold #include "elf_load_image.h" 2894830eb2SIngo Weinhold #include "elf_symbol_lookup.h" 2944c0c4d3SPawel Dziepak #include "elf_tls.h" 3094830eb2SIngo Weinhold #include "elf_versioning.h" 3194830eb2SIngo Weinhold #include "errors.h" 3294830eb2SIngo Weinhold #include "images.h" 330c0fea5dSIngo Weinhold 340c0fea5dSIngo Weinhold 3510b4b5d1SIngo Weinhold // TODO: implement better locking strategy 3610b4b5d1SIngo Weinhold // TODO: implement lazy binding 370c0fea5dSIngo Weinhold 380c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen()) 390c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE ((void*)-2l) 400c85bd05SIngo Weinhold 41f7127458SIngo Weinhold static const char* const kLockName = "runtime loader"; 42f7127458SIngo Weinhold 430c0fea5dSIngo Weinhold 440c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 45354b60afSAugustin Cavalier typedef void (*initfini_array_function)(); 460c0fea5dSIngo Weinhold 4794830eb2SIngo Weinhold bool gProgramLoaded = false; 4894830eb2SIngo Weinhold image_t* gProgramImage; 49003ebb0eSIngo Weinhold 5035fa85dbSJérôme Duval static image_t** sPreloadedAddons = NULL; 5135fa85dbSJérôme Duval static uint32 sPreloadedAddonCount = 0; 520c0fea5dSIngo Weinhold 53f7127458SIngo Weinhold static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName); 540c0fea5dSIngo Weinhold 557486b72dSIngo Weinhold 560c0fea5dSIngo Weinhold static const char * 570c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 580c0fea5dSIngo Weinhold { 590c0fea5dSIngo Weinhold int i; 60e3ac2588SAlex Smith elf_dyn *d = (elf_dyn *)image->dynamic_ptr; 610c0fea5dSIngo Weinhold 620c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 630c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 640c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 650c0fea5dSIngo Weinhold } 660c0fea5dSIngo Weinhold 670c0fea5dSIngo Weinhold return NULL; 680c0fea5dSIngo Weinhold } 690c0fea5dSIngo Weinhold 700c0fea5dSIngo Weinhold 7135fa85dbSJérôme Duval image_id 7235fa85dbSJérôme Duval preload_image(char const* path, image_t **image) 7335fa85dbSJérôme Duval { 7435fa85dbSJérôme Duval if (path == NULL) 7535fa85dbSJérôme Duval return B_BAD_VALUE; 7635fa85dbSJérôme Duval 7735fa85dbSJérôme Duval KTRACE("rld: preload_image(\"%s\")", path); 7835fa85dbSJérôme Duval 7935fa85dbSJérôme Duval status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, image); 8035fa85dbSJérôme Duval if (status < B_OK) { 8135fa85dbSJérôme Duval KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, 8235fa85dbSJérôme Duval strerror(status)); 8335fa85dbSJérôme Duval return status; 8435fa85dbSJérôme Duval } 8535fa85dbSJérôme Duval 8635fa85dbSJérôme Duval if ((*image)->find_undefined_symbol == NULL) 8735fa85dbSJérôme Duval (*image)->find_undefined_symbol = find_undefined_symbol_global; 8835fa85dbSJérôme Duval 8935fa85dbSJérôme Duval KTRACE("rld: preload_image(\"%s\") done: id: %" B_PRId32, path, (*image)->id); 9035fa85dbSJérôme Duval 9135fa85dbSJérôme Duval return (*image)->id; 9235fa85dbSJérôme Duval } 9335fa85dbSJérôme Duval 9435fa85dbSJérôme Duval 9535fa85dbSJérôme Duval static void 9635fa85dbSJérôme Duval preload_images(image_t **image, int32 *_count = NULL) 9735fa85dbSJérôme Duval { 9835fa85dbSJérôme Duval const char* imagePaths = getenv("LD_PRELOAD"); 9935fa85dbSJérôme Duval if (imagePaths == NULL) { 10035fa85dbSJérôme Duval if (_count != NULL) 10135fa85dbSJérôme Duval *_count = 0; 10235fa85dbSJérôme Duval return; 10335fa85dbSJérôme Duval } 10435fa85dbSJérôme Duval 10535fa85dbSJérôme Duval int32 count = 0; 10635fa85dbSJérôme Duval 10735fa85dbSJérôme Duval while (*imagePaths != '\0') { 10835fa85dbSJérôme Duval // find begin of image path 10935fa85dbSJérôme Duval while (*imagePaths != '\0' && isspace(*imagePaths)) 11035fa85dbSJérôme Duval imagePaths++; 11135fa85dbSJérôme Duval 11235fa85dbSJérôme Duval if (*imagePaths == '\0') 11335fa85dbSJérôme Duval break; 11435fa85dbSJérôme Duval 11535fa85dbSJérôme Duval // find end of image path 11635fa85dbSJérôme Duval const char* imagePath = imagePaths; 11735fa85dbSJérôme Duval while (*imagePaths != '\0' && !isspace(*imagePaths)) 11835fa85dbSJérôme Duval imagePaths++; 11935fa85dbSJérôme Duval 12035fa85dbSJérôme Duval // extract the path 12135fa85dbSJérôme Duval char path[B_PATH_NAME_LENGTH]; 12235fa85dbSJérôme Duval size_t pathLen = imagePaths - imagePath; 12335fa85dbSJérôme Duval if (pathLen > sizeof(path) - 1) 12435fa85dbSJérôme Duval continue; 12535fa85dbSJérôme Duval 12635fa85dbSJérôme Duval if (image == NULL) { 12735fa85dbSJérôme Duval count++; 12835fa85dbSJérôme Duval continue; 12935fa85dbSJérôme Duval } 13035fa85dbSJérôme Duval memcpy(path, imagePath, pathLen); 13135fa85dbSJérôme Duval path[pathLen] = '\0'; 13235fa85dbSJérôme Duval 13335fa85dbSJérôme Duval // load the image 13435fa85dbSJérôme Duval preload_image(path, &image[count++]); 13535fa85dbSJérôme Duval } 13635fa85dbSJérôme Duval 13735fa85dbSJérôme Duval KTRACE("rld: preload_images count: %d", count); 13835fa85dbSJérôme Duval 13935fa85dbSJérôme Duval if (_count != NULL) 14035fa85dbSJérôme Duval *_count = count; 14135fa85dbSJérôme Duval } 14235fa85dbSJérôme Duval 14335fa85dbSJérôme Duval 1440c0fea5dSIngo Weinhold static status_t 14535fa85dbSJérôme Duval load_immediate_dependencies(image_t *image, bool preload) 1460c0fea5dSIngo Weinhold { 147e3ac2588SAlex Smith elf_dyn *d = (elf_dyn *)image->dynamic_ptr; 1484bef3723SAxel Dörfler bool reportErrors = report_errors(); 14974c0424aSAxel Dörfler status_t status = B_OK; 1500c0fea5dSIngo Weinhold uint32 i, j; 1510c0fea5dSIngo Weinhold const char *rpath; 1520c0fea5dSIngo Weinhold 1530c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 1540c0fea5dSIngo Weinhold return B_OK; 1550c0fea5dSIngo Weinhold 1560c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 1570c0fea5dSIngo Weinhold 15835fa85dbSJérôme Duval int32 preloadedCount = 0; 15935fa85dbSJérôme Duval if (preload) { 16035fa85dbSJérôme Duval preload_images(NULL, &preloadedCount); 16135fa85dbSJérôme Duval image->num_needed += preloadedCount; 16235fa85dbSJérôme Duval } 1630c0fea5dSIngo Weinhold if (image->num_needed == 0) 1640c0fea5dSIngo Weinhold return B_OK; 1650c0fea5dSIngo Weinhold 166ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ")", image->name, 1677486b72dSIngo Weinhold image->id); 1687486b72dSIngo Weinhold 1690c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 1700c0fea5dSIngo Weinhold if (image->needed == NULL) { 171c533f813SIngo Weinhold FATAL("%s: Failed to allocate needed struct\n", image->path); 172ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 173ded25be1SIngo Weinhold ") failed: no memory", image->name, image->id); 1740c0fea5dSIngo Weinhold return B_NO_MEMORY; 1750c0fea5dSIngo Weinhold } 1760c0fea5dSIngo Weinhold 1770c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 17835fa85dbSJérôme Duval if (preload) 17935fa85dbSJérôme Duval preload_images(image->needed); 1800c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 1810c0fea5dSIngo Weinhold 18235fa85dbSJérôme Duval for (i = 0, j = preloadedCount; d[i].d_tag != DT_NULL; i++) { 1830c0fea5dSIngo Weinhold switch (d[i].d_tag) { 1840c0fea5dSIngo Weinhold case DT_NEEDED: 18574c0424aSAxel Dörfler { 18674c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 18774c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 1880c0fea5dSIngo Weinhold 18994830eb2SIngo Weinhold status_t loadStatus = load_image(name, B_LIBRARY_IMAGE, 1908d23c440SIngo Weinhold rpath, image->path, &image->needed[j]); 19174c0424aSAxel Dörfler if (loadStatus < B_OK) { 19274c0424aSAxel Dörfler status = loadStatus; 19374c0424aSAxel Dörfler // correct error code in case the file could not been found 19474c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 19574c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 19674c0424aSAxel Dörfler 19774c0424aSAxel Dörfler if (reportErrors) 19894830eb2SIngo Weinhold gErrorMessage.AddString("missing library", name); 19974c0424aSAxel Dörfler } 20074c0424aSAxel Dörfler 20174c0424aSAxel Dörfler // Collect all missing libraries in case we report back 2027486b72dSIngo Weinhold if (!reportErrors) { 203ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 204ded25be1SIngo Weinhold ") failed: %s", image->name, image->id, 2057486b72dSIngo Weinhold strerror(status)); 2060c0fea5dSIngo Weinhold return status; 20774c0424aSAxel Dörfler } 2087486b72dSIngo Weinhold } 2090c0fea5dSIngo Weinhold 2100c0fea5dSIngo Weinhold j += 1; 2110c0fea5dSIngo Weinhold break; 21274c0424aSAxel Dörfler } 2130c0fea5dSIngo Weinhold 2140c0fea5dSIngo Weinhold default: 2150c0fea5dSIngo Weinhold // ignore any other tag 2160c0fea5dSIngo Weinhold continue; 2170c0fea5dSIngo Weinhold } 2180c0fea5dSIngo Weinhold } 2190c0fea5dSIngo Weinhold 2207486b72dSIngo Weinhold if (status < B_OK) { 221ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") " 2227486b72dSIngo Weinhold "failed: %s", image->name, image->id, 2237486b72dSIngo Weinhold strerror(status)); 22474c0424aSAxel Dörfler return status; 2257486b72dSIngo Weinhold } 22674c0424aSAxel Dörfler 2270c0fea5dSIngo Weinhold if (j != image->num_needed) { 2280c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 229ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") " 2307486b72dSIngo Weinhold "failed: internal error", image->name, image->id); 2310c0fea5dSIngo Weinhold return B_ERROR; 2320c0fea5dSIngo Weinhold } 2330c0fea5dSIngo Weinhold 234ded25be1SIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %" B_PRId32 ") done", 235ded25be1SIngo Weinhold image->name, image->id); 2367486b72dSIngo Weinhold 2370c0fea5dSIngo Weinhold return B_OK; 2380c0fea5dSIngo Weinhold } 2390c0fea5dSIngo Weinhold 2400c0fea5dSIngo Weinhold 2410c85bd05SIngo Weinhold static status_t 24235fa85dbSJérôme Duval load_dependencies(image_t* image, bool preload = false) 2430c85bd05SIngo Weinhold { 244003ebb0eSIngo Weinhold // load dependencies (breadth-first) 2450c85bd05SIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 2460c85bd05SIngo Weinhold otherImage = otherImage->next) { 24735fa85dbSJérôme Duval status_t status = load_immediate_dependencies(otherImage, preload); 2480c85bd05SIngo Weinhold if (status != B_OK) 2490c85bd05SIngo Weinhold return status; 25035fa85dbSJérôme Duval preload = false; 2510c85bd05SIngo Weinhold } 2520c85bd05SIngo Weinhold 253003ebb0eSIngo Weinhold // Check the needed versions for the given image and all newly loaded 254003ebb0eSIngo Weinhold // dependencies. 255003ebb0eSIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 256003ebb0eSIngo Weinhold otherImage = otherImage->next) { 257003ebb0eSIngo Weinhold status_t status = check_needed_image_versions(otherImage); 258003ebb0eSIngo Weinhold if (status != B_OK) 259003ebb0eSIngo Weinhold return status; 260003ebb0eSIngo Weinhold } 261003ebb0eSIngo Weinhold 2620c85bd05SIngo Weinhold return B_OK; 2630c85bd05SIngo Weinhold } 2640c85bd05SIngo Weinhold 2650c85bd05SIngo Weinhold 26694830eb2SIngo Weinhold static status_t 26794830eb2SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 2680c0fea5dSIngo Weinhold { 26925dc253dSIngo Weinhold SymbolLookupCache cache(image); 27025dc253dSIngo Weinhold 27125dc253dSIngo Weinhold status_t status = arch_relocate_image(rootImage, image, &cache); 27294830eb2SIngo Weinhold if (status < B_OK) { 273c533f813SIngo Weinhold FATAL("%s: Troubles relocating: %s\n", image->path, strerror(status)); 27494830eb2SIngo Weinhold return status; 2750c0fea5dSIngo Weinhold } 2760c0fea5dSIngo Weinhold 27794830eb2SIngo Weinhold _kern_image_relocated(image->id); 27894830eb2SIngo Weinhold image_event(image, IMAGE_EVENT_RELOCATED); 27994830eb2SIngo Weinhold return B_OK; 2800c0fea5dSIngo Weinhold } 2810c0fea5dSIngo Weinhold 2820c0fea5dSIngo Weinhold 2830c0fea5dSIngo Weinhold static status_t 2840c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 2850c0fea5dSIngo Weinhold { 286ca618b22SIngo Weinhold // get the images that still have to be relocated 287ca618b22SIngo Weinhold image_t **list; 288ca618b22SIngo Weinhold ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 2890c0fea5dSIngo Weinhold if (count < B_OK) 2900c0fea5dSIngo Weinhold return count; 2910c0fea5dSIngo Weinhold 2920c85bd05SIngo Weinhold // relocate 293ca618b22SIngo Weinhold for (ssize_t i = 0; i < count; i++) { 29446f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 2950c85bd05SIngo Weinhold if (status < B_OK) { 2960c85bd05SIngo Weinhold free(list); 2970c0fea5dSIngo Weinhold return status; 2980c0fea5dSIngo Weinhold } 2990c85bd05SIngo Weinhold } 3000c0fea5dSIngo Weinhold 3010c0fea5dSIngo Weinhold free(list); 3020c0fea5dSIngo Weinhold return B_OK; 3030c0fea5dSIngo Weinhold } 3040c0fea5dSIngo Weinhold 3050c0fea5dSIngo Weinhold 3060c0fea5dSIngo Weinhold static void 3070c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 3080c0fea5dSIngo Weinhold { 309*58dcc29bSAugustin Cavalier image_t **initList = NULL; 3100c0fea5dSIngo Weinhold ssize_t count, i; 3110c0fea5dSIngo Weinhold 3123a75ef9aSJérôme Duval if (initHead && image->preinit_array) { 3133a75ef9aSJérôme Duval uint count_preinit = image->preinit_array_len / sizeof(addr_t); 3143a75ef9aSJérôme Duval for (uint j = 0; j < count_preinit; j++) 3153a75ef9aSJérôme Duval ((initfini_array_function)image->preinit_array[j])(); 3163a75ef9aSJérôme Duval } 3173a75ef9aSJérôme Duval 3180c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 319*58dcc29bSAugustin Cavalier if (count <= 0) { 320*58dcc29bSAugustin Cavalier free(initList); 3210c0fea5dSIngo Weinhold return; 322*58dcc29bSAugustin Cavalier } 3230c0fea5dSIngo Weinhold 3240c0fea5dSIngo Weinhold if (!initHead) { 3250c0fea5dSIngo Weinhold // this removes the "calling" image 3260c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 3270c0fea5dSIngo Weinhold initList[--count] = NULL; 3280c0fea5dSIngo Weinhold } 3290c0fea5dSIngo Weinhold 3300c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 3310c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 3320c0fea5dSIngo Weinhold image = initList[i]; 3330c0fea5dSIngo Weinhold 3340c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 3350c0fea5dSIngo Weinhold 336354b60afSAugustin Cavalier init_term_function before; 337354b60afSAugustin Cavalier if (find_symbol(image, 338354b60afSAugustin Cavalier SymbolLookupInfo(B_INIT_BEFORE_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT), 339354b60afSAugustin Cavalier (void**)&before) == B_OK) { 340354b60afSAugustin Cavalier before(image->id); 341e340f717SJérôme Duval } 342e340f717SJérôme Duval 343dd76bc97SIngo Weinhold if (image->init_routine != 0) 3440c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 34510b4b5d1SIngo Weinhold 346e340f717SJérôme Duval if (image->init_array) { 347e340f717SJérôme Duval uint count_init = image->init_array_len / sizeof(addr_t); 348e340f717SJérôme Duval for (uint j = 0; j < count_init; j++) 349354b60afSAugustin Cavalier ((initfini_array_function)image->init_array[j])(); 350354b60afSAugustin Cavalier } 351354b60afSAugustin Cavalier 352354b60afSAugustin Cavalier init_term_function after; 353354b60afSAugustin Cavalier if (find_symbol(image, 354354b60afSAugustin Cavalier SymbolLookupInfo(B_INIT_AFTER_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT), 355354b60afSAugustin Cavalier (void**)&after) == B_OK) { 356354b60afSAugustin Cavalier after(image->id); 357e340f717SJérôme Duval } 358e340f717SJérôme Duval 35910b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_INITIALIZED); 3600c0fea5dSIngo Weinhold } 3610c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 3620c0fea5dSIngo Weinhold 3630c0fea5dSIngo Weinhold free(initList); 3640c0fea5dSIngo Weinhold } 3650c0fea5dSIngo Weinhold 3660c0fea5dSIngo Weinhold 3670c0fea5dSIngo Weinhold static void 3685d08e3a5SAugustin Cavalier call_term_functions(image_t* image) 3695d08e3a5SAugustin Cavalier { 3705d08e3a5SAugustin Cavalier init_term_function before; 3715d08e3a5SAugustin Cavalier if (find_symbol(image, 3725d08e3a5SAugustin Cavalier SymbolLookupInfo(B_TERM_BEFORE_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT), 3735d08e3a5SAugustin Cavalier (void**)&before) == B_OK) { 3745d08e3a5SAugustin Cavalier before(image->id); 3755d08e3a5SAugustin Cavalier } 3765d08e3a5SAugustin Cavalier 3775d08e3a5SAugustin Cavalier if (image->term_array) { 3785d08e3a5SAugustin Cavalier uint count_term = image->term_array_len / sizeof(addr_t); 3795d08e3a5SAugustin Cavalier for (uint i = count_term; i-- > 0;) 3805d08e3a5SAugustin Cavalier ((initfini_array_function)image->term_array[i])(); 3815d08e3a5SAugustin Cavalier } 3825d08e3a5SAugustin Cavalier 3835d08e3a5SAugustin Cavalier if (image->term_routine) 3845d08e3a5SAugustin Cavalier ((init_term_function)image->term_routine)(image->id); 3855d08e3a5SAugustin Cavalier 3865d08e3a5SAugustin Cavalier init_term_function after; 3875d08e3a5SAugustin Cavalier if (find_symbol(image, 3885d08e3a5SAugustin Cavalier SymbolLookupInfo(B_TERM_AFTER_FUNCTION_NAME, B_SYMBOL_TYPE_TEXT), 3895d08e3a5SAugustin Cavalier (void**)&after) == B_OK) { 3905d08e3a5SAugustin Cavalier after(image->id); 3915d08e3a5SAugustin Cavalier } 3925d08e3a5SAugustin Cavalier } 3935d08e3a5SAugustin Cavalier 3945d08e3a5SAugustin Cavalier 3955d08e3a5SAugustin Cavalier static void 396ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage) 397ca618b22SIngo Weinhold { 398ca618b22SIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private 399ca618b22SIngo Weinhold // API. 400ca618b22SIngo Weinhold image_t* image; 4010c85bd05SIngo Weinhold void* _export; 402003ebb0eSIngo Weinhold if (find_symbol_breadth_first(rootImage, 403003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image, 404003ebb0eSIngo Weinhold &_export) == B_OK) { 4050c85bd05SIngo Weinhold *(void**)_export = &gRuntimeLoader; 406ca618b22SIngo Weinhold } 407ca618b22SIngo Weinhold } 408ca618b22SIngo Weinhold 409ca618b22SIngo Weinhold 410ca618b22SIngo Weinhold static status_t 41135fa85dbSJérôme Duval add_preloaded_addon(image_t* image) 412ca618b22SIngo Weinhold { 413ca618b22SIngo Weinhold // We realloc() everytime -- not particularly efficient, but good enough for 41435fa85dbSJérôme Duval // small number of preloaded addons. 41535fa85dbSJérôme Duval image_t** newArray = (image_t**)realloc(sPreloadedAddons, 41635fa85dbSJérôme Duval sizeof(image_t*) * (sPreloadedAddonCount + 1)); 417ca618b22SIngo Weinhold if (newArray == NULL) 418ca618b22SIngo Weinhold return B_NO_MEMORY; 419ca618b22SIngo Weinhold 42035fa85dbSJérôme Duval sPreloadedAddons = newArray; 42135fa85dbSJérôme Duval newArray[sPreloadedAddonCount++] = image; 422ca618b22SIngo Weinhold 423ca618b22SIngo Weinhold return B_OK; 424ca618b22SIngo Weinhold } 425ca618b22SIngo Weinhold 426ca618b22SIngo Weinhold 427ca618b22SIngo Weinhold image_id 42835fa85dbSJérôme Duval preload_addon(char const* path) 429ca618b22SIngo Weinhold { 430ca618b22SIngo Weinhold if (path == NULL) 431ca618b22SIngo Weinhold return B_BAD_VALUE; 432ca618b22SIngo Weinhold 43335fa85dbSJérôme Duval KTRACE("rld: preload_addon(\"%s\")", path); 434ca618b22SIngo Weinhold 435ca618b22SIngo Weinhold image_t *image = NULL; 4368d23c440SIngo Weinhold status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, &image); 437ca618b22SIngo Weinhold if (status < B_OK) { 43835fa85dbSJérôme Duval KTRACE("rld: preload_addon(\"%s\") failed to load container: %s", path, 439ca618b22SIngo Weinhold strerror(status)); 440ca618b22SIngo Weinhold return status; 441ca618b22SIngo Weinhold } 442ca618b22SIngo Weinhold 4430c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) 4440c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 4450c85bd05SIngo Weinhold 4460c85bd05SIngo Weinhold status = load_dependencies(image); 447ca618b22SIngo Weinhold if (status < B_OK) 448ca618b22SIngo Weinhold goto err; 4490c85bd05SIngo Weinhold 4500c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 451ca618b22SIngo Weinhold 452ca618b22SIngo Weinhold status = relocate_dependencies(image); 453ca618b22SIngo Weinhold if (status < B_OK) 454ca618b22SIngo Weinhold goto err; 455ca618b22SIngo Weinhold 45635fa85dbSJérôme Duval status = add_preloaded_addon(image); 457ca618b22SIngo Weinhold if (status < B_OK) 458ca618b22SIngo Weinhold goto err; 459ca618b22SIngo Weinhold 460ca618b22SIngo Weinhold inject_runtime_loader_api(image); 461ca618b22SIngo Weinhold 462ca618b22SIngo Weinhold remap_images(); 463ca618b22SIngo Weinhold init_dependencies(image, true); 464ca618b22SIngo Weinhold 46510b4b5d1SIngo Weinhold // if the image contains an add-on, register it 46610b4b5d1SIngo Weinhold runtime_loader_add_on* addOnStruct; 467003ebb0eSIngo Weinhold if (find_symbol(image, 468003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA), 46910b4b5d1SIngo Weinhold (void**)&addOnStruct) == B_OK) { 47094830eb2SIngo Weinhold add_add_on(image, addOnStruct); 47110b4b5d1SIngo Weinhold } 47210b4b5d1SIngo Weinhold 47335fa85dbSJérôme Duval KTRACE("rld: preload_addon(\"%s\") done: id: %" B_PRId32, path, image->id); 474ca618b22SIngo Weinhold 475ca618b22SIngo Weinhold return image->id; 476ca618b22SIngo Weinhold 477ca618b22SIngo Weinhold err: 47835fa85dbSJérôme Duval KTRACE("rld: preload_addon(\"%s\") failed: %s", path, strerror(status)); 479ca618b22SIngo Weinhold 48094830eb2SIngo Weinhold dequeue_loaded_image(image); 481ca618b22SIngo Weinhold delete_image(image); 482ca618b22SIngo Weinhold return status; 483ca618b22SIngo Weinhold } 484ca618b22SIngo Weinhold 485ca618b22SIngo Weinhold 486ca618b22SIngo Weinhold static void 48735fa85dbSJérôme Duval preload_addons() 488ca618b22SIngo Weinhold { 48935fa85dbSJérôme Duval const char* imagePaths = getenv("LD_PRELOAD_ADDONS"); 490ca618b22SIngo Weinhold if (imagePaths == NULL) 491ca618b22SIngo Weinhold return; 492ca618b22SIngo Weinhold 493ca618b22SIngo Weinhold while (*imagePaths != '\0') { 494ca618b22SIngo Weinhold // find begin of image path 495ca618b22SIngo Weinhold while (*imagePaths != '\0' && isspace(*imagePaths)) 496ca618b22SIngo Weinhold imagePaths++; 497ca618b22SIngo Weinhold 498ca618b22SIngo Weinhold if (*imagePaths == '\0') 499ca618b22SIngo Weinhold break; 500ca618b22SIngo Weinhold 501ca618b22SIngo Weinhold // find end of image path 502ca618b22SIngo Weinhold const char* imagePath = imagePaths; 503ca618b22SIngo Weinhold while (*imagePaths != '\0' && !isspace(*imagePaths)) 504ca618b22SIngo Weinhold imagePaths++; 505ca618b22SIngo Weinhold 506ca618b22SIngo Weinhold // extract the path 507ca618b22SIngo Weinhold char path[B_PATH_NAME_LENGTH]; 508ca618b22SIngo Weinhold size_t pathLen = imagePaths - imagePath; 509ca618b22SIngo Weinhold if (pathLen > sizeof(path) - 1) 510ca618b22SIngo Weinhold continue; 511ca618b22SIngo Weinhold memcpy(path, imagePath, pathLen); 512ca618b22SIngo Weinhold path[pathLen] = '\0'; 513ca618b22SIngo Weinhold 514ca618b22SIngo Weinhold // load the image 51535fa85dbSJérôme Duval preload_addon(path); 516ca618b22SIngo Weinhold } 517ca618b22SIngo Weinhold } 518ca618b22SIngo Weinhold 519ca618b22SIngo Weinhold 52074c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 5210c0fea5dSIngo Weinhold 5220c0fea5dSIngo Weinhold 5230c0fea5dSIngo Weinhold image_id 5240c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 5250c0fea5dSIngo Weinhold { 5260c0fea5dSIngo Weinhold status_t status; 5270c0fea5dSIngo Weinhold image_t *image; 5280c0fea5dSIngo Weinhold 5297486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path); 5307486b72dSIngo Weinhold 531f167d21aSAugustin Cavalier RecursiveLocker _(sLock); 5320c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 5330c0fea5dSIngo Weinhold 53435fa85dbSJérôme Duval preload_addons(); 535ca618b22SIngo Weinhold 5360c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 5370c0fea5dSIngo Weinhold 5388d23c440SIngo Weinhold status = load_image(path, B_APP_IMAGE, NULL, NULL, &gProgramImage); 53974c0424aSAxel Dörfler if (status < B_OK) 54074c0424aSAxel Dörfler goto err; 5410c0fea5dSIngo Weinhold 54294830eb2SIngo Weinhold if (gProgramImage->find_undefined_symbol == NULL) 54394830eb2SIngo Weinhold gProgramImage->find_undefined_symbol = find_undefined_symbol_global; 5440c85bd05SIngo Weinhold 54535fa85dbSJérôme Duval status = load_dependencies(gProgramImage, true); 5460c0fea5dSIngo Weinhold if (status < B_OK) 5470c0fea5dSIngo Weinhold goto err; 5480c85bd05SIngo Weinhold 54947bc6663SIngo Weinhold // Set RTLD_GLOBAL on all libraries including the program. 5500c85bd05SIngo Weinhold // This results in the desired symbol resolution for dlopen()ed libraries. 55194830eb2SIngo Weinhold set_image_flags_recursively(gProgramImage, RTLD_GLOBAL); 5520c0fea5dSIngo Weinhold 55394830eb2SIngo Weinhold status = relocate_dependencies(gProgramImage); 5540c0fea5dSIngo Weinhold if (status < B_OK) 5550c0fea5dSIngo Weinhold goto err; 5560c0fea5dSIngo Weinhold 55794830eb2SIngo Weinhold inject_runtime_loader_api(gProgramImage); 5580c0fea5dSIngo Weinhold 5590c0fea5dSIngo Weinhold remap_images(); 56094830eb2SIngo Weinhold init_dependencies(gProgramImage, true); 5610c0fea5dSIngo Weinhold 5620c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 5630c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 56494830eb2SIngo Weinhold find_symbol_breadth_first(gProgramImage, 565003ebb0eSIngo Weinhold SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image, 566003ebb0eSIngo Weinhold (void**)&gGetEnv); 5670c0fea5dSIngo Weinhold 56894830eb2SIngo Weinhold if (gProgramImage->entry_point == 0) { 5690c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 5700c0fea5dSIngo Weinhold goto err; 5710c0fea5dSIngo Weinhold } 5720c0fea5dSIngo Weinhold 57394830eb2SIngo Weinhold *_entry = (void *)(gProgramImage->entry_point); 5740c0fea5dSIngo Weinhold 57594830eb2SIngo Weinhold gProgramLoaded = true; 5765d0638bfSIngo Weinhold 577ded25be1SIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %" B_PRId32 , path, 57894830eb2SIngo Weinhold *_entry, gProgramImage->id); 5797486b72dSIngo Weinhold 58094830eb2SIngo Weinhold return gProgramImage->id; 5810c0fea5dSIngo Weinhold 5820c0fea5dSIngo Weinhold err: 5837486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); 5847486b72dSIngo Weinhold 58594830eb2SIngo Weinhold delete_image(gProgramImage); 58674c0424aSAxel Dörfler 5874bef3723SAxel Dörfler if (report_errors()) { 5884bef3723SAxel Dörfler // send error message 58994830eb2SIngo Weinhold gErrorMessage.AddInt32("error", status); 59094830eb2SIngo Weinhold gErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 5914bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 5924bef3723SAxel Dörfler 5934bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 59494830eb2SIngo Weinhold gErrorMessage.Buffer(), gErrorMessage.ContentSize(), 0, 0); 59574c0424aSAxel Dörfler } 59674c0424aSAxel Dörfler _kern_loading_app_failed(status); 59774c0424aSAxel Dörfler 5980c0fea5dSIngo Weinhold return status; 5990c0fea5dSIngo Weinhold } 6000c0fea5dSIngo Weinhold 6010c0fea5dSIngo Weinhold 6020c0fea5dSIngo Weinhold image_id 6030c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle) 6040c0fea5dSIngo Weinhold { 6050c0fea5dSIngo Weinhold image_t *image = NULL; 6060c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 6070c0fea5dSIngo Weinhold status_t status; 6080c0fea5dSIngo Weinhold 6090c85bd05SIngo Weinhold if (path == NULL && addOn) 6100c0fea5dSIngo Weinhold return B_BAD_VALUE; 6110c0fea5dSIngo Weinhold 612ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\", %#" B_PRIx32 ", %d)", path, flags, addOn); 6137486b72dSIngo Weinhold 614f167d21aSAugustin Cavalier RecursiveLocker _(sLock); 6150c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 6160c0fea5dSIngo Weinhold 6170c0fea5dSIngo Weinhold // have we already loaded this library? 6180c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 6190c0fea5dSIngo Weinhold if (!addOn) { 6200c85bd05SIngo Weinhold // a NULL path is fine -- it means the global scope shall be opened 6210c85bd05SIngo Weinhold if (path == NULL) { 6220c85bd05SIngo Weinhold *_handle = RLD_GLOBAL_SCOPE; 6230c85bd05SIngo Weinhold return 0; 6240c85bd05SIngo Weinhold } 6250c85bd05SIngo Weinhold 62694830eb2SIngo Weinhold image = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE); 6270c85bd05SIngo Weinhold if (image != NULL && (flags & RTLD_GLOBAL) != 0) 6280c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 6290c85bd05SIngo Weinhold 6300c0fea5dSIngo Weinhold if (image) { 6310c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 632ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %" B_PRId32, 633ded25be1SIngo Weinhold path, image->id); 6340c85bd05SIngo Weinhold *_handle = image; 6350c0fea5dSIngo Weinhold return image->id; 6360c0fea5dSIngo Weinhold } 6370c0fea5dSIngo Weinhold } 6380c0fea5dSIngo Weinhold 6398d23c440SIngo Weinhold status = load_image(path, type, NULL, NULL, &image); 6400c0fea5dSIngo Weinhold if (status < B_OK) { 6417486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, 6427486b72dSIngo Weinhold strerror(status)); 6430c0fea5dSIngo Weinhold return status; 6440c0fea5dSIngo Weinhold } 6450c0fea5dSIngo Weinhold 6460c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) { 6470c85bd05SIngo Weinhold if (addOn) 6480c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_add_on; 6490c85bd05SIngo Weinhold else 6500c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 6510c85bd05SIngo Weinhold } 6520c85bd05SIngo Weinhold 6530c85bd05SIngo Weinhold status = load_dependencies(image); 6540c0fea5dSIngo Weinhold if (status < B_OK) 6550c0fea5dSIngo Weinhold goto err; 6560c85bd05SIngo Weinhold 6570c85bd05SIngo Weinhold // If specified, set the RTLD_GLOBAL flag recursively on this image and all 6580c85bd05SIngo Weinhold // dependencies. If not specified, we temporarily set 6590c85bd05SIngo Weinhold // RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used 6600c85bd05SIngo Weinhold // for undefined symbol resolution. 6610c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) != 0) 6620c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 6630c85bd05SIngo Weinhold else 6640c85bd05SIngo Weinhold set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 6650c0fea5dSIngo Weinhold 6660c0fea5dSIngo Weinhold status = relocate_dependencies(image); 6670c0fea5dSIngo Weinhold if (status < B_OK) 6680c0fea5dSIngo Weinhold goto err; 6690c0fea5dSIngo Weinhold 6700c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) == 0) 6710c85bd05SIngo Weinhold clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 6720c85bd05SIngo Weinhold 6730c0fea5dSIngo Weinhold remap_images(); 6740c0fea5dSIngo Weinhold init_dependencies(image, true); 6750c0fea5dSIngo Weinhold 676ded25be1SIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %" B_PRId32, path, image->id); 6777486b72dSIngo Weinhold 6780c85bd05SIngo Weinhold *_handle = image; 6790c0fea5dSIngo Weinhold return image->id; 6800c0fea5dSIngo Weinhold 6810c0fea5dSIngo Weinhold err: 6827486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status)); 6837486b72dSIngo Weinhold 68494830eb2SIngo Weinhold dequeue_loaded_image(image); 6850c0fea5dSIngo Weinhold delete_image(image); 6860c0fea5dSIngo Weinhold return status; 6870c0fea5dSIngo Weinhold } 6880c0fea5dSIngo Weinhold 6890c0fea5dSIngo Weinhold 6900c0fea5dSIngo Weinhold status_t 6910c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn) 6920c0fea5dSIngo Weinhold { 6930c0fea5dSIngo Weinhold image_t *image; 6940c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 6950c0fea5dSIngo Weinhold 6960c85bd05SIngo Weinhold if (handle == NULL && imageID < 0) 6970c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 6980c0fea5dSIngo Weinhold 6990c85bd05SIngo Weinhold if (handle == RLD_GLOBAL_SCOPE) 7000c85bd05SIngo Weinhold return B_OK; 7010c85bd05SIngo Weinhold 702f167d21aSAugustin Cavalier RecursiveLocker _(sLock); 7030c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 7040c0fea5dSIngo Weinhold 70594830eb2SIngo Weinhold if (gInvalidImageIDs) { 7069a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 7079a6072a3SAxel Dörfler update_image_ids(); 7089a6072a3SAxel Dörfler } 7099a6072a3SAxel Dörfler 7100c0fea5dSIngo Weinhold // we only check images that have been already initialized 7110c0fea5dSIngo Weinhold 712df30098dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 713df30098dSIngo Weinhold 7140c85bd05SIngo Weinhold if (handle != NULL) { 7150c85bd05SIngo Weinhold image = (image_t*)handle; 7160c85bd05SIngo Weinhold put_image(image); 717df30098dSIngo Weinhold status = B_OK; 7180c85bd05SIngo Weinhold } else { 71994830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, true); 72094830eb2SIngo Weinhold if (image != NULL) { 7210c0fea5dSIngo Weinhold // unload image 7220c0fea5dSIngo Weinhold if (type == image->type) { 7230c0fea5dSIngo Weinhold put_image(image); 7240c0fea5dSIngo Weinhold status = B_OK; 7250c0fea5dSIngo Weinhold } else 7260c0fea5dSIngo Weinhold status = B_BAD_VALUE; 7270c0fea5dSIngo Weinhold } 7280c85bd05SIngo Weinhold } 7290c0fea5dSIngo Weinhold 7300c0fea5dSIngo Weinhold if (status == B_OK) { 73194830eb2SIngo Weinhold while ((image = get_disposable_images().head) != NULL) { 732d64f6189SIngo Weinhold // Call the exit hooks that live in this image. 733d64f6189SIngo Weinhold // Note: With the Itanium ABI this shouldn't really be done this 734d64f6189SIngo Weinhold // way anymore, since global destructors are registered via 735d64f6189SIngo Weinhold // __cxa_atexit() (the ones that are registered dynamically) and the 736d64f6189SIngo Weinhold // termination routine should call __cxa_finalize() for the image. 737d64f6189SIngo Weinhold // The reason why we still do it is that hooks registered with 738d64f6189SIngo Weinhold // atexit() aren't associated with the image. We could find out 739d64f6189SIngo Weinhold // there which image the hooks lives in and register it 740d64f6189SIngo Weinhold // respectively, but since that would be done always, that's 741d64f6189SIngo Weinhold // probably more expensive than calling 742d64f6189SIngo Weinhold // call_atexit_hooks_for_range() only here, which happens only when 743d64f6189SIngo Weinhold // libraries are unloaded dynamically. 7448c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 7458c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 7463be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize); 7478c2a9d74SMichael Lotz } 7488c2a9d74SMichael Lotz 74910b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 75010b4b5d1SIngo Weinhold 7515d08e3a5SAugustin Cavalier call_term_functions(image); 752354b60afSAugustin Cavalier 75344c0c4d3SPawel Dziepak TLSBlockTemplates::Get().Unregister(image->dso_tls_id); 75444c0c4d3SPawel Dziepak 75594830eb2SIngo Weinhold dequeue_disposable_image(image); 7560c0fea5dSIngo Weinhold unmap_image(image); 7570c0fea5dSIngo Weinhold 75810b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 75910b4b5d1SIngo Weinhold 7600c0fea5dSIngo Weinhold delete_image(image); 7610c0fea5dSIngo Weinhold } 7620c0fea5dSIngo Weinhold } 7630c0fea5dSIngo Weinhold 7640c0fea5dSIngo Weinhold return status; 7650c0fea5dSIngo Weinhold } 7660c0fea5dSIngo Weinhold 7670c0fea5dSIngo Weinhold 7680c0fea5dSIngo Weinhold status_t 7699a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, 7709a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location) 7710c0fea5dSIngo Weinhold { 7720c0fea5dSIngo Weinhold int32 count = 0, j; 7730c0fea5dSIngo Weinhold uint32 i; 7740c0fea5dSIngo Weinhold image_t *image; 7750c0fea5dSIngo Weinhold 776f167d21aSAugustin Cavalier RecursiveLocker _(sLock); 7770c0fea5dSIngo Weinhold 7780c0fea5dSIngo Weinhold // get the image from those who have been already initialized 77994830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false); 780f167d21aSAugustin Cavalier if (image == NULL) 7810c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 7820c0fea5dSIngo Weinhold 7830c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 7840c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 7850c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 786e3ac2588SAlex Smith elf_sym *symbol = &image->syms[j]; 7870c0fea5dSIngo Weinhold 7880c0fea5dSIngo Weinhold if (count == num) { 78910b4b5d1SIngo Weinhold const char* symbolName = SYMNAME(image, symbol); 79010b4b5d1SIngo Weinhold strlcpy(nameBuffer, symbolName, *_nameLength); 79110b4b5d1SIngo Weinhold *_nameLength = strlen(symbolName); 7920c0fea5dSIngo Weinhold 79310b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value 79410b4b5d1SIngo Weinhold + image->regions[0].delta); 79510b4b5d1SIngo Weinhold int32 type; 796e3ac2588SAlex Smith if (symbol->Type() == STT_FUNC) 79710b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 798e3ac2588SAlex Smith else if (symbol->Type() == STT_OBJECT) 79910b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 8000c0fea5dSIngo Weinhold else 80110b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_ANY; 80210b4b5d1SIngo Weinhold // TODO: check with the return types of that BeOS function 8030c0fea5dSIngo Weinhold 80410b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &type); 80510b4b5d1SIngo Weinhold 80610b4b5d1SIngo Weinhold if (_type != NULL) 80710b4b5d1SIngo Weinhold *_type = type; 8080c0fea5dSIngo Weinhold if (_location != NULL) 80910b4b5d1SIngo Weinhold *_location = location; 8100c0fea5dSIngo Weinhold goto out; 8110c0fea5dSIngo Weinhold } 8120c0fea5dSIngo Weinhold count++; 8130c0fea5dSIngo Weinhold } 8140c0fea5dSIngo Weinhold } 8150c0fea5dSIngo Weinhold out: 8160c0fea5dSIngo Weinhold if (num != count) 8170c0fea5dSIngo Weinhold return B_BAD_INDEX; 8180c0fea5dSIngo Weinhold 8190c0fea5dSIngo Weinhold return B_OK; 8200c0fea5dSIngo Weinhold } 8210c0fea5dSIngo Weinhold 8220c0fea5dSIngo Weinhold 8230c0fea5dSIngo Weinhold status_t 82443e7b1c2SHamish Morrison get_nearest_symbol_at_address(void* address, image_id* _imageID, 825ebdc1d48SMichael Lotz char** _imagePath, char** _imageName, char** _symbolName, int32* _type, 826ebdc1d48SMichael Lotz void** _location, bool* _exactMatch) 827b6455c08SAxel Dörfler { 828f167d21aSAugustin Cavalier RecursiveLocker _(sLock); 829b6455c08SAxel Dörfler 830b6455c08SAxel Dörfler image_t* image = find_loaded_image_by_address((addr_t)address); 831f167d21aSAugustin Cavalier if (image == NULL) 832b6455c08SAxel Dörfler return B_BAD_VALUE; 833b6455c08SAxel Dörfler 834dee722ceSAugustin Cavalier if (_imageID != NULL) 835dee722ceSAugustin Cavalier *_imageID = image->id; 836dee722ceSAugustin Cavalier if (_imagePath != NULL) 837dee722ceSAugustin Cavalier *_imagePath = image->path; 838dee722ceSAugustin Cavalier if (_imageName != NULL) 839dee722ceSAugustin Cavalier *_imageName = image->name; 840dee722ceSAugustin Cavalier 841dee722ceSAugustin Cavalier // If the caller does not want the actual symbol name, only the image, 842dee722ceSAugustin Cavalier // we can just return immediately. 843dee722ceSAugustin Cavalier if (_symbolName == NULL && _type == NULL && _location == NULL) 844dee722ceSAugustin Cavalier return B_OK; 845dee722ceSAugustin Cavalier 846ebdc1d48SMichael Lotz bool exactMatch = false; 847e3ac2588SAlex Smith elf_sym* foundSymbol = NULL; 84843e7b1c2SHamish Morrison addr_t foundLocation = (addr_t)NULL; 84943e7b1c2SHamish Morrison 850ebdc1d48SMichael Lotz for (uint32 i = 0; i < HASHTABSIZE(image) && !exactMatch; i++) { 851b6455c08SAxel Dörfler for (int32 j = HASHBUCKETS(image)[i]; j != STN_UNDEF; 852b6455c08SAxel Dörfler j = HASHCHAINS(image)[j]) { 853e3ac2588SAlex Smith elf_sym *symbol = &image->syms[j]; 854b6455c08SAxel Dörfler addr_t location = symbol->st_value + image->regions[0].delta; 855b6455c08SAxel Dörfler 85643e7b1c2SHamish Morrison if (location <= (addr_t)address && location >= foundLocation) { 85743e7b1c2SHamish Morrison foundSymbol = symbol; 85843e7b1c2SHamish Morrison foundLocation = location; 859b6455c08SAxel Dörfler 86043e7b1c2SHamish Morrison // jump out if we have an exact match 861ebdc1d48SMichael Lotz if (location + symbol->st_size > (addr_t)address) { 862ebdc1d48SMichael Lotz exactMatch = true; 86343e7b1c2SHamish Morrison break; 86443e7b1c2SHamish Morrison } 86543e7b1c2SHamish Morrison } 86643e7b1c2SHamish Morrison } 86743e7b1c2SHamish Morrison } 868b6455c08SAxel Dörfler 869ebdc1d48SMichael Lotz if (_exactMatch != NULL) 870ebdc1d48SMichael Lotz *_exactMatch = exactMatch; 87143e7b1c2SHamish Morrison 87243e7b1c2SHamish Morrison if (foundSymbol != NULL) { 87343e7b1c2SHamish Morrison *_symbolName = SYMNAME(image, foundSymbol); 87443e7b1c2SHamish Morrison 87543e7b1c2SHamish Morrison if (_type != NULL) { 876e3ac2588SAlex Smith if (foundSymbol->Type() == STT_FUNC) 87743e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_TEXT; 878e3ac2588SAlex Smith else if (foundSymbol->Type() == STT_OBJECT) 87943e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_DATA; 88043e7b1c2SHamish Morrison else 88143e7b1c2SHamish Morrison *_type = B_SYMBOL_TYPE_ANY; 88243e7b1c2SHamish Morrison // TODO: check with the return types of that BeOS function 88343e7b1c2SHamish Morrison } 88443e7b1c2SHamish Morrison 885b6455c08SAxel Dörfler if (_location != NULL) 88643e7b1c2SHamish Morrison *_location = (void*)foundLocation; 88743e7b1c2SHamish Morrison } else { 88843e7b1c2SHamish Morrison *_symbolName = NULL; 88943e7b1c2SHamish Morrison if (_location != NULL) 89043e7b1c2SHamish Morrison *_location = NULL; 89143e7b1c2SHamish Morrison } 892b6455c08SAxel Dörfler 893b6455c08SAxel Dörfler return B_OK; 894b6455c08SAxel Dörfler } 895b6455c08SAxel Dörfler 896b6455c08SAxel Dörfler 897b6455c08SAxel Dörfler status_t 8989a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType, 89980ece785SIngo Weinhold bool recursive, image_id *_inImage, void **_location) 9000c0fea5dSIngo Weinhold { 9010c0fea5dSIngo Weinhold status_t status = B_OK; 9020c0fea5dSIngo Weinhold image_t *image; 9030c0fea5dSIngo Weinhold 9040c0fea5dSIngo Weinhold if (imageID < B_OK) 9050c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 9060c0fea5dSIngo Weinhold if (symbolName == NULL) 9070c0fea5dSIngo Weinhold return B_BAD_VALUE; 9080c0fea5dSIngo Weinhold 909354b60afSAugustin Cavalier // Previously, these functions were called in __haiku_init_before 910354b60afSAugustin Cavalier // and __haiku_init_after. Now we call them inside runtime_loader, 911354b60afSAugustin Cavalier // so we prevent applications from fetching them. 912354b60afSAugustin Cavalier if (strcmp(symbolName, B_INIT_BEFORE_FUNCTION_NAME) == 0 913354b60afSAugustin Cavalier || strcmp(symbolName, B_INIT_AFTER_FUNCTION_NAME) == 0 914354b60afSAugustin Cavalier || strcmp(symbolName, B_TERM_BEFORE_FUNCTION_NAME) == 0 915354b60afSAugustin Cavalier || strcmp(symbolName, B_TERM_AFTER_FUNCTION_NAME) == 0) 916354b60afSAugustin Cavalier return B_BAD_VALUE; 917354b60afSAugustin Cavalier 918f167d21aSAugustin Cavalier RecursiveLocker _(sLock); 9190c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 9200c0fea5dSIngo Weinhold 9210c0fea5dSIngo Weinhold // get the image from those who have been already initialized 92294830eb2SIngo Weinhold image = find_loaded_image_by_id(imageID, false); 92380ece785SIngo Weinhold if (image != NULL) { 92480ece785SIngo Weinhold if (recursive) { 92580ece785SIngo Weinhold // breadth-first search in the given image and its dependencies 926003ebb0eSIngo Weinhold status = find_symbol_breadth_first(image, 927003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 928003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 92980ece785SIngo Weinhold &image, _location); 930003ebb0eSIngo Weinhold } else { 931003ebb0eSIngo Weinhold status = find_symbol(image, 932003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 933003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 934003ebb0eSIngo Weinhold _location); 935003ebb0eSIngo Weinhold } 93680ece785SIngo Weinhold 93780ece785SIngo Weinhold if (status == B_OK && _inImage != NULL) 93880ece785SIngo Weinhold *_inImage = image->id; 93980ece785SIngo Weinhold } else 9400c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 9410c0fea5dSIngo Weinhold 9420c0fea5dSIngo Weinhold return status; 9430c0fea5dSIngo Weinhold } 9440c0fea5dSIngo Weinhold 9450c0fea5dSIngo Weinhold 9460c0fea5dSIngo Weinhold status_t 9470c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName, 9480c85bd05SIngo Weinhold void **_location) 9490c85bd05SIngo Weinhold { 9500c85bd05SIngo Weinhold status_t status = B_ENTRY_NOT_FOUND; 9510c85bd05SIngo Weinhold 9520c85bd05SIngo Weinhold if (symbolName == NULL) 9530c85bd05SIngo Weinhold return B_BAD_VALUE; 9540c85bd05SIngo Weinhold 955f167d21aSAugustin Cavalier RecursiveLocker _(sLock); 9560c85bd05SIngo Weinhold // for now, just do stupid simple global locking 9570c85bd05SIngo Weinhold 9580c85bd05SIngo Weinhold if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) { 9590c85bd05SIngo Weinhold // look in the default scope 9600c85bd05SIngo Weinhold image_t* image; 961e3ac2588SAlex Smith elf_sym* symbol = find_undefined_symbol_global(gProgramImage, 96294830eb2SIngo Weinhold gProgramImage, 963003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 964003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 965003ebb0eSIngo Weinhold &image); 9660c85bd05SIngo Weinhold if (symbol != NULL) { 9670c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value + image->regions[0].delta); 968e3ac2588SAlex Smith int32 symbolType = symbol->Type() == STT_FUNC 9690c85bd05SIngo Weinhold ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 9700c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, &symbolType); 9710c85bd05SIngo Weinhold status = B_OK; 9720c85bd05SIngo Weinhold } 9730c85bd05SIngo Weinhold } else if (handle == RTLD_NEXT) { 9740c85bd05SIngo Weinhold // Look in the default scope, but also in the dependencies of the 9750c85bd05SIngo Weinhold // calling image. Return the next after the caller symbol. 9760c85bd05SIngo Weinhold 977a2dad9e1SIngo Weinhold // First of all, find the caller image. 97894830eb2SIngo Weinhold image_t* callerImage = get_loaded_images().head; 9790c85bd05SIngo Weinhold for (; callerImage != NULL; callerImage = callerImage->next) { 9800c85bd05SIngo Weinhold elf_region_t& text = callerImage->regions[0]; 981a2dad9e1SIngo Weinhold if ((addr_t)caller >= text.vmstart 982a2dad9e1SIngo Weinhold && (addr_t)caller < text.vmstart + text.vmsize) { 983a2dad9e1SIngo Weinhold // found the image 9840c85bd05SIngo Weinhold break; 9850c85bd05SIngo Weinhold } 9860c85bd05SIngo Weinhold } 9870c85bd05SIngo Weinhold 988a2dad9e1SIngo Weinhold if (callerImage != NULL) { 9890c85bd05SIngo Weinhold // found the caller -- now search the global scope until we find 9900c85bd05SIngo Weinhold // the next symbol 991a2dad9e1SIngo Weinhold bool hitCallerImage = false; 9920c85bd05SIngo Weinhold set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 9930c85bd05SIngo Weinhold 994e3ac2588SAlex Smith elf_sym* candidateSymbol = NULL; 99525dc253dSIngo Weinhold image_t* candidateImage = NULL; 99625dc253dSIngo Weinhold 99794830eb2SIngo Weinhold image_t* image = get_loaded_images().head; 9980c85bd05SIngo Weinhold for (; image != NULL; image = image->next) { 999a2dad9e1SIngo Weinhold // skip the caller image 1000a2dad9e1SIngo Weinhold if (image == callerImage) { 1001a2dad9e1SIngo Weinhold hitCallerImage = true; 1002a2dad9e1SIngo Weinhold continue; 1003a2dad9e1SIngo Weinhold } 1004a2dad9e1SIngo Weinhold 1005a2dad9e1SIngo Weinhold // skip all images up to the caller image; also skip add-on 1006a2dad9e1SIngo Weinhold // images and those not marked above for resolution 1007a2dad9e1SIngo Weinhold if (!hitCallerImage || image->type == B_ADD_ON_IMAGE 10080c85bd05SIngo Weinhold || (image->flags 1009a2dad9e1SIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) { 10100c85bd05SIngo Weinhold continue; 10110c85bd05SIngo Weinhold } 10120c85bd05SIngo Weinhold 1013e3ac2588SAlex Smith elf_sym *symbol = find_symbol(image, 1014003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL, 1015003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION)); 10160c85bd05SIngo Weinhold if (symbol == NULL) 10170c85bd05SIngo Weinhold continue; 10180c85bd05SIngo Weinhold 101925dc253dSIngo Weinhold // found a symbol 1020e3ac2588SAlex Smith bool isWeak = symbol->Bind() == STB_WEAK; 102125dc253dSIngo Weinhold if (candidateImage == NULL || !isWeak) { 102225dc253dSIngo Weinhold candidateSymbol = symbol; 102325dc253dSIngo Weinhold candidateImage = image; 102425dc253dSIngo Weinhold 102525dc253dSIngo Weinhold if (!isWeak) 102625dc253dSIngo Weinhold break; 102725dc253dSIngo Weinhold } 102825dc253dSIngo Weinhold 102925dc253dSIngo Weinhold // symbol is weak, so we need to continue 103025dc253dSIngo Weinhold } 103125dc253dSIngo Weinhold 103225dc253dSIngo Weinhold if (candidateSymbol != NULL) { 1033a2dad9e1SIngo Weinhold // found the symbol 103425dc253dSIngo Weinhold *_location = (void*)(candidateSymbol->st_value 103525dc253dSIngo Weinhold + candidateImage->regions[0].delta); 10360c85bd05SIngo Weinhold int32 symbolType = B_SYMBOL_TYPE_TEXT; 103725dc253dSIngo Weinhold patch_defined_symbol(candidateImage, symbolName, _location, 10380c85bd05SIngo Weinhold &symbolType); 10390c85bd05SIngo Weinhold status = B_OK; 10400c85bd05SIngo Weinhold } 10410c85bd05SIngo Weinhold 10420c85bd05SIngo Weinhold clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 10430c85bd05SIngo Weinhold } 10440c85bd05SIngo Weinhold } else { 10450c85bd05SIngo Weinhold // breadth-first search in the given image and its dependencies 10460c85bd05SIngo Weinhold image_t* inImage; 1047003ebb0eSIngo Weinhold status = find_symbol_breadth_first((image_t*)handle, 1048003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 1049003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 1050003ebb0eSIngo Weinhold &inImage, _location); 10510c85bd05SIngo Weinhold } 10520c85bd05SIngo Weinhold 10530c85bd05SIngo Weinhold return status; 10540c85bd05SIngo Weinhold } 10550c85bd05SIngo Weinhold 10560c85bd05SIngo Weinhold 10570c85bd05SIngo Weinhold status_t 10580c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 10590c0fea5dSIngo Weinhold { 10600c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 1061e3ac2588SAlex Smith elf_dyn *dynamicSection; 10620c0fea5dSIngo Weinhold image_t *image; 10630c0fea5dSIngo Weinhold 10640c0fea5dSIngo Weinhold if (_name == NULL) 10650c0fea5dSIngo Weinhold return B_BAD_VALUE; 10660c0fea5dSIngo Weinhold 1067f167d21aSAugustin Cavalier RecursiveLocker _(sLock); 10680c0fea5dSIngo Weinhold 106994830eb2SIngo Weinhold image = find_loaded_image_by_id(id, false); 1070f167d21aSAugustin Cavalier if (image == NULL) 10710c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 10720c0fea5dSIngo Weinhold 1073e3ac2588SAlex Smith dynamicSection = (elf_dyn *)image->dynamic_ptr; 1074f167d21aSAugustin Cavalier if (dynamicSection == NULL || image->num_needed <= searchIndex) 10750c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 10760c0fea5dSIngo Weinhold 10770c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 10780c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 10790c0fea5dSIngo Weinhold continue; 10800c0fea5dSIngo Weinhold 10810c0fea5dSIngo Weinhold if (j++ == searchIndex) { 10820c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 10830c0fea5dSIngo Weinhold 10840c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 10850c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 10860c0fea5dSIngo Weinhold return B_OK; 10870c0fea5dSIngo Weinhold } 10880c0fea5dSIngo Weinhold } 10890c0fea5dSIngo Weinhold 10900c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 10910c0fea5dSIngo Weinhold } 10920c0fea5dSIngo Weinhold 10930c0fea5dSIngo Weinhold 109474c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 10950c0fea5dSIngo Weinhold 10960c0fea5dSIngo Weinhold 10979a6072a3SAxel Dörfler /*! Read and verify the ELF header */ 10980c0fea5dSIngo Weinhold status_t 1099e3ac2588SAlex Smith elf_verify_header(void *header, size_t length) 11000c0fea5dSIngo Weinhold { 11010c0fea5dSIngo Weinhold int32 programSize, sectionSize; 11020c0fea5dSIngo Weinhold 1103e3ac2588SAlex Smith if (length < sizeof(elf_ehdr)) 11040c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 11050c0fea5dSIngo Weinhold 1106e3ac2588SAlex Smith return parse_elf_header((elf_ehdr *)header, &programSize, §ionSize); 11070c0fea5dSIngo Weinhold } 11080c0fea5dSIngo Weinhold 11090c0fea5dSIngo Weinhold 11102aaad308SJérôme Duval #ifdef _COMPAT_MODE 11112aaad308SJérôme Duval #ifdef __x86_64__ 11122aaad308SJérôme Duval status_t 11132aaad308SJérôme Duval elf32_verify_header(void *header, size_t length) 11142aaad308SJérôme Duval { 11152aaad308SJérôme Duval int32 programSize, sectionSize; 11162aaad308SJérôme Duval 11172aaad308SJérôme Duval if (length < sizeof(Elf32_Ehdr)) 11182aaad308SJérôme Duval return B_NOT_AN_EXECUTABLE; 11192aaad308SJérôme Duval 11202aaad308SJérôme Duval return parse_elf32_header((Elf32_Ehdr *)header, &programSize, §ionSize); 11212aaad308SJérôme Duval } 11222aaad308SJérôme Duval #else 11232aaad308SJérôme Duval status_t 11242aaad308SJérôme Duval elf64_verify_header(void *header, size_t length) 11252aaad308SJérôme Duval { 11262aaad308SJérôme Duval int32 programSize, sectionSize; 11272aaad308SJérôme Duval 11282aaad308SJérôme Duval if (length < sizeof(Elf64_Ehdr)) 11292aaad308SJérôme Duval return B_NOT_AN_EXECUTABLE; 11302aaad308SJérôme Duval 11312aaad308SJérôme Duval return parse_elf64_header((Elf64_Ehdr *)header, &programSize, §ionSize); 11322aaad308SJérôme Duval } 11332aaad308SJérôme Duval #endif // __x86_64__ 11342aaad308SJérôme Duval #endif // _COMPAT_MODE 11352aaad308SJérôme Duval 11362aaad308SJérôme Duval 11370c0fea5dSIngo Weinhold void 11380c0fea5dSIngo Weinhold terminate_program(void) 11390c0fea5dSIngo Weinhold { 11400c0fea5dSIngo Weinhold image_t **termList; 11410c0fea5dSIngo Weinhold ssize_t count, i; 11420c0fea5dSIngo Weinhold 1143aa3507feSIngo Weinhold count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED); 11440c0fea5dSIngo Weinhold if (count < B_OK) 11450c0fea5dSIngo Weinhold return; 11460c0fea5dSIngo Weinhold 114794830eb2SIngo Weinhold if (gInvalidImageIDs) { 11489a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 11499a6072a3SAxel Dörfler update_image_ids(); 11509a6072a3SAxel Dörfler } 11519a6072a3SAxel Dörfler 11520c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 11530c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 11540c0fea5dSIngo Weinhold image_t *image = termList[i]; 11550c0fea5dSIngo Weinhold 11560c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 11570c0fea5dSIngo Weinhold 115810b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 115910b4b5d1SIngo Weinhold 11605d08e3a5SAugustin Cavalier call_term_functions(image); 116110b4b5d1SIngo Weinhold 116210b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 11630c0fea5dSIngo Weinhold } 11640c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 11650c0fea5dSIngo Weinhold 11660c0fea5dSIngo Weinhold free(termList); 11670c0fea5dSIngo Weinhold } 11680c0fea5dSIngo Weinhold 11690c0fea5dSIngo Weinhold 11700c0fea5dSIngo Weinhold void 11710c0fea5dSIngo Weinhold rldelf_init(void) 11720c0fea5dSIngo Weinhold { 117394830eb2SIngo Weinhold init_add_ons(); 117494830eb2SIngo Weinhold 11750c0fea5dSIngo Weinhold // create the debug area 11760c0fea5dSIngo Weinhold { 1177e3ac2588SAlex Smith size_t size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 11780c0fea5dSIngo Weinhold 11790c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 11800c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 11819f3bd497SPawel Dziepak (void **)&area, B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK, 118240b0fbbbSAugustin Cavalier B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA); 11830c0fea5dSIngo Weinhold if (areaID < B_OK) { 11840c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 11850c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 11860c0fea5dSIngo Weinhold } 11870c0fea5dSIngo Weinhold 118894830eb2SIngo Weinhold area->loaded_images = &get_loaded_images(); 11890c0fea5dSIngo Weinhold } 119074c0424aSAxel Dörfler 119174c0424aSAxel Dörfler // initialize error message if needed 11924bef3723SAxel Dörfler if (report_errors()) { 119374c0424aSAxel Dörfler void *buffer = malloc(1024); 119474c0424aSAxel Dörfler if (buffer == NULL) 119574c0424aSAxel Dörfler return; 119674c0424aSAxel Dörfler 119794830eb2SIngo Weinhold gErrorMessage.SetTo(buffer, 1024, 'Rler'); 119874c0424aSAxel Dörfler } 11990c0fea5dSIngo Weinhold } 12001873b4b3SIngo Weinhold 12011873b4b3SIngo Weinhold 12021873b4b3SIngo Weinhold status_t 12039a6072a3SAxel Dörfler elf_reinit_after_fork(void) 12041873b4b3SIngo Weinhold { 1205f7127458SIngo Weinhold recursive_lock_init(&sLock, kLockName); 12061873b4b3SIngo Weinhold 12079a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and 1208cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork() 1209cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one 12109a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different. 121194830eb2SIngo Weinhold gInvalidImageIDs = true; 1212cbc456deSIngo Weinhold 12131873b4b3SIngo Weinhold return B_OK; 12141873b4b3SIngo Weinhold } 1215