diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2008-12-23 23:24:13 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-12-29 06:46:12 -0500 |
| commit | f633cef0200bbaec539e2dbb0bc4bed7f022f98b (patch) | |
| tree | 725d0b181b8e417303e27fa9e62d06b780fe4934 | |
| parent | f0868d1e23a8efec33beb3aa688aab7fdb1ae093 (diff) | |
ftrace: change trace.c to use registered events
Impact: rework trace.c to use new event register API
Almost every ftrace event has to implement its output display in
trace.c through a different function. Some events did not handle
all the formats (trace, latency-trace, raw, hex, binary), and
this method does not scale well.
This patch converts the format functions to use the event API to
find the event and and print its format. Currently, we have
a print function for trace, latency_trace, raw, hex and binary.
A trace_nop_print is available if the event wants to avoid output
on a particular format.
Perhaps other tracers could use this in the future (like mmiotrace and
function_graph).
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | kernel/trace/trace.c | 402 | ||||
| -rw-r--r-- | kernel/trace/trace_branch.c | 53 | ||||
| -rw-r--r-- | kernel/trace/trace_output.c | 467 | ||||
| -rw-r--r-- | kernel/trace/trace_output.h | 16 |
4 files changed, 574 insertions, 364 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 90ce0c1d437b..3f0317586cfd 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -1483,15 +1483,6 @@ lat_print_timestamp(struct trace_seq *s, u64 abs_usecs, | |||
| 1483 | trace_seq_puts(s, " : "); | 1483 | trace_seq_puts(s, " : "); |
| 1484 | } | 1484 | } |
| 1485 | 1485 | ||
| 1486 | static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; | ||
| 1487 | |||
| 1488 | static int task_state_char(unsigned long state) | ||
| 1489 | { | ||
| 1490 | int bit = state ? __ffs(state) + 1 : 0; | ||
| 1491 | |||
| 1492 | return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?'; | ||
| 1493 | } | ||
| 1494 | |||
| 1495 | static void test_cpu_buff_start(struct trace_iterator *iter) | 1486 | static void test_cpu_buff_start(struct trace_iterator *iter) |
| 1496 | { | 1487 | { |
| 1497 | struct trace_seq *s = &iter->seq; | 1488 | struct trace_seq *s = &iter->seq; |
| @@ -1515,14 +1506,14 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) | |||
| 1515 | struct trace_seq *s = &iter->seq; | 1506 | struct trace_seq *s = &iter->seq; |
| 1516 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); | 1507 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); |
| 1517 | struct trace_entry *next_entry; | 1508 | struct trace_entry *next_entry; |
| 1509 | struct trace_event *event; | ||
| 1518 | unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE); | 1510 | unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE); |
| 1519 | struct trace_entry *entry = iter->ent; | 1511 | struct trace_entry *entry = iter->ent; |
| 1520 | unsigned long abs_usecs; | 1512 | unsigned long abs_usecs; |
| 1521 | unsigned long rel_usecs; | 1513 | unsigned long rel_usecs; |
| 1522 | u64 next_ts; | 1514 | u64 next_ts; |
| 1523 | char *comm; | 1515 | char *comm; |
| 1524 | int S, T; | 1516 | int ret; |
| 1525 | int i; | ||
| 1526 | 1517 | ||
| 1527 | test_cpu_buff_start(iter); | 1518 | test_cpu_buff_start(iter); |
| 1528 | 1519 | ||
| @@ -1547,94 +1538,16 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) | |||
| 1547 | lat_print_generic(s, entry, cpu); | 1538 | lat_print_generic(s, entry, cpu); |
| 1548 | lat_print_timestamp(s, abs_usecs, rel_usecs); | 1539 | lat_print_timestamp(s, abs_usecs, rel_usecs); |
| 1549 | } | 1540 | } |
| 1550 | switch (entry->type) { | ||
| 1551 | case TRACE_FN: { | ||
| 1552 | struct ftrace_entry *field; | ||
| 1553 | |||
| 1554 | trace_assign_type(field, entry); | ||
| 1555 | |||
| 1556 | seq_print_ip_sym(s, field->ip, sym_flags); | ||
| 1557 | trace_seq_puts(s, " ("); | ||
| 1558 | seq_print_ip_sym(s, field->parent_ip, sym_flags); | ||
| 1559 | trace_seq_puts(s, ")\n"); | ||
| 1560 | break; | ||
| 1561 | } | ||
| 1562 | case TRACE_CTX: | ||
| 1563 | case TRACE_WAKE: { | ||
| 1564 | struct ctx_switch_entry *field; | ||
| 1565 | |||
| 1566 | trace_assign_type(field, entry); | ||
| 1567 | |||
| 1568 | T = task_state_char(field->next_state); | ||
| 1569 | S = task_state_char(field->prev_state); | ||
| 1570 | comm = trace_find_cmdline(field->next_pid); | ||
| 1571 | trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n", | ||
| 1572 | field->prev_pid, | ||
| 1573 | field->prev_prio, | ||
| 1574 | S, entry->type == TRACE_CTX ? "==>" : " +", | ||
| 1575 | field->next_cpu, | ||
| 1576 | field->next_pid, | ||
| 1577 | field->next_prio, | ||
| 1578 | T, comm); | ||
| 1579 | break; | ||
| 1580 | } | ||
| 1581 | case TRACE_SPECIAL: { | ||
| 1582 | struct special_entry *field; | ||
| 1583 | |||
| 1584 | trace_assign_type(field, entry); | ||
| 1585 | |||
| 1586 | trace_seq_printf(s, "# %ld %ld %ld\n", | ||
| 1587 | field->arg1, | ||
| 1588 | field->arg2, | ||
| 1589 | field->arg3); | ||
| 1590 | break; | ||
| 1591 | } | ||
| 1592 | case TRACE_STACK: { | ||
| 1593 | struct stack_entry *field; | ||
| 1594 | |||
| 1595 | trace_assign_type(field, entry); | ||
| 1596 | |||
| 1597 | for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { | ||
| 1598 | if (i) | ||
| 1599 | trace_seq_puts(s, " <= "); | ||
| 1600 | seq_print_ip_sym(s, field->caller[i], sym_flags); | ||
| 1601 | } | ||
| 1602 | trace_seq_puts(s, "\n"); | ||
| 1603 | break; | ||
| 1604 | } | ||
| 1605 | case TRACE_PRINT: { | ||
| 1606 | struct print_entry *field; | ||
| 1607 | |||
| 1608 | trace_assign_type(field, entry); | ||
| 1609 | 1541 | ||
| 1610 | seq_print_ip_sym(s, field->ip, sym_flags); | 1542 | event = ftrace_find_event(entry->type); |
| 1611 | trace_seq_printf(s, ": %s", field->buf); | 1543 | if (event && event->latency_trace) { |
| 1612 | break; | 1544 | ret = event->latency_trace(s, entry, sym_flags); |
| 1613 | } | 1545 | if (ret) |
| 1614 | case TRACE_BRANCH: { | 1546 | return ret; |
| 1615 | struct trace_branch *field; | 1547 | return TRACE_TYPE_HANDLED; |
| 1616 | |||
| 1617 | trace_assign_type(field, entry); | ||
| 1618 | |||
| 1619 | trace_seq_printf(s, "[%s] %s:%s:%d\n", | ||
| 1620 | field->correct ? " ok " : " MISS ", | ||
| 1621 | field->func, | ||
| 1622 | field->file, | ||
| 1623 | field->line); | ||
| 1624 | break; | ||
| 1625 | } | 1548 | } |
| 1626 | case TRACE_USER_STACK: { | ||
| 1627 | struct userstack_entry *field; | ||
| 1628 | 1549 | ||
| 1629 | trace_assign_type(field, entry); | 1550 | trace_seq_printf(s, "Unknown type %d\n", entry->type); |
| 1630 | |||
| 1631 | seq_print_userip_objs(field, s, sym_flags); | ||
| 1632 | trace_seq_putc(s, '\n'); | ||
| 1633 | break; | ||
| 1634 | } | ||
| 1635 | default: | ||
| 1636 | trace_seq_printf(s, "Unknown type %d\n", entry->type); | ||
| 1637 | } | ||
| 1638 | return TRACE_TYPE_HANDLED; | 1551 | return TRACE_TYPE_HANDLED; |
| 1639 | } | 1552 | } |
| 1640 | 1553 | ||
| @@ -1643,13 +1556,12 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter) | |||
| 1643 | struct trace_seq *s = &iter->seq; | 1556 | struct trace_seq *s = &iter->seq; |
| 1644 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); | 1557 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); |
| 1645 | struct trace_entry *entry; | 1558 | struct trace_entry *entry; |
| 1559 | struct trace_event *event; | ||
| 1646 | unsigned long usec_rem; | 1560 | unsigned long usec_rem; |
| 1647 | unsigned long long t; | 1561 | unsigned long long t; |
| 1648 | unsigned long secs; | 1562 | unsigned long secs; |
| 1649 | char *comm; | 1563 | char *comm; |
| 1650 | int ret; | 1564 | int ret; |
| 1651 | int S, T; | ||
| 1652 | int i; | ||
| 1653 | 1565 | ||
| 1654 | entry = iter->ent; | 1566 | entry = iter->ent; |
| 1655 | 1567 | ||
| @@ -1671,127 +1583,17 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter) | |||
| 1671 | if (!ret) | 1583 | if (!ret) |
| 1672 | return TRACE_TYPE_PARTIAL_LINE; | 1584 | return TRACE_TYPE_PARTIAL_LINE; |
| 1673 | 1585 | ||
| 1674 | switch (entry->type) { | 1586 | event = ftrace_find_event(entry->type); |
| 1675 | case TRACE_FN: { | 1587 | if (event && event->trace) { |
| 1676 | struct ftrace_entry *field; | 1588 | ret = event->trace(s, entry, sym_flags); |
| 1677 | 1589 | if (ret) | |
| 1678 | trace_assign_type(field, entry); | 1590 | return ret; |
| 1679 | 1591 | return TRACE_TYPE_HANDLED; | |
| 1680 | ret = seq_print_ip_sym(s, field->ip, sym_flags); | ||
| 1681 | if (!ret) | ||
| 1682 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1683 | if ((sym_flags & TRACE_ITER_PRINT_PARENT) && | ||
| 1684 | field->parent_ip) { | ||
| 1685 | ret = trace_seq_printf(s, " <-"); | ||
| 1686 | if (!ret) | ||
| 1687 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1688 | ret = seq_print_ip_sym(s, | ||
| 1689 | field->parent_ip, | ||
| 1690 | sym_flags); | ||
| 1691 | if (!ret) | ||
| 1692 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1693 | } | ||
| 1694 | ret = trace_seq_printf(s, "\n"); | ||
| 1695 | if (!ret) | ||
| 1696 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1697 | break; | ||
| 1698 | } | ||
| 1699 | case TRACE_CTX: | ||
| 1700 | case TRACE_WAKE: { | ||
| 1701 | struct ctx_switch_entry *field; | ||
| 1702 | |||
| 1703 | trace_assign_type(field, entry); | ||
| 1704 | |||
| 1705 | T = task_state_char(field->next_state); | ||
| 1706 | S = task_state_char(field->prev_state); | ||
| 1707 | ret = trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c\n", | ||
| 1708 | field->prev_pid, | ||
| 1709 | field->prev_prio, | ||
| 1710 | S, | ||
| 1711 | entry->type == TRACE_CTX ? "==>" : " +", | ||
| 1712 | field->next_cpu, | ||
| 1713 | field->next_pid, | ||
| 1714 | field->next_prio, | ||
| 1715 | T); | ||
| 1716 | if (!ret) | ||
| 1717 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1718 | break; | ||
| 1719 | } | ||
| 1720 | case TRACE_SPECIAL: { | ||
| 1721 | struct special_entry *field; | ||
| 1722 | |||
| 1723 | trace_assign_type(field, entry); | ||
| 1724 | |||
| 1725 | ret = trace_seq_printf(s, "# %ld %ld %ld\n", | ||
| 1726 | field->arg1, | ||
| 1727 | field->arg2, | ||
| 1728 | field->arg3); | ||
| 1729 | if (!ret) | ||
| 1730 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1731 | break; | ||
| 1732 | } | ||
| 1733 | case TRACE_STACK: { | ||
| 1734 | struct stack_entry *field; | ||
| 1735 | |||
| 1736 | trace_assign_type(field, entry); | ||
| 1737 | |||
| 1738 | for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { | ||
| 1739 | if (i) { | ||
| 1740 | ret = trace_seq_puts(s, " <= "); | ||
| 1741 | if (!ret) | ||
| 1742 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1743 | } | ||
| 1744 | ret = seq_print_ip_sym(s, field->caller[i], | ||
| 1745 | sym_flags); | ||
| 1746 | if (!ret) | ||
| 1747 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1748 | } | ||
| 1749 | ret = trace_seq_puts(s, "\n"); | ||
| 1750 | if (!ret) | ||
| 1751 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1752 | break; | ||
| 1753 | } | ||
| 1754 | case TRACE_PRINT: { | ||
| 1755 | struct print_entry *field; | ||
| 1756 | |||
| 1757 | trace_assign_type(field, entry); | ||
| 1758 | |||
| 1759 | seq_print_ip_sym(s, field->ip, sym_flags); | ||
| 1760 | trace_seq_printf(s, ": %s", field->buf); | ||
| 1761 | break; | ||
| 1762 | } | ||
| 1763 | case TRACE_GRAPH_RET: { | ||
| 1764 | return print_graph_function(iter); | ||
| 1765 | } | ||
| 1766 | case TRACE_GRAPH_ENT: { | ||
| 1767 | return print_graph_function(iter); | ||
| 1768 | } | ||
| 1769 | case TRACE_BRANCH: { | ||
| 1770 | struct trace_branch *field; | ||
| 1771 | |||
| 1772 | trace_assign_type(field, entry); | ||
| 1773 | |||
| 1774 | trace_seq_printf(s, "[%s] %s:%s:%d\n", | ||
| 1775 | field->correct ? " ok " : " MISS ", | ||
| 1776 | field->func, | ||
| 1777 | field->file, | ||
| 1778 | field->line); | ||
| 1779 | break; | ||
| 1780 | } | 1592 | } |
| 1781 | case TRACE_USER_STACK: { | 1593 | ret = trace_seq_printf(s, "Unknown type %d\n", entry->type); |
| 1782 | struct userstack_entry *field; | 1594 | if (!ret) |
| 1783 | 1595 | return TRACE_TYPE_PARTIAL_LINE; | |
| 1784 | trace_assign_type(field, entry); | ||
| 1785 | 1596 | ||
| 1786 | ret = seq_print_userip_objs(field, s, sym_flags); | ||
| 1787 | if (!ret) | ||
| 1788 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1789 | ret = trace_seq_putc(s, '\n'); | ||
| 1790 | if (!ret) | ||
| 1791 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1792 | break; | ||
| 1793 | } | ||
| 1794 | } | ||
| 1795 | return TRACE_TYPE_HANDLED; | 1597 | return TRACE_TYPE_HANDLED; |
| 1796 | } | 1598 | } |
| 1797 | 1599 | ||
| @@ -1799,8 +1601,8 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter) | |||
| 1799 | { | 1601 | { |
| 1800 | struct trace_seq *s = &iter->seq; | 1602 | struct trace_seq *s = &iter->seq; |
| 1801 | struct trace_entry *entry; | 1603 | struct trace_entry *entry; |
| 1604 | struct trace_event *event; | ||
| 1802 | int ret; | 1605 | int ret; |
| 1803 | int S, T; | ||
| 1804 | 1606 | ||
| 1805 | entry = iter->ent; | 1607 | entry = iter->ent; |
| 1806 | 1608 | ||
| @@ -1809,86 +1611,26 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter) | |||
| 1809 | if (!ret) | 1611 | if (!ret) |
| 1810 | return TRACE_TYPE_PARTIAL_LINE; | 1612 | return TRACE_TYPE_PARTIAL_LINE; |
| 1811 | 1613 | ||
| 1812 | switch (entry->type) { | 1614 | event = ftrace_find_event(entry->type); |
| 1813 | case TRACE_FN: { | 1615 | if (event && event->raw) { |
| 1814 | struct ftrace_entry *field; | 1616 | ret = event->raw(s, entry, 0); |
| 1815 | 1617 | if (ret) | |
| 1816 | trace_assign_type(field, entry); | 1618 | return ret; |
| 1817 | 1619 | return TRACE_TYPE_HANDLED; | |
| 1818 | ret = trace_seq_printf(s, "%x %x\n", | ||
| 1819 | field->ip, | ||
| 1820 | field->parent_ip); | ||
| 1821 | if (!ret) | ||
| 1822 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1823 | break; | ||
| 1824 | } | ||
| 1825 | case TRACE_CTX: | ||
| 1826 | case TRACE_WAKE: { | ||
| 1827 | struct ctx_switch_entry *field; | ||
| 1828 | |||
| 1829 | trace_assign_type(field, entry); | ||
| 1830 | |||
| 1831 | T = task_state_char(field->next_state); | ||
| 1832 | S = entry->type == TRACE_WAKE ? '+' : | ||
| 1833 | task_state_char(field->prev_state); | ||
| 1834 | ret = trace_seq_printf(s, "%d %d %c %d %d %d %c\n", | ||
| 1835 | field->prev_pid, | ||
| 1836 | field->prev_prio, | ||
| 1837 | S, | ||
| 1838 | field->next_cpu, | ||
| 1839 | field->next_pid, | ||
| 1840 | field->next_prio, | ||
| 1841 | T); | ||
| 1842 | if (!ret) | ||
| 1843 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1844 | break; | ||
| 1845 | } | ||
| 1846 | case TRACE_SPECIAL: | ||
| 1847 | case TRACE_USER_STACK: | ||
| 1848 | case TRACE_STACK: { | ||
| 1849 | struct special_entry *field; | ||
| 1850 | |||
| 1851 | trace_assign_type(field, entry); | ||
| 1852 | |||
| 1853 | ret = trace_seq_printf(s, "# %ld %ld %ld\n", | ||
| 1854 | field->arg1, | ||
| 1855 | field->arg2, | ||
| 1856 | field->arg3); | ||
| 1857 | if (!ret) | ||
| 1858 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 1859 | break; | ||
| 1860 | } | 1620 | } |
| 1861 | case TRACE_PRINT: { | 1621 | ret = trace_seq_printf(s, "%d ?\n", entry->type); |
| 1862 | struct print_entry *field; | 1622 | if (!ret) |
| 1863 | 1623 | return TRACE_TYPE_PARTIAL_LINE; | |
| 1864 | trace_assign_type(field, entry); | ||
| 1865 | 1624 | ||
| 1866 | trace_seq_printf(s, "# %lx %s", field->ip, field->buf); | ||
| 1867 | break; | ||
| 1868 | } | ||
| 1869 | } | ||
| 1870 | return TRACE_TYPE_HANDLED; | 1625 | return TRACE_TYPE_HANDLED; |
| 1871 | } | 1626 | } |
| 1872 | 1627 | ||
| 1873 | #define SEQ_PUT_FIELD_RET(s, x) \ | ||
| 1874 | do { \ | ||
| 1875 | if (!trace_seq_putmem(s, &(x), sizeof(x))) \ | ||
| 1876 | return 0; \ | ||
| 1877 | } while (0) | ||
| 1878 | |||
| 1879 | #define SEQ_PUT_HEX_FIELD_RET(s, x) \ | ||
| 1880 | do { \ | ||
| 1881 | BUILD_BUG_ON(sizeof(x) > MAX_MEMHEX_BYTES); \ | ||
| 1882 | if (!trace_seq_putmem_hex(s, &(x), sizeof(x))) \ | ||
| 1883 | return 0; \ | ||
| 1884 | } while (0) | ||
| 1885 | |||
| 1886 | static enum print_line_t print_hex_fmt(struct trace_iterator *iter) | 1628 | static enum print_line_t print_hex_fmt(struct trace_iterator *iter) |
| 1887 | { | 1629 | { |
| 1888 | struct trace_seq *s = &iter->seq; | 1630 | struct trace_seq *s = &iter->seq; |
| 1889 | unsigned char newline = '\n'; | 1631 | unsigned char newline = '\n'; |
| 1890 | struct trace_entry *entry; | 1632 | struct trace_entry *entry; |
| 1891 | int S, T; | 1633 | struct trace_event *event; |
| 1892 | 1634 | ||
| 1893 | entry = iter->ent; | 1635 | entry = iter->ent; |
| 1894 | 1636 | ||
| @@ -1896,47 +1638,10 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter) | |||
| 1896 | SEQ_PUT_HEX_FIELD_RET(s, iter->cpu); | 1638 | SEQ_PUT_HEX_FIELD_RET(s, iter->cpu); |
| 1897 | SEQ_PUT_HEX_FIELD_RET(s, iter->ts); | 1639 | SEQ_PUT_HEX_FIELD_RET(s, iter->ts); |
| 1898 | 1640 | ||
| 1899 | switch (entry->type) { | 1641 | event = ftrace_find_event(entry->type); |
| 1900 | case TRACE_FN: { | 1642 | if (event && event->hex) |
| 1901 | struct ftrace_entry *field; | 1643 | event->hex(s, entry, 0); |
| 1902 | |||
| 1903 | trace_assign_type(field, entry); | ||
| 1904 | |||
| 1905 | SEQ_PUT_HEX_FIELD_RET(s, field->ip); | ||
| 1906 | SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip); | ||
| 1907 | break; | ||
| 1908 | } | ||
| 1909 | case TRACE_CTX: | ||
| 1910 | case TRACE_WAKE: { | ||
| 1911 | struct ctx_switch_entry *field; | ||
| 1912 | |||
| 1913 | trace_assign_type(field, entry); | ||
| 1914 | |||
| 1915 | T = task_state_char(field->next_state); | ||
| 1916 | S = entry->type == TRACE_WAKE ? '+' : | ||
| 1917 | task_state_char(field->prev_state); | ||
| 1918 | SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid); | ||
| 1919 | SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio); | ||
| 1920 | SEQ_PUT_HEX_FIELD_RET(s, S); | ||
| 1921 | SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu); | ||
| 1922 | SEQ_PUT_HEX_FIELD_RET(s, field->next_pid); | ||
| 1923 | SEQ_PUT_HEX_FIELD_RET(s, field->next_prio); | ||
| 1924 | SEQ_PUT_HEX_FIELD_RET(s, T); | ||
| 1925 | break; | ||
| 1926 | } | ||
| 1927 | case TRACE_SPECIAL: | ||
| 1928 | case TRACE_USER_STACK: | ||
| 1929 | case TRACE_STACK: { | ||
| 1930 | struct special_entry *field; | ||
| 1931 | |||
| 1932 | trace_assign_type(field, entry); | ||
| 1933 | 1644 | ||
| 1934 | SEQ_PUT_HEX_FIELD_RET(s, field->arg1); | ||
| 1935 | SEQ_PUT_HEX_FIELD_RET(s, field->arg2); | ||
| 1936 | SEQ_PUT_HEX_FIELD_RET(s, field->arg3); | ||
| 1937 | break; | ||
| 1938 | } | ||
| 1939 | } | ||
| 1940 | SEQ_PUT_FIELD_RET(s, newline); | 1645 | SEQ_PUT_FIELD_RET(s, newline); |
| 1941 | 1646 | ||
| 1942 | return TRACE_TYPE_HANDLED; | 1647 | return TRACE_TYPE_HANDLED; |
| @@ -1962,6 +1667,7 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter) | |||
| 1962 | { | 1667 | { |
| 1963 | struct trace_seq *s = &iter->seq; | 1668 | struct trace_seq *s = &iter->seq; |
| 1964 | struct trace_entry *entry; | 1669 | struct trace_entry *entry; |
| 1670 | struct trace_event *event; | ||
| 1965 | 1671 | ||
| 1966 | entry = iter->ent; | 1672 | entry = iter->ent; |
| 1967 | 1673 | ||
| @@ -1969,43 +1675,11 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter) | |||
| 1969 | SEQ_PUT_FIELD_RET(s, entry->cpu); | 1675 | SEQ_PUT_FIELD_RET(s, entry->cpu); |
| 1970 | SEQ_PUT_FIELD_RET(s, iter->ts); | 1676 | SEQ_PUT_FIELD_RET(s, iter->ts); |
| 1971 | 1677 | ||
| 1972 | switch (entry->type) { | 1678 | event = ftrace_find_event(entry->type); |
| 1973 | case TRACE_FN: { | 1679 | if (event && event->binary) |
| 1974 | struct ftrace_entry *field; | 1680 | event->binary(s, entry, 0); |
| 1975 | |||
| 1976 | trace_assign_type(field, entry); | ||
| 1977 | 1681 | ||
| 1978 | SEQ_PUT_FIELD_RET(s, field->ip); | 1682 | return TRACE_TYPE_HANDLED; |
| 1979 | SEQ_PUT_FIELD_RET(s, field->parent_ip); | ||
| 1980 | break; | ||
| 1981 | } | ||
| 1982 | case TRACE_CTX: { | ||
| 1983 | struct ctx_switch_entry *field; | ||
| 1984 | |||
| 1985 | trace_assign_type(field, entry); | ||
| 1986 | |||
| 1987 | SEQ_PUT_FIELD_RET(s, field->prev_pid); | ||
| 1988 | SEQ_PUT_FIELD_RET(s, field->prev_prio); | ||
| 1989 | SEQ_PUT_FIELD_RET(s, field->prev_state); | ||
| 1990 | SEQ_PUT_FIELD_RET(s, field->next_pid); | ||
| 1991 | SEQ_PUT_FIELD_RET(s, field->next_prio); | ||
| 1992 | SEQ_PUT_FIELD_RET(s, field->next_state); | ||
| 1993 | break; | ||
| 1994 | } | ||
| 1995 | case TRACE_SPECIAL: | ||
| 1996 | case TRACE_USER_STACK: | ||
| 1997 | case TRACE_STACK: { | ||
| 1998 | struct special_entry *field; | ||
| 1999 | |||
| 2000 | trace_assign_type(field, entry); | ||
| 2001 | |||
| 2002 | SEQ_PUT_FIELD_RET(s, field->arg1); | ||
| 2003 | SEQ_PUT_FIELD_RET(s, field->arg2); | ||
| 2004 | SEQ_PUT_FIELD_RET(s, field->arg3); | ||
| 2005 | break; | ||
| 2006 | } | ||
| 2007 | } | ||
| 2008 | return 1; | ||
| 2009 | } | 1683 | } |
| 2010 | 1684 | ||
| 2011 | static int trace_empty(struct trace_iterator *iter) | 1685 | static int trace_empty(struct trace_iterator *iter) |
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c index 6c00feb3bac7..c15222a01073 100644 --- a/kernel/trace/trace_branch.c +++ b/kernel/trace/trace_branch.c | |||
| @@ -14,7 +14,9 @@ | |||
| 14 | #include <linux/hash.h> | 14 | #include <linux/hash.h> |
| 15 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
| 16 | #include <asm/local.h> | 16 | #include <asm/local.h> |
| 17 | |||
| 17 | #include "trace.h" | 18 | #include "trace.h" |
| 19 | #include "trace_output.h" | ||
| 18 | 20 | ||
| 19 | #ifdef CONFIG_BRANCH_TRACER | 21 | #ifdef CONFIG_BRANCH_TRACER |
| 20 | 22 | ||
| @@ -142,6 +144,49 @@ static void branch_trace_reset(struct trace_array *tr) | |||
| 142 | stop_branch_trace(tr); | 144 | stop_branch_trace(tr); |
| 143 | } | 145 | } |
| 144 | 146 | ||
| 147 | static int | ||
| 148 | trace_print_print(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 149 | { | ||
| 150 | struct print_entry *field; | ||
| 151 | |||
| 152 | trace_assign_type(field, entry); | ||
| 153 | |||
| 154 | if (seq_print_ip_sym(s, field->ip, flags)) | ||
| 155 | goto partial; | ||
| 156 | |||
| 157 | if (trace_seq_printf(s, ": %s", field->buf)) | ||
| 158 | goto partial; | ||
| 159 | |||
| 160 | partial: | ||
| 161 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 162 | } | ||
| 163 | |||
| 164 | static int | ||
| 165 | trace_branch_print(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 166 | { | ||
| 167 | struct trace_branch *field; | ||
| 168 | |||
| 169 | trace_assign_type(field, entry); | ||
| 170 | |||
| 171 | if (trace_seq_printf(s, "[%s] %s:%s:%d\n", | ||
| 172 | field->correct ? " ok " : " MISS ", | ||
| 173 | field->func, | ||
| 174 | field->file, | ||
| 175 | field->line)) | ||
| 176 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 177 | |||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | static struct trace_event trace_branch_event = { | ||
| 182 | .type = TRACE_BRANCH, | ||
| 183 | .trace = trace_branch_print, | ||
| 184 | .latency_trace = trace_branch_print, | ||
| 185 | .raw = trace_nop_print, | ||
| 186 | .hex = trace_nop_print, | ||
| 187 | .binary = trace_nop_print, | ||
| 188 | }; | ||
| 189 | |||
| 145 | struct tracer branch_trace __read_mostly = | 190 | struct tracer branch_trace __read_mostly = |
| 146 | { | 191 | { |
| 147 | .name = "branch", | 192 | .name = "branch", |
| @@ -154,6 +199,14 @@ struct tracer branch_trace __read_mostly = | |||
| 154 | 199 | ||
| 155 | __init static int init_branch_trace(void) | 200 | __init static int init_branch_trace(void) |
| 156 | { | 201 | { |
| 202 | int ret; | ||
| 203 | |||
| 204 | ret = register_ftrace_event(&trace_branch_event); | ||
| 205 | if (!ret) { | ||
| 206 | printk(KERN_WARNING "Warning: could not register branch events\n"); | ||
| 207 | return 1; | ||
| 208 | } | ||
| 209 | |||
| 157 | return register_tracer(&branch_trace); | 210 | return register_tracer(&branch_trace); |
| 158 | } | 211 | } |
| 159 | 212 | ||
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 1f3f80002b5e..df0c25cbed30 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
| @@ -286,6 +286,15 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags) | |||
| 286 | return ret; | 286 | return ret; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; | ||
| 290 | |||
| 291 | static int task_state_char(unsigned long state) | ||
| 292 | { | ||
| 293 | int bit = state ? __ffs(state) + 1 : 0; | ||
| 294 | |||
| 295 | return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?'; | ||
| 296 | } | ||
| 297 | |||
| 289 | /** | 298 | /** |
| 290 | * ftrace_find_event - find a registered event | 299 | * ftrace_find_event - find a registered event |
| 291 | * @type: the type of event to look for | 300 | * @type: the type of event to look for |
| @@ -363,3 +372,461 @@ int unregister_ftrace_event(struct trace_event *event) | |||
| 363 | 372 | ||
| 364 | return 0; | 373 | return 0; |
| 365 | } | 374 | } |
| 375 | |||
| 376 | /* | ||
| 377 | * Standard events | ||
| 378 | */ | ||
| 379 | |||
| 380 | int | ||
| 381 | trace_nop_print(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 382 | { | ||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | /* TRACE_FN */ | ||
| 387 | static int | ||
| 388 | trace_fn_latency(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 389 | { | ||
| 390 | struct ftrace_entry *field; | ||
| 391 | |||
| 392 | trace_assign_type(field, entry); | ||
| 393 | |||
| 394 | if (!seq_print_ip_sym(s, field->ip, flags)) | ||
| 395 | goto partial; | ||
| 396 | if (!trace_seq_puts(s, " (")) | ||
| 397 | goto partial; | ||
| 398 | if (!seq_print_ip_sym(s, field->parent_ip, flags)) | ||
| 399 | goto partial; | ||
| 400 | if (!trace_seq_puts(s, ")\n")) | ||
| 401 | goto partial; | ||
| 402 | |||
| 403 | return 0; | ||
| 404 | |||
| 405 | partial: | ||
| 406 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 407 | } | ||
| 408 | |||
| 409 | static int | ||
| 410 | trace_fn_trace(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 411 | { | ||
| 412 | struct ftrace_entry *field; | ||
| 413 | |||
| 414 | trace_assign_type(field, entry); | ||
| 415 | |||
| 416 | if (!seq_print_ip_sym(s, field->ip, flags)) | ||
| 417 | goto partial; | ||
| 418 | |||
| 419 | if ((flags & TRACE_ITER_PRINT_PARENT) && field->parent_ip) { | ||
| 420 | if (!trace_seq_printf(s, " <-")) | ||
| 421 | goto partial; | ||
| 422 | if (!seq_print_ip_sym(s, | ||
| 423 | field->parent_ip, | ||
| 424 | flags)) | ||
| 425 | goto partial; | ||
| 426 | } | ||
| 427 | if (!trace_seq_printf(s, "\n")) | ||
| 428 | goto partial; | ||
| 429 | |||
| 430 | return 0; | ||
| 431 | |||
| 432 | partial: | ||
| 433 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 434 | } | ||
| 435 | |||
| 436 | static int | ||
| 437 | trace_fn_raw(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 438 | { | ||
| 439 | struct ftrace_entry *field; | ||
| 440 | |||
| 441 | trace_assign_type(field, entry); | ||
| 442 | |||
| 443 | if (trace_seq_printf(s, "%x %x\n", | ||
| 444 | field->ip, | ||
| 445 | field->parent_ip)) | ||
| 446 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 447 | |||
| 448 | return 0; | ||
| 449 | } | ||
| 450 | |||
| 451 | static int | ||
| 452 | trace_fn_hex(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 453 | { | ||
| 454 | struct ftrace_entry *field; | ||
| 455 | |||
| 456 | trace_assign_type(field, entry); | ||
| 457 | |||
| 458 | SEQ_PUT_HEX_FIELD_RET(s, field->ip); | ||
| 459 | SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip); | ||
| 460 | |||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | static int | ||
| 465 | trace_fn_bin(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 466 | { | ||
| 467 | struct ftrace_entry *field; | ||
| 468 | |||
| 469 | trace_assign_type(field, entry); | ||
| 470 | |||
| 471 | SEQ_PUT_FIELD_RET(s, field->ip); | ||
| 472 | SEQ_PUT_FIELD_RET(s, field->parent_ip); | ||
| 473 | |||
| 474 | return 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | static struct trace_event trace_fn_event = { | ||
| 478 | .type = TRACE_FN, | ||
| 479 | .trace = trace_fn_trace, | ||
| 480 | .latency_trace = trace_fn_latency, | ||
| 481 | .raw = trace_fn_raw, | ||
| 482 | .hex = trace_fn_hex, | ||
| 483 | .binary = trace_fn_bin, | ||
| 484 | }; | ||
| 485 | |||
| 486 | /* TRACE_CTX an TRACE_WAKE */ | ||
| 487 | static int | ||
| 488 | trace_ctxwake_print(struct trace_seq *s, struct trace_entry *entry, int flags, | ||
| 489 | char *delim) | ||
| 490 | { | ||
| 491 | struct ctx_switch_entry *field; | ||
| 492 | char *comm; | ||
| 493 | int S, T; | ||
| 494 | |||
| 495 | trace_assign_type(field, entry); | ||
| 496 | |||
| 497 | T = task_state_char(field->next_state); | ||
| 498 | S = task_state_char(field->prev_state); | ||
| 499 | comm = trace_find_cmdline(field->next_pid); | ||
| 500 | if (trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n", | ||
| 501 | field->prev_pid, | ||
| 502 | field->prev_prio, | ||
| 503 | S, delim, | ||
| 504 | field->next_cpu, | ||
| 505 | field->next_pid, | ||
| 506 | field->next_prio, | ||
| 507 | T, comm)) | ||
| 508 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 509 | |||
| 510 | return 0; | ||
| 511 | } | ||
| 512 | |||
| 513 | static int | ||
| 514 | trace_ctx_print(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 515 | { | ||
| 516 | return trace_ctxwake_print(s, entry, flags, "==>"); | ||
| 517 | } | ||
| 518 | |||
| 519 | static int | ||
| 520 | trace_wake_print(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 521 | { | ||
| 522 | return trace_ctxwake_print(s, entry, flags, " +"); | ||
| 523 | } | ||
| 524 | |||
| 525 | static int | ||
| 526 | trace_ctxwake_raw(struct trace_seq *s, struct trace_entry *entry, int flags, | ||
| 527 | char S) | ||
| 528 | { | ||
| 529 | struct ctx_switch_entry *field; | ||
| 530 | int T; | ||
| 531 | |||
| 532 | trace_assign_type(field, entry); | ||
| 533 | |||
| 534 | if (!S) | ||
| 535 | task_state_char(field->prev_state); | ||
| 536 | T = task_state_char(field->next_state); | ||
| 537 | if (trace_seq_printf(s, "%d %d %c %d %d %d %c\n", | ||
| 538 | field->prev_pid, | ||
| 539 | field->prev_prio, | ||
| 540 | S, | ||
| 541 | field->next_cpu, | ||
| 542 | field->next_pid, | ||
| 543 | field->next_prio, | ||
| 544 | T)) | ||
| 545 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 546 | |||
| 547 | return 0; | ||
| 548 | } | ||
| 549 | |||
| 550 | static int | ||
| 551 | trace_ctx_raw(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 552 | { | ||
| 553 | return trace_ctxwake_raw(s, entry, flags, 0); | ||
| 554 | } | ||
| 555 | |||
| 556 | static int | ||
| 557 | trace_wake_raw(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 558 | { | ||
| 559 | return trace_ctxwake_raw(s, entry, flags, '+'); | ||
| 560 | } | ||
| 561 | |||
| 562 | |||
| 563 | static int | ||
| 564 | trace_ctxwake_hex(struct trace_seq *s, struct trace_entry *entry, int flags, | ||
| 565 | char S) | ||
| 566 | { | ||
| 567 | struct ctx_switch_entry *field; | ||
| 568 | int T; | ||
| 569 | |||
| 570 | trace_assign_type(field, entry); | ||
| 571 | |||
| 572 | if (!S) | ||
| 573 | task_state_char(field->prev_state); | ||
| 574 | T = task_state_char(field->next_state); | ||
| 575 | |||
| 576 | SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid); | ||
| 577 | SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio); | ||
| 578 | SEQ_PUT_HEX_FIELD_RET(s, S); | ||
| 579 | SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu); | ||
| 580 | SEQ_PUT_HEX_FIELD_RET(s, field->next_pid); | ||
| 581 | SEQ_PUT_HEX_FIELD_RET(s, field->next_prio); | ||
| 582 | SEQ_PUT_HEX_FIELD_RET(s, T); | ||
| 583 | |||
| 584 | return 0; | ||
| 585 | } | ||
| 586 | |||
| 587 | static int | ||
| 588 | trace_ctx_hex(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 589 | { | ||
| 590 | return trace_ctxwake_hex(s, entry, flags, 0); | ||
| 591 | } | ||
| 592 | |||
| 593 | static int | ||
| 594 | trace_wake_hex(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 595 | { | ||
| 596 | return trace_ctxwake_hex(s, entry, flags, '+'); | ||
| 597 | } | ||
| 598 | |||
| 599 | static int | ||
| 600 | trace_ctxwake_bin(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 601 | { | ||
| 602 | struct ctx_switch_entry *field; | ||
| 603 | |||
| 604 | trace_assign_type(field, entry); | ||
| 605 | |||
| 606 | SEQ_PUT_FIELD_RET(s, field->prev_pid); | ||
| 607 | SEQ_PUT_FIELD_RET(s, field->prev_prio); | ||
| 608 | SEQ_PUT_FIELD_RET(s, field->prev_state); | ||
| 609 | SEQ_PUT_FIELD_RET(s, field->next_pid); | ||
| 610 | SEQ_PUT_FIELD_RET(s, field->next_prio); | ||
| 611 | SEQ_PUT_FIELD_RET(s, field->next_state); | ||
| 612 | |||
| 613 | return 0; | ||
| 614 | } | ||
| 615 | |||
| 616 | static struct trace_event trace_ctx_event = { | ||
| 617 | .type = TRACE_CTX, | ||
| 618 | .trace = trace_ctx_print, | ||
| 619 | .latency_trace = trace_ctx_print, | ||
| 620 | .raw = trace_ctx_raw, | ||
| 621 | .hex = trace_ctx_hex, | ||
| 622 | .binary = trace_ctxwake_bin, | ||
| 623 | }; | ||
| 624 | |||
| 625 | static struct trace_event trace_wake_event = { | ||
| 626 | .type = TRACE_WAKE, | ||
| 627 | .trace = trace_wake_print, | ||
| 628 | .latency_trace = trace_wake_print, | ||
| 629 | .raw = trace_wake_raw, | ||
| 630 | .hex = trace_wake_hex, | ||
| 631 | .binary = trace_ctxwake_bin, | ||
| 632 | }; | ||
| 633 | |||
| 634 | /* TRACE_SPECIAL */ | ||
| 635 | static int | ||
| 636 | trace_special_print(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 637 | { | ||
| 638 | struct special_entry *field; | ||
| 639 | |||
| 640 | trace_assign_type(field, entry); | ||
| 641 | |||
| 642 | if (trace_seq_printf(s, "# %ld %ld %ld\n", | ||
| 643 | field->arg1, | ||
| 644 | field->arg2, | ||
| 645 | field->arg3)) | ||
| 646 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 647 | |||
| 648 | return 0; | ||
| 649 | } | ||
| 650 | |||
| 651 | static int | ||
| 652 | trace_special_hex(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 653 | { | ||
| 654 | struct special_entry *field; | ||
| 655 | |||
| 656 | trace_assign_type(field, entry); | ||
| 657 | |||
| 658 | SEQ_PUT_HEX_FIELD_RET(s, field->arg1); | ||
| 659 | SEQ_PUT_HEX_FIELD_RET(s, field->arg2); | ||
| 660 | SEQ_PUT_HEX_FIELD_RET(s, field->arg3); | ||
| 661 | |||
| 662 | return 0; | ||
| 663 | } | ||
| 664 | |||
| 665 | static int | ||
| 666 | trace_special_bin(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 667 | { | ||
| 668 | struct special_entry *field; | ||
| 669 | |||
| 670 | trace_assign_type(field, entry); | ||
| 671 | |||
| 672 | SEQ_PUT_FIELD_RET(s, field->arg1); | ||
| 673 | SEQ_PUT_FIELD_RET(s, field->arg2); | ||
| 674 | SEQ_PUT_FIELD_RET(s, field->arg3); | ||
| 675 | |||
| 676 | return 0; | ||
| 677 | } | ||
| 678 | |||
| 679 | static struct trace_event trace_special_event = { | ||
| 680 | .type = TRACE_SPECIAL, | ||
| 681 | .trace = trace_special_print, | ||
| 682 | .latency_trace = trace_special_print, | ||
| 683 | .raw = trace_special_print, | ||
| 684 | .hex = trace_special_hex, | ||
| 685 | .binary = trace_special_bin, | ||
| 686 | }; | ||
| 687 | |||
| 688 | /* TRACE_STACK */ | ||
| 689 | |||
| 690 | static int | ||
| 691 | trace_stack_print(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 692 | { | ||
| 693 | struct stack_entry *field; | ||
| 694 | int i; | ||
| 695 | |||
| 696 | trace_assign_type(field, entry); | ||
| 697 | |||
| 698 | for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { | ||
| 699 | if (i) { | ||
| 700 | if (trace_seq_puts(s, " <= ")) | ||
| 701 | goto partial; | ||
| 702 | |||
| 703 | if (seq_print_ip_sym(s, field->caller[i], flags)) | ||
| 704 | goto partial; | ||
| 705 | } | ||
| 706 | if (trace_seq_puts(s, "\n")) | ||
| 707 | goto partial; | ||
| 708 | } | ||
| 709 | |||
| 710 | return 0; | ||
| 711 | |||
| 712 | partial: | ||
| 713 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 714 | } | ||
| 715 | |||
| 716 | static struct trace_event trace_stack_event = { | ||
| 717 | .type = TRACE_STACK, | ||
| 718 | .trace = trace_stack_print, | ||
| 719 | .latency_trace = trace_stack_print, | ||
| 720 | .raw = trace_special_print, | ||
| 721 | .hex = trace_special_hex, | ||
| 722 | .binary = trace_special_bin, | ||
| 723 | }; | ||
| 724 | |||
| 725 | /* TRACE_USER_STACK */ | ||
| 726 | static int | ||
| 727 | trace_user_stack_print(struct trace_seq *s, struct trace_entry *entry, | ||
| 728 | int flags) | ||
| 729 | { | ||
| 730 | struct userstack_entry *field; | ||
| 731 | |||
| 732 | trace_assign_type(field, entry); | ||
| 733 | |||
| 734 | if (seq_print_userip_objs(field, s, flags)) | ||
| 735 | goto partial; | ||
| 736 | |||
| 737 | if (trace_seq_putc(s, '\n')) | ||
| 738 | goto partial; | ||
| 739 | |||
| 740 | return 0; | ||
| 741 | |||
| 742 | partial: | ||
| 743 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 744 | } | ||
| 745 | |||
| 746 | static struct trace_event trace_user_stack_event = { | ||
| 747 | .type = TRACE_USER_STACK, | ||
| 748 | .trace = trace_user_stack_print, | ||
| 749 | .latency_trace = trace_user_stack_print, | ||
| 750 | .raw = trace_special_print, | ||
| 751 | .hex = trace_special_hex, | ||
| 752 | .binary = trace_special_bin, | ||
| 753 | }; | ||
| 754 | |||
| 755 | /* TRACE_PRINT */ | ||
| 756 | static int | ||
| 757 | trace_print_print(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 758 | { | ||
| 759 | struct print_entry *field; | ||
| 760 | |||
| 761 | trace_assign_type(field, entry); | ||
| 762 | |||
| 763 | if (seq_print_ip_sym(s, field->ip, flags)) | ||
| 764 | goto partial; | ||
| 765 | |||
| 766 | if (trace_seq_printf(s, ": %s", field->buf)) | ||
| 767 | goto partial; | ||
| 768 | |||
| 769 | return 0; | ||
| 770 | |||
| 771 | partial: | ||
| 772 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 773 | } | ||
| 774 | |||
| 775 | static int | ||
| 776 | trace_print_raw(struct trace_seq *s, struct trace_entry *entry, int flags) | ||
| 777 | { | ||
| 778 | struct print_entry *field; | ||
| 779 | |||
| 780 | trace_assign_type(field, entry); | ||
| 781 | |||
| 782 | if (seq_print_ip_sym(s, field->ip, flags)) | ||
| 783 | goto partial; | ||
| 784 | |||
| 785 | if (trace_seq_printf(s, "# %lx %s", field->ip, field->buf)) | ||
| 786 | goto partial; | ||
| 787 | |||
| 788 | return 0; | ||
| 789 | |||
| 790 | partial: | ||
| 791 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 792 | } | ||
| 793 | |||
| 794 | static struct trace_event trace_print_event = { | ||
| 795 | .type = TRACE_PRINT, | ||
| 796 | .trace = trace_print_print, | ||
| 797 | .latency_trace = trace_print_print, | ||
| 798 | .raw = trace_print_raw, | ||
| 799 | .hex = trace_nop_print, | ||
| 800 | .binary = trace_nop_print, | ||
| 801 | }; | ||
| 802 | |||
| 803 | static struct trace_event *events[] __initdata = { | ||
| 804 | &trace_fn_event, | ||
| 805 | &trace_ctx_event, | ||
| 806 | &trace_wake_event, | ||
| 807 | &trace_special_event, | ||
| 808 | &trace_stack_event, | ||
| 809 | &trace_user_stack_event, | ||
| 810 | &trace_print_event, | ||
| 811 | NULL | ||
| 812 | }; | ||
| 813 | |||
| 814 | __init static int init_events(void) | ||
| 815 | { | ||
| 816 | struct trace_event *event; | ||
| 817 | int i, ret; | ||
| 818 | |||
| 819 | for (i = 0; events[i]; i++) { | ||
| 820 | event = events[i]; | ||
| 821 | |||
| 822 | ret = register_ftrace_event(event); | ||
| 823 | if (!ret) { | ||
| 824 | printk(KERN_WARNING "event %d failed to register\n", | ||
| 825 | event->type); | ||
| 826 | WARN_ON_ONCE(1); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 830 | return 0; | ||
| 831 | } | ||
| 832 | device_initcall(init_events); | ||
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h index 1fcc76e1378e..ecab4ea4a4fd 100644 --- a/kernel/trace/trace_output.h +++ b/kernel/trace/trace_output.h | |||
| @@ -36,8 +36,24 @@ struct trace_event *ftrace_find_event(int type); | |||
| 36 | int register_ftrace_event(struct trace_event *event); | 36 | int register_ftrace_event(struct trace_event *event); |
| 37 | int unregister_ftrace_event(struct trace_event *event); | 37 | int unregister_ftrace_event(struct trace_event *event); |
| 38 | 38 | ||
| 39 | int | ||
| 40 | trace_nop_print(struct trace_seq *s, struct trace_entry *entry, int flags); | ||
| 41 | |||
| 39 | #define MAX_MEMHEX_BYTES 8 | 42 | #define MAX_MEMHEX_BYTES 8 |
| 40 | #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) | 43 | #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) |
| 41 | 44 | ||
| 45 | #define SEQ_PUT_FIELD_RET(s, x) \ | ||
| 46 | do { \ | ||
| 47 | if (!trace_seq_putmem(s, &(x), sizeof(x))) \ | ||
| 48 | return 0; \ | ||
| 49 | } while (0) | ||
| 50 | |||
| 51 | #define SEQ_PUT_HEX_FIELD_RET(s, x) \ | ||
| 52 | do { \ | ||
| 53 | BUILD_BUG_ON(sizeof(x) > MAX_MEMHEX_BYTES); \ | ||
| 54 | if (!trace_seq_putmem_hex(s, &(x), sizeof(x))) \ | ||
| 55 | return 0; \ | ||
| 56 | } while (0) | ||
| 57 | |||
| 42 | #endif | 58 | #endif |
| 43 | 59 | ||
