813 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			813 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* SPDX-License-Identifier: GPL-2.0-or-later */
 | 
						|
/*
 | 
						|
 * Ptrace interface test helper functions
 | 
						|
 *
 | 
						|
 * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
 | 
						|
 */
 | 
						|
 | 
						|
#define __SANE_USERSPACE_TYPES__
 | 
						|
 | 
						|
#include <inttypes.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <malloc.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <time.h>
 | 
						|
#include <sys/ptrace.h>
 | 
						|
#include <sys/ioctl.h>
 | 
						|
#include <sys/uio.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/wait.h>
 | 
						|
#include <sys/signal.h>
 | 
						|
#include <sys/ipc.h>
 | 
						|
#include <sys/shm.h>
 | 
						|
#include <sys/user.h>
 | 
						|
#include <sys/syscall.h>
 | 
						|
#include <linux/elf.h>
 | 
						|
#include <linux/types.h>
 | 
						|
#include <linux/auxvec.h>
 | 
						|
#include "reg.h"
 | 
						|
#include "utils.h"
 | 
						|
 | 
						|
#define TEST_PASS 0
 | 
						|
#define TEST_FAIL 1
 | 
						|
 | 
						|
struct fpr_regs {
 | 
						|
	__u64 fpr[32];
 | 
						|
	__u64 fpscr;
 | 
						|
};
 | 
						|
 | 
						|
struct tm_spr_regs {
 | 
						|
	unsigned long tm_tfhar;
 | 
						|
	unsigned long tm_texasr;
 | 
						|
	unsigned long tm_tfiar;
 | 
						|
};
 | 
						|
 | 
						|
#ifndef NT_PPC_TAR
 | 
						|
#define NT_PPC_TAR	0x103
 | 
						|
#define NT_PPC_PPR	0x104
 | 
						|
#define NT_PPC_DSCR	0x105
 | 
						|
#define NT_PPC_EBB	0x106
 | 
						|
#define NT_PPC_PMU	0x107
 | 
						|
#define NT_PPC_TM_CGPR	0x108
 | 
						|
#define NT_PPC_TM_CFPR	0x109
 | 
						|
#define NT_PPC_TM_CVMX	0x10a
 | 
						|
#define NT_PPC_TM_CVSX	0x10b
 | 
						|
#define NT_PPC_TM_SPR	0x10c
 | 
						|
#define NT_PPC_TM_CTAR	0x10d
 | 
						|
#define NT_PPC_TM_CPPR	0x10e
 | 
						|
#define NT_PPC_TM_CDSCR	0x10f
 | 
						|
#endif
 | 
						|
 | 
						|
/* Basic ptrace operations */
 | 
						|
int start_trace(pid_t child)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_ATTACH, child, NULL, NULL);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_ATTACH) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	ret = waitpid(child, NULL, 0);
 | 
						|
	if (ret != child) {
 | 
						|
		perror("waitpid() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int stop_trace(pid_t child)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_DETACH, child, NULL, NULL);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_DETACH) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int cont_trace(pid_t child)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_CONT, child, NULL, NULL);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_CONT) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int ptrace_read_regs(pid_t child, unsigned long type, unsigned long regs[],
 | 
						|
		     int n)
 | 
						|
{
 | 
						|
	struct iovec iov;
 | 
						|
	long ret;
 | 
						|
 | 
						|
	FAIL_IF(start_trace(child));
 | 
						|
 | 
						|
	iov.iov_base = regs;
 | 
						|
	iov.iov_len = n * sizeof(unsigned long);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, type, &iov);
 | 
						|
	if (ret)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	FAIL_IF(stop_trace(child));
 | 
						|
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
long ptrace_write_regs(pid_t child, unsigned long type, unsigned long regs[],
 | 
						|
		       int n)
 | 
						|
{
 | 
						|
	struct iovec iov;
 | 
						|
	long ret;
 | 
						|
 | 
						|
	FAIL_IF(start_trace(child));
 | 
						|
 | 
						|
	iov.iov_base = regs;
 | 
						|
	iov.iov_len = n * sizeof(unsigned long);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, type, &iov);
 | 
						|
 | 
						|
	FAIL_IF(stop_trace(child));
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
/* TAR, PPR, DSCR */
 | 
						|
int show_tar_registers(pid_t child, unsigned long *out)
 | 
						|
{
 | 
						|
	struct iovec iov;
 | 
						|
	unsigned long *reg;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	reg = malloc(sizeof(unsigned long));
 | 
						|
	if (!reg) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	iov.iov_base = (u64 *) reg;
 | 
						|
	iov.iov_len = sizeof(unsigned long);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TAR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
	if (out)
 | 
						|
		out[0] = *reg;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_PPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
	if (out)
 | 
						|
		out[1] = *reg;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_DSCR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
	if (out)
 | 
						|
		out[2] = *reg;
 | 
						|
 | 
						|
	free(reg);
 | 
						|
	return TEST_PASS;
 | 
						|
fail:
 | 
						|
	free(reg);
 | 
						|
	return TEST_FAIL;
 | 
						|
}
 | 
						|
 | 
						|
int write_tar_registers(pid_t child, unsigned long tar,
 | 
						|
		unsigned long ppr, unsigned long dscr)
 | 
						|
{
 | 
						|
	struct iovec iov;
 | 
						|
	unsigned long *reg;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	reg = malloc(sizeof(unsigned long));
 | 
						|
	if (!reg) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	iov.iov_base = (u64 *) reg;
 | 
						|
	iov.iov_len = sizeof(unsigned long);
 | 
						|
 | 
						|
	*reg = tar;
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TAR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_SETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
 | 
						|
	*reg = ppr;
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_PPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_SETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
 | 
						|
	*reg = dscr;
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_DSCR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_SETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
 | 
						|
	free(reg);
 | 
						|
	return TEST_PASS;
 | 
						|
fail:
 | 
						|
	free(reg);
 | 
						|
	return TEST_FAIL;
 | 
						|
}
 | 
						|
 | 
						|
int show_tm_checkpointed_state(pid_t child, unsigned long *out)
 | 
						|
{
 | 
						|
	struct iovec iov;
 | 
						|
	unsigned long *reg;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	reg = malloc(sizeof(unsigned long));
 | 
						|
	if (!reg) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	iov.iov_base = (u64 *) reg;
 | 
						|
	iov.iov_len = sizeof(unsigned long);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CTAR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
	if (out)
 | 
						|
		out[0] = *reg;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CPPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
	if (out)
 | 
						|
		out[1] = *reg;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CDSCR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
	if (out)
 | 
						|
		out[2] = *reg;
 | 
						|
 | 
						|
	free(reg);
 | 
						|
	return TEST_PASS;
 | 
						|
 | 
						|
fail:
 | 
						|
	free(reg);
 | 
						|
	return TEST_FAIL;
 | 
						|
}
 | 
						|
 | 
						|
int write_ckpt_tar_registers(pid_t child, unsigned long tar,
 | 
						|
		unsigned long ppr, unsigned long dscr)
 | 
						|
{
 | 
						|
	struct iovec iov;
 | 
						|
	unsigned long *reg;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	reg = malloc(sizeof(unsigned long));
 | 
						|
	if (!reg) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	iov.iov_base = (u64 *) reg;
 | 
						|
	iov.iov_len = sizeof(unsigned long);
 | 
						|
 | 
						|
	*reg = tar;
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CTAR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
 | 
						|
	*reg = ppr;
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CPPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
 | 
						|
	*reg = dscr;
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CDSCR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
 | 
						|
	free(reg);
 | 
						|
	return TEST_PASS;
 | 
						|
fail:
 | 
						|
	free(reg);
 | 
						|
	return TEST_FAIL;
 | 
						|
}
 | 
						|
 | 
						|
/* FPR */
 | 
						|
int show_fpr(pid_t child, __u64 *fpr)
 | 
						|
{
 | 
						|
	struct fpr_regs *regs;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs));
 | 
						|
	ret = ptrace(PTRACE_GETFPREGS, child, NULL, regs);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (fpr) {
 | 
						|
		for (i = 0; i < 32; i++)
 | 
						|
			fpr[i] = regs->fpr[i];
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int write_fpr(pid_t child, __u64 val)
 | 
						|
{
 | 
						|
	struct fpr_regs *regs;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs));
 | 
						|
	ret = ptrace(PTRACE_GETFPREGS, child, NULL, regs);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < 32; i++)
 | 
						|
		regs->fpr[i] = val;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_SETFPREGS, child, NULL, regs);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int show_ckpt_fpr(pid_t child, __u64 *fpr)
 | 
						|
{
 | 
						|
	struct fpr_regs *regs;
 | 
						|
	struct iovec iov;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs));
 | 
						|
	iov.iov_base = regs;
 | 
						|
	iov.iov_len = sizeof(struct fpr_regs);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (fpr) {
 | 
						|
		for (i = 0; i < 32; i++)
 | 
						|
			fpr[i] = regs->fpr[i];
 | 
						|
	}
 | 
						|
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int write_ckpt_fpr(pid_t child, unsigned long val)
 | 
						|
{
 | 
						|
	struct fpr_regs *regs;
 | 
						|
	struct iovec iov;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs));
 | 
						|
	iov.iov_base = regs;
 | 
						|
	iov.iov_len = sizeof(struct fpr_regs);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < 32; i++)
 | 
						|
		regs->fpr[i] = val;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CFPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
/* GPR */
 | 
						|
int show_gpr(pid_t child, unsigned long *gpr)
 | 
						|
{
 | 
						|
	struct pt_regs *regs;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	regs = (struct pt_regs *) malloc(sizeof(struct pt_regs));
 | 
						|
	if (!regs) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGS, child, NULL, regs);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (gpr) {
 | 
						|
		for (i = 14; i < 32; i++)
 | 
						|
			gpr[i-14] = regs->gpr[i];
 | 
						|
	}
 | 
						|
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
long sys_ptrace(enum __ptrace_request request, pid_t pid, unsigned long addr, unsigned long data)
 | 
						|
{
 | 
						|
	return syscall(__NR_ptrace, request, pid, (void *)addr, data);
 | 
						|
}
 | 
						|
 | 
						|
// 33 because of FPSCR
 | 
						|
#define PT_NUM_FPRS	(33 * (sizeof(__u64) / sizeof(unsigned long)))
 | 
						|
 | 
						|
__u64 *peek_fprs(pid_t child)
 | 
						|
{
 | 
						|
	unsigned long *fprs, *p, addr;
 | 
						|
	long ret;
 | 
						|
	int i;
 | 
						|
 | 
						|
	fprs = malloc(sizeof(unsigned long) * PT_NUM_FPRS);
 | 
						|
	if (!fprs) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0, p = fprs; i < PT_NUM_FPRS; i++, p++) {
 | 
						|
		addr = sizeof(unsigned long) * (PT_FPR0 + i);
 | 
						|
		ret = sys_ptrace(PTRACE_PEEKUSER, child, addr, (unsigned long)p);
 | 
						|
		if (ret) {
 | 
						|
			perror("ptrace(PTRACE_PEEKUSR) failed");
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	addr = sizeof(unsigned long) * (PT_FPR0 + i);
 | 
						|
	ret = sys_ptrace(PTRACE_PEEKUSER, child, addr, (unsigned long)&addr);
 | 
						|
	if (!ret) {
 | 
						|
		printf("ptrace(PTRACE_PEEKUSR) succeeded unexpectedly!\n");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return (__u64 *)fprs;
 | 
						|
}
 | 
						|
 | 
						|
int poke_fprs(pid_t child, unsigned long *fprs)
 | 
						|
{
 | 
						|
	unsigned long *p, addr;
 | 
						|
	long ret;
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0, p = fprs; i < PT_NUM_FPRS; i++, p++) {
 | 
						|
		addr = sizeof(unsigned long) * (PT_FPR0 + i);
 | 
						|
		ret = sys_ptrace(PTRACE_POKEUSER, child, addr, *p);
 | 
						|
		if (ret) {
 | 
						|
			perror("ptrace(PTRACE_POKEUSR) failed");
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	addr = sizeof(unsigned long) * (PT_FPR0 + i);
 | 
						|
	ret = sys_ptrace(PTRACE_POKEUSER, child, addr, addr);
 | 
						|
	if (!ret) {
 | 
						|
		printf("ptrace(PTRACE_POKEUSR) succeeded unexpectedly!\n");
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int write_gpr(pid_t child, unsigned long val)
 | 
						|
{
 | 
						|
	struct pt_regs *regs;
 | 
						|
	int i, ret;
 | 
						|
 | 
						|
	regs = (struct pt_regs *) malloc(sizeof(struct pt_regs));
 | 
						|
	if (!regs) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGS, child, NULL, regs);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 14; i < 32; i++)
 | 
						|
		regs->gpr[i] = val;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_SETREGS, child, NULL, regs);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int show_ckpt_gpr(pid_t child, unsigned long *gpr)
 | 
						|
{
 | 
						|
	struct pt_regs *regs;
 | 
						|
	struct iovec iov;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	regs = (struct pt_regs *) malloc(sizeof(struct pt_regs));
 | 
						|
	if (!regs) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	iov.iov_base = (u64 *) regs;
 | 
						|
	iov.iov_len = sizeof(struct pt_regs);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (gpr) {
 | 
						|
		for (i = 14; i < 32; i++)
 | 
						|
			gpr[i-14] = regs->gpr[i];
 | 
						|
	}
 | 
						|
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int write_ckpt_gpr(pid_t child, unsigned long val)
 | 
						|
{
 | 
						|
	struct pt_regs *regs;
 | 
						|
	struct iovec iov;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	regs = (struct pt_regs *) malloc(sizeof(struct pt_regs));
 | 
						|
	if (!regs) {
 | 
						|
		perror("malloc() failed\n");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	iov.iov_base = (u64 *) regs;
 | 
						|
	iov.iov_len = sizeof(struct pt_regs);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 14; i < 32; i++)
 | 
						|
		regs->gpr[i] = val;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CGPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
/* VMX */
 | 
						|
int show_vmx(pid_t child, unsigned long vmx[][2])
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETVRREGS, child, 0, vmx);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETVRREGS) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int show_vmx_ckpt(pid_t child, unsigned long vmx[][2])
 | 
						|
{
 | 
						|
	unsigned long regs[34][2];
 | 
						|
	struct iovec iov;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	iov.iov_base = (u64 *) regs;
 | 
						|
	iov.iov_len = sizeof(regs);
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CVMX, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET, NT_PPC_TM_CVMX) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	memcpy(vmx, regs, sizeof(regs));
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int write_vmx(pid_t child, unsigned long vmx[][2])
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_SETVRREGS, child, 0, vmx);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_SETVRREGS) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int write_vmx_ckpt(pid_t child, unsigned long vmx[][2])
 | 
						|
{
 | 
						|
	unsigned long regs[34][2];
 | 
						|
	struct iovec iov;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	memcpy(regs, vmx, sizeof(regs));
 | 
						|
	iov.iov_base = (u64 *) regs;
 | 
						|
	iov.iov_len = sizeof(regs);
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CVMX, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_SETREGSET, NT_PPC_TM_CVMX) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
/* VSX */
 | 
						|
int show_vsx(pid_t child, unsigned long *vsx)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETVSRREGS, child, 0, vsx);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETVSRREGS) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int show_vsx_ckpt(pid_t child, unsigned long *vsx)
 | 
						|
{
 | 
						|
	unsigned long regs[32];
 | 
						|
	struct iovec iov;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	iov.iov_base = (u64 *) regs;
 | 
						|
	iov.iov_len = sizeof(regs);
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CVSX, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET, NT_PPC_TM_CVSX) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	memcpy(vsx, regs, sizeof(regs));
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int write_vsx(pid_t child, unsigned long *vsx)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_SETVSRREGS, child, 0, vsx);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_SETVSRREGS) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
int write_vsx_ckpt(pid_t child, unsigned long *vsx)
 | 
						|
{
 | 
						|
	unsigned long regs[32];
 | 
						|
	struct iovec iov;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	memcpy(regs, vsx, sizeof(regs));
 | 
						|
	iov.iov_base = (u64 *) regs;
 | 
						|
	iov.iov_len = sizeof(regs);
 | 
						|
	ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CVSX, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_SETREGSET, NT_PPC_TM_CVSX) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
/* TM SPR */
 | 
						|
int show_tm_spr(pid_t child, struct tm_spr_regs *out)
 | 
						|
{
 | 
						|
	struct tm_spr_regs *regs;
 | 
						|
	struct iovec iov;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	regs = (struct tm_spr_regs *) malloc(sizeof(struct tm_spr_regs));
 | 
						|
	if (!regs) {
 | 
						|
		perror("malloc() failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	iov.iov_base = (u64 *) regs;
 | 
						|
	iov.iov_len = sizeof(struct tm_spr_regs);
 | 
						|
 | 
						|
	ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_SPR, &iov);
 | 
						|
	if (ret) {
 | 
						|
		perror("ptrace(PTRACE_GETREGSET) failed");
 | 
						|
		return TEST_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (out)
 | 
						|
		memcpy(out, regs, sizeof(struct tm_spr_regs));
 | 
						|
 | 
						|
	return TEST_PASS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* Analyse TEXASR after TM failure */
 | 
						|
inline unsigned long get_tfiar(void)
 | 
						|
{
 | 
						|
	unsigned long ret;
 | 
						|
 | 
						|
	asm volatile("mfspr %0,%1" : "=r" (ret) : "i" (SPRN_TFIAR));
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
void analyse_texasr(unsigned long texasr)
 | 
						|
{
 | 
						|
	printf("TEXASR: %16lx\t", texasr);
 | 
						|
 | 
						|
	if (texasr & TEXASR_FP)
 | 
						|
		printf("TEXASR_FP  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_DA)
 | 
						|
		printf("TEXASR_DA  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_NO)
 | 
						|
		printf("TEXASR_NO  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_FO)
 | 
						|
		printf("TEXASR_FO  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_SIC)
 | 
						|
		printf("TEXASR_SIC  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_NTC)
 | 
						|
		printf("TEXASR_NTC  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_TC)
 | 
						|
		printf("TEXASR_TC  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_TIC)
 | 
						|
		printf("TEXASR_TIC  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_IC)
 | 
						|
		printf("TEXASR_IC  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_IFC)
 | 
						|
		printf("TEXASR_IFC  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_ABT)
 | 
						|
		printf("TEXASR_ABT  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_SPD)
 | 
						|
		printf("TEXASR_SPD  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_HV)
 | 
						|
		printf("TEXASR_HV  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_PR)
 | 
						|
		printf("TEXASR_PR  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_FS)
 | 
						|
		printf("TEXASR_FS  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_TE)
 | 
						|
		printf("TEXASR_TE  ");
 | 
						|
 | 
						|
	if (texasr & TEXASR_ROT)
 | 
						|
		printf("TEXASR_ROT  ");
 | 
						|
 | 
						|
	printf("TFIAR :%lx\n", get_tfiar());
 | 
						|
}
 | 
						|
 | 
						|
void store_gpr(unsigned long *addr);
 |