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
This commit is contained in:
Ingo Weinhold 2009-05-12 21:08:56 +00:00
parent 51c706f70c
commit 593ee7bbc3
5 changed files with 129 additions and 27 deletions

View File

@ -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()

View File

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

View File

@ -20,6 +20,7 @@
#include <AutoDeleter.h>
#include <debug.h>
#include <image_defs.h>
#include <kernel.h>
#include <kimage.h>
#include <syscalls.h>
@ -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);

View File

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

View File

@ -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 <OS.h>
#include <elf32.h>
#include <image_defs.h>
#include <runtime_loader.h>
#include <syscalls.h>
#include <user_runtime.h>
@ -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);