/* This is the Linux kernel elf-loading code, ported into user space */
-#include <sys/time.h>
+#include "qemu/osdep.h"
#include <sys/param.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/mman.h>
#include <sys/resource.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
#include "qemu.h"
#include "disas/disas.h"
+#include "qemu/path.h"
#ifdef _ARCH_PPC64
#undef ARCH_DLINFO
#ifdef TARGET_X86_64
#define ELF_START_MMAP 0x2aaaaab000ULL
-#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_X86_64
#define ELF_START_MMAP 0x80000000
-#define elf_check_arch(x) ((x) == ELF_MACHINE)
-
-#define ELF_ARCH ELF_MACHINE
+#define ELF_ARCH EM_ARM
#define ELF_CLASS ELFCLASS32
static inline void init_thread(struct target_pt_regs *regs,
abi_long stack = infop->start_stack;
memset(regs, 0, sizeof(*regs));
- regs->ARM_cpsr = 0x10;
- if (infop->entry & 1)
- regs->ARM_cpsr |= CPSR_T;
- regs->ARM_pc = infop->entry & 0xfffffffe;
- regs->ARM_sp = infop->start_stack;
+ regs->uregs[16] = ARM_CPU_MODE_USR;
+ if (infop->entry & 1) {
+ regs->uregs[16] |= CPSR_T;
+ }
+ regs->uregs[15] = infop->entry & 0xfffffffe;
+ regs->uregs[13] = infop->start_stack;
/* FIXME - what to for failure of get_user()? */
- get_user_ual(regs->ARM_r2, stack + 8); /* envp */
- get_user_ual(regs->ARM_r1, stack + 4); /* envp */
+ get_user_ual(regs->uregs[2], stack + 8); /* envp */
+ get_user_ual(regs->uregs[1], stack + 4); /* envp */
/* XXX: it seems that r0 is zeroed after ! */
- regs->ARM_r0 = 0;
+ regs->uregs[0] = 0;
/* For uClinux PIC binaries. */
/* XXX: Linux does this only on ARM with no MMU (do we care ?) */
- regs->ARM_r10 = infop->start_data;
+ regs->uregs[10] = infop->start_data;
}
#define ELF_NREG 18
/* 64 bit ARM definitions */
#define ELF_START_MMAP 0x80000000
-#define elf_check_arch(x) ((x) == ELF_MACHINE)
-
-#define ELF_ARCH ELF_MACHINE
+#define ELF_ARCH EM_AARCH64
#define ELF_CLASS ELFCLASS64
#define ELF_PLATFORM "aarch64"
#define ELF_START_MMAP 0x80000000
-#define elf_check_arch(x) ((x) == EM_UNICORE32)
-
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_UNICORE32
#define ELF_START_MMAP 0x80000000
#define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
| HWCAP_SPARC_MULDIV)
-#define elf_check_arch(x) ( (x) == EM_SPARC )
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_SPARC
#ifdef TARGET_PPC
+#define ELF_MACHINE PPC_ELF_MACHINE
#define ELF_START_MMAP 0x80000000
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
#else
-#define elf_check_arch(x) ( (x) == EM_PPC )
-
#define ELF_CLASS ELFCLASS32
#endif
Altivec/FP/SPE support. Anything else is just a bonus. */
#define GET_FEATURE(flag, feature) \
do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
-#define GET_FEATURE2(flag, feature) \
- do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
+#define GET_FEATURE2(flags, feature) \
+ do { \
+ if ((cpu->env.insns_flags2 & flags) == flags) { \
+ features |= feature; \
+ } \
+ } while (0)
GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
#define ELF_START_MMAP 0x80000000
-#define elf_check_arch(x) ( (x) == EM_MIPS )
-
#ifdef TARGET_MIPS64
#define ELF_CLASS ELFCLASS64
#else
#endif /* TARGET_MICROBLAZE */
+#ifdef TARGET_NIOS2
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_ALTERA_NIOS2
+
+static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+ regs->ea = infop->entry;
+ regs->sp = infop->start_stack;
+ regs->estatus = 0x3;
+}
+
+#define ELF_EXEC_PAGESIZE 4096
+
+#define USE_ELF_CORE_DUMP
+#define ELF_NREG 49
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */
+static void elf_core_copy_regs(target_elf_gregset_t *regs,
+ const CPUNios2State *env)
+{
+ int i;
+
+ (*regs)[0] = -1;
+ for (i = 1; i < 8; i++) /* r0-r7 */
+ (*regs)[i] = tswapreg(env->regs[i + 7]);
+
+ for (i = 8; i < 16; i++) /* r8-r15 */
+ (*regs)[i] = tswapreg(env->regs[i - 8]);
+
+ for (i = 16; i < 24; i++) /* r16-r23 */
+ (*regs)[i] = tswapreg(env->regs[i + 7]);
+ (*regs)[24] = -1; /* R_ET */
+ (*regs)[25] = -1; /* R_BT */
+ (*regs)[26] = tswapreg(env->regs[R_GP]);
+ (*regs)[27] = tswapreg(env->regs[R_SP]);
+ (*regs)[28] = tswapreg(env->regs[R_FP]);
+ (*regs)[29] = tswapreg(env->regs[R_EA]);
+ (*regs)[30] = -1; /* R_SSTATUS */
+ (*regs)[31] = tswapreg(env->regs[R_RA]);
+
+ (*regs)[32] = tswapreg(env->regs[R_PC]);
+
+ (*regs)[33] = -1; /* R_STATUS */
+ (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
+
+ for (i = 35; i < 49; i++) /* ... */
+ (*regs)[i] = -1;
+}
+
+#endif /* TARGET_NIOS2 */
+
#ifdef TARGET_OPENRISC
#define ELF_START_MMAP 0x08000000
-#define elf_check_arch(x) ((x) == EM_OPENRISC)
-
#define ELF_ARCH EM_OPENRISC
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
for (i = 0; i < 32; i++) {
(*regs)[i] = tswapreg(env->gpr[i]);
}
-
(*regs)[32] = tswapreg(env->pc);
- (*regs)[33] = tswapreg(env->sr);
+ (*regs)[33] = tswapreg(cpu_get_sr(env));
}
#define ELF_HWCAP 0
#define ELF_PLATFORM NULL
#define ELF_START_MMAP 0x80000000
-#define elf_check_arch(x) ( (x) == EM_SH )
-
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_SH
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
+enum {
+ SH_CPU_HAS_FPU = 0x0001, /* Hardware FPU support */
+ SH_CPU_HAS_P2_FLUSH_BUG = 0x0002, /* Need to flush the cache in P2 area */
+ SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
+ SH_CPU_HAS_DSP = 0x0008, /* SH-DSP: DSP support */
+ SH_CPU_HAS_PERF_COUNTER = 0x0010, /* Hardware performance counters */
+ SH_CPU_HAS_PTEA = 0x0020, /* PTEA register */
+ SH_CPU_HAS_LLSC = 0x0040, /* movli.l/movco.l */
+ SH_CPU_HAS_L2_CACHE = 0x0080, /* Secondary cache / URAM */
+ SH_CPU_HAS_OP32 = 0x0100, /* 32-bit instruction support */
+ SH_CPU_HAS_PTEAEX = 0x0200, /* PTE ASID Extension support */
+};
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+ SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
+ uint32_t hwcap = 0;
+
+ hwcap |= SH_CPU_HAS_FPU;
+
+ if (cpu->env.features & SH_FEATURE_SH4A) {
+ hwcap |= SH_CPU_HAS_LLSC;
+ }
+
+ return hwcap;
+}
+
#endif
#ifdef TARGET_CRIS
#define ELF_START_MMAP 0x80000000
-#define elf_check_arch(x) ( (x) == EM_CRIS )
-
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_CRIS
#define ELF_START_MMAP 0x80000000
-#define elf_check_arch(x) ( (x) == EM_68K )
-
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_68K
#define ELF_START_MMAP (0x30000000000ULL)
-#define elf_check_arch(x) ( (x) == ELF_ARCH )
-
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_ALPHA
#define ELF_START_MMAP (0x20000000000ULL)
-#define elf_check_arch(x) ( (x) == ELF_ARCH )
-
#define ELF_CLASS ELFCLASS64
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_S390
#endif /* TARGET_S390X */
+#ifdef TARGET_TILEGX
+
+/* 42 bits real used address, a half for user mode */
+#define ELF_START_MMAP (0x00000020000000000ULL)
+
+#define elf_check_arch(x) ((x) == EM_TILEGX)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_TILEGX
+
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
+{
+ regs->pc = infop->entry;
+ regs->sp = infop->start_stack;
+
+}
+
+#define ELF_EXEC_PAGESIZE 65536 /* TILE-Gx page size is 64KB */
+
+#endif /* TARGET_TILEGX */
+
+#ifdef TARGET_HPPA
+
+#define ELF_START_MMAP 0x80000000
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_PARISC
+#define ELF_PLATFORM "PARISC"
+#define STACK_GROWS_DOWN 0
+#define STACK_ALIGNMENT 64
+
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
+{
+ regs->iaoq[0] = infop->entry;
+ regs->iaoq[1] = infop->entry + 4;
+ regs->gr[23] = 0;
+ regs->gr[24] = infop->arg_start;
+ regs->gr[25] = (infop->arg_end - infop->arg_start) / sizeof(abi_ulong);
+ /* The top-of-stack contains a linkage buffer. */
+ regs->gr[30] = infop->start_stack + 64;
+ regs->gr[31] = infop->entry;
+}
+
+#endif /* TARGET_HPPA */
+
#ifndef ELF_PLATFORM
#define ELF_PLATFORM (NULL)
#endif
+#ifndef ELF_MACHINE
+#define ELF_MACHINE ELF_ARCH
+#endif
+
+#ifndef elf_check_arch
+#define elf_check_arch(x) ((x) == ELF_ARCH)
+#endif
+
#ifndef ELF_HWCAP
#define ELF_HWCAP 0
#endif
+#ifndef STACK_GROWS_DOWN
+#define STACK_GROWS_DOWN 1
+#endif
+
+#ifndef STACK_ALIGNMENT
+#define STACK_ALIGNMENT 16
+#endif
+
#ifdef TARGET_ABI32
#undef ELF_CLASS
#define ELF_CLASS ELFCLASS32
/* Necessary parameters */
#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
-#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
+#define TARGET_ELF_PAGESTART(_v) ((_v) & \
+ ~(abi_ulong)(TARGET_ELF_EXEC_PAGESIZE-1))
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
#define DLINFO_ITEMS 14
* to be put directly into the top of new user memory.
*
*/
-static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
- abi_ulong p)
+static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
+ abi_ulong p, abi_ulong stack_limit)
{
- char *tmp, *tmp1, *pag = NULL;
- int len, offset = 0;
+ char *tmp;
+ int len, i;
+ abi_ulong top = p;
if (!p) {
return 0; /* bullet-proofing */
}
- while (argc-- > 0) {
- tmp = argv[argc];
- if (!tmp) {
- fprintf(stderr, "VFS: argc is wrong");
- exit(-1);
- }
- tmp1 = tmp;
- while (*tmp++);
- len = tmp - tmp1;
- if (p < len) { /* this shouldn't happen - 128kB */
- return 0;
- }
- while (len) {
- --p; --tmp; --len;
- if (--offset < 0) {
- offset = p % TARGET_PAGE_SIZE;
- pag = (char *)page[p/TARGET_PAGE_SIZE];
- if (!pag) {
- pag = g_try_malloc0(TARGET_PAGE_SIZE);
- page[p/TARGET_PAGE_SIZE] = pag;
- if (!pag)
- return 0;
- }
+
+ if (STACK_GROWS_DOWN) {
+ int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
+ for (i = argc - 1; i >= 0; --i) {
+ tmp = argv[i];
+ if (!tmp) {
+ fprintf(stderr, "VFS: argc is wrong");
+ exit(-1);
}
- if (len == 0 || offset == 0) {
- *(pag + offset) = *tmp;
+ len = strlen(tmp) + 1;
+ tmp += len;
+
+ if (len > (p - stack_limit)) {
+ return 0;
}
- else {
+ while (len) {
int bytes_to_copy = (len > offset) ? offset : len;
tmp -= bytes_to_copy;
p -= bytes_to_copy;
offset -= bytes_to_copy;
len -= bytes_to_copy;
- memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
+
+ memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
+
+ if (offset == 0) {
+ memcpy_to_target(p, scratch, top - p);
+ top = p;
+ offset = TARGET_PAGE_SIZE;
+ }
}
}
+ if (p != top) {
+ memcpy_to_target(p, scratch + offset, top - p);
+ }
+ } else {
+ int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
+ for (i = 0; i < argc; ++i) {
+ tmp = argv[i];
+ if (!tmp) {
+ fprintf(stderr, "VFS: argc is wrong");
+ exit(-1);
+ }
+ len = strlen(tmp) + 1;
+ if (len > (stack_limit - p)) {
+ return 0;
+ }
+ while (len) {
+ int bytes_to_copy = (len > remaining) ? remaining : len;
+
+ memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
+
+ tmp += bytes_to_copy;
+ remaining -= bytes_to_copy;
+ p += bytes_to_copy;
+ len -= bytes_to_copy;
+
+ if (remaining == 0) {
+ memcpy_to_target(top, scratch, p - top);
+ top = p;
+ remaining = TARGET_PAGE_SIZE;
+ }
+ }
+ }
+ if (p != top) {
+ memcpy_to_target(top, scratch, p - top);
+ }
}
+
return p;
}
-static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
+/* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
+ * argument/environment space. Newer kernels (>2.6.33) allow more,
+ * dependent on stack size, but guarantee at least 32 pages for
+ * backwards compatibility.
+ */
+#define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
+
+static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
struct image_info *info)
{
- abi_ulong stack_base, size, error, guard;
- int i;
+ abi_ulong size, error, guard;
- /* Create enough stack to hold everything. If we don't use
- it for args, we'll use it for something else. */
size = guest_stack_size;
- if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
- size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+ if (size < STACK_LOWER_LIMIT) {
+ size = STACK_LOWER_LIMIT;
}
guard = TARGET_PAGE_SIZE;
if (guard < qemu_real_host_page_size) {
}
/* We reserve one extra page at the top of the stack as guard. */
- target_mprotect(error, guard, PROT_NONE);
-
- info->stack_limit = error + guard;
- stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
- p += stack_base;
-
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- if (bprm->page[i]) {
- info->rss++;
- /* FIXME - check return value of memcpy_to_target() for failure */
- memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
- g_free(bprm->page[i]);
- }
- stack_base += TARGET_PAGE_SIZE;
+ if (STACK_GROWS_DOWN) {
+ target_mprotect(error, guard, PROT_NONE);
+ info->stack_limit = error + guard;
+ return info->stack_limit + size - sizeof(void *);
+ } else {
+ target_mprotect(error + size, guard, PROT_NONE);
+ info->stack_limit = error + size;
+ return error;
}
- return p;
}
/* Map and zero the bss. We need to explicitly zero any fractional pages
host_start = (uintptr_t) g2h(elf_bss);
host_end = (uintptr_t) g2h(last_bss);
- host_map_start = (host_start + qemu_real_host_page_size - 1);
- host_map_start &= -qemu_real_host_page_size;
+ host_map_start = REAL_HOST_PAGE_ALIGN(host_start);
if (host_map_start < host_end) {
void *p = mmap((void *)host_map_start, host_end - host_map_start,
struct image_info *interp_info)
{
abi_ulong sp;
- abi_ulong sp_auxv;
+ abi_ulong u_argc, u_argv, u_envp, u_auxv;
int size;
int i;
abi_ulong u_rand_bytes;
k_platform = ELF_PLATFORM;
if (k_platform) {
size_t len = strlen(k_platform) + 1;
- sp -= (len + n - 1) & ~(n - 1);
- u_platform = sp;
- /* FIXME - check return value of memcpy_to_target() for failure */
- memcpy_to_target(sp, k_platform, len);
+ if (STACK_GROWS_DOWN) {
+ sp -= (len + n - 1) & ~(n - 1);
+ u_platform = sp;
+ /* FIXME - check return value of memcpy_to_target() for failure */
+ memcpy_to_target(sp, k_platform, len);
+ } else {
+ memcpy_to_target(sp, k_platform, len);
+ u_platform = sp;
+ sp += len + 1;
+ }
+ }
+
+ /* Provide 16 byte alignment for the PRNG, and basic alignment for
+ * the argv and envp pointers.
+ */
+ if (STACK_GROWS_DOWN) {
+ sp = QEMU_ALIGN_DOWN(sp, 16);
+ } else {
+ sp = QEMU_ALIGN_UP(sp, 16);
}
/*
for (i = 0; i < 16; i++) {
k_rand_bytes[i] = rand();
}
- sp -= 16;
- u_rand_bytes = sp;
- /* FIXME - check return value of memcpy_to_target() for failure */
- memcpy_to_target(sp, k_rand_bytes, 16);
+ if (STACK_GROWS_DOWN) {
+ sp -= 16;
+ u_rand_bytes = sp;
+ /* FIXME - check return value of memcpy_to_target() for failure */
+ memcpy_to_target(sp, k_rand_bytes, 16);
+ } else {
+ memcpy_to_target(sp, k_rand_bytes, 16);
+ u_rand_bytes = sp;
+ sp += 16;
+ }
- /*
- * Force 16 byte _final_ alignment here for generality.
- */
- sp = sp &~ (abi_ulong)15;
size = (DLINFO_ITEMS + 1) * 2;
if (k_platform)
size += 2;
size += envc + argc + 2;
size += 1; /* argc itself */
size *= n;
- if (size & 15)
- sp -= 16 - (size & 15);
+
+ /* Allocate space and finalize stack alignment for entry now. */
+ if (STACK_GROWS_DOWN) {
+ u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
+ sp = u_argc;
+ } else {
+ u_argc = sp;
+ sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
+ }
+
+ u_argv = u_argc + n;
+ u_envp = u_argv + (argc + 1) * n;
+ u_auxv = u_envp + (envc + 1) * n;
+ info->saved_auxv = u_auxv;
+ info->arg_start = u_argv;
+ info->arg_end = u_argv + argc * n;
/* This is correct because Linux defines
* elf_addr_t as Elf32_Off / Elf64_Off
*/
#define NEW_AUX_ENT(id, val) do { \
- sp -= n; put_user_ual(val, sp); \
- sp -= n; put_user_ual(id, sp); \
+ put_user_ual(id, u_auxv); u_auxv += n; \
+ put_user_ual(val, u_auxv); u_auxv += n; \
} while(0)
- sp_auxv = sp;
- NEW_AUX_ENT (AT_NULL, 0);
-
/* There must be exactly DLINFO_ITEMS entries here. */
NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
#endif
- if (k_platform)
+ if (u_platform) {
NEW_AUX_ENT(AT_PLATFORM, u_platform);
+ }
#ifdef ARCH_DLINFO
/*
* ARCH_DLINFO must come last so platform specific code can enforce
*/
ARCH_DLINFO;
#endif
+ NEW_AUX_ENT (AT_NULL, 0);
#undef NEW_AUX_ENT
- info->saved_auxv = sp;
- info->auxv_len = sp_auxv - sp;
+ info->auxv_len = u_argv - info->saved_auxv;
+
+ put_user_ual(argc, u_argc);
+
+ p = info->arg_strings;
+ for (i = 0; i < argc; ++i) {
+ put_user_ual(p, u_argv);
+ u_argv += n;
+ p += target_strlen(p) + 1;
+ }
+ put_user_ual(0, u_argv);
+
+ p = info->env_strings;
+ for (i = 0; i < envc; ++i) {
+ put_user_ual(p, u_envp);
+ u_envp += n;
+ p += target_strlen(p) + 1;
+ }
+ put_user_ual(0, u_envp);
- sp = loader_build_argptr(envc, argc, sp, p, 0);
- /* Check the right amount of stack was allocated for auxvec, envp & argv. */
- assert(sp_auxv - sp == size);
return sp;
}
}
}
- qemu_log("Reserved 0x%lx bytes of guest address space\n", host_size);
+ qemu_log_mask(CPU_LOG_PAGE, "Reserved 0x%lx bytes of guest address space\n", host_size);
return real_start;
}
* it explicitly, and set guest_base appropriately.
* In case of error we will print a suitable message and exit.
*/
-#if defined(CONFIG_USE_GUEST_BASE)
const char *errmsg;
if (!have_guest_base && !reserved_va) {
unsigned long host_start, real_start, host_size;
}
guest_base = real_start - loaddr;
- qemu_log("Relocating guest address space from 0x"
- TARGET_ABI_FMT_lx " to 0x%lx\n",
- loaddr, real_start);
+ qemu_log_mask(CPU_LOG_PAGE, "Relocating guest address space from 0x"
+ TARGET_ABI_FMT_lx " to 0x%lx\n",
+ loaddr, real_start);
}
return;
exit_errmsg:
fprintf(stderr, "%s: %s\n", image_name, errmsg);
exit(-1);
-#endif
}
info->pt_dynamic_addr = 0;
#endif
+ mmap_lock();
+
/* Find the maximum size of the image and allocate an appropriate
amount of memory to handle that. */
loaddr = -1, hiaddr = 0;
load_symbols(ehdr, image_fd, load_bias);
}
+ mmap_unlock();
+
close(image_fd);
return;
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
{
int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
+ uint64_t segsz;
struct elf_shdr *shdr;
char *strings = NULL;
struct syminfo *s = NULL;
found:
/* Now know where the strtab and symtab are. Snarf them. */
- s = malloc(sizeof(*s));
+ s = g_try_new(struct syminfo, 1);
if (!s) {
goto give_up;
}
- i = shdr[str_idx].sh_size;
- s->disas_strtab = strings = malloc(i);
- if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
+ segsz = shdr[str_idx].sh_size;
+ s->disas_strtab = strings = g_try_malloc(segsz);
+ if (!strings ||
+ pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) {
goto give_up;
}
- i = shdr[sym_idx].sh_size;
- syms = malloc(i);
- if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
+ segsz = shdr[sym_idx].sh_size;
+ syms = g_try_malloc(segsz);
+ if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
goto give_up;
}
- nsyms = i / sizeof(struct elf_sym);
+ if (segsz / sizeof(struct elf_sym) > INT_MAX) {
+ /* Implausibly large symbol table: give up rather than ploughing
+ * on with the number of symbols calculation overflowing
+ */
+ goto give_up;
+ }
+ nsyms = segsz / sizeof(struct elf_sym);
for (i = 0; i < nsyms; ) {
bswap_sym(syms + i);
/* Throw away entries which we do not need. */
that we threw away. Whether or not this has any effect on the
memory allocation depends on the malloc implementation and how
many symbols we managed to discard. */
- new_syms = realloc(syms, nsyms * sizeof(*syms));
+ new_syms = g_try_renew(struct elf_sym, syms, nsyms);
if (new_syms == NULL) {
goto give_up;
}
return;
give_up:
- free(s);
- free(strings);
- free(syms);
+ g_free(s);
+ g_free(strings);
+ g_free(syms);
}
int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
struct image_info interp_info;
struct elfhdr elf_ex;
char *elf_interpreter = NULL;
+ char *scratch;
info->start_mmap = (abi_ulong)ELF_START_MMAP;
- info->mmap = 0;
- info->rss = 0;
load_elf_image(bprm->filename, bprm->fd, info,
&elf_interpreter, bprm->buf);
when we load the interpreter. */
elf_ex = *(struct elfhdr *)bprm->buf;
- bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
- bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
- bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
+ /* Do this so that we can load the interpreter, if need be. We will
+ change some of these later */
+ bprm->p = setup_arg_pages(bprm, info);
+
+ scratch = g_new0(char, TARGET_PAGE_SIZE);
+ if (STACK_GROWS_DOWN) {
+ bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
+ bprm->p, info->stack_limit);
+ info->file_string = bprm->p;
+ bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
+ bprm->p, info->stack_limit);
+ info->env_strings = bprm->p;
+ bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
+ bprm->p, info->stack_limit);
+ info->arg_strings = bprm->p;
+ } else {
+ info->arg_strings = bprm->p;
+ bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
+ bprm->p, info->stack_limit);
+ info->env_strings = bprm->p;
+ bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
+ bprm->p, info->stack_limit);
+ info->file_string = bprm->p;
+ bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
+ bprm->p, info->stack_limit);
+ }
+
+ g_free(scratch);
+
if (!bprm->p) {
fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
exit(-1);
}
- /* Do this so that we can load the interpreter, if need be. We will
- change some of these later */
- bprm->p = setup_arg_pages(bprm->p, bprm, info);
-
if (elf_interpreter) {
load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
we do not have the power to recompile these, we emulate
the SVr4 behavior. Sigh. */
target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, -1, 0);
+ MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
}
size_t bufsize)
{
char timestamp[64];
- char *filename = NULL;
char *base_filename = NULL;
struct timeval tv;
struct tm tm;
return (-1);
}
- filename = strdup(ts->bprm->filename);
- base_filename = strdup(basename(filename));
+ base_filename = g_path_get_basename(ts->bprm->filename);
(void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
localtime_r(&tv.tv_sec, &tm));
(void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
base_filename, timestamp, (int)getpid());
- free(base_filename);
- free(filename);
+ g_free(base_filename);
return (0);
}
TaskState *ts = (TaskState *)cpu->opaque;
int i;
- info->notes = g_malloc0(NUMNOTES * sizeof (struct memelfnote));
+ info->notes = g_new0(struct memelfnote, NUMNOTES);
if (info->notes == NULL)
return (-ENOMEM);
info->prstatus = g_malloc0(sizeof (*info->prstatus));
if (dump_write(fd, &elf, sizeof (elf)) != 0)
goto out;
- /* fill in in-memory version of notes */
+ /* fill in the in-memory version of notes */
if (fill_note_info(&info, signr, env) < 0)
goto out;
phdr.p_align = ELF_EXEC_PAGESIZE;
bswap_phdr(&phdr, 1);
- dump_write(fd, &phdr, sizeof (phdr));
+ if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
+ goto out;
+ }
}
/*