From d0fd11ffd3e2cb65234da354f14d745e5fbfce67 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Sat, 28 Jan 2012 22:00:17 +0200 Subject: [PATCH 01/19] linux-user: stack_base is now mandatory on all targets Signed-off-by: Riku Voipio --- linux-user/qemu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 55ad9d858..30e2abd83 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -123,10 +123,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; From 125b0f55b63d11518f7d17480c795697c98b9bd3 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 28 Jan 2012 21:12:14 +0200 Subject: [PATCH 02/19] linux-user: save auxv length We create our own AUXV segment on stack and save a pointer to it. However we don't save the length of it, so any code that wants to do anything useful with it later on has to walk it again. Instead, let's remember the length of our AUXV segment. This simplifies later uses by a lot. (edited by Riku to apply to qemu HEAD) Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/elfload.c | 15 ++++----------- linux-user/qemu.h | 1 + 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 845be8be3..2fd4a93f8 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/qemu.h b/linux-user/qemu.h index 30e2abd83..308dbc025 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; From 3be14d05d45774b67398debe42e3bb5524998f4f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 2 Nov 2011 20:23:23 +0100 Subject: [PATCH 03/19] linux-user: add open() hijack infrastructure There are a number of files in /proc that expose host information to the guest program. This patch adds infrastructure to override the open() syscall for guest programs to enable us to on the fly generate guest sensible files. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 52 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2bf9e7ec4..e100025b0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4600,6 +4600,52 @@ int get_osversion(void) return osversion; } +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[] = { + { 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_. */ @@ -4685,9 +4731,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) From 36c08d498b8ea6995666b805d37c6bb14da66a97 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 2 Nov 2011 20:23:24 +0100 Subject: [PATCH 04/19] linux-user: fake /proc/self/maps glibc's pthread_attr_getstack tries to find the stack range from /proc/self/maps. Unfortunately, /proc is usually the host's /proc which means linux-user guests see qemu's stack there. Fake the file with a constructed maps entry that exposes the guest's stack range. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e100025b0..1864d7fa1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4600,6 +4600,20 @@ 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 do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) { struct fake_open { @@ -4608,6 +4622,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) }; const struct fake_open *fake_open; static const struct fake_open fakes[] = { + { "/proc/self/maps", open_self_maps }, { NULL, NULL } }; From 480b8e7dd56746c550a8ae9d7d1ba5d22cf1a4ee Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 2 Nov 2011 20:23:25 +0100 Subject: [PATCH 05/19] linux-user: fake /proc/self/stat The boehm gc finds the program's stack starting pointer by checking /proc/self/stat. Unfortunately, so far it reads qemu's stack pointer which clearly is wrong. So let's instead fake the file so the guest program sees the right address. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1864d7fa1..5a5fdac1e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4614,6 +4614,31 @@ static int open_self_maps(void *cpu_env, int fd) 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 do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) { struct fake_open { @@ -4623,6 +4648,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) const struct fake_open *fake_open; static const struct fake_open fakes[] = { { "/proc/self/maps", open_self_maps }, + { "/proc/self/stat", open_self_stat }, { NULL, NULL } }; From 257450ee59fd7e781cb4e2316ddc845c40b9fc42 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 2 Nov 2011 20:23:26 +0100 Subject: [PATCH 06/19] linux-user: fake /proc/self/auxv Gtk tries to read /proc/self/auxv to find its auxv table instead of taking it from its own program memory space. However, when running with linux-user, we see the host's auxv which clearly exposes wrong information. so let's instead expose the guest memory backed auxv tables via /proc/self/auxv as well. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5a5fdac1e..c6bfcd881 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4639,6 +4639,35 @@ static int open_self_stat(void *cpu_env, int fd) 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 { @@ -4649,6 +4678,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) 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 } }; From 50171d42071d492b916f737b227bc6f3751fee7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E9=9F=8B=E4=BB=BB?= Date: Tue, 8 Nov 2011 17:46:44 +0800 Subject: [PATCH 07/19] linux-user/main.c: Add option to user-mode emulation so that user can specify log file name QEMU linux user-mode's default log file name is "/tmp/qemu.log". In order to change the log file name, user need to modify the source code then recompile QEMU. This patch allow user use "-D logfile" option to specify the log file name. Signed-off-by: Chen Wen-Ren Signed-off-by: Riku Voipio --- linux-user/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 64d2208a0..14bf5f0bc 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, From 583359a68922fb91b793a5ad3a2dd4536bf9b99e Mon Sep 17 00:00:00 2001 From: Akos PASZTORY Date: Mon, 14 Nov 2011 15:09:49 +0200 Subject: [PATCH 08/19] linux-user: add SO_PEERCRED support for getsockopt Signed-off-by: Akos PASZTORY Signed-off-by: Riku Voipio --- linux-user/syscall.c | 34 +++++++++++++++++++++++++++++++++- linux-user/syscall_defs.h | 6 ++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c6bfcd881..15b8b2293 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1530,9 +1530,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; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 2857805e1..41f0ff8c7 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; +}; From 962b289ef35087fcd8764e4e29808d8ac90157f7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 21 Nov 2011 12:04:07 +0100 Subject: [PATCH 09/19] linux-user: fix QEMU_STRACE=1 segfault While debugging some issues with QEMU_STRACE I stumbled over segmentation faults that were pretty reproducible. Turns out we tried to treat a normal return value as errno, resulting in an access over array boundaries for the resolution. Fix this by allowing failure to resolve invalid errnos into strings. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/strace.c | 18 ++++++++++++++---- linux-user/syscall.c | 3 +++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 90027a110..269481e7a 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -284,8 +284,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 == -1) { + errstr = target_strerror(errno); + } + if ((ret == -1) && errstr) { + gemu_log(" = -1 errno=%d (%s)\n", errno, errstr); } else { gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); } @@ -1515,14 +1520,19 @@ void print_syscall_ret(int num, abi_long ret) { int i; + char *errstr = NULL; for(i=0;i= ERRNO_TABLE_SIZE) || (err < 0)) { + return NULL; + } return strerror(target_to_host_errno(err)); } From 2a7e12455c1d388e41f4c8d2231fb48a968792cd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Nov 2011 12:21:19 +0000 Subject: [PATCH 10/19] linux-user/strace.c: Correct errno printing for mmap etc Correct the printing of errnos for syscalls which are handled via print_syscall_ret_addr (mmap, mmap2, brk, shmat): errnos are returned as negative returned values at this level, not via the host 'errno' variable. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/strace.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 269481e7a..05a0d3e9d 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -286,11 +285,11 @@ print_syscall_ret_addr(const struct syscallname *name, abi_long ret) { char *errstr = NULL; - if (ret == -1) { - errstr = target_strerror(errno); + if (ret < 0) { + errstr = target_strerror(-ret); } - if ((ret == -1) && errstr) { - gemu_log(" = -1 errno=%d (%s)\n", errno, errstr); + if (errstr) { + gemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr); } else { gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); } From 5379557b8d5acb140c17e00441fda45eae627fed Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 24 Nov 2011 00:44:43 +0100 Subject: [PATCH 11/19] linux-user: fix wait* syscall status returns When calling wait4 or waitpid with a status pointer and WNOHANG, the syscall can potentially not modify the status pointer input. Now if we have guest code like: int status = 0; waitpid(pid, &status, WNOHANG); if (status) then we have to make sure that in case status did not change we actually return the guest's initialized status variable instead of our own uninitialized. We fail to do so today, as we proxy everything through an uninitialized status variable which for me ended up always containing the last error code. This patch fixes some test cases when building yast2-core in OBS for ARM. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 29d92c4af..06b19e047 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4867,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; } @@ -6423,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; From e3c33ec6b07dc4d0503cb43b2114be47fc344d36 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2011 15:37:17 +0000 Subject: [PATCH 12/19] linux-user: Allow NULL value pointer in setxattr and getxattr It's valid to pass a NULL value pointer to setxattr, so don't fail this case EFAULT. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 06b19e047..0a78a185b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7809,11 +7809,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NR_setxattr: { - 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) { + if (p && n) { ret = get_errno(setxattr(p, n, v, arg4, arg5)); } else { ret = -TARGET_EFAULT; @@ -7825,11 +7831,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NR_getxattr: { - 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) { + if (p && n) { ret = get_errno(getxattr(p, n, v, arg4)); } else { ret = -TARGET_EFAULT; From 30297b55f797e5b74d1823b64c52b1bebd2a5d85 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2011 15:37:18 +0000 Subject: [PATCH 13/19] linux-user/syscall.c: Implement f and l versions of set/get/removexattr Implement the f and l versions (operate on fd, don't follow links) of the setxattr, getxattr and removexattr syscalls. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 79 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0a78a185b..762115bad 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7796,18 +7796,13 @@ 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: case TARGET_NR_flistxattr: - case TARGET_NR_lremovexattr: - case TARGET_NR_fremovexattr: ret = -TARGET_EOPNOTSUPP; break; case TARGET_NR_setxattr: + case TARGET_NR_lsetxattr: { void *p, *n, *v = 0; if (arg3) { @@ -7820,7 +7815,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, p = lock_user_string(arg1); n = lock_user_string(arg2); if (p && n) { - ret = get_errno(setxattr(p, n, v, arg4, arg5)); + 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; } @@ -7829,7 +7828,28 @@ 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 = 0; if (arg3) { @@ -7842,7 +7862,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, p = lock_user_string(arg1); n = lock_user_string(arg2); if (p && n) { - ret = get_errno(getxattr(p, n, v, arg4)); + 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; } @@ -7851,13 +7875,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; } @@ -7865,6 +7914,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 From fb5590f7f5a897fc8e2ff36051fa0aa917ef4053 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2011 15:37:19 +0000 Subject: [PATCH 14/19] linux-user: Implement *listxattr syscalls Implement listxattr, flistxattr and llistxattr syscalls. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 762115bad..ee8899ef3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7798,9 +7798,43 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_setxattr case TARGET_NR_listxattr: case TARGET_NR_llistxattr: - case TARGET_NR_flistxattr: - ret = -TARGET_EOPNOTSUPP; + { + 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: + { + 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: { From 72f341ff7a4aefef03a2b450d12f3278a7c7b552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 29 Dec 2011 16:55:39 +0100 Subject: [PATCH 15/19] linux-user: Add default-configs for mipsn32[el] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepares for mipsn32[el]-linux-user targets. Signed-off-by: Ulricht Hecht Signed-off-by: Andreas Färber Signed-off-by: Riku Voipio --- default-configs/mipsn32-linux-user.mak | 1 + default-configs/mipsn32el-linux-user.mak | 1 + 2 files changed, 2 insertions(+) create mode 100644 default-configs/mipsn32-linux-user.mak create mode 100644 default-configs/mipsn32el-linux-user.mak diff --git a/default-configs/mipsn32-linux-user.mak b/default-configs/mipsn32-linux-user.mak new file mode 100644 index 000000000..5b9791979 --- /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 000000000..d6367ff98 --- /dev/null +++ b/default-configs/mipsn32el-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mipsn32el-linux-user From 10ecb3f66558e3634556eb538305a06f713a39f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 29 Dec 2011 16:55:40 +0100 Subject: [PATCH 16/19] linux-user: Add default configs for mips64[el] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepares for mips64[el]-linux-user targets. Signed-off-by: Khansa Butt Signed-off-by: Andreas Färber Signed-off-by: Riku Voipio --- default-configs/mips64-linux-user.mak | 1 + default-configs/mips64el-linux-user.mak | 1 + 2 files changed, 2 insertions(+) create mode 100644 default-configs/mips64-linux-user.mak create mode 100644 default-configs/mips64el-linux-user.mak diff --git a/default-configs/mips64-linux-user.mak b/default-configs/mips64-linux-user.mak new file mode 100644 index 000000000..1598bfcf7 --- /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 000000000..629f08408 --- /dev/null +++ b/default-configs/mips64el-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mips64el-linux-user From 63249cb9ebaf327ecc30bac90c1625debcd759cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 29 Dec 2011 16:55:41 +0100 Subject: [PATCH 17/19] linux-user: Define TARGET_QEMU_ESIGRETURN for mipsn32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copied from mips/syscall.h. Signed-off-by: Ulrich Hecht Signed-off-by: Andreas Färber Signed-off-by: Riku Voipio --- linux-user/mipsn32/syscall.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/mipsn32/syscall.h b/linux-user/mipsn32/syscall.h index 4ec506cb0..ebe98f207 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" From 2aeb36a897c6de08e9ede9e318d5970855b4b8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 29 Dec 2011 16:55:42 +0100 Subject: [PATCH 18/19] linux-user: Define TARGET_QEMU_ESIGRETURN for mips64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copied from mips/syscall.h. Signed-off-by: Khansa Butt Signed-off-by: Andreas Färber Signed-off-by: Riku Voipio --- linux-user/mips64/syscall.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index 668a2b95d..e436ea57d 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" From f78b0f05414f911d36afcd52f2330574d5a21952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 29 Dec 2011 16:55:43 +0100 Subject: [PATCH 19/19] linux-user: Fix sa_flags byte swaps for mips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sa_flags is uint32_t for mips{,n32,64}, so don't use tswapal(). edited by Riku Voipio: likewise on alpha Reported-by: Khansa Butt Suggested-by: Richard Henderson Signed-off-by: Andreas Färber Cc: Ehsan Ul Haq Signed-off-by: Riku Voipio --- linux-user/signal.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/signal.c b/linux-user/signal.c index ded12caa1..79a39dcd7 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