diff options
author | Blue Swirl <blauwirbel@gmail.com> | 2012-02-04 12:18:36 +0000 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2012-02-04 12:18:36 +0000 |
commit | cb437e48ab7ddd9b85843beb524904ee4b565721 (patch) | |
tree | 56b81401aaec347d689102972d028010fd35e8ba | |
parent | 2944e4ece235c74dcce3aa11c456f3645ae594fc (diff) | |
parent | f78b0f05414f911d36afcd52f2330574d5a21952 (diff) | |
download | qemu-cb437e48ab7ddd9b85843beb524904ee4b565721.zip qemu-cb437e48ab7ddd9b85843beb524904ee4b565721.tar.gz qemu-cb437e48ab7ddd9b85843beb524904ee4b565721.tar.bz2 |
Merge branch 'linux-user-for-upstream' of git://git.linaro.org/people/rikuvoipio/qemu
* 'linux-user-for-upstream' of git://git.linaro.org/people/rikuvoipio/qemu:
linux-user: Fix sa_flags byte swaps for mips
linux-user: Define TARGET_QEMU_ESIGRETURN for mips64
linux-user: Define TARGET_QEMU_ESIGRETURN for mipsn32
linux-user: Add default configs for mips64[el]
linux-user: Add default-configs for mipsn32[el]
linux-user: Implement *listxattr syscalls
linux-user/syscall.c: Implement f and l versions of set/get/removexattr
linux-user: Allow NULL value pointer in setxattr and getxattr
linux-user: fix wait* syscall status returns
linux-user/strace.c: Correct errno printing for mmap etc
linux-user: fix QEMU_STRACE=1 segfault
linux-user: add SO_PEERCRED support for getsockopt
linux-user/main.c: Add option to user-mode emulation so that user can specify log file name
linux-user: fake /proc/self/auxv
linux-user: fake /proc/self/stat
linux-user: fake /proc/self/maps
linux-user: add open() hijack infrastructure
linux-user: save auxv length
linux-user: stack_base is now mandatory on all targets
-rw-r--r-- | default-configs/mips64-linux-user.mak | 1 | ||||
-rw-r--r-- | default-configs/mips64el-linux-user.mak | 1 | ||||
-rw-r--r-- | default-configs/mipsn32-linux-user.mak | 1 | ||||
-rw-r--r-- | default-configs/mipsn32el-linux-user.mak | 1 | ||||
-rw-r--r-- | linux-user/elfload.c | 15 | ||||
-rw-r--r-- | linux-user/main.c | 7 | ||||
-rw-r--r-- | linux-user/mips64/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/mipsn32/syscall.h | 3 | ||||
-rw-r--r-- | linux-user/qemu.h | 3 | ||||
-rw-r--r-- | linux-user/signal.c | 8 | ||||
-rw-r--r-- | linux-user/strace.c | 19 | ||||
-rw-r--r-- | linux-user/syscall.c | 303 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 6 |
13 files changed, 332 insertions, 39 deletions
diff --git a/default-configs/mips64-linux-user.mak b/default-configs/mips64-linux-user.mak new file mode 100644 index 0000000..1598bfc --- /dev/null +++ b/default-configs/mips64-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mips64-linux-user diff --git a/default-configs/mips64el-linux-user.mak b/default-configs/mips64el-linux-user.mak new file mode 100644 index 0000000..629f084 --- /dev/null +++ b/default-configs/mips64el-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mips64el-linux-user diff --git a/default-configs/mipsn32-linux-user.mak b/default-configs/mipsn32-linux-user.mak new file mode 100644 index 0000000..5b97919 --- /dev/null +++ b/default-configs/mipsn32-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mipsn32-linux-user diff --git a/default-configs/mipsn32el-linux-user.mak b/default-configs/mipsn32el-linux-user.mak new file mode 100644 index 0000000..d6367ff --- /dev/null +++ b/default-configs/mipsn32el-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mipsn32el-linux-user diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 845be8b..2fd4a93 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1245,6 +1245,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, struct image_info *interp_info) { abi_ulong sp; + abi_ulong sp_auxv; int size; int i; abi_ulong u_rand_bytes; @@ -1316,6 +1317,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, sp -= n; put_user_ual(id, sp); \ } while(0) + sp_auxv = sp; NEW_AUX_ENT (AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ @@ -1346,6 +1348,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, #undef NEW_AUX_ENT info->saved_auxv = sp; + info->auxv_len = sp_auxv - sp; sp = loader_build_argptr(envc, argc, sp, p, 0); return sp; @@ -2326,9 +2329,8 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts) { elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv; elf_addr_t orig_auxv = auxv; - abi_ulong val; void *ptr; - int i, len; + int len = ts->info->auxv_len; /* * Auxiliary vector is stored in target process stack. It contains @@ -2336,15 +2338,6 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts) * strictly necessary but we do it here for sake of completeness. */ - /* find out length of the vector, AT_NULL is terminator */ - i = len = 0; - do { - get_user_ual(val, auxv); - i += 2; - auxv += 2 * sizeof (elf_addr_t); - } while (val != AT_NULL); - len = i * sizeof (elf_addr_t); - /* read in whole auxv vector and copy it to memelfnote */ ptr = lock_user(VERIFY_READ, orig_auxv, len, 0); if (ptr != NULL) { diff --git a/linux-user/main.c b/linux-user/main.c index 64d2208..14bf5f0 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2945,6 +2945,11 @@ static void handle_arg_log(const char *arg) cpu_set_log(mask); } +static void handle_arg_log_filename(const char *arg) +{ + cpu_set_log_filename(arg); +} + static void handle_arg_set_env(const char *arg) { char *r, *p, *token; @@ -3125,6 +3130,8 @@ struct qemu_argument arg_table[] = { #endif {"d", "QEMU_LOG", true, handle_arg_log, "options", "activate log"}, + {"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename, + "logfile", "override default logfile location"}, {"p", "QEMU_PAGESIZE", true, handle_arg_pagesize, "pagesize", "set the host page size to 'pagesize'"}, {"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep, diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index 668a2b9..e436ea5 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -218,4 +218,7 @@ struct target_pt_regs { +/* Nasty hack: define a fake errno value for use by sigreturn. */ +#define TARGET_QEMU_ESIGRETURN 255 + #define UNAME_MACHINE "mips64" diff --git a/linux-user/mipsn32/syscall.h b/linux-user/mipsn32/syscall.h index 4ec506c..ebe98f2 100644 --- a/linux-user/mipsn32/syscall.h +++ b/linux-user/mipsn32/syscall.h @@ -218,4 +218,7 @@ struct target_pt_regs { +/* Nasty hack: define a fake errno value for use by sigreturn. */ +#define TARGET_QEMU_ESIGRETURN 255 + #define UNAME_MACHINE "mips64" diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 55ad9d8..308dbc0 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -48,6 +48,7 @@ struct image_info { abi_ulong code_offset; abi_ulong data_offset; abi_ulong saved_auxv; + abi_ulong auxv_len; abi_ulong arg_start; abi_ulong arg_end; int personality; @@ -123,10 +124,10 @@ typedef struct TaskState { #endif #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) /* Extra fields for semihosted binaries. */ - uint32_t stack_base; uint32_t heap_base; uint32_t heap_limit; #endif + uint32_t stack_base; int used; /* non zero if used */ struct image_info *info; struct linux_binprm *bprm; diff --git a/linux-user/signal.c b/linux-user/signal.c index ded12ca..79a39dc 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -587,7 +587,11 @@ int do_sigaction(int sig, const struct target_sigaction *act, #endif if (oact) { oact->_sa_handler = tswapal(k->_sa_handler); +#if defined(TARGET_MIPS) || defined (TARGET_ALPHA) + oact->sa_flags = bswap32(k->sa_flags); +#else oact->sa_flags = tswapal(k->sa_flags); +#endif #if !defined(TARGET_MIPS) oact->sa_restorer = tswapal(k->sa_restorer); #endif @@ -596,7 +600,11 @@ int do_sigaction(int sig, const struct target_sigaction *act, if (act) { /* FIXME: This is not threadsafe. */ k->_sa_handler = tswapal(act->_sa_handler); +#if defined(TARGET_MIPS) || defined (TARGET_ALPHA) + k->sa_flags = bswap32(act->sa_flags); +#else k->sa_flags = tswapal(act->sa_flags); +#endif #if !defined(TARGET_MIPS) k->sa_restorer = tswapal(act->sa_restorer); #endif diff --git a/linux-user/strace.c b/linux-user/strace.c index 90027a1..05a0d3e 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1,5 +1,4 @@ #include <stdio.h> -#include <errno.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/sem.h> @@ -284,8 +283,13 @@ print_ipc(const struct syscallname *name, static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret) { -if( ret == -1 ) { - gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno)); + char *errstr = NULL; + + if (ret < 0) { + errstr = target_strerror(-ret); + } + if (errstr) { + gemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr); } else { gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); } @@ -1515,14 +1519,19 @@ void print_syscall_ret(int num, abi_long ret) { int i; + char *errstr = NULL; for(i=0;i<nsyscalls;i++) if( scnames[i].nr == num ) { if( scnames[i].result != NULL ) { scnames[i].result(&scnames[i],ret); } else { - if( ret < 0 ) { - gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, target_strerror(-ret)); + if (ret < 0) { + errstr = target_strerror(-ret); + } + if (errstr) { + gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", + -ret, errstr); } else { gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret); } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2bf9e7e..ee8899e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -731,6 +731,9 @@ static inline int is_error(abi_long ret) char *target_strerror(int err) { + if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) { + return NULL; + } return strerror(target_to_host_errno(err)); } @@ -1530,9 +1533,41 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, case TARGET_SO_LINGER: case TARGET_SO_RCVTIMEO: case TARGET_SO_SNDTIMEO: - case TARGET_SO_PEERCRED: case TARGET_SO_PEERNAME: goto unimplemented; + case TARGET_SO_PEERCRED: { + struct ucred cr; + socklen_t crlen; + struct target_ucred *tcr; + + if (get_user_u32(len, optlen)) { + return -TARGET_EFAULT; + } + if (len < 0) { + return -TARGET_EINVAL; + } + + crlen = sizeof(cr); + ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED, + &cr, &crlen)); + if (ret < 0) { + return ret; + } + if (len > crlen) { + len = crlen; + } + if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(cr.pid, &tcr->pid); + __put_user(cr.uid, &tcr->uid); + __put_user(cr.gid, &tcr->gid); + unlock_user_struct(tcr, optval_addr, 1); + if (put_user_u32(len, optlen)) { + return -TARGET_EFAULT; + } + break; + } /* Options with 'int' argument. */ case TARGET_SO_DEBUG: optname = SO_DEBUG; @@ -4600,6 +4635,123 @@ int get_osversion(void) return osversion; } + +static int open_self_maps(void *cpu_env, int fd) +{ + TaskState *ts = ((CPUState *)cpu_env)->opaque; + + dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n", + (unsigned long long)ts->info->stack_limit, + (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1)) + & TARGET_PAGE_MASK, + (unsigned long long)ts->stack_base); + + return 0; +} + +static int open_self_stat(void *cpu_env, int fd) +{ + TaskState *ts = ((CPUState *)cpu_env)->opaque; + abi_ulong start_stack = ts->info->start_stack; + int i; + + for (i = 0; i < 44; i++) { + char buf[128]; + int len; + uint64_t val = 0; + + if (i == 27) { + /* stack bottom */ + val = start_stack; + } + snprintf(buf, sizeof(buf), "%"PRId64 "%c", val, i == 43 ? '\n' : ' '); + len = strlen(buf); + if (write(fd, buf, len) != len) { + return -1; + } + } + + return 0; +} + +static int open_self_auxv(void *cpu_env, int fd) +{ + TaskState *ts = ((CPUState *)cpu_env)->opaque; + abi_ulong auxv = ts->info->saved_auxv; + abi_ulong len = ts->info->auxv_len; + char *ptr; + + /* + * Auxiliary vector is stored in target process stack. + * read in whole auxv vector and copy it to file + */ + ptr = lock_user(VERIFY_READ, auxv, len, 0); + if (ptr != NULL) { + while (len > 0) { + ssize_t r; + r = write(fd, ptr, len); + if (r <= 0) { + break; + } + len -= r; + ptr += r; + } + lseek(fd, 0, SEEK_SET); + unlock_user(ptr, auxv, len); + } + + return 0; +} + +static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) +{ + struct fake_open { + const char *filename; + int (*fill)(void *cpu_env, int fd); + }; + const struct fake_open *fake_open; + static const struct fake_open fakes[] = { + { "/proc/self/maps", open_self_maps }, + { "/proc/self/stat", open_self_stat }, + { "/proc/self/auxv", open_self_auxv }, + { NULL, NULL } + }; + + for (fake_open = fakes; fake_open->filename; fake_open++) { + if (!strncmp(pathname, fake_open->filename, + strlen(fake_open->filename))) { + break; + } + } + + if (fake_open->filename) { + const char *tmpdir; + char filename[PATH_MAX]; + int fd, r; + + /* create temporary file to map stat to */ + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir); + fd = mkstemp(filename); + if (fd < 0) { + return fd; + } + unlink(filename); + + if ((r = fake_open->fill(cpu_env, fd))) { + close(fd); + return r; + } + lseek(fd, 0, SEEK_SET); + + return fd; + } + + return get_errno(open(path(pathname), flags, mode)); +} + /* do_syscall() should always have a single exit point at the end so that actions, such as logging of syscall results, can be performed. All errnos that do_syscall() returns must be -TARGET_<errcode>. */ @@ -4685,9 +4837,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_open: if (!(p = lock_user_string(arg1))) goto efault; - ret = get_errno(open(path(p), - target_to_host_bitmask(arg2, fcntl_flags_tbl), - arg3)); + ret = get_errno(do_open(cpu_env, p, + target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_openat) && defined(__NR_openat) @@ -4715,7 +4867,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { int status; ret = get_errno(waitpid(arg1, &status, arg3)); - if (!is_error(ret) && arg2 + if (!is_error(ret) && arg2 && ret && put_user_s32(host_to_target_waitstatus(status), arg2)) goto efault; } @@ -6271,7 +6423,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, rusage_ptr = NULL; ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); if (!is_error(ret)) { - if (status_ptr) { + if (status_ptr && ret) { status = host_to_target_waitstatus(status); if (put_user_s32(status, status_ptr)) goto efault; @@ -7644,25 +7796,64 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef CONFIG_ATTR #ifdef TARGET_NR_setxattr - case TARGET_NR_lsetxattr: - case TARGET_NR_fsetxattr: - case TARGET_NR_lgetxattr: - case TARGET_NR_fgetxattr: case TARGET_NR_listxattr: case TARGET_NR_llistxattr: + { + void *p, *b = 0; + if (arg2) { + b = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!b) { + ret = -TARGET_EFAULT; + break; + } + } + p = lock_user_string(arg1); + if (p) { + if (num == TARGET_NR_listxattr) { + ret = get_errno(listxattr(p, b, arg3)); + } else { + ret = get_errno(llistxattr(p, b, arg3)); + } + } else { + ret = -TARGET_EFAULT; + } + unlock_user(p, arg1, 0); + unlock_user(b, arg2, arg3); + break; + } case TARGET_NR_flistxattr: - case TARGET_NR_lremovexattr: - case TARGET_NR_fremovexattr: - ret = -TARGET_EOPNOTSUPP; + { + void *b = 0; + if (arg2) { + b = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!b) { + ret = -TARGET_EFAULT; + break; + } + } + ret = get_errno(flistxattr(arg1, b, arg3)); + unlock_user(b, arg2, arg3); break; + } case TARGET_NR_setxattr: + case TARGET_NR_lsetxattr: { - void *p, *n, *v; + void *p, *n, *v = 0; + if (arg3) { + v = lock_user(VERIFY_READ, arg3, arg4, 1); + if (!v) { + ret = -TARGET_EFAULT; + break; + } + } p = lock_user_string(arg1); n = lock_user_string(arg2); - v = lock_user(VERIFY_READ, arg3, arg4, 1); - if (p && n && v) { - ret = get_errno(setxattr(p, n, v, arg4, arg5)); + if (p && n) { + if (num == TARGET_NR_setxattr) { + ret = get_errno(setxattr(p, n, v, arg4, arg5)); + } else { + ret = get_errno(lsetxattr(p, n, v, arg4, arg5)); + } } else { ret = -TARGET_EFAULT; } @@ -7671,14 +7862,45 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(v, arg3, 0); } break; + case TARGET_NR_fsetxattr: + { + void *n, *v = 0; + if (arg3) { + v = lock_user(VERIFY_READ, arg3, arg4, 1); + if (!v) { + ret = -TARGET_EFAULT; + break; + } + } + n = lock_user_string(arg2); + if (n) { + ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5)); + } else { + ret = -TARGET_EFAULT; + } + unlock_user(n, arg2, 0); + unlock_user(v, arg3, 0); + } + break; case TARGET_NR_getxattr: + case TARGET_NR_lgetxattr: { - void *p, *n, *v; + void *p, *n, *v = 0; + if (arg3) { + v = lock_user(VERIFY_WRITE, arg3, arg4, 0); + if (!v) { + ret = -TARGET_EFAULT; + break; + } + } p = lock_user_string(arg1); n = lock_user_string(arg2); - v = lock_user(VERIFY_WRITE, arg3, arg4, 0); - if (p && n && v) { - ret = get_errno(getxattr(p, n, v, arg4)); + if (p && n) { + if (num == TARGET_NR_getxattr) { + ret = get_errno(getxattr(p, n, v, arg4)); + } else { + ret = get_errno(lgetxattr(p, n, v, arg4)); + } } else { ret = -TARGET_EFAULT; } @@ -7687,13 +7909,38 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(v, arg3, arg4); } break; + case TARGET_NR_fgetxattr: + { + void *n, *v = 0; + if (arg3) { + v = lock_user(VERIFY_WRITE, arg3, arg4, 0); + if (!v) { + ret = -TARGET_EFAULT; + break; + } + } + n = lock_user_string(arg2); + if (n) { + ret = get_errno(fgetxattr(arg1, n, v, arg4)); + } else { + ret = -TARGET_EFAULT; + } + unlock_user(n, arg2, 0); + unlock_user(v, arg3, arg4); + } + break; case TARGET_NR_removexattr: + case TARGET_NR_lremovexattr: { void *p, *n; p = lock_user_string(arg1); n = lock_user_string(arg2); if (p && n) { - ret = get_errno(removexattr(p, n)); + if (num == TARGET_NR_removexattr) { + ret = get_errno(removexattr(p, n)); + } else { + ret = get_errno(lremovexattr(p, n)); + } } else { ret = -TARGET_EFAULT; } @@ -7701,6 +7948,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(n, arg2, 0); } break; + case TARGET_NR_fremovexattr: + { + void *n; + n = lock_user_string(arg2); + if (n) { + ret = get_errno(fremovexattr(arg1, n)); + } else { + ret = -TARGET_EFAULT; + } + unlock_user(n, arg2, 0); + } + break; #endif #endif /* CONFIG_ATTR */ #ifdef TARGET_NR_set_thread_area diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 2857805..41f0ff8 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2336,3 +2336,9 @@ struct target_rlimit64 { uint64_t rlim_cur; uint64_t rlim_max; }; + +struct target_ucred { + uint32_t pid; + uint32_t uid; + uint32_t gid; +}; |