Commit cb437e48 authored by Blue Swirl's avatar Blue Swirl

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
parents 2944e4ec f78b0f05
# Default configuration for mips64-linux-user
# Default configuration for mips64el-linux-user
# Default configuration for mipsn32-linux-user
# Default configuration for mipsn32el-linux-user
......@@ -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) {
......
......@@ -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,
......
......@@ -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"
......@@ -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"
......@@ -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;
......
......@@ -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
......
#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);
}
......
......@@ -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
......
......@@ -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;
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment