1 /*- 2 * Copyright (c) 2014 Andrew Turner 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/elf.h> 32 #include <sys/exec.h> 33 #include <sys/imgact.h> 34 #include <sys/kernel.h> 35 #include <sys/limits.h> 36 #include <sys/lock.h> 37 #include <sys/mutex.h> 38 #include <sys/proc.h> 39 #include <sys/ptrace.h> 40 #include <sys/reg.h> 41 #include <sys/rwlock.h> 42 #include <sys/signalvar.h> 43 #include <sys/syscallsubr.h> 44 #include <sys/sysent.h> 45 #include <sys/sysproto.h> 46 #include <sys/ucontext.h> 47 48 #include <machine/armreg.h> 49 #include <machine/pcb.h> 50 51 /* Only used to get/set 32bits VFP regs */ 52 int 53 cpu_ptrace(struct thread *td, int req, void *arg, int data) 54 { 55 #if defined(VFP) && defined(COMPAT_FREEBSD32) 56 mcontext32_vfp_t vfp; 57 int error; 58 59 if (!SV_CURPROC_FLAG(SV_ILP32)) 60 return (EINVAL); 61 switch (req) { 62 case PT_GETVFPREGS32: 63 get_fpcontext32(td, &vfp); 64 error = copyout(&vfp, arg, sizeof(vfp)); 65 break; 66 case PT_SETVFPREGS32: 67 error = copyin(arg, &vfp, sizeof(vfp)); 68 if (error == 0) 69 set_fpcontext32(td, &vfp); 70 break; 71 default: 72 error = EINVAL; 73 } 74 75 return (error); 76 #else 77 return (EINVAL); 78 #endif 79 } 80 81 #if defined(VFP) && defined(COMPAT_FREEBSD32) 82 static bool 83 get_arm_vfp(struct regset *rs, struct thread *td, void *buf, size_t *sizep) 84 { 85 if (buf != NULL) { 86 KASSERT(*sizep == sizeof(mcontext32_vfp_t), 87 ("%s: invalid size", __func__)); 88 get_fpcontext32(td, buf); 89 } 90 *sizep = sizeof(mcontext32_vfp_t); 91 return (true); 92 } 93 94 static bool 95 set_arm_vfp(struct regset *rs, struct thread *td, void *buf, 96 size_t size) 97 { 98 KASSERT(size == sizeof(mcontext32_vfp_t), ("%s: invalid size", 99 __func__)); 100 set_fpcontext32(td, buf); 101 return (true); 102 } 103 104 static struct regset regset_arm_vfp = { 105 .note = NT_ARM_VFP, 106 .size = sizeof(mcontext32_vfp_t), 107 .get = get_arm_vfp, 108 .set = set_arm_vfp, 109 }; 110 ELF32_REGSET(regset_arm_vfp); 111 #endif 112 113 static bool 114 get_arm64_tls(struct regset *rs, struct thread *td, void *buf, 115 size_t *sizep) 116 { 117 if (buf != NULL) { 118 KASSERT(*sizep == sizeof(td->td_pcb->pcb_tpidr_el0), 119 ("%s: invalid size", __func__)); 120 memcpy(buf, &td->td_pcb->pcb_tpidr_el0, 121 sizeof(td->td_pcb->pcb_tpidr_el0)); 122 } 123 *sizep = sizeof(td->td_pcb->pcb_tpidr_el0); 124 125 return (true); 126 } 127 128 static struct regset regset_arm64_tls = { 129 .note = NT_ARM_TLS, 130 .size = sizeof(uint64_t), 131 .get = get_arm64_tls, 132 }; 133 ELF_REGSET(regset_arm64_tls); 134 135 #ifdef COMPAT_FREEBSD32 136 static bool 137 get_arm_tls(struct regset *rs, struct thread *td, void *buf, 138 size_t *sizep) 139 { 140 if (buf != NULL) { 141 uint32_t tp; 142 143 KASSERT(*sizep == sizeof(uint32_t), 144 ("%s: invalid size", __func__)); 145 tp = (uint32_t)td->td_pcb->pcb_tpidr_el0; 146 memcpy(buf, &tp, sizeof(tp)); 147 } 148 *sizep = sizeof(uint32_t); 149 150 return (true); 151 } 152 153 static struct regset regset_arm_tls = { 154 .note = NT_ARM_TLS, 155 .size = sizeof(uint32_t), 156 .get = get_arm_tls, 157 }; 158 ELF32_REGSET(regset_arm_tls); 159 #endif 160 161 int 162 ptrace_set_pc(struct thread *td, u_long addr) 163 { 164 165 td->td_frame->tf_elr = addr; 166 return (0); 167 } 168 169 int 170 ptrace_single_step(struct thread *td) 171 { 172 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 173 if ((td->td_frame->tf_spsr & PSR_SS) == 0) { 174 td->td_frame->tf_spsr |= PSR_SS; 175 td->td_pcb->pcb_flags |= PCB_SINGLE_STEP; 176 td->td_dbgflags |= TDB_STEP; 177 } 178 return (0); 179 } 180 181 int 182 ptrace_clear_single_step(struct thread *td) 183 { 184 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 185 td->td_frame->tf_spsr &= ~PSR_SS; 186 td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP; 187 td->td_dbgflags &= ~TDB_STEP; 188 return (0); 189 } 190 191