0001
0002
0003 #include <linux/regset.h>
0004 #include <linux/hw_breakpoint.h>
0005
0006 #include <asm/debug.h>
0007
0008 #include "ptrace-decl.h"
0009
0010 void user_enable_single_step(struct task_struct *task)
0011 {
0012 struct pt_regs *regs = task->thread.regs;
0013
0014 if (regs != NULL)
0015 regs_set_return_msr(regs, (regs->msr & ~MSR_BE) | MSR_SE);
0016 set_tsk_thread_flag(task, TIF_SINGLESTEP);
0017 }
0018
0019 void user_enable_block_step(struct task_struct *task)
0020 {
0021 struct pt_regs *regs = task->thread.regs;
0022
0023 if (regs != NULL)
0024 regs_set_return_msr(regs, (regs->msr & ~MSR_SE) | MSR_BE);
0025 set_tsk_thread_flag(task, TIF_SINGLESTEP);
0026 }
0027
0028 void user_disable_single_step(struct task_struct *task)
0029 {
0030 struct pt_regs *regs = task->thread.regs;
0031
0032 if (regs != NULL)
0033 regs_set_return_msr(regs, regs->msr & ~(MSR_SE | MSR_BE));
0034
0035 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
0036 }
0037
0038 void ppc_gethwdinfo(struct ppc_debug_info *dbginfo)
0039 {
0040 dbginfo->version = 1;
0041 dbginfo->num_instruction_bps = 0;
0042 if (ppc_breakpoint_available())
0043 dbginfo->num_data_bps = nr_wp_slots();
0044 else
0045 dbginfo->num_data_bps = 0;
0046 dbginfo->num_condition_regs = 0;
0047 dbginfo->data_bp_alignment = sizeof(long);
0048 dbginfo->sizeof_condition = 0;
0049 if (IS_ENABLED(CONFIG_HAVE_HW_BREAKPOINT)) {
0050 dbginfo->features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
0051 if (dawr_enabled())
0052 dbginfo->features |= PPC_DEBUG_FEATURE_DATA_BP_DAWR;
0053 } else {
0054 dbginfo->features = 0;
0055 }
0056 if (cpu_has_feature(CPU_FTR_ARCH_31))
0057 dbginfo->features |= PPC_DEBUG_FEATURE_DATA_BP_ARCH_31;
0058 }
0059
0060 int ptrace_get_debugreg(struct task_struct *child, unsigned long addr,
0061 unsigned long __user *datalp)
0062 {
0063 unsigned long dabr_fake;
0064
0065
0066 if (addr > 0)
0067 return -EINVAL;
0068 dabr_fake = ((child->thread.hw_brk[0].address & (~HW_BRK_TYPE_DABR)) |
0069 (child->thread.hw_brk[0].type & HW_BRK_TYPE_DABR));
0070 return put_user(dabr_fake, datalp);
0071 }
0072
0073
0074
0075
0076
0077
0078 int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned long data)
0079 {
0080 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0081 int ret;
0082 struct thread_struct *thread = &task->thread;
0083 struct perf_event *bp;
0084 struct perf_event_attr attr;
0085 #endif
0086 bool set_bp = true;
0087 struct arch_hw_breakpoint hw_brk;
0088
0089
0090
0091
0092
0093 if (addr > 0)
0094 return -EINVAL;
0095
0096
0097 if ((data & ~0x7UL) >= TASK_SIZE)
0098 return -EIO;
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 if (data && !(data & HW_BRK_TYPE_TRANSLATE))
0114 return -EIO;
0115 hw_brk.address = data & (~HW_BRK_TYPE_DABR);
0116 hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
0117 hw_brk.len = DABR_MAX_LEN;
0118 hw_brk.hw_len = DABR_MAX_LEN;
0119 set_bp = (data) && (hw_brk.type & HW_BRK_TYPE_RDWR);
0120 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0121 bp = thread->ptrace_bps[0];
0122 if (!set_bp) {
0123 if (bp) {
0124 unregister_hw_breakpoint(bp);
0125 thread->ptrace_bps[0] = NULL;
0126 }
0127 return 0;
0128 }
0129 if (bp) {
0130 attr = bp->attr;
0131 attr.bp_addr = hw_brk.address;
0132 attr.bp_len = DABR_MAX_LEN;
0133 arch_bp_generic_fields(hw_brk.type, &attr.bp_type);
0134
0135
0136 attr.disabled = false;
0137
0138 ret = modify_user_hw_breakpoint(bp, &attr);
0139 if (ret)
0140 return ret;
0141
0142 thread->ptrace_bps[0] = bp;
0143 thread->hw_brk[0] = hw_brk;
0144 return 0;
0145 }
0146
0147
0148 hw_breakpoint_init(&attr);
0149 attr.bp_addr = hw_brk.address;
0150 attr.bp_len = DABR_MAX_LEN;
0151 arch_bp_generic_fields(hw_brk.type,
0152 &attr.bp_type);
0153
0154 thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
0155 ptrace_triggered, NULL, task);
0156 if (IS_ERR(bp)) {
0157 thread->ptrace_bps[0] = NULL;
0158 return PTR_ERR(bp);
0159 }
0160
0161 #else
0162 if (set_bp && (!ppc_breakpoint_available()))
0163 return -ENODEV;
0164 #endif
0165 task->thread.hw_brk[0] = hw_brk;
0166 return 0;
0167 }
0168
0169 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0170 static int find_empty_ptrace_bp(struct thread_struct *thread)
0171 {
0172 int i;
0173
0174 for (i = 0; i < nr_wp_slots(); i++) {
0175 if (!thread->ptrace_bps[i])
0176 return i;
0177 }
0178 return -1;
0179 }
0180 #endif
0181
0182 static int find_empty_hw_brk(struct thread_struct *thread)
0183 {
0184 int i;
0185
0186 for (i = 0; i < nr_wp_slots(); i++) {
0187 if (!thread->hw_brk[i].address)
0188 return i;
0189 }
0190 return -1;
0191 }
0192
0193 long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
0194 {
0195 int i;
0196 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0197 int len = 0;
0198 struct thread_struct *thread = &child->thread;
0199 struct perf_event *bp;
0200 struct perf_event_attr attr;
0201 #endif
0202 struct arch_hw_breakpoint brk;
0203
0204 if (bp_info->version != 1)
0205 return -ENOTSUPP;
0206
0207
0208
0209 if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 ||
0210 (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 ||
0211 bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
0212 return -EINVAL;
0213
0214 if ((unsigned long)bp_info->addr >= TASK_SIZE)
0215 return -EIO;
0216
0217 brk.address = ALIGN_DOWN(bp_info->addr, HW_BREAKPOINT_SIZE);
0218 brk.type = HW_BRK_TYPE_TRANSLATE | HW_BRK_TYPE_PRIV_ALL;
0219 brk.len = DABR_MAX_LEN;
0220 brk.hw_len = DABR_MAX_LEN;
0221 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
0222 brk.type |= HW_BRK_TYPE_READ;
0223 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
0224 brk.type |= HW_BRK_TYPE_WRITE;
0225 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0226 if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
0227 len = bp_info->addr2 - bp_info->addr;
0228 else if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT)
0229 len = 1;
0230 else
0231 return -EINVAL;
0232
0233 i = find_empty_ptrace_bp(thread);
0234 if (i < 0)
0235 return -ENOSPC;
0236
0237
0238 hw_breakpoint_init(&attr);
0239 attr.bp_addr = (unsigned long)bp_info->addr;
0240 attr.bp_len = len;
0241 arch_bp_generic_fields(brk.type, &attr.bp_type);
0242
0243 bp = register_user_hw_breakpoint(&attr, ptrace_triggered, NULL, child);
0244 thread->ptrace_bps[i] = bp;
0245 if (IS_ERR(bp)) {
0246 thread->ptrace_bps[i] = NULL;
0247 return PTR_ERR(bp);
0248 }
0249
0250 return i + 1;
0251 #endif
0252
0253 if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
0254 return -EINVAL;
0255
0256 i = find_empty_hw_brk(&child->thread);
0257 if (i < 0)
0258 return -ENOSPC;
0259
0260 if (!ppc_breakpoint_available())
0261 return -ENODEV;
0262
0263 child->thread.hw_brk[i] = brk;
0264
0265 return i + 1;
0266 }
0267
0268 long ppc_del_hwdebug(struct task_struct *child, long data)
0269 {
0270 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0271 int ret = 0;
0272 struct thread_struct *thread = &child->thread;
0273 struct perf_event *bp;
0274 #endif
0275 if (data < 1 || data > nr_wp_slots())
0276 return -EINVAL;
0277
0278 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0279 bp = thread->ptrace_bps[data - 1];
0280 if (bp) {
0281 unregister_hw_breakpoint(bp);
0282 thread->ptrace_bps[data - 1] = NULL;
0283 } else {
0284 ret = -ENOENT;
0285 }
0286 return ret;
0287 #else
0288 if (!(child->thread.hw_brk[data - 1].flags & HW_BRK_FLAG_DISABLED) &&
0289 child->thread.hw_brk[data - 1].address == 0)
0290 return -ENOENT;
0291
0292 child->thread.hw_brk[data - 1].address = 0;
0293 child->thread.hw_brk[data - 1].type = 0;
0294 child->thread.hw_brk[data - 1].flags = 0;
0295 #endif
0296
0297 return 0;
0298 }