aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorK.Prasad <prasad@linux.vnet.ibm.com>2012-05-10 18:43:38 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-05-13 20:48:55 -0400
commit1b788400bbcbfe25280dc0b8000d2142bfe3be3b (patch)
tree2601bdf294a99f2aa03615b67dcc7ceb4750a666 /arch/powerpc/kernel
parent404e32e4a8f68d218b73b7db7bb831d887ab6046 (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). 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>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/ptrace.c77
1 files changed, 71 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index ac3cb008fb31..8643ac890235 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1336,6 +1336,12 @@ static int set_dac_range(struct task_struct *child,
1336static long ppc_set_hwdebug(struct task_struct *child, 1336static long ppc_set_hwdebug(struct task_struct *child,
1337 struct ppc_hw_breakpoint *bp_info) 1337 struct ppc_hw_breakpoint *bp_info)
1338{ 1338{
1339#ifdef CONFIG_HAVE_HW_BREAKPOINT
1340 int len = 0;
1341 struct thread_struct *thread = &(child->thread);
1342 struct perf_event *bp;
1343 struct perf_event_attr attr;
1344#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1339#ifndef CONFIG_PPC_ADV_DEBUG_REGS 1345#ifndef CONFIG_PPC_ADV_DEBUG_REGS
1340 unsigned long dabr; 1346 unsigned long dabr;
1341#endif 1347#endif
@@ -1379,13 +1385,9 @@ static long ppc_set_hwdebug(struct task_struct *child,
1379 */ 1385 */
1380 if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 || 1386 if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 ||
1381 (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 || 1387 (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 ||
1382 bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT ||
1383 bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE) 1388 bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
1384 return -EINVAL; 1389 return -EINVAL;
1385 1390
1386 if (child->thread.dabr)
1387 return -ENOSPC;
1388
1389 if ((unsigned long)bp_info->addr >= TASK_SIZE) 1391 if ((unsigned long)bp_info->addr >= TASK_SIZE)
1390 return -EIO; 1392 return -EIO;
1391 1393
@@ -1395,15 +1397,63 @@ static long ppc_set_hwdebug(struct task_struct *child,
1395 dabr |= DABR_DATA_READ; 1397 dabr |= DABR_DATA_READ;
1396 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) 1398 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
1397 dabr |= DABR_DATA_WRITE; 1399 dabr |= DABR_DATA_WRITE;
1400#ifdef CONFIG_HAVE_HW_BREAKPOINT
1401 if (ptrace_get_breakpoints(child) < 0)
1402 return -ESRCH;
1398 1403
1399 child->thread.dabr = dabr; 1404 /*
1405 * Check if the request is for 'range' breakpoints. We can
1406 * support it if range < 8 bytes.
1407 */
1408 if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE) {
1409 len = bp_info->addr2 - bp_info->addr;
1410 } else if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) {
1411 ptrace_put_breakpoints(child);
1412 return -EINVAL;
1413 }
1414 bp = thread->ptrace_bps[0];
1415 if (bp) {
1416 ptrace_put_breakpoints(child);
1417 return -ENOSPC;
1418 }
1419
1420 /* Create a new breakpoint request if one doesn't exist already */
1421 hw_breakpoint_init(&attr);
1422 attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN;
1423 attr.bp_len = len;
1424 arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ),
1425 &attr.bp_type);
1426
1427 thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
1428 ptrace_triggered, NULL, child);
1429 if (IS_ERR(bp)) {
1430 thread->ptrace_bps[0] = NULL;
1431 ptrace_put_breakpoints(child);
1432 return PTR_ERR(bp);
1433 }
1400 1434
1435 ptrace_put_breakpoints(child);
1436 return 1;
1437#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1438
1439 if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
1440 return -EINVAL;
1441
1442 if (child->thread.dabr)
1443 return -ENOSPC;
1444
1445 child->thread.dabr = dabr;
1401 return 1; 1446 return 1;
1402#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */ 1447#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
1403} 1448}
1404 1449
1405static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) 1450static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
1406{ 1451{
1452#ifdef CONFIG_HAVE_HW_BREAKPOINT
1453 int ret = 0;
1454 struct thread_struct *thread = &(child->thread);
1455 struct perf_event *bp;
1456#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1407#ifdef CONFIG_PPC_ADV_DEBUG_REGS 1457#ifdef CONFIG_PPC_ADV_DEBUG_REGS
1408 int rc; 1458 int rc;
1409 1459
@@ -1423,10 +1473,25 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
1423#else 1473#else
1424 if (data != 1) 1474 if (data != 1)
1425 return -EINVAL; 1475 return -EINVAL;
1476
1477#ifdef CONFIG_HAVE_HW_BREAKPOINT
1478 if (ptrace_get_breakpoints(child) < 0)
1479 return -ESRCH;
1480
1481 bp = thread->ptrace_bps[0];
1482 if (bp) {
1483 unregister_hw_breakpoint(bp);
1484 thread->ptrace_bps[0] = NULL;
1485 } else
1486 ret = -ENOENT;
1487 ptrace_put_breakpoints(child);
1488 return ret;
1489#else /* CONFIG_HAVE_HW_BREAKPOINT */
1426 if (child->thread.dabr == 0) 1490 if (child->thread.dabr == 0)
1427 return -ENOENT; 1491 return -ENOENT;
1428 1492
1429 child->thread.dabr = 0; 1493 child->thread.dabr = 0;
1494#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1430 1495
1431 return 0; 1496 return 0;
1432#endif 1497#endif
@@ -1533,7 +1598,7 @@ long arch_ptrace(struct task_struct *child, long request,
1533 dbginfo.data_bp_alignment = 4; 1598 dbginfo.data_bp_alignment = 4;
1534#endif 1599#endif
1535 dbginfo.sizeof_condition = 0; 1600 dbginfo.sizeof_condition = 0;
1536 dbginfo.features = 0; 1601 dbginfo.features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
1537#endif /* CONFIG_PPC_ADV_DEBUG_REGS */ 1602#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
1538 1603
1539 if (!access_ok(VERIFY_WRITE, datavp, 1604 if (!access_ok(VERIFY_WRITE, datavp,