mirror of https://github.com/xemu-project/xemu.git
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:
commit
cb437e48ab
|
@ -0,0 +1 @@
|
|||
# Default configuration for mips64-linux-user
|
|
@ -0,0 +1 @@
|
|||
# Default configuration for mips64el-linux-user
|
|
@ -0,0 +1 @@
|
|||
# Default configuration for mipsn32-linux-user
|
|
@ -0,0 +1 @@
|
|||
# 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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
case TARGET_NR_flistxattr:
|
||||
case TARGET_NR_lremovexattr:
|
||||
case TARGET_NR_fremovexattr:
|
||||
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:
|
||||
{
|
||||
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_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);
|
||||
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;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue