|
@@ -905,6 +905,9 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
|
|
struct perf_event *bp;
|
|
struct perf_event *bp;
|
|
struct perf_event_attr attr;
|
|
struct perf_event_attr attr;
|
|
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
|
|
+#ifndef CONFIG_PPC_ADV_DEBUG_REGS
|
|
|
|
+ struct arch_hw_breakpoint hw_brk;
|
|
|
|
+#endif
|
|
|
|
|
|
/* For ppc64 we support one DABR and no IABR's at the moment (ppc64).
|
|
/* For ppc64 we support one DABR and no IABR's at the moment (ppc64).
|
|
* For embedded processors we support one DAC and no IAC's at the
|
|
* For embedded processors we support one DAC and no IAC's at the
|
|
@@ -931,14 +934,17 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
|
|
*/
|
|
*/
|
|
|
|
|
|
/* Ensure breakpoint translation bit is set */
|
|
/* Ensure breakpoint translation bit is set */
|
|
- if (data && !(data & DABR_TRANSLATION))
|
|
|
|
|
|
+ if (data && !(data & HW_BRK_TYPE_TRANSLATE))
|
|
return -EIO;
|
|
return -EIO;
|
|
|
|
+ hw_brk.address = data & (~HW_BRK_TYPE_DABR);
|
|
|
|
+ hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
|
|
|
|
+ hw_brk.len = 8;
|
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
|
if (ptrace_get_breakpoints(task) < 0)
|
|
if (ptrace_get_breakpoints(task) < 0)
|
|
return -ESRCH;
|
|
return -ESRCH;
|
|
|
|
|
|
bp = thread->ptrace_bps[0];
|
|
bp = thread->ptrace_bps[0];
|
|
- if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) {
|
|
|
|
|
|
+ if ((!data) || !(hw_brk.type & HW_BRK_TYPE_RDWR)) {
|
|
if (bp) {
|
|
if (bp) {
|
|
unregister_hw_breakpoint(bp);
|
|
unregister_hw_breakpoint(bp);
|
|
thread->ptrace_bps[0] = NULL;
|
|
thread->ptrace_bps[0] = NULL;
|
|
@@ -948,10 +954,8 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
|
|
}
|
|
}
|
|
if (bp) {
|
|
if (bp) {
|
|
attr = bp->attr;
|
|
attr = bp->attr;
|
|
- attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN;
|
|
|
|
- arch_bp_generic_fields(data &
|
|
|
|
- (DABR_DATA_WRITE | DABR_DATA_READ),
|
|
|
|
- &attr.bp_type);
|
|
|
|
|
|
+ attr.bp_addr = hw_brk.address;
|
|
|
|
+ arch_bp_generic_fields(hw_brk.type, &attr.bp_type);
|
|
|
|
|
|
/* Enable breakpoint */
|
|
/* Enable breakpoint */
|
|
attr.disabled = false;
|
|
attr.disabled = false;
|
|
@@ -963,16 +967,15 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
|
|
}
|
|
}
|
|
thread->ptrace_bps[0] = bp;
|
|
thread->ptrace_bps[0] = bp;
|
|
ptrace_put_breakpoints(task);
|
|
ptrace_put_breakpoints(task);
|
|
- thread->dabr = data;
|
|
|
|
- thread->dabrx = DABRX_ALL;
|
|
|
|
|
|
+ thread->hw_brk = hw_brk;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* Create a new breakpoint request if one doesn't exist already */
|
|
/* Create a new breakpoint request if one doesn't exist already */
|
|
hw_breakpoint_init(&attr);
|
|
hw_breakpoint_init(&attr);
|
|
- attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN;
|
|
|
|
- arch_bp_generic_fields(data & (DABR_DATA_WRITE | DABR_DATA_READ),
|
|
|
|
- &attr.bp_type);
|
|
|
|
|
|
+ attr.bp_addr = hw_brk.address;
|
|
|
|
+ arch_bp_generic_fields(hw_brk.type,
|
|
|
|
+ &attr.bp_type);
|
|
|
|
|
|
thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
|
|
thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
|
|
ptrace_triggered, NULL, task);
|
|
ptrace_triggered, NULL, task);
|
|
@@ -985,10 +988,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
|
|
ptrace_put_breakpoints(task);
|
|
ptrace_put_breakpoints(task);
|
|
|
|
|
|
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
-
|
|
|
|
- /* Move contents to the DABR register */
|
|
|
|
- task->thread.dabr = data;
|
|
|
|
- task->thread.dabrx = DABRX_ALL;
|
|
|
|
|
|
+ task->thread.hw_brk = hw_brk;
|
|
#else /* CONFIG_PPC_ADV_DEBUG_REGS */
|
|
#else /* CONFIG_PPC_ADV_DEBUG_REGS */
|
|
/* As described above, it was assumed 3 bits were passed with the data
|
|
/* As described above, it was assumed 3 bits were passed with the data
|
|
* address, but we will assume only the mode bits will be passed
|
|
* address, but we will assume only the mode bits will be passed
|
|
@@ -1349,7 +1349,7 @@ static long ppc_set_hwdebug(struct task_struct *child,
|
|
struct perf_event_attr attr;
|
|
struct perf_event_attr attr;
|
|
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
#ifndef CONFIG_PPC_ADV_DEBUG_REGS
|
|
#ifndef CONFIG_PPC_ADV_DEBUG_REGS
|
|
- unsigned long dabr;
|
|
|
|
|
|
+ struct arch_hw_breakpoint brk;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
if (bp_info->version != 1)
|
|
if (bp_info->version != 1)
|
|
@@ -1397,12 +1397,12 @@ static long ppc_set_hwdebug(struct task_struct *child,
|
|
if ((unsigned long)bp_info->addr >= TASK_SIZE)
|
|
if ((unsigned long)bp_info->addr >= TASK_SIZE)
|
|
return -EIO;
|
|
return -EIO;
|
|
|
|
|
|
- dabr = (unsigned long)bp_info->addr & ~7UL;
|
|
|
|
- dabr |= DABR_TRANSLATION;
|
|
|
|
|
|
+ brk.address = bp_info->addr & ~7UL;
|
|
|
|
+ brk.type = HW_BRK_TYPE_TRANSLATE;
|
|
if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
|
|
if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
|
|
- dabr |= DABR_DATA_READ;
|
|
|
|
|
|
+ brk.type |= HW_BRK_TYPE_READ;
|
|
if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
|
|
if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
|
|
- dabr |= DABR_DATA_WRITE;
|
|
|
|
|
|
+ brk.type |= HW_BRK_TYPE_WRITE;
|
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
|
if (ptrace_get_breakpoints(child) < 0)
|
|
if (ptrace_get_breakpoints(child) < 0)
|
|
return -ESRCH;
|
|
return -ESRCH;
|
|
@@ -1427,8 +1427,7 @@ static long ppc_set_hwdebug(struct task_struct *child,
|
|
hw_breakpoint_init(&attr);
|
|
hw_breakpoint_init(&attr);
|
|
attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN;
|
|
attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN;
|
|
attr.bp_len = len;
|
|
attr.bp_len = len;
|
|
- arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ),
|
|
|
|
- &attr.bp_type);
|
|
|
|
|
|
+ arch_bp_generic_fields(brk.type, &attr.bp_type);
|
|
|
|
|
|
thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
|
|
thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
|
|
ptrace_triggered, NULL, child);
|
|
ptrace_triggered, NULL, child);
|
|
@@ -1445,11 +1444,10 @@ static long ppc_set_hwdebug(struct task_struct *child,
|
|
if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
|
|
if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- if (child->thread.dabr)
|
|
|
|
|
|
+ if (child->thread.hw_brk.address)
|
|
return -ENOSPC;
|
|
return -ENOSPC;
|
|
|
|
|
|
- child->thread.dabr = dabr;
|
|
|
|
- child->thread.dabrx = DABRX_ALL;
|
|
|
|
|
|
+ child->thread.hw_brk = brk;
|
|
|
|
|
|
return 1;
|
|
return 1;
|
|
#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
|
|
#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
|
|
@@ -1495,10 +1493,11 @@ static long ppc_del_hwdebug(struct task_struct *child, long data)
|
|
ptrace_put_breakpoints(child);
|
|
ptrace_put_breakpoints(child);
|
|
return ret;
|
|
return ret;
|
|
#else /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
#else /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
- if (child->thread.dabr == 0)
|
|
|
|
|
|
+ if (child->thread.hw_brk.address == 0)
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
|
|
|
|
- child->thread.dabr = 0;
|
|
|
|
|
|
+ child->thread.hw_brk.address = 0;
|
|
|
|
+ child->thread.hw_brk.type = 0;
|
|
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -1642,6 +1641,9 @@ long arch_ptrace(struct task_struct *child, long request,
|
|
}
|
|
}
|
|
|
|
|
|
case PTRACE_GET_DEBUGREG: {
|
|
case PTRACE_GET_DEBUGREG: {
|
|
|
|
+#ifndef CONFIG_PPC_ADV_DEBUG_REGS
|
|
|
|
+ unsigned long dabr_fake;
|
|
|
|
+#endif
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
/* We only support one DABR and no IABRS at the moment */
|
|
/* We only support one DABR and no IABRS at the moment */
|
|
if (addr > 0)
|
|
if (addr > 0)
|
|
@@ -1649,7 +1651,9 @@ long arch_ptrace(struct task_struct *child, long request,
|
|
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
|
|
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
|
|
ret = put_user(child->thread.dac1, datalp);
|
|
ret = put_user(child->thread.dac1, datalp);
|
|
#else
|
|
#else
|
|
- ret = put_user(child->thread.dabr, datalp);
|
|
|
|
|
|
+ dabr_fake = ((child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) |
|
|
|
|
+ (child->thread.hw_brk.type & HW_BRK_TYPE_DABR));
|
|
|
|
+ ret = put_user(dabr_fake, datalp);
|
|
#endif
|
|
#endif
|
|
break;
|
|
break;
|
|
}
|
|
}
|