From 2716cfd3d79e5e71870527afc66de278430cc8d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 10 Oct 2008 22:13:05 +0000 Subject: [PATCH] * Threw away the broken stat() vs. _stat() mechanism to allow for more fields in struct stat. * Instead, I followed Marcus' great idea and added a compatibility check in the runtime loader: now, R5 binaries (also shared libraries) are detected, and they get special versions for stat(), fstat(), and lstat() that return the smaller stat struct. * However, I've disabled (in src/system/libroot/posix/sys/stat.c) using the larger stat field for now, as this breaks some of our optional packages. So until we rebuild them all, this shouldn't be enabled. * This should now also be used for BeOS compatibility in libnetwork.so. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27961 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/posix/sys/stat.h | 23 +----- .../private/runtime_loader/runtime_loader.h | 1 + src/system/libroot/posix/sys/stat.c | 48 +++++++----- src/system/runtime_loader/elf.cpp | 75 ++++++++++++++----- 4 files changed, 90 insertions(+), 57 deletions(-) diff --git a/headers/posix/sys/stat.h b/headers/posix/sys/stat.h index 194378a0a2..ad060a9d84 100644 --- a/headers/posix/sys/stat.h +++ b/headers/posix/sys/stat.h @@ -23,11 +23,6 @@ struct stat { time_t st_mtime; /* last modification time */ time_t st_ctime; /* last change time, not creation time */ time_t st_crtime; /* creation time */ - - /* Haiku extensions: - * TODO: we might also define special types for files and TTYs - * TODO: we should find another solution for this, as BStatable::GetStat() - * can only retrieve the R5 stat structure */ unsigned int st_type; /* attribute/index type */ blkcnt_t st_blocks; /* number of blocks allocated for object */ }; @@ -104,24 +99,12 @@ extern "C" { extern int chmod(const char *path, mode_t mode); extern int fchmod(int fd, mode_t mode); -extern int _stat(const char *path, struct stat *st, size_t statSize); -extern int _fstat(int fd, struct stat *st, size_t statSize); -extern int _lstat(const char *path, struct stat *st, size_t statSize); -extern int mkdir(const char *path, mode_t mode); -extern int mkfifo(const char *path, mode_t mode); -extern mode_t umask(mode_t cmask); - -/* This achieves backwards compatibility with R5 */ -#if 0 /* def HAIKU_TARGET_PLATFORM_HAIKU */ -#define stat(fd, st) _stat(fd, st, sizeof(struct stat)) -#define fstat(fd, st) _fstat(fd, st, sizeof(struct stat)) -#define lstat(fd, st) _lstat(fd, st, sizeof(struct stat)) -#else -/* ... and this fixes the build for R5 for now */ extern int stat(const char *path, struct stat *st); extern int fstat(int fd, struct stat *st); extern int lstat(const char *path, struct stat *st); -#endif +extern int mkdir(const char *path, mode_t mode); +extern int mkfifo(const char *path, mode_t mode); +extern mode_t umask(mode_t cmask); #ifdef __cplusplus } diff --git a/headers/private/runtime_loader/runtime_loader.h b/headers/private/runtime_loader/runtime_loader.h index 15266e3390..99230ca1e7 100644 --- a/headers/private/runtime_loader/runtime_loader.h +++ b/headers/private/runtime_loader/runtime_loader.h @@ -43,6 +43,7 @@ typedef struct image_t { int major; int middle; int minor; + bool haiku; } gcc_version; addr_t entry_point; diff --git a/src/system/libroot/posix/sys/stat.c b/src/system/libroot/posix/sys/stat.c index 434d43fda6..1d6890e56c 100644 --- a/src/system/libroot/posix/sys/stat.c +++ b/src/system/libroot/posix/sys/stat.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. */ @@ -18,63 +18,71 @@ return err; -// R5 compatibility -#define R5_STAT_SIZE 60 -#undef stat -#undef fstat -#undef lstat - -extern int stat(const char *path, struct stat *stat); -extern int fstat(int fd, struct stat *stat); -extern int lstat(const char *path, struct stat *stat); +// BeOS compatibility +#define BEOS_STAT_SIZE 60 int stat(const char *path, struct stat *stat) { - return _stat(path, stat, R5_STAT_SIZE); + int status = _kern_read_stat(-1, path, true, stat, BEOS_STAT_SIZE/*sizeof(struct stat)*/); + + RETURN_AND_SET_ERRNO(status); } int fstat(int fd, struct stat *stat) { - return _fstat(fd, stat, R5_STAT_SIZE); + int status = _kern_read_stat(fd, NULL, false, stat, BEOS_STAT_SIZE/*sizeof(struct stat)*/); + + RETURN_AND_SET_ERRNO(status); } int lstat(const char *path, struct stat *stat) { - return _lstat(path, stat, R5_STAT_SIZE); + int status = _kern_read_stat(-1, path, false, stat, BEOS_STAT_SIZE/*sizeof(struct stat)*/); + + RETURN_AND_SET_ERRNO(status); } -// #pragma mark - +// #pragma mark - BeOS compatibility + + +#ifndef _KERNEL_MODE + +int __be_stat(const char *path, struct stat *stat); +int __be_fstat(int fd, struct stat *stat); +int __be_lstat(const char *path, struct stat *stat); int -_stat(const char *path, struct stat *stat, size_t statSize) +__be_stat(const char *path, struct stat *stat) { - int status = _kern_read_stat(-1, path, true, stat, statSize); + int status = _kern_read_stat(-1, path, true, stat, BEOS_STAT_SIZE); RETURN_AND_SET_ERRNO(status); } int -_lstat(const char *path, struct stat *stat, size_t statSize) +__be_fstat(int fd, struct stat *stat) { - int status = _kern_read_stat(-1, path, false, stat, statSize); + int status = _kern_read_stat(fd, NULL, false, stat, BEOS_STAT_SIZE); RETURN_AND_SET_ERRNO(status); } int -_fstat(int fd, struct stat *stat, size_t statSize) +__be_lstat(const char *path, struct stat *stat) { - int status = _kern_read_stat(fd, NULL, false, stat, statSize); + int status = _kern_read_stat(-1, path, false, stat, BEOS_STAT_SIZE); RETURN_AND_SET_ERRNO(status); } + +#endif // !_KERNEL_MODE diff --git a/src/system/runtime_loader/elf.cpp b/src/system/runtime_loader/elf.cpp index 2328e6e849..b9c9fc1ea6 100644 --- a/src/system/runtime_loader/elf.cpp +++ b/src/system/runtime_loader/elf.cpp @@ -651,6 +651,7 @@ analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader, int gccMajor = 0; int gccMiddle = 0; int gccMinor = 0; + bool isHaiku = true; // Read up to 10 comments. The first three or four are usually from the // glue code. @@ -720,11 +721,15 @@ analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader, gccMiddle = version[1]; gccMinor = version[2]; } + + if (gccMajor == 2 && strcmp(gccPlatform, "haiku")) + isHaiku = false; } image->gcc_version.major = gccMajor; image->gcc_version.middle = gccMiddle; image->gcc_version.minor = gccMinor; + image->gcc_version.haiku = isHaiku; return gccMajor != 0; } @@ -1099,47 +1104,83 @@ find_undefined_symbol(image_t* rootImage, image_t* image, const char* name, } +/*! This functions is called when we run BeOS images on Haiku. + It allows us to redirect functions to ensure compatibility. +*/ +static const char* +beos_compatibility_map_symbol(const char* symbolName) +{ + struct symbol_mapping { + const char* from; + const char* to; + }; + static const struct symbol_mapping kMappings[] = { + // TODO: improve this, and also use it for libnet.so compatibility! + {"fstat", "__be_fstat"}, + {"lstat", "__be_lstat"}, + {"stat", "__be_stat"}, + }; + const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]); + + for (uint32 i = 0; i < kMappingCount; i++) { + if (!strcmp(symbolName, kMappings[i].from)) + return kMappings[i].to; + } + + return symbolName; +} + + int resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym, - addr_t *sym_addr) + addr_t *symAddress) { - struct Elf32_Sym *sym2; - char *symname; - image_t *shimg; - switch (sym->st_shndx) { case SHN_UNDEF: + { + struct Elf32_Sym *sharedSym; + image_t *sharedImage; + const char *symName; + // patch the symbol name - symname = SYMNAME(image, sym); + symName = SYMNAME(image, sym); + if (!image->gcc_version.haiku) { + // The image has been compiled with a BeOS compiler. This means + // we'll have to redirect some functions for compatibility. + symName = beos_compatibility_map_symbol(symName); + } // it's undefined, must be outside this image, try the other images - sym2 = find_undefined_symbol(rootImage, image, symname, &shimg); - if (!sym2) { + sharedSym = find_undefined_symbol(rootImage, image, symName, + &sharedImage); + if (sharedSym == NULL) { FATAL("elf_resolve_symbol: could not resolve symbol '%s'\n", - symname); + symName); return B_MISSING_SYMBOL; } // make sure they're the same type if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE - && ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) { + && ELF32_ST_TYPE(sym->st_info) + != ELF32_ST_TYPE(sharedSym->st_info)) { FATAL("elf_resolve_symbol: found symbol '%s' in shared image " - "but wrong type\n", symname); + "but wrong type\n", symName); return B_MISSING_SYMBOL; } - if (ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL - && ELF32_ST_BIND(sym2->st_info) != STB_WEAK) { + if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL + && ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) { FATAL("elf_resolve_symbol: found symbol '%s' but not " - "exported\n", symname); + "exported\n", symName); return B_MISSING_SYMBOL; } - *sym_addr = sym2->st_value + shimg->regions[0].delta; + *symAddress = sharedSym->st_value + sharedImage->regions[0].delta; return B_NO_ERROR; + } case SHN_ABS: - *sym_addr = sym->st_value + image->regions[0].delta; + *symAddress = sym->st_value + image->regions[0].delta; return B_NO_ERROR; case SHN_COMMON: @@ -1149,7 +1190,7 @@ resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym, default: // standard symbol - *sym_addr = sym->st_value + image->regions[0].delta; + *symAddress = sym->st_value + image->regions[0].delta; return B_NO_ERROR; } }