fork: Allow ABI to specify fork return values for child.
At least Linux x86 ABI's does not use carry bit and expects that the dx register is preserved. For this add a new sv_set_fork_retval hook and call it from cpu_fork(). Add a short comment about touching dx in x86_set_fork_retval(), for more details see phab comments from kib@ and imp@. Reviewed by: kib Differential revision: https://reviews.freebsd.org/D31472 MFC after: 2 weeks
This commit is contained in:
parent
fc37be2460
commit
de8374df28
@ -87,6 +87,7 @@ struct sysentvec elf64_freebsd_sysvec_la48 = {
|
||||
.sv_stackgap = elf64_stackgap,
|
||||
.sv_onexec_old = exec_onexec_old,
|
||||
.sv_onexit = exit_onexit,
|
||||
.sv_set_fork_retval = x86_set_fork_retval,
|
||||
};
|
||||
|
||||
struct sysentvec elf64_freebsd_sysvec_la57 = {
|
||||
@ -127,6 +128,7 @@ struct sysentvec elf64_freebsd_sysvec_la57 = {
|
||||
.sv_stackgap = elf64_stackgap,
|
||||
.sv_onexec_old = exec_onexec_old,
|
||||
.sv_onexit = exit_onexit,
|
||||
.sv_set_fork_retval= x86_set_fork_retval,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -245,9 +245,8 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
|
||||
td2->td_frame = (struct trapframe *)td2->td_md.md_stack_base - 1;
|
||||
bcopy(td1->td_frame, td2->td_frame, sizeof(struct trapframe));
|
||||
|
||||
td2->td_frame->tf_rax = 0; /* Child returns zero */
|
||||
td2->td_frame->tf_rflags &= ~PSL_C; /* success */
|
||||
td2->td_frame->tf_rdx = 1;
|
||||
/* Set child return values. */
|
||||
p2->p_sysent->sv_set_fork_retval(td2);
|
||||
|
||||
/*
|
||||
* If the parent process has the trap bit set (i.e. a debugger
|
||||
@ -300,6 +299,16 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
x86_set_fork_retval(struct thread *td)
|
||||
{
|
||||
struct trapframe *frame = td->td_frame;
|
||||
|
||||
frame->tf_rax = 0; /* Child returns zero */
|
||||
frame->tf_rflags &= ~PSL_C; /* success */
|
||||
frame->tf_rdx = 1; /* System V emulation */
|
||||
}
|
||||
|
||||
/*
|
||||
* Intercept the return address from a freshly forked process that has NOT
|
||||
* been scheduled yet.
|
||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/frame.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
@ -225,6 +226,7 @@ static struct sysentvec cloudabi32_elf_sysvec = {
|
||||
.sv_fetch_syscall_args = cloudabi32_fetch_syscall_args,
|
||||
.sv_syscallnames = cloudabi32_syscallnames,
|
||||
.sv_schedtail = cloudabi32_schedtail,
|
||||
.sv_set_fork_retval = x86_set_fork_retval,
|
||||
};
|
||||
|
||||
INIT_SYSENTVEC(elf_sysvec, &cloudabi32_elf_sysvec);
|
||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/frame.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
@ -212,6 +213,7 @@ static struct sysentvec cloudabi64_elf_sysvec = {
|
||||
.sv_fetch_syscall_args = cloudabi64_fetch_syscall_args,
|
||||
.sv_syscallnames = cloudabi64_syscallnames,
|
||||
.sv_schedtail = cloudabi64_schedtail,
|
||||
.sv_set_fork_retval = x86_set_fork_retval,
|
||||
};
|
||||
|
||||
INIT_SYSENTVEC(elf_sysvec, &cloudabi64_elf_sysvec);
|
||||
|
@ -125,6 +125,7 @@ static void linux_exec_setregs(struct thread *td, struct image_params *imgp,
|
||||
static void linux_exec_sysvec_init(void *param);
|
||||
static int linux_on_exec_vmspace(struct proc *p,
|
||||
struct image_params *imgp);
|
||||
static void linux_set_fork_retval(struct thread *td);
|
||||
static int linux_vsyscall(struct thread *td);
|
||||
|
||||
#define LINUX_T_UNKNOWN 255
|
||||
@ -269,6 +270,14 @@ linux_set_syscall_retval(struct thread *td, int error)
|
||||
set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_set_fork_retval(struct thread *td)
|
||||
{
|
||||
struct trapframe *frame = td->td_frame;
|
||||
|
||||
frame->tf_rax = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
linux_copyout_auxargs(struct image_params *imgp, uintptr_t base)
|
||||
{
|
||||
@ -790,6 +799,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_onexit = linux_on_exit,
|
||||
.sv_ontdexit = linux_thread_dtor,
|
||||
.sv_setid_allowed = &linux_setid_allowed_query,
|
||||
.sv_set_fork_retval = linux_set_fork_retval,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -128,6 +128,7 @@ static bool linux32_trans_osrel(const Elf_Note *note, int32_t *osrel);
|
||||
static void linux_vdso_install(const void *param);
|
||||
static void linux_vdso_deinstall(const void *param);
|
||||
static void linux_vdso_reloc(char *mapping, Elf_Addr offset);
|
||||
static void linux32_set_fork_retval(struct thread *td);
|
||||
static void linux32_set_syscall_retval(struct thread *td, int error);
|
||||
|
||||
#define LINUX_T_UNKNOWN 255
|
||||
@ -703,6 +704,14 @@ linux32_set_syscall_retval(struct thread *td, int error)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
linux32_set_fork_retval(struct thread *td)
|
||||
{
|
||||
struct trapframe *frame = td->td_frame;
|
||||
|
||||
frame->tf_rax = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear registers on exec
|
||||
* XXX copied from ia32_signal.c.
|
||||
@ -956,6 +965,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_onexit = linux_on_exit,
|
||||
.sv_ontdexit = linux_thread_dtor,
|
||||
.sv_setid_allowed = &linux_setid_allowed_query,
|
||||
.sv_set_fork_retval = linux32_set_fork_retval,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -133,6 +133,7 @@ struct sysentvec ia32_freebsd_sysvec = {
|
||||
.sv_stackgap = elf32_stackgap,
|
||||
.sv_onexec_old = exec_onexec_old,
|
||||
.sv_onexit = exit_onexit,
|
||||
.sv_set_fork_retval = x86_set_fork_retval,
|
||||
};
|
||||
INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec);
|
||||
|
||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/frame.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
@ -195,6 +196,7 @@ static struct sysentvec cloudabi32_elf_sysvec = {
|
||||
.sv_fetch_syscall_args = cloudabi32_fetch_syscall_args,
|
||||
.sv_syscallnames = cloudabi32_syscallnames,
|
||||
.sv_schedtail = cloudabi32_schedtail,
|
||||
.sv_set_fork_retval = x86_set_fork_retval,
|
||||
};
|
||||
|
||||
INIT_SYSENTVEC(elf_sysvec, &cloudabi32_elf_sysvec);
|
||||
|
@ -88,6 +88,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_trap = NULL,
|
||||
.sv_onexec_old = exec_onexec_old,
|
||||
.sv_onexit = exit_onexit,
|
||||
.sv_set_fork_retval = x86_set_fork_retval,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
|
@ -258,9 +258,8 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
|
||||
VM86_STACK_SPACE) - 1;
|
||||
bcopy(td1->td_frame, td2->td_frame, sizeof(struct trapframe));
|
||||
|
||||
td2->td_frame->tf_eax = 0; /* Child returns zero */
|
||||
td2->td_frame->tf_eflags &= ~PSL_C; /* success */
|
||||
td2->td_frame->tf_edx = 1;
|
||||
/* Set child return values. */
|
||||
p2->p_sysent->sv_set_fork_retval(td2);
|
||||
|
||||
/*
|
||||
* If the parent process has the trap bit set (i.e. a debugger
|
||||
@ -302,6 +301,16 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
x86_set_fork_retval(struct thread *td)
|
||||
{
|
||||
struct trapframe * frame = td->td_frame;
|
||||
|
||||
frame->tf_eax = 0; /* Child returns zero */
|
||||
frame->tf_eflags &= ~PSL_C; /* success */
|
||||
frame->tf_edx = 1; /* System V emulation */
|
||||
}
|
||||
|
||||
/*
|
||||
* Intercept the return address from a freshly forked process that has NOT
|
||||
* been scheduled yet.
|
||||
|
@ -108,6 +108,7 @@ static int linux_on_exec_vmspace(struct proc *p,
|
||||
struct image_params *imgp);
|
||||
static int linux_copyout_strings(struct image_params *imgp,
|
||||
uintptr_t *stack_base);
|
||||
static void linux_set_fork_retval(struct thread *td);
|
||||
static bool linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
|
||||
static void linux_vdso_install(const void *param);
|
||||
static void linux_vdso_deinstall(const void *param);
|
||||
@ -803,6 +804,14 @@ linux_set_syscall_retval(struct thread *td, int error)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
linux_set_fork_retval(struct thread *td)
|
||||
{
|
||||
struct trapframe *frame = td->td_frame;
|
||||
|
||||
frame->tf_eax = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* exec_setregs may initialize some registers differently than Linux
|
||||
* does, thus potentially confusing Linux binaries. If necessary, we
|
||||
@ -856,6 +865,7 @@ struct sysentvec linux_sysvec = {
|
||||
.sv_onexit = linux_on_exit,
|
||||
.sv_ontdexit = linux_thread_dtor,
|
||||
.sv_setid_allowed = &linux_setid_allowed_query,
|
||||
.sv_set_fork_retval = linux_set_fork_retval,
|
||||
};
|
||||
INIT_SYSENTVEC(aout_sysvec, &linux_sysvec);
|
||||
|
||||
@ -898,6 +908,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_onexit = linux_on_exit,
|
||||
.sv_ontdexit = linux_thread_dtor,
|
||||
.sv_setid_allowed = &linux_setid_allowed_query,
|
||||
.sv_set_fork_retval = linux_set_fork_retval,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -103,6 +103,7 @@ struct sysentvec aout_sysvec = {
|
||||
.sv_trap = NULL,
|
||||
.sv_onexec_old = exec_onexec_old,
|
||||
.sv_onexit = exit_onexit,
|
||||
.sv_set_fork_retval = x86_set_fork_retval,
|
||||
};
|
||||
|
||||
#elif defined(__amd64__)
|
||||
@ -141,6 +142,7 @@ struct sysentvec aout_sysvec = {
|
||||
.sv_syscallnames = freebsd32_syscallnames,
|
||||
.sv_onexec_old = exec_onexec_old,
|
||||
.sv_onexit = exit_onexit,
|
||||
.sv_set_fork_retval = x86_set_fork_retval,
|
||||
};
|
||||
#else
|
||||
#error "Port me"
|
||||
|
@ -402,6 +402,12 @@ null_set_syscall_retval(struct thread *td __unused, int error __unused)
|
||||
panic("null_set_syscall_retval");
|
||||
}
|
||||
|
||||
static void
|
||||
null_set_fork_retval(struct thread *td __unused)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct sysentvec null_sysvec = {
|
||||
.sv_size = 0,
|
||||
.sv_table = NULL,
|
||||
@ -430,6 +436,7 @@ struct sysentvec null_sysvec = {
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
.sv_set_fork_retval = null_set_fork_retval,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -156,6 +156,8 @@ struct sysentvec {
|
||||
void (*sv_ontdexit)(struct thread *td);
|
||||
int (*sv_setid_allowed)(struct thread *td,
|
||||
struct image_params *imgp);
|
||||
void (*sv_set_fork_retval)(struct thread *);
|
||||
/* Only used on x86 */
|
||||
};
|
||||
|
||||
#define SV_ILP32 0x000100 /* 32-bit executable. */
|
||||
|
@ -153,6 +153,7 @@ int pti_get_default(void);
|
||||
int user_dbreg_trap(register_t dr6);
|
||||
int minidumpsys(struct dumperinfo *);
|
||||
struct pcb *get_pcb_td(struct thread *td);
|
||||
void x86_set_fork_retval(struct thread *td);
|
||||
|
||||
/*
|
||||
* MSR ops for x86_msr_op()
|
||||
|
Loading…
Reference in New Issue
Block a user