int trace_gpr(pid_t child)
 {
+       __u64 tmp, fpr[32], *peeked_fprs;
        unsigned long gpr[18];
-       __u64 tmp, fpr[32];
 
        FAIL_IF(start_trace(child));
+
+       // Check child GPRs match what we expect using GETREGS
        FAIL_IF(show_gpr(child, gpr));
        FAIL_IF(validate_gpr(gpr, child_gpr_val));
-       FAIL_IF(show_fpr(child, fpr));
 
+       // Check child FPRs match what we expect using GETFPREGS
+       FAIL_IF(show_fpr(child, fpr));
        memcpy(&tmp, &child_fpr_val, sizeof(tmp));
        FAIL_IF(validate_fpr(fpr, tmp));
 
+       // Check child FPRs match what we expect using PEEKUSR
+       peeked_fprs = peek_fprs(child);
+       FAIL_IF(!peeked_fprs);
+       FAIL_IF(validate_fpr(peeked_fprs, tmp));
+       free(peeked_fprs);
+
+       // Write child GPRs using SETREGS
        FAIL_IF(write_gpr(child, parent_gpr_val));
 
+       // Write child FPRs using SETFPREGS
        memcpy(&tmp, &parent_fpr_val, sizeof(tmp));
        FAIL_IF(write_fpr(child, tmp));
 
+       // Check child FPRs match what we just set, using PEEKUSR
+       peeked_fprs = peek_fprs(child);
+       FAIL_IF(!peeked_fprs);
+       FAIL_IF(validate_fpr(peeked_fprs, tmp));
+
+       // Write child FPRs using POKEUSR
+       FAIL_IF(poke_fprs(child, (unsigned long *)peeked_fprs));
+
+       // Child will check its FPRs match before exiting
        FAIL_IF(stop_trace(child));
 
        return TEST_PASS;
 
 #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>
        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;