aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
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,