diff options
author | Mika Westerberg <mika.westerberg@iki.fi> | 2009-03-17 18:52:33 +0200 |
---|---|---|
committer | Lauri Leukkunen <lle@rahina.org> | 2009-03-23 01:37:48 +0200 |
commit | 0a405718da6da1d404c1b2fbcb350e9adc288a6f (patch) | |
tree | 22b271e7f373f834e6dd5f99fccad904e591c6b8 | |
parent | 259e1fe6ead8c8723a6bc3a4035fc5ca822b6556 (diff) |
x86_64 fix: now it is possible to run sb2 in 64-bit host
- Changed inpect_binary() to support 64-bit host binaries
that are exec'd from 32-bit binary.
- Initial shell is now invoked through host shell "trampoline" to
get into the valid sb2 shell.
- Corrected bug in sb2 that always generated ld_library_path_extras,
even when it wasn't needed.
Signed-off-by: Lauri Aarnio <Lauri.Aarnio@iki.fi>
-rw-r--r-- | preload/sb_exec.c | 201 | ||||
-rwxr-xr-x | utils/sb2 | 30 |
2 files changed, 127 insertions, 104 deletions
diff --git a/preload/sb_exec.c b/preload/sb_exec.c index 6d739f2..727f1dd 100644 --- a/preload/sb_exec.c +++ b/preload/sb_exec.c @@ -123,30 +123,21 @@ # error Invalid __BYTE_ORDER #endif -#ifdef __i386__ -# define HOST_ELF_MACHINE EM_386 -#elif defined(__x86_64__) -# define HOST_ELF_MACHINE EM_X86_64 +#if defined(__i386__) || defined(__x86_64__) +/* + * We support exec'ing 64-bit programs from 32-bit programs + * as tools distribution might be 32-bit even in 64-bit machine. + */ +# define HOST_ELF_MACHINE_32 EM_386 +# define HOST_ELF_MACHINE_64 EM_X86_64 #elif defined(__ia64__) -# define HOST_ELF_MACHINE EM_IA_64 +# define HOST_ELF_MACHINE_64 EM_IA_64 #elif defined(__powerpc__) -# define HOST_ELF_MACHINE EM_PPC +# define HOST_ELF_MACHINE_32 EM_PPC #else # error Unsupported host CPU architecture #endif -#ifndef PAGE_MASK -# define PAGE_MASK sysconf(_SC_PAGE_SIZE) -#endif - -#ifdef __x86_64__ -typedef Elf64_Ehdr Elf_Ehdr; -typedef Elf64_Phdr Elf_Phdr; -#else -typedef Elf32_Ehdr Elf_Ehdr; -typedef Elf32_Phdr Elf_Phdr; -#endif - struct target_info { char name[8]; uint16_t machine; @@ -161,7 +152,8 @@ static const struct target_info target_table[] = { { "sh", EM_SH, ELFDATA2LSB, 1 }, }; -static int elf_hdr_match(Elf_Ehdr *ehdr, uint16_t match, int ei_data); +static int elf_hdr_match(const char *region, uint16_t match, int ei_data); +static enum binary_type inspect_elf_binary(const char *); static int prepare_exec(const char *exec_fn_name, const char *orig_file, int file_has_been_mapped, @@ -263,8 +255,13 @@ char **split_to_tokens(char *str) return tokens; } -static int elf_hdr_match(Elf_Ehdr *ehdr, uint16_t match, int ei_data) +static int elf_hdr_match(const char *region, uint16_t match, int ei_data) { + /* + * It is OK to use Elf32_Ehdr here because fields accessed + * in this function are same in both 64-bit and 32-bit ELF formats. + */ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)region; int swap; if (ehdr->e_ident[EI_DATA] != ei_data) @@ -285,21 +282,65 @@ static int elf_hdr_match(Elf_Ehdr *ehdr, uint16_t match, int ei_data) return 0; } +static enum binary_type inspect_elf_binary(const char *region) +{ + assert(region != NULL); + + /* check for hashbang */ + if (region[EI_MAG0] == '#' && region[EI_MAG1] == '!') + return (BIN_HASHBANG); + + /* + * We go through ELF program headers one by one and check + * whether there is interpreter (PT_INTERP) section. + * In that case this is dynamically linked, otherwise + * it is statically linked. + */ +#ifdef HOST_ELF_MACHINE_32 + if (elf_hdr_match(region, HOST_ELF_MACHINE_32, HOST_ELF_DATA)) { + Elf32_Ehdr *eh = (Elf32_Ehdr *)region; + Elf32_Phdr *ph; + size_t ph_entsize = eh->e_phentsize; + int i; + + for (i = 0; i < eh->e_phnum; i++) { + ph = (Elf32_Phdr *) + (region + eh->e_phoff + (i * ph_entsize)); + if (ph->p_type == PT_INTERP) + return (BIN_HOST_DYNAMIC); + } + return (BIN_HOST_STATIC); + } +#endif +#ifdef HOST_ELF_MACHINE_64 + if (elf_hdr_match(region, HOST_ELF_MACHINE_64, HOST_ELF_DATA)) { + Elf64_Ehdr *eh = (Elf64_Ehdr *)region; + Elf64_Phdr *ph; + size_t ph_entsize = eh->e_phentsize; + int i; + + for (i = 0; i < eh->e_phnum; i++) { + ph = (Elf64_Phdr *) + (region + eh->e_phoff + (i * ph_entsize)); + if (ph->p_type == PT_INTERP) + return (BIN_HOST_DYNAMIC); + } + return (BIN_HOST_STATIC); + } +#endif + /* could not identify as host binary */ + return (BIN_UNKNOWN); +} + static enum binary_type inspect_binary(const char *filename) { + static char *target_cpu = NULL; enum binary_type retval; - int fd, phnum, j; + int fd, j; struct stat status; char *region; - unsigned int ph_base, ph_frag, ei_data; + unsigned int ei_data; uint16_t e_machine; -#ifdef __x86_64__ - int64_t reloc0; -#else - int reloc0; -#endif - Elf_Ehdr *ehdr; - Elf_Phdr *phdr; retval = BIN_NONE; /* assume it doesn't exist, until proven otherwise */ if (access_nomap_nolog(filename, X_OK) < 0) { @@ -394,83 +435,59 @@ static enum binary_type inspect_binary(const char *filename) goto _out_close; } - /* check for hashbang */ - - if (region[0] == '#' && region[1] == '!') { - retval = BIN_HASHBANG; + retval = inspect_elf_binary(region); + switch (retval) { + case BIN_HASHBANG: + case BIN_HOST_STATIC: + case BIN_HOST_DYNAMIC: + /* host binary, lets go out of here */ goto _out_munmap; - } - - ehdr = (Elf_Ehdr *) region; - -#ifdef __x86_64__ - if (elf_hdr_match(ehdr, EM_386, HOST_ELF_DATA) || - elf_hdr_match(ehdr, EM_X86_64, HOST_ELF_DATA)) { -#else - if (elf_hdr_match(ehdr, HOST_ELF_MACHINE, HOST_ELF_DATA)) { -#endif - retval = BIN_HOST_STATIC; - phnum = ehdr->e_phnum; - reloc0 = ~0; - ph_base = ehdr->e_phoff & PAGE_MASK; - ph_frag = ehdr->e_phoff - ph_base; - - phdr = (Elf_Phdr *) (region + ph_base + ph_frag); - - for (j = phnum; --j >= 0; ++phdr) - if (PT_LOAD == phdr->p_type && ~0 == reloc0) - reloc0 = phdr->p_vaddr - phdr->p_offset; - - phdr -= phnum; - - for (j = phnum; --j >= 0; ++phdr) { - if (PT_DYNAMIC != phdr->p_type) - continue; - - retval = BIN_HOST_DYNAMIC; - } - } else { - static char *target_cpu = NULL; - - if (!target_cpu) { - target_cpu = sb2__read_string_variable_from_lua__( - "sbox_cpu"); + default: + break; + } - if (!target_cpu) - target_cpu = "arm"; - } + /* + * Target binary. Find out whether it is supported + * by scratchbox2. + */ + if (!target_cpu) { + target_cpu = sb2__read_string_variable_from_lua__( + "sbox_cpu"); - ei_data = ELFDATANONE; - e_machine = EM_NONE; + if (!target_cpu) + target_cpu = "arm"; + } - for (j = 0; (size_t) j < ARRAY_SIZE(target_table); j++) { - const struct target_info *ti = &target_table[j]; + ei_data = ELFDATANONE; + e_machine = EM_NONE; - if (strncmp(target_cpu, ti->name, strlen(ti->name))) - continue; + for (j = 0; (size_t) j < ARRAY_SIZE(target_table); j++) { + const struct target_info *ti = &target_table[j]; - ei_data = ti->default_byteorder; - e_machine = ti->machine; + if (strncmp(target_cpu, ti->name, strlen(ti->name))) + continue; - if (ti->multi_byteorder && - strlen(target_cpu) >= strlen(ti->name) + 2) { - size_t len = strlen(target_cpu); - const char *tail = target_cpu + len - 2; + ei_data = ti->default_byteorder; + e_machine = ti->machine; - if (strcmp(tail, "eb") == 0) - ei_data = ELFDATA2MSB; - else if (strcmp(tail, "el") == 0) - ei_data = ELFDATA2LSB; - } + if (ti->multi_byteorder && + strlen(target_cpu) >= strlen(ti->name) + 2) { + size_t len = strlen(target_cpu); + const char *tail = target_cpu + len - 2; - break; + if (strcmp(tail, "eb") == 0) + ei_data = ELFDATA2MSB; + else if (strcmp(tail, "el") == 0) + ei_data = ELFDATA2LSB; } - if (elf_hdr_match(ehdr, e_machine, ei_data)) - retval = BIN_TARGET; + break; } + if (elf_hdr_match(region, e_machine, ei_data)) + retval = BIN_TARGET; + _out_munmap: munmap(region, status.st_size); _out_close: @@ -726,7 +726,7 @@ END $HOME/.scratchbox2/$tools_basename/locales \ conf_tools_locale_path - if [ ld_so_found != "yes" ]; then + if [ $ld_so_found != "yes" ]; then # ld.so from tools can not be used. Add tools' shared # library locations to the normal LD_LIBRARY_PATH; # this is risky but the best what we can do now @@ -1169,12 +1169,7 @@ fi # set the initial binary name for the mapping engine export __SB2_BINARYNAME="bash" - -if [ -n "$SBOX_TOOLS_ROOT" ]; then - SHELL=$SBOX_TOOLS_ROOT/bin/bash -else - SHELL=/bin/bash -fi +SHELL=/bin/bash # Final addition to LD_LIBRARY_PATH, if needed if [ -f $SBOX_SESSION_DIR/ld_library_path_extras ]; then @@ -1248,14 +1243,25 @@ unset SBOX_TOOLS_ROOT # ------------ +# +# We need to start "trampoline" host shell that is run under +# influence of libsb2.so.1. When it exec's real shell, we can +# be sure that all mappings and exec rules are in place. +# if [ $# -gt 0 -o "$STDIN" = true ]; then binary="$1" shift 1 args="$@" - exec $SBOX_FAKEROOT_PREFIX sb2-monitor -L $SBOX_LIBSB2 -x $SBOX_DIR/share/scratchbox2/scripts/sb2-exitreport \ - -- $SHELL -c "$binary $args" + exec $SBOX_FAKEROOT_PREFIX sb2-monitor \ + -L $SBOX_LIBSB2 \ + -x $SBOX_DIR/share/scratchbox2/scripts/sb2-exitreport \ + -- \ + $SHELL -c "exec $SHELL -c '$binary $args'" else - exec $SBOX_FAKEROOT_PREFIX sb2-monitor -L $SBOX_LIBSB2 -x $SBOX_DIR/share/scratchbox2/scripts/sb2-exitreport \ - -- $SHELL --noprofile --norc + exec $SBOX_FAKEROOT_PREFIX sb2-monitor \ + -L $SBOX_LIBSB2 \ + -x $SBOX_DIR/share/scratchbox2/scripts/sb2-exitreport \ + -- \ + $SHELL -c \ + "export PS1='$PS1'; exec $SHELL --noprofile --norc" fi - |