Merge branch 'linux-user-for-upstream' of git://gitorious.org/qemu-maemo/qemu

* 'linux-user-for-upstream' of git://gitorious.org/qemu-maemo/qemu:
  linux-user: fix for loopmount ioctl
  linux-user: fix build errors for mmap2-only ports
  user: speed up init_paths a bit
  linux-user: implement sched_{g,s}etaffinity
  linux-user/FLAT: allow targets to override FLAT processing
  linux-user/FLAT: fix auto-stack sizing
  linux-user: decode MAP_{UNINITIALIZED,EXECUTABLE} in strace
  linux-user: add ppoll syscall support
  linux-user/elfload: add FDPIC support
  linux-user: fix sizeof handling for getsockopt
  linux-user: Fix possible realloc memory leak
  linux-user: Add support for -version option
This commit is contained in:
Aurelien Jarno 2011-02-09 19:53:36 +01:00
commit 1c0de9fa50
12 changed files with 298 additions and 39 deletions

View File

@ -107,7 +107,7 @@ ifdef CONFIG_LINUX_USER
$(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR))
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \
qemu-malloc.o $(oslib-obj-y)

19
elf.h
View File

@ -1191,6 +1191,25 @@ typedef struct elf64_note {
Elf64_Word n_type; /* Content type */
} Elf64_Nhdr;
/* This data structure represents a PT_LOAD segment. */
struct elf32_fdpic_loadseg {
/* Core address to which the segment is mapped. */
Elf32_Addr addr;
/* VMA recorded in the program header. */
Elf32_Addr p_vaddr;
/* Size of this segment in memory. */
Elf32_Word p_memsz;
};
struct elf32_fdpic_loadmap {
/* Protocol version number, must be zero. */
Elf32_Half version;
/* Number of segments in this map. */
Elf32_Half nsegs;
/* The actual memory map. */
struct elf32_fdpic_loadseg segs[/*nsegs*/];
};
#ifdef ELF_CLASS
#if ELF_CLASS == ELFCLASS32

View File

@ -1075,6 +1075,33 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
}
}
#ifdef CONFIG_USE_FDPIC
static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
{
uint16_t n;
struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
/* elf32_fdpic_loadseg */
n = info->nsegs;
while (n--) {
sp -= 12;
put_user_u32(loadsegs[n].addr, sp+0);
put_user_u32(loadsegs[n].p_vaddr, sp+4);
put_user_u32(loadsegs[n].p_memsz, sp+8);
}
/* elf32_fdpic_loadmap */
sp -= 4;
put_user_u16(0, sp+0); /* version */
put_user_u16(info->nsegs, sp+2); /* nsegs */
info->personality = PER_LINUX_FDPIC;
info->loadmap_addr = sp;
return sp;
}
#endif
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr *exec,
struct image_info *info,
@ -1087,6 +1114,21 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
const int n = sizeof(elf_addr_t);
sp = p;
#ifdef CONFIG_USE_FDPIC
/* Needs to be before we load the env/argc/... */
if (elf_is_fdpic(exec)) {
/* Need 4 byte alignment for these structs */
sp &= ~3;
sp = loader_build_fdpic_loadmap(info, sp);
info->other_info = interp_info;
if (interp_info) {
interp_info->other_info = info;
sp = loader_build_fdpic_loadmap(interp_info, sp);
}
}
#endif
u_platform = 0;
k_platform = ELF_PLATFORM;
if (k_platform) {
@ -1197,6 +1239,11 @@ static void load_elf_image(const char *image_name, int image_fd,
}
bswap_phdr(phdr, ehdr->e_phnum);
#ifdef CONFIG_USE_FDPIC
info->nsegs = 0;
info->pt_dynamic_addr = 0;
#endif
/* Find the maximum size of the image and allocate an appropriate
amount of memory to handle that. */
loaddr = -1, hiaddr = 0;
@ -1210,6 +1257,9 @@ static void load_elf_image(const char *image_name, int image_fd,
if (a > hiaddr) {
hiaddr = a;
}
#ifdef CONFIG_USE_FDPIC
++info->nsegs;
#endif
}
}
@ -1290,6 +1340,27 @@ static void load_elf_image(const char *image_name, int image_fd,
}
load_bias = load_addr - loaddr;
#ifdef CONFIG_USE_FDPIC
{
struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
qemu_malloc(sizeof(*loadsegs) * info->nsegs);
for (i = 0; i < ehdr->e_phnum; ++i) {
switch (phdr[i].p_type) {
case PT_DYNAMIC:
info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
break;
case PT_LOAD:
loadsegs->addr = phdr[i].p_vaddr + load_bias;
loadsegs->p_vaddr = phdr[i].p_vaddr;
loadsegs->p_memsz = phdr[i].p_memsz;
++loadsegs;
break;
}
}
}
#endif
info->load_bias = load_bias;
info->load_addr = load_addr;
info->entry = ehdr->e_entry + load_bias;
@ -1481,7 +1552,7 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
struct elf_shdr *shdr;
char *strings;
struct syminfo *s;
struct elf_sym *syms;
struct elf_sym *syms, *new_syms;
shnum = hdr->e_shnum;
i = shnum * sizeof(struct elf_shdr);
@ -1550,12 +1621,14 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
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. */
syms = realloc(syms, nsyms * sizeof(*syms));
if (syms == NULL) {
new_syms = realloc(syms, nsyms * sizeof(*syms));
if (new_syms == NULL) {
free(s);
free(syms);
free(strings);
return;
}
syms = new_syms;
qsort(syms, nsyms, sizeof(*syms), symcmp);

View File

@ -41,6 +41,8 @@
#include "qemu.h"
#include "flat.h"
#define ntohl(x) be32_to_cpu(x)
#include <target_flat.h>
//#define DEBUG
@ -50,14 +52,6 @@
#define DBG_FLT(...)
#endif
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
#define flat_old_ram_flag(flag) (flag)
#ifdef TARGET_WORDS_BIGENDIAN
#define flat_get_relocate_addr(relval) (relval)
#else
#define flat_get_relocate_addr(relval) bswap32(relval)
#endif
#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */
#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */
@ -78,8 +72,6 @@ static int load_flat_shared_library(int id, struct lib_info *p);
struct linux_binprm;
#define ntohl(x) be32_to_cpu(x)
/****************************************************************************/
/*
* create_flat_tables() parses the env- and arg-strings in new user
@ -625,6 +617,7 @@ static int load_flat_file(struct linux_binprm * bprm,
* __start to address 4 so that is okay).
*/
if (rev > OLD_FLAT_VERSION) {
abi_ulong persistent = 0;
for (i = 0; i < relocs; i++) {
abi_ulong addr, relval;
@ -633,6 +626,9 @@ static int load_flat_file(struct linux_binprm * bprm,
relocated first). */
if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
return -EFAULT;
relval = ntohl(relval);
if (flat_set_persistent(relval, &persistent))
continue;
addr = flat_get_relocate_addr(relval);
rp = calc_reloc(addr, libinfo, id, 1);
if (rp == RELOC_FAILED)
@ -641,22 +637,20 @@ static int load_flat_file(struct linux_binprm * bprm,
/* Get the pointer's value. */
if (get_user_ual(addr, rp))
return -EFAULT;
addr = flat_get_addr_from_rp(rp, relval, flags, &persistent);
if (addr != 0) {
/*
* Do the relocation. PIC relocs in the data section are
* already in target order
*/
#ifndef TARGET_WORDS_BIGENDIAN
if ((flags & FLAT_FLAG_GOTPIC) == 0)
addr = bswap32(addr);
#endif
addr = ntohl(addr);
addr = calc_reloc(addr, libinfo, id, 0);
if (addr == RELOC_FAILED)
return -ENOEXEC;
/* Write back the relocated pointer. */
if (put_user_ual(addr, rp))
if (flat_put_addr_at_rp(rp, addr, relval))
return -EFAULT;
}
}
@ -733,8 +727,15 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
* pedantic and include space for the argv/envp array as it may have
* a lot of entries.
*/
#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
stack_len = TOP_OF_ARGS - bprm->p; /* the strings */
stack_len = 0;
for (i = 0; i < bprm->argc; ++i) {
/* the argv strings */
stack_len += strlen(bprm->argv[i]);
}
for (i = 0; i < bprm->envc; ++i) {
/* the envp strings */
stack_len += strlen(bprm->envp[i]);
}
stack_len += (bprm->argc + 1) * 4; /* the argv array */
stack_len += (bprm->envc + 1) * 4; /* the envp array */
@ -775,7 +776,8 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
stack_len *= sizeof(abi_ulong);
if ((sp + stack_len) & 15)
sp -= 16 - ((sp + stack_len) & 15);
sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p,
flat_argvp_envp_on_stack());
/* Fake some return addresses to ensure the call chain will
* initialise library in order for us. We are required to call

View File

@ -312,10 +312,8 @@
IOCTL(LOOP_CLR_FD, 0, TYPE_INT)
IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info)))
IOCTL(LOOP_GET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info)))
#if 0 /* These have some problems - not fully tested */
IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64)))
IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64)))
#endif
IOCTL(LOOP_CHANGE_FD, 0, TYPE_INT)
IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop)))

View File

@ -2624,14 +2624,21 @@ void cpu_loop (CPUState *env)
}
#endif /* TARGET_ALPHA */
static void version(void)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
", Copyright (c) 2003-2008 Fabrice Bellard\n");
}
static void usage(void)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
"usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
version();
printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
"Standard options:\n"
"-h print this help\n"
"-version display version information and exit\n"
"-g port wait gdb connection to port\n"
"-L path set the elf interpreter prefix (default=%s)\n"
"-s size set the stack size in bytes (default=%ld)\n"
@ -2886,8 +2893,10 @@ int main(int argc, char **argv, char **envp)
singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else
{
} else if (!strcmp(r, "version")) {
version();
exit(0);
} else {
usage();
}
}

View File

@ -51,6 +51,13 @@ struct image_info {
abi_ulong arg_start;
abi_ulong arg_end;
int personality;
#ifdef CONFIG_USE_FDPIC
abi_ulong loadmap_addr;
uint16_t nsegs;
void *loadsegs;
abi_ulong pt_dynamic_addr;
struct image_info *other_info;
#endif
};
#ifdef TARGET_I386

View File

@ -398,6 +398,7 @@ UNUSED static struct flags mmap_flags[] = {
FLAG_TARGET(MAP_DENYWRITE),
FLAG_TARGET(MAP_FIXED),
FLAG_TARGET(MAP_GROWSDOWN),
FLAG_TARGET(MAP_EXECUTABLE),
#ifdef MAP_LOCKED
FLAG_TARGET(MAP_LOCKED),
#endif
@ -407,6 +408,9 @@ UNUSED static struct flags mmap_flags[] = {
FLAG_TARGET(MAP_NORESERVE),
#ifdef MAP_POPULATE
FLAG_TARGET(MAP_POPULATE),
#endif
#ifdef TARGET_MAP_UNINITIALIZED
FLAG_TARGET(MAP_UNINITIALIZED),
#endif
FLAG_END,
};
@ -1199,7 +1203,7 @@ print_utimensat(const struct syscallname *name,
}
#endif
#ifdef TARGET_NR_mmap
#if defined(TARGET_NR_mmap) || defined(TARGET_NR_mmap2)
static void
print_mmap(const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,

View File

@ -235,6 +235,12 @@ _syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
const struct timespec *,timeout,int *,uaddr2,int,val3)
#endif
#endif
#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr);
#define __NR_sys_sched_setaffinity __NR_sched_setaffinity
_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr);
static bitmask_transtbl fcntl_flags_tbl[] = {
{ TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
@ -529,6 +535,15 @@ static int sys_inotify_init1(int flags)
#undef TARGET_NR_inotify_rm_watch
#endif /* CONFIG_INOTIFY */
#if defined(TARGET_NR_ppoll)
#ifndef __NR_ppoll
# define __NR_ppoll -1
#endif
#define __NR_sys_ppoll __NR_ppoll
_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
struct timespec *, timeout, const __sigset_t *, sigmask,
size_t, sigsetsize)
#endif
extern int personality(int);
extern int flock(int, int);
@ -1448,7 +1463,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
return -TARGET_EFAULT;
if (len < 0)
return -TARGET_EINVAL;
lv = sizeof(int);
lv = sizeof(lv);
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
if (ret < 0)
return ret;
@ -1485,7 +1500,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
return -TARGET_EFAULT;
if (len < 0)
return -TARGET_EINVAL;
lv = sizeof(int);
lv = sizeof(lv);
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
if (ret < 0)
return ret;
@ -6230,8 +6245,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = do_select(arg1, arg2, arg3, arg4, arg5);
break;
#endif
#ifdef TARGET_NR_poll
#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
# ifdef TARGET_NR_poll
case TARGET_NR_poll:
# endif
# ifdef TARGET_NR_ppoll
case TARGET_NR_ppoll:
# endif
{
struct target_pollfd *target_pfd;
unsigned int nfds = arg2;
@ -6242,12 +6262,51 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1);
if (!target_pfd)
goto efault;
pfd = alloca(sizeof(struct pollfd) * nfds);
for(i = 0; i < nfds; i++) {
pfd[i].fd = tswap32(target_pfd[i].fd);
pfd[i].events = tswap16(target_pfd[i].events);
}
# ifdef TARGET_NR_ppoll
if (num == TARGET_NR_ppoll) {
struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
target_sigset_t *target_set;
sigset_t _set, *set = &_set;
if (arg3) {
if (target_to_host_timespec(timeout_ts, arg3)) {
unlock_user(target_pfd, arg1, 0);
goto efault;
}
} else {
timeout_ts = NULL;
}
if (arg4) {
target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
if (!target_set) {
unlock_user(target_pfd, arg1, 0);
goto efault;
}
target_to_host_sigset(set, target_set);
} else {
set = NULL;
}
ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8));
if (!is_error(ret) && arg3) {
host_to_target_timespec(arg3, timeout_ts);
}
if (arg4) {
unlock_user(target_set, arg4, 0);
}
} else
# endif
ret = get_errno(poll(pfd, nfds, timeout));
if (!is_error(ret)) {
for(i = 0; i < nfds; i++) {
target_pfd[i].revents = tswap16(pfd[i].revents);
@ -6301,6 +6360,67 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
return value. */
ret = -TARGET_ENOTDIR;
break;
case TARGET_NR_sched_getaffinity:
{
unsigned int mask_size;
unsigned long *mask;
/*
* sched_getaffinity needs multiples of ulong, so need to take
* care of mismatches between target ulong and host ulong sizes.
*/
if (arg2 & (sizeof(abi_ulong) - 1)) {
ret = -TARGET_EINVAL;
break;
}
mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
mask = alloca(mask_size);
ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
if (!is_error(ret)) {
if (arg2 > ret) {
/* Zero out any extra space kernel didn't fill */
unsigned long zero = arg2 - ret;
p = alloca(zero);
memset(p, 0, zero);
if (copy_to_user(arg3 + zero, p, zero)) {
goto efault;
}
arg2 = ret;
}
if (copy_to_user(arg3, mask, arg2)) {
goto efault;
}
ret = arg2;
}
}
break;
case TARGET_NR_sched_setaffinity:
{
unsigned int mask_size;
unsigned long *mask;
/*
* sched_setaffinity needs multiples of ulong, so need to take
* care of mismatches between target ulong and host ulong sizes.
*/
if (arg2 & (sizeof(abi_ulong) - 1)) {
ret = -TARGET_EINVAL;
break;
}
mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
mask = alloca(mask_size);
if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
goto efault;
}
memcpy(mask, p, arg2);
unlock_user_struct(p, arg2, 0);
ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
}
break;
case TARGET_NR_sched_setparam:
{
struct sched_param *target_schp;

View File

@ -999,6 +999,7 @@ struct target_winsize {
#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
#define TARGET_MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
#define TARGET_MAP_NONBLOCK 0x10000 /* do not block on IO */
#define TARGET_MAP_UNINITIALIZED 0x4000000 /* for anonymous mmap, memory could be uninitialized */
#endif
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_CRIS)

10
linux-user/target_flat.h Normal file
View File

@ -0,0 +1,10 @@
/* If your arch needs to do custom stuff, create your own target_flat.h
* header file in linux-user/<your arch>/
*/
#define flat_argvp_envp_on_stack() 1
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
#define flat_old_ram_flag(flag) (flag)
#define flat_get_relocate_addr(relval) (relval)
#define flat_get_addr_from_rp(rp, relval, flags, persistent) (rp)
#define flat_set_persistent(relval, persistent) (*persistent)
#define flat_put_addr_at_rp(rp, addr, relval) put_user_ual(addr, rp)

28
path.c
View File

@ -38,7 +38,8 @@ static int strneq(const char *s1, unsigned int n, const char *s2)
return s2[i] == 0;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name);
static struct pathelem *add_entry(struct pathelem *root, const char *name,
unsigned char type);
static struct pathelem *new_entry(const char *root,
struct pathelem *parent,
@ -56,6 +57,15 @@ static struct pathelem *new_entry(const char *root,
#define streq(a,b) (strcmp((a), (b)) == 0)
/* Not all systems provide this feature */
#if defined(DT_DIR) && defined(DT_UNKNOWN)
# define dirent_type(dirent) ((dirent)->d_type)
# define is_dir_maybe(type) ((type) == DT_DIR || (type) == DT_UNKNOWN)
#else
# define dirent_type(dirent) (1)
# define is_dir_maybe(type) (type)
#endif
static struct pathelem *add_dir_maybe(struct pathelem *path)
{
DIR *dir;
@ -65,7 +75,7 @@ static struct pathelem *add_dir_maybe(struct pathelem *path)
while ((dirent = readdir(dir)) != NULL) {
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
path = add_entry(path, dirent->d_name);
path = add_entry(path, dirent->d_name, dirent_type(dirent));
}
}
closedir(dir);
@ -73,16 +83,22 @@ static struct pathelem *add_dir_maybe(struct pathelem *path)
return path;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name)
static struct pathelem *add_entry(struct pathelem *root, const char *name,
unsigned char type)
{
struct pathelem **e;
root->num_entries++;
root = realloc(root, sizeof(*root)
+ sizeof(root->entries[0])*root->num_entries);
e = &root->entries[root->num_entries-1];
*e = new_entry(root->pathname, root, name);
if (is_dir_maybe(type)) {
*e = add_dir_maybe(*e);
}
root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
root->entries[root->num_entries-1]
= add_dir_maybe(root->entries[root->num_entries-1]);
return root;
}