aarch64-dbreg-contents.c revision 1.1.1.2
1/* Test case for setting a memory-write unaligned watchpoint on aarch64. 2 3 This software is provided 'as-is', without any express or implied 4 warranty. In no event will the authors be held liable for any damages 5 arising from the use of this software. 6 7 Permission is granted to anyone to use this software for any purpose, 8 including commercial applications, and to alter it and redistribute it 9 freely. */ 10 11#define _GNU_SOURCE 1 12#include <stdlib.h> 13#include <unistd.h> 14#include <sys/ptrace.h> 15#include <asm/ptrace.h> 16#include <assert.h> 17#include <sys/wait.h> 18#include <stddef.h> 19#include <errno.h> 20#include <sys/uio.h> 21#include <elf.h> 22#include <error.h> 23 24static pid_t child; 25 26static void 27cleanup (void) 28{ 29 if (child > 0) 30 kill (child, SIGKILL); 31 child = 0; 32} 33 34/* Macros to extract fields from the hardware debug information word. */ 35#define AARCH64_DEBUG_NUM_SLOTS(x) ((x) & 0xff) 36#define AARCH64_DEBUG_ARCH(x) (((x) >> 8) & 0xff) 37/* Macro for the expected version of the ARMv8-A debug architecture. */ 38#define AARCH64_DEBUG_ARCH_V8 0x6 39#define DR_CONTROL_ENABLED(ctrl) (((ctrl) & 0x1) == 1) 40#define DR_CONTROL_LENGTH(ctrl) (((ctrl) >> 5) & 0xff) 41 42static void 43set_watchpoint (pid_t pid, volatile void *addr, unsigned len_mask) 44{ 45 struct user_hwdebug_state dreg_state; 46 struct iovec iov; 47 long l; 48 49 assert (len_mask >= 0x01); 50 assert (len_mask <= 0xff); 51 52 iov.iov_base = &dreg_state; 53 iov.iov_len = sizeof (dreg_state); 54 errno = 0; 55 l = ptrace (PTRACE_GETREGSET, pid, NT_ARM_HW_WATCH, &iov); 56 assert (l == 0); 57 assert (AARCH64_DEBUG_ARCH (dreg_state.dbg_info) == AARCH64_DEBUG_ARCH_V8); 58 assert (AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info) >= 1); 59 60 assert (!DR_CONTROL_ENABLED (dreg_state.dbg_regs[0].ctrl)); 61 dreg_state.dbg_regs[0].ctrl |= 1; 62 assert ( DR_CONTROL_ENABLED (dreg_state.dbg_regs[0].ctrl)); 63 64 assert (DR_CONTROL_LENGTH (dreg_state.dbg_regs[0].ctrl) == 0); 65 dreg_state.dbg_regs[0].ctrl |= len_mask << 5; 66 assert (DR_CONTROL_LENGTH (dreg_state.dbg_regs[0].ctrl) == len_mask); 67 68 dreg_state.dbg_regs[0].ctrl |= 2 << 3; // write 69 dreg_state.dbg_regs[0].ctrl |= 2 << 1; // enabled at el0 70 dreg_state.dbg_regs[0].addr = (uintptr_t) addr; 71 72 iov.iov_base = &dreg_state; 73 iov.iov_len = (offsetof (struct user_hwdebug_state, dbg_regs) 74 + sizeof (dreg_state.dbg_regs[0])); 75 errno = 0; 76 l = ptrace (PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &iov); 77 if (errno != 0) 78 error (1, errno, "PTRACE_SETREGSET: NT_ARM_HW_WATCH"); 79 assert (l == 0); 80} 81 82static volatile long long check; 83 84int 85main (void) 86{ 87 pid_t got_pid; 88 int i, status; 89 long l; 90 91 atexit (cleanup); 92 93 child = fork (); 94 assert (child >= 0); 95 if (child == 0) 96 { 97 l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); 98 assert (l == 0); 99 i = raise (SIGUSR1); 100 assert (i == 0); 101 check = -1; 102 i = raise (SIGUSR2); 103 /* NOTREACHED */ 104 assert (0); 105 } 106 107 got_pid = waitpid (child, &status, 0); 108 assert (got_pid == child); 109 assert (WIFSTOPPED (status)); 110 assert (WSTOPSIG (status) == SIGUSR1); 111 112 /* Add a watchpoint to check. 113 Restart the child. It will write to check. 114 Check child has stopped on the watchpoint. */ 115 set_watchpoint (child, &check, 0x02); 116 117 errno = 0; 118 l = ptrace (PTRACE_CONT, child, 0l, 0l); 119 assert_perror (errno); 120 assert (l == 0); 121 122 got_pid = waitpid (child, &status, 0); 123 assert (got_pid == child); 124 assert (WIFSTOPPED (status)); 125 if (WSTOPSIG (status) == SIGUSR2) 126 { 127 /* We missed the watchpoint - unsupported by hardware? */ 128 cleanup (); 129 return 2; 130 } 131 assert (WSTOPSIG (status) == SIGTRAP); 132 133 return 0; 134} 135