aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2022-09-28 17:03:54 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2022-09-28 17:03:54 -0400
commit36cd0aeac3337af06875e08683380389df48ccd0 (patch)
treef3f0e2a5ad875b6af4492b4224336f336b270a09 /linux-user
parentdc6c2342a0c1103bf4b2750dd756609d6ab7ecac (diff)
parent4a877b82f7f99f7366fbb4820687d88dcf97478f (diff)
Merge tag 'linux-user-for-7.2-pull-request' of https://gitlab.com/laurent_vivier/qemu into staging
linux-user pull request 20220928-v2 use 'max' instead of 'qemu32' / 'qemu64' add pidfd_open(), pidfd_send_signal() and pidfd_getfd() Improve madvise(MADV_DONTNEED) futex syscal rework strace improvement HP/PA fixes and improvement Misc fixes # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmM0riISHGxhdXJlbnRA # dml2aWVyLmV1AAoJEPMMOL0/L748gH4P/2wesXJKPMY2zQzP3Rld4iyefoPGG/Yp # mdq59BbjO2jQMR8GBss/nl9l84cIzzkYRQIogaKsjljtZYm/OO5xRefqrzJY6apD # eidxv20dAVjuaXHAIdGhbFlxot1ctExbZs9atB4uj5DWxfYGD6e/stoBy5/pSmr4 # M5EbGHhyrRI7tRbHGtVQVvG6AT6XGE0pT9tzT5JLaApF8UPMkgJwmez16PNWvcMm # v8GEvKm/vEVS8CCpzLV4kfwVeo3f54VAOrEBDi29ph2Yo50IA21k8BvoRZaSp+Kn # G6TMnnly/DkMspAs5EOVfat+kv3TziNNdDH7EnVU1vV1yTDdZgW/1204Uy/JY0Pw # WotwAFuO9FYeHKmjY0CfnIIZZHYZpDYUOZ8M6dESD/O0EjoB8LMf5p9cbYlze4DE # csJZCsVcz19HDv6QZXi5mvvDcJ83B2IDb8/PUAzSc0n62lXL9qjYD0wdb0QsLdAT # I25qLDge1HCmQfCIKcaoHYvE0pDmvkF6ftuQUXLtIwtaV0Z/N5wDf2PEHikjOYHM # gD2izz23/2wQx6KP/9ZNnCJ5QEBkEgm5wpHncsvjzSzi1uIdNlHyzJJwGTAcc5qZ # hOeoJ7dT0D6g0BGnvOdg2W/bDx18KW65mNDxE4d+W0uzn0YmQtArk2YsnhKQNO46 # 12/0ltPFnSV/ # =DIzQ # -----END PGP SIGNATURE----- # gpg: Signature made Wed 28 Sep 2022 16:27:14 EDT # gpg: using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C # gpg: issuer "laurent@vivier.eu" # gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full] # gpg: aka "Laurent Vivier <laurent@vivier.eu>" [full] # gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full] # Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F 5173 F30C 38BD 3F2F BE3C * tag 'linux-user-for-7.2-pull-request' of https://gitlab.com/laurent_vivier/qemu: (37 commits) linux-user: Add parameters of getrandom() syscall for strace linux-user: Lock log around strace linux-user: Update print_futex_op linux-user: Implement PI futexes linux-user: Convert signal number for FUTEX_FD linux-user: Implement FUTEX_WAKE_BITSET linux-user: Sink call to do_safe_futex linux-user: Combine do_futex and do_futex_time64 linux-user: Set ELF_BASE_PLATFORM for MIPS linux-user: Introduce stubs for ELF AT_BASE_PLATFORM linux-user/s390x: Save/restore fpc when handling a signal linux-user: Don't assume 0 is not a valid host timer_t value linux-user: fix bug about missing signum convert of sigqueue linux-user/hppa: Fix setup_sigcontext() linux-user/hppa: Allow PROT_GROWSUP and PROT_GROWSDOWN in mprotect() linux-user/hppa: Increase guest stack size to 80MB for hppa target linux-user/hppa: Drop stack guard page on hppa target linux-user/hppa: Add signal trampoline for hppa target linux-user: Add proper strace format strings for getdents()/getdents64() linux-user: Fix TARGET_PROT_SEM for XTENSA ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/aarch64/target_mman.h1
-rw-r--r--linux-user/alpha/target_mman.h8
-rw-r--r--linux-user/arm/target_mman.h1
-rw-r--r--linux-user/cpu_loop-common.h2
-rw-r--r--linux-user/cris/target_mman.h1
-rw-r--r--linux-user/elfload.c73
-rw-r--r--linux-user/generic/target_mman.h92
-rw-r--r--linux-user/hexagon/target_mman.h1
-rw-r--r--linux-user/hppa/cpu_loop.c6
-rw-r--r--linux-user/hppa/signal.c57
-rw-r--r--linux-user/hppa/target_mman.h15
-rw-r--r--linux-user/hppa/target_signal.h14
-rw-r--r--linux-user/hppa/target_syscall.h2
-rw-r--r--linux-user/i386/target_elf.h2
-rw-r--r--linux-user/i386/target_mman.h1
-rw-r--r--linux-user/loongarch64/target_mman.h1
-rw-r--r--linux-user/m68k/target_mman.h1
-rw-r--r--linux-user/main.c9
-rw-r--r--linux-user/microblaze/target_mman.h1
-rw-r--r--linux-user/mips/target_mman.h1
-rw-r--r--linux-user/mips64/target_mman.h1
-rw-r--r--linux-user/mmap.c36
-rw-r--r--linux-user/nios2/target_mman.h1
-rw-r--r--linux-user/openrisc/target_mman.h1
-rw-r--r--linux-user/ppc/target_mman.h1
-rw-r--r--linux-user/riscv/target_mman.h1
-rw-r--r--linux-user/s390x/signal.c2
-rw-r--r--linux-user/s390x/target_mman.h1
-rw-r--r--linux-user/sh4/target_mman.h1
-rw-r--r--linux-user/signal-common.h46
-rw-r--r--linux-user/signal.c37
-rw-r--r--linux-user/sparc/target_mman.h1
-rw-r--r--linux-user/strace.c318
-rw-r--r--linux-user/strace.list24
-rw-r--r--linux-user/syscall.c206
-rw-r--r--linux-user/syscall_defs.h5
-rw-r--r--linux-user/x86_64/target_elf.h2
-rw-r--r--linux-user/x86_64/target_mman.h1
-rw-r--r--linux-user/xtensa/target_mman.h1
39 files changed, 716 insertions, 259 deletions
diff --git a/linux-user/aarch64/target_mman.h b/linux-user/aarch64/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/aarch64/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/alpha/target_mman.h b/linux-user/alpha/target_mman.h
new file mode 100644
index 0000000000..cd6e3d70a6
--- /dev/null
+++ b/linux-user/alpha/target_mman.h
@@ -0,0 +1,8 @@
+#ifndef ALPHA_TARGET_MMAN_H
+#define ALPHA_TARGET_MMAN_H
+
+#define TARGET_MADV_DONTNEED 6
+
+#include "../generic/target_mman.h"
+
+#endif
diff --git a/linux-user/arm/target_mman.h b/linux-user/arm/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/arm/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/cpu_loop-common.h b/linux-user/cpu_loop-common.h
index dc0042e4de..36ff5b14f2 100644
--- a/linux-user/cpu_loop-common.h
+++ b/linux-user/cpu_loop-common.h
@@ -27,9 +27,11 @@
do { \
CPUState *cs = env_cpu(env); \
fprintf(stderr, fmt , ## __VA_ARGS__); \
+ fprintf(stderr, "Failing executable: %s\n", exec_path); \
cpu_dump_state(cs, stderr, 0); \
if (qemu_log_separate()) { \
qemu_log(fmt, ## __VA_ARGS__); \
+ qemu_log("Failing executable: %s\n", exec_path); \
log_cpu_state(cs, 0); \
} \
} while (0)
diff --git a/linux-user/cris/target_mman.h b/linux-user/cris/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/cris/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ba5c4c02e5..20894b633f 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1080,6 +1080,37 @@ static uint32_t get_elf_hwcap(void)
#define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
#endif
+#define ELF_BASE_PLATFORM get_elf_base_platform()
+
+#define MATCH_PLATFORM_INSN(_flags, _base_platform) \
+ do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
+ { return _base_platform; } } while (0)
+
+static const char *get_elf_base_platform(void)
+{
+ MIPSCPU *cpu = MIPS_CPU(thread_cpu);
+
+ /* 64 bit ISAs goes first */
+ MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
+ MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
+ MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
+ MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
+ MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
+ MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
+ MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
+
+ /* 32 bit ISAs */
+ MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
+ MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
+ MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
+ MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
+ MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
+
+ /* Fallback */
+ return "mips";
+}
+#undef MATCH_PLATFORM_INSN
+
static inline void init_thread(struct target_pt_regs *regs,
struct image_info *infop)
{
@@ -1776,6 +1807,10 @@ static inline void init_thread(struct target_pt_regs *regs,
#endif /* TARGET_HEXAGON */
+#ifndef ELF_BASE_PLATFORM
+#define ELF_BASE_PLATFORM (NULL)
+#endif
+
#ifndef ELF_PLATFORM
#define ELF_PLATFORM (NULL)
#endif
@@ -2096,9 +2131,15 @@ static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
if (size < STACK_LOWER_LIMIT) {
size = STACK_LOWER_LIMIT;
}
- guard = TARGET_PAGE_SIZE;
- if (guard < qemu_real_host_page_size()) {
- guard = qemu_real_host_page_size();
+
+ if (STACK_GROWS_DOWN) {
+ guard = TARGET_PAGE_SIZE;
+ if (guard < qemu_real_host_page_size()) {
+ guard = qemu_real_host_page_size();
+ }
+ } else {
+ /* no guard page for hppa target where stack grows upwards. */
+ guard = 0;
}
prot = PROT_READ | PROT_WRITE;
@@ -2118,7 +2159,6 @@ static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
info->stack_limit = error + guard;
return info->stack_limit + size - sizeof(void *);
} else {
- target_mprotect(error + size, guard, PROT_NONE);
info->stack_limit = error + size;
return error;
}
@@ -2215,8 +2255,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
int i;
abi_ulong u_rand_bytes;
uint8_t k_rand_bytes[16];
- abi_ulong u_platform;
- const char *k_platform;
+ abi_ulong u_platform, u_base_platform;
+ const char *k_platform, *k_base_platform;
const int n = sizeof(elf_addr_t);
sp = p;
@@ -2238,6 +2278,22 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
}
}
+ u_base_platform = 0;
+ k_base_platform = ELF_BASE_PLATFORM;
+ if (k_base_platform) {
+ size_t len = strlen(k_base_platform) + 1;
+ if (STACK_GROWS_DOWN) {
+ sp -= (len + n - 1) & ~(n - 1);
+ u_base_platform = sp;
+ /* FIXME - check return value of memcpy_to_target() for failure */
+ memcpy_to_target(sp, k_base_platform, len);
+ } else {
+ memcpy_to_target(sp, k_base_platform, len);
+ u_base_platform = sp;
+ sp += len + 1;
+ }
+ }
+
u_platform = 0;
k_platform = ELF_PLATFORM;
if (k_platform) {
@@ -2279,6 +2335,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
}
size = (DLINFO_ITEMS + 1) * 2;
+ if (k_base_platform)
+ size += 2;
if (k_platform)
size += 2;
#ifdef DLINFO_ARCH_ITEMS
@@ -2356,6 +2414,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
#endif
+ if (u_base_platform) {
+ NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
+ }
if (u_platform) {
NEW_AUX_ENT(AT_PLATFORM, u_platform);
}
diff --git a/linux-user/generic/target_mman.h b/linux-user/generic/target_mman.h
new file mode 100644
index 0000000000..1436a3c543
--- /dev/null
+++ b/linux-user/generic/target_mman.h
@@ -0,0 +1,92 @@
+#ifndef LINUX_USER_TARGET_MMAN_H
+#define LINUX_USER_TARGET_MMAN_H
+
+#ifndef TARGET_MADV_NORMAL
+#define TARGET_MADV_NORMAL 0
+#endif
+
+#ifndef TARGET_MADV_RANDOM
+#define TARGET_MADV_RANDOM 1
+#endif
+
+#ifndef TARGET_MADV_SEQUENTIAL
+#define TARGET_MADV_SEQUENTIAL 2
+#endif
+
+#ifndef TARGET_MADV_WILLNEED
+#define TARGET_MADV_WILLNEED 3
+#endif
+
+#ifndef TARGET_MADV_DONTNEED
+#define TARGET_MADV_DONTNEED 4
+#endif
+
+#ifndef TARGET_MADV_FREE
+#define TARGET_MADV_FREE 8
+#endif
+
+#ifndef TARGET_MADV_REMOVE
+#define TARGET_MADV_REMOVE 9
+#endif
+
+#ifndef TARGET_MADV_DONTFORK
+#define TARGET_MADV_DONTFORK 10
+#endif
+
+#ifndef TARGET_MADV_DOFORK
+#define TARGET_MADV_DOFORK 11
+#endif
+
+#ifndef TARGET_MADV_MERGEABLE
+#define TARGET_MADV_MERGEABLE 12
+#endif
+
+#ifndef TARGET_MADV_UNMERGEABLE
+#define TARGET_MADV_UNMERGEABLE 13
+#endif
+
+#ifndef TARGET_MADV_HUGEPAGE
+#define TARGET_MADV_HUGEPAGE 14
+#endif
+
+#ifndef TARGET_MADV_NOHUGEPAGE
+#define TARGET_MADV_NOHUGEPAGE 15
+#endif
+
+#ifndef TARGET_MADV_DONTDUMP
+#define TARGET_MADV_DONTDUMP 16
+#endif
+
+#ifndef TARGET_MADV_DODUMP
+#define TARGET_MADV_DODUMP 17
+#endif
+
+#ifndef TARGET_MADV_WIPEONFORK
+#define TARGET_MADV_WIPEONFORK 18
+#endif
+
+#ifndef TARGET_MADV_KEEPONFORK
+#define TARGET_MADV_KEEPONFORK 19
+#endif
+
+#ifndef TARGET_MADV_COLD
+#define TARGET_MADV_COLD 20
+#endif
+
+#ifndef TARGET_MADV_PAGEOUT
+#define TARGET_MADV_PAGEOUT 21
+#endif
+
+#ifndef TARGET_MADV_POPULATE_READ
+#define TARGET_MADV_POPULATE_READ 22
+#endif
+
+#ifndef TARGET_MADV_POPULATE_WRITE
+#define TARGET_MADV_POPULATE_WRITE 23
+#endif
+
+#ifndef TARGET_MADV_DONTNEED_LOCKED
+#define TARGET_MADV_DONTNEED_LOCKED 24
+#endif
+
+#endif
diff --git a/linux-user/hexagon/target_mman.h b/linux-user/hexagon/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/hexagon/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
index 64263c3dc4..1ef3b46191 100644
--- a/linux-user/hppa/cpu_loop.c
+++ b/linux-user/hppa/cpu_loop.c
@@ -147,12 +147,15 @@ void cpu_loop(CPUHPPAState *env)
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f);
break;
case EXCP_ILL:
+ EXCP_DUMP(env, "qemu: got CPU exception 0x%x - aborting\n", trapnr);
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->iaoq_f);
break;
case EXCP_PRIV_OPR:
+ EXCP_DUMP(env, "qemu: got CPU exception 0x%x - aborting\n", trapnr);
force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->iaoq_f);
break;
case EXCP_PRIV_REG:
+ EXCP_DUMP(env, "qemu: got CPU exception 0x%x - aborting\n", trapnr);
force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVREG, env->iaoq_f);
break;
case EXCP_OVERFLOW:
@@ -171,7 +174,8 @@ void cpu_loop(CPUHPPAState *env)
/* just indicate that signals should be handled asap */
break;
default:
- g_assert_not_reached();
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
+ abort();
}
process_pending_signals(env);
}
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
index 962f551c04..f253a15864 100644
--- a/linux-user/hppa/signal.c
+++ b/linux-user/hppa/signal.c
@@ -41,7 +41,7 @@ struct target_ucontext {
};
struct target_rt_sigframe {
- abi_uint tramp[9];
+ abi_uint tramp[2]; /* syscall restart return address */
target_siginfo_t info;
struct target_ucontext uc;
/* hidden location of upper halves of pa2.0 64-bit gregs */
@@ -49,23 +49,13 @@ struct target_rt_sigframe {
static void setup_sigcontext(struct target_sigcontext *sc, CPUArchState *env)
{
- int flags = 0;
int i;
- /* ??? if on_sig_stack, flags |= 1 (PARISC_SC_FLAG_ONSTACK). */
-
- if (env->iaoq_f < TARGET_PAGE_SIZE) {
- /* In the gateway page, executing a syscall. */
- flags |= 2; /* PARISC_SC_FLAG_IN_SYSCALL */
- __put_user(env->gr[31], &sc->sc_iaoq[0]);
- __put_user(env->gr[31] + 4, &sc->sc_iaoq[1]);
- } else {
- __put_user(env->iaoq_f, &sc->sc_iaoq[0]);
- __put_user(env->iaoq_b, &sc->sc_iaoq[1]);
- }
+ __put_user(env->iaoq_f, &sc->sc_iaoq[0]);
+ __put_user(env->iaoq_b, &sc->sc_iaoq[1]);
__put_user(0, &sc->sc_iasq[0]);
__put_user(0, &sc->sc_iasq[1]);
- __put_user(flags, &sc->sc_flags);
+ __put_user(0, &sc->sc_flags);
__put_user(cpu_hppa_get_psw(env), &sc->sc_gr[0]);
for (i = 1; i < 32; ++i) {
@@ -101,9 +91,15 @@ static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc)
__get_user(env->cr[CR_SAR], &sc->sc_sar);
}
-/* No, this doesn't look right, but it's copied straight from the kernel. */
+#if TARGET_ABI_BITS == 32
+#define SIGFRAME 64
+#define FUNCTIONCALLFRAME 48
+#else
+#define SIGFRAME 128
+#define FUNCTIONCALLFRAME 96
+#endif
#define PARISC_RT_SIGFRAME_SIZE32 \
- ((sizeof(struct target_rt_sigframe) + 48 + 64) & -64)
+ ((sizeof(struct target_rt_sigframe) + FUNCTIONCALLFRAME + SIGFRAME) & -SIGFRAME)
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
@@ -118,7 +114,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
sp = (ts->sigaltstack_used.ss_sp + 0x7f) & ~0x3f;
}
- frame_addr = QEMU_ALIGN_UP(sp, 64);
+ frame_addr = QEMU_ALIGN_UP(sp, SIGFRAME);
sp = frame_addr + PARISC_RT_SIGFRAME_SIZE32;
trace_user_setup_rt_frame(env, frame_addr);
@@ -139,14 +135,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
setup_sigcontext(&frame->uc.tuc_mcontext, env);
- __put_user(0x34190000, frame->tramp + 0); /* ldi 0,%r25 */
- __put_user(0x3414015a, frame->tramp + 1); /* ldi __NR_rt_sigreturn,%r20 */
- __put_user(0xe4008200, frame->tramp + 2); /* be,l 0x100(%sr2,%r0) */
- __put_user(0x08000240, frame->tramp + 3); /* nop */
-
unlock_user_struct(frame, frame_addr, 1);
- env->gr[2] = h2g(frame->tramp);
+ env->gr[2] = default_rt_sigreturn;
env->gr[30] = sp;
env->gr[26] = sig;
env->gr[25] = h2g(&frame->info);
@@ -197,3 +188,23 @@ long do_rt_sigreturn(CPUArchState *env)
force_sig(TARGET_SIGSEGV);
return -QEMU_ESIGRETURN;
}
+
+void setup_sigtramp(abi_ulong sigtramp_page)
+{
+ uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6*4, 0);
+ abi_ulong SIGFRAME_CONTEXT_REGS32;
+ assert(tramp != NULL);
+
+ SIGFRAME_CONTEXT_REGS32 = offsetof(struct target_rt_sigframe, uc.tuc_mcontext);
+ SIGFRAME_CONTEXT_REGS32 -= PARISC_RT_SIGFRAME_SIZE32;
+
+ __put_user(SIGFRAME_CONTEXT_REGS32, tramp + 0);
+ __put_user(0x08000240, tramp + 1); /* nop - b/c dwarf2 unwind routines */
+ __put_user(0x34190000, tramp + 2); /* ldi 0, %r25 (in_syscall=0) */
+ __put_user(0x3414015a, tramp + 3); /* ldi __NR_rt_sigreturn, %r20 */
+ __put_user(0xe4008200, tramp + 4); /* ble 0x100(%sr2, %r0) */
+ __put_user(0x08000240, tramp + 5); /* nop */
+
+ default_rt_sigreturn = (sigtramp_page + 8) | 3;
+ unlock_user(tramp, sigtramp_page, 6*4);
+}
diff --git a/linux-user/hppa/target_mman.h b/linux-user/hppa/target_mman.h
new file mode 100644
index 0000000000..66dd9f7941
--- /dev/null
+++ b/linux-user/hppa/target_mman.h
@@ -0,0 +1,15 @@
+#ifndef HPPA_TARGET_MMAN_H
+#define HPPA_TARGET_MMAN_H
+
+#define TARGET_MADV_MERGEABLE 65
+#define TARGET_MADV_UNMERGEABLE 66
+#define TARGET_MADV_HUGEPAGE 67
+#define TARGET_MADV_NOHUGEPAGE 68
+#define TARGET_MADV_DONTDUMP 69
+#define TARGET_MADV_DODUMP 70
+#define TARGET_MADV_WIPEONFORK 71
+#define TARGET_MADV_KEEPONFORK 72
+
+#include "../generic/target_mman.h"
+
+#endif
diff --git a/linux-user/hppa/target_signal.h b/linux-user/hppa/target_signal.h
index af6c2fce58..190bb3d653 100644
--- a/linux-user/hppa/target_signal.h
+++ b/linux-user/hppa/target_signal.h
@@ -70,18 +70,6 @@ typedef struct target_sigaltstack {
/* mask for all SS_xxx flags */
#define TARGET_SS_FLAG_BITS TARGET_SS_AUTODISARM
-/*
- * We cannot use a bare sigtramp page for hppa-linux.
- *
- * Unlike other guests where we use the instructions at PC to validate
- * an offset from SP, the hppa libgcc signal frame fallback unwinding uses
- * the PC address itself to find the frame. This is due to the fact that
- * the hppa grows the stack upward, and the frame is of unknown size.
- *
- * TODO: We should be able to use a VDSO to address this, by providing
- * proper unwind info for the sigtramp code, at which point the fallback
- * unwinder will not be used.
- */
-#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
+#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* HPPA_TARGET_SIGNAL_H */
diff --git a/linux-user/hppa/target_syscall.h b/linux-user/hppa/target_syscall.h
index 4b382c1fcf..9a8f8ca628 100644
--- a/linux-user/hppa/target_syscall.h
+++ b/linux-user/hppa/target_syscall.h
@@ -26,4 +26,6 @@ struct target_pt_regs {
#define TARGET_MCL_FUTURE 2
#define TARGET_MCL_ONFAULT 4
+#define TARGET_DEFAULT_STACK_SIZE 80 * 1024 * 1024UL
+
#endif /* HPPA_TARGET_SYSCALL_H */
diff --git a/linux-user/i386/target_elf.h b/linux-user/i386/target_elf.h
index 1c6142e7da..238a9aba73 100644
--- a/linux-user/i386/target_elf.h
+++ b/linux-user/i386/target_elf.h
@@ -9,6 +9,6 @@
#define I386_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
- return "qemu32";
+ return "max";
}
#endif
diff --git a/linux-user/i386/target_mman.h b/linux-user/i386/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/i386/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/loongarch64/target_mman.h b/linux-user/loongarch64/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/loongarch64/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/m68k/target_mman.h b/linux-user/m68k/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/m68k/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/main.c b/linux-user/main.c
index e44bdb17b8..88fccfe261 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -124,10 +124,14 @@ static void usage(int exitcode);
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
+#if !defined(TARGET_DEFAULT_STACK_SIZE)
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
by remapping the process stack directly at the right place */
-unsigned long guest_stack_size = 8 * 1024 * 1024UL;
+#define TARGET_DEFAULT_STACK_SIZE 8 * 1024 * 1024UL
+#endif
+
+unsigned long guest_stack_size = TARGET_DEFAULT_STACK_SIZE;
/***********************************************************/
/* Helper routines for implementing atomic operations. */
@@ -668,7 +672,8 @@ int main(int argc, char **argv, char **envp)
struct rlimit lim;
if (getrlimit(RLIMIT_STACK, &lim) == 0
&& lim.rlim_cur != RLIM_INFINITY
- && lim.rlim_cur == (target_long)lim.rlim_cur) {
+ && lim.rlim_cur == (target_long)lim.rlim_cur
+ && lim.rlim_cur > guest_stack_size) {
guest_stack_size = lim.rlim_cur;
}
}
diff --git a/linux-user/microblaze/target_mman.h b/linux-user/microblaze/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/microblaze/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/mips/target_mman.h b/linux-user/mips/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/mips/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/mips64/target_mman.h b/linux-user/mips64/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/mips64/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 6a828e8418..28f3bc85ed 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -22,6 +22,7 @@
#include "qemu.h"
#include "user-internals.h"
#include "user-mmap.h"
+#include "target_mman.h"
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
static __thread int mmap_lock_count;
@@ -105,6 +106,8 @@ static int validate_prot_to_pageflags(int *host_prot, int prot)
page_flags |= PAGE_MTE;
}
}
+#elif defined(TARGET_HPPA)
+ valid |= PROT_GROWSDOWN | PROT_GROWSUP;
#endif
return prot & ~valid ? 0 : page_flags;
@@ -253,8 +256,12 @@ static int mmap_frag(abi_ulong real_start,
# define TASK_UNMAPPED_BASE (1ul << 38)
#endif
#else
+#ifdef TARGET_HPPA
+# define TASK_UNMAPPED_BASE 0xfa000000
+#else
# define TASK_UNMAPPED_BASE 0x40000000
#endif
+#endif
abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
unsigned long last_brk;
@@ -426,7 +433,8 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
int flags, int fd, abi_ulong offset)
{
- abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
+ abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len,
+ passthrough_start = -1, passthrough_end = -1;
int page_flags, host_prot;
mmap_lock();
@@ -539,6 +547,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
host_start += offset - host_offset;
}
start = h2g(host_start);
+ passthrough_start = start;
+ passthrough_end = start + len;
} else {
if (start & ~TARGET_PAGE_MASK) {
errno = EINVAL;
@@ -621,6 +631,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
host_prot, flags, fd, offset1);
if (p == MAP_FAILED)
goto fail;
+ passthrough_start = real_start;
+ passthrough_end = real_end;
}
}
the_end1:
@@ -628,7 +640,18 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
page_flags |= PAGE_ANON;
}
page_flags |= PAGE_RESET;
- page_set_flags(start, start + len, page_flags);
+ if (passthrough_start == passthrough_end) {
+ page_set_flags(start, start + len, page_flags);
+ } else {
+ if (start < passthrough_start) {
+ page_set_flags(start, passthrough_start, page_flags);
+ }
+ page_set_flags(passthrough_start, passthrough_end,
+ page_flags | PAGE_PASSTHROUGH);
+ if (passthrough_end < start + len) {
+ page_set_flags(passthrough_end, start + len, page_flags);
+ }
+ }
the_end:
trace_target_mmap_complete(start);
if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
@@ -847,7 +870,7 @@ static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end)
}
for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
- if (!(page_get_flags(addr) & PAGE_ANON)) {
+ if (!(page_get_flags(addr) & PAGE_PASSTHROUGH)) {
return false;
}
}
@@ -889,11 +912,12 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice)
* This is a hint, so ignoring and returning success is ok.
*
* This breaks MADV_DONTNEED, completely implementing which is quite
- * complicated. However, there is one low-hanging fruit: host-page-aligned
- * anonymous mappings. In this case passthrough is safe, so do it.
+ * complicated. However, there is one low-hanging fruit: mappings that are
+ * known to have the same semantics in the host and the guest. In this case
+ * passthrough is safe, so do it.
*/
mmap_lock();
- if (advice == MADV_DONTNEED &&
+ if (advice == TARGET_MADV_DONTNEED &&
can_passthrough_madv_dontneed(start, end)) {
ret = get_errno(madvise(g2h_untagged(start), len, MADV_DONTNEED));
if (ret == 0) {
diff --git a/linux-user/nios2/target_mman.h b/linux-user/nios2/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/nios2/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/openrisc/target_mman.h b/linux-user/openrisc/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/openrisc/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/ppc/target_mman.h b/linux-user/ppc/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/ppc/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/riscv/target_mman.h b/linux-user/riscv/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/riscv/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index 4979c4b017..f72165576f 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -146,6 +146,7 @@ static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
* We have to store the fp registers to current->thread.fp_regs
* to merge them with the emulated registers.
*/
+ __put_user(env->fpc, &sregs->fpregs.fpc);
for (i = 0; i < 16; i++) {
__put_user(*get_freg(env, i), &sregs->fpregs.fprs[i]);
}
@@ -331,6 +332,7 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
for (i = 0; i < 16; i++) {
__get_user(env->aregs[i], &sc->regs.acrs[i]);
}
+ __get_user(env->fpc, &sc->fpregs.fpc);
for (i = 0; i < 16; i++) {
__get_user(*get_freg(env, i), &sc->fpregs.fprs[i]);
}
diff --git a/linux-user/s390x/target_mman.h b/linux-user/s390x/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/s390x/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/sh4/target_mman.h b/linux-user/sh4/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/sh4/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
index 6a7e4a93fc..3e2dc604c2 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -118,4 +118,50 @@ static inline void finish_sigsuspend_mask(int ret)
}
}
+#if defined(SIGSTKFLT) && defined(TARGET_SIGSTKFLT)
+#define MAKE_SIG_ENTRY_SIGSTKFLT MAKE_SIG_ENTRY(SIGSTKFLT)
+#else
+#define MAKE_SIG_ENTRY_SIGSTKFLT
+#endif
+
+#if defined(SIGIOT) && defined(TARGET_SIGIOT)
+#define MAKE_SIG_ENTRY_SIGIOT MAKE_SIG_ENTRY(SIGIOT)
+#else
+#define MAKE_SIG_ENTRY_SIGIOT
+#endif
+
+#define MAKE_SIGNAL_LIST \
+ MAKE_SIG_ENTRY(SIGHUP) \
+ MAKE_SIG_ENTRY(SIGINT) \
+ MAKE_SIG_ENTRY(SIGQUIT) \
+ MAKE_SIG_ENTRY(SIGILL) \
+ MAKE_SIG_ENTRY(SIGTRAP) \
+ MAKE_SIG_ENTRY(SIGABRT) \
+ MAKE_SIG_ENTRY(SIGBUS) \
+ MAKE_SIG_ENTRY(SIGFPE) \
+ MAKE_SIG_ENTRY(SIGKILL) \
+ MAKE_SIG_ENTRY(SIGUSR1) \
+ MAKE_SIG_ENTRY(SIGSEGV) \
+ MAKE_SIG_ENTRY(SIGUSR2) \
+ MAKE_SIG_ENTRY(SIGPIPE) \
+ MAKE_SIG_ENTRY(SIGALRM) \
+ MAKE_SIG_ENTRY(SIGTERM) \
+ MAKE_SIG_ENTRY(SIGCHLD) \
+ MAKE_SIG_ENTRY(SIGCONT) \
+ MAKE_SIG_ENTRY(SIGSTOP) \
+ MAKE_SIG_ENTRY(SIGTSTP) \
+ MAKE_SIG_ENTRY(SIGTTIN) \
+ MAKE_SIG_ENTRY(SIGTTOU) \
+ MAKE_SIG_ENTRY(SIGURG) \
+ MAKE_SIG_ENTRY(SIGXCPU) \
+ MAKE_SIG_ENTRY(SIGXFSZ) \
+ MAKE_SIG_ENTRY(SIGVTALRM) \
+ MAKE_SIG_ENTRY(SIGPROF) \
+ MAKE_SIG_ENTRY(SIGWINCH) \
+ MAKE_SIG_ENTRY(SIGIO) \
+ MAKE_SIG_ENTRY(SIGPWR) \
+ MAKE_SIG_ENTRY(SIGSYS) \
+ MAKE_SIG_ENTRY_SIGSTKFLT \
+ MAKE_SIG_ENTRY_SIGIOT
+
#endif
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 8d29bfaa6b..61c6fa3fcf 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -53,40 +53,9 @@ abi_ulong default_rt_sigreturn;
QEMU_BUILD_BUG_ON(__SIGRTMAX + 1 != _NSIG);
#endif
static uint8_t host_to_target_signal_table[_NSIG] = {
- [SIGHUP] = TARGET_SIGHUP,
- [SIGINT] = TARGET_SIGINT,
- [SIGQUIT] = TARGET_SIGQUIT,
- [SIGILL] = TARGET_SIGILL,
- [SIGTRAP] = TARGET_SIGTRAP,
- [SIGABRT] = TARGET_SIGABRT,
-/* [SIGIOT] = TARGET_SIGIOT,*/
- [SIGBUS] = TARGET_SIGBUS,
- [SIGFPE] = TARGET_SIGFPE,
- [SIGKILL] = TARGET_SIGKILL,
- [SIGUSR1] = TARGET_SIGUSR1,
- [SIGSEGV] = TARGET_SIGSEGV,
- [SIGUSR2] = TARGET_SIGUSR2,
- [SIGPIPE] = TARGET_SIGPIPE,
- [SIGALRM] = TARGET_SIGALRM,
- [SIGTERM] = TARGET_SIGTERM,
-#ifdef SIGSTKFLT
- [SIGSTKFLT] = TARGET_SIGSTKFLT,
-#endif
- [SIGCHLD] = TARGET_SIGCHLD,
- [SIGCONT] = TARGET_SIGCONT,
- [SIGSTOP] = TARGET_SIGSTOP,
- [SIGTSTP] = TARGET_SIGTSTP,
- [SIGTTIN] = TARGET_SIGTTIN,
- [SIGTTOU] = TARGET_SIGTTOU,
- [SIGURG] = TARGET_SIGURG,
- [SIGXCPU] = TARGET_SIGXCPU,
- [SIGXFSZ] = TARGET_SIGXFSZ,
- [SIGVTALRM] = TARGET_SIGVTALRM,
- [SIGPROF] = TARGET_SIGPROF,
- [SIGWINCH] = TARGET_SIGWINCH,
- [SIGIO] = TARGET_SIGIO,
- [SIGPWR] = TARGET_SIGPWR,
- [SIGSYS] = TARGET_SIGSYS,
+#define MAKE_SIG_ENTRY(sig) [sig] = TARGET_##sig,
+ MAKE_SIGNAL_LIST
+#undef MAKE_SIG_ENTRY
/* next signals stay the same */
};
diff --git a/linux-user/sparc/target_mman.h b/linux-user/sparc/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/sparc/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 7d882526da..37bc96df9b 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -17,6 +17,8 @@
#include "qemu.h"
#include "user-internals.h"
#include "strace.h"
+#include "signal-common.h"
+#include "target_mman.h"
struct syscallname {
int nr;
@@ -81,6 +83,7 @@ UNUSED static void print_buf(abi_long addr, abi_long len, int last);
UNUSED static void print_raw_param(const char *, abi_long, int);
UNUSED static void print_timeval(abi_ulong, int);
UNUSED static void print_timespec(abi_ulong, int);
+UNUSED static void print_timespec64(abi_ulong, int);
UNUSED static void print_timezone(abi_ulong, int);
UNUSED static void print_itimerval(abi_ulong, int);
UNUSED static void print_number(abi_long, int);
@@ -141,30 +144,21 @@ if( cmd == val ) { \
qemu_log("%d", cmd);
}
+static const char * const target_signal_name[] = {
+#define MAKE_SIG_ENTRY(sig) [TARGET_##sig] = #sig,
+ MAKE_SIGNAL_LIST
+#undef MAKE_SIG_ENTRY
+};
+
static void
print_signal(abi_ulong arg, int last)
{
const char *signal_name = NULL;
- switch(arg) {
- case TARGET_SIGHUP: signal_name = "SIGHUP"; break;
- case TARGET_SIGINT: signal_name = "SIGINT"; break;
- case TARGET_SIGQUIT: signal_name = "SIGQUIT"; break;
- case TARGET_SIGILL: signal_name = "SIGILL"; break;
- case TARGET_SIGABRT: signal_name = "SIGABRT"; break;
- case TARGET_SIGFPE: signal_name = "SIGFPE"; break;
- case TARGET_SIGKILL: signal_name = "SIGKILL"; break;
- case TARGET_SIGSEGV: signal_name = "SIGSEGV"; break;
- case TARGET_SIGPIPE: signal_name = "SIGPIPE"; break;
- case TARGET_SIGALRM: signal_name = "SIGALRM"; break;
- case TARGET_SIGTERM: signal_name = "SIGTERM"; break;
- case TARGET_SIGUSR1: signal_name = "SIGUSR1"; break;
- case TARGET_SIGUSR2: signal_name = "SIGUSR2"; break;
- case TARGET_SIGCHLD: signal_name = "SIGCHLD"; break;
- case TARGET_SIGCONT: signal_name = "SIGCONT"; break;
- case TARGET_SIGSTOP: signal_name = "SIGSTOP"; break;
- case TARGET_SIGTTIN: signal_name = "SIGTTIN"; break;
- case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break;
+
+ if (arg < ARRAY_SIZE(target_signal_name)) {
+ signal_name = target_signal_name[arg];
}
+
if (signal_name == NULL) {
print_raw_param("%ld", arg, last);
return;
@@ -803,6 +797,24 @@ print_syscall_ret_clock_gettime(CPUArchState *cpu_env, const struct syscallname
#define print_syscall_ret_clock_getres print_syscall_ret_clock_gettime
#endif
+#if defined(TARGET_NR_clock_gettime64)
+static void
+print_syscall_ret_clock_gettime64(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long ret, abi_long arg0, abi_long arg1,
+ abi_long arg2, abi_long arg3, abi_long arg4,
+ abi_long arg5)
+{
+ if (!print_syscall_err(ret)) {
+ qemu_log(TARGET_ABI_FMT_ld, ret);
+ qemu_log(" (");
+ print_timespec64(arg1, 1);
+ qemu_log(")");
+ }
+
+ qemu_log("\n");
+}
+#endif
+
#ifdef TARGET_NR_gettimeofday
static void
print_syscall_ret_gettimeofday(CPUArchState *cpu_env, const struct syscallname *name,
@@ -1494,6 +1506,11 @@ print_file_mode(abi_long mode, int last)
const char *sep = "";
const struct flags *m;
+ if (mode == 0) {
+ qemu_log("000%s", get_comma(last));
+ return;
+ }
+
for (m = &mode_flags[0]; m->f_string != NULL; m++) {
if ((m->f_value & mode) == m->f_value) {
qemu_log("%s%s", m->f_string, sep);
@@ -1661,6 +1678,27 @@ print_timespec(abi_ulong ts_addr, int last)
}
static void
+print_timespec64(abi_ulong ts_addr, int last)
+{
+ if (ts_addr) {
+ struct target__kernel_timespec *ts;
+
+ ts = lock_user(VERIFY_READ, ts_addr, sizeof(*ts), 1);
+ if (!ts) {
+ print_pointer(ts_addr, last);
+ return;
+ }
+ qemu_log("{tv_sec = %lld"
+ ",tv_nsec = %lld}%s",
+ (long long)tswap64(ts->tv_sec), (long long)tswap64(ts->tv_nsec),
+ get_comma(last));
+ unlock_user(ts, ts_addr, 0);
+ } else {
+ qemu_log("NULL%s", get_comma(last));
+ }
+}
+
+static void
print_timezone(abi_ulong tz_addr, int last)
{
if (tz_addr) {
@@ -2275,6 +2313,19 @@ print_clock_gettime(CPUArchState *cpu_env, const struct syscallname *name,
#define print_clock_getres print_clock_gettime
#endif
+#if defined(TARGET_NR_clock_gettime64)
+static void
+print_clock_gettime64(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_syscall_prologue(name);
+ print_enums(clockids, arg0, 0);
+ print_pointer(arg1, 1);
+ print_syscall_epilogue(name);
+}
+#endif
+
#ifdef TARGET_NR_clock_settime
static void
print_clock_settime(CPUArchState *cpu_env, const struct syscallname *name,
@@ -2969,6 +3020,46 @@ print_stat(CPUArchState *cpu_env, const struct syscallname *name,
#define print_lstat64 print_stat
#endif
+#if defined(TARGET_NR_madvise)
+static struct enums madvise_advice[] = {
+ ENUM_TARGET(MADV_NORMAL),
+ ENUM_TARGET(MADV_RANDOM),
+ ENUM_TARGET(MADV_SEQUENTIAL),
+ ENUM_TARGET(MADV_WILLNEED),
+ ENUM_TARGET(MADV_DONTNEED),
+ ENUM_TARGET(MADV_FREE),
+ ENUM_TARGET(MADV_REMOVE),
+ ENUM_TARGET(MADV_DONTFORK),
+ ENUM_TARGET(MADV_DOFORK),
+ ENUM_TARGET(MADV_MERGEABLE),
+ ENUM_TARGET(MADV_UNMERGEABLE),
+ ENUM_TARGET(MADV_HUGEPAGE),
+ ENUM_TARGET(MADV_NOHUGEPAGE),
+ ENUM_TARGET(MADV_DONTDUMP),
+ ENUM_TARGET(MADV_DODUMP),
+ ENUM_TARGET(MADV_WIPEONFORK),
+ ENUM_TARGET(MADV_KEEPONFORK),
+ ENUM_TARGET(MADV_COLD),
+ ENUM_TARGET(MADV_PAGEOUT),
+ ENUM_TARGET(MADV_POPULATE_READ),
+ ENUM_TARGET(MADV_POPULATE_WRITE),
+ ENUM_TARGET(MADV_DONTNEED_LOCKED),
+ ENUM_END,
+};
+
+static void
+print_madvise(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_syscall_prologue(name);
+ print_pointer(arg0, 0);
+ print_raw_param("%d", arg1, 0);
+ print_enums(madvise_advice, arg2, 1);
+ print_syscall_epilogue(name);
+}
+#endif
+
#if defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64)
static void
print_fstat(CPUArchState *cpu_env, const struct syscallname *name,
@@ -3272,6 +3363,34 @@ print_openat(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif
+#ifdef TARGET_NR_pidfd_send_signal
+static void
+print_pidfd_send_signal(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ void *p;
+ target_siginfo_t uinfo;
+
+ print_syscall_prologue(name);
+ print_raw_param("%d", arg0, 0);
+ print_signal(arg1, 0);
+
+ p = lock_user(VERIFY_READ, arg2, sizeof(target_siginfo_t), 1);
+ if (p) {
+ get_target_siginfo(&uinfo, p);
+ print_siginfo(&uinfo);
+
+ unlock_user(p, arg2, 0);
+ } else {
+ print_pointer(arg2, 1);
+ }
+
+ print_raw_param("%u", arg3, 0);
+ print_syscall_epilogue(name);
+}
+#endif
+
#ifdef TARGET_NR_mq_unlink
static void
print_mq_unlink(CPUArchState *cpu_env, const struct syscallname *name,
@@ -3489,6 +3608,21 @@ print_unshare(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif
+#ifdef TARGET_NR_clock_nanosleep
+static void
+print_clock_nanosleep(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_syscall_prologue(name);
+ print_enums(clockids, arg0, 0);
+ print_raw_param("%d", arg1, 0);
+ print_timespec(arg2, 0);
+ print_timespec(arg3, 1);
+ print_syscall_epilogue(name);
+}
+#endif
+
#ifdef TARGET_NR_utime
static void
print_utime(CPUArchState *cpu_env, const struct syscallname *name,
@@ -3576,44 +3710,37 @@ print_munmap(CPUArchState *cpu_env, const struct syscallname *name,
#endif
#ifdef TARGET_NR_futex
-static void print_futex_op(abi_long tflag, int last)
-{
-#define print_op(val) \
-if( cmd == val ) { \
- qemu_log(#val); \
- return; \
-}
-
- int cmd = (int)tflag;
-#ifdef FUTEX_PRIVATE_FLAG
- if (cmd & FUTEX_PRIVATE_FLAG) {
- qemu_log("FUTEX_PRIVATE_FLAG|");
- cmd &= ~FUTEX_PRIVATE_FLAG;
- }
-#endif
-#ifdef FUTEX_CLOCK_REALTIME
- if (cmd & FUTEX_CLOCK_REALTIME) {
- qemu_log("FUTEX_CLOCK_REALTIME|");
- cmd &= ~FUTEX_CLOCK_REALTIME;
+static void print_futex_op(int cmd, int last)
+{
+ static const char * const futex_names[] = {
+#define NAME(X) [X] = #X
+ NAME(FUTEX_WAIT),
+ NAME(FUTEX_WAKE),
+ NAME(FUTEX_FD),
+ NAME(FUTEX_REQUEUE),
+ NAME(FUTEX_CMP_REQUEUE),
+ NAME(FUTEX_WAKE_OP),
+ NAME(FUTEX_LOCK_PI),
+ NAME(FUTEX_UNLOCK_PI),
+ NAME(FUTEX_TRYLOCK_PI),
+ NAME(FUTEX_WAIT_BITSET),
+ NAME(FUTEX_WAKE_BITSET),
+ NAME(FUTEX_WAIT_REQUEUE_PI),
+ NAME(FUTEX_CMP_REQUEUE_PI),
+ NAME(FUTEX_LOCK_PI2),
+#undef NAME
+ };
+
+ unsigned base_cmd = cmd & FUTEX_CMD_MASK;
+
+ if (base_cmd < ARRAY_SIZE(futex_names)) {
+ qemu_log("%s%s%s",
+ (cmd & FUTEX_PRIVATE_FLAG ? "FUTEX_PRIVATE_FLAG|" : ""),
+ (cmd & FUTEX_CLOCK_REALTIME ? "FUTEX_CLOCK_REALTIME|" : ""),
+ futex_names[base_cmd]);
+ } else {
+ qemu_log("0x%x", cmd);
}
-#endif
- print_op(FUTEX_WAIT)
- print_op(FUTEX_WAKE)
- print_op(FUTEX_FD)
- print_op(FUTEX_REQUEUE)
- print_op(FUTEX_CMP_REQUEUE)
- print_op(FUTEX_WAKE_OP)
- print_op(FUTEX_LOCK_PI)
- print_op(FUTEX_UNLOCK_PI)
- print_op(FUTEX_TRYLOCK_PI)
-#ifdef FUTEX_WAIT_BITSET
- print_op(FUTEX_WAIT_BITSET)
-#endif
-#ifdef FUTEX_WAKE_BITSET
- print_op(FUTEX_WAKE_BITSET)
-#endif
- /* unknown values */
- qemu_log("%d", cmd);
}
static void
@@ -3621,11 +3748,23 @@ print_futex(CPUArchState *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
+ abi_long op = arg1 & FUTEX_CMD_MASK;
print_syscall_prologue(name);
print_pointer(arg0, 0);
print_futex_op(arg1, 0);
print_raw_param(",%d", arg2, 0);
- print_pointer(arg3, 0); /* struct timespec */
+ switch (op) {
+ case FUTEX_WAIT:
+ case FUTEX_WAIT_BITSET:
+ case FUTEX_LOCK_PI:
+ case FUTEX_LOCK_PI2:
+ case FUTEX_WAIT_REQUEUE_PI:
+ print_timespec(arg3, 0);
+ break;
+ default:
+ print_pointer(arg3, 0);
+ break;
+ }
print_pointer(arg4, 0);
print_raw_param("%d", arg4, 1);
print_syscall_epilogue(name);
@@ -3780,26 +3919,37 @@ print_syscall(CPUArchState *cpu_env, int num,
abi_long arg4, abi_long arg5, abi_long arg6)
{
int i;
- const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")";
+ FILE *f;
+ const char *format = "%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
+ TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
+ TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")";
- qemu_log("%d ", getpid());
+ f = qemu_log_trylock();
+ if (!f) {
+ return;
+ }
+ fprintf(f, "%d ", getpid());
- for(i=0;i<nsyscalls;i++)
- if( scnames[i].nr == num ) {
- if( scnames[i].call != NULL ) {
- scnames[i].call(
- cpu_env, &scnames[i], arg1, arg2, arg3, arg4, arg5, arg6);
+ for (i = 0; i < nsyscalls; i++) {
+ if (scnames[i].nr == num) {
+ if (scnames[i].call != NULL) {
+ scnames[i].call(cpu_env, &scnames[i], arg1, arg2, arg3,
+ arg4, arg5, arg6);
} else {
/* XXX: this format system is broken because it uses
host types and host pointers for strings */
- if( scnames[i].format != NULL )
+ if (scnames[i].format != NULL) {
format = scnames[i].format;
- qemu_log(format,
- scnames[i].name, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+ fprintf(f, format, scnames[i].name, arg1, arg2,
+ arg3, arg4, arg5, arg6);
}
+ qemu_log_unlock(f);
return;
}
- qemu_log("Unknown syscall %d\n", num);
+ }
+ fprintf(f, "Unknown syscall %d\n", num);
+ qemu_log_unlock(f);
}
@@ -3809,21 +3959,29 @@ print_syscall_ret(CPUArchState *cpu_env, int num, abi_long ret,
abi_long arg4, abi_long arg5, abi_long arg6)
{
int i;
+ FILE *f;
- for(i=0;i<nsyscalls;i++)
- if( scnames[i].nr == num ) {
- if( scnames[i].result != NULL ) {
+ f = qemu_log_trylock();
+ if (!f) {
+ return;
+ }
+
+ for (i = 0; i < nsyscalls; i++) {
+ if (scnames[i].nr == num) {
+ if (scnames[i].result != NULL) {
scnames[i].result(cpu_env, &scnames[i], ret,
arg1, arg2, arg3,
arg4, arg5, arg6);
} else {
if (!print_syscall_err(ret)) {
- qemu_log(TARGET_ABI_FMT_ld, ret);
+ fprintf(f, TARGET_ABI_FMT_ld, ret);
}
- qemu_log("\n");
+ fprintf(f, "\n");
}
break;
}
+ }
+ qemu_log_unlock(f);
}
void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
@@ -3831,9 +3989,17 @@ void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
/* Print the strace output for a signal being taken:
* --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
*/
- qemu_log("--- ");
+ FILE *f;
+
+ f = qemu_log_trylock();
+ if (!f) {
+ return;
+ }
+
+ fprintf(f, "--- ");
print_signal(target_signum, 1);
- qemu_log(" ");
+ fprintf(f, " ");
print_siginfo(tinfo);
- qemu_log(" ---\n");
+ fprintf(f, " ---\n");
+ qemu_log_unlock(f);
}
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 72e17b1acf..a87415bf3d 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -91,7 +91,8 @@
print_syscall_ret_clock_gettime },
#endif
#ifdef TARGET_NR_clock_nanosleep
-{ TARGET_NR_clock_nanosleep, "clock_nanosleep" , NULL, NULL, NULL },
+{ TARGET_NR_clock_nanosleep, "clock_nanosleep" , NULL, print_clock_nanosleep,
+ NULL },
#endif
#ifdef TARGET_NR_clock_settime
{ TARGET_NR_clock_settime, "clock_settime" , NULL, print_clock_settime, NULL },
@@ -278,10 +279,10 @@
{ TARGET_NR_getcwd, "getcwd" , "%s(%p,%d)", NULL, NULL },
#endif
#ifdef TARGET_NR_getdents
-{ TARGET_NR_getdents, "getdents" , NULL, NULL, NULL },
+{ TARGET_NR_getdents, "getdents" , "%s(%d,%p,%u)", NULL, NULL },
#endif
#ifdef TARGET_NR_getdents64
-{ TARGET_NR_getdents64, "getdents64" , NULL, NULL, NULL },
+{ TARGET_NR_getdents64, "getdents64" , "%s(%d,%p,%u)", NULL, NULL },
#endif
#ifdef TARGET_NR_getdomainname
{ TARGET_NR_getdomainname, "getdomainname" , NULL, NULL, NULL },
@@ -351,7 +352,7 @@
{ TARGET_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
#endif
#ifdef TARGET_NR_getrandom
-{ TARGET_NR_getrandom, "getrandom", NULL, NULL, NULL },
+{ TARGET_NR_getrandom, "getrandom", "%s(%p,%u,%u)", NULL, NULL },
#endif
#ifdef TARGET_NR_getresgid
{ TARGET_NR_getresgid, "getresgid" , NULL, NULL, NULL },
@@ -541,7 +542,7 @@
{ TARGET_NR_lstat64, "lstat64" , NULL, print_lstat64, NULL },
#endif
#ifdef TARGET_NR_madvise
-{ TARGET_NR_madvise, "madvise" , NULL, NULL, NULL },
+{ TARGET_NR_madvise, "madvise" , NULL, print_madvise, NULL },
#endif
#ifdef TARGET_NR_madvise1
{ TARGET_NR_madvise1, "madvise1" , NULL, NULL, NULL },
@@ -1664,6 +1665,15 @@
#ifdef TARGET_NR_pipe2
{ TARGET_NR_pipe2, "pipe2", NULL, NULL, NULL },
#endif
+#ifdef TARGET_NR_pidfd_open
+{ TARGET_NR_pidfd_open, "pidfd_open", "%s(%d,%u)", NULL, NULL },
+#endif
+#ifdef TARGET_NR_pidfd_send_signal
+{ TARGET_NR_pidfd_send_signal, "pidfd_send_signal", NULL, print_pidfd_send_signal, NULL },
+#endif
+#ifdef TARGET_NR_pidfd_getfd
+{ TARGET_NR_pidfd_getfd, "pidfd_getfd", "%s(%d,%d,%u)", NULL, NULL },
+#endif
#ifdef TARGET_NR_atomic_cmpxchg_32
{ TARGET_NR_atomic_cmpxchg_32, "atomic_cmpxchg_32", NULL, NULL, NULL },
#endif
@@ -1676,3 +1686,7 @@
#ifdef TARGET_NR_copy_file_range
{ TARGET_NR_copy_file_range, "copy_file_range", "%s(%d,%p,%d,%p,"TARGET_ABI_FMT_lu",%u)", NULL, NULL },
#endif
+#ifdef TARGET_NR_clock_gettime64
+{ TARGET_NR_clock_gettime64, "clock_gettime64" , NULL, print_clock_gettime64,
+ print_syscall_ret_clock_gettime64 },
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f409121202..2e954d8dbd 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -346,6 +346,16 @@ _syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
_syscall6(int,sys_futex_time64,int *,uaddr,int,op,int,val,
const struct timespec *,timeout,int *,uaddr2,int,val3)
#endif
+#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
+_syscall2(int, pidfd_open, pid_t, pid, unsigned int, flags);
+#endif
+#if defined(__NR_pidfd_send_signal) && defined(TARGET_NR_pidfd_send_signal)
+_syscall4(int, pidfd_send_signal, int, pidfd, int, sig, siginfo_t *, info,
+ unsigned int, flags);
+#endif
+#if defined(__NR_pidfd_getfd) && defined(TARGET_NR_pidfd_getfd)
+_syscall3(int, pidfd_getfd, int, pidfd, int, targetfd, unsigned int, flags);
+#endif
#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr);
@@ -515,20 +525,25 @@ _syscall4(int, sys_prlimit64, pid_t, pid, int, resource,
#if defined(TARGET_NR_timer_create)
/* Maximum of 32 active POSIX timers allowed at any one time. */
-static timer_t g_posix_timers[32] = { 0, } ;
+#define GUEST_TIMER_MAX 32
+static timer_t g_posix_timers[GUEST_TIMER_MAX];
+static int g_posix_timer_allocated[GUEST_TIMER_MAX];
static inline int next_free_host_timer(void)
{
- int k ;
- /* FIXME: Does finding the next free slot require a lock? */
- for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
- if (g_posix_timers[k] == 0) {
- g_posix_timers[k] = (timer_t) 1;
+ int k;
+ for (k = 0; k < ARRAY_SIZE(g_posix_timer_allocated); k++) {
+ if (qatomic_xchg(g_posix_timer_allocated + k, 1) == 0) {
return k;
}
}
return -1;
}
+
+static inline void free_host_timer_slot(int id)
+{
+ qatomic_store_release(g_posix_timer_allocated + id, 0);
+}
#endif
static inline int host_to_target_errno(int host_errno)
@@ -7753,15 +7768,16 @@ static int do_safe_futex(int *uaddr, int op, int val,
futexes locally would make futexes shared between multiple processes
tricky. However they're probably useless because guest atomic
operations won't work either. */
-#if defined(TARGET_NR_futex)
-static int do_futex(CPUState *cpu, target_ulong uaddr, int op, int val,
- target_ulong timeout, target_ulong uaddr2, int val3)
+#if defined(TARGET_NR_futex) || defined(TARGET_NR_futex_time64)
+static int do_futex(CPUState *cpu, bool time64, target_ulong uaddr,
+ int op, int val, target_ulong timeout,
+ target_ulong uaddr2, int val3)
{
- struct timespec ts, *pts;
+ struct timespec ts, *pts = NULL;
+ void *haddr2 = NULL;
int base_op;
- /* ??? We assume FUTEX_* constants are the same on both host
- and target. */
+ /* We assume FUTEX_* constants are the same on both host and target. */
#ifdef FUTEX_CMD_MASK
base_op = op & FUTEX_CMD_MASK;
#else
@@ -7770,85 +7786,53 @@ static int do_futex(CPUState *cpu, target_ulong uaddr, int op, int val,
switch (base_op) {
case FUTEX_WAIT:
case FUTEX_WAIT_BITSET:
- if (timeout) {
- pts = &ts;
- target_to_host_timespec(pts, timeout);
- } else {
- pts = NULL;
- }
- return do_safe_futex(g2h(cpu, uaddr),
- op, tswap32(val), pts, NULL, val3);
+ val = tswap32(val);
+ break;
+ case FUTEX_WAIT_REQUEUE_PI:
+ val = tswap32(val);
+ haddr2 = g2h(cpu, uaddr2);
+ break;
+ case FUTEX_LOCK_PI:
+ case FUTEX_LOCK_PI2:
+ break;
case FUTEX_WAKE:
- return do_safe_futex(g2h(cpu, uaddr),
- op, val, NULL, NULL, 0);
+ case FUTEX_WAKE_BITSET:
+ case FUTEX_TRYLOCK_PI:
+ case FUTEX_UNLOCK_PI:
+ timeout = 0;
+ break;
case FUTEX_FD:
- return do_safe_futex(g2h(cpu, uaddr),
- op, val, NULL, NULL, 0);
- case FUTEX_REQUEUE:
+ val = target_to_host_signal(val);
+ timeout = 0;
+ break;
case FUTEX_CMP_REQUEUE:
+ case FUTEX_CMP_REQUEUE_PI:
+ val3 = tswap32(val3);
+ /* fall through */
+ case FUTEX_REQUEUE:
case FUTEX_WAKE_OP:
- /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
- TIMEOUT parameter is interpreted as a uint32_t by the kernel.
- But the prototype takes a `struct timespec *'; insert casts
- to satisfy the compiler. We do not need to tswap TIMEOUT
- since it's not compared to guest memory. */
- pts = (struct timespec *)(uintptr_t) timeout;
- return do_safe_futex(g2h(cpu, uaddr), op, val, pts, g2h(cpu, uaddr2),
- (base_op == FUTEX_CMP_REQUEUE
- ? tswap32(val3) : val3));
+ /*
+ * For these, the 4th argument is not TIMEOUT, but VAL2.
+ * But the prototype of do_safe_futex takes a pointer, so
+ * insert casts to satisfy the compiler. We do not need
+ * to tswap VAL2 since it's not compared to guest memory.
+ */
+ pts = (struct timespec *)(uintptr_t)timeout;
+ timeout = 0;
+ haddr2 = g2h(cpu, uaddr2);
+ break;
default:
return -TARGET_ENOSYS;
}
-}
-#endif
-
-#if defined(TARGET_NR_futex_time64)
-static int do_futex_time64(CPUState *cpu, target_ulong uaddr, int op,
- int val, target_ulong timeout,
- target_ulong uaddr2, int val3)
-{
- struct timespec ts, *pts;
- int base_op;
-
- /* ??? We assume FUTEX_* constants are the same on both host
- and target. */
-#ifdef FUTEX_CMD_MASK
- base_op = op & FUTEX_CMD_MASK;
-#else
- base_op = op;
-#endif
- switch (base_op) {
- case FUTEX_WAIT:
- case FUTEX_WAIT_BITSET:
- if (timeout) {
- pts = &ts;
- if (target_to_host_timespec64(pts, timeout)) {
- return -TARGET_EFAULT;
- }
- } else {
- pts = NULL;
+ if (timeout) {
+ pts = &ts;
+ if (time64
+ ? target_to_host_timespec64(pts, timeout)
+ : target_to_host_timespec(pts, timeout)) {
+ return -TARGET_EFAULT;
}
- return do_safe_futex(g2h(cpu, uaddr), op,
- tswap32(val), pts, NULL, val3);
- case FUTEX_WAKE:
- return do_safe_futex(g2h(cpu, uaddr), op, val, NULL, NULL, 0);
- case FUTEX_FD:
- return do_safe_futex(g2h(cpu, uaddr), op, val, NULL, NULL, 0);
- case FUTEX_REQUEUE:
- case FUTEX_CMP_REQUEUE:
- case FUTEX_WAKE_OP:
- /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the
- TIMEOUT parameter is interpreted as a uint32_t by the kernel.
- But the prototype takes a `struct timespec *'; insert casts
- to satisfy the compiler. We do not need to tswap TIMEOUT
- since it's not compared to guest memory. */
- pts = (struct timespec *)(uintptr_t) timeout;
- return do_safe_futex(g2h(cpu, uaddr), op, val, pts, g2h(cpu, uaddr2),
- (base_op == FUTEX_CMP_REQUEUE
- ? tswap32(val3) : val3));
- default:
- return -TARGET_ENOSYS;
}
+ return do_safe_futex(g2h(cpu, uaddr), op, val, pts, haddr2, val3);
}
#endif
@@ -8026,7 +8010,11 @@ static int open_self_maps(CPUArchState *cpu_env, int fd)
continue;
}
+#ifdef TARGET_HPPA
+ if (h2g(max) == ts->info->stack_limit) {
+#else
if (h2g(min) == ts->info->stack_limit) {
+#endif
path = "[stack]";
} else {
path = e->path;
@@ -8684,6 +8672,30 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
fd_trans_unregister(ret);
return ret;
#endif
+#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
+ case TARGET_NR_pidfd_open:
+ return get_errno(pidfd_open(arg1, arg2));
+#endif
+#if defined(__NR_pidfd_send_signal) && defined(TARGET_NR_pidfd_send_signal)
+ case TARGET_NR_pidfd_send_signal:
+ {
+ siginfo_t uinfo;
+
+ p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ target_to_host_siginfo(&uinfo, p);
+ unlock_user(p, arg3, 0);
+ ret = get_errno(pidfd_send_signal(arg1, target_to_host_signal(arg2),
+ &uinfo, arg4));
+ }
+ return ret;
+#endif
+#if defined(__NR_pidfd_getfd) && defined(TARGET_NR_pidfd_getfd)
+ case TARGET_NR_pidfd_getfd:
+ return get_errno(pidfd_getfd(arg1, arg2, arg3));
+#endif
case TARGET_NR_close:
fd_trans_unregister(arg1);
return get_errno(close(arg1));
@@ -9690,7 +9702,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
}
target_to_host_siginfo(&uinfo, p);
unlock_user(p, arg3, 0);
- ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
+ ret = get_errno(sys_rt_sigqueueinfo(arg1, target_to_host_signal(arg2), &uinfo));
}
return ret;
case TARGET_NR_rt_tgsigqueueinfo:
@@ -9703,7 +9715,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
}
target_to_host_siginfo(&uinfo, p);
unlock_user(p, arg4, 0);
- ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
+ ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, target_to_host_signal(arg3), &uinfo));
}
return ret;
#ifdef TARGET_NR_sigreturn
@@ -9912,11 +9924,22 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
if (!p || !p2) {
ret = -TARGET_EFAULT;
+ } else if (!arg4) {
+ /* Short circuit this for the magic exe check. */
+ ret = -TARGET_EINVAL;
} else if (is_proc_myself((const char *)p, "exe")) {
char real[PATH_MAX], *temp;
temp = realpath(exec_path, real);
- ret = temp == NULL ? get_errno(-1) : strlen(real) ;
- snprintf((char *)p2, arg4, "%s", real);
+ /* Return value is # of bytes that we wrote to the buffer. */
+ if (temp == NULL) {
+ ret = get_errno(-1);
+ } else {
+ /* Don't worry about sign mismatch as earlier mapping
+ * logic would have thrown a bad address error. */
+ ret = MIN(strlen(real), arg4);
+ /* We cannot NUL terminate the string. */
+ memcpy(p2, real, ret);
+ }
} else {
ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
}
@@ -12318,11 +12341,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_futex
case TARGET_NR_futex:
- return do_futex(cpu, arg1, arg2, arg3, arg4, arg5, arg6);
+ return do_futex(cpu, false, arg1, arg2, arg3, arg4, arg5, arg6);
#endif
#ifdef TARGET_NR_futex_time64
case TARGET_NR_futex_time64:
- return do_futex_time64(cpu, arg1, arg2, arg3, arg4, arg5, arg6);
+ return do_futex(cpu, true, arg1, arg2, arg3, arg4, arg5, arg6);
#endif
#ifdef CONFIG_INOTIFY
#if defined(TARGET_NR_inotify_init)
@@ -12847,15 +12870,18 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
phost_sevp = &host_sevp;
ret = target_to_host_sigevent(phost_sevp, arg2);
if (ret != 0) {
+ free_host_timer_slot(timer_index);
return ret;
}
}
ret = get_errno(timer_create(clkid, phost_sevp, phtimer));
if (ret) {
- phtimer = NULL;
+ free_host_timer_slot(timer_index);
} else {
if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
+ timer_delete(*phtimer);
+ free_host_timer_slot(timer_index);
return -TARGET_EFAULT;
}
}
@@ -12991,7 +13017,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
} else {
timer_t htimer = g_posix_timers[timerid];
ret = get_errno(timer_delete(htimer));
- g_posix_timers[timerid] = 0;
+ free_host_timer_slot(timerid);
}
return ret;
}
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 85b0f33e91..01ee10a88f 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1246,7 +1246,7 @@ struct target_winsize {
#include "termbits.h"
-#if defined(TARGET_MIPS)
+#if defined(TARGET_MIPS) || defined(TARGET_XTENSA)
#define TARGET_PROT_SEM 0x10
#else
#define TARGET_PROT_SEM 0x08
@@ -2699,6 +2699,9 @@ struct target_drm_i915_getparam {
#define FUTEX_TRYLOCK_PI 8
#define FUTEX_WAIT_BITSET 9
#define FUTEX_WAKE_BITSET 10
+#define FUTEX_WAIT_REQUEUE_PI 11
+#define FUTEX_CMP_REQUEUE_PI 12
+#define FUTEX_LOCK_PI2 13
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256
diff --git a/linux-user/x86_64/target_elf.h b/linux-user/x86_64/target_elf.h
index 7b76a90de8..3f628f8d66 100644
--- a/linux-user/x86_64/target_elf.h
+++ b/linux-user/x86_64/target_elf.h
@@ -9,6 +9,6 @@
#define X86_64_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
- return "qemu64";
+ return "max";
}
#endif
diff --git a/linux-user/x86_64/target_mman.h b/linux-user/x86_64/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/x86_64/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"
diff --git a/linux-user/xtensa/target_mman.h b/linux-user/xtensa/target_mman.h
new file mode 100644
index 0000000000..e7ba6070fe
--- /dev/null
+++ b/linux-user/xtensa/target_mman.h
@@ -0,0 +1 @@
+#include "../generic/target_mman.h"