aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c91
1 files changed, 83 insertions, 8 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6ff07ad0ede3..c55f7e274613 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -314,6 +314,20 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
314 if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK) 314 if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK)
315 return -EINVAL; 315 return -EINVAL;
316 316
317#ifndef ARCH_SUPPORTS_FTRACE_SAVE_REGS
318 /*
319 * If the ftrace_ops specifies SAVE_REGS, then it only can be used
320 * if the arch supports it, or SAVE_REGS_IF_SUPPORTED is also set.
321 * Setting SAVE_REGS_IF_SUPPORTED makes SAVE_REGS irrelevant.
322 */
323 if (ops->flags & FTRACE_OPS_FL_SAVE_REGS &&
324 !(ops->flags & FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED))
325 return -EINVAL;
326
327 if (ops->flags & FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED)
328 ops->flags |= FTRACE_OPS_FL_SAVE_REGS;
329#endif
330
317 if (!core_kernel_data((unsigned long)ops)) 331 if (!core_kernel_data((unsigned long)ops))
318 ops->flags |= FTRACE_OPS_FL_DYNAMIC; 332 ops->flags |= FTRACE_OPS_FL_DYNAMIC;
319 333
@@ -1515,6 +1529,12 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
1515 rec->flags++; 1529 rec->flags++;
1516 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == FTRACE_REF_MAX)) 1530 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == FTRACE_REF_MAX))
1517 return; 1531 return;
1532 /*
1533 * If any ops wants regs saved for this function
1534 * then all ops will get saved regs.
1535 */
1536 if (ops->flags & FTRACE_OPS_FL_SAVE_REGS)
1537 rec->flags |= FTRACE_FL_REGS;
1518 } else { 1538 } else {
1519 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == 0)) 1539 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == 0))
1520 return; 1540 return;
@@ -1606,18 +1626,59 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
1606 if (enable && (rec->flags & ~FTRACE_FL_MASK)) 1626 if (enable && (rec->flags & ~FTRACE_FL_MASK))
1607 flag = FTRACE_FL_ENABLED; 1627 flag = FTRACE_FL_ENABLED;
1608 1628
1629 /*
1630 * If enabling and the REGS flag does not match the REGS_EN, then
1631 * do not ignore this record. Set flags to fail the compare against
1632 * ENABLED.
1633 */
1634 if (flag &&
1635 (!(rec->flags & FTRACE_FL_REGS) != !(rec->flags & FTRACE_FL_REGS_EN)))
1636 flag |= FTRACE_FL_REGS;
1637
1609 /* If the state of this record hasn't changed, then do nothing */ 1638 /* If the state of this record hasn't changed, then do nothing */
1610 if ((rec->flags & FTRACE_FL_ENABLED) == flag) 1639 if ((rec->flags & FTRACE_FL_ENABLED) == flag)
1611 return FTRACE_UPDATE_IGNORE; 1640 return FTRACE_UPDATE_IGNORE;
1612 1641
1613 if (flag) { 1642 if (flag) {
1614 if (update) 1643 /* Save off if rec is being enabled (for return value) */
1644 flag ^= rec->flags & FTRACE_FL_ENABLED;
1645
1646 if (update) {
1615 rec->flags |= FTRACE_FL_ENABLED; 1647 rec->flags |= FTRACE_FL_ENABLED;
1616 return FTRACE_UPDATE_MAKE_CALL; 1648 if (flag & FTRACE_FL_REGS) {
1649 if (rec->flags & FTRACE_FL_REGS)
1650 rec->flags |= FTRACE_FL_REGS_EN;
1651 else
1652 rec->flags &= ~FTRACE_FL_REGS_EN;
1653 }
1654 }
1655
1656 /*
1657 * If this record is being updated from a nop, then
1658 * return UPDATE_MAKE_CALL.
1659 * Otherwise, if the EN flag is set, then return
1660 * UPDATE_MODIFY_CALL_REGS to tell the caller to convert
1661 * from the non-save regs, to a save regs function.
1662 * Otherwise,
1663 * return UPDATE_MODIFY_CALL to tell the caller to convert
1664 * from the save regs, to a non-save regs function.
1665 */
1666 if (flag & FTRACE_FL_ENABLED)
1667 return FTRACE_UPDATE_MAKE_CALL;
1668 else if (rec->flags & FTRACE_FL_REGS_EN)
1669 return FTRACE_UPDATE_MODIFY_CALL_REGS;
1670 else
1671 return FTRACE_UPDATE_MODIFY_CALL;
1617 } 1672 }
1618 1673
1619 if (update) 1674 if (update) {
1620 rec->flags &= ~FTRACE_FL_ENABLED; 1675 /* If there's no more users, clear all flags */
1676 if (!(rec->flags & ~FTRACE_FL_MASK))
1677 rec->flags = 0;
1678 else
1679 /* Just disable the record (keep REGS state) */
1680 rec->flags &= ~FTRACE_FL_ENABLED;
1681 }
1621 1682
1622 return FTRACE_UPDATE_MAKE_NOP; 1683 return FTRACE_UPDATE_MAKE_NOP;
1623} 1684}
@@ -1652,13 +1713,17 @@ int ftrace_test_record(struct dyn_ftrace *rec, int enable)
1652static int 1713static int
1653__ftrace_replace_code(struct dyn_ftrace *rec, int enable) 1714__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
1654{ 1715{
1716 unsigned long ftrace_old_addr;
1655 unsigned long ftrace_addr; 1717 unsigned long ftrace_addr;
1656 int ret; 1718 int ret;
1657 1719
1658 ftrace_addr = (unsigned long)FTRACE_ADDR;
1659
1660 ret = ftrace_update_record(rec, enable); 1720 ret = ftrace_update_record(rec, enable);
1661 1721
1722 if (rec->flags & FTRACE_FL_REGS)
1723 ftrace_addr = (unsigned long)FTRACE_REGS_ADDR;
1724 else
1725 ftrace_addr = (unsigned long)FTRACE_ADDR;
1726
1662 switch (ret) { 1727 switch (ret) {
1663 case FTRACE_UPDATE_IGNORE: 1728 case FTRACE_UPDATE_IGNORE:
1664 return 0; 1729 return 0;
@@ -1668,6 +1733,15 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
1668 1733
1669 case FTRACE_UPDATE_MAKE_NOP: 1734 case FTRACE_UPDATE_MAKE_NOP:
1670 return ftrace_make_nop(NULL, rec, ftrace_addr); 1735 return ftrace_make_nop(NULL, rec, ftrace_addr);
1736
1737 case FTRACE_UPDATE_MODIFY_CALL_REGS:
1738 case FTRACE_UPDATE_MODIFY_CALL:
1739 if (rec->flags & FTRACE_FL_REGS)
1740 ftrace_old_addr = (unsigned long)FTRACE_ADDR;
1741 else
1742 ftrace_old_addr = (unsigned long)FTRACE_REGS_ADDR;
1743
1744 return ftrace_modify_call(rec, ftrace_old_addr, ftrace_addr);
1671 } 1745 }
1672 1746
1673 return -1; /* unknow ftrace bug */ 1747 return -1; /* unknow ftrace bug */
@@ -2421,8 +2495,9 @@ static int t_show(struct seq_file *m, void *v)
2421 2495
2422 seq_printf(m, "%ps", (void *)rec->ip); 2496 seq_printf(m, "%ps", (void *)rec->ip);
2423 if (iter->flags & FTRACE_ITER_ENABLED) 2497 if (iter->flags & FTRACE_ITER_ENABLED)
2424 seq_printf(m, " (%ld)", 2498 seq_printf(m, " (%ld)%s",
2425 rec->flags & ~FTRACE_FL_MASK); 2499 rec->flags & ~FTRACE_FL_MASK,
2500 rec->flags & FTRACE_FL_REGS ? " R" : "");
2426 seq_printf(m, "\n"); 2501 seq_printf(m, "\n");
2427 2502
2428 return 0; 2503 return 0;