10c0fea5dSIngo Weinhold /* 234982809SIngo Weinhold * Copyright 2008, 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> 140c0fea5dSIngo Weinhold #include <stdio.h> 150c0fea5dSIngo Weinhold #include <stdlib.h> 1634982809SIngo Weinhold #include <string.h> 170c0fea5dSIngo Weinhold 18ca618b22SIngo Weinhold #include <OS.h> 19ca618b22SIngo Weinhold 207486b72dSIngo Weinhold #include <elf32.h> 217486b72dSIngo Weinhold #include <runtime_loader.h> 227486b72dSIngo Weinhold #include <syscalls.h> 237486b72dSIngo Weinhold #include <user_runtime.h> 24*10b4b5d1SIngo Weinhold #include <util/DoublyLinkedList.h> 25*10b4b5d1SIngo Weinhold #include <util/kernel_cpp.h> 266b202f4eSIngo Weinhold #include <util/KMessage.h> 276b202f4eSIngo Weinhold #include <vm_defs.h> 287486b72dSIngo Weinhold 29071f9c3aSIngo Weinhold #include "tracing_config.h" 30071f9c3aSIngo Weinhold 310c0fea5dSIngo Weinhold 320c0fea5dSIngo Weinhold //#define TRACE_RLD 330c0fea5dSIngo Weinhold #ifdef TRACE_RLD 340c0fea5dSIngo Weinhold # define TRACE(x) dprintf x 350c0fea5dSIngo Weinhold #else 360c0fea5dSIngo Weinhold # define TRACE(x) ; 370c0fea5dSIngo Weinhold #endif 380c0fea5dSIngo Weinhold 390c0fea5dSIngo Weinhold 40*10b4b5d1SIngo Weinhold // TODO: implement better locking strategy 41*10b4b5d1SIngo Weinhold // TODO: implement lazy binding 420c0fea5dSIngo Weinhold 430c0fea5dSIngo Weinhold #define PAGE_MASK (B_PAGE_SIZE - 1) 440c0fea5dSIngo Weinhold 450c0fea5dSIngo Weinhold #define PAGE_OFFSET(x) ((x) & (PAGE_MASK)) 460c0fea5dSIngo Weinhold #define PAGE_BASE(x) ((x) & ~(PAGE_MASK)) 470c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK)) 480c0fea5dSIngo Weinhold 490c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000 500c0fea5dSIngo Weinhold /* keep in sync with app ldscript */ 510c0fea5dSIngo Weinhold 520c0fea5dSIngo Weinhold enum { 530c0fea5dSIngo Weinhold RFLAG_RW = 0x0001, 540c0fea5dSIngo Weinhold RFLAG_ANON = 0x0002, 550c0fea5dSIngo Weinhold 560c0fea5dSIngo Weinhold RFLAG_TERMINATED = 0x0200, 570c0fea5dSIngo Weinhold RFLAG_INITIALIZED = 0x0400, 580c0fea5dSIngo Weinhold RFLAG_SYMBOLIC = 0x0800, 590c0fea5dSIngo Weinhold RFLAG_RELOCATED = 0x1000, 600c0fea5dSIngo Weinhold RFLAG_PROTECTED = 0x2000, 610c0fea5dSIngo Weinhold RFLAG_DEPENDENCIES_LOADED = 0x4000, 6246f4d849SIngo Weinhold RFLAG_REMAPPED = 0x8000, 6346f4d849SIngo Weinhold 6446f4d849SIngo Weinhold RFLAG_VISITED = 0x10000 6546f4d849SIngo Weinhold // temporarily set in the symbol resolution code 660c0fea5dSIngo Weinhold }; 670c0fea5dSIngo Weinhold 680c0fea5dSIngo Weinhold 690c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type) (1 << ((type) - 1)) 700c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 710c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \ 720c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \ 730c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE)) 740c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 750c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE)) 760c0fea5dSIngo Weinhold 770c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 780c0fea5dSIngo Weinhold 79*10b4b5d1SIngo Weinhold 80*10b4b5d1SIngo Weinhold // image events 81*10b4b5d1SIngo Weinhold enum { 82*10b4b5d1SIngo Weinhold IMAGE_EVENT_LOADED, 83*10b4b5d1SIngo Weinhold IMAGE_EVENT_RELOCATED, 84*10b4b5d1SIngo Weinhold IMAGE_EVENT_INITIALIZED, 85*10b4b5d1SIngo Weinhold IMAGE_EVENT_UNINITIALIZING, 86*10b4b5d1SIngo Weinhold IMAGE_EVENT_UNLOADING 87*10b4b5d1SIngo Weinhold }; 88*10b4b5d1SIngo Weinhold 89*10b4b5d1SIngo Weinhold 90*10b4b5d1SIngo Weinhold struct RuntimeLoaderAddOn 91*10b4b5d1SIngo Weinhold : public DoublyLinkedListLinkImpl<RuntimeLoaderAddOn> { 92*10b4b5d1SIngo Weinhold image_t* image; 93*10b4b5d1SIngo Weinhold runtime_loader_add_on* addOn; 94*10b4b5d1SIngo Weinhold 95*10b4b5d1SIngo Weinhold RuntimeLoaderAddOn(image_t* image, runtime_loader_add_on* addOn) 96*10b4b5d1SIngo Weinhold : 97*10b4b5d1SIngo Weinhold image(image), 98*10b4b5d1SIngo Weinhold addOn(addOn) 99*10b4b5d1SIngo Weinhold { 100*10b4b5d1SIngo Weinhold } 101*10b4b5d1SIngo Weinhold }; 102*10b4b5d1SIngo Weinhold 103*10b4b5d1SIngo Weinhold typedef DoublyLinkedList<RuntimeLoaderAddOn> AddOnList; 104*10b4b5d1SIngo Weinhold 105*10b4b5d1SIngo Weinhold struct RuntimeLoaderSymbolPatcher { 106*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* next; 107*10b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* patcher; 108*10b4b5d1SIngo Weinhold void* cookie; 109*10b4b5d1SIngo Weinhold 110*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher(runtime_loader_symbol_patcher* patcher, 111*10b4b5d1SIngo Weinhold void* cookie) 112*10b4b5d1SIngo Weinhold : 113*10b4b5d1SIngo Weinhold patcher(patcher), 114*10b4b5d1SIngo Weinhold cookie(cookie) 115*10b4b5d1SIngo Weinhold { 116*10b4b5d1SIngo Weinhold } 117*10b4b5d1SIngo Weinhold }; 118*10b4b5d1SIngo Weinhold 119*10b4b5d1SIngo Weinhold 1200c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0}; 1210c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0}; 1220c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0; 1230c0fea5dSIngo Weinhold static image_t *sProgramImage; 12474c0424aSAxel Dörfler static KMessage sErrorMessage; 1255d0638bfSIngo Weinhold static bool sProgramLoaded = false; 12661b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL; 1279a6072a3SAxel Dörfler static bool sInvalidImageIDs; 128ca618b22SIngo Weinhold static image_t **sPreloadedImages = NULL; 129ca618b22SIngo Weinhold static uint32 sPreloadedImageCount = 0; 130*10b4b5d1SIngo Weinhold static AddOnList sAddOns; 1310c0fea5dSIngo Weinhold 1320c0fea5dSIngo Weinhold // a recursive lock 133e73923b0SAxel Dörfler static sem_id sSem; 134e73923b0SAxel Dörfler static thread_id sSemOwner; 135e73923b0SAxel Dörfler static int32 sSemCount; 1360c0fea5dSIngo Weinhold 137*10b4b5d1SIngo Weinhold extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport; 138*10b4b5d1SIngo Weinhold 1390c0fea5dSIngo Weinhold 1400c0fea5dSIngo Weinhold void 1410c0fea5dSIngo Weinhold dprintf(const char *format, ...) 1420c0fea5dSIngo Weinhold { 1430c0fea5dSIngo Weinhold char buffer[1024]; 1440c0fea5dSIngo Weinhold 1450c0fea5dSIngo Weinhold va_list list; 1460c0fea5dSIngo Weinhold va_start(list, format); 1470c0fea5dSIngo Weinhold 1480c0fea5dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 1490c0fea5dSIngo Weinhold _kern_debug_output(buffer); 1500c0fea5dSIngo Weinhold 1510c0fea5dSIngo Weinhold va_end(list); 1520c0fea5dSIngo Weinhold } 1535d0638bfSIngo Weinhold 1545d0638bfSIngo Weinhold #define FATAL(x...) \ 1555d0638bfSIngo Weinhold do { \ 1565d0638bfSIngo Weinhold dprintf("runtime_loader: " x); \ 1575d0638bfSIngo Weinhold if (!sProgramLoaded) \ 1585d0638bfSIngo Weinhold printf("runtime_loader: " x); \ 1595d0638bfSIngo Weinhold } while (false) 1600c0fea5dSIngo Weinhold 1610c0fea5dSIngo Weinhold 16234982809SIngo Weinhold /*! Mini atoi(), so we don't have to include the libroot dependencies. 16334982809SIngo Weinhold */ 16434982809SIngo Weinhold int 16534982809SIngo Weinhold atoi(const char* num) 16634982809SIngo Weinhold { 16734982809SIngo Weinhold int result = 0; 16834982809SIngo Weinhold while (*num >= '0' && *num <= '9') { 16934982809SIngo Weinhold result = (result * 10) + (*num - '0'); 17034982809SIngo Weinhold num++; 17134982809SIngo Weinhold } 17234982809SIngo Weinhold 17334982809SIngo Weinhold return result; 17434982809SIngo Weinhold } 17534982809SIngo Weinhold 17634982809SIngo Weinhold 1776bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING 1787486b72dSIngo Weinhold 1797486b72dSIngo Weinhold void 1807486b72dSIngo Weinhold ktrace_printf(const char *format, ...) 1817486b72dSIngo Weinhold { 1827486b72dSIngo Weinhold va_list list; 1837486b72dSIngo Weinhold va_start(list, format); 1847486b72dSIngo Weinhold 1857486b72dSIngo Weinhold char buffer[1024]; 1867486b72dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 1877486b72dSIngo Weinhold _kern_ktrace_output(buffer); 1887486b72dSIngo Weinhold 1897486b72dSIngo Weinhold va_end(list); 1907486b72dSIngo Weinhold } 1917486b72dSIngo Weinhold 1927486b72dSIngo Weinhold #define KTRACE(x...) ktrace_printf(x) 1937486b72dSIngo Weinhold 1947486b72dSIngo Weinhold #else 1957486b72dSIngo Weinhold # define KTRACE(x...) 1967486b72dSIngo Weinhold #endif // RUNTIME_LOADER_TRACING 1977486b72dSIngo Weinhold 1987486b72dSIngo Weinhold 1990c0fea5dSIngo Weinhold static void 2000c0fea5dSIngo Weinhold rld_unlock() 2010c0fea5dSIngo Weinhold { 202e73923b0SAxel Dörfler if (sSemCount-- == 1) { 203e73923b0SAxel Dörfler sSemOwner = -1; 204e73923b0SAxel Dörfler release_sem(sSem); 2050c0fea5dSIngo Weinhold } 2060c0fea5dSIngo Weinhold } 2070c0fea5dSIngo Weinhold 2080c0fea5dSIngo Weinhold 2090c0fea5dSIngo Weinhold static void 2100c0fea5dSIngo Weinhold rld_lock() 2110c0fea5dSIngo Weinhold { 2120c0fea5dSIngo Weinhold thread_id self = find_thread(NULL); 213e73923b0SAxel Dörfler if (self != sSemOwner) { 214e73923b0SAxel Dörfler acquire_sem(sSem); 215e73923b0SAxel Dörfler sSemOwner = self; 2160c0fea5dSIngo Weinhold } 217e73923b0SAxel Dörfler sSemCount++; 2180c0fea5dSIngo Weinhold } 2190c0fea5dSIngo Weinhold 2200c0fea5dSIngo Weinhold 2210c0fea5dSIngo Weinhold static void 2220c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image) 2230c0fea5dSIngo Weinhold { 2240c0fea5dSIngo Weinhold image->next = 0; 2250c0fea5dSIngo Weinhold 2260c0fea5dSIngo Weinhold image->prev = queue->tail; 2270c0fea5dSIngo Weinhold if (queue->tail) 2280c0fea5dSIngo Weinhold queue->tail->next = image; 2290c0fea5dSIngo Weinhold 2300c0fea5dSIngo Weinhold queue->tail = image; 2310c0fea5dSIngo Weinhold if (!queue->head) 2320c0fea5dSIngo Weinhold queue->head = image; 2330c0fea5dSIngo Weinhold } 2340c0fea5dSIngo Weinhold 2350c0fea5dSIngo Weinhold 2360c0fea5dSIngo Weinhold static void 2370c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image) 2380c0fea5dSIngo Weinhold { 2390c0fea5dSIngo Weinhold if (image->next) 2400c0fea5dSIngo Weinhold image->next->prev = image->prev; 2410c0fea5dSIngo Weinhold else 2420c0fea5dSIngo Weinhold queue->tail = image->prev; 2430c0fea5dSIngo Weinhold 2440c0fea5dSIngo Weinhold if (image->prev) 2450c0fea5dSIngo Weinhold image->prev->next = image->next; 2460c0fea5dSIngo Weinhold else 2470c0fea5dSIngo Weinhold queue->head = image->next; 2480c0fea5dSIngo Weinhold 2490c0fea5dSIngo Weinhold image->prev = 0; 2500c0fea5dSIngo Weinhold image->next = 0; 2510c0fea5dSIngo Weinhold } 2520c0fea5dSIngo Weinhold 2530c0fea5dSIngo Weinhold 2540c0fea5dSIngo Weinhold static uint32 2550c0fea5dSIngo Weinhold elf_hash(const uint8 *name) 2560c0fea5dSIngo Weinhold { 2570c0fea5dSIngo Weinhold uint32 hash = 0; 2580c0fea5dSIngo Weinhold uint32 temp; 2590c0fea5dSIngo Weinhold 2600c0fea5dSIngo Weinhold while (*name) { 2610c0fea5dSIngo Weinhold hash = (hash << 4) + *name++; 2620c0fea5dSIngo Weinhold if ((temp = hash & 0xf0000000)) { 2630c0fea5dSIngo Weinhold hash ^= temp >> 24; 2640c0fea5dSIngo Weinhold } 2650c0fea5dSIngo Weinhold hash &= ~temp; 2660c0fea5dSIngo Weinhold } 2670c0fea5dSIngo Weinhold return hash; 2680c0fea5dSIngo Weinhold } 2690c0fea5dSIngo Weinhold 2700c0fea5dSIngo Weinhold 2714bef3723SAxel Dörfler static inline bool 2724bef3723SAxel Dörfler report_errors() 2734bef3723SAxel Dörfler { 2744bef3723SAxel Dörfler return gProgramArgs->error_port >= 0; 2754bef3723SAxel Dörfler } 2764bef3723SAxel Dörfler 2774bef3723SAxel Dörfler 2789a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork. 2799a6072a3SAxel Dörfler static status_t 2809a6072a3SAxel Dörfler update_image_id(image_t *image) 2819a6072a3SAxel Dörfler { 2829a6072a3SAxel Dörfler int32 cookie = 0; 2839a6072a3SAxel Dörfler image_info info; 2849a6072a3SAxel Dörfler while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info, 2859a6072a3SAxel Dörfler sizeof(image_info)) == B_OK) { 2869a6072a3SAxel Dörfler for (uint32 i = 0; i < image->num_regions; i++) { 2879a6072a3SAxel Dörfler if (image->regions[i].vmstart == (addr_t)info.text) { 2889a6072a3SAxel Dörfler image->id = info.id; 2899a6072a3SAxel Dörfler return B_OK; 2909a6072a3SAxel Dörfler } 2919a6072a3SAxel Dörfler } 2929a6072a3SAxel Dörfler } 2939a6072a3SAxel Dörfler 2949a6072a3SAxel Dörfler FATAL("Could not update image ID %ld after fork()!\n", image->id); 2959a6072a3SAxel Dörfler return B_ENTRY_NOT_FOUND; 2969a6072a3SAxel Dörfler } 2979a6072a3SAxel Dörfler 2989a6072a3SAxel Dörfler 2999a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images. 3009a6072a3SAxel Dörfler static status_t 3019a6072a3SAxel Dörfler update_image_ids(void) 3029a6072a3SAxel Dörfler { 3039a6072a3SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 3049a6072a3SAxel Dörfler status_t status = update_image_id(image); 3059a6072a3SAxel Dörfler if (status != B_OK) 3069a6072a3SAxel Dörfler return status; 3079a6072a3SAxel Dörfler } 3089a6072a3SAxel Dörfler for (image_t *image = sDisposableImages.head; image; image = image->next) { 3099a6072a3SAxel Dörfler status_t status = update_image_id(image); 3109a6072a3SAxel Dörfler if (status != B_OK) 3119a6072a3SAxel Dörfler return status; 3129a6072a3SAxel Dörfler } 3139a6072a3SAxel Dörfler 3149a6072a3SAxel Dörfler sInvalidImageIDs = false; 3159a6072a3SAxel Dörfler return B_OK; 3169a6072a3SAxel Dörfler } 3179a6072a3SAxel Dörfler 3189a6072a3SAxel Dörfler 3190c0fea5dSIngo Weinhold static image_t * 3200c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath, 3210c0fea5dSIngo Weinhold uint32 typeMask) 3220c0fea5dSIngo Weinhold { 3239a6072a3SAxel Dörfler for (image_t *image = queue->head; image; image = image->next) { 3240c0fea5dSIngo Weinhold const char *imageName = isPath ? image->path : image->name; 3250c0fea5dSIngo Weinhold int length = isPath ? sizeof(image->path) : sizeof(image->name); 3260c0fea5dSIngo Weinhold 3270c0fea5dSIngo Weinhold if (!strncmp(imageName, name, length) 3280c0fea5dSIngo Weinhold && (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) { 3290c0fea5dSIngo Weinhold return image; 3300c0fea5dSIngo Weinhold } 3310c0fea5dSIngo Weinhold } 3320c0fea5dSIngo Weinhold 3330c0fea5dSIngo Weinhold return NULL; 3340c0fea5dSIngo Weinhold } 3350c0fea5dSIngo Weinhold 3360c0fea5dSIngo Weinhold 3370c0fea5dSIngo Weinhold static image_t * 3380c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask) 3390c0fea5dSIngo Weinhold { 3409a6072a3SAxel Dörfler bool isPath = strchr(name, '/') != NULL; 34146f4d849SIngo Weinhold return find_image_in_queue(&sLoadedImages, name, isPath, typeMask); 3420c0fea5dSIngo Weinhold } 3430c0fea5dSIngo Weinhold 3440c0fea5dSIngo Weinhold 3450c0fea5dSIngo Weinhold static image_t * 3460c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id) 3470c0fea5dSIngo Weinhold { 3489a6072a3SAxel Dörfler if (sInvalidImageIDs) { 3499a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 3509a6072a3SAxel Dörfler update_image_ids(); 3519a6072a3SAxel Dörfler } 3520c0fea5dSIngo Weinhold 3539a6072a3SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 3540c0fea5dSIngo Weinhold if (image->id == id) 3550c0fea5dSIngo Weinhold return image; 3560c0fea5dSIngo Weinhold } 3570c0fea5dSIngo Weinhold 3580c0fea5dSIngo Weinhold // For the termination routine, we need to look into the list of 3590c0fea5dSIngo Weinhold // disposable images as well 3609a6072a3SAxel Dörfler for (image_t *image = sDisposableImages.head; image; image = image->next) { 3610c0fea5dSIngo Weinhold if (image->id == id) 3620c0fea5dSIngo Weinhold return image; 3630c0fea5dSIngo Weinhold } 3640c0fea5dSIngo Weinhold 3650c0fea5dSIngo Weinhold return NULL; 3660c0fea5dSIngo Weinhold } 3670c0fea5dSIngo Weinhold 3680c0fea5dSIngo Weinhold 3695fd6637bSIngo Weinhold static image_t* 3705fd6637bSIngo Weinhold get_program_image() 37112a5e9a4SAxel Dörfler { 37212a5e9a4SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 37312a5e9a4SAxel Dörfler if (image->type == B_APP_IMAGE) 3745fd6637bSIngo Weinhold return image; 37512a5e9a4SAxel Dörfler } 37612a5e9a4SAxel Dörfler 37712a5e9a4SAxel Dörfler return NULL; 37812a5e9a4SAxel Dörfler } 37912a5e9a4SAxel Dörfler 38012a5e9a4SAxel Dörfler 3815fd6637bSIngo Weinhold static const char * 3825fd6637bSIngo Weinhold get_program_path() 3835fd6637bSIngo Weinhold { 3845fd6637bSIngo Weinhold if (image_t* image = get_program_image()) 3855fd6637bSIngo Weinhold return image->path; 3865fd6637bSIngo Weinhold 3875fd6637bSIngo Weinhold return NULL; 3885fd6637bSIngo Weinhold } 3895fd6637bSIngo Weinhold 3905fd6637bSIngo Weinhold 3910c0fea5dSIngo Weinhold static status_t 39212a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize, 39312a5e9a4SAxel Dörfler int32 *_sheaderSize) 3940c0fea5dSIngo Weinhold { 3950c0fea5dSIngo Weinhold if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) 3960c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 3970c0fea5dSIngo Weinhold 3980c0fea5dSIngo Weinhold if (eheader->e_ident[4] != ELFCLASS32) 3990c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4000c0fea5dSIngo Weinhold 4010c0fea5dSIngo Weinhold if (eheader->e_phoff == 0) 4020c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4030c0fea5dSIngo Weinhold 4040c0fea5dSIngo Weinhold if (eheader->e_phentsize < sizeof(struct Elf32_Phdr)) 4050c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 4060c0fea5dSIngo Weinhold 4070c0fea5dSIngo Weinhold *_pheaderSize = eheader->e_phentsize * eheader->e_phnum; 4080c0fea5dSIngo Weinhold *_sheaderSize = eheader->e_shentsize * eheader->e_shnum; 4090c0fea5dSIngo Weinhold 4105aa7b7b6SMarcus Overhagen if (*_pheaderSize <= 0 || *_sheaderSize <= 0) 4115aa7b7b6SMarcus Overhagen return B_NOT_AN_EXECUTABLE; 4125aa7b7b6SMarcus Overhagen 4135aa7b7b6SMarcus Overhagen return B_OK; 4140c0fea5dSIngo Weinhold } 4150c0fea5dSIngo Weinhold 4160c0fea5dSIngo Weinhold 4170c0fea5dSIngo Weinhold static int32 4180c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize) 4190c0fea5dSIngo Weinhold { 4200c0fea5dSIngo Weinhold struct Elf32_Phdr *pheaders; 4210c0fea5dSIngo Weinhold int32 count = 0; 4220c0fea5dSIngo Weinhold int i; 4230c0fea5dSIngo Weinhold 4240c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 4250c0fea5dSIngo Weinhold pheaders = (struct Elf32_Phdr *)(buff + i * phentsize); 4260c0fea5dSIngo Weinhold 4270c0fea5dSIngo Weinhold switch (pheaders->p_type) { 4280c0fea5dSIngo Weinhold case PT_NULL: 4290c0fea5dSIngo Weinhold /* NOP header */ 4300c0fea5dSIngo Weinhold break; 4310c0fea5dSIngo Weinhold case PT_LOAD: 4320c0fea5dSIngo Weinhold count += 1; 4330c0fea5dSIngo Weinhold if (pheaders->p_memsz != pheaders->p_filesz) { 4340c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz); 4350c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz); 4360c0fea5dSIngo Weinhold 4370c0fea5dSIngo Weinhold if (A != B) 4380c0fea5dSIngo Weinhold count += 1; 4390c0fea5dSIngo Weinhold } 4400c0fea5dSIngo Weinhold break; 4410c0fea5dSIngo Weinhold case PT_DYNAMIC: 4420c0fea5dSIngo Weinhold /* will be handled at some other place */ 4430c0fea5dSIngo Weinhold break; 4440c0fea5dSIngo Weinhold case PT_INTERP: 4450c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 4460c0fea5dSIngo Weinhold break; 4470c0fea5dSIngo Weinhold case PT_NOTE: 4480c0fea5dSIngo Weinhold /* unsupported */ 4490c0fea5dSIngo Weinhold break; 4500c0fea5dSIngo Weinhold case PT_SHLIB: 4510c0fea5dSIngo Weinhold /* undefined semantics */ 4520c0fea5dSIngo Weinhold break; 4530c0fea5dSIngo Weinhold case PT_PHDR: 4540c0fea5dSIngo Weinhold /* we don't use it */ 4550c0fea5dSIngo Weinhold break; 4560c0fea5dSIngo Weinhold default: 4570c0fea5dSIngo Weinhold FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type); 4580c0fea5dSIngo Weinhold return B_BAD_DATA; 4590c0fea5dSIngo Weinhold } 4600c0fea5dSIngo Weinhold } 4610c0fea5dSIngo Weinhold 4620c0fea5dSIngo Weinhold return count; 4630c0fea5dSIngo Weinhold } 4640c0fea5dSIngo Weinhold 4650c0fea5dSIngo Weinhold 4660c0fea5dSIngo Weinhold static image_t * 4670c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions) 4680c0fea5dSIngo Weinhold { 4690c0fea5dSIngo Weinhold size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t); 4700c0fea5dSIngo Weinhold const char *lastSlash; 4710c0fea5dSIngo Weinhold 4720c0fea5dSIngo Weinhold image_t *image = (image_t*)malloc(allocSize); 4730c0fea5dSIngo Weinhold if (image == NULL) { 4740c0fea5dSIngo Weinhold FATAL("no memory for image %s\n", path); 4750c0fea5dSIngo Weinhold return NULL; 4760c0fea5dSIngo Weinhold } 4770c0fea5dSIngo Weinhold 4780c0fea5dSIngo Weinhold memset(image, 0, allocSize); 4790c0fea5dSIngo Weinhold 4800c0fea5dSIngo Weinhold strlcpy(image->path, path, sizeof(image->path)); 4810c0fea5dSIngo Weinhold 4820c0fea5dSIngo Weinhold // Make the last component of the supplied name the image name. 4830c0fea5dSIngo Weinhold // If present, DT_SONAME will replace this name. 4840c0fea5dSIngo Weinhold if ((lastSlash = strrchr(name, '/'))) 4850c0fea5dSIngo Weinhold strlcpy(image->name, lastSlash + 1, sizeof(image->name)); 4860c0fea5dSIngo Weinhold else 4870c0fea5dSIngo Weinhold strlcpy(image->name, name, sizeof(image->name)); 4880c0fea5dSIngo Weinhold 4890c0fea5dSIngo Weinhold image->ref_count = 1; 4900c0fea5dSIngo Weinhold image->num_regions = num_regions; 4910c0fea5dSIngo Weinhold 4920c0fea5dSIngo Weinhold return image; 4930c0fea5dSIngo Weinhold } 4940c0fea5dSIngo Weinhold 4950c0fea5dSIngo Weinhold 4960c0fea5dSIngo Weinhold static void 4970c0fea5dSIngo Weinhold delete_image_struct(image_t *image) 4980c0fea5dSIngo Weinhold { 4990c0fea5dSIngo Weinhold #ifdef DEBUG 5000c0fea5dSIngo Weinhold size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t); 5010c0fea5dSIngo Weinhold memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed); 5020c0fea5dSIngo Weinhold #endif 5030c0fea5dSIngo Weinhold free(image->needed); 504*10b4b5d1SIngo Weinhold free(image->symbol_resolution_images); 505*10b4b5d1SIngo Weinhold 506*10b4b5d1SIngo Weinhold while (RuntimeLoaderSymbolPatcher* patcher 507*10b4b5d1SIngo Weinhold = image->defined_symbol_patchers) { 508*10b4b5d1SIngo Weinhold image->defined_symbol_patchers = patcher->next; 509*10b4b5d1SIngo Weinhold delete patcher; 510*10b4b5d1SIngo Weinhold } 511*10b4b5d1SIngo Weinhold while (RuntimeLoaderSymbolPatcher* patcher 512*10b4b5d1SIngo Weinhold = image->undefined_symbol_patchers) { 513*10b4b5d1SIngo Weinhold image->undefined_symbol_patchers = patcher->next; 514*10b4b5d1SIngo Weinhold delete patcher; 515*10b4b5d1SIngo Weinhold } 5160c0fea5dSIngo Weinhold 5170c0fea5dSIngo Weinhold #ifdef DEBUG 5189a6072a3SAxel Dörfler // overwrite images to make sure they aren't accidently reused anywhere 5190c0fea5dSIngo Weinhold memset(image, 0xa5, size); 5200c0fea5dSIngo Weinhold #endif 5210c0fea5dSIngo Weinhold free(image); 5220c0fea5dSIngo Weinhold } 5230c0fea5dSIngo Weinhold 5240c0fea5dSIngo Weinhold 5250c0fea5dSIngo Weinhold static void 5260c0fea5dSIngo Weinhold delete_image(image_t *image) 5270c0fea5dSIngo Weinhold { 5282760c4cdSAxel Dörfler if (image == NULL) 5292760c4cdSAxel Dörfler return; 5302760c4cdSAxel Dörfler 5310c0fea5dSIngo Weinhold _kern_unregister_image(image->id); 5320c0fea5dSIngo Weinhold // registered in load_container() 5330c0fea5dSIngo Weinhold 5340c0fea5dSIngo Weinhold delete_image_struct(image); 5350c0fea5dSIngo Weinhold } 5360c0fea5dSIngo Weinhold 5370c0fea5dSIngo Weinhold 5380c0fea5dSIngo Weinhold static status_t 5390c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) 5400c0fea5dSIngo Weinhold { 5410c0fea5dSIngo Weinhold struct Elf32_Phdr *pheader; 5420c0fea5dSIngo Weinhold int regcount; 5430c0fea5dSIngo Weinhold int i; 5440c0fea5dSIngo Weinhold 5450c0fea5dSIngo Weinhold regcount = 0; 5460c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 5470c0fea5dSIngo Weinhold pheader = (struct Elf32_Phdr *)(buff + i * phentsize); 5480c0fea5dSIngo Weinhold 5490c0fea5dSIngo Weinhold switch (pheader->p_type) { 5500c0fea5dSIngo Weinhold case PT_NULL: 5510c0fea5dSIngo Weinhold /* NOP header */ 5520c0fea5dSIngo Weinhold break; 5530c0fea5dSIngo Weinhold case PT_LOAD: 5540c0fea5dSIngo Weinhold if (pheader->p_memsz == pheader->p_filesz) { 5550c0fea5dSIngo Weinhold /* 5560c0fea5dSIngo Weinhold * everything in one area 5570c0fea5dSIngo Weinhold */ 5580c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 5590c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz; 5600c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 5610c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz 5620c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 5630c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 5640c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 5650c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 5660c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 5670c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 5680c0fea5dSIngo Weinhold // this is a writable segment 5690c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 5700c0fea5dSIngo Weinhold } 5710c0fea5dSIngo Weinhold } else { 5720c0fea5dSIngo Weinhold /* 5730c0fea5dSIngo Weinhold * may require splitting 5740c0fea5dSIngo Weinhold */ 5750c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz); 5760c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz); 5770c0fea5dSIngo Weinhold 5780c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 5790c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_filesz; 5800c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 5810c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz 5820c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 5830c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 5840c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 5850c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 5860c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 5870c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 5880c0fea5dSIngo Weinhold // this is a writable segment 5890c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 5900c0fea5dSIngo Weinhold } 5910c0fea5dSIngo Weinhold 5920c0fea5dSIngo Weinhold if (A != B) { 5930c0fea5dSIngo Weinhold /* 5940c0fea5dSIngo Weinhold * yeah, it requires splitting 5950c0fea5dSIngo Weinhold */ 5960c0fea5dSIngo Weinhold regcount += 1; 5970c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 5980c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz; 5990c0fea5dSIngo Weinhold image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize; 6000c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr)) 6010c0fea5dSIngo Weinhold - image->regions[regcount-1].vmsize; 6020c0fea5dSIngo Weinhold image->regions[regcount].fdstart = 0; 6030c0fea5dSIngo Weinhold image->regions[regcount].fdsize = 0; 6040c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 6050c0fea5dSIngo Weinhold image->regions[regcount].flags = RFLAG_ANON; 6060c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 6070c0fea5dSIngo Weinhold // this is a writable segment 6080c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 6090c0fea5dSIngo Weinhold } 6100c0fea5dSIngo Weinhold } 6110c0fea5dSIngo Weinhold } 6120c0fea5dSIngo Weinhold regcount += 1; 6130c0fea5dSIngo Weinhold break; 6140c0fea5dSIngo Weinhold case PT_DYNAMIC: 6150c0fea5dSIngo Weinhold image->dynamic_ptr = pheader->p_vaddr; 6160c0fea5dSIngo Weinhold break; 6170c0fea5dSIngo Weinhold case PT_INTERP: 6180c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 6190c0fea5dSIngo Weinhold break; 6200c0fea5dSIngo Weinhold case PT_NOTE: 6210c0fea5dSIngo Weinhold /* unsupported */ 6220c0fea5dSIngo Weinhold break; 6230c0fea5dSIngo Weinhold case PT_SHLIB: 6240c0fea5dSIngo Weinhold /* undefined semantics */ 6250c0fea5dSIngo Weinhold break; 6260c0fea5dSIngo Weinhold case PT_PHDR: 6270c0fea5dSIngo Weinhold /* we don't use it */ 6280c0fea5dSIngo Weinhold break; 6290c0fea5dSIngo Weinhold default: 6300c0fea5dSIngo Weinhold FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type); 6310c0fea5dSIngo Weinhold return B_BAD_DATA; 6320c0fea5dSIngo Weinhold } 6330c0fea5dSIngo Weinhold } 6340c0fea5dSIngo Weinhold 6350c0fea5dSIngo Weinhold return B_OK; 6360c0fea5dSIngo Weinhold } 6370c0fea5dSIngo Weinhold 6380c0fea5dSIngo Weinhold 6390c0fea5dSIngo Weinhold static bool 64034982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader, 64134982809SIngo Weinhold int32 sheaderSize, char* buffer, size_t bufferSize) 64234982809SIngo Weinhold { 64334982809SIngo Weinhold image->gcc_version.major = 0; 64434982809SIngo Weinhold image->gcc_version.middle = 0; 64534982809SIngo Weinhold image->gcc_version.minor = 0; 64634982809SIngo Weinhold 64734982809SIngo Weinhold if (sheaderSize > (int)bufferSize) { 64834982809SIngo Weinhold FATAL("Cannot handle section headers bigger than %lu\n", bufferSize); 64934982809SIngo Weinhold return false; 65034982809SIngo Weinhold } 65134982809SIngo Weinhold 65234982809SIngo Weinhold // read section headers 65334982809SIngo Weinhold ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize); 65434982809SIngo Weinhold if (length != sheaderSize) { 65534982809SIngo Weinhold FATAL("Could not read section headers: %s\n", strerror(length)); 65634982809SIngo Weinhold return false; 65734982809SIngo Weinhold } 65834982809SIngo Weinhold 65934982809SIngo Weinhold // load the string section 66034982809SIngo Weinhold Elf32_Shdr* sectionHeader 66134982809SIngo Weinhold = (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize); 66234982809SIngo Weinhold 66334982809SIngo Weinhold if (sheaderSize + sectionHeader->sh_size > bufferSize) { 66434982809SIngo Weinhold FATAL("Buffer not big enough for section string section\n"); 66534982809SIngo Weinhold return false; 66634982809SIngo Weinhold } 66734982809SIngo Weinhold 66834982809SIngo Weinhold char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size; 66934982809SIngo Weinhold length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings, 67034982809SIngo Weinhold sectionHeader->sh_size); 67134982809SIngo Weinhold if (length != (int)sectionHeader->sh_size) { 67234982809SIngo Weinhold FATAL("Could not read section string section: %s\n", strerror(length)); 67334982809SIngo Weinhold return false; 67434982809SIngo Weinhold } 67534982809SIngo Weinhold 67634982809SIngo Weinhold // find the .comment section 67734982809SIngo Weinhold off_t commentOffset = 0; 67834982809SIngo Weinhold size_t commentSize = 0; 67934982809SIngo Weinhold for (uint32 i = 0; i < eheader.e_shnum; i++) { 68034982809SIngo Weinhold sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize); 68134982809SIngo Weinhold const char* sectionName = sectionStrings + sectionHeader->sh_name; 68234982809SIngo Weinhold if (sectionHeader->sh_name != 0 68334982809SIngo Weinhold && strcmp(sectionName, ".comment") == 0) { 68434982809SIngo Weinhold commentOffset = sectionHeader->sh_offset; 68534982809SIngo Weinhold commentSize = sectionHeader->sh_size; 68634982809SIngo Weinhold break; 68734982809SIngo Weinhold } 68834982809SIngo Weinhold } 68934982809SIngo Weinhold 69034982809SIngo Weinhold if (commentSize == 0) { 69134982809SIngo Weinhold FATAL("Could not find .comment section\n"); 69234982809SIngo Weinhold return false; 69334982809SIngo Weinhold } 69434982809SIngo Weinhold 69534982809SIngo Weinhold // read a part of the comment section 69634982809SIngo Weinhold if (commentSize > 512) 69734982809SIngo Weinhold commentSize = 512; 69834982809SIngo Weinhold 69934982809SIngo Weinhold length = _kern_read(fd, commentOffset, buffer, commentSize); 70034982809SIngo Weinhold if (length != (int)commentSize) { 70134982809SIngo Weinhold FATAL("Could not read .comment section: %s\n", strerror(length)); 70234982809SIngo Weinhold return false; 70334982809SIngo Weinhold } 70434982809SIngo Weinhold 70534982809SIngo Weinhold // the common prefix of the strings in the .comment section 70634982809SIngo Weinhold static const char* kGCCVersionPrefix = "GCC: (GNU) "; 70734982809SIngo Weinhold size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix); 70834982809SIngo Weinhold 70934982809SIngo Weinhold size_t index = 0; 71034982809SIngo Weinhold int gccMajor = 0; 71134982809SIngo Weinhold int gccMiddle = 0; 71234982809SIngo Weinhold int gccMinor = 0; 7132716cfd3SAxel Dörfler bool isHaiku = true; 71434982809SIngo Weinhold 71534982809SIngo Weinhold // Read up to 10 comments. The first three or four are usually from the 71634982809SIngo Weinhold // glue code. 71734982809SIngo Weinhold for (int i = 0; i < 10; i++) { 71834982809SIngo Weinhold // skip '\0' 71934982809SIngo Weinhold while (index < commentSize && buffer[index] == '\0') 72034982809SIngo Weinhold index++; 72134982809SIngo Weinhold char* stringStart = buffer + index; 72234982809SIngo Weinhold 72334982809SIngo Weinhold // find string end 72434982809SIngo Weinhold while (index < commentSize && buffer[index] != '\0') 72534982809SIngo Weinhold index++; 72634982809SIngo Weinhold 72734982809SIngo Weinhold // ignore the entry at the end of the buffer 72834982809SIngo Weinhold if (index == commentSize) 72934982809SIngo Weinhold break; 73034982809SIngo Weinhold 73134982809SIngo Weinhold // We have to analyze string like these: 73234982809SIngo Weinhold // GCC: (GNU) 2.9-beos-991026 73334982809SIngo Weinhold // GCC: (GNU) 2.95.3-haiku-080322 73434982809SIngo Weinhold // GCC: (GNU) 4.1.2 73534982809SIngo Weinhold 73634982809SIngo Weinhold // skip the common prefix 73734982809SIngo Weinhold if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0) 73834982809SIngo Weinhold continue; 73934982809SIngo Weinhold 74034982809SIngo Weinhold // the rest is the GCC version 74134982809SIngo Weinhold char* gccVersion = stringStart + gccVersionPrefixLen; 74234982809SIngo Weinhold char* gccPlatform = strchr(gccVersion, '-'); 74334982809SIngo Weinhold char* patchLevel = NULL; 74434982809SIngo Weinhold if (gccPlatform != NULL) { 74534982809SIngo Weinhold *gccPlatform = '\0'; 74634982809SIngo Weinhold gccPlatform++; 74734982809SIngo Weinhold patchLevel = strchr(gccPlatform, '-'); 74834982809SIngo Weinhold if (patchLevel != NULL) { 74934982809SIngo Weinhold *patchLevel = '\0'; 75034982809SIngo Weinhold patchLevel++; 75134982809SIngo Weinhold } 75234982809SIngo Weinhold } 75334982809SIngo Weinhold 75434982809SIngo Weinhold // split the gcc version into major, middle, and minor 75534982809SIngo Weinhold int version[3] = { 0, 0, 0 }; 75634982809SIngo Weinhold 75734982809SIngo Weinhold for (int k = 0; gccVersion != NULL && k < 3; k++) { 75834982809SIngo Weinhold char* dot = strchr(gccVersion, '.'); 75934982809SIngo Weinhold if (dot) { 76034982809SIngo Weinhold *dot = '\0'; 76134982809SIngo Weinhold dot++; 76234982809SIngo Weinhold } 76334982809SIngo Weinhold version[k] = atoi(gccVersion); 76434982809SIngo Weinhold gccVersion = dot; 76534982809SIngo Weinhold } 76634982809SIngo Weinhold 76734982809SIngo Weinhold // got any version? 76834982809SIngo Weinhold if (version[0] == 0) 76934982809SIngo Weinhold continue; 77034982809SIngo Weinhold 77134982809SIngo Weinhold // Select the gcc version with the smallest major, but the greatest 77234982809SIngo Weinhold // middle/minor. This should usually ignore the glue code version as 77334982809SIngo Weinhold // well as cases where e.g. in a gcc 2 program a single C file has 77434982809SIngo Weinhold // been compiled with gcc 4. 77534982809SIngo Weinhold if (gccMajor == 0 || gccMajor > version[0] 77634982809SIngo Weinhold || gccMajor == version[0] 77734982809SIngo Weinhold && (gccMiddle < version[1] 77834982809SIngo Weinhold || gccMiddle == version[1] && gccMinor < version[2])) { 77934982809SIngo Weinhold gccMajor = version[0]; 78034982809SIngo Weinhold gccMiddle = version[1]; 78134982809SIngo Weinhold gccMinor = version[2]; 78234982809SIngo Weinhold } 7832716cfd3SAxel Dörfler 78485f9771aSFrançois Revol if (gccMajor == 2 && gccPlatform != NULL && strcmp(gccPlatform, "haiku")) 7852716cfd3SAxel Dörfler isHaiku = false; 78634982809SIngo Weinhold } 78734982809SIngo Weinhold 78834982809SIngo Weinhold image->gcc_version.major = gccMajor; 78934982809SIngo Weinhold image->gcc_version.middle = gccMiddle; 79034982809SIngo Weinhold image->gcc_version.minor = gccMinor; 7912716cfd3SAxel Dörfler image->gcc_version.haiku = isHaiku; 79234982809SIngo Weinhold 79334982809SIngo Weinhold return gccMajor != 0; 79434982809SIngo Weinhold } 79534982809SIngo Weinhold 79634982809SIngo Weinhold 79734982809SIngo Weinhold static bool 7980c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image) 7990c0fea5dSIngo Weinhold { 8000c0fea5dSIngo Weinhold uint32 i; 8010c0fea5dSIngo Weinhold 8020c0fea5dSIngo Weinhold if (!image->dynamic_ptr) 8030c0fea5dSIngo Weinhold return true; 8040c0fea5dSIngo Weinhold 8050c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 8060c0fea5dSIngo Weinhold if (image->dynamic_ptr >= image->regions[i].start 8070c0fea5dSIngo Weinhold && image->dynamic_ptr < image->regions[i].start + image->regions[i].size) 8080c0fea5dSIngo Weinhold return true; 8090c0fea5dSIngo Weinhold } 8100c0fea5dSIngo Weinhold 8110c0fea5dSIngo Weinhold return false; 8120c0fea5dSIngo Weinhold } 8130c0fea5dSIngo Weinhold 8140c0fea5dSIngo Weinhold 8150c0fea5dSIngo Weinhold /** This function will change the protection of all read-only segments 8160c0fea5dSIngo Weinhold * to really be read-only. 8170c0fea5dSIngo Weinhold * The areas have to be read/write first, so that they can be relocated. 8180c0fea5dSIngo Weinhold */ 8190c0fea5dSIngo Weinhold 8200c0fea5dSIngo Weinhold static void 8210c0fea5dSIngo Weinhold remap_images(void) 8220c0fea5dSIngo Weinhold { 8230c0fea5dSIngo Weinhold image_t *image; 8240c0fea5dSIngo Weinhold uint32 i; 8250c0fea5dSIngo Weinhold 8260c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image != NULL; image = image->next) { 8270c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 8280c0fea5dSIngo Weinhold if ((image->regions[i].flags & RFLAG_RW) == 0 8290c0fea5dSIngo Weinhold && (image->regions[i].flags & RFLAG_REMAPPED) == 0) { 8300c0fea5dSIngo Weinhold // we only need to do this once, so we remember those we've already mapped 8310c0fea5dSIngo Weinhold if (_kern_set_area_protection(image->regions[i].id, 8320c0fea5dSIngo Weinhold B_READ_AREA | B_EXECUTE_AREA) == B_OK) 8330c0fea5dSIngo Weinhold image->regions[i].flags |= RFLAG_REMAPPED; 8340c0fea5dSIngo Weinhold } 8350c0fea5dSIngo Weinhold } 8360c0fea5dSIngo Weinhold } 8370c0fea5dSIngo Weinhold } 8380c0fea5dSIngo Weinhold 8390c0fea5dSIngo Weinhold 8400c0fea5dSIngo Weinhold static status_t 8410c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed) 8420c0fea5dSIngo Weinhold { 8430c0fea5dSIngo Weinhold status_t status = B_OK; 8440c0fea5dSIngo Weinhold const char *baseName; 8450c0fea5dSIngo Weinhold uint32 i; 8460c0fea5dSIngo Weinhold 8470c0fea5dSIngo Weinhold (void)(fd); 8480c0fea5dSIngo Weinhold 8490c0fea5dSIngo Weinhold // cut the file name from the path as base name for the created areas 8500c0fea5dSIngo Weinhold baseName = strrchr(path, '/'); 8510c0fea5dSIngo Weinhold if (baseName != NULL) 8520c0fea5dSIngo Weinhold baseName++; 8530c0fea5dSIngo Weinhold else 8540c0fea5dSIngo Weinhold baseName = path; 8550c0fea5dSIngo Weinhold 8560c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 8570c0fea5dSIngo Weinhold char regionName[B_OS_NAME_LENGTH]; 8580c0fea5dSIngo Weinhold addr_t loadAddress; 8590c0fea5dSIngo Weinhold uint32 addressSpecifier; 8600c0fea5dSIngo Weinhold 8610c0fea5dSIngo Weinhold // for BeOS compatibility: if we load an old BeOS executable, we 8620c0fea5dSIngo Weinhold // have to relocate it, if possible - we recognize it because the 8630c0fea5dSIngo Weinhold // vmstart is set to 0 (hopefully always) 8640c0fea5dSIngo Weinhold if (fixed && image->regions[i].vmstart == 0) 8650c0fea5dSIngo Weinhold fixed = false; 8660c0fea5dSIngo Weinhold 8670c0fea5dSIngo Weinhold snprintf(regionName, sizeof(regionName), "%s_seg%lu%s", 8680c0fea5dSIngo Weinhold baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro"); 8690c0fea5dSIngo Weinhold 8700c0fea5dSIngo Weinhold if (image->dynamic_ptr && !fixed) { 8710c0fea5dSIngo Weinhold // relocatable image... we can afford to place wherever 8720c0fea5dSIngo Weinhold if (i == 0) { 8730c0fea5dSIngo Weinhold // but only the first segment gets a free ride 8740c0fea5dSIngo Weinhold loadAddress = RLD_PROGRAM_BASE; 8750c0fea5dSIngo Weinhold addressSpecifier = B_BASE_ADDRESS; 8760c0fea5dSIngo Weinhold } else { 8770c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart + image->regions[i-1].delta; 8780c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 8790c0fea5dSIngo Weinhold } 8800c0fea5dSIngo Weinhold } else { 8810c0fea5dSIngo Weinhold // not relocatable, put it where it asks or die trying 8820c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart; 8830c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 8840c0fea5dSIngo Weinhold } 8850c0fea5dSIngo Weinhold 8860c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_ANON) { 8870c0fea5dSIngo Weinhold image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress, 8880c0fea5dSIngo Weinhold addressSpecifier, image->regions[i].vmsize, B_NO_LOCK, 8890c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 8900c0fea5dSIngo Weinhold 8910c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 8920c0fea5dSIngo Weinhold status = image->regions[i].id; 8930c0fea5dSIngo Weinhold goto error; 8940c0fea5dSIngo Weinhold } 8950c0fea5dSIngo Weinhold 8960c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 8970c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 8980c0fea5dSIngo Weinhold } else { 8993cf7ecd1SIngo Weinhold image->regions[i].id = _kern_map_file(regionName, 9003cf7ecd1SIngo Weinhold (void **)&loadAddress, addressSpecifier, 9013cf7ecd1SIngo Weinhold image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA, 9023cf7ecd1SIngo Weinhold REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart)); 9030c0fea5dSIngo Weinhold 9040c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 9050c0fea5dSIngo Weinhold status = image->regions[i].id; 9060c0fea5dSIngo Weinhold goto error; 9070c0fea5dSIngo Weinhold } 9080c0fea5dSIngo Weinhold 9090c0fea5dSIngo Weinhold TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path, 9100c0fea5dSIngo Weinhold (void *)loadAddress, image->regions[i].vmsize, 9110c0fea5dSIngo Weinhold image->regions[i].flags & RFLAG_RW ? "rw" : "read-only")); 9120c0fea5dSIngo Weinhold 9130c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 9140c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 9150c0fea5dSIngo Weinhold 9160c0fea5dSIngo Weinhold // handle trailer bits in data segment 9170c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_RW) { 9180c0fea5dSIngo Weinhold addr_t startClearing; 9190c0fea5dSIngo Weinhold addr_t toClear; 9200c0fea5dSIngo Weinhold 9210c0fea5dSIngo Weinhold startClearing = image->regions[i].vmstart 9220c0fea5dSIngo Weinhold + PAGE_OFFSET(image->regions[i].start) 9230c0fea5dSIngo Weinhold + image->regions[i].size; 9240c0fea5dSIngo Weinhold toClear = image->regions[i].vmsize 9250c0fea5dSIngo Weinhold - PAGE_OFFSET(image->regions[i].start) 9260c0fea5dSIngo Weinhold - image->regions[i].size; 9270c0fea5dSIngo Weinhold 9280c0fea5dSIngo Weinhold TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear)); 9290c0fea5dSIngo Weinhold memset((void *)startClearing, 0, toClear); 9300c0fea5dSIngo Weinhold } 9310c0fea5dSIngo Weinhold } 9320c0fea5dSIngo Weinhold } 9330c0fea5dSIngo Weinhold 9340c0fea5dSIngo Weinhold if (image->dynamic_ptr) 9350c0fea5dSIngo Weinhold image->dynamic_ptr += image->regions[0].delta; 9360c0fea5dSIngo Weinhold 9370c0fea5dSIngo Weinhold return B_OK; 9380c0fea5dSIngo Weinhold 9390c0fea5dSIngo Weinhold error: 9400c0fea5dSIngo Weinhold return status; 9410c0fea5dSIngo Weinhold } 9420c0fea5dSIngo Weinhold 9430c0fea5dSIngo Weinhold 9440c0fea5dSIngo Weinhold static void 9450c0fea5dSIngo Weinhold unmap_image(image_t *image) 9460c0fea5dSIngo Weinhold { 9470c0fea5dSIngo Weinhold uint32 i; 9480c0fea5dSIngo Weinhold 9490c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 9500c0fea5dSIngo Weinhold _kern_delete_area(image->regions[i].id); 9510c0fea5dSIngo Weinhold 9520c0fea5dSIngo Weinhold image->regions[i].id = -1; 9530c0fea5dSIngo Weinhold } 9540c0fea5dSIngo Weinhold } 9550c0fea5dSIngo Weinhold 9560c0fea5dSIngo Weinhold 9570c0fea5dSIngo Weinhold static bool 9580c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image) 9590c0fea5dSIngo Weinhold { 9600c0fea5dSIngo Weinhold struct Elf32_Dyn *d; 9610c0fea5dSIngo Weinhold int i; 9620c0fea5dSIngo Weinhold int sonameOffset = -1; 9630c0fea5dSIngo Weinhold 9640c0fea5dSIngo Weinhold image->symhash = 0; 9650c0fea5dSIngo Weinhold image->syms = 0; 9660c0fea5dSIngo Weinhold image->strtab = 0; 9670c0fea5dSIngo Weinhold 9680c0fea5dSIngo Weinhold d = (struct Elf32_Dyn *)image->dynamic_ptr; 9690c0fea5dSIngo Weinhold if (!d) 9700c0fea5dSIngo Weinhold return true; 9710c0fea5dSIngo Weinhold 9720c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 9730c0fea5dSIngo Weinhold switch (d[i].d_tag) { 9740c0fea5dSIngo Weinhold case DT_NEEDED: 9750c0fea5dSIngo Weinhold image->num_needed += 1; 9760c0fea5dSIngo Weinhold break; 9770c0fea5dSIngo Weinhold case DT_HASH: 9780c0fea5dSIngo Weinhold image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta); 9790c0fea5dSIngo Weinhold break; 9800c0fea5dSIngo Weinhold case DT_STRTAB: 9810c0fea5dSIngo Weinhold image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta); 9820c0fea5dSIngo Weinhold break; 9830c0fea5dSIngo Weinhold case DT_SYMTAB: 9840c0fea5dSIngo Weinhold image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta); 9850c0fea5dSIngo Weinhold break; 9860c0fea5dSIngo Weinhold case DT_REL: 9870c0fea5dSIngo Weinhold image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 9880c0fea5dSIngo Weinhold break; 9890c0fea5dSIngo Weinhold case DT_RELSZ: 9900c0fea5dSIngo Weinhold image->rel_len = d[i].d_un.d_val; 9910c0fea5dSIngo Weinhold break; 9920c0fea5dSIngo Weinhold case DT_RELA: 9930c0fea5dSIngo Weinhold image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta); 9940c0fea5dSIngo Weinhold break; 9950c0fea5dSIngo Weinhold case DT_RELASZ: 9960c0fea5dSIngo Weinhold image->rela_len = d[i].d_un.d_val; 9970c0fea5dSIngo Weinhold break; 9980c0fea5dSIngo Weinhold // TK: procedure linkage table 9990c0fea5dSIngo Weinhold case DT_JMPREL: 10000c0fea5dSIngo Weinhold image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 10010c0fea5dSIngo Weinhold break; 10020c0fea5dSIngo Weinhold case DT_PLTRELSZ: 10030c0fea5dSIngo Weinhold image->pltrel_len = d[i].d_un.d_val; 10040c0fea5dSIngo Weinhold break; 10050c0fea5dSIngo Weinhold case DT_INIT: 10060c0fea5dSIngo Weinhold image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 10070c0fea5dSIngo Weinhold break; 10080c0fea5dSIngo Weinhold case DT_FINI: 10090c0fea5dSIngo Weinhold image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 10100c0fea5dSIngo Weinhold break; 10110c0fea5dSIngo Weinhold case DT_SONAME: 10120c0fea5dSIngo Weinhold sonameOffset = d[i].d_un.d_val; 10130c0fea5dSIngo Weinhold break; 10140c0fea5dSIngo Weinhold default: 10150c0fea5dSIngo Weinhold continue; 10160c0fea5dSIngo Weinhold } 10170c0fea5dSIngo Weinhold } 10180c0fea5dSIngo Weinhold 10190c0fea5dSIngo Weinhold // lets make sure we found all the required sections 10200c0fea5dSIngo Weinhold if (!image->symhash || !image->syms || !image->strtab) 10210c0fea5dSIngo Weinhold return false; 10220c0fea5dSIngo Weinhold 10230c0fea5dSIngo Weinhold if (sonameOffset >= 0) 10240c0fea5dSIngo Weinhold strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name)); 10250c0fea5dSIngo Weinhold 10260c0fea5dSIngo Weinhold return true; 10270c0fea5dSIngo Weinhold } 10280c0fea5dSIngo Weinhold 10290c0fea5dSIngo Weinhold 1030*10b4b5d1SIngo Weinhold static void 1031*10b4b5d1SIngo Weinhold patch_defined_symbol(image_t* image, const char* name, void** symbol, 1032*10b4b5d1SIngo Weinhold int32* type) 1033*10b4b5d1SIngo Weinhold { 1034*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers; 1035*10b4b5d1SIngo Weinhold while (patcher != NULL && *symbol != 0) { 1036*10b4b5d1SIngo Weinhold image_t* inImage = image; 1037*10b4b5d1SIngo Weinhold patcher->patcher(patcher->cookie, NULL, image, name, &inImage, 1038*10b4b5d1SIngo Weinhold symbol, type); 1039*10b4b5d1SIngo Weinhold patcher = patcher->next; 1040*10b4b5d1SIngo Weinhold } 1041*10b4b5d1SIngo Weinhold } 1042*10b4b5d1SIngo Weinhold 1043*10b4b5d1SIngo Weinhold 1044*10b4b5d1SIngo Weinhold static void 1045*10b4b5d1SIngo Weinhold patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name, 1046*10b4b5d1SIngo Weinhold image_t** foundInImage, void** symbol, int32* type) 1047*10b4b5d1SIngo Weinhold { 1048*10b4b5d1SIngo Weinhold if (*foundInImage != NULL) 1049*10b4b5d1SIngo Weinhold patch_defined_symbol(*foundInImage, name, symbol, type); 1050*10b4b5d1SIngo Weinhold 1051*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers; 1052*10b4b5d1SIngo Weinhold while (patcher != NULL) { 1053*10b4b5d1SIngo Weinhold patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage, 1054*10b4b5d1SIngo Weinhold symbol, type); 1055*10b4b5d1SIngo Weinhold patcher = patcher->next; 1056*10b4b5d1SIngo Weinhold } 1057*10b4b5d1SIngo Weinhold } 1058*10b4b5d1SIngo Weinhold 1059*10b4b5d1SIngo Weinhold 1060*10b4b5d1SIngo Weinhold status_t 1061*10b4b5d1SIngo Weinhold register_defined_symbol_patcher(struct image_t* image, 1062*10b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 1063*10b4b5d1SIngo Weinhold { 1064*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher 1065*10b4b5d1SIngo Weinhold = new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie); 1066*10b4b5d1SIngo Weinhold if (patcher == NULL) 1067*10b4b5d1SIngo Weinhold return B_NO_MEMORY; 1068*10b4b5d1SIngo Weinhold 1069*10b4b5d1SIngo Weinhold patcher->next = image->defined_symbol_patchers; 1070*10b4b5d1SIngo Weinhold image->defined_symbol_patchers = patcher; 1071*10b4b5d1SIngo Weinhold 1072*10b4b5d1SIngo Weinhold return B_OK; 1073*10b4b5d1SIngo Weinhold } 1074*10b4b5d1SIngo Weinhold 1075*10b4b5d1SIngo Weinhold 1076*10b4b5d1SIngo Weinhold void 1077*10b4b5d1SIngo Weinhold unregister_defined_symbol_patcher(struct image_t* image, 1078*10b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 1079*10b4b5d1SIngo Weinhold { 1080*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher** patcher = &image->defined_symbol_patchers; 1081*10b4b5d1SIngo Weinhold while (*patcher != NULL) { 1082*10b4b5d1SIngo Weinhold if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) { 1083*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* toDelete = *patcher; 1084*10b4b5d1SIngo Weinhold *patcher = (*patcher)->next; 1085*10b4b5d1SIngo Weinhold delete toDelete; 1086*10b4b5d1SIngo Weinhold return; 1087*10b4b5d1SIngo Weinhold } 1088*10b4b5d1SIngo Weinhold patcher = &(*patcher)->next; 1089*10b4b5d1SIngo Weinhold } 1090*10b4b5d1SIngo Weinhold } 1091*10b4b5d1SIngo Weinhold 1092*10b4b5d1SIngo Weinhold 1093*10b4b5d1SIngo Weinhold status_t 1094*10b4b5d1SIngo Weinhold register_undefined_symbol_patcher(struct image_t* image, 1095*10b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 1096*10b4b5d1SIngo Weinhold { 1097*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* patcher 1098*10b4b5d1SIngo Weinhold = new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie); 1099*10b4b5d1SIngo Weinhold if (patcher == NULL) 1100*10b4b5d1SIngo Weinhold return B_NO_MEMORY; 1101*10b4b5d1SIngo Weinhold 1102*10b4b5d1SIngo Weinhold patcher->next = image->undefined_symbol_patchers; 1103*10b4b5d1SIngo Weinhold image->undefined_symbol_patchers = patcher; 1104*10b4b5d1SIngo Weinhold 1105*10b4b5d1SIngo Weinhold return B_OK; 1106*10b4b5d1SIngo Weinhold } 1107*10b4b5d1SIngo Weinhold 1108*10b4b5d1SIngo Weinhold 1109*10b4b5d1SIngo Weinhold void 1110*10b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher(struct image_t* image, 1111*10b4b5d1SIngo Weinhold runtime_loader_symbol_patcher* _patcher, void* cookie) 1112*10b4b5d1SIngo Weinhold { 1113*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher** patcher = &image->undefined_symbol_patchers; 1114*10b4b5d1SIngo Weinhold while (*patcher != NULL) { 1115*10b4b5d1SIngo Weinhold if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) { 1116*10b4b5d1SIngo Weinhold RuntimeLoaderSymbolPatcher* toDelete = *patcher; 1117*10b4b5d1SIngo Weinhold *patcher = (*patcher)->next; 1118*10b4b5d1SIngo Weinhold delete toDelete; 1119*10b4b5d1SIngo Weinhold return; 1120*10b4b5d1SIngo Weinhold } 1121*10b4b5d1SIngo Weinhold patcher = &(*patcher)->next; 1122*10b4b5d1SIngo Weinhold } 1123*10b4b5d1SIngo Weinhold } 1124*10b4b5d1SIngo Weinhold 1125*10b4b5d1SIngo Weinhold 1126*10b4b5d1SIngo Weinhold runtime_loader_add_on_export gRuntimeLoaderAddOnExport = { 1127*10b4b5d1SIngo Weinhold register_defined_symbol_patcher, 1128*10b4b5d1SIngo Weinhold unregister_defined_symbol_patcher, 1129*10b4b5d1SIngo Weinhold register_undefined_symbol_patcher, 1130*10b4b5d1SIngo Weinhold unregister_undefined_symbol_patcher 1131*10b4b5d1SIngo Weinhold }; 1132*10b4b5d1SIngo Weinhold 1133*10b4b5d1SIngo Weinhold 11340c0fea5dSIngo Weinhold static struct Elf32_Sym * 11350c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type) 11360c0fea5dSIngo Weinhold { 11370c0fea5dSIngo Weinhold uint32 hash, i; 11380c0fea5dSIngo Weinhold 11390c0fea5dSIngo Weinhold // ToDo: "type" is currently ignored! 11400c0fea5dSIngo Weinhold (void)type; 11410c0fea5dSIngo Weinhold 1142dd76bc97SIngo Weinhold if (image->dynamic_ptr == 0) 11430c0fea5dSIngo Weinhold return NULL; 11440c0fea5dSIngo Weinhold 11450c0fea5dSIngo Weinhold hash = elf_hash((uint8 *)name) % HASHTABSIZE(image); 11460c0fea5dSIngo Weinhold 11470c0fea5dSIngo Weinhold for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) { 11480c0fea5dSIngo Weinhold struct Elf32_Sym *symbol = &image->syms[i]; 11490c0fea5dSIngo Weinhold 11500c0fea5dSIngo Weinhold if (symbol->st_shndx != SHN_UNDEF 11510c0fea5dSIngo Weinhold && ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL) 11520c0fea5dSIngo Weinhold || (ELF32_ST_BIND(symbol->st_info) == STB_WEAK)) 11530c0fea5dSIngo Weinhold && !strcmp(SYMNAME(image, symbol), name)) { 11540c0fea5dSIngo Weinhold // check if the type matches 11550c0fea5dSIngo Weinhold if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC) 11560c0fea5dSIngo Weinhold || (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)) 11570c0fea5dSIngo Weinhold continue; 11580c0fea5dSIngo Weinhold 11590c0fea5dSIngo Weinhold return symbol; 11600c0fea5dSIngo Weinhold } 11610c0fea5dSIngo Weinhold } 11620c0fea5dSIngo Weinhold 11630c0fea5dSIngo Weinhold return NULL; 11640c0fea5dSIngo Weinhold } 11650c0fea5dSIngo Weinhold 11660c0fea5dSIngo Weinhold 1167*10b4b5d1SIngo Weinhold static status_t 1168*10b4b5d1SIngo Weinhold find_symbol(image_t* image, char const* symbolName, int32 symbolType, 1169*10b4b5d1SIngo Weinhold void **_location) 1170*10b4b5d1SIngo Weinhold { 1171*10b4b5d1SIngo Weinhold // get the symbol in the image 1172*10b4b5d1SIngo Weinhold struct Elf32_Sym* symbol = find_symbol(image, symbolName, symbolType); 1173*10b4b5d1SIngo Weinhold if (symbol == NULL) 1174*10b4b5d1SIngo Weinhold return B_ENTRY_NOT_FOUND; 1175*10b4b5d1SIngo Weinhold 1176*10b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value + image->regions[0].delta); 1177*10b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &symbolType); 1178*10b4b5d1SIngo Weinhold 1179*10b4b5d1SIngo Weinhold if (_location != NULL) 1180*10b4b5d1SIngo Weinhold *_location = location; 1181*10b4b5d1SIngo Weinhold 1182*10b4b5d1SIngo Weinhold return B_OK; 1183*10b4b5d1SIngo Weinhold } 1184*10b4b5d1SIngo Weinhold 1185*10b4b5d1SIngo Weinhold 11860c0fea5dSIngo Weinhold static struct Elf32_Sym* 1187ca618b22SIngo Weinhold find_symbol_in_root_image_list(image_t* rootImage, const char* name, 118846f4d849SIngo Weinhold image_t** foundInImage) 11890c0fea5dSIngo Weinhold { 1190ca618b22SIngo Weinhold int32 count = rootImage->symbol_resolution_image_count; 1191ca618b22SIngo Weinhold image_t** images = rootImage->symbol_resolution_images; 1192ca618b22SIngo Weinhold for (int32 i = 0; i < count; i++) { 1193ca618b22SIngo Weinhold image_t* image = images[i]; 119446f4d849SIngo Weinhold if (image->dynamic_ptr) { 1195ca618b22SIngo Weinhold Elf32_Sym* symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY); 11960c0fea5dSIngo Weinhold if (symbol) { 119746f4d849SIngo Weinhold *foundInImage = image; 119846f4d849SIngo Weinhold return symbol; 119946f4d849SIngo Weinhold } 120046f4d849SIngo Weinhold } 12010c0fea5dSIngo Weinhold } 12020c0fea5dSIngo Weinhold 12030c0fea5dSIngo Weinhold return NULL; 12040c0fea5dSIngo Weinhold } 12050c0fea5dSIngo Weinhold 12060c0fea5dSIngo Weinhold 120746f4d849SIngo Weinhold static struct Elf32_Sym* 120846f4d849SIngo Weinhold find_undefined_symbol(image_t* rootImage, image_t* image, const char* name, 120946f4d849SIngo Weinhold image_t** foundInImage) 121046f4d849SIngo Weinhold { 121146f4d849SIngo Weinhold // If not simulating BeOS style symbol resolution, undefined symbols are 121292af28dfSIngo Weinhold // searched recursively starting from the root image. 1213ca618b22SIngo Weinhold if ((rootImage->flags & IMAGE_FLAG_R5_SYMBOL_RESOLUTION) == 0) 1214ca618b22SIngo Weinhold return find_symbol_in_root_image_list(rootImage, name, foundInImage); 121546f4d849SIngo Weinhold 121646f4d849SIngo Weinhold // BeOS style symbol resolution: It is sufficient to check the direct 121746f4d849SIngo Weinhold // dependencies. The linker would have complained, if the symbol wasn't 121846f4d849SIngo Weinhold // there. 121946f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 122046f4d849SIngo Weinhold if (image->needed[i]->dynamic_ptr) { 122146f4d849SIngo Weinhold struct Elf32_Sym *symbol = find_symbol(image->needed[i], name, 122246f4d849SIngo Weinhold B_SYMBOL_TYPE_ANY); 122346f4d849SIngo Weinhold if (symbol) { 122446f4d849SIngo Weinhold *foundInImage = image->needed[i]; 122546f4d849SIngo Weinhold return symbol; 122646f4d849SIngo Weinhold } 122746f4d849SIngo Weinhold } 122846f4d849SIngo Weinhold } 122946f4d849SIngo Weinhold 123046f4d849SIngo Weinhold return NULL; 123146f4d849SIngo Weinhold } 123246f4d849SIngo Weinhold 123346f4d849SIngo Weinhold 1234*10b4b5d1SIngo Weinhold /*! This function is called when we run BeOS images on Haiku. 12352716cfd3SAxel Dörfler It allows us to redirect functions to ensure compatibility. 12362716cfd3SAxel Dörfler */ 12372716cfd3SAxel Dörfler static const char* 12382716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName) 12392716cfd3SAxel Dörfler { 12402716cfd3SAxel Dörfler struct symbol_mapping { 12412716cfd3SAxel Dörfler const char* from; 12422716cfd3SAxel Dörfler const char* to; 12432716cfd3SAxel Dörfler }; 12442716cfd3SAxel Dörfler static const struct symbol_mapping kMappings[] = { 1245*10b4b5d1SIngo Weinhold // TODO: Improve this, and also use it for libnet.so compatibility! 1246*10b4b5d1SIngo Weinhold // Allow an image to provide a function that will be invoked for every 1247*10b4b5d1SIngo Weinhold // (transitively) depending image. The function can return a table to 1248*10b4b5d1SIngo Weinhold // remap symbols (probably better address to address). All the tables 1249*10b4b5d1SIngo Weinhold // for a single image would be combined into a hash table and an 1250*10b4b5d1SIngo Weinhold // undefined symbol patcher using this hash table would be added. 12512716cfd3SAxel Dörfler {"fstat", "__be_fstat"}, 12522716cfd3SAxel Dörfler {"lstat", "__be_lstat"}, 12532716cfd3SAxel Dörfler {"stat", "__be_stat"}, 12542716cfd3SAxel Dörfler }; 12552716cfd3SAxel Dörfler const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]); 12562716cfd3SAxel Dörfler 12572716cfd3SAxel Dörfler for (uint32 i = 0; i < kMappingCount; i++) { 12582716cfd3SAxel Dörfler if (!strcmp(symbolName, kMappings[i].from)) 12592716cfd3SAxel Dörfler return kMappings[i].to; 12602716cfd3SAxel Dörfler } 12612716cfd3SAxel Dörfler 12622716cfd3SAxel Dörfler return symbolName; 12632716cfd3SAxel Dörfler } 12642716cfd3SAxel Dörfler 12652716cfd3SAxel Dörfler 12660c0fea5dSIngo Weinhold int 126746f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym, 12682716cfd3SAxel Dörfler addr_t *symAddress) 12690c0fea5dSIngo Weinhold { 12700c0fea5dSIngo Weinhold switch (sym->st_shndx) { 12710c0fea5dSIngo Weinhold case SHN_UNDEF: 12722716cfd3SAxel Dörfler { 12732716cfd3SAxel Dörfler struct Elf32_Sym *sharedSym; 12742716cfd3SAxel Dörfler image_t *sharedImage; 12752716cfd3SAxel Dörfler const char *symName; 12762716cfd3SAxel Dörfler 12770c0fea5dSIngo Weinhold // patch the symbol name 12782716cfd3SAxel Dörfler symName = SYMNAME(image, sym); 12792716cfd3SAxel Dörfler if (!image->gcc_version.haiku) { 12802716cfd3SAxel Dörfler // The image has been compiled with a BeOS compiler. This means 12812716cfd3SAxel Dörfler // we'll have to redirect some functions for compatibility. 12822716cfd3SAxel Dörfler symName = beos_compatibility_map_symbol(symName); 12832716cfd3SAxel Dörfler } 12840c0fea5dSIngo Weinhold 1285*10b4b5d1SIngo Weinhold int32 type = B_SYMBOL_TYPE_ANY; 1286*10b4b5d1SIngo Weinhold if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC) 1287*10b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 1288*10b4b5d1SIngo Weinhold else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT) 1289*10b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 1290*10b4b5d1SIngo Weinhold 129146f4d849SIngo Weinhold // it's undefined, must be outside this image, try the other images 12922716cfd3SAxel Dörfler sharedSym = find_undefined_symbol(rootImage, image, symName, 12932716cfd3SAxel Dörfler &sharedImage); 1294*10b4b5d1SIngo Weinhold void* location = NULL; 12950c0fea5dSIngo Weinhold 1296*10b4b5d1SIngo Weinhold enum { 1297*10b4b5d1SIngo Weinhold ERROR_NO_SYMBOL, 1298*10b4b5d1SIngo Weinhold ERROR_WRONG_TYPE, 1299*10b4b5d1SIngo Weinhold ERROR_NOT_EXPORTED, 1300*10b4b5d1SIngo Weinhold ERROR_UNPATCHED 1301*10b4b5d1SIngo Weinhold }; 1302*10b4b5d1SIngo Weinhold uint32 lookupError = ERROR_UNPATCHED; 1303*10b4b5d1SIngo Weinhold 1304*10b4b5d1SIngo Weinhold if (sharedSym == NULL) { 1305*10b4b5d1SIngo Weinhold // symbol not found at all 1306*10b4b5d1SIngo Weinhold lookupError = ERROR_NO_SYMBOL; 1307*10b4b5d1SIngo Weinhold sharedImage = NULL; 1308*10b4b5d1SIngo Weinhold } else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE 13092716cfd3SAxel Dörfler && ELF32_ST_TYPE(sym->st_info) 13102716cfd3SAxel Dörfler != ELF32_ST_TYPE(sharedSym->st_info)) { 1311*10b4b5d1SIngo Weinhold // symbol not of the requested type 1312*10b4b5d1SIngo Weinhold lookupError = ERROR_WRONG_TYPE; 1313*10b4b5d1SIngo Weinhold sharedImage = NULL; 1314*10b4b5d1SIngo Weinhold } else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL 13152716cfd3SAxel Dörfler && ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) { 1316*10b4b5d1SIngo Weinhold // symbol not exported 1317*10b4b5d1SIngo Weinhold lookupError = ERROR_NOT_EXPORTED; 1318*10b4b5d1SIngo Weinhold sharedImage = NULL; 1319*10b4b5d1SIngo Weinhold } else { 1320*10b4b5d1SIngo Weinhold // symbol is fine, get its location 1321*10b4b5d1SIngo Weinhold location = (void*)(sharedSym->st_value 1322*10b4b5d1SIngo Weinhold + sharedImage->regions[0].delta); 1323*10b4b5d1SIngo Weinhold } 1324*10b4b5d1SIngo Weinhold 1325*10b4b5d1SIngo Weinhold patch_undefined_symbol(rootImage, image, symName, &sharedImage, 1326*10b4b5d1SIngo Weinhold &location, &type); 1327*10b4b5d1SIngo Weinhold 1328*10b4b5d1SIngo Weinhold if (location == NULL) { 1329*10b4b5d1SIngo Weinhold switch (lookupError) { 1330*10b4b5d1SIngo Weinhold case ERROR_NO_SYMBOL: 1331*10b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: could not resolve symbol " 1332*10b4b5d1SIngo Weinhold "'%s'\n", symName); 1333*10b4b5d1SIngo Weinhold break; 1334*10b4b5d1SIngo Weinhold case ERROR_WRONG_TYPE: 1335*10b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s' in shared " 1336*10b4b5d1SIngo Weinhold "image but wrong type\n", symName); 1337*10b4b5d1SIngo Weinhold break; 1338*10b4b5d1SIngo Weinhold case ERROR_NOT_EXPORTED: 1339*10b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s', but not " 13402716cfd3SAxel Dörfler "exported\n", symName); 1341*10b4b5d1SIngo Weinhold break; 1342*10b4b5d1SIngo Weinhold case ERROR_UNPATCHED: 1343*10b4b5d1SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s', but was " 1344*10b4b5d1SIngo Weinhold "hidden by symbol patchers\n", symName); 1345*10b4b5d1SIngo Weinhold break; 1346*10b4b5d1SIngo Weinhold } 13470c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 13480c0fea5dSIngo Weinhold } 13490c0fea5dSIngo Weinhold 1350*10b4b5d1SIngo Weinhold *symAddress = (addr_t)location; 1351*10b4b5d1SIngo Weinhold return B_OK; 13522716cfd3SAxel Dörfler } 13530c0fea5dSIngo Weinhold 13540c0fea5dSIngo Weinhold case SHN_ABS: 13552716cfd3SAxel Dörfler *symAddress = sym->st_value + image->regions[0].delta; 13560c0fea5dSIngo Weinhold return B_NO_ERROR; 13570c0fea5dSIngo Weinhold 13580c0fea5dSIngo Weinhold case SHN_COMMON: 13590c0fea5dSIngo Weinhold // ToDo: finish this 13602a33a944SIngo Weinhold FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n"); 13610c0fea5dSIngo Weinhold return B_ERROR; //ERR_NOT_IMPLEMENTED_YET; 13620c0fea5dSIngo Weinhold 13630c0fea5dSIngo Weinhold default: 13640c0fea5dSIngo Weinhold // standard symbol 13652716cfd3SAxel Dörfler *symAddress = sym->st_value + image->regions[0].delta; 13660c0fea5dSIngo Weinhold return B_NO_ERROR; 13670c0fea5dSIngo Weinhold } 13680c0fea5dSIngo Weinhold } 13690c0fea5dSIngo Weinhold 13700c0fea5dSIngo Weinhold 13710c0fea5dSIngo Weinhold static void 1372*10b4b5d1SIngo Weinhold image_event(image_t* image, uint32 event) 1373*10b4b5d1SIngo Weinhold { 1374*10b4b5d1SIngo Weinhold AddOnList::Iterator it = sAddOns.GetIterator(); 1375*10b4b5d1SIngo Weinhold while (RuntimeLoaderAddOn* addOn = it.Next()) { 1376*10b4b5d1SIngo Weinhold void (*function)(image_t* image) = NULL; 1377*10b4b5d1SIngo Weinhold 1378*10b4b5d1SIngo Weinhold switch (event) { 1379*10b4b5d1SIngo Weinhold case IMAGE_EVENT_LOADED: 1380*10b4b5d1SIngo Weinhold function = addOn->addOn->image_loaded; 1381*10b4b5d1SIngo Weinhold break; 1382*10b4b5d1SIngo Weinhold case IMAGE_EVENT_RELOCATED: 1383*10b4b5d1SIngo Weinhold function = addOn->addOn->image_relocated; 1384*10b4b5d1SIngo Weinhold break; 1385*10b4b5d1SIngo Weinhold case IMAGE_EVENT_INITIALIZED: 1386*10b4b5d1SIngo Weinhold function = addOn->addOn->image_initialized; 1387*10b4b5d1SIngo Weinhold break; 1388*10b4b5d1SIngo Weinhold case IMAGE_EVENT_UNINITIALIZING: 1389*10b4b5d1SIngo Weinhold function = addOn->addOn->image_uninitializing; 1390*10b4b5d1SIngo Weinhold break; 1391*10b4b5d1SIngo Weinhold case IMAGE_EVENT_UNLOADING: 1392*10b4b5d1SIngo Weinhold function = addOn->addOn->image_unloading; 1393*10b4b5d1SIngo Weinhold break; 1394*10b4b5d1SIngo Weinhold } 1395*10b4b5d1SIngo Weinhold 1396*10b4b5d1SIngo Weinhold if (function != NULL) 1397*10b4b5d1SIngo Weinhold function(image); 1398*10b4b5d1SIngo Weinhold } 1399*10b4b5d1SIngo Weinhold } 1400*10b4b5d1SIngo Weinhold 1401*10b4b5d1SIngo Weinhold 1402*10b4b5d1SIngo Weinhold static void 14030c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path) 14040c0fea5dSIngo Weinhold { 14050c0fea5dSIngo Weinhold struct stat stat; 14060c0fea5dSIngo Weinhold image_info info; 14070c0fea5dSIngo Weinhold 14080c0fea5dSIngo Weinhold // ToDo: set these correctly 14090c0fea5dSIngo Weinhold info.id = 0; 14100c0fea5dSIngo Weinhold info.type = image->type; 14110c0fea5dSIngo Weinhold info.sequence = 0; 14120c0fea5dSIngo Weinhold info.init_order = 0; 14130c0fea5dSIngo Weinhold info.init_routine = (void (*)())image->init_routine; 14140c0fea5dSIngo Weinhold info.term_routine = (void (*)())image->term_routine; 14150c0fea5dSIngo Weinhold 14160c0fea5dSIngo Weinhold if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) { 14170c0fea5dSIngo Weinhold info.device = stat.st_dev; 14180c0fea5dSIngo Weinhold info.node = stat.st_ino; 14190c0fea5dSIngo Weinhold } else { 14200c0fea5dSIngo Weinhold info.device = -1; 14210c0fea5dSIngo Weinhold info.node = -1; 14220c0fea5dSIngo Weinhold } 14230c0fea5dSIngo Weinhold 14240c0fea5dSIngo Weinhold strlcpy(info.name, path, sizeof(info.name)); 14250c0fea5dSIngo Weinhold info.text = (void *)image->regions[0].vmstart; 14260c0fea5dSIngo Weinhold info.text_size = image->regions[0].vmsize; 14270c0fea5dSIngo Weinhold info.data = (void *)image->regions[1].vmstart; 14280c0fea5dSIngo Weinhold info.data_size = image->regions[1].vmsize; 14290c0fea5dSIngo Weinhold image->id = _kern_register_image(&info, sizeof(image_info)); 14300c0fea5dSIngo Weinhold } 14310c0fea5dSIngo Weinhold 14320c0fea5dSIngo Weinhold 14330c0fea5dSIngo Weinhold static status_t 143446f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 14350c0fea5dSIngo Weinhold { 143646f4d849SIngo Weinhold status_t status = arch_relocate_image(rootImage, image); 14370c0fea5dSIngo Weinhold if (status < B_OK) { 1438320bd2bdSAxel Dörfler FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status, 1439320bd2bdSAxel Dörfler image->path, image->name); 14400c0fea5dSIngo Weinhold return status; 14410c0fea5dSIngo Weinhold } 14420c0fea5dSIngo Weinhold 14430c0fea5dSIngo Weinhold _kern_image_relocated(image->id); 1444*10b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_RELOCATED); 14450c0fea5dSIngo Weinhold return B_OK; 14460c0fea5dSIngo Weinhold } 14470c0fea5dSIngo Weinhold 14480c0fea5dSIngo Weinhold 14490c0fea5dSIngo Weinhold static status_t 14500c0fea5dSIngo Weinhold load_container(char const *name, image_type type, const char *rpath, image_t **_image) 14510c0fea5dSIngo Weinhold { 14520c0fea5dSIngo Weinhold int32 pheaderSize, sheaderSize; 14530c0fea5dSIngo Weinhold char path[PATH_MAX]; 14540c0fea5dSIngo Weinhold ssize_t length; 14550c0fea5dSIngo Weinhold char ph_buff[4096]; 14560c0fea5dSIngo Weinhold int32 numRegions; 14570c0fea5dSIngo Weinhold image_t *found; 14580c0fea5dSIngo Weinhold image_t *image; 14590c0fea5dSIngo Weinhold status_t status; 14600c0fea5dSIngo Weinhold int fd; 14610c0fea5dSIngo Weinhold 14620c0fea5dSIngo Weinhold struct Elf32_Ehdr eheader; 14630c0fea5dSIngo Weinhold 14640c0fea5dSIngo Weinhold // Have we already loaded that image? Don't check for add-ons -- we always 14650c0fea5dSIngo Weinhold // reload them. 14660c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 14670c0fea5dSIngo Weinhold found = find_image(name, APP_OR_LIBRARY_TYPE); 146802e577f9SIngo Weinhold 146902e577f9SIngo Weinhold if (found == NULL && type != B_APP_IMAGE) { 147002e577f9SIngo Weinhold // Special case for add-ons that link against the application 147102e577f9SIngo Weinhold // executable, with the executable not having a soname set. 147202e577f9SIngo Weinhold if (const char* lastSlash = strrchr(name, '/')) { 147302e577f9SIngo Weinhold image_t* programImage = get_program_image(); 147402e577f9SIngo Weinhold if (strcmp(programImage->name, lastSlash + 1) == 0) 147502e577f9SIngo Weinhold found = programImage; 147602e577f9SIngo Weinhold } 147702e577f9SIngo Weinhold } 147802e577f9SIngo Weinhold 14790c0fea5dSIngo Weinhold if (found) { 14800c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 14810c0fea5dSIngo Weinhold *_image = found; 14827486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") " 14837486b72dSIngo Weinhold "already loaded", name, type, rpath); 14840c0fea5dSIngo Weinhold return B_OK; 14850c0fea5dSIngo Weinhold } 14860c0fea5dSIngo Weinhold } 14870c0fea5dSIngo Weinhold 14887486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type, 14897486b72dSIngo Weinhold rpath); 14907486b72dSIngo Weinhold 14910c0fea5dSIngo Weinhold strlcpy(path, name, sizeof(path)); 14920c0fea5dSIngo Weinhold 149361b37794SIngo Weinhold // find and open the file 149461b37794SIngo Weinhold fd = open_executable(path, type, rpath, get_program_path(), 149561b37794SIngo Weinhold sSearchPathSubDir); 14960c0fea5dSIngo Weinhold if (fd < 0) { 149702e577f9SIngo Weinhold FATAL("cannot open file %s\n", name); 14987486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): failed to open file", name); 14990c0fea5dSIngo Weinhold return fd; 15000c0fea5dSIngo Weinhold } 15010c0fea5dSIngo Weinhold 15026918dbf4SIngo Weinhold // normalize the image path 15036918dbf4SIngo Weinhold status = _kern_normalize_path(path, true, path); 15046918dbf4SIngo Weinhold if (status != B_OK) 15050c0fea5dSIngo Weinhold goto err1; 15060c0fea5dSIngo Weinhold 15070c0fea5dSIngo Weinhold // Test again if this image has been registered already - this time, 15080c0fea5dSIngo Weinhold // we can check the full path, not just its name as noted. 15090c0fea5dSIngo Weinhold // You could end up loading an image twice with symbolic links, else. 15100c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 15110c0fea5dSIngo Weinhold found = find_image(path, APP_OR_LIBRARY_TYPE); 15120c0fea5dSIngo Weinhold if (found) { 15130c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 15140c0fea5dSIngo Weinhold *_image = found; 1515b2568a30SIngo Weinhold _kern_close(fd); 15167486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): already loaded after all", 15177486b72dSIngo Weinhold name); 15180c0fea5dSIngo Weinhold return B_OK; 15190c0fea5dSIngo Weinhold } 15200c0fea5dSIngo Weinhold } 15210c0fea5dSIngo Weinhold 15220c0fea5dSIngo Weinhold length = _kern_read(fd, 0, &eheader, sizeof(eheader)); 15230c0fea5dSIngo Weinhold if (length != sizeof(eheader)) { 15240c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 15250c0fea5dSIngo Weinhold FATAL("troubles reading ELF header\n"); 15260c0fea5dSIngo Weinhold goto err1; 15270c0fea5dSIngo Weinhold } 15280c0fea5dSIngo Weinhold 15290c0fea5dSIngo Weinhold status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize); 15300c0fea5dSIngo Weinhold if (status < B_OK) { 15310c0fea5dSIngo Weinhold FATAL("incorrect ELF header\n"); 15320c0fea5dSIngo Weinhold goto err1; 15330c0fea5dSIngo Weinhold } 15340c0fea5dSIngo Weinhold 15350c0fea5dSIngo Weinhold // ToDo: what to do about this restriction?? 15360c0fea5dSIngo Weinhold if (pheaderSize > (int)sizeof(ph_buff)) { 15370c0fea5dSIngo Weinhold FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff)); 15380c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 15390c0fea5dSIngo Weinhold goto err1; 15400c0fea5dSIngo Weinhold } 15410c0fea5dSIngo Weinhold 15420c0fea5dSIngo Weinhold length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize); 15430c0fea5dSIngo Weinhold if (length != pheaderSize) { 15440c0fea5dSIngo Weinhold FATAL("Could not read program headers: %s\n", strerror(length)); 15450c0fea5dSIngo Weinhold status = B_BAD_DATA; 15460c0fea5dSIngo Weinhold goto err1; 15470c0fea5dSIngo Weinhold } 15480c0fea5dSIngo Weinhold 15490c0fea5dSIngo Weinhold numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize); 15500c0fea5dSIngo Weinhold if (numRegions <= 0) { 15510c0fea5dSIngo Weinhold FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions); 15520c0fea5dSIngo Weinhold status = B_BAD_DATA; 15530c0fea5dSIngo Weinhold goto err1; 15540c0fea5dSIngo Weinhold } 15550c0fea5dSIngo Weinhold 15560c0fea5dSIngo Weinhold image = create_image(name, path, numRegions); 15570c0fea5dSIngo Weinhold if (image == NULL) { 15580c0fea5dSIngo Weinhold FATAL("Failed to allocate image_t object\n"); 15590c0fea5dSIngo Weinhold status = B_NO_MEMORY; 15600c0fea5dSIngo Weinhold goto err1; 15610c0fea5dSIngo Weinhold } 15620c0fea5dSIngo Weinhold 15630c0fea5dSIngo Weinhold status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize); 15640c0fea5dSIngo Weinhold if (status < B_OK) 15650c0fea5dSIngo Weinhold goto err2; 15660c0fea5dSIngo Weinhold 15670c0fea5dSIngo Weinhold if (!assert_dynamic_loadable(image)) { 15680c0fea5dSIngo Weinhold FATAL("Dynamic segment must be loadable (implementation restriction)\n"); 15690c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 15700c0fea5dSIngo Weinhold goto err2; 15710c0fea5dSIngo Weinhold } 15720c0fea5dSIngo Weinhold 157361b37794SIngo Weinhold if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff, 157434982809SIngo Weinhold sizeof(ph_buff))) { 157561b37794SIngo Weinhold // If this is the executable image, we init the search path 157661b37794SIngo Weinhold // subdir, if the compiler version doesn't match ours. 157761b37794SIngo Weinhold if (type == B_APP_IMAGE) { 157861b37794SIngo Weinhold #if __GNUC__ == 2 157961b37794SIngo Weinhold if (image->gcc_version.major > 2) 158061b37794SIngo Weinhold sSearchPathSubDir = "gcc4"; 158161b37794SIngo Weinhold #elif __GNUC__ == 4 158261b37794SIngo Weinhold if (image->gcc_version.major == 2) 158361b37794SIngo Weinhold sSearchPathSubDir = "gcc2"; 158461b37794SIngo Weinhold #endif 158561b37794SIngo Weinhold } 158661b37794SIngo Weinhold } else { 158734982809SIngo Weinhold FATAL("Failed to get gcc version for %s\n", path); 158834982809SIngo Weinhold // not really fatal, actually 158934982809SIngo Weinhold } 159034982809SIngo Weinhold 15915fd6637bSIngo Weinhold // init gcc version dependent image flags 15925fd6637bSIngo Weinhold // symbol resolution strategy (fallback is R5-style, if version is 15935fd6637bSIngo Weinhold // unavailable) 15945fd6637bSIngo Weinhold if (image->gcc_version.major == 0 15955fd6637bSIngo Weinhold || image->gcc_version.major == 2 && image->gcc_version.middle < 95) { 15965fd6637bSIngo Weinhold image->flags |= IMAGE_FLAG_R5_SYMBOL_RESOLUTION; 15975fd6637bSIngo Weinhold } 15985fd6637bSIngo Weinhold 15990c0fea5dSIngo Weinhold status = map_image(fd, path, image, type == B_APP_IMAGE); 16000c0fea5dSIngo Weinhold if (status < B_OK) { 16010c0fea5dSIngo Weinhold FATAL("Could not map image: %s\n", strerror(status)); 16020c0fea5dSIngo Weinhold status = B_ERROR; 16030c0fea5dSIngo Weinhold goto err2; 16040c0fea5dSIngo Weinhold } 16050c0fea5dSIngo Weinhold 16060c0fea5dSIngo Weinhold if (!parse_dynamic_segment(image)) { 16070c0fea5dSIngo Weinhold FATAL("Troubles handling dynamic section\n"); 16080c0fea5dSIngo Weinhold status = B_BAD_DATA; 16090c0fea5dSIngo Weinhold goto err3; 16100c0fea5dSIngo Weinhold } 16110c0fea5dSIngo Weinhold 1612dd76bc97SIngo Weinhold if (eheader.e_entry != 0) 16130c0fea5dSIngo Weinhold image->entry_point = eheader.e_entry + image->regions[0].delta; 16140c0fea5dSIngo Weinhold 16150c0fea5dSIngo Weinhold image->type = type; 16160c0fea5dSIngo Weinhold register_image(image, fd, path); 1617*10b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_LOADED); 16180c0fea5dSIngo Weinhold 16190c0fea5dSIngo Weinhold _kern_close(fd); 16200c0fea5dSIngo Weinhold 16210c0fea5dSIngo Weinhold enqueue_image(&sLoadedImages, image); 16220c0fea5dSIngo Weinhold sLoadedImageCount++; 16230c0fea5dSIngo Weinhold 16240c0fea5dSIngo Weinhold *_image = image; 16257486b72dSIngo Weinhold 162634982809SIngo Weinhold KTRACE("rld: load_container(\"%s\"): done: id: %ld (gcc: %d.%d.%d)", name, 162734982809SIngo Weinhold image->id, image->gcc_version.major, image->gcc_version.middle, 162834982809SIngo Weinhold image->gcc_version.minor); 16297486b72dSIngo Weinhold 16300c0fea5dSIngo Weinhold return B_OK; 16310c0fea5dSIngo Weinhold 16320c0fea5dSIngo Weinhold err3: 16330c0fea5dSIngo Weinhold unmap_image(image); 16340c0fea5dSIngo Weinhold err2: 16350c0fea5dSIngo Weinhold delete_image_struct(image); 16360c0fea5dSIngo Weinhold err1: 16370c0fea5dSIngo Weinhold _kern_close(fd); 16387486b72dSIngo Weinhold 16397486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): failed: %s", name, 16407486b72dSIngo Weinhold strerror(status)); 16417486b72dSIngo Weinhold 16420c0fea5dSIngo Weinhold return status; 16430c0fea5dSIngo Weinhold } 16440c0fea5dSIngo Weinhold 16450c0fea5dSIngo Weinhold 16460c0fea5dSIngo Weinhold static const char * 16470c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 16480c0fea5dSIngo Weinhold { 16490c0fea5dSIngo Weinhold int i; 16500c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 16510c0fea5dSIngo Weinhold 16520c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 16530c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 16540c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 16550c0fea5dSIngo Weinhold } 16560c0fea5dSIngo Weinhold 16570c0fea5dSIngo Weinhold return NULL; 16580c0fea5dSIngo Weinhold } 16590c0fea5dSIngo Weinhold 16600c0fea5dSIngo Weinhold 16610c0fea5dSIngo Weinhold static status_t 16620c0fea5dSIngo Weinhold load_dependencies(image_t *image) 16630c0fea5dSIngo Weinhold { 16640c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 16654bef3723SAxel Dörfler bool reportErrors = report_errors(); 166674c0424aSAxel Dörfler status_t status = B_OK; 16670c0fea5dSIngo Weinhold uint32 i, j; 16680c0fea5dSIngo Weinhold const char *rpath; 16690c0fea5dSIngo Weinhold 16700c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 16710c0fea5dSIngo Weinhold return B_OK; 16720c0fea5dSIngo Weinhold 16730c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 16740c0fea5dSIngo Weinhold 16750c0fea5dSIngo Weinhold if (image->num_needed == 0) 16760c0fea5dSIngo Weinhold return B_OK; 16770c0fea5dSIngo Weinhold 16787486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name, 16797486b72dSIngo Weinhold image->id); 16807486b72dSIngo Weinhold 16810c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 16820c0fea5dSIngo Weinhold if (image->needed == NULL) { 16830c0fea5dSIngo Weinhold FATAL("failed to allocate needed struct\n"); 16847486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory", 16857486b72dSIngo Weinhold image->name, image->id); 16860c0fea5dSIngo Weinhold return B_NO_MEMORY; 16870c0fea5dSIngo Weinhold } 16880c0fea5dSIngo Weinhold 16890c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 16900c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 16910c0fea5dSIngo Weinhold 16920c0fea5dSIngo Weinhold for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { 16930c0fea5dSIngo Weinhold switch (d[i].d_tag) { 16940c0fea5dSIngo Weinhold case DT_NEEDED: 169574c0424aSAxel Dörfler { 169674c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 169774c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 16980c0fea5dSIngo Weinhold 169974c0424aSAxel Dörfler status_t loadStatus = load_container(name, B_LIBRARY_IMAGE, 170074c0424aSAxel Dörfler rpath, &image->needed[j]); 170174c0424aSAxel Dörfler if (loadStatus < B_OK) { 170274c0424aSAxel Dörfler status = loadStatus; 170374c0424aSAxel Dörfler // correct error code in case the file could not been found 170474c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 170574c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 170674c0424aSAxel Dörfler 170774c0424aSAxel Dörfler if (reportErrors) 170874c0424aSAxel Dörfler sErrorMessage.AddString("missing library", name); 170974c0424aSAxel Dörfler } 171074c0424aSAxel Dörfler 171174c0424aSAxel Dörfler // Collect all missing libraries in case we report back 17127486b72dSIngo Weinhold if (!reportErrors) { 17137486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 17147486b72dSIngo Weinhold "failed: %s", image->name, image->id, 17157486b72dSIngo Weinhold strerror(status)); 17160c0fea5dSIngo Weinhold return status; 171774c0424aSAxel Dörfler } 17187486b72dSIngo Weinhold } 17190c0fea5dSIngo Weinhold 17200c0fea5dSIngo Weinhold j += 1; 17210c0fea5dSIngo Weinhold break; 172274c0424aSAxel Dörfler } 17230c0fea5dSIngo Weinhold 17240c0fea5dSIngo Weinhold default: 17250c0fea5dSIngo Weinhold // ignore any other tag 17260c0fea5dSIngo Weinhold continue; 17270c0fea5dSIngo Weinhold } 17280c0fea5dSIngo Weinhold } 17290c0fea5dSIngo Weinhold 17307486b72dSIngo Weinhold if (status < B_OK) { 17317486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 17327486b72dSIngo Weinhold "failed: %s", image->name, image->id, 17337486b72dSIngo Weinhold strerror(status)); 173474c0424aSAxel Dörfler return status; 17357486b72dSIngo Weinhold } 173674c0424aSAxel Dörfler 17370c0fea5dSIngo Weinhold if (j != image->num_needed) { 17380c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 17397486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 17407486b72dSIngo Weinhold "failed: internal error", image->name, image->id); 17410c0fea5dSIngo Weinhold return B_ERROR; 17420c0fea5dSIngo Weinhold } 17430c0fea5dSIngo Weinhold 17447486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name, 17457486b72dSIngo Weinhold image->id); 17467486b72dSIngo Weinhold 17470c0fea5dSIngo Weinhold return B_OK; 17480c0fea5dSIngo Weinhold } 17490c0fea5dSIngo Weinhold 17500c0fea5dSIngo Weinhold 17510c0fea5dSIngo Weinhold static uint32 17520c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList, 17530c0fea5dSIngo Weinhold uint32 sortFlag) 17540c0fea5dSIngo Weinhold { 17550c0fea5dSIngo Weinhold uint32 i; 17560c0fea5dSIngo Weinhold 17570c0fea5dSIngo Weinhold if (image->flags & sortFlag) 17580c0fea5dSIngo Weinhold return slot; 17590c0fea5dSIngo Weinhold 17600c0fea5dSIngo Weinhold image->flags |= sortFlag; /* make sure we don't visit this one */ 17610c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) 17620c0fea5dSIngo Weinhold slot = topological_sort(image->needed[i], slot, initList, sortFlag); 17630c0fea5dSIngo Weinhold 17640c0fea5dSIngo Weinhold initList[slot] = image; 17650c0fea5dSIngo Weinhold return slot + 1; 17660c0fea5dSIngo Weinhold } 17670c0fea5dSIngo Weinhold 17680c0fea5dSIngo Weinhold 1769ca618b22SIngo Weinhold static uint32 1770ca618b22SIngo Weinhold topological_sort_breadth_first(image_t* image, image_t** list, uint32 sortFlag) 1771ca618b22SIngo Weinhold { 1772ca618b22SIngo Weinhold if ((image->flags & sortFlag) != 0) 1773ca618b22SIngo Weinhold return 0; 1774ca618b22SIngo Weinhold 1775ca618b22SIngo Weinhold // We directly use the result list as queue for the breadth first search. 1776ca618b22SIngo Weinhold list[0] = image; 1777ca618b22SIngo Weinhold image->flags |= sortFlag; 1778ca618b22SIngo Weinhold 1779ca618b22SIngo Weinhold int32 index = 0; 1780ca618b22SIngo Weinhold int32 count = 1; 1781ca618b22SIngo Weinhold 1782ca618b22SIngo Weinhold while (index < count) { 1783ca618b22SIngo Weinhold image = list[index++]; 1784ca618b22SIngo Weinhold 1785ca618b22SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 1786ca618b22SIngo Weinhold image_t* neededImage = image->needed[i]; 1787ca618b22SIngo Weinhold if ((neededImage->flags & sortFlag) == 0) { 1788ca618b22SIngo Weinhold // dependency not yet visited -- add to queue 1789ca618b22SIngo Weinhold list[count++] = neededImage; 1790ca618b22SIngo Weinhold neededImage->flags |= sortFlag; 1791ca618b22SIngo Weinhold } 1792ca618b22SIngo Weinhold } 1793ca618b22SIngo Weinhold } 1794ca618b22SIngo Weinhold 1795ca618b22SIngo Weinhold return count; 1796ca618b22SIngo Weinhold } 1797ca618b22SIngo Weinhold 1798ca618b22SIngo Weinhold 17990c0fea5dSIngo Weinhold static ssize_t 18000c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag) 18010c0fea5dSIngo Weinhold { 18020c0fea5dSIngo Weinhold image_t **list; 18030c0fea5dSIngo Weinhold 18040c0fea5dSIngo Weinhold list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *)); 18050c0fea5dSIngo Weinhold if (list == NULL) { 18060c0fea5dSIngo Weinhold FATAL("memory shortage in get_sorted_image_list()"); 18070c0fea5dSIngo Weinhold *_list = NULL; 18080c0fea5dSIngo Weinhold return B_NO_MEMORY; 18090c0fea5dSIngo Weinhold } 18100c0fea5dSIngo Weinhold 18110c0fea5dSIngo Weinhold memset(list, 0, sLoadedImageCount * sizeof(image_t *)); 18120c0fea5dSIngo Weinhold 18130c0fea5dSIngo Weinhold *_list = list; 18140c0fea5dSIngo Weinhold return topological_sort(image, 0, list, sortFlag); 18150c0fea5dSIngo Weinhold } 18160c0fea5dSIngo Weinhold 18170c0fea5dSIngo Weinhold 1818ca618b22SIngo Weinhold static ssize_t 1819ca618b22SIngo Weinhold get_sorted_image_list_breadth_first(image_t* image, image_t*** _list, 1820ca618b22SIngo Weinhold uint32 sortFlag) 1821ca618b22SIngo Weinhold { 1822ca618b22SIngo Weinhold image_t** list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t*)); 1823ca618b22SIngo Weinhold if (list == NULL) { 1824ca618b22SIngo Weinhold FATAL("memory shortage in get_sorted_image_list()"); 1825ca618b22SIngo Weinhold *_list = NULL; 1826ca618b22SIngo Weinhold return B_NO_MEMORY; 1827ca618b22SIngo Weinhold } 1828ca618b22SIngo Weinhold 1829ca618b22SIngo Weinhold memset(list, 0, sLoadedImageCount * sizeof(image_t *)); 1830ca618b22SIngo Weinhold 1831ca618b22SIngo Weinhold *_list = list; 1832ca618b22SIngo Weinhold 1833ca618b22SIngo Weinhold return topological_sort_breadth_first(image, list, sortFlag); 1834ca618b22SIngo Weinhold } 1835ca618b22SIngo Weinhold 1836ca618b22SIngo Weinhold 18370c0fea5dSIngo Weinhold static status_t 18380c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 18390c0fea5dSIngo Weinhold { 1840ca618b22SIngo Weinhold // build an array of images in the order we want to lookup symbols 1841ca618b22SIngo Weinhold image_t** lookupList; 1842ca618b22SIngo Weinhold ssize_t lookupCount = get_sorted_image_list_breadth_first(image, 1843ca618b22SIngo Weinhold &lookupList, RFLAG_VISITED); 1844ca618b22SIngo Weinhold if (lookupCount < 0) 1845ca618b22SIngo Weinhold return lookupCount; 18460c0fea5dSIngo Weinhold 1847ca618b22SIngo Weinhold // If the image is not the program image, add it and its dependencies, too. 1848ca618b22SIngo Weinhold if (sProgramImage != NULL && image != sProgramImage) { 1849ca618b22SIngo Weinhold lookupCount += topological_sort_breadth_first(sProgramImage, 1850ca618b22SIngo Weinhold lookupList + lookupCount, RFLAG_VISITED); 1851ca618b22SIngo Weinhold } 1852ca618b22SIngo Weinhold 1853ca618b22SIngo Weinhold // If we have pre-loaded images, prepend them. 1854ca618b22SIngo Weinhold if (sPreloadedImageCount > 0) { 1855ca618b22SIngo Weinhold // Count the ones that have to be added -- normally all, but one never 1856ca618b22SIngo Weinhold // knows. 1857ca618b22SIngo Weinhold uint32 preloadedCount = 0; 1858ca618b22SIngo Weinhold for (uint32 i = 0; i < sPreloadedImageCount; i++) { 1859ca618b22SIngo Weinhold image_t* preloadedImage = sPreloadedImages[i]; 1860ca618b22SIngo Weinhold if ((preloadedImage->flags & RFLAG_VISITED) == 0) 1861ca618b22SIngo Weinhold preloadedCount++; 1862ca618b22SIngo Weinhold } 1863ca618b22SIngo Weinhold 1864ca618b22SIngo Weinhold // add them 1865ca618b22SIngo Weinhold if (preloadedCount > 0) { 1866ca618b22SIngo Weinhold memmove(lookupList + preloadedCount, lookupList, 1867ca618b22SIngo Weinhold lookupCount * sizeof(image_t*)); 1868ca618b22SIngo Weinhold lookupCount += preloadedCount; 1869ca618b22SIngo Weinhold 1870ca618b22SIngo Weinhold preloadedCount = 0; 1871ca618b22SIngo Weinhold for (uint32 i = 0; i < sPreloadedImageCount; i++) { 1872ca618b22SIngo Weinhold image_t* preloadedImage = sPreloadedImages[i]; 1873ca618b22SIngo Weinhold if ((preloadedImage->flags & RFLAG_VISITED) == 0) 1874ca618b22SIngo Weinhold lookupList[preloadedCount++] = preloadedImage; 1875ca618b22SIngo Weinhold } 1876ca618b22SIngo Weinhold } 1877ca618b22SIngo Weinhold } 1878ca618b22SIngo Weinhold 1879ca618b22SIngo Weinhold // clear the "visited" flag 1880ca618b22SIngo Weinhold for (int32 i = 0; i < lookupCount; i++) 1881ca618b22SIngo Weinhold lookupList[i]->flags &= ~RFLAG_VISITED; 1882ca618b22SIngo Weinhold 1883ca618b22SIngo Weinhold image->symbol_resolution_images = lookupList; 1884ca618b22SIngo Weinhold image->symbol_resolution_image_count = lookupCount; 1885ca618b22SIngo Weinhold 1886ca618b22SIngo Weinhold // get the images that still have to be relocated 1887ca618b22SIngo Weinhold image_t **list; 1888ca618b22SIngo Weinhold ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 18890c0fea5dSIngo Weinhold if (count < B_OK) 18900c0fea5dSIngo Weinhold return count; 18910c0fea5dSIngo Weinhold 1892ca618b22SIngo Weinhold for (ssize_t i = 0; i < count; i++) { 189346f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 18940c0fea5dSIngo Weinhold if (status < B_OK) 18950c0fea5dSIngo Weinhold return status; 18960c0fea5dSIngo Weinhold } 18970c0fea5dSIngo Weinhold 18980c0fea5dSIngo Weinhold free(list); 18990c0fea5dSIngo Weinhold return B_OK; 19000c0fea5dSIngo Weinhold } 19010c0fea5dSIngo Weinhold 19020c0fea5dSIngo Weinhold 19030c0fea5dSIngo Weinhold static void 19040c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 19050c0fea5dSIngo Weinhold { 19060c0fea5dSIngo Weinhold image_t **initList; 19070c0fea5dSIngo Weinhold ssize_t count, i; 19080c0fea5dSIngo Weinhold 19090c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 19100c0fea5dSIngo Weinhold if (count <= 0) 19110c0fea5dSIngo Weinhold return; 19120c0fea5dSIngo Weinhold 19130c0fea5dSIngo Weinhold if (!initHead) { 19140c0fea5dSIngo Weinhold // this removes the "calling" image 19150c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 19160c0fea5dSIngo Weinhold initList[--count] = NULL; 19170c0fea5dSIngo Weinhold } 19180c0fea5dSIngo Weinhold 19190c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 19200c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 19210c0fea5dSIngo Weinhold image = initList[i]; 19220c0fea5dSIngo Weinhold 19230c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 19240c0fea5dSIngo Weinhold 1925dd76bc97SIngo Weinhold if (image->init_routine != 0) 19260c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 1927*10b4b5d1SIngo Weinhold 1928*10b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_INITIALIZED); 19290c0fea5dSIngo Weinhold } 19300c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 19310c0fea5dSIngo Weinhold 19320c0fea5dSIngo Weinhold free(initList); 19330c0fea5dSIngo Weinhold } 19340c0fea5dSIngo Weinhold 19350c0fea5dSIngo Weinhold 19360c0fea5dSIngo Weinhold static void 19370c0fea5dSIngo Weinhold put_image(image_t *image) 19380c0fea5dSIngo Weinhold { 19390c0fea5dSIngo Weinhold // If all references to the image are gone, add it to the disposable list 19400c0fea5dSIngo Weinhold // and remove all dependencies 19410c0fea5dSIngo Weinhold 19420c0fea5dSIngo Weinhold if (atomic_add(&image->ref_count, -1) == 1) { 19430c0fea5dSIngo Weinhold size_t i; 19440c0fea5dSIngo Weinhold 19450c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 19460c0fea5dSIngo Weinhold enqueue_image(&sDisposableImages, image); 19470c0fea5dSIngo Weinhold sLoadedImageCount--; 19480c0fea5dSIngo Weinhold 19490c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) { 19500c0fea5dSIngo Weinhold put_image(image->needed[i]); 19510c0fea5dSIngo Weinhold } 19520c0fea5dSIngo Weinhold } 19530c0fea5dSIngo Weinhold } 19540c0fea5dSIngo Weinhold 19550c0fea5dSIngo Weinhold 1956ca618b22SIngo Weinhold void 1957ca618b22SIngo Weinhold inject_runtime_loader_api(image_t* rootImage) 1958ca618b22SIngo Weinhold { 1959ca618b22SIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private 1960ca618b22SIngo Weinhold // API. 1961ca618b22SIngo Weinhold image_t* image; 1962ca618b22SIngo Weinhold Elf32_Sym* symbol = find_symbol_in_root_image_list(rootImage, 1963ca618b22SIngo Weinhold "__gRuntimeLoader", &image); 1964ca618b22SIngo Weinhold 1965ca618b22SIngo Weinhold if (symbol != NULL) { 1966ca618b22SIngo Weinhold void** _export = (void**)(symbol->st_value + image->regions[0].delta); 1967ca618b22SIngo Weinhold *_export = &gRuntimeLoader; 1968ca618b22SIngo Weinhold } 1969ca618b22SIngo Weinhold } 1970ca618b22SIngo Weinhold 1971ca618b22SIngo Weinhold 1972ca618b22SIngo Weinhold static status_t 1973ca618b22SIngo Weinhold add_preloaded_image(image_t* image) 1974ca618b22SIngo Weinhold { 1975ca618b22SIngo Weinhold // We realloc() everytime -- not particularly efficient, but good enough for 1976ca618b22SIngo Weinhold // small number of preloaded images. 1977ca618b22SIngo Weinhold image_t** newArray = (image_t**)realloc(sPreloadedImages, 1978ca618b22SIngo Weinhold sizeof(image_t*) * (sPreloadedImageCount + 1)); 1979ca618b22SIngo Weinhold if (newArray == NULL) 1980ca618b22SIngo Weinhold return B_NO_MEMORY; 1981ca618b22SIngo Weinhold 1982ca618b22SIngo Weinhold sPreloadedImages = newArray; 1983ca618b22SIngo Weinhold newArray[sPreloadedImageCount++] = image; 1984ca618b22SIngo Weinhold 1985ca618b22SIngo Weinhold return B_OK; 1986ca618b22SIngo Weinhold } 1987ca618b22SIngo Weinhold 1988ca618b22SIngo Weinhold 1989ca618b22SIngo Weinhold image_id 1990ca618b22SIngo Weinhold preload_image(char const* path) 1991ca618b22SIngo Weinhold { 1992ca618b22SIngo Weinhold if (path == NULL) 1993ca618b22SIngo Weinhold return B_BAD_VALUE; 1994ca618b22SIngo Weinhold 1995ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\")", path); 1996ca618b22SIngo Weinhold 1997ca618b22SIngo Weinhold image_t *image = NULL; 1998ca618b22SIngo Weinhold status_t status = load_container(path, B_ADD_ON_IMAGE, NULL, &image); 1999ca618b22SIngo Weinhold if (status < B_OK) { 2000ca618b22SIngo Weinhold rld_unlock(); 2001ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path, 2002ca618b22SIngo Weinhold strerror(status)); 2003ca618b22SIngo Weinhold return status; 2004ca618b22SIngo Weinhold } 2005ca618b22SIngo Weinhold 2006ca618b22SIngo Weinhold for (image_t* otherImage = sLoadedImages.head; otherImage != NULL; 2007ca618b22SIngo Weinhold otherImage = otherImage->next) { 2008ca618b22SIngo Weinhold status = load_dependencies(otherImage); 2009ca618b22SIngo Weinhold if (status < B_OK) 2010ca618b22SIngo Weinhold goto err; 2011ca618b22SIngo Weinhold } 2012ca618b22SIngo Weinhold 2013ca618b22SIngo Weinhold status = relocate_dependencies(image); 2014ca618b22SIngo Weinhold if (status < B_OK) 2015ca618b22SIngo Weinhold goto err; 2016ca618b22SIngo Weinhold 2017ca618b22SIngo Weinhold status = add_preloaded_image(image); 2018ca618b22SIngo Weinhold if (status < B_OK) 2019ca618b22SIngo Weinhold goto err; 2020ca618b22SIngo Weinhold 2021ca618b22SIngo Weinhold inject_runtime_loader_api(image); 2022ca618b22SIngo Weinhold 2023ca618b22SIngo Weinhold remap_images(); 2024ca618b22SIngo Weinhold init_dependencies(image, true); 2025ca618b22SIngo Weinhold 2026*10b4b5d1SIngo Weinhold // if the image contains an add-on, register it 2027*10b4b5d1SIngo Weinhold runtime_loader_add_on* addOnStruct; 2028*10b4b5d1SIngo Weinhold if (find_symbol(image, "__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA, 2029*10b4b5d1SIngo Weinhold (void**)&addOnStruct) == B_OK) { 2030*10b4b5d1SIngo Weinhold RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image, 2031*10b4b5d1SIngo Weinhold addOnStruct); 2032*10b4b5d1SIngo Weinhold if (addOn != NULL) { 2033*10b4b5d1SIngo Weinhold sAddOns.Add(addOn); 2034*10b4b5d1SIngo Weinhold addOnStruct->init(&gRuntimeLoader, &gRuntimeLoaderAddOnExport); 2035*10b4b5d1SIngo Weinhold } 2036*10b4b5d1SIngo Weinhold } 2037*10b4b5d1SIngo Weinhold 2038ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") done: id: %ld", path, image->id); 2039ca618b22SIngo Weinhold 2040ca618b22SIngo Weinhold return image->id; 2041ca618b22SIngo Weinhold 2042ca618b22SIngo Weinhold err: 2043ca618b22SIngo Weinhold KTRACE("rld: preload_image(\"%s\") failed: %s", path, strerror(status)); 2044ca618b22SIngo Weinhold 2045ca618b22SIngo Weinhold dequeue_image(&sLoadedImages, image); 2046ca618b22SIngo Weinhold sLoadedImageCount--; 2047ca618b22SIngo Weinhold delete_image(image); 2048ca618b22SIngo Weinhold return status; 2049ca618b22SIngo Weinhold } 2050ca618b22SIngo Weinhold 2051ca618b22SIngo Weinhold 2052ca618b22SIngo Weinhold static void 2053ca618b22SIngo Weinhold preload_images() 2054ca618b22SIngo Weinhold { 2055ca618b22SIngo Weinhold const char* imagePaths = getenv("LD_PRELOAD"); 2056ca618b22SIngo Weinhold if (imagePaths == NULL) 2057ca618b22SIngo Weinhold return; 2058ca618b22SIngo Weinhold 2059ca618b22SIngo Weinhold while (*imagePaths != '\0') { 2060ca618b22SIngo Weinhold // find begin of image path 2061ca618b22SIngo Weinhold while (*imagePaths != '\0' && isspace(*imagePaths)) 2062ca618b22SIngo Weinhold imagePaths++; 2063ca618b22SIngo Weinhold 2064ca618b22SIngo Weinhold if (*imagePaths == '\0') 2065ca618b22SIngo Weinhold break; 2066ca618b22SIngo Weinhold 2067ca618b22SIngo Weinhold // find end of image path 2068ca618b22SIngo Weinhold const char* imagePath = imagePaths; 2069ca618b22SIngo Weinhold while (*imagePaths != '\0' && !isspace(*imagePaths)) 2070ca618b22SIngo Weinhold imagePaths++; 2071ca618b22SIngo Weinhold 2072ca618b22SIngo Weinhold // extract the path 2073ca618b22SIngo Weinhold char path[B_PATH_NAME_LENGTH]; 2074ca618b22SIngo Weinhold size_t pathLen = imagePaths - imagePath; 2075ca618b22SIngo Weinhold if (pathLen > sizeof(path) - 1) 2076ca618b22SIngo Weinhold continue; 2077ca618b22SIngo Weinhold memcpy(path, imagePath, pathLen); 2078ca618b22SIngo Weinhold path[pathLen] = '\0'; 2079ca618b22SIngo Weinhold 2080ca618b22SIngo Weinhold // load the image 2081ca618b22SIngo Weinhold preload_image(path); 2082ca618b22SIngo Weinhold } 2083ca618b22SIngo Weinhold } 2084ca618b22SIngo Weinhold 2085ca618b22SIngo Weinhold 208674c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 20870c0fea5dSIngo Weinhold 20880c0fea5dSIngo Weinhold 20890c0fea5dSIngo Weinhold image_id 20900c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 20910c0fea5dSIngo Weinhold { 20920c0fea5dSIngo Weinhold status_t status; 20930c0fea5dSIngo Weinhold image_t *image; 20940c0fea5dSIngo Weinhold 20957486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path); 20967486b72dSIngo Weinhold 20970c0fea5dSIngo Weinhold rld_lock(); 20980c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 20990c0fea5dSIngo Weinhold 2100ca618b22SIngo Weinhold preload_images(); 2101ca618b22SIngo Weinhold 21020c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 21030c0fea5dSIngo Weinhold 21040c0fea5dSIngo Weinhold status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage); 210574c0424aSAxel Dörfler if (status < B_OK) 210674c0424aSAxel Dörfler goto err; 21070c0fea5dSIngo Weinhold 21080c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image != NULL; image = image->next) { 21090c0fea5dSIngo Weinhold status = load_dependencies(image); 21100c0fea5dSIngo Weinhold if (status < B_OK) 21110c0fea5dSIngo Weinhold goto err; 21120c0fea5dSIngo Weinhold } 21130c0fea5dSIngo Weinhold 21140c0fea5dSIngo Weinhold status = relocate_dependencies(sProgramImage); 21150c0fea5dSIngo Weinhold if (status < B_OK) 21160c0fea5dSIngo Weinhold goto err; 21170c0fea5dSIngo Weinhold 2118ca618b22SIngo Weinhold inject_runtime_loader_api(sProgramImage); 21190c0fea5dSIngo Weinhold 21200c0fea5dSIngo Weinhold remap_images(); 2121ca618b22SIngo Weinhold init_dependencies(sProgramImage, true); 21220c0fea5dSIngo Weinhold 21230c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 21240c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 21250c0fea5dSIngo Weinhold { 2126ca618b22SIngo Weinhold struct Elf32_Sym *symbol = find_symbol_in_root_image_list(sProgramImage, 2127ca618b22SIngo Weinhold "getenv", &image); 2128ca618b22SIngo Weinhold 21290c0fea5dSIngo Weinhold if (symbol != NULL) 21300c0fea5dSIngo Weinhold gGetEnv = (char* (*)(const char*)) 21310c0fea5dSIngo Weinhold (symbol->st_value + image->regions[0].delta); 21320c0fea5dSIngo Weinhold } 21330c0fea5dSIngo Weinhold 2134dd76bc97SIngo Weinhold if (sProgramImage->entry_point == 0) { 21350c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 21360c0fea5dSIngo Weinhold goto err; 21370c0fea5dSIngo Weinhold } 21380c0fea5dSIngo Weinhold 21390c0fea5dSIngo Weinhold *_entry = (void *)(sProgramImage->entry_point); 21400c0fea5dSIngo Weinhold 21410c0fea5dSIngo Weinhold rld_unlock(); 21427486b72dSIngo Weinhold 21435d0638bfSIngo Weinhold sProgramLoaded = true; 21445d0638bfSIngo Weinhold 21457486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path, 21467486b72dSIngo Weinhold *_entry, sProgramImage->id); 21477486b72dSIngo Weinhold 21480c0fea5dSIngo Weinhold return sProgramImage->id; 21490c0fea5dSIngo Weinhold 21500c0fea5dSIngo Weinhold err: 21517486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); 21527486b72dSIngo Weinhold 21530c0fea5dSIngo Weinhold delete_image(sProgramImage); 215474c0424aSAxel Dörfler 21554bef3723SAxel Dörfler if (report_errors()) { 21564bef3723SAxel Dörfler // send error message 215774c0424aSAxel Dörfler sErrorMessage.AddInt32("error", status); 21584bef3723SAxel Dörfler sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 21594bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 21604bef3723SAxel Dörfler 21614bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 21624bef3723SAxel Dörfler sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0); 216374c0424aSAxel Dörfler } 216474c0424aSAxel Dörfler _kern_loading_app_failed(status); 21650c0fea5dSIngo Weinhold rld_unlock(); 216674c0424aSAxel Dörfler 21670c0fea5dSIngo Weinhold return status; 21680c0fea5dSIngo Weinhold } 21690c0fea5dSIngo Weinhold 21700c0fea5dSIngo Weinhold 21710c0fea5dSIngo Weinhold image_id 21720c0fea5dSIngo Weinhold load_library(char const *path, uint32 flags, bool addOn) 21730c0fea5dSIngo Weinhold { 21740c0fea5dSIngo Weinhold image_t *image = NULL; 21750c0fea5dSIngo Weinhold image_t *iter; 21760c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 21770c0fea5dSIngo Weinhold status_t status; 21780c0fea5dSIngo Weinhold 21790c0fea5dSIngo Weinhold if (path == NULL) 21800c0fea5dSIngo Weinhold return B_BAD_VALUE; 21810c0fea5dSIngo Weinhold 21820c0fea5dSIngo Weinhold // ToDo: implement flags 21830c0fea5dSIngo Weinhold (void)flags; 21840c0fea5dSIngo Weinhold 21857486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn); 21867486b72dSIngo Weinhold 21870c0fea5dSIngo Weinhold rld_lock(); 21880c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 21890c0fea5dSIngo Weinhold 21900c0fea5dSIngo Weinhold // have we already loaded this library? 21910c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 21920c0fea5dSIngo Weinhold if (!addOn) { 21930c0fea5dSIngo Weinhold image = find_image(path, APP_OR_LIBRARY_TYPE); 21940c0fea5dSIngo Weinhold if (image) { 21950c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 21960c0fea5dSIngo Weinhold rld_unlock(); 21977486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path, 21987486b72dSIngo Weinhold image->id); 21990c0fea5dSIngo Weinhold return image->id; 22000c0fea5dSIngo Weinhold } 22010c0fea5dSIngo Weinhold } 22020c0fea5dSIngo Weinhold 22030c0fea5dSIngo Weinhold status = load_container(path, type, NULL, &image); 22040c0fea5dSIngo Weinhold if (status < B_OK) { 22050c0fea5dSIngo Weinhold rld_unlock(); 22067486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, 22077486b72dSIngo Weinhold strerror(status)); 22080c0fea5dSIngo Weinhold return status; 22090c0fea5dSIngo Weinhold } 22100c0fea5dSIngo Weinhold 22110c0fea5dSIngo Weinhold for (iter = sLoadedImages.head; iter; iter = iter->next) { 22120c0fea5dSIngo Weinhold status = load_dependencies(iter); 22130c0fea5dSIngo Weinhold if (status < B_OK) 22140c0fea5dSIngo Weinhold goto err; 22150c0fea5dSIngo Weinhold } 22160c0fea5dSIngo Weinhold 22170c0fea5dSIngo Weinhold status = relocate_dependencies(image); 22180c0fea5dSIngo Weinhold if (status < B_OK) 22190c0fea5dSIngo Weinhold goto err; 22200c0fea5dSIngo Weinhold 22210c0fea5dSIngo Weinhold remap_images(); 22220c0fea5dSIngo Weinhold init_dependencies(image, true); 22230c0fea5dSIngo Weinhold 22240c0fea5dSIngo Weinhold rld_unlock(); 22257486b72dSIngo Weinhold 22267486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id); 22277486b72dSIngo Weinhold 22280c0fea5dSIngo Weinhold return image->id; 22290c0fea5dSIngo Weinhold 22300c0fea5dSIngo Weinhold err: 22317486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status)); 22327486b72dSIngo Weinhold 22330c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 22340c0fea5dSIngo Weinhold sLoadedImageCount--; 22350c0fea5dSIngo Weinhold delete_image(image); 22360c0fea5dSIngo Weinhold rld_unlock(); 22370c0fea5dSIngo Weinhold return status; 22380c0fea5dSIngo Weinhold } 22390c0fea5dSIngo Weinhold 22400c0fea5dSIngo Weinhold 22410c0fea5dSIngo Weinhold status_t 22420c0fea5dSIngo Weinhold unload_library(image_id imageID, bool addOn) 22430c0fea5dSIngo Weinhold { 22440c0fea5dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 22450c0fea5dSIngo Weinhold image_t *image; 22460c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 22470c0fea5dSIngo Weinhold 22480c0fea5dSIngo Weinhold if (imageID < B_OK) 22490c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 22500c0fea5dSIngo Weinhold 22510c0fea5dSIngo Weinhold rld_lock(); 22520c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 22530c0fea5dSIngo Weinhold 22549a6072a3SAxel Dörfler if (sInvalidImageIDs) { 22559a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 22569a6072a3SAxel Dörfler update_image_ids(); 22579a6072a3SAxel Dörfler } 22589a6072a3SAxel Dörfler 22590c0fea5dSIngo Weinhold // we only check images that have been already initialized 22600c0fea5dSIngo Weinhold 22610c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image; image = image->next) { 22620c0fea5dSIngo Weinhold if (image->id == imageID) { 22630c0fea5dSIngo Weinhold // unload image 22640c0fea5dSIngo Weinhold if (type == image->type) { 22650c0fea5dSIngo Weinhold put_image(image); 22660c0fea5dSIngo Weinhold status = B_OK; 22670c0fea5dSIngo Weinhold } else 22680c0fea5dSIngo Weinhold status = B_BAD_VALUE; 22690c0fea5dSIngo Weinhold break; 22700c0fea5dSIngo Weinhold } 22710c0fea5dSIngo Weinhold } 22720c0fea5dSIngo Weinhold 22730c0fea5dSIngo Weinhold if (status == B_OK) { 22740c0fea5dSIngo Weinhold while ((image = sDisposableImages.head) != NULL) { 22750c0fea5dSIngo Weinhold // call image fini here... 22768c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 22778c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 22783be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize); 22798c2a9d74SMichael Lotz } 22808c2a9d74SMichael Lotz 2281*10b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 2282*10b4b5d1SIngo Weinhold 22830c0fea5dSIngo Weinhold if (image->term_routine) 22840c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 22850c0fea5dSIngo Weinhold 22860c0fea5dSIngo Weinhold dequeue_image(&sDisposableImages, image); 22870c0fea5dSIngo Weinhold unmap_image(image); 22880c0fea5dSIngo Weinhold 2289*10b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 2290*10b4b5d1SIngo Weinhold 22910c0fea5dSIngo Weinhold delete_image(image); 22920c0fea5dSIngo Weinhold } 22930c0fea5dSIngo Weinhold } 22940c0fea5dSIngo Weinhold 22950c0fea5dSIngo Weinhold rld_unlock(); 22960c0fea5dSIngo Weinhold return status; 22970c0fea5dSIngo Weinhold } 22980c0fea5dSIngo Weinhold 22990c0fea5dSIngo Weinhold 23000c0fea5dSIngo Weinhold status_t 23019a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, 23029a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location) 23030c0fea5dSIngo Weinhold { 23040c0fea5dSIngo Weinhold int32 count = 0, j; 23050c0fea5dSIngo Weinhold uint32 i; 23060c0fea5dSIngo Weinhold image_t *image; 23070c0fea5dSIngo Weinhold 23080c0fea5dSIngo Weinhold rld_lock(); 23090c0fea5dSIngo Weinhold 23100c0fea5dSIngo Weinhold // get the image from those who have been already initialized 23110c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 23120c0fea5dSIngo Weinhold if (image == NULL) { 23130c0fea5dSIngo Weinhold rld_unlock(); 23140c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 23150c0fea5dSIngo Weinhold } 23160c0fea5dSIngo Weinhold 23170c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 23180c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 23190c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 23200555803aSAxel Dörfler struct Elf32_Sym *symbol = &image->syms[j]; 23210c0fea5dSIngo Weinhold 23220c0fea5dSIngo Weinhold if (count == num) { 2323*10b4b5d1SIngo Weinhold const char* symbolName = SYMNAME(image, symbol); 2324*10b4b5d1SIngo Weinhold strlcpy(nameBuffer, symbolName, *_nameLength); 2325*10b4b5d1SIngo Weinhold *_nameLength = strlen(symbolName); 23260c0fea5dSIngo Weinhold 2327*10b4b5d1SIngo Weinhold void* location = (void*)(symbol->st_value 2328*10b4b5d1SIngo Weinhold + image->regions[0].delta); 2329*10b4b5d1SIngo Weinhold int32 type; 23300c0fea5dSIngo Weinhold if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) 2331*10b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_TEXT; 23320c0fea5dSIngo Weinhold else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) 2333*10b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_DATA; 23340c0fea5dSIngo Weinhold else 2335*10b4b5d1SIngo Weinhold type = B_SYMBOL_TYPE_ANY; 2336*10b4b5d1SIngo Weinhold // TODO: check with the return types of that BeOS function 23370c0fea5dSIngo Weinhold 2338*10b4b5d1SIngo Weinhold patch_defined_symbol(image, symbolName, &location, &type); 2339*10b4b5d1SIngo Weinhold 2340*10b4b5d1SIngo Weinhold if (_type != NULL) 2341*10b4b5d1SIngo Weinhold *_type = type; 23420c0fea5dSIngo Weinhold if (_location != NULL) 2343*10b4b5d1SIngo Weinhold *_location = location; 23440c0fea5dSIngo Weinhold goto out; 23450c0fea5dSIngo Weinhold } 23460c0fea5dSIngo Weinhold count++; 23470c0fea5dSIngo Weinhold } 23480c0fea5dSIngo Weinhold } 23490c0fea5dSIngo Weinhold out: 23500c0fea5dSIngo Weinhold rld_unlock(); 23510c0fea5dSIngo Weinhold 23520c0fea5dSIngo Weinhold if (num != count) 23530c0fea5dSIngo Weinhold return B_BAD_INDEX; 23540c0fea5dSIngo Weinhold 23550c0fea5dSIngo Weinhold return B_OK; 23560c0fea5dSIngo Weinhold } 23570c0fea5dSIngo Weinhold 23580c0fea5dSIngo Weinhold 23590c0fea5dSIngo Weinhold status_t 23609a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType, 23619a6072a3SAxel Dörfler void **_location) 23620c0fea5dSIngo Weinhold { 23630c0fea5dSIngo Weinhold status_t status = B_OK; 23640c0fea5dSIngo Weinhold image_t *image; 23650c0fea5dSIngo Weinhold 23660c0fea5dSIngo Weinhold if (imageID < B_OK) 23670c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 23680c0fea5dSIngo Weinhold if (symbolName == NULL) 23690c0fea5dSIngo Weinhold return B_BAD_VALUE; 23700c0fea5dSIngo Weinhold 23710c0fea5dSIngo Weinhold rld_lock(); 23720c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 23730c0fea5dSIngo Weinhold 23740c0fea5dSIngo Weinhold // get the image from those who have been already initialized 23750c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 2376*10b4b5d1SIngo Weinhold if (image != NULL) 2377*10b4b5d1SIngo Weinhold status = find_symbol(image, symbolName, symbolType, _location); 2378*10b4b5d1SIngo Weinhold else 23790c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 23800c0fea5dSIngo Weinhold 23810c0fea5dSIngo Weinhold rld_unlock(); 23820c0fea5dSIngo Weinhold return status; 23830c0fea5dSIngo Weinhold } 23840c0fea5dSIngo Weinhold 23850c0fea5dSIngo Weinhold 23860c0fea5dSIngo Weinhold status_t 23870c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 23880c0fea5dSIngo Weinhold { 23890c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 23900c0fea5dSIngo Weinhold struct Elf32_Dyn *dynamicSection; 23910c0fea5dSIngo Weinhold image_t *image; 23920c0fea5dSIngo Weinhold 23930c0fea5dSIngo Weinhold if (_name == NULL) 23940c0fea5dSIngo Weinhold return B_BAD_VALUE; 23950c0fea5dSIngo Weinhold 23960c0fea5dSIngo Weinhold rld_lock(); 23970c0fea5dSIngo Weinhold 23980c0fea5dSIngo Weinhold image = find_loaded_image_by_id(id); 23990c0fea5dSIngo Weinhold if (image == NULL) { 24000c0fea5dSIngo Weinhold rld_unlock(); 24010c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 24020c0fea5dSIngo Weinhold } 24030c0fea5dSIngo Weinhold 24040c0fea5dSIngo Weinhold dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr; 24050c0fea5dSIngo Weinhold if (dynamicSection == NULL || image->num_needed <= searchIndex) { 24060c0fea5dSIngo Weinhold rld_unlock(); 24070c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 24080c0fea5dSIngo Weinhold } 24090c0fea5dSIngo Weinhold 24100c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 24110c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 24120c0fea5dSIngo Weinhold continue; 24130c0fea5dSIngo Weinhold 24140c0fea5dSIngo Weinhold if (j++ == searchIndex) { 24150c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 24160c0fea5dSIngo Weinhold 24170c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 24180c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 24190c0fea5dSIngo Weinhold rld_unlock(); 24200c0fea5dSIngo Weinhold return B_OK; 24210c0fea5dSIngo Weinhold } 24220c0fea5dSIngo Weinhold } 24230c0fea5dSIngo Weinhold 24240c0fea5dSIngo Weinhold rld_unlock(); 24250c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 24260c0fea5dSIngo Weinhold } 24270c0fea5dSIngo Weinhold 24280c0fea5dSIngo Weinhold 242974c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 24300c0fea5dSIngo Weinhold 24310c0fea5dSIngo Weinhold 24329a6072a3SAxel Dörfler /*! Read and verify the ELF header */ 24330c0fea5dSIngo Weinhold status_t 24340c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length) 24350c0fea5dSIngo Weinhold { 24360c0fea5dSIngo Weinhold int32 programSize, sectionSize; 24370c0fea5dSIngo Weinhold 24380c0fea5dSIngo Weinhold if (length < (int32)sizeof(struct Elf32_Ehdr)) 24390c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 24400c0fea5dSIngo Weinhold 24419a6072a3SAxel Dörfler return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, 24429a6072a3SAxel Dörfler §ionSize); 24430c0fea5dSIngo Weinhold } 24440c0fea5dSIngo Weinhold 24450c0fea5dSIngo Weinhold 24460c0fea5dSIngo Weinhold void 24470c0fea5dSIngo Weinhold terminate_program(void) 24480c0fea5dSIngo Weinhold { 24490c0fea5dSIngo Weinhold image_t **termList; 24500c0fea5dSIngo Weinhold ssize_t count, i; 24510c0fea5dSIngo Weinhold 24520c0fea5dSIngo Weinhold count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED); 24530c0fea5dSIngo Weinhold if (count < B_OK) 24540c0fea5dSIngo Weinhold return; 24550c0fea5dSIngo Weinhold 24569a6072a3SAxel Dörfler if (sInvalidImageIDs) { 24579a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 24589a6072a3SAxel Dörfler update_image_ids(); 24599a6072a3SAxel Dörfler } 24609a6072a3SAxel Dörfler 24610c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 24620c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 24630c0fea5dSIngo Weinhold image_t *image = termList[i]; 24640c0fea5dSIngo Weinhold 24650c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 24660c0fea5dSIngo Weinhold 2467*10b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNINITIALIZING); 2468*10b4b5d1SIngo Weinhold 24690c0fea5dSIngo Weinhold if (image->term_routine) 24700c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 2471*10b4b5d1SIngo Weinhold 2472*10b4b5d1SIngo Weinhold image_event(image, IMAGE_EVENT_UNLOADING); 24730c0fea5dSIngo Weinhold } 24740c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 24750c0fea5dSIngo Weinhold 24760c0fea5dSIngo Weinhold free(termList); 24770c0fea5dSIngo Weinhold } 24780c0fea5dSIngo Weinhold 24790c0fea5dSIngo Weinhold 24800c0fea5dSIngo Weinhold void 24810c0fea5dSIngo Weinhold rldelf_init(void) 24820c0fea5dSIngo Weinhold { 2483*10b4b5d1SIngo Weinhold // invoke static constructors 2484*10b4b5d1SIngo Weinhold new(&sAddOns) AddOnList; 2485*10b4b5d1SIngo Weinhold 2486e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 2487e73923b0SAxel Dörfler sSemOwner = -1; 2488e73923b0SAxel Dörfler sSemCount = 0; 24890c0fea5dSIngo Weinhold 24900c0fea5dSIngo Weinhold // create the debug area 24910c0fea5dSIngo Weinhold { 24920c0fea5dSIngo Weinhold int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 24930c0fea5dSIngo Weinhold 24940c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 24950c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 24960c0fea5dSIngo Weinhold (void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK, 24970c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 24980c0fea5dSIngo Weinhold if (areaID < B_OK) { 24990c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 25000c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 25010c0fea5dSIngo Weinhold } 25020c0fea5dSIngo Weinhold 25030c0fea5dSIngo Weinhold area->loaded_images = &sLoadedImages; 25040c0fea5dSIngo Weinhold } 250574c0424aSAxel Dörfler 250674c0424aSAxel Dörfler // initialize error message if needed 25074bef3723SAxel Dörfler if (report_errors()) { 250874c0424aSAxel Dörfler void *buffer = malloc(1024); 250974c0424aSAxel Dörfler if (buffer == NULL) 251074c0424aSAxel Dörfler return; 251174c0424aSAxel Dörfler 251274c0424aSAxel Dörfler sErrorMessage.SetTo(buffer, 1024, 'Rler'); 251374c0424aSAxel Dörfler } 25140c0fea5dSIngo Weinhold } 25151873b4b3SIngo Weinhold 25161873b4b3SIngo Weinhold 25171873b4b3SIngo Weinhold status_t 25189a6072a3SAxel Dörfler elf_reinit_after_fork(void) 25191873b4b3SIngo Weinhold { 2520e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 2521e73923b0SAxel Dörfler if (sSem < 0) 2522e73923b0SAxel Dörfler return sSem; 25231873b4b3SIngo Weinhold 25249a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and 2525cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork() 2526cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one 25279a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different. 25289a6072a3SAxel Dörfler sInvalidImageIDs = true; 2529cbc456deSIngo Weinhold 25301873b4b3SIngo Weinhold return B_OK; 25311873b4b3SIngo Weinhold } 2532