Commit 3b8dcf02 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Andrei Vagin

infect: Move get_task_regs-s into arch/infect.c

Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 590856f5
......@@ -81,33 +81,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
#define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e
int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{
struct iovec iov;
user_fpregs_struct_t fpsimd;
int ret;
pr_info("Dumping GP/FPU registers for %d\n", pid);
iov.iov_base = &regs;
iov.iov_len = sizeof(user_regs_struct_t);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))) {
pr_perror("Failed to obtain CPU registers for %d", pid);
goto err;
}
iov.iov_base = &fpsimd;
iov.iov_len = sizeof(fpsimd);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) {
pr_perror("Failed to obtain FPU registers for %d", pid);
goto err;
}
ret = save(arg, &regs, &fpsimd);
err:
return ret;
}
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd)
{
int i;
......
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
......
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <linux/elf.h>
#include "asm/parasite-syscall.h"
#include "uapi/std/syscall-codes.h"
#include "asm/types.h"
#include "criu-log.h"
#include "kerndat.h"
#include "parasite-syscall.h"
#include "errno.h"
#include "infect.h"
#include "infect-priv.h"
int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{
struct iovec iov;
user_fpregs_struct_t fpsimd;
int ret;
pr_info("Dumping GP/FPU registers for %d\n", pid);
iov.iov_base = &regs;
iov.iov_len = sizeof(user_regs_struct_t);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))) {
pr_perror("Failed to obtain CPU registers for %d", pid);
goto err;
}
iov.iov_base = &fpsimd;
iov.iov_len = sizeof(fpsimd);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) {
pr_perror("Failed to obtain FPU registers for %d", pid);
goto err;
}
ret = save(arg, &regs, &fpsimd);
err:
return ret;
}
......@@ -83,41 +83,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
#define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e)
#define PTRACE_GETVFPREGS 27
int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{
user_fpregs_struct_t vfp;
int ret = -1;
pr_info("Dumping GP/FPU registers for %d\n", pid);
if (ptrace(PTRACE_GETVFPREGS, pid, NULL, &vfp)) {
pr_perror("Can't obtain FPU registers for %d", pid);
goto err;
}
/* Did we come from a system call? */
if ((int)regs.ARM_ORIG_r0 >= 0) {
/* Restart the system call */
switch ((long)(int)regs.ARM_r0) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
regs.ARM_r0 = regs.ARM_ORIG_r0;
regs.ARM_pc -= 4;
break;
case -ERESTART_RESTARTBLOCK:
regs.ARM_r0 = __NR_restart_syscall;
regs.ARM_pc -= 4;
break;
}
}
ret = save(arg, &regs, &vfp);
err:
return ret;
}
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
CoreEntry *core = x;
......
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
......
#include <sys/ptrace.h>
#include <sys/types.h>
#include "asm/parasite-syscall.h"
#include "uapi/std/syscall-codes.h"
#include "asm/types.h"
#include "criu-log.h"
#include "kerndat.h"
#include "parasite-syscall.h"
#include "errno.h"
#include "infect.h"
#include "infect-priv.h"
#define PTRACE_GETVFPREGS 27
int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{
user_fpregs_struct_t vfp;
int ret = -1;
pr_info("Dumping GP/FPU registers for %d\n", pid);
if (ptrace(PTRACE_GETVFPREGS, pid, NULL, &vfp)) {
pr_perror("Can't obtain FPU registers for %d", pid);
goto err;
}
/* Did we come from a system call? */
if ((int)regs.ARM_ORIG_r0 >= 0) {
/* Restart the system call */
switch ((long)(int)regs.ARM_r0) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
regs.ARM_r0 = regs.ARM_ORIG_r0;
regs.ARM_pc -= 4;
break;
case -ERESTART_RESTARTBLOCK:
regs.ARM_r0 = __NR_restart_syscall;
regs.ARM_pc -= 4;
break;
}
}
ret = save(arg, &regs, &vfp);
err:
return ret;
}
......@@ -25,15 +25,6 @@
#include "images/core.pb-c.h"
#include "images/creds.pb-c.h"
#ifndef NT_PPC_TM_SPR
#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */
#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */
#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */
#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */
#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */
#endif
/*
* Injected syscall instruction
*/
......@@ -118,55 +109,6 @@ static UserPpc64FpstateEntry *copy_fp_regs(uint64_t *fpregs)
return fpe;
}
/* This is the layout of the POWER7 VSX registers and the way they
* overlap with the existing FPR and VMX registers.
*
* VSR doubleword 0 VSR doubleword 1
* ----------------------------------------------------------------
* VSR[0] | FPR[0] | |
* ----------------------------------------------------------------
* VSR[1] | FPR[1] | |
* ----------------------------------------------------------------
* | ... | |
* ----------------------------------------------------------------
* VSR[30] | FPR[30] | |
* ----------------------------------------------------------------
* VSR[31] | FPR[31] | |
* ----------------------------------------------------------------
* VSR[32] | VR[0] |
* ----------------------------------------------------------------
* VSR[33] | VR[1] |
* ----------------------------------------------------------------
* | ... |
* ----------------------------------------------------------------
* VSR[62] | VR[30] |
* ----------------------------------------------------------------
* VSR[63] | VR[31] |
* ----------------------------------------------------------------
*
* PTRACE_GETFPREGS returns FPR[0..31] + FPSCR
* PTRACE_GETVRREGS returns VR[0..31] + VSCR + VRSAVE
* PTRACE_GETVSRREGS returns VSR[0..31]
*
* PTRACE_GETVSRREGS and PTRACE_GETFPREGS are required since we need
* to save FPSCR too.
*
* There 32 VSX double word registers to save since the 32 first VSX double
* word registers are saved through FPR[0..32] and the remaining registers
* are saved when saving the Altivec registers VR[0..32].
*/
static int get_fpu_regs(pid_t pid, user_fpregs_struct_t *fp)
{
if (ptrace(PTRACE_GETFPREGS, pid, 0, (void *)&fp->fpregs) < 0) {
pr_perror("Couldn't get floating-point registers");
return -1;
}
fp->flags |= USER_FPREGS_FL_FP;
return 0;
}
static void put_fpu_regs(mcontext_t *mc, UserPpc64FpstateEntry *fpe)
{
int i;
......@@ -209,24 +151,6 @@ static UserPpc64VrstateEntry *copy_altivec_regs(__vector128 *vrregs)
return vse;
}
static int get_altivec_regs(pid_t pid, user_fpregs_struct_t *fp)
{
if (ptrace(PTRACE_GETVRREGS, pid, 0, (void*)&fp->vrregs) < 0) {
/* PTRACE_GETVRREGS returns EIO if Altivec is not supported.
* This should not happen if msr_vec is set. */
if (errno != EIO) {
pr_perror("Couldn't get Altivec registers");
return -1;
}
pr_debug("Altivec not supported\n");
}
else {
pr_debug("Dumping Altivec registers\n");
fp->flags |= USER_FPREGS_FL_ALTIVEC;
}
return 0;
}
static int put_altivec_regs(mcontext_t *mc, UserPpc64VrstateEntry *vse)
{
vrregset_t *v_regs = (vrregset_t *)(((unsigned long)mc->vmx_reserve + 15) & ~0xful);
......@@ -278,35 +202,6 @@ static UserPpc64VsxstateEntry* copy_vsx_regs(uint64_t *vsregs)
return vse;
}
/*
* Since the FPR[0-31] is stored in the first double word of VSR[0-31] and
* FPR are saved through the FP state, there is no need to save the upper part
* of the first 32 VSX registers.
* Furthermore, the 32 last VSX registers are also the 32 Altivec registers
* already saved, so no need to save them.
* As a consequence, only the doubleword 1 of the 32 first VSX registers have
* to be saved (the ones are returned by PTRACE_GETVSRREGS).
*/
static int get_vsx_regs(pid_t pid, user_fpregs_struct_t *fp)
{
if (ptrace(PTRACE_GETVSRREGS, pid, 0, (void*)fp->vsxregs) < 0) {
/*
* EIO is returned in the case PTRACE_GETVRREGS is not
* supported.
*/
if (errno != EIO) {
pr_perror("Couldn't get VSX registers");
return -1;
}
pr_debug("VSX register's dump not supported.\n");
}
else {
pr_debug("Dumping VSX registers\n");
fp->flags |= USER_FPREGS_FL_VSX;
}
return 0;
}
static int put_vsx_regs(mcontext_t *mc, UserPpc64VsxstateEntry *vse)
{
uint64_t *buf;
......@@ -415,56 +310,6 @@ static void xfree_tm_state(UserPpc64TmRegsEntry *tme)
}
}
static int get_tm_regs(pid_t pid, user_fpregs_struct_t *fpregs)
{
struct iovec iov;
pr_debug("Dumping TM registers\n");
#define TM_REQUIRED 0
#define TM_OPTIONAL 1
#define PTRACE_GET_TM(s,n,c,u) do { \
iov.iov_base = &s; \
iov.iov_len = sizeof(s); \
if (ptrace(PTRACE_GETREGSET, pid, c, &iov)) { \
if (!u || errno != EIO) { \
pr_perror("Couldn't get TM "n); \
pr_err("Your kernel seems to not support the " \
"new TM ptrace API (>= 4.8)\n"); \
goto out_free; \
} \
pr_debug("TM "n" not supported.\n"); \
iov.iov_base = NULL; \
} \
} while(0)
/* Get special registers */
PTRACE_GET_TM(fpregs->tm.tm_spr_regs, "SPR", NT_PPC_TM_SPR, TM_REQUIRED);
/* Get checkpointed regular registers */
PTRACE_GET_TM(fpregs->tm.regs, "GPR", NT_PPC_TM_CGPR, TM_REQUIRED);
/* Get checkpointed FP registers */
PTRACE_GET_TM(fpregs->tm.fpregs, "FPR", NT_PPC_TM_CFPR, TM_OPTIONAL);
if (iov.iov_base)
fpregs->tm.flags |= USER_FPREGS_FL_FP;
/* Get checkpointed VMX (Altivec) registers */
PTRACE_GET_TM(fpregs->tm.vrregs, "VMX", NT_PPC_TM_CVMX, TM_OPTIONAL);
if (iov.iov_base)
fpregs->tm.flags |= USER_FPREGS_FL_ALTIVEC;
/* Get checkpointed VSX registers */
PTRACE_GET_TM(fpregs->tm.vsxregs, "VSX", NT_PPC_TM_CVSX, TM_OPTIONAL);
if (iov.iov_base)
fpregs->tm.flags |= USER_FPREGS_FL_VSX;
return 0;
out_free:
return -1; /* still failing the checkpoint */
}
static int put_tm_regs(struct rt_sigframe *f, UserPpc64TmRegsEntry *tme)
{
/*
......@@ -499,71 +344,6 @@ static int put_tm_regs(struct rt_sigframe *f, UserPpc64TmRegsEntry *tme)
}
/****************************************************************************/
static int __get_task_regs(pid_t pid, user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs)
{
pr_info("Dumping GP/FPU registers for %d\n", pid);
/*
* This is inspired by kernel function check_syscall_restart in
* arch/powerpc/kernel/signal.c
*/
#ifndef TRAP
#define TRAP(r) ((r).trap & ~0xF)
#endif
if (TRAP(*regs) == 0x0C00 && regs->ccr & 0x10000000) {
/* Restart the system call */
switch (regs->gpr[3]) {
case ERESTARTNOHAND:
case ERESTARTSYS:
case ERESTARTNOINTR:
regs->gpr[3] = regs->orig_gpr3;
regs->nip -= 4;
break;
case ERESTART_RESTARTBLOCK:
regs->gpr[0] = __NR_restart_syscall;
regs->nip -= 4;
break;
}
}
/* Resetting trap since we are now coming from user space. */
regs->trap = 0;
fpregs->flags = 0;
/*
* Check for Transactional Memory operation in progress.
* Until we have support of TM register's state through the ptrace API,
* we can't checkpoint process with TM operation in progress (almost
* impossible) or suspended (easy to get).
*/
if (MSR_TM_ACTIVE(regs->msr)) {
pr_debug("Task %d has %s TM operation at 0x%lx\n",
pid,
(regs->msr & MSR_TMS) ? "a suspended" : "an active",
regs->nip);
if (get_tm_regs(pid, fpregs))
return -1;
fpregs->flags = USER_FPREGS_FL_TM;
}
if (get_fpu_regs(pid, fpregs))
return -1;
if (get_altivec_regs(pid, fpregs))
return -1;
if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) {
/*
* Save the VSX registers if Altivec registers are supported
*/
if (get_vsx_regs(pid, fpregs))
return -1;
}
return 0;
}
static int copy_tm_regs(user_regs_struct_t *regs, user_fpregs_struct_t *fpregs,
CoreEntry *core)
{
......@@ -701,18 +481,6 @@ int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f)
}
/****************************************************************************/
int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{
user_fpregs_struct_t fpregs;
int ret;
ret = __get_task_regs(pid, &regs, &fpregs);
if (ret)
return ret;
return save(arg, &regs, &fpregs);
}
int arch_alloc_thread_info(CoreEntry *core)
{
ThreadInfoPpc64 *ti_ppc64;
......
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
......
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <errno.h>
#include "uapi/std/syscall-codes.h"
#include "asm/types.h"
#include "ptrace.h"
#include "parasite-syscall.h"
#include "errno.h"
#include "criu-log.h"
#include "infect.h"
#include "infect-priv.h"
#ifndef NT_PPC_TM_SPR
#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */
#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */
#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */
#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */
#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */
#endif
/* This is the layout of the POWER7 VSX registers and the way they
* overlap with the existing FPR and VMX registers.
*
* VSR doubleword 0 VSR doubleword 1
* ----------------------------------------------------------------
* VSR[0] | FPR[0] | |
* ----------------------------------------------------------------
* VSR[1] | FPR[1] | |
* ----------------------------------------------------------------
* | ... | |
* ----------------------------------------------------------------
* VSR[30] | FPR[30] | |
* ----------------------------------------------------------------
* VSR[31] | FPR[31] | |
* ----------------------------------------------------------------
* VSR[32] | VR[0] |
* ----------------------------------------------------------------
* VSR[33] | VR[1] |
* ----------------------------------------------------------------
* | ... |
* ----------------------------------------------------------------
* VSR[62] | VR[30] |
* ----------------------------------------------------------------
* VSR[63] | VR[31] |
* ----------------------------------------------------------------
*
* PTRACE_GETFPREGS returns FPR[0..31] + FPSCR
* PTRACE_GETVRREGS returns VR[0..31] + VSCR + VRSAVE
* PTRACE_GETVSRREGS returns VSR[0..31]
*
* PTRACE_GETVSRREGS and PTRACE_GETFPREGS are required since we need
* to save FPSCR too.
*
* There 32 VSX double word registers to save since the 32 first VSX double
* word registers are saved through FPR[0..32] and the remaining registers
* are saved when saving the Altivec registers VR[0..32].
*/
static int get_fpu_regs(pid_t pid, user_fpregs_struct_t *fp)
{
if (ptrace(PTRACE_GETFPREGS, pid, 0, (void *)&fp->fpregs) < 0) {
pr_perror("Couldn't get floating-point registers");
return -1;
}
fp->flags |= USER_FPREGS_FL_FP;
return 0;
}
static int get_altivec_regs(pid_t pid, user_fpregs_struct_t *fp)
{
if (ptrace(PTRACE_GETVRREGS, pid, 0, (void*)&fp->vrregs) < 0) {
/* PTRACE_GETVRREGS returns EIO if Altivec is not supported.
* This should not happen if msr_vec is set. */
if (errno != EIO) {
pr_perror("Couldn't get Altivec registers");
return -1;
}
pr_debug("Altivec not supported\n");
}
else {
pr_debug("Dumping Altivec registers\n");
fp->flags |= USER_FPREGS_FL_ALTIVEC;
}
return 0;
}
/*
* Since the FPR[0-31] is stored in the first double word of VSR[0-31] and
* FPR are saved through the FP state, there is no need to save the upper part
* of the first 32 VSX registers.
* Furthermore, the 32 last VSX registers are also the 32 Altivec registers
* already saved, so no need to save them.
* As a consequence, only the doubleword 1 of the 32 first VSX registers have
* to be saved (the ones are returned by PTRACE_GETVSRREGS).
*/
static int get_vsx_regs(pid_t pid, user_fpregs_struct_t *fp)
{
if (ptrace(PTRACE_GETVSRREGS, pid, 0, (void*)fp->vsxregs) < 0) {
/*
* EIO is returned in the case PTRACE_GETVRREGS is not
* supported.
*/
if (errno != EIO) {
pr_perror("Couldn't get VSX registers");
return -1;
}
pr_debug("VSX register's dump not supported.\n");
}
else {
pr_debug("Dumping VSX registers\n");
fp->flags |= USER_FPREGS_FL_VSX;
}
return 0;
}
static int get_tm_regs(pid_t pid, user_fpregs_struct_t *fpregs)
{
struct iovec iov;
pr_debug("Dumping TM registers\n");
#define TM_REQUIRED 0
#define TM_OPTIONAL 1
#define PTRACE_GET_TM(s,n,c,u) do { \
iov.iov_base = &s; \
iov.iov_len = sizeof(s); \
if (ptrace(PTRACE_GETREGSET, pid, c, &iov)) { \
if (!u || errno != EIO) { \
pr_perror("Couldn't get TM "n); \
pr_err("Your kernel seems to not support the " \
"new TM ptrace API (>= 4.8)\n"); \
goto out_free; \
} \
pr_debug("TM "n" not supported.\n"); \
iov.iov_base = NULL; \
} \
} while(0)
/* Get special registers */
PTRACE_GET_TM(fpregs->tm.tm_spr_regs, "SPR", NT_PPC_TM_SPR, TM_REQUIRED);
/* Get checkpointed regular registers */
PTRACE_GET_TM(fpregs->tm.regs, "GPR", NT_PPC_TM_CGPR, TM_REQUIRED);
/* Get checkpointed FP registers */
PTRACE_GET_TM(fpregs->tm.fpregs, "FPR", NT_PPC_TM_CFPR, TM_OPTIONAL);
if (iov.iov_base)
fpregs->tm.flags |= USER_FPREGS_FL_FP;
/* Get checkpointed VMX (Altivec) registers */
PTRACE_GET_TM(fpregs->tm.vrregs, "VMX", NT_PPC_TM_CVMX, TM_OPTIONAL);
if (iov.iov_base)
fpregs->tm.flags |= USER_FPREGS_FL_ALTIVEC;
/* Get checkpointed VSX registers */
PTRACE_GET_TM(fpregs->tm.vsxregs, "VSX", NT_PPC_TM_CVSX, TM_OPTIONAL);
if (iov.iov_base)
fpregs->tm.flags |= USER_FPREGS_FL_VSX;
return 0;
out_free:
return -1; /* still failing the checkpoint */
}
static int __get_task_regs(pid_t pid, user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs)
{
pr_info("Dumping GP/FPU registers for %d\n", pid);
/*
* This is inspired by kernel function check_syscall_restart in
* arch/powerpc/kernel/signal.c
*/
#ifndef TRAP
#define TRAP(r) ((r).trap & ~0xF)
#endif
if (TRAP(*regs) == 0x0C00 && regs->ccr & 0x10000000) {
/* Restart the system call */
switch (regs->gpr[3]) {
case ERESTARTNOHAND:
case ERESTARTSYS:
case ERESTARTNOINTR:
regs->gpr[3] = regs->orig_gpr3;
regs->nip -= 4;
break;
case ERESTART_RESTARTBLOCK:
regs->gpr[0] = __NR_restart_syscall;
regs->nip -= 4;
break;
}
}
/* Resetting trap since we are now coming from user space. */
regs->trap = 0;
fpregs->flags = 0;
/*
* Check for Transactional Memory operation in progress.
* Until we have support of TM register's state through the ptrace API,
* we can't checkpoint process with TM operation in progress (almost
* impossible) or suspended (easy to get).
*/
if (MSR_TM_ACTIVE(regs->msr)) {
pr_debug("Task %d has %s TM operation at 0x%lx\n",
pid,
(regs->msr & MSR_TMS) ? "a suspended" : "an active",
regs->nip);
if (get_tm_regs(pid, fpregs))
return -1;
fpregs->flags = USER_FPREGS_FL_TM;
}
if (get_fpu_regs(pid, fpregs))
return -1;
if (get_altivec_regs(pid, fpregs))
return -1;
if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) {
/*
* Save the VSX registers if Altivec registers are supported
*/
if (get_vsx_regs(pid, fpregs))
return -1;
}
return 0;
}
int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{
user_fpregs_struct_t fpregs;
int ret;
ret = __get_task_regs(pid, &regs, &fpregs);
if (ret)
return ret;
return save(arg, &regs, &fpregs);
}
......@@ -187,73 +187,6 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
return err;
}
#define get_signed_user_reg(pregs, name) \
((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \
(int32_t)((pregs)->compat.name))
int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{
user_fpregs_struct_t xsave = { }, *xs = NULL;
struct iovec iov;
int ret = -1;
pr_info("Dumping general registers for %d in %s mode\n", pid,
user_regs_native(&regs) ? "native" : "compat");
/* Did we come from a system call? */
if (get_signed_user_reg(&regs, orig_ax) >= 0) {
/* Restart the system call */
switch (get_signed_user_reg(&regs, ax)) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
set_user_reg(&regs, ax, get_user_reg(&regs, orig_ax));
set_user_reg(&regs, ip, get_user_reg(&regs, ip) - 2);
break;
case -ERESTART_RESTARTBLOCK:
pr_warn("Will restore %d with interrupted system call\n", pid);
set_user_reg(&regs, ax, -EINTR);
break;
}
}
#ifndef PTRACE_GETREGSET
# define PTRACE_GETREGSET 0x4204
#endif
if (!cpu_has_feature(X86_FEATURE_FPU))
goto out;
/*
* FPU fetched either via fxsave or via xsave,
* thus decode it accrodingly.
*/
pr_info("Dumping GP/FPU registers for %d\n", pid);
if (cpu_has_feature(X86_FEATURE_OSXSAVE)) {
iov.iov_base = &xsave;
iov.iov_len = sizeof(xsave);
if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) {
pr_perror("Can't obtain FPU registers for %d", pid);
goto err;
}
} else {
if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) {
pr_perror("Can't obtain FPU registers for %d", pid);
goto err;
}
}
xs = &xsave;
out:
ret = save(arg, &regs, xs);
err:
return ret;
}
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
CoreEntry *core = x;
......
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
......
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/auxv.h>
#include "asm/fpu.h"
#include "asm/types.h"
#include "errno.h"
#include "asm/cpu.h"
#include "parasite-syscall.h"
#include "infect.h"
#include "infect-priv.h"
#define get_signed_user_reg(pregs, name) \
((user_regs_native(pregs)) ? (int64_t)((pregs)->native.name) : \
(int32_t)((pregs)->compat.name))
int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t save, void *arg)
{
user_fpregs_struct_t xsave = { }, *xs = NULL;
struct iovec iov;
int ret = -1;
pr_info("Dumping general registers for %d in %s mode\n", pid,
user_regs_native(&regs) ? "native" : "compat");
/* Did we come from a system call? */
if (get_signed_user_reg(&regs, orig_ax) >= 0) {
/* Restart the system call */
switch (get_signed_user_reg(&regs, ax)) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
set_user_reg(&regs, ax, get_user_reg(&regs, orig_ax));
set_user_reg(&regs, ip, get_user_reg(&regs, ip) - 2);
break;
case -ERESTART_RESTARTBLOCK:
pr_warn("Will restore %d with interrupted system call\n", pid);
set_user_reg(&regs, ax, -EINTR);
break;
}
}
#ifndef PTRACE_GETREGSET
# define PTRACE_GETREGSET 0x4204
#endif
if (!cpu_has_feature(X86_FEATURE_FPU))
goto out;
/*
* FPU fetched either via fxsave or via xsave,
* thus decode it accrodingly.
*/
pr_info("Dumping GP/FPU registers for %d\n", pid);
if (cpu_has_feature(X86_FEATURE_OSXSAVE)) {
iov.iov_base = &xsave;
iov.iov_len = sizeof(xsave);
if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) {
pr_perror("Can't obtain FPU registers for %d", pid);
goto err;
}
} else {
if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) {
pr_perror("Can't obtain FPU registers for %d", pid);
goto err;
}
}
xs = &xsave;
out:
ret = save(arg, &regs, xs);
err:
return ret;
}
......@@ -105,4 +105,7 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *);
#define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */
#define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */
typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int compel_get_task_regs(pid_t pid, user_regs_struct_t regs, save_regs_t, void *);
#endif
......@@ -581,11 +581,11 @@ static int parasite_start_daemon(struct parasite_ctl *ctl)
/*
* Get task registers before going daemon, since the
* get_task_regs needs to call ptrace on _stopped_ task,
* compel_get_task_regs needs to call ptrace on _stopped_ task,
* while in daemon it is not such.
*/
if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) {
if (compel_get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) {
pr_err("Can't obtain regs for thread %d\n", pid);
return -1;
}
......
......@@ -243,7 +243,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
return -1;
}
ret = get_task_regs(pid, octx.regs, save_task_regs, core);
ret = compel_get_task_regs(pid, octx.regs, save_task_regs, core);
if (ret) {
pr_err("Can't obtain regs for thread %d\n", pid);
return -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment