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> 22593ee7bbSIngo Weinhold #include <image_defs.h> 237486b72dSIngo Weinhold #include <runtime_loader.h> 247486b72dSIngo Weinhold #include <syscalls.h> 257486b72dSIngo Weinhold #include <user_runtime.h> 2610b4b5d1SIngo Weinhold #include <util/DoublyLinkedList.h> 2710b4b5d1SIngo Weinhold #include <util/kernel_cpp.h> 286b202f4eSIngo Weinhold #include <util/KMessage.h> 296b202f4eSIngo Weinhold #include <vm_defs.h> 307486b72dSIngo Weinhold 31071f9c3aSIngo Weinhold #include "tracing_config.h" 32071f9c3aSIngo Weinhold 330c0fea5dSIngo Weinhold 340c0fea5dSIngo Weinhold //#define TRACE_RLD 350c0fea5dSIngo Weinhold #ifdef TRACE_RLD 360c0fea5dSIngo Weinhold # define TRACE(x) dprintf x 370c0fea5dSIngo Weinhold #else 380c0fea5dSIngo Weinhold # define TRACE(x) ; 390c0fea5dSIngo Weinhold #endif 400c0fea5dSIngo Weinhold 410c0fea5dSIngo Weinhold 4210b4b5d1SIngo Weinhold // TODO: implement better locking strategy 4310b4b5d1SIngo Weinhold // TODO: implement lazy binding 440c0fea5dSIngo Weinhold 45f91194e5SIngo Weinhold // interim Haiku API versions 46f91194e5SIngo Weinhold #define HAIKU_VERSION_PRE_GLUE_CODE 0x00000010 47f91194e5SIngo Weinhold 480c0fea5dSIngo Weinhold #define PAGE_MASK (B_PAGE_SIZE - 1) 490c0fea5dSIngo Weinhold 500c0fea5dSIngo Weinhold #define PAGE_OFFSET(x) ((x) & (PAGE_MASK)) 510c0fea5dSIngo Weinhold #define PAGE_BASE(x) ((x) & ~(PAGE_MASK)) 520c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK)) 530c0fea5dSIngo Weinhold 540c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000 550c0fea5dSIngo Weinhold /* keep in sync with app ldscript */ 560c0fea5dSIngo Weinhold 570c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen()) 580c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE ((void*)-2l) 590c85bd05SIngo Weinhold 600c0fea5dSIngo Weinhold enum { 610c85bd05SIngo Weinhold // the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL 620c85bd05SIngo Weinhold 630c85bd05SIngo Weinhold RFLAG_RW = 0x0010, 640c85bd05SIngo Weinhold RFLAG_ANON = 0x0020, 650c0fea5dSIngo Weinhold 660c0fea5dSIngo Weinhold RFLAG_TERMINATED = 0x0200, 670c0fea5dSIngo Weinhold RFLAG_INITIALIZED = 0x0400, 680c0fea5dSIngo Weinhold RFLAG_SYMBOLIC = 0x0800, 690c0fea5dSIngo Weinhold RFLAG_RELOCATED = 0x1000, 700c0fea5dSIngo Weinhold RFLAG_PROTECTED = 0x2000, 710c0fea5dSIngo Weinhold RFLAG_DEPENDENCIES_LOADED = 0x4000, 7246f4d849SIngo Weinhold RFLAG_REMAPPED = 0x8000, 7346f4d849SIngo Weinhold 740c85bd05SIngo Weinhold RFLAG_VISITED = 0x10000, 750c85bd05SIngo Weinhold RFLAG_USE_FOR_RESOLVING = 0x20000 7646f4d849SIngo Weinhold // temporarily set in the symbol resolution code 770c0fea5dSIngo Weinhold }; 780c0fea5dSIngo Weinhold 790c0fea5dSIngo Weinhold 800c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type) (1 << ((type) - 1)) 810c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 820c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \ 830c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \ 840c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE)) 850c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 860c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE)) 870c0fea5dSIngo Weinhold 880c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 890c0fea5dSIngo Weinhold 90*003ebb0eSIngo Weinhold static Elf32_Sym* find_symbol(image_t* image, 91*003ebb0eSIngo Weinhold const SymbolLookupInfo& lookupInfo); 92*003ebb0eSIngo Weinhold static uint32 elf_hash(const uint8 *name); 93*003ebb0eSIngo Weinhold 9410b4b5d1SIngo Weinhold 9510b4b5d1SIngo Weinhold // image events 9610b4b5d1SIngo Weinhold enum { 9710b4b5d1SIngo Weinhold IMAGE_EVENT_LOADED, 9810b4b5d1SIngo Weinhold IMAGE_EVENT_RELOCATED, 9910b4b5d1SIngo Weinhold IMAGE_EVENT_INITIALIZED, 10010b4b5d1SIngo Weinhold IMAGE_EVENT_UNINITIALIZING, 10110b4b5d1SIngo Weinhold IMAGE_EVENT_UNLOADING 10210b4b5d1SIngo Weinhold }; 10310b4b5d1SIngo Weinhold 10410b4b5d1SIngo Weinhold 10510b4b5d1SIngo Weinhold struct RuntimeLoaderAddOn 10610b4b5d1SIngo Weinhold : public DoublyLinkedListLinkImpl<RuntimeLoaderAddOn> { 10710b4b5d1SIngo Weinhold image_t* image; 10810b4b5d1SIngo Weinhold runtime_loader_add_on* addOn; 10910b4b5d1SIngo Weinhold 11010b4b5d1SIngo Weinhold RuntimeLoaderAddOn(image_t* image, runtime_loader_add_on* addOn) 11110b4b5d1SIngo Weinhold : 11210b4b5d1SIngo Weinhold image(image), 11310b4b5d1SIngo Weinhold addOn(addOn) 11410b4b5d1SIngo Weinhold { 11510b4b5d1SIngo Weinhold } 11610b4b5d1SIngo Weinhold }; 11710b4b5d1SIngo Weinhold 11810b4b5d1SIngo Weinhold typedef DoublyLinkedList<RuntimeLoaderAddOn> AddOnList; 11910b4b5d1SIngo Weinhold 12010b4b5d1SIngo Weinhold struct RuntimeLoaderSymbolPatcher { 12110b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* next; 12210b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* patcher; 12310b4b5d1SIngo Weinhold void* cookie; 12410b4b5d1SIngo Weinhold 12510b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher(runtime_loader_symbol_patcher* patcher, 12610b4b5d1SIngo Weinhold void* cookie) 12710b4b5d1SIngo Weinhold : 12810b4b5d1SIngo Weinhold patcher(patcher), 12910b4b5d1SIngo Weinhold cookie(cookie) 13010b4b5d1SIngo Weinhold { 13110b4b5d1SIngo Weinhold } 13210b4b5d1SIngo Weinhold }; 13310b4b5d1SIngo Weinhold 13410b4b5d1SIngo Weinhold 135*003ebb0eSIngo Weinhold struct SymbolLookupInfo { 136*003ebb0eSIngo Weinhold const char* name; 137*003ebb0eSIngo Weinhold int32 type; 138*003ebb0eSIngo Weinhold uint32 hash; 139*003ebb0eSIngo Weinhold uint32 flags; 140*003ebb0eSIngo Weinhold const elf_version_info* version; 141*003ebb0eSIngo Weinhold 142*003ebb0eSIngo Weinhold SymbolLookupInfo(const char* name, int32 type, uint32 hash, 143*003ebb0eSIngo Weinhold const elf_version_info* version = NULL, uint32 flags = 0) 144*003ebb0eSIngo Weinhold : 145*003ebb0eSIngo Weinhold name(name), 146*003ebb0eSIngo Weinhold type(type), 147*003ebb0eSIngo Weinhold hash(hash), 148*003ebb0eSIngo Weinhold flags(flags), 149*003ebb0eSIngo Weinhold version(version) 150*003ebb0eSIngo Weinhold { 151*003ebb0eSIngo Weinhold } 152*003ebb0eSIngo Weinhold 153*003ebb0eSIngo Weinhold SymbolLookupInfo(const char* name, int32 type, 154*003ebb0eSIngo Weinhold const elf_version_info* version = NULL, uint32 flags = 0) 155*003ebb0eSIngo Weinhold : 156*003ebb0eSIngo Weinhold name(name), 157*003ebb0eSIngo Weinhold type(type), 158*003ebb0eSIngo Weinhold hash(elf_hash((const uint8*)name)), 159*003ebb0eSIngo Weinhold flags(flags), 160*003ebb0eSIngo Weinhold version(version) 161*003ebb0eSIngo Weinhold { 162*003ebb0eSIngo Weinhold } 163*003ebb0eSIngo Weinhold }; 164*003ebb0eSIngo Weinhold 165*003ebb0eSIngo Weinhold 166*003ebb0eSIngo Weinhold // values for SymbolLookupInfo::flags 167*003ebb0eSIngo Weinhold #define LOOKUP_FLAG_DEFAULT_VERSION 0x01 168*003ebb0eSIngo Weinhold 169*003ebb0eSIngo Weinhold 1700c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0}; 1710c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0}; 1720c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0; 1730c0fea5dSIngo Weinhold static image_t *sProgramImage; 17474c0424aSAxel Dörfler static KMessage sErrorMessage; 1755d0638bfSIngo Weinhold static bool sProgramLoaded = false; 17661b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL; 1779a6072a3SAxel Dörfler static bool sInvalidImageIDs; 178ca618b22SIngo Weinhold static image_t **sPreloadedImages = NULL; 179ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0; 18010b4b5d1SIngo Weinhold static AddOnList sAddOns; 1810c0fea5dSIngo Weinhold 1820c0fea5dSIngo Weinhold // a recursive lock 183e73923b0SAxel Dörfler static sem_id sSem; 184e73923b0SAxel Dörfler static thread_id sSemOwner; 185e73923b0SAxel Dörfler static int32 sSemCount; 1860c0fea5dSIngo Weinhold 18710b4b5d1SIngo Weinhold extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport; 18810b4b5d1SIngo Weinhold 1890c0fea5dSIngo Weinhold 1900c0fea5dSIngo Weinhold void 1910c0fea5dSIngo Weinhold dprintf(const char *format, ...) 1920c0fea5dSIngo Weinhold { 1930c0fea5dSIngo Weinhold char buffer[1024]; 1940c0fea5dSIngo Weinhold 1950c0fea5dSIngo Weinhold va_list list; 1960c0fea5dSIngo Weinhold va_start(list, format); 1970c0fea5dSIngo Weinhold 1980c0fea5dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 1990c0fea5dSIngo Weinhold _kern_debug_output(buffer); 2000c0fea5dSIngo Weinhold 2010c0fea5dSIngo Weinhold va_end(list); 2020c0fea5dSIngo Weinhold } 2035d0638bfSIngo Weinhold 2045d0638bfSIngo Weinhold #define FATAL(x...) \ 2055d0638bfSIngo Weinhold do { \ 2065d0638bfSIngo Weinhold dprintf("runtime_loader: " x); \ 2075d0638bfSIngo Weinhold if (!sProgramLoaded) \ 2085d0638bfSIngo Weinhold printf("runtime_loader: " x); \ 2095d0638bfSIngo Weinhold } while (false) 2100c0fea5dSIngo Weinhold 2110c0fea5dSIngo Weinhold 21234982809SIngo Weinhold /*! Mini atoi(), so we don't have to include the libroot dependencies. 21334982809SIngo Weinhold */ 21434982809SIngo Weinhold int 21534982809SIngo Weinhold atoi(const char* num) 21634982809SIngo Weinhold { 21734982809SIngo Weinhold int result = 0; 21834982809SIngo Weinhold while (*num >= '0' && *num <= '9') { 21934982809SIngo Weinhold result = (result * 10) + (*num - '0'); 22034982809SIngo Weinhold num++; 22134982809SIngo Weinhold } 22234982809SIngo Weinhold 22334982809SIngo Weinhold return result; 22434982809SIngo Weinhold } 22534982809SIngo Weinhold 22634982809SIngo Weinhold 2276bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING 2287486b72dSIngo Weinhold 2297486b72dSIngo Weinhold void 2307486b72dSIngo Weinhold ktrace_printf(const char *format, ...) 2317486b72dSIngo Weinhold { 2327486b72dSIngo Weinhold va_list list; 2337486b72dSIngo Weinhold va_start(list, format); 2347486b72dSIngo Weinhold 2357486b72dSIngo Weinhold char buffer[1024]; 2367486b72dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 2377486b72dSIngo Weinhold _kern_ktrace_output(buffer); 2387486b72dSIngo Weinhold 2397486b72dSIngo Weinhold va_end(list); 2407486b72dSIngo Weinhold } 2417486b72dSIngo Weinhold 2427486b72dSIngo Weinhold #define KTRACE(x...) ktrace_printf(x) 2437486b72dSIngo Weinhold 2447486b72dSIngo Weinhold #else 2457486b72dSIngo Weinhold # define KTRACE(x...) 2467486b72dSIngo Weinhold #endif // RUNTIME_LOADER_TRACING 2477486b72dSIngo Weinhold 2487486b72dSIngo Weinhold 2490c0fea5dSIngo Weinhold static void 2500c0fea5dSIngo Weinhold rld_unlock() 2510c0fea5dSIngo Weinhold { 252e73923b0SAxel Dörfler if (sSemCount-- == 1) { 253e73923b0SAxel Dörfler sSemOwner = -1; 254e73923b0SAxel Dörfler release_sem(sSem); 2550c0fea5dSIngo Weinhold } 2560c0fea5dSIngo Weinhold } 2570c0fea5dSIngo Weinhold 2580c0fea5dSIngo Weinhold 2590c0fea5dSIngo Weinhold static void 2600c0fea5dSIngo Weinhold rld_lock() 2610c0fea5dSIngo Weinhold { 2620c0fea5dSIngo Weinhold thread_id self = find_thread(NULL); 263e73923b0SAxel Dörfler if (self != sSemOwner) { 264e73923b0SAxel Dörfler acquire_sem(sSem); 265e73923b0SAxel Dörfler sSemOwner = self; 2660c0fea5dSIngo Weinhold } 267e73923b0SAxel Dörfler sSemCount++; 2680c0fea5dSIngo Weinhold } 2690c0fea5dSIngo Weinhold 2700c0fea5dSIngo Weinhold 2710c0fea5dSIngo Weinhold static void 2720c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image) 2730c0fea5dSIngo Weinhold { 2740c0fea5dSIngo Weinhold image->next = 0; 2750c0fea5dSIngo Weinhold 2760c0fea5dSIngo Weinhold image->prev = queue->tail; 2770c0fea5dSIngo Weinhold if (queue->tail) 2780c0fea5dSIngo Weinhold queue->tail->next = image; 2790c0fea5dSIngo Weinhold 2800c0fea5dSIngo Weinhold queue->tail = image; 2810c0fea5dSIngo Weinhold if (!queue->head) 2820c0fea5dSIngo Weinhold queue->head = image; 2830c0fea5dSIngo Weinhold } 2840c0fea5dSIngo Weinhold 2850c0fea5dSIngo Weinhold 2860c0fea5dSIngo Weinhold static void 2870c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image) 2880c0fea5dSIngo Weinhold { 2890c0fea5dSIngo Weinhold if (image->next) 2900c0fea5dSIngo Weinhold image->next->prev = image->prev; 2910c0fea5dSIngo Weinhold else 2920c0fea5dSIngo Weinhold queue->tail = image->prev; 2930c0fea5dSIngo Weinhold 2940c0fea5dSIngo Weinhold if (image->prev) 2950c0fea5dSIngo Weinhold image->prev->next = image->next; 2960c0fea5dSIngo Weinhold else 2970c0fea5dSIngo Weinhold queue->head = image->next; 2980c0fea5dSIngo Weinhold 2990c0fea5dSIngo Weinhold image->prev = 0; 3000c0fea5dSIngo Weinhold image->next = 0; 3010c0fea5dSIngo Weinhold } 3020c0fea5dSIngo Weinhold 3030c0fea5dSIngo Weinhold 3040c0fea5dSIngo Weinhold static uint32 3050c0fea5dSIngo Weinhold elf_hash(const uint8 *name) 3060c0fea5dSIngo Weinhold { 3070c0fea5dSIngo Weinhold uint32 hash = 0; 3080c0fea5dSIngo Weinhold uint32 temp; 3090c0fea5dSIngo Weinhold 3100c0fea5dSIngo Weinhold while (*name) { 3110c0fea5dSIngo Weinhold hash = (hash << 4) + *name++; 3120c0fea5dSIngo Weinhold if ((temp = hash & 0xf0000000)) { 3130c0fea5dSIngo Weinhold hash ^= temp >> 24; 3140c0fea5dSIngo Weinhold } 3150c0fea5dSIngo Weinhold hash &= ~temp; 3160c0fea5dSIngo Weinhold } 3170c0fea5dSIngo Weinhold return hash; 3180c0fea5dSIngo Weinhold } 3190c0fea5dSIngo Weinhold 3200c0fea5dSIngo Weinhold 3214bef3723SAxel Dörfler static inline bool 3224bef3723SAxel Dörfler report_errors() 3234bef3723SAxel Dörfler { 3244bef3723SAxel Dörfler return gProgramArgs->error_port >= 0; 3254bef3723SAxel Dörfler } 3264bef3723SAxel Dörfler 3274bef3723SAxel Dörfler 3289a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork. 3299a6072a3SAxel Dörfler static status_t 3309a6072a3SAxel Dörfler update_image_id(image_t *image) 3319a6072a3SAxel Dörfler { 3329a6072a3SAxel Dörfler int32 cookie = 0; 3339a6072a3SAxel Dörfler image_info info; 3349a6072a3SAxel Dörfler while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info, 3359a6072a3SAxel Dörfler sizeof(image_info)) == B_OK) { 3369a6072a3SAxel Dörfler for (uint32 i = 0; i < image->num_regions; i++) { 3379a6072a3SAxel Dörfler if (image->regions[i].vmstart == (addr_t)info.text) { 3389a6072a3SAxel Dörfler image->id = info.id; 3399a6072a3SAxel Dörfler return B_OK; 3409a6072a3SAxel Dörfler } 3419a6072a3SAxel Dörfler } 3429a6072a3SAxel Dörfler } 3439a6072a3SAxel Dörfler 3449a6072a3SAxel Dörfler FATAL("Could not update image ID %ld after fork()!\n", image->id); 3459a6072a3SAxel Dörfler return B_ENTRY_NOT_FOUND; 3469a6072a3SAxel Dörfler } 3479a6072a3SAxel Dörfler 3489a6072a3SAxel Dörfler 3499a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images. 3509a6072a3SAxel Dörfler static status_t 3519a6072a3SAxel Dörfler update_image_ids(void) 3529a6072a3SAxel Dörfler { 3539a6072a3SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 3549a6072a3SAxel Dörfler status_t status = update_image_id(image); 3559a6072a3SAxel Dörfler if (status != B_OK) 3569a6072a3SAxel Dörfler return status; 3579a6072a3SAxel Dörfler } 3589a6072a3SAxel Dörfler for (image_t *image = sDisposableImages.head; image; image = image->next) { 3599a6072a3SAxel Dörfler status_t status = update_image_id(image); 3609a6072a3SAxel Dörfler if (status != B_OK) 3619a6072a3SAxel Dörfler return status; 3629a6072a3SAxel Dörfler } 3639a6072a3SAxel Dörfler 3649a6072a3SAxel Dörfler sInvalidImageIDs = false; 3659a6072a3SAxel Dörfler return B_OK; 3669a6072a3SAxel Dörfler } 3679a6072a3SAxel Dörfler 3689a6072a3SAxel Dörfler 3690c0fea5dSIngo Weinhold static image_t * 3700c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath, 3710c0fea5dSIngo Weinhold uint32 typeMask) 3720c0fea5dSIngo Weinhold { 3739a6072a3SAxel Dörfler for (image_t *image = queue->head; image; image = image->next) { 3740c0fea5dSIngo Weinhold const char *imageName = isPath ? image->path : image->name; 3750c0fea5dSIngo Weinhold int length = isPath ? sizeof(image->path) : sizeof(image->name); 3760c0fea5dSIngo Weinhold 3770c0fea5dSIngo Weinhold if (!strncmp(imageName, name, length) 3780c0fea5dSIngo Weinhold && (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) { 3790c0fea5dSIngo Weinhold return image; 3800c0fea5dSIngo Weinhold } 3810c0fea5dSIngo Weinhold } 3820c0fea5dSIngo Weinhold 3830c0fea5dSIngo Weinhold return NULL; 3840c0fea5dSIngo Weinhold } 3850c0fea5dSIngo Weinhold 3860c0fea5dSIngo Weinhold 3870c0fea5dSIngo Weinhold static image_t * 3880c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask) 3890c0fea5dSIngo Weinhold { 3909a6072a3SAxel Dörfler bool isPath = strchr(name, '/') != NULL; 39146f4d849SIngo Weinhold return find_image_in_queue(&sLoadedImages, name, isPath, typeMask); 3920c0fea5dSIngo Weinhold } 3930c0fea5dSIngo Weinhold 3940c0fea5dSIngo Weinhold 3950c0fea5dSIngo Weinhold static image_t * 3960c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id) 3970c0fea5dSIngo Weinhold { 3989a6072a3SAxel Dörfler if (sInvalidImageIDs) { 3999a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 4009a6072a3SAxel Dörfler update_image_ids(); 4019a6072a3SAxel Dörfler } 4020c0fea5dSIngo Weinhold 4039a6072a3SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 4040c0fea5dSIngo Weinhold if (image->id == id) 4050c0fea5dSIngo Weinhold return image; 4060c0fea5dSIngo Weinhold } 4070c0fea5dSIngo Weinhold 4080c0fea5dSIngo Weinhold // For the termination routine, we need to look into the list of 4090c0fea5dSIngo Weinhold // disposable images as well 4109a6072a3SAxel Dörfler for (image_t *image = sDisposableImages.head; image; image = image->next) { 4110c0fea5dSIngo Weinhold if (image->id == id) 4120c0fea5dSIngo Weinhold return image; 4130c0fea5dSIngo Weinhold } 4140c0fea5dSIngo Weinhold 4150c0fea5dSIngo Weinhold return NULL; 4160c0fea5dSIngo Weinhold } 4170c0fea5dSIngo Weinhold 4180c0fea5dSIngo Weinhold 4195fd6637bSIngo Weinhold static image_t* 4205fd6637bSIngo Weinhold get_program_image() 42112a5e9a4SAxel Dörfler { 42212a5e9a4SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 42312a5e9a4SAxel Dörfler if (image->type == B_APP_IMAGE) 4245fd6637bSIngo Weinhold return image; 42512a5e9a4SAxel Dörfler } 42612a5e9a4SAxel Dörfler 42712a5e9a4SAxel Dörfler return NULL; 42812a5e9a4SAxel Dörfler } 42912a5e9a4SAxel Dörfler 43012a5e9a4SAxel Dörfler 4315fd6637bSIngo Weinhold static const char * 4325fd6637bSIngo Weinhold get_program_path() 4335fd6637bSIngo Weinhold { 4345fd6637bSIngo Weinhold if (image_t* image = get_program_image()) 4355fd6637bSIngo Weinhold return image->path; 4365fd6637bSIngo Weinhold 4375fd6637bSIngo Weinhold return NULL; 4385fd6637bSIngo Weinhold } 4395fd6637bSIngo Weinhold 4405fd6637bSIngo Weinhold 4410c0fea5dSIngo Weinhold static status_t 44212a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize, 44312a5e9a4SAxel Dörfler int32 *_sheaderSize) 4440c0fea5dSIngo Weinhold { 4450c0fea5dSIngo Weinhold if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) 4460c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4470c0fea5dSIngo Weinhold 4480c0fea5dSIngo Weinhold if (eheader->e_ident[4] != ELFCLASS32) 4490c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4500c0fea5dSIngo Weinhold 4510c0fea5dSIngo Weinhold if (eheader->e_phoff == 0) 4520c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4530c0fea5dSIngo Weinhold 4540c0fea5dSIngo Weinhold if (eheader->e_phentsize < sizeof(struct Elf32_Phdr)) 4550c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4560c0fea5dSIngo Weinhold 4570c0fea5dSIngo Weinhold *_pheaderSize = eheader->e_phentsize * eheader->e_phnum; 4580c0fea5dSIngo Weinhold *_sheaderSize = eheader->e_shentsize * eheader->e_shnum; 4590c0fea5dSIngo Weinhold 4605aa7b7b6SMarcus Overhagen if (*_pheaderSize <= 0 || *_sheaderSize <= 0) 4615aa7b7b6SMarcus Overhagen return B_NOT_AN_EXECUTABLE; 4625aa7b7b6SMarcus Overhagen 4635aa7b7b6SMarcus Overhagen return B_OK; 4640c0fea5dSIngo Weinhold } 4650c0fea5dSIngo Weinhold 4660c0fea5dSIngo Weinhold 4670c0fea5dSIngo Weinhold static int32 4680c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize) 4690c0fea5dSIngo Weinhold { 4700c0fea5dSIngo Weinhold struct Elf32_Phdr *pheaders; 4710c0fea5dSIngo Weinhold int32 count = 0; 4720c0fea5dSIngo Weinhold int i; 4730c0fea5dSIngo Weinhold 4740c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 4750c0fea5dSIngo Weinhold pheaders = (struct Elf32_Phdr *)(buff + i * phentsize); 4760c0fea5dSIngo Weinhold 4770c0fea5dSIngo Weinhold switch (pheaders->p_type) { 4780c0fea5dSIngo Weinhold case PT_NULL: 4790c0fea5dSIngo Weinhold /* NOP header */ 4800c0fea5dSIngo Weinhold break; 4810c0fea5dSIngo Weinhold case PT_LOAD: 4820c0fea5dSIngo Weinhold count += 1; 4830c0fea5dSIngo Weinhold if (pheaders->p_memsz != pheaders->p_filesz) { 4840c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz); 4850c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz); 4860c0fea5dSIngo Weinhold 4870c0fea5dSIngo Weinhold if (A != B) 4880c0fea5dSIngo Weinhold count += 1; 4890c0fea5dSIngo Weinhold } 4900c0fea5dSIngo Weinhold break; 4910c0fea5dSIngo Weinhold case PT_DYNAMIC: 4920c0fea5dSIngo Weinhold /* will be handled at some other place */ 4930c0fea5dSIngo Weinhold break; 4940c0fea5dSIngo Weinhold case PT_INTERP: 4950c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 4960c0fea5dSIngo Weinhold break; 4970c0fea5dSIngo Weinhold case PT_NOTE: 4980c0fea5dSIngo Weinhold /* unsupported */ 4990c0fea5dSIngo Weinhold break; 5000c0fea5dSIngo Weinhold case PT_SHLIB: 5010c0fea5dSIngo Weinhold /* undefined semantics */ 5020c0fea5dSIngo Weinhold break; 5030c0fea5dSIngo Weinhold case PT_PHDR: 5040c0fea5dSIngo Weinhold /* we don't use it */ 5050c0fea5dSIngo Weinhold break; 5062ecebae1SDavid McPaul case PT_STACK: 5072ecebae1SDavid McPaul /* we don't use it */ 5082ecebae1SDavid McPaul break; 5090c0fea5dSIngo Weinhold default: 5102ecebae1SDavid McPaul FATAL("unhandled pheader type in count 0x%lx\n", pheaders->p_type); 5110c0fea5dSIngo Weinhold return B_BAD_DATA; 5120c0fea5dSIngo Weinhold } 5130c0fea5dSIngo Weinhold } 5140c0fea5dSIngo Weinhold 5150c0fea5dSIngo Weinhold return count; 5160c0fea5dSIngo Weinhold } 5170c0fea5dSIngo Weinhold 5180c0fea5dSIngo Weinhold 5190c0fea5dSIngo Weinhold static image_t * 5200c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions) 5210c0fea5dSIngo Weinhold { 5220c0fea5dSIngo Weinhold size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t); 5230c0fea5dSIngo Weinhold const char *lastSlash; 5240c0fea5dSIngo Weinhold 5250c0fea5dSIngo Weinhold image_t *image = (image_t*)malloc(allocSize); 5260c0fea5dSIngo Weinhold if (image == NULL) { 5270c0fea5dSIngo Weinhold FATAL("no memory for image %s\n", path); 5280c0fea5dSIngo Weinhold return NULL; 5290c0fea5dSIngo Weinhold } 5300c0fea5dSIngo Weinhold 5310c0fea5dSIngo Weinhold memset(image, 0, allocSize); 5320c0fea5dSIngo Weinhold 5330c0fea5dSIngo Weinhold strlcpy(image->path, path, sizeof(image->path)); 5340c0fea5dSIngo Weinhold 5350c0fea5dSIngo Weinhold // Make the last component of the supplied name the image name. 5360c0fea5dSIngo Weinhold // If present, DT_SONAME will replace this name. 5370c0fea5dSIngo Weinhold if ((lastSlash = strrchr(name, '/'))) 5380c0fea5dSIngo Weinhold strlcpy(image->name, lastSlash + 1, sizeof(image->name)); 5390c0fea5dSIngo Weinhold else 5400c0fea5dSIngo Weinhold strlcpy(image->name, name, sizeof(image->name)); 5410c0fea5dSIngo Weinhold 5420c0fea5dSIngo Weinhold image->ref_count = 1; 5430c0fea5dSIngo Weinhold image->num_regions = num_regions; 5440c0fea5dSIngo Weinhold 5450c0fea5dSIngo Weinhold return image; 5460c0fea5dSIngo Weinhold } 5470c0fea5dSIngo Weinhold 5480c0fea5dSIngo Weinhold 5490c0fea5dSIngo Weinhold static void 5500c0fea5dSIngo Weinhold delete_image_struct(image_t *image) 5510c0fea5dSIngo Weinhold { 5520c0fea5dSIngo Weinhold #ifdef DEBUG 5530c0fea5dSIngo Weinhold size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t); 5540c0fea5dSIngo Weinhold memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed); 5550c0fea5dSIngo Weinhold #endif 5560c0fea5dSIngo Weinhold free(image->needed); 557*003ebb0eSIngo Weinhold free(image->versions); 55810b4b5d1SIngo Weinhold 55910b4b5d1SIngo Weinhold while (RuntimeLoaderSymbolPatcher* patcher 56010b4b5d1SIngo Weinhold = image->defined_symbol_patchers) { 56110b4b5d1SIngo Weinhold image->defined_symbol_patchers = patcher->next; 56210b4b5d1SIngo Weinhold delete patcher; 56310b4b5d1SIngo Weinhold } 56410b4b5d1SIngo Weinhold while (RuntimeLoaderSymbolPatcher* patcher 56510b4b5d1SIngo Weinhold = image->undefined_symbol_patchers) { 56610b4b5d1SIngo Weinhold image->undefined_symbol_patchers = patcher->next; 56710b4b5d1SIngo Weinhold delete patcher; 56810b4b5d1SIngo Weinhold } 5690c0fea5dSIngo Weinhold 5700c0fea5dSIngo Weinhold #ifdef DEBUG 5719a6072a3SAxel Dörfler // overwrite images to make sure they aren't accidently reused anywhere 5720c0fea5dSIngo Weinhold memset(image, 0xa5, size); 5730c0fea5dSIngo Weinhold #endif 5740c0fea5dSIngo Weinhold free(image); 5750c0fea5dSIngo Weinhold } 5760c0fea5dSIngo Weinhold 5770c0fea5dSIngo Weinhold 5780c0fea5dSIngo Weinhold static void 5790c0fea5dSIngo Weinhold delete_image(image_t *image) 5800c0fea5dSIngo Weinhold { 5812760c4cdSAxel Dörfler if (image == NULL) 5822760c4cdSAxel Dörfler return; 5832760c4cdSAxel Dörfler 5840c0fea5dSIngo Weinhold _kern_unregister_image(image->id); 5850c0fea5dSIngo Weinhold // registered in load_container() 5860c0fea5dSIngo Weinhold 5870c0fea5dSIngo Weinhold delete_image_struct(image); 5880c0fea5dSIngo Weinhold } 5890c0fea5dSIngo Weinhold 5900c0fea5dSIngo Weinhold 5910c85bd05SIngo Weinhold static void 5920c85bd05SIngo Weinhold update_image_flags_recursively(image_t* image, uint32 flagsToSet, 5930c85bd05SIngo Weinhold uint32 flagsToClear) 5940c85bd05SIngo Weinhold { 5950c85bd05SIngo Weinhold image_t* queue[sLoadedImageCount]; 5960c85bd05SIngo Weinhold uint32 count = 0; 5970c85bd05SIngo Weinhold uint32 index = 0; 5980c85bd05SIngo Weinhold queue[count++] = image; 5990c85bd05SIngo Weinhold image->flags |= RFLAG_VISITED; 6000c85bd05SIngo Weinhold 6010c85bd05SIngo Weinhold while (index < count) { 6020c85bd05SIngo Weinhold // pop next image 6030c85bd05SIngo Weinhold image = queue[index++]; 6040c85bd05SIngo Weinhold 6050c85bd05SIngo Weinhold // push dependencies 6060c85bd05SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 6070c85bd05SIngo Weinhold image_t* needed = image->needed[i]; 6080c85bd05SIngo Weinhold if ((needed->flags & RFLAG_VISITED) == 0) { 6090c85bd05SIngo Weinhold queue[count++] = needed; 6100c85bd05SIngo Weinhold needed->flags |= RFLAG_VISITED; 6110c85bd05SIngo Weinhold } 6120c85bd05SIngo Weinhold } 6130c85bd05SIngo Weinhold } 6140c85bd05SIngo Weinhold 6150c85bd05SIngo Weinhold // update flags 6160c85bd05SIngo Weinhold for (uint32 i = 0; i < count; i++) { 6170c85bd05SIngo Weinhold queue[i]->flags = (queue[i]->flags | flagsToSet) 6180c85bd05SIngo Weinhold & ~(flagsToClear | RFLAG_VISITED); 6190c85bd05SIngo Weinhold } 6200c85bd05SIngo Weinhold } 6210c85bd05SIngo Weinhold 6220c85bd05SIngo Weinhold 6230c85bd05SIngo Weinhold static void 6240c85bd05SIngo Weinhold set_image_flags_recursively(image_t* image, uint32 flags) 6250c85bd05SIngo Weinhold { 6260c85bd05SIngo Weinhold update_image_flags_recursively(image, flags, 0); 6270c85bd05SIngo Weinhold } 6280c85bd05SIngo Weinhold 6290c85bd05SIngo Weinhold 6300c85bd05SIngo Weinhold static void 6310c85bd05SIngo Weinhold clear_image_flags_recursively(image_t* image, uint32 flags) 6320c85bd05SIngo Weinhold { 6330c85bd05SIngo Weinhold update_image_flags_recursively(image, 0, flags); 6340c85bd05SIngo Weinhold } 6350c85bd05SIngo Weinhold 6360c85bd05SIngo Weinhold 6370c0fea5dSIngo Weinhold static status_t 6380c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) 6390c0fea5dSIngo Weinhold { 6400c0fea5dSIngo Weinhold struct Elf32_Phdr *pheader; 6410c0fea5dSIngo Weinhold int regcount; 6420c0fea5dSIngo Weinhold int i; 6430c0fea5dSIngo Weinhold 6440c0fea5dSIngo Weinhold regcount = 0; 6450c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 6460c0fea5dSIngo Weinhold pheader = (struct Elf32_Phdr *)(buff + i * phentsize); 6470c0fea5dSIngo Weinhold 6480c0fea5dSIngo Weinhold switch (pheader->p_type) { 6490c0fea5dSIngo Weinhold case PT_NULL: 6500c0fea5dSIngo Weinhold /* NOP header */ 6510c0fea5dSIngo Weinhold break; 6520c0fea5dSIngo Weinhold case PT_LOAD: 6530c0fea5dSIngo Weinhold if (pheader->p_memsz == pheader->p_filesz) { 6540c0fea5dSIngo Weinhold /* 6550c0fea5dSIngo Weinhold * everything in one area 6560c0fea5dSIngo Weinhold */ 6570c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 6580c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz; 6590c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 6600c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz 6610c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 6620c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 6630c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 6640c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 6650c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 6660c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 6670c0fea5dSIngo Weinhold // this is a writable segment 6680c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 6690c0fea5dSIngo Weinhold } 6700c0fea5dSIngo Weinhold } else { 6710c0fea5dSIngo Weinhold /* 6720c0fea5dSIngo Weinhold * may require splitting 6730c0fea5dSIngo Weinhold */ 6740c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz); 6750c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz); 6760c0fea5dSIngo Weinhold 6770c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 6780c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_filesz; 6790c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 6800c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz 6810c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 6820c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 6830c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 6840c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 6850c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 6860c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 6870c0fea5dSIngo Weinhold // this is a writable segment 6880c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 6890c0fea5dSIngo Weinhold } 6900c0fea5dSIngo Weinhold 6910c0fea5dSIngo Weinhold if (A != B) { 6920c0fea5dSIngo Weinhold /* 6930c0fea5dSIngo Weinhold * yeah, it requires splitting 6940c0fea5dSIngo Weinhold */ 6950c0fea5dSIngo Weinhold regcount += 1; 6960c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 6970c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz; 6980c0fea5dSIngo Weinhold image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize; 6990c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr)) 7000c0fea5dSIngo Weinhold - image->regions[regcount-1].vmsize; 7010c0fea5dSIngo Weinhold image->regions[regcount].fdstart = 0; 7020c0fea5dSIngo Weinhold image->regions[regcount].fdsize = 0; 7030c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 7040c0fea5dSIngo Weinhold image->regions[regcount].flags = RFLAG_ANON; 7050c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 7060c0fea5dSIngo Weinhold // this is a writable segment 7070c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 7080c0fea5dSIngo Weinhold } 7090c0fea5dSIngo Weinhold } 7100c0fea5dSIngo Weinhold } 7110c0fea5dSIngo Weinhold regcount += 1; 7120c0fea5dSIngo Weinhold break; 7130c0fea5dSIngo Weinhold case PT_DYNAMIC: 7140c0fea5dSIngo Weinhold image->dynamic_ptr = pheader->p_vaddr; 7150c0fea5dSIngo Weinhold break; 7160c0fea5dSIngo Weinhold case PT_INTERP: 7170c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 7180c0fea5dSIngo Weinhold break; 7190c0fea5dSIngo Weinhold case PT_NOTE: 7200c0fea5dSIngo Weinhold /* unsupported */ 7210c0fea5dSIngo Weinhold break; 7220c0fea5dSIngo Weinhold case PT_SHLIB: 7230c0fea5dSIngo Weinhold /* undefined semantics */ 7240c0fea5dSIngo Weinhold break; 7250c0fea5dSIngo Weinhold case PT_PHDR: 7260c0fea5dSIngo Weinhold /* we don't use it */ 7270c0fea5dSIngo Weinhold break; 7282ecebae1SDavid McPaul case PT_STACK: 7292ecebae1SDavid McPaul /* we don't use it */ 7302ecebae1SDavid McPaul break; 7310c0fea5dSIngo Weinhold default: 7322ecebae1SDavid McPaul FATAL("unhandled pheader type in parse 0x%lx\n", pheader->p_type); 7330c0fea5dSIngo Weinhold return B_BAD_DATA; 7340c0fea5dSIngo Weinhold } 7350c0fea5dSIngo Weinhold } 7360c0fea5dSIngo Weinhold 7370c0fea5dSIngo Weinhold return B_OK; 7380c0fea5dSIngo Weinhold } 7390c0fea5dSIngo Weinhold 7400c0fea5dSIngo Weinhold 741593ee7bbSIngo Weinhold static void 742593ee7bbSIngo Weinhold analyze_image_haiku_version_and_abi(image_t* image) 743593ee7bbSIngo Weinhold { 744593ee7bbSIngo Weinhold // Haiku API version 745593ee7bbSIngo Weinhold struct Elf32_Sym* symbol = find_symbol(image, 746*003ebb0eSIngo Weinhold SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME, 747*003ebb0eSIngo Weinhold B_SYMBOL_TYPE_DATA)); 748593ee7bbSIngo Weinhold if (symbol != NULL && symbol->st_shndx != SHN_UNDEF 749593ee7bbSIngo Weinhold && symbol->st_value > 0 750593ee7bbSIngo Weinhold && ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT 751593ee7bbSIngo Weinhold && symbol->st_size >= sizeof(uint32)) { 752593ee7bbSIngo Weinhold image->api_version 753593ee7bbSIngo Weinhold = *(uint32*)(symbol->st_value + image->regions[0].delta); 754593ee7bbSIngo Weinhold } else 755593ee7bbSIngo Weinhold image->api_version = 0; 756593ee7bbSIngo Weinhold 757593ee7bbSIngo Weinhold // Haiku ABI 758*003ebb0eSIngo Weinhold symbol = find_symbol(image, 759*003ebb0eSIngo Weinhold SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME, 760*003ebb0eSIngo Weinhold B_SYMBOL_TYPE_DATA)); 761593ee7bbSIngo Weinhold if (symbol != NULL && symbol->st_shndx != SHN_UNDEF 762593ee7bbSIngo Weinhold && symbol->st_value > 0 763593ee7bbSIngo Weinhold && ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT 764593ee7bbSIngo Weinhold && symbol->st_size >= sizeof(uint32)) { 765593ee7bbSIngo Weinhold image->abi = *(uint32*)(symbol->st_value + image->regions[0].delta); 766593ee7bbSIngo Weinhold } else 767593ee7bbSIngo Weinhold image->abi = 0; 768593ee7bbSIngo Weinhold } 769593ee7bbSIngo Weinhold 770593ee7bbSIngo Weinhold 7710c0fea5dSIngo Weinhold static bool 77234982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader, 77334982809SIngo Weinhold int32 sheaderSize, char* buffer, size_t bufferSize) 77434982809SIngo Weinhold { 77534982809SIngo Weinhold if (sheaderSize > (int)bufferSize) { 77634982809SIngo Weinhold FATAL("Cannot handle section headers bigger than %lu\n", bufferSize); 77734982809SIngo Weinhold return false; 77834982809SIngo Weinhold } 77934982809SIngo Weinhold 78034982809SIngo Weinhold // read section headers 78134982809SIngo Weinhold ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize); 78234982809SIngo Weinhold if (length != sheaderSize) { 78334982809SIngo Weinhold FATAL("Could not read section headers: %s\n", strerror(length)); 78434982809SIngo Weinhold return false; 78534982809SIngo Weinhold } 78634982809SIngo Weinhold 78734982809SIngo Weinhold // load the string section 78834982809SIngo Weinhold Elf32_Shdr* sectionHeader 78934982809SIngo Weinhold = (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize); 79034982809SIngo Weinhold 79134982809SIngo Weinhold if (sheaderSize + sectionHeader->sh_size > bufferSize) { 79234982809SIngo Weinhold FATAL("Buffer not big enough for section string section\n"); 79334982809SIngo Weinhold return false; 79434982809SIngo Weinhold } 79534982809SIngo Weinhold 79634982809SIngo Weinhold char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size; 79734982809SIngo Weinhold length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings, 79834982809SIngo Weinhold sectionHeader->sh_size); 79934982809SIngo Weinhold if (length != (int)sectionHeader->sh_size) { 80034982809SIngo Weinhold FATAL("Could not read section string section: %s\n", strerror(length)); 80134982809SIngo Weinhold return false; 80234982809SIngo Weinhold } 80334982809SIngo Weinhold 80434982809SIngo Weinhold // find the .comment section 80534982809SIngo Weinhold off_t commentOffset = 0; 80634982809SIngo Weinhold size_t commentSize = 0; 80734982809SIngo Weinhold for (uint32 i = 0; i < eheader.e_shnum; i++) { 80834982809SIngo Weinhold sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize); 80934982809SIngo Weinhold const char* sectionName = sectionStrings + sectionHeader->sh_name; 81034982809SIngo Weinhold if (sectionHeader->sh_name != 0 81134982809SIngo Weinhold && strcmp(sectionName, ".comment") == 0) { 81234982809SIngo Weinhold commentOffset = sectionHeader->sh_offset; 81334982809SIngo Weinhold commentSize = sectionHeader->sh_size; 81434982809SIngo Weinhold break; 81534982809SIngo Weinhold } 81634982809SIngo Weinhold } 81734982809SIngo Weinhold 81834982809SIngo Weinhold if (commentSize == 0) { 81934982809SIngo Weinhold FATAL("Could not find .comment section\n"); 82034982809SIngo Weinhold return false; 82134982809SIngo Weinhold } 82234982809SIngo Weinhold 82334982809SIngo Weinhold // read a part of the comment section 82434982809SIngo Weinhold if (commentSize > 512) 82534982809SIngo Weinhold commentSize = 512; 82634982809SIngo Weinhold 82734982809SIngo Weinhold length = _kern_read(fd, commentOffset, buffer, commentSize); 82834982809SIngo Weinhold if (length != (int)commentSize) { 82934982809SIngo Weinhold FATAL("Could not read .comment section: %s\n", strerror(length)); 83034982809SIngo Weinhold return false; 83134982809SIngo Weinhold } 83234982809SIngo Weinhold 83334982809SIngo Weinhold // the common prefix of the strings in the .comment section 83434982809SIngo Weinhold static const char* kGCCVersionPrefix = "GCC: (GNU) "; 83534982809SIngo Weinhold size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix); 83634982809SIngo Weinhold 83734982809SIngo Weinhold size_t index = 0; 83834982809SIngo Weinhold int gccMajor = 0; 83934982809SIngo Weinhold int gccMiddle = 0; 84034982809SIngo Weinhold int gccMinor = 0; 8412716cfd3SAxel Dörfler bool isHaiku = true; 84234982809SIngo Weinhold 84334982809SIngo Weinhold // Read up to 10 comments. The first three or four are usually from the 84434982809SIngo Weinhold // glue code. 84534982809SIngo Weinhold for (int i = 0; i < 10; i++) { 84634982809SIngo Weinhold // skip '\0' 84734982809SIngo Weinhold while (index < commentSize && buffer[index] == '\0') 84834982809SIngo Weinhold index++; 84934982809SIngo Weinhold char* stringStart = buffer + index; 85034982809SIngo Weinhold 85134982809SIngo Weinhold // find string end 85234982809SIngo Weinhold while (index < commentSize && buffer[index] != '\0') 85334982809SIngo Weinhold index++; 85434982809SIngo Weinhold 85534982809SIngo Weinhold // ignore the entry at the end of the buffer 85634982809SIngo Weinhold if (index == commentSize) 85734982809SIngo Weinhold break; 85834982809SIngo Weinhold 85934982809SIngo Weinhold // We have to analyze string like these: 86034982809SIngo Weinhold // GCC: (GNU) 2.9-beos-991026 86134982809SIngo Weinhold // GCC: (GNU) 2.95.3-haiku-080322 86234982809SIngo Weinhold // GCC: (GNU) 4.1.2 86334982809SIngo Weinhold 86434982809SIngo Weinhold // skip the common prefix 86534982809SIngo Weinhold if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0) 86634982809SIngo Weinhold continue; 86734982809SIngo Weinhold 86834982809SIngo Weinhold // the rest is the GCC version 86934982809SIngo Weinhold char* gccVersion = stringStart + gccVersionPrefixLen; 87034982809SIngo Weinhold char* gccPlatform = strchr(gccVersion, '-'); 87134982809SIngo Weinhold char* patchLevel = NULL; 87234982809SIngo Weinhold if (gccPlatform != NULL) { 87334982809SIngo Weinhold *gccPlatform = '\0'; 87434982809SIngo Weinhold gccPlatform++; 87534982809SIngo Weinhold patchLevel = strchr(gccPlatform, '-'); 87634982809SIngo Weinhold if (patchLevel != NULL) { 87734982809SIngo Weinhold *patchLevel = '\0'; 87834982809SIngo Weinhold patchLevel++; 87934982809SIngo Weinhold } 88034982809SIngo Weinhold } 88134982809SIngo Weinhold 88234982809SIngo Weinhold // split the gcc version into major, middle, and minor 88334982809SIngo Weinhold int version[3] = { 0, 0, 0 }; 88434982809SIngo Weinhold 88534982809SIngo Weinhold for (int k = 0; gccVersion != NULL && k < 3; k++) { 88634982809SIngo Weinhold char* dot = strchr(gccVersion, '.'); 88734982809SIngo Weinhold if (dot) { 88834982809SIngo Weinhold *dot = '\0'; 88934982809SIngo Weinhold dot++; 89034982809SIngo Weinhold } 89134982809SIngo Weinhold version[k] = atoi(gccVersion); 89234982809SIngo Weinhold gccVersion = dot; 89334982809SIngo Weinhold } 89434982809SIngo Weinhold 89534982809SIngo Weinhold // got any version? 89634982809SIngo Weinhold if (version[0] == 0) 89734982809SIngo Weinhold continue; 89834982809SIngo Weinhold 89934982809SIngo Weinhold // Select the gcc version with the smallest major, but the greatest 90034982809SIngo Weinhold // middle/minor. This should usually ignore the glue code version as 90134982809SIngo Weinhold // well as cases where e.g. in a gcc 2 program a single C file has 90234982809SIngo Weinhold // been compiled with gcc 4. 90334982809SIngo Weinhold if (gccMajor == 0 || gccMajor > version[0] 904593ee7bbSIngo Weinhold || (gccMajor == version[0] 90534982809SIngo Weinhold && (gccMiddle < version[1] 906593ee7bbSIngo Weinhold || (gccMiddle == version[1] && gccMinor < version[2])))) { 90734982809SIngo Weinhold gccMajor = version[0]; 90834982809SIngo Weinhold gccMiddle = version[1]; 90934982809SIngo Weinhold gccMinor = version[2]; 91034982809SIngo Weinhold } 9112716cfd3SAxel Dörfler 912f91194e5SIngo Weinhold if (gccMajor == 2 && gccPlatform != NULL 913f91194e5SIngo Weinhold && strcmp(gccPlatform, "haiku")) { 9142716cfd3SAxel Dörfler isHaiku = false; 91534982809SIngo Weinhold } 916f91194e5SIngo Weinhold } 91734982809SIngo Weinhold 918f91194e5SIngo Weinhold if (gccMajor == 0) 919f91194e5SIngo Weinhold return false; 92034982809SIngo Weinhold 921f91194e5SIngo Weinhold if (gccMajor == 2) { 922f91194e5SIngo Weinhold if (gccMiddle < 95) 923f91194e5SIngo Weinhold image->abi = B_HAIKU_ABI_GCC_2_ANCIENT; 924f91194e5SIngo Weinhold else if (isHaiku) 925f91194e5SIngo Weinhold image->abi = B_HAIKU_ABI_GCC_2_HAIKU; 926f91194e5SIngo Weinhold else 927f91194e5SIngo Weinhold image->abi = B_HAIKU_ABI_GCC_2_BEOS; 928f91194e5SIngo Weinhold } else 929f91194e5SIngo Weinhold image->abi = gccMajor << 16; 930f91194e5SIngo Weinhold 931f91194e5SIngo Weinhold return true; 93234982809SIngo Weinhold } 93334982809SIngo Weinhold 93434982809SIngo Weinhold 93534982809SIngo Weinhold static bool 9360c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image) 9370c0fea5dSIngo Weinhold { 9380c0fea5dSIngo Weinhold uint32 i; 9390c0fea5dSIngo Weinhold 9400c0fea5dSIngo Weinhold if (!image->dynamic_ptr) 9410c0fea5dSIngo Weinhold return true; 9420c0fea5dSIngo Weinhold 9430c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 9440c0fea5dSIngo Weinhold if (image->dynamic_ptr >= image->regions[i].start 9450c0fea5dSIngo Weinhold && image->dynamic_ptr < image->regions[i].start + image->regions[i].size) 9460c0fea5dSIngo Weinhold return true; 9470c0fea5dSIngo Weinhold } 9480c0fea5dSIngo Weinhold 9490c0fea5dSIngo Weinhold return false; 9500c0fea5dSIngo Weinhold } 9510c0fea5dSIngo Weinhold 9520c0fea5dSIngo Weinhold 9530c0fea5dSIngo Weinhold /** This function will change the protection of all read-only segments 9540c0fea5dSIngo Weinhold * to really be read-only. 9550c0fea5dSIngo Weinhold * The areas have to be read/write first, so that they can be relocated. 9560c0fea5dSIngo Weinhold */ 9570c0fea5dSIngo Weinhold 9580c0fea5dSIngo Weinhold static void 9590c0fea5dSIngo Weinhold remap_images(void) 9600c0fea5dSIngo Weinhold { 9610c0fea5dSIngo Weinhold image_t *image; 9620c0fea5dSIngo Weinhold uint32 i; 9630c0fea5dSIngo Weinhold 9640c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image != NULL; image = image->next) { 9650c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 9660c0fea5dSIngo Weinhold if ((image->regions[i].flags & RFLAG_RW) == 0 9670c0fea5dSIngo Weinhold && (image->regions[i].flags & RFLAG_REMAPPED) == 0) { 9680c0fea5dSIngo Weinhold // we only need to do this once, so we remember those we've already mapped 9690c0fea5dSIngo Weinhold if (_kern_set_area_protection(image->regions[i].id, 9700c0fea5dSIngo Weinhold B_READ_AREA | B_EXECUTE_AREA) == B_OK) 9710c0fea5dSIngo Weinhold image->regions[i].flags |= RFLAG_REMAPPED; 9720c0fea5dSIngo Weinhold } 9730c0fea5dSIngo Weinhold } 9740c0fea5dSIngo Weinhold } 9750c0fea5dSIngo Weinhold } 9760c0fea5dSIngo Weinhold 9770c0fea5dSIngo Weinhold 9780c0fea5dSIngo Weinhold static status_t 9790c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed) 9800c0fea5dSIngo Weinhold { 9810c0fea5dSIngo Weinhold status_t status = B_OK; 9820c0fea5dSIngo Weinhold const char *baseName; 9830c0fea5dSIngo Weinhold uint32 i; 9840c0fea5dSIngo Weinhold 9850c0fea5dSIngo Weinhold (void)(fd); 9860c0fea5dSIngo Weinhold 9870c0fea5dSIngo Weinhold // cut the file name from the path as base name for the created areas 9880c0fea5dSIngo Weinhold baseName = strrchr(path, '/'); 9890c0fea5dSIngo Weinhold if (baseName != NULL) 9900c0fea5dSIngo Weinhold baseName++; 9910c0fea5dSIngo Weinhold else 9920c0fea5dSIngo Weinhold baseName = path; 9930c0fea5dSIngo Weinhold 9940c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 9950c0fea5dSIngo Weinhold char regionName[B_OS_NAME_LENGTH]; 9960c0fea5dSIngo Weinhold addr_t loadAddress; 9970c0fea5dSIngo Weinhold uint32 addressSpecifier; 9980c0fea5dSIngo Weinhold 9990c0fea5dSIngo Weinhold // for BeOS compatibility: if we load an old BeOS executable, we 10000c0fea5dSIngo Weinhold // have to relocate it, if possible - we recognize it because the 10010c0fea5dSIngo Weinhold // vmstart is set to 0 (hopefully always) 10020c0fea5dSIngo Weinhold if (fixed && image->regions[i].vmstart == 0) 10030c0fea5dSIngo Weinhold fixed = false; 10040c0fea5dSIngo Weinhold 10050c0fea5dSIngo Weinhold snprintf(regionName, sizeof(regionName), "%s_seg%lu%s", 10060c0fea5dSIngo Weinhold baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro"); 10070c0fea5dSIngo Weinhold 10080c0fea5dSIngo Weinhold if (image->dynamic_ptr && !fixed) { 10090c0fea5dSIngo Weinhold // relocatable image... we can afford to place wherever 10100c0fea5dSIngo Weinhold if (i == 0) { 10110c0fea5dSIngo Weinhold // but only the first segment gets a free ride 10120c0fea5dSIngo Weinhold loadAddress = RLD_PROGRAM_BASE; 10130c0fea5dSIngo Weinhold addressSpecifier = B_BASE_ADDRESS; 10140c0fea5dSIngo Weinhold } else { 10150c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart + image->regions[i-1].delta; 10160c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 10170c0fea5dSIngo Weinhold } 10180c0fea5dSIngo Weinhold } else { 10190c0fea5dSIngo Weinhold // not relocatable, put it where it asks or die trying 10200c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart; 10210c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 10220c0fea5dSIngo Weinhold } 10230c0fea5dSIngo Weinhold 10240c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_ANON) { 10250c0fea5dSIngo Weinhold image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress, 10260c0fea5dSIngo Weinhold addressSpecifier, image->regions[i].vmsize, B_NO_LOCK, 10270c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 10280c0fea5dSIngo Weinhold 10290c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 10300c0fea5dSIngo Weinhold status = image->regions[i].id; 10310c0fea5dSIngo Weinhold goto error; 10320c0fea5dSIngo Weinhold } 10330c0fea5dSIngo Weinhold 10340c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 10350c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 10360c0fea5dSIngo Weinhold } else { 10373cf7ecd1SIngo Weinhold image->regions[i].id = _kern_map_file(regionName, 10383cf7ecd1SIngo Weinhold (void **)&loadAddress, addressSpecifier, 10393cf7ecd1SIngo Weinhold image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA, 10403cf7ecd1SIngo Weinhold REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart)); 10410c0fea5dSIngo Weinhold 10420c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 10430c0fea5dSIngo Weinhold status = image->regions[i].id; 10440c0fea5dSIngo Weinhold goto error; 10450c0fea5dSIngo Weinhold } 10460c0fea5dSIngo Weinhold 10470c0fea5dSIngo Weinhold TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path, 10480c0fea5dSIngo Weinhold (void *)loadAddress, image->regions[i].vmsize, 10490c0fea5dSIngo Weinhold image->regions[i].flags & RFLAG_RW ? "rw" : "read-only")); 10500c0fea5dSIngo Weinhold 10510c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 10520c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 10530c0fea5dSIngo Weinhold 10540c0fea5dSIngo Weinhold // handle trailer bits in data segment 10550c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_RW) { 10560c0fea5dSIngo Weinhold addr_t startClearing; 10570c0fea5dSIngo Weinhold addr_t toClear; 10580c0fea5dSIngo Weinhold 10590c0fea5dSIngo Weinhold startClearing = image->regions[i].vmstart 10600c0fea5dSIngo Weinhold + PAGE_OFFSET(image->regions[i].start) 10610c0fea5dSIngo Weinhold + image->regions[i].size; 10620c0fea5dSIngo Weinhold toClear = image->regions[i].vmsize 10630c0fea5dSIngo Weinhold - PAGE_OFFSET(image->regions[i].start) 10640c0fea5dSIngo Weinhold - image->regions[i].size; 10650c0fea5dSIngo Weinhold 10660c0fea5dSIngo Weinhold TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear)); 10670c0fea5dSIngo Weinhold memset((void *)startClearing, 0, toClear); 10680c0fea5dSIngo Weinhold } 10690c0fea5dSIngo Weinhold } 10700c0fea5dSIngo Weinhold } 10710c0fea5dSIngo Weinhold 10720c0fea5dSIngo Weinhold if (image->dynamic_ptr) 10730c0fea5dSIngo Weinhold image->dynamic_ptr += image->regions[0].delta; 10740c0fea5dSIngo Weinhold 10750c0fea5dSIngo Weinhold return B_OK; 10760c0fea5dSIngo Weinhold 10770c0fea5dSIngo Weinhold error: 10780c0fea5dSIngo Weinhold return status; 10790c0fea5dSIngo Weinhold } 10800c0fea5dSIngo Weinhold 10810c0fea5dSIngo Weinhold 10820c0fea5dSIngo Weinhold static void 10830c0fea5dSIngo Weinhold unmap_image(image_t *image) 10840c0fea5dSIngo Weinhold { 10850c0fea5dSIngo Weinhold uint32 i; 10860c0fea5dSIngo Weinhold 10870c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 10880c0fea5dSIngo Weinhold _kern_delete_area(image->regions[i].id); 10890c0fea5dSIngo Weinhold 10900c0fea5dSIngo Weinhold image->regions[i].id = -1; 10910c0fea5dSIngo Weinhold } 10920c0fea5dSIngo Weinhold } 10930c0fea5dSIngo Weinhold 10940c0fea5dSIngo Weinhold 10950c0fea5dSIngo Weinhold static bool 10960c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image) 10970c0fea5dSIngo Weinhold { 10980c0fea5dSIngo Weinhold struct Elf32_Dyn *d; 10990c0fea5dSIngo Weinhold int i; 11000c0fea5dSIngo Weinhold int sonameOffset = -1; 11010c0fea5dSIngo Weinhold 11020c0fea5dSIngo Weinhold image->symhash = 0; 11030c0fea5dSIngo Weinhold image->syms = 0; 11040c0fea5dSIngo Weinhold image->strtab = 0; 11050c0fea5dSIngo Weinhold 11060c0fea5dSIngo Weinhold d = (struct Elf32_Dyn *)image->dynamic_ptr; 11070c0fea5dSIngo Weinhold if (!d) 11080c0fea5dSIngo Weinhold return true; 11090c0fea5dSIngo Weinhold 11100c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 11110c0fea5dSIngo Weinhold switch (d[i].d_tag) { 11120c0fea5dSIngo Weinhold case DT_NEEDED: 11130c0fea5dSIngo Weinhold image->num_needed += 1; 11140c0fea5dSIngo Weinhold break; 11150c0fea5dSIngo Weinhold case DT_HASH: 11160c0fea5dSIngo Weinhold image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta); 11170c0fea5dSIngo Weinhold break; 11180c0fea5dSIngo Weinhold case DT_STRTAB: 11190c0fea5dSIngo Weinhold image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta); 11200c0fea5dSIngo Weinhold break; 11210c0fea5dSIngo Weinhold case DT_SYMTAB: 11220c0fea5dSIngo Weinhold image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta); 11230c0fea5dSIngo Weinhold break; 11240c0fea5dSIngo Weinhold case DT_REL: 11250c0fea5dSIngo Weinhold image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 11260c0fea5dSIngo Weinhold break; 11270c0fea5dSIngo Weinhold case DT_RELSZ: 11280c0fea5dSIngo Weinhold image->rel_len = d[i].d_un.d_val; 11290c0fea5dSIngo Weinhold break; 11300c0fea5dSIngo Weinhold case DT_RELA: 11310c0fea5dSIngo Weinhold image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta); 11320c0fea5dSIngo Weinhold break; 11330c0fea5dSIngo Weinhold case DT_RELASZ: 11340c0fea5dSIngo Weinhold image->rela_len = d[i].d_un.d_val; 11350c0fea5dSIngo Weinhold break; 11360c0fea5dSIngo Weinhold // TK: procedure linkage table 11370c0fea5dSIngo Weinhold case DT_JMPREL: 11380c0fea5dSIngo Weinhold image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 11390c0fea5dSIngo Weinhold break; 11400c0fea5dSIngo Weinhold case DT_PLTRELSZ: 11410c0fea5dSIngo Weinhold image->pltrel_len = d[i].d_un.d_val; 11420c0fea5dSIngo Weinhold break; 11430c0fea5dSIngo Weinhold case DT_INIT: 11440c0fea5dSIngo Weinhold image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 11450c0fea5dSIngo Weinhold break; 11460c0fea5dSIngo Weinhold case DT_FINI: 11470c0fea5dSIngo Weinhold image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 11480c0fea5dSIngo Weinhold break; 11490c0fea5dSIngo Weinhold case DT_SONAME: 11500c0fea5dSIngo Weinhold sonameOffset = d[i].d_un.d_val; 11510c0fea5dSIngo Weinhold break; 1152*003ebb0eSIngo Weinhold case DT_VERSYM: 1153*003ebb0eSIngo Weinhold image->symbol_versions = (Elf32_Versym*) 1154*003ebb0eSIngo Weinhold (d[i].d_un.d_ptr + image->regions[0].delta); 1155*003ebb0eSIngo Weinhold break; 1156*003ebb0eSIngo Weinhold case DT_VERDEF: 1157*003ebb0eSIngo Weinhold image->version_definitions = (Elf32_Verdef*) 1158*003ebb0eSIngo Weinhold (d[i].d_un.d_ptr + image->regions[0].delta); 1159*003ebb0eSIngo Weinhold break; 1160*003ebb0eSIngo Weinhold case DT_VERDEFNUM: 1161*003ebb0eSIngo Weinhold image->num_version_definitions = d[i].d_un.d_val; 1162*003ebb0eSIngo Weinhold break; 1163*003ebb0eSIngo Weinhold case DT_VERNEED: 1164*003ebb0eSIngo Weinhold image->needed_versions = (Elf32_Verneed*) 1165*003ebb0eSIngo Weinhold (d[i].d_un.d_ptr + image->regions[0].delta); 1166*003ebb0eSIngo Weinhold break; 1167*003ebb0eSIngo Weinhold case DT_VERNEEDNUM: 1168*003ebb0eSIngo Weinhold image->num_needed_versions = d[i].d_un.d_val; 1169*003ebb0eSIngo Weinhold break; 11700c0fea5dSIngo Weinhold default: 11710c0fea5dSIngo Weinhold continue; 11720c0fea5dSIngo Weinhold } 11730c0fea5dSIngo Weinhold } 11740c0fea5dSIngo Weinhold 11750c0fea5dSIngo Weinhold // lets make sure we found all the required sections 11760c0fea5dSIngo Weinhold if (!image->symhash || !image->syms || !image->strtab) 11770c0fea5dSIngo Weinhold return false; 11780c0fea5dSIngo Weinhold 11790c0fea5dSIngo Weinhold if (sonameOffset >= 0) 11800c0fea5dSIngo Weinhold strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name)); 11810c0fea5dSIngo Weinhold 11820c0fea5dSIngo Weinhold return true; 11830c0fea5dSIngo Weinhold } 11840c0fea5dSIngo Weinhold 11850c0fea5dSIngo Weinhold 118610b4b5d1SIngo Weinhold static void 118710b4b5d1SIngo Weinhold patch_defined_symbol(image_t* image, const char* name, void** symbol, 118810b4b5d1SIngo Weinhold int32* type) 118910b4b5d1SIngo Weinhold { 119010b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers; 119110b4b5d1SIngo Weinhold while (patcher != NULL && *symbol != 0) { 119210b4b5d1SIngo Weinhold image_t* inImage = image; 119310b4b5d1SIngo Weinhold patcher->patcher(patcher->cookie, NULL, image, name, &inImage, 119410b4b5d1SIngo Weinhold symbol, type); 119510b4b5d1SIngo Weinhold patcher = patcher->next; 119610b4b5d1SIngo Weinhold } 119710b4b5d1SIngo Weinhold } 119810b4b5d1SIngo Weinhold 119910b4b5d1SIngo Weinhold 120010b4b5d1SIngo Weinhold static void 120110b4b5d1SIngo Weinhold patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name, 120210b4b5d1SIngo Weinhold image_t** foundInImage, void** symbol, int32* type) 120310b4b5d1SIngo Weinhold { 120410b4b5d1SIngo Weinhold if (*foundInImage != NULL) 120510b4b5d1SIngo Weinhold patch_defined_symbol(*foundInImage, name, symbol, type); 120610b4b5d1SIngo Weinhold 120710b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers; 120810b4b5d1SIngo Weinhold while (patcher != NULL) { 120910b4b5d1SIngo Weinhold patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage, 121010b4b5d1SIngo Weinhold symbol, type); 121110b4b5d1SIngo Weinhold patcher = patcher->next; 121210b4b5d1SIngo Weinhold } 121310b4b5d1SIngo Weinhold } 121410b4b5d1SIngo Weinhold 121510b4b5d1SIngo Weinhold 121610b4b5d1SIngo Weinhold status_t 121710b4b5d1SIngo Weinhold register_defined_symbol_patcher(struct image_t* image, 121810b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 121910b4b5d1SIngo Weinhold { 122010b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher 122110b4b5d1SIngo Weinhold = new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie); 122210b4b5d1SIngo Weinhold if (patcher == NULL) 122310b4b5d1SIngo Weinhold return B_NO_MEMORY; 122410b4b5d1SIngo Weinhold 122510b4b5d1SIngo Weinhold patcher->next = image->defined_symbol_patchers; 122610b4b5d1SIngo Weinhold image->defined_symbol_patchers = patcher; 122710b4b5d1SIngo Weinhold 122810b4b5d1SIngo Weinhold return B_OK; 122910b4b5d1SIngo Weinhold } 123010b4b5d1SIngo Weinhold 123110b4b5d1SIngo Weinhold 123210b4b5d1SIngo Weinhold void 123310b4b5d1SIngo Weinhold unregister_defined_symbol_patcher(struct image_t* image, 123410b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 123510b4b5d1SIngo Weinhold { 123610b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher** patcher = &image->defined_symbol_patchers; 123710b4b5d1SIngo Weinhold while (*patcher != NULL) { 123810b4b5d1SIngo Weinhold if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) { 123910b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* toDelete = *patcher; 124010b4b5d1SIngo Weinhold *patcher = (*patcher)->next; 124110b4b5d1SIngo Weinhold delete toDelete; 124210b4b5d1SIngo Weinhold return; 124310b4b5d1SIngo Weinhold } 124410b4b5d1SIngo Weinhold patcher = &(*patcher)->next; 124510b4b5d1SIngo Weinhold } 124610b4b5d1SIngo Weinhold } 124710b4b5d1SIngo Weinhold 124810b4b5d1SIngo Weinhold 124910b4b5d1SIngo Weinhold status_t 125010b4b5d1SIngo Weinhold register_undefined_symbol_patcher(struct image_t* image, 125110b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 125210b4b5d1SIngo Weinhold { 125310b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher 125410b4b5d1SIngo Weinhold = new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie); 125510b4b5d1SIngo Weinhold if (patcher == NULL) 125610b4b5d1SIngo Weinhold return B_NO_MEMORY; 125710b4b5d1SIngo Weinhold 125810b4b5d1SIngo Weinhold patcher->next = image->undefined_symbol_patchers; 125910b4b5d1SIngo Weinhold image->undefined_symbol_patchers = patcher; 126010b4b5d1SIngo Weinhold 126110b4b5d1SIngo Weinhold return B_OK; 126210b4b5d1SIngo Weinhold } 126310b4b5d1SIngo Weinhold 126410b4b5d1SIngo Weinhold 126510b4b5d1SIngo Weinhold void 126610b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher(struct image_t* image, 126710b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 126810b4b5d1SIngo Weinhold { 126910b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher** patcher = &image->undefined_symbol_patchers; 127010b4b5d1SIngo Weinhold while (*patcher != NULL) { 127110b4b5d1SIngo Weinhold if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) { 127210b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* toDelete = *patcher; 127310b4b5d1SIngo Weinhold *patcher = (*patcher)->next; 127410b4b5d1SIngo Weinhold delete toDelete; 127510b4b5d1SIngo Weinhold return; 127610b4b5d1SIngo Weinhold } 127710b4b5d1SIngo Weinhold patcher = &(*patcher)->next; 127810b4b5d1SIngo Weinhold } 127910b4b5d1SIngo Weinhold } 128010b4b5d1SIngo Weinhold 128110b4b5d1SIngo Weinhold 128210b4b5d1SIngo Weinhold runtime_loader_add_on_export gRuntimeLoaderAddOnExport = { 128310b4b5d1SIngo Weinhold register_defined_symbol_patcher, 128410b4b5d1SIngo Weinhold unregister_defined_symbol_patcher, 128510b4b5d1SIngo Weinhold register_undefined_symbol_patcher, 128610b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher 128710b4b5d1SIngo Weinhold }; 128810b4b5d1SIngo Weinhold 128910b4b5d1SIngo Weinhold 1290*003ebb0eSIngo Weinhold static bool 1291*003ebb0eSIngo Weinhold equals_image_name(image_t* image, const char* name) 12920c0fea5dSIngo Weinhold { 1293*003ebb0eSIngo Weinhold const char* lastSlash = strrchr(name, '/'); 1294*003ebb0eSIngo Weinhold return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0; 1295*003ebb0eSIngo Weinhold } 12960c0fea5dSIngo Weinhold 12970c0fea5dSIngo Weinhold 1298*003ebb0eSIngo Weinhold static Elf32_Sym* 1299*003ebb0eSIngo Weinhold find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo) 1300*003ebb0eSIngo Weinhold { 1301dd76bc97SIngo Weinhold if (image->dynamic_ptr == 0) 13020c0fea5dSIngo Weinhold return NULL; 13030c0fea5dSIngo Weinhold 1304*003ebb0eSIngo Weinhold Elf32_Sym* versionedSymbol = NULL; 1305*003ebb0eSIngo Weinhold uint32 versionedSymbolCount = 0; 13060c0fea5dSIngo Weinhold 1307*003ebb0eSIngo Weinhold uint32 bucket = lookupInfo.hash % HASHTABSIZE(image); 1308*003ebb0eSIngo Weinhold 1309*003ebb0eSIngo Weinhold for (uint32 i = HASHBUCKETS(image)[bucket]; i != STN_UNDEF; 1310*003ebb0eSIngo Weinhold i = HASHCHAINS(image)[i]) { 13110c0fea5dSIngo Weinhold struct Elf32_Sym* symbol = &image->syms[i]; 13120c0fea5dSIngo Weinhold 13130c0fea5dSIngo Weinhold if (symbol->st_shndx != SHN_UNDEF 13140c0fea5dSIngo Weinhold && ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL) 13150c0fea5dSIngo Weinhold || (ELF32_ST_BIND(symbol->st_info) == STB_WEAK)) 1316*003ebb0eSIngo Weinhold && !strcmp(SYMNAME(image, symbol), lookupInfo.name)) { 13170c0fea5dSIngo Weinhold 1318*003ebb0eSIngo Weinhold // check if the type matches 1319*003ebb0eSIngo Weinhold uint32 type = ELF32_ST_TYPE(symbol->st_info); 1320*003ebb0eSIngo Weinhold if ((lookupInfo.type == B_SYMBOL_TYPE_TEXT && type != STT_FUNC) 1321*003ebb0eSIngo Weinhold || (lookupInfo.type == B_SYMBOL_TYPE_DATA 1322*003ebb0eSIngo Weinhold && type != STT_OBJECT)) { 1323*003ebb0eSIngo Weinhold continue; 1324*003ebb0eSIngo Weinhold } 1325*003ebb0eSIngo Weinhold 1326*003ebb0eSIngo Weinhold // check the version 1327*003ebb0eSIngo Weinhold 1328*003ebb0eSIngo Weinhold // Handle the simple cases -- the image doesn't have version 1329*003ebb0eSIngo Weinhold // information -- first. 1330*003ebb0eSIngo Weinhold if (image->symbol_versions == NULL) { 1331*003ebb0eSIngo Weinhold if (lookupInfo.version == NULL) { 1332*003ebb0eSIngo Weinhold // No specific symbol version was requested either, so the 1333*003ebb0eSIngo Weinhold // symbol is just fine. 13340c0fea5dSIngo Weinhold return symbol; 13350c0fea5dSIngo Weinhold } 1336*003ebb0eSIngo Weinhold 1337*003ebb0eSIngo Weinhold // A specific version is requested. If it's the dependency 1338*003ebb0eSIngo Weinhold // referred to by the requested version, it's apparently an 1339*003ebb0eSIngo Weinhold // older version of the dependency and we're not happy. 1340*003ebb0eSIngo Weinhold if (equals_image_name(image, lookupInfo.version->file_name)) { 1341*003ebb0eSIngo Weinhold // TODO: That should actually be kind of fatal! 1342*003ebb0eSIngo Weinhold return NULL; 13430c0fea5dSIngo Weinhold } 13440c0fea5dSIngo Weinhold 1345*003ebb0eSIngo Weinhold // This is some other image. We accept the symbol. 1346*003ebb0eSIngo Weinhold return symbol; 1347*003ebb0eSIngo Weinhold } 1348*003ebb0eSIngo Weinhold 1349*003ebb0eSIngo Weinhold // The image has version information. Let's see what we've got. 1350*003ebb0eSIngo Weinhold uint32 versionID = image->symbol_versions[i]; 1351*003ebb0eSIngo Weinhold uint32 versionIndex = VER_NDX(versionID); 1352*003ebb0eSIngo Weinhold elf_version_info& version = image->versions[versionIndex]; 1353*003ebb0eSIngo Weinhold 1354*003ebb0eSIngo Weinhold // skip local versions 1355*003ebb0eSIngo Weinhold if (versionIndex == VER_NDX_LOCAL) 1356*003ebb0eSIngo Weinhold continue; 1357*003ebb0eSIngo Weinhold 1358*003ebb0eSIngo Weinhold if (lookupInfo.version != NULL) { 1359*003ebb0eSIngo Weinhold // a specific version is requested 1360*003ebb0eSIngo Weinhold 1361*003ebb0eSIngo Weinhold // compare the versions 1362*003ebb0eSIngo Weinhold if (version.hash == lookupInfo.version->hash 1363*003ebb0eSIngo Weinhold && strcmp(version.name, lookupInfo.version->name) == 0) { 1364*003ebb0eSIngo Weinhold // versions match 1365*003ebb0eSIngo Weinhold return symbol; 1366*003ebb0eSIngo Weinhold } 1367*003ebb0eSIngo Weinhold 1368*003ebb0eSIngo Weinhold // The versions don't match. We're still fine with the 1369*003ebb0eSIngo Weinhold // base version, if it is public and we're not looking for 1370*003ebb0eSIngo Weinhold // the default version. 1371*003ebb0eSIngo Weinhold if ((versionID & VER_NDX_FLAG_HIDDEN) == 0 1372*003ebb0eSIngo Weinhold && versionIndex == VER_NDX_GLOBAL 1373*003ebb0eSIngo Weinhold && (lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) 1374*003ebb0eSIngo Weinhold == 0) { 1375*003ebb0eSIngo Weinhold // TODO: Revise the default version case! That's how 1376*003ebb0eSIngo Weinhold // FreeBSD implements it, but glibc doesn't handle it 1377*003ebb0eSIngo Weinhold // specially. 1378*003ebb0eSIngo Weinhold return symbol; 1379*003ebb0eSIngo Weinhold } 1380*003ebb0eSIngo Weinhold } else { 1381*003ebb0eSIngo Weinhold // No specific version requested, but the image has version 1382*003ebb0eSIngo Weinhold // information. This can happen in either of these cases: 1383*003ebb0eSIngo Weinhold // 1384*003ebb0eSIngo Weinhold // * The dependent object was linked against an older version 1385*003ebb0eSIngo Weinhold // of the now versioned dependency. 1386*003ebb0eSIngo Weinhold // * The symbol is looked up via find_image_symbol() or dlsym(). 1387*003ebb0eSIngo Weinhold // 1388*003ebb0eSIngo Weinhold // In the first case we return the base version of the symbol 1389*003ebb0eSIngo Weinhold // (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't 1390*003ebb0eSIngo Weinhold // exist, the unique, non-hidden versioned symbol. 1391*003ebb0eSIngo Weinhold // 1392*003ebb0eSIngo Weinhold // In the second case we want to return the public default 1393*003ebb0eSIngo Weinhold // version of the symbol. The handling is pretty similar to the 1394*003ebb0eSIngo Weinhold // first case, with the exception that we treat VER_NDX_INITIAL 1395*003ebb0eSIngo Weinhold // as regular version. 1396*003ebb0eSIngo Weinhold 1397*003ebb0eSIngo Weinhold // VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if 1398*003ebb0eSIngo Weinhold // we don't look for the default version. 1399*003ebb0eSIngo Weinhold if (versionIndex == VER_NDX_GLOBAL 1400*003ebb0eSIngo Weinhold || ((lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) == 0 1401*003ebb0eSIngo Weinhold && versionIndex == VER_NDX_INITIAL)) { 1402*003ebb0eSIngo Weinhold return symbol; 1403*003ebb0eSIngo Weinhold } 1404*003ebb0eSIngo Weinhold 1405*003ebb0eSIngo Weinhold // If not hidden, remember the version -- we'll return it, if 1406*003ebb0eSIngo Weinhold // it is the only one. 1407*003ebb0eSIngo Weinhold if ((versionID & VER_NDX_FLAG_HIDDEN) == 0) { 1408*003ebb0eSIngo Weinhold versionedSymbolCount++; 1409*003ebb0eSIngo Weinhold versionedSymbol = symbol; 1410*003ebb0eSIngo Weinhold } 1411*003ebb0eSIngo Weinhold } 1412*003ebb0eSIngo Weinhold } 1413*003ebb0eSIngo Weinhold } 1414*003ebb0eSIngo Weinhold 1415*003ebb0eSIngo Weinhold return versionedSymbolCount == 1 ? versionedSymbol : NULL; 14160c0fea5dSIngo Weinhold } 14170c0fea5dSIngo Weinhold 14180c0fea5dSIngo Weinhold 141910b4b5d1SIngo Weinhold static status_t 1420*003ebb0eSIngo Weinhold find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo, 142110b4b5d1SIngo Weinhold void **_location) 142210b4b5d1SIngo Weinhold { 142310b4b5d1SIngo Weinhold // get the symbol in the image 1424*003ebb0eSIngo Weinhold struct Elf32_Sym* symbol = find_symbol(image, lookupInfo); 142510b4b5d1SIngo Weinhold if (symbol == NULL) 142610b4b5d1SIngo Weinhold return B_ENTRY_NOT_FOUND; 142710b4b5d1SIngo Weinhold 142810b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value + image->regions[0].delta); 1429*003ebb0eSIngo Weinhold int32 symbolType = lookupInfo.type; 1430*003ebb0eSIngo Weinhold patch_defined_symbol(image, lookupInfo.name, &location, &symbolType); 143110b4b5d1SIngo Weinhold 143210b4b5d1SIngo Weinhold if (_location != NULL) 143310b4b5d1SIngo Weinhold *_location = location; 143410b4b5d1SIngo Weinhold 143510b4b5d1SIngo Weinhold return B_OK; 143610b4b5d1SIngo Weinhold } 143710b4b5d1SIngo Weinhold 143810b4b5d1SIngo Weinhold 14390c85bd05SIngo Weinhold static status_t 1440*003ebb0eSIngo Weinhold find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo, 14410c85bd05SIngo Weinhold image_t** _foundInImage, void** _location) 14420c0fea5dSIngo Weinhold { 14430c85bd05SIngo Weinhold image_t* queue[sLoadedImageCount]; 14440c85bd05SIngo Weinhold uint32 count = 0; 14450c85bd05SIngo Weinhold uint32 index = 0; 14460c85bd05SIngo Weinhold queue[count++] = image; 14470c85bd05SIngo Weinhold image->flags |= RFLAG_VISITED; 14480c85bd05SIngo Weinhold 14490c85bd05SIngo Weinhold bool found = false; 14500c85bd05SIngo Weinhold while (index < count) { 14510c85bd05SIngo Weinhold // pop next image 14520c85bd05SIngo Weinhold image = queue[index++]; 14530c85bd05SIngo Weinhold 1454*003ebb0eSIngo Weinhold if (find_symbol(image, lookupInfo, _location) == B_OK) { 14550c85bd05SIngo Weinhold found = true; 14560c85bd05SIngo Weinhold break; 14570c85bd05SIngo Weinhold } 14580c85bd05SIngo Weinhold 14590c85bd05SIngo Weinhold // push needed images 14600c85bd05SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 14610c85bd05SIngo Weinhold image_t* needed = image->needed[i]; 14620c85bd05SIngo Weinhold if ((needed->flags & RFLAG_VISITED) == 0) { 14630c85bd05SIngo Weinhold queue[count++] = needed; 14640c85bd05SIngo Weinhold needed->flags |= RFLAG_VISITED; 146546f4d849SIngo Weinhold } 146646f4d849SIngo Weinhold } 14670c0fea5dSIngo Weinhold } 14680c0fea5dSIngo Weinhold 14690c85bd05SIngo Weinhold // clear visited flags 14700c85bd05SIngo Weinhold for (uint32 i = 0; i < count; i++) 14710c85bd05SIngo Weinhold queue[i]->flags &= ~RFLAG_VISITED; 14720c85bd05SIngo Weinhold 14730c85bd05SIngo Weinhold return found ? B_OK : B_ENTRY_NOT_FOUND; 14740c0fea5dSIngo Weinhold } 14750c0fea5dSIngo Weinhold 14760c0fea5dSIngo Weinhold 147746f4d849SIngo Weinhold static struct Elf32_Sym* 1478*003ebb0eSIngo Weinhold find_undefined_symbol_beos(image_t* rootImage, image_t* image, 1479*003ebb0eSIngo Weinhold const SymbolLookupInfo& lookupInfo, image_t** foundInImage) 148046f4d849SIngo Weinhold { 148146f4d849SIngo Weinhold // BeOS style symbol resolution: It is sufficient to check the direct 148246f4d849SIngo Weinhold // dependencies. The linker would have complained, if the symbol wasn't 148346f4d849SIngo Weinhold // there. 148446f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 148546f4d849SIngo Weinhold if (image->needed[i]->dynamic_ptr) { 1486*003ebb0eSIngo Weinhold struct Elf32_Sym *symbol = find_symbol(image->needed[i], 1487*003ebb0eSIngo Weinhold lookupInfo); 148846f4d849SIngo Weinhold if (symbol) { 148946f4d849SIngo Weinhold *foundInImage = image->needed[i]; 149046f4d849SIngo Weinhold return symbol; 149146f4d849SIngo Weinhold } 149246f4d849SIngo Weinhold } 149346f4d849SIngo Weinhold } 149446f4d849SIngo Weinhold 149546f4d849SIngo Weinhold return NULL; 149646f4d849SIngo Weinhold } 149746f4d849SIngo Weinhold 149846f4d849SIngo Weinhold 14990c85bd05SIngo Weinhold static struct Elf32_Sym* 15000c85bd05SIngo Weinhold find_undefined_symbol_global(image_t* rootImage, image_t* image, 1501*003ebb0eSIngo Weinhold const SymbolLookupInfo& lookupInfo, image_t** foundInImage) 15020c85bd05SIngo Weinhold { 15030c85bd05SIngo Weinhold // Global load order symbol resolution: All loaded images are searched for 15040c85bd05SIngo Weinhold // the symbol in the order they have been loaded. We skip add-on images and 15050c85bd05SIngo Weinhold // RTLD_LOCAL images though. 15060c85bd05SIngo Weinhold image_t* otherImage = sLoadedImages.head; 15070c85bd05SIngo Weinhold while (otherImage != NULL) { 15080c85bd05SIngo Weinhold if (otherImage == rootImage 1509593ee7bbSIngo Weinhold || (otherImage->type != B_ADD_ON_IMAGE 15100c85bd05SIngo Weinhold && (otherImage->flags 1511593ee7bbSIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) { 1512*003ebb0eSIngo Weinhold struct Elf32_Sym *symbol = find_symbol(otherImage, lookupInfo); 15130c85bd05SIngo Weinhold if (symbol) { 15140c85bd05SIngo Weinhold *foundInImage = otherImage; 15150c85bd05SIngo Weinhold return symbol; 15160c85bd05SIngo Weinhold } 15170c85bd05SIngo Weinhold } 15180c85bd05SIngo Weinhold otherImage = otherImage->next; 15190c85bd05SIngo Weinhold } 15200c85bd05SIngo Weinhold 15210c85bd05SIngo Weinhold return NULL; 15220c85bd05SIngo Weinhold } 15230c85bd05SIngo Weinhold 15240c85bd05SIngo Weinhold 15250c85bd05SIngo Weinhold static struct Elf32_Sym* 15260c85bd05SIngo Weinhold find_undefined_symbol_add_on(image_t* rootImage, image_t* image, 1527*003ebb0eSIngo Weinhold const SymbolLookupInfo& lookupInfo, image_t** foundInImage) 15280c85bd05SIngo Weinhold { 15290c85bd05SIngo Weinhold // TODO: How do we want to implement this one? Using global scope resolution 15300c85bd05SIngo Weinhold // might be undesired as it is now, since libraries could refer to symbols in 15310c85bd05SIngo Weinhold // the add-on, which would result in add-on symbols implicitely becoming used 15320c85bd05SIngo Weinhold // outside of the add-on. So the options would be to use the global scope but 15330c85bd05SIngo Weinhold // skip the add-on, or to do breadth-first resolution in the add-on dependency 15340c85bd05SIngo Weinhold // scope, also skipping the add-on itself. BeOS style resolution is safe, too, 15350c85bd05SIngo Weinhold // but we miss out features like undefined symbols and preloading. 1536*003ebb0eSIngo Weinhold return find_undefined_symbol_beos(rootImage, image, lookupInfo, 1537*003ebb0eSIngo Weinhold foundInImage); 15380c85bd05SIngo Weinhold } 15390c85bd05SIngo Weinhold 15400c85bd05SIngo Weinhold 154110b4b5d1SIngo Weinhold /*! This function is called when we run BeOS images on Haiku. 15422716cfd3SAxel Dörfler It allows us to redirect functions to ensure compatibility. 15432716cfd3SAxel Dörfler */ 15442716cfd3SAxel Dörfler static const char* 15452716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName) 15462716cfd3SAxel Dörfler { 15472716cfd3SAxel Dörfler struct symbol_mapping { 15482716cfd3SAxel Dörfler const char* from; 15492716cfd3SAxel Dörfler const char* to; 15502716cfd3SAxel Dörfler }; 15512716cfd3SAxel Dörfler static const struct symbol_mapping kMappings[] = { 155210b4b5d1SIngo Weinhold // TODO: Improve this, and also use it for libnet.so compatibility! 155310b4b5d1SIngo Weinhold // Allow an image to provide a function that will be invoked for every 155410b4b5d1SIngo Weinhold // (transitively) depending image. The function can return a table to 155510b4b5d1SIngo Weinhold // remap symbols (probably better address to address). All the tables 155610b4b5d1SIngo Weinhold // for a single image would be combined into a hash table and an 155710b4b5d1SIngo Weinhold // undefined symbol patcher using this hash table would be added. 15582716cfd3SAxel Dörfler {"fstat", "__be_fstat"}, 15592716cfd3SAxel Dörfler {"lstat", "__be_lstat"}, 15602716cfd3SAxel Dörfler {"stat", "__be_stat"}, 15612716cfd3SAxel Dörfler }; 15622716cfd3SAxel Dörfler const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]); 15632716cfd3SAxel Dörfler 15642716cfd3SAxel Dörfler for (uint32 i = 0; i < kMappingCount; i++) { 15652716cfd3SAxel Dörfler if (!strcmp(symbolName, kMappings[i].from)) 15662716cfd3SAxel Dörfler return kMappings[i].to; 15672716cfd3SAxel Dörfler } 15682716cfd3SAxel Dörfler 15692716cfd3SAxel Dörfler return symbolName; 15702716cfd3SAxel Dörfler } 15712716cfd3SAxel Dörfler 15722716cfd3SAxel Dörfler 15730c0fea5dSIngo Weinhold int 157446f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym, 15752716cfd3SAxel Dörfler addr_t *symAddress) 15760c0fea5dSIngo Weinhold { 15770c0fea5dSIngo Weinhold switch (sym->st_shndx) { 15780c0fea5dSIngo Weinhold case SHN_UNDEF: 15792716cfd3SAxel Dörfler { 15802716cfd3SAxel Dörfler struct Elf32_Sym *sharedSym; 15812716cfd3SAxel Dörfler image_t *sharedImage; 1582*003ebb0eSIngo Weinhold const char *symName = SYMNAME(image, sym); 15832716cfd3SAxel Dörfler 15840c0fea5dSIngo Weinhold // patch the symbol name 1585f91194e5SIngo Weinhold if (image->abi < B_HAIKU_ABI_GCC_2_HAIKU) { 15862716cfd3SAxel Dörfler // The image has been compiled with a BeOS compiler. This means 15872716cfd3SAxel Dörfler // we'll have to redirect some functions for compatibility. 15882716cfd3SAxel Dörfler symName = beos_compatibility_map_symbol(symName); 15892716cfd3SAxel Dörfler } 15900c0fea5dSIngo Weinhold 1591*003ebb0eSIngo Weinhold // get the version info 1592*003ebb0eSIngo Weinhold const elf_version_info* versionInfo = NULL; 1593*003ebb0eSIngo Weinhold if (image->symbol_versions != NULL) { 1594*003ebb0eSIngo Weinhold uint32 index = sym - image->syms; 1595*003ebb0eSIngo Weinhold uint32 versionIndex = VER_NDX(image->symbol_versions[index]); 1596*003ebb0eSIngo Weinhold if (versionIndex >= VER_NDX_INITIAL) 1597*003ebb0eSIngo Weinhold versionInfo = image->versions + versionIndex; 1598*003ebb0eSIngo Weinhold } 1599*003ebb0eSIngo Weinhold 160010b4b5d1SIngo Weinhold int32 type = B_SYMBOL_TYPE_ANY; 160110b4b5d1SIngo Weinhold if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC) 160210b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 160310b4b5d1SIngo Weinhold else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT) 160410b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 160510b4b5d1SIngo Weinhold 160646f4d849SIngo Weinhold // it's undefined, must be outside this image, try the other images 16070c85bd05SIngo Weinhold sharedSym = rootImage->find_undefined_symbol(rootImage, image, 1608*003ebb0eSIngo Weinhold SymbolLookupInfo(symName, type, versionInfo), &sharedImage); 160910b4b5d1SIngo Weinhold void* location = NULL; 16100c0fea5dSIngo Weinhold 161110b4b5d1SIngo Weinhold enum { 161210b4b5d1SIngo Weinhold ERROR_NO_SYMBOL, 161310b4b5d1SIngo Weinhold ERROR_WRONG_TYPE, 161410b4b5d1SIngo Weinhold ERROR_NOT_EXPORTED, 161510b4b5d1SIngo Weinhold ERROR_UNPATCHED 161610b4b5d1SIngo Weinhold }; 161710b4b5d1SIngo Weinhold uint32 lookupError = ERROR_UNPATCHED; 161810b4b5d1SIngo Weinhold 161910b4b5d1SIngo Weinhold if (sharedSym == NULL) { 162010b4b5d1SIngo Weinhold // symbol not found at all 162110b4b5d1SIngo Weinhold lookupError = ERROR_NO_SYMBOL; 162210b4b5d1SIngo Weinhold sharedImage = NULL; 162310b4b5d1SIngo Weinhold } else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE 16242716cfd3SAxel Dörfler && ELF32_ST_TYPE(sym->st_info) 16252716cfd3SAxel Dörfler != ELF32_ST_TYPE(sharedSym->st_info)) { 162610b4b5d1SIngo Weinhold // symbol not of the requested type 162710b4b5d1SIngo Weinhold lookupError = ERROR_WRONG_TYPE; 162810b4b5d1SIngo Weinhold sharedImage = NULL; 162910b4b5d1SIngo Weinhold } else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL 16302716cfd3SAxel Dörfler && ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) { 163110b4b5d1SIngo Weinhold // symbol not exported 163210b4b5d1SIngo Weinhold lookupError = ERROR_NOT_EXPORTED; 163310b4b5d1SIngo Weinhold sharedImage = NULL; 163410b4b5d1SIngo Weinhold } else { 163510b4b5d1SIngo Weinhold // symbol is fine, get its location 163610b4b5d1SIngo Weinhold location = (void*)(sharedSym->st_value 163710b4b5d1SIngo Weinhold + sharedImage->regions[0].delta); 163810b4b5d1SIngo Weinhold } 163910b4b5d1SIngo Weinhold 164010b4b5d1SIngo Weinhold patch_undefined_symbol(rootImage, image, symName, &sharedImage, 164110b4b5d1SIngo Weinhold &location, &type); 164210b4b5d1SIngo Weinhold 164310b4b5d1SIngo Weinhold if (location == NULL) { 164410b4b5d1SIngo Weinhold switch (lookupError) { 164510b4b5d1SIngo Weinhold case ERROR_NO_SYMBOL: 164610b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: could not resolve symbol " 164710b4b5d1SIngo Weinhold "'%s'\n", symName); 164810b4b5d1SIngo Weinhold break; 164910b4b5d1SIngo Weinhold case ERROR_WRONG_TYPE: 165010b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s' in shared " 165110b4b5d1SIngo Weinhold "image but wrong type\n", symName); 165210b4b5d1SIngo Weinhold break; 165310b4b5d1SIngo Weinhold case ERROR_NOT_EXPORTED: 165410b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s', but not " 16552716cfd3SAxel Dörfler "exported\n", symName); 165610b4b5d1SIngo Weinhold break; 165710b4b5d1SIngo Weinhold case ERROR_UNPATCHED: 165810b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s', but was " 165910b4b5d1SIngo Weinhold "hidden by symbol patchers\n", symName); 166010b4b5d1SIngo Weinhold break; 166110b4b5d1SIngo Weinhold } 1662e94d1badSMichael Lotz 1663e94d1badSMichael Lotz if (report_errors()) 1664e94d1badSMichael Lotz sErrorMessage.AddString("missing symbol", symName); 1665e94d1badSMichael Lotz 16660c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 16670c0fea5dSIngo Weinhold } 16680c0fea5dSIngo Weinhold 166910b4b5d1SIngo Weinhold *symAddress = (addr_t)location; 167010b4b5d1SIngo Weinhold return B_OK; 16712716cfd3SAxel Dörfler } 16720c0fea5dSIngo Weinhold 16730c0fea5dSIngo Weinhold case SHN_ABS: 16742716cfd3SAxel Dörfler *symAddress = sym->st_value + image->regions[0].delta; 16750c0fea5dSIngo Weinhold return B_NO_ERROR; 16760c0fea5dSIngo Weinhold 16770c0fea5dSIngo Weinhold case SHN_COMMON: 16780c0fea5dSIngo Weinhold // ToDo: finish this 16792a33a944SIngo Weinhold FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n"); 16800c0fea5dSIngo Weinhold return B_ERROR; //ERR_NOT_IMPLEMENTED_YET; 16810c0fea5dSIngo Weinhold 16820c0fea5dSIngo Weinhold default: 16830c0fea5dSIngo Weinhold // standard symbol 16842716cfd3SAxel Dörfler *symAddress = sym->st_value + image->regions[0].delta; 16850c0fea5dSIngo Weinhold return B_NO_ERROR; 16860c0fea5dSIngo Weinhold } 16870c0fea5dSIngo Weinhold } 16880c0fea5dSIngo Weinhold 16890c0fea5dSIngo Weinhold 16900c0fea5dSIngo Weinhold static void 169110b4b5d1SIngo Weinhold image_event(image_t* image, uint32 event) 169210b4b5d1SIngo Weinhold { 169310b4b5d1SIngo Weinhold AddOnList::Iterator it = sAddOns.GetIterator(); 169410b4b5d1SIngo Weinhold while (RuntimeLoaderAddOn* addOn = it.Next()) { 169510b4b5d1SIngo Weinhold void (*function)(image_t* image) = NULL; 169610b4b5d1SIngo Weinhold 169710b4b5d1SIngo Weinhold switch (event) { 169810b4b5d1SIngo Weinhold case IMAGE_EVENT_LOADED: 169910b4b5d1SIngo Weinhold function = addOn->addOn->image_loaded; 170010b4b5d1SIngo Weinhold break; 170110b4b5d1SIngo Weinhold case IMAGE_EVENT_RELOCATED: 170210b4b5d1SIngo Weinhold function = addOn->addOn->image_relocated; 170310b4b5d1SIngo Weinhold break; 170410b4b5d1SIngo Weinhold case IMAGE_EVENT_INITIALIZED: 170510b4b5d1SIngo Weinhold function = addOn->addOn->image_initialized; 170610b4b5d1SIngo Weinhold break; 170710b4b5d1SIngo Weinhold case IMAGE_EVENT_UNINITIALIZING: 170810b4b5d1SIngo Weinhold function = addOn->addOn->image_uninitializing; 170910b4b5d1SIngo Weinhold break; 171010b4b5d1SIngo Weinhold case IMAGE_EVENT_UNLOADING: 171110b4b5d1SIngo Weinhold function = addOn->addOn->image_unloading; 171210b4b5d1SIngo Weinhold break; 171310b4b5d1SIngo Weinhold } 171410b4b5d1SIngo Weinhold 171510b4b5d1SIngo Weinhold if (function != NULL) 171610b4b5d1SIngo Weinhold function(image); 171710b4b5d1SIngo Weinhold } 171810b4b5d1SIngo Weinhold } 171910b4b5d1SIngo Weinhold 172010b4b5d1SIngo Weinhold 1721*003ebb0eSIngo Weinhold static status_t 1722*003ebb0eSIngo Weinhold init_image_version_infos(image_t* image) 1723*003ebb0eSIngo Weinhold { 1724*003ebb0eSIngo Weinhold // First find out how many version infos we need -- i.e. get the greatest 1725*003ebb0eSIngo Weinhold // version index from the defined and needed versions (they use the same 1726*003ebb0eSIngo Weinhold // index namespace). 1727*003ebb0eSIngo Weinhold uint32 maxIndex = 0; 1728*003ebb0eSIngo Weinhold 1729*003ebb0eSIngo Weinhold if (image->version_definitions != NULL) { 1730*003ebb0eSIngo Weinhold Elf32_Verdef* definition = image->version_definitions; 1731*003ebb0eSIngo Weinhold for (uint32 i = 0; i < image->num_version_definitions; i++) { 1732*003ebb0eSIngo Weinhold if (definition->vd_version != 1) { 1733*003ebb0eSIngo Weinhold FATAL("Unsupported version definition revision: %u\n", 1734*003ebb0eSIngo Weinhold definition->vd_version); 1735*003ebb0eSIngo Weinhold return B_BAD_VALUE; 1736*003ebb0eSIngo Weinhold } 1737*003ebb0eSIngo Weinhold 1738*003ebb0eSIngo Weinhold uint32 versionIndex = VER_NDX(definition->vd_ndx); 1739*003ebb0eSIngo Weinhold if (versionIndex > maxIndex) 1740*003ebb0eSIngo Weinhold maxIndex = versionIndex; 1741*003ebb0eSIngo Weinhold 1742*003ebb0eSIngo Weinhold definition = (Elf32_Verdef*) 1743*003ebb0eSIngo Weinhold ((uint8*)definition + definition->vd_next); 1744*003ebb0eSIngo Weinhold } 1745*003ebb0eSIngo Weinhold } 1746*003ebb0eSIngo Weinhold 1747*003ebb0eSIngo Weinhold if (image->needed_versions != NULL) { 1748*003ebb0eSIngo Weinhold Elf32_Verneed* needed = image->needed_versions; 1749*003ebb0eSIngo Weinhold for (uint32 i = 0; i < image->num_needed_versions; i++) { 1750*003ebb0eSIngo Weinhold if (needed->vn_version != 1) { 1751*003ebb0eSIngo Weinhold FATAL("Unsupported version needed revision: %u\n", 1752*003ebb0eSIngo Weinhold needed->vn_version); 1753*003ebb0eSIngo Weinhold return B_BAD_VALUE; 1754*003ebb0eSIngo Weinhold } 1755*003ebb0eSIngo Weinhold 1756*003ebb0eSIngo Weinhold Elf32_Vernaux* vernaux 1757*003ebb0eSIngo Weinhold = (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux); 1758*003ebb0eSIngo Weinhold for (uint32 k = 0; k < needed->vn_cnt; k++) { 1759*003ebb0eSIngo Weinhold uint32 versionIndex = VER_NDX(vernaux->vna_other); 1760*003ebb0eSIngo Weinhold if (versionIndex > maxIndex) 1761*003ebb0eSIngo Weinhold maxIndex = versionIndex; 1762*003ebb0eSIngo Weinhold 1763*003ebb0eSIngo Weinhold vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next); 1764*003ebb0eSIngo Weinhold } 1765*003ebb0eSIngo Weinhold 1766*003ebb0eSIngo Weinhold needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next); 1767*003ebb0eSIngo Weinhold } 1768*003ebb0eSIngo Weinhold } 1769*003ebb0eSIngo Weinhold 1770*003ebb0eSIngo Weinhold if (maxIndex == 0) 1771*003ebb0eSIngo Weinhold return B_OK; 1772*003ebb0eSIngo Weinhold 1773*003ebb0eSIngo Weinhold // allocate the version infos 1774*003ebb0eSIngo Weinhold image->versions 1775*003ebb0eSIngo Weinhold = (elf_version_info*)malloc(sizeof(elf_version_info) * (maxIndex + 1)); 1776*003ebb0eSIngo Weinhold if (image->versions == NULL) { 1777*003ebb0eSIngo Weinhold FATAL("Memory shortage in init_image_version_infos()"); 1778*003ebb0eSIngo Weinhold return B_NO_MEMORY; 1779*003ebb0eSIngo Weinhold } 1780*003ebb0eSIngo Weinhold image->num_versions = maxIndex + 1; 1781*003ebb0eSIngo Weinhold 1782*003ebb0eSIngo Weinhold // init the version infos 1783*003ebb0eSIngo Weinhold 1784*003ebb0eSIngo Weinhold // version definitions 1785*003ebb0eSIngo Weinhold if (image->version_definitions != NULL) { 1786*003ebb0eSIngo Weinhold Elf32_Verdef* definition = image->version_definitions; 1787*003ebb0eSIngo Weinhold for (uint32 i = 0; i < image->num_version_definitions; i++) { 1788*003ebb0eSIngo Weinhold if (definition->vd_cnt > 0 1789*003ebb0eSIngo Weinhold && (definition->vd_flags & VER_FLG_BASE) == 0) { 1790*003ebb0eSIngo Weinhold Elf32_Verdaux* verdaux 1791*003ebb0eSIngo Weinhold = (Elf32_Verdaux*)((uint8*)definition + definition->vd_aux); 1792*003ebb0eSIngo Weinhold 1793*003ebb0eSIngo Weinhold uint32 versionIndex = VER_NDX(definition->vd_ndx); 1794*003ebb0eSIngo Weinhold elf_version_info& info = image->versions[versionIndex]; 1795*003ebb0eSIngo Weinhold info.hash = definition->vd_hash; 1796*003ebb0eSIngo Weinhold info.name = STRING(image, verdaux->vda_name); 1797*003ebb0eSIngo Weinhold } 1798*003ebb0eSIngo Weinhold 1799*003ebb0eSIngo Weinhold definition = (Elf32_Verdef*) 1800*003ebb0eSIngo Weinhold ((uint8*)definition + definition->vd_next); 1801*003ebb0eSIngo Weinhold } 1802*003ebb0eSIngo Weinhold } 1803*003ebb0eSIngo Weinhold 1804*003ebb0eSIngo Weinhold // needed versions 1805*003ebb0eSIngo Weinhold if (image->needed_versions != NULL) { 1806*003ebb0eSIngo Weinhold Elf32_Verneed* needed = image->needed_versions; 1807*003ebb0eSIngo Weinhold for (uint32 i = 0; i < image->num_needed_versions; i++) { 1808*003ebb0eSIngo Weinhold const char* fileName = STRING(image, needed->vn_file); 1809*003ebb0eSIngo Weinhold 1810*003ebb0eSIngo Weinhold Elf32_Vernaux* vernaux 1811*003ebb0eSIngo Weinhold = (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux); 1812*003ebb0eSIngo Weinhold for (uint32 k = 0; k < needed->vn_cnt; k++) { 1813*003ebb0eSIngo Weinhold uint32 versionIndex = VER_NDX(vernaux->vna_other); 1814*003ebb0eSIngo Weinhold elf_version_info& info = image->versions[versionIndex]; 1815*003ebb0eSIngo Weinhold info.hash = vernaux->vna_hash; 1816*003ebb0eSIngo Weinhold info.name = STRING(image, vernaux->vna_name); 1817*003ebb0eSIngo Weinhold info.file_name = fileName; 1818*003ebb0eSIngo Weinhold info.hidden = (vernaux->vna_other & VER_NDX_FLAG_HIDDEN) != 0; 1819*003ebb0eSIngo Weinhold 1820*003ebb0eSIngo Weinhold vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next); 1821*003ebb0eSIngo Weinhold } 1822*003ebb0eSIngo Weinhold 1823*003ebb0eSIngo Weinhold needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next); 1824*003ebb0eSIngo Weinhold } 1825*003ebb0eSIngo Weinhold } 1826*003ebb0eSIngo Weinhold 1827*003ebb0eSIngo Weinhold return B_OK; 1828*003ebb0eSIngo Weinhold } 1829*003ebb0eSIngo Weinhold 1830*003ebb0eSIngo Weinhold 1831*003ebb0eSIngo Weinhold static status_t 1832*003ebb0eSIngo Weinhold assert_defined_image_version(image_t* dependentImage, image_t* image, 1833*003ebb0eSIngo Weinhold const elf_version_info& neededVersion, bool weak) 1834*003ebb0eSIngo Weinhold { 1835*003ebb0eSIngo Weinhold // If the image doesn't have version definitions, we print a warning and 1836*003ebb0eSIngo Weinhold // succeed. Weird, but that's how glibc does it. Not unlikely we'll fail 1837*003ebb0eSIngo Weinhold // later when resolving versioned symbols. 1838*003ebb0eSIngo Weinhold if (image->version_definitions == NULL) { 1839*003ebb0eSIngo Weinhold FATAL("%s: No version information available (required by %s)\n", 1840*003ebb0eSIngo Weinhold image->name, dependentImage->name); 1841*003ebb0eSIngo Weinhold return B_OK; 1842*003ebb0eSIngo Weinhold } 1843*003ebb0eSIngo Weinhold 1844*003ebb0eSIngo Weinhold // iterate through the defined versions to find the given one 1845*003ebb0eSIngo Weinhold Elf32_Verdef* definition = image->version_definitions; 1846*003ebb0eSIngo Weinhold for (uint32 i = 0; i < image->num_version_definitions; i++) { 1847*003ebb0eSIngo Weinhold uint32 versionIndex = VER_NDX(definition->vd_ndx); 1848*003ebb0eSIngo Weinhold elf_version_info& info = image->versions[versionIndex]; 1849*003ebb0eSIngo Weinhold 1850*003ebb0eSIngo Weinhold if (neededVersion.hash == info.hash 1851*003ebb0eSIngo Weinhold && strcmp(neededVersion.name, info.name) == 0) { 1852*003ebb0eSIngo Weinhold return B_OK; 1853*003ebb0eSIngo Weinhold } 1854*003ebb0eSIngo Weinhold 1855*003ebb0eSIngo Weinhold definition = (Elf32_Verdef*) 1856*003ebb0eSIngo Weinhold ((uint8*)definition + definition->vd_next); 1857*003ebb0eSIngo Weinhold } 1858*003ebb0eSIngo Weinhold 1859*003ebb0eSIngo Weinhold // version not found -- fail, if not weak 1860*003ebb0eSIngo Weinhold if (!weak) { 1861*003ebb0eSIngo Weinhold FATAL("%s: version \"%s\" not found (required by %s)\n", image->name, 1862*003ebb0eSIngo Weinhold neededVersion.name, dependentImage->name); 1863*003ebb0eSIngo Weinhold return B_MISSING_SYMBOL; 1864*003ebb0eSIngo Weinhold } 1865*003ebb0eSIngo Weinhold 1866*003ebb0eSIngo Weinhold return B_OK; 1867*003ebb0eSIngo Weinhold } 1868*003ebb0eSIngo Weinhold 1869*003ebb0eSIngo Weinhold 1870*003ebb0eSIngo Weinhold static status_t 1871*003ebb0eSIngo Weinhold check_needed_image_versions(image_t* image) 1872*003ebb0eSIngo Weinhold { 1873*003ebb0eSIngo Weinhold if (image->needed_versions == NULL) 1874*003ebb0eSIngo Weinhold return B_OK; 1875*003ebb0eSIngo Weinhold 1876*003ebb0eSIngo Weinhold Elf32_Verneed* needed = image->needed_versions; 1877*003ebb0eSIngo Weinhold for (uint32 i = 0; i < image->num_needed_versions; i++) { 1878*003ebb0eSIngo Weinhold const char* fileName = STRING(image, needed->vn_file); 1879*003ebb0eSIngo Weinhold image_t* dependency = find_image(fileName, ALL_IMAGE_TYPES); 1880*003ebb0eSIngo Weinhold if (dependency == NULL) { 1881*003ebb0eSIngo Weinhold // This can't really happen, unless the object file is broken, since 1882*003ebb0eSIngo Weinhold // the file should also appear in DT_NEEDED. 1883*003ebb0eSIngo Weinhold FATAL("Version dependency \"%s\" not found", fileName); 1884*003ebb0eSIngo Weinhold return B_FILE_NOT_FOUND; 1885*003ebb0eSIngo Weinhold } 1886*003ebb0eSIngo Weinhold 1887*003ebb0eSIngo Weinhold Elf32_Vernaux* vernaux 1888*003ebb0eSIngo Weinhold = (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux); 1889*003ebb0eSIngo Weinhold for (uint32 k = 0; k < needed->vn_cnt; k++) { 1890*003ebb0eSIngo Weinhold uint32 versionIndex = VER_NDX(vernaux->vna_other); 1891*003ebb0eSIngo Weinhold elf_version_info& info = image->versions[versionIndex]; 1892*003ebb0eSIngo Weinhold 1893*003ebb0eSIngo Weinhold status_t error = assert_defined_image_version(image, dependency, 1894*003ebb0eSIngo Weinhold info, (vernaux->vna_flags & VER_FLG_WEAK) != 0); 1895*003ebb0eSIngo Weinhold if (error != B_OK) 1896*003ebb0eSIngo Weinhold return error; 1897*003ebb0eSIngo Weinhold 1898*003ebb0eSIngo Weinhold vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next); 1899*003ebb0eSIngo Weinhold } 1900*003ebb0eSIngo Weinhold 1901*003ebb0eSIngo Weinhold needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next); 1902*003ebb0eSIngo Weinhold } 1903*003ebb0eSIngo Weinhold 1904*003ebb0eSIngo Weinhold return B_OK; 1905*003ebb0eSIngo Weinhold } 1906*003ebb0eSIngo Weinhold 1907*003ebb0eSIngo Weinhold 190810b4b5d1SIngo Weinhold static void 19090c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path) 19100c0fea5dSIngo Weinhold { 19110c0fea5dSIngo Weinhold struct stat stat; 19120c0fea5dSIngo Weinhold image_info info; 19130c0fea5dSIngo Weinhold 19140c0fea5dSIngo Weinhold // ToDo: set these correctly 19150c0fea5dSIngo Weinhold info.id = 0; 19160c0fea5dSIngo Weinhold info.type = image->type; 19170c0fea5dSIngo Weinhold info.sequence = 0; 19180c0fea5dSIngo Weinhold info.init_order = 0; 19190c0fea5dSIngo Weinhold info.init_routine = (void (*)())image->init_routine; 19200c0fea5dSIngo Weinhold info.term_routine = (void (*)())image->term_routine; 19210c0fea5dSIngo Weinhold 19220c0fea5dSIngo Weinhold if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) { 19230c0fea5dSIngo Weinhold info.device = stat.st_dev; 19240c0fea5dSIngo Weinhold info.node = stat.st_ino; 19250c0fea5dSIngo Weinhold } else { 19260c0fea5dSIngo Weinhold info.device = -1; 19270c0fea5dSIngo Weinhold info.node = -1; 19280c0fea5dSIngo Weinhold } 19290c0fea5dSIngo Weinhold 19300c0fea5dSIngo Weinhold strlcpy(info.name, path, sizeof(info.name)); 19310c0fea5dSIngo Weinhold info.text = (void *)image->regions[0].vmstart; 19320c0fea5dSIngo Weinhold info.text_size = image->regions[0].vmsize; 19330c0fea5dSIngo Weinhold info.data = (void *)image->regions[1].vmstart; 19340c0fea5dSIngo Weinhold info.data_size = image->regions[1].vmsize; 1935593ee7bbSIngo Weinhold info.api_version = image->api_version; 1936593ee7bbSIngo Weinhold info.abi = image->abi; 19370c0fea5dSIngo Weinhold image->id = _kern_register_image(&info, sizeof(image_info)); 19380c0fea5dSIngo Weinhold } 19390c0fea5dSIngo Weinhold 19400c0fea5dSIngo Weinhold 19410c0fea5dSIngo Weinhold static status_t 194246f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 19430c0fea5dSIngo Weinhold { 194446f4d849SIngo Weinhold status_t status = arch_relocate_image(rootImage, image); 19450c0fea5dSIngo Weinhold if (status < B_OK) { 1946320bd2bdSAxel Dörfler FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status, 1947320bd2bdSAxel Dörfler image->path, image->name); 19480c0fea5dSIngo Weinhold return status; 19490c0fea5dSIngo Weinhold } 19500c0fea5dSIngo Weinhold 19510c0fea5dSIngo Weinhold _kern_image_relocated(image->id); 195210b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_RELOCATED); 19530c0fea5dSIngo Weinhold return B_OK; 19540c0fea5dSIngo Weinhold } 19550c0fea5dSIngo Weinhold 19560c0fea5dSIngo Weinhold 19570c0fea5dSIngo Weinhold static status_t 19580c85bd05SIngo Weinhold load_container(char const *name, image_type type, const char *rpath, 19590c85bd05SIngo Weinhold image_t **_image) 19600c0fea5dSIngo Weinhold { 19610c0fea5dSIngo Weinhold int32 pheaderSize, sheaderSize; 19620c0fea5dSIngo Weinhold char path[PATH_MAX]; 19630c0fea5dSIngo Weinhold ssize_t length; 19640c0fea5dSIngo Weinhold char ph_buff[4096]; 19650c0fea5dSIngo Weinhold int32 numRegions; 19660c0fea5dSIngo Weinhold image_t *found; 19670c0fea5dSIngo Weinhold image_t *image; 19680c0fea5dSIngo Weinhold status_t status; 19690c0fea5dSIngo Weinhold int fd; 19700c0fea5dSIngo Weinhold 19710c0fea5dSIngo Weinhold struct Elf32_Ehdr eheader; 19720c0fea5dSIngo Weinhold 19730c0fea5dSIngo Weinhold // Have we already loaded that image? Don't check for add-ons -- we always 19740c0fea5dSIngo Weinhold // reload them. 19750c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 19760c0fea5dSIngo Weinhold found = find_image(name, APP_OR_LIBRARY_TYPE); 197702e577f9SIngo Weinhold 197802e577f9SIngo Weinhold if (found == NULL && type != B_APP_IMAGE) { 197902e577f9SIngo Weinhold // Special case for add-ons that link against the application 198002e577f9SIngo Weinhold // executable, with the executable not having a soname set. 198102e577f9SIngo Weinhold if (const char* lastSlash = strrchr(name, '/')) { 198202e577f9SIngo Weinhold image_t* programImage = get_program_image(); 198302e577f9SIngo Weinhold if (strcmp(programImage->name, lastSlash + 1) == 0) 198402e577f9SIngo Weinhold found = programImage; 198502e577f9SIngo Weinhold } 198602e577f9SIngo Weinhold } 198702e577f9SIngo Weinhold 19880c0fea5dSIngo Weinhold if (found) { 19890c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 19900c0fea5dSIngo Weinhold *_image = found; 19917486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") " 19927486b72dSIngo Weinhold "already loaded", name, type, rpath); 19930c0fea5dSIngo Weinhold return B_OK; 19940c0fea5dSIngo Weinhold } 19950c0fea5dSIngo Weinhold } 19960c0fea5dSIngo Weinhold 19977486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type, 19987486b72dSIngo Weinhold rpath); 19997486b72dSIngo Weinhold 20000c0fea5dSIngo Weinhold strlcpy(path, name, sizeof(path)); 20010c0fea5dSIngo Weinhold 200261b37794SIngo Weinhold // find and open the file 200361b37794SIngo Weinhold fd = open_executable(path, type, rpath, get_program_path(), 200461b37794SIngo Weinhold sSearchPathSubDir); 20050c0fea5dSIngo Weinhold if (fd < 0) { 200602e577f9SIngo Weinhold FATAL("cannot open file %s\n", name); 20077486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): failed to open file", name); 20080c0fea5dSIngo Weinhold return fd; 20090c0fea5dSIngo Weinhold } 20100c0fea5dSIngo Weinhold 20116918dbf4SIngo Weinhold // normalize the image path 20126918dbf4SIngo Weinhold status = _kern_normalize_path(path, true, path); 20136918dbf4SIngo Weinhold if (status != B_OK) 20140c0fea5dSIngo Weinhold goto err1; 20150c0fea5dSIngo Weinhold 20160c0fea5dSIngo Weinhold // Test again if this image has been registered already - this time, 20170c0fea5dSIngo Weinhold // we can check the full path, not just its name as noted. 20180c0fea5dSIngo Weinhold // You could end up loading an image twice with symbolic links, else. 20190c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 20200c0fea5dSIngo Weinhold found = find_image(path, APP_OR_LIBRARY_TYPE); 20210c0fea5dSIngo Weinhold if (found) { 20220c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 20230c0fea5dSIngo Weinhold *_image = found; 2024b2568a30SIngo Weinhold _kern_close(fd); 20257486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): already loaded after all", 20267486b72dSIngo Weinhold name); 20270c0fea5dSIngo Weinhold return B_OK; 20280c0fea5dSIngo Weinhold } 20290c0fea5dSIngo Weinhold } 20300c0fea5dSIngo Weinhold 20310c0fea5dSIngo Weinhold length = _kern_read(fd, 0, &eheader, sizeof(eheader)); 20320c0fea5dSIngo Weinhold if (length != sizeof(eheader)) { 20330c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 20340c0fea5dSIngo Weinhold FATAL("troubles reading ELF header\n"); 20350c0fea5dSIngo Weinhold goto err1; 20360c0fea5dSIngo Weinhold } 20370c0fea5dSIngo Weinhold 20380c0fea5dSIngo Weinhold status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize); 20390c0fea5dSIngo Weinhold if (status < B_OK) { 20400c0fea5dSIngo Weinhold FATAL("incorrect ELF header\n"); 20410c0fea5dSIngo Weinhold goto err1; 20420c0fea5dSIngo Weinhold } 20430c0fea5dSIngo Weinhold 20440c0fea5dSIngo Weinhold // ToDo: what to do about this restriction?? 20450c0fea5dSIngo Weinhold if (pheaderSize > (int)sizeof(ph_buff)) { 20460c0fea5dSIngo Weinhold FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff)); 20470c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 20480c0fea5dSIngo Weinhold goto err1; 20490c0fea5dSIngo Weinhold } 20500c0fea5dSIngo Weinhold 20510c0fea5dSIngo Weinhold length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize); 20520c0fea5dSIngo Weinhold if (length != pheaderSize) { 20530c0fea5dSIngo Weinhold FATAL("Could not read program headers: %s\n", strerror(length)); 20540c0fea5dSIngo Weinhold status = B_BAD_DATA; 20550c0fea5dSIngo Weinhold goto err1; 20560c0fea5dSIngo Weinhold } 20570c0fea5dSIngo Weinhold 20580c0fea5dSIngo Weinhold numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize); 20590c0fea5dSIngo Weinhold if (numRegions <= 0) { 20600c0fea5dSIngo Weinhold FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions); 20610c0fea5dSIngo Weinhold status = B_BAD_DATA; 20620c0fea5dSIngo Weinhold goto err1; 20630c0fea5dSIngo Weinhold } 20640c0fea5dSIngo Weinhold 20650c0fea5dSIngo Weinhold image = create_image(name, path, numRegions); 20660c0fea5dSIngo Weinhold if (image == NULL) { 20670c0fea5dSIngo Weinhold FATAL("Failed to allocate image_t object\n"); 20680c0fea5dSIngo Weinhold status = B_NO_MEMORY; 20690c0fea5dSIngo Weinhold goto err1; 20700c0fea5dSIngo Weinhold } 20710c0fea5dSIngo Weinhold 20720c0fea5dSIngo Weinhold status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize); 20730c0fea5dSIngo Weinhold if (status < B_OK) 20740c0fea5dSIngo Weinhold goto err2; 20750c0fea5dSIngo Weinhold 20760c0fea5dSIngo Weinhold if (!assert_dynamic_loadable(image)) { 20770c0fea5dSIngo Weinhold FATAL("Dynamic segment must be loadable (implementation restriction)\n"); 20780c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 20790c0fea5dSIngo Weinhold goto err2; 20800c0fea5dSIngo Weinhold } 20810c0fea5dSIngo Weinhold 2082593ee7bbSIngo Weinhold status = map_image(fd, path, image, type == B_APP_IMAGE); 2083593ee7bbSIngo Weinhold if (status < B_OK) { 2084593ee7bbSIngo Weinhold FATAL("Could not map image: %s\n", strerror(status)); 2085593ee7bbSIngo Weinhold status = B_ERROR; 2086593ee7bbSIngo Weinhold goto err2; 2087593ee7bbSIngo Weinhold } 2088593ee7bbSIngo Weinhold 2089593ee7bbSIngo Weinhold if (!parse_dynamic_segment(image)) { 2090593ee7bbSIngo Weinhold FATAL("Troubles handling dynamic section\n"); 2091593ee7bbSIngo Weinhold status = B_BAD_DATA; 2092593ee7bbSIngo Weinhold goto err3; 2093593ee7bbSIngo Weinhold } 2094593ee7bbSIngo Weinhold 2095593ee7bbSIngo Weinhold if (eheader.e_entry != 0) 2096593ee7bbSIngo Weinhold image->entry_point = eheader.e_entry + image->regions[0].delta; 2097593ee7bbSIngo Weinhold 2098593ee7bbSIngo Weinhold analyze_image_haiku_version_and_abi(image); 2099593ee7bbSIngo Weinhold 2100f91194e5SIngo Weinhold if (image->abi == 0) { 2101f91194e5SIngo Weinhold // No ABI version in the shared object, i.e. it has been built before 2102f91194e5SIngo Weinhold // that was introduced in Haiku. We have to try and analyze the gcc 2103f91194e5SIngo Weinhold // version. 2104f91194e5SIngo Weinhold if (!analyze_object_gcc_version(fd, image, eheader, sheaderSize, 2105f91194e5SIngo Weinhold ph_buff, sizeof(ph_buff))) { 2106f91194e5SIngo Weinhold FATAL("Failed to get gcc version for %s\n", path); 2107f91194e5SIngo Weinhold // not really fatal, actually 2108f91194e5SIngo Weinhold 2109f91194e5SIngo Weinhold // assume ancient BeOS 2110f91194e5SIngo Weinhold image->abi = B_HAIKU_ABI_GCC_2_ANCIENT; 2111f91194e5SIngo Weinhold } 2112f91194e5SIngo Weinhold } 2113f91194e5SIngo Weinhold 2114f91194e5SIngo Weinhold // guess the API version, if we couldn't figure it out yet 2115f91194e5SIngo Weinhold if (image->api_version == 0) { 2116f91194e5SIngo Weinhold image->api_version = image->abi > B_HAIKU_ABI_GCC_2_BEOS 2117f91194e5SIngo Weinhold ? HAIKU_VERSION_PRE_GLUE_CODE : B_HAIKU_VERSION_BEOS; 2118f91194e5SIngo Weinhold } 2119f91194e5SIngo Weinhold 212061b37794SIngo Weinhold // If this is the executable image, we init the search path 212161b37794SIngo Weinhold // subdir, if the compiler version doesn't match ours. 212261b37794SIngo Weinhold if (type == B_APP_IMAGE) { 212361b37794SIngo Weinhold #if __GNUC__ == 2 2124f91194e5SIngo Weinhold if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_4) 212561b37794SIngo Weinhold sSearchPathSubDir = "gcc4"; 212661b37794SIngo Weinhold #elif __GNUC__ == 4 2127f91194e5SIngo Weinhold if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2) 212861b37794SIngo Weinhold sSearchPathSubDir = "gcc2"; 212961b37794SIngo Weinhold #endif 213061b37794SIngo Weinhold } 213134982809SIngo Weinhold 21325fd6637bSIngo Weinhold // init gcc version dependent image flags 2133f91194e5SIngo Weinhold // symbol resolution strategy 2134f91194e5SIngo Weinhold if (image->abi == B_HAIKU_ABI_GCC_2_ANCIENT) 21350c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_beos; 21365fd6637bSIngo Weinhold 2137*003ebb0eSIngo Weinhold // init version infos 2138*003ebb0eSIngo Weinhold status = init_image_version_infos(image); 2139*003ebb0eSIngo Weinhold 21400c0fea5dSIngo Weinhold image->type = type; 21410c0fea5dSIngo Weinhold register_image(image, fd, path); 214210b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_LOADED); 21430c0fea5dSIngo Weinhold 21440c0fea5dSIngo Weinhold _kern_close(fd); 21450c0fea5dSIngo Weinhold 21460c0fea5dSIngo Weinhold enqueue_image(&sLoadedImages, image); 21470c0fea5dSIngo Weinhold sLoadedImageCount++; 21480c0fea5dSIngo Weinhold 21490c0fea5dSIngo Weinhold *_image = image; 21507486b72dSIngo Weinhold 2151f91194e5SIngo Weinhold KTRACE("rld: load_container(\"%s\"): done: id: %ld (ABI: %#lx)", name, 2152f91194e5SIngo Weinhold image->id, image->abi); 21537486b72dSIngo Weinhold 21540c0fea5dSIngo Weinhold return B_OK; 21550c0fea5dSIngo Weinhold 21560c0fea5dSIngo Weinhold err3: 21570c0fea5dSIngo Weinhold unmap_image(image); 21580c0fea5dSIngo Weinhold err2: 21590c0fea5dSIngo Weinhold delete_image_struct(image); 21600c0fea5dSIngo Weinhold err1: 21610c0fea5dSIngo Weinhold _kern_close(fd); 21627486b72dSIngo Weinhold 21637486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): failed: %s", name, 21647486b72dSIngo Weinhold strerror(status)); 21657486b72dSIngo Weinhold 21660c0fea5dSIngo Weinhold return status; 21670c0fea5dSIngo Weinhold } 21680c0fea5dSIngo Weinhold 21690c0fea5dSIngo Weinhold 21700c0fea5dSIngo Weinhold static const char * 21710c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 21720c0fea5dSIngo Weinhold { 21730c0fea5dSIngo Weinhold int i; 21740c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 21750c0fea5dSIngo Weinhold 21760c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 21770c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 21780c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 21790c0fea5dSIngo Weinhold } 21800c0fea5dSIngo Weinhold 21810c0fea5dSIngo Weinhold return NULL; 21820c0fea5dSIngo Weinhold } 21830c0fea5dSIngo Weinhold 21840c0fea5dSIngo Weinhold 21850c0fea5dSIngo Weinhold static status_t 21860c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image) 21870c0fea5dSIngo Weinhold { 21880c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 21894bef3723SAxel Dörfler bool reportErrors = report_errors(); 219074c0424aSAxel Dörfler status_t status = B_OK; 21910c0fea5dSIngo Weinhold uint32 i, j; 21920c0fea5dSIngo Weinhold const char *rpath; 21930c0fea5dSIngo Weinhold 21940c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 21950c0fea5dSIngo Weinhold return B_OK; 21960c0fea5dSIngo Weinhold 21970c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 21980c0fea5dSIngo Weinhold 21990c0fea5dSIngo Weinhold if (image->num_needed == 0) 22000c0fea5dSIngo Weinhold return B_OK; 22010c0fea5dSIngo Weinhold 22027486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name, 22037486b72dSIngo Weinhold image->id); 22047486b72dSIngo Weinhold 22050c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 22060c0fea5dSIngo Weinhold if (image->needed == NULL) { 22070c0fea5dSIngo Weinhold FATAL("failed to allocate needed struct\n"); 22087486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory", 22097486b72dSIngo Weinhold image->name, image->id); 22100c0fea5dSIngo Weinhold return B_NO_MEMORY; 22110c0fea5dSIngo Weinhold } 22120c0fea5dSIngo Weinhold 22130c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 22140c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 22150c0fea5dSIngo Weinhold 22160c0fea5dSIngo Weinhold for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { 22170c0fea5dSIngo Weinhold switch (d[i].d_tag) { 22180c0fea5dSIngo Weinhold case DT_NEEDED: 221974c0424aSAxel Dörfler { 222074c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 222174c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 22220c0fea5dSIngo Weinhold 222374c0424aSAxel Dörfler status_t loadStatus = load_container(name, B_LIBRARY_IMAGE, 222474c0424aSAxel Dörfler rpath, &image->needed[j]); 222574c0424aSAxel Dörfler if (loadStatus < B_OK) { 222674c0424aSAxel Dörfler status = loadStatus; 222774c0424aSAxel Dörfler // correct error code in case the file could not been found 222874c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 222974c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 223074c0424aSAxel Dörfler 223174c0424aSAxel Dörfler if (reportErrors) 223274c0424aSAxel Dörfler sErrorMessage.AddString("missing library", name); 223374c0424aSAxel Dörfler } 223474c0424aSAxel Dörfler 223574c0424aSAxel Dörfler // Collect all missing libraries in case we report back 22367486b72dSIngo Weinhold if (!reportErrors) { 22377486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 22387486b72dSIngo Weinhold "failed: %s", image->name, image->id, 22397486b72dSIngo Weinhold strerror(status)); 22400c0fea5dSIngo Weinhold return status; 224174c0424aSAxel Dörfler } 22427486b72dSIngo Weinhold } 22430c0fea5dSIngo Weinhold 22440c0fea5dSIngo Weinhold j += 1; 22450c0fea5dSIngo Weinhold break; 224674c0424aSAxel Dörfler } 22470c0fea5dSIngo Weinhold 22480c0fea5dSIngo Weinhold default: 22490c0fea5dSIngo Weinhold // ignore any other tag 22500c0fea5dSIngo Weinhold continue; 22510c0fea5dSIngo Weinhold } 22520c0fea5dSIngo Weinhold } 22530c0fea5dSIngo Weinhold 22547486b72dSIngo Weinhold if (status < B_OK) { 22557486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 22567486b72dSIngo Weinhold "failed: %s", image->name, image->id, 22577486b72dSIngo Weinhold strerror(status)); 225874c0424aSAxel Dörfler return status; 22597486b72dSIngo Weinhold } 226074c0424aSAxel Dörfler 22610c0fea5dSIngo Weinhold if (j != image->num_needed) { 22620c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 22637486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 22647486b72dSIngo Weinhold "failed: internal error", image->name, image->id); 22650c0fea5dSIngo Weinhold return B_ERROR; 22660c0fea5dSIngo Weinhold } 22670c0fea5dSIngo Weinhold 22687486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name, 22697486b72dSIngo Weinhold image->id); 22707486b72dSIngo Weinhold 22710c0fea5dSIngo Weinhold return B_OK; 22720c0fea5dSIngo Weinhold } 22730c0fea5dSIngo Weinhold 22740c0fea5dSIngo Weinhold 22750c85bd05SIngo Weinhold static status_t 22760c85bd05SIngo Weinhold load_dependencies(image_t* image) 22770c85bd05SIngo Weinhold { 2278*003ebb0eSIngo Weinhold // load dependencies (breadth-first) 22790c85bd05SIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 22800c85bd05SIngo Weinhold otherImage = otherImage->next) { 22810c85bd05SIngo Weinhold status_t status = load_immediate_dependencies(otherImage); 22820c85bd05SIngo Weinhold if (status != B_OK) 22830c85bd05SIngo Weinhold return status; 22840c85bd05SIngo Weinhold } 22850c85bd05SIngo Weinhold 2286*003ebb0eSIngo Weinhold // Check the needed versions for the given image and all newly loaded 2287*003ebb0eSIngo Weinhold // dependencies. 2288*003ebb0eSIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 2289*003ebb0eSIngo Weinhold otherImage = otherImage->next) { 2290*003ebb0eSIngo Weinhold status_t status = check_needed_image_versions(otherImage); 2291*003ebb0eSIngo Weinhold if (status != B_OK) 2292*003ebb0eSIngo Weinhold return status; 2293*003ebb0eSIngo Weinhold } 2294*003ebb0eSIngo Weinhold 22950c85bd05SIngo Weinhold return B_OK; 22960c85bd05SIngo Weinhold } 22970c85bd05SIngo Weinhold 22980c85bd05SIngo Weinhold 22990c0fea5dSIngo Weinhold static uint32 23000c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList, 23010c0fea5dSIngo Weinhold uint32 sortFlag) 23020c0fea5dSIngo Weinhold { 23030c0fea5dSIngo Weinhold uint32 i; 23040c0fea5dSIngo Weinhold 23050c0fea5dSIngo Weinhold if (image->flags & sortFlag) 23060c0fea5dSIngo Weinhold return slot; 23070c0fea5dSIngo Weinhold 23080c0fea5dSIngo Weinhold image->flags |= sortFlag; /* make sure we don't visit this one */ 23090c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) 23100c0fea5dSIngo Weinhold slot = topological_sort(image->needed[i], slot, initList, sortFlag); 23110c0fea5dSIngo Weinhold 23120c0fea5dSIngo Weinhold initList[slot] = image; 23130c0fea5dSIngo Weinhold return slot + 1; 23140c0fea5dSIngo Weinhold } 23150c0fea5dSIngo Weinhold 23160c0fea5dSIngo Weinhold 23170c0fea5dSIngo Weinhold static ssize_t 23180c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag) 23190c0fea5dSIngo Weinhold { 23200c0fea5dSIngo Weinhold image_t **list; 23210c0fea5dSIngo Weinhold 23220c0fea5dSIngo Weinhold list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *)); 23230c0fea5dSIngo Weinhold if (list == NULL) { 23240c0fea5dSIngo Weinhold FATAL("memory shortage in get_sorted_image_list()"); 23250c0fea5dSIngo Weinhold *_list = NULL; 23260c0fea5dSIngo Weinhold return B_NO_MEMORY; 23270c0fea5dSIngo Weinhold } 23280c0fea5dSIngo Weinhold 23290c0fea5dSIngo Weinhold memset(list, 0, sLoadedImageCount * sizeof(image_t *)); 23300c0fea5dSIngo Weinhold 23310c0fea5dSIngo Weinhold *_list = list; 23320c0fea5dSIngo Weinhold return topological_sort(image, 0, list, sortFlag); 23330c0fea5dSIngo Weinhold } 23340c0fea5dSIngo Weinhold 23350c0fea5dSIngo Weinhold 23360c0fea5dSIngo Weinhold static status_t 23370c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 23380c0fea5dSIngo Weinhold { 2339ca618b22SIngo Weinhold // get the images that still have to be relocated 2340ca618b22SIngo Weinhold image_t **list; 2341ca618b22SIngo Weinhold ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 23420c0fea5dSIngo Weinhold if (count < B_OK) 23430c0fea5dSIngo Weinhold return count; 23440c0fea5dSIngo Weinhold 23450c85bd05SIngo Weinhold // relocate 2346ca618b22SIngo Weinhold for (ssize_t i = 0; i < count; i++) { 234746f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 23480c85bd05SIngo Weinhold if (status < B_OK) { 23490c85bd05SIngo Weinhold free(list); 23500c0fea5dSIngo Weinhold return status; 23510c0fea5dSIngo Weinhold } 23520c85bd05SIngo Weinhold } 23530c0fea5dSIngo Weinhold 23540c0fea5dSIngo Weinhold free(list); 23550c0fea5dSIngo Weinhold return B_OK; 23560c0fea5dSIngo Weinhold } 23570c0fea5dSIngo Weinhold 23580c0fea5dSIngo Weinhold 23590c0fea5dSIngo Weinhold static void 23600c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 23610c0fea5dSIngo Weinhold { 23620c0fea5dSIngo Weinhold image_t **initList; 23630c0fea5dSIngo Weinhold ssize_t count, i; 23640c0fea5dSIngo Weinhold 23650c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 23660c0fea5dSIngo Weinhold if (count <= 0) 23670c0fea5dSIngo Weinhold return; 23680c0fea5dSIngo Weinhold 23690c0fea5dSIngo Weinhold if (!initHead) { 23700c0fea5dSIngo Weinhold // this removes the "calling" image 23710c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 23720c0fea5dSIngo Weinhold initList[--count] = NULL; 23730c0fea5dSIngo Weinhold } 23740c0fea5dSIngo Weinhold 23750c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 23760c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 23770c0fea5dSIngo Weinhold image = initList[i]; 23780c0fea5dSIngo Weinhold 23790c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 23800c0fea5dSIngo Weinhold 2381dd76bc97SIngo Weinhold if (image->init_routine != 0) 23820c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 238310b4b5d1SIngo Weinhold 238410b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_INITIALIZED); 23850c0fea5dSIngo Weinhold } 23860c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 23870c0fea5dSIngo Weinhold 23880c0fea5dSIngo Weinhold free(initList); 23890c0fea5dSIngo Weinhold } 23900c0fea5dSIngo Weinhold 23910c0fea5dSIngo Weinhold 23920c0fea5dSIngo Weinhold static void 23930c0fea5dSIngo Weinhold put_image(image_t *image) 23940c0fea5dSIngo Weinhold { 23950c0fea5dSIngo Weinhold // If all references to the image are gone, add it to the disposable list 23960c0fea5dSIngo Weinhold // and remove all dependencies 23970c0fea5dSIngo Weinhold 23980c0fea5dSIngo Weinhold if (atomic_add(&image->ref_count, -1) == 1) { 23990c0fea5dSIngo Weinhold size_t i; 24000c0fea5dSIngo Weinhold 24010c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 24020c0fea5dSIngo Weinhold enqueue_image(&sDisposableImages, image); 24030c0fea5dSIngo Weinhold sLoadedImageCount--; 24040c0fea5dSIngo Weinhold 24050c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) { 24060c0fea5dSIngo Weinhold put_image(image->needed[i]); 24070c0fea5dSIngo Weinhold } 24080c0fea5dSIngo Weinhold } 24090c0fea5dSIngo Weinhold } 24100c0fea5dSIngo Weinhold 24110c0fea5dSIngo Weinhold 2412ca618b22SIngo Weinhold void 2413ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage) 2414ca618b22SIngo Weinhold { 2415ca618b22SIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private 2416ca618b22SIngo Weinhold // API. 2417ca618b22SIngo Weinhold image_t* image; 24180c85bd05SIngo Weinhold void* _export; 2419*003ebb0eSIngo Weinhold if (find_symbol_breadth_first(rootImage, 2420*003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image, 2421*003ebb0eSIngo Weinhold &_export) == B_OK) { 24220c85bd05SIngo Weinhold *(void**)_export = &gRuntimeLoader; 2423ca618b22SIngo Weinhold } 2424ca618b22SIngo Weinhold } 2425ca618b22SIngo Weinhold 2426ca618b22SIngo Weinhold 2427ca618b22SIngo Weinhold static status_t 2428ca618b22SIngo Weinhold add_preloaded_image(image_t* image) 2429ca618b22SIngo Weinhold { 2430ca618b22SIngo Weinhold // We realloc() everytime -- not particularly efficient, but good enough for 2431ca618b22SIngo Weinhold // small number of preloaded images. 2432ca618b22SIngo Weinhold image_t** newArray = (image_t**)realloc(sPreloadedImages, 2433ca618b22SIngo Weinhold sizeof(image_t*) * (sPreloadedImageCount + 1)); 2434ca618b22SIngo Weinhold if (newArray == NULL) 2435ca618b22SIngo Weinhold return B_NO_MEMORY; 2436ca618b22SIngo Weinhold 2437ca618b22SIngo Weinhold sPreloadedImages = newArray; 2438ca618b22SIngo Weinhold newArray[sPreloadedImageCount++] = image; 2439ca618b22SIngo Weinhold 2440ca618b22SIngo Weinhold return B_OK; 2441ca618b22SIngo Weinhold } 2442ca618b22SIngo Weinhold 2443ca618b22SIngo Weinhold 2444ca618b22SIngo Weinhold image_id 2445ca618b22SIngo Weinhold preload_image(char const* path) 2446ca618b22SIngo Weinhold { 2447ca618b22SIngo Weinhold if (path == NULL) 2448ca618b22SIngo Weinhold return B_BAD_VALUE; 2449ca618b22SIngo Weinhold 2450ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\")", path); 2451ca618b22SIngo Weinhold 2452ca618b22SIngo Weinhold image_t *image = NULL; 2453ca618b22SIngo Weinhold status_t status = load_container(path, B_ADD_ON_IMAGE, NULL, &image); 2454ca618b22SIngo Weinhold if (status < B_OK) { 2455ca618b22SIngo Weinhold rld_unlock(); 2456ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, 2457ca618b22SIngo Weinhold strerror(status)); 2458ca618b22SIngo Weinhold return status; 2459ca618b22SIngo Weinhold } 2460ca618b22SIngo Weinhold 24610c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) 24620c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 24630c85bd05SIngo Weinhold 24640c85bd05SIngo Weinhold status = load_dependencies(image); 2465ca618b22SIngo Weinhold if (status < B_OK) 2466ca618b22SIngo Weinhold goto err; 24670c85bd05SIngo Weinhold 24680c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 2469ca618b22SIngo Weinhold 2470ca618b22SIngo Weinhold status = relocate_dependencies(image); 2471ca618b22SIngo Weinhold if (status < B_OK) 2472ca618b22SIngo Weinhold goto err; 2473ca618b22SIngo Weinhold 2474ca618b22SIngo Weinhold status = add_preloaded_image(image); 2475ca618b22SIngo Weinhold if (status < B_OK) 2476ca618b22SIngo Weinhold goto err; 2477ca618b22SIngo Weinhold 2478ca618b22SIngo Weinhold inject_runtime_loader_api(image); 2479ca618b22SIngo Weinhold 2480ca618b22SIngo Weinhold remap_images(); 2481ca618b22SIngo Weinhold init_dependencies(image, true); 2482ca618b22SIngo Weinhold 248310b4b5d1SIngo Weinhold // if the image contains an add-on, register it 248410b4b5d1SIngo Weinhold runtime_loader_add_on* addOnStruct; 2485*003ebb0eSIngo Weinhold if (find_symbol(image, 2486*003ebb0eSIngo Weinhold SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA), 248710b4b5d1SIngo Weinhold (void**)&addOnStruct) == B_OK) { 248810b4b5d1SIngo Weinhold RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image, 248910b4b5d1SIngo Weinhold addOnStruct); 249010b4b5d1SIngo Weinhold if (addOn != NULL) { 249110b4b5d1SIngo Weinhold sAddOns.Add(addOn); 249210b4b5d1SIngo Weinhold addOnStruct->init(&gRuntimeLoader, &gRuntimeLoaderAddOnExport); 249310b4b5d1SIngo Weinhold } 249410b4b5d1SIngo Weinhold } 249510b4b5d1SIngo Weinhold 2496ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id); 2497ca618b22SIngo Weinhold 2498ca618b22SIngo Weinhold return image->id; 2499ca618b22SIngo Weinhold 2500ca618b22SIngo Weinhold err: 2501ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status)); 2502ca618b22SIngo Weinhold 2503ca618b22SIngo Weinhold dequeue_image(&sLoadedImages, image); 2504ca618b22SIngo Weinhold sLoadedImageCount--; 2505ca618b22SIngo Weinhold delete_image(image); 2506ca618b22SIngo Weinhold return status; 2507ca618b22SIngo Weinhold } 2508ca618b22SIngo Weinhold 2509ca618b22SIngo Weinhold 2510ca618b22SIngo Weinhold static void 2511ca618b22SIngo Weinhold preload_images() 2512ca618b22SIngo Weinhold { 2513ca618b22SIngo Weinhold const char* imagePaths = getenv("LD_PRELOAD"); 2514ca618b22SIngo Weinhold if (imagePaths == NULL) 2515ca618b22SIngo Weinhold return; 2516ca618b22SIngo Weinhold 2517ca618b22SIngo Weinhold while (*imagePaths != '\0') { 2518ca618b22SIngo Weinhold // find begin of image path 2519ca618b22SIngo Weinhold while (*imagePaths != '\0' && isspace(*imagePaths)) 2520ca618b22SIngo Weinhold imagePaths++; 2521ca618b22SIngo Weinhold 2522ca618b22SIngo Weinhold if (*imagePaths == '\0') 2523ca618b22SIngo Weinhold break; 2524ca618b22SIngo Weinhold 2525ca618b22SIngo Weinhold // find end of image path 2526ca618b22SIngo Weinhold const char* imagePath = imagePaths; 2527ca618b22SIngo Weinhold while (*imagePaths != '\0' && !isspace(*imagePaths)) 2528ca618b22SIngo Weinhold imagePaths++; 2529ca618b22SIngo Weinhold 2530ca618b22SIngo Weinhold // extract the path 2531ca618b22SIngo Weinhold char path[B_PATH_NAME_LENGTH]; 2532ca618b22SIngo Weinhold size_t pathLen = imagePaths - imagePath; 2533ca618b22SIngo Weinhold if (pathLen > sizeof(path) - 1) 2534ca618b22SIngo Weinhold continue; 2535ca618b22SIngo Weinhold memcpy(path, imagePath, pathLen); 2536ca618b22SIngo Weinhold path[pathLen] = '\0'; 2537ca618b22SIngo Weinhold 2538ca618b22SIngo Weinhold // load the image 2539ca618b22SIngo Weinhold preload_image(path); 2540ca618b22SIngo Weinhold } 2541ca618b22SIngo Weinhold } 2542ca618b22SIngo Weinhold 2543ca618b22SIngo Weinhold 254474c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 25450c0fea5dSIngo Weinhold 25460c0fea5dSIngo Weinhold 25470c0fea5dSIngo Weinhold image_id 25480c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 25490c0fea5dSIngo Weinhold { 25500c0fea5dSIngo Weinhold status_t status; 25510c0fea5dSIngo Weinhold image_t *image; 25520c0fea5dSIngo Weinhold 25537486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path); 25547486b72dSIngo Weinhold 25550c0fea5dSIngo Weinhold rld_lock(); 25560c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 25570c0fea5dSIngo Weinhold 2558ca618b22SIngo Weinhold preload_images(); 2559ca618b22SIngo Weinhold 25600c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 25610c0fea5dSIngo Weinhold 25620c0fea5dSIngo Weinhold status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage); 256374c0424aSAxel Dörfler if (status < B_OK) 256474c0424aSAxel Dörfler goto err; 25650c0fea5dSIngo Weinhold 25660c85bd05SIngo Weinhold if (sProgramImage->find_undefined_symbol == NULL) 25670c85bd05SIngo Weinhold sProgramImage->find_undefined_symbol = find_undefined_symbol_global; 25680c85bd05SIngo Weinhold 25690c85bd05SIngo Weinhold status = load_dependencies(sProgramImage); 25700c0fea5dSIngo Weinhold if (status < B_OK) 25710c0fea5dSIngo Weinhold goto err; 25720c85bd05SIngo Weinhold 257347bc6663SIngo Weinhold // Set RTLD_GLOBAL on all libraries including the program. 25740c85bd05SIngo Weinhold // This results in the desired symbol resolution for dlopen()ed libraries. 25750c85bd05SIngo Weinhold set_image_flags_recursively(sProgramImage, RTLD_GLOBAL); 25760c0fea5dSIngo Weinhold 25770c0fea5dSIngo Weinhold status = relocate_dependencies(sProgramImage); 25780c0fea5dSIngo Weinhold if (status < B_OK) 25790c0fea5dSIngo Weinhold goto err; 25800c0fea5dSIngo Weinhold 2581ca618b22SIngo Weinhold inject_runtime_loader_api(sProgramImage); 25820c0fea5dSIngo Weinhold 25830c0fea5dSIngo Weinhold remap_images(); 2584ca618b22SIngo Weinhold init_dependencies(sProgramImage, true); 25850c0fea5dSIngo Weinhold 25860c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 25870c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 2588*003ebb0eSIngo Weinhold find_symbol_breadth_first(sProgramImage, 2589*003ebb0eSIngo Weinhold SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image, 2590*003ebb0eSIngo Weinhold (void**)&gGetEnv); 25910c0fea5dSIngo Weinhold 2592dd76bc97SIngo Weinhold if (sProgramImage->entry_point == 0) { 25930c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 25940c0fea5dSIngo Weinhold goto err; 25950c0fea5dSIngo Weinhold } 25960c0fea5dSIngo Weinhold 25970c0fea5dSIngo Weinhold *_entry = (void *)(sProgramImage->entry_point); 25980c0fea5dSIngo Weinhold 25990c0fea5dSIngo Weinhold rld_unlock(); 26007486b72dSIngo Weinhold 26015d0638bfSIngo Weinhold sProgramLoaded = true; 26025d0638bfSIngo Weinhold 26037486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path, 26047486b72dSIngo Weinhold *_entry, sProgramImage->id); 26057486b72dSIngo Weinhold 26060c0fea5dSIngo Weinhold return sProgramImage->id; 26070c0fea5dSIngo Weinhold 26080c0fea5dSIngo Weinhold err: 26097486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); 26107486b72dSIngo Weinhold 26110c0fea5dSIngo Weinhold delete_image(sProgramImage); 261274c0424aSAxel Dörfler 26134bef3723SAxel Dörfler if (report_errors()) { 26144bef3723SAxel Dörfler // send error message 261574c0424aSAxel Dörfler sErrorMessage.AddInt32("error", status); 26164bef3723SAxel Dörfler sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 26174bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 26184bef3723SAxel Dörfler 26194bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 26204bef3723SAxel Dörfler sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0); 262174c0424aSAxel Dörfler } 262274c0424aSAxel Dörfler _kern_loading_app_failed(status); 26230c0fea5dSIngo Weinhold rld_unlock(); 262474c0424aSAxel Dörfler 26250c0fea5dSIngo Weinhold return status; 26260c0fea5dSIngo Weinhold } 26270c0fea5dSIngo Weinhold 26280c0fea5dSIngo Weinhold 26290c0fea5dSIngo Weinhold image_id 26300c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle) 26310c0fea5dSIngo Weinhold { 26320c0fea5dSIngo Weinhold image_t *image = NULL; 26330c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 26340c0fea5dSIngo Weinhold status_t status; 26350c0fea5dSIngo Weinhold 26360c85bd05SIngo Weinhold if (path == NULL && addOn) 26370c0fea5dSIngo Weinhold return B_BAD_VALUE; 26380c0fea5dSIngo Weinhold 26397486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn); 26407486b72dSIngo Weinhold 26410c0fea5dSIngo Weinhold rld_lock(); 26420c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 26430c0fea5dSIngo Weinhold 26440c0fea5dSIngo Weinhold // have we already loaded this library? 26450c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 26460c0fea5dSIngo Weinhold if (!addOn) { 26470c85bd05SIngo Weinhold // a NULL path is fine -- it means the global scope shall be opened 26480c85bd05SIngo Weinhold if (path == NULL) { 26490c85bd05SIngo Weinhold *_handle = RLD_GLOBAL_SCOPE; 26500c85bd05SIngo Weinhold rld_unlock(); 26510c85bd05SIngo Weinhold return 0; 26520c85bd05SIngo Weinhold } 26530c85bd05SIngo Weinhold 26540c0fea5dSIngo Weinhold image = find_image(path, APP_OR_LIBRARY_TYPE); 26550c85bd05SIngo Weinhold if (image != NULL && (flags & RTLD_GLOBAL) != 0) 26560c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 26570c85bd05SIngo Weinhold 26580c0fea5dSIngo Weinhold if (image) { 26590c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 26600c0fea5dSIngo Weinhold rld_unlock(); 26617486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path, 26627486b72dSIngo Weinhold image->id); 26630c85bd05SIngo Weinhold *_handle = image; 26640c0fea5dSIngo Weinhold return image->id; 26650c0fea5dSIngo Weinhold } 26660c0fea5dSIngo Weinhold } 26670c0fea5dSIngo Weinhold 26680c0fea5dSIngo Weinhold status = load_container(path, type, NULL, &image); 26690c0fea5dSIngo Weinhold if (status < B_OK) { 26700c0fea5dSIngo Weinhold rld_unlock(); 26717486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, 26727486b72dSIngo Weinhold strerror(status)); 26730c0fea5dSIngo Weinhold return status; 26740c0fea5dSIngo Weinhold } 26750c0fea5dSIngo Weinhold 26760c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) { 26770c85bd05SIngo Weinhold if (addOn) 26780c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_add_on; 26790c85bd05SIngo Weinhold else 26800c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 26810c85bd05SIngo Weinhold } 26820c85bd05SIngo Weinhold 26830c85bd05SIngo Weinhold status = load_dependencies(image); 26840c0fea5dSIngo Weinhold if (status < B_OK) 26850c0fea5dSIngo Weinhold goto err; 26860c85bd05SIngo Weinhold 26870c85bd05SIngo Weinhold // If specified, set the RTLD_GLOBAL flag recursively on this image and all 26880c85bd05SIngo Weinhold // dependencies. If not specified, we temporarily set 26890c85bd05SIngo Weinhold // RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used 26900c85bd05SIngo Weinhold // for undefined symbol resolution. 26910c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) != 0) 26920c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 26930c85bd05SIngo Weinhold else 26940c85bd05SIngo Weinhold set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 26950c0fea5dSIngo Weinhold 26960c0fea5dSIngo Weinhold status = relocate_dependencies(image); 26970c0fea5dSIngo Weinhold if (status < B_OK) 26980c0fea5dSIngo Weinhold goto err; 26990c0fea5dSIngo Weinhold 27000c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) == 0) 27010c85bd05SIngo Weinhold clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 27020c85bd05SIngo Weinhold 27030c0fea5dSIngo Weinhold remap_images(); 27040c0fea5dSIngo Weinhold init_dependencies(image, true); 27050c0fea5dSIngo Weinhold 27060c0fea5dSIngo Weinhold rld_unlock(); 27077486b72dSIngo Weinhold 27087486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id); 27097486b72dSIngo Weinhold 27100c85bd05SIngo Weinhold *_handle = image; 27110c0fea5dSIngo Weinhold return image->id; 27120c0fea5dSIngo Weinhold 27130c0fea5dSIngo Weinhold err: 27147486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status)); 27157486b72dSIngo Weinhold 27160c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 27170c0fea5dSIngo Weinhold sLoadedImageCount--; 27180c0fea5dSIngo Weinhold delete_image(image); 27190c0fea5dSIngo Weinhold rld_unlock(); 27200c0fea5dSIngo Weinhold return status; 27210c0fea5dSIngo Weinhold } 27220c0fea5dSIngo Weinhold 27230c0fea5dSIngo Weinhold 27240c0fea5dSIngo Weinhold status_t 27250c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn) 27260c0fea5dSIngo Weinhold { 27270c0fea5dSIngo Weinhold image_t *image; 27280c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 27290c0fea5dSIngo Weinhold 27300c85bd05SIngo Weinhold if (handle == NULL && imageID < 0) 27310c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 27320c0fea5dSIngo Weinhold 27330c85bd05SIngo Weinhold if (handle == RLD_GLOBAL_SCOPE) 27340c85bd05SIngo Weinhold return B_OK; 27350c85bd05SIngo Weinhold 27360c0fea5dSIngo Weinhold rld_lock(); 27370c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 27380c0fea5dSIngo Weinhold 27399a6072a3SAxel Dörfler if (sInvalidImageIDs) { 27409a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 27419a6072a3SAxel Dörfler update_image_ids(); 27429a6072a3SAxel Dörfler } 27439a6072a3SAxel Dörfler 27440c0fea5dSIngo Weinhold // we only check images that have been already initialized 27450c0fea5dSIngo Weinhold 2746df30098dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 2747df30098dSIngo Weinhold 27480c85bd05SIngo Weinhold if (handle != NULL) { 27490c85bd05SIngo Weinhold image = (image_t*)handle; 27500c85bd05SIngo Weinhold put_image(image); 2751df30098dSIngo Weinhold status = B_OK; 27520c85bd05SIngo Weinhold } else { 27530c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image; image = image->next) { 27540c0fea5dSIngo Weinhold if (image->id == imageID) { 27550c0fea5dSIngo Weinhold // unload image 27560c0fea5dSIngo Weinhold if (type == image->type) { 27570c0fea5dSIngo Weinhold put_image(image); 27580c0fea5dSIngo Weinhold status = B_OK; 27590c0fea5dSIngo Weinhold } else 27600c0fea5dSIngo Weinhold status = B_BAD_VALUE; 27610c0fea5dSIngo Weinhold break; 27620c0fea5dSIngo Weinhold } 27630c0fea5dSIngo Weinhold } 27640c85bd05SIngo Weinhold } 27650c0fea5dSIngo Weinhold 27660c0fea5dSIngo Weinhold if (status == B_OK) { 27670c0fea5dSIngo Weinhold while ((image = sDisposableImages.head) != NULL) { 27680c0fea5dSIngo Weinhold // call image fini here... 27698c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 27708c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 27713be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize); 27728c2a9d74SMichael Lotz } 27738c2a9d74SMichael Lotz 277410b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 277510b4b5d1SIngo Weinhold 27760c0fea5dSIngo Weinhold if (image->term_routine) 27770c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 27780c0fea5dSIngo Weinhold 27790c0fea5dSIngo Weinhold dequeue_image(&sDisposableImages, image); 27800c0fea5dSIngo Weinhold unmap_image(image); 27810c0fea5dSIngo Weinhold 278210b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 278310b4b5d1SIngo Weinhold 27840c0fea5dSIngo Weinhold delete_image(image); 27850c0fea5dSIngo Weinhold } 27860c0fea5dSIngo Weinhold } 27870c0fea5dSIngo Weinhold 27880c0fea5dSIngo Weinhold rld_unlock(); 27890c0fea5dSIngo Weinhold return status; 27900c0fea5dSIngo Weinhold } 27910c0fea5dSIngo Weinhold 27920c0fea5dSIngo Weinhold 27930c0fea5dSIngo Weinhold status_t 27949a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, 27959a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location) 27960c0fea5dSIngo Weinhold { 27970c0fea5dSIngo Weinhold int32 count = 0, j; 27980c0fea5dSIngo Weinhold uint32 i; 27990c0fea5dSIngo Weinhold image_t *image; 28000c0fea5dSIngo Weinhold 28010c0fea5dSIngo Weinhold rld_lock(); 28020c0fea5dSIngo Weinhold 28030c0fea5dSIngo Weinhold // get the image from those who have been already initialized 28040c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 28050c0fea5dSIngo Weinhold if (image == NULL) { 28060c0fea5dSIngo Weinhold rld_unlock(); 28070c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 28080c0fea5dSIngo Weinhold } 28090c0fea5dSIngo Weinhold 28100c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 28110c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 28120c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 28130555803aSAxel Dörfler struct Elf32_Sym *symbol = &image->syms[j]; 28140c0fea5dSIngo Weinhold 28150c0fea5dSIngo Weinhold if (count == num) { 281610b4b5d1SIngo Weinhold const char* symbolName = SYMNAME(image, symbol); 281710b4b5d1SIngo Weinhold strlcpy(nameBuffer, symbolName, *_nameLength); 281810b4b5d1SIngo Weinhold *_nameLength = strlen(symbolName); 28190c0fea5dSIngo Weinhold 282010b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value 282110b4b5d1SIngo Weinhold + image->regions[0].delta); 282210b4b5d1SIngo Weinhold int32 type; 28230c0fea5dSIngo Weinhold if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) 282410b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 28250c0fea5dSIngo Weinhold else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) 282610b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 28270c0fea5dSIngo Weinhold else 282810b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_ANY; 282910b4b5d1SIngo Weinhold // TODO: check with the return types of that BeOS function 28300c0fea5dSIngo Weinhold 283110b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &type); 283210b4b5d1SIngo Weinhold 283310b4b5d1SIngo Weinhold if (_type != NULL) 283410b4b5d1SIngo Weinhold *_type = type; 28350c0fea5dSIngo Weinhold if (_location != NULL) 283610b4b5d1SIngo Weinhold *_location = location; 28370c0fea5dSIngo Weinhold goto out; 28380c0fea5dSIngo Weinhold } 28390c0fea5dSIngo Weinhold count++; 28400c0fea5dSIngo Weinhold } 28410c0fea5dSIngo Weinhold } 28420c0fea5dSIngo Weinhold out: 28430c0fea5dSIngo Weinhold rld_unlock(); 28440c0fea5dSIngo Weinhold 28450c0fea5dSIngo Weinhold if (num != count) 28460c0fea5dSIngo Weinhold return B_BAD_INDEX; 28470c0fea5dSIngo Weinhold 28480c0fea5dSIngo Weinhold return B_OK; 28490c0fea5dSIngo Weinhold } 28500c0fea5dSIngo Weinhold 28510c0fea5dSIngo Weinhold 28520c0fea5dSIngo Weinhold status_t 28539a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType, 285480ece785SIngo Weinhold bool recursive, image_id *_inImage, void **_location) 28550c0fea5dSIngo Weinhold { 28560c0fea5dSIngo Weinhold status_t status = B_OK; 28570c0fea5dSIngo Weinhold image_t *image; 28580c0fea5dSIngo Weinhold 28590c0fea5dSIngo Weinhold if (imageID < B_OK) 28600c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 28610c0fea5dSIngo Weinhold if (symbolName == NULL) 28620c0fea5dSIngo Weinhold return B_BAD_VALUE; 28630c0fea5dSIngo Weinhold 28640c0fea5dSIngo Weinhold rld_lock(); 28650c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 28660c0fea5dSIngo Weinhold 28670c0fea5dSIngo Weinhold // get the image from those who have been already initialized 28680c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 286980ece785SIngo Weinhold if (image != NULL) { 287080ece785SIngo Weinhold if (recursive) { 287180ece785SIngo Weinhold // breadth-first search in the given image and its dependencies 2872*003ebb0eSIngo Weinhold status = find_symbol_breadth_first(image, 2873*003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 2874*003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 287580ece785SIngo Weinhold &image, _location); 2876*003ebb0eSIngo Weinhold } else { 2877*003ebb0eSIngo Weinhold status = find_symbol(image, 2878*003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, symbolType, NULL, 2879*003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 2880*003ebb0eSIngo Weinhold _location); 2881*003ebb0eSIngo Weinhold } 288280ece785SIngo Weinhold 288380ece785SIngo Weinhold if (status == B_OK && _inImage != NULL) 288480ece785SIngo Weinhold *_inImage = image->id; 288580ece785SIngo Weinhold } else 28860c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 28870c0fea5dSIngo Weinhold 28880c0fea5dSIngo Weinhold rld_unlock(); 28890c0fea5dSIngo Weinhold return status; 28900c0fea5dSIngo Weinhold } 28910c0fea5dSIngo Weinhold 28920c0fea5dSIngo Weinhold 28930c0fea5dSIngo Weinhold status_t 28940c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName, 28950c85bd05SIngo Weinhold void **_location) 28960c85bd05SIngo Weinhold { 28970c85bd05SIngo Weinhold status_t status = B_ENTRY_NOT_FOUND; 28980c85bd05SIngo Weinhold 28990c85bd05SIngo Weinhold if (symbolName == NULL) 29000c85bd05SIngo Weinhold return B_BAD_VALUE; 29010c85bd05SIngo Weinhold 29020c85bd05SIngo Weinhold rld_lock(); 29030c85bd05SIngo Weinhold // for now, just do stupid simple global locking 29040c85bd05SIngo Weinhold 29050c85bd05SIngo Weinhold if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) { 29060c85bd05SIngo Weinhold // look in the default scope 29070c85bd05SIngo Weinhold image_t* image; 29080c85bd05SIngo Weinhold Elf32_Sym* symbol = find_undefined_symbol_global(sProgramImage, 2909*003ebb0eSIngo Weinhold sProgramImage, 2910*003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 2911*003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 2912*003ebb0eSIngo Weinhold &image); 29130c85bd05SIngo Weinhold if (symbol != NULL) { 29140c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value + image->regions[0].delta); 29150c85bd05SIngo Weinhold int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC 29160c85bd05SIngo Weinhold ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 29170c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, &symbolType); 29180c85bd05SIngo Weinhold status = B_OK; 29190c85bd05SIngo Weinhold } 29200c85bd05SIngo Weinhold } else if (handle == RTLD_NEXT) { 29210c85bd05SIngo Weinhold // Look in the default scope, but also in the dependencies of the 29220c85bd05SIngo Weinhold // calling image. Return the next after the caller symbol. 29230c85bd05SIngo Weinhold 2924a2dad9e1SIngo Weinhold // First of all, find the caller image. 29250c85bd05SIngo Weinhold image_t* callerImage = sLoadedImages.head; 29260c85bd05SIngo Weinhold for (; callerImage != NULL; callerImage = callerImage->next) { 29270c85bd05SIngo Weinhold elf_region_t& text = callerImage->regions[0]; 2928a2dad9e1SIngo Weinhold if ((addr_t)caller >= text.vmstart 2929a2dad9e1SIngo Weinhold && (addr_t)caller < text.vmstart + text.vmsize) { 2930a2dad9e1SIngo Weinhold // found the image 29310c85bd05SIngo Weinhold break; 29320c85bd05SIngo Weinhold } 29330c85bd05SIngo Weinhold } 29340c85bd05SIngo Weinhold 2935a2dad9e1SIngo Weinhold if (callerImage != NULL) { 29360c85bd05SIngo Weinhold // found the caller -- now search the global scope until we find 29370c85bd05SIngo Weinhold // the next symbol 2938a2dad9e1SIngo Weinhold bool hitCallerImage = false; 29390c85bd05SIngo Weinhold set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 29400c85bd05SIngo Weinhold 29410c85bd05SIngo Weinhold image_t* image = sLoadedImages.head; 29420c85bd05SIngo Weinhold for (; image != NULL; image = image->next) { 2943a2dad9e1SIngo Weinhold // skip the caller image 2944a2dad9e1SIngo Weinhold if (image == callerImage) { 2945a2dad9e1SIngo Weinhold hitCallerImage = true; 2946a2dad9e1SIngo Weinhold continue; 2947a2dad9e1SIngo Weinhold } 2948a2dad9e1SIngo Weinhold 2949a2dad9e1SIngo Weinhold // skip all images up to the caller image; also skip add-on 2950a2dad9e1SIngo Weinhold // images and those not marked above for resolution 2951a2dad9e1SIngo Weinhold if (!hitCallerImage || image->type == B_ADD_ON_IMAGE 29520c85bd05SIngo Weinhold || (image->flags 2953a2dad9e1SIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) { 29540c85bd05SIngo Weinhold continue; 29550c85bd05SIngo Weinhold } 29560c85bd05SIngo Weinhold 2957*003ebb0eSIngo Weinhold struct Elf32_Sym *symbol = find_symbol(image, 2958*003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL, 2959*003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION)); 29600c85bd05SIngo Weinhold if (symbol == NULL) 29610c85bd05SIngo Weinhold continue; 29620c85bd05SIngo Weinhold 2963a2dad9e1SIngo Weinhold // found the symbol 29640c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value 29650c85bd05SIngo Weinhold + image->regions[0].delta); 29660c85bd05SIngo Weinhold int32 symbolType = B_SYMBOL_TYPE_TEXT; 29670c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, 29680c85bd05SIngo Weinhold &symbolType); 29690c85bd05SIngo Weinhold status = B_OK; 29700c85bd05SIngo Weinhold break; 29710c85bd05SIngo Weinhold } 29720c85bd05SIngo Weinhold 29730c85bd05SIngo Weinhold clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 29740c85bd05SIngo Weinhold } 29750c85bd05SIngo Weinhold } else { 29760c85bd05SIngo Weinhold // breadth-first search in the given image and its dependencies 29770c85bd05SIngo Weinhold image_t* inImage; 2978*003ebb0eSIngo Weinhold status = find_symbol_breadth_first((image_t*)handle, 2979*003ebb0eSIngo Weinhold SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL, 2980*003ebb0eSIngo Weinhold LOOKUP_FLAG_DEFAULT_VERSION), 2981*003ebb0eSIngo Weinhold &inImage, _location); 29820c85bd05SIngo Weinhold } 29830c85bd05SIngo Weinhold 29840c85bd05SIngo Weinhold rld_unlock(); 29850c85bd05SIngo Weinhold return status; 29860c85bd05SIngo Weinhold } 29870c85bd05SIngo Weinhold 29880c85bd05SIngo Weinhold 29890c85bd05SIngo Weinhold status_t 29900c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 29910c0fea5dSIngo Weinhold { 29920c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 29930c0fea5dSIngo Weinhold struct Elf32_Dyn *dynamicSection; 29940c0fea5dSIngo Weinhold image_t *image; 29950c0fea5dSIngo Weinhold 29960c0fea5dSIngo Weinhold if (_name == NULL) 29970c0fea5dSIngo Weinhold return B_BAD_VALUE; 29980c0fea5dSIngo Weinhold 29990c0fea5dSIngo Weinhold rld_lock(); 30000c0fea5dSIngo Weinhold 30010c0fea5dSIngo Weinhold image = find_loaded_image_by_id(id); 30020c0fea5dSIngo Weinhold if (image == NULL) { 30030c0fea5dSIngo Weinhold rld_unlock(); 30040c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 30050c0fea5dSIngo Weinhold } 30060c0fea5dSIngo Weinhold 30070c0fea5dSIngo Weinhold dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr; 30080c0fea5dSIngo Weinhold if (dynamicSection == NULL || image->num_needed <= searchIndex) { 30090c0fea5dSIngo Weinhold rld_unlock(); 30100c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 30110c0fea5dSIngo Weinhold } 30120c0fea5dSIngo Weinhold 30130c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 30140c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 30150c0fea5dSIngo Weinhold continue; 30160c0fea5dSIngo Weinhold 30170c0fea5dSIngo Weinhold if (j++ == searchIndex) { 30180c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 30190c0fea5dSIngo Weinhold 30200c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 30210c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 30220c0fea5dSIngo Weinhold rld_unlock(); 30230c0fea5dSIngo Weinhold return B_OK; 30240c0fea5dSIngo Weinhold } 30250c0fea5dSIngo Weinhold } 30260c0fea5dSIngo Weinhold 30270c0fea5dSIngo Weinhold rld_unlock(); 30280c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 30290c0fea5dSIngo Weinhold } 30300c0fea5dSIngo Weinhold 30310c0fea5dSIngo Weinhold 303274c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 30330c0fea5dSIngo Weinhold 30340c0fea5dSIngo Weinhold 30359a6072a3SAxel Dörfler /*! Read and verify the ELF header */ 30360c0fea5dSIngo Weinhold status_t 30370c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length) 30380c0fea5dSIngo Weinhold { 30390c0fea5dSIngo Weinhold int32 programSize, sectionSize; 30400c0fea5dSIngo Weinhold 30410c0fea5dSIngo Weinhold if (length < (int32)sizeof(struct Elf32_Ehdr)) 30420c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 30430c0fea5dSIngo Weinhold 30449a6072a3SAxel Dörfler return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, 30459a6072a3SAxel Dörfler §ionSize); 30460c0fea5dSIngo Weinhold } 30470c0fea5dSIngo Weinhold 30480c0fea5dSIngo Weinhold 30490c0fea5dSIngo Weinhold void 30500c0fea5dSIngo Weinhold terminate_program(void) 30510c0fea5dSIngo Weinhold { 30520c0fea5dSIngo Weinhold image_t **termList; 30530c0fea5dSIngo Weinhold ssize_t count, i; 30540c0fea5dSIngo Weinhold 30550c0fea5dSIngo Weinhold count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED); 30560c0fea5dSIngo Weinhold if (count < B_OK) 30570c0fea5dSIngo Weinhold return; 30580c0fea5dSIngo Weinhold 30599a6072a3SAxel Dörfler if (sInvalidImageIDs) { 30609a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 30619a6072a3SAxel Dörfler update_image_ids(); 30629a6072a3SAxel Dörfler } 30639a6072a3SAxel Dörfler 30640c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 30650c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 30660c0fea5dSIngo Weinhold image_t *image = termList[i]; 30670c0fea5dSIngo Weinhold 30680c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 30690c0fea5dSIngo Weinhold 307010b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 307110b4b5d1SIngo Weinhold 30720c0fea5dSIngo Weinhold if (image->term_routine) 30730c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 307410b4b5d1SIngo Weinhold 307510b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 30760c0fea5dSIngo Weinhold } 30770c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 30780c0fea5dSIngo Weinhold 30790c0fea5dSIngo Weinhold free(termList); 30800c0fea5dSIngo Weinhold } 30810c0fea5dSIngo Weinhold 30820c0fea5dSIngo Weinhold 30830c0fea5dSIngo Weinhold void 30840c0fea5dSIngo Weinhold rldelf_init(void) 30850c0fea5dSIngo Weinhold { 308610b4b5d1SIngo Weinhold // invoke static constructors 308710b4b5d1SIngo Weinhold new(&sAddOns) AddOnList; 308810b4b5d1SIngo Weinhold 3089e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 3090e73923b0SAxel Dörfler sSemOwner = -1; 3091e73923b0SAxel Dörfler sSemCount = 0; 30920c0fea5dSIngo Weinhold 30930c0fea5dSIngo Weinhold // create the debug area 30940c0fea5dSIngo Weinhold { 30950c0fea5dSIngo Weinhold int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 30960c0fea5dSIngo Weinhold 30970c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 30980c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 30990c0fea5dSIngo Weinhold (void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK, 31000c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 31010c0fea5dSIngo Weinhold if (areaID < B_OK) { 31020c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 31030c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 31040c0fea5dSIngo Weinhold } 31050c0fea5dSIngo Weinhold 31060c0fea5dSIngo Weinhold area->loaded_images = &sLoadedImages; 31070c0fea5dSIngo Weinhold } 310874c0424aSAxel Dörfler 310974c0424aSAxel Dörfler // initialize error message if needed 31104bef3723SAxel Dörfler if (report_errors()) { 311174c0424aSAxel Dörfler void *buffer = malloc(1024); 311274c0424aSAxel Dörfler if (buffer == NULL) 311374c0424aSAxel Dörfler return; 311474c0424aSAxel Dörfler 311574c0424aSAxel Dörfler sErrorMessage.SetTo(buffer, 1024, 'Rler'); 311674c0424aSAxel Dörfler } 31170c0fea5dSIngo Weinhold } 31181873b4b3SIngo Weinhold 31191873b4b3SIngo Weinhold 31201873b4b3SIngo Weinhold status_t 31219a6072a3SAxel Dörfler elf_reinit_after_fork(void) 31221873b4b3SIngo Weinhold { 3123e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 3124e73923b0SAxel Dörfler if (sSem < 0) 3125e73923b0SAxel Dörfler return sSem; 31261873b4b3SIngo Weinhold 31279a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and 3128cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork() 3129cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one 31309a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different. 31319a6072a3SAxel Dörfler sInvalidImageIDs = true; 3132cbc456deSIngo Weinhold 31331873b4b3SIngo Weinhold return B_OK; 31341873b4b3SIngo Weinhold } 3135