mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-25 19:14:04 +00:00
As ptrace() sets errno, it makes sense to use pr_perror(). This also fixes the bug of missing '\n'. Signed-off-by: Kir Kolyshkin <kir@openvz.org> Acked-by: Andrew Vagin <avagin@odin.com> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
234 lines
5.1 KiB
C
234 lines
5.1 KiB
C
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <linux/elf.h>
|
|
|
|
#include "asm/types.h"
|
|
#include "asm/restorer.h"
|
|
#include "compiler.h"
|
|
#include "ptrace.h"
|
|
#include "asm/processor-flags.h"
|
|
#include "protobuf.h"
|
|
#include "protobuf/core.pb-c.h"
|
|
#include "protobuf/creds.pb-c.h"
|
|
#include "parasite-syscall.h"
|
|
#include "syscall.h"
|
|
#include "log.h"
|
|
#include "util.h"
|
|
#include "cpu.h"
|
|
#include "parasite-syscall.h"
|
|
#include "restorer.h"
|
|
|
|
|
|
/*
|
|
* Injected syscall instruction
|
|
*/
|
|
const char code_syscall[] = {
|
|
0x01, 0x00, 0x00, 0xd4, /* SVC #0 */
|
|
0x00, 0x00, 0x20, 0xd4 /* BRK #0 */
|
|
};
|
|
|
|
const int code_syscall_size = round_up(sizeof(code_syscall), sizeof(long));
|
|
|
|
static inline void __always_unused __check_code_syscall(void)
|
|
{
|
|
BUILD_BUG_ON(sizeof(code_syscall) != BUILTIN_SYSCALL_SIZE);
|
|
BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
|
|
}
|
|
|
|
void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs)
|
|
{
|
|
regs->pc = new_ip;
|
|
if (stack)
|
|
regs->sp = (unsigned long)stack;
|
|
}
|
|
|
|
bool arch_can_dump_task(pid_t pid)
|
|
{
|
|
/*
|
|
* TODO: Add proper check here
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
|
|
unsigned long arg1,
|
|
unsigned long arg2,
|
|
unsigned long arg3,
|
|
unsigned long arg4,
|
|
unsigned long arg5,
|
|
unsigned long arg6)
|
|
{
|
|
user_regs_struct_t regs = ctl->orig.regs;
|
|
int err;
|
|
|
|
regs.regs[8] = (unsigned long)nr;
|
|
regs.regs[0] = arg1;
|
|
regs.regs[1] = arg2;
|
|
regs.regs[2] = arg3;
|
|
regs.regs[3] = arg4;
|
|
regs.regs[4] = arg5;
|
|
regs.regs[5] = arg6;
|
|
regs.regs[6] = 0;
|
|
regs.regs[7] = 0;
|
|
|
|
err = __parasite_execute_syscall(ctl, ®s);
|
|
|
|
*ret = regs.regs[0];
|
|
return err;
|
|
}
|
|
|
|
|
|
#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, CoreEntry *core)
|
|
{
|
|
struct iovec iov;
|
|
struct user_fpsimd_state fpsimd;
|
|
int i, ret;
|
|
|
|
pr_info("Dumping GP/FPU registers for %d\n", pid);
|
|
|
|
iov.iov_base = ®s;
|
|
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;
|
|
}
|
|
|
|
|
|
// Save the Aarch64 CPU state
|
|
for (i = 0; i < 31; ++i)
|
|
assign_reg(core->ti_aarch64->gpregs, regs, regs[i]);
|
|
assign_reg(core->ti_aarch64->gpregs, regs, sp);
|
|
assign_reg(core->ti_aarch64->gpregs, regs, pc);
|
|
assign_reg(core->ti_aarch64->gpregs, regs, pstate);
|
|
|
|
|
|
// Save the FP/SIMD state
|
|
for (i = 0; i < 32; ++i)
|
|
{
|
|
core->ti_aarch64->fpsimd->vregs[2*i] = fpsimd.vregs[i];
|
|
core->ti_aarch64->fpsimd->vregs[2*i + 1] = fpsimd.vregs[i] >> 64;
|
|
}
|
|
assign_reg(core->ti_aarch64->fpsimd, fpsimd, fpsr);
|
|
assign_reg(core->ti_aarch64->fpsimd, fpsimd, fpcr);
|
|
|
|
ret = 0;
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
int arch_alloc_thread_info(CoreEntry *core)
|
|
{
|
|
ThreadInfoAarch64 *ti_aarch64;
|
|
UserAarch64RegsEntry *gpregs;
|
|
UserAarch64FpsimdContextEntry *fpsimd;
|
|
|
|
ti_aarch64 = xmalloc(sizeof(*ti_aarch64));
|
|
if (!ti_aarch64)
|
|
goto err;
|
|
thread_info_aarch64__init(ti_aarch64);
|
|
core->ti_aarch64 = ti_aarch64;
|
|
|
|
gpregs = xmalloc(sizeof(*gpregs));
|
|
if (!gpregs)
|
|
goto err;
|
|
user_aarch64_regs_entry__init(gpregs);
|
|
|
|
gpregs->regs = xmalloc(31*sizeof(uint64_t));
|
|
if (!gpregs->regs)
|
|
goto err;
|
|
gpregs->n_regs = 31;
|
|
|
|
ti_aarch64->gpregs = gpregs;
|
|
|
|
fpsimd = xmalloc(sizeof(*fpsimd));
|
|
if (!fpsimd)
|
|
goto err;
|
|
user_aarch64_fpsimd_context_entry__init(fpsimd);
|
|
ti_aarch64->fpsimd = fpsimd;
|
|
fpsimd->vregs = xmalloc(64*sizeof(fpsimd->vregs[0]));
|
|
fpsimd->n_vregs = 64;
|
|
if (!fpsimd->vregs)
|
|
goto err;
|
|
|
|
return 0;
|
|
err:
|
|
return -1;
|
|
}
|
|
|
|
void arch_free_thread_info(CoreEntry *core)
|
|
{
|
|
if (CORE_THREAD_ARCH_INFO(core)) {
|
|
if (CORE_THREAD_ARCH_INFO(core)->fpsimd) {
|
|
xfree(CORE_THREAD_ARCH_INFO(core)->fpsimd->vregs);
|
|
xfree(CORE_THREAD_ARCH_INFO(core)->fpsimd);
|
|
}
|
|
xfree(CORE_THREAD_ARCH_INFO(core)->gpregs->regs);
|
|
xfree(CORE_THREAD_ARCH_INFO(core)->gpregs);
|
|
xfree(CORE_THREAD_ARCH_INFO(core));
|
|
CORE_THREAD_ARCH_INFO(core) = NULL;
|
|
}
|
|
}
|
|
|
|
int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core)
|
|
{
|
|
int i;
|
|
struct fpsimd_context *fpsimd = &RT_SIGFRAME_FPU(sigframe);
|
|
|
|
if (core->ti_aarch64->fpsimd->n_vregs != 64)
|
|
return 1;
|
|
|
|
for (i = 0; i < 32; ++i)
|
|
fpsimd->vregs[i] = (__uint128_t)core->ti_aarch64->fpsimd->vregs[2*i] |
|
|
((__uint128_t)core->ti_aarch64->fpsimd->vregs[2*i + 1] << 64);
|
|
assign_reg(fpsimd, *core->ti_aarch64->fpsimd, fpsr);
|
|
assign_reg(fpsimd, *core->ti_aarch64->fpsimd, fpcr);
|
|
|
|
fpsimd->head.magic = FPSIMD_MAGIC;
|
|
fpsimd->head.size = sizeof(*fpsimd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *mmap_seized(
|
|
struct parasite_ctl *ctl,
|
|
void *addr, size_t length, int prot,
|
|
int flags, int fd, off_t offset)
|
|
{
|
|
unsigned long map;
|
|
int err;
|
|
|
|
err = syscall_seized(ctl, __NR_mmap, &map,
|
|
(unsigned long)addr, length, prot, flags, fd, offset);
|
|
if (err < 0 || (long)map < 0)
|
|
map = 0;
|
|
|
|
return (void *)map;
|
|
}
|
|
|
|
int restore_gpregs(struct rt_sigframe *f, UserRegsEntry *r)
|
|
{
|
|
#define CPREG1(d) f->uc.uc_mcontext.d = r->d
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 31; ++i)
|
|
CPREG1(regs[i]);
|
|
CPREG1(sp);
|
|
CPREG1(pc);
|
|
CPREG1(pstate);
|
|
|
|
#undef CPREG1
|
|
|
|
return 0;
|
|
}
|