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
This commit is contained in:
Blue Swirl 2012-02-04 12:18:36 +00:00
commit cb437e48ab
13 changed files with 334 additions and 41 deletions

View File

@ -0,0 +1 @@
# Default configuration for mips64-linux-user

View File

@ -0,0 +1 @@
# Default configuration for mips64el-linux-user

View File

@ -0,0 +1 @@
# Default configuration for mipsn32-linux-user

View File

@ -0,0 +1 @@
# Default configuration for mipsn32el-linux-user

View File

@ -1245,6 +1245,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct image_info *interp_info) struct image_info *interp_info)
{ {
abi_ulong sp; abi_ulong sp;
abi_ulong sp_auxv;
int size; int size;
int i; int i;
abi_ulong u_rand_bytes; 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); \ sp -= n; put_user_ual(id, sp); \
} while(0) } while(0)
sp_auxv = sp;
NEW_AUX_ENT (AT_NULL, 0); NEW_AUX_ENT (AT_NULL, 0);
/* There must be exactly DLINFO_ITEMS entries here. */ /* 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 #undef NEW_AUX_ENT
info->saved_auxv = sp; info->saved_auxv = sp;
info->auxv_len = sp_auxv - sp;
sp = loader_build_argptr(envc, argc, sp, p, 0); sp = loader_build_argptr(envc, argc, sp, p, 0);
return sp; 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 auxv = (elf_addr_t)ts->info->saved_auxv;
elf_addr_t orig_auxv = auxv; elf_addr_t orig_auxv = auxv;
abi_ulong val;
void *ptr; void *ptr;
int i, len; int len = ts->info->auxv_len;
/* /*
* Auxiliary vector is stored in target process stack. It contains * 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. * 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 */ /* read in whole auxv vector and copy it to memelfnote */
ptr = lock_user(VERIFY_READ, orig_auxv, len, 0); ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
if (ptr != NULL) { if (ptr != NULL) {

View File

@ -2945,6 +2945,11 @@ static void handle_arg_log(const char *arg)
cpu_set_log(mask); 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) static void handle_arg_set_env(const char *arg)
{ {
char *r, *p, *token; char *r, *p, *token;
@ -3125,6 +3130,8 @@ struct qemu_argument arg_table[] = {
#endif #endif
{"d", "QEMU_LOG", true, handle_arg_log, {"d", "QEMU_LOG", true, handle_arg_log,
"options", "activate 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, {"p", "QEMU_PAGESIZE", true, handle_arg_pagesize,
"pagesize", "set the host page size to 'pagesize'"}, "pagesize", "set the host page size to 'pagesize'"},
{"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep, {"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep,

View File

@ -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" #define UNAME_MACHINE "mips64"

View File

@ -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" #define UNAME_MACHINE "mips64"

View File

@ -48,6 +48,7 @@ struct image_info {
abi_ulong code_offset; abi_ulong code_offset;
abi_ulong data_offset; abi_ulong data_offset;
abi_ulong saved_auxv; abi_ulong saved_auxv;
abi_ulong auxv_len;
abi_ulong arg_start; abi_ulong arg_start;
abi_ulong arg_end; abi_ulong arg_end;
int personality; int personality;
@ -123,10 +124,10 @@ typedef struct TaskState {
#endif #endif
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
/* Extra fields for semihosted binaries. */ /* Extra fields for semihosted binaries. */
uint32_t stack_base;
uint32_t heap_base; uint32_t heap_base;
uint32_t heap_limit; uint32_t heap_limit;
#endif #endif
uint32_t stack_base;
int used; /* non zero if used */ int used; /* non zero if used */
struct image_info *info; struct image_info *info;
struct linux_binprm *bprm; struct linux_binprm *bprm;

View File

@ -587,7 +587,11 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#endif #endif
if (oact) { if (oact) {
oact->_sa_handler = tswapal(k->_sa_handler); 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); oact->sa_flags = tswapal(k->sa_flags);
#endif
#if !defined(TARGET_MIPS) #if !defined(TARGET_MIPS)
oact->sa_restorer = tswapal(k->sa_restorer); oact->sa_restorer = tswapal(k->sa_restorer);
#endif #endif
@ -596,7 +600,11 @@ int do_sigaction(int sig, const struct target_sigaction *act,
if (act) { if (act) {
/* FIXME: This is not threadsafe. */ /* FIXME: This is not threadsafe. */
k->_sa_handler = tswapal(act->_sa_handler); 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); k->sa_flags = tswapal(act->sa_flags);
#endif
#if !defined(TARGET_MIPS) #if !defined(TARGET_MIPS)
k->sa_restorer = tswapal(act->sa_restorer); k->sa_restorer = tswapal(act->sa_restorer);
#endif #endif

View File

@ -1,5 +1,4 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#include <sys/ipc.h> #include <sys/ipc.h>
#include <sys/msg.h> #include <sys/msg.h>
#include <sys/sem.h> #include <sys/sem.h>
@ -284,8 +283,13 @@ print_ipc(const struct syscallname *name,
static void static void
print_syscall_ret_addr(const struct syscallname *name, abi_long ret) print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
{ {
if( ret == -1 ) { char *errstr = NULL;
gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno));
if (ret < 0) {
errstr = target_strerror(-ret);
}
if (errstr) {
gemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr);
} else { } else {
gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
} }
@ -1515,6 +1519,7 @@ void
print_syscall_ret(int num, abi_long ret) print_syscall_ret(int num, abi_long ret)
{ {
int i; int i;
char *errstr = NULL;
for(i=0;i<nsyscalls;i++) for(i=0;i<nsyscalls;i++)
if( scnames[i].nr == num ) { if( scnames[i].nr == num ) {
@ -1522,7 +1527,11 @@ print_syscall_ret(int num, abi_long ret)
scnames[i].result(&scnames[i],ret); scnames[i].result(&scnames[i],ret);
} else { } else {
if (ret < 0) { if (ret < 0) {
gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, target_strerror(-ret)); errstr = target_strerror(-ret);
}
if (errstr) {
gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n",
-ret, errstr);
} else { } else {
gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret); gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
} }

View File

@ -731,6 +731,9 @@ static inline int is_error(abi_long ret)
char *target_strerror(int err) char *target_strerror(int err)
{ {
if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
return NULL;
}
return strerror(target_to_host_errno(err)); 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_LINGER:
case TARGET_SO_RCVTIMEO: case TARGET_SO_RCVTIMEO:
case TARGET_SO_SNDTIMEO: case TARGET_SO_SNDTIMEO:
case TARGET_SO_PEERCRED:
case TARGET_SO_PEERNAME: case TARGET_SO_PEERNAME:
goto unimplemented; 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. */ /* Options with 'int' argument. */
case TARGET_SO_DEBUG: case TARGET_SO_DEBUG:
optname = SO_DEBUG; optname = SO_DEBUG;
@ -4600,6 +4635,123 @@ int get_osversion(void)
return osversion; 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 /* do_syscall() should always have a single exit point at the end so
that actions, such as logging of syscall results, can be performed. that actions, such as logging of syscall results, can be performed.
All errnos that do_syscall() returns must be -TARGET_<errcode>. */ All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@ -4685,7 +4837,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_open: case TARGET_NR_open:
if (!(p = lock_user_string(arg1))) if (!(p = lock_user_string(arg1)))
goto efault; goto efault;
ret = get_errno(open(path(p), ret = get_errno(do_open(cpu_env, p,
target_to_host_bitmask(arg2, fcntl_flags_tbl), target_to_host_bitmask(arg2, fcntl_flags_tbl),
arg3)); arg3));
unlock_user(p, arg1, 0); unlock_user(p, arg1, 0);
@ -4715,7 +4867,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{ {
int status; int status;
ret = get_errno(waitpid(arg1, &status, arg3)); 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)) && put_user_s32(host_to_target_waitstatus(status), arg2))
goto efault; goto efault;
} }
@ -6271,7 +6423,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
rusage_ptr = NULL; rusage_ptr = NULL;
ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
if (!is_error(ret)) { if (!is_error(ret)) {
if (status_ptr) { if (status_ptr && ret) {
status = host_to_target_waitstatus(status); status = host_to_target_waitstatus(status);
if (put_user_s32(status, status_ptr)) if (put_user_s32(status, status_ptr))
goto efault; goto efault;
@ -7644,25 +7796,64 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif #endif
#ifdef CONFIG_ATTR #ifdef CONFIG_ATTR
#ifdef TARGET_NR_setxattr #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_listxattr:
case TARGET_NR_llistxattr: case TARGET_NR_llistxattr:
case TARGET_NR_flistxattr:
case TARGET_NR_lremovexattr:
case TARGET_NR_fremovexattr:
ret = -TARGET_EOPNOTSUPP;
break;
case TARGET_NR_setxattr:
{ {
void *p, *n, *v; 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:
{
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); p = lock_user_string(arg1);
n = lock_user_string(arg2); n = lock_user_string(arg2);
v = lock_user(VERIFY_READ, arg3, arg4, 1); if (p && n) {
if (p && n && v) { if (num == TARGET_NR_setxattr) {
ret = get_errno(setxattr(p, n, v, arg4, arg5)); ret = get_errno(setxattr(p, n, v, arg4, arg5));
} else {
ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
}
} else { } else {
ret = -TARGET_EFAULT; ret = -TARGET_EFAULT;
} }
@ -7671,14 +7862,45 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(v, arg3, 0); unlock_user(v, arg3, 0);
} }
break; break;
case TARGET_NR_getxattr: case TARGET_NR_fsetxattr:
{ {
void *p, *n, *v; 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) {
v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
if (!v) {
ret = -TARGET_EFAULT;
break;
}
}
p = lock_user_string(arg1); p = lock_user_string(arg1);
n = lock_user_string(arg2); n = lock_user_string(arg2);
v = lock_user(VERIFY_WRITE, arg3, arg4, 0); if (p && n) {
if (p && n && v) { if (num == TARGET_NR_getxattr) {
ret = get_errno(getxattr(p, n, v, arg4)); ret = get_errno(getxattr(p, n, v, arg4));
} else {
ret = get_errno(lgetxattr(p, n, v, arg4));
}
} else { } else {
ret = -TARGET_EFAULT; ret = -TARGET_EFAULT;
} }
@ -7687,13 +7909,38 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(v, arg3, arg4); unlock_user(v, arg3, arg4);
} }
break; 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_removexattr:
case TARGET_NR_lremovexattr:
{ {
void *p, *n; void *p, *n;
p = lock_user_string(arg1); p = lock_user_string(arg1);
n = lock_user_string(arg2); n = lock_user_string(arg2);
if (p && n) { if (p && n) {
if (num == TARGET_NR_removexattr) {
ret = get_errno(removexattr(p, n)); ret = get_errno(removexattr(p, n));
} else {
ret = get_errno(lremovexattr(p, n));
}
} else { } else {
ret = -TARGET_EFAULT; ret = -TARGET_EFAULT;
} }
@ -7701,6 +7948,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(n, arg2, 0); unlock_user(n, arg2, 0);
} }
break; 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
#endif /* CONFIG_ATTR */ #endif /* CONFIG_ATTR */
#ifdef TARGET_NR_set_thread_area #ifdef TARGET_NR_set_thread_area

View File

@ -2336,3 +2336,9 @@ struct target_rlimit64 {
uint64_t rlim_cur; uint64_t rlim_cur;
uint64_t rlim_max; uint64_t rlim_max;
}; };
struct target_ucred {
uint32_t pid;
uint32_t uid;
uint32_t gid;
};