10c0fea5dSIngo Weinhold /* 20c0fea5dSIngo Weinhold * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. 30c0fea5dSIngo Weinhold * Distributed under the terms of the MIT License. 40c0fea5dSIngo Weinhold * 50c0fea5dSIngo Weinhold * Copyright 2002, Manuel J. Petit. All rights reserved. 60c0fea5dSIngo Weinhold * Copyright 2001, Travis Geiselbrecht. All rights reserved. 70c0fea5dSIngo Weinhold * Distributed under the terms of the NewOS License. 80c0fea5dSIngo Weinhold */ 90c0fea5dSIngo Weinhold 100c0fea5dSIngo Weinhold 110c0fea5dSIngo Weinhold #include "runtime_loader_private.h" 125aa7b7b6SMarcus Overhagen #include "vm.h" 130c0fea5dSIngo Weinhold 140c0fea5dSIngo Weinhold #include <OS.h> 150c0fea5dSIngo Weinhold 160c0fea5dSIngo Weinhold #include <elf32.h> 170c0fea5dSIngo Weinhold #include <user_runtime.h> 180c0fea5dSIngo Weinhold #include <syscalls.h> 190c0fea5dSIngo Weinhold #include <vm_types.h> 200c0fea5dSIngo Weinhold #include <arch/cpu.h> 210c0fea5dSIngo Weinhold #include <sem.h> 220c0fea5dSIngo Weinhold #include <runtime_loader.h> 230c0fea5dSIngo Weinhold 240c0fea5dSIngo Weinhold #include <string.h> 250c0fea5dSIngo Weinhold #include <stdio.h> 260c0fea5dSIngo Weinhold #include <stdlib.h> 270c0fea5dSIngo Weinhold 280c0fea5dSIngo Weinhold 290c0fea5dSIngo Weinhold //#define TRACE_RLD 300c0fea5dSIngo Weinhold #ifdef TRACE_RLD 310c0fea5dSIngo Weinhold # define TRACE(x) dprintf x 320c0fea5dSIngo Weinhold #else 330c0fea5dSIngo Weinhold # define TRACE(x) ; 340c0fea5dSIngo Weinhold #endif 350c0fea5dSIngo Weinhold 360c0fea5dSIngo Weinhold 370c0fea5dSIngo Weinhold // ToDo: implement better locking strategy 380c0fea5dSIngo Weinhold // ToDo: implement lazy binding 390c0fea5dSIngo Weinhold 400c0fea5dSIngo Weinhold #define PAGE_MASK (B_PAGE_SIZE - 1) 410c0fea5dSIngo Weinhold 420c0fea5dSIngo Weinhold #define PAGE_OFFSET(x) ((x) & (PAGE_MASK)) 430c0fea5dSIngo Weinhold #define PAGE_BASE(x) ((x) & ~(PAGE_MASK)) 440c0fea5dSIngo Weinhold #define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK)) 450c0fea5dSIngo Weinhold 460c0fea5dSIngo Weinhold #define RLD_PROGRAM_BASE 0x00200000 470c0fea5dSIngo Weinhold /* keep in sync with app ldscript */ 480c0fea5dSIngo Weinhold 490c0fea5dSIngo Weinhold enum { 500c0fea5dSIngo Weinhold RFLAG_RW = 0x0001, 510c0fea5dSIngo Weinhold RFLAG_ANON = 0x0002, 520c0fea5dSIngo Weinhold 530c0fea5dSIngo Weinhold RFLAG_TERMINATED = 0x0200, 540c0fea5dSIngo Weinhold RFLAG_INITIALIZED = 0x0400, 550c0fea5dSIngo Weinhold RFLAG_SYMBOLIC = 0x0800, 560c0fea5dSIngo Weinhold RFLAG_RELOCATED = 0x1000, 570c0fea5dSIngo Weinhold RFLAG_PROTECTED = 0x2000, 580c0fea5dSIngo Weinhold RFLAG_DEPENDENCIES_LOADED = 0x4000, 5946f4d849SIngo Weinhold RFLAG_REMAPPED = 0x8000, 6046f4d849SIngo Weinhold 6146f4d849SIngo Weinhold RFLAG_VISITED = 0x10000 6246f4d849SIngo Weinhold // temporarily set in the symbol resolution code 630c0fea5dSIngo Weinhold }; 640c0fea5dSIngo Weinhold 650c0fea5dSIngo Weinhold 660c0fea5dSIngo Weinhold #define IMAGE_TYPE_TO_MASK(type) (1 << ((type) - 1)) 670c0fea5dSIngo Weinhold #define ALL_IMAGE_TYPES (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 680c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \ 690c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \ 700c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE)) 710c0fea5dSIngo Weinhold #define APP_OR_LIBRARY_TYPE (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \ 720c0fea5dSIngo Weinhold | IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE)) 730c0fea5dSIngo Weinhold 740c0fea5dSIngo Weinhold typedef void (*init_term_function)(image_id); 750c0fea5dSIngo Weinhold 760c0fea5dSIngo Weinhold static image_queue_t sLoadedImages = {0, 0}; 770c0fea5dSIngo Weinhold static image_queue_t sDisposableImages = {0, 0}; 780c0fea5dSIngo Weinhold static uint32 sLoadedImageCount = 0; 790c0fea5dSIngo Weinhold static image_t *sProgramImage; 8074c0424aSAxel Dörfler static KMessage sErrorMessage; 810c0fea5dSIngo Weinhold 8246f4d849SIngo Weinhold #ifdef BEOS_STYLE_SYMBOLS_RESOLUTION 8346f4d849SIngo Weinhold static bool sResolveSymbolsBeOSStyle = true; 8446f4d849SIngo Weinhold #else 8546f4d849SIngo Weinhold static bool sResolveSymbolsBeOSStyle = false; 8646f4d849SIngo Weinhold #endif 8746f4d849SIngo Weinhold 880c0fea5dSIngo Weinhold // a recursive lock 890c0fea5dSIngo Weinhold static sem_id rld_sem; 900c0fea5dSIngo Weinhold static thread_id rld_sem_owner; 910c0fea5dSIngo Weinhold static int32 rld_sem_count; 920c0fea5dSIngo Weinhold 930c0fea5dSIngo Weinhold 940c0fea5dSIngo Weinhold #ifdef TRACE_RLD 950c0fea5dSIngo Weinhold # define FATAL(x...) dprintf("runtime_loader: " x); 960c0fea5dSIngo Weinhold 970c0fea5dSIngo Weinhold void 980c0fea5dSIngo Weinhold dprintf(const char *format, ...) 990c0fea5dSIngo Weinhold { 1000c0fea5dSIngo Weinhold char buffer[1024]; 1010c0fea5dSIngo Weinhold 1020c0fea5dSIngo Weinhold va_list list; 1030c0fea5dSIngo Weinhold va_start(list, format); 1040c0fea5dSIngo Weinhold 1050c0fea5dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 1060c0fea5dSIngo Weinhold _kern_debug_output(buffer); 1070c0fea5dSIngo Weinhold 1080c0fea5dSIngo Weinhold va_end(list); 1090c0fea5dSIngo Weinhold } 1100c0fea5dSIngo Weinhold #else 1110c0fea5dSIngo Weinhold # define FATAL(x...) printf("runtime_loader: " x); 1120c0fea5dSIngo Weinhold #endif 1130c0fea5dSIngo Weinhold 1140c0fea5dSIngo Weinhold 1150c0fea5dSIngo Weinhold static void 1160c0fea5dSIngo Weinhold rld_unlock() 1170c0fea5dSIngo Weinhold { 1180c0fea5dSIngo Weinhold if (rld_sem_count-- == 1) { 1190c0fea5dSIngo Weinhold rld_sem_owner = -1; 1200c0fea5dSIngo Weinhold release_sem(rld_sem); 1210c0fea5dSIngo Weinhold } 1220c0fea5dSIngo Weinhold } 1230c0fea5dSIngo Weinhold 1240c0fea5dSIngo Weinhold 1250c0fea5dSIngo Weinhold static void 1260c0fea5dSIngo Weinhold rld_lock() 1270c0fea5dSIngo Weinhold { 1280c0fea5dSIngo Weinhold thread_id self = find_thread(NULL); 1290c0fea5dSIngo Weinhold if (self != rld_sem_owner) { 1300c0fea5dSIngo Weinhold acquire_sem(rld_sem); 1310c0fea5dSIngo Weinhold rld_sem_owner = self; 1320c0fea5dSIngo Weinhold } 1330c0fea5dSIngo Weinhold rld_sem_count++; 1340c0fea5dSIngo Weinhold } 1350c0fea5dSIngo Weinhold 1360c0fea5dSIngo Weinhold 1370c0fea5dSIngo Weinhold static void 1380c0fea5dSIngo Weinhold enqueue_image(image_queue_t *queue, image_t *image) 1390c0fea5dSIngo Weinhold { 1400c0fea5dSIngo Weinhold image->next = 0; 1410c0fea5dSIngo Weinhold 1420c0fea5dSIngo Weinhold image->prev = queue->tail; 1430c0fea5dSIngo Weinhold if (queue->tail) 1440c0fea5dSIngo Weinhold queue->tail->next = image; 1450c0fea5dSIngo Weinhold 1460c0fea5dSIngo Weinhold queue->tail = image; 1470c0fea5dSIngo Weinhold if (!queue->head) 1480c0fea5dSIngo Weinhold queue->head = image; 1490c0fea5dSIngo Weinhold } 1500c0fea5dSIngo Weinhold 1510c0fea5dSIngo Weinhold 1520c0fea5dSIngo Weinhold static void 1530c0fea5dSIngo Weinhold dequeue_image(image_queue_t *queue, image_t *image) 1540c0fea5dSIngo Weinhold { 1550c0fea5dSIngo Weinhold if (image->next) 1560c0fea5dSIngo Weinhold image->next->prev = image->prev; 1570c0fea5dSIngo Weinhold else 1580c0fea5dSIngo Weinhold queue->tail = image->prev; 1590c0fea5dSIngo Weinhold 1600c0fea5dSIngo Weinhold if (image->prev) 1610c0fea5dSIngo Weinhold image->prev->next = image->next; 1620c0fea5dSIngo Weinhold else 1630c0fea5dSIngo Weinhold queue->head = image->next; 1640c0fea5dSIngo Weinhold 1650c0fea5dSIngo Weinhold image->prev = 0; 1660c0fea5dSIngo Weinhold image->next = 0; 1670c0fea5dSIngo Weinhold } 1680c0fea5dSIngo Weinhold 1690c0fea5dSIngo Weinhold 1700c0fea5dSIngo Weinhold static uint32 1710c0fea5dSIngo Weinhold elf_hash(const uint8 *name) 1720c0fea5dSIngo Weinhold { 1730c0fea5dSIngo Weinhold uint32 hash = 0; 1740c0fea5dSIngo Weinhold uint32 temp; 1750c0fea5dSIngo Weinhold 1760c0fea5dSIngo Weinhold while (*name) { 1770c0fea5dSIngo Weinhold hash = (hash << 4) + *name++; 1780c0fea5dSIngo Weinhold if ((temp = hash & 0xf0000000)) { 1790c0fea5dSIngo Weinhold hash ^= temp >> 24; 1800c0fea5dSIngo Weinhold } 1810c0fea5dSIngo Weinhold hash &= ~temp; 1820c0fea5dSIngo Weinhold } 1830c0fea5dSIngo Weinhold return hash; 1840c0fea5dSIngo Weinhold } 1850c0fea5dSIngo Weinhold 1860c0fea5dSIngo Weinhold 1874bef3723SAxel Dörfler static inline bool 1884bef3723SAxel Dörfler report_errors() 1894bef3723SAxel Dörfler { 1904bef3723SAxel Dörfler return gProgramArgs->error_port >= 0; 1914bef3723SAxel Dörfler } 1924bef3723SAxel Dörfler 1934bef3723SAxel Dörfler 1940c0fea5dSIngo Weinhold static image_t * 1950c0fea5dSIngo Weinhold find_image_in_queue(image_queue_t *queue, const char *name, bool isPath, 1960c0fea5dSIngo Weinhold uint32 typeMask) 1970c0fea5dSIngo Weinhold { 1980c0fea5dSIngo Weinhold image_t *image; 1990c0fea5dSIngo Weinhold 2000c0fea5dSIngo Weinhold for (image = queue->head; image; image = image->next) { 2010c0fea5dSIngo Weinhold const char *imageName = isPath ? image->path : image->name; 2020c0fea5dSIngo Weinhold int length = isPath ? sizeof(image->path) : sizeof(image->name); 2030c0fea5dSIngo Weinhold 2040c0fea5dSIngo Weinhold if (!strncmp(imageName, name, length) 2050c0fea5dSIngo Weinhold && (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) { 2060c0fea5dSIngo Weinhold return image; 2070c0fea5dSIngo Weinhold } 2080c0fea5dSIngo Weinhold } 2090c0fea5dSIngo Weinhold 2100c0fea5dSIngo Weinhold return NULL; 2110c0fea5dSIngo Weinhold } 2120c0fea5dSIngo Weinhold 2130c0fea5dSIngo Weinhold 2140c0fea5dSIngo Weinhold static image_t * 2150c0fea5dSIngo Weinhold find_image(char const *name, uint32 typeMask) 2160c0fea5dSIngo Weinhold { 2170c0fea5dSIngo Weinhold bool isPath = (strchr(name, '/') != NULL); 21846f4d849SIngo Weinhold return find_image_in_queue(&sLoadedImages, name, isPath, typeMask); 2190c0fea5dSIngo Weinhold } 2200c0fea5dSIngo Weinhold 2210c0fea5dSIngo Weinhold 2220c0fea5dSIngo Weinhold static image_t * 2230c0fea5dSIngo Weinhold find_loaded_image_by_id(image_id id) 2240c0fea5dSIngo Weinhold { 2250c0fea5dSIngo Weinhold image_t *image; 2260c0fea5dSIngo Weinhold 2270c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image; image = image->next) { 2280c0fea5dSIngo Weinhold if (image->id == id) 2290c0fea5dSIngo Weinhold return image; 2300c0fea5dSIngo Weinhold } 2310c0fea5dSIngo Weinhold 2320c0fea5dSIngo Weinhold // For the termination routine, we need to look into the list of 2330c0fea5dSIngo Weinhold // disposable images as well 2340c0fea5dSIngo Weinhold for (image = sDisposableImages.head; image; image = image->next) { 2350c0fea5dSIngo Weinhold if (image->id == id) 2360c0fea5dSIngo Weinhold return image; 2370c0fea5dSIngo Weinhold } 2380c0fea5dSIngo Weinhold 2390c0fea5dSIngo Weinhold return NULL; 2400c0fea5dSIngo Weinhold } 2410c0fea5dSIngo Weinhold 2420c0fea5dSIngo Weinhold 2430c0fea5dSIngo Weinhold static status_t 2440c0fea5dSIngo Weinhold parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize, int32 *_sheaderSize) 2450c0fea5dSIngo Weinhold { 2460c0fea5dSIngo Weinhold if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) 2470c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 2480c0fea5dSIngo Weinhold 2490c0fea5dSIngo Weinhold if (eheader->e_ident[4] != ELFCLASS32) 2500c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 2510c0fea5dSIngo Weinhold 2520c0fea5dSIngo Weinhold if (eheader->e_phoff == 0) 2530c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 2540c0fea5dSIngo Weinhold 2550c0fea5dSIngo Weinhold if (eheader->e_phentsize < sizeof(struct Elf32_Phdr)) 2560c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 2570c0fea5dSIngo Weinhold 2580c0fea5dSIngo Weinhold *_pheaderSize = eheader->e_phentsize * eheader->e_phnum; 2590c0fea5dSIngo Weinhold *_sheaderSize = eheader->e_shentsize * eheader->e_shnum; 2600c0fea5dSIngo Weinhold 2615aa7b7b6SMarcus Overhagen if (*_pheaderSize <= 0 || *_sheaderSize <= 0) 2625aa7b7b6SMarcus Overhagen return B_NOT_AN_EXECUTABLE; 2635aa7b7b6SMarcus Overhagen 2645aa7b7b6SMarcus Overhagen return B_OK; 2650c0fea5dSIngo Weinhold } 2660c0fea5dSIngo Weinhold 2670c0fea5dSIngo Weinhold 2680c0fea5dSIngo Weinhold static int32 2690c0fea5dSIngo Weinhold count_regions(char const *buff, int phnum, int phentsize) 2700c0fea5dSIngo Weinhold { 2710c0fea5dSIngo Weinhold struct Elf32_Phdr *pheaders; 2720c0fea5dSIngo Weinhold int32 count = 0; 2730c0fea5dSIngo Weinhold int i; 2740c0fea5dSIngo Weinhold 2750c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 2760c0fea5dSIngo Weinhold pheaders = (struct Elf32_Phdr *)(buff + i * phentsize); 2770c0fea5dSIngo Weinhold 2780c0fea5dSIngo Weinhold switch (pheaders->p_type) { 2790c0fea5dSIngo Weinhold case PT_NULL: 2800c0fea5dSIngo Weinhold /* NOP header */ 2810c0fea5dSIngo Weinhold break; 2820c0fea5dSIngo Weinhold case PT_LOAD: 2830c0fea5dSIngo Weinhold count += 1; 2840c0fea5dSIngo Weinhold if (pheaders->p_memsz != pheaders->p_filesz) { 2850c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_memsz); 2860c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr + pheaders->p_filesz); 2870c0fea5dSIngo Weinhold 2880c0fea5dSIngo Weinhold if (A != B) 2890c0fea5dSIngo Weinhold count += 1; 2900c0fea5dSIngo Weinhold } 2910c0fea5dSIngo Weinhold break; 2920c0fea5dSIngo Weinhold case PT_DYNAMIC: 2930c0fea5dSIngo Weinhold /* will be handled at some other place */ 2940c0fea5dSIngo Weinhold break; 2950c0fea5dSIngo Weinhold case PT_INTERP: 2960c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 2970c0fea5dSIngo Weinhold break; 2980c0fea5dSIngo Weinhold case PT_NOTE: 2990c0fea5dSIngo Weinhold /* unsupported */ 3000c0fea5dSIngo Weinhold break; 3010c0fea5dSIngo Weinhold case PT_SHLIB: 3020c0fea5dSIngo Weinhold /* undefined semantics */ 3030c0fea5dSIngo Weinhold break; 3040c0fea5dSIngo Weinhold case PT_PHDR: 3050c0fea5dSIngo Weinhold /* we don't use it */ 3060c0fea5dSIngo Weinhold break; 3070c0fea5dSIngo Weinhold default: 3080c0fea5dSIngo Weinhold FATAL("unhandled pheader type 0x%lx\n", pheaders[i].p_type); 3090c0fea5dSIngo Weinhold return B_BAD_DATA; 3100c0fea5dSIngo Weinhold } 3110c0fea5dSIngo Weinhold } 3120c0fea5dSIngo Weinhold 3130c0fea5dSIngo Weinhold return count; 3140c0fea5dSIngo Weinhold } 3150c0fea5dSIngo Weinhold 3160c0fea5dSIngo Weinhold 3170c0fea5dSIngo Weinhold /* 3180c0fea5dSIngo Weinhold * create_image() & destroy_image() 3190c0fea5dSIngo Weinhold * 3200c0fea5dSIngo Weinhold * Create and destroy image_t structures. The destroyer makes sure that the 3210c0fea5dSIngo Weinhold * memory buffers are full of garbage before freeing. 3220c0fea5dSIngo Weinhold */ 3230c0fea5dSIngo Weinhold 3240c0fea5dSIngo Weinhold static image_t * 3250c0fea5dSIngo Weinhold create_image(const char *name, const char *path, int num_regions) 3260c0fea5dSIngo Weinhold { 3270c0fea5dSIngo Weinhold size_t allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t); 3280c0fea5dSIngo Weinhold const char *lastSlash; 3290c0fea5dSIngo Weinhold 3300c0fea5dSIngo Weinhold image_t *image = (image_t*)malloc(allocSize); 3310c0fea5dSIngo Weinhold if (image == NULL) { 3320c0fea5dSIngo Weinhold FATAL("no memory for image %s\n", path); 3330c0fea5dSIngo Weinhold return NULL; 3340c0fea5dSIngo Weinhold } 3350c0fea5dSIngo Weinhold 3360c0fea5dSIngo Weinhold memset(image, 0, allocSize); 3370c0fea5dSIngo Weinhold 3380c0fea5dSIngo Weinhold strlcpy(image->path, path, sizeof(image->path)); 3390c0fea5dSIngo Weinhold 3400c0fea5dSIngo Weinhold // Make the last component of the supplied name the image name. 3410c0fea5dSIngo Weinhold // If present, DT_SONAME will replace this name. 3420c0fea5dSIngo Weinhold if ((lastSlash = strrchr(name, '/'))) 3430c0fea5dSIngo Weinhold strlcpy(image->name, lastSlash + 1, sizeof(image->name)); 3440c0fea5dSIngo Weinhold else 3450c0fea5dSIngo Weinhold strlcpy(image->name, name, sizeof(image->name)); 3460c0fea5dSIngo Weinhold 3470c0fea5dSIngo Weinhold image->ref_count = 1; 3480c0fea5dSIngo Weinhold image->num_regions = num_regions; 3490c0fea5dSIngo Weinhold 3500c0fea5dSIngo Weinhold return image; 3510c0fea5dSIngo Weinhold } 3520c0fea5dSIngo Weinhold 3530c0fea5dSIngo Weinhold 3540c0fea5dSIngo Weinhold static void 3550c0fea5dSIngo Weinhold delete_image_struct(image_t *image) 3560c0fea5dSIngo Weinhold { 3570c0fea5dSIngo Weinhold #ifdef DEBUG 3580c0fea5dSIngo Weinhold size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t); 3590c0fea5dSIngo Weinhold memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed); 3600c0fea5dSIngo Weinhold #endif 3610c0fea5dSIngo Weinhold free(image->needed); 3620c0fea5dSIngo Weinhold 3630c0fea5dSIngo Weinhold #ifdef DEBUG 3640c0fea5dSIngo Weinhold memset(image, 0xa5, size); 3650c0fea5dSIngo Weinhold #endif 3660c0fea5dSIngo Weinhold free(image); 3670c0fea5dSIngo Weinhold } 3680c0fea5dSIngo Weinhold 3690c0fea5dSIngo Weinhold 3700c0fea5dSIngo Weinhold static void 3710c0fea5dSIngo Weinhold delete_image(image_t *image) 3720c0fea5dSIngo Weinhold { 3732760c4cdSAxel Dörfler if (image == NULL) 3742760c4cdSAxel Dörfler return; 3752760c4cdSAxel Dörfler 3760c0fea5dSIngo Weinhold _kern_unregister_image(image->id); 3770c0fea5dSIngo Weinhold // registered in load_container() 3780c0fea5dSIngo Weinhold 3790c0fea5dSIngo Weinhold delete_image_struct(image); 3800c0fea5dSIngo Weinhold } 3810c0fea5dSIngo Weinhold 3820c0fea5dSIngo Weinhold 3830c0fea5dSIngo Weinhold static status_t 3840c0fea5dSIngo Weinhold parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) 3850c0fea5dSIngo Weinhold { 3860c0fea5dSIngo Weinhold struct Elf32_Phdr *pheader; 3870c0fea5dSIngo Weinhold int regcount; 3880c0fea5dSIngo Weinhold int i; 3890c0fea5dSIngo Weinhold 3900c0fea5dSIngo Weinhold regcount = 0; 3910c0fea5dSIngo Weinhold for (i = 0; i < phnum; i++) { 3920c0fea5dSIngo Weinhold pheader = (struct Elf32_Phdr *)(buff + i * phentsize); 3930c0fea5dSIngo Weinhold 3940c0fea5dSIngo Weinhold switch (pheader->p_type) { 3950c0fea5dSIngo Weinhold case PT_NULL: 3960c0fea5dSIngo Weinhold /* NOP header */ 3970c0fea5dSIngo Weinhold break; 3980c0fea5dSIngo Weinhold case PT_LOAD: 3990c0fea5dSIngo Weinhold if (pheader->p_memsz == pheader->p_filesz) { 4000c0fea5dSIngo Weinhold /* 4010c0fea5dSIngo Weinhold * everything in one area 4020c0fea5dSIngo Weinhold */ 4030c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 4040c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz; 4050c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 4060c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz 4070c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 4080c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 4090c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 4100c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 4110c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 4120c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 4130c0fea5dSIngo Weinhold // this is a writable segment 4140c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 4150c0fea5dSIngo Weinhold } 4160c0fea5dSIngo Weinhold } else { 4170c0fea5dSIngo Weinhold /* 4180c0fea5dSIngo Weinhold * may require splitting 4190c0fea5dSIngo Weinhold */ 4200c0fea5dSIngo Weinhold addr_t A = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_memsz); 4210c0fea5dSIngo Weinhold addr_t B = TO_PAGE_SIZE(pheader->p_vaddr + pheader->p_filesz); 4220c0fea5dSIngo Weinhold 4230c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 4240c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_filesz; 4250c0fea5dSIngo Weinhold image->regions[regcount].vmstart = PAGE_BASE(pheader->p_vaddr); 4260c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_filesz 4270c0fea5dSIngo Weinhold + PAGE_OFFSET(pheader->p_vaddr)); 4280c0fea5dSIngo Weinhold image->regions[regcount].fdstart = pheader->p_offset; 4290c0fea5dSIngo Weinhold image->regions[regcount].fdsize = pheader->p_filesz; 4300c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 4310c0fea5dSIngo Weinhold image->regions[regcount].flags = 0; 4320c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 4330c0fea5dSIngo Weinhold // this is a writable segment 4340c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 4350c0fea5dSIngo Weinhold } 4360c0fea5dSIngo Weinhold 4370c0fea5dSIngo Weinhold if (A != B) { 4380c0fea5dSIngo Weinhold /* 4390c0fea5dSIngo Weinhold * yeah, it requires splitting 4400c0fea5dSIngo Weinhold */ 4410c0fea5dSIngo Weinhold regcount += 1; 4420c0fea5dSIngo Weinhold image->regions[regcount].start = pheader->p_vaddr; 4430c0fea5dSIngo Weinhold image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz; 4440c0fea5dSIngo Weinhold image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize; 4450c0fea5dSIngo Weinhold image->regions[regcount].vmsize = TO_PAGE_SIZE(pheader->p_memsz + PAGE_OFFSET(pheader->p_vaddr)) 4460c0fea5dSIngo Weinhold - image->regions[regcount-1].vmsize; 4470c0fea5dSIngo Weinhold image->regions[regcount].fdstart = 0; 4480c0fea5dSIngo Weinhold image->regions[regcount].fdsize = 0; 4490c0fea5dSIngo Weinhold image->regions[regcount].delta = 0; 4500c0fea5dSIngo Weinhold image->regions[regcount].flags = RFLAG_ANON; 4510c0fea5dSIngo Weinhold if (pheader->p_flags & PF_WRITE) { 4520c0fea5dSIngo Weinhold // this is a writable segment 4530c0fea5dSIngo Weinhold image->regions[regcount].flags |= RFLAG_RW; 4540c0fea5dSIngo Weinhold } 4550c0fea5dSIngo Weinhold } 4560c0fea5dSIngo Weinhold } 4570c0fea5dSIngo Weinhold regcount += 1; 4580c0fea5dSIngo Weinhold break; 4590c0fea5dSIngo Weinhold case PT_DYNAMIC: 4600c0fea5dSIngo Weinhold image->dynamic_ptr = pheader->p_vaddr; 4610c0fea5dSIngo Weinhold break; 4620c0fea5dSIngo Weinhold case PT_INTERP: 4630c0fea5dSIngo Weinhold /* should check here for appropiate interpreter */ 4640c0fea5dSIngo Weinhold break; 4650c0fea5dSIngo Weinhold case PT_NOTE: 4660c0fea5dSIngo Weinhold /* unsupported */ 4670c0fea5dSIngo Weinhold break; 4680c0fea5dSIngo Weinhold case PT_SHLIB: 4690c0fea5dSIngo Weinhold /* undefined semantics */ 4700c0fea5dSIngo Weinhold break; 4710c0fea5dSIngo Weinhold case PT_PHDR: 4720c0fea5dSIngo Weinhold /* we don't use it */ 4730c0fea5dSIngo Weinhold break; 4740c0fea5dSIngo Weinhold default: 4750c0fea5dSIngo Weinhold FATAL("unhandled pheader type 0x%lx\n", pheader[i].p_type); 4760c0fea5dSIngo Weinhold return B_BAD_DATA; 4770c0fea5dSIngo Weinhold } 4780c0fea5dSIngo Weinhold } 4790c0fea5dSIngo Weinhold 4800c0fea5dSIngo Weinhold return B_OK; 4810c0fea5dSIngo Weinhold } 4820c0fea5dSIngo Weinhold 4830c0fea5dSIngo Weinhold 4840c0fea5dSIngo Weinhold static bool 4850c0fea5dSIngo Weinhold assert_dynamic_loadable(image_t *image) 4860c0fea5dSIngo Weinhold { 4870c0fea5dSIngo Weinhold uint32 i; 4880c0fea5dSIngo Weinhold 4890c0fea5dSIngo Weinhold if (!image->dynamic_ptr) 4900c0fea5dSIngo Weinhold return true; 4910c0fea5dSIngo Weinhold 4920c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 4930c0fea5dSIngo Weinhold if (image->dynamic_ptr >= image->regions[i].start 4940c0fea5dSIngo Weinhold && image->dynamic_ptr < image->regions[i].start + image->regions[i].size) 4950c0fea5dSIngo Weinhold return true; 4960c0fea5dSIngo Weinhold } 4970c0fea5dSIngo Weinhold 4980c0fea5dSIngo Weinhold return false; 4990c0fea5dSIngo Weinhold } 5000c0fea5dSIngo Weinhold 5010c0fea5dSIngo Weinhold 5020c0fea5dSIngo Weinhold /** This function will change the protection of all read-only segments 5030c0fea5dSIngo Weinhold * to really be read-only. 5040c0fea5dSIngo Weinhold * The areas have to be read/write first, so that they can be relocated. 5050c0fea5dSIngo Weinhold */ 5060c0fea5dSIngo Weinhold 5070c0fea5dSIngo Weinhold static void 5080c0fea5dSIngo Weinhold remap_images(void) 5090c0fea5dSIngo Weinhold { 5100c0fea5dSIngo Weinhold image_t *image; 5110c0fea5dSIngo Weinhold uint32 i; 5120c0fea5dSIngo Weinhold 5130c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image != NULL; image = image->next) { 5140c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 5150c0fea5dSIngo Weinhold if ((image->regions[i].flags & RFLAG_RW) == 0 5160c0fea5dSIngo Weinhold && (image->regions[i].flags & RFLAG_REMAPPED) == 0) { 5170c0fea5dSIngo Weinhold // we only need to do this once, so we remember those we've already mapped 5180c0fea5dSIngo Weinhold if (_kern_set_area_protection(image->regions[i].id, 5190c0fea5dSIngo Weinhold B_READ_AREA | B_EXECUTE_AREA) == B_OK) 5200c0fea5dSIngo Weinhold image->regions[i].flags |= RFLAG_REMAPPED; 5210c0fea5dSIngo Weinhold } 5220c0fea5dSIngo Weinhold } 5230c0fea5dSIngo Weinhold } 5240c0fea5dSIngo Weinhold } 5250c0fea5dSIngo Weinhold 5260c0fea5dSIngo Weinhold 5270c0fea5dSIngo Weinhold static status_t 5280c0fea5dSIngo Weinhold map_image(int fd, char const *path, image_t *image, bool fixed) 5290c0fea5dSIngo Weinhold { 5300c0fea5dSIngo Weinhold status_t status = B_OK; 5310c0fea5dSIngo Weinhold const char *baseName; 5320c0fea5dSIngo Weinhold uint32 i; 5330c0fea5dSIngo Weinhold 5340c0fea5dSIngo Weinhold (void)(fd); 5350c0fea5dSIngo Weinhold 5360c0fea5dSIngo Weinhold // cut the file name from the path as base name for the created areas 5370c0fea5dSIngo Weinhold baseName = strrchr(path, '/'); 5380c0fea5dSIngo Weinhold if (baseName != NULL) 5390c0fea5dSIngo Weinhold baseName++; 5400c0fea5dSIngo Weinhold else 5410c0fea5dSIngo Weinhold baseName = path; 5420c0fea5dSIngo Weinhold 5430c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 5440c0fea5dSIngo Weinhold char regionName[B_OS_NAME_LENGTH]; 5450c0fea5dSIngo Weinhold addr_t loadAddress; 5460c0fea5dSIngo Weinhold uint32 addressSpecifier; 5470c0fea5dSIngo Weinhold 5480c0fea5dSIngo Weinhold // for BeOS compatibility: if we load an old BeOS executable, we 5490c0fea5dSIngo Weinhold // have to relocate it, if possible - we recognize it because the 5500c0fea5dSIngo Weinhold // vmstart is set to 0 (hopefully always) 5510c0fea5dSIngo Weinhold if (fixed && image->regions[i].vmstart == 0) 5520c0fea5dSIngo Weinhold fixed = false; 5530c0fea5dSIngo Weinhold 5540c0fea5dSIngo Weinhold snprintf(regionName, sizeof(regionName), "%s_seg%lu%s", 5550c0fea5dSIngo Weinhold baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro"); 5560c0fea5dSIngo Weinhold 5570c0fea5dSIngo Weinhold if (image->dynamic_ptr && !fixed) { 5580c0fea5dSIngo Weinhold // relocatable image... we can afford to place wherever 5590c0fea5dSIngo Weinhold if (i == 0) { 5600c0fea5dSIngo Weinhold // but only the first segment gets a free ride 5610c0fea5dSIngo Weinhold loadAddress = RLD_PROGRAM_BASE; 5620c0fea5dSIngo Weinhold addressSpecifier = B_BASE_ADDRESS; 5630c0fea5dSIngo Weinhold } else { 5640c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart + image->regions[i-1].delta; 5650c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 5660c0fea5dSIngo Weinhold } 5670c0fea5dSIngo Weinhold } else { 5680c0fea5dSIngo Weinhold // not relocatable, put it where it asks or die trying 5690c0fea5dSIngo Weinhold loadAddress = image->regions[i].vmstart; 5700c0fea5dSIngo Weinhold addressSpecifier = B_EXACT_ADDRESS; 5710c0fea5dSIngo Weinhold } 5720c0fea5dSIngo Weinhold 5730c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_ANON) { 5740c0fea5dSIngo Weinhold image->regions[i].id = _kern_create_area(regionName, (void **)&loadAddress, 5750c0fea5dSIngo Weinhold addressSpecifier, image->regions[i].vmsize, B_NO_LOCK, 5760c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 5770c0fea5dSIngo Weinhold 5780c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 5790c0fea5dSIngo Weinhold status = image->regions[i].id; 5800c0fea5dSIngo Weinhold goto error; 5810c0fea5dSIngo Weinhold } 5820c0fea5dSIngo Weinhold 5830c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 5840c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 5850c0fea5dSIngo Weinhold } else { 5860c0fea5dSIngo Weinhold image->regions[i].id = sys_vm_map_file(regionName, (void **)&loadAddress, 5870c0fea5dSIngo Weinhold addressSpecifier, image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA, 5880c0fea5dSIngo Weinhold REGION_PRIVATE_MAP, path, PAGE_BASE(image->regions[i].fdstart)); 5890c0fea5dSIngo Weinhold 5900c0fea5dSIngo Weinhold if (image->regions[i].id < 0) { 5910c0fea5dSIngo Weinhold status = image->regions[i].id; 5920c0fea5dSIngo Weinhold goto error; 5930c0fea5dSIngo Weinhold } 5940c0fea5dSIngo Weinhold 5950c0fea5dSIngo Weinhold TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path, 5960c0fea5dSIngo Weinhold (void *)loadAddress, image->regions[i].vmsize, 5970c0fea5dSIngo Weinhold image->regions[i].flags & RFLAG_RW ? "rw" : "read-only")); 5980c0fea5dSIngo Weinhold 5990c0fea5dSIngo Weinhold image->regions[i].delta = loadAddress - image->regions[i].vmstart; 6000c0fea5dSIngo Weinhold image->regions[i].vmstart = loadAddress; 6010c0fea5dSIngo Weinhold 6020c0fea5dSIngo Weinhold // handle trailer bits in data segment 6030c0fea5dSIngo Weinhold if (image->regions[i].flags & RFLAG_RW) { 6040c0fea5dSIngo Weinhold addr_t startClearing; 6050c0fea5dSIngo Weinhold addr_t toClear; 6060c0fea5dSIngo Weinhold 6070c0fea5dSIngo Weinhold startClearing = image->regions[i].vmstart 6080c0fea5dSIngo Weinhold + PAGE_OFFSET(image->regions[i].start) 6090c0fea5dSIngo Weinhold + image->regions[i].size; 6100c0fea5dSIngo Weinhold toClear = image->regions[i].vmsize 6110c0fea5dSIngo Weinhold - PAGE_OFFSET(image->regions[i].start) 6120c0fea5dSIngo Weinhold - image->regions[i].size; 6130c0fea5dSIngo Weinhold 6140c0fea5dSIngo Weinhold TRACE(("cleared 0x%lx and the following 0x%lx bytes\n", startClearing, toClear)); 6150c0fea5dSIngo Weinhold memset((void *)startClearing, 0, toClear); 6160c0fea5dSIngo Weinhold } 6170c0fea5dSIngo Weinhold } 6180c0fea5dSIngo Weinhold } 6190c0fea5dSIngo Weinhold 6200c0fea5dSIngo Weinhold if (image->dynamic_ptr) 6210c0fea5dSIngo Weinhold image->dynamic_ptr += image->regions[0].delta; 6220c0fea5dSIngo Weinhold 6230c0fea5dSIngo Weinhold return B_OK; 6240c0fea5dSIngo Weinhold 6250c0fea5dSIngo Weinhold error: 6260c0fea5dSIngo Weinhold return status; 6270c0fea5dSIngo Weinhold } 6280c0fea5dSIngo Weinhold 6290c0fea5dSIngo Weinhold 6300c0fea5dSIngo Weinhold static void 6310c0fea5dSIngo Weinhold unmap_image(image_t *image) 6320c0fea5dSIngo Weinhold { 6330c0fea5dSIngo Weinhold uint32 i; 6340c0fea5dSIngo Weinhold 6350c0fea5dSIngo Weinhold for (i = 0; i < image->num_regions; i++) { 6360c0fea5dSIngo Weinhold _kern_delete_area(image->regions[i].id); 6370c0fea5dSIngo Weinhold 6380c0fea5dSIngo Weinhold image->regions[i].id = -1; 6390c0fea5dSIngo Weinhold } 6400c0fea5dSIngo Weinhold } 6410c0fea5dSIngo Weinhold 6420c0fea5dSIngo Weinhold 6430c0fea5dSIngo Weinhold static bool 6440c0fea5dSIngo Weinhold parse_dynamic_segment(image_t *image) 6450c0fea5dSIngo Weinhold { 6460c0fea5dSIngo Weinhold struct Elf32_Dyn *d; 6470c0fea5dSIngo Weinhold int i; 6480c0fea5dSIngo Weinhold int sonameOffset = -1; 6490c0fea5dSIngo Weinhold 6500c0fea5dSIngo Weinhold image->symhash = 0; 6510c0fea5dSIngo Weinhold image->syms = 0; 6520c0fea5dSIngo Weinhold image->strtab = 0; 6530c0fea5dSIngo Weinhold 6540c0fea5dSIngo Weinhold d = (struct Elf32_Dyn *)image->dynamic_ptr; 6550c0fea5dSIngo Weinhold if (!d) 6560c0fea5dSIngo Weinhold return true; 6570c0fea5dSIngo Weinhold 6580c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 6590c0fea5dSIngo Weinhold switch (d[i].d_tag) { 6600c0fea5dSIngo Weinhold case DT_NEEDED: 6610c0fea5dSIngo Weinhold image->num_needed += 1; 6620c0fea5dSIngo Weinhold break; 6630c0fea5dSIngo Weinhold case DT_HASH: 6640c0fea5dSIngo Weinhold image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta); 6650c0fea5dSIngo Weinhold break; 6660c0fea5dSIngo Weinhold case DT_STRTAB: 6670c0fea5dSIngo Weinhold image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta); 6680c0fea5dSIngo Weinhold break; 6690c0fea5dSIngo Weinhold case DT_SYMTAB: 6700c0fea5dSIngo Weinhold image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta); 6710c0fea5dSIngo Weinhold break; 6720c0fea5dSIngo Weinhold case DT_REL: 6730c0fea5dSIngo Weinhold image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 6740c0fea5dSIngo Weinhold break; 6750c0fea5dSIngo Weinhold case DT_RELSZ: 6760c0fea5dSIngo Weinhold image->rel_len = d[i].d_un.d_val; 6770c0fea5dSIngo Weinhold break; 6780c0fea5dSIngo Weinhold case DT_RELA: 6790c0fea5dSIngo Weinhold image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta); 6800c0fea5dSIngo Weinhold break; 6810c0fea5dSIngo Weinhold case DT_RELASZ: 6820c0fea5dSIngo Weinhold image->rela_len = d[i].d_un.d_val; 6830c0fea5dSIngo Weinhold break; 6840c0fea5dSIngo Weinhold // TK: procedure linkage table 6850c0fea5dSIngo Weinhold case DT_JMPREL: 6860c0fea5dSIngo Weinhold image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); 6870c0fea5dSIngo Weinhold break; 6880c0fea5dSIngo Weinhold case DT_PLTRELSZ: 6890c0fea5dSIngo Weinhold image->pltrel_len = d[i].d_un.d_val; 6900c0fea5dSIngo Weinhold break; 6910c0fea5dSIngo Weinhold case DT_INIT: 6920c0fea5dSIngo Weinhold image->init_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 6930c0fea5dSIngo Weinhold break; 6940c0fea5dSIngo Weinhold case DT_FINI: 6950c0fea5dSIngo Weinhold image->term_routine = (d[i].d_un.d_ptr + image->regions[0].delta); 6960c0fea5dSIngo Weinhold break; 6970c0fea5dSIngo Weinhold case DT_SONAME: 6980c0fea5dSIngo Weinhold sonameOffset = d[i].d_un.d_val; 6990c0fea5dSIngo Weinhold break; 7000c0fea5dSIngo Weinhold default: 7010c0fea5dSIngo Weinhold continue; 7020c0fea5dSIngo Weinhold } 7030c0fea5dSIngo Weinhold } 7040c0fea5dSIngo Weinhold 7050c0fea5dSIngo Weinhold // lets make sure we found all the required sections 7060c0fea5dSIngo Weinhold if (!image->symhash || !image->syms || !image->strtab) 7070c0fea5dSIngo Weinhold return false; 7080c0fea5dSIngo Weinhold 7090c0fea5dSIngo Weinhold if (sonameOffset >= 0) 7100c0fea5dSIngo Weinhold strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name)); 7110c0fea5dSIngo Weinhold 7120c0fea5dSIngo Weinhold return true; 7130c0fea5dSIngo Weinhold } 7140c0fea5dSIngo Weinhold 7150c0fea5dSIngo Weinhold 7160c0fea5dSIngo Weinhold static struct Elf32_Sym * 7170c0fea5dSIngo Weinhold find_symbol(image_t *image, const char *name, int32 type) 7180c0fea5dSIngo Weinhold { 7190c0fea5dSIngo Weinhold uint32 hash, i; 7200c0fea5dSIngo Weinhold 7210c0fea5dSIngo Weinhold // ToDo: "type" is currently ignored! 7220c0fea5dSIngo Weinhold (void)type; 7230c0fea5dSIngo Weinhold 7240c0fea5dSIngo Weinhold if (image->dynamic_ptr == NULL) 7250c0fea5dSIngo Weinhold return NULL; 7260c0fea5dSIngo Weinhold 7270c0fea5dSIngo Weinhold hash = elf_hash((uint8 *)name) % HASHTABSIZE(image); 7280c0fea5dSIngo Weinhold 7290c0fea5dSIngo Weinhold for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) { 7300c0fea5dSIngo Weinhold struct Elf32_Sym *symbol = &image->syms[i]; 7310c0fea5dSIngo Weinhold 7320c0fea5dSIngo Weinhold if (symbol->st_shndx != SHN_UNDEF 7330c0fea5dSIngo Weinhold && ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL) 7340c0fea5dSIngo Weinhold || (ELF32_ST_BIND(symbol->st_info) == STB_WEAK)) 7350c0fea5dSIngo Weinhold && !strcmp(SYMNAME(image, symbol), name)) { 7360c0fea5dSIngo Weinhold // check if the type matches 7370c0fea5dSIngo Weinhold if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC) 7380c0fea5dSIngo Weinhold || (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)) 7390c0fea5dSIngo Weinhold continue; 7400c0fea5dSIngo Weinhold 7410c0fea5dSIngo Weinhold return symbol; 7420c0fea5dSIngo Weinhold } 7430c0fea5dSIngo Weinhold } 7440c0fea5dSIngo Weinhold 7450c0fea5dSIngo Weinhold return NULL; 7460c0fea5dSIngo Weinhold } 7470c0fea5dSIngo Weinhold 7480c0fea5dSIngo Weinhold 7490c0fea5dSIngo Weinhold static struct Elf32_Sym* 75046f4d849SIngo Weinhold find_symbol_recursively_impl(image_t* image, const char* name, 75146f4d849SIngo Weinhold image_t** foundInImage) 7520c0fea5dSIngo Weinhold { 75346f4d849SIngo Weinhold image->flags |= RFLAG_VISITED; 7540c0fea5dSIngo Weinhold 7550c0fea5dSIngo Weinhold struct Elf32_Sym *symbol; 7560c0fea5dSIngo Weinhold 75746f4d849SIngo Weinhold // look up the symbol in this image 75846f4d849SIngo Weinhold if (image->dynamic_ptr) { 7590c0fea5dSIngo Weinhold symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY); 7600c0fea5dSIngo Weinhold if (symbol) { 76146f4d849SIngo Weinhold *foundInImage = image; 76246f4d849SIngo Weinhold return symbol; 76346f4d849SIngo Weinhold } 76446f4d849SIngo Weinhold } 76546f4d849SIngo Weinhold 76646f4d849SIngo Weinhold // recursively search dependencies 76746f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 76846f4d849SIngo Weinhold if (!(image->needed[i]->flags & RFLAG_VISITED)) { 76946f4d849SIngo Weinhold symbol = find_symbol_recursively_impl(image->needed[i], name, 77046f4d849SIngo Weinhold foundInImage); 77146f4d849SIngo Weinhold if (symbol) 7720c0fea5dSIngo Weinhold return symbol; 7730c0fea5dSIngo Weinhold } 7740c0fea5dSIngo Weinhold } 7750c0fea5dSIngo Weinhold 7760c0fea5dSIngo Weinhold return NULL; 7770c0fea5dSIngo Weinhold } 7780c0fea5dSIngo Weinhold 7790c0fea5dSIngo Weinhold 78046f4d849SIngo Weinhold static void 78146f4d849SIngo Weinhold clear_image_flag_recursively(image_t* image, uint32 flag) 78246f4d849SIngo Weinhold { 78346f4d849SIngo Weinhold image->flags &= ~flag; 78446f4d849SIngo Weinhold 78546f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 78646f4d849SIngo Weinhold if (image->needed[i]->flags & flag) 78746f4d849SIngo Weinhold clear_image_flag_recursively(image->needed[i], flag); 78846f4d849SIngo Weinhold } 78946f4d849SIngo Weinhold } 79046f4d849SIngo Weinhold 79146f4d849SIngo Weinhold 79246f4d849SIngo Weinhold static struct Elf32_Sym* 79346f4d849SIngo Weinhold find_symbol_recursively(image_t* image, const char* name, 79446f4d849SIngo Weinhold image_t** foundInImage) 79546f4d849SIngo Weinhold { 79646f4d849SIngo Weinhold struct Elf32_Sym* symbol = find_symbol_recursively_impl(image, name, 79746f4d849SIngo Weinhold foundInImage); 79846f4d849SIngo Weinhold clear_image_flag_recursively(image, RFLAG_VISITED); 79946f4d849SIngo Weinhold return symbol; 80046f4d849SIngo Weinhold } 80146f4d849SIngo Weinhold 80246f4d849SIngo Weinhold 80346f4d849SIngo Weinhold static struct Elf32_Sym* 80446f4d849SIngo Weinhold find_symbol_in_loaded_images(const char* name, image_t** foundInImage) 80546f4d849SIngo Weinhold { 80646f4d849SIngo Weinhold return find_symbol_recursively(sLoadedImages.head, name, foundInImage); 80746f4d849SIngo Weinhold } 80846f4d849SIngo Weinhold 80946f4d849SIngo Weinhold 81046f4d849SIngo Weinhold static struct Elf32_Sym* 81146f4d849SIngo Weinhold find_undefined_symbol(image_t* rootImage, image_t* image, const char* name, 81246f4d849SIngo Weinhold image_t** foundInImage) 81346f4d849SIngo Weinhold { 81446f4d849SIngo Weinhold // If not simulating BeOS style symbol resolution, undefined symbols are 81546f4d849SIngo Weinhold // search recursively starting from the root image. (Note, breadth first 81646f4d849SIngo Weinhold // might be better than the depth first use here.) 81746f4d849SIngo Weinhold if (!sResolveSymbolsBeOSStyle) 81846f4d849SIngo Weinhold return find_symbol_recursively(rootImage, name, foundInImage); 81946f4d849SIngo Weinhold 82046f4d849SIngo Weinhold // BeOS style symbol resolution: It is sufficient to check the direct 82146f4d849SIngo Weinhold // dependencies. The linker would have complained, if the symbol wasn't 82246f4d849SIngo Weinhold // there. 82346f4d849SIngo Weinhold for (uint32 i = 0; i < image->num_needed; i++) { 82446f4d849SIngo Weinhold if (image->needed[i]->dynamic_ptr) { 82546f4d849SIngo Weinhold struct Elf32_Sym *symbol = find_symbol(image->needed[i], name, 82646f4d849SIngo Weinhold B_SYMBOL_TYPE_ANY); 82746f4d849SIngo Weinhold if (symbol) { 82846f4d849SIngo Weinhold *foundInImage = image->needed[i]; 82946f4d849SIngo Weinhold return symbol; 83046f4d849SIngo Weinhold } 83146f4d849SIngo Weinhold } 83246f4d849SIngo Weinhold } 83346f4d849SIngo Weinhold 83446f4d849SIngo Weinhold return NULL; 83546f4d849SIngo Weinhold } 83646f4d849SIngo Weinhold 83746f4d849SIngo Weinhold 8380c0fea5dSIngo Weinhold int 83946f4d849SIngo Weinhold resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym, 84046f4d849SIngo Weinhold addr_t *sym_addr) 8410c0fea5dSIngo Weinhold { 8420c0fea5dSIngo Weinhold struct Elf32_Sym *sym2; 8430c0fea5dSIngo Weinhold char *symname; 8440c0fea5dSIngo Weinhold image_t *shimg; 8450c0fea5dSIngo Weinhold 8460c0fea5dSIngo Weinhold switch (sym->st_shndx) { 8470c0fea5dSIngo Weinhold case SHN_UNDEF: 8480c0fea5dSIngo Weinhold // patch the symbol name 8490c0fea5dSIngo Weinhold symname = SYMNAME(image, sym); 8500c0fea5dSIngo Weinhold 85146f4d849SIngo Weinhold // it's undefined, must be outside this image, try the other images 85246f4d849SIngo Weinhold sym2 = find_undefined_symbol(rootImage, image, symname, &shimg); 8530c0fea5dSIngo Weinhold if (!sym2) { 8540c0fea5dSIngo Weinhold printf("elf_resolve_symbol: could not resolve symbol '%s'\n", symname); 8550c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 8560c0fea5dSIngo Weinhold } 8570c0fea5dSIngo Weinhold 8580c0fea5dSIngo Weinhold // make sure they're the same type 8590c0fea5dSIngo Weinhold if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE 8600c0fea5dSIngo Weinhold && ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) { 8610c0fea5dSIngo Weinhold printf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", symname); 8620c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 8630c0fea5dSIngo Weinhold } 8640c0fea5dSIngo Weinhold 8650c0fea5dSIngo Weinhold if (ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL 8660c0fea5dSIngo Weinhold && ELF32_ST_BIND(sym2->st_info) != STB_WEAK) { 8670c0fea5dSIngo Weinhold printf("elf_resolve_symbol: found symbol '%s' but not exported\n", symname); 8680c0fea5dSIngo Weinhold return B_MISSING_SYMBOL; 8690c0fea5dSIngo Weinhold } 8700c0fea5dSIngo Weinhold 8710c0fea5dSIngo Weinhold *sym_addr = sym2->st_value + shimg->regions[0].delta; 8720c0fea5dSIngo Weinhold return B_NO_ERROR; 8730c0fea5dSIngo Weinhold 8740c0fea5dSIngo Weinhold case SHN_ABS: 8750c0fea5dSIngo Weinhold *sym_addr = sym->st_value + image->regions[0].delta; 8760c0fea5dSIngo Weinhold return B_NO_ERROR; 8770c0fea5dSIngo Weinhold 8780c0fea5dSIngo Weinhold case SHN_COMMON: 8790c0fea5dSIngo Weinhold // ToDo: finish this 8800c0fea5dSIngo Weinhold printf("elf_resolve_symbol: COMMON symbol, finish me!\n"); 8810c0fea5dSIngo Weinhold return B_ERROR; //ERR_NOT_IMPLEMENTED_YET; 8820c0fea5dSIngo Weinhold 8830c0fea5dSIngo Weinhold default: 8840c0fea5dSIngo Weinhold // standard symbol 8850c0fea5dSIngo Weinhold *sym_addr = sym->st_value + image->regions[0].delta; 8860c0fea5dSIngo Weinhold return B_NO_ERROR; 8870c0fea5dSIngo Weinhold } 8880c0fea5dSIngo Weinhold } 8890c0fea5dSIngo Weinhold 8900c0fea5dSIngo Weinhold 8910c0fea5dSIngo Weinhold static void 8920c0fea5dSIngo Weinhold register_image(image_t *image, int fd, const char *path) 8930c0fea5dSIngo Weinhold { 8940c0fea5dSIngo Weinhold struct stat stat; 8950c0fea5dSIngo Weinhold image_info info; 8960c0fea5dSIngo Weinhold 8970c0fea5dSIngo Weinhold // ToDo: set these correctly 8980c0fea5dSIngo Weinhold info.id = 0; 8990c0fea5dSIngo Weinhold info.type = image->type; 9000c0fea5dSIngo Weinhold info.sequence = 0; 9010c0fea5dSIngo Weinhold info.init_order = 0; 9020c0fea5dSIngo Weinhold info.init_routine = (void (*)())image->init_routine; 9030c0fea5dSIngo Weinhold info.term_routine = (void (*)())image->term_routine; 9040c0fea5dSIngo Weinhold 9050c0fea5dSIngo Weinhold if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) { 9060c0fea5dSIngo Weinhold info.device = stat.st_dev; 9070c0fea5dSIngo Weinhold info.node = stat.st_ino; 9080c0fea5dSIngo Weinhold } else { 9090c0fea5dSIngo Weinhold info.device = -1; 9100c0fea5dSIngo Weinhold info.node = -1; 9110c0fea5dSIngo Weinhold } 9120c0fea5dSIngo Weinhold 9130c0fea5dSIngo Weinhold strlcpy(info.name, path, sizeof(info.name)); 9140c0fea5dSIngo Weinhold info.text = (void *)image->regions[0].vmstart; 9150c0fea5dSIngo Weinhold info.text_size = image->regions[0].vmsize; 9160c0fea5dSIngo Weinhold info.data = (void *)image->regions[1].vmstart; 9170c0fea5dSIngo Weinhold info.data_size = image->regions[1].vmsize; 9180c0fea5dSIngo Weinhold image->id = _kern_register_image(&info, sizeof(image_info)); 9190c0fea5dSIngo Weinhold } 9200c0fea5dSIngo Weinhold 9210c0fea5dSIngo Weinhold 9220c0fea5dSIngo Weinhold static status_t 92346f4d849SIngo Weinhold relocate_image(image_t *rootImage, image_t *image) 9240c0fea5dSIngo Weinhold { 92546f4d849SIngo Weinhold status_t status = arch_relocate_image(rootImage, image); 9260c0fea5dSIngo Weinhold if (status < B_OK) { 92746f4d849SIngo Weinhold FATAL("troubles relocating: 0x%lx (image: %s)\n", status, image->name); 9280c0fea5dSIngo Weinhold return status; 9290c0fea5dSIngo Weinhold } 9300c0fea5dSIngo Weinhold 9310c0fea5dSIngo Weinhold _kern_image_relocated(image->id); 9320c0fea5dSIngo Weinhold return B_OK; 9330c0fea5dSIngo Weinhold } 9340c0fea5dSIngo Weinhold 9350c0fea5dSIngo Weinhold 9360c0fea5dSIngo Weinhold static status_t 9370c0fea5dSIngo Weinhold load_container(char const *name, image_type type, const char *rpath, image_t **_image) 9380c0fea5dSIngo Weinhold { 9390c0fea5dSIngo Weinhold int32 pheaderSize, sheaderSize; 9400c0fea5dSIngo Weinhold char path[PATH_MAX]; 9410c0fea5dSIngo Weinhold ssize_t length; 9420c0fea5dSIngo Weinhold char ph_buff[4096]; 9430c0fea5dSIngo Weinhold int32 numRegions; 9440c0fea5dSIngo Weinhold image_t *found; 9450c0fea5dSIngo Weinhold image_t *image; 9460c0fea5dSIngo Weinhold status_t status; 9470c0fea5dSIngo Weinhold int fd; 9480c0fea5dSIngo Weinhold 9490c0fea5dSIngo Weinhold struct Elf32_Ehdr eheader; 9500c0fea5dSIngo Weinhold 9510c0fea5dSIngo Weinhold // Have we already loaded that image? Don't check for add-ons -- we always 9520c0fea5dSIngo Weinhold // reload them. 9530c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 9540c0fea5dSIngo Weinhold found = find_image(name, APP_OR_LIBRARY_TYPE); 9550c0fea5dSIngo Weinhold if (found) { 9560c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 9570c0fea5dSIngo Weinhold *_image = found; 9580c0fea5dSIngo Weinhold return B_OK; 9590c0fea5dSIngo Weinhold } 9600c0fea5dSIngo Weinhold } 9610c0fea5dSIngo Weinhold 9620c0fea5dSIngo Weinhold strlcpy(path, name, sizeof(path)); 9630c0fea5dSIngo Weinhold 9640c0fea5dSIngo Weinhold // Try to load explicit image path first 9650c0fea5dSIngo Weinhold fd = open_executable(path, type, rpath); 9660c0fea5dSIngo Weinhold if (fd < 0) { 9670c0fea5dSIngo Weinhold FATAL("cannot open file %s\n", path); 9680c0fea5dSIngo Weinhold return fd; 9690c0fea5dSIngo Weinhold } 9700c0fea5dSIngo Weinhold 9710c0fea5dSIngo Weinhold // If the path is not absolute, we prepend the CWD to make it one. 9720c0fea5dSIngo Weinhold if (path[0] != '/') { 9730c0fea5dSIngo Weinhold char relativePath[PATH_MAX]; 9740c0fea5dSIngo Weinhold if (!strncmp(path, "./", 2)) 9750c0fea5dSIngo Weinhold strcpy(relativePath, path + 2); 9760c0fea5dSIngo Weinhold else 9770c0fea5dSIngo Weinhold strcpy(relativePath, path); 9780c0fea5dSIngo Weinhold 9790c0fea5dSIngo Weinhold // get the CWD 9800c0fea5dSIngo Weinhold status = _kern_getcwd(path, sizeof(path)); 9810c0fea5dSIngo Weinhold if (status < B_OK) { 9820c0fea5dSIngo Weinhold FATAL("_kern_getcwd() failed\n"); 9830c0fea5dSIngo Weinhold goto err1; 9840c0fea5dSIngo Weinhold } 9850c0fea5dSIngo Weinhold 9860c0fea5dSIngo Weinhold if (strlcat(path, "/", sizeof(path)) >= sizeof(path) 9870c0fea5dSIngo Weinhold || strlcat(path, relativePath, sizeof(path)) >= sizeof(path)) { 9880c0fea5dSIngo Weinhold status = B_NAME_TOO_LONG; 9890c0fea5dSIngo Weinhold FATAL("Absolute path of image %s is too " 9900c0fea5dSIngo Weinhold "long!\n", relativePath); 9910c0fea5dSIngo Weinhold goto err1; 9920c0fea5dSIngo Weinhold } 9930c0fea5dSIngo Weinhold } 9940c0fea5dSIngo Weinhold 9950c0fea5dSIngo Weinhold // Test again if this image has been registered already - this time, 9960c0fea5dSIngo Weinhold // we can check the full path, not just its name as noted. 9970c0fea5dSIngo Weinhold // You could end up loading an image twice with symbolic links, else. 9980c0fea5dSIngo Weinhold if (type != B_ADD_ON_IMAGE) { 9990c0fea5dSIngo Weinhold found = find_image(path, APP_OR_LIBRARY_TYPE); 10000c0fea5dSIngo Weinhold if (found) { 10010c0fea5dSIngo Weinhold atomic_add(&found->ref_count, 1); 10020c0fea5dSIngo Weinhold *_image = found; 10030c0fea5dSIngo Weinhold return B_OK; 10040c0fea5dSIngo Weinhold } 10050c0fea5dSIngo Weinhold } 10060c0fea5dSIngo Weinhold 10070c0fea5dSIngo Weinhold length = _kern_read(fd, 0, &eheader, sizeof(eheader)); 10080c0fea5dSIngo Weinhold if (length != sizeof(eheader)) { 10090c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 10100c0fea5dSIngo Weinhold FATAL("troubles reading ELF header\n"); 10110c0fea5dSIngo Weinhold goto err1; 10120c0fea5dSIngo Weinhold } 10130c0fea5dSIngo Weinhold 10140c0fea5dSIngo Weinhold status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize); 10150c0fea5dSIngo Weinhold if (status < B_OK) { 10160c0fea5dSIngo Weinhold FATAL("incorrect ELF header\n"); 10170c0fea5dSIngo Weinhold goto err1; 10180c0fea5dSIngo Weinhold } 10190c0fea5dSIngo Weinhold 10200c0fea5dSIngo Weinhold // ToDo: what to do about this restriction?? 10210c0fea5dSIngo Weinhold if (pheaderSize > (int)sizeof(ph_buff)) { 10220c0fea5dSIngo Weinhold FATAL("Cannot handle program headers bigger than %lu\n", sizeof(ph_buff)); 10230c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 10240c0fea5dSIngo Weinhold goto err1; 10250c0fea5dSIngo Weinhold } 10260c0fea5dSIngo Weinhold 10270c0fea5dSIngo Weinhold length = _kern_read(fd, eheader.e_phoff, ph_buff, pheaderSize); 10280c0fea5dSIngo Weinhold if (length != pheaderSize) { 10290c0fea5dSIngo Weinhold FATAL("Could not read program headers: %s\n", strerror(length)); 10300c0fea5dSIngo Weinhold status = B_BAD_DATA; 10310c0fea5dSIngo Weinhold goto err1; 10320c0fea5dSIngo Weinhold } 10330c0fea5dSIngo Weinhold 10340c0fea5dSIngo Weinhold numRegions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize); 10350c0fea5dSIngo Weinhold if (numRegions <= 0) { 10360c0fea5dSIngo Weinhold FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions); 10370c0fea5dSIngo Weinhold status = B_BAD_DATA; 10380c0fea5dSIngo Weinhold goto err1; 10390c0fea5dSIngo Weinhold } 10400c0fea5dSIngo Weinhold 10410c0fea5dSIngo Weinhold image = create_image(name, path, numRegions); 10420c0fea5dSIngo Weinhold if (image == NULL) { 10430c0fea5dSIngo Weinhold FATAL("Failed to allocate image_t object\n"); 10440c0fea5dSIngo Weinhold status = B_NO_MEMORY; 10450c0fea5dSIngo Weinhold goto err1; 10460c0fea5dSIngo Weinhold } 10470c0fea5dSIngo Weinhold 10480c0fea5dSIngo Weinhold status = parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize); 10490c0fea5dSIngo Weinhold if (status < B_OK) 10500c0fea5dSIngo Weinhold goto err2; 10510c0fea5dSIngo Weinhold 10520c0fea5dSIngo Weinhold if (!assert_dynamic_loadable(image)) { 10530c0fea5dSIngo Weinhold FATAL("Dynamic segment must be loadable (implementation restriction)\n"); 10540c0fea5dSIngo Weinhold status = B_UNSUPPORTED; 10550c0fea5dSIngo Weinhold goto err2; 10560c0fea5dSIngo Weinhold } 10570c0fea5dSIngo Weinhold 10580c0fea5dSIngo Weinhold status = map_image(fd, path, image, type == B_APP_IMAGE); 10590c0fea5dSIngo Weinhold if (status < B_OK) { 10600c0fea5dSIngo Weinhold FATAL("Could not map image: %s\n", strerror(status)); 10610c0fea5dSIngo Weinhold status = B_ERROR; 10620c0fea5dSIngo Weinhold goto err2; 10630c0fea5dSIngo Weinhold } 10640c0fea5dSIngo Weinhold 10650c0fea5dSIngo Weinhold if (!parse_dynamic_segment(image)) { 10660c0fea5dSIngo Weinhold FATAL("Troubles handling dynamic section\n"); 10670c0fea5dSIngo Weinhold status = B_BAD_DATA; 10680c0fea5dSIngo Weinhold goto err3; 10690c0fea5dSIngo Weinhold } 10700c0fea5dSIngo Weinhold 10710c0fea5dSIngo Weinhold if (eheader.e_entry != NULL) 10720c0fea5dSIngo Weinhold image->entry_point = eheader.e_entry + image->regions[0].delta; 10730c0fea5dSIngo Weinhold 10740c0fea5dSIngo Weinhold image->type = type; 10750c0fea5dSIngo Weinhold register_image(image, fd, path); 10760c0fea5dSIngo Weinhold 10770c0fea5dSIngo Weinhold _kern_close(fd); 10780c0fea5dSIngo Weinhold 10790c0fea5dSIngo Weinhold enqueue_image(&sLoadedImages, image); 10800c0fea5dSIngo Weinhold sLoadedImageCount++; 10810c0fea5dSIngo Weinhold 10820c0fea5dSIngo Weinhold *_image = image; 10830c0fea5dSIngo Weinhold return B_OK; 10840c0fea5dSIngo Weinhold 10850c0fea5dSIngo Weinhold err3: 10860c0fea5dSIngo Weinhold unmap_image(image); 10870c0fea5dSIngo Weinhold err2: 10880c0fea5dSIngo Weinhold delete_image_struct(image); 10890c0fea5dSIngo Weinhold err1: 10900c0fea5dSIngo Weinhold _kern_close(fd); 10910c0fea5dSIngo Weinhold return status; 10920c0fea5dSIngo Weinhold } 10930c0fea5dSIngo Weinhold 10940c0fea5dSIngo Weinhold 10950c0fea5dSIngo Weinhold static const char * 10960c0fea5dSIngo Weinhold find_dt_rpath(image_t *image) 10970c0fea5dSIngo Weinhold { 10980c0fea5dSIngo Weinhold int i; 10990c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 11000c0fea5dSIngo Weinhold 11010c0fea5dSIngo Weinhold for (i = 0; d[i].d_tag != DT_NULL; i++) { 11020c0fea5dSIngo Weinhold if (d[i].d_tag == DT_RPATH) 11030c0fea5dSIngo Weinhold return STRING(image, d[i].d_un.d_val); 11040c0fea5dSIngo Weinhold } 11050c0fea5dSIngo Weinhold 11060c0fea5dSIngo Weinhold return NULL; 11070c0fea5dSIngo Weinhold } 11080c0fea5dSIngo Weinhold 11090c0fea5dSIngo Weinhold 11100c0fea5dSIngo Weinhold static status_t 11110c0fea5dSIngo Weinhold load_dependencies(image_t *image) 11120c0fea5dSIngo Weinhold { 11130c0fea5dSIngo Weinhold struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; 11144bef3723SAxel Dörfler bool reportErrors = report_errors(); 111574c0424aSAxel Dörfler status_t status = B_OK; 11160c0fea5dSIngo Weinhold uint32 i, j; 11170c0fea5dSIngo Weinhold const char *rpath; 11180c0fea5dSIngo Weinhold 11190c0fea5dSIngo Weinhold if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED)) 11200c0fea5dSIngo Weinhold return B_OK; 11210c0fea5dSIngo Weinhold 11220c0fea5dSIngo Weinhold image->flags |= RFLAG_DEPENDENCIES_LOADED; 11230c0fea5dSIngo Weinhold 11240c0fea5dSIngo Weinhold if (image->num_needed == 0) 11250c0fea5dSIngo Weinhold return B_OK; 11260c0fea5dSIngo Weinhold 11270c0fea5dSIngo Weinhold image->needed = (image_t**)malloc(image->num_needed * sizeof(image_t *)); 11280c0fea5dSIngo Weinhold if (image->needed == NULL) { 11290c0fea5dSIngo Weinhold FATAL("failed to allocate needed struct\n"); 11300c0fea5dSIngo Weinhold return B_NO_MEMORY; 11310c0fea5dSIngo Weinhold } 11320c0fea5dSIngo Weinhold 11330c0fea5dSIngo Weinhold memset(image->needed, 0, image->num_needed * sizeof(image_t *)); 11340c0fea5dSIngo Weinhold rpath = find_dt_rpath(image); 11350c0fea5dSIngo Weinhold 11360c0fea5dSIngo Weinhold for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { 11370c0fea5dSIngo Weinhold switch (d[i].d_tag) { 11380c0fea5dSIngo Weinhold case DT_NEEDED: 113974c0424aSAxel Dörfler { 114074c0424aSAxel Dörfler int32 neededOffset = d[i].d_un.d_val; 114174c0424aSAxel Dörfler const char *name = STRING(image, neededOffset); 11420c0fea5dSIngo Weinhold 114374c0424aSAxel Dörfler status_t loadStatus = load_container(name, B_LIBRARY_IMAGE, 114474c0424aSAxel Dörfler rpath, &image->needed[j]); 114574c0424aSAxel Dörfler if (loadStatus < B_OK) { 114674c0424aSAxel Dörfler status = loadStatus; 114774c0424aSAxel Dörfler // correct error code in case the file could not been found 114874c0424aSAxel Dörfler if (status == B_ENTRY_NOT_FOUND) { 114974c0424aSAxel Dörfler status = B_MISSING_LIBRARY; 115074c0424aSAxel Dörfler 115174c0424aSAxel Dörfler if (reportErrors) 115274c0424aSAxel Dörfler sErrorMessage.AddString("missing library", name); 115374c0424aSAxel Dörfler } 115474c0424aSAxel Dörfler 115574c0424aSAxel Dörfler // Collect all missing libraries in case we report back 115674c0424aSAxel Dörfler if (!reportErrors) 11570c0fea5dSIngo Weinhold return status; 115874c0424aSAxel Dörfler } 11590c0fea5dSIngo Weinhold 11600c0fea5dSIngo Weinhold j += 1; 11610c0fea5dSIngo Weinhold break; 116274c0424aSAxel Dörfler } 11630c0fea5dSIngo Weinhold 11640c0fea5dSIngo Weinhold default: 11650c0fea5dSIngo Weinhold // ignore any other tag 11660c0fea5dSIngo Weinhold continue; 11670c0fea5dSIngo Weinhold } 11680c0fea5dSIngo Weinhold } 11690c0fea5dSIngo Weinhold 117074c0424aSAxel Dörfler if (status < B_OK) 117174c0424aSAxel Dörfler return status; 117274c0424aSAxel Dörfler 11730c0fea5dSIngo Weinhold if (j != image->num_needed) { 11740c0fea5dSIngo Weinhold FATAL("Internal error at load_dependencies()"); 11750c0fea5dSIngo Weinhold return B_ERROR; 11760c0fea5dSIngo Weinhold } 11770c0fea5dSIngo Weinhold 11780c0fea5dSIngo Weinhold return B_OK; 11790c0fea5dSIngo Weinhold } 11800c0fea5dSIngo Weinhold 11810c0fea5dSIngo Weinhold 11820c0fea5dSIngo Weinhold static uint32 11830c0fea5dSIngo Weinhold topological_sort(image_t *image, uint32 slot, image_t **initList, 11840c0fea5dSIngo Weinhold uint32 sortFlag) 11850c0fea5dSIngo Weinhold { 11860c0fea5dSIngo Weinhold uint32 i; 11870c0fea5dSIngo Weinhold 11880c0fea5dSIngo Weinhold if (image->flags & sortFlag) 11890c0fea5dSIngo Weinhold return slot; 11900c0fea5dSIngo Weinhold 11910c0fea5dSIngo Weinhold image->flags |= sortFlag; /* make sure we don't visit this one */ 11920c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) 11930c0fea5dSIngo Weinhold slot = topological_sort(image->needed[i], slot, initList, sortFlag); 11940c0fea5dSIngo Weinhold 11950c0fea5dSIngo Weinhold initList[slot] = image; 11960c0fea5dSIngo Weinhold return slot + 1; 11970c0fea5dSIngo Weinhold } 11980c0fea5dSIngo Weinhold 11990c0fea5dSIngo Weinhold 12000c0fea5dSIngo Weinhold static ssize_t 12010c0fea5dSIngo Weinhold get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag) 12020c0fea5dSIngo Weinhold { 12030c0fea5dSIngo Weinhold image_t **list; 12040c0fea5dSIngo Weinhold 12050c0fea5dSIngo Weinhold list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t *)); 12060c0fea5dSIngo Weinhold if (list == NULL) { 12070c0fea5dSIngo Weinhold FATAL("memory shortage in get_sorted_image_list()"); 12080c0fea5dSIngo Weinhold *_list = NULL; 12090c0fea5dSIngo Weinhold return B_NO_MEMORY; 12100c0fea5dSIngo Weinhold } 12110c0fea5dSIngo Weinhold 12120c0fea5dSIngo Weinhold memset(list, 0, sLoadedImageCount * sizeof(image_t *)); 12130c0fea5dSIngo Weinhold 12140c0fea5dSIngo Weinhold *_list = list; 12150c0fea5dSIngo Weinhold return topological_sort(image, 0, list, sortFlag); 12160c0fea5dSIngo Weinhold } 12170c0fea5dSIngo Weinhold 12180c0fea5dSIngo Weinhold 12190c0fea5dSIngo Weinhold static status_t 12200c0fea5dSIngo Weinhold relocate_dependencies(image_t *image) 12210c0fea5dSIngo Weinhold { 12220c0fea5dSIngo Weinhold ssize_t count, i; 12230c0fea5dSIngo Weinhold image_t **list; 12240c0fea5dSIngo Weinhold 12250c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); 12260c0fea5dSIngo Weinhold if (count < B_OK) 12270c0fea5dSIngo Weinhold return count; 12280c0fea5dSIngo Weinhold 12290c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 123046f4d849SIngo Weinhold status_t status = relocate_image(image, list[i]); 12310c0fea5dSIngo Weinhold if (status < B_OK) 12320c0fea5dSIngo Weinhold return status; 12330c0fea5dSIngo Weinhold } 12340c0fea5dSIngo Weinhold 12350c0fea5dSIngo Weinhold free(list); 12360c0fea5dSIngo Weinhold return B_OK; 12370c0fea5dSIngo Weinhold } 12380c0fea5dSIngo Weinhold 12390c0fea5dSIngo Weinhold 12400c0fea5dSIngo Weinhold static void 12410c0fea5dSIngo Weinhold init_dependencies(image_t *image, bool initHead) 12420c0fea5dSIngo Weinhold { 12430c0fea5dSIngo Weinhold image_t **initList; 12440c0fea5dSIngo Weinhold ssize_t count, i; 12450c0fea5dSIngo Weinhold 12460c0fea5dSIngo Weinhold count = get_sorted_image_list(image, &initList, RFLAG_INITIALIZED); 12470c0fea5dSIngo Weinhold if (count <= 0) 12480c0fea5dSIngo Weinhold return; 12490c0fea5dSIngo Weinhold 12500c0fea5dSIngo Weinhold if (!initHead) { 12510c0fea5dSIngo Weinhold // this removes the "calling" image 12520c0fea5dSIngo Weinhold image->flags &= ~RFLAG_INITIALIZED; 12530c0fea5dSIngo Weinhold initList[--count] = NULL; 12540c0fea5dSIngo Weinhold } 12550c0fea5dSIngo Weinhold 12560c0fea5dSIngo Weinhold TRACE(("%ld: init dependencies\n", find_thread(NULL))); 12570c0fea5dSIngo Weinhold for (i = 0; i < count; i++) { 12580c0fea5dSIngo Weinhold image = initList[i]; 12590c0fea5dSIngo Weinhold 12600c0fea5dSIngo Weinhold TRACE(("%ld: init: %s\n", find_thread(NULL), image->name)); 12610c0fea5dSIngo Weinhold 12620c0fea5dSIngo Weinhold if (image->init_routine != NULL) 12630c0fea5dSIngo Weinhold ((init_term_function)image->init_routine)(image->id); 12640c0fea5dSIngo Weinhold } 12650c0fea5dSIngo Weinhold TRACE(("%ld: init done.\n", find_thread(NULL))); 12660c0fea5dSIngo Weinhold 12670c0fea5dSIngo Weinhold free(initList); 12680c0fea5dSIngo Weinhold } 12690c0fea5dSIngo Weinhold 12700c0fea5dSIngo Weinhold 12710c0fea5dSIngo Weinhold static void 12720c0fea5dSIngo Weinhold put_image(image_t *image) 12730c0fea5dSIngo Weinhold { 12740c0fea5dSIngo Weinhold // If all references to the image are gone, add it to the disposable list 12750c0fea5dSIngo Weinhold // and remove all dependencies 12760c0fea5dSIngo Weinhold 12770c0fea5dSIngo Weinhold if (atomic_add(&image->ref_count, -1) == 1) { 12780c0fea5dSIngo Weinhold size_t i; 12790c0fea5dSIngo Weinhold 12800c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 12810c0fea5dSIngo Weinhold enqueue_image(&sDisposableImages, image); 12820c0fea5dSIngo Weinhold sLoadedImageCount--; 12830c0fea5dSIngo Weinhold 12840c0fea5dSIngo Weinhold for (i = 0; i < image->num_needed; i++) { 12850c0fea5dSIngo Weinhold put_image(image->needed[i]); 12860c0fea5dSIngo Weinhold } 12870c0fea5dSIngo Weinhold } 12880c0fea5dSIngo Weinhold } 12890c0fea5dSIngo Weinhold 12900c0fea5dSIngo Weinhold 129174c0424aSAxel Dörfler // #pragma mark - libroot.so exported functions 12920c0fea5dSIngo Weinhold 12930c0fea5dSIngo Weinhold 12940c0fea5dSIngo Weinhold image_id 12950c0fea5dSIngo Weinhold load_program(char const *path, void **_entry) 12960c0fea5dSIngo Weinhold { 12970c0fea5dSIngo Weinhold status_t status; 12980c0fea5dSIngo Weinhold image_t *image; 12990c0fea5dSIngo Weinhold 13000c0fea5dSIngo Weinhold rld_lock(); 13010c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 13020c0fea5dSIngo Weinhold 13030c0fea5dSIngo Weinhold TRACE(("rld: load %s\n", path)); 13040c0fea5dSIngo Weinhold 13050c0fea5dSIngo Weinhold status = load_container(path, B_APP_IMAGE, NULL, &sProgramImage); 130674c0424aSAxel Dörfler if (status < B_OK) 130774c0424aSAxel Dörfler goto err; 13080c0fea5dSIngo Weinhold 13090c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image != NULL; image = image->next) { 13100c0fea5dSIngo Weinhold status = load_dependencies(image); 13110c0fea5dSIngo Weinhold if (status < B_OK) 13120c0fea5dSIngo Weinhold goto err; 13130c0fea5dSIngo Weinhold } 13140c0fea5dSIngo Weinhold 13150c0fea5dSIngo Weinhold status = relocate_dependencies(sProgramImage); 13160c0fea5dSIngo Weinhold if (status < B_OK) 13170c0fea5dSIngo Weinhold goto err; 13180c0fea5dSIngo Weinhold 13190c0fea5dSIngo Weinhold // We patch any exported __gRuntimeLoader symbols to point to our private API 13200c0fea5dSIngo Weinhold { 132146f4d849SIngo Weinhold struct Elf32_Sym *symbol = find_symbol_in_loaded_images( 132246f4d849SIngo Weinhold "__gRuntimeLoader", &image); 13230c0fea5dSIngo Weinhold if (symbol != NULL) { 13240c0fea5dSIngo Weinhold void **_export = (void **)(symbol->st_value + image->regions[0].delta); 13250c0fea5dSIngo Weinhold *_export = &gRuntimeLoader; 13260c0fea5dSIngo Weinhold } 13270c0fea5dSIngo Weinhold } 13280c0fea5dSIngo Weinhold 13290c0fea5dSIngo Weinhold init_dependencies(sLoadedImages.head, true); 13300c0fea5dSIngo Weinhold remap_images(); 13310c0fea5dSIngo Weinhold // ToDo: once setup_system_time() is fixed, move this one line higher! 13320c0fea5dSIngo Weinhold 13330c0fea5dSIngo Weinhold // Since the images are initialized now, we no longer should use our 13340c0fea5dSIngo Weinhold // getenv(), but use the one from libroot.so 13350c0fea5dSIngo Weinhold { 133646f4d849SIngo Weinhold struct Elf32_Sym *symbol = find_symbol_in_loaded_images("getenv", 133746f4d849SIngo Weinhold &image); 13380c0fea5dSIngo Weinhold if (symbol != NULL) 13390c0fea5dSIngo Weinhold gGetEnv = (char* (*)(const char*)) 13400c0fea5dSIngo Weinhold (symbol->st_value + image->regions[0].delta); 13410c0fea5dSIngo Weinhold } 13420c0fea5dSIngo Weinhold 13430c0fea5dSIngo Weinhold if (sProgramImage->entry_point == NULL) { 13440c0fea5dSIngo Weinhold status = B_NOT_AN_EXECUTABLE; 13450c0fea5dSIngo Weinhold goto err; 13460c0fea5dSIngo Weinhold } 13470c0fea5dSIngo Weinhold 13480c0fea5dSIngo Weinhold *_entry = (void *)(sProgramImage->entry_point); 13490c0fea5dSIngo Weinhold 13500c0fea5dSIngo Weinhold rld_unlock(); 13510c0fea5dSIngo Weinhold return sProgramImage->id; 13520c0fea5dSIngo Weinhold 13530c0fea5dSIngo Weinhold err: 13540c0fea5dSIngo Weinhold delete_image(sProgramImage); 135574c0424aSAxel Dörfler 13564bef3723SAxel Dörfler if (report_errors()) { 13574bef3723SAxel Dörfler // send error message 135874c0424aSAxel Dörfler sErrorMessage.AddInt32("error", status); 13594bef3723SAxel Dörfler sErrorMessage.SetDeliveryInfo(gProgramArgs->error_token, 13604bef3723SAxel Dörfler -1, 0, find_thread(NULL)); 13614bef3723SAxel Dörfler 13624bef3723SAxel Dörfler _kern_write_port_etc(gProgramArgs->error_port, 'KMSG', 13634bef3723SAxel Dörfler sErrorMessage.Buffer(), sErrorMessage.ContentSize(), 0, 0); 136474c0424aSAxel Dörfler } 136574c0424aSAxel Dörfler _kern_loading_app_failed(status); 13660c0fea5dSIngo Weinhold rld_unlock(); 136774c0424aSAxel Dörfler 13680c0fea5dSIngo Weinhold return status; 13690c0fea5dSIngo Weinhold } 13700c0fea5dSIngo Weinhold 13710c0fea5dSIngo Weinhold 13720c0fea5dSIngo Weinhold image_id 13730c0fea5dSIngo Weinhold load_library(char const *path, uint32 flags, bool addOn) 13740c0fea5dSIngo Weinhold { 13750c0fea5dSIngo Weinhold image_t *image = NULL; 13760c0fea5dSIngo Weinhold image_t *iter; 13770c0fea5dSIngo Weinhold image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); 13780c0fea5dSIngo Weinhold status_t status; 13790c0fea5dSIngo Weinhold 13800c0fea5dSIngo Weinhold if (path == NULL) 13810c0fea5dSIngo Weinhold return B_BAD_VALUE; 13820c0fea5dSIngo Weinhold 13830c0fea5dSIngo Weinhold // ToDo: implement flags 13840c0fea5dSIngo Weinhold (void)flags; 13850c0fea5dSIngo Weinhold 13860c0fea5dSIngo Weinhold rld_lock(); 13870c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 13880c0fea5dSIngo Weinhold 13890c0fea5dSIngo Weinhold // have we already loaded this library? 13900c0fea5dSIngo Weinhold // Checking it at this stage saves loading its dependencies again 13910c0fea5dSIngo Weinhold if (!addOn) { 13920c0fea5dSIngo Weinhold image = find_image(path, APP_OR_LIBRARY_TYPE); 13930c0fea5dSIngo Weinhold if (image) { 13940c0fea5dSIngo Weinhold atomic_add(&image->ref_count, 1); 13950c0fea5dSIngo Weinhold rld_unlock(); 13960c0fea5dSIngo Weinhold return image->id; 13970c0fea5dSIngo Weinhold } 13980c0fea5dSIngo Weinhold } 13990c0fea5dSIngo Weinhold 14000c0fea5dSIngo Weinhold status = load_container(path, type, NULL, &image); 14010c0fea5dSIngo Weinhold if (status < B_OK) { 14020c0fea5dSIngo Weinhold rld_unlock(); 14030c0fea5dSIngo Weinhold return status; 14040c0fea5dSIngo Weinhold } 14050c0fea5dSIngo Weinhold 14060c0fea5dSIngo Weinhold for (iter = sLoadedImages.head; iter; iter = iter->next) { 14070c0fea5dSIngo Weinhold status = load_dependencies(iter); 14080c0fea5dSIngo Weinhold if (status < B_OK) 14090c0fea5dSIngo Weinhold goto err; 14100c0fea5dSIngo Weinhold } 14110c0fea5dSIngo Weinhold 14120c0fea5dSIngo Weinhold status = relocate_dependencies(image); 14130c0fea5dSIngo Weinhold if (status < B_OK) 14140c0fea5dSIngo Weinhold goto err; 14150c0fea5dSIngo Weinhold 14160c0fea5dSIngo Weinhold remap_images(); 14170c0fea5dSIngo Weinhold init_dependencies(image, true); 14180c0fea5dSIngo Weinhold 14190c0fea5dSIngo Weinhold rld_unlock(); 14200c0fea5dSIngo Weinhold return image->id; 14210c0fea5dSIngo Weinhold 14220c0fea5dSIngo Weinhold err: 14230c0fea5dSIngo Weinhold dequeue_image(&sLoadedImages, image); 14240c0fea5dSIngo Weinhold sLoadedImageCount--; 14250c0fea5dSIngo Weinhold delete_image(image); 14260c0fea5dSIngo Weinhold rld_unlock(); 14270c0fea5dSIngo Weinhold return status; 14280c0fea5dSIngo Weinhold } 14290c0fea5dSIngo Weinhold 14300c0fea5dSIngo Weinhold 14310c0fea5dSIngo Weinhold status_t 14320c0fea5dSIngo Weinhold unload_library(image_id imageID, bool addOn) 14330c0fea5dSIngo Weinhold { 14340c0fea5dSIngo Weinhold status_t status = B_BAD_IMAGE_ID; 14350c0fea5dSIngo Weinhold image_t *image; 14360c0fea5dSIngo Weinhold image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; 14370c0fea5dSIngo Weinhold 14380c0fea5dSIngo Weinhold if (imageID < B_OK) 14390c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 14400c0fea5dSIngo Weinhold 14410c0fea5dSIngo Weinhold rld_lock(); 14420c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 14430c0fea5dSIngo Weinhold 14440c0fea5dSIngo Weinhold // we only check images that have been already initialized 14450c0fea5dSIngo Weinhold 14460c0fea5dSIngo Weinhold for (image = sLoadedImages.head; image; image = image->next) { 14470c0fea5dSIngo Weinhold if (image->id == imageID) { 14480c0fea5dSIngo Weinhold // unload image 14490c0fea5dSIngo Weinhold if (type == image->type) { 14500c0fea5dSIngo Weinhold put_image(image); 14510c0fea5dSIngo Weinhold status = B_OK; 14520c0fea5dSIngo Weinhold } else 14530c0fea5dSIngo Weinhold status = B_BAD_VALUE; 14540c0fea5dSIngo Weinhold break; 14550c0fea5dSIngo Weinhold } 14560c0fea5dSIngo Weinhold } 14570c0fea5dSIngo Weinhold 14580c0fea5dSIngo Weinhold if (status == B_OK) { 14590c0fea5dSIngo Weinhold while ((image = sDisposableImages.head) != NULL) { 14600c0fea5dSIngo Weinhold // call image fini here... 1461*8c2a9d74SMichael Lotz if (gRuntimeLoader.call_atexit_hooks_for_range) { 1462*8c2a9d74SMichael Lotz gRuntimeLoader.call_atexit_hooks_for_range( 1463*8c2a9d74SMichael Lotz image->regions[0].start, image->regions[0].size); 1464*8c2a9d74SMichael Lotz } 1465*8c2a9d74SMichael Lotz 14660c0fea5dSIngo Weinhold if (image->term_routine) 14670c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 14680c0fea5dSIngo Weinhold 14690c0fea5dSIngo Weinhold dequeue_image(&sDisposableImages, image); 14700c0fea5dSIngo Weinhold unmap_image(image); 14710c0fea5dSIngo Weinhold 14720c0fea5dSIngo Weinhold delete_image(image); 14730c0fea5dSIngo Weinhold } 14740c0fea5dSIngo Weinhold } 14750c0fea5dSIngo Weinhold 14760c0fea5dSIngo Weinhold rld_unlock(); 14770c0fea5dSIngo Weinhold return status; 14780c0fea5dSIngo Weinhold } 14790c0fea5dSIngo Weinhold 14800c0fea5dSIngo Weinhold 14810c0fea5dSIngo Weinhold status_t 14820c0fea5dSIngo Weinhold get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, int32 *_nameLength, 14830c0fea5dSIngo Weinhold int32 *_type, void **_location) 14840c0fea5dSIngo Weinhold { 14850c0fea5dSIngo Weinhold int32 count = 0, j; 14860c0fea5dSIngo Weinhold uint32 i; 14870c0fea5dSIngo Weinhold image_t *image; 14880c0fea5dSIngo Weinhold 14890c0fea5dSIngo Weinhold rld_lock(); 14900c0fea5dSIngo Weinhold 14910c0fea5dSIngo Weinhold // get the image from those who have been already initialized 14920c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 14930c0fea5dSIngo Weinhold if (image == NULL) { 14940c0fea5dSIngo Weinhold rld_unlock(); 14950c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 14960c0fea5dSIngo Weinhold } 14970c0fea5dSIngo Weinhold 14980c0fea5dSIngo Weinhold // iterate through all the hash buckets until we've found the one 14990c0fea5dSIngo Weinhold for (i = 0; i < HASHTABSIZE(image); i++) { 15000c0fea5dSIngo Weinhold for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { 15010c0fea5dSIngo Weinhold struct Elf32_Sym *symbol = &image->syms[i]; 15020c0fea5dSIngo Weinhold 15030c0fea5dSIngo Weinhold if (count == num) { 15040c0fea5dSIngo Weinhold strlcpy(nameBuffer, SYMNAME(image, symbol), *_nameLength); 15050c0fea5dSIngo Weinhold *_nameLength = strlen(SYMNAME(image, symbol)); 15060c0fea5dSIngo Weinhold 15070c0fea5dSIngo Weinhold if (_type != NULL) { 15080c0fea5dSIngo Weinhold // ToDo: check with the return types of that BeOS function 15090c0fea5dSIngo Weinhold if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) 15100c0fea5dSIngo Weinhold *_type = B_SYMBOL_TYPE_TEXT; 15110c0fea5dSIngo Weinhold else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) 15120c0fea5dSIngo Weinhold *_type = B_SYMBOL_TYPE_DATA; 15130c0fea5dSIngo Weinhold else 15140c0fea5dSIngo Weinhold *_type = B_SYMBOL_TYPE_ANY; 15150c0fea5dSIngo Weinhold } 15160c0fea5dSIngo Weinhold 15170c0fea5dSIngo Weinhold if (_location != NULL) 15180c0fea5dSIngo Weinhold *_location = (void *)(symbol->st_value + image->regions[0].delta); 15190c0fea5dSIngo Weinhold goto out; 15200c0fea5dSIngo Weinhold } 15210c0fea5dSIngo Weinhold count++; 15220c0fea5dSIngo Weinhold } 15230c0fea5dSIngo Weinhold } 15240c0fea5dSIngo Weinhold out: 15250c0fea5dSIngo Weinhold rld_unlock(); 15260c0fea5dSIngo Weinhold 15270c0fea5dSIngo Weinhold if (num != count) 15280c0fea5dSIngo Weinhold return B_BAD_INDEX; 15290c0fea5dSIngo Weinhold 15300c0fea5dSIngo Weinhold return B_OK; 15310c0fea5dSIngo Weinhold } 15320c0fea5dSIngo Weinhold 15330c0fea5dSIngo Weinhold 15340c0fea5dSIngo Weinhold status_t 15350c0fea5dSIngo Weinhold get_symbol(image_id imageID, char const *symbolName, int32 symbolType, void **_location) 15360c0fea5dSIngo Weinhold { 15370c0fea5dSIngo Weinhold status_t status = B_OK; 15380c0fea5dSIngo Weinhold image_t *image; 15390c0fea5dSIngo Weinhold 15400c0fea5dSIngo Weinhold if (imageID < B_OK) 15410c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 15420c0fea5dSIngo Weinhold if (symbolName == NULL) 15430c0fea5dSIngo Weinhold return B_BAD_VALUE; 15440c0fea5dSIngo Weinhold 15450c0fea5dSIngo Weinhold rld_lock(); 15460c0fea5dSIngo Weinhold // for now, just do stupid simple global locking 15470c0fea5dSIngo Weinhold 15480c0fea5dSIngo Weinhold // get the image from those who have been already initialized 15490c0fea5dSIngo Weinhold image = find_loaded_image_by_id(imageID); 15500c0fea5dSIngo Weinhold if (image != NULL) { 15510c0fea5dSIngo Weinhold struct Elf32_Sym *symbol; 15520c0fea5dSIngo Weinhold 15530c0fea5dSIngo Weinhold // get the symbol in the image 15540c0fea5dSIngo Weinhold symbol = find_symbol(image, symbolName, symbolType); 15550c0fea5dSIngo Weinhold if (symbol) { 15560c0fea5dSIngo Weinhold if (_location != NULL) 15570c0fea5dSIngo Weinhold *_location = (void *)(symbol->st_value + image->regions[0].delta); 15580c0fea5dSIngo Weinhold } else 15590c0fea5dSIngo Weinhold status = B_ENTRY_NOT_FOUND; 15600c0fea5dSIngo Weinhold } else 15610c0fea5dSIngo Weinhold status = B_BAD_IMAGE_ID; 15620c0fea5dSIngo Weinhold 15630c0fea5dSIngo Weinhold rld_unlock(); 15640c0fea5dSIngo Weinhold return status; 15650c0fea5dSIngo Weinhold } 15660c0fea5dSIngo Weinhold 15670c0fea5dSIngo Weinhold 15680c0fea5dSIngo Weinhold status_t 15690c0fea5dSIngo Weinhold get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 15700c0fea5dSIngo Weinhold { 15710c0fea5dSIngo Weinhold uint32 i, j, searchIndex = *cookie; 15720c0fea5dSIngo Weinhold struct Elf32_Dyn *dynamicSection; 15730c0fea5dSIngo Weinhold image_t *image; 15740c0fea5dSIngo Weinhold 15750c0fea5dSIngo Weinhold if (_name == NULL) 15760c0fea5dSIngo Weinhold return B_BAD_VALUE; 15770c0fea5dSIngo Weinhold 15780c0fea5dSIngo Weinhold rld_lock(); 15790c0fea5dSIngo Weinhold 15800c0fea5dSIngo Weinhold image = find_loaded_image_by_id(id); 15810c0fea5dSIngo Weinhold if (image == NULL) { 15820c0fea5dSIngo Weinhold rld_unlock(); 15830c0fea5dSIngo Weinhold return B_BAD_IMAGE_ID; 15840c0fea5dSIngo Weinhold } 15850c0fea5dSIngo Weinhold 15860c0fea5dSIngo Weinhold dynamicSection = (struct Elf32_Dyn *)image->dynamic_ptr; 15870c0fea5dSIngo Weinhold if (dynamicSection == NULL || image->num_needed <= searchIndex) { 15880c0fea5dSIngo Weinhold rld_unlock(); 15890c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 15900c0fea5dSIngo Weinhold } 15910c0fea5dSIngo Weinhold 15920c0fea5dSIngo Weinhold for (i = 0, j = 0; dynamicSection[i].d_tag != DT_NULL; i++) { 15930c0fea5dSIngo Weinhold if (dynamicSection[i].d_tag != DT_NEEDED) 15940c0fea5dSIngo Weinhold continue; 15950c0fea5dSIngo Weinhold 15960c0fea5dSIngo Weinhold if (j++ == searchIndex) { 15970c0fea5dSIngo Weinhold int32 neededOffset = dynamicSection[i].d_un.d_val; 15980c0fea5dSIngo Weinhold 15990c0fea5dSIngo Weinhold *_name = STRING(image, neededOffset); 16000c0fea5dSIngo Weinhold *cookie = searchIndex + 1; 16010c0fea5dSIngo Weinhold rld_unlock(); 16020c0fea5dSIngo Weinhold return B_OK; 16030c0fea5dSIngo Weinhold } 16040c0fea5dSIngo Weinhold } 16050c0fea5dSIngo Weinhold 16060c0fea5dSIngo Weinhold rld_unlock(); 16070c0fea5dSIngo Weinhold return B_ENTRY_NOT_FOUND; 16080c0fea5dSIngo Weinhold } 16090c0fea5dSIngo Weinhold 16100c0fea5dSIngo Weinhold 161174c0424aSAxel Dörfler // #pragma mark - runtime_loader private exports 16120c0fea5dSIngo Weinhold 16130c0fea5dSIngo Weinhold 16140c0fea5dSIngo Weinhold /** Read and verify the ELF header */ 16150c0fea5dSIngo Weinhold 16160c0fea5dSIngo Weinhold status_t 16170c0fea5dSIngo Weinhold elf_verify_header(void *header, int32 length) 16180c0fea5dSIngo Weinhold { 16190c0fea5dSIngo Weinhold int32 programSize, sectionSize; 16200c0fea5dSIngo Weinhold 16210c0fea5dSIngo Weinhold if (length < (int32)sizeof(struct Elf32_Ehdr)) 16220c0fea5dSIngo Weinhold return B_NOT_AN_EXECUTABLE; 16230c0fea5dSIngo Weinhold 16240c0fea5dSIngo Weinhold return parse_elf_header((struct Elf32_Ehdr *)header, &programSize, §ionSize); 16250c0fea5dSIngo Weinhold } 16260c0fea5dSIngo Weinhold 16270c0fea5dSIngo Weinhold 16280c0fea5dSIngo Weinhold void 16290c0fea5dSIngo Weinhold terminate_program(void) 16300c0fea5dSIngo Weinhold { 16310c0fea5dSIngo Weinhold image_t **termList; 16320c0fea5dSIngo Weinhold ssize_t count, i; 16330c0fea5dSIngo Weinhold 16340c0fea5dSIngo Weinhold count = get_sorted_image_list(sProgramImage, &termList, RFLAG_TERMINATED); 16350c0fea5dSIngo Weinhold if (count < B_OK) 16360c0fea5dSIngo Weinhold return; 16370c0fea5dSIngo Weinhold 16380c0fea5dSIngo Weinhold TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); 16390c0fea5dSIngo Weinhold for (i = count; i-- > 0;) { 16400c0fea5dSIngo Weinhold image_t *image = termList[i]; 16410c0fea5dSIngo Weinhold 16420c0fea5dSIngo Weinhold TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); 16430c0fea5dSIngo Weinhold 16440c0fea5dSIngo Weinhold if (image->term_routine) 16450c0fea5dSIngo Weinhold ((init_term_function)image->term_routine)(image->id); 16460c0fea5dSIngo Weinhold } 16470c0fea5dSIngo Weinhold TRACE(("%ld: term done.\n", find_thread(NULL))); 16480c0fea5dSIngo Weinhold 16490c0fea5dSIngo Weinhold free(termList); 16500c0fea5dSIngo Weinhold } 16510c0fea5dSIngo Weinhold 16520c0fea5dSIngo Weinhold 16530c0fea5dSIngo Weinhold void 16540c0fea5dSIngo Weinhold rldelf_init(void) 16550c0fea5dSIngo Weinhold { 16560c0fea5dSIngo Weinhold rld_sem = create_sem(1, "rld_lock"); 16570c0fea5dSIngo Weinhold rld_sem_owner = -1; 16580c0fea5dSIngo Weinhold rld_sem_count = 0; 16590c0fea5dSIngo Weinhold 16600c0fea5dSIngo Weinhold // create the debug area 16610c0fea5dSIngo Weinhold { 16620c0fea5dSIngo Weinhold int32 size = TO_PAGE_SIZE(sizeof(runtime_loader_debug_area)); 16630c0fea5dSIngo Weinhold 16640c0fea5dSIngo Weinhold runtime_loader_debug_area *area; 16650c0fea5dSIngo Weinhold area_id areaID = _kern_create_area(RUNTIME_LOADER_DEBUG_AREA_NAME, 16660c0fea5dSIngo Weinhold (void **)&area, B_ANY_ADDRESS, size, B_NO_LOCK, 16670c0fea5dSIngo Weinhold B_READ_AREA | B_WRITE_AREA); 16680c0fea5dSIngo Weinhold if (areaID < B_OK) { 16690c0fea5dSIngo Weinhold FATAL("Failed to create debug area.\n"); 16700c0fea5dSIngo Weinhold _kern_loading_app_failed(areaID); 16710c0fea5dSIngo Weinhold } 16720c0fea5dSIngo Weinhold 16730c0fea5dSIngo Weinhold area->loaded_images = &sLoadedImages; 16740c0fea5dSIngo Weinhold } 167574c0424aSAxel Dörfler 167674c0424aSAxel Dörfler // initialize error message if needed 16774bef3723SAxel Dörfler if (report_errors()) { 167874c0424aSAxel Dörfler void *buffer = malloc(1024); 167974c0424aSAxel Dörfler if (buffer == NULL) 168074c0424aSAxel Dörfler return; 168174c0424aSAxel Dörfler 168274c0424aSAxel Dörfler sErrorMessage.SetTo(buffer, 1024, 'Rler'); 168374c0424aSAxel Dörfler } 16840c0fea5dSIngo Weinhold } 16851873b4b3SIngo Weinhold 16861873b4b3SIngo Weinhold 16871873b4b3SIngo Weinhold status_t 16881873b4b3SIngo Weinhold elf_reinit_after_fork() 16891873b4b3SIngo Weinhold { 16901873b4b3SIngo Weinhold rld_sem = create_sem(1, "rld_lock"); 16911873b4b3SIngo Weinhold if (rld_sem < 0) 16921873b4b3SIngo Weinhold return rld_sem; 16931873b4b3SIngo Weinhold 16941873b4b3SIngo Weinhold return B_OK; 16951873b4b3SIngo Weinhold } 1696