10c0fea5dSIngo Weinhold /* 2*593ee7bbSIngo 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> 22*593ee7bbSIngo 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 450c0fea5dSIngo Weinhold #define PAGE_MASK (B_PAGE_SIZE - 1) 460c0fea5dSIngo Weinhold 470c0fea5dSIngo Weinhold #define PAGE_OFFSET(x) ((x) & (PAGE_MASK)) 480c0fea5dSIngo Weinhold #define PAGE_BASE(x) ((x) & ~(PAGE_MASK)) 490c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK)) 500c0fea5dSIngo Weinhold 510c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000 520c0fea5dSIngo Weinhold /* keep in sync with app ldscript */ 530c0fea5dSIngo Weinhold 540c85bd05SIngo Weinhold // a handle returned by load_library() (dlopen()) 550c85bd05SIngo Weinhold #define RLD_GLOBAL_SCOPE ((void*)-2l) 560c85bd05SIngo Weinhold 570c0fea5dSIngo Weinhold enum { 580c85bd05SIngo Weinhold // the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL 590c85bd05SIngo Weinhold 600c85bd05SIngo Weinhold RFLAG_RW = 0x0010, 610c85bd05SIngo Weinhold RFLAG_ANON = 0x0020, 620c0fea5dSIngo Weinhold 630c0fea5dSIngo Weinhold RFLAG_TERMINATED = 0x0200, 640c0fea5dSIngo Weinhold RFLAG_INITIALIZED = 0x0400, 650c0fea5dSIngo Weinhold RFLAG_SYMBOLIC = 0x0800, 660c0fea5dSIngo Weinhold RFLAG_RELOCATED = 0x1000, 670c0fea5dSIngo Weinhold RFLAG_PROTECTED = 0x2000, 680c0fea5dSIngo Weinhold RFLAG_DEPENDENCIES_LOADED = 0x4000, 6946f4d849SIngo Weinhold RFLAG_REMAPPED = 0x8000, 7046f4d849SIngo Weinhold 710c85bd05SIngo Weinhold RFLAG_VISITED = 0x10000, 720c85bd05SIngo Weinhold RFLAG_USE_FOR_RESOLVING = 0x20000 7346f4d849SIngo Weinhold // temporarily set in the symbol resolution code 740c0fea5dSIngo Weinhold }; 750c0fea5dSIngo Weinhold 760c0fea5dSIngo Weinhold 770c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type) (1 << ((type) - 1)) 780c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 790c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \ 800c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \ 810c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE)) 820c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 830c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE)) 840c0fea5dSIngo Weinhold 850c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 860c0fea5dSIngo Weinhold 8710b4b5d1SIngo Weinhold 8810b4b5d1SIngo Weinhold // image events 8910b4b5d1SIngo Weinhold enum { 9010b4b5d1SIngo Weinhold IMAGE_EVENT_LOADED, 9110b4b5d1SIngo Weinhold IMAGE_EVENT_RELOCATED, 9210b4b5d1SIngo Weinhold IMAGE_EVENT_INITIALIZED, 9310b4b5d1SIngo Weinhold IMAGE_EVENT_UNINITIALIZING, 9410b4b5d1SIngo Weinhold IMAGE_EVENT_UNLOADING 9510b4b5d1SIngo Weinhold }; 9610b4b5d1SIngo Weinhold 9710b4b5d1SIngo Weinhold 9810b4b5d1SIngo Weinhold struct RuntimeLoaderAddOn 9910b4b5d1SIngo Weinhold : public DoublyLinkedListLinkImpl<RuntimeLoaderAddOn> { 10010b4b5d1SIngo Weinhold image_t* image; 10110b4b5d1SIngo Weinhold runtime_loader_add_on* addOn; 10210b4b5d1SIngo Weinhold 10310b4b5d1SIngo Weinhold RuntimeLoaderAddOn(image_t* image, runtime_loader_add_on* addOn) 10410b4b5d1SIngo Weinhold : 10510b4b5d1SIngo Weinhold image(image), 10610b4b5d1SIngo Weinhold addOn(addOn) 10710b4b5d1SIngo Weinhold { 10810b4b5d1SIngo Weinhold } 10910b4b5d1SIngo Weinhold }; 11010b4b5d1SIngo Weinhold 11110b4b5d1SIngo Weinhold typedef DoublyLinkedList<RuntimeLoaderAddOn> AddOnList; 11210b4b5d1SIngo Weinhold 11310b4b5d1SIngo Weinhold struct RuntimeLoaderSymbolPatcher { 11410b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* next; 11510b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* patcher; 11610b4b5d1SIngo Weinhold void* cookie; 11710b4b5d1SIngo Weinhold 11810b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher(runtime_loader_symbol_patcher* patcher, 11910b4b5d1SIngo Weinhold void* cookie) 12010b4b5d1SIngo Weinhold : 12110b4b5d1SIngo Weinhold patcher(patcher), 12210b4b5d1SIngo Weinhold cookie(cookie) 12310b4b5d1SIngo Weinhold { 12410b4b5d1SIngo Weinhold } 12510b4b5d1SIngo Weinhold }; 12610b4b5d1SIngo Weinhold 12710b4b5d1SIngo Weinhold 1280c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0}; 1290c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0}; 1300c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0; 1310c0fea5dSIngo Weinhold static image_t *sProgramImage; 13274c0424aSAxel Dörfler static KMessage sErrorMessage; 1335d0638bfSIngo Weinhold static bool sProgramLoaded = false; 13461b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL; 1359a6072a3SAxel Dörfler static bool sInvalidImageIDs; 136ca618b22SIngo Weinhold static image_t **sPreloadedImages = NULL; 137ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0; 13810b4b5d1SIngo Weinhold static AddOnList sAddOns; 1390c0fea5dSIngo Weinhold 1400c0fea5dSIngo Weinhold // a recursive lock 141e73923b0SAxel Dörfler static sem_id sSem; 142e73923b0SAxel Dörfler static thread_id sSemOwner; 143e73923b0SAxel Dörfler static int32 sSemCount; 1440c0fea5dSIngo Weinhold 14510b4b5d1SIngo Weinhold extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport; 14610b4b5d1SIngo Weinhold 1470c0fea5dSIngo Weinhold 148*593ee7bbSIngo Weinhold static struct Elf32_Sym* find_symbol(image_t* image, const char* name, 149*593ee7bbSIngo Weinhold int32 type); 150*593ee7bbSIngo Weinhold 151*593ee7bbSIngo Weinhold 1520c0fea5dSIngo Weinhold void 1530c0fea5dSIngo Weinhold dprintf(const char *format, ...) 1540c0fea5dSIngo Weinhold { 1550c0fea5dSIngo Weinhold char buffer[1024]; 1560c0fea5dSIngo Weinhold 1570c0fea5dSIngo Weinhold va_list list; 1580c0fea5dSIngo Weinhold va_start(list, format); 1590c0fea5dSIngo Weinhold 1600c0fea5dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 1610c0fea5dSIngo Weinhold _kern_debug_output(buffer); 1620c0fea5dSIngo Weinhold 1630c0fea5dSIngo Weinhold va_end(list); 1640c0fea5dSIngo Weinhold } 1655d0638bfSIngo Weinhold 1665d0638bfSIngo Weinhold #define FATAL(x...) \ 1675d0638bfSIngo Weinhold do { \ 1685d0638bfSIngo Weinhold dprintf("runtime_loader: " x); \ 1695d0638bfSIngo Weinhold if (!sProgramLoaded) \ 1705d0638bfSIngo Weinhold printf("runtime_loader: " x); \ 1715d0638bfSIngo Weinhold } while (false) 1720c0fea5dSIngo Weinhold 1730c0fea5dSIngo Weinhold 17434982809SIngo Weinhold /*! Mini atoi(), so we don't have to include the libroot dependencies. 17534982809SIngo Weinhold */ 17634982809SIngo Weinhold int 17734982809SIngo Weinhold atoi(const char* num) 17834982809SIngo Weinhold { 17934982809SIngo Weinhold int result = 0; 18034982809SIngo Weinhold while (*num >= '0' && *num <= '9') { 18134982809SIngo Weinhold result = (result * 10) + (*num - '0'); 18234982809SIngo Weinhold num++; 18334982809SIngo Weinhold } 18434982809SIngo Weinhold 18534982809SIngo Weinhold return result; 18634982809SIngo Weinhold } 18734982809SIngo Weinhold 18834982809SIngo Weinhold 1896bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING 1907486b72dSIngo Weinhold 1917486b72dSIngo Weinhold void 1927486b72dSIngo Weinhold ktrace_printf(const char *format, ...) 1937486b72dSIngo Weinhold { 1947486b72dSIngo Weinhold va_list list; 1957486b72dSIngo Weinhold va_start(list, format); 1967486b72dSIngo Weinhold 1977486b72dSIngo Weinhold char buffer[1024]; 1987486b72dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 1997486b72dSIngo Weinhold _kern_ktrace_output(buffer); 2007486b72dSIngo Weinhold 2017486b72dSIngo Weinhold va_end(list); 2027486b72dSIngo Weinhold } 2037486b72dSIngo Weinhold 2047486b72dSIngo Weinhold #define KTRACE(x...) ktrace_printf(x) 2057486b72dSIngo Weinhold 2067486b72dSIngo Weinhold #else 2077486b72dSIngo Weinhold # define KTRACE(x...) 2087486b72dSIngo Weinhold #endif // RUNTIME_LOADER_TRACING 2097486b72dSIngo Weinhold 2107486b72dSIngo Weinhold 2110c0fea5dSIngo Weinhold static void 2120c0fea5dSIngo Weinhold rld_unlock() 2130c0fea5dSIngo Weinhold { 214e73923b0SAxel Dörfler if (sSemCount-- == 1) { 215e73923b0SAxel Dörfler sSemOwner = -1; 216e73923b0SAxel Dörfler release_sem(sSem); 2170c0fea5dSIngo Weinhold } 2180c0fea5dSIngo Weinhold } 2190c0fea5dSIngo Weinhold 2200c0fea5dSIngo Weinhold 2210c0fea5dSIngo Weinhold static void 2220c0fea5dSIngo Weinhold rld_lock() 2230c0fea5dSIngo Weinhold { 2240c0fea5dSIngo Weinhold thread_id self = find_thread(NULL); 225e73923b0SAxel Dörfler if (self != sSemOwner) { 226e73923b0SAxel Dörfler acquire_sem(sSem); 227e73923b0SAxel Dörfler sSemOwner = self; 2280c0fea5dSIngo Weinhold } 229e73923b0SAxel Dörfler sSemCount++; 2300c0fea5dSIngo Weinhold } 2310c0fea5dSIngo Weinhold 2320c0fea5dSIngo Weinhold 2330c0fea5dSIngo Weinhold static void 2340c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image) 2350c0fea5dSIngo Weinhold { 2360c0fea5dSIngo Weinhold image->next = 0; 2370c0fea5dSIngo Weinhold 2380c0fea5dSIngo Weinhold image->prev = queue->tail; 2390c0fea5dSIngo Weinhold if (queue->tail) 2400c0fea5dSIngo Weinhold queue->tail->next = image; 2410c0fea5dSIngo Weinhold 2420c0fea5dSIngo Weinhold queue->tail = image; 2430c0fea5dSIngo Weinhold if (!queue->head) 2440c0fea5dSIngo Weinhold queue->head = image; 2450c0fea5dSIngo Weinhold } 2460c0fea5dSIngo Weinhold 2470c0fea5dSIngo Weinhold 2480c0fea5dSIngo Weinhold static void 2490c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image) 2500c0fea5dSIngo Weinhold { 2510c0fea5dSIngo Weinhold if (image->next) 2520c0fea5dSIngo Weinhold image->next->prev = image->prev; 2530c0fea5dSIngo Weinhold else 2540c0fea5dSIngo Weinhold queue->tail = image->prev; 2550c0fea5dSIngo Weinhold 2560c0fea5dSIngo Weinhold if (image->prev) 2570c0fea5dSIngo Weinhold image->prev->next = image->next; 2580c0fea5dSIngo Weinhold else 2590c0fea5dSIngo Weinhold queue->head = image->next; 2600c0fea5dSIngo Weinhold 2610c0fea5dSIngo Weinhold image->prev = 0; 2620c0fea5dSIngo Weinhold image->next = 0; 2630c0fea5dSIngo Weinhold } 2640c0fea5dSIngo Weinhold 2650c0fea5dSIngo Weinhold 2660c0fea5dSIngo Weinhold static uint32 2670c0fea5dSIngo Weinhold elf_hash(const uint8 *name) 2680c0fea5dSIngo Weinhold { 2690c0fea5dSIngo Weinhold uint32 hash = 0; 2700c0fea5dSIngo Weinhold uint32 temp; 2710c0fea5dSIngo Weinhold 2720c0fea5dSIngo Weinhold while (*name) { 2730c0fea5dSIngo Weinhold hash = (hash << 4) + *name++; 2740c0fea5dSIngo Weinhold if ((temp = hash & 0xf0000000)) { 2750c0fea5dSIngo Weinhold hash ^= temp >> 24; 2760c0fea5dSIngo Weinhold } 2770c0fea5dSIngo Weinhold hash &= ~temp; 2780c0fea5dSIngo Weinhold } 2790c0fea5dSIngo Weinhold return hash; 2800c0fea5dSIngo Weinhold } 2810c0fea5dSIngo Weinhold 2820c0fea5dSIngo Weinhold 2834bef3723SAxel Dörfler static inline bool 2844bef3723SAxel Dörfler report_errors() 2854bef3723SAxel Dörfler { 2864bef3723SAxel Dörfler return gProgramArgs->error_port >= 0; 2874bef3723SAxel Dörfler } 2884bef3723SAxel Dörfler 2894bef3723SAxel Dörfler 2909a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork. 2919a6072a3SAxel Dörfler static status_t 2929a6072a3SAxel Dörfler update_image_id(image_t *image) 2939a6072a3SAxel Dörfler { 2949a6072a3SAxel Dörfler int32 cookie = 0; 2959a6072a3SAxel Dörfler image_info info; 2969a6072a3SAxel Dörfler while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info, 2979a6072a3SAxel Dörfler sizeof(image_info)) == B_OK) { 2989a6072a3SAxel Dörfler for (uint32 i = 0; i < image->num_regions; i++) { 2999a6072a3SAxel Dörfler if (image->regions[i].vmstart == (addr_t)info.text) { 3009a6072a3SAxel Dörfler image->id = info.id; 3019a6072a3SAxel Dörfler return B_OK; 3029a6072a3SAxel Dörfler } 3039a6072a3SAxel Dörfler } 3049a6072a3SAxel Dörfler } 3059a6072a3SAxel Dörfler 3069a6072a3SAxel Dörfler FATAL("Could not update image ID %ld after fork()!\n", image->id); 3079a6072a3SAxel Dörfler return B_ENTRY_NOT_FOUND; 3089a6072a3SAxel Dörfler } 3099a6072a3SAxel Dörfler 3109a6072a3SAxel Dörfler 3119a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images. 3129a6072a3SAxel Dörfler static status_t 3139a6072a3SAxel Dörfler update_image_ids(void) 3149a6072a3SAxel Dörfler { 3159a6072a3SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 3169a6072a3SAxel Dörfler status_t status = update_image_id(image); 3179a6072a3SAxel Dörfler if (status != B_OK) 3189a6072a3SAxel Dörfler return status; 3199a6072a3SAxel Dörfler } 3209a6072a3SAxel Dörfler for (image_t *image = sDisposableImages.head; image; image = image->next) { 3219a6072a3SAxel Dörfler status_t status = update_image_id(image); 3229a6072a3SAxel Dörfler if (status != B_OK) 3239a6072a3SAxel Dörfler return status; 3249a6072a3SAxel Dörfler } 3259a6072a3SAxel Dörfler 3269a6072a3SAxel Dörfler sInvalidImageIDs = false; 3279a6072a3SAxel Dörfler return B_OK; 3289a6072a3SAxel Dörfler } 3299a6072a3SAxel Dörfler 3309a6072a3SAxel Dörfler 3310c0fea5dSIngo Weinhold static image_t * 3320c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath, 3330c0fea5dSIngo Weinhold uint32 typeMask) 3340c0fea5dSIngo Weinhold { 3359a6072a3SAxel Dörfler for (image_t *image = queue->head; image; image = image->next) { 3360c0fea5dSIngo Weinhold const char *imageName = isPath ? image->path : image->name; 3370c0fea5dSIngo Weinhold int length = isPath ? sizeof(image->path) : sizeof(image->name); 3380c0fea5dSIngo Weinhold 3390c0fea5dSIngo Weinhold if (!strncmp(imageName, name, length) 3400c0fea5dSIngo Weinhold && (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) { 3410c0fea5dSIngo Weinhold return image; 3420c0fea5dSIngo Weinhold } 3430c0fea5dSIngo Weinhold } 3440c0fea5dSIngo Weinhold 3450c0fea5dSIngo Weinhold return NULL; 3460c0fea5dSIngo Weinhold } 3470c0fea5dSIngo Weinhold 3480c0fea5dSIngo Weinhold 3490c0fea5dSIngo Weinhold static image_t * 3500c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask) 3510c0fea5dSIngo Weinhold { 3529a6072a3SAxel Dörfler bool isPath = strchr(name, '/') != NULL; 35346f4d849SIngo Weinhold return find_image_in_queue(&sLoadedImages, name, isPath, typeMask); 3540c0fea5dSIngo Weinhold } 3550c0fea5dSIngo Weinhold 3560c0fea5dSIngo Weinhold 3570c0fea5dSIngo Weinhold static image_t * 3580c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id) 3590c0fea5dSIngo Weinhold { 3609a6072a3SAxel Dörfler if (sInvalidImageIDs) { 3619a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 3629a6072a3SAxel Dörfler update_image_ids(); 3639a6072a3SAxel Dörfler } 3640c0fea5dSIngo Weinhold 3659a6072a3SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 3660c0fea5dSIngo Weinhold if (image->id == id) 3670c0fea5dSIngo Weinhold return image; 3680c0fea5dSIngo Weinhold } 3690c0fea5dSIngo Weinhold 3700c0fea5dSIngo Weinhold // For the termination routine, we need to look into the list of 3710c0fea5dSIngo Weinhold // disposable images as well 3729a6072a3SAxel Dörfler for (image_t *image = sDisposableImages.head; image; image = image->next) { 3730c0fea5dSIngo Weinhold if (image->id == id) 3740c0fea5dSIngo Weinhold return image; 3750c0fea5dSIngo Weinhold } 3760c0fea5dSIngo Weinhold 3770c0fea5dSIngo Weinhold return NULL; 3780c0fea5dSIngo Weinhold } 3790c0fea5dSIngo Weinhold 3800c0fea5dSIngo Weinhold 3815fd6637bSIngo Weinhold static image_t* 3825fd6637bSIngo Weinhold get_program_image() 38312a5e9a4SAxel Dörfler { 38412a5e9a4SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 38512a5e9a4SAxel Dörfler if (image->type == B_APP_IMAGE) 3865fd6637bSIngo Weinhold return image; 38712a5e9a4SAxel Dörfler } 38812a5e9a4SAxel Dörfler 38912a5e9a4SAxel Dörfler return NULL; 39012a5e9a4SAxel Dörfler } 39112a5e9a4SAxel Dörfler 39212a5e9a4SAxel Dörfler 3935fd6637bSIngo Weinhold static const char * 3945fd6637bSIngo Weinhold get_program_path() 3955fd6637bSIngo Weinhold { 3965fd6637bSIngo Weinhold if (image_t* image = get_program_image()) 3975fd6637bSIngo Weinhold return image->path; 3985fd6637bSIngo Weinhold 3995fd6637bSIngo Weinhold return NULL; 4005fd6637bSIngo Weinhold } 4015fd6637bSIngo Weinhold 4025fd6637bSIngo Weinhold 4030c0fea5dSIngo Weinhold static status_t 40412a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize, 40512a5e9a4SAxel Dörfler int32 *_sheaderSize) 4060c0fea5dSIngo Weinhold { 4070c0fea5dSIngo Weinhold if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) 4080c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4090c0fea5dSIngo Weinhold 4100c0fea5dSIngo Weinhold if (eheader->e_ident[4] != ELFCLASS32) 4110c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4120c0fea5dSIngo Weinhold 4130c0fea5dSIngo Weinhold if (eheader->e_phoff == 0) 4140c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4150c0fea5dSIngo Weinhold 4160c0fea5dSIngo Weinhold if (eheader->e_phentsize < sizeof(struct Elf32_Phdr)) 4170c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4180c0fea5dSIngo Weinhold 4190c0fea5dSIngo Weinhold *_pheaderSize = eheader->e_phentsize * eheader->e_phnum; 4200c0fea5dSIngo Weinhold *_sheaderSize = eheader->e_shentsize * eheader->e_shnum; 4210c0fea5dSIngo Weinhold 4225aa7b7b6SMarcus Overhagen if (*_pheaderSize <= 0 || *_sheaderSize <= 0) 4235aa7b7b6SMarcus Overhagen return B_NOT_AN_EXECUTABLE; 4245aa7b7b6SMarcus Overhagen 4255aa7b7b6SMarcus Overhagen return B_OK; 4260c0fea5dSIngo Weinhold } 4270c0fea5dSIngo Weinhold 4280c0fea5dSIngo Weinhold 4290c0fea5dSIngo Weinhold static int32 4300c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize) 4310c0fea5dSIngo Weinhold { 4320c0fea5dSIngo Weinhold struct Elf32_Phdr *pheaders; 4330c0fea5dSIngo Weinhold int32 count = 0; 4340c0fea5dSIngo Weinhold int i; 4350c0fea5dSIngo Weinhold 4360c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 4370c0fea5dSIngo Weinhold pheaders = (struct Elf32_Phdr *)(buff + i * phentsize); 4380c0fea5dSIngo Weinhold 4390c0fea5dSIngo Weinhold switch (pheaders->p_type) { 4400c0fea5dSIngo Weinhold case PT_NULL: 4410c0fea5dSIngo Weinhold /* NOP header */ 4420c0fea5dSIngo Weinhold break; 4430c0fea5dSIngo Weinhold case PT_LOAD: 4440c0fea5dSIngo Weinhold count += 1; 4450c0fea5dSIngo Weinhold if (pheaders->p_memsz != pheaders->p_filesz) { 4460c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz); 4470c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz); 4480c0fea5dSIngo Weinhold 4490c0fea5dSIngo Weinhold if (A != B) 4500c0fea5dSIngo Weinhold count += 1; 4510c0fea5dSIngo Weinhold } 4520c0fea5dSIngo Weinhold break; 4530c0fea5dSIngo Weinhold case PT_DYNAMIC: 4540c0fea5dSIngo Weinhold /* will be handled at some other place */ 4550c0fea5dSIngo Weinhold break; 4560c0fea5dSIngo Weinhold case PT_INTERP: 4570c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 4580c0fea5dSIngo Weinhold break; 4590c0fea5dSIngo Weinhold case PT_NOTE: 4600c0fea5dSIngo Weinhold /* unsupported */ 4610c0fea5dSIngo Weinhold break; 4620c0fea5dSIngo Weinhold case PT_SHLIB: 4630c0fea5dSIngo Weinhold /* undefined semantics */ 4640c0fea5dSIngo Weinhold break; 4650c0fea5dSIngo Weinhold case PT_PHDR: 4660c0fea5dSIngo Weinhold /* we don't use it */ 4670c0fea5dSIngo Weinhold break; 4682ecebae1SDavid McPaul case PT_STACK: 4692ecebae1SDavid McPaul /* we don't use it */ 4702ecebae1SDavid McPaul break; 4710c0fea5dSIngo Weinhold default: 4722ecebae1SDavid McPaul FATAL("unhandled pheader type in count 0x%lx\n", pheaders->p_type); 4730c0fea5dSIngo Weinhold return B_BAD_DATA; 4740c0fea5dSIngo Weinhold } 4750c0fea5dSIngo Weinhold } 4760c0fea5dSIngo Weinhold 4770c0fea5dSIngo Weinhold return count; 4780c0fea5dSIngo Weinhold } 4790c0fea5dSIngo Weinhold 4800c0fea5dSIngo Weinhold 4810c0fea5dSIngo Weinhold static image_t * 4820c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions) 4830c0fea5dSIngo Weinhold { 4840c0fea5dSIngo Weinhold size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t); 4850c0fea5dSIngo Weinhold const char *lastSlash; 4860c0fea5dSIngo Weinhold 4870c0fea5dSIngo Weinhold image_t *image = (image_t*)malloc(allocSize); 4880c0fea5dSIngo Weinhold if (image == NULL) { 4890c0fea5dSIngo Weinhold FATAL("no memory for image %s\n", path); 4900c0fea5dSIngo Weinhold return NULL; 4910c0fea5dSIngo Weinhold } 4920c0fea5dSIngo Weinhold 4930c0fea5dSIngo Weinhold memset(image, 0, allocSize); 4940c0fea5dSIngo Weinhold 4950c0fea5dSIngo Weinhold strlcpy(image->path, path, sizeof(image->path)); 4960c0fea5dSIngo Weinhold 4970c0fea5dSIngo Weinhold // Make the last component of the supplied name the image name. 4980c0fea5dSIngo Weinhold // If present, DT_SONAME will replace this name. 4990c0fea5dSIngo Weinhold if ((lastSlash = strrchr(name, '/'))) 5000c0fea5dSIngo Weinhold strlcpy(image->name, lastSlash + 1, sizeof(image->name)); 5010c0fea5dSIngo Weinhold else 5020c0fea5dSIngo Weinhold strlcpy(image->name, name, sizeof(image->name)); 5030c0fea5dSIngo Weinhold 5040c0fea5dSIngo Weinhold image->ref_count = 1; 5050c0fea5dSIngo Weinhold image->num_regions = num_regions; 5060c0fea5dSIngo Weinhold 5070c0fea5dSIngo Weinhold return image; 5080c0fea5dSIngo Weinhold } 5090c0fea5dSIngo Weinhold 5100c0fea5dSIngo Weinhold 5110c0fea5dSIngo Weinhold static void 5120c0fea5dSIngo Weinhold delete_image_struct(image_t *image) 5130c0fea5dSIngo Weinhold { 5140c0fea5dSIngo Weinhold #ifdef DEBUG 5150c0fea5dSIngo Weinhold size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t); 5160c0fea5dSIngo Weinhold memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed); 5170c0fea5dSIngo Weinhold #endif 5180c0fea5dSIngo Weinhold free(image->needed); 51910b4b5d1SIngo Weinhold 52010b4b5d1SIngo Weinhold while (RuntimeLoaderSymbolPatcher* patcher 52110b4b5d1SIngo Weinhold = image->defined_symbol_patchers) { 52210b4b5d1SIngo Weinhold image->defined_symbol_patchers = patcher->next; 52310b4b5d1SIngo Weinhold delete patcher; 52410b4b5d1SIngo Weinhold } 52510b4b5d1SIngo Weinhold while (RuntimeLoaderSymbolPatcher* patcher 52610b4b5d1SIngo Weinhold = image->undefined_symbol_patchers) { 52710b4b5d1SIngo Weinhold image->undefined_symbol_patchers = patcher->next; 52810b4b5d1SIngo Weinhold delete patcher; 52910b4b5d1SIngo Weinhold } 5300c0fea5dSIngo Weinhold 5310c0fea5dSIngo Weinhold #ifdef DEBUG 5329a6072a3SAxel Dörfler // overwrite images to make sure they aren't accidently reused anywhere 5330c0fea5dSIngo Weinhold memset(image, 0xa5, size); 5340c0fea5dSIngo Weinhold #endif 5350c0fea5dSIngo Weinhold free(image); 5360c0fea5dSIngo Weinhold } 5370c0fea5dSIngo Weinhold 5380c0fea5dSIngo Weinhold 5390c0fea5dSIngo Weinhold static void 5400c0fea5dSIngo Weinhold delete_image(image_t *image) 5410c0fea5dSIngo Weinhold { 5422760c4cdSAxel Dörfler if (image == NULL) 5432760c4cdSAxel Dörfler return; 5442760c4cdSAxel Dörfler 5450c0fea5dSIngo Weinhold _kern_unregister_image(image->id); 5460c0fea5dSIngo Weinhold // registered in load_container() 5470c0fea5dSIngo Weinhold 5480c0fea5dSIngo Weinhold delete_image_struct(image); 5490c0fea5dSIngo Weinhold } 5500c0fea5dSIngo Weinhold 5510c0fea5dSIngo Weinhold 5520c85bd05SIngo Weinhold static void 5530c85bd05SIngo Weinhold update_image_flags_recursively(image_t* image, uint32 flagsToSet, 5540c85bd05SIngo Weinhold uint32 flagsToClear) 5550c85bd05SIngo Weinhold { 5560c85bd05SIngo Weinhold image_t* queue[sLoadedImageCount]; 5570c85bd05SIngo Weinhold uint32 count = 0; 5580c85bd05SIngo Weinhold uint32 index = 0; 5590c85bd05SIngo Weinhold queue[count++] = image; 5600c85bd05SIngo Weinhold image->flags |= RFLAG_VISITED; 5610c85bd05SIngo Weinhold 5620c85bd05SIngo Weinhold while (index < count) { 5630c85bd05SIngo Weinhold // pop next image 5640c85bd05SIngo Weinhold image = queue[index++]; 5650c85bd05SIngo Weinhold 5660c85bd05SIngo Weinhold // push dependencies 5670c85bd05SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 5680c85bd05SIngo Weinhold image_t* needed = image->needed[i]; 5690c85bd05SIngo Weinhold if ((needed->flags & RFLAG_VISITED) == 0) { 5700c85bd05SIngo Weinhold queue[count++] = needed; 5710c85bd05SIngo Weinhold needed->flags |= RFLAG_VISITED; 5720c85bd05SIngo Weinhold } 5730c85bd05SIngo Weinhold } 5740c85bd05SIngo Weinhold } 5750c85bd05SIngo Weinhold 5760c85bd05SIngo Weinhold // update flags 5770c85bd05SIngo Weinhold for (uint32 i = 0; i < count; i++) { 5780c85bd05SIngo Weinhold queue[i]->flags = (queue[i]->flags | flagsToSet) 5790c85bd05SIngo Weinhold & ~(flagsToClear | RFLAG_VISITED); 5800c85bd05SIngo Weinhold } 5810c85bd05SIngo Weinhold } 5820c85bd05SIngo Weinhold 5830c85bd05SIngo Weinhold 5840c85bd05SIngo Weinhold static void 5850c85bd05SIngo Weinhold set_image_flags_recursively(image_t* image, uint32 flags) 5860c85bd05SIngo Weinhold { 5870c85bd05SIngo Weinhold update_image_flags_recursively(image, flags, 0); 5880c85bd05SIngo Weinhold } 5890c85bd05SIngo Weinhold 5900c85bd05SIngo Weinhold 5910c85bd05SIngo Weinhold static void 5920c85bd05SIngo Weinhold clear_image_flags_recursively(image_t* image, uint32 flags) 5930c85bd05SIngo Weinhold { 5940c85bd05SIngo Weinhold update_image_flags_recursively(image, 0, flags); 5950c85bd05SIngo Weinhold } 5960c85bd05SIngo Weinhold 5970c85bd05SIngo Weinhold 5980c0fea5dSIngo Weinhold static status_t 5990c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) 6000c0fea5dSIngo Weinhold { 6010c0fea5dSIngo Weinhold struct Elf32_Phdr *pheader; 6020c0fea5dSIngo Weinhold int regcount; 6030c0fea5dSIngo Weinhold int i; 6040c0fea5dSIngo Weinhold 6050c0fea5dSIngo Weinhold regcount = 0; 6060c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 6070c0fea5dSIngo Weinhold pheader = (struct Elf32_Phdr *)(buff + i * phentsize); 6080c0fea5dSIngo Weinhold 6090c0fea5dSIngo Weinhold switch (pheader->p_type) { 6100c0fea5dSIngo Weinhold case PT_NULL: 6110c0fea5dSIngo Weinhold /* NOP header */ 6120c0fea5dSIngo Weinhold break; 6130c0fea5dSIngo Weinhold case PT_LOAD: 6140c0fea5dSIngo Weinhold if (pheader->p_memsz == pheader->p_filesz) { 6150c0fea5dSIngo Weinhold /* 6160c0fea5dSIngo Weinhold * everything in one area 6170c0fea5dSIngo Weinhold */ 6180c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 6190c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz; 6200c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 6210c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz 6220c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 6230c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 6240c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 6250c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 6260c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 6270c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 6280c0fea5dSIngo Weinhold // this is a writable segment 6290c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 6300c0fea5dSIngo Weinhold } 6310c0fea5dSIngo Weinhold } else { 6320c0fea5dSIngo Weinhold /* 6330c0fea5dSIngo Weinhold * may require splitting 6340c0fea5dSIngo Weinhold */ 6350c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz); 6360c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz); 6370c0fea5dSIngo Weinhold 6380c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 6390c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_filesz; 6400c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 6410c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz 6420c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 6430c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 6440c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 6450c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 6460c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 6470c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 6480c0fea5dSIngo Weinhold // this is a writable segment 6490c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 6500c0fea5dSIngo Weinhold } 6510c0fea5dSIngo Weinhold 6520c0fea5dSIngo Weinhold if (A != B) { 6530c0fea5dSIngo Weinhold /* 6540c0fea5dSIngo Weinhold * yeah, it requires splitting 6550c0fea5dSIngo Weinhold */ 6560c0fea5dSIngo Weinhold regcount += 1; 6570c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 6580c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz; 6590c0fea5dSIngo Weinhold image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize; 6600c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr)) 6610c0fea5dSIngo Weinhold - image->regions[regcount-1].vmsize; 6620c0fea5dSIngo Weinhold image->regions[regcount].fdstart = 0; 6630c0fea5dSIngo Weinhold image->regions[regcount].fdsize = 0; 6640c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 6650c0fea5dSIngo Weinhold image->regions[regcount].flags = RFLAG_ANON; 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 } 6710c0fea5dSIngo Weinhold } 6720c0fea5dSIngo Weinhold regcount += 1; 6730c0fea5dSIngo Weinhold break; 6740c0fea5dSIngo Weinhold case PT_DYNAMIC: 6750c0fea5dSIngo Weinhold image->dynamic_ptr = pheader->p_vaddr; 6760c0fea5dSIngo Weinhold break; 6770c0fea5dSIngo Weinhold case PT_INTERP: 6780c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 6790c0fea5dSIngo Weinhold break; 6800c0fea5dSIngo Weinhold case PT_NOTE: 6810c0fea5dSIngo Weinhold /* unsupported */ 6820c0fea5dSIngo Weinhold break; 6830c0fea5dSIngo Weinhold case PT_SHLIB: 6840c0fea5dSIngo Weinhold /* undefined semantics */ 6850c0fea5dSIngo Weinhold break; 6860c0fea5dSIngo Weinhold case PT_PHDR: 6870c0fea5dSIngo Weinhold /* we don't use it */ 6880c0fea5dSIngo Weinhold break; 6892ecebae1SDavid McPaul case PT_STACK: 6902ecebae1SDavid McPaul /* we don't use it */ 6912ecebae1SDavid McPaul break; 6920c0fea5dSIngo Weinhold default: 6932ecebae1SDavid McPaul FATAL("unhandled pheader type in parse 0x%lx\n", pheader->p_type); 6940c0fea5dSIngo Weinhold return B_BAD_DATA; 6950c0fea5dSIngo Weinhold } 6960c0fea5dSIngo Weinhold } 6970c0fea5dSIngo Weinhold 6980c0fea5dSIngo Weinhold return B_OK; 6990c0fea5dSIngo Weinhold } 7000c0fea5dSIngo Weinhold 7010c0fea5dSIngo Weinhold 702*593ee7bbSIngo Weinhold static void 703*593ee7bbSIngo Weinhold analyze_image_haiku_version_and_abi(image_t* image) 704*593ee7bbSIngo Weinhold { 705*593ee7bbSIngo Weinhold // Haiku API version 706*593ee7bbSIngo Weinhold struct Elf32_Sym* symbol = find_symbol(image, 707*593ee7bbSIngo Weinhold B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME, B_SYMBOL_TYPE_DATA); 708*593ee7bbSIngo Weinhold if (symbol != NULL && symbol->st_shndx != SHN_UNDEF 709*593ee7bbSIngo Weinhold && symbol->st_value > 0 710*593ee7bbSIngo Weinhold && ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT 711*593ee7bbSIngo Weinhold && symbol->st_size >= sizeof(uint32)) { 712*593ee7bbSIngo Weinhold image->api_version 713*593ee7bbSIngo Weinhold = *(uint32*)(symbol->st_value + image->regions[0].delta); 714*593ee7bbSIngo Weinhold } else 715*593ee7bbSIngo Weinhold image->api_version = 0; 716*593ee7bbSIngo Weinhold 717*593ee7bbSIngo Weinhold // Haiku ABI 718*593ee7bbSIngo Weinhold symbol = find_symbol(image, B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME, 719*593ee7bbSIngo Weinhold B_SYMBOL_TYPE_DATA); 720*593ee7bbSIngo Weinhold if (symbol != NULL && symbol->st_shndx != SHN_UNDEF 721*593ee7bbSIngo Weinhold && symbol->st_value > 0 722*593ee7bbSIngo Weinhold && ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT 723*593ee7bbSIngo Weinhold && symbol->st_size >= sizeof(uint32)) { 724*593ee7bbSIngo Weinhold image->abi = *(uint32*)(symbol->st_value + image->regions[0].delta); 725*593ee7bbSIngo Weinhold } else 726*593ee7bbSIngo Weinhold image->abi = 0; 727*593ee7bbSIngo Weinhold } 728*593ee7bbSIngo Weinhold 729*593ee7bbSIngo Weinhold 7300c0fea5dSIngo Weinhold static bool 73134982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader, 73234982809SIngo Weinhold int32 sheaderSize, char* buffer, size_t bufferSize) 73334982809SIngo Weinhold { 73434982809SIngo Weinhold image->gcc_version.major = 0; 73534982809SIngo Weinhold image->gcc_version.middle = 0; 73634982809SIngo Weinhold image->gcc_version.minor = 0; 73734982809SIngo Weinhold 73834982809SIngo Weinhold if (sheaderSize > (int)bufferSize) { 73934982809SIngo Weinhold FATAL("Cannot handle section headers bigger than %lu\n", bufferSize); 74034982809SIngo Weinhold return false; 74134982809SIngo Weinhold } 74234982809SIngo Weinhold 74334982809SIngo Weinhold // read section headers 74434982809SIngo Weinhold ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize); 74534982809SIngo Weinhold if (length != sheaderSize) { 74634982809SIngo Weinhold FATAL("Could not read section headers: %s\n", strerror(length)); 74734982809SIngo Weinhold return false; 74834982809SIngo Weinhold } 74934982809SIngo Weinhold 75034982809SIngo Weinhold // load the string section 75134982809SIngo Weinhold Elf32_Shdr* sectionHeader 75234982809SIngo Weinhold = (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize); 75334982809SIngo Weinhold 75434982809SIngo Weinhold if (sheaderSize + sectionHeader->sh_size > bufferSize) { 75534982809SIngo Weinhold FATAL("Buffer not big enough for section string section\n"); 75634982809SIngo Weinhold return false; 75734982809SIngo Weinhold } 75834982809SIngo Weinhold 75934982809SIngo Weinhold char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size; 76034982809SIngo Weinhold length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings, 76134982809SIngo Weinhold sectionHeader->sh_size); 76234982809SIngo Weinhold if (length != (int)sectionHeader->sh_size) { 76334982809SIngo Weinhold FATAL("Could not read section string section: %s\n", strerror(length)); 76434982809SIngo Weinhold return false; 76534982809SIngo Weinhold } 76634982809SIngo Weinhold 76734982809SIngo Weinhold // find the .comment section 76834982809SIngo Weinhold off_t commentOffset = 0; 76934982809SIngo Weinhold size_t commentSize = 0; 77034982809SIngo Weinhold for (uint32 i = 0; i < eheader.e_shnum; i++) { 77134982809SIngo Weinhold sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize); 77234982809SIngo Weinhold const char* sectionName = sectionStrings + sectionHeader->sh_name; 77334982809SIngo Weinhold if (sectionHeader->sh_name != 0 77434982809SIngo Weinhold && strcmp(sectionName, ".comment") == 0) { 77534982809SIngo Weinhold commentOffset = sectionHeader->sh_offset; 77634982809SIngo Weinhold commentSize = sectionHeader->sh_size; 77734982809SIngo Weinhold break; 77834982809SIngo Weinhold } 77934982809SIngo Weinhold } 78034982809SIngo Weinhold 78134982809SIngo Weinhold if (commentSize == 0) { 78234982809SIngo Weinhold FATAL("Could not find .comment section\n"); 78334982809SIngo Weinhold return false; 78434982809SIngo Weinhold } 78534982809SIngo Weinhold 78634982809SIngo Weinhold // read a part of the comment section 78734982809SIngo Weinhold if (commentSize > 512) 78834982809SIngo Weinhold commentSize = 512; 78934982809SIngo Weinhold 79034982809SIngo Weinhold length = _kern_read(fd, commentOffset, buffer, commentSize); 79134982809SIngo Weinhold if (length != (int)commentSize) { 79234982809SIngo Weinhold FATAL("Could not read .comment section: %s\n", strerror(length)); 79334982809SIngo Weinhold return false; 79434982809SIngo Weinhold } 79534982809SIngo Weinhold 79634982809SIngo Weinhold // the common prefix of the strings in the .comment section 79734982809SIngo Weinhold static const char* kGCCVersionPrefix = "GCC: (GNU) "; 79834982809SIngo Weinhold size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix); 79934982809SIngo Weinhold 80034982809SIngo Weinhold size_t index = 0; 80134982809SIngo Weinhold int gccMajor = 0; 80234982809SIngo Weinhold int gccMiddle = 0; 80334982809SIngo Weinhold int gccMinor = 0; 8042716cfd3SAxel Dörfler bool isHaiku = true; 80534982809SIngo Weinhold 80634982809SIngo Weinhold // Read up to 10 comments. The first three or four are usually from the 80734982809SIngo Weinhold // glue code. 80834982809SIngo Weinhold for (int i = 0; i < 10; i++) { 80934982809SIngo Weinhold // skip '\0' 81034982809SIngo Weinhold while (index < commentSize && buffer[index] == '\0') 81134982809SIngo Weinhold index++; 81234982809SIngo Weinhold char* stringStart = buffer + index; 81334982809SIngo Weinhold 81434982809SIngo Weinhold // find string end 81534982809SIngo Weinhold while (index < commentSize && buffer[index] != '\0') 81634982809SIngo Weinhold index++; 81734982809SIngo Weinhold 81834982809SIngo Weinhold // ignore the entry at the end of the buffer 81934982809SIngo Weinhold if (index == commentSize) 82034982809SIngo Weinhold break; 82134982809SIngo Weinhold 82234982809SIngo Weinhold // We have to analyze string like these: 82334982809SIngo Weinhold // GCC: (GNU) 2.9-beos-991026 82434982809SIngo Weinhold // GCC: (GNU) 2.95.3-haiku-080322 82534982809SIngo Weinhold // GCC: (GNU) 4.1.2 82634982809SIngo Weinhold 82734982809SIngo Weinhold // skip the common prefix 82834982809SIngo Weinhold if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0) 82934982809SIngo Weinhold continue; 83034982809SIngo Weinhold 83134982809SIngo Weinhold // the rest is the GCC version 83234982809SIngo Weinhold char* gccVersion = stringStart + gccVersionPrefixLen; 83334982809SIngo Weinhold char* gccPlatform = strchr(gccVersion, '-'); 83434982809SIngo Weinhold char* patchLevel = NULL; 83534982809SIngo Weinhold if (gccPlatform != NULL) { 83634982809SIngo Weinhold *gccPlatform = '\0'; 83734982809SIngo Weinhold gccPlatform++; 83834982809SIngo Weinhold patchLevel = strchr(gccPlatform, '-'); 83934982809SIngo Weinhold if (patchLevel != NULL) { 84034982809SIngo Weinhold *patchLevel = '\0'; 84134982809SIngo Weinhold patchLevel++; 84234982809SIngo Weinhold } 84334982809SIngo Weinhold } 84434982809SIngo Weinhold 84534982809SIngo Weinhold // split the gcc version into major, middle, and minor 84634982809SIngo Weinhold int version[3] = { 0, 0, 0 }; 84734982809SIngo Weinhold 84834982809SIngo Weinhold for (int k = 0; gccVersion != NULL && k < 3; k++) { 84934982809SIngo Weinhold char* dot = strchr(gccVersion, '.'); 85034982809SIngo Weinhold if (dot) { 85134982809SIngo Weinhold *dot = '\0'; 85234982809SIngo Weinhold dot++; 85334982809SIngo Weinhold } 85434982809SIngo Weinhold version[k] = atoi(gccVersion); 85534982809SIngo Weinhold gccVersion = dot; 85634982809SIngo Weinhold } 85734982809SIngo Weinhold 85834982809SIngo Weinhold // got any version? 85934982809SIngo Weinhold if (version[0] == 0) 86034982809SIngo Weinhold continue; 86134982809SIngo Weinhold 86234982809SIngo Weinhold // Select the gcc version with the smallest major, but the greatest 86334982809SIngo Weinhold // middle/minor. This should usually ignore the glue code version as 86434982809SIngo Weinhold // well as cases where e.g. in a gcc 2 program a single C file has 86534982809SIngo Weinhold // been compiled with gcc 4. 86634982809SIngo Weinhold if (gccMajor == 0 || gccMajor > version[0] 867*593ee7bbSIngo Weinhold || (gccMajor == version[0] 86834982809SIngo Weinhold && (gccMiddle < version[1] 869*593ee7bbSIngo Weinhold || (gccMiddle == version[1] && gccMinor < version[2])))) { 87034982809SIngo Weinhold gccMajor = version[0]; 87134982809SIngo Weinhold gccMiddle = version[1]; 87234982809SIngo Weinhold gccMinor = version[2]; 87334982809SIngo Weinhold } 8742716cfd3SAxel Dörfler 87585f9771aSFrançois Revol if (gccMajor == 2 && gccPlatform != NULL && strcmp(gccPlatform, "haiku")) 8762716cfd3SAxel Dörfler isHaiku = false; 87734982809SIngo Weinhold } 87834982809SIngo Weinhold 87934982809SIngo Weinhold image->gcc_version.major = gccMajor; 88034982809SIngo Weinhold image->gcc_version.middle = gccMiddle; 88134982809SIngo Weinhold image->gcc_version.minor = gccMinor; 8822716cfd3SAxel Dörfler image->gcc_version.haiku = isHaiku; 88334982809SIngo Weinhold 88434982809SIngo Weinhold return gccMajor != 0; 88534982809SIngo Weinhold } 88634982809SIngo Weinhold 88734982809SIngo Weinhold 88834982809SIngo Weinhold static bool 8890c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image) 8900c0fea5dSIngo Weinhold { 8910c0fea5dSIngo Weinhold uint32 i; 8920c0fea5dSIngo Weinhold 8930c0fea5dSIngo Weinhold if (!image->dynamic_ptr) 8940c0fea5dSIngo Weinhold return true; 8950c0fea5dSIngo Weinhold 8960c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 8970c0fea5dSIngo Weinhold if (image->dynamic_ptr >= image->regions[i].start 8980c0fea5dSIngo Weinhold && image->dynamic_ptr < image->regions[i].start + image->regions[i].size) 8990c0fea5dSIngo Weinhold return true; 9000c0fea5dSIngo Weinhold } 9010c0fea5dSIngo Weinhold 9020c0fea5dSIngo Weinhold return false; 9030c0fea5dSIngo Weinhold } 9040c0fea5dSIngo Weinhold 9050c0fea5dSIngo Weinhold 9060c0fea5dSIngo Weinhold /** This function will change the protection of all read-only segments 9070c0fea5dSIngo Weinhold * to really be read-only. 9080c0fea5dSIngo Weinhold * The areas have to be read/write first, so that they can be relocated. 9090c0fea5dSIngo Weinhold */ 9100c0fea5dSIngo Weinhold 9110c0fea5dSIngo Weinhold static void 9120c0fea5dSIngo Weinhold remap_images(void) 9130c0fea5dSIngo Weinhold { 9140c0fea5dSIngo Weinhold image_t *image; 9150c0fea5dSIngo Weinhold uint32 i; 9160c0fea5dSIngo Weinhold 9170c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image != NULL; image = image->next) { 9180c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 9190c0fea5dSIngo Weinhold if ((image->regions[i].flags & RFLAG_RW) == 0 9200c0fea5dSIngo Weinhold && (image->regions[i].flags & RFLAG_REMAPPED) == 0) { 9210c0fea5dSIngo Weinhold // we only need to do this once, so we remember those we've already mapped 9220c0fea5dSIngo Weinhold if (_kern_set_area_protection(image->regions[i].id, 9230c0fea5dSIngo Weinhold B_READ_AREA | B_EXECUTE_AREA) == B_OK) 9240c0fea5dSIngo Weinhold image->regions[i].flags |= RFLAG_REMAPPED; 9250c0fea5dSIngo Weinhold } 9260c0fea5dSIngo Weinhold } 9270c0fea5dSIngo Weinhold } 9280c0fea5dSIngo Weinhold } 9290c0fea5dSIngo Weinhold 9300c0fea5dSIngo Weinhold 9310c0fea5dSIngo Weinhold static status_t 9320c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed) 9330c0fea5dSIngo Weinhold { 9340c0fea5dSIngo Weinhold status_t status = B_OK; 9350c0fea5dSIngo Weinhold const char *baseName; 9360c0fea5dSIngo Weinhold uint32 i; 9370c0fea5dSIngo Weinhold 9380c0fea5dSIngo Weinhold (void)(fd); 9390c0fea5dSIngo Weinhold 9400c0fea5dSIngo Weinhold // cut the file name from the path as base name for the created areas 9410c0fea5dSIngo Weinhold baseName = strrchr(path, '/'); 9420c0fea5dSIngo Weinhold if (baseName != NULL) 9430c0fea5dSIngo Weinhold baseName++; 9440c0fea5dSIngo Weinhold else 9450c0fea5dSIngo Weinhold baseName = path; 9460c0fea5dSIngo Weinhold 9470c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 9480c0fea5dSIngo Weinhold char regionName[B_OS_NAME_LENGTH]; 9490c0fea5dSIngo Weinhold addr_t loadAddress; 9500c0fea5dSIngo Weinhold uint32 addressSpecifier; 9510c0fea5dSIngo Weinhold 9520c0fea5dSIngo Weinhold // for BeOS compatibility: if we load an old BeOS executable, we 9530c0fea5dSIngo Weinhold // have to relocate it, if possible - we recognize it because the 9540c0fea5dSIngo Weinhold // vmstart is set to 0 (hopefully always) 9550c0fea5dSIngo Weinhold if (fixed && image->regions[i].vmstart == 0) 9560c0fea5dSIngo Weinhold fixed = false; 9570c0fea5dSIngo Weinhold 9580c0fea5dSIngo Weinhold snprintf(regionName, sizeof(regionName), "%s_seg%lu%s", 9590c0fea5dSIngo Weinhold baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro"); 9600c0fea5dSIngo Weinhold 9610c0fea5dSIngo Weinhold if (image->dynamic_ptr && !fixed) { 9620c0fea5dSIngo Weinhold // relocatable image... we can afford to place wherever 9630c0fea5dSIngo Weinhold if (i == 0) { 9640c0fea5dSIngo Weinhold // but only the first segment gets a free ride 9650c0fea5dSIngo Weinhold loadAddress = RLD_PROGRAM_BASE; 9660c0fea5dSIngo Weinhold addressSpecifier = B_BASE_ADDRESS; 9670c0fea5dSIngo Weinhold } else { 9680c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart + image->regions[i-1].delta; 9690c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 9700c0fea5dSIngo Weinhold } 9710c0fea5dSIngo Weinhold } else { 9720c0fea5dSIngo Weinhold // not relocatable, put it where it asks or die trying 9730c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart; 9740c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 9750c0fea5dSIngo Weinhold } 9760c0fea5dSIngo Weinhold 9770c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_ANON) { 9780c0fea5dSIngo Weinhold image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress, 9790c0fea5dSIngo Weinhold addressSpecifier, image->regions[i].vmsize, B_NO_LOCK, 9800c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 9810c0fea5dSIngo Weinhold 9820c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 9830c0fea5dSIngo Weinhold status = image->regions[i].id; 9840c0fea5dSIngo Weinhold goto error; 9850c0fea5dSIngo Weinhold } 9860c0fea5dSIngo Weinhold 9870c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 9880c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 9890c0fea5dSIngo Weinhold } else { 9903cf7ecd1SIngo Weinhold image->regions[i].id = _kern_map_file(regionName, 9913cf7ecd1SIngo Weinhold (void **)&loadAddress, addressSpecifier, 9923cf7ecd1SIngo Weinhold image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA, 9933cf7ecd1SIngo Weinhold REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart)); 9940c0fea5dSIngo Weinhold 9950c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 9960c0fea5dSIngo Weinhold status = image->regions[i].id; 9970c0fea5dSIngo Weinhold goto error; 9980c0fea5dSIngo Weinhold } 9990c0fea5dSIngo Weinhold 10000c0fea5dSIngo Weinhold TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path, 10010c0fea5dSIngo Weinhold (void *)loadAddress, image->regions[i].vmsize, 10020c0fea5dSIngo Weinhold image->regions[i].flags & RFLAG_RW ? "rw" : "read-only")); 10030c0fea5dSIngo Weinhold 10040c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 10050c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 10060c0fea5dSIngo Weinhold 10070c0fea5dSIngo Weinhold // handle trailer bits in data segment 10080c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_RW) { 10090c0fea5dSIngo Weinhold addr_t startClearing; 10100c0fea5dSIngo Weinhold addr_t toClear; 10110c0fea5dSIngo Weinhold 10120c0fea5dSIngo Weinhold startClearing = image->regions[i].vmstart 10130c0fea5dSIngo Weinhold + PAGE_OFFSET(image->regions[i].start) 10140c0fea5dSIngo Weinhold + image->regions[i].size; 10150c0fea5dSIngo Weinhold toClear = image->regions[i].vmsize 10160c0fea5dSIngo Weinhold - PAGE_OFFSET(image->regions[i].start) 10170c0fea5dSIngo Weinhold - image->regions[i].size; 10180c0fea5dSIngo Weinhold 10190c0fea5dSIngo Weinhold TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear)); 10200c0fea5dSIngo Weinhold memset((void *)startClearing, 0, toClear); 10210c0fea5dSIngo Weinhold } 10220c0fea5dSIngo Weinhold } 10230c0fea5dSIngo Weinhold } 10240c0fea5dSIngo Weinhold 10250c0fea5dSIngo Weinhold if (image->dynamic_ptr) 10260c0fea5dSIngo Weinhold image->dynamic_ptr += image->regions[0].delta; 10270c0fea5dSIngo Weinhold 10280c0fea5dSIngo Weinhold return B_OK; 10290c0fea5dSIngo Weinhold 10300c0fea5dSIngo Weinhold error: 10310c0fea5dSIngo Weinhold return status; 10320c0fea5dSIngo Weinhold } 10330c0fea5dSIngo Weinhold 10340c0fea5dSIngo Weinhold 10350c0fea5dSIngo Weinhold static void 10360c0fea5dSIngo Weinhold unmap_image(image_t *image) 10370c0fea5dSIngo Weinhold { 10380c0fea5dSIngo Weinhold uint32 i; 10390c0fea5dSIngo Weinhold 10400c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 10410c0fea5dSIngo Weinhold _kern_delete_area(image->regions[i].id); 10420c0fea5dSIngo Weinhold 10430c0fea5dSIngo Weinhold image->regions[i].id = -1; 10440c0fea5dSIngo Weinhold } 10450c0fea5dSIngo Weinhold } 10460c0fea5dSIngo Weinhold 10470c0fea5dSIngo Weinhold 10480c0fea5dSIngo Weinhold static bool 10490c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image) 10500c0fea5dSIngo Weinhold { 10510c0fea5dSIngo Weinhold struct Elf32_Dyn *d; 10520c0fea5dSIngo Weinhold int i; 10530c0fea5dSIngo Weinhold int sonameOffset = -1; 10540c0fea5dSIngo Weinhold 10550c0fea5dSIngo Weinhold image->symhash = 0; 10560c0fea5dSIngo Weinhold image->syms = 0; 10570c0fea5dSIngo Weinhold image->strtab = 0; 10580c0fea5dSIngo Weinhold 10590c0fea5dSIngo Weinhold d = (struct Elf32_Dyn *)image->dynamic_ptr; 10600c0fea5dSIngo Weinhold if (!d) 10610c0fea5dSIngo Weinhold return true; 10620c0fea5dSIngo Weinhold 10630c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 10640c0fea5dSIngo Weinhold switch (d[i].d_tag) { 10650c0fea5dSIngo Weinhold case DT_NEEDED: 10660c0fea5dSIngo Weinhold image->num_needed += 1; 10670c0fea5dSIngo Weinhold break; 10680c0fea5dSIngo Weinhold case DT_HASH: 10690c0fea5dSIngo Weinhold image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta); 10700c0fea5dSIngo Weinhold break; 10710c0fea5dSIngo Weinhold case DT_STRTAB: 10720c0fea5dSIngo Weinhold image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta); 10730c0fea5dSIngo Weinhold break; 10740c0fea5dSIngo Weinhold case DT_SYMTAB: 10750c0fea5dSIngo Weinhold image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta); 10760c0fea5dSIngo Weinhold break; 10770c0fea5dSIngo Weinhold case DT_REL: 10780c0fea5dSIngo Weinhold image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 10790c0fea5dSIngo Weinhold break; 10800c0fea5dSIngo Weinhold case DT_RELSZ: 10810c0fea5dSIngo Weinhold image->rel_len = d[i].d_un.d_val; 10820c0fea5dSIngo Weinhold break; 10830c0fea5dSIngo Weinhold case DT_RELA: 10840c0fea5dSIngo Weinhold image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta); 10850c0fea5dSIngo Weinhold break; 10860c0fea5dSIngo Weinhold case DT_RELASZ: 10870c0fea5dSIngo Weinhold image->rela_len = d[i].d_un.d_val; 10880c0fea5dSIngo Weinhold break; 10890c0fea5dSIngo Weinhold // TK: procedure linkage table 10900c0fea5dSIngo Weinhold case DT_JMPREL: 10910c0fea5dSIngo Weinhold image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 10920c0fea5dSIngo Weinhold break; 10930c0fea5dSIngo Weinhold case DT_PLTRELSZ: 10940c0fea5dSIngo Weinhold image->pltrel_len = d[i].d_un.d_val; 10950c0fea5dSIngo Weinhold break; 10960c0fea5dSIngo Weinhold case DT_INIT: 10970c0fea5dSIngo Weinhold image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 10980c0fea5dSIngo Weinhold break; 10990c0fea5dSIngo Weinhold case DT_FINI: 11000c0fea5dSIngo Weinhold image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 11010c0fea5dSIngo Weinhold break; 11020c0fea5dSIngo Weinhold case DT_SONAME: 11030c0fea5dSIngo Weinhold sonameOffset = d[i].d_un.d_val; 11040c0fea5dSIngo Weinhold break; 11050c0fea5dSIngo Weinhold default: 11060c0fea5dSIngo Weinhold continue; 11070c0fea5dSIngo Weinhold } 11080c0fea5dSIngo Weinhold } 11090c0fea5dSIngo Weinhold 11100c0fea5dSIngo Weinhold // lets make sure we found all the required sections 11110c0fea5dSIngo Weinhold if (!image->symhash || !image->syms || !image->strtab) 11120c0fea5dSIngo Weinhold return false; 11130c0fea5dSIngo Weinhold 11140c0fea5dSIngo Weinhold if (sonameOffset >= 0) 11150c0fea5dSIngo Weinhold strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name)); 11160c0fea5dSIngo Weinhold 11170c0fea5dSIngo Weinhold return true; 11180c0fea5dSIngo Weinhold } 11190c0fea5dSIngo Weinhold 11200c0fea5dSIngo Weinhold 112110b4b5d1SIngo Weinhold static void 112210b4b5d1SIngo Weinhold patch_defined_symbol(image_t* image, const char* name, void** symbol, 112310b4b5d1SIngo Weinhold int32* type) 112410b4b5d1SIngo Weinhold { 112510b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers; 112610b4b5d1SIngo Weinhold while (patcher != NULL && *symbol != 0) { 112710b4b5d1SIngo Weinhold image_t* inImage = image; 112810b4b5d1SIngo Weinhold patcher->patcher(patcher->cookie, NULL, image, name, &inImage, 112910b4b5d1SIngo Weinhold symbol, type); 113010b4b5d1SIngo Weinhold patcher = patcher->next; 113110b4b5d1SIngo Weinhold } 113210b4b5d1SIngo Weinhold } 113310b4b5d1SIngo Weinhold 113410b4b5d1SIngo Weinhold 113510b4b5d1SIngo Weinhold static void 113610b4b5d1SIngo Weinhold patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name, 113710b4b5d1SIngo Weinhold image_t** foundInImage, void** symbol, int32* type) 113810b4b5d1SIngo Weinhold { 113910b4b5d1SIngo Weinhold if (*foundInImage != NULL) 114010b4b5d1SIngo Weinhold patch_defined_symbol(*foundInImage, name, symbol, type); 114110b4b5d1SIngo Weinhold 114210b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers; 114310b4b5d1SIngo Weinhold while (patcher != NULL) { 114410b4b5d1SIngo Weinhold patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage, 114510b4b5d1SIngo Weinhold symbol, type); 114610b4b5d1SIngo Weinhold patcher = patcher->next; 114710b4b5d1SIngo Weinhold } 114810b4b5d1SIngo Weinhold } 114910b4b5d1SIngo Weinhold 115010b4b5d1SIngo Weinhold 115110b4b5d1SIngo Weinhold status_t 115210b4b5d1SIngo Weinhold register_defined_symbol_patcher(struct image_t* image, 115310b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 115410b4b5d1SIngo Weinhold { 115510b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher 115610b4b5d1SIngo Weinhold = new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie); 115710b4b5d1SIngo Weinhold if (patcher == NULL) 115810b4b5d1SIngo Weinhold return B_NO_MEMORY; 115910b4b5d1SIngo Weinhold 116010b4b5d1SIngo Weinhold patcher->next = image->defined_symbol_patchers; 116110b4b5d1SIngo Weinhold image->defined_symbol_patchers = patcher; 116210b4b5d1SIngo Weinhold 116310b4b5d1SIngo Weinhold return B_OK; 116410b4b5d1SIngo Weinhold } 116510b4b5d1SIngo Weinhold 116610b4b5d1SIngo Weinhold 116710b4b5d1SIngo Weinhold void 116810b4b5d1SIngo Weinhold unregister_defined_symbol_patcher(struct image_t* image, 116910b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 117010b4b5d1SIngo Weinhold { 117110b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher** patcher = &image->defined_symbol_patchers; 117210b4b5d1SIngo Weinhold while (*patcher != NULL) { 117310b4b5d1SIngo Weinhold if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) { 117410b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* toDelete = *patcher; 117510b4b5d1SIngo Weinhold *patcher = (*patcher)->next; 117610b4b5d1SIngo Weinhold delete toDelete; 117710b4b5d1SIngo Weinhold return; 117810b4b5d1SIngo Weinhold } 117910b4b5d1SIngo Weinhold patcher = &(*patcher)->next; 118010b4b5d1SIngo Weinhold } 118110b4b5d1SIngo Weinhold } 118210b4b5d1SIngo Weinhold 118310b4b5d1SIngo Weinhold 118410b4b5d1SIngo Weinhold status_t 118510b4b5d1SIngo Weinhold register_undefined_symbol_patcher(struct image_t* image, 118610b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 118710b4b5d1SIngo Weinhold { 118810b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher 118910b4b5d1SIngo Weinhold = new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie); 119010b4b5d1SIngo Weinhold if (patcher == NULL) 119110b4b5d1SIngo Weinhold return B_NO_MEMORY; 119210b4b5d1SIngo Weinhold 119310b4b5d1SIngo Weinhold patcher->next = image->undefined_symbol_patchers; 119410b4b5d1SIngo Weinhold image->undefined_symbol_patchers = patcher; 119510b4b5d1SIngo Weinhold 119610b4b5d1SIngo Weinhold return B_OK; 119710b4b5d1SIngo Weinhold } 119810b4b5d1SIngo Weinhold 119910b4b5d1SIngo Weinhold 120010b4b5d1SIngo Weinhold void 120110b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher(struct image_t* image, 120210b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 120310b4b5d1SIngo Weinhold { 120410b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher** patcher = &image->undefined_symbol_patchers; 120510b4b5d1SIngo Weinhold while (*patcher != NULL) { 120610b4b5d1SIngo Weinhold if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) { 120710b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* toDelete = *patcher; 120810b4b5d1SIngo Weinhold *patcher = (*patcher)->next; 120910b4b5d1SIngo Weinhold delete toDelete; 121010b4b5d1SIngo Weinhold return; 121110b4b5d1SIngo Weinhold } 121210b4b5d1SIngo Weinhold patcher = &(*patcher)->next; 121310b4b5d1SIngo Weinhold } 121410b4b5d1SIngo Weinhold } 121510b4b5d1SIngo Weinhold 121610b4b5d1SIngo Weinhold 121710b4b5d1SIngo Weinhold runtime_loader_add_on_export gRuntimeLoaderAddOnExport = { 121810b4b5d1SIngo Weinhold register_defined_symbol_patcher, 121910b4b5d1SIngo Weinhold unregister_defined_symbol_patcher, 122010b4b5d1SIngo Weinhold register_undefined_symbol_patcher, 122110b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher 122210b4b5d1SIngo Weinhold }; 122310b4b5d1SIngo Weinhold 122410b4b5d1SIngo Weinhold 12250c0fea5dSIngo Weinhold static struct Elf32_Sym * 12260c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type) 12270c0fea5dSIngo Weinhold { 12280c0fea5dSIngo Weinhold uint32 hash, i; 12290c0fea5dSIngo Weinhold 12300c0fea5dSIngo Weinhold // ToDo: "type" is currently ignored! 12310c0fea5dSIngo Weinhold (void)type; 12320c0fea5dSIngo Weinhold 1233dd76bc97SIngo Weinhold if (image->dynamic_ptr == 0) 12340c0fea5dSIngo Weinhold return NULL; 12350c0fea5dSIngo Weinhold 12360c0fea5dSIngo Weinhold hash = elf_hash((uint8 *)name) % HASHTABSIZE(image); 12370c0fea5dSIngo Weinhold 12380c0fea5dSIngo Weinhold for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) { 12390c0fea5dSIngo Weinhold struct Elf32_Sym *symbol = &image->syms[i]; 12400c0fea5dSIngo Weinhold 12410c0fea5dSIngo Weinhold if (symbol->st_shndx != SHN_UNDEF 12420c0fea5dSIngo Weinhold && ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL) 12430c0fea5dSIngo Weinhold || (ELF32_ST_BIND(symbol->st_info) == STB_WEAK)) 12440c0fea5dSIngo Weinhold && !strcmp(SYMNAME(image, symbol), name)) { 12450c0fea5dSIngo Weinhold // check if the type matches 12460c0fea5dSIngo Weinhold if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC) 12470c0fea5dSIngo Weinhold || (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)) 12480c0fea5dSIngo Weinhold continue; 12490c0fea5dSIngo Weinhold 12500c0fea5dSIngo Weinhold return symbol; 12510c0fea5dSIngo Weinhold } 12520c0fea5dSIngo Weinhold } 12530c0fea5dSIngo Weinhold 12540c0fea5dSIngo Weinhold return NULL; 12550c0fea5dSIngo Weinhold } 12560c0fea5dSIngo Weinhold 12570c0fea5dSIngo Weinhold 125810b4b5d1SIngo Weinhold static status_t 125910b4b5d1SIngo Weinhold find_symbol(image_t* image, char const* symbolName, int32 symbolType, 126010b4b5d1SIngo Weinhold void **_location) 126110b4b5d1SIngo Weinhold { 126210b4b5d1SIngo Weinhold // get the symbol in the image 126310b4b5d1SIngo Weinhold struct Elf32_Sym* symbol = find_symbol(image, symbolName, symbolType); 126410b4b5d1SIngo Weinhold if (symbol == NULL) 126510b4b5d1SIngo Weinhold return B_ENTRY_NOT_FOUND; 126610b4b5d1SIngo Weinhold 126710b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value + image->regions[0].delta); 126810b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &symbolType); 126910b4b5d1SIngo Weinhold 127010b4b5d1SIngo Weinhold if (_location != NULL) 127110b4b5d1SIngo Weinhold *_location = location; 127210b4b5d1SIngo Weinhold 127310b4b5d1SIngo Weinhold return B_OK; 127410b4b5d1SIngo Weinhold } 127510b4b5d1SIngo Weinhold 127610b4b5d1SIngo Weinhold 12770c85bd05SIngo Weinhold static status_t 12780c85bd05SIngo Weinhold find_symbol_breadth_first(image_t* image, const char* name, int32 type, 12790c85bd05SIngo Weinhold image_t** _foundInImage, void** _location) 12800c0fea5dSIngo Weinhold { 12810c85bd05SIngo Weinhold image_t* queue[sLoadedImageCount]; 12820c85bd05SIngo Weinhold uint32 count = 0; 12830c85bd05SIngo Weinhold uint32 index = 0; 12840c85bd05SIngo Weinhold queue[count++] = image; 12850c85bd05SIngo Weinhold image->flags |= RFLAG_VISITED; 12860c85bd05SIngo Weinhold 12870c85bd05SIngo Weinhold bool found = false; 12880c85bd05SIngo Weinhold while (index < count) { 12890c85bd05SIngo Weinhold // pop next image 12900c85bd05SIngo Weinhold image = queue[index++]; 12910c85bd05SIngo Weinhold 12920c85bd05SIngo Weinhold if (find_symbol(image, name, type, _location) == B_OK) { 12930c85bd05SIngo Weinhold found = true; 12940c85bd05SIngo Weinhold break; 12950c85bd05SIngo Weinhold } 12960c85bd05SIngo Weinhold 12970c85bd05SIngo Weinhold // push needed images 12980c85bd05SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 12990c85bd05SIngo Weinhold image_t* needed = image->needed[i]; 13000c85bd05SIngo Weinhold if ((needed->flags & RFLAG_VISITED) == 0) { 13010c85bd05SIngo Weinhold queue[count++] = needed; 13020c85bd05SIngo Weinhold needed->flags |= RFLAG_VISITED; 130346f4d849SIngo Weinhold } 130446f4d849SIngo Weinhold } 13050c0fea5dSIngo Weinhold } 13060c0fea5dSIngo Weinhold 13070c85bd05SIngo Weinhold // clear visited flags 13080c85bd05SIngo Weinhold for (uint32 i = 0; i < count; i++) 13090c85bd05SIngo Weinhold queue[i]->flags &= ~RFLAG_VISITED; 13100c85bd05SIngo Weinhold 13110c85bd05SIngo Weinhold return found ? B_OK : B_ENTRY_NOT_FOUND; 13120c0fea5dSIngo Weinhold } 13130c0fea5dSIngo Weinhold 13140c0fea5dSIngo Weinhold 131546f4d849SIngo Weinhold static struct Elf32_Sym* 13160c85bd05SIngo Weinhold find_undefined_symbol_beos(image_t* rootImage, image_t* image, const char* name, 131746f4d849SIngo Weinhold image_t** foundInImage) 131846f4d849SIngo Weinhold { 131946f4d849SIngo Weinhold // BeOS style symbol resolution: It is sufficient to check the direct 132046f4d849SIngo Weinhold // dependencies. The linker would have complained, if the symbol wasn't 132146f4d849SIngo Weinhold // there. 132246f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 132346f4d849SIngo Weinhold if (image->needed[i]->dynamic_ptr) { 132446f4d849SIngo Weinhold struct Elf32_Sym *symbol = find_symbol(image->needed[i], name, 132546f4d849SIngo Weinhold B_SYMBOL_TYPE_ANY); 132646f4d849SIngo Weinhold if (symbol) { 132746f4d849SIngo Weinhold *foundInImage = image->needed[i]; 132846f4d849SIngo Weinhold return symbol; 132946f4d849SIngo Weinhold } 133046f4d849SIngo Weinhold } 133146f4d849SIngo Weinhold } 133246f4d849SIngo Weinhold 133346f4d849SIngo Weinhold return NULL; 133446f4d849SIngo Weinhold } 133546f4d849SIngo Weinhold 133646f4d849SIngo Weinhold 13370c85bd05SIngo Weinhold static struct Elf32_Sym* 13380c85bd05SIngo Weinhold find_undefined_symbol_global(image_t* rootImage, image_t* image, 13390c85bd05SIngo Weinhold const char* name, image_t** foundInImage) 13400c85bd05SIngo Weinhold { 13410c85bd05SIngo Weinhold // Global load order symbol resolution: All loaded images are searched for 13420c85bd05SIngo Weinhold // the symbol in the order they have been loaded. We skip add-on images and 13430c85bd05SIngo Weinhold // RTLD_LOCAL images though. 13440c85bd05SIngo Weinhold image_t* otherImage = sLoadedImages.head; 13450c85bd05SIngo Weinhold while (otherImage != NULL) { 13460c85bd05SIngo Weinhold if (otherImage == rootImage 1347*593ee7bbSIngo Weinhold || (otherImage->type != B_ADD_ON_IMAGE 13480c85bd05SIngo Weinhold && (otherImage->flags 1349*593ee7bbSIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) { 13500c85bd05SIngo Weinhold struct Elf32_Sym *symbol = find_symbol(otherImage, name, 13510c85bd05SIngo Weinhold B_SYMBOL_TYPE_ANY); 13520c85bd05SIngo Weinhold if (symbol) { 13530c85bd05SIngo Weinhold *foundInImage = otherImage; 13540c85bd05SIngo Weinhold return symbol; 13550c85bd05SIngo Weinhold } 13560c85bd05SIngo Weinhold } 13570c85bd05SIngo Weinhold otherImage = otherImage->next; 13580c85bd05SIngo Weinhold } 13590c85bd05SIngo Weinhold 13600c85bd05SIngo Weinhold return NULL; 13610c85bd05SIngo Weinhold } 13620c85bd05SIngo Weinhold 13630c85bd05SIngo Weinhold 13640c85bd05SIngo Weinhold static struct Elf32_Sym* 13650c85bd05SIngo Weinhold find_undefined_symbol_add_on(image_t* rootImage, image_t* image, 13660c85bd05SIngo Weinhold const char* name, image_t** foundInImage) 13670c85bd05SIngo Weinhold { 13680c85bd05SIngo Weinhold // TODO: How do we want to implement this one? Using global scope resolution 13690c85bd05SIngo Weinhold // might be undesired as it is now, since libraries could refer to symbols in 13700c85bd05SIngo Weinhold // the add-on, which would result in add-on symbols implicitely becoming used 13710c85bd05SIngo Weinhold // outside of the add-on. So the options would be to use the global scope but 13720c85bd05SIngo Weinhold // skip the add-on, or to do breadth-first resolution in the add-on dependency 13730c85bd05SIngo Weinhold // scope, also skipping the add-on itself. BeOS style resolution is safe, too, 13740c85bd05SIngo Weinhold // but we miss out features like undefined symbols and preloading. 13750c85bd05SIngo Weinhold return find_undefined_symbol_beos(rootImage, image, name, foundInImage); 13760c85bd05SIngo Weinhold } 13770c85bd05SIngo Weinhold 13780c85bd05SIngo Weinhold 137910b4b5d1SIngo Weinhold /*! This function is called when we run BeOS images on Haiku. 13802716cfd3SAxel Dörfler It allows us to redirect functions to ensure compatibility. 13812716cfd3SAxel Dörfler */ 13822716cfd3SAxel Dörfler static const char* 13832716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName) 13842716cfd3SAxel Dörfler { 13852716cfd3SAxel Dörfler struct symbol_mapping { 13862716cfd3SAxel Dörfler const char* from; 13872716cfd3SAxel Dörfler const char* to; 13882716cfd3SAxel Dörfler }; 13892716cfd3SAxel Dörfler static const struct symbol_mapping kMappings[] = { 139010b4b5d1SIngo Weinhold // TODO: Improve this, and also use it for libnet.so compatibility! 139110b4b5d1SIngo Weinhold // Allow an image to provide a function that will be invoked for every 139210b4b5d1SIngo Weinhold // (transitively) depending image. The function can return a table to 139310b4b5d1SIngo Weinhold // remap symbols (probably better address to address). All the tables 139410b4b5d1SIngo Weinhold // for a single image would be combined into a hash table and an 139510b4b5d1SIngo Weinhold // undefined symbol patcher using this hash table would be added. 13962716cfd3SAxel Dörfler {"fstat", "__be_fstat"}, 13972716cfd3SAxel Dörfler {"lstat", "__be_lstat"}, 13982716cfd3SAxel Dörfler {"stat", "__be_stat"}, 13992716cfd3SAxel Dörfler }; 14002716cfd3SAxel Dörfler const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]); 14012716cfd3SAxel Dörfler 14022716cfd3SAxel Dörfler for (uint32 i = 0; i < kMappingCount; i++) { 14032716cfd3SAxel Dörfler if (!strcmp(symbolName, kMappings[i].from)) 14042716cfd3SAxel Dörfler return kMappings[i].to; 14052716cfd3SAxel Dörfler } 14062716cfd3SAxel Dörfler 14072716cfd3SAxel Dörfler return symbolName; 14082716cfd3SAxel Dörfler } 14092716cfd3SAxel Dörfler 14102716cfd3SAxel Dörfler 14110c0fea5dSIngo Weinhold int 141246f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym, 14132716cfd3SAxel Dörfler addr_t *symAddress) 14140c0fea5dSIngo Weinhold { 14150c0fea5dSIngo Weinhold switch (sym->st_shndx) { 14160c0fea5dSIngo Weinhold case SHN_UNDEF: 14172716cfd3SAxel Dörfler { 14182716cfd3SAxel Dörfler struct Elf32_Sym *sharedSym; 14192716cfd3SAxel Dörfler image_t *sharedImage; 14202716cfd3SAxel Dörfler const char *symName; 14212716cfd3SAxel Dörfler 14220c0fea5dSIngo Weinhold // patch the symbol name 14232716cfd3SAxel Dörfler symName = SYMNAME(image, sym); 14242716cfd3SAxel Dörfler if (!image->gcc_version.haiku) { 14252716cfd3SAxel Dörfler // The image has been compiled with a BeOS compiler. This means 14262716cfd3SAxel Dörfler // we'll have to redirect some functions for compatibility. 14272716cfd3SAxel Dörfler symName = beos_compatibility_map_symbol(symName); 14282716cfd3SAxel Dörfler } 14290c0fea5dSIngo Weinhold 143010b4b5d1SIngo Weinhold int32 type = B_SYMBOL_TYPE_ANY; 143110b4b5d1SIngo Weinhold if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC) 143210b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 143310b4b5d1SIngo Weinhold else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT) 143410b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 143510b4b5d1SIngo Weinhold 143646f4d849SIngo Weinhold // it's undefined, must be outside this image, try the other images 14370c85bd05SIngo Weinhold sharedSym = rootImage->find_undefined_symbol(rootImage, image, 14380c85bd05SIngo Weinhold symName, &sharedImage); 143910b4b5d1SIngo Weinhold void* location = NULL; 14400c0fea5dSIngo Weinhold 144110b4b5d1SIngo Weinhold enum { 144210b4b5d1SIngo Weinhold ERROR_NO_SYMBOL, 144310b4b5d1SIngo Weinhold ERROR_WRONG_TYPE, 144410b4b5d1SIngo Weinhold ERROR_NOT_EXPORTED, 144510b4b5d1SIngo Weinhold ERROR_UNPATCHED 144610b4b5d1SIngo Weinhold }; 144710b4b5d1SIngo Weinhold uint32 lookupError = ERROR_UNPATCHED; 144810b4b5d1SIngo Weinhold 144910b4b5d1SIngo Weinhold if (sharedSym == NULL) { 145010b4b5d1SIngo Weinhold // symbol not found at all 145110b4b5d1SIngo Weinhold lookupError = ERROR_NO_SYMBOL; 145210b4b5d1SIngo Weinhold sharedImage = NULL; 145310b4b5d1SIngo Weinhold } else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE 14542716cfd3SAxel Dörfler && ELF32_ST_TYPE(sym->st_info) 14552716cfd3SAxel Dörfler != ELF32_ST_TYPE(sharedSym->st_info)) { 145610b4b5d1SIngo Weinhold // symbol not of the requested type 145710b4b5d1SIngo Weinhold lookupError = ERROR_WRONG_TYPE; 145810b4b5d1SIngo Weinhold sharedImage = NULL; 145910b4b5d1SIngo Weinhold } else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL 14602716cfd3SAxel Dörfler && ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) { 146110b4b5d1SIngo Weinhold // symbol not exported 146210b4b5d1SIngo Weinhold lookupError = ERROR_NOT_EXPORTED; 146310b4b5d1SIngo Weinhold sharedImage = NULL; 146410b4b5d1SIngo Weinhold } else { 146510b4b5d1SIngo Weinhold // symbol is fine, get its location 146610b4b5d1SIngo Weinhold location = (void*)(sharedSym->st_value 146710b4b5d1SIngo Weinhold + sharedImage->regions[0].delta); 146810b4b5d1SIngo Weinhold } 146910b4b5d1SIngo Weinhold 147010b4b5d1SIngo Weinhold patch_undefined_symbol(rootImage, image, symName, &sharedImage, 147110b4b5d1SIngo Weinhold &location, &type); 147210b4b5d1SIngo Weinhold 147310b4b5d1SIngo Weinhold if (location == NULL) { 147410b4b5d1SIngo Weinhold switch (lookupError) { 147510b4b5d1SIngo Weinhold case ERROR_NO_SYMBOL: 147610b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: could not resolve symbol " 147710b4b5d1SIngo Weinhold "'%s'\n", symName); 147810b4b5d1SIngo Weinhold break; 147910b4b5d1SIngo Weinhold case ERROR_WRONG_TYPE: 148010b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s' in shared " 148110b4b5d1SIngo Weinhold "image but wrong type\n", symName); 148210b4b5d1SIngo Weinhold break; 148310b4b5d1SIngo Weinhold case ERROR_NOT_EXPORTED: 148410b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s', but not " 14852716cfd3SAxel Dörfler "exported\n", symName); 148610b4b5d1SIngo Weinhold break; 148710b4b5d1SIngo Weinhold case ERROR_UNPATCHED: 148810b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s', but was " 148910b4b5d1SIngo Weinhold "hidden by symbol patchers\n", symName); 149010b4b5d1SIngo Weinhold break; 149110b4b5d1SIngo Weinhold } 1492e94d1badSMichael Lotz 1493e94d1badSMichael Lotz if (report_errors()) 1494e94d1badSMichael Lotz sErrorMessage.AddString("missing symbol", symName); 1495e94d1badSMichael Lotz 14960c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 14970c0fea5dSIngo Weinhold } 14980c0fea5dSIngo Weinhold 149910b4b5d1SIngo Weinhold *symAddress = (addr_t)location; 150010b4b5d1SIngo Weinhold return B_OK; 15012716cfd3SAxel Dörfler } 15020c0fea5dSIngo Weinhold 15030c0fea5dSIngo Weinhold case SHN_ABS: 15042716cfd3SAxel Dörfler *symAddress = sym->st_value + image->regions[0].delta; 15050c0fea5dSIngo Weinhold return B_NO_ERROR; 15060c0fea5dSIngo Weinhold 15070c0fea5dSIngo Weinhold case SHN_COMMON: 15080c0fea5dSIngo Weinhold // ToDo: finish this 15092a33a944SIngo Weinhold FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n"); 15100c0fea5dSIngo Weinhold return B_ERROR; //ERR_NOT_IMPLEMENTED_YET; 15110c0fea5dSIngo Weinhold 15120c0fea5dSIngo Weinhold default: 15130c0fea5dSIngo Weinhold // standard symbol 15142716cfd3SAxel Dörfler *symAddress = sym->st_value + image->regions[0].delta; 15150c0fea5dSIngo Weinhold return B_NO_ERROR; 15160c0fea5dSIngo Weinhold } 15170c0fea5dSIngo Weinhold } 15180c0fea5dSIngo Weinhold 15190c0fea5dSIngo Weinhold 15200c0fea5dSIngo Weinhold static void 152110b4b5d1SIngo Weinhold image_event(image_t* image, uint32 event) 152210b4b5d1SIngo Weinhold { 152310b4b5d1SIngo Weinhold AddOnList::Iterator it = sAddOns.GetIterator(); 152410b4b5d1SIngo Weinhold while (RuntimeLoaderAddOn* addOn = it.Next()) { 152510b4b5d1SIngo Weinhold void (*function)(image_t* image) = NULL; 152610b4b5d1SIngo Weinhold 152710b4b5d1SIngo Weinhold switch (event) { 152810b4b5d1SIngo Weinhold case IMAGE_EVENT_LOADED: 152910b4b5d1SIngo Weinhold function = addOn->addOn->image_loaded; 153010b4b5d1SIngo Weinhold break; 153110b4b5d1SIngo Weinhold case IMAGE_EVENT_RELOCATED: 153210b4b5d1SIngo Weinhold function = addOn->addOn->image_relocated; 153310b4b5d1SIngo Weinhold break; 153410b4b5d1SIngo Weinhold case IMAGE_EVENT_INITIALIZED: 153510b4b5d1SIngo Weinhold function = addOn->addOn->image_initialized; 153610b4b5d1SIngo Weinhold break; 153710b4b5d1SIngo Weinhold case IMAGE_EVENT_UNINITIALIZING: 153810b4b5d1SIngo Weinhold function = addOn->addOn->image_uninitializing; 153910b4b5d1SIngo Weinhold break; 154010b4b5d1SIngo Weinhold case IMAGE_EVENT_UNLOADING: 154110b4b5d1SIngo Weinhold function = addOn->addOn->image_unloading; 154210b4b5d1SIngo Weinhold break; 154310b4b5d1SIngo Weinhold } 154410b4b5d1SIngo Weinhold 154510b4b5d1SIngo Weinhold if (function != NULL) 154610b4b5d1SIngo Weinhold function(image); 154710b4b5d1SIngo Weinhold } 154810b4b5d1SIngo Weinhold } 154910b4b5d1SIngo Weinhold 155010b4b5d1SIngo Weinhold 155110b4b5d1SIngo Weinhold static void 15520c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path) 15530c0fea5dSIngo Weinhold { 15540c0fea5dSIngo Weinhold struct stat stat; 15550c0fea5dSIngo Weinhold image_info info; 15560c0fea5dSIngo Weinhold 15570c0fea5dSIngo Weinhold // ToDo: set these correctly 15580c0fea5dSIngo Weinhold info.id = 0; 15590c0fea5dSIngo Weinhold info.type = image->type; 15600c0fea5dSIngo Weinhold info.sequence = 0; 15610c0fea5dSIngo Weinhold info.init_order = 0; 15620c0fea5dSIngo Weinhold info.init_routine = (void (*)())image->init_routine; 15630c0fea5dSIngo Weinhold info.term_routine = (void (*)())image->term_routine; 15640c0fea5dSIngo Weinhold 15650c0fea5dSIngo Weinhold if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) { 15660c0fea5dSIngo Weinhold info.device = stat.st_dev; 15670c0fea5dSIngo Weinhold info.node = stat.st_ino; 15680c0fea5dSIngo Weinhold } else { 15690c0fea5dSIngo Weinhold info.device = -1; 15700c0fea5dSIngo Weinhold info.node = -1; 15710c0fea5dSIngo Weinhold } 15720c0fea5dSIngo Weinhold 15730c0fea5dSIngo Weinhold strlcpy(info.name, path, sizeof(info.name)); 15740c0fea5dSIngo Weinhold info.text = (void *)image->regions[0].vmstart; 15750c0fea5dSIngo Weinhold info.text_size = image->regions[0].vmsize; 15760c0fea5dSIngo Weinhold info.data = (void *)image->regions[1].vmstart; 15770c0fea5dSIngo Weinhold info.data_size = image->regions[1].vmsize; 1578*593ee7bbSIngo Weinhold info.api_version = image->api_version; 1579*593ee7bbSIngo Weinhold info.abi = image->abi; 15800c0fea5dSIngo Weinhold image->id = _kern_register_image(&info, sizeof(image_info)); 15810c0fea5dSIngo Weinhold } 15820c0fea5dSIngo Weinhold 15830c0fea5dSIngo Weinhold 15840c0fea5dSIngo Weinhold static status_t 158546f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 15860c0fea5dSIngo Weinhold { 158746f4d849SIngo Weinhold status_t status = arch_relocate_image(rootImage, image); 15880c0fea5dSIngo Weinhold if (status < B_OK) { 1589320bd2bdSAxel Dörfler FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status, 1590320bd2bdSAxel Dörfler image->path, image->name); 15910c0fea5dSIngo Weinhold return status; 15920c0fea5dSIngo Weinhold } 15930c0fea5dSIngo Weinhold 15940c0fea5dSIngo Weinhold _kern_image_relocated(image->id); 159510b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_RELOCATED); 15960c0fea5dSIngo Weinhold return B_OK; 15970c0fea5dSIngo Weinhold } 15980c0fea5dSIngo Weinhold 15990c0fea5dSIngo Weinhold 16000c0fea5dSIngo Weinhold static status_t 16010c85bd05SIngo Weinhold load_container(char const *name, image_type type, const char *rpath, 16020c85bd05SIngo Weinhold image_t **_image) 16030c0fea5dSIngo Weinhold { 16040c0fea5dSIngo Weinhold int32 pheaderSize, sheaderSize; 16050c0fea5dSIngo Weinhold char path[PATH_MAX]; 16060c0fea5dSIngo Weinhold ssize_t length; 16070c0fea5dSIngo Weinhold char ph_buff[4096]; 16080c0fea5dSIngo Weinhold int32 numRegions; 16090c0fea5dSIngo Weinhold image_t *found; 16100c0fea5dSIngo Weinhold image_t *image; 16110c0fea5dSIngo Weinhold status_t status; 16120c0fea5dSIngo Weinhold int fd; 16130c0fea5dSIngo Weinhold 16140c0fea5dSIngo Weinhold struct Elf32_Ehdr eheader; 16150c0fea5dSIngo Weinhold 16160c0fea5dSIngo Weinhold // Have we already loaded that image? Don't check for add-ons -- we always 16170c0fea5dSIngo Weinhold // reload them. 16180c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 16190c0fea5dSIngo Weinhold found = find_image(name, APP_OR_LIBRARY_TYPE); 162002e577f9SIngo Weinhold 162102e577f9SIngo Weinhold if (found == NULL && type != B_APP_IMAGE) { 162202e577f9SIngo Weinhold // Special case for add-ons that link against the application 162302e577f9SIngo Weinhold // executable, with the executable not having a soname set. 162402e577f9SIngo Weinhold if (const char* lastSlash = strrchr(name, '/')) { 162502e577f9SIngo Weinhold image_t* programImage = get_program_image(); 162602e577f9SIngo Weinhold if (strcmp(programImage->name, lastSlash + 1) == 0) 162702e577f9SIngo Weinhold found = programImage; 162802e577f9SIngo Weinhold } 162902e577f9SIngo Weinhold } 163002e577f9SIngo Weinhold 16310c0fea5dSIngo Weinhold if (found) { 16320c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 16330c0fea5dSIngo Weinhold *_image = found; 16347486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") " 16357486b72dSIngo Weinhold "already loaded", name, type, rpath); 16360c0fea5dSIngo Weinhold return B_OK; 16370c0fea5dSIngo Weinhold } 16380c0fea5dSIngo Weinhold } 16390c0fea5dSIngo Weinhold 16407486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type, 16417486b72dSIngo Weinhold rpath); 16427486b72dSIngo Weinhold 16430c0fea5dSIngo Weinhold strlcpy(path, name, sizeof(path)); 16440c0fea5dSIngo Weinhold 164561b37794SIngo Weinhold // find and open the file 164661b37794SIngo Weinhold fd = open_executable(path, type, rpath, get_program_path(), 164761b37794SIngo Weinhold sSearchPathSubDir); 16480c0fea5dSIngo Weinhold if (fd < 0) { 164902e577f9SIngo Weinhold FATAL("cannot open file %s\n", name); 16507486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): failed to open file", name); 16510c0fea5dSIngo Weinhold return fd; 16520c0fea5dSIngo Weinhold } 16530c0fea5dSIngo Weinhold 16546918dbf4SIngo Weinhold // normalize the image path 16556918dbf4SIngo Weinhold status = _kern_normalize_path(path, true, path); 16566918dbf4SIngo Weinhold if (status != B_OK) 16570c0fea5dSIngo Weinhold goto err1; 16580c0fea5dSIngo Weinhold 16590c0fea5dSIngo Weinhold // Test again if this image has been registered already - this time, 16600c0fea5dSIngo Weinhold // we can check the full path, not just its name as noted. 16610c0fea5dSIngo Weinhold // You could end up loading an image twice with symbolic links, else. 16620c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 16630c0fea5dSIngo Weinhold found = find_image(path, APP_OR_LIBRARY_TYPE); 16640c0fea5dSIngo Weinhold if (found) { 16650c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 16660c0fea5dSIngo Weinhold *_image = found; 1667b2568a30SIngo Weinhold _kern_close(fd); 16687486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): already loaded after all", 16697486b72dSIngo Weinhold name); 16700c0fea5dSIngo Weinhold return B_OK; 16710c0fea5dSIngo Weinhold } 16720c0fea5dSIngo Weinhold } 16730c0fea5dSIngo Weinhold 16740c0fea5dSIngo Weinhold length = _kern_read(fd, 0, &eheader, sizeof(eheader)); 16750c0fea5dSIngo Weinhold if (length != sizeof(eheader)) { 16760c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 16770c0fea5dSIngo Weinhold FATAL("troubles reading ELF header\n"); 16780c0fea5dSIngo Weinhold goto err1; 16790c0fea5dSIngo Weinhold } 16800c0fea5dSIngo Weinhold 16810c0fea5dSIngo Weinhold status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize); 16820c0fea5dSIngo Weinhold if (status < B_OK) { 16830c0fea5dSIngo Weinhold FATAL("incorrect ELF header\n"); 16840c0fea5dSIngo Weinhold goto err1; 16850c0fea5dSIngo Weinhold } 16860c0fea5dSIngo Weinhold 16870c0fea5dSIngo Weinhold // ToDo: what to do about this restriction?? 16880c0fea5dSIngo Weinhold if (pheaderSize > (int)sizeof(ph_buff)) { 16890c0fea5dSIngo Weinhold FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff)); 16900c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 16910c0fea5dSIngo Weinhold goto err1; 16920c0fea5dSIngo Weinhold } 16930c0fea5dSIngo Weinhold 16940c0fea5dSIngo Weinhold length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize); 16950c0fea5dSIngo Weinhold if (length != pheaderSize) { 16960c0fea5dSIngo Weinhold FATAL("Could not read program headers: %s\n", strerror(length)); 16970c0fea5dSIngo Weinhold status = B_BAD_DATA; 16980c0fea5dSIngo Weinhold goto err1; 16990c0fea5dSIngo Weinhold } 17000c0fea5dSIngo Weinhold 17010c0fea5dSIngo Weinhold numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize); 17020c0fea5dSIngo Weinhold if (numRegions <= 0) { 17030c0fea5dSIngo Weinhold FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions); 17040c0fea5dSIngo Weinhold status = B_BAD_DATA; 17050c0fea5dSIngo Weinhold goto err1; 17060c0fea5dSIngo Weinhold } 17070c0fea5dSIngo Weinhold 17080c0fea5dSIngo Weinhold image = create_image(name, path, numRegions); 17090c0fea5dSIngo Weinhold if (image == NULL) { 17100c0fea5dSIngo Weinhold FATAL("Failed to allocate image_t object\n"); 17110c0fea5dSIngo Weinhold status = B_NO_MEMORY; 17120c0fea5dSIngo Weinhold goto err1; 17130c0fea5dSIngo Weinhold } 17140c0fea5dSIngo Weinhold 17150c0fea5dSIngo Weinhold status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize); 17160c0fea5dSIngo Weinhold if (status < B_OK) 17170c0fea5dSIngo Weinhold goto err2; 17180c0fea5dSIngo Weinhold 17190c0fea5dSIngo Weinhold if (!assert_dynamic_loadable(image)) { 17200c0fea5dSIngo Weinhold FATAL("Dynamic segment must be loadable (implementation restriction)\n"); 17210c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 17220c0fea5dSIngo Weinhold goto err2; 17230c0fea5dSIngo Weinhold } 17240c0fea5dSIngo Weinhold 1725*593ee7bbSIngo Weinhold status = map_image(fd, path, image, type == B_APP_IMAGE); 1726*593ee7bbSIngo Weinhold if (status < B_OK) { 1727*593ee7bbSIngo Weinhold FATAL("Could not map image: %s\n", strerror(status)); 1728*593ee7bbSIngo Weinhold status = B_ERROR; 1729*593ee7bbSIngo Weinhold goto err2; 1730*593ee7bbSIngo Weinhold } 1731*593ee7bbSIngo Weinhold 1732*593ee7bbSIngo Weinhold if (!parse_dynamic_segment(image)) { 1733*593ee7bbSIngo Weinhold FATAL("Troubles handling dynamic section\n"); 1734*593ee7bbSIngo Weinhold status = B_BAD_DATA; 1735*593ee7bbSIngo Weinhold goto err3; 1736*593ee7bbSIngo Weinhold } 1737*593ee7bbSIngo Weinhold 1738*593ee7bbSIngo Weinhold if (eheader.e_entry != 0) 1739*593ee7bbSIngo Weinhold image->entry_point = eheader.e_entry + image->regions[0].delta; 1740*593ee7bbSIngo Weinhold 1741*593ee7bbSIngo Weinhold analyze_image_haiku_version_and_abi(image); 1742*593ee7bbSIngo Weinhold 174361b37794SIngo Weinhold if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff, 174434982809SIngo Weinhold sizeof(ph_buff))) { 174561b37794SIngo Weinhold // If this is the executable image, we init the search path 174661b37794SIngo Weinhold // subdir, if the compiler version doesn't match ours. 174761b37794SIngo Weinhold if (type == B_APP_IMAGE) { 174861b37794SIngo Weinhold #if __GNUC__ == 2 174961b37794SIngo Weinhold if (image->gcc_version.major > 2) 175061b37794SIngo Weinhold sSearchPathSubDir = "gcc4"; 175161b37794SIngo Weinhold #elif __GNUC__ == 4 175261b37794SIngo Weinhold if (image->gcc_version.major == 2) 175361b37794SIngo Weinhold sSearchPathSubDir = "gcc2"; 175461b37794SIngo Weinhold #endif 175561b37794SIngo Weinhold } 175661b37794SIngo Weinhold } else { 175734982809SIngo Weinhold FATAL("Failed to get gcc version for %s\n", path); 175834982809SIngo Weinhold // not really fatal, actually 175934982809SIngo Weinhold } 176034982809SIngo Weinhold 17615fd6637bSIngo Weinhold // init gcc version dependent image flags 17625fd6637bSIngo Weinhold // symbol resolution strategy (fallback is R5-style, if version is 17635fd6637bSIngo Weinhold // unavailable) 17645fd6637bSIngo Weinhold if (image->gcc_version.major == 0 1765*593ee7bbSIngo Weinhold || (image->gcc_version.major == 2 && image->gcc_version.middle < 95)) { 17660c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_beos; 17675fd6637bSIngo Weinhold } 17685fd6637bSIngo Weinhold 17690c0fea5dSIngo Weinhold image->type = type; 17700c0fea5dSIngo Weinhold register_image(image, fd, path); 177110b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_LOADED); 17720c0fea5dSIngo Weinhold 17730c0fea5dSIngo Weinhold _kern_close(fd); 17740c0fea5dSIngo Weinhold 17750c0fea5dSIngo Weinhold enqueue_image(&sLoadedImages, image); 17760c0fea5dSIngo Weinhold sLoadedImageCount++; 17770c0fea5dSIngo Weinhold 17780c0fea5dSIngo Weinhold *_image = image; 17797486b72dSIngo Weinhold 178034982809SIngo Weinhold KTRACE("rld: load_container(\"%s\"): done: id: %ld (gcc: %d.%d.%d)", name, 178134982809SIngo Weinhold image->id, image->gcc_version.major, image->gcc_version.middle, 178234982809SIngo Weinhold image->gcc_version.minor); 17837486b72dSIngo Weinhold 17840c0fea5dSIngo Weinhold return B_OK; 17850c0fea5dSIngo Weinhold 17860c0fea5dSIngo Weinhold err3: 17870c0fea5dSIngo Weinhold unmap_image(image); 17880c0fea5dSIngo Weinhold err2: 17890c0fea5dSIngo Weinhold delete_image_struct(image); 17900c0fea5dSIngo Weinhold err1: 17910c0fea5dSIngo Weinhold _kern_close(fd); 17927486b72dSIngo Weinhold 17937486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): failed: %s", name, 17947486b72dSIngo Weinhold strerror(status)); 17957486b72dSIngo Weinhold 17960c0fea5dSIngo Weinhold return status; 17970c0fea5dSIngo Weinhold } 17980c0fea5dSIngo Weinhold 17990c0fea5dSIngo Weinhold 18000c0fea5dSIngo Weinhold static const char * 18010c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 18020c0fea5dSIngo Weinhold { 18030c0fea5dSIngo Weinhold int i; 18040c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 18050c0fea5dSIngo Weinhold 18060c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 18070c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 18080c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 18090c0fea5dSIngo Weinhold } 18100c0fea5dSIngo Weinhold 18110c0fea5dSIngo Weinhold return NULL; 18120c0fea5dSIngo Weinhold } 18130c0fea5dSIngo Weinhold 18140c0fea5dSIngo Weinhold 18150c0fea5dSIngo Weinhold static status_t 18160c85bd05SIngo Weinhold load_immediate_dependencies(image_t *image) 18170c0fea5dSIngo Weinhold { 18180c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 18194bef3723SAxel Dörfler bool reportErrors = report_errors(); 182074c0424aSAxel Dörfler status_t status = B_OK; 18210c0fea5dSIngo Weinhold uint32 i, j; 18220c0fea5dSIngo Weinhold const char *rpath; 18230c0fea5dSIngo Weinhold 18240c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 18250c0fea5dSIngo Weinhold return B_OK; 18260c0fea5dSIngo Weinhold 18270c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 18280c0fea5dSIngo Weinhold 18290c0fea5dSIngo Weinhold if (image->num_needed == 0) 18300c0fea5dSIngo Weinhold return B_OK; 18310c0fea5dSIngo Weinhold 18327486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name, 18337486b72dSIngo Weinhold image->id); 18347486b72dSIngo Weinhold 18350c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 18360c0fea5dSIngo Weinhold if (image->needed == NULL) { 18370c0fea5dSIngo Weinhold FATAL("failed to allocate needed struct\n"); 18387486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory", 18397486b72dSIngo Weinhold image->name, image->id); 18400c0fea5dSIngo Weinhold return B_NO_MEMORY; 18410c0fea5dSIngo Weinhold } 18420c0fea5dSIngo Weinhold 18430c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 18440c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 18450c0fea5dSIngo Weinhold 18460c0fea5dSIngo Weinhold for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { 18470c0fea5dSIngo Weinhold switch (d[i].d_tag) { 18480c0fea5dSIngo Weinhold case DT_NEEDED: 184974c0424aSAxel Dörfler { 185074c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 185174c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 18520c0fea5dSIngo Weinhold 185374c0424aSAxel Dörfler status_t loadStatus = load_container(name, B_LIBRARY_IMAGE, 185474c0424aSAxel Dörfler rpath, &image->needed[j]); 185574c0424aSAxel Dörfler if (loadStatus < B_OK) { 185674c0424aSAxel Dörfler status = loadStatus; 185774c0424aSAxel Dörfler // correct error code in case the file could not been found 185874c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 185974c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 186074c0424aSAxel Dörfler 186174c0424aSAxel Dörfler if (reportErrors) 186274c0424aSAxel Dörfler sErrorMessage.AddString("missing library", name); 186374c0424aSAxel Dörfler } 186474c0424aSAxel Dörfler 186574c0424aSAxel Dörfler // Collect all missing libraries in case we report back 18667486b72dSIngo Weinhold if (!reportErrors) { 18677486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 18687486b72dSIngo Weinhold "failed: %s", image->name, image->id, 18697486b72dSIngo Weinhold strerror(status)); 18700c0fea5dSIngo Weinhold return status; 187174c0424aSAxel Dörfler } 18727486b72dSIngo Weinhold } 18730c0fea5dSIngo Weinhold 18740c0fea5dSIngo Weinhold j += 1; 18750c0fea5dSIngo Weinhold break; 187674c0424aSAxel Dörfler } 18770c0fea5dSIngo Weinhold 18780c0fea5dSIngo Weinhold default: 18790c0fea5dSIngo Weinhold // ignore any other tag 18800c0fea5dSIngo Weinhold continue; 18810c0fea5dSIngo Weinhold } 18820c0fea5dSIngo Weinhold } 18830c0fea5dSIngo Weinhold 18847486b72dSIngo Weinhold if (status < B_OK) { 18857486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 18867486b72dSIngo Weinhold "failed: %s", image->name, image->id, 18877486b72dSIngo Weinhold strerror(status)); 188874c0424aSAxel Dörfler return status; 18897486b72dSIngo Weinhold } 189074c0424aSAxel Dörfler 18910c0fea5dSIngo Weinhold if (j != image->num_needed) { 18920c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 18937486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 18947486b72dSIngo Weinhold "failed: internal error", image->name, image->id); 18950c0fea5dSIngo Weinhold return B_ERROR; 18960c0fea5dSIngo Weinhold } 18970c0fea5dSIngo Weinhold 18987486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name, 18997486b72dSIngo Weinhold image->id); 19007486b72dSIngo Weinhold 19010c0fea5dSIngo Weinhold return B_OK; 19020c0fea5dSIngo Weinhold } 19030c0fea5dSIngo Weinhold 19040c0fea5dSIngo Weinhold 19050c85bd05SIngo Weinhold static status_t 19060c85bd05SIngo Weinhold load_dependencies(image_t* image) 19070c85bd05SIngo Weinhold { 19080c85bd05SIngo Weinhold for (image_t* otherImage = image; otherImage != NULL; 19090c85bd05SIngo Weinhold otherImage = otherImage->next) { 19100c85bd05SIngo Weinhold status_t status = load_immediate_dependencies(otherImage); 19110c85bd05SIngo Weinhold if (status != B_OK) 19120c85bd05SIngo Weinhold return status; 19130c85bd05SIngo Weinhold } 19140c85bd05SIngo Weinhold 19150c85bd05SIngo Weinhold return B_OK; 19160c85bd05SIngo Weinhold } 19170c85bd05SIngo Weinhold 19180c85bd05SIngo Weinhold 19190c0fea5dSIngo Weinhold static uint32 19200c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList, 19210c0fea5dSIngo Weinhold uint32 sortFlag) 19220c0fea5dSIngo Weinhold { 19230c0fea5dSIngo Weinhold uint32 i; 19240c0fea5dSIngo Weinhold 19250c0fea5dSIngo Weinhold if (image->flags & sortFlag) 19260c0fea5dSIngo Weinhold return slot; 19270c0fea5dSIngo Weinhold 19280c0fea5dSIngo Weinhold image->flags |= sortFlag; /* make sure we don't visit this one */ 19290c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) 19300c0fea5dSIngo Weinhold slot = topological_sort(image->needed[i], slot, initList, sortFlag); 19310c0fea5dSIngo Weinhold 19320c0fea5dSIngo Weinhold initList[slot] = image; 19330c0fea5dSIngo Weinhold return slot + 1; 19340c0fea5dSIngo Weinhold } 19350c0fea5dSIngo Weinhold 19360c0fea5dSIngo Weinhold 19370c0fea5dSIngo Weinhold static ssize_t 19380c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag) 19390c0fea5dSIngo Weinhold { 19400c0fea5dSIngo Weinhold image_t **list; 19410c0fea5dSIngo Weinhold 19420c0fea5dSIngo Weinhold list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *)); 19430c0fea5dSIngo Weinhold if (list == NULL) { 19440c0fea5dSIngo Weinhold FATAL("memory shortage in get_sorted_image_list()"); 19450c0fea5dSIngo Weinhold *_list = NULL; 19460c0fea5dSIngo Weinhold return B_NO_MEMORY; 19470c0fea5dSIngo Weinhold } 19480c0fea5dSIngo Weinhold 19490c0fea5dSIngo Weinhold memset(list, 0, sLoadedImageCount * sizeof(image_t *)); 19500c0fea5dSIngo Weinhold 19510c0fea5dSIngo Weinhold *_list = list; 19520c0fea5dSIngo Weinhold return topological_sort(image, 0, list, sortFlag); 19530c0fea5dSIngo Weinhold } 19540c0fea5dSIngo Weinhold 19550c0fea5dSIngo Weinhold 19560c0fea5dSIngo Weinhold static status_t 19570c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 19580c0fea5dSIngo Weinhold { 1959ca618b22SIngo Weinhold // get the images that still have to be relocated 1960ca618b22SIngo Weinhold image_t **list; 1961ca618b22SIngo Weinhold ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 19620c0fea5dSIngo Weinhold if (count < B_OK) 19630c0fea5dSIngo Weinhold return count; 19640c0fea5dSIngo Weinhold 19650c85bd05SIngo Weinhold // relocate 1966ca618b22SIngo Weinhold for (ssize_t i = 0; i < count; i++) { 196746f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 19680c85bd05SIngo Weinhold if (status < B_OK) { 19690c85bd05SIngo Weinhold free(list); 19700c0fea5dSIngo Weinhold return status; 19710c0fea5dSIngo Weinhold } 19720c85bd05SIngo Weinhold } 19730c0fea5dSIngo Weinhold 19740c0fea5dSIngo Weinhold free(list); 19750c0fea5dSIngo Weinhold return B_OK; 19760c0fea5dSIngo Weinhold } 19770c0fea5dSIngo Weinhold 19780c0fea5dSIngo Weinhold 19790c0fea5dSIngo Weinhold static void 19800c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 19810c0fea5dSIngo Weinhold { 19820c0fea5dSIngo Weinhold image_t **initList; 19830c0fea5dSIngo Weinhold ssize_t count, i; 19840c0fea5dSIngo Weinhold 19850c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 19860c0fea5dSIngo Weinhold if (count <= 0) 19870c0fea5dSIngo Weinhold return; 19880c0fea5dSIngo Weinhold 19890c0fea5dSIngo Weinhold if (!initHead) { 19900c0fea5dSIngo Weinhold // this removes the "calling" image 19910c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 19920c0fea5dSIngo Weinhold initList[--count] = NULL; 19930c0fea5dSIngo Weinhold } 19940c0fea5dSIngo Weinhold 19950c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 19960c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 19970c0fea5dSIngo Weinhold image = initList[i]; 19980c0fea5dSIngo Weinhold 19990c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 20000c0fea5dSIngo Weinhold 2001dd76bc97SIngo Weinhold if (image->init_routine != 0) 20020c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 200310b4b5d1SIngo Weinhold 200410b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_INITIALIZED); 20050c0fea5dSIngo Weinhold } 20060c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 20070c0fea5dSIngo Weinhold 20080c0fea5dSIngo Weinhold free(initList); 20090c0fea5dSIngo Weinhold } 20100c0fea5dSIngo Weinhold 20110c0fea5dSIngo Weinhold 20120c0fea5dSIngo Weinhold static void 20130c0fea5dSIngo Weinhold put_image(image_t *image) 20140c0fea5dSIngo Weinhold { 20150c0fea5dSIngo Weinhold // If all references to the image are gone, add it to the disposable list 20160c0fea5dSIngo Weinhold // and remove all dependencies 20170c0fea5dSIngo Weinhold 20180c0fea5dSIngo Weinhold if (atomic_add(&image->ref_count, -1) == 1) { 20190c0fea5dSIngo Weinhold size_t i; 20200c0fea5dSIngo Weinhold 20210c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 20220c0fea5dSIngo Weinhold enqueue_image(&sDisposableImages, image); 20230c0fea5dSIngo Weinhold sLoadedImageCount--; 20240c0fea5dSIngo Weinhold 20250c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) { 20260c0fea5dSIngo Weinhold put_image(image->needed[i]); 20270c0fea5dSIngo Weinhold } 20280c0fea5dSIngo Weinhold } 20290c0fea5dSIngo Weinhold } 20300c0fea5dSIngo Weinhold 20310c0fea5dSIngo Weinhold 2032ca618b22SIngo Weinhold void 2033ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage) 2034ca618b22SIngo Weinhold { 2035ca618b22SIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private 2036ca618b22SIngo Weinhold // API. 2037ca618b22SIngo Weinhold image_t* image; 20380c85bd05SIngo Weinhold void* _export; 20390c85bd05SIngo Weinhold if (find_symbol_breadth_first(rootImage, "__gRuntimeLoader", 20400c85bd05SIngo Weinhold B_SYMBOL_TYPE_DATA, &image, &_export) == B_OK) { 20410c85bd05SIngo Weinhold *(void**)_export = &gRuntimeLoader; 2042ca618b22SIngo Weinhold } 2043ca618b22SIngo Weinhold } 2044ca618b22SIngo Weinhold 2045ca618b22SIngo Weinhold 2046ca618b22SIngo Weinhold static status_t 2047ca618b22SIngo Weinhold add_preloaded_image(image_t* image) 2048ca618b22SIngo Weinhold { 2049ca618b22SIngo Weinhold // We realloc() everytime -- not particularly efficient, but good enough for 2050ca618b22SIngo Weinhold // small number of preloaded images. 2051ca618b22SIngo Weinhold image_t** newArray = (image_t**)realloc(sPreloadedImages, 2052ca618b22SIngo Weinhold sizeof(image_t*) * (sPreloadedImageCount + 1)); 2053ca618b22SIngo Weinhold if (newArray == NULL) 2054ca618b22SIngo Weinhold return B_NO_MEMORY; 2055ca618b22SIngo Weinhold 2056ca618b22SIngo Weinhold sPreloadedImages = newArray; 2057ca618b22SIngo Weinhold newArray[sPreloadedImageCount++] = image; 2058ca618b22SIngo Weinhold 2059ca618b22SIngo Weinhold return B_OK; 2060ca618b22SIngo Weinhold } 2061ca618b22SIngo Weinhold 2062ca618b22SIngo Weinhold 2063ca618b22SIngo Weinhold image_id 2064ca618b22SIngo Weinhold preload_image(char const* path) 2065ca618b22SIngo Weinhold { 2066ca618b22SIngo Weinhold if (path == NULL) 2067ca618b22SIngo Weinhold return B_BAD_VALUE; 2068ca618b22SIngo Weinhold 2069ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\")", path); 2070ca618b22SIngo Weinhold 2071ca618b22SIngo Weinhold image_t *image = NULL; 2072ca618b22SIngo Weinhold status_t status = load_container(path, B_ADD_ON_IMAGE, NULL, &image); 2073ca618b22SIngo Weinhold if (status < B_OK) { 2074ca618b22SIngo Weinhold rld_unlock(); 2075ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, 2076ca618b22SIngo Weinhold strerror(status)); 2077ca618b22SIngo Weinhold return status; 2078ca618b22SIngo Weinhold } 2079ca618b22SIngo Weinhold 20800c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) 20810c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 20820c85bd05SIngo Weinhold 20830c85bd05SIngo Weinhold status = load_dependencies(image); 2084ca618b22SIngo Weinhold if (status < B_OK) 2085ca618b22SIngo Weinhold goto err; 20860c85bd05SIngo Weinhold 20870c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 2088ca618b22SIngo Weinhold 2089ca618b22SIngo Weinhold status = relocate_dependencies(image); 2090ca618b22SIngo Weinhold if (status < B_OK) 2091ca618b22SIngo Weinhold goto err; 2092ca618b22SIngo Weinhold 2093ca618b22SIngo Weinhold status = add_preloaded_image(image); 2094ca618b22SIngo Weinhold if (status < B_OK) 2095ca618b22SIngo Weinhold goto err; 2096ca618b22SIngo Weinhold 2097ca618b22SIngo Weinhold inject_runtime_loader_api(image); 2098ca618b22SIngo Weinhold 2099ca618b22SIngo Weinhold remap_images(); 2100ca618b22SIngo Weinhold init_dependencies(image, true); 2101ca618b22SIngo Weinhold 210210b4b5d1SIngo Weinhold // if the image contains an add-on, register it 210310b4b5d1SIngo Weinhold runtime_loader_add_on* addOnStruct; 210410b4b5d1SIngo Weinhold if (find_symbol(image, "__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA, 210510b4b5d1SIngo Weinhold (void**)&addOnStruct) == B_OK) { 210610b4b5d1SIngo Weinhold RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image, 210710b4b5d1SIngo Weinhold addOnStruct); 210810b4b5d1SIngo Weinhold if (addOn != NULL) { 210910b4b5d1SIngo Weinhold sAddOns.Add(addOn); 211010b4b5d1SIngo Weinhold addOnStruct->init(&gRuntimeLoader, &gRuntimeLoaderAddOnExport); 211110b4b5d1SIngo Weinhold } 211210b4b5d1SIngo Weinhold } 211310b4b5d1SIngo Weinhold 2114ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id); 2115ca618b22SIngo Weinhold 2116ca618b22SIngo Weinhold return image->id; 2117ca618b22SIngo Weinhold 2118ca618b22SIngo Weinhold err: 2119ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status)); 2120ca618b22SIngo Weinhold 2121ca618b22SIngo Weinhold dequeue_image(&sLoadedImages, image); 2122ca618b22SIngo Weinhold sLoadedImageCount--; 2123ca618b22SIngo Weinhold delete_image(image); 2124ca618b22SIngo Weinhold return status; 2125ca618b22SIngo Weinhold } 2126ca618b22SIngo Weinhold 2127ca618b22SIngo Weinhold 2128ca618b22SIngo Weinhold static void 2129ca618b22SIngo Weinhold preload_images() 2130ca618b22SIngo Weinhold { 2131ca618b22SIngo Weinhold const char* imagePaths = getenv("LD_PRELOAD"); 2132ca618b22SIngo Weinhold if (imagePaths == NULL) 2133ca618b22SIngo Weinhold return; 2134ca618b22SIngo Weinhold 2135ca618b22SIngo Weinhold while (*imagePaths != '\0') { 2136ca618b22SIngo Weinhold // find begin of image path 2137ca618b22SIngo Weinhold while (*imagePaths != '\0' && isspace(*imagePaths)) 2138ca618b22SIngo Weinhold imagePaths++; 2139ca618b22SIngo Weinhold 2140ca618b22SIngo Weinhold if (*imagePaths == '\0') 2141ca618b22SIngo Weinhold break; 2142ca618b22SIngo Weinhold 2143ca618b22SIngo Weinhold // find end of image path 2144ca618b22SIngo Weinhold const char* imagePath = imagePaths; 2145ca618b22SIngo Weinhold while (*imagePaths != '\0' && !isspace(*imagePaths)) 2146ca618b22SIngo Weinhold imagePaths++; 2147ca618b22SIngo Weinhold 2148ca618b22SIngo Weinhold // extract the path 2149ca618b22SIngo Weinhold char path[B_PATH_NAME_LENGTH]; 2150ca618b22SIngo Weinhold size_t pathLen = imagePaths - imagePath; 2151ca618b22SIngo Weinhold if (pathLen > sizeof(path) - 1) 2152ca618b22SIngo Weinhold continue; 2153ca618b22SIngo Weinhold memcpy(path, imagePath, pathLen); 2154ca618b22SIngo Weinhold path[pathLen] = '\0'; 2155ca618b22SIngo Weinhold 2156ca618b22SIngo Weinhold // load the image 2157ca618b22SIngo Weinhold preload_image(path); 2158ca618b22SIngo Weinhold } 2159ca618b22SIngo Weinhold } 2160ca618b22SIngo Weinhold 2161ca618b22SIngo Weinhold 216274c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 21630c0fea5dSIngo Weinhold 21640c0fea5dSIngo Weinhold 21650c0fea5dSIngo Weinhold image_id 21660c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 21670c0fea5dSIngo Weinhold { 21680c0fea5dSIngo Weinhold status_t status; 21690c0fea5dSIngo Weinhold image_t *image; 21700c0fea5dSIngo Weinhold 21717486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path); 21727486b72dSIngo Weinhold 21730c0fea5dSIngo Weinhold rld_lock(); 21740c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 21750c0fea5dSIngo Weinhold 2176ca618b22SIngo Weinhold preload_images(); 2177ca618b22SIngo Weinhold 21780c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 21790c0fea5dSIngo Weinhold 21800c0fea5dSIngo Weinhold status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage); 218174c0424aSAxel Dörfler if (status < B_OK) 218274c0424aSAxel Dörfler goto err; 21830c0fea5dSIngo Weinhold 21840c85bd05SIngo Weinhold if (sProgramImage->find_undefined_symbol == NULL) 21850c85bd05SIngo Weinhold sProgramImage->find_undefined_symbol = find_undefined_symbol_global; 21860c85bd05SIngo Weinhold 21870c85bd05SIngo Weinhold status = load_dependencies(sProgramImage); 21880c0fea5dSIngo Weinhold if (status < B_OK) 21890c0fea5dSIngo Weinhold goto err; 21900c85bd05SIngo Weinhold 219147bc6663SIngo Weinhold // Set RTLD_GLOBAL on all libraries including the program. 21920c85bd05SIngo Weinhold // This results in the desired symbol resolution for dlopen()ed libraries. 21930c85bd05SIngo Weinhold set_image_flags_recursively(sProgramImage, RTLD_GLOBAL); 21940c0fea5dSIngo Weinhold 21950c0fea5dSIngo Weinhold status = relocate_dependencies(sProgramImage); 21960c0fea5dSIngo Weinhold if (status < B_OK) 21970c0fea5dSIngo Weinhold goto err; 21980c0fea5dSIngo Weinhold 2199ca618b22SIngo Weinhold inject_runtime_loader_api(sProgramImage); 22000c0fea5dSIngo Weinhold 22010c0fea5dSIngo Weinhold remap_images(); 2202ca618b22SIngo Weinhold init_dependencies(sProgramImage, true); 22030c0fea5dSIngo Weinhold 22040c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 22050c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 22060c85bd05SIngo Weinhold find_symbol_breadth_first(sProgramImage, "getenv", B_SYMBOL_TYPE_TEXT, 22070c85bd05SIngo Weinhold &image, (void**)&gGetEnv); 22080c0fea5dSIngo Weinhold 2209dd76bc97SIngo Weinhold if (sProgramImage->entry_point == 0) { 22100c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 22110c0fea5dSIngo Weinhold goto err; 22120c0fea5dSIngo Weinhold } 22130c0fea5dSIngo Weinhold 22140c0fea5dSIngo Weinhold *_entry = (void *)(sProgramImage->entry_point); 22150c0fea5dSIngo Weinhold 22160c0fea5dSIngo Weinhold rld_unlock(); 22177486b72dSIngo Weinhold 22185d0638bfSIngo Weinhold sProgramLoaded = true; 22195d0638bfSIngo Weinhold 22207486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path, 22217486b72dSIngo Weinhold *_entry, sProgramImage->id); 22227486b72dSIngo Weinhold 22230c0fea5dSIngo Weinhold return sProgramImage->id; 22240c0fea5dSIngo Weinhold 22250c0fea5dSIngo Weinhold err: 22267486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); 22277486b72dSIngo Weinhold 22280c0fea5dSIngo Weinhold delete_image(sProgramImage); 222974c0424aSAxel Dörfler 22304bef3723SAxel Dörfler if (report_errors()) { 22314bef3723SAxel Dörfler // send error message 223274c0424aSAxel Dörfler sErrorMessage.AddInt32("error", status); 22334bef3723SAxel Dörfler sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 22344bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 22354bef3723SAxel Dörfler 22364bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 22374bef3723SAxel Dörfler sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0); 223874c0424aSAxel Dörfler } 223974c0424aSAxel Dörfler _kern_loading_app_failed(status); 22400c0fea5dSIngo Weinhold rld_unlock(); 224174c0424aSAxel Dörfler 22420c0fea5dSIngo Weinhold return status; 22430c0fea5dSIngo Weinhold } 22440c0fea5dSIngo Weinhold 22450c0fea5dSIngo Weinhold 22460c0fea5dSIngo Weinhold image_id 22470c85bd05SIngo Weinhold load_library(char const *path, uint32 flags, bool addOn, void** _handle) 22480c0fea5dSIngo Weinhold { 22490c0fea5dSIngo Weinhold image_t *image = NULL; 22500c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 22510c0fea5dSIngo Weinhold status_t status; 22520c0fea5dSIngo Weinhold 22530c85bd05SIngo Weinhold if (path == NULL && addOn) 22540c0fea5dSIngo Weinhold return B_BAD_VALUE; 22550c0fea5dSIngo Weinhold 22567486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn); 22577486b72dSIngo Weinhold 22580c0fea5dSIngo Weinhold rld_lock(); 22590c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 22600c0fea5dSIngo Weinhold 22610c0fea5dSIngo Weinhold // have we already loaded this library? 22620c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 22630c0fea5dSIngo Weinhold if (!addOn) { 22640c85bd05SIngo Weinhold // a NULL path is fine -- it means the global scope shall be opened 22650c85bd05SIngo Weinhold if (path == NULL) { 22660c85bd05SIngo Weinhold *_handle = RLD_GLOBAL_SCOPE; 22670c85bd05SIngo Weinhold rld_unlock(); 22680c85bd05SIngo Weinhold return 0; 22690c85bd05SIngo Weinhold } 22700c85bd05SIngo Weinhold 22710c0fea5dSIngo Weinhold image = find_image(path, APP_OR_LIBRARY_TYPE); 22720c85bd05SIngo Weinhold if (image != NULL && (flags & RTLD_GLOBAL) != 0) 22730c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 22740c85bd05SIngo Weinhold 22750c0fea5dSIngo Weinhold if (image) { 22760c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 22770c0fea5dSIngo Weinhold rld_unlock(); 22787486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path, 22797486b72dSIngo Weinhold image->id); 22800c85bd05SIngo Weinhold *_handle = image; 22810c0fea5dSIngo Weinhold return image->id; 22820c0fea5dSIngo Weinhold } 22830c0fea5dSIngo Weinhold } 22840c0fea5dSIngo Weinhold 22850c0fea5dSIngo Weinhold status = load_container(path, type, NULL, &image); 22860c0fea5dSIngo Weinhold if (status < B_OK) { 22870c0fea5dSIngo Weinhold rld_unlock(); 22887486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, 22897486b72dSIngo Weinhold strerror(status)); 22900c0fea5dSIngo Weinhold return status; 22910c0fea5dSIngo Weinhold } 22920c0fea5dSIngo Weinhold 22930c85bd05SIngo Weinhold if (image->find_undefined_symbol == NULL) { 22940c85bd05SIngo Weinhold if (addOn) 22950c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_add_on; 22960c85bd05SIngo Weinhold else 22970c85bd05SIngo Weinhold image->find_undefined_symbol = find_undefined_symbol_global; 22980c85bd05SIngo Weinhold } 22990c85bd05SIngo Weinhold 23000c85bd05SIngo Weinhold status = load_dependencies(image); 23010c0fea5dSIngo Weinhold if (status < B_OK) 23020c0fea5dSIngo Weinhold goto err; 23030c85bd05SIngo Weinhold 23040c85bd05SIngo Weinhold // If specified, set the RTLD_GLOBAL flag recursively on this image and all 23050c85bd05SIngo Weinhold // dependencies. If not specified, we temporarily set 23060c85bd05SIngo Weinhold // RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used 23070c85bd05SIngo Weinhold // for undefined symbol resolution. 23080c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) != 0) 23090c85bd05SIngo Weinhold set_image_flags_recursively(image, RTLD_GLOBAL); 23100c85bd05SIngo Weinhold else 23110c85bd05SIngo Weinhold set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 23120c0fea5dSIngo Weinhold 23130c0fea5dSIngo Weinhold status = relocate_dependencies(image); 23140c0fea5dSIngo Weinhold if (status < B_OK) 23150c0fea5dSIngo Weinhold goto err; 23160c0fea5dSIngo Weinhold 23170c85bd05SIngo Weinhold if ((flags & RTLD_GLOBAL) == 0) 23180c85bd05SIngo Weinhold clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); 23190c85bd05SIngo Weinhold 23200c0fea5dSIngo Weinhold remap_images(); 23210c0fea5dSIngo Weinhold init_dependencies(image, true); 23220c0fea5dSIngo Weinhold 23230c0fea5dSIngo Weinhold rld_unlock(); 23247486b72dSIngo Weinhold 23257486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id); 23267486b72dSIngo Weinhold 23270c85bd05SIngo Weinhold *_handle = image; 23280c0fea5dSIngo Weinhold return image->id; 23290c0fea5dSIngo Weinhold 23300c0fea5dSIngo Weinhold err: 23317486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status)); 23327486b72dSIngo Weinhold 23330c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 23340c0fea5dSIngo Weinhold sLoadedImageCount--; 23350c0fea5dSIngo Weinhold delete_image(image); 23360c0fea5dSIngo Weinhold rld_unlock(); 23370c0fea5dSIngo Weinhold return status; 23380c0fea5dSIngo Weinhold } 23390c0fea5dSIngo Weinhold 23400c0fea5dSIngo Weinhold 23410c0fea5dSIngo Weinhold status_t 23420c85bd05SIngo Weinhold unload_library(void* handle, image_id imageID, bool addOn) 23430c0fea5dSIngo Weinhold { 23440c0fea5dSIngo Weinhold image_t *image; 23450c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 23460c0fea5dSIngo Weinhold 23470c85bd05SIngo Weinhold if (handle == NULL && imageID < 0) 23480c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 23490c0fea5dSIngo Weinhold 23500c85bd05SIngo Weinhold if (handle == RLD_GLOBAL_SCOPE) 23510c85bd05SIngo Weinhold return B_OK; 23520c85bd05SIngo Weinhold 23530c0fea5dSIngo Weinhold rld_lock(); 23540c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 23550c0fea5dSIngo Weinhold 23569a6072a3SAxel Dörfler if (sInvalidImageIDs) { 23579a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 23589a6072a3SAxel Dörfler update_image_ids(); 23599a6072a3SAxel Dörfler } 23609a6072a3SAxel Dörfler 23610c0fea5dSIngo Weinhold // we only check images that have been already initialized 23620c0fea5dSIngo Weinhold 2363df30098dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 2364df30098dSIngo Weinhold 23650c85bd05SIngo Weinhold if (handle != NULL) { 23660c85bd05SIngo Weinhold image = (image_t*)handle; 23670c85bd05SIngo Weinhold put_image(image); 2368df30098dSIngo Weinhold status = B_OK; 23690c85bd05SIngo Weinhold } else { 23700c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image; image = image->next) { 23710c0fea5dSIngo Weinhold if (image->id == imageID) { 23720c0fea5dSIngo Weinhold // unload image 23730c0fea5dSIngo Weinhold if (type == image->type) { 23740c0fea5dSIngo Weinhold put_image(image); 23750c0fea5dSIngo Weinhold status = B_OK; 23760c0fea5dSIngo Weinhold } else 23770c0fea5dSIngo Weinhold status = B_BAD_VALUE; 23780c0fea5dSIngo Weinhold break; 23790c0fea5dSIngo Weinhold } 23800c0fea5dSIngo Weinhold } 23810c85bd05SIngo Weinhold } 23820c0fea5dSIngo Weinhold 23830c0fea5dSIngo Weinhold if (status == B_OK) { 23840c0fea5dSIngo Weinhold while ((image = sDisposableImages.head) != NULL) { 23850c0fea5dSIngo Weinhold // call image fini here... 23868c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 23878c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 23883be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize); 23898c2a9d74SMichael Lotz } 23908c2a9d74SMichael Lotz 239110b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 239210b4b5d1SIngo Weinhold 23930c0fea5dSIngo Weinhold if (image->term_routine) 23940c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 23950c0fea5dSIngo Weinhold 23960c0fea5dSIngo Weinhold dequeue_image(&sDisposableImages, image); 23970c0fea5dSIngo Weinhold unmap_image(image); 23980c0fea5dSIngo Weinhold 239910b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 240010b4b5d1SIngo Weinhold 24010c0fea5dSIngo Weinhold delete_image(image); 24020c0fea5dSIngo Weinhold } 24030c0fea5dSIngo Weinhold } 24040c0fea5dSIngo Weinhold 24050c0fea5dSIngo Weinhold rld_unlock(); 24060c0fea5dSIngo Weinhold return status; 24070c0fea5dSIngo Weinhold } 24080c0fea5dSIngo Weinhold 24090c0fea5dSIngo Weinhold 24100c0fea5dSIngo Weinhold status_t 24119a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, 24129a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location) 24130c0fea5dSIngo Weinhold { 24140c0fea5dSIngo Weinhold int32 count = 0, j; 24150c0fea5dSIngo Weinhold uint32 i; 24160c0fea5dSIngo Weinhold image_t *image; 24170c0fea5dSIngo Weinhold 24180c0fea5dSIngo Weinhold rld_lock(); 24190c0fea5dSIngo Weinhold 24200c0fea5dSIngo Weinhold // get the image from those who have been already initialized 24210c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 24220c0fea5dSIngo Weinhold if (image == NULL) { 24230c0fea5dSIngo Weinhold rld_unlock(); 24240c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 24250c0fea5dSIngo Weinhold } 24260c0fea5dSIngo Weinhold 24270c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 24280c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 24290c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 24300555803aSAxel Dörfler struct Elf32_Sym *symbol = &image->syms[j]; 24310c0fea5dSIngo Weinhold 24320c0fea5dSIngo Weinhold if (count == num) { 243310b4b5d1SIngo Weinhold const char* symbolName = SYMNAME(image, symbol); 243410b4b5d1SIngo Weinhold strlcpy(nameBuffer, symbolName, *_nameLength); 243510b4b5d1SIngo Weinhold *_nameLength = strlen(symbolName); 24360c0fea5dSIngo Weinhold 243710b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value 243810b4b5d1SIngo Weinhold + image->regions[0].delta); 243910b4b5d1SIngo Weinhold int32 type; 24400c0fea5dSIngo Weinhold if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) 244110b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 24420c0fea5dSIngo Weinhold else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) 244310b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 24440c0fea5dSIngo Weinhold else 244510b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_ANY; 244610b4b5d1SIngo Weinhold // TODO: check with the return types of that BeOS function 24470c0fea5dSIngo Weinhold 244810b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &type); 244910b4b5d1SIngo Weinhold 245010b4b5d1SIngo Weinhold if (_type != NULL) 245110b4b5d1SIngo Weinhold *_type = type; 24520c0fea5dSIngo Weinhold if (_location != NULL) 245310b4b5d1SIngo Weinhold *_location = location; 24540c0fea5dSIngo Weinhold goto out; 24550c0fea5dSIngo Weinhold } 24560c0fea5dSIngo Weinhold count++; 24570c0fea5dSIngo Weinhold } 24580c0fea5dSIngo Weinhold } 24590c0fea5dSIngo Weinhold out: 24600c0fea5dSIngo Weinhold rld_unlock(); 24610c0fea5dSIngo Weinhold 24620c0fea5dSIngo Weinhold if (num != count) 24630c0fea5dSIngo Weinhold return B_BAD_INDEX; 24640c0fea5dSIngo Weinhold 24650c0fea5dSIngo Weinhold return B_OK; 24660c0fea5dSIngo Weinhold } 24670c0fea5dSIngo Weinhold 24680c0fea5dSIngo Weinhold 24690c0fea5dSIngo Weinhold status_t 24709a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType, 247180ece785SIngo Weinhold bool recursive, image_id *_inImage, void **_location) 24720c0fea5dSIngo Weinhold { 24730c0fea5dSIngo Weinhold status_t status = B_OK; 24740c0fea5dSIngo Weinhold image_t *image; 24750c0fea5dSIngo Weinhold 24760c0fea5dSIngo Weinhold if (imageID < B_OK) 24770c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 24780c0fea5dSIngo Weinhold if (symbolName == NULL) 24790c0fea5dSIngo Weinhold return B_BAD_VALUE; 24800c0fea5dSIngo Weinhold 24810c0fea5dSIngo Weinhold rld_lock(); 24820c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 24830c0fea5dSIngo Weinhold 24840c0fea5dSIngo Weinhold // get the image from those who have been already initialized 24850c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 248680ece785SIngo Weinhold if (image != NULL) { 248780ece785SIngo Weinhold if (recursive) { 248880ece785SIngo Weinhold // breadth-first search in the given image and its dependencies 248980ece785SIngo Weinhold status = find_symbol_breadth_first(image, symbolName, symbolType, 249080ece785SIngo Weinhold &image, _location); 249180ece785SIngo Weinhold } else 249210b4b5d1SIngo Weinhold status = find_symbol(image, symbolName, symbolType, _location); 249380ece785SIngo Weinhold 249480ece785SIngo Weinhold if (status == B_OK && _inImage != NULL) 249580ece785SIngo Weinhold *_inImage = image->id; 249680ece785SIngo Weinhold } else 24970c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 24980c0fea5dSIngo Weinhold 24990c0fea5dSIngo Weinhold rld_unlock(); 25000c0fea5dSIngo Weinhold return status; 25010c0fea5dSIngo Weinhold } 25020c0fea5dSIngo Weinhold 25030c0fea5dSIngo Weinhold 25040c0fea5dSIngo Weinhold status_t 25050c85bd05SIngo Weinhold get_library_symbol(void* handle, void* caller, const char* symbolName, 25060c85bd05SIngo Weinhold void **_location) 25070c85bd05SIngo Weinhold { 25080c85bd05SIngo Weinhold status_t status = B_ENTRY_NOT_FOUND; 25090c85bd05SIngo Weinhold 25100c85bd05SIngo Weinhold if (symbolName == NULL) 25110c85bd05SIngo Weinhold return B_BAD_VALUE; 25120c85bd05SIngo Weinhold 25130c85bd05SIngo Weinhold rld_lock(); 25140c85bd05SIngo Weinhold // for now, just do stupid simple global locking 25150c85bd05SIngo Weinhold 25160c85bd05SIngo Weinhold if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) { 25170c85bd05SIngo Weinhold // look in the default scope 25180c85bd05SIngo Weinhold image_t* image; 25190c85bd05SIngo Weinhold Elf32_Sym* symbol = find_undefined_symbol_global(sProgramImage, 25200c85bd05SIngo Weinhold sProgramImage, symbolName, &image); 25210c85bd05SIngo Weinhold if (symbol != NULL) { 25220c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value + image->regions[0].delta); 25230c85bd05SIngo Weinhold int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC 25240c85bd05SIngo Weinhold ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 25250c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, &symbolType); 25260c85bd05SIngo Weinhold status = B_OK; 25270c85bd05SIngo Weinhold } 25280c85bd05SIngo Weinhold } else if (handle == RTLD_NEXT) { 25290c85bd05SIngo Weinhold // Look in the default scope, but also in the dependencies of the 25300c85bd05SIngo Weinhold // calling image. Return the next after the caller symbol. 25310c85bd05SIngo Weinhold 2532a2dad9e1SIngo Weinhold // First of all, find the caller image. 25330c85bd05SIngo Weinhold image_t* callerImage = sLoadedImages.head; 25340c85bd05SIngo Weinhold for (; callerImage != NULL; callerImage = callerImage->next) { 25350c85bd05SIngo Weinhold elf_region_t& text = callerImage->regions[0]; 2536a2dad9e1SIngo Weinhold if ((addr_t)caller >= text.vmstart 2537a2dad9e1SIngo Weinhold && (addr_t)caller < text.vmstart + text.vmsize) { 2538a2dad9e1SIngo Weinhold // found the image 25390c85bd05SIngo Weinhold break; 25400c85bd05SIngo Weinhold } 25410c85bd05SIngo Weinhold } 25420c85bd05SIngo Weinhold 2543a2dad9e1SIngo Weinhold if (callerImage != NULL) { 25440c85bd05SIngo Weinhold // found the caller -- now search the global scope until we find 25450c85bd05SIngo Weinhold // the next symbol 2546a2dad9e1SIngo Weinhold bool hitCallerImage = false; 25470c85bd05SIngo Weinhold set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 25480c85bd05SIngo Weinhold 25490c85bd05SIngo Weinhold image_t* image = sLoadedImages.head; 25500c85bd05SIngo Weinhold for (; image != NULL; image = image->next) { 2551a2dad9e1SIngo Weinhold // skip the caller image 2552a2dad9e1SIngo Weinhold if (image == callerImage) { 2553a2dad9e1SIngo Weinhold hitCallerImage = true; 2554a2dad9e1SIngo Weinhold continue; 2555a2dad9e1SIngo Weinhold } 2556a2dad9e1SIngo Weinhold 2557a2dad9e1SIngo Weinhold // skip all images up to the caller image; also skip add-on 2558a2dad9e1SIngo Weinhold // images and those not marked above for resolution 2559a2dad9e1SIngo Weinhold if (!hitCallerImage || image->type == B_ADD_ON_IMAGE 25600c85bd05SIngo Weinhold || (image->flags 2561a2dad9e1SIngo Weinhold & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0) { 25620c85bd05SIngo Weinhold continue; 25630c85bd05SIngo Weinhold } 25640c85bd05SIngo Weinhold 25650c85bd05SIngo Weinhold struct Elf32_Sym *symbol = find_symbol(image, symbolName, 25660c85bd05SIngo Weinhold B_SYMBOL_TYPE_TEXT); 25670c85bd05SIngo Weinhold if (symbol == NULL) 25680c85bd05SIngo Weinhold continue; 25690c85bd05SIngo Weinhold 2570a2dad9e1SIngo Weinhold // found the symbol 25710c85bd05SIngo Weinhold *_location = (void*)(symbol->st_value 25720c85bd05SIngo Weinhold + image->regions[0].delta); 25730c85bd05SIngo Weinhold int32 symbolType = B_SYMBOL_TYPE_TEXT; 25740c85bd05SIngo Weinhold patch_defined_symbol(image, symbolName, _location, 25750c85bd05SIngo Weinhold &symbolType); 25760c85bd05SIngo Weinhold status = B_OK; 25770c85bd05SIngo Weinhold break; 25780c85bd05SIngo Weinhold } 25790c85bd05SIngo Weinhold 25800c85bd05SIngo Weinhold clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); 25810c85bd05SIngo Weinhold } 25820c85bd05SIngo Weinhold } else { 25830c85bd05SIngo Weinhold // breadth-first search in the given image and its dependencies 25840c85bd05SIngo Weinhold image_t* inImage; 25850c85bd05SIngo Weinhold status = find_symbol_breadth_first((image_t*)handle, symbolName, 25860c85bd05SIngo Weinhold B_SYMBOL_TYPE_ANY, &inImage, _location); 25870c85bd05SIngo Weinhold } 25880c85bd05SIngo Weinhold 25890c85bd05SIngo Weinhold rld_unlock(); 25900c85bd05SIngo Weinhold return status; 25910c85bd05SIngo Weinhold } 25920c85bd05SIngo Weinhold 25930c85bd05SIngo Weinhold 25940c85bd05SIngo Weinhold status_t 25950c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 25960c0fea5dSIngo Weinhold { 25970c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 25980c0fea5dSIngo Weinhold struct Elf32_Dyn *dynamicSection; 25990c0fea5dSIngo Weinhold image_t *image; 26000c0fea5dSIngo Weinhold 26010c0fea5dSIngo Weinhold if (_name == NULL) 26020c0fea5dSIngo Weinhold return B_BAD_VALUE; 26030c0fea5dSIngo Weinhold 26040c0fea5dSIngo Weinhold rld_lock(); 26050c0fea5dSIngo Weinhold 26060c0fea5dSIngo Weinhold image = find_loaded_image_by_id(id); 26070c0fea5dSIngo Weinhold if (image == NULL) { 26080c0fea5dSIngo Weinhold rld_unlock(); 26090c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 26100c0fea5dSIngo Weinhold } 26110c0fea5dSIngo Weinhold 26120c0fea5dSIngo Weinhold dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr; 26130c0fea5dSIngo Weinhold if (dynamicSection == NULL || image->num_needed <= searchIndex) { 26140c0fea5dSIngo Weinhold rld_unlock(); 26150c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 26160c0fea5dSIngo Weinhold } 26170c0fea5dSIngo Weinhold 26180c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 26190c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 26200c0fea5dSIngo Weinhold continue; 26210c0fea5dSIngo Weinhold 26220c0fea5dSIngo Weinhold if (j++ == searchIndex) { 26230c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 26240c0fea5dSIngo Weinhold 26250c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 26260c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 26270c0fea5dSIngo Weinhold rld_unlock(); 26280c0fea5dSIngo Weinhold return B_OK; 26290c0fea5dSIngo Weinhold } 26300c0fea5dSIngo Weinhold } 26310c0fea5dSIngo Weinhold 26320c0fea5dSIngo Weinhold rld_unlock(); 26330c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 26340c0fea5dSIngo Weinhold } 26350c0fea5dSIngo Weinhold 26360c0fea5dSIngo Weinhold 263774c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 26380c0fea5dSIngo Weinhold 26390c0fea5dSIngo Weinhold 26409a6072a3SAxel Dörfler /*! Read and verify the ELF header */ 26410c0fea5dSIngo Weinhold status_t 26420c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length) 26430c0fea5dSIngo Weinhold { 26440c0fea5dSIngo Weinhold int32 programSize, sectionSize; 26450c0fea5dSIngo Weinhold 26460c0fea5dSIngo Weinhold if (length < (int32)sizeof(struct Elf32_Ehdr)) 26470c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 26480c0fea5dSIngo Weinhold 26499a6072a3SAxel Dörfler return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, 26509a6072a3SAxel Dörfler §ionSize); 26510c0fea5dSIngo Weinhold } 26520c0fea5dSIngo Weinhold 26530c0fea5dSIngo Weinhold 26540c0fea5dSIngo Weinhold void 26550c0fea5dSIngo Weinhold terminate_program(void) 26560c0fea5dSIngo Weinhold { 26570c0fea5dSIngo Weinhold image_t **termList; 26580c0fea5dSIngo Weinhold ssize_t count, i; 26590c0fea5dSIngo Weinhold 26600c0fea5dSIngo Weinhold count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED); 26610c0fea5dSIngo Weinhold if (count < B_OK) 26620c0fea5dSIngo Weinhold return; 26630c0fea5dSIngo Weinhold 26649a6072a3SAxel Dörfler if (sInvalidImageIDs) { 26659a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 26669a6072a3SAxel Dörfler update_image_ids(); 26679a6072a3SAxel Dörfler } 26689a6072a3SAxel Dörfler 26690c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 26700c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 26710c0fea5dSIngo Weinhold image_t *image = termList[i]; 26720c0fea5dSIngo Weinhold 26730c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 26740c0fea5dSIngo Weinhold 267510b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 267610b4b5d1SIngo Weinhold 26770c0fea5dSIngo Weinhold if (image->term_routine) 26780c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 267910b4b5d1SIngo Weinhold 268010b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 26810c0fea5dSIngo Weinhold } 26820c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 26830c0fea5dSIngo Weinhold 26840c0fea5dSIngo Weinhold free(termList); 26850c0fea5dSIngo Weinhold } 26860c0fea5dSIngo Weinhold 26870c0fea5dSIngo Weinhold 26880c0fea5dSIngo Weinhold void 26890c0fea5dSIngo Weinhold rldelf_init(void) 26900c0fea5dSIngo Weinhold { 269110b4b5d1SIngo Weinhold // invoke static constructors 269210b4b5d1SIngo Weinhold new(&sAddOns) AddOnList; 269310b4b5d1SIngo Weinhold 2694e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 2695e73923b0SAxel Dörfler sSemOwner = -1; 2696e73923b0SAxel Dörfler sSemCount = 0; 26970c0fea5dSIngo Weinhold 26980c0fea5dSIngo Weinhold // create the debug area 26990c0fea5dSIngo Weinhold { 27000c0fea5dSIngo Weinhold int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 27010c0fea5dSIngo Weinhold 27020c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 27030c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 27040c0fea5dSIngo Weinhold (void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK, 27050c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 27060c0fea5dSIngo Weinhold if (areaID < B_OK) { 27070c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 27080c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 27090c0fea5dSIngo Weinhold } 27100c0fea5dSIngo Weinhold 27110c0fea5dSIngo Weinhold area->loaded_images = &sLoadedImages; 27120c0fea5dSIngo Weinhold } 271374c0424aSAxel Dörfler 271474c0424aSAxel Dörfler // initialize error message if needed 27154bef3723SAxel Dörfler if (report_errors()) { 271674c0424aSAxel Dörfler void *buffer = malloc(1024); 271774c0424aSAxel Dörfler if (buffer == NULL) 271874c0424aSAxel Dörfler return; 271974c0424aSAxel Dörfler 272074c0424aSAxel Dörfler sErrorMessage.SetTo(buffer, 1024, 'Rler'); 272174c0424aSAxel Dörfler } 27220c0fea5dSIngo Weinhold } 27231873b4b3SIngo Weinhold 27241873b4b3SIngo Weinhold 27251873b4b3SIngo Weinhold status_t 27269a6072a3SAxel Dörfler elf_reinit_after_fork(void) 27271873b4b3SIngo Weinhold { 2728e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 2729e73923b0SAxel Dörfler if (sSem < 0) 2730e73923b0SAxel Dörfler return sSem; 27311873b4b3SIngo Weinhold 27329a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and 2733cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork() 2734cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one 27359a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different. 27369a6072a3SAxel Dörfler sInvalidImageIDs = true; 2737cbc456deSIngo Weinhold 27381873b4b3SIngo Weinhold return B_OK; 27391873b4b3SIngo Weinhold } 2740