From 593ee7bbc334e3ca6ecf6553543ad8037bd7b58a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 12 May 2009 21:08:56 +0000 Subject: [PATCH] Extended image_info by fields for the Haiku version and ABI. The runtime loader and the kernel read those values from the shared object (if available). In the runtime loader this should eventually replace the gcc version guessing method currently used (at least for shared objects built for Haiku). The optional packages need to be rebuilt first, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30729 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/kernel/image.h | 4 + .../private/runtime_loader/runtime_loader.h | 3 + src/system/kernel/elf.cpp | 51 ++++++++++++ src/system/kernel/image.cpp | 17 ++-- src/system/runtime_loader/elf.cpp | 81 ++++++++++++++----- 5 files changed, 129 insertions(+), 27 deletions(-) diff --git a/headers/os/kernel/image.h b/headers/os/kernel/image.h index 63aac77ee5..9057616d71 100644 --- a/headers/os/kernel/image.h +++ b/headers/os/kernel/image.h @@ -33,6 +33,10 @@ typedef struct { void *data; int32 text_size; int32 data_size; + + // Haiku R1 extensions + int32 api_version; // the Haiku API version used by the image + int32 abi; // the Haiku ABI used by the image } image_info; // flags for clear_caches() diff --git a/headers/private/runtime_loader/runtime_loader.h b/headers/private/runtime_loader/runtime_loader.h index ca57fcf25f..74bd5edc6e 100644 --- a/headers/private/runtime_loader/runtime_loader.h +++ b/headers/private/runtime_loader/runtime_loader.h @@ -85,6 +85,9 @@ typedef struct image_t { bool haiku; } gcc_version; + uint32 api_version; + uint32 abi; + addr_t entry_point; addr_t init_routine; addr_t term_routine; diff --git a/src/system/kernel/elf.cpp b/src/system/kernel/elf.cpp index ee2e9c435e..19ca312c1d 100644 --- a/src/system/kernel/elf.cpp +++ b/src/system/kernel/elf.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,10 @@ static mutex sImageLoadMutex = MUTEX_INITIALIZER("kimages_load_lock"); static bool sInitialized = false; +static struct Elf32_Sym *elf_find_symbol(struct elf_image_info *image, + const char *name); + + /*! Calculates hash for an image using its ID */ static uint32 image_hash(void *_image, const void *_key, uint32 range) @@ -107,6 +112,46 @@ register_elf_image(struct elf_image_info *image) imageInfo.data = (void *)image->data_region.start; imageInfo.data_size = image->data_region.size; + if (image->text_region.id >= 0) { + // evaluate the API/ABI version symbols + + // Haiku API version + imageInfo.api_version = 0; + struct Elf32_Sym* symbol = elf_find_symbol(image, + B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME); + if (symbol != NULL && symbol->st_shndx != SHN_UNDEF + && symbol->st_value > 0 + && ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT + && symbol->st_size >= sizeof(uint32)) { + addr_t symbolAddress = symbol->st_value + image->text_region.delta; + if (symbolAddress >= image->text_region.start + && symbolAddress - image->text_region.start + sizeof(uint32) + <= image->text_region.size) { + imageInfo.api_version = *(uint32*)symbolAddress; + } + } + + // Haiku ABI + imageInfo.abi = 0; + symbol = elf_find_symbol(image, + B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME); + if (symbol != NULL && symbol->st_shndx != SHN_UNDEF + && symbol->st_value > 0 + && ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT + && symbol->st_size >= sizeof(uint32)) { + addr_t symbolAddress = symbol->st_value + image->text_region.delta; + if (symbolAddress >= image->text_region.start + && symbolAddress - image->text_region.start + sizeof(uint32) + <= image->text_region.size) { + imageInfo.api_version = *(uint32*)symbolAddress; + } + } + } else { + // in-memory image -- use the current values + imageInfo.api_version = B_HAIKU_VERSION; + imageInfo.abi = B_HAIKU_ABI; + } + image->id = register_image(team_get_kernel_team(), &imageInfo, sizeof(image_info)); hash_insert(sImagesHash, image); @@ -1529,6 +1574,12 @@ elf_load_user_image(const char *path, struct team *team, int flags, imageInfo.node = st.st_ino; strlcpy(imageInfo.name, path, sizeof(imageInfo.name)); + imageInfo.api_version = B_HAIKU_VERSION; + imageInfo.abi = B_HAIKU_ABI; + // TODO: Get the actual values for the shared object. Currently only + // the runtime loader is loaded, so this is good enough for the time + // being. + imageInfo.id = register_image(team, &imageInfo, sizeof(image_info)); if (imageInfo.id >= 0 && team_get_current_team_id() == team->id) user_debug_image_created(&imageInfo); diff --git a/src/system/kernel/image.cpp b/src/system/kernel/image.cpp index e24b23c976..a6208ab504 100644 --- a/src/system/kernel/image.cpp +++ b/src/system/kernel/image.cpp @@ -189,6 +189,9 @@ remove_images(struct team *team) status_t _get_image_info(image_id id, image_info *info, size_t size) { + if (size > sizeof(image_info)) + return B_BAD_VALUE; + status_t status = B_ENTRY_NOT_FOUND; mutex_lock(&sImageMutex); @@ -209,6 +212,9 @@ status_t _get_next_image_info(team_id teamID, int32 *cookie, image_info *info, size_t size) { + if (size > sizeof(image_info)) + return B_BAD_VALUE; + status_t status = B_ENTRY_NOT_FOUND; struct team *team; cpu_status state; @@ -468,13 +474,13 @@ _user_get_image_info(image_id id, image_info *userInfo, size_t size) image_info info; status_t status; - if (size != sizeof(image_info)) + if (size > sizeof(image_info)) return B_BAD_VALUE; if (!IS_USER_ADDRESS(userInfo)) return B_BAD_ADDRESS; - status = _get_image_info(id, &info, size); + status = _get_image_info(id, &info, sizeof(image_info)); if (user_memcpy(userInfo, &info, size) < B_OK) return B_BAD_ADDRESS; @@ -484,18 +490,19 @@ _user_get_image_info(image_id id, image_info *userInfo, size_t size) status_t -_user_get_next_image_info(team_id team, int32 *_cookie, image_info *userInfo, size_t size) +_user_get_next_image_info(team_id team, int32 *_cookie, image_info *userInfo, + size_t size) { image_info info; status_t status; - if (size != sizeof(image_info)) + if (size > sizeof(image_info)) return B_BAD_VALUE; if (!IS_USER_ADDRESS(userInfo) || !IS_USER_ADDRESS(_cookie)) return B_BAD_ADDRESS; - status = _get_next_image_info(team, _cookie, &info, size); + status = _get_next_image_info(team, _cookie, &info, sizeof(image_info)); if (user_memcpy(userInfo, &info, size) < B_OK) return B_BAD_ADDRESS; diff --git a/src/system/runtime_loader/elf.cpp b/src/system/runtime_loader/elf.cpp index f30a82091d..6374282ca7 100644 --- a/src/system/runtime_loader/elf.cpp +++ b/src/system/runtime_loader/elf.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -144,6 +145,10 @@ static int32 sSemCount; extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport; +static struct Elf32_Sym* find_symbol(image_t* image, const char* name, + int32 type); + + void dprintf(const char *format, ...) { @@ -694,6 +699,34 @@ parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) } +static void +analyze_image_haiku_version_and_abi(image_t* image) +{ + // Haiku API version + struct Elf32_Sym* symbol = find_symbol(image, + B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME, B_SYMBOL_TYPE_DATA); + if (symbol != NULL && symbol->st_shndx != SHN_UNDEF + && symbol->st_value > 0 + && ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT + && symbol->st_size >= sizeof(uint32)) { + image->api_version + = *(uint32*)(symbol->st_value + image->regions[0].delta); + } else + image->api_version = 0; + + // Haiku ABI + symbol = find_symbol(image, B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME, + B_SYMBOL_TYPE_DATA); + if (symbol != NULL && symbol->st_shndx != SHN_UNDEF + && symbol->st_value > 0 + && ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT + && symbol->st_size >= sizeof(uint32)) { + image->abi = *(uint32*)(symbol->st_value + image->regions[0].delta); + } else + image->abi = 0; +} + + static bool analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader, int32 sheaderSize, char* buffer, size_t bufferSize) @@ -831,9 +864,9 @@ analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader, // well as cases where e.g. in a gcc 2 program a single C file has // been compiled with gcc 4. if (gccMajor == 0 || gccMajor > version[0] - || gccMajor == version[0] + || (gccMajor == version[0] && (gccMiddle < version[1] - || gccMiddle == version[1] && gccMinor < version[2])) { + || (gccMiddle == version[1] && gccMinor < version[2])))) { gccMajor = version[0]; gccMiddle = version[1]; gccMinor = version[2]; @@ -1311,9 +1344,9 @@ find_undefined_symbol_global(image_t* rootImage, image_t* image, image_t* otherImage = sLoadedImages.head; while (otherImage != NULL) { if (otherImage == rootImage - || otherImage->type != B_ADD_ON_IMAGE + || (otherImage->type != B_ADD_ON_IMAGE && (otherImage->flags - & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0) { + & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) { struct Elf32_Sym *symbol = find_symbol(otherImage, name, B_SYMBOL_TYPE_ANY); if (symbol) { @@ -1542,6 +1575,8 @@ register_image(image_t *image, int fd, const char *path) info.text_size = image->regions[0].vmsize; info.data = (void *)image->regions[1].vmstart; info.data_size = image->regions[1].vmsize; + info.api_version = image->api_version; + info.abi = image->abi; image->id = _kern_register_image(&info, sizeof(image_info)); } @@ -1687,6 +1722,24 @@ load_container(char const *name, image_type type, const char *rpath, goto err2; } + status = map_image(fd, path, image, type == B_APP_IMAGE); + if (status < B_OK) { + FATAL("Could not map image: %s\n", strerror(status)); + status = B_ERROR; + goto err2; + } + + if (!parse_dynamic_segment(image)) { + FATAL("Troubles handling dynamic section\n"); + status = B_BAD_DATA; + goto err3; + } + + if (eheader.e_entry != 0) + image->entry_point = eheader.e_entry + image->regions[0].delta; + + analyze_image_haiku_version_and_abi(image); + if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff, sizeof(ph_buff))) { // If this is the executable image, we init the search path @@ -1709,26 +1762,10 @@ load_container(char const *name, image_type type, const char *rpath, // symbol resolution strategy (fallback is R5-style, if version is // unavailable) if (image->gcc_version.major == 0 - || image->gcc_version.major == 2 && image->gcc_version.middle < 95) { + || (image->gcc_version.major == 2 && image->gcc_version.middle < 95)) { image->find_undefined_symbol = find_undefined_symbol_beos; } - status = map_image(fd, path, image, type == B_APP_IMAGE); - if (status < B_OK) { - FATAL("Could not map image: %s\n", strerror(status)); - status = B_ERROR; - goto err2; - } - - if (!parse_dynamic_segment(image)) { - FATAL("Troubles handling dynamic section\n"); - status = B_BAD_DATA; - goto err3; - } - - if (eheader.e_entry != 0) - image->entry_point = eheader.e_entry + image->regions[0].delta; - image->type = type; register_image(image, fd, path); image_event(image, IMAGE_EVENT_LOADED);