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 120c0fea5dSIngo Weinhold #include "runtime_loader_private.h" 130c0fea5dSIngo Weinhold 140c0fea5dSIngo Weinhold #include <OS.h> 150c0fea5dSIngo Weinhold 160c0fea5dSIngo Weinhold #include <string.h> 170c0fea5dSIngo Weinhold #include <stdio.h> 180c0fea5dSIngo Weinhold #include <stdlib.h> 1934982809SIngo Weinhold #include <string.h> 200c0fea5dSIngo Weinhold 217486b72dSIngo Weinhold #include <elf32.h> 227486b72dSIngo Weinhold #include <runtime_loader.h> 237486b72dSIngo Weinhold #include <syscalls.h> 247486b72dSIngo Weinhold #include <user_runtime.h> 256b202f4eSIngo Weinhold #include <util/KMessage.h> 266b202f4eSIngo Weinhold #include <vm_defs.h> 277486b72dSIngo Weinhold 28071f9c3aSIngo Weinhold #include "tracing_config.h" 29071f9c3aSIngo Weinhold 300c0fea5dSIngo Weinhold 310c0fea5dSIngo Weinhold //#define TRACE_RLD 320c0fea5dSIngo Weinhold #ifdef TRACE_RLD 330c0fea5dSIngo Weinhold # define TRACE(x) dprintf x 340c0fea5dSIngo Weinhold #else 350c0fea5dSIngo Weinhold # define TRACE(x) ; 360c0fea5dSIngo Weinhold #endif 370c0fea5dSIngo Weinhold 380c0fea5dSIngo Weinhold 390c0fea5dSIngo Weinhold // ToDo: implement better locking strategy 400c0fea5dSIngo Weinhold // ToDo: implement lazy binding 410c0fea5dSIngo Weinhold 420c0fea5dSIngo Weinhold #define PAGE_MASK (B_PAGE_SIZE - 1) 430c0fea5dSIngo Weinhold 440c0fea5dSIngo Weinhold #define PAGE_OFFSET(x) ((x) & (PAGE_MASK)) 450c0fea5dSIngo Weinhold #define PAGE_BASE(x) ((x) & ~(PAGE_MASK)) 460c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK)) 470c0fea5dSIngo Weinhold 480c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000 490c0fea5dSIngo Weinhold /* keep in sync with app ldscript */ 500c0fea5dSIngo Weinhold 510c0fea5dSIngo Weinhold enum { 520c0fea5dSIngo Weinhold RFLAG_RW = 0x0001, 530c0fea5dSIngo Weinhold RFLAG_ANON = 0x0002, 540c0fea5dSIngo Weinhold 550c0fea5dSIngo Weinhold RFLAG_TERMINATED = 0x0200, 560c0fea5dSIngo Weinhold RFLAG_INITIALIZED = 0x0400, 570c0fea5dSIngo Weinhold RFLAG_SYMBOLIC = 0x0800, 580c0fea5dSIngo Weinhold RFLAG_RELOCATED = 0x1000, 590c0fea5dSIngo Weinhold RFLAG_PROTECTED = 0x2000, 600c0fea5dSIngo Weinhold RFLAG_DEPENDENCIES_LOADED = 0x4000, 6146f4d849SIngo Weinhold RFLAG_REMAPPED = 0x8000, 6246f4d849SIngo Weinhold 6346f4d849SIngo Weinhold RFLAG_VISITED = 0x10000 6446f4d849SIngo Weinhold // temporarily set in the symbol resolution code 650c0fea5dSIngo Weinhold }; 660c0fea5dSIngo Weinhold 670c0fea5dSIngo Weinhold 680c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type) (1 << ((type) - 1)) 690c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 700c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \ 710c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \ 720c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE)) 730c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 740c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE)) 750c0fea5dSIngo Weinhold 760c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 770c0fea5dSIngo Weinhold 780c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0}; 790c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0}; 800c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0; 810c0fea5dSIngo Weinhold static image_t *sProgramImage; 8274c0424aSAxel Dörfler static KMessage sErrorMessage; 835d0638bfSIngo Weinhold static bool sProgramLoaded = false; 8461b37794SIngo Weinhold static const char *sSearchPathSubDir = NULL; 859a6072a3SAxel Dörfler static bool sInvalidImageIDs; 860c0fea5dSIngo Weinhold 870c0fea5dSIngo Weinhold // a recursive lock 88e73923b0SAxel Dörfler static sem_id sSem; 89e73923b0SAxel Dörfler static thread_id sSemOwner; 90e73923b0SAxel Dörfler static int32 sSemCount; 910c0fea5dSIngo Weinhold 920c0fea5dSIngo Weinhold 930c0fea5dSIngo Weinhold void 940c0fea5dSIngo Weinhold dprintf(const char *format, ...) 950c0fea5dSIngo Weinhold { 960c0fea5dSIngo Weinhold char buffer[1024]; 970c0fea5dSIngo Weinhold 980c0fea5dSIngo Weinhold va_list list; 990c0fea5dSIngo Weinhold va_start(list, format); 1000c0fea5dSIngo Weinhold 1010c0fea5dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 1020c0fea5dSIngo Weinhold _kern_debug_output(buffer); 1030c0fea5dSIngo Weinhold 1040c0fea5dSIngo Weinhold va_end(list); 1050c0fea5dSIngo Weinhold } 1065d0638bfSIngo Weinhold 1075d0638bfSIngo Weinhold #define FATAL(x...) \ 1085d0638bfSIngo Weinhold do { \ 1095d0638bfSIngo Weinhold dprintf("runtime_loader: " x); \ 1105d0638bfSIngo Weinhold if (!sProgramLoaded) \ 1115d0638bfSIngo Weinhold printf("runtime_loader: " x); \ 1125d0638bfSIngo Weinhold } while (false) 1130c0fea5dSIngo Weinhold 1140c0fea5dSIngo Weinhold 11534982809SIngo Weinhold /*! Mini atoi(), so we don't have to include the libroot dependencies. 11634982809SIngo Weinhold */ 11734982809SIngo Weinhold int 11834982809SIngo Weinhold atoi(const char* num) 11934982809SIngo Weinhold { 12034982809SIngo Weinhold int result = 0; 12134982809SIngo Weinhold while (*num >= '0' && *num <= '9') { 12234982809SIngo Weinhold result = (result * 10) + (*num - '0'); 12334982809SIngo Weinhold num++; 12434982809SIngo Weinhold } 12534982809SIngo Weinhold 12634982809SIngo Weinhold return result; 12734982809SIngo Weinhold } 12834982809SIngo Weinhold 12934982809SIngo Weinhold 1306bf15ffcSIngo Weinhold #if RUNTIME_LOADER_TRACING 1317486b72dSIngo Weinhold 1327486b72dSIngo Weinhold void 1337486b72dSIngo Weinhold ktrace_printf(const char *format, ...) 1347486b72dSIngo Weinhold { 1357486b72dSIngo Weinhold va_list list; 1367486b72dSIngo Weinhold va_start(list, format); 1377486b72dSIngo Weinhold 1387486b72dSIngo Weinhold char buffer[1024]; 1397486b72dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 1407486b72dSIngo Weinhold _kern_ktrace_output(buffer); 1417486b72dSIngo Weinhold 1427486b72dSIngo Weinhold va_end(list); 1437486b72dSIngo Weinhold } 1447486b72dSIngo Weinhold 1457486b72dSIngo Weinhold #define KTRACE(x...) ktrace_printf(x) 1467486b72dSIngo Weinhold 1477486b72dSIngo Weinhold #else 1487486b72dSIngo Weinhold # define KTRACE(x...) 1497486b72dSIngo Weinhold #endif // RUNTIME_LOADER_TRACING 1507486b72dSIngo Weinhold 1517486b72dSIngo Weinhold 1520c0fea5dSIngo Weinhold static void 1530c0fea5dSIngo Weinhold rld_unlock() 1540c0fea5dSIngo Weinhold { 155e73923b0SAxel Dörfler if (sSemCount-- == 1) { 156e73923b0SAxel Dörfler sSemOwner = -1; 157e73923b0SAxel Dörfler release_sem(sSem); 1580c0fea5dSIngo Weinhold } 1590c0fea5dSIngo Weinhold } 1600c0fea5dSIngo Weinhold 1610c0fea5dSIngo Weinhold 1620c0fea5dSIngo Weinhold static void 1630c0fea5dSIngo Weinhold rld_lock() 1640c0fea5dSIngo Weinhold { 1650c0fea5dSIngo Weinhold thread_id self = find_thread(NULL); 166e73923b0SAxel Dörfler if (self != sSemOwner) { 167e73923b0SAxel Dörfler acquire_sem(sSem); 168e73923b0SAxel Dörfler sSemOwner = self; 1690c0fea5dSIngo Weinhold } 170e73923b0SAxel Dörfler sSemCount++; 1710c0fea5dSIngo Weinhold } 1720c0fea5dSIngo Weinhold 1730c0fea5dSIngo Weinhold 1740c0fea5dSIngo Weinhold static void 1750c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image) 1760c0fea5dSIngo Weinhold { 1770c0fea5dSIngo Weinhold image->next = 0; 1780c0fea5dSIngo Weinhold 1790c0fea5dSIngo Weinhold image->prev = queue->tail; 1800c0fea5dSIngo Weinhold if (queue->tail) 1810c0fea5dSIngo Weinhold queue->tail->next = image; 1820c0fea5dSIngo Weinhold 1830c0fea5dSIngo Weinhold queue->tail = image; 1840c0fea5dSIngo Weinhold if (!queue->head) 1850c0fea5dSIngo Weinhold queue->head = image; 1860c0fea5dSIngo Weinhold } 1870c0fea5dSIngo Weinhold 1880c0fea5dSIngo Weinhold 1890c0fea5dSIngo Weinhold static void 1900c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image) 1910c0fea5dSIngo Weinhold { 1920c0fea5dSIngo Weinhold if (image->next) 1930c0fea5dSIngo Weinhold image->next->prev = image->prev; 1940c0fea5dSIngo Weinhold else 1950c0fea5dSIngo Weinhold queue->tail = image->prev; 1960c0fea5dSIngo Weinhold 1970c0fea5dSIngo Weinhold if (image->prev) 1980c0fea5dSIngo Weinhold image->prev->next = image->next; 1990c0fea5dSIngo Weinhold else 2000c0fea5dSIngo Weinhold queue->head = image->next; 2010c0fea5dSIngo Weinhold 2020c0fea5dSIngo Weinhold image->prev = 0; 2030c0fea5dSIngo Weinhold image->next = 0; 2040c0fea5dSIngo Weinhold } 2050c0fea5dSIngo Weinhold 2060c0fea5dSIngo Weinhold 2070c0fea5dSIngo Weinhold static uint32 2080c0fea5dSIngo Weinhold elf_hash(const uint8 *name) 2090c0fea5dSIngo Weinhold { 2100c0fea5dSIngo Weinhold uint32 hash = 0; 2110c0fea5dSIngo Weinhold uint32 temp; 2120c0fea5dSIngo Weinhold 2130c0fea5dSIngo Weinhold while (*name) { 2140c0fea5dSIngo Weinhold hash = (hash << 4) + *name++; 2150c0fea5dSIngo Weinhold if ((temp = hash & 0xf0000000)) { 2160c0fea5dSIngo Weinhold hash ^= temp >> 24; 2170c0fea5dSIngo Weinhold } 2180c0fea5dSIngo Weinhold hash &= ~temp; 2190c0fea5dSIngo Weinhold } 2200c0fea5dSIngo Weinhold return hash; 2210c0fea5dSIngo Weinhold } 2220c0fea5dSIngo Weinhold 2230c0fea5dSIngo Weinhold 2244bef3723SAxel Dörfler static inline bool 2254bef3723SAxel Dörfler report_errors() 2264bef3723SAxel Dörfler { 2274bef3723SAxel Dörfler return gProgramArgs->error_port >= 0; 2284bef3723SAxel Dörfler } 2294bef3723SAxel Dörfler 2304bef3723SAxel Dörfler 2319a6072a3SAxel Dörfler //! Remaps the image ID of \a image after fork. 2329a6072a3SAxel Dörfler static status_t 2339a6072a3SAxel Dörfler update_image_id(image_t *image) 2349a6072a3SAxel Dörfler { 2359a6072a3SAxel Dörfler int32 cookie = 0; 2369a6072a3SAxel Dörfler image_info info; 2379a6072a3SAxel Dörfler while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info, 2389a6072a3SAxel Dörfler sizeof(image_info)) == B_OK) { 2399a6072a3SAxel Dörfler for (uint32 i = 0; i < image->num_regions; i++) { 2409a6072a3SAxel Dörfler if (image->regions[i].vmstart == (addr_t)info.text) { 2419a6072a3SAxel Dörfler image->id = info.id; 2429a6072a3SAxel Dörfler return B_OK; 2439a6072a3SAxel Dörfler } 2449a6072a3SAxel Dörfler } 2459a6072a3SAxel Dörfler } 2469a6072a3SAxel Dörfler 2479a6072a3SAxel Dörfler FATAL("Could not update image ID %ld after fork()!\n", image->id); 2489a6072a3SAxel Dörfler return B_ENTRY_NOT_FOUND; 2499a6072a3SAxel Dörfler } 2509a6072a3SAxel Dörfler 2519a6072a3SAxel Dörfler 2529a6072a3SAxel Dörfler //! After fork, we lazily rebuild the image IDs of all loaded images. 2539a6072a3SAxel Dörfler static status_t 2549a6072a3SAxel Dörfler update_image_ids(void) 2559a6072a3SAxel Dörfler { 2569a6072a3SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 2579a6072a3SAxel Dörfler status_t status = update_image_id(image); 2589a6072a3SAxel Dörfler if (status != B_OK) 2599a6072a3SAxel Dörfler return status; 2609a6072a3SAxel Dörfler } 2619a6072a3SAxel Dörfler for (image_t *image = sDisposableImages.head; image; image = image->next) { 2629a6072a3SAxel Dörfler status_t status = update_image_id(image); 2639a6072a3SAxel Dörfler if (status != B_OK) 2649a6072a3SAxel Dörfler return status; 2659a6072a3SAxel Dörfler } 2669a6072a3SAxel Dörfler 2679a6072a3SAxel Dörfler sInvalidImageIDs = false; 2689a6072a3SAxel Dörfler return B_OK; 2699a6072a3SAxel Dörfler } 2709a6072a3SAxel Dörfler 2719a6072a3SAxel Dörfler 2720c0fea5dSIngo Weinhold static image_t * 2730c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath, 2740c0fea5dSIngo Weinhold uint32 typeMask) 2750c0fea5dSIngo Weinhold { 2769a6072a3SAxel Dörfler for (image_t *image = queue->head; image; image = image->next) { 2770c0fea5dSIngo Weinhold const char *imageName = isPath ? image->path : image->name; 2780c0fea5dSIngo Weinhold int length = isPath ? sizeof(image->path) : sizeof(image->name); 2790c0fea5dSIngo Weinhold 2800c0fea5dSIngo Weinhold if (!strncmp(imageName, name, length) 2810c0fea5dSIngo Weinhold && (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) { 2820c0fea5dSIngo Weinhold return image; 2830c0fea5dSIngo Weinhold } 2840c0fea5dSIngo Weinhold } 2850c0fea5dSIngo Weinhold 2860c0fea5dSIngo Weinhold return NULL; 2870c0fea5dSIngo Weinhold } 2880c0fea5dSIngo Weinhold 2890c0fea5dSIngo Weinhold 2900c0fea5dSIngo Weinhold static image_t * 2910c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask) 2920c0fea5dSIngo Weinhold { 2939a6072a3SAxel Dörfler bool isPath = strchr(name, '/') != NULL; 29446f4d849SIngo Weinhold return find_image_in_queue(&sLoadedImages, name, isPath, typeMask); 2950c0fea5dSIngo Weinhold } 2960c0fea5dSIngo Weinhold 2970c0fea5dSIngo Weinhold 2980c0fea5dSIngo Weinhold static image_t * 2990c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id) 3000c0fea5dSIngo Weinhold { 3019a6072a3SAxel Dörfler if (sInvalidImageIDs) { 3029a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 3039a6072a3SAxel Dörfler update_image_ids(); 3049a6072a3SAxel Dörfler } 3050c0fea5dSIngo Weinhold 3069a6072a3SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 3070c0fea5dSIngo Weinhold if (image->id == id) 3080c0fea5dSIngo Weinhold return image; 3090c0fea5dSIngo Weinhold } 3100c0fea5dSIngo Weinhold 3110c0fea5dSIngo Weinhold // For the termination routine, we need to look into the list of 3120c0fea5dSIngo Weinhold // disposable images as well 3139a6072a3SAxel Dörfler for (image_t *image = sDisposableImages.head; image; image = image->next) { 3140c0fea5dSIngo Weinhold if (image->id == id) 3150c0fea5dSIngo Weinhold return image; 3160c0fea5dSIngo Weinhold } 3170c0fea5dSIngo Weinhold 3180c0fea5dSIngo Weinhold return NULL; 3190c0fea5dSIngo Weinhold } 3200c0fea5dSIngo Weinhold 3210c0fea5dSIngo Weinhold 3225fd6637bSIngo Weinhold static image_t* 3235fd6637bSIngo Weinhold get_program_image() 32412a5e9a4SAxel Dörfler { 32512a5e9a4SAxel Dörfler for (image_t *image = sLoadedImages.head; image; image = image->next) { 32612a5e9a4SAxel Dörfler if (image->type == B_APP_IMAGE) 3275fd6637bSIngo Weinhold return image; 32812a5e9a4SAxel Dörfler } 32912a5e9a4SAxel Dörfler 33012a5e9a4SAxel Dörfler return NULL; 33112a5e9a4SAxel Dörfler } 33212a5e9a4SAxel Dörfler 33312a5e9a4SAxel Dörfler 3345fd6637bSIngo Weinhold static const char * 3355fd6637bSIngo Weinhold get_program_path() 3365fd6637bSIngo Weinhold { 3375fd6637bSIngo Weinhold if (image_t* image = get_program_image()) 3385fd6637bSIngo Weinhold return image->path; 3395fd6637bSIngo Weinhold 3405fd6637bSIngo Weinhold return NULL; 3415fd6637bSIngo Weinhold } 3425fd6637bSIngo Weinhold 3435fd6637bSIngo Weinhold 3440c0fea5dSIngo Weinhold static status_t 34512a5e9a4SAxel Dörfler parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize, 34612a5e9a4SAxel Dörfler int32 *_sheaderSize) 3470c0fea5dSIngo Weinhold { 3480c0fea5dSIngo Weinhold if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) 3490c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 3500c0fea5dSIngo Weinhold 3510c0fea5dSIngo Weinhold if (eheader->e_ident[4] != ELFCLASS32) 3520c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 3530c0fea5dSIngo Weinhold 3540c0fea5dSIngo Weinhold if (eheader->e_phoff == 0) 3550c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 3560c0fea5dSIngo Weinhold 3570c0fea5dSIngo Weinhold if (eheader->e_phentsize < sizeof(struct Elf32_Phdr)) 3580c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 3590c0fea5dSIngo Weinhold 3600c0fea5dSIngo Weinhold *_pheaderSize = eheader->e_phentsize * eheader->e_phnum; 3610c0fea5dSIngo Weinhold *_sheaderSize = eheader->e_shentsize * eheader->e_shnum; 3620c0fea5dSIngo Weinhold 3635aa7b7b6SMarcus Overhagen if (*_pheaderSize <= 0 || *_sheaderSize <= 0) 3645aa7b7b6SMarcus Overhagen return B_NOT_AN_EXECUTABLE; 3655aa7b7b6SMarcus Overhagen 3665aa7b7b6SMarcus Overhagen return B_OK; 3670c0fea5dSIngo Weinhold } 3680c0fea5dSIngo Weinhold 3690c0fea5dSIngo Weinhold 3700c0fea5dSIngo Weinhold static int32 3710c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize) 3720c0fea5dSIngo Weinhold { 3730c0fea5dSIngo Weinhold struct Elf32_Phdr *pheaders; 3740c0fea5dSIngo Weinhold int32 count = 0; 3750c0fea5dSIngo Weinhold int i; 3760c0fea5dSIngo Weinhold 3770c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 3780c0fea5dSIngo Weinhold pheaders = (struct Elf32_Phdr *)(buff + i * phentsize); 3790c0fea5dSIngo Weinhold 3800c0fea5dSIngo Weinhold switch (pheaders->p_type) { 3810c0fea5dSIngo Weinhold case PT_NULL: 3820c0fea5dSIngo Weinhold /* NOP header */ 3830c0fea5dSIngo Weinhold break; 3840c0fea5dSIngo Weinhold case PT_LOAD: 3850c0fea5dSIngo Weinhold count += 1; 3860c0fea5dSIngo Weinhold if (pheaders->p_memsz != pheaders->p_filesz) { 3870c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz); 3880c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz); 3890c0fea5dSIngo Weinhold 3900c0fea5dSIngo Weinhold if (A != B) 3910c0fea5dSIngo Weinhold count += 1; 3920c0fea5dSIngo Weinhold } 3930c0fea5dSIngo Weinhold break; 3940c0fea5dSIngo Weinhold case PT_DYNAMIC: 3950c0fea5dSIngo Weinhold /* will be handled at some other place */ 3960c0fea5dSIngo Weinhold break; 3970c0fea5dSIngo Weinhold case PT_INTERP: 3980c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 3990c0fea5dSIngo Weinhold break; 4000c0fea5dSIngo Weinhold case PT_NOTE: 4010c0fea5dSIngo Weinhold /* unsupported */ 4020c0fea5dSIngo Weinhold break; 4030c0fea5dSIngo Weinhold case PT_SHLIB: 4040c0fea5dSIngo Weinhold /* undefined semantics */ 4050c0fea5dSIngo Weinhold break; 4060c0fea5dSIngo Weinhold case PT_PHDR: 4070c0fea5dSIngo Weinhold /* we don't use it */ 4080c0fea5dSIngo Weinhold break; 4090c0fea5dSIngo Weinhold default: 4100c0fea5dSIngo Weinhold FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type); 4110c0fea5dSIngo Weinhold return B_BAD_DATA; 4120c0fea5dSIngo Weinhold } 4130c0fea5dSIngo Weinhold } 4140c0fea5dSIngo Weinhold 4150c0fea5dSIngo Weinhold return count; 4160c0fea5dSIngo Weinhold } 4170c0fea5dSIngo Weinhold 4180c0fea5dSIngo Weinhold 4190c0fea5dSIngo Weinhold static image_t * 4200c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions) 4210c0fea5dSIngo Weinhold { 4220c0fea5dSIngo Weinhold size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t); 4230c0fea5dSIngo Weinhold const char *lastSlash; 4240c0fea5dSIngo Weinhold 4250c0fea5dSIngo Weinhold image_t *image = (image_t*)malloc(allocSize); 4260c0fea5dSIngo Weinhold if (image == NULL) { 4270c0fea5dSIngo Weinhold FATAL("no memory for image %s\n", path); 4280c0fea5dSIngo Weinhold return NULL; 4290c0fea5dSIngo Weinhold } 4300c0fea5dSIngo Weinhold 4310c0fea5dSIngo Weinhold memset(image, 0, allocSize); 4320c0fea5dSIngo Weinhold 4330c0fea5dSIngo Weinhold strlcpy(image->path, path, sizeof(image->path)); 4340c0fea5dSIngo Weinhold 4350c0fea5dSIngo Weinhold // Make the last component of the supplied name the image name. 4360c0fea5dSIngo Weinhold // If present, DT_SONAME will replace this name. 4370c0fea5dSIngo Weinhold if ((lastSlash = strrchr(name, '/'))) 4380c0fea5dSIngo Weinhold strlcpy(image->name, lastSlash + 1, sizeof(image->name)); 4390c0fea5dSIngo Weinhold else 4400c0fea5dSIngo Weinhold strlcpy(image->name, name, sizeof(image->name)); 4410c0fea5dSIngo Weinhold 4420c0fea5dSIngo Weinhold image->ref_count = 1; 4430c0fea5dSIngo Weinhold image->num_regions = num_regions; 4440c0fea5dSIngo Weinhold 4450c0fea5dSIngo Weinhold return image; 4460c0fea5dSIngo Weinhold } 4470c0fea5dSIngo Weinhold 4480c0fea5dSIngo Weinhold 4490c0fea5dSIngo Weinhold static void 4500c0fea5dSIngo Weinhold delete_image_struct(image_t *image) 4510c0fea5dSIngo Weinhold { 4520c0fea5dSIngo Weinhold #ifdef DEBUG 4530c0fea5dSIngo Weinhold size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t); 4540c0fea5dSIngo Weinhold memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed); 4550c0fea5dSIngo Weinhold #endif 4560c0fea5dSIngo Weinhold free(image->needed); 4570c0fea5dSIngo Weinhold 4580c0fea5dSIngo Weinhold #ifdef DEBUG 4599a6072a3SAxel Dörfler // overwrite images to make sure they aren't accidently reused anywhere 4600c0fea5dSIngo Weinhold memset(image, 0xa5, size); 4610c0fea5dSIngo Weinhold #endif 4620c0fea5dSIngo Weinhold free(image); 4630c0fea5dSIngo Weinhold } 4640c0fea5dSIngo Weinhold 4650c0fea5dSIngo Weinhold 4660c0fea5dSIngo Weinhold static void 4670c0fea5dSIngo Weinhold delete_image(image_t *image) 4680c0fea5dSIngo Weinhold { 4692760c4cdSAxel Dörfler if (image == NULL) 4702760c4cdSAxel Dörfler return; 4712760c4cdSAxel Dörfler 4720c0fea5dSIngo Weinhold _kern_unregister_image(image->id); 4730c0fea5dSIngo Weinhold // registered in load_container() 4740c0fea5dSIngo Weinhold 4750c0fea5dSIngo Weinhold delete_image_struct(image); 4760c0fea5dSIngo Weinhold } 4770c0fea5dSIngo Weinhold 4780c0fea5dSIngo Weinhold 4790c0fea5dSIngo Weinhold static status_t 4800c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) 4810c0fea5dSIngo Weinhold { 4820c0fea5dSIngo Weinhold struct Elf32_Phdr *pheader; 4830c0fea5dSIngo Weinhold int regcount; 4840c0fea5dSIngo Weinhold int i; 4850c0fea5dSIngo Weinhold 4860c0fea5dSIngo Weinhold regcount = 0; 4870c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 4880c0fea5dSIngo Weinhold pheader = (struct Elf32_Phdr *)(buff + i * phentsize); 4890c0fea5dSIngo Weinhold 4900c0fea5dSIngo Weinhold switch (pheader->p_type) { 4910c0fea5dSIngo Weinhold case PT_NULL: 4920c0fea5dSIngo Weinhold /* NOP header */ 4930c0fea5dSIngo Weinhold break; 4940c0fea5dSIngo Weinhold case PT_LOAD: 4950c0fea5dSIngo Weinhold if (pheader->p_memsz == pheader->p_filesz) { 4960c0fea5dSIngo Weinhold /* 4970c0fea5dSIngo Weinhold * everything in one area 4980c0fea5dSIngo Weinhold */ 4990c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 5000c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz; 5010c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 5020c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz 5030c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 5040c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 5050c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 5060c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 5070c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 5080c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 5090c0fea5dSIngo Weinhold // this is a writable segment 5100c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 5110c0fea5dSIngo Weinhold } 5120c0fea5dSIngo Weinhold } else { 5130c0fea5dSIngo Weinhold /* 5140c0fea5dSIngo Weinhold * may require splitting 5150c0fea5dSIngo Weinhold */ 5160c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz); 5170c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz); 5180c0fea5dSIngo Weinhold 5190c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 5200c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_filesz; 5210c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 5220c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz 5230c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 5240c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 5250c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 5260c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 5270c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 5280c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 5290c0fea5dSIngo Weinhold // this is a writable segment 5300c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 5310c0fea5dSIngo Weinhold } 5320c0fea5dSIngo Weinhold 5330c0fea5dSIngo Weinhold if (A != B) { 5340c0fea5dSIngo Weinhold /* 5350c0fea5dSIngo Weinhold * yeah, it requires splitting 5360c0fea5dSIngo Weinhold */ 5370c0fea5dSIngo Weinhold regcount += 1; 5380c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 5390c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz; 5400c0fea5dSIngo Weinhold image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize; 5410c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr)) 5420c0fea5dSIngo Weinhold - image->regions[regcount-1].vmsize; 5430c0fea5dSIngo Weinhold image->regions[regcount].fdstart = 0; 5440c0fea5dSIngo Weinhold image->regions[regcount].fdsize = 0; 5450c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 5460c0fea5dSIngo Weinhold image->regions[regcount].flags = RFLAG_ANON; 5470c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 5480c0fea5dSIngo Weinhold // this is a writable segment 5490c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 5500c0fea5dSIngo Weinhold } 5510c0fea5dSIngo Weinhold } 5520c0fea5dSIngo Weinhold } 5530c0fea5dSIngo Weinhold regcount += 1; 5540c0fea5dSIngo Weinhold break; 5550c0fea5dSIngo Weinhold case PT_DYNAMIC: 5560c0fea5dSIngo Weinhold image->dynamic_ptr = pheader->p_vaddr; 5570c0fea5dSIngo Weinhold break; 5580c0fea5dSIngo Weinhold case PT_INTERP: 5590c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 5600c0fea5dSIngo Weinhold break; 5610c0fea5dSIngo Weinhold case PT_NOTE: 5620c0fea5dSIngo Weinhold /* unsupported */ 5630c0fea5dSIngo Weinhold break; 5640c0fea5dSIngo Weinhold case PT_SHLIB: 5650c0fea5dSIngo Weinhold /* undefined semantics */ 5660c0fea5dSIngo Weinhold break; 5670c0fea5dSIngo Weinhold case PT_PHDR: 5680c0fea5dSIngo Weinhold /* we don't use it */ 5690c0fea5dSIngo Weinhold break; 5700c0fea5dSIngo Weinhold default: 5710c0fea5dSIngo Weinhold FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type); 5720c0fea5dSIngo Weinhold return B_BAD_DATA; 5730c0fea5dSIngo Weinhold } 5740c0fea5dSIngo Weinhold } 5750c0fea5dSIngo Weinhold 5760c0fea5dSIngo Weinhold return B_OK; 5770c0fea5dSIngo Weinhold } 5780c0fea5dSIngo Weinhold 5790c0fea5dSIngo Weinhold 5800c0fea5dSIngo Weinhold static bool 58134982809SIngo Weinhold analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader, 58234982809SIngo Weinhold int32 sheaderSize, char* buffer, size_t bufferSize) 58334982809SIngo Weinhold { 58434982809SIngo Weinhold image->gcc_version.major = 0; 58534982809SIngo Weinhold image->gcc_version.middle = 0; 58634982809SIngo Weinhold image->gcc_version.minor = 0; 58734982809SIngo Weinhold 58834982809SIngo Weinhold if (sheaderSize > (int)bufferSize) { 58934982809SIngo Weinhold FATAL("Cannot handle section headers bigger than %lu\n", bufferSize); 59034982809SIngo Weinhold return false; 59134982809SIngo Weinhold } 59234982809SIngo Weinhold 59334982809SIngo Weinhold // read section headers 59434982809SIngo Weinhold ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize); 59534982809SIngo Weinhold if (length != sheaderSize) { 59634982809SIngo Weinhold FATAL("Could not read section headers: %s\n", strerror(length)); 59734982809SIngo Weinhold return false; 59834982809SIngo Weinhold } 59934982809SIngo Weinhold 60034982809SIngo Weinhold // load the string section 60134982809SIngo Weinhold Elf32_Shdr* sectionHeader 60234982809SIngo Weinhold = (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize); 60334982809SIngo Weinhold 60434982809SIngo Weinhold if (sheaderSize + sectionHeader->sh_size > bufferSize) { 60534982809SIngo Weinhold FATAL("Buffer not big enough for section string section\n"); 60634982809SIngo Weinhold return false; 60734982809SIngo Weinhold } 60834982809SIngo Weinhold 60934982809SIngo Weinhold char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size; 61034982809SIngo Weinhold length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings, 61134982809SIngo Weinhold sectionHeader->sh_size); 61234982809SIngo Weinhold if (length != (int)sectionHeader->sh_size) { 61334982809SIngo Weinhold FATAL("Could not read section string section: %s\n", strerror(length)); 61434982809SIngo Weinhold return false; 61534982809SIngo Weinhold } 61634982809SIngo Weinhold 61734982809SIngo Weinhold // find the .comment section 61834982809SIngo Weinhold off_t commentOffset = 0; 61934982809SIngo Weinhold size_t commentSize = 0; 62034982809SIngo Weinhold for (uint32 i = 0; i < eheader.e_shnum; i++) { 62134982809SIngo Weinhold sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize); 62234982809SIngo Weinhold const char* sectionName = sectionStrings + sectionHeader->sh_name; 62334982809SIngo Weinhold if (sectionHeader->sh_name != 0 62434982809SIngo Weinhold && strcmp(sectionName, ".comment") == 0) { 62534982809SIngo Weinhold commentOffset = sectionHeader->sh_offset; 62634982809SIngo Weinhold commentSize = sectionHeader->sh_size; 62734982809SIngo Weinhold break; 62834982809SIngo Weinhold } 62934982809SIngo Weinhold } 63034982809SIngo Weinhold 63134982809SIngo Weinhold if (commentSize == 0) { 63234982809SIngo Weinhold FATAL("Could not find .comment section\n"); 63334982809SIngo Weinhold return false; 63434982809SIngo Weinhold } 63534982809SIngo Weinhold 63634982809SIngo Weinhold // read a part of the comment section 63734982809SIngo Weinhold if (commentSize > 512) 63834982809SIngo Weinhold commentSize = 512; 63934982809SIngo Weinhold 64034982809SIngo Weinhold length = _kern_read(fd, commentOffset, buffer, commentSize); 64134982809SIngo Weinhold if (length != (int)commentSize) { 64234982809SIngo Weinhold FATAL("Could not read .comment section: %s\n", strerror(length)); 64334982809SIngo Weinhold return false; 64434982809SIngo Weinhold } 64534982809SIngo Weinhold 64634982809SIngo Weinhold // the common prefix of the strings in the .comment section 64734982809SIngo Weinhold static const char* kGCCVersionPrefix = "GCC: (GNU) "; 64834982809SIngo Weinhold size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix); 64934982809SIngo Weinhold 65034982809SIngo Weinhold size_t index = 0; 65134982809SIngo Weinhold int gccMajor = 0; 65234982809SIngo Weinhold int gccMiddle = 0; 65334982809SIngo Weinhold int gccMinor = 0; 654*2716cfd3SAxel Dörfler bool isHaiku = true; 65534982809SIngo Weinhold 65634982809SIngo Weinhold // Read up to 10 comments. The first three or four are usually from the 65734982809SIngo Weinhold // glue code. 65834982809SIngo Weinhold for (int i = 0; i < 10; i++) { 65934982809SIngo Weinhold // skip '\0' 66034982809SIngo Weinhold while (index < commentSize && buffer[index] == '\0') 66134982809SIngo Weinhold index++; 66234982809SIngo Weinhold char* stringStart = buffer + index; 66334982809SIngo Weinhold 66434982809SIngo Weinhold // find string end 66534982809SIngo Weinhold while (index < commentSize && buffer[index] != '\0') 66634982809SIngo Weinhold index++; 66734982809SIngo Weinhold 66834982809SIngo Weinhold // ignore the entry at the end of the buffer 66934982809SIngo Weinhold if (index == commentSize) 67034982809SIngo Weinhold break; 67134982809SIngo Weinhold 67234982809SIngo Weinhold // We have to analyze string like these: 67334982809SIngo Weinhold // GCC: (GNU) 2.9-beos-991026 67434982809SIngo Weinhold // GCC: (GNU) 2.95.3-haiku-080322 67534982809SIngo Weinhold // GCC: (GNU) 4.1.2 67634982809SIngo Weinhold 67734982809SIngo Weinhold // skip the common prefix 67834982809SIngo Weinhold if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0) 67934982809SIngo Weinhold continue; 68034982809SIngo Weinhold 68134982809SIngo Weinhold // the rest is the GCC version 68234982809SIngo Weinhold char* gccVersion = stringStart + gccVersionPrefixLen; 68334982809SIngo Weinhold char* gccPlatform = strchr(gccVersion, '-'); 68434982809SIngo Weinhold char* patchLevel = NULL; 68534982809SIngo Weinhold if (gccPlatform != NULL) { 68634982809SIngo Weinhold *gccPlatform = '\0'; 68734982809SIngo Weinhold gccPlatform++; 68834982809SIngo Weinhold patchLevel = strchr(gccPlatform, '-'); 68934982809SIngo Weinhold if (patchLevel != NULL) { 69034982809SIngo Weinhold *patchLevel = '\0'; 69134982809SIngo Weinhold patchLevel++; 69234982809SIngo Weinhold } 69334982809SIngo Weinhold } 69434982809SIngo Weinhold 69534982809SIngo Weinhold // split the gcc version into major, middle, and minor 69634982809SIngo Weinhold int version[3] = { 0, 0, 0 }; 69734982809SIngo Weinhold 69834982809SIngo Weinhold for (int k = 0; gccVersion != NULL && k < 3; k++) { 69934982809SIngo Weinhold char* dot = strchr(gccVersion, '.'); 70034982809SIngo Weinhold if (dot) { 70134982809SIngo Weinhold *dot = '\0'; 70234982809SIngo Weinhold dot++; 70334982809SIngo Weinhold } 70434982809SIngo Weinhold version[k] = atoi(gccVersion); 70534982809SIngo Weinhold gccVersion = dot; 70634982809SIngo Weinhold } 70734982809SIngo Weinhold 70834982809SIngo Weinhold // got any version? 70934982809SIngo Weinhold if (version[0] == 0) 71034982809SIngo Weinhold continue; 71134982809SIngo Weinhold 71234982809SIngo Weinhold // Select the gcc version with the smallest major, but the greatest 71334982809SIngo Weinhold // middle/minor. This should usually ignore the glue code version as 71434982809SIngo Weinhold // well as cases where e.g. in a gcc 2 program a single C file has 71534982809SIngo Weinhold // been compiled with gcc 4. 71634982809SIngo Weinhold if (gccMajor == 0 || gccMajor > version[0] 71734982809SIngo Weinhold || gccMajor == version[0] 71834982809SIngo Weinhold && (gccMiddle < version[1] 71934982809SIngo Weinhold || gccMiddle == version[1] && gccMinor < version[2])) { 72034982809SIngo Weinhold gccMajor = version[0]; 72134982809SIngo Weinhold gccMiddle = version[1]; 72234982809SIngo Weinhold gccMinor = version[2]; 72334982809SIngo Weinhold } 724*2716cfd3SAxel Dörfler 725*2716cfd3SAxel Dörfler if (gccMajor == 2 && strcmp(gccPlatform, "haiku")) 726*2716cfd3SAxel Dörfler isHaiku = false; 72734982809SIngo Weinhold } 72834982809SIngo Weinhold 72934982809SIngo Weinhold image->gcc_version.major = gccMajor; 73034982809SIngo Weinhold image->gcc_version.middle = gccMiddle; 73134982809SIngo Weinhold image->gcc_version.minor = gccMinor; 732*2716cfd3SAxel Dörfler image->gcc_version.haiku = isHaiku; 73334982809SIngo Weinhold 73434982809SIngo Weinhold return gccMajor != 0; 73534982809SIngo Weinhold } 73634982809SIngo Weinhold 73734982809SIngo Weinhold 73834982809SIngo Weinhold static bool 7390c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image) 7400c0fea5dSIngo Weinhold { 7410c0fea5dSIngo Weinhold uint32 i; 7420c0fea5dSIngo Weinhold 7430c0fea5dSIngo Weinhold if (!image->dynamic_ptr) 7440c0fea5dSIngo Weinhold return true; 7450c0fea5dSIngo Weinhold 7460c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 7470c0fea5dSIngo Weinhold if (image->dynamic_ptr >= image->regions[i].start 7480c0fea5dSIngo Weinhold && image->dynamic_ptr < image->regions[i].start + image->regions[i].size) 7490c0fea5dSIngo Weinhold return true; 7500c0fea5dSIngo Weinhold } 7510c0fea5dSIngo Weinhold 7520c0fea5dSIngo Weinhold return false; 7530c0fea5dSIngo Weinhold } 7540c0fea5dSIngo Weinhold 7550c0fea5dSIngo Weinhold 7560c0fea5dSIngo Weinhold /** This function will change the protection of all read-only segments 7570c0fea5dSIngo Weinhold * to really be read-only. 7580c0fea5dSIngo Weinhold * The areas have to be read/write first, so that they can be relocated. 7590c0fea5dSIngo Weinhold */ 7600c0fea5dSIngo Weinhold 7610c0fea5dSIngo Weinhold static void 7620c0fea5dSIngo Weinhold remap_images(void) 7630c0fea5dSIngo Weinhold { 7640c0fea5dSIngo Weinhold image_t *image; 7650c0fea5dSIngo Weinhold uint32 i; 7660c0fea5dSIngo Weinhold 7670c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image != NULL; image = image->next) { 7680c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 7690c0fea5dSIngo Weinhold if ((image->regions[i].flags & RFLAG_RW) == 0 7700c0fea5dSIngo Weinhold && (image->regions[i].flags & RFLAG_REMAPPED) == 0) { 7710c0fea5dSIngo Weinhold // we only need to do this once, so we remember those we've already mapped 7720c0fea5dSIngo Weinhold if (_kern_set_area_protection(image->regions[i].id, 7730c0fea5dSIngo Weinhold B_READ_AREA | B_EXECUTE_AREA) == B_OK) 7740c0fea5dSIngo Weinhold image->regions[i].flags |= RFLAG_REMAPPED; 7750c0fea5dSIngo Weinhold } 7760c0fea5dSIngo Weinhold } 7770c0fea5dSIngo Weinhold } 7780c0fea5dSIngo Weinhold } 7790c0fea5dSIngo Weinhold 7800c0fea5dSIngo Weinhold 7810c0fea5dSIngo Weinhold static status_t 7820c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed) 7830c0fea5dSIngo Weinhold { 7840c0fea5dSIngo Weinhold status_t status = B_OK; 7850c0fea5dSIngo Weinhold const char *baseName; 7860c0fea5dSIngo Weinhold uint32 i; 7870c0fea5dSIngo Weinhold 7880c0fea5dSIngo Weinhold (void)(fd); 7890c0fea5dSIngo Weinhold 7900c0fea5dSIngo Weinhold // cut the file name from the path as base name for the created areas 7910c0fea5dSIngo Weinhold baseName = strrchr(path, '/'); 7920c0fea5dSIngo Weinhold if (baseName != NULL) 7930c0fea5dSIngo Weinhold baseName++; 7940c0fea5dSIngo Weinhold else 7950c0fea5dSIngo Weinhold baseName = path; 7960c0fea5dSIngo Weinhold 7970c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 7980c0fea5dSIngo Weinhold char regionName[B_OS_NAME_LENGTH]; 7990c0fea5dSIngo Weinhold addr_t loadAddress; 8000c0fea5dSIngo Weinhold uint32 addressSpecifier; 8010c0fea5dSIngo Weinhold 8020c0fea5dSIngo Weinhold // for BeOS compatibility: if we load an old BeOS executable, we 8030c0fea5dSIngo Weinhold // have to relocate it, if possible - we recognize it because the 8040c0fea5dSIngo Weinhold // vmstart is set to 0 (hopefully always) 8050c0fea5dSIngo Weinhold if (fixed && image->regions[i].vmstart == 0) 8060c0fea5dSIngo Weinhold fixed = false; 8070c0fea5dSIngo Weinhold 8080c0fea5dSIngo Weinhold snprintf(regionName, sizeof(regionName), "%s_seg%lu%s", 8090c0fea5dSIngo Weinhold baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro"); 8100c0fea5dSIngo Weinhold 8110c0fea5dSIngo Weinhold if (image->dynamic_ptr && !fixed) { 8120c0fea5dSIngo Weinhold // relocatable image... we can afford to place wherever 8130c0fea5dSIngo Weinhold if (i == 0) { 8140c0fea5dSIngo Weinhold // but only the first segment gets a free ride 8150c0fea5dSIngo Weinhold loadAddress = RLD_PROGRAM_BASE; 8160c0fea5dSIngo Weinhold addressSpecifier = B_BASE_ADDRESS; 8170c0fea5dSIngo Weinhold } else { 8180c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart + image->regions[i-1].delta; 8190c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 8200c0fea5dSIngo Weinhold } 8210c0fea5dSIngo Weinhold } else { 8220c0fea5dSIngo Weinhold // not relocatable, put it where it asks or die trying 8230c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart; 8240c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 8250c0fea5dSIngo Weinhold } 8260c0fea5dSIngo Weinhold 8270c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_ANON) { 8280c0fea5dSIngo Weinhold image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress, 8290c0fea5dSIngo Weinhold addressSpecifier, image->regions[i].vmsize, B_NO_LOCK, 8300c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 8310c0fea5dSIngo Weinhold 8320c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 8330c0fea5dSIngo Weinhold status = image->regions[i].id; 8340c0fea5dSIngo Weinhold goto error; 8350c0fea5dSIngo Weinhold } 8360c0fea5dSIngo Weinhold 8370c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 8380c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 8390c0fea5dSIngo Weinhold } else { 8403cf7ecd1SIngo Weinhold image->regions[i].id = _kern_map_file(regionName, 8413cf7ecd1SIngo Weinhold (void **)&loadAddress, addressSpecifier, 8423cf7ecd1SIngo Weinhold image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA, 8433cf7ecd1SIngo Weinhold REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart)); 8440c0fea5dSIngo Weinhold 8450c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 8460c0fea5dSIngo Weinhold status = image->regions[i].id; 8470c0fea5dSIngo Weinhold goto error; 8480c0fea5dSIngo Weinhold } 8490c0fea5dSIngo Weinhold 8500c0fea5dSIngo Weinhold TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path, 8510c0fea5dSIngo Weinhold (void *)loadAddress, image->regions[i].vmsize, 8520c0fea5dSIngo Weinhold image->regions[i].flags & RFLAG_RW ? "rw" : "read-only")); 8530c0fea5dSIngo Weinhold 8540c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 8550c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 8560c0fea5dSIngo Weinhold 8570c0fea5dSIngo Weinhold // handle trailer bits in data segment 8580c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_RW) { 8590c0fea5dSIngo Weinhold addr_t startClearing; 8600c0fea5dSIngo Weinhold addr_t toClear; 8610c0fea5dSIngo Weinhold 8620c0fea5dSIngo Weinhold startClearing = image->regions[i].vmstart 8630c0fea5dSIngo Weinhold + PAGE_OFFSET(image->regions[i].start) 8640c0fea5dSIngo Weinhold + image->regions[i].size; 8650c0fea5dSIngo Weinhold toClear = image->regions[i].vmsize 8660c0fea5dSIngo Weinhold - PAGE_OFFSET(image->regions[i].start) 8670c0fea5dSIngo Weinhold - image->regions[i].size; 8680c0fea5dSIngo Weinhold 8690c0fea5dSIngo Weinhold TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear)); 8700c0fea5dSIngo Weinhold memset((void *)startClearing, 0, toClear); 8710c0fea5dSIngo Weinhold } 8720c0fea5dSIngo Weinhold } 8730c0fea5dSIngo Weinhold } 8740c0fea5dSIngo Weinhold 8750c0fea5dSIngo Weinhold if (image->dynamic_ptr) 8760c0fea5dSIngo Weinhold image->dynamic_ptr += image->regions[0].delta; 8770c0fea5dSIngo Weinhold 8780c0fea5dSIngo Weinhold return B_OK; 8790c0fea5dSIngo Weinhold 8800c0fea5dSIngo Weinhold error: 8810c0fea5dSIngo Weinhold return status; 8820c0fea5dSIngo Weinhold } 8830c0fea5dSIngo Weinhold 8840c0fea5dSIngo Weinhold 8850c0fea5dSIngo Weinhold static void 8860c0fea5dSIngo Weinhold unmap_image(image_t *image) 8870c0fea5dSIngo Weinhold { 8880c0fea5dSIngo Weinhold uint32 i; 8890c0fea5dSIngo Weinhold 8900c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 8910c0fea5dSIngo Weinhold _kern_delete_area(image->regions[i].id); 8920c0fea5dSIngo Weinhold 8930c0fea5dSIngo Weinhold image->regions[i].id = -1; 8940c0fea5dSIngo Weinhold } 8950c0fea5dSIngo Weinhold } 8960c0fea5dSIngo Weinhold 8970c0fea5dSIngo Weinhold 8980c0fea5dSIngo Weinhold static bool 8990c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image) 9000c0fea5dSIngo Weinhold { 9010c0fea5dSIngo Weinhold struct Elf32_Dyn *d; 9020c0fea5dSIngo Weinhold int i; 9030c0fea5dSIngo Weinhold int sonameOffset = -1; 9040c0fea5dSIngo Weinhold 9050c0fea5dSIngo Weinhold image->symhash = 0; 9060c0fea5dSIngo Weinhold image->syms = 0; 9070c0fea5dSIngo Weinhold image->strtab = 0; 9080c0fea5dSIngo Weinhold 9090c0fea5dSIngo Weinhold d = (struct Elf32_Dyn *)image->dynamic_ptr; 9100c0fea5dSIngo Weinhold if (!d) 9110c0fea5dSIngo Weinhold return true; 9120c0fea5dSIngo Weinhold 9130c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 9140c0fea5dSIngo Weinhold switch (d[i].d_tag) { 9150c0fea5dSIngo Weinhold case DT_NEEDED: 9160c0fea5dSIngo Weinhold image->num_needed += 1; 9170c0fea5dSIngo Weinhold break; 9180c0fea5dSIngo Weinhold case DT_HASH: 9190c0fea5dSIngo Weinhold image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta); 9200c0fea5dSIngo Weinhold break; 9210c0fea5dSIngo Weinhold case DT_STRTAB: 9220c0fea5dSIngo Weinhold image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta); 9230c0fea5dSIngo Weinhold break; 9240c0fea5dSIngo Weinhold case DT_SYMTAB: 9250c0fea5dSIngo Weinhold image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta); 9260c0fea5dSIngo Weinhold break; 9270c0fea5dSIngo Weinhold case DT_REL: 9280c0fea5dSIngo Weinhold image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 9290c0fea5dSIngo Weinhold break; 9300c0fea5dSIngo Weinhold case DT_RELSZ: 9310c0fea5dSIngo Weinhold image->rel_len = d[i].d_un.d_val; 9320c0fea5dSIngo Weinhold break; 9330c0fea5dSIngo Weinhold case DT_RELA: 9340c0fea5dSIngo Weinhold image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta); 9350c0fea5dSIngo Weinhold break; 9360c0fea5dSIngo Weinhold case DT_RELASZ: 9370c0fea5dSIngo Weinhold image->rela_len = d[i].d_un.d_val; 9380c0fea5dSIngo Weinhold break; 9390c0fea5dSIngo Weinhold // TK: procedure linkage table 9400c0fea5dSIngo Weinhold case DT_JMPREL: 9410c0fea5dSIngo Weinhold image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 9420c0fea5dSIngo Weinhold break; 9430c0fea5dSIngo Weinhold case DT_PLTRELSZ: 9440c0fea5dSIngo Weinhold image->pltrel_len = d[i].d_un.d_val; 9450c0fea5dSIngo Weinhold break; 9460c0fea5dSIngo Weinhold case DT_INIT: 9470c0fea5dSIngo Weinhold image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 9480c0fea5dSIngo Weinhold break; 9490c0fea5dSIngo Weinhold case DT_FINI: 9500c0fea5dSIngo Weinhold image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 9510c0fea5dSIngo Weinhold break; 9520c0fea5dSIngo Weinhold case DT_SONAME: 9530c0fea5dSIngo Weinhold sonameOffset = d[i].d_un.d_val; 9540c0fea5dSIngo Weinhold break; 9550c0fea5dSIngo Weinhold default: 9560c0fea5dSIngo Weinhold continue; 9570c0fea5dSIngo Weinhold } 9580c0fea5dSIngo Weinhold } 9590c0fea5dSIngo Weinhold 9600c0fea5dSIngo Weinhold // lets make sure we found all the required sections 9610c0fea5dSIngo Weinhold if (!image->symhash || !image->syms || !image->strtab) 9620c0fea5dSIngo Weinhold return false; 9630c0fea5dSIngo Weinhold 9640c0fea5dSIngo Weinhold if (sonameOffset >= 0) 9650c0fea5dSIngo Weinhold strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name)); 9660c0fea5dSIngo Weinhold 9670c0fea5dSIngo Weinhold return true; 9680c0fea5dSIngo Weinhold } 9690c0fea5dSIngo Weinhold 9700c0fea5dSIngo Weinhold 9710c0fea5dSIngo Weinhold static struct Elf32_Sym * 9720c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type) 9730c0fea5dSIngo Weinhold { 9740c0fea5dSIngo Weinhold uint32 hash, i; 9750c0fea5dSIngo Weinhold 9760c0fea5dSIngo Weinhold // ToDo: "type" is currently ignored! 9770c0fea5dSIngo Weinhold (void)type; 9780c0fea5dSIngo Weinhold 979dd76bc97SIngo Weinhold if (image->dynamic_ptr == 0) 9800c0fea5dSIngo Weinhold return NULL; 9810c0fea5dSIngo Weinhold 9820c0fea5dSIngo Weinhold hash = elf_hash((uint8 *)name) % HASHTABSIZE(image); 9830c0fea5dSIngo Weinhold 9840c0fea5dSIngo Weinhold for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) { 9850c0fea5dSIngo Weinhold struct Elf32_Sym *symbol = &image->syms[i]; 9860c0fea5dSIngo Weinhold 9870c0fea5dSIngo Weinhold if (symbol->st_shndx != SHN_UNDEF 9880c0fea5dSIngo Weinhold && ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL) 9890c0fea5dSIngo Weinhold || (ELF32_ST_BIND(symbol->st_info) == STB_WEAK)) 9900c0fea5dSIngo Weinhold && !strcmp(SYMNAME(image, symbol), name)) { 9910c0fea5dSIngo Weinhold // check if the type matches 9920c0fea5dSIngo Weinhold if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC) 9930c0fea5dSIngo Weinhold || (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)) 9940c0fea5dSIngo Weinhold continue; 9950c0fea5dSIngo Weinhold 9960c0fea5dSIngo Weinhold return symbol; 9970c0fea5dSIngo Weinhold } 9980c0fea5dSIngo Weinhold } 9990c0fea5dSIngo Weinhold 10000c0fea5dSIngo Weinhold return NULL; 10010c0fea5dSIngo Weinhold } 10020c0fea5dSIngo Weinhold 10030c0fea5dSIngo Weinhold 10040c0fea5dSIngo Weinhold static struct Elf32_Sym* 100546f4d849SIngo Weinhold find_symbol_recursively_impl(image_t* image, const char* name, 100646f4d849SIngo Weinhold image_t** foundInImage) 10070c0fea5dSIngo Weinhold { 100846f4d849SIngo Weinhold image->flags |= RFLAG_VISITED; 10090c0fea5dSIngo Weinhold 10100c0fea5dSIngo Weinhold struct Elf32_Sym *symbol; 10110c0fea5dSIngo Weinhold 101246f4d849SIngo Weinhold // look up the symbol in this image 101346f4d849SIngo Weinhold if (image->dynamic_ptr) { 10140c0fea5dSIngo Weinhold symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY); 10150c0fea5dSIngo Weinhold if (symbol) { 101646f4d849SIngo Weinhold *foundInImage = image; 101746f4d849SIngo Weinhold return symbol; 101846f4d849SIngo Weinhold } 101946f4d849SIngo Weinhold } 102046f4d849SIngo Weinhold 102146f4d849SIngo Weinhold // recursively search dependencies 102246f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 102346f4d849SIngo Weinhold if (!(image->needed[i]->flags & RFLAG_VISITED)) { 102446f4d849SIngo Weinhold symbol = find_symbol_recursively_impl(image->needed[i], name, 102546f4d849SIngo Weinhold foundInImage); 102646f4d849SIngo Weinhold if (symbol) 10270c0fea5dSIngo Weinhold return symbol; 10280c0fea5dSIngo Weinhold } 10290c0fea5dSIngo Weinhold } 10300c0fea5dSIngo Weinhold 10310c0fea5dSIngo Weinhold return NULL; 10320c0fea5dSIngo Weinhold } 10330c0fea5dSIngo Weinhold 10340c0fea5dSIngo Weinhold 103546f4d849SIngo Weinhold static void 103646f4d849SIngo Weinhold clear_image_flag_recursively(image_t* image, uint32 flag) 103746f4d849SIngo Weinhold { 103846f4d849SIngo Weinhold image->flags &= ~flag; 103946f4d849SIngo Weinhold 104046f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 104146f4d849SIngo Weinhold if (image->needed[i]->flags & flag) 104246f4d849SIngo Weinhold clear_image_flag_recursively(image->needed[i], flag); 104346f4d849SIngo Weinhold } 104446f4d849SIngo Weinhold } 104546f4d849SIngo Weinhold 104646f4d849SIngo Weinhold 104746f4d849SIngo Weinhold static struct Elf32_Sym* 104846f4d849SIngo Weinhold find_symbol_recursively(image_t* image, const char* name, 104946f4d849SIngo Weinhold image_t** foundInImage) 105046f4d849SIngo Weinhold { 105146f4d849SIngo Weinhold struct Elf32_Sym* symbol = find_symbol_recursively_impl(image, name, 105246f4d849SIngo Weinhold foundInImage); 105346f4d849SIngo Weinhold clear_image_flag_recursively(image, RFLAG_VISITED); 105446f4d849SIngo Weinhold return symbol; 105546f4d849SIngo Weinhold } 105646f4d849SIngo Weinhold 105746f4d849SIngo Weinhold 105846f4d849SIngo Weinhold static struct Elf32_Sym* 105946f4d849SIngo Weinhold find_symbol_in_loaded_images(const char* name, image_t** foundInImage) 106046f4d849SIngo Weinhold { 106146f4d849SIngo Weinhold return find_symbol_recursively(sLoadedImages.head, name, foundInImage); 106246f4d849SIngo Weinhold } 106346f4d849SIngo Weinhold 106446f4d849SIngo Weinhold 106546f4d849SIngo Weinhold static struct Elf32_Sym* 106646f4d849SIngo Weinhold find_undefined_symbol(image_t* rootImage, image_t* image, const char* name, 106746f4d849SIngo Weinhold image_t** foundInImage) 106846f4d849SIngo Weinhold { 106946f4d849SIngo Weinhold // If not simulating BeOS style symbol resolution, undefined symbols are 107092af28dfSIngo Weinhold // searched recursively starting from the root image. 107192af28dfSIngo Weinhold // TODO: Breadth first might be better than the depth first strategy used 107292af28dfSIngo Weinhold // here. We're also visiting images multiple times. Consider building a 107392af28dfSIngo Weinhold // breadth-first sorted array of images for each root image. 10745fd6637bSIngo Weinhold if ((rootImage->flags & IMAGE_FLAG_R5_SYMBOL_RESOLUTION) == 0) { 10755fd6637bSIngo Weinhold Elf32_Sym* symbol = find_symbol_recursively(rootImage, name, 10765fd6637bSIngo Weinhold foundInImage); 10775fd6637bSIngo Weinhold if (symbol != NULL) 10785fd6637bSIngo Weinhold return symbol; 10795fd6637bSIngo Weinhold 10805fd6637bSIngo Weinhold // If the root image is not the program image (i.e. it is a dynamically 10815fd6637bSIngo Weinhold // loaded add-on or library), we try the program image hierarchy too. 10825fd6637bSIngo Weinhold image_t* programImage = get_program_image(); 10835fd6637bSIngo Weinhold if (rootImage != programImage) 10845fd6637bSIngo Weinhold return find_symbol_recursively(programImage, name, foundInImage); 10855fd6637bSIngo Weinhold 10865fd6637bSIngo Weinhold return NULL; 10875fd6637bSIngo Weinhold } 108846f4d849SIngo Weinhold 108946f4d849SIngo Weinhold // BeOS style symbol resolution: It is sufficient to check the direct 109046f4d849SIngo Weinhold // dependencies. The linker would have complained, if the symbol wasn't 109146f4d849SIngo Weinhold // there. 109246f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 109346f4d849SIngo Weinhold if (image->needed[i]->dynamic_ptr) { 109446f4d849SIngo Weinhold struct Elf32_Sym *symbol = find_symbol(image->needed[i], name, 109546f4d849SIngo Weinhold B_SYMBOL_TYPE_ANY); 109646f4d849SIngo Weinhold if (symbol) { 109746f4d849SIngo Weinhold *foundInImage = image->needed[i]; 109846f4d849SIngo Weinhold return symbol; 109946f4d849SIngo Weinhold } 110046f4d849SIngo Weinhold } 110146f4d849SIngo Weinhold } 110246f4d849SIngo Weinhold 110346f4d849SIngo Weinhold return NULL; 110446f4d849SIngo Weinhold } 110546f4d849SIngo Weinhold 110646f4d849SIngo Weinhold 1107*2716cfd3SAxel Dörfler /*! This functions is called when we run BeOS images on Haiku. 1108*2716cfd3SAxel Dörfler It allows us to redirect functions to ensure compatibility. 1109*2716cfd3SAxel Dörfler */ 1110*2716cfd3SAxel Dörfler static const char* 1111*2716cfd3SAxel Dörfler beos_compatibility_map_symbol(const char* symbolName) 1112*2716cfd3SAxel Dörfler { 1113*2716cfd3SAxel Dörfler struct symbol_mapping { 1114*2716cfd3SAxel Dörfler const char* from; 1115*2716cfd3SAxel Dörfler const char* to; 1116*2716cfd3SAxel Dörfler }; 1117*2716cfd3SAxel Dörfler static const struct symbol_mapping kMappings[] = { 1118*2716cfd3SAxel Dörfler // TODO: improve this, and also use it for libnet.so compatibility! 1119*2716cfd3SAxel Dörfler {"fstat", "__be_fstat"}, 1120*2716cfd3SAxel Dörfler {"lstat", "__be_lstat"}, 1121*2716cfd3SAxel Dörfler {"stat", "__be_stat"}, 1122*2716cfd3SAxel Dörfler }; 1123*2716cfd3SAxel Dörfler const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]); 1124*2716cfd3SAxel Dörfler 1125*2716cfd3SAxel Dörfler for (uint32 i = 0; i < kMappingCount; i++) { 1126*2716cfd3SAxel Dörfler if (!strcmp(symbolName, kMappings[i].from)) 1127*2716cfd3SAxel Dörfler return kMappings[i].to; 1128*2716cfd3SAxel Dörfler } 1129*2716cfd3SAxel Dörfler 1130*2716cfd3SAxel Dörfler return symbolName; 1131*2716cfd3SAxel Dörfler } 1132*2716cfd3SAxel Dörfler 1133*2716cfd3SAxel Dörfler 11340c0fea5dSIngo Weinhold int 113546f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym, 1136*2716cfd3SAxel Dörfler addr_t *symAddress) 11370c0fea5dSIngo Weinhold { 11380c0fea5dSIngo Weinhold switch (sym->st_shndx) { 11390c0fea5dSIngo Weinhold case SHN_UNDEF: 1140*2716cfd3SAxel Dörfler { 1141*2716cfd3SAxel Dörfler struct Elf32_Sym *sharedSym; 1142*2716cfd3SAxel Dörfler image_t *sharedImage; 1143*2716cfd3SAxel Dörfler const char *symName; 1144*2716cfd3SAxel Dörfler 11450c0fea5dSIngo Weinhold // patch the symbol name 1146*2716cfd3SAxel Dörfler symName = SYMNAME(image, sym); 1147*2716cfd3SAxel Dörfler if (!image->gcc_version.haiku) { 1148*2716cfd3SAxel Dörfler // The image has been compiled with a BeOS compiler. This means 1149*2716cfd3SAxel Dörfler // we'll have to redirect some functions for compatibility. 1150*2716cfd3SAxel Dörfler symName = beos_compatibility_map_symbol(symName); 1151*2716cfd3SAxel Dörfler } 11520c0fea5dSIngo Weinhold 115346f4d849SIngo Weinhold // it's undefined, must be outside this image, try the other images 1154*2716cfd3SAxel Dörfler sharedSym = find_undefined_symbol(rootImage, image, symName, 1155*2716cfd3SAxel Dörfler &sharedImage); 1156*2716cfd3SAxel Dörfler if (sharedSym == NULL) { 11572a33a944SIngo Weinhold FATAL("elf_resolve_symbol: could not resolve symbol '%s'\n", 1158*2716cfd3SAxel Dörfler symName); 11590c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 11600c0fea5dSIngo Weinhold } 11610c0fea5dSIngo Weinhold 11620c0fea5dSIngo Weinhold // make sure they're the same type 11630c0fea5dSIngo Weinhold if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE 1164*2716cfd3SAxel Dörfler && ELF32_ST_TYPE(sym->st_info) 1165*2716cfd3SAxel Dörfler != ELF32_ST_TYPE(sharedSym->st_info)) { 11662a33a944SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s' in shared image " 1167*2716cfd3SAxel Dörfler "but wrong type\n", symName); 11680c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 11690c0fea5dSIngo Weinhold } 11700c0fea5dSIngo Weinhold 1171*2716cfd3SAxel Dörfler if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL 1172*2716cfd3SAxel Dörfler && ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) { 11732a33a944SIngo Weinhold FATAL("elf_resolve_symbol: found symbol '%s' but not " 1174*2716cfd3SAxel Dörfler "exported\n", symName); 11750c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 11760c0fea5dSIngo Weinhold } 11770c0fea5dSIngo Weinhold 1178*2716cfd3SAxel Dörfler *symAddress = sharedSym->st_value + sharedImage->regions[0].delta; 11790c0fea5dSIngo Weinhold return B_NO_ERROR; 1180*2716cfd3SAxel Dörfler } 11810c0fea5dSIngo Weinhold 11820c0fea5dSIngo Weinhold case SHN_ABS: 1183*2716cfd3SAxel Dörfler *symAddress = sym->st_value + image->regions[0].delta; 11840c0fea5dSIngo Weinhold return B_NO_ERROR; 11850c0fea5dSIngo Weinhold 11860c0fea5dSIngo Weinhold case SHN_COMMON: 11870c0fea5dSIngo Weinhold // ToDo: finish this 11882a33a944SIngo Weinhold FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n"); 11890c0fea5dSIngo Weinhold return B_ERROR; //ERR_NOT_IMPLEMENTED_YET; 11900c0fea5dSIngo Weinhold 11910c0fea5dSIngo Weinhold default: 11920c0fea5dSIngo Weinhold // standard symbol 1193*2716cfd3SAxel Dörfler *symAddress = sym->st_value + image->regions[0].delta; 11940c0fea5dSIngo Weinhold return B_NO_ERROR; 11950c0fea5dSIngo Weinhold } 11960c0fea5dSIngo Weinhold } 11970c0fea5dSIngo Weinhold 11980c0fea5dSIngo Weinhold 11990c0fea5dSIngo Weinhold static void 12000c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path) 12010c0fea5dSIngo Weinhold { 12020c0fea5dSIngo Weinhold struct stat stat; 12030c0fea5dSIngo Weinhold image_info info; 12040c0fea5dSIngo Weinhold 12050c0fea5dSIngo Weinhold // ToDo: set these correctly 12060c0fea5dSIngo Weinhold info.id = 0; 12070c0fea5dSIngo Weinhold info.type = image->type; 12080c0fea5dSIngo Weinhold info.sequence = 0; 12090c0fea5dSIngo Weinhold info.init_order = 0; 12100c0fea5dSIngo Weinhold info.init_routine = (void (*)())image->init_routine; 12110c0fea5dSIngo Weinhold info.term_routine = (void (*)())image->term_routine; 12120c0fea5dSIngo Weinhold 12130c0fea5dSIngo Weinhold if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) { 12140c0fea5dSIngo Weinhold info.device = stat.st_dev; 12150c0fea5dSIngo Weinhold info.node = stat.st_ino; 12160c0fea5dSIngo Weinhold } else { 12170c0fea5dSIngo Weinhold info.device = -1; 12180c0fea5dSIngo Weinhold info.node = -1; 12190c0fea5dSIngo Weinhold } 12200c0fea5dSIngo Weinhold 12210c0fea5dSIngo Weinhold strlcpy(info.name, path, sizeof(info.name)); 12220c0fea5dSIngo Weinhold info.text = (void *)image->regions[0].vmstart; 12230c0fea5dSIngo Weinhold info.text_size = image->regions[0].vmsize; 12240c0fea5dSIngo Weinhold info.data = (void *)image->regions[1].vmstart; 12250c0fea5dSIngo Weinhold info.data_size = image->regions[1].vmsize; 12260c0fea5dSIngo Weinhold image->id = _kern_register_image(&info, sizeof(image_info)); 12270c0fea5dSIngo Weinhold } 12280c0fea5dSIngo Weinhold 12290c0fea5dSIngo Weinhold 12300c0fea5dSIngo Weinhold static status_t 123146f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 12320c0fea5dSIngo Weinhold { 123346f4d849SIngo Weinhold status_t status = arch_relocate_image(rootImage, image); 12340c0fea5dSIngo Weinhold if (status < B_OK) { 1235320bd2bdSAxel Dörfler FATAL("troubles relocating: 0x%lx (image: %s, %s)\n", status, 1236320bd2bdSAxel Dörfler image->path, image->name); 12370c0fea5dSIngo Weinhold return status; 12380c0fea5dSIngo Weinhold } 12390c0fea5dSIngo Weinhold 12400c0fea5dSIngo Weinhold _kern_image_relocated(image->id); 12410c0fea5dSIngo Weinhold return B_OK; 12420c0fea5dSIngo Weinhold } 12430c0fea5dSIngo Weinhold 12440c0fea5dSIngo Weinhold 12450c0fea5dSIngo Weinhold static status_t 12460c0fea5dSIngo Weinhold load_container(char const *name, image_type type, const char *rpath, image_t **_image) 12470c0fea5dSIngo Weinhold { 12480c0fea5dSIngo Weinhold int32 pheaderSize, sheaderSize; 12490c0fea5dSIngo Weinhold char path[PATH_MAX]; 12500c0fea5dSIngo Weinhold ssize_t length; 12510c0fea5dSIngo Weinhold char ph_buff[4096]; 12520c0fea5dSIngo Weinhold int32 numRegions; 12530c0fea5dSIngo Weinhold image_t *found; 12540c0fea5dSIngo Weinhold image_t *image; 12550c0fea5dSIngo Weinhold status_t status; 12560c0fea5dSIngo Weinhold int fd; 12570c0fea5dSIngo Weinhold 12580c0fea5dSIngo Weinhold struct Elf32_Ehdr eheader; 12590c0fea5dSIngo Weinhold 12600c0fea5dSIngo Weinhold // Have we already loaded that image? Don't check for add-ons -- we always 12610c0fea5dSIngo Weinhold // reload them. 12620c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 12630c0fea5dSIngo Weinhold found = find_image(name, APP_OR_LIBRARY_TYPE); 12640c0fea5dSIngo Weinhold if (found) { 12650c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 12660c0fea5dSIngo Weinhold *_image = found; 12677486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") " 12687486b72dSIngo Weinhold "already loaded", name, type, rpath); 12690c0fea5dSIngo Weinhold return B_OK; 12700c0fea5dSIngo Weinhold } 12710c0fea5dSIngo Weinhold } 12720c0fea5dSIngo Weinhold 12737486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type, 12747486b72dSIngo Weinhold rpath); 12757486b72dSIngo Weinhold 12760c0fea5dSIngo Weinhold strlcpy(path, name, sizeof(path)); 12770c0fea5dSIngo Weinhold 127861b37794SIngo Weinhold // find and open the file 127961b37794SIngo Weinhold fd = open_executable(path, type, rpath, get_program_path(), 128061b37794SIngo Weinhold sSearchPathSubDir); 12810c0fea5dSIngo Weinhold if (fd < 0) { 12820c0fea5dSIngo Weinhold FATAL("cannot open file %s\n", path); 12837486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): failed to open file", name); 12840c0fea5dSIngo Weinhold return fd; 12850c0fea5dSIngo Weinhold } 12860c0fea5dSIngo Weinhold 12876918dbf4SIngo Weinhold // normalize the image path 12886918dbf4SIngo Weinhold status = _kern_normalize_path(path, true, path); 12896918dbf4SIngo Weinhold if (status != B_OK) 12900c0fea5dSIngo Weinhold goto err1; 12910c0fea5dSIngo Weinhold 12920c0fea5dSIngo Weinhold // Test again if this image has been registered already - this time, 12930c0fea5dSIngo Weinhold // we can check the full path, not just its name as noted. 12940c0fea5dSIngo Weinhold // You could end up loading an image twice with symbolic links, else. 12950c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 12960c0fea5dSIngo Weinhold found = find_image(path, APP_OR_LIBRARY_TYPE); 12970c0fea5dSIngo Weinhold if (found) { 12980c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 12990c0fea5dSIngo Weinhold *_image = found; 13007486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): already loaded after all", 13017486b72dSIngo Weinhold name); 13020c0fea5dSIngo Weinhold return B_OK; 13030c0fea5dSIngo Weinhold } 13040c0fea5dSIngo Weinhold } 13050c0fea5dSIngo Weinhold 13060c0fea5dSIngo Weinhold length = _kern_read(fd, 0, &eheader, sizeof(eheader)); 13070c0fea5dSIngo Weinhold if (length != sizeof(eheader)) { 13080c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 13090c0fea5dSIngo Weinhold FATAL("troubles reading ELF header\n"); 13100c0fea5dSIngo Weinhold goto err1; 13110c0fea5dSIngo Weinhold } 13120c0fea5dSIngo Weinhold 13130c0fea5dSIngo Weinhold status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize); 13140c0fea5dSIngo Weinhold if (status < B_OK) { 13150c0fea5dSIngo Weinhold FATAL("incorrect ELF header\n"); 13160c0fea5dSIngo Weinhold goto err1; 13170c0fea5dSIngo Weinhold } 13180c0fea5dSIngo Weinhold 13190c0fea5dSIngo Weinhold // ToDo: what to do about this restriction?? 13200c0fea5dSIngo Weinhold if (pheaderSize > (int)sizeof(ph_buff)) { 13210c0fea5dSIngo Weinhold FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff)); 13220c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 13230c0fea5dSIngo Weinhold goto err1; 13240c0fea5dSIngo Weinhold } 13250c0fea5dSIngo Weinhold 13260c0fea5dSIngo Weinhold length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize); 13270c0fea5dSIngo Weinhold if (length != pheaderSize) { 13280c0fea5dSIngo Weinhold FATAL("Could not read program headers: %s\n", strerror(length)); 13290c0fea5dSIngo Weinhold status = B_BAD_DATA; 13300c0fea5dSIngo Weinhold goto err1; 13310c0fea5dSIngo Weinhold } 13320c0fea5dSIngo Weinhold 13330c0fea5dSIngo Weinhold numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize); 13340c0fea5dSIngo Weinhold if (numRegions <= 0) { 13350c0fea5dSIngo Weinhold FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions); 13360c0fea5dSIngo Weinhold status = B_BAD_DATA; 13370c0fea5dSIngo Weinhold goto err1; 13380c0fea5dSIngo Weinhold } 13390c0fea5dSIngo Weinhold 13400c0fea5dSIngo Weinhold image = create_image(name, path, numRegions); 13410c0fea5dSIngo Weinhold if (image == NULL) { 13420c0fea5dSIngo Weinhold FATAL("Failed to allocate image_t object\n"); 13430c0fea5dSIngo Weinhold status = B_NO_MEMORY; 13440c0fea5dSIngo Weinhold goto err1; 13450c0fea5dSIngo Weinhold } 13460c0fea5dSIngo Weinhold 13470c0fea5dSIngo Weinhold status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize); 13480c0fea5dSIngo Weinhold if (status < B_OK) 13490c0fea5dSIngo Weinhold goto err2; 13500c0fea5dSIngo Weinhold 13510c0fea5dSIngo Weinhold if (!assert_dynamic_loadable(image)) { 13520c0fea5dSIngo Weinhold FATAL("Dynamic segment must be loadable (implementation restriction)\n"); 13530c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 13540c0fea5dSIngo Weinhold goto err2; 13550c0fea5dSIngo Weinhold } 13560c0fea5dSIngo Weinhold 135761b37794SIngo Weinhold if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff, 135834982809SIngo Weinhold sizeof(ph_buff))) { 135961b37794SIngo Weinhold // If this is the executable image, we init the search path 136061b37794SIngo Weinhold // subdir, if the compiler version doesn't match ours. 136161b37794SIngo Weinhold if (type == B_APP_IMAGE) { 136261b37794SIngo Weinhold #if __GNUC__ == 2 136361b37794SIngo Weinhold if (image->gcc_version.major > 2) 136461b37794SIngo Weinhold sSearchPathSubDir = "gcc4"; 136561b37794SIngo Weinhold #elif __GNUC__ == 4 136661b37794SIngo Weinhold if (image->gcc_version.major == 2) 136761b37794SIngo Weinhold sSearchPathSubDir = "gcc2"; 136861b37794SIngo Weinhold #endif 136961b37794SIngo Weinhold } 137061b37794SIngo Weinhold } else { 137134982809SIngo Weinhold FATAL("Failed to get gcc version for %s\n", path); 137234982809SIngo Weinhold // not really fatal, actually 137334982809SIngo Weinhold } 137434982809SIngo Weinhold 13755fd6637bSIngo Weinhold // init gcc version dependent image flags 13765fd6637bSIngo Weinhold // symbol resolution strategy (fallback is R5-style, if version is 13775fd6637bSIngo Weinhold // unavailable) 13785fd6637bSIngo Weinhold if (image->gcc_version.major == 0 13795fd6637bSIngo Weinhold || image->gcc_version.major == 2 && image->gcc_version.middle < 95) { 13805fd6637bSIngo Weinhold image->flags |= IMAGE_FLAG_R5_SYMBOL_RESOLUTION; 13815fd6637bSIngo Weinhold } 13825fd6637bSIngo Weinhold 13830c0fea5dSIngo Weinhold status = map_image(fd, path, image, type == B_APP_IMAGE); 13840c0fea5dSIngo Weinhold if (status < B_OK) { 13850c0fea5dSIngo Weinhold FATAL("Could not map image: %s\n", strerror(status)); 13860c0fea5dSIngo Weinhold status = B_ERROR; 13870c0fea5dSIngo Weinhold goto err2; 13880c0fea5dSIngo Weinhold } 13890c0fea5dSIngo Weinhold 13900c0fea5dSIngo Weinhold if (!parse_dynamic_segment(image)) { 13910c0fea5dSIngo Weinhold FATAL("Troubles handling dynamic section\n"); 13920c0fea5dSIngo Weinhold status = B_BAD_DATA; 13930c0fea5dSIngo Weinhold goto err3; 13940c0fea5dSIngo Weinhold } 13950c0fea5dSIngo Weinhold 1396dd76bc97SIngo Weinhold if (eheader.e_entry != 0) 13970c0fea5dSIngo Weinhold image->entry_point = eheader.e_entry + image->regions[0].delta; 13980c0fea5dSIngo Weinhold 13990c0fea5dSIngo Weinhold image->type = type; 14000c0fea5dSIngo Weinhold register_image(image, fd, path); 14010c0fea5dSIngo Weinhold 14020c0fea5dSIngo Weinhold _kern_close(fd); 14030c0fea5dSIngo Weinhold 14040c0fea5dSIngo Weinhold enqueue_image(&sLoadedImages, image); 14050c0fea5dSIngo Weinhold sLoadedImageCount++; 14060c0fea5dSIngo Weinhold 14070c0fea5dSIngo Weinhold *_image = image; 14087486b72dSIngo Weinhold 140934982809SIngo Weinhold KTRACE("rld: load_container(\"%s\"): done: id: %ld (gcc: %d.%d.%d)", name, 141034982809SIngo Weinhold image->id, image->gcc_version.major, image->gcc_version.middle, 141134982809SIngo Weinhold image->gcc_version.minor); 14127486b72dSIngo Weinhold 14130c0fea5dSIngo Weinhold return B_OK; 14140c0fea5dSIngo Weinhold 14150c0fea5dSIngo Weinhold err3: 14160c0fea5dSIngo Weinhold unmap_image(image); 14170c0fea5dSIngo Weinhold err2: 14180c0fea5dSIngo Weinhold delete_image_struct(image); 14190c0fea5dSIngo Weinhold err1: 14200c0fea5dSIngo Weinhold _kern_close(fd); 14217486b72dSIngo Weinhold 14227486b72dSIngo Weinhold KTRACE("rld: load_container(\"%s\"): failed: %s", name, 14237486b72dSIngo Weinhold strerror(status)); 14247486b72dSIngo Weinhold 14250c0fea5dSIngo Weinhold return status; 14260c0fea5dSIngo Weinhold } 14270c0fea5dSIngo Weinhold 14280c0fea5dSIngo Weinhold 14290c0fea5dSIngo Weinhold static const char * 14300c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 14310c0fea5dSIngo Weinhold { 14320c0fea5dSIngo Weinhold int i; 14330c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 14340c0fea5dSIngo Weinhold 14350c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 14360c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 14370c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 14380c0fea5dSIngo Weinhold } 14390c0fea5dSIngo Weinhold 14400c0fea5dSIngo Weinhold return NULL; 14410c0fea5dSIngo Weinhold } 14420c0fea5dSIngo Weinhold 14430c0fea5dSIngo Weinhold 14440c0fea5dSIngo Weinhold static status_t 14450c0fea5dSIngo Weinhold load_dependencies(image_t *image) 14460c0fea5dSIngo Weinhold { 14470c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 14484bef3723SAxel Dörfler bool reportErrors = report_errors(); 144974c0424aSAxel Dörfler status_t status = B_OK; 14500c0fea5dSIngo Weinhold uint32 i, j; 14510c0fea5dSIngo Weinhold const char *rpath; 14520c0fea5dSIngo Weinhold 14530c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 14540c0fea5dSIngo Weinhold return B_OK; 14550c0fea5dSIngo Weinhold 14560c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 14570c0fea5dSIngo Weinhold 14580c0fea5dSIngo Weinhold if (image->num_needed == 0) 14590c0fea5dSIngo Weinhold return B_OK; 14600c0fea5dSIngo Weinhold 14617486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld)", image->name, 14627486b72dSIngo Weinhold image->id); 14637486b72dSIngo Weinhold 14640c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 14650c0fea5dSIngo Weinhold if (image->needed == NULL) { 14660c0fea5dSIngo Weinhold FATAL("failed to allocate needed struct\n"); 14677486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) failed: no memory", 14687486b72dSIngo Weinhold image->name, image->id); 14690c0fea5dSIngo Weinhold return B_NO_MEMORY; 14700c0fea5dSIngo Weinhold } 14710c0fea5dSIngo Weinhold 14720c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 14730c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 14740c0fea5dSIngo Weinhold 14750c0fea5dSIngo Weinhold for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { 14760c0fea5dSIngo Weinhold switch (d[i].d_tag) { 14770c0fea5dSIngo Weinhold case DT_NEEDED: 147874c0424aSAxel Dörfler { 147974c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 148074c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 14810c0fea5dSIngo Weinhold 148274c0424aSAxel Dörfler status_t loadStatus = load_container(name, B_LIBRARY_IMAGE, 148374c0424aSAxel Dörfler rpath, &image->needed[j]); 148474c0424aSAxel Dörfler if (loadStatus < B_OK) { 148574c0424aSAxel Dörfler status = loadStatus; 148674c0424aSAxel Dörfler // correct error code in case the file could not been found 148774c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 148874c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 148974c0424aSAxel Dörfler 149074c0424aSAxel Dörfler if (reportErrors) 149174c0424aSAxel Dörfler sErrorMessage.AddString("missing library", name); 149274c0424aSAxel Dörfler } 149374c0424aSAxel Dörfler 149474c0424aSAxel Dörfler // Collect all missing libraries in case we report back 14957486b72dSIngo Weinhold if (!reportErrors) { 14967486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 14977486b72dSIngo Weinhold "failed: %s", image->name, image->id, 14987486b72dSIngo Weinhold strerror(status)); 14990c0fea5dSIngo Weinhold return status; 150074c0424aSAxel Dörfler } 15017486b72dSIngo Weinhold } 15020c0fea5dSIngo Weinhold 15030c0fea5dSIngo Weinhold j += 1; 15040c0fea5dSIngo Weinhold break; 150574c0424aSAxel Dörfler } 15060c0fea5dSIngo Weinhold 15070c0fea5dSIngo Weinhold default: 15080c0fea5dSIngo Weinhold // ignore any other tag 15090c0fea5dSIngo Weinhold continue; 15100c0fea5dSIngo Weinhold } 15110c0fea5dSIngo Weinhold } 15120c0fea5dSIngo Weinhold 15137486b72dSIngo Weinhold if (status < B_OK) { 15147486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 15157486b72dSIngo Weinhold "failed: %s", image->name, image->id, 15167486b72dSIngo Weinhold strerror(status)); 151774c0424aSAxel Dörfler return status; 15187486b72dSIngo Weinhold } 151974c0424aSAxel Dörfler 15200c0fea5dSIngo Weinhold if (j != image->num_needed) { 15210c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 15227486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) " 15237486b72dSIngo Weinhold "failed: internal error", image->name, image->id); 15240c0fea5dSIngo Weinhold return B_ERROR; 15250c0fea5dSIngo Weinhold } 15260c0fea5dSIngo Weinhold 15277486b72dSIngo Weinhold KTRACE("rld: load_dependencies(\"%s\", id: %ld) done", image->name, 15287486b72dSIngo Weinhold image->id); 15297486b72dSIngo Weinhold 15300c0fea5dSIngo Weinhold return B_OK; 15310c0fea5dSIngo Weinhold } 15320c0fea5dSIngo Weinhold 15330c0fea5dSIngo Weinhold 15340c0fea5dSIngo Weinhold static uint32 15350c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList, 15360c0fea5dSIngo Weinhold uint32 sortFlag) 15370c0fea5dSIngo Weinhold { 15380c0fea5dSIngo Weinhold uint32 i; 15390c0fea5dSIngo Weinhold 15400c0fea5dSIngo Weinhold if (image->flags & sortFlag) 15410c0fea5dSIngo Weinhold return slot; 15420c0fea5dSIngo Weinhold 15430c0fea5dSIngo Weinhold image->flags |= sortFlag; /* make sure we don't visit this one */ 15440c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) 15450c0fea5dSIngo Weinhold slot = topological_sort(image->needed[i], slot, initList, sortFlag); 15460c0fea5dSIngo Weinhold 15470c0fea5dSIngo Weinhold initList[slot] = image; 15480c0fea5dSIngo Weinhold return slot + 1; 15490c0fea5dSIngo Weinhold } 15500c0fea5dSIngo Weinhold 15510c0fea5dSIngo Weinhold 15520c0fea5dSIngo Weinhold static ssize_t 15530c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag) 15540c0fea5dSIngo Weinhold { 15550c0fea5dSIngo Weinhold image_t **list; 15560c0fea5dSIngo Weinhold 15570c0fea5dSIngo Weinhold list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *)); 15580c0fea5dSIngo Weinhold if (list == NULL) { 15590c0fea5dSIngo Weinhold FATAL("memory shortage in get_sorted_image_list()"); 15600c0fea5dSIngo Weinhold *_list = NULL; 15610c0fea5dSIngo Weinhold return B_NO_MEMORY; 15620c0fea5dSIngo Weinhold } 15630c0fea5dSIngo Weinhold 15640c0fea5dSIngo Weinhold memset(list, 0, sLoadedImageCount * sizeof(image_t *)); 15650c0fea5dSIngo Weinhold 15660c0fea5dSIngo Weinhold *_list = list; 15670c0fea5dSIngo Weinhold return topological_sort(image, 0, list, sortFlag); 15680c0fea5dSIngo Weinhold } 15690c0fea5dSIngo Weinhold 15700c0fea5dSIngo Weinhold 15710c0fea5dSIngo Weinhold static status_t 15720c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 15730c0fea5dSIngo Weinhold { 15740c0fea5dSIngo Weinhold ssize_t count, i; 15750c0fea5dSIngo Weinhold image_t **list; 15760c0fea5dSIngo Weinhold 15770c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 15780c0fea5dSIngo Weinhold if (count < B_OK) 15790c0fea5dSIngo Weinhold return count; 15800c0fea5dSIngo Weinhold 15810c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 158246f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 15830c0fea5dSIngo Weinhold if (status < B_OK) 15840c0fea5dSIngo Weinhold return status; 15850c0fea5dSIngo Weinhold } 15860c0fea5dSIngo Weinhold 15870c0fea5dSIngo Weinhold free(list); 15880c0fea5dSIngo Weinhold return B_OK; 15890c0fea5dSIngo Weinhold } 15900c0fea5dSIngo Weinhold 15910c0fea5dSIngo Weinhold 15920c0fea5dSIngo Weinhold static void 15930c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 15940c0fea5dSIngo Weinhold { 15950c0fea5dSIngo Weinhold image_t **initList; 15960c0fea5dSIngo Weinhold ssize_t count, i; 15970c0fea5dSIngo Weinhold 15980c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 15990c0fea5dSIngo Weinhold if (count <= 0) 16000c0fea5dSIngo Weinhold return; 16010c0fea5dSIngo Weinhold 16020c0fea5dSIngo Weinhold if (!initHead) { 16030c0fea5dSIngo Weinhold // this removes the "calling" image 16040c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 16050c0fea5dSIngo Weinhold initList[--count] = NULL; 16060c0fea5dSIngo Weinhold } 16070c0fea5dSIngo Weinhold 16080c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 16090c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 16100c0fea5dSIngo Weinhold image = initList[i]; 16110c0fea5dSIngo Weinhold 16120c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 16130c0fea5dSIngo Weinhold 1614dd76bc97SIngo Weinhold if (image->init_routine != 0) 16150c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 16160c0fea5dSIngo Weinhold } 16170c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 16180c0fea5dSIngo Weinhold 16190c0fea5dSIngo Weinhold free(initList); 16200c0fea5dSIngo Weinhold } 16210c0fea5dSIngo Weinhold 16220c0fea5dSIngo Weinhold 16230c0fea5dSIngo Weinhold static void 16240c0fea5dSIngo Weinhold put_image(image_t *image) 16250c0fea5dSIngo Weinhold { 16260c0fea5dSIngo Weinhold // If all references to the image are gone, add it to the disposable list 16270c0fea5dSIngo Weinhold // and remove all dependencies 16280c0fea5dSIngo Weinhold 16290c0fea5dSIngo Weinhold if (atomic_add(&image->ref_count, -1) == 1) { 16300c0fea5dSIngo Weinhold size_t i; 16310c0fea5dSIngo Weinhold 16320c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 16330c0fea5dSIngo Weinhold enqueue_image(&sDisposableImages, image); 16340c0fea5dSIngo Weinhold sLoadedImageCount--; 16350c0fea5dSIngo Weinhold 16360c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) { 16370c0fea5dSIngo Weinhold put_image(image->needed[i]); 16380c0fea5dSIngo Weinhold } 16390c0fea5dSIngo Weinhold } 16400c0fea5dSIngo Weinhold } 16410c0fea5dSIngo Weinhold 16420c0fea5dSIngo Weinhold 164374c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 16440c0fea5dSIngo Weinhold 16450c0fea5dSIngo Weinhold 16460c0fea5dSIngo Weinhold image_id 16470c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 16480c0fea5dSIngo Weinhold { 16490c0fea5dSIngo Weinhold status_t status; 16500c0fea5dSIngo Weinhold image_t *image; 16510c0fea5dSIngo Weinhold 16527486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\")", path); 16537486b72dSIngo Weinhold 16540c0fea5dSIngo Weinhold rld_lock(); 16550c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 16560c0fea5dSIngo Weinhold 16570c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 16580c0fea5dSIngo Weinhold 16590c0fea5dSIngo Weinhold status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage); 166074c0424aSAxel Dörfler if (status < B_OK) 166174c0424aSAxel Dörfler goto err; 16620c0fea5dSIngo Weinhold 16630c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image != NULL; image = image->next) { 16640c0fea5dSIngo Weinhold status = load_dependencies(image); 16650c0fea5dSIngo Weinhold if (status < B_OK) 16660c0fea5dSIngo Weinhold goto err; 16670c0fea5dSIngo Weinhold } 16680c0fea5dSIngo Weinhold 16690c0fea5dSIngo Weinhold status = relocate_dependencies(sProgramImage); 16700c0fea5dSIngo Weinhold if (status < B_OK) 16710c0fea5dSIngo Weinhold goto err; 16720c0fea5dSIngo Weinhold 16730c0fea5dSIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private API 16740c0fea5dSIngo Weinhold { 167546f4d849SIngo Weinhold struct Elf32_Sym *symbol = find_symbol_in_loaded_images( 167646f4d849SIngo Weinhold "__gRuntimeLoader", &image); 16770c0fea5dSIngo Weinhold if (symbol != NULL) { 16780c0fea5dSIngo Weinhold void **_export = (void **)(symbol->st_value + image->regions[0].delta); 16790c0fea5dSIngo Weinhold *_export = &gRuntimeLoader; 16800c0fea5dSIngo Weinhold } 16810c0fea5dSIngo Weinhold } 16820c0fea5dSIngo Weinhold 16830c0fea5dSIngo Weinhold init_dependencies(sLoadedImages.head, true); 16840c0fea5dSIngo Weinhold remap_images(); 16850c0fea5dSIngo Weinhold // ToDo: once setup_system_time() is fixed, move this one line higher! 16860c0fea5dSIngo Weinhold 16870c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 16880c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 16890c0fea5dSIngo Weinhold { 169046f4d849SIngo Weinhold struct Elf32_Sym *symbol = find_symbol_in_loaded_images("getenv", 169146f4d849SIngo Weinhold &image); 16920c0fea5dSIngo Weinhold if (symbol != NULL) 16930c0fea5dSIngo Weinhold gGetEnv = (char* (*)(const char*)) 16940c0fea5dSIngo Weinhold (symbol->st_value + image->regions[0].delta); 16950c0fea5dSIngo Weinhold } 16960c0fea5dSIngo Weinhold 1697dd76bc97SIngo Weinhold if (sProgramImage->entry_point == 0) { 16980c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 16990c0fea5dSIngo Weinhold goto err; 17000c0fea5dSIngo Weinhold } 17010c0fea5dSIngo Weinhold 17020c0fea5dSIngo Weinhold *_entry = (void *)(sProgramImage->entry_point); 17030c0fea5dSIngo Weinhold 17040c0fea5dSIngo Weinhold rld_unlock(); 17057486b72dSIngo Weinhold 17065d0638bfSIngo Weinhold sProgramLoaded = true; 17075d0638bfSIngo Weinhold 17087486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") done: entry: %p, id: %ld", path, 17097486b72dSIngo Weinhold *_entry, sProgramImage->id); 17107486b72dSIngo Weinhold 17110c0fea5dSIngo Weinhold return sProgramImage->id; 17120c0fea5dSIngo Weinhold 17130c0fea5dSIngo Weinhold err: 17147486b72dSIngo Weinhold KTRACE("rld: load_program(\"%s\") failed: %s", path, strerror(status)); 17157486b72dSIngo Weinhold 17160c0fea5dSIngo Weinhold delete_image(sProgramImage); 171774c0424aSAxel Dörfler 17184bef3723SAxel Dörfler if (report_errors()) { 17194bef3723SAxel Dörfler // send error message 172074c0424aSAxel Dörfler sErrorMessage.AddInt32("error", status); 17214bef3723SAxel Dörfler sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 17224bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 17234bef3723SAxel Dörfler 17244bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 17254bef3723SAxel Dörfler sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0); 172674c0424aSAxel Dörfler } 172774c0424aSAxel Dörfler _kern_loading_app_failed(status); 17280c0fea5dSIngo Weinhold rld_unlock(); 172974c0424aSAxel Dörfler 17300c0fea5dSIngo Weinhold return status; 17310c0fea5dSIngo Weinhold } 17320c0fea5dSIngo Weinhold 17330c0fea5dSIngo Weinhold 17340c0fea5dSIngo Weinhold image_id 17350c0fea5dSIngo Weinhold load_library(char const *path, uint32 flags, bool addOn) 17360c0fea5dSIngo Weinhold { 17370c0fea5dSIngo Weinhold image_t *image = NULL; 17380c0fea5dSIngo Weinhold image_t *iter; 17390c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 17400c0fea5dSIngo Weinhold status_t status; 17410c0fea5dSIngo Weinhold 17420c0fea5dSIngo Weinhold if (path == NULL) 17430c0fea5dSIngo Weinhold return B_BAD_VALUE; 17440c0fea5dSIngo Weinhold 17450c0fea5dSIngo Weinhold // ToDo: implement flags 17460c0fea5dSIngo Weinhold (void)flags; 17470c0fea5dSIngo Weinhold 17487486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn); 17497486b72dSIngo Weinhold 17500c0fea5dSIngo Weinhold rld_lock(); 17510c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 17520c0fea5dSIngo Weinhold 17530c0fea5dSIngo Weinhold // have we already loaded this library? 17540c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 17550c0fea5dSIngo Weinhold if (!addOn) { 17560c0fea5dSIngo Weinhold image = find_image(path, APP_OR_LIBRARY_TYPE); 17570c0fea5dSIngo Weinhold if (image) { 17580c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 17590c0fea5dSIngo Weinhold rld_unlock(); 17607486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path, 17617486b72dSIngo Weinhold image->id); 17620c0fea5dSIngo Weinhold return image->id; 17630c0fea5dSIngo Weinhold } 17640c0fea5dSIngo Weinhold } 17650c0fea5dSIngo Weinhold 17660c0fea5dSIngo Weinhold status = load_container(path, type, NULL, &image); 17670c0fea5dSIngo Weinhold if (status < B_OK) { 17680c0fea5dSIngo Weinhold rld_unlock(); 17697486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed to load container: %s", path, 17707486b72dSIngo Weinhold strerror(status)); 17710c0fea5dSIngo Weinhold return status; 17720c0fea5dSIngo Weinhold } 17730c0fea5dSIngo Weinhold 17740c0fea5dSIngo Weinhold for (iter = sLoadedImages.head; iter; iter = iter->next) { 17750c0fea5dSIngo Weinhold status = load_dependencies(iter); 17760c0fea5dSIngo Weinhold if (status < B_OK) 17770c0fea5dSIngo Weinhold goto err; 17780c0fea5dSIngo Weinhold } 17790c0fea5dSIngo Weinhold 17800c0fea5dSIngo Weinhold status = relocate_dependencies(image); 17810c0fea5dSIngo Weinhold if (status < B_OK) 17820c0fea5dSIngo Weinhold goto err; 17830c0fea5dSIngo Weinhold 17840c0fea5dSIngo Weinhold remap_images(); 17850c0fea5dSIngo Weinhold init_dependencies(image, true); 17860c0fea5dSIngo Weinhold 17870c0fea5dSIngo Weinhold rld_unlock(); 17887486b72dSIngo Weinhold 17897486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id); 17907486b72dSIngo Weinhold 17910c0fea5dSIngo Weinhold return image->id; 17920c0fea5dSIngo Weinhold 17930c0fea5dSIngo Weinhold err: 17947486b72dSIngo Weinhold KTRACE("rld: load_library(\"%s\") failed: %s", path, strerror(status)); 17957486b72dSIngo Weinhold 17960c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 17970c0fea5dSIngo Weinhold sLoadedImageCount--; 17980c0fea5dSIngo Weinhold delete_image(image); 17990c0fea5dSIngo Weinhold rld_unlock(); 18000c0fea5dSIngo Weinhold return status; 18010c0fea5dSIngo Weinhold } 18020c0fea5dSIngo Weinhold 18030c0fea5dSIngo Weinhold 18040c0fea5dSIngo Weinhold status_t 18050c0fea5dSIngo Weinhold unload_library(image_id imageID, bool addOn) 18060c0fea5dSIngo Weinhold { 18070c0fea5dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 18080c0fea5dSIngo Weinhold image_t *image; 18090c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 18100c0fea5dSIngo Weinhold 18110c0fea5dSIngo Weinhold if (imageID < B_OK) 18120c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 18130c0fea5dSIngo Weinhold 18140c0fea5dSIngo Weinhold rld_lock(); 18150c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 18160c0fea5dSIngo Weinhold 18179a6072a3SAxel Dörfler if (sInvalidImageIDs) { 18189a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 18199a6072a3SAxel Dörfler update_image_ids(); 18209a6072a3SAxel Dörfler } 18219a6072a3SAxel Dörfler 18220c0fea5dSIngo Weinhold // we only check images that have been already initialized 18230c0fea5dSIngo Weinhold 18240c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image; image = image->next) { 18250c0fea5dSIngo Weinhold if (image->id == imageID) { 18260c0fea5dSIngo Weinhold // unload image 18270c0fea5dSIngo Weinhold if (type == image->type) { 18280c0fea5dSIngo Weinhold put_image(image); 18290c0fea5dSIngo Weinhold status = B_OK; 18300c0fea5dSIngo Weinhold } else 18310c0fea5dSIngo Weinhold status = B_BAD_VALUE; 18320c0fea5dSIngo Weinhold break; 18330c0fea5dSIngo Weinhold } 18340c0fea5dSIngo Weinhold } 18350c0fea5dSIngo Weinhold 18360c0fea5dSIngo Weinhold if (status == B_OK) { 18370c0fea5dSIngo Weinhold while ((image = sDisposableImages.head) != NULL) { 18380c0fea5dSIngo Weinhold // call image fini here... 18398c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 18408c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 18413be509a2SMichael Lotz image->regions[0].vmstart, image->regions[0].vmsize); 18428c2a9d74SMichael Lotz } 18438c2a9d74SMichael Lotz 18440c0fea5dSIngo Weinhold if (image->term_routine) 18450c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 18460c0fea5dSIngo Weinhold 18470c0fea5dSIngo Weinhold dequeue_image(&sDisposableImages, image); 18480c0fea5dSIngo Weinhold unmap_image(image); 18490c0fea5dSIngo Weinhold 18500c0fea5dSIngo Weinhold delete_image(image); 18510c0fea5dSIngo Weinhold } 18520c0fea5dSIngo Weinhold } 18530c0fea5dSIngo Weinhold 18540c0fea5dSIngo Weinhold rld_unlock(); 18550c0fea5dSIngo Weinhold return status; 18560c0fea5dSIngo Weinhold } 18570c0fea5dSIngo Weinhold 18580c0fea5dSIngo Weinhold 18590c0fea5dSIngo Weinhold status_t 18609a6072a3SAxel Dörfler get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, 18619a6072a3SAxel Dörfler int32 *_nameLength, int32 *_type, void **_location) 18620c0fea5dSIngo Weinhold { 18630c0fea5dSIngo Weinhold int32 count = 0, j; 18640c0fea5dSIngo Weinhold uint32 i; 18650c0fea5dSIngo Weinhold image_t *image; 18660c0fea5dSIngo Weinhold 18670c0fea5dSIngo Weinhold rld_lock(); 18680c0fea5dSIngo Weinhold 18690c0fea5dSIngo Weinhold // get the image from those who have been already initialized 18700c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 18710c0fea5dSIngo Weinhold if (image == NULL) { 18720c0fea5dSIngo Weinhold rld_unlock(); 18730c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 18740c0fea5dSIngo Weinhold } 18750c0fea5dSIngo Weinhold 18760c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 18770c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 18780c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 18790555803aSAxel Dörfler struct Elf32_Sym *symbol = &image->syms[j]; 18800c0fea5dSIngo Weinhold 18810c0fea5dSIngo Weinhold if (count == num) { 18820c0fea5dSIngo Weinhold strlcpy(nameBuffer, SYMNAME(image, symbol), *_nameLength); 18830c0fea5dSIngo Weinhold *_nameLength = strlen(SYMNAME(image, symbol)); 18840c0fea5dSIngo Weinhold 18850c0fea5dSIngo Weinhold if (_type != NULL) { 18860c0fea5dSIngo Weinhold // ToDo: check with the return types of that BeOS function 18870c0fea5dSIngo Weinhold if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) 18880c0fea5dSIngo Weinhold *_type = B_SYMBOL_TYPE_TEXT; 18890c0fea5dSIngo Weinhold else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) 18900c0fea5dSIngo Weinhold *_type = B_SYMBOL_TYPE_DATA; 18910c0fea5dSIngo Weinhold else 18920c0fea5dSIngo Weinhold *_type = B_SYMBOL_TYPE_ANY; 18930c0fea5dSIngo Weinhold } 18940c0fea5dSIngo Weinhold 18950c0fea5dSIngo Weinhold if (_location != NULL) 18960c0fea5dSIngo Weinhold *_location = (void *)(symbol->st_value + image->regions[0].delta); 18970c0fea5dSIngo Weinhold goto out; 18980c0fea5dSIngo Weinhold } 18990c0fea5dSIngo Weinhold count++; 19000c0fea5dSIngo Weinhold } 19010c0fea5dSIngo Weinhold } 19020c0fea5dSIngo Weinhold out: 19030c0fea5dSIngo Weinhold rld_unlock(); 19040c0fea5dSIngo Weinhold 19050c0fea5dSIngo Weinhold if (num != count) 19060c0fea5dSIngo Weinhold return B_BAD_INDEX; 19070c0fea5dSIngo Weinhold 19080c0fea5dSIngo Weinhold return B_OK; 19090c0fea5dSIngo Weinhold } 19100c0fea5dSIngo Weinhold 19110c0fea5dSIngo Weinhold 19120c0fea5dSIngo Weinhold status_t 19139a6072a3SAxel Dörfler get_symbol(image_id imageID, char const *symbolName, int32 symbolType, 19149a6072a3SAxel Dörfler void **_location) 19150c0fea5dSIngo Weinhold { 19160c0fea5dSIngo Weinhold status_t status = B_OK; 19170c0fea5dSIngo Weinhold image_t *image; 19180c0fea5dSIngo Weinhold 19190c0fea5dSIngo Weinhold if (imageID < B_OK) 19200c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 19210c0fea5dSIngo Weinhold if (symbolName == NULL) 19220c0fea5dSIngo Weinhold return B_BAD_VALUE; 19230c0fea5dSIngo Weinhold 19240c0fea5dSIngo Weinhold rld_lock(); 19250c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 19260c0fea5dSIngo Weinhold 19270c0fea5dSIngo Weinhold // get the image from those who have been already initialized 19280c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 19290c0fea5dSIngo Weinhold if (image != NULL) { 19300c0fea5dSIngo Weinhold struct Elf32_Sym *symbol; 19310c0fea5dSIngo Weinhold 19320c0fea5dSIngo Weinhold // get the symbol in the image 19330c0fea5dSIngo Weinhold symbol = find_symbol(image, symbolName, symbolType); 19340c0fea5dSIngo Weinhold if (symbol) { 19350c0fea5dSIngo Weinhold if (_location != NULL) 19360c0fea5dSIngo Weinhold *_location = (void *)(symbol->st_value + image->regions[0].delta); 19370c0fea5dSIngo Weinhold } else 19380c0fea5dSIngo Weinhold status = B_ENTRY_NOT_FOUND; 19390c0fea5dSIngo Weinhold } else 19400c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 19410c0fea5dSIngo Weinhold 19420c0fea5dSIngo Weinhold rld_unlock(); 19430c0fea5dSIngo Weinhold return status; 19440c0fea5dSIngo Weinhold } 19450c0fea5dSIngo Weinhold 19460c0fea5dSIngo Weinhold 19470c0fea5dSIngo Weinhold status_t 19480c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 19490c0fea5dSIngo Weinhold { 19500c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 19510c0fea5dSIngo Weinhold struct Elf32_Dyn *dynamicSection; 19520c0fea5dSIngo Weinhold image_t *image; 19530c0fea5dSIngo Weinhold 19540c0fea5dSIngo Weinhold if (_name == NULL) 19550c0fea5dSIngo Weinhold return B_BAD_VALUE; 19560c0fea5dSIngo Weinhold 19570c0fea5dSIngo Weinhold rld_lock(); 19580c0fea5dSIngo Weinhold 19590c0fea5dSIngo Weinhold image = find_loaded_image_by_id(id); 19600c0fea5dSIngo Weinhold if (image == NULL) { 19610c0fea5dSIngo Weinhold rld_unlock(); 19620c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 19630c0fea5dSIngo Weinhold } 19640c0fea5dSIngo Weinhold 19650c0fea5dSIngo Weinhold dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr; 19660c0fea5dSIngo Weinhold if (dynamicSection == NULL || image->num_needed <= searchIndex) { 19670c0fea5dSIngo Weinhold rld_unlock(); 19680c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 19690c0fea5dSIngo Weinhold } 19700c0fea5dSIngo Weinhold 19710c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 19720c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 19730c0fea5dSIngo Weinhold continue; 19740c0fea5dSIngo Weinhold 19750c0fea5dSIngo Weinhold if (j++ == searchIndex) { 19760c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 19770c0fea5dSIngo Weinhold 19780c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 19790c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 19800c0fea5dSIngo Weinhold rld_unlock(); 19810c0fea5dSIngo Weinhold return B_OK; 19820c0fea5dSIngo Weinhold } 19830c0fea5dSIngo Weinhold } 19840c0fea5dSIngo Weinhold 19850c0fea5dSIngo Weinhold rld_unlock(); 19860c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 19870c0fea5dSIngo Weinhold } 19880c0fea5dSIngo Weinhold 19890c0fea5dSIngo Weinhold 199074c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 19910c0fea5dSIngo Weinhold 19920c0fea5dSIngo Weinhold 19939a6072a3SAxel Dörfler /*! Read and verify the ELF header */ 19940c0fea5dSIngo Weinhold status_t 19950c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length) 19960c0fea5dSIngo Weinhold { 19970c0fea5dSIngo Weinhold int32 programSize, sectionSize; 19980c0fea5dSIngo Weinhold 19990c0fea5dSIngo Weinhold if (length < (int32)sizeof(struct Elf32_Ehdr)) 20000c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 20010c0fea5dSIngo Weinhold 20029a6072a3SAxel Dörfler return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, 20039a6072a3SAxel Dörfler §ionSize); 20040c0fea5dSIngo Weinhold } 20050c0fea5dSIngo Weinhold 20060c0fea5dSIngo Weinhold 20070c0fea5dSIngo Weinhold void 20080c0fea5dSIngo Weinhold terminate_program(void) 20090c0fea5dSIngo Weinhold { 20100c0fea5dSIngo Weinhold image_t **termList; 20110c0fea5dSIngo Weinhold ssize_t count, i; 20120c0fea5dSIngo Weinhold 20130c0fea5dSIngo Weinhold count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED); 20140c0fea5dSIngo Weinhold if (count < B_OK) 20150c0fea5dSIngo Weinhold return; 20160c0fea5dSIngo Weinhold 20179a6072a3SAxel Dörfler if (sInvalidImageIDs) { 20189a6072a3SAxel Dörfler // After fork, we lazily rebuild the image IDs of all loaded images 20199a6072a3SAxel Dörfler update_image_ids(); 20209a6072a3SAxel Dörfler } 20219a6072a3SAxel Dörfler 20220c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 20230c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 20240c0fea5dSIngo Weinhold image_t *image = termList[i]; 20250c0fea5dSIngo Weinhold 20260c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 20270c0fea5dSIngo Weinhold 20280c0fea5dSIngo Weinhold if (image->term_routine) 20290c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 20300c0fea5dSIngo Weinhold } 20310c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 20320c0fea5dSIngo Weinhold 20330c0fea5dSIngo Weinhold free(termList); 20340c0fea5dSIngo Weinhold } 20350c0fea5dSIngo Weinhold 20360c0fea5dSIngo Weinhold 20370c0fea5dSIngo Weinhold void 20380c0fea5dSIngo Weinhold rldelf_init(void) 20390c0fea5dSIngo Weinhold { 2040e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 2041e73923b0SAxel Dörfler sSemOwner = -1; 2042e73923b0SAxel Dörfler sSemCount = 0; 20430c0fea5dSIngo Weinhold 20440c0fea5dSIngo Weinhold // create the debug area 20450c0fea5dSIngo Weinhold { 20460c0fea5dSIngo Weinhold int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 20470c0fea5dSIngo Weinhold 20480c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 20490c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 20500c0fea5dSIngo Weinhold (void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK, 20510c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 20520c0fea5dSIngo Weinhold if (areaID < B_OK) { 20530c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 20540c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 20550c0fea5dSIngo Weinhold } 20560c0fea5dSIngo Weinhold 20570c0fea5dSIngo Weinhold area->loaded_images = &sLoadedImages; 20580c0fea5dSIngo Weinhold } 205974c0424aSAxel Dörfler 206074c0424aSAxel Dörfler // initialize error message if needed 20614bef3723SAxel Dörfler if (report_errors()) { 206274c0424aSAxel Dörfler void *buffer = malloc(1024); 206374c0424aSAxel Dörfler if (buffer == NULL) 206474c0424aSAxel Dörfler return; 206574c0424aSAxel Dörfler 206674c0424aSAxel Dörfler sErrorMessage.SetTo(buffer, 1024, 'Rler'); 206774c0424aSAxel Dörfler } 20680c0fea5dSIngo Weinhold } 20691873b4b3SIngo Weinhold 20701873b4b3SIngo Weinhold 20711873b4b3SIngo Weinhold status_t 20729a6072a3SAxel Dörfler elf_reinit_after_fork(void) 20731873b4b3SIngo Weinhold { 2074e73923b0SAxel Dörfler sSem = create_sem(1, "runtime loader"); 2075e73923b0SAxel Dörfler if (sSem < 0) 2076e73923b0SAxel Dörfler return sSem; 20771873b4b3SIngo Weinhold 20789a6072a3SAxel Dörfler // We also need to update the IDs of our images. We are the child and 2079cbc456deSIngo Weinhold // and have cloned images with different IDs. Since in most cases (fork() 2080cbc456deSIngo Weinhold // + exec*()) this would just increase the fork() overhead with no one 20819a6072a3SAxel Dörfler // caring, we do that lazily, when first doing something different. 20829a6072a3SAxel Dörfler sInvalidImageIDs = true; 2083cbc456deSIngo Weinhold 20841873b4b3SIngo Weinhold return B_OK; 20851873b4b3SIngo Weinhold } 2086