aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorK.Prasad <prasad@linux.vnet.ibm.com>2012-10-28 11:13:15 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-11-14 21:00:23 -0500
commit6c7a2856ade6a58c20038024247d16a12a8d2323 (patch)
tree87d43dc2aeaded2c7d9cc9faaa2ce326334f2360 /arch/powerpc/kernel
parent16b86bf2520ed29712ca7462dbfe76c856b445e9 (diff)
powerpc/hw-breakpoint: Use generic hw-breakpoint interfaces for new PPC ptrace flags
PPC_PTRACE_GETHWDBGINFO, PPC_PTRACE_SETHWDEBUG and PPC_PTRACE_DELHWDEBUG are PowerPC specific ptrace flags that use the watchpoint register. While they are targeted primarily towards BookE users, user-space applications such as GDB have started using them for BookS too. This patch enables the use of generic hardware breakpoint interfaces for these new flags. Apart from the usual benefits of using generic hw-breakpoint interfaces, these changes allow debuggers (such as GDB) to use a common set of ptrace flags for their watchpoint needs and allow more precise breakpoint specification (length of the variable can be specified). Mikey added: rebased and added dbginfo.features around #ifdef CONFIG_HAVE_HW_BREAKPOINT Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> Acked-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/ptrace.c78
1 files changed, 74 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 79d8e56470df..140238aad718 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1338,6 +1338,12 @@ static int set_dac_range(struct task_struct *child,
1338static long ppc_set_hwdebug(struct task_struct *child, 1338static long ppc_set_hwdebug(struct task_struct *child,
1339 struct ppc_hw_breakpoint *bp_info) 1339 struct ppc_hw_breakpoint *bp_info)
1340{ 1340{
1341#ifdef CONFIG_HAVE_HW_BREAKPOINT
1342 int len = 0;
1343 struct thread_struct *thread = &(child->thread);
1344 struct perf_event *bp;
1345 struct perf_event_attr attr;
1346#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1341#ifndef CONFIG_PPC_ADV_DEBUG_REGS 1347#ifndef CONFIG_PPC_ADV_DEBUG_REGS
1342 unsigned long dabr; 1348 unsigned long dabr;
1343#endif 1349#endif
@@ -1381,13 +1387,9 @@ static long ppc_set_hwdebug(struct task_struct *child,
1381 */ 1387 */
1382 if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 || 1388 if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 ||
1383 (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 || 1389 (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 ||
1384 bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT ||
1385 bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE) 1390 bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
1386 return -EINVAL; 1391 return -EINVAL;
1387 1392
1388 if (child->thread.dabr)
1389 return -ENOSPC;
1390
1391 if ((unsigned long)bp_info->addr >= TASK_SIZE) 1393 if ((unsigned long)bp_info->addr >= TASK_SIZE)
1392 return -EIO; 1394 return -EIO;
1393 1395
@@ -1397,6 +1399,50 @@ static long ppc_set_hwdebug(struct task_struct *child,
1397 dabr |= DABR_DATA_READ; 1399 dabr |= DABR_DATA_READ;
1398 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) 1400 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
1399 dabr |= DABR_DATA_WRITE; 1401 dabr |= DABR_DATA_WRITE;
1402#ifdef CONFIG_HAVE_HW_BREAKPOINT
1403 if (ptrace_get_breakpoints(child) < 0)
1404 return -ESRCH;
1405
1406 /*
1407 * Check if the request is for 'range' breakpoints. We can
1408 * support it if range < 8 bytes.
1409 */
1410 if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE) {
1411 len = bp_info->addr2 - bp_info->addr;
1412 } else if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) {
1413 ptrace_put_breakpoints(child);
1414 return -EINVAL;
1415 }
1416 bp = thread->ptrace_bps[0];
1417 if (bp) {
1418 ptrace_put_breakpoints(child);
1419 return -ENOSPC;
1420 }
1421
1422 /* Create a new breakpoint request if one doesn't exist already */
1423 hw_breakpoint_init(&attr);
1424 attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN;
1425 attr.bp_len = len;
1426 arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ),
1427 &attr.bp_type);
1428
1429 thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
1430 ptrace_triggered, NULL, child);
1431 if (IS_ERR(bp)) {
1432 thread->ptrace_bps[0] = NULL;
1433 ptrace_put_breakpoints(child);
1434 return PTR_ERR(bp);
1435 }
1436
1437 ptrace_put_breakpoints(child);
1438 return 1;
1439#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1440
1441 if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
1442 return -EINVAL;
1443
1444 if (child->thread.dabr)
1445 return -ENOSPC;
1400 1446
1401 child->thread.dabr = dabr; 1447 child->thread.dabr = dabr;
1402 child->thread.dabrx = DABRX_ALL; 1448 child->thread.dabrx = DABRX_ALL;
@@ -1407,6 +1453,11 @@ static long ppc_set_hwdebug(struct task_struct *child,
1407 1453
1408static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) 1454static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
1409{ 1455{
1456#ifdef CONFIG_HAVE_HW_BREAKPOINT
1457 int ret = 0;
1458 struct thread_struct *thread = &(child->thread);
1459 struct perf_event *bp;
1460#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1410#ifdef CONFIG_PPC_ADV_DEBUG_REGS 1461#ifdef CONFIG_PPC_ADV_DEBUG_REGS
1411 int rc; 1462 int rc;
1412 1463
@@ -1426,10 +1477,25 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
1426#else 1477#else
1427 if (data != 1) 1478 if (data != 1)
1428 return -EINVAL; 1479 return -EINVAL;
1480
1481#ifdef CONFIG_HAVE_HW_BREAKPOINT
1482 if (ptrace_get_breakpoints(child) < 0)
1483 return -ESRCH;
1484
1485 bp = thread->ptrace_bps[0];
1486 if (bp) {
1487 unregister_hw_breakpoint(bp);
1488 thread->ptrace_bps[0] = NULL;
1489 } else
1490 ret = -ENOENT;
1491 ptrace_put_breakpoints(child);
1492 return ret;
1493#else /* CONFIG_HAVE_HW_BREAKPOINT */
1429 if (child->thread.dabr == 0) 1494 if (child->thread.dabr == 0)
1430 return -ENOENT; 1495 return -ENOENT;
1431 1496
1432 child->thread.dabr = 0; 1497 child->thread.dabr = 0;
1498#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1433 1499
1434 return 0; 1500 return 0;
1435#endif 1501#endif
@@ -1536,7 +1602,11 @@ long arch_ptrace(struct task_struct *child, long request,
1536 dbginfo.data_bp_alignment = 4; 1602 dbginfo.data_bp_alignment = 4;
1537#endif 1603#endif
1538 dbginfo.sizeof_condition = 0; 1604 dbginfo.sizeof_condition = 0;
1605#ifdef CONFIG_HAVE_HW_BREAKPOINT
1606 dbginfo.features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
1607#else
1539 dbginfo.features = 0; 1608 dbginfo.features = 0;
1609#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1540#endif /* CONFIG_PPC_ADV_DEBUG_REGS */ 1610#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
1541 1611
1542 if (!access_ok(VERIFY_WRITE, datavp, 1612 if (!access_ok(VERIFY_WRITE, datavp,