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);