History

Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf updates from Ingo Molnar: "Kernel side changes: - Ftrace is one of the last W^X violators (after this only KLP is left). These patches move it over to the generic text_poke() interface and thereby get rid of this oddity. This requires a surprising amount of surgery, by Peter Zijlstra. - x86/AMD PMUs: add support for 'Large Increment per Cycle Events' to count certain types of events that have a special, quirky hw ABI (by Kim Phillips) - kprobes fixes by Masami Hiramatsu Lots of tooling updates as well, the following subcommands were updated: annotate/report/top, c2c, clang, record, report/top TUI, sched timehist, tests; plus updates were done to the gtk ui, libperf, headers and the parser" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (57 commits) perf/x86/amd: Add support for Large Increment per Cycle Events perf/x86/amd: Constrain Large Increment per Cycle events perf/x86/intel/rapl: Add Comet Lake support tracing: Initialize ret in syscall_enter_define_fields() perf header: Use last modification time for timestamp perf c2c: Fix return type for histogram sorting comparision functions perf beauty sockaddr: Fix augmented syscall format warning perf/ui/gtk: Fix gtk2 build perf ui gtk: Add missing zalloc object perf tools: Use %define api.pure full instead of %pure-parser libperf: Setup initial evlist::all_cpus value perf report: Fix no libunwind compiled warning break s390 issue perf tools: Support --prefix/--prefix-strip perf report: Clarify in help that --children is default tools build: Fix test-clang.cpp with Clang 8+ perf clang: Fix build with Clang 9 kprobes: Fix optimize_kprobe()/unoptimize_kprobe() cancellation logic tools lib: Fix builds when glibc contains strlcpy() perf report/top: Make 'e' visible in the help and make it toggle showing callchains perf report/top: Do not offer annotation for symbols without samples ...

Linus Torvalds committed 6 years ago

Commit c0e809e2 parents 2180f21 0cc4bd8128 files · +2515 −1591Browse files

Unified · Split

128 files
  1. arch/arm/kernel/Makefile +2 −2
  2. arch/arm/kernel/ftrace.c +2 −8
  3. arch/nds32/kernel/ftrace.c +0 −12
  4. arch/x86/events/amd/core.c +79 −30
  5. arch/x86/events/core.c +59 −15
  6. arch/x86/events/intel/rapl.c +2 −0
  7. arch/x86/events/perf_event.h +20 −0
  8. arch/x86/include/asm/ftrace.h +0 −2
  9. arch/x86/include/asm/kprobes.h +5 −9
  10. arch/x86/include/asm/set_memory.h +0 −2
  11. arch/x86/include/asm/text-patching.h +67 −19
  12. arch/x86/kernel/alternative.c +150 −48
  13. arch/x86/kernel/ftrace.c +126 −562
  14. arch/x86/kernel/jump_label.c +38 −78
  15. arch/x86/kernel/kprobes/core.c +11 −9
  16. arch/x86/kernel/kprobes/opt.c +33 −34
  17. arch/x86/kernel/traps.c +0 −9
  18. arch/x86/mm/init_32.c +0 −28
  19. arch/x86/mm/init_64.c +0 −36
  20. drivers/infiniband/hw/hfi1/trace_tid.h +4 −4
  21. drivers/infiniband/hw/hfi1/trace_tx.h +1 −1
  22. drivers/lightnvm/pblk-trace.h +4 −4
  23. drivers/net/fjes/fjes_trace.h +1 −1
  24. drivers/net/wireless/ath/ath10k/trace.h +3 −3
  25. fs/xfs/scrub/trace.h +3 −3
  26. fs/xfs/xfs_trace.h +2 −2
  27. include/linux/module.h +0 −4
  28. include/linux/trace_events.h +17 −1
  29. include/trace/events/filemap.h +1 −1
  30. include/trace/trace_events.h +21 −43
  31. kernel/kprobes.c +46 −25
  32. kernel/module.c +0 −43
  33. kernel/trace/trace.h +14 −17
  34. kernel/trace/trace_entries.h +18 −48
  35. kernel/trace/trace_events.c +19 −1
  36. kernel/trace/trace_events_hist.c +7 −1
  37. kernel/trace/trace_export.c +39 −67
  38. kernel/trace/trace_kprobe.c +14 −2
  39. kernel/trace/trace_syscalls.c +21 −30
  40. kernel/trace/trace_uprobe.c +7 −2
  41. net/mac80211/trace.h +14 −14
  42. net/wireless/trace.h +3 −3
  43. tools/build/feature/Makefile +1 −1
  44. tools/build/feature/test-clang.cpp +6 −0
  45. tools/include/linux/bitmap.h +30 −0
  46. tools/include/linux/string.h +8 −0
  47. tools/lib/api/fs/fs.c +3 −1
  48. tools/lib/bitmap.c +15 −0
  49. tools/lib/perf/Build +0 −0
  50. tools/lib/perf/Documentation/Makefile +156 −0
  51. tools/lib/perf/Documentation/asciidoc.conf +120 −0
  52. tools/lib/perf/Documentation/examples/sampling.c +119 −0
  53. tools/lib/perf/Documentation/libperf-counting.txt +211 −0
  54. tools/lib/perf/Documentation/libperf-sampling.txt +243 −0
  55. tools/lib/perf/Documentation/libperf.txt +246 −0
  56. tools/lib/perf/Documentation/manpage-1.72.xsl +14 −0
  57. tools/lib/perf/Documentation/manpage-base.xsl +35 −0
  58. tools/lib/perf/Documentation/manpage-bold-literal.xsl +17 −0
  59. tools/lib/perf/Documentation/manpage-normal.xsl +13 −0
  60. tools/lib/perf/Documentation/manpage-suppress-sp.xsl +21 −0
  61. tools/lib/perf/Makefile +5 −2
  62. tools/lib/perf/core.c +0 −0
  63. tools/lib/perf/cpumap.c +0 −0
  64. tools/lib/perf/evlist.c +3 −0
  65. tools/lib/perf/evsel.c +0 −0
  66. tools/lib/perf/include/internal/cpumap.h +0 −0
  67. tools/lib/perf/include/internal/evlist.h +0 −0
  68. tools/lib/perf/include/internal/evsel.h +0 −0
  69. tools/lib/perf/include/internal/lib.h +0 −0
  70. tools/lib/perf/include/internal/mmap.h +0 −0
  71. tools/lib/perf/include/internal/tests.h +0 −0
  72. tools/lib/perf/include/internal/threadmap.h +0 −0
  73. tools/lib/perf/include/internal/xyarray.h +0 −0
  74. tools/lib/perf/include/perf/core.h +0 −0
  75. tools/lib/perf/include/perf/cpumap.h +0 −0
  76. tools/lib/perf/include/perf/event.h +0 −0
  77. tools/lib/perf/include/perf/evlist.h +0 −0
  78. tools/lib/perf/include/perf/evsel.h +0 −0
  79. tools/lib/perf/include/perf/mmap.h +0 −0
  80. tools/lib/perf/include/perf/threadmap.h +0 −0
  81. tools/lib/perf/internal.h +0 −0
  82. tools/lib/perf/lib.c +0 −0
  83. tools/lib/perf/libperf.map +0 −0
  84. tools/lib/perf/libperf.pc.template +0 −0
  85. tools/lib/perf/mmap.c +0 −0
  86. tools/lib/perf/tests/Makefile +1 −1
  87. tools/lib/perf/tests/test-cpumap.c +0 −0
  88. tools/lib/perf/tests/test-evlist.c +0 −0
  89. tools/lib/perf/tests/test-evsel.c +0 −0
  90. tools/lib/perf/tests/test-threadmap.c +0 −0
  91. tools/lib/perf/threadmap.c +0 −0
  92. tools/lib/perf/xyarray.c +0 −0
  93. tools/lib/string.c +7 −0
  94. tools/perf/Documentation/perf-annotate.txt +6 −0
  95. tools/perf/Documentation/perf-report.txt +6 −0
  96. tools/perf/Documentation/perf-sched.txt +4 −0
  97. tools/perf/Documentation/perf-top.txt +6 −0
  98. tools/perf/MANIFEST +1 −0
  99. tools/perf/Makefile.config +1 −1
  100. tools/perf/Makefile.perf +1 −1
  101. tools/perf/builtin-annotate.c +7 −0
  102. tools/perf/builtin-c2c.c +8 −6
  103. tools/perf/builtin-record.c +22 −6
  104. tools/perf/builtin-report.c +12 −4
  105. tools/perf/builtin-sched.c +13 −0
  106. tools/perf/builtin-top.c +7 −0
  107. tools/perf/lib/Documentation/Makefile +0 −7
  108. tools/perf/lib/Documentation/man/libperf.rst +0 −100
  109. tools/perf/lib/Documentation/tutorial/tutorial.rst +0 −123
  110. tools/perf/tests/bp_signal.c +5 −5
  111. tools/perf/trace/beauty/sockaddr.c +1 −1
  112. tools/perf/ui/browsers/hists.c +191 −86
  113. tools/perf/ui/browsers/hists.h +1 −1
  114. tools/perf/ui/browsers/res_sample.c +1 −1
  115. tools/perf/ui/browsers/scripts.c +1 −1
  116. tools/perf/ui/gtk/Build +6 −1
  117. tools/perf/ui/tui/util.c +8 −4
  118. tools/perf/ui/util.h +1 −1
  119. tools/perf/util/annotate.c +17 −2
  120. tools/perf/util/annotate.h +5 −0
  121. tools/perf/util/c++/clang.cpp +4 −0
  122. tools/perf/util/expr.y +2 −1
  123. tools/perf/util/header.c +1 −1
  124. tools/perf/util/mmap.c +34 −6
  125. tools/perf/util/mmap.h +12 −1
  126. tools/perf/util/parse-events.y +1 −1
  127. tools/perf/util/sort.c +1 −2
  128. tools/perf/util/sort.h +2 −0
arch/arm/kernel/Makefile+2−2
@@ -53,8 +53,8 @@ obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o · 52 unmodified lines
53obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o53obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
54obj-$(CONFIG_ARM_ARCH_TIMER) += arch_timer.o54obj-$(CONFIG_ARM_ARCH_TIMER) += arch_timer.o
55obj-$(CONFIG_FUNCTION_TRACER) += entry-ftrace.o55obj-$(CONFIG_FUNCTION_TRACER) += entry-ftrace.o
56obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o56obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o patch.o
57obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o57obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o patch.o
58obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o58obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o
59obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o59obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
60# Main staffs in KPROBES are in arch/arm/probes/ .60# Main staffs in KPROBES are in arch/arm/probes/ .
arch/arm/kernel/ftrace.c+2−8
@@ -22,6 +22,7 @@ · 21 unmodified lines
22#include <asm/ftrace.h>22#include <asm/ftrace.h>
23#include <asm/insn.h>23#include <asm/insn.h>
24#include <asm/set_memory.h>24#include <asm/set_memory.h>
25#include <asm/patch.h>
25 26
26#ifdef CONFIG_THUMB2_KERNEL27#ifdef CONFIG_THUMB2_KERNEL
27#define NOP 0xf85deb04 /* pop.w {lr} */28#define NOP 0xf85deb04 /* pop.w {lr} */
@@ -35,9 +36,7 @@ static int __ftrace_modify_code(void *data) · 7 unmodified lines
35{36{
36 int *command = data;37 int *command = data;
37 38
38 set_kernel_text_rw();
39 ftrace_modify_all_code(*command);39 ftrace_modify_all_code(*command);
40 set_kernel_text_ro();
41 40
42 return 0;41 return 0;
43}42}
@@ -59,13 +58,11 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) · 15 unmodified lines
59 58
60int ftrace_arch_code_modify_prepare(void)59int ftrace_arch_code_modify_prepare(void)
61{60{
62 set_all_modules_text_rw();
63 return 0;61 return 0;
64}62}
65 63
66int ftrace_arch_code_modify_post_process(void)64int ftrace_arch_code_modify_post_process(void)
67{65{
68 set_all_modules_text_ro();
69 /* Make sure any TLB misses during machine stop are cleared. */66 /* Make sure any TLB misses during machine stop are cleared. */
70 flush_tlb_all();67 flush_tlb_all();
71 return 0;68 return 0;
@@ -97,10 +94,7 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old, · 25 unmodified lines
97 return -EINVAL;94 return -EINVAL;
98 }95 }
99 96
100 if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE))97 __patch_text((void *)pc, new);
101 return -EPERM;
102
103 flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
104 98
105 return 0;99 return 0;
106}100}
arch/nds32/kernel/ftrace.c+0−12
@@ -89,18 +89,6 @@ int __init ftrace_dyn_arch_init(void) · 88 unmodified lines
89 return 0;89 return 0;
90}90}
91 91
92int ftrace_arch_code_modify_prepare(void)
93{
94 set_all_modules_text_rw();
95 return 0;
96}
97
98int ftrace_arch_code_modify_post_process(void)
99{
100 set_all_modules_text_ro();
101 return 0;
102}
103
104static unsigned long gen_sethi_insn(unsigned long addr)92static unsigned long gen_sethi_insn(unsigned long addr)
105{93{
106 unsigned long opcode = 0x46000000;94 unsigned long opcode = 0x46000000;
arch/x86/events/amd/core.c+79−30
@@ -14,6 +14,10 @@ · 13 unmodified lines
14static DEFINE_PER_CPU(unsigned long, perf_nmi_tstamp);14static DEFINE_PER_CPU(unsigned long, perf_nmi_tstamp);
15static unsigned long perf_nmi_window;15static unsigned long perf_nmi_window;
16 16
17/* AMD Event 0xFFF: Merge. Used with Large Increment per Cycle events */
18#define AMD_MERGE_EVENT ((0xFULL << 32) | 0xFFULL)
19#define AMD_MERGE_EVENT_ENABLE (AMD_MERGE_EVENT | ARCH_PERFMON_EVENTSEL_ENABLE)
20
17static __initconst const u64 amd_hw_cache_event_ids21static __initconst const u64 amd_hw_cache_event_ids
18 [PERF_COUNT_HW_CACHE_MAX]22 [PERF_COUNT_HW_CACHE_MAX]
19 [PERF_COUNT_HW_CACHE_OP_MAX]23 [PERF_COUNT_HW_CACHE_OP_MAX]
@@ -301,6 +305,25 @@ static inline int amd_pmu_addr_offset(int index, bool eventsel) · 281 unmodified lines
301 return offset;305 return offset;
302}306}
303 307
308/*
309 * AMD64 events are detected based on their event codes.
310 */
311static inline unsigned int amd_get_event_code(struct hw_perf_event *hwc)
312{
313 return ((hwc->config >> 24) & 0x0f00) | (hwc->config & 0x00ff);
314}
315
316static inline bool amd_is_pair_event_code(struct hw_perf_event *hwc)
317{
318 if (!(x86_pmu.flags & PMU_FL_PAIR))
319 return false;
320
321 switch (amd_get_event_code(hwc)) {
322 case 0x003: return true; /* Retired SSE/AVX FLOPs */
323 default: return false;
324 }
325}
326
304static int amd_core_hw_config(struct perf_event *event)327static int amd_core_hw_config(struct perf_event *event)
305{328{
306 if (event->attr.exclude_host && event->attr.exclude_guest)329 if (event->attr.exclude_host && event->attr.exclude_guest)
@@ -316,15 +339,10 @@ static int amd_core_hw_config(struct perf_event *event) · 9 unmodified lines
316 else if (event->attr.exclude_guest)339 else if (event->attr.exclude_guest)
317 event->hw.config |= AMD64_EVENTSEL_HOSTONLY;340 event->hw.config |= AMD64_EVENTSEL_HOSTONLY;
318 341
319 return 0;342 if ((x86_pmu.flags & PMU_FL_PAIR) && amd_is_pair_event_code(&event->hw))
320}343 event->hw.flags |= PERF_X86_EVENT_PAIR;
321 344
322/*345 return 0;
323 * AMD64 events are detected based on their event codes.
324 */
325static inline unsigned int amd_get_event_code(struct hw_perf_event *hwc)
326{
327 return ((hwc->config >> 24) & 0x0f00) | (hwc->config & 0x00ff);
328}346}
329 347
330static inline int amd_is_nb_event(struct hw_perf_event *hwc)348static inline int amd_is_nb_event(struct hw_perf_event *hwc)
@@ -855,6 +873,29 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, int idx, · 524 unmodified lines
855 }873 }
856}874}
857 875
876static struct event_constraint pair_constraint;
877
878static struct event_constraint *
879amd_get_event_constraints_f17h(struct cpu_hw_events *cpuc, int idx,
880 struct perf_event *event)
881{
882 struct hw_perf_event *hwc = &event->hw;
883
884 if (amd_is_pair_event_code(hwc))
885 return &pair_constraint;
886
887 return &unconstrained;
888}
889
890static void amd_put_event_constraints_f17h(struct cpu_hw_events *cpuc,
891 struct perf_event *event)
892{
893 struct hw_perf_event *hwc = &event->hw;
894
895 if (is_counter_pair(hwc))
896 --cpuc->n_pair;
897}
898
858static ssize_t amd_event_sysfs_show(char *page, u64 config)899static ssize_t amd_event_sysfs_show(char *page, u64 config)
859{900{
860 u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT) |901 u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT) |
@@ -898,33 +939,15 @@ static __initconst const struct x86_pmu amd_pmu = { · 37 unmodified lines
898 939
899static int __init amd_core_pmu_init(void)940static int __init amd_core_pmu_init(void)
900{941{
942 u64 even_ctr_mask = 0ULL;
943 int i;
944
901 if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))945 if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
902 return 0;946 return 0;
903 947
904 /* Avoid calulating the value each time in the NMI handler */948 /* Avoid calculating the value each time in the NMI handler */
905 perf_nmi_window = msecs_to_jiffies(100);949 perf_nmi_window = msecs_to_jiffies(100);
906 950
907 switch (boot_cpu_data.x86) {
908 case 0x15:
909 pr_cont("Fam15h ");
910 x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
911 break;
912 case 0x17:
913 pr_cont("Fam17h ");
914 /*
915 * In family 17h, there are no event constraints in the PMC hardware.
916 * We fallback to using default amd_get_event_constraints.
917 */
918 break;
919 case 0x18:
920 pr_cont("Fam18h ");
921 /* Using default amd_get_event_constraints. */
922 break;
923 default:
924 pr_err("core perfctr but no constraints; unknown hardware!\n");
925 return -ENODEV;
926 }
927
928 /*951 /*
929 * If core performance counter extensions exists, we must use952 * If core performance counter extensions exists, we must use
930 * MSR_F15H_PERF_CTL/MSR_F15H_PERF_CTR msrs. See also953 * MSR_F15H_PERF_CTL/MSR_F15H_PERF_CTR msrs. See also
@@ -939,6 +962,32 @@ static int __init amd_core_pmu_init(void) · 8 unmodified lines
939 */962 */
940 x86_pmu.amd_nb_constraints = 0;963 x86_pmu.amd_nb_constraints = 0;
941 964
965 if (boot_cpu_data.x86 == 0x15) {
966 pr_cont("Fam15h ");
967 x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
968 }
969 if (boot_cpu_data.x86 >= 0x17) {
970 pr_cont("Fam17h+ ");
971 /*
972 * Family 17h and compatibles have constraints for Large
973 * Increment per Cycle events: they may only be assigned an
974 * even numbered counter that has a consecutive adjacent odd
975 * numbered counter following it.
976 */
977 for (i = 0; i < x86_pmu.num_counters - 1; i += 2)
978 even_ctr_mask |= 1 << i;
979
980 pair_constraint = (struct event_constraint)
981 __EVENT_CONSTRAINT(0, even_ctr_mask, 0,
982 x86_pmu.num_counters / 2, 0,
983 PERF_X86_EVENT_PAIR);
984
985 x86_pmu.get_event_constraints = amd_get_event_constraints_f17h;
986 x86_pmu.put_event_constraints = amd_put_event_constraints_f17h;
987 x86_pmu.perf_ctr_pair_en = AMD_MERGE_EVENT_ENABLE;
988 x86_pmu.flags |= PMU_FL_PAIR;
989 }
990
942 pr_cont("core perfctr, ");991 pr_cont("core perfctr, ");
943 return 0;992 return 0;
944}993}
arch/x86/events/core.c+59−15
@@ -618,6 +618,7 @@ void x86_pmu_disable_all(void) · 617 unmodified lines
618 int idx;618 int idx;
619 619
620 for (idx = 0; idx < x86_pmu.num_counters; idx++) {620 for (idx = 0; idx < x86_pmu.num_counters; idx++) {
621 struct hw_perf_event *hwc = &cpuc->events[idx]->hw;
621 u64 val;622 u64 val;
622 623
623 if (!test_bit(idx, cpuc->active_mask))624 if (!test_bit(idx, cpuc->active_mask))
@@ -627,6 +628,8 @@ void x86_pmu_disable_all(void) · 3 unmodified lines
627 continue;628 continue;
628 val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;629 val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
629 wrmsrl(x86_pmu_config_addr(idx), val);630 wrmsrl(x86_pmu_config_addr(idx), val);
631 if (is_counter_pair(hwc))
632 wrmsrl(x86_pmu_config_addr(idx + 1), 0);
630 }633 }
631}634}
632 635
@@ -699,7 +702,7 @@ struct sched_state { · 66 unmodified lines
699 int counter; /* counter index */702 int counter; /* counter index */
700 int unassigned; /* number of events to be assigned left */703 int unassigned; /* number of events to be assigned left */
701 int nr_gp; /* number of GP counters used */704 int nr_gp; /* number of GP counters used */
702 unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)];705 u64 used;
703};706};
704 707
705/* Total max is X86_PMC_IDX_MAX, but we are O(n!) limited */708/* Total max is X86_PMC_IDX_MAX, but we are O(n!) limited */
@@ -756,8 +759,12 @@ static bool perf_sched_restore_state(struct perf_sched *sched) · 50 unmodified lines
756 sched->saved_states--;759 sched->saved_states--;
757 sched->state = sched->saved[sched->saved_states];760 sched->state = sched->saved[sched->saved_states];
758 761
759 /* continue with next counter: */762 /* this assignment didn't work out */
760 clear_bit(sched->state.counter++, sched->state.used);763 /* XXX broken vs EVENT_PAIR */
764 sched->state.used &= ~BIT_ULL(sched->state.counter);
765
766 /* try the next one */
767 sched->state.counter++;
761 768
762 return true;769 return true;
763}770}
@@ -782,20 +789,32 @@ static bool __perf_sched_find_counter(struct perf_sched *sched) · 18 unmodified lines
782 if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) {789 if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) {
783 idx = INTEL_PMC_IDX_FIXED;790 idx = INTEL_PMC_IDX_FIXED;
784 for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) {791 for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) {
785 if (!__test_and_set_bit(idx, sched->state.used))792 u64 mask = BIT_ULL(idx);
786 goto done;793
794 if (sched->state.used & mask)
795 continue;
796
797 sched->state.used |= mask;
798 goto done;
787 }799 }
788 }800 }
789 801
790 /* Grab the first unused counter starting with idx */802 /* Grab the first unused counter starting with idx */
791 idx = sched->state.counter;803 idx = sched->state.counter;
792 for_each_set_bit_from(idx, c->idxmsk, INTEL_PMC_IDX_FIXED) {804 for_each_set_bit_from(idx, c->idxmsk, INTEL_PMC_IDX_FIXED) {
793 if (!__test_and_set_bit(idx, sched->state.used)) {805 u64 mask = BIT_ULL(idx);
794 if (sched->state.nr_gp++ >= sched->max_gp)
795 return false;
796 806
797 goto done;807 if (c->flags & PERF_X86_EVENT_PAIR)
798 }808 mask |= mask << 1;
809
810 if (sched->state.used & mask)
811 continue;
812
813 if (sched->state.nr_gp++ >= sched->max_gp)
814 return false;
815
816 sched->state.used |= mask;
817 goto done;
799 }818 }
800 819
801 return false;820 return false;
@@ -872,12 +891,10 @@ EXPORT_SYMBOL_GPL(perf_assign_events); · 70 unmodified lines
872int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)891int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
873{892{
874 struct event_constraint *c;893 struct event_constraint *c;
875 unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
876 struct perf_event *e;894 struct perf_event *e;
877 int n0, i, wmin, wmax, unsched = 0;895 int n0, i, wmin, wmax, unsched = 0;
878 struct hw_perf_event *hwc;896 struct hw_perf_event *hwc;
879 897 u64 used_mask = 0;
880 bitmap_zero(used_mask, X86_PMC_IDX_MAX);
881 898
882 /*899 /*
883 * Compute the number of events already present; see x86_pmu_add(),900 * Compute the number of events already present; see x86_pmu_add(),
@@ -920,6 +937,8 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) · 36 unmodified lines
920 * fastpath, try to reuse previous register937 * fastpath, try to reuse previous register
921 */938 */
922 for (i = 0; i < n; i++) {939 for (i = 0; i < n; i++) {
940 u64 mask;
941
923 hwc = &cpuc->event_list[i]->hw;942 hwc = &cpuc->event_list[i]->hw;
924 c = cpuc->event_constraint[i];943 c = cpuc->event_constraint[i];
925 944
@@ -931,11 +950,16 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) · 5 unmodified lines
931 if (!test_bit(hwc->idx, c->idxmsk))950 if (!test_bit(hwc->idx, c->idxmsk))
932 break;951 break;
933 952
953 mask = BIT_ULL(hwc->idx);
954 if (is_counter_pair(hwc))
955 mask |= mask << 1;
956
934 /* not already used */957 /* not already used */
935 if (test_bit(hwc->idx, used_mask))958 if (used_mask & mask)
936 break;959 break;
937 960
938 __set_bit(hwc->idx, used_mask);961 used_mask |= mask;
962
939 if (assign)963 if (assign)
940 assign[i] = hwc->idx;964 assign[i] = hwc->idx;
941 }965 }
@@ -958,6 +982,15 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) · 16 unmodified lines
958 READ_ONCE(cpuc->excl_cntrs->exclusive_present))982 READ_ONCE(cpuc->excl_cntrs->exclusive_present))
959 gpmax /= 2;983 gpmax /= 2;
960 984
985 /*
986 * Reduce the amount of available counters to allow fitting
987 * the extra Merge events needed by large increment events.
988 */
989 if (x86_pmu.flags & PMU_FL_PAIR) {
990 gpmax = x86_pmu.num_counters - cpuc->n_pair;
991 WARN_ON(gpmax <= 0);
992 }
993
961 unsched = perf_assign_events(cpuc->event_constraint, n, wmin,994 unsched = perf_assign_events(cpuc->event_constraint, n, wmin,
962 wmax, gpmax, assign);995 wmax, gpmax, assign);
963 }996 }
@@ -1038,6 +1071,8 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, · 74 unmodified lines
1038 return -EINVAL;1071 return -EINVAL;
1039 cpuc->event_list[n] = leader;1072 cpuc->event_list[n] = leader;
1040 n++;1073 n++;
1074 if (is_counter_pair(&leader->hw))
1075 cpuc->n_pair++;
1041 }1076 }
1042 if (!dogrp)1077 if (!dogrp)
1043 return n;1078 return n;
@@ -1052,6 +1087,8 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, · 8 unmodified lines
1052 1087
1053 cpuc->event_list[n] = event;1088 cpuc->event_list[n] = event;
1054 n++;1089 n++;
1090 if (is_counter_pair(&event->hw))
1091 cpuc->n_pair++;
1055 }1092 }
1056 return n;1093 return n;
1057}1094}
@@ -1237,6 +1274,13 @@ int x86_perf_event_set_period(struct perf_event *event) · 179 unmodified lines
1237 1274
1238 wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask);1275 wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask);
1239 1276
1277 /*
1278 * Clear the Merge event counter's upper 16 bits since
1279 * we currently declare a 48-bit counter width
1280 */
1281 if (is_counter_pair(hwc))
1282 wrmsrl(x86_pmu_event_addr(idx + 1), 0);
1283
1240 /*1284 /*
1241 * Due to erratum on certan cpu we need1285 * Due to erratum on certan cpu we need
1242 * a second write to be sure the register1286 * a second write to be sure the register
arch/x86/events/intel/rapl.c+2−0
@@ -741,6 +741,8 @@ static const struct x86_cpu_id rapl_model_match[] __initconst = { · 740 unmodified lines
741 X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_PLUS, model_hsw),741 X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_PLUS, model_hsw),
742 X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_L, model_skl),742 X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_L, model_skl),
743 X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE, model_skl),743 X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE, model_skl),
744 X86_RAPL_MODEL_MATCH(INTEL_FAM6_COMETLAKE_L, model_skl),
745 X86_RAPL_MODEL_MATCH(INTEL_FAM6_COMETLAKE, model_skl),
744 {},746 {},
745};747};
746 748
arch/x86/events/perf_event.h+20−0
@@ -77,6 +77,7 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode) · 76 unmodified lines
77#define PERF_X86_EVENT_AUTO_RELOAD 0x0200 /* use PEBS auto-reload */77#define PERF_X86_EVENT_AUTO_RELOAD 0x0200 /* use PEBS auto-reload */
78#define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */78#define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */
79#define PERF_X86_EVENT_PEBS_VIA_PT 0x0800 /* use PT buffer for PEBS */79#define PERF_X86_EVENT_PEBS_VIA_PT 0x0800 /* use PT buffer for PEBS */
80#define PERF_X86_EVENT_PAIR 0x1000 /* Large Increment per Cycle */
80 81
81struct amd_nb {82struct amd_nb {
82 int nb_id; /* NorthBridge id */83 int nb_id; /* NorthBridge id */
@@ -272,6 +273,7 @@ struct cpu_hw_events { · 189 unmodified lines
272 struct amd_nb *amd_nb;273 struct amd_nb *amd_nb;
273 /* Inverted mask of bits to clear in the perf_ctr ctrl registers */274 /* Inverted mask of bits to clear in the perf_ctr ctrl registers */
274 u64 perf_ctr_virt_mask;275 u64 perf_ctr_virt_mask;
276 int n_pair; /* Large increment events */
275 277
276 void *kfree_on_online[X86_PERF_KFREE_MAX];278 void *kfree_on_online[X86_PERF_KFREE_MAX];
277};279};
@@ -694,6 +696,7 @@ struct x86_pmu { · 416 unmodified lines
694 * AMD bits696 * AMD bits
695 */697 */
696 unsigned int amd_nb_constraints : 1;698 unsigned int amd_nb_constraints : 1;
699 u64 perf_ctr_pair_en;
697 700
698 /*701 /*
699 * Extra registers for events702 * Extra registers for events
@@ -743,6 +746,7 @@ do { \ · 43 unmodified lines
743#define PMU_FL_EXCL_ENABLED 0x8 /* exclusive counter active */746#define PMU_FL_EXCL_ENABLED 0x8 /* exclusive counter active */
744#define PMU_FL_PEBS_ALL 0x10 /* all events are valid PEBS events */747#define PMU_FL_PEBS_ALL 0x10 /* all events are valid PEBS events */
745#define PMU_FL_TFA 0x20 /* deal with TSX force abort */748#define PMU_FL_TFA 0x20 /* deal with TSX force abort */
749#define PMU_FL_PAIR 0x40 /* merge counters for large incr. events */
746 750
747#define EVENT_VAR(_id) event_attr_##_id751#define EVENT_VAR(_id) event_attr_##_id
748#define EVENT_PTR(_id) &event_attr_##_id.attr.attr752#define EVENT_PTR(_id) &event_attr_##_id.attr.attr
@@ -838,6 +842,11 @@ int x86_pmu_hw_config(struct perf_event *event); · 89 unmodified lines
838 842
839void x86_pmu_disable_all(void);843void x86_pmu_disable_all(void);
840 844
845static inline bool is_counter_pair(struct hw_perf_event *hwc)
846{
847 return hwc->flags & PERF_X86_EVENT_PAIR;
848}
849
841static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,850static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
842 u64 enable_mask)851 u64 enable_mask)
843{852{
@@ -845,6 +854,14 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, · 1 unmodified line
845 854
846 if (hwc->extra_reg.reg)855 if (hwc->extra_reg.reg)
847 wrmsrl(hwc->extra_reg.reg, hwc->extra_reg.config);856 wrmsrl(hwc->extra_reg.reg, hwc->extra_reg.config);
857
858 /*
859 * Add enabled Merge event on next counter
860 * if large increment event being enabled on this counter
861 */
862 if (is_counter_pair(hwc))
863 wrmsrl(x86_pmu_config_addr(hwc->idx + 1), x86_pmu.perf_ctr_pair_en);
864
848 wrmsrl(hwc->config_base, (hwc->config | enable_mask) & ~disable_mask);865 wrmsrl(hwc->config_base, (hwc->config | enable_mask) & ~disable_mask);
849}866}
850 867
@@ -861,6 +878,9 @@ static inline void x86_pmu_disable_event(struct perf_event *event) · 10 unmodified lines
861 struct hw_perf_event *hwc = &event->hw;878 struct hw_perf_event *hwc = &event->hw;
862 879
863 wrmsrl(hwc->config_base, hwc->config);880 wrmsrl(hwc->config_base, hwc->config);
881
882 if (is_counter_pair(hwc))
883 wrmsrl(x86_pmu_config_addr(hwc->idx + 1), 0);
864}884}
865 885
866void x86_pmu_enable_event(struct perf_event *event);886void x86_pmu_enable_event(struct perf_event *event);
arch/x86/include/asm/ftrace.h+0−2
@@ -47,8 +47,6 @@ struct dyn_arch_ftrace { · 46 unmodified lines
47 /* No extra data needed for x86 */47 /* No extra data needed for x86 */
48};48};
49 49
50int ftrace_int3_handler(struct pt_regs *regs);
51
52#define FTRACE_GRAPH_TRAMP_ADDR FTRACE_GRAPH_ADDR50#define FTRACE_GRAPH_TRAMP_ADDR FTRACE_GRAPH_ADDR
53 51
54#endif /* CONFIG_DYNAMIC_FTRACE */52#endif /* CONFIG_DYNAMIC_FTRACE */
arch/x86/include/asm/kprobes.h+5−9
@@ -11,12 +11,11 @@ · 10 unmodified lines
11 11
12#include <asm-generic/kprobes.h>12#include <asm-generic/kprobes.h>
13 13
14#define BREAKPOINT_INSTRUCTION 0xcc
15
16#ifdef CONFIG_KPROBES14#ifdef CONFIG_KPROBES
17#include <linux/types.h>15#include <linux/types.h>
18#include <linux/ptrace.h>16#include <linux/ptrace.h>
19#include <linux/percpu.h>17#include <linux/percpu.h>
18#include <asm/text-patching.h>
20#include <asm/insn.h>19#include <asm/insn.h>
21 20
22#define __ARCH_WANT_KPROBES_INSN_SLOT21#define __ARCH_WANT_KPROBES_INSN_SLOT
@@ -25,10 +24,7 @@ struct pt_regs; · 2 unmodified lines
25struct kprobe;24struct kprobe;
26 25
27typedef u8 kprobe_opcode_t;26typedef u8 kprobe_opcode_t;
28#define RELATIVEJUMP_OPCODE 0xe927
29#define RELATIVEJUMP_SIZE 5
30#define RELATIVECALL_OPCODE 0xe8
31#define RELATIVE_ADDR_SIZE 4
32#define MAX_STACK_SIZE 6428#define MAX_STACK_SIZE 64
33#define CUR_STACK_SIZE(ADDR) \29#define CUR_STACK_SIZE(ADDR) \
34 (current_top_of_stack() - (unsigned long)(ADDR))30 (current_top_of_stack() - (unsigned long)(ADDR))
@@ -43,11 +39,11 @@ extern __visible kprobe_opcode_t optprobe_template_entry[]; · 8 unmodified lines
43extern __visible kprobe_opcode_t optprobe_template_val[];39extern __visible kprobe_opcode_t optprobe_template_val[];
44extern __visible kprobe_opcode_t optprobe_template_call[];40extern __visible kprobe_opcode_t optprobe_template_call[];
45extern __visible kprobe_opcode_t optprobe_template_end[];41extern __visible kprobe_opcode_t optprobe_template_end[];
46#define MAX_OPTIMIZED_LENGTH (MAX_INSN_SIZE + RELATIVE_ADDR_SIZE)42#define MAX_OPTIMIZED_LENGTH (MAX_INSN_SIZE + DISP32_SIZE)
47#define MAX_OPTINSN_SIZE \43#define MAX_OPTINSN_SIZE \
48 (((unsigned long)optprobe_template_end - \44 (((unsigned long)optprobe_template_end - \
49 (unsigned long)optprobe_template_entry) + \45 (unsigned long)optprobe_template_entry) + \
50 MAX_OPTIMIZED_LENGTH + RELATIVEJUMP_SIZE)46 MAX_OPTIMIZED_LENGTH + JMP32_INSN_SIZE)
51 47
52extern const int kretprobe_blacklist_size;48extern const int kretprobe_blacklist_size;
53 49
@@ -73,7 +69,7 @@ struct arch_specific_insn { · 19 unmodified lines
73 69
74struct arch_optimized_insn {70struct arch_optimized_insn {
75 /* copy of the original instructions */71 /* copy of the original instructions */
76 kprobe_opcode_t copied_insn[RELATIVE_ADDR_SIZE];72 kprobe_opcode_t copied_insn[DISP32_SIZE];
77 /* detour code buffer */73 /* detour code buffer */
78 kprobe_opcode_t *insn;74 kprobe_opcode_t *insn;
79 /* the size of instructions copied to detour code buffer */75 /* the size of instructions copied to detour code buffer */
arch/x86/include/asm/set_memory.h+0−2
@@ -81,8 +81,6 @@ int set_direct_map_invalid_noflush(struct page *page); · 80 unmodified lines
81int set_direct_map_default_noflush(struct page *page);81int set_direct_map_default_noflush(struct page *page);
82 82
83extern int kernel_set_to_readonly;83extern int kernel_set_to_readonly;
84void set_kernel_text_rw(void);
85void set_kernel_text_ro(void);
86 84
87#ifdef CONFIG_X86_6485#ifdef CONFIG_X86_64
88static inline int set_mce_nospec(unsigned long pfn)86static inline int set_mce_nospec(unsigned long pfn)
arch/x86/include/asm/text-patching.h+67−19
@@ -25,14 +25,6 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, · 24 unmodified lines
25 */25 */
26#define POKE_MAX_OPCODE_SIZE 526#define POKE_MAX_OPCODE_SIZE 5
27 27
28struct text_poke_loc {
29 void *addr;
30 int len;
31 s32 rel32;
32 u8 opcode;
33 const u8 text[POKE_MAX_OPCODE_SIZE];
34};
35
36extern void text_poke_early(void *addr, const void *opcode, size_t len);28extern void text_poke_early(void *addr, const void *opcode, size_t len);
37 29
38/*30/*
@@ -50,21 +42,13 @@ extern void text_poke_early(void *addr, const void *opcode, size_t len); · 11 unmodified lines
50 * an inconsistent instruction while you patch.42 * an inconsistent instruction while you patch.
51 */43 */
52extern void *text_poke(void *addr, const void *opcode, size_t len);44extern void *text_poke(void *addr, const void *opcode, size_t len);
45extern void text_poke_sync(void);
53extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len);46extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len);
54extern int poke_int3_handler(struct pt_regs *regs);47extern int poke_int3_handler(struct pt_regs *regs);
55extern void text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulate);48extern void text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulate);
56extern void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries);
57extern void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
58 const void *opcode, size_t len, const void *emulate);
59extern int after_bootmem;
60extern __ro_after_init struct mm_struct *poking_mm;
61extern __ro_after_init unsigned long poking_addr;
62 49
63#ifndef CONFIG_UML_X8650extern void text_poke_queue(void *addr, const void *opcode, size_t len, const void *emulate);
64static inline void int3_emulate_jmp(struct pt_regs *regs, unsigned long ip)51extern void text_poke_finish(void);
65{
66 regs->ip = ip;
67}
68 52
69#define INT3_INSN_SIZE 153#define INT3_INSN_SIZE 1
70#define INT3_INSN_OPCODE 0xCC54#define INT3_INSN_OPCODE 0xCC
@@ -78,6 +62,67 @@ static inline void int3_emulate_jmp(struct pt_regs *regs, unsigned long ip) · 7 unmodified lines
78#define JMP8_INSN_SIZE 262#define JMP8_INSN_SIZE 2
79#define JMP8_INSN_OPCODE 0xEB63#define JMP8_INSN_OPCODE 0xEB
80 64
65#define DISP32_SIZE 4
66
67static inline int text_opcode_size(u8 opcode)
68{
69 int size = 0;
70
71#define __CASE(insn) \
72 case insn##_INSN_OPCODE: size = insn##_INSN_SIZE; break
73
74 switch(opcode) {
75 __CASE(INT3);
76 __CASE(CALL);
77 __CASE(JMP32);
78 __CASE(JMP8);
79 }
80
81#undef __CASE
82
83 return size;
84}
85
86union text_poke_insn {
87 u8 text[POKE_MAX_OPCODE_SIZE];
88 struct {
89 u8 opcode;
90 s32 disp;
91 } __attribute__((packed));
92};
93
94static __always_inline
95void *text_gen_insn(u8 opcode, const void *addr, const void *dest)
96{
97 static union text_poke_insn insn; /* per instance */
98 int size = text_opcode_size(opcode);
99
100 insn.opcode = opcode;
101
102 if (size > 1) {
103 insn.disp = (long)dest - (long)(addr + size);
104 if (size == 2) {
105 /*
106 * Ensure that for JMP9 the displacement
107 * actually fits the signed byte.
108 */
109 BUG_ON((insn.disp >> 31) != (insn.disp >> 7));
110 }
111 }
112
113 return &insn.text;
114}
115
116extern int after_bootmem;
117extern __ro_after_init struct mm_struct *poking_mm;
118extern __ro_after_init unsigned long poking_addr;
119
120#ifndef CONFIG_UML_X86
121static inline void int3_emulate_jmp(struct pt_regs *regs, unsigned long ip)
122{
123 regs->ip = ip;
124}
125
81static inline void int3_emulate_push(struct pt_regs *regs, unsigned long val)126static inline void int3_emulate_push(struct pt_regs *regs, unsigned long val)
82{127{
83 /*128 /*
@@ -85,6 +130,9 @@ static inline void int3_emulate_push(struct pt_regs *regs, unsigned long val) · 1 unmodified line
85 * stack where the break point happened, and the saving of130 * stack where the break point happened, and the saving of
86 * pt_regs. We can extend the original stack because of131 * pt_regs. We can extend the original stack because of
87 * this gap. See the idtentry macro's create_gap option.132 * this gap. See the idtentry macro's create_gap option.
133 *
134 * Similarly entry_32.S will have a gap on the stack for (any) hardware
135 * exception and pt_regs; see FIXUP_FRAME.
88 */136 */
89 regs->sp -= sizeof(unsigned long);137 regs->sp -= sizeof(unsigned long);
90 *(unsigned long *)regs->sp = val;138 *(unsigned long *)regs->sp = val;
arch/x86/kernel/alternative.c+150−48
@@ -936,44 +936,81 @@ static void do_sync_core(void *info) · 935 unmodified lines
936 sync_core();936 sync_core();
937}937}
938 938
939static struct bp_patching_desc {939void text_poke_sync(void)
940{
941 on_each_cpu(do_sync_core, NULL, 1);
942}
943
944struct text_poke_loc {
945 s32 rel_addr; /* addr := _stext + rel_addr */
946 s32 rel32;
947 u8 opcode;
948 const u8 text[POKE_MAX_OPCODE_SIZE];
949};
950
951struct bp_patching_desc {
940 struct text_poke_loc *vec;952 struct text_poke_loc *vec;
941 int nr_entries;953 int nr_entries;
942} bp_patching;954 atomic_t refs;
955};
956
957static struct bp_patching_desc *bp_desc;
958
959static inline struct bp_patching_desc *try_get_desc(struct bp_patching_desc **descp)
960{
961 struct bp_patching_desc *desc = READ_ONCE(*descp); /* rcu_dereference */
962
963 if (!desc || !atomic_inc_not_zero(&desc->refs))
964 return NULL;
965
966 return desc;
967}
968
969static inline void put_desc(struct bp_patching_desc *desc)
970{
971 smp_mb__before_atomic();
972 atomic_dec(&desc->refs);
973}
943 974
944static int patch_cmp(const void *key, const void *elt)975static inline void *text_poke_addr(struct text_poke_loc *tp)
976{
977 return _stext + tp->rel_addr;
978}
979
980static int notrace patch_cmp(const void *key, const void *elt)
945{981{
946 struct text_poke_loc *tp = (struct text_poke_loc *) elt;982 struct text_poke_loc *tp = (struct text_poke_loc *) elt;
947 983
948 if (key < tp->addr)984 if (key < text_poke_addr(tp))
949 return -1;985 return -1;
950 if (key > tp->addr)986 if (key > text_poke_addr(tp))
951 return 1;987 return 1;
952 return 0;988 return 0;
953}989}
954NOKPROBE_SYMBOL(patch_cmp);990NOKPROBE_SYMBOL(patch_cmp);
955 991
956int poke_int3_handler(struct pt_regs *regs)992int notrace poke_int3_handler(struct pt_regs *regs)
957{993{
994 struct bp_patching_desc *desc;
958 struct text_poke_loc *tp;995 struct text_poke_loc *tp;
996 int len, ret = 0;
959 void *ip;997 void *ip;
960 998
999 if (user_mode(regs))
1000 return 0;
1001
961 /*1002 /*
962 * Having observed our INT3 instruction, we now must observe1003 * Having observed our INT3 instruction, we now must observe
963 * bp_patching.nr_entries.1004 * bp_desc:
964 *1005 *
965 * nr_entries != 0 INT31006 * bp_desc = desc INT3
966 * WMB RMB1007 * WMB RMB
967 * write INT3 if (nr_entries)1008 * write INT3 if (desc)
968 *
969 * Idem for other elements in bp_patching.
970 */1009 */
971 smp_rmb();1010 smp_rmb();
972 1011
973 if (likely(!bp_patching.nr_entries))1012 desc = try_get_desc(&bp_desc);
974 return 0;1013 if (!desc)
975
976 if (user_mode(regs))
977 return 0;1014 return 0;
978 1015
979 /*1016 /*
@@ -984,19 +1021,20 @@ int poke_int3_handler(struct pt_regs *regs) · 4 unmodified lines
984 /*1021 /*
985 * Skip the binary search if there is a single member in the vector.1022 * Skip the binary search if there is a single member in the vector.
986 */1023 */
987 if (unlikely(bp_patching.nr_entries > 1)) {1024 if (unlikely(desc->nr_entries > 1)) {
988 tp = bsearch(ip, bp_patching.vec, bp_patching.nr_entries,1025 tp = bsearch(ip, desc->vec, desc->nr_entries,
989 sizeof(struct text_poke_loc),1026 sizeof(struct text_poke_loc),
990 patch_cmp);1027 patch_cmp);
991 if (!tp)1028 if (!tp)
992 return 0;1029 goto out_put;
993 } else {1030 } else {
994 tp = bp_patching.vec;1031 tp = desc->vec;
995 if (tp->addr != ip)1032 if (text_poke_addr(tp) != ip)
996 return 0;1033 goto out_put;
997 }1034 }
998 1035
999 ip += tp->len;1036 len = text_opcode_size(tp->opcode);
1037 ip += len;
1000 1038
1001 switch (tp->opcode) {1039 switch (tp->opcode) {
1002 case INT3_INSN_OPCODE:1040 case INT3_INSN_OPCODE:
@@ -1004,7 +1042,7 @@ int poke_int3_handler(struct pt_regs *regs) · 1 unmodified line
1004 * Someone poked an explicit INT3, they'll want to handle it,1042 * Someone poked an explicit INT3, they'll want to handle it,
1005 * do not consume.1043 * do not consume.
1006 */1044 */
1007 return 0;1045 goto out_put;
1008 1046
1009 case CALL_INSN_OPCODE:1047 case CALL_INSN_OPCODE:
1010 int3_emulate_call(regs, (long)ip + tp->rel32);1048 int3_emulate_call(regs, (long)ip + tp->rel32);
@@ -1019,10 +1057,18 @@ int poke_int3_handler(struct pt_regs *regs) · 8 unmodified lines
1019 BUG();1057 BUG();
1020 }1058 }
1021 1059
1022 return 1;1060 ret = 1;
1061
1062out_put:
1063 put_desc(desc);
1064 return ret;
1023}1065}
1024NOKPROBE_SYMBOL(poke_int3_handler);1066NOKPROBE_SYMBOL(poke_int3_handler);
1025 1067
1068#define TP_VEC_MAX (PAGE_SIZE / sizeof(struct text_poke_loc))
1069static struct text_poke_loc tp_vec[TP_VEC_MAX];
1070static int tp_vec_nr;
1071
1026/**1072/**
1027 * text_poke_bp_batch() -- update instructions on live kernel on SMP1073 * text_poke_bp_batch() -- update instructions on live kernel on SMP
1028 * @tp: vector of instructions to patch1074 * @tp: vector of instructions to patch
@@ -1044,16 +1090,20 @@ NOKPROBE_SYMBOL(poke_int3_handler); · 15 unmodified lines
1044 * replacing opcode1090 * replacing opcode
1045 * - sync cores1091 * - sync cores
1046 */1092 */
1047void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries)1093static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries)
1048{1094{
1095 struct bp_patching_desc desc = {
1096 .vec = tp,
1097 .nr_entries = nr_entries,
1098 .refs = ATOMIC_INIT(1),
1099 };
1049 unsigned char int3 = INT3_INSN_OPCODE;1100 unsigned char int3 = INT3_INSN_OPCODE;
1050 unsigned int i;1101 unsigned int i;
1051 int do_sync;1102 int do_sync;
1052 1103
1053 lockdep_assert_held(&text_mutex);1104 lockdep_assert_held(&text_mutex);
1054 1105
1055 bp_patching.vec = tp;1106 smp_store_release(&bp_desc, &desc); /* rcu_assign_pointer */
1056 bp_patching.nr_entries = nr_entries;
1057 1107
1058 /*1108 /*
1059 * Corresponding read barrier in int3 notifier for making sure the1109 * Corresponding read barrier in int3 notifier for making sure the
@@ -1065,18 +1115,20 @@ void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries) · 5 unmodified lines
1065 * First step: add a int3 trap to the address that will be patched.1115 * First step: add a int3 trap to the address that will be patched.
1066 */1116 */
1067 for (i = 0; i < nr_entries; i++)1117 for (i = 0; i < nr_entries; i++)
1068 text_poke(tp[i].addr, &int3, sizeof(int3));1118 text_poke(text_poke_addr(&tp[i]), &int3, INT3_INSN_SIZE);
1069 1119
1070 on_each_cpu(do_sync_core, NULL, 1);1120 text_poke_sync();
1071 1121
1072 /*1122 /*
1073 * Second step: update all but the first byte of the patched range.1123 * Second step: update all but the first byte of the patched range.
1074 */1124 */
1075 for (do_sync = 0, i = 0; i < nr_entries; i++) {1125 for (do_sync = 0, i = 0; i < nr_entries; i++) {
1076 if (tp[i].len - sizeof(int3) > 0) {1126 int len = text_opcode_size(tp[i].opcode);
1077 text_poke((char *)tp[i].addr + sizeof(int3),1127
1078 (const char *)tp[i].text + sizeof(int3),1128 if (len - INT3_INSN_SIZE > 0) {
1079 tp[i].len - sizeof(int3));1129 text_poke(text_poke_addr(&tp[i]) + INT3_INSN_SIZE,
1130 (const char *)tp[i].text + INT3_INSN_SIZE,
1131 len - INT3_INSN_SIZE);
1080 do_sync++;1132 do_sync++;
1081 }1133 }
1082 }1134 }
@@ -1087,7 +1139,7 @@ void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries) · 4 unmodified lines
1087 * not necessary and we'd be safe even without it. But1139 * not necessary and we'd be safe even without it. But
1088 * better safe than sorry (plus there's not only Intel).1140 * better safe than sorry (plus there's not only Intel).
1089 */1141 */
1090 on_each_cpu(do_sync_core, NULL, 1);1142 text_poke_sync();
1091 }1143 }
1092 1144
1093 /*1145 /*
@@ -1098,19 +1150,20 @@ void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries) · 4 unmodified lines
1098 if (tp[i].text[0] == INT3_INSN_OPCODE)1150 if (tp[i].text[0] == INT3_INSN_OPCODE)
1099 continue;1151 continue;
1100 1152
1101 text_poke(tp[i].addr, tp[i].text, sizeof(int3));1153 text_poke(text_poke_addr(&tp[i]), tp[i].text, INT3_INSN_SIZE);
1102 do_sync++;1154 do_sync++;
1103 }1155 }
1104 1156
1105 if (do_sync)1157 if (do_sync)
1106 on_each_cpu(do_sync_core, NULL, 1);1158 text_poke_sync();
1107 1159
1108 /*1160 /*
1109 * sync_core() implies an smp_mb() and orders this store against1161 * Remove and synchronize_rcu(), except we have a very primitive
1110 * the writing of the new instruction.1162 * refcount based completion.
1111 */1163 */
1112 bp_patching.vec = NULL;1164 WRITE_ONCE(bp_desc, NULL); /* RCU_INIT_POINTER */
1113 bp_patching.nr_entries = 0;1165 if (!atomic_dec_and_test(&desc.refs))
1166 atomic_cond_read_acquire(&desc.refs, !VAL);
1114}1167}
1115 1168
1116void text_poke_loc_init(struct text_poke_loc *tp, void *addr,1169void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
@@ -1118,11 +1171,7 @@ void text_poke_loc_init(struct text_poke_loc *tp, void *addr, · 1 unmodified line
1118{1171{
1119 struct insn insn;1172 struct insn insn;
1120 1173
1121 if (!opcode)1174 memcpy((void *)tp->text, opcode, len);
1122 opcode = (void *)tp->text;
1123 else
1124 memcpy((void *)tp->text, opcode, len);
1125
1126 if (!emulate)1175 if (!emulate)
1127 emulate = opcode;1176 emulate = opcode;
1128 1177
@@ -1132,8 +1181,7 @@ void text_poke_loc_init(struct text_poke_loc *tp, void *addr, · 3 unmodified lines
1132 BUG_ON(!insn_complete(&insn));1181 BUG_ON(!insn_complete(&insn));
1133 BUG_ON(len != insn.length);1182 BUG_ON(len != insn.length);
1134 1183
1135 tp->addr = addr;1184 tp->rel_addr = addr - (void *)_stext;
1136 tp->len = len;
1137 tp->opcode = insn.opcode.bytes[0];1185 tp->opcode = insn.opcode.bytes[0];
1138 1186
1139 switch (tp->opcode) {1187 switch (tp->opcode) {
@@ -1167,6 +1215,55 @@ void text_poke_loc_init(struct text_poke_loc *tp, void *addr, · 27 unmodified lines
1167 }1215 }
1168}1216}
1169 1217
1218/*
1219 * We hard rely on the tp_vec being ordered; ensure this is so by flushing
1220 * early if needed.
1221 */
1222static bool tp_order_fail(void *addr)
1223{
1224 struct text_poke_loc *tp;
1225
1226 if (!tp_vec_nr)
1227 return false;
1228
1229 if (!addr) /* force */
1230 return true;
1231
1232 tp = &tp_vec[tp_vec_nr - 1];
1233 if ((unsigned long)text_poke_addr(tp) > (unsigned long)addr)
1234 return true;
1235
1236 return false;
1237}
1238
1239static void text_poke_flush(void *addr)
1240{
1241 if (tp_vec_nr == TP_VEC_MAX || tp_order_fail(addr)) {
1242 text_poke_bp_batch(tp_vec, tp_vec_nr);
1243 tp_vec_nr = 0;
1244 }
1245}
1246
1247void text_poke_finish(void)
1248{
1249 text_poke_flush(NULL);
1250}
1251
1252void __ref text_poke_queue(void *addr, const void *opcode, size_t len, const void *emulate)
1253{
1254 struct text_poke_loc *tp;
1255
1256 if (unlikely(system_state == SYSTEM_BOOTING)) {
1257 text_poke_early(addr, opcode, len);
1258 return;
1259 }
1260
1261 text_poke_flush(addr);
1262
1263 tp = &tp_vec[tp_vec_nr++];
1264 text_poke_loc_init(tp, addr, opcode, len, emulate);
1265}
1266
1170/**1267/**
1171 * text_poke_bp() -- update instructions on live kernel on SMP1268 * text_poke_bp() -- update instructions on live kernel on SMP
1172 * @addr: address to patch1269 * @addr: address to patch
@@ -1178,10 +1275,15 @@ void text_poke_loc_init(struct text_poke_loc *tp, void *addr, · 5 unmodified lines
1178 * dynamically allocated memory. This function should be used when it is1275 * dynamically allocated memory. This function should be used when it is
1179 * not possible to allocate memory.1276 * not possible to allocate memory.
1180 */1277 */
1181void text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulate)1278void __ref text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulate)
1182{1279{
1183 struct text_poke_loc tp;1280 struct text_poke_loc tp;
1184 1281
1282 if (unlikely(system_state == SYSTEM_BOOTING)) {
1283 text_poke_early(addr, opcode, len);
1284 return;
1285 }
1286
1185 text_poke_loc_init(&tp, addr, opcode, len, emulate);1287 text_poke_loc_init(&tp, addr, opcode, len, emulate);
1186 text_poke_bp_batch(&tp, 1);1288 text_poke_bp_batch(&tp, 1);
1187}1289}
arch/x86/kernel/ftrace.c+126−562
@@ -35,6 +35,8 @@ · 34 unmodified lines
35 35
36#ifdef CONFIG_DYNAMIC_FTRACE36#ifdef CONFIG_DYNAMIC_FTRACE
37 37
38static int ftrace_poke_late = 0;
39
38int ftrace_arch_code_modify_prepare(void)40int ftrace_arch_code_modify_prepare(void)
39 __acquires(&text_mutex)41 __acquires(&text_mutex)
40{42{
@@ -44,84 +46,37 @@ int ftrace_arch_code_modify_prepare(void) · 3 unmodified lines
44 * ftrace has it set to "read/write".46 * ftrace has it set to "read/write".
45 */47 */
46 mutex_lock(&text_mutex);48 mutex_lock(&text_mutex);
47 set_kernel_text_rw();49 ftrace_poke_late = 1;
48 set_all_modules_text_rw();
49 return 0;50 return 0;
50}51}
51 52
52int ftrace_arch_code_modify_post_process(void)53int ftrace_arch_code_modify_post_process(void)
53 __releases(&text_mutex)54 __releases(&text_mutex)
54{55{
55 set_all_modules_text_ro();56 /*
56 set_kernel_text_ro();57 * ftrace_make_{call,nop}() may be called during
58 * module load, and we need to finish the text_poke_queue()
59 * that they do, here.
60 */
61 text_poke_finish();
62 ftrace_poke_late = 0;
57 mutex_unlock(&text_mutex);63 mutex_unlock(&text_mutex);
58 return 0;64 return 0;
59}65}
60 66
61union ftrace_code_union {67static const char *ftrace_nop_replace(void)
62 char code[MCOUNT_INSN_SIZE];
63 struct {
64 unsigned char op;
65 int offset;
66 } __attribute__((packed));
67};
68
69static int ftrace_calc_offset(long ip, long addr)
70{
71 return (int)(addr - ip);
72}
73
74static unsigned char *
75ftrace_text_replace(unsigned char op, unsigned long ip, unsigned long addr)
76{68{
77 static union ftrace_code_union calc;69 return ideal_nops[NOP_ATOMIC5];
78
79 calc.op = op;
80 calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
81
82 return calc.code;
83}
84
85static unsigned char *
86ftrace_call_replace(unsigned long ip, unsigned long addr)
87{
88 return ftrace_text_replace(0xe8, ip, addr);
89}
90
91static inline int
92within(unsigned long addr, unsigned long start, unsigned long end)
93{
94 return addr >= start && addr < end;
95}70}
96 71
97static unsigned long text_ip_addr(unsigned long ip)72static const char *ftrace_call_replace(unsigned long ip, unsigned long addr)
98{73{
99 /*74 return text_gen_insn(CALL_INSN_OPCODE, (void *)ip, (void *)addr);
100 * On x86_64, kernel text mappings are mapped read-only, so we use
101 * the kernel identity mapping instead of the kernel text mapping
102 * to modify the kernel text.
103 *
104 * For 32bit kernels, these mappings are same and we can use
105 * kernel identity mapping to modify code.
106 */
107 if (within(ip, (unsigned long)_text, (unsigned long)_etext))
108 ip = (unsigned long)__va(__pa_symbol(ip));
109
110 return ip;
111}75}
112 76
113static const unsigned char *ftrace_nop_replace(void)77static int ftrace_verify_code(unsigned long ip, const char *old_code)
114{78{
115 return ideal_nops[NOP_ATOMIC5];79 char cur_code[MCOUNT_INSN_SIZE];
116}
117
118static int
119ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code,
120 unsigned const char *new_code)
121{
122 unsigned char replaced[MCOUNT_INSN_SIZE];
123
124 ftrace_expected = old_code;
125 80
126 /*81 /*
127 * Note:82 * Note:
@@ -130,31 +85,46 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code, · 2 unmodified lines
130 * Carefully read and modify the code with probe_kernel_*(), and make85 * Carefully read and modify the code with probe_kernel_*(), and make
131 * sure what we read is what we expected it to be before modifying it.86 * sure what we read is what we expected it to be before modifying it.
132 */87 */
133
134 /* read the text we want to modify */88 /* read the text we want to modify */
135 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))89 if (probe_kernel_read(cur_code, (void *)ip, MCOUNT_INSN_SIZE)) {
90 WARN_ON(1);
136 return -EFAULT;91 return -EFAULT;
92 }
137 93
138 /* Make sure it is what we expect it to be */94 /* Make sure it is what we expect it to be */
139 if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)95 if (memcmp(cur_code, old_code, MCOUNT_INSN_SIZE) != 0) {
96 WARN_ON(1);
140 return -EINVAL;97 return -EINVAL;
98 }
141 99
142 ip = text_ip_addr(ip);100 return 0;
143 101}
144 /* replace the text with the new text */
145 if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
146 return -EPERM;
147 102
148 sync_core();103/*
104 * Marked __ref because it calls text_poke_early() which is .init.text. That is
105 * ok because that call will happen early, during boot, when .init sections are
106 * still present.
107 */
108static int __ref
109ftrace_modify_code_direct(unsigned long ip, const char *old_code,
110 const char *new_code)
111{
112 int ret = ftrace_verify_code(ip, old_code);
113 if (ret)
114 return ret;
149 115
116 /* replace the text with the new text */
117 if (ftrace_poke_late)
118 text_poke_queue((void *)ip, new_code, MCOUNT_INSN_SIZE, NULL);
119 else
120 text_poke_early((void *)ip, new_code, MCOUNT_INSN_SIZE);
150 return 0;121 return 0;
151}122}
152 123
153int ftrace_make_nop(struct module *mod,124int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr)
154 struct dyn_ftrace *rec, unsigned long addr)
155{125{
156 unsigned const char *new, *old;
157 unsigned long ip = rec->ip;126 unsigned long ip = rec->ip;
127 const char *new, *old;
158 128
159 old = ftrace_call_replace(ip, addr);129 old = ftrace_call_replace(ip, addr);
160 new = ftrace_nop_replace();130 new = ftrace_nop_replace();
@@ -168,19 +138,20 @@ int ftrace_make_nop(struct module *mod, · 7 unmodified lines
168 * just modify the code directly.138 * just modify the code directly.
169 */139 */
170 if (addr == MCOUNT_ADDR)140 if (addr == MCOUNT_ADDR)
171 return ftrace_modify_code_direct(rec->ip, old, new);141 return ftrace_modify_code_direct(ip, old, new);
172 142
173 ftrace_expected = NULL;143 /*
174 144 * x86 overrides ftrace_replace_code -- this function will never be used
175 /* Normal cases use add_brk_on_nop */145 * in this case.
146 */
176 WARN_ONCE(1, "invalid use of ftrace_make_nop");147 WARN_ONCE(1, "invalid use of ftrace_make_nop");
177 return -EINVAL;148 return -EINVAL;
178}149}
179 150
180int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)151int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
181{152{
182 unsigned const char *new, *old;
183 unsigned long ip = rec->ip;153 unsigned long ip = rec->ip;
154 const char *new, *old;
184 155
185 old = ftrace_nop_replace();156 old = ftrace_nop_replace();
186 new = ftrace_call_replace(ip, addr);157 new = ftrace_call_replace(ip, addr);
@@ -189,43 +160,6 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) · 2 unmodified lines
189 return ftrace_modify_code_direct(rec->ip, old, new);160 return ftrace_modify_code_direct(rec->ip, old, new);
190}161}
191 162
192/*
193 * The modifying_ftrace_code is used to tell the breakpoint
194 * handler to call ftrace_int3_handler(). If it fails to
195 * call this handler for a breakpoint added by ftrace, then
196 * the kernel may crash.
197 *
198 * As atomic_writes on x86 do not need a barrier, we do not
199 * need to add smp_mb()s for this to work. It is also considered
200 * that we can not read the modifying_ftrace_code before
201 * executing the breakpoint. That would be quite remarkable if
202 * it could do that. Here's the flow that is required:
203 *
204 * CPU-0 CPU-1
205 *
206 * atomic_inc(mfc);
207 * write int3s
208 * <trap-int3> // implicit (r)mb
209 * if (atomic_read(mfc))
210 * call ftrace_int3_handler()
211 *
212 * Then when we are finished:
213 *
214 * atomic_dec(mfc);
215 *
216 * If we hit a breakpoint that was not set by ftrace, it does not
217 * matter if ftrace_int3_handler() is called or not. It will
218 * simply be ignored. But it is crucial that a ftrace nop/caller
219 * breakpoint is handled. No other user should ever place a
220 * breakpoint on an ftrace nop/caller location. It must only
221 * be done by this code.
222 */
223atomic_t modifying_ftrace_code __read_mostly;
224
225static int
226ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
227 unsigned const char *new_code);
228
229/*163/*
230 * Should never be called:164 * Should never be called:
231 * As it is only called by __ftrace_replace_code() which is called by165 * As it is only called by __ftrace_replace_code() which is called by
@@ -238,452 +172,84 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, · 6 unmodified lines
238 unsigned long addr)172 unsigned long addr)
239{173{
240 WARN_ON(1);174 WARN_ON(1);
241 ftrace_expected = NULL;
242 return -EINVAL;175 return -EINVAL;
243}176}
244 177
245static unsigned long ftrace_update_func;
246static unsigned long ftrace_update_func_call;
247
248static int update_ftrace_func(unsigned long ip, void *new)
249{
250 unsigned char old[MCOUNT_INSN_SIZE];
251 int ret;
252
253 memcpy(old, (void *)ip, MCOUNT_INSN_SIZE);
254
255 ftrace_update_func = ip;
256 /* Make sure the breakpoints see the ftrace_update_func update */
257 smp_wmb();
258
259 /* See comment above by declaration of modifying_ftrace_code */
260 atomic_inc(&modifying_ftrace_code);
261
262 ret = ftrace_modify_code(ip, old, new);
263
264 atomic_dec(&modifying_ftrace_code);
265
266 return ret;
267}
268
269int ftrace_update_ftrace_func(ftrace_func_t func)178int ftrace_update_ftrace_func(ftrace_func_t func)
270{
271 unsigned long ip = (unsigned long)(&ftrace_call);
272 unsigned char *new;
273 int ret;
274
275 ftrace_update_func_call = (unsigned long)func;
276
277 new = ftrace_call_replace(ip, (unsigned long)func);
278 ret = update_ftrace_func(ip, new);
279
280 /* Also update the regs callback function */
281 if (!ret) {
282 ip = (unsigned long)(&ftrace_regs_call);
283 new = ftrace_call_replace(ip, (unsigned long)func);
284 ret = update_ftrace_func(ip, new);
285 }
286
287 return ret;
288}
289
290static nokprobe_inline int is_ftrace_caller(unsigned long ip)
291{
292 if (ip == ftrace_update_func)
293 return 1;
294
295 return 0;
296}
297
298/*
299 * A breakpoint was added to the code address we are about to
300 * modify, and this is the handle that will just skip over it.
301 * We are either changing a nop into a trace call, or a trace
302 * call to a nop. While the change is taking place, we treat
303 * it just like it was a nop.
304 */
305int ftrace_int3_handler(struct pt_regs *regs)
306{179{
307 unsigned long ip;180 unsigned long ip;
181 const char *new;
308 182
309 if (WARN_ON_ONCE(!regs))183 ip = (unsigned long)(&ftrace_call);
310 return 0;184 new = ftrace_call_replace(ip, (unsigned long)func);
311 185 text_poke_bp((void *)ip, new, MCOUNT_INSN_SIZE, NULL);
312 ip = regs->ip - INT3_INSN_SIZE;
313
314 if (ftrace_location(ip)) {
315 int3_emulate_call(regs, (unsigned long)ftrace_regs_caller);
316 return 1;
317 } else if (is_ftrace_caller(ip)) {
318 if (!ftrace_update_func_call) {
319 int3_emulate_jmp(regs, ip + CALL_INSN_SIZE);
320 return 1;
321 }
322 int3_emulate_call(regs, ftrace_update_func_call);
323 return 1;
324 }
325
326 return 0;
327}
328NOKPROBE_SYMBOL(ftrace_int3_handler);
329
330static int ftrace_write(unsigned long ip, const char *val, int size)
331{
332 ip = text_ip_addr(ip);
333
334 if (probe_kernel_write((void *)ip, val, size))
335 return -EPERM;
336
337 return 0;
338}
339
340static int add_break(unsigned long ip, const char *old)
341{
342 unsigned char replaced[MCOUNT_INSN_SIZE];
343 unsigned char brk = BREAKPOINT_INSTRUCTION;
344
345 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
346 return -EFAULT;
347
348 ftrace_expected = old;
349
350 /* Make sure it is what we expect it to be */
351 if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0)
352 return -EINVAL;
353
354 return ftrace_write(ip, &brk, 1);
355}
356
357static int add_brk_on_call(struct dyn_ftrace *rec, unsigned long addr)
358{
359 unsigned const char *old;
360 unsigned long ip = rec->ip;
361
362 old = ftrace_call_replace(ip, addr);
363
364 return add_break(rec->ip, old);
365}
366
367
368static int add_brk_on_nop(struct dyn_ftrace *rec)
369{
370 unsigned const char *old;
371
372 old = ftrace_nop_replace();
373
374 return add_break(rec->ip, old);
375}
376
377static int add_breakpoints(struct dyn_ftrace *rec, bool enable)
378{
379 unsigned long ftrace_addr;
380 int ret;
381
382 ftrace_addr = ftrace_get_addr_curr(rec);
383
384 ret = ftrace_test_record(rec, enable);
385
386 switch (ret) {
387 case FTRACE_UPDATE_IGNORE:
388 return 0;
389
390 case FTRACE_UPDATE_MAKE_CALL:
391 /* converting nop to call */
392 return add_brk_on_nop(rec);
393
394 case FTRACE_UPDATE_MODIFY_CALL:
395 case FTRACE_UPDATE_MAKE_NOP:
396 /* converting a call to a nop */
397 return add_brk_on_call(rec, ftrace_addr);
398 }
399 return 0;
400}
401
402/*
403 * On error, we need to remove breakpoints. This needs to
404 * be done caefully. If the address does not currently have a
405 * breakpoint, we know we are done. Otherwise, we look at the
406 * remaining 4 bytes of the instruction. If it matches a nop
407 * we replace the breakpoint with the nop. Otherwise we replace
408 * it with the call instruction.
409 */
410static int remove_breakpoint(struct dyn_ftrace *rec)
411{
412 unsigned char ins[MCOUNT_INSN_SIZE];
413 unsigned char brk = BREAKPOINT_INSTRUCTION;
414 const unsigned char *nop;
415 unsigned long ftrace_addr;
416 unsigned long ip = rec->ip;
417
418 /* If we fail the read, just give up */
419 if (probe_kernel_read(ins, (void *)ip, MCOUNT_INSN_SIZE))
420 return -EFAULT;
421
422 /* If this does not have a breakpoint, we are done */
423 if (ins[0] != brk)
424 return 0;
425
426 nop = ftrace_nop_replace();
427
428 /*
429 * If the last 4 bytes of the instruction do not match
430 * a nop, then we assume that this is a call to ftrace_addr.
431 */
432 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0) {
433 /*
434 * For extra paranoidism, we check if the breakpoint is on
435 * a call that would actually jump to the ftrace_addr.
436 * If not, don't touch the breakpoint, we make just create
437 * a disaster.
438 */
439 ftrace_addr = ftrace_get_addr_new(rec);
440 nop = ftrace_call_replace(ip, ftrace_addr);
441
442 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) == 0)
443 goto update;
444
445 /* Check both ftrace_addr and ftrace_old_addr */
446 ftrace_addr = ftrace_get_addr_curr(rec);
447 nop = ftrace_call_replace(ip, ftrace_addr);
448
449 ftrace_expected = nop;
450
451 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
452 return -EINVAL;
453 }
454
455 update:
456 return ftrace_write(ip, nop, 1);
457}
458
459static int add_update_code(unsigned long ip, unsigned const char *new)
460{
461 /* skip breakpoint */
462 ip++;
463 new++;
464 return ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1);
465}
466
467static int add_update_call(struct dyn_ftrace *rec, unsigned long addr)
468{
469 unsigned long ip = rec->ip;
470 unsigned const char *new;
471
472 new = ftrace_call_replace(ip, addr);
473 return add_update_code(ip, new);
474}
475
476static int add_update_nop(struct dyn_ftrace *rec)
477{
478 unsigned long ip = rec->ip;
479 unsigned const char *new;
480
481 new = ftrace_nop_replace();
482 return add_update_code(ip, new);
483}
484
485static int add_update(struct dyn_ftrace *rec, bool enable)
486{
487 unsigned long ftrace_addr;
488 int ret;
489
490 ret = ftrace_test_record(rec, enable);
491
492 ftrace_addr = ftrace_get_addr_new(rec);
493
494 switch (ret) {
495 case FTRACE_UPDATE_IGNORE:
496 return 0;
497
498 case FTRACE_UPDATE_MODIFY_CALL:
499 case FTRACE_UPDATE_MAKE_CALL:
500 /* converting nop to call */
501 return add_update_call(rec, ftrace_addr);
502
503 case FTRACE_UPDATE_MAKE_NOP:
504 /* converting a call to a nop */
505 return add_update_nop(rec);
506 }
507
508 return 0;
509}
510
511static int finish_update_call(struct dyn_ftrace *rec, unsigned long addr)
512{
513 unsigned long ip = rec->ip;
514 unsigned const char *new;
515
516 new = ftrace_call_replace(ip, addr);
517
518 return ftrace_write(ip, new, 1);
519}
520
521static int finish_update_nop(struct dyn_ftrace *rec)
522{
523 unsigned long ip = rec->ip;
524 unsigned const char *new;
525
526 new = ftrace_nop_replace();
527
528 return ftrace_write(ip, new, 1);
529}
530
531static int finish_update(struct dyn_ftrace *rec, bool enable)
532{
533 unsigned long ftrace_addr;
534 int ret;
535
536 ret = ftrace_update_record(rec, enable);
537
538 ftrace_addr = ftrace_get_addr_new(rec);
539
540 switch (ret) {
541 case FTRACE_UPDATE_IGNORE:
542 return 0;
543
544 case FTRACE_UPDATE_MODIFY_CALL:
545 case FTRACE_UPDATE_MAKE_CALL:
546 /* converting nop to call */
547 return finish_update_call(rec, ftrace_addr);
548 186
549 case FTRACE_UPDATE_MAKE_NOP:187 ip = (unsigned long)(&ftrace_regs_call);
550 /* converting a call to a nop */188 new = ftrace_call_replace(ip, (unsigned long)func);
551 return finish_update_nop(rec);189 text_poke_bp((void *)ip, new, MCOUNT_INSN_SIZE, NULL);
552 }
553 190
554 return 0;191 return 0;
555}192}
556 193
557static void do_sync_core(void *data)
558{
559 sync_core();
560}
561
562static void run_sync(void)
563{
564 int enable_irqs;
565
566 /* No need to sync if there's only one CPU */
567 if (num_online_cpus() == 1)
568 return;
569
570 enable_irqs = irqs_disabled();
571
572 /* We may be called with interrupts disabled (on bootup). */
573 if (enable_irqs)
574 local_irq_enable();
575 on_each_cpu(do_sync_core, NULL, 1);
576 if (enable_irqs)
577 local_irq_disable();
578}
579
580void ftrace_replace_code(int enable)194void ftrace_replace_code(int enable)
581{195{
582 struct ftrace_rec_iter *iter;196 struct ftrace_rec_iter *iter;
583 struct dyn_ftrace *rec;197 struct dyn_ftrace *rec;
584 const char *report = "adding breakpoints";198 const char *new, *old;
585 int count = 0;
586 int ret;199 int ret;
587 200
588 for_ftrace_rec_iter(iter) {201 for_ftrace_rec_iter(iter) {
589 rec = ftrace_rec_iter_record(iter);202 rec = ftrace_rec_iter_record(iter);
590 203
591 ret = add_breakpoints(rec, enable);204 switch (ftrace_test_record(rec, enable)) {
592 if (ret)205 case FTRACE_UPDATE_IGNORE:
593 goto remove_breakpoints;206 default:
594 count++;207 continue;
595 }
596
597 run_sync();
598 208
599 report = "updating code";209 case FTRACE_UPDATE_MAKE_CALL:
600 count = 0;210 old = ftrace_nop_replace();
211 break;
601 212
602 for_ftrace_rec_iter(iter) {213 case FTRACE_UPDATE_MODIFY_CALL:
603 rec = ftrace_rec_iter_record(iter);214 case FTRACE_UPDATE_MAKE_NOP:
215 old = ftrace_call_replace(rec->ip, ftrace_get_addr_curr(rec));
216 break;
217 }
604 218
605 ret = add_update(rec, enable);219 ret = ftrace_verify_code(rec->ip, old);
606 if (ret)220 if (ret) {
607 goto remove_breakpoints;221 ftrace_bug(ret, rec);
608 count++;222 return;
223 }
609 }224 }
610 225
611 run_sync();
612
613 report = "removing breakpoints";
614 count = 0;
615
616 for_ftrace_rec_iter(iter) {226 for_ftrace_rec_iter(iter) {
617 rec = ftrace_rec_iter_record(iter);227 rec = ftrace_rec_iter_record(iter);
618 228
619 ret = finish_update(rec, enable);229 switch (ftrace_test_record(rec, enable)) {
620 if (ret)230 case FTRACE_UPDATE_IGNORE:
621 goto remove_breakpoints;231 default:
622 count++;232 continue;
623 }
624 233
625 run_sync();234 case FTRACE_UPDATE_MAKE_CALL:
235 case FTRACE_UPDATE_MODIFY_CALL:
236 new = ftrace_call_replace(rec->ip, ftrace_get_addr_new(rec));
237 break;
626 238
627 return;239 case FTRACE_UPDATE_MAKE_NOP:
240 new = ftrace_nop_replace();
241 break;
242 }
628 243
629 remove_breakpoints:244 text_poke_queue((void *)rec->ip, new, MCOUNT_INSN_SIZE, NULL);
630 pr_warn("Failed on %s (%d):\n", report, count);245 ftrace_update_record(rec, enable);
631 ftrace_bug(ret, rec);
632 for_ftrace_rec_iter(iter) {
633 rec = ftrace_rec_iter_record(iter);
634 /*
635 * Breakpoints are handled only when this function is in
636 * progress. The system could not work with them.
637 */
638 if (remove_breakpoint(rec))
639 BUG();
640 }246 }
641 run_sync();247 text_poke_finish();
642}
643
644static int
645ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
646 unsigned const char *new_code)
647{
648 int ret;
649
650 ret = add_break(ip, old_code);
651 if (ret)
652 goto out;
653
654 run_sync();
655
656 ret = add_update_code(ip, new_code);
657 if (ret)
658 goto fail_update;
659
660 run_sync();
661
662 ret = ftrace_write(ip, new_code, 1);
663 /*
664 * The breakpoint is handled only when this function is in progress.
665 * The system could not work if we could not remove it.
666 */
667 BUG_ON(ret);
668 out:
669 run_sync();
670 return ret;
671
672 fail_update:
673 /* Also here the system could not work with the breakpoint */
674 if (ftrace_write(ip, old_code, 1))
675 BUG();
676 goto out;
677}248}
678 249
679void arch_ftrace_update_code(int command)250void arch_ftrace_update_code(int command)
680{251{
681 /* See comment above by declaration of modifying_ftrace_code */
682 atomic_inc(&modifying_ftrace_code);
683
684 ftrace_modify_all_code(command);252 ftrace_modify_all_code(command);
685
686 atomic_dec(&modifying_ftrace_code);
687}253}
688 254
689int __init ftrace_dyn_arch_init(void)255int __init ftrace_dyn_arch_init(void)
@@ -748,6 +314,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) · 58 unmodified lines
748 unsigned long start_offset;314 unsigned long start_offset;
749 unsigned long end_offset;315 unsigned long end_offset;
750 unsigned long op_offset;316 unsigned long op_offset;
317 unsigned long call_offset;
751 unsigned long offset;318 unsigned long offset;
752 unsigned long npages;319 unsigned long npages;
753 unsigned long size;320 unsigned long size;
@@ -764,10 +331,12 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) · 10 unmodified lines
764 start_offset = (unsigned long)ftrace_regs_caller;331 start_offset = (unsigned long)ftrace_regs_caller;
765 end_offset = (unsigned long)ftrace_regs_caller_end;332 end_offset = (unsigned long)ftrace_regs_caller_end;
766 op_offset = (unsigned long)ftrace_regs_caller_op_ptr;333 op_offset = (unsigned long)ftrace_regs_caller_op_ptr;
334 call_offset = (unsigned long)ftrace_regs_call;
767 } else {335 } else {
768 start_offset = (unsigned long)ftrace_caller;336 start_offset = (unsigned long)ftrace_caller;
769 end_offset = (unsigned long)ftrace_epilogue;337 end_offset = (unsigned long)ftrace_epilogue;
770 op_offset = (unsigned long)ftrace_caller_op_ptr;338 op_offset = (unsigned long)ftrace_caller_op_ptr;
339 call_offset = (unsigned long)ftrace_call;
771 }340 }
772 341
773 size = end_offset - start_offset;342 size = end_offset - start_offset;
@@ -824,16 +393,21 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) · 50 unmodified lines
824 /* put in the new offset to the ftrace_ops */393 /* put in the new offset to the ftrace_ops */
825 memcpy(trampoline + op_offset, &op_ptr, OP_REF_SIZE);394 memcpy(trampoline + op_offset, &op_ptr, OP_REF_SIZE);
826 395
396 /* put in the call to the function */
397 mutex_lock(&text_mutex);
398 call_offset -= start_offset;
399 memcpy(trampoline + call_offset,
400 text_gen_insn(CALL_INSN_OPCODE,
401 trampoline + call_offset,
402 ftrace_ops_get_func(ops)), CALL_INSN_SIZE);
403 mutex_unlock(&text_mutex);
404
827 /* ALLOC_TRAMP flags lets us know we created it */405 /* ALLOC_TRAMP flags lets us know we created it */
828 ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP;406 ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP;
829 407
830 set_vm_flush_reset_perms(trampoline);408 set_vm_flush_reset_perms(trampoline);
831 409
832 /*410 set_memory_ro((unsigned long)trampoline, npages);
833 * Module allocation needs to be completed by making the page
834 * executable. The page is still writable, which is a security hazard,
835 * but anyhow ftrace breaks W^X completely.
836 */
837 set_memory_x((unsigned long)trampoline, npages);411 set_memory_x((unsigned long)trampoline, npages);
838 return (unsigned long)trampoline;412 return (unsigned long)trampoline;
839fail:413fail:
@@ -860,62 +434,54 @@ static unsigned long calc_trampoline_call_offset(bool save_regs) · 20 unmodified lines
860void arch_ftrace_update_trampoline(struct ftrace_ops *ops)434void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
861{435{
862 ftrace_func_t func;436 ftrace_func_t func;
863 unsigned char *new;
864 unsigned long offset;437 unsigned long offset;
865 unsigned long ip;438 unsigned long ip;
866 unsigned int size;439 unsigned int size;
867 int ret, npages;440 const char *new;
868 441
869 if (ops->trampoline) {442 if (!ops->trampoline) {
870 /*
871 * The ftrace_ops caller may set up its own trampoline.
872 * In such a case, this code must not modify it.
873 */
874 if (!(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
875 return;
876 npages = PAGE_ALIGN(ops->trampoline_size) >> PAGE_SHIFT;
877 set_memory_rw(ops->trampoline, npages);
878 } else {
879 ops->trampoline = create_trampoline(ops, &size);443 ops->trampoline = create_trampoline(ops, &size);
880 if (!ops->trampoline)444 if (!ops->trampoline)
881 return;445 return;
882 ops->trampoline_size = size;446 ops->trampoline_size = size;
883 npages = PAGE_ALIGN(size) >> PAGE_SHIFT;447 return;
884 }448 }
885 449
450 /*
451 * The ftrace_ops caller may set up its own trampoline.
452 * In such a case, this code must not modify it.
453 */
454 if (!(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
455 return;
456
886 offset = calc_trampoline_call_offset(ops->flags & FTRACE_OPS_FL_SAVE_REGS);457 offset = calc_trampoline_call_offset(ops->flags & FTRACE_OPS_FL_SAVE_REGS);
887 ip = ops->trampoline + offset;458 ip = ops->trampoline + offset;
888
889 func = ftrace_ops_get_func(ops);459 func = ftrace_ops_get_func(ops);
890 460
891 ftrace_update_func_call = (unsigned long)func;461 mutex_lock(&text_mutex);
892
893 /* Do a safe modify in case the trampoline is executing */462 /* Do a safe modify in case the trampoline is executing */
894 new = ftrace_call_replace(ip, (unsigned long)func);463 new = ftrace_call_replace(ip, (unsigned long)func);
895 ret = update_ftrace_func(ip, new);464 text_poke_bp((void *)ip, new, MCOUNT_INSN_SIZE, NULL);
896 set_memory_ro(ops->trampoline, npages);465 mutex_unlock(&text_mutex);
897
898 /* The update should never fail */
899 WARN_ON(ret);
900}466}
901 467
902/* Return the address of the function the trampoline calls */468/* Return the address of the function the trampoline calls */
903static void *addr_from_call(void *ptr)469static void *addr_from_call(void *ptr)
904{470{
905 union ftrace_code_union calc;471 union text_poke_insn call;
906 int ret;472 int ret;
907 473
908 ret = probe_kernel_read(&calc, ptr, MCOUNT_INSN_SIZE);474 ret = probe_kernel_read(&call, ptr, CALL_INSN_SIZE);
909 if (WARN_ON_ONCE(ret < 0))475 if (WARN_ON_ONCE(ret < 0))
910 return NULL;476 return NULL;
911 477
912 /* Make sure this is a call */478 /* Make sure this is a call */
913 if (WARN_ON_ONCE(calc.op != 0xe8)) {479 if (WARN_ON_ONCE(call.opcode != CALL_INSN_OPCODE)) {
914 pr_warn("Expected e8, got %x\n", calc.op);480 pr_warn("Expected E8, got %x\n", call.opcode);
915 return NULL;481 return NULL;
916 }482 }
917 483
918 return ptr + MCOUNT_INSN_SIZE + calc.offset;484 return ptr + CALL_INSN_SIZE + call.disp;
919}485}
920 486
921void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,487void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
@@ -982,19 +548,18 @@ void arch_ftrace_trampoline_free(struct ftrace_ops *ops) · 60 unmodified lines
982#ifdef CONFIG_DYNAMIC_FTRACE548#ifdef CONFIG_DYNAMIC_FTRACE
983extern void ftrace_graph_call(void);549extern void ftrace_graph_call(void);
984 550
985static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)551static const char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)
986{552{
987 return ftrace_text_replace(0xe9, ip, addr);553 return text_gen_insn(JMP32_INSN_OPCODE, (void *)ip, (void *)addr);
988}554}
989 555
990static int ftrace_mod_jmp(unsigned long ip, void *func)556static int ftrace_mod_jmp(unsigned long ip, void *func)
991{557{
992 unsigned char *new;558 const char *new;
993 559
994 ftrace_update_func_call = 0UL;
995 new = ftrace_jmp_replace(ip, (unsigned long)func);560 new = ftrace_jmp_replace(ip, (unsigned long)func);
996 561 text_poke_bp((void *)ip, new, MCOUNT_INSN_SIZE, NULL);
997 return update_ftrace_func(ip, new);562 return 0;
998}563}
999 564
1000int ftrace_enable_ftrace_graph_caller(void)565int ftrace_enable_ftrace_graph_caller(void)
@@ -1020,10 +585,9 @@ int ftrace_disable_ftrace_graph_caller(void) · 19 unmodified lines
1020void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,585void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
1021 unsigned long frame_pointer)586 unsigned long frame_pointer)
1022{587{
588 unsigned long return_hooker = (unsigned long)&return_to_handler;
1023 unsigned long old;589 unsigned long old;
1024 int faulted;590 int faulted;
1025 unsigned long return_hooker = (unsigned long)
1026 &return_to_handler;
1027 591
1028 /*592 /*
1029 * When resuming from suspend-to-ram, this function can be indirectly593 * When resuming from suspend-to-ram, this function can be indirectly
arch/x86/kernel/jump_label.c+38−78
@@ -16,15 +16,7 @@ · 15 unmodified lines
16#include <asm/alternative.h>16#include <asm/alternative.h>
17#include <asm/text-patching.h>17#include <asm/text-patching.h>
18 18
19union jump_code_union {19static void bug_at(const void *ip, int line)
20 char code[JUMP_LABEL_NOP_SIZE];
21 struct {
22 char jump;
23 int offset;
24 } __attribute__((packed));
25};
26
27static void bug_at(unsigned char *ip, int line)
28{20{
29 /*21 /*
30 * The location is not an op that we were expecting.22 * The location is not an op that we were expecting.
@@ -35,42 +27,42 @@ static void bug_at(unsigned char *ip, int line) · 4 unmodified lines
35 BUG();27 BUG();
36}28}
37 29
38static void __jump_label_set_jump_code(struct jump_entry *entry,30static const void *
39 enum jump_label_type type,31__jump_label_set_jump_code(struct jump_entry *entry, enum jump_label_type type, int init)
40 union jump_code_union *code,
41 int init)
42{32{
43 const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };33 const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
44 const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];34 const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
45 const void *expect;35 const void *expect, *code;
36 const void *addr, *dest;
46 int line;37 int line;
47 38
48 code->jump = 0xe9;39 addr = (void *)jump_entry_code(entry);
49 code->offset = jump_entry_target(entry) -40 dest = (void *)jump_entry_target(entry);
50 (jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE);41
42 code = text_gen_insn(JMP32_INSN_OPCODE, addr, dest);
51 43
52 if (init) {44 if (init) {
53 expect = default_nop; line = __LINE__;45 expect = default_nop; line = __LINE__;
54 } else if (type == JUMP_LABEL_JMP) {46 } else if (type == JUMP_LABEL_JMP) {
55 expect = ideal_nop; line = __LINE__;47 expect = ideal_nop; line = __LINE__;
56 } else {48 } else {
57 expect = code->code; line = __LINE__;49 expect = code; line = __LINE__;
58 }50 }
59 51
60 if (memcmp((void *)jump_entry_code(entry), expect, JUMP_LABEL_NOP_SIZE))52 if (memcmp(addr, expect, JUMP_LABEL_NOP_SIZE))
61 bug_at((void *)jump_entry_code(entry), line);53 bug_at(addr, line);
62 54
63 if (type == JUMP_LABEL_NOP)55 if (type == JUMP_LABEL_NOP)
64 memcpy(code, ideal_nop, JUMP_LABEL_NOP_SIZE);56 code = ideal_nop;
57
58 return code;
65}59}
66 60
67static void __ref __jump_label_transform(struct jump_entry *entry,61static void inline __jump_label_transform(struct jump_entry *entry,
68 enum jump_label_type type,62 enum jump_label_type type,
69 int init)63 int init)
70{64{
71 union jump_code_union code;65 const void *opcode = __jump_label_set_jump_code(entry, type, init);
72
73 __jump_label_set_jump_code(entry, type, &code, init);
74 66
75 /*67 /*
76 * As long as only a single processor is running and the code is still68 * As long as only a single processor is running and the code is still
@@ -84,31 +76,33 @@ static void __ref __jump_label_transform(struct jump_entry *entry, · 7 unmodified lines
84 * always nop being the 'currently valid' instruction76 * always nop being the 'currently valid' instruction
85 */77 */
86 if (init || system_state == SYSTEM_BOOTING) {78 if (init || system_state == SYSTEM_BOOTING) {
87 text_poke_early((void *)jump_entry_code(entry), &code,79 text_poke_early((void *)jump_entry_code(entry), opcode,
88 JUMP_LABEL_NOP_SIZE);80 JUMP_LABEL_NOP_SIZE);
89 return;81 return;
90 }82 }
91 83
92 text_poke_bp((void *)jump_entry_code(entry), &code, JUMP_LABEL_NOP_SIZE, NULL);84 text_poke_bp((void *)jump_entry_code(entry), opcode, JUMP_LABEL_NOP_SIZE, NULL);
93}85}
94 86
95void arch_jump_label_transform(struct jump_entry *entry,87static void __ref jump_label_transform(struct jump_entry *entry,
96 enum jump_label_type type)88 enum jump_label_type type,
89 int init)
97{90{
98 mutex_lock(&text_mutex);91 mutex_lock(&text_mutex);
99 __jump_label_transform(entry, type, 0);92 __jump_label_transform(entry, type, init);
100 mutex_unlock(&text_mutex);93 mutex_unlock(&text_mutex);
101}94}
102 95
103#define TP_VEC_MAX (PAGE_SIZE / sizeof(struct text_poke_loc))96void arch_jump_label_transform(struct jump_entry *entry,
104static struct text_poke_loc tp_vec[TP_VEC_MAX];97 enum jump_label_type type)
105static int tp_vec_nr;98{
99 jump_label_transform(entry, type, 0);
100}
106 101
107bool arch_jump_label_transform_queue(struct jump_entry *entry,102bool arch_jump_label_transform_queue(struct jump_entry *entry,
108 enum jump_label_type type)103 enum jump_label_type type)
109{104{
110 struct text_poke_loc *tp;105 const void *opcode;
111 void *entry_code;
112 106
113 if (system_state == SYSTEM_BOOTING) {107 if (system_state == SYSTEM_BOOTING) {
114 /*108 /*
@@ -118,53 +112,19 @@ bool arch_jump_label_transform_queue(struct jump_entry *entry, · 3 unmodified lines
118 return true;112 return true;
119 }113 }
120 114
121 /*115 mutex_lock(&text_mutex);
122 * No more space in the vector, tell upper layer to apply116 opcode = __jump_label_set_jump_code(entry, type, 0);
123 * the queue before continuing.117 text_poke_queue((void *)jump_entry_code(entry),
124 */118 opcode, JUMP_LABEL_NOP_SIZE, NULL);
125 if (tp_vec_nr == TP_VEC_MAX)119 mutex_unlock(&text_mutex);
126 return false;
127
128 tp = &tp_vec[tp_vec_nr];
129
130 entry_code = (void *)jump_entry_code(entry);
131
132 /*
133 * The INT3 handler will do a bsearch in the queue, so we need entries
134 * to be sorted. We can survive an unsorted list by rejecting the entry,
135 * forcing the generic jump_label code to apply the queue. Warning once,
136 * to raise the attention to the case of an unsorted entry that is
137 * better not happen, because, in the worst case we will perform in the
138 * same way as we do without batching - with some more overhead.
139 */
140 if (tp_vec_nr > 0) {
141 int prev = tp_vec_nr - 1;
142 struct text_poke_loc *prev_tp = &tp_vec[prev];
143
144 if (WARN_ON_ONCE(prev_tp->addr > entry_code))
145 return false;
146 }
147
148 __jump_label_set_jump_code(entry, type,
149 (union jump_code_union *)&tp->text, 0);
150
151 text_poke_loc_init(tp, entry_code, NULL, JUMP_LABEL_NOP_SIZE, NULL);
152
153 tp_vec_nr++;
154
155 return true;120 return true;
156}121}
157 122
158void arch_jump_label_transform_apply(void)123void arch_jump_label_transform_apply(void)
159{124{
160 if (!tp_vec_nr)
161 return;
162
163 mutex_lock(&text_mutex);125 mutex_lock(&text_mutex);
164 text_poke_bp_batch(tp_vec, tp_vec_nr);126 text_poke_finish();
165 mutex_unlock(&text_mutex);127 mutex_unlock(&text_mutex);
166
167 tp_vec_nr = 0;
168}128}
169 129
170static enum {130static enum {
@@ -193,5 +153,5 @@ __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, · 22 unmodified lines
193 jlstate = JL_STATE_NO_UPDATE;153 jlstate = JL_STATE_NO_UPDATE;
194 }154 }
195 if (jlstate == JL_STATE_UPDATE)155 if (jlstate == JL_STATE_UPDATE)
196 __jump_label_transform(entry, type, 1);156 jump_label_transform(entry, type, 1);
197}157}
arch/x86/kernel/kprobes/core.c+11−9
@@ -120,14 +120,14 @@ __synthesize_relative_insn(void *dest, void *from, void *to, u8 op) · 119 unmodified lines
120/* Insert a jump instruction at address 'from', which jumps to address 'to'.*/120/* Insert a jump instruction at address 'from', which jumps to address 'to'.*/
121void synthesize_reljump(void *dest, void *from, void *to)121void synthesize_reljump(void *dest, void *from, void *to)
122{122{
123 __synthesize_relative_insn(dest, from, to, RELATIVEJUMP_OPCODE);123 __synthesize_relative_insn(dest, from, to, JMP32_INSN_OPCODE);
124}124}
125NOKPROBE_SYMBOL(synthesize_reljump);125NOKPROBE_SYMBOL(synthesize_reljump);
126 126
127/* Insert a call instruction at address 'from', which calls address 'to'.*/127/* Insert a call instruction at address 'from', which calls address 'to'.*/
128void synthesize_relcall(void *dest, void *from, void *to)128void synthesize_relcall(void *dest, void *from, void *to)
129{129{
130 __synthesize_relative_insn(dest, from, to, RELATIVECALL_OPCODE);130 __synthesize_relative_insn(dest, from, to, CALL_INSN_OPCODE);
131}131}
132NOKPROBE_SYMBOL(synthesize_relcall);132NOKPROBE_SYMBOL(synthesize_relcall);
133 133
@@ -302,7 +302,7 @@ static int can_probe(unsigned long paddr) · 168 unmodified lines
302 * Another debugging subsystem might insert this breakpoint.302 * Another debugging subsystem might insert this breakpoint.
303 * In that case, we can't recover it.303 * In that case, we can't recover it.
304 */304 */
305 if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)305 if (insn.opcode.bytes[0] == INT3_INSN_OPCODE)
306 return 0;306 return 0;
307 addr += insn.length;307 addr += insn.length;
308 }308 }
@@ -357,7 +357,7 @@ int __copy_instruction(u8 *dest, u8 *src, u8 *real, struct insn *insn) · 48 unmodified lines
357 return 0;357 return 0;
358 358
359 /* Another subsystem puts a breakpoint, failed to recover */359 /* Another subsystem puts a breakpoint, failed to recover */
360 if (insn->opcode.bytes[0] == BREAKPOINT_INSTRUCTION)360 if (insn->opcode.bytes[0] == INT3_INSN_OPCODE)
361 return 0;361 return 0;
362 362
363 /* We should not singlestep on the exception masking instructions */363 /* We should not singlestep on the exception masking instructions */
@@ -401,14 +401,14 @@ static int prepare_boost(kprobe_opcode_t *buf, struct kprobe *p, · 37 unmodified lines
401 int len = insn->length;401 int len = insn->length;
402 402
403 if (can_boost(insn, p->addr) &&403 if (can_boost(insn, p->addr) &&
404 MAX_INSN_SIZE - len >= RELATIVEJUMP_SIZE) {404 MAX_INSN_SIZE - len >= JMP32_INSN_SIZE) {
405 /*405 /*
406 * These instructions can be executed directly if it406 * These instructions can be executed directly if it
407 * jumps back to correct address.407 * jumps back to correct address.
408 */408 */
409 synthesize_reljump(buf + len, p->ainsn.insn + len,409 synthesize_reljump(buf + len, p->ainsn.insn + len,
410 p->addr + insn->length);410 p->addr + insn->length);
411 len += RELATIVEJUMP_SIZE;411 len += JMP32_INSN_SIZE;
412 p->ainsn.boostable = true;412 p->ainsn.boostable = true;
413 } else {413 } else {
414 p->ainsn.boostable = false;414 p->ainsn.boostable = false;
@@ -502,12 +502,14 @@ int arch_prepare_kprobe(struct kprobe *p) · 87 unmodified lines
502 502
503void arch_arm_kprobe(struct kprobe *p)503void arch_arm_kprobe(struct kprobe *p)
504{504{
505 text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);505 text_poke(p->addr, ((unsigned char []){INT3_INSN_OPCODE}), 1);
506 text_poke_sync();
506}507}
507 508
508void arch_disarm_kprobe(struct kprobe *p)509void arch_disarm_kprobe(struct kprobe *p)
509{510{
510 text_poke(p->addr, &p->opcode, 1);511 text_poke(p->addr, &p->opcode, 1);
512 text_poke_sync();
511}513}
512 514
513void arch_remove_kprobe(struct kprobe *p)515void arch_remove_kprobe(struct kprobe *p)
@@ -610,7 +612,7 @@ static void setup_singlestep(struct kprobe *p, struct pt_regs *regs, · 96 unmodified lines
610 regs->flags |= X86_EFLAGS_TF;612 regs->flags |= X86_EFLAGS_TF;
611 regs->flags &= ~X86_EFLAGS_IF;613 regs->flags &= ~X86_EFLAGS_IF;
612 /* single step inline if the instruction is an int3 */614 /* single step inline if the instruction is an int3 */
613 if (p->opcode == BREAKPOINT_INSTRUCTION)615 if (p->opcode == INT3_INSN_OPCODE)
614 regs->ip = (unsigned long)p->addr;616 regs->ip = (unsigned long)p->addr;
615 else617 else
616 regs->ip = (unsigned long)p->ainsn.insn;618 regs->ip = (unsigned long)p->ainsn.insn;
@@ -696,7 +698,7 @@ int kprobe_int3_handler(struct pt_regs *regs) · 79 unmodified lines
696 reset_current_kprobe();698 reset_current_kprobe();
697 return 1;699 return 1;
698 }700 }
699 } else if (*addr != BREAKPOINT_INSTRUCTION) {701 } else if (*addr != INT3_INSN_OPCODE) {
700 /*702 /*
701 * The breakpoint instruction was removed right703 * The breakpoint instruction was removed right
702 * after we hit it. Another cpu has removed704 * after we hit it. Another cpu has removed
arch/x86/kernel/kprobes/opt.c+33−34
@@ -38,7 +38,7 @@ unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr) · 37 unmodified lines
38 long offs;38 long offs;
39 int i;39 int i;
40 40
41 for (i = 0; i < RELATIVEJUMP_SIZE; i++) {41 for (i = 0; i < JMP32_INSN_SIZE; i++) {
42 kp = get_kprobe((void *)addr - i);42 kp = get_kprobe((void *)addr - i);
43 /* This function only handles jump-optimized kprobe */43 /* This function only handles jump-optimized kprobe */
44 if (kp && kprobe_optimized(kp)) {44 if (kp && kprobe_optimized(kp)) {
@@ -62,10 +62,10 @@ found: · 17 unmodified lines
62 62
63 if (addr == (unsigned long)kp->addr) {63 if (addr == (unsigned long)kp->addr) {
64 buf[0] = kp->opcode;64 buf[0] = kp->opcode;
65 memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);65 memcpy(buf + 1, op->optinsn.copied_insn, DISP32_SIZE);
66 } else {66 } else {
67 offs = addr - (unsigned long)kp->addr - 1;67 offs = addr - (unsigned long)kp->addr - 1;
68 memcpy(buf, op->optinsn.copied_insn + offs, RELATIVE_ADDR_SIZE - offs);68 memcpy(buf, op->optinsn.copied_insn + offs, DISP32_SIZE - offs);
69 }69 }
70 70
71 return (unsigned long)buf;71 return (unsigned long)buf;
@@ -141,8 +141,6 @@ STACK_FRAME_NON_STANDARD(optprobe_template_func); · 69 unmodified lines
141#define TMPL_END_IDX \141#define TMPL_END_IDX \
142 ((long)optprobe_template_end - (long)optprobe_template_entry)142 ((long)optprobe_template_end - (long)optprobe_template_entry)
143 143
144#define INT3_SIZE sizeof(kprobe_opcode_t)
145
146/* Optimized kprobe call back function: called from optinsn */144/* Optimized kprobe call back function: called from optinsn */
147static void145static void
148optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)146optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
@@ -162,7 +160,7 @@ optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) · 13 unmodified lines
162 regs->cs |= get_kernel_rpl();160 regs->cs |= get_kernel_rpl();
163 regs->gs = 0;161 regs->gs = 0;
164#endif162#endif
165 regs->ip = (unsigned long)op->kp.addr + INT3_SIZE;163 regs->ip = (unsigned long)op->kp.addr + INT3_INSN_SIZE;
166 regs->orig_ax = ~0UL;164 regs->orig_ax = ~0UL;
167 165
168 __this_cpu_write(current_kprobe, &op->kp);166 __this_cpu_write(current_kprobe, &op->kp);
@@ -179,7 +177,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real) · 10 unmodified lines
179 struct insn insn;177 struct insn insn;
180 int len = 0, ret;178 int len = 0, ret;
181 179
182 while (len < RELATIVEJUMP_SIZE) {180 while (len < JMP32_INSN_SIZE) {
183 ret = __copy_instruction(dest + len, src + len, real + len, &insn);181 ret = __copy_instruction(dest + len, src + len, real + len, &insn);
184 if (!ret || !can_boost(&insn, src + len))182 if (!ret || !can_boost(&insn, src + len))
185 return -EINVAL;183 return -EINVAL;
@@ -271,7 +269,7 @@ static int can_optimize(unsigned long paddr) · 85 unmodified lines
271 return 0;269 return 0;
272 270
273 /* Check there is enough space for a relative jump. */271 /* Check there is enough space for a relative jump. */
274 if (size - offset < RELATIVEJUMP_SIZE)272 if (size - offset < JMP32_INSN_SIZE)
275 return 0;273 return 0;
276 274
277 /* Decode instructions */275 /* Decode instructions */
@@ -290,15 +288,15 @@ static int can_optimize(unsigned long paddr) · 12 unmodified lines
290 kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);288 kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
291 insn_get_length(&insn);289 insn_get_length(&insn);
292 /* Another subsystem puts a breakpoint */290 /* Another subsystem puts a breakpoint */
293 if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)291 if (insn.opcode.bytes[0] == INT3_INSN_OPCODE)
294 return 0;292 return 0;
295 /* Recover address */293 /* Recover address */
296 insn.kaddr = (void *)addr;294 insn.kaddr = (void *)addr;
297 insn.next_byte = (void *)(addr + insn.length);295 insn.next_byte = (void *)(addr + insn.length);
298 /* Check any instructions don't jump into target */296 /* Check any instructions don't jump into target */
299 if (insn_is_indirect_jump(&insn) ||297 if (insn_is_indirect_jump(&insn) ||
300 insn_jump_into_range(&insn, paddr + INT3_SIZE,298 insn_jump_into_range(&insn, paddr + INT3_INSN_SIZE,
301 RELATIVE_ADDR_SIZE))299 DISP32_SIZE))
302 return 0;300 return 0;
303 addr += insn.length;301 addr += insn.length;
304 }302 }
@@ -374,7 +372,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, · 69 unmodified lines
374 * Verify if the address gap is in 2GB range, because this uses372 * Verify if the address gap is in 2GB range, because this uses
375 * a relative jump.373 * a relative jump.
376 */374 */
377 rel = (long)slot - (long)op->kp.addr + RELATIVEJUMP_SIZE;375 rel = (long)slot - (long)op->kp.addr + JMP32_INSN_SIZE;
378 if (abs(rel) > 0x7fffffff) {376 if (abs(rel) > 0x7fffffff) {
379 ret = -ERANGE;377 ret = -ERANGE;
380 goto err;378 goto err;
@@ -401,7 +399,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, · 20 unmodified lines
401 /* Set returning jmp instruction at the tail of out-of-line buffer */399 /* Set returning jmp instruction at the tail of out-of-line buffer */
402 synthesize_reljump(buf + len, slot + len,400 synthesize_reljump(buf + len, slot + len,
403 (u8 *)op->kp.addr + op->optinsn.size);401 (u8 *)op->kp.addr + op->optinsn.size);
404 len += RELATIVEJUMP_SIZE;402 len += JMP32_INSN_SIZE;
405 403
406 /* We have to use text_poke() for instruction buffer because it is RO */404 /* We have to use text_poke() for instruction buffer because it is RO */
407 text_poke(slot, buf, len);405 text_poke(slot, buf, len);
@@ -416,49 +414,50 @@ err: · 8 unmodified lines
416}414}
417 415
418/*416/*
419 * Replace breakpoints (int3) with relative jumps.417 * Replace breakpoints (INT3) with relative jumps (JMP.d32).
420 * Caller must call with locking kprobe_mutex and text_mutex.418 * Caller must call with locking kprobe_mutex and text_mutex.
419 *
420 * The caller will have installed a regular kprobe and after that issued
421 * syncrhonize_rcu_tasks(), this ensures that the instruction(s) that live in
422 * the 4 bytes after the INT3 are unused and can now be overwritten.
421 */423 */
422void arch_optimize_kprobes(struct list_head *oplist)424void arch_optimize_kprobes(struct list_head *oplist)
423{425{
424 struct optimized_kprobe *op, *tmp;426 struct optimized_kprobe *op, *tmp;
425 u8 insn_buff[RELATIVEJUMP_SIZE];427 u8 insn_buff[JMP32_INSN_SIZE];
426 428
427 list_for_each_entry_safe(op, tmp, oplist, list) {429 list_for_each_entry_safe(op, tmp, oplist, list) {
428 s32 rel = (s32)((long)op->optinsn.insn -430 s32 rel = (s32)((long)op->optinsn.insn -
429 ((long)op->kp.addr + RELATIVEJUMP_SIZE));431 ((long)op->kp.addr + JMP32_INSN_SIZE));
430 432
431 WARN_ON(kprobe_disabled(&op->kp));433 WARN_ON(kprobe_disabled(&op->kp));
432 434
433 /* Backup instructions which will be replaced by jump address */435 /* Backup instructions which will be replaced by jump address */
434 memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE,436 memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_INSN_SIZE,
435 RELATIVE_ADDR_SIZE);437 DISP32_SIZE);
436 438
437 insn_buff[0] = RELATIVEJUMP_OPCODE;439 insn_buff[0] = JMP32_INSN_OPCODE;
438 *(s32 *)(&insn_buff[1]) = rel;440 *(s32 *)(&insn_buff[1]) = rel;
439 441
440 text_poke_bp(op->kp.addr, insn_buff, RELATIVEJUMP_SIZE, NULL);442 text_poke_bp(op->kp.addr, insn_buff, JMP32_INSN_SIZE, NULL);
441 443
442 list_del_init(&op->list);444 list_del_init(&op->list);
443 }445 }
444}446}
445 447
446/* Replace a relative jump with a breakpoint (int3). */448/*
449 * Replace a relative jump (JMP.d32) with a breakpoint (INT3).
450 *
451 * After that, we can restore the 4 bytes after the INT3 to undo what
452 * arch_optimize_kprobes() scribbled. This is safe since those bytes will be
453 * unused once the INT3 lands.
454 */
447void arch_unoptimize_kprobe(struct optimized_kprobe *op)455void arch_unoptimize_kprobe(struct optimized_kprobe *op)
448{456{
449 u8 insn_buff[RELATIVEJUMP_SIZE];457 arch_arm_kprobe(&op->kp);
450 u8 emulate_buff[RELATIVEJUMP_SIZE];458 text_poke(op->kp.addr + INT3_INSN_SIZE,
451 459 op->optinsn.copied_insn, DISP32_SIZE);
452 /* Set int3 to first byte for kprobes */460 text_poke_sync();
453 insn_buff[0] = BREAKPOINT_INSTRUCTION;
454 memcpy(insn_buff + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
455
456 emulate_buff[0] = RELATIVEJUMP_OPCODE;
457 *(s32 *)(&emulate_buff[1]) = (s32)((long)op->optinsn.insn -
458 ((long)op->kp.addr + RELATIVEJUMP_SIZE));
459
460 text_poke_bp(op->kp.addr, insn_buff, RELATIVEJUMP_SIZE,
461 emulate_buff);
462}461}
463 462
464/*463/*
arch/x86/kernel/traps.c+0−9
@@ -572,15 +572,6 @@ NOKPROBE_SYMBOL(do_general_protection); · 571 unmodified lines
572 572
573dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)573dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
574{574{
575#ifdef CONFIG_DYNAMIC_FTRACE
576 /*
577 * ftrace must be first, everything else may cause a recursive crash.
578 * See note by declaration of modifying_ftrace_code in ftrace.c
579 */
580 if (unlikely(atomic_read(&modifying_ftrace_code)) &&
581 ftrace_int3_handler(regs))
582 return;
583#endif
584 if (poke_int3_handler(regs))575 if (poke_int3_handler(regs))
585 return;576 return;
586 577
arch/x86/mm/init_32.c+0−28
@@ -873,34 +873,6 @@ void arch_remove_memory(int nid, u64 start, u64 size, · 872 unmodified lines
873 873
874int kernel_set_to_readonly __read_mostly;874int kernel_set_to_readonly __read_mostly;
875 875
876void set_kernel_text_rw(void)
877{
878 unsigned long start = PFN_ALIGN(_text);
879 unsigned long size = PFN_ALIGN(_etext) - start;
880
881 if (!kernel_set_to_readonly)
882 return;
883
884 pr_debug("Set kernel text: %lx - %lx for read write\n",
885 start, start+size);
886
887 set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT);
888}
889
890void set_kernel_text_ro(void)
891{
892 unsigned long start = PFN_ALIGN(_text);
893 unsigned long size = PFN_ALIGN(_etext) - start;
894
895 if (!kernel_set_to_readonly)
896 return;
897
898 pr_debug("Set kernel text: %lx - %lx for read only\n",
899 start, start+size);
900
901 set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
902}
903
904static void mark_nxdata_nx(void)876static void mark_nxdata_nx(void)
905{877{
906 /*878 /*
arch/x86/mm/init_64.c+0−36
@@ -1258,42 +1258,6 @@ void __init mem_init(void) · 1257 unmodified lines
1258 1258
1259int kernel_set_to_readonly;1259int kernel_set_to_readonly;
1260 1260
1261void set_kernel_text_rw(void)
1262{
1263 unsigned long start = PFN_ALIGN(_text);
1264 unsigned long end = PFN_ALIGN(_etext);
1265
1266 if (!kernel_set_to_readonly)
1267 return;
1268
1269 pr_debug("Set kernel text: %lx - %lx for read write\n",
1270 start, end);
1271
1272 /*
1273 * Make the kernel identity mapping for text RW. Kernel text
1274 * mapping will always be RO. Refer to the comment in
1275 * static_protections() in pageattr.c
1276 */
1277 set_memory_rw(start, (end - start) >> PAGE_SHIFT);
1278}
1279
1280void set_kernel_text_ro(void)
1281{
1282 unsigned long start = PFN_ALIGN(_text);
1283 unsigned long end = PFN_ALIGN(_etext);
1284
1285 if (!kernel_set_to_readonly)
1286 return;
1287
1288 pr_debug("Set kernel text: %lx - %lx for read only\n",
1289 start, end);
1290
1291 /*
1292 * Set the kernel identity mapping for text RO.
1293 */
1294 set_memory_ro(start, (end - start) >> PAGE_SHIFT);
1295}
1296
1297void mark_rodata_ro(void)1261void mark_rodata_ro(void)
1298{1262{
1299 unsigned long start = PFN_ALIGN(_text);1263 unsigned long start = PFN_ALIGN(_text);
drivers/infiniband/hw/hfi1/trace_tid.h+4−4
@@ -138,10 +138,10 @@ TRACE_EVENT(/* put_tid */ · 137 unmodified lines
138 TP_ARGS(dd, index, type, pa, order),138 TP_ARGS(dd, index, type, pa, order),
139 TP_STRUCT__entry(/* entry */139 TP_STRUCT__entry(/* entry */
140 DD_DEV_ENTRY(dd)140 DD_DEV_ENTRY(dd)
141 __field(unsigned long, pa);141 __field(unsigned long, pa)
142 __field(u32, index);142 __field(u32, index)
143 __field(u32, type);143 __field(u32, type)
144 __field(u16, order);144 __field(u16, order)
145 ),145 ),
146 TP_fast_assign(/* assign */146 TP_fast_assign(/* assign */
147 DD_DEV_ASSIGN(dd);147 DD_DEV_ASSIGN(dd);
drivers/infiniband/hw/hfi1/trace_tx.h+1−1
@@ -588,7 +588,7 @@ TRACE_EVENT(hfi1_sdma_user_reqinfo, · 587 unmodified lines
588 TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 *i),588 TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 *i),
589 TP_ARGS(dd, ctxt, subctxt, i),589 TP_ARGS(dd, ctxt, subctxt, i),
590 TP_STRUCT__entry(590 TP_STRUCT__entry(
591 DD_DEV_ENTRY(dd);591 DD_DEV_ENTRY(dd)
592 __field(u16, ctxt)592 __field(u16, ctxt)
593 __field(u8, subctxt)593 __field(u8, subctxt)
594 __field(u8, ver_opcode)594 __field(u8, ver_opcode)
drivers/lightnvm/pblk-trace.h+4−4
@@ -46,7 +46,7 @@ TRACE_EVENT(pblk_chunk_reset, · 45 unmodified lines
46 TP_STRUCT__entry(46 TP_STRUCT__entry(
47 __string(name, name)47 __string(name, name)
48 __field(u64, ppa)48 __field(u64, ppa)
49 __field(int, state);49 __field(int, state)
50 ),50 ),
51 51
52 TP_fast_assign(52 TP_fast_assign(
@@ -72,7 +72,7 @@ TRACE_EVENT(pblk_chunk_state, · 19 unmodified lines
72 TP_STRUCT__entry(72 TP_STRUCT__entry(
73 __string(name, name)73 __string(name, name)
74 __field(u64, ppa)74 __field(u64, ppa)
75 __field(int, state);75 __field(int, state)
76 ),76 ),
77 77
78 TP_fast_assign(78 TP_fast_assign(
@@ -98,7 +98,7 @@ TRACE_EVENT(pblk_line_state, · 19 unmodified lines
98 TP_STRUCT__entry(98 TP_STRUCT__entry(
99 __string(name, name)99 __string(name, name)
100 __field(int, line)100 __field(int, line)
101 __field(int, state);101 __field(int, state)
102 ),102 ),
103 103
104 TP_fast_assign(104 TP_fast_assign(
@@ -121,7 +121,7 @@ TRACE_EVENT(pblk_state, · 16 unmodified lines
121 121
122 TP_STRUCT__entry(122 TP_STRUCT__entry(
123 __string(name, name)123 __string(name, name)
124 __field(int, state);124 __field(int, state)
125 ),125 ),
126 126
127 TP_fast_assign(127 TP_fast_assign(
drivers/net/fjes/fjes_trace.h+1−1
@@ -28,7 +28,7 @@ TRACE_EVENT(fjes_hw_issue_request_command, · 27 unmodified lines
28 __field(u8, cs_busy)28 __field(u8, cs_busy)
29 __field(u8, cs_complete)29 __field(u8, cs_complete)
30 __field(int, timeout)30 __field(int, timeout)
31 __field(int, ret);31 __field(int, ret)
32 ),32 ),
33 TP_fast_assign(33 TP_fast_assign(
34 __entry->cr_req = cr->bits.req_code;34 __entry->cr_req = cr->bits.req_code;
drivers/net/wireless/ath/ath10k/trace.h+3−3
@@ -239,7 +239,7 @@ TRACE_EVENT(ath10k_wmi_dbglog, · 238 unmodified lines
239 TP_STRUCT__entry(239 TP_STRUCT__entry(
240 __string(device, dev_name(ar->dev))240 __string(device, dev_name(ar->dev))
241 __string(driver, dev_driver_string(ar->dev))241 __string(driver, dev_driver_string(ar->dev))
242 __field(u8, hw_type);242 __field(u8, hw_type)
243 __field(size_t, buf_len)243 __field(size_t, buf_len)
244 __dynamic_array(u8, buf, buf_len)244 __dynamic_array(u8, buf, buf_len)
245 ),245 ),
@@ -269,7 +269,7 @@ TRACE_EVENT(ath10k_htt_pktlog, · 23 unmodified lines
269 TP_STRUCT__entry(269 TP_STRUCT__entry(
270 __string(device, dev_name(ar->dev))270 __string(device, dev_name(ar->dev))
271 __string(driver, dev_driver_string(ar->dev))271 __string(driver, dev_driver_string(ar->dev))
272 __field(u8, hw_type);272 __field(u8, hw_type)
273 __field(u16, buf_len)273 __field(u16, buf_len)
274 __dynamic_array(u8, pktlog, buf_len)274 __dynamic_array(u8, pktlog, buf_len)
275 ),275 ),
@@ -435,7 +435,7 @@ TRACE_EVENT(ath10k_htt_rx_desc, · 159 unmodified lines
435 TP_STRUCT__entry(435 TP_STRUCT__entry(
436 __string(device, dev_name(ar->dev))436 __string(device, dev_name(ar->dev))
437 __string(driver, dev_driver_string(ar->dev))437 __string(driver, dev_driver_string(ar->dev))
438 __field(u8, hw_type);438 __field(u8, hw_type)
439 __field(u16, len)439 __field(u16, len)
440 __dynamic_array(u8, rxdesc, len)440 __dynamic_array(u8, rxdesc, len)
441 ),441 ),
fs/xfs/scrub/trace.h+3−3
@@ -329,7 +329,7 @@ TRACE_EVENT(xchk_btree_op_error, · 328 unmodified lines
329 __field(int, level)329 __field(int, level)
330 __field(xfs_agnumber_t, agno)330 __field(xfs_agnumber_t, agno)
331 __field(xfs_agblock_t, bno)331 __field(xfs_agblock_t, bno)
332 __field(int, ptr);332 __field(int, ptr)
333 __field(int, error)333 __field(int, error)
334 __field(void *, ret_ip)334 __field(void *, ret_ip)
335 ),335 ),
@@ -414,7 +414,7 @@ TRACE_EVENT(xchk_btree_error, · 78 unmodified lines
414 __field(int, level)414 __field(int, level)
415 __field(xfs_agnumber_t, agno)415 __field(xfs_agnumber_t, agno)
416 __field(xfs_agblock_t, bno)416 __field(xfs_agblock_t, bno)
417 __field(int, ptr);417 __field(int, ptr)
418 __field(void *, ret_ip)418 __field(void *, ret_ip)
419 ),419 ),
420 TP_fast_assign(420 TP_fast_assign(
@@ -452,7 +452,7 @@ TRACE_EVENT(xchk_ifork_btree_error, · 31 unmodified lines
452 __field(int, level)452 __field(int, level)
453 __field(xfs_agnumber_t, agno)453 __field(xfs_agnumber_t, agno)
454 __field(xfs_agblock_t, bno)454 __field(xfs_agblock_t, bno)
455 __field(int, ptr);455 __field(int, ptr)
456 __field(void *, ret_ip)456 __field(void *, ret_ip)
457 ),457 ),
458 TP_fast_assign(458 TP_fast_assign(
fs/xfs/xfs_trace.h+2−2
@@ -218,8 +218,8 @@ DECLARE_EVENT_CLASS(xfs_bmap_class, · 217 unmodified lines
218 TP_STRUCT__entry(218 TP_STRUCT__entry(
219 __field(dev_t, dev)219 __field(dev_t, dev)
220 __field(xfs_ino_t, ino)220 __field(xfs_ino_t, ino)
221 __field(void *, leaf);221 __field(void *, leaf)
222 __field(int, pos);222 __field(int, pos)
223 __field(xfs_fileoff_t, startoff)223 __field(xfs_fileoff_t, startoff)
224 __field(xfs_fsblock_t, startblock)224 __field(xfs_fsblock_t, startblock)
225 __field(xfs_filblks_t, blockcount)225 __field(xfs_filblks_t, blockcount)
include/linux/module.h+0−4
@@ -849,13 +849,9 @@ extern int module_sysfs_initialized; · 848 unmodified lines
849#define __MODULE_STRING(x) __stringify(x)849#define __MODULE_STRING(x) __stringify(x)
850 850
851#ifdef CONFIG_STRICT_MODULE_RWX851#ifdef CONFIG_STRICT_MODULE_RWX
852extern void set_all_modules_text_rw(void);
853extern void set_all_modules_text_ro(void);
854extern void module_enable_ro(const struct module *mod, bool after_init);852extern void module_enable_ro(const struct module *mod, bool after_init);
855extern void module_disable_ro(const struct module *mod);853extern void module_disable_ro(const struct module *mod);
856#else854#else
857static inline void set_all_modules_text_rw(void) { }
858static inline void set_all_modules_text_ro(void) { }
859static inline void module_enable_ro(const struct module *mod, bool after_init) { }855static inline void module_enable_ro(const struct module *mod, bool after_init) { }
860static inline void module_disable_ro(const struct module *mod) { }856static inline void module_disable_ro(const struct module *mod) { }
861#endif857#endif
include/linux/trace_events.h+17−1
@@ -192,6 +192,22 @@ enum trace_reg { · 191 unmodified lines
192 192
193struct trace_event_call;193struct trace_event_call;
194 194
195#define TRACE_FUNCTION_TYPE ((const char *)~0UL)
196
197struct trace_event_fields {
198 const char *type;
199 union {
200 struct {
201 const char *name;
202 const int size;
203 const int align;
204 const int is_signed;
205 const int filter_type;
206 };
207 int (*define_fields)(struct trace_event_call *);
208 };
209};
210
195struct trace_event_class {211struct trace_event_class {
196 const char *system;212 const char *system;
197 void *probe;213 void *probe;
@@ -200,7 +216,7 @@ struct trace_event_class { · 2 unmodified lines
200#endif216#endif
201 int (*reg)(struct trace_event_call *event,217 int (*reg)(struct trace_event_call *event,
202 enum trace_reg type, void *data);218 enum trace_reg type, void *data);
203 int (*define_fields)(struct trace_event_call *);219 struct trace_event_fields *fields_array;
204 struct list_head *(*get_fields)(struct trace_event_call *);220 struct list_head *(*get_fields)(struct trace_event_call *);
205 struct list_head fields;221 struct list_head fields;
206 int (*raw_init)(struct trace_event_call *);222 int (*raw_init)(struct trace_event_call *);
include/trace/events/filemap.h+1−1
@@ -85,7 +85,7 @@ TRACE_EVENT(file_check_and_advance_wb_err, · 84 unmodified lines
85 TP_ARGS(file, old),85 TP_ARGS(file, old),
86 86
87 TP_STRUCT__entry(87 TP_STRUCT__entry(
88 __field(struct file *, file);88 __field(struct file *, file)
89 __field(unsigned long, i_ino)89 __field(unsigned long, i_ino)
90 __field(dev_t, s_dev)90 __field(dev_t, s_dev)
91 __field(errseq_t, old)91 __field(errseq_t, old)
include/trace/trace_events.h+21−43
@@ -400,22 +400,16 @@ static struct trace_event_functions trace_event_type_funcs_##call = { \ · 399 unmodified lines
400#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)400#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
401 401
402#undef __field_ext402#undef __field_ext
403#define __field_ext(type, item, filter_type) \403#define __field_ext(_type, _item, _filter_type) { \
404 ret = trace_define_field(event_call, #type, #item, \404 .type = #_type, .name = #_item, \
405 offsetof(typeof(field), item), \405 .size = sizeof(_type), .align = __alignof__(_type), \
406 sizeof(field.item), \406 .is_signed = is_signed_type(_type), .filter_type = _filter_type },
407 is_signed_type(type), filter_type); \
408 if (ret) \
409 return ret;
410 407
411#undef __field_struct_ext408#undef __field_struct_ext
412#define __field_struct_ext(type, item, filter_type) \409#define __field_struct_ext(_type, _item, _filter_type) { \
413 ret = trace_define_field(event_call, #type, #item, \410 .type = #_type, .name = #_item, \
414 offsetof(typeof(field), item), \411 .size = sizeof(_type), .align = __alignof__(_type), \
415 sizeof(field.item), \412 0, .filter_type = _filter_type },
416 0, filter_type); \
417 if (ret) \
418 return ret;
419 413
420#undef __field414#undef __field
421#define __field(type, item) __field_ext(type, item, FILTER_OTHER)415#define __field(type, item) __field_ext(type, item, FILTER_OTHER)
@@ -424,25 +418,16 @@ static struct trace_event_functions trace_event_type_funcs_##call = { \ · 2 unmodified lines
424#define __field_struct(type, item) __field_struct_ext(type, item, FILTER_OTHER)418#define __field_struct(type, item) __field_struct_ext(type, item, FILTER_OTHER)
425 419
426#undef __array420#undef __array
427#define __array(type, item, len) \421#define __array(_type, _item, _len) { \
428 do { \422 .type = #_type"["__stringify(_len)"]", .name = #_item, \
429 char *type_str = #type"["__stringify(len)"]"; \423 .size = sizeof(_type[_len]), .align = __alignof__(_type), \
430 BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \424 .is_signed = is_signed_type(_type), .filter_type = FILTER_OTHER },
431 BUILD_BUG_ON(len <= 0); \
432 ret = trace_define_field(event_call, type_str, #item, \
433 offsetof(typeof(field), item), \
434 sizeof(field.item), \
435 is_signed_type(type), FILTER_OTHER); \
436 if (ret) \
437 return ret; \
438 } while (0);
439 425
440#undef __dynamic_array426#undef __dynamic_array
441#define __dynamic_array(type, item, len) \427#define __dynamic_array(_type, _item, _len) { \
442 ret = trace_define_field(event_call, "__data_loc " #type "[]", #item, \428 .type = "__data_loc " #_type "[]", .name = #_item, \
443 offsetof(typeof(field), __data_loc_##item), \429 .size = 4, .align = 4, \
444 sizeof(field.__data_loc_##item), \430 .is_signed = is_signed_type(_type), .filter_type = FILTER_OTHER },
445 is_signed_type(type), FILTER_OTHER);
446 431
447#undef __string432#undef __string
448#define __string(item, src) __dynamic_array(char, item, -1)433#define __string(item, src) __dynamic_array(char, item, -1)
@@ -452,16 +437,9 @@ static struct trace_event_functions trace_event_type_funcs_##call = { \ · 3 unmodified lines
452 437
453#undef DECLARE_EVENT_CLASS438#undef DECLARE_EVENT_CLASS
454#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print) \439#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print) \
455static int notrace __init \440static struct trace_event_fields trace_event_fields_##call[] = { \
456trace_event_define_fields_##call(struct trace_event_call *event_call) \441 tstruct \
457{ \442 {} };
458 struct trace_event_raw_##call field; \
459 int ret; \
460 \
461 tstruct; \
462 \
463 return ret; \
464}
465 443
466#undef DEFINE_EVENT444#undef DEFINE_EVENT
467#define DEFINE_EVENT(template, name, proto, args)445#define DEFINE_EVENT(template, name, proto, args)
@@ -619,7 +597,7 @@ static inline notrace int trace_event_get_offsets_##call( \ · 151 unmodified lines
619 *597 *
620 * static struct trace_event_class __used event_class_<template> = {598 * static struct trace_event_class __used event_class_<template> = {
621 * .system = "<system>",599 * .system = "<system>",
622 * .define_fields = trace_event_define_fields_<call>,600 * .fields_array = trace_event_fields_<call>,
623 * .fields = LIST_HEAD_INIT(event_class_##call.fields),601 * .fields = LIST_HEAD_INIT(event_class_##call.fields),
624 * .raw_init = trace_event_raw_init,602 * .raw_init = trace_event_raw_init,
625 * .probe = trace_event_raw_event_##call,603 * .probe = trace_event_raw_event_##call,
@@ -768,7 +746,7 @@ _TRACE_PERF_PROTO(call, PARAMS(proto)); \ · 142 unmodified lines
768static char print_fmt_##call[] = print; \746static char print_fmt_##call[] = print; \
769static struct trace_event_class __used __refdata event_class_##call = { \747static struct trace_event_class __used __refdata event_class_##call = { \
770 .system = TRACE_SYSTEM_STRING, \748 .system = TRACE_SYSTEM_STRING, \
771 .define_fields = trace_event_define_fields_##call, \749 .fields_array = trace_event_fields_##call, \
772 .fields = LIST_HEAD_INIT(event_class_##call.fields),\750 .fields = LIST_HEAD_INIT(event_class_##call.fields),\
773 .raw_init = trace_event_raw_init, \751 .raw_init = trace_event_raw_init, \
774 .probe = trace_event_raw_event_##call, \752 .probe = trace_event_raw_event_##call, \
kernel/kprobes.c+46−25
@@ -510,6 +510,8 @@ static void do_unoptimize_kprobes(void) · 509 unmodified lines
510 arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);510 arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
511 /* Loop free_list for disarming */511 /* Loop free_list for disarming */
512 list_for_each_entry_safe(op, tmp, &freeing_list, list) {512 list_for_each_entry_safe(op, tmp, &freeing_list, list) {
513 /* Switching from detour code to origin */
514 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
513 /* Disarm probes if marked disabled */515 /* Disarm probes if marked disabled */
514 if (kprobe_disabled(&op->kp))516 if (kprobe_disabled(&op->kp))
515 arch_disarm_kprobe(&op->kp);517 arch_disarm_kprobe(&op->kp);
@@ -610,6 +612,18 @@ void wait_for_kprobe_optimizer(void) · 94 unmodified lines
610 mutex_unlock(&kprobe_mutex);612 mutex_unlock(&kprobe_mutex);
611}613}
612 614
615static bool optprobe_queued_unopt(struct optimized_kprobe *op)
616{
617 struct optimized_kprobe *_op;
618
619 list_for_each_entry(_op, &unoptimizing_list, list) {
620 if (op == _op)
621 return true;
622 }
623
624 return false;
625}
626
613/* Optimize kprobe if p is ready to be optimized */627/* Optimize kprobe if p is ready to be optimized */
614static void optimize_kprobe(struct kprobe *p)628static void optimize_kprobe(struct kprobe *p)
615{629{
@@ -631,17 +645,21 @@ static void optimize_kprobe(struct kprobe *p) · 15 unmodified lines
631 return;645 return;
632 646
633 /* Check if it is already optimized. */647 /* Check if it is already optimized. */
634 if (op->kp.flags & KPROBE_FLAG_OPTIMIZED)648 if (op->kp.flags & KPROBE_FLAG_OPTIMIZED) {
649 if (optprobe_queued_unopt(op)) {
650 /* This is under unoptimizing. Just dequeue the probe */
651 list_del_init(&op->list);
652 }
635 return;653 return;
654 }
636 op->kp.flags |= KPROBE_FLAG_OPTIMIZED;655 op->kp.flags |= KPROBE_FLAG_OPTIMIZED;
637 656
638 if (!list_empty(&op->list))657 /* On unoptimizing/optimizing_list, op must have OPTIMIZED flag */
639 /* This is under unoptimizing. Just dequeue the probe */658 if (WARN_ON_ONCE(!list_empty(&op->list)))
640 list_del_init(&op->list);659 return;
641 else {660
642 list_add(&op->list, &optimizing_list);661 list_add(&op->list, &optimizing_list);
643 kick_kprobe_optimizer();662 kick_kprobe_optimizer();
644 }
645}663}
646 664
647/* Short cut to direct unoptimizing */665/* Short cut to direct unoptimizing */
@@ -649,6 +667,7 @@ static void force_unoptimize_kprobe(struct optimized_kprobe *op) · 1 unmodified line
649{667{
650 lockdep_assert_cpus_held();668 lockdep_assert_cpus_held();
651 arch_unoptimize_kprobe(op);669 arch_unoptimize_kprobe(op);
670 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
652 if (kprobe_disabled(&op->kp))671 if (kprobe_disabled(&op->kp))
653 arch_disarm_kprobe(&op->kp);672 arch_disarm_kprobe(&op->kp);
654}673}
@@ -662,31 +681,33 @@ static void unoptimize_kprobe(struct kprobe *p, bool force) · 7 unmodified lines
662 return; /* This is not an optprobe nor optimized */681 return; /* This is not an optprobe nor optimized */
663 682
664 op = container_of(p, struct optimized_kprobe, kp);683 op = container_of(p, struct optimized_kprobe, kp);
665 if (!kprobe_optimized(p)) {684 if (!kprobe_optimized(p))
666 /* Unoptimized or unoptimizing case */
667 if (force && !list_empty(&op->list)) {
668 /*
669 * Only if this is unoptimizing kprobe and forced,
670 * forcibly unoptimize it. (No need to unoptimize
671 * unoptimized kprobe again :)
672 */
673 list_del_init(&op->list);
674 force_unoptimize_kprobe(op);
675 }
676 return;685 return;
677 }
678 686
679 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
680 if (!list_empty(&op->list)) {687 if (!list_empty(&op->list)) {
681 /* Dequeue from the optimization queue */688 if (optprobe_queued_unopt(op)) {
682 list_del_init(&op->list);689 /* Queued in unoptimizing queue */
690 if (force) {
691 /*
692 * Forcibly unoptimize the kprobe here, and queue it
693 * in the freeing list for release afterwards.
694 */
695 force_unoptimize_kprobe(op);
696 list_move(&op->list, &freeing_list);
697 }
698 } else {
699 /* Dequeue from the optimizing queue */
700 list_del_init(&op->list);
701 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
702 }
683 return;703 return;
684 }704 }
705
685 /* Optimized kprobe case */706 /* Optimized kprobe case */
686 if (force)707 if (force) {
687 /* Forcibly update the code: this is a special case */708 /* Forcibly update the code: this is a special case */
688 force_unoptimize_kprobe(op);709 force_unoptimize_kprobe(op);
689 else {710 } else {
690 list_add(&op->list, &unoptimizing_list);711 list_add(&op->list, &unoptimizing_list);
691 kick_kprobe_optimizer();712 kick_kprobe_optimizer();
692 }713 }
kernel/module.c+0−43
@@ -2031,49 +2031,6 @@ static void module_enable_nx(const struct module *mod) · 2030 unmodified lines
2031 frob_writable_data(&mod->init_layout, set_memory_nx);2031 frob_writable_data(&mod->init_layout, set_memory_nx);
2032}2032}
2033 2033
2034/* Iterate through all modules and set each module's text as RW */
2035void set_all_modules_text_rw(void)
2036{
2037 struct module *mod;
2038
2039 if (!rodata_enabled)
2040 return;
2041
2042 mutex_lock(&module_mutex);
2043 list_for_each_entry_rcu(mod, &modules, list) {
2044 if (mod->state == MODULE_STATE_UNFORMED)
2045 continue;
2046
2047 frob_text(&mod->core_layout, set_memory_rw);
2048 frob_text(&mod->init_layout, set_memory_rw);
2049 }
2050 mutex_unlock(&module_mutex);
2051}
2052
2053/* Iterate through all modules and set each module's text as RO */
2054void set_all_modules_text_ro(void)
2055{
2056 struct module *mod;
2057
2058 if (!rodata_enabled)
2059 return;
2060
2061 mutex_lock(&module_mutex);
2062 list_for_each_entry_rcu(mod, &modules, list) {
2063 /*
2064 * Ignore going modules since it's possible that ro
2065 * protection has already been disabled, otherwise we'll
2066 * run into protection faults at module deallocation.
2067 */
2068 if (mod->state == MODULE_STATE_UNFORMED ||
2069 mod->state == MODULE_STATE_GOING)
2070 continue;
2071
2072 frob_text(&mod->core_layout, set_memory_ro);
2073 frob_text(&mod->init_layout, set_memory_ro);
2074 }
2075 mutex_unlock(&module_mutex);
2076}
2077#else /* !CONFIG_STRICT_MODULE_RWX */2034#else /* !CONFIG_STRICT_MODULE_RWX */
2078static void module_enable_nx(const struct module *mod) { }2035static void module_enable_nx(const struct module *mod) { }
2079#endif /* CONFIG_STRICT_MODULE_RWX */2036#endif /* CONFIG_STRICT_MODULE_RWX */
kernel/trace/trace.h+14−17
@@ -52,6 +52,9 @@ enum trace_type { · 51 unmodified lines
52#undef __field52#undef __field
53#define __field(type, item) type item;53#define __field(type, item) type item;
54 54
55#undef __field_fn
56#define __field_fn(type, item) type item;
57
55#undef __field_struct58#undef __field_struct
56#define __field_struct(type, item) __field(type, item)59#define __field_struct(type, item) __field(type, item)
57 60
@@ -71,26 +74,22 @@ enum trace_type { · 13 unmodified lines
71#define F_STRUCT(args...) args74#define F_STRUCT(args...) args
72 75
73#undef FTRACE_ENTRY76#undef FTRACE_ENTRY
74#define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter) \77#define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \
75 struct struct_name { \78 struct struct_name { \
76 struct trace_entry ent; \79 struct trace_entry ent; \
77 tstruct \80 tstruct \
78 }81 }
79 82
80#undef FTRACE_ENTRY_DUP83#undef FTRACE_ENTRY_DUP
81#define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk, filter)84#define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk)
82 85
83#undef FTRACE_ENTRY_REG86#undef FTRACE_ENTRY_REG
84#define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print, \87#define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print, regfn) \
85 filter, regfn) \88 FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print))
86 FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
87 filter)
88 89
89#undef FTRACE_ENTRY_PACKED90#undef FTRACE_ENTRY_PACKED
90#define FTRACE_ENTRY_PACKED(name, struct_name, id, tstruct, print, \91#define FTRACE_ENTRY_PACKED(name, struct_name, id, tstruct, print) \
91 filter) \92 FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print)) __packed
92 FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
93 filter) __packed
94 93
95#include "trace_entries.h"94#include "trace_entries.h"
96 95
@@ -1917,17 +1916,15 @@ extern void tracing_log_err(struct trace_array *tr, · 1820 unmodified lines
1917#define internal_trace_puts(str) __trace_puts(_THIS_IP_, str, strlen(str))1916#define internal_trace_puts(str) __trace_puts(_THIS_IP_, str, strlen(str))
1918 1917
1919#undef FTRACE_ENTRY1918#undef FTRACE_ENTRY
1920#define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter) \1919#define FTRACE_ENTRY(call, struct_name, id, tstruct, print) \
1921 extern struct trace_event_call \1920 extern struct trace_event_call \
1922 __aligned(4) event_##call;1921 __aligned(4) event_##call;
1923#undef FTRACE_ENTRY_DUP1922#undef FTRACE_ENTRY_DUP
1924#define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print, filter) \1923#define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print) \
1925 FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \1924 FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print))
1926 filter)
1927#undef FTRACE_ENTRY_PACKED1925#undef FTRACE_ENTRY_PACKED
1928#define FTRACE_ENTRY_PACKED(call, struct_name, id, tstruct, print, filter) \1926#define FTRACE_ENTRY_PACKED(call, struct_name, id, tstruct, print) \
1929 FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \1927 FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print))
1930 filter)
1931 1928
1932#include "trace_entries.h"1929#include "trace_entries.h"
1933 1930
kernel/trace/trace_entries.h+18−48
@@ -61,15 +61,13 @@ FTRACE_ENTRY_REG(function, ftrace_entry, · 60 unmodified lines
61 TRACE_FN,61 TRACE_FN,
62 62
63 F_STRUCT(63 F_STRUCT(
64 __field( unsigned long, ip )64 __field_fn( unsigned long, ip )
65 __field( unsigned long, parent_ip )65 __field_fn( unsigned long, parent_ip )
66 ),66 ),
67 67
68 F_printk(" %ps <-- %ps",68 F_printk(" %ps <-- %ps",
69 (void *)__entry->ip, (void *)__entry->parent_ip),69 (void *)__entry->ip, (void *)__entry->parent_ip),
70 70
71 FILTER_TRACE_FN,
72
73 perf_ftrace_event_register71 perf_ftrace_event_register
74);72);
75 73
@@ -84,9 +82,7 @@ FTRACE_ENTRY_PACKED(funcgraph_entry, ftrace_graph_ent_entry, · 8 unmodified lines
84 __field_desc( int, graph_ent, depth )82 __field_desc( int, graph_ent, depth )
85 ),83 ),
86 84
87 F_printk("--> %ps (%d)", (void *)__entry->func, __entry->depth),85 F_printk("--> %ps (%d)", (void *)__entry->func, __entry->depth)
88
89 FILTER_OTHER
90);86);
91 87
92/* Function return entry */88/* Function return entry */
@@ -97,18 +93,16 @@ FTRACE_ENTRY_PACKED(funcgraph_exit, ftrace_graph_ret_entry, · 4 unmodified lines
97 F_STRUCT(93 F_STRUCT(
98 __field_struct( struct ftrace_graph_ret, ret )94 __field_struct( struct ftrace_graph_ret, ret )
99 __field_desc( unsigned long, ret, func )95 __field_desc( unsigned long, ret, func )
96 __field_desc( unsigned long, ret, overrun )
100 __field_desc( unsigned long long, ret, calltime)97 __field_desc( unsigned long long, ret, calltime)
101 __field_desc( unsigned long long, ret, rettime )98 __field_desc( unsigned long long, ret, rettime )
102 __field_desc( unsigned long, ret, overrun )
103 __field_desc( int, ret, depth )99 __field_desc( int, ret, depth )
104 ),100 ),
105 101
106 F_printk("<-- %ps (%d) (start: %llx end: %llx) over: %d",102 F_printk("<-- %ps (%d) (start: %llx end: %llx) over: %d",
107 (void *)__entry->func, __entry->depth,103 (void *)__entry->func, __entry->depth,
108 __entry->calltime, __entry->rettime,104 __entry->calltime, __entry->rettime,
109 __entry->depth),105 __entry->depth)
110
111 FILTER_OTHER
112);106);
113 107
114/*108/*
@@ -137,9 +131,7 @@ FTRACE_ENTRY(context_switch, ctx_switch_entry, · 22 unmodified lines
137 F_printk("%u:%u:%u ==> %u:%u:%u [%03u]",131 F_printk("%u:%u:%u ==> %u:%u:%u [%03u]",
138 __entry->prev_pid, __entry->prev_prio, __entry->prev_state,132 __entry->prev_pid, __entry->prev_prio, __entry->prev_state,
139 __entry->next_pid, __entry->next_prio, __entry->next_state,133 __entry->next_pid, __entry->next_prio, __entry->next_state,
140 __entry->next_cpu),134 __entry->next_cpu)
141
142 FILTER_OTHER
143);135);
144 136
145/*137/*
@@ -157,9 +149,7 @@ FTRACE_ENTRY_DUP(wakeup, ctx_switch_entry, · 11 unmodified lines
157 F_printk("%u:%u:%u ==+ %u:%u:%u [%03u]",149 F_printk("%u:%u:%u ==+ %u:%u:%u [%03u]",
158 __entry->prev_pid, __entry->prev_prio, __entry->prev_state,150 __entry->prev_pid, __entry->prev_prio, __entry->prev_state,
159 __entry->next_pid, __entry->next_prio, __entry->next_state,151 __entry->next_pid, __entry->next_prio, __entry->next_state,
160 __entry->next_cpu),152 __entry->next_cpu)
161
162 FILTER_OTHER
163);153);
164 154
165/*155/*
@@ -183,9 +173,7 @@ FTRACE_ENTRY(kernel_stack, stack_entry, · 17 unmodified lines
183 (void *)__entry->caller[0], (void *)__entry->caller[1],173 (void *)__entry->caller[0], (void *)__entry->caller[1],
184 (void *)__entry->caller[2], (void *)__entry->caller[3],174 (void *)__entry->caller[2], (void *)__entry->caller[3],
185 (void *)__entry->caller[4], (void *)__entry->caller[5],175 (void *)__entry->caller[4], (void *)__entry->caller[5],
186 (void *)__entry->caller[6], (void *)__entry->caller[7]),176 (void *)__entry->caller[6], (void *)__entry->caller[7])
187
188 FILTER_OTHER
189);177);
190 178
191FTRACE_ENTRY(user_stack, userstack_entry,179FTRACE_ENTRY(user_stack, userstack_entry,
@@ -203,9 +191,7 @@ FTRACE_ENTRY(user_stack, userstack_entry, · 11 unmodified lines
203 (void *)__entry->caller[0], (void *)__entry->caller[1],191 (void *)__entry->caller[0], (void *)__entry->caller[1],
204 (void *)__entry->caller[2], (void *)__entry->caller[3],192 (void *)__entry->caller[2], (void *)__entry->caller[3],
205 (void *)__entry->caller[4], (void *)__entry->caller[5],193 (void *)__entry->caller[4], (void *)__entry->caller[5],
206 (void *)__entry->caller[6], (void *)__entry->caller[7]),194 (void *)__entry->caller[6], (void *)__entry->caller[7])
207
208 FILTER_OTHER
209);195);
210 196
211/*197/*
@@ -222,9 +208,7 @@ FTRACE_ENTRY(bprint, bprint_entry, · 10 unmodified lines
222 ),208 ),
223 209
224 F_printk("%ps: %s",210 F_printk("%ps: %s",
225 (void *)__entry->ip, __entry->fmt),211 (void *)__entry->ip, __entry->fmt)
226
227 FILTER_OTHER
228);212);
229 213
230FTRACE_ENTRY_REG(print, print_entry,214FTRACE_ENTRY_REG(print, print_entry,
@@ -239,8 +223,6 @@ FTRACE_ENTRY_REG(print, print_entry, · 8 unmodified lines
239 F_printk("%ps: %s",223 F_printk("%ps: %s",
240 (void *)__entry->ip, __entry->buf),224 (void *)__entry->ip, __entry->buf),
241 225
242 FILTER_OTHER,
243
244 ftrace_event_register226 ftrace_event_register
245);227);
246 228
@@ -254,9 +236,7 @@ FTRACE_ENTRY(raw_data, raw_data_entry, · 7 unmodified lines
254 ),236 ),
255 237
256 F_printk("id:%04x %08x",238 F_printk("id:%04x %08x",
257 __entry->id, (int)__entry->buf[0]),239 __entry->id, (int)__entry->buf[0])
258
259 FILTER_OTHER
260);240);
261 241
262FTRACE_ENTRY(bputs, bputs_entry,242FTRACE_ENTRY(bputs, bputs_entry,
@@ -269,9 +249,7 @@ FTRACE_ENTRY(bputs, bputs_entry, · 6 unmodified lines
269 ),249 ),
270 250
271 F_printk("%ps: %s",251 F_printk("%ps: %s",
272 (void *)__entry->ip, __entry->str),252 (void *)__entry->ip, __entry->str)
273
274 FILTER_OTHER
275);253);
276 254
277FTRACE_ENTRY(mmiotrace_rw, trace_mmiotrace_rw,255FTRACE_ENTRY(mmiotrace_rw, trace_mmiotrace_rw,
@@ -283,16 +261,14 @@ FTRACE_ENTRY(mmiotrace_rw, trace_mmiotrace_rw, · 5 unmodified lines
283 __field_desc( resource_size_t, rw, phys )261 __field_desc( resource_size_t, rw, phys )
284 __field_desc( unsigned long, rw, value )262 __field_desc( unsigned long, rw, value )
285 __field_desc( unsigned long, rw, pc )263 __field_desc( unsigned long, rw, pc )
286 __field_desc( int, rw, map_id )264 __field_desc( int, rw, map_id )
287 __field_desc( unsigned char, rw, opcode )265 __field_desc( unsigned char, rw, opcode )
288 __field_desc( unsigned char, rw, width )266 __field_desc( unsigned char, rw, width )
289 ),267 ),
290 268
291 F_printk("%lx %lx %lx %d %x %x",269 F_printk("%lx %lx %lx %d %x %x",
292 (unsigned long)__entry->phys, __entry->value, __entry->pc,270 (unsigned long)__entry->phys, __entry->value, __entry->pc,
293 __entry->map_id, __entry->opcode, __entry->width),271 __entry->map_id, __entry->opcode, __entry->width)
294
295 FILTER_OTHER
296);272);
297 273
298FTRACE_ENTRY(mmiotrace_map, trace_mmiotrace_map,274FTRACE_ENTRY(mmiotrace_map, trace_mmiotrace_map,
@@ -304,15 +280,13 @@ FTRACE_ENTRY(mmiotrace_map, trace_mmiotrace_map, · 5 unmodified lines
304 __field_desc( resource_size_t, map, phys )280 __field_desc( resource_size_t, map, phys )
305 __field_desc( unsigned long, map, virt )281 __field_desc( unsigned long, map, virt )
306 __field_desc( unsigned long, map, len )282 __field_desc( unsigned long, map, len )
307 __field_desc( int, map, map_id )283 __field_desc( int, map, map_id )
308 __field_desc( unsigned char, map, opcode )284 __field_desc( unsigned char, map, opcode )
309 ),285 ),
310 286
311 F_printk("%lx %lx %lx %d %x",287 F_printk("%lx %lx %lx %d %x",
312 (unsigned long)__entry->phys, __entry->virt, __entry->len,288 (unsigned long)__entry->phys, __entry->virt, __entry->len,
313 __entry->map_id, __entry->opcode),289 __entry->map_id, __entry->opcode)
314
315 FILTER_OTHER
316);290);
317 291
318 292
@@ -334,9 +308,7 @@ FTRACE_ENTRY(branch, trace_branch, · 15 unmodified lines
334 F_printk("%u:%s:%s (%u)%s",308 F_printk("%u:%s:%s (%u)%s",
335 __entry->line,309 __entry->line,
336 __entry->func, __entry->file, __entry->correct,310 __entry->func, __entry->file, __entry->correct,
337 __entry->constant ? " CONSTANT" : ""),311 __entry->constant ? " CONSTANT" : "")
338
339 FILTER_OTHER
340);312);
341 313
342 314
@@ -362,7 +334,5 @@ FTRACE_ENTRY(hwlat, hwlat_entry, · 19 unmodified lines
362 __entry->duration,334 __entry->duration,
363 __entry->outer_duration,335 __entry->outer_duration,
364 __entry->nmi_total_ts,336 __entry->nmi_total_ts,
365 __entry->nmi_count),337 __entry->nmi_count)
366
367 FILTER_OTHER
368);338);
kernel/trace/trace_events.c+19−1
@@ -24,6 +24,7 @@ · 23 unmodified lines
24#include <linux/delay.h>24#include <linux/delay.h>
25 25
26#include <trace/events/sched.h>26#include <trace/events/sched.h>
27#include <trace/syscall.h>
27 28
28#include <asm/setup.h>29#include <asm/setup.h>
29 30
@@ -2017,7 +2018,24 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file) · 1987 unmodified lines
2017 */2018 */
2018 head = trace_get_fields(call);2019 head = trace_get_fields(call);
2019 if (list_empty(head)) {2020 if (list_empty(head)) {
2020 ret = call->class->define_fields(call);2021 struct trace_event_fields *field = call->class->fields_array;
2022 unsigned int offset = sizeof(struct trace_entry);
2023
2024 for (; field->type; field++) {
2025 if (field->type == TRACE_FUNCTION_TYPE) {
2026 ret = field->define_fields(call);
2027 break;
2028 }
2029
2030 offset = ALIGN(offset, field->align);
2031 ret = trace_define_field(call, field->type, field->name,
2032 offset, field->size,
2033 field->is_signed, field->filter_type);
2034 if (ret)
2035 break;
2036
2037 offset += field->size;
2038 }
2021 if (ret < 0) {2039 if (ret < 0) {
2022 pr_warn("Could not initialize trace point events/%s\n",2040 pr_warn("Could not initialize trace point events/%s\n",
2023 name);2041 name);
kernel/trace/trace_events_hist.c+7−1
@@ -1155,6 +1155,12 @@ static struct synth_event *find_synth_event(const char *name) · 1154 unmodified lines
1155 return NULL;1155 return NULL;
1156}1156}
1157 1157
1158static struct trace_event_fields synth_event_fields_array[] = {
1159 { .type = TRACE_FUNCTION_TYPE,
1160 .define_fields = synth_event_define_fields },
1161 {}
1162};
1163
1158static int register_synth_event(struct synth_event *event)1164static int register_synth_event(struct synth_event *event)
1159{1165{
1160 struct trace_event_call *call = &event->call;1166 struct trace_event_call *call = &event->call;
@@ -1176,7 +1182,7 @@ static int register_synth_event(struct synth_event *event) · 15 unmodified lines
1176 1182
1177 INIT_LIST_HEAD(&call->class->fields);1183 INIT_LIST_HEAD(&call->class->fields);
1178 call->event.funcs = &synth_event_funcs;1184 call->event.funcs = &synth_event_funcs;
1179 call->class->define_fields = synth_event_define_fields;1185 call->class->fields_array = synth_event_fields_array;
1180 1186
1181 ret = register_trace_event(&call->event);1187 ret = register_trace_event(&call->event);
1182 if (!ret) {1188 if (!ret) {
kernel/trace/trace_export.c+39−67
@@ -29,10 +29,8 @@ static int ftrace_event_register(struct trace_event_call *call, · 28 unmodified lines
29 * function and thus become accesible via perf.29 * function and thus become accesible via perf.
30 */30 */
31#undef FTRACE_ENTRY_REG31#undef FTRACE_ENTRY_REG
32#define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print, \32#define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print, regfn) \
33 filter, regfn) \33 FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print))
34 FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \
35 filter)
36 34
37/* not needed for this file */35/* not needed for this file */
38#undef __field_struct36#undef __field_struct
@@ -41,6 +39,9 @@ static int ftrace_event_register(struct trace_event_call *call, · 2 unmodified lines
41#undef __field39#undef __field
42#define __field(type, item) type item;40#define __field(type, item) type item;
43 41
42#undef __field_fn
43#define __field_fn(type, item) type item;
44
44#undef __field_desc45#undef __field_desc
45#define __field_desc(type, container, item) type item;46#define __field_desc(type, container, item) type item;
46 47
@@ -60,7 +61,7 @@ static int ftrace_event_register(struct trace_event_call *call, · 13 unmodified lines
60#define F_printk(fmt, args...) fmt, args61#define F_printk(fmt, args...) fmt, args
61 62
62#undef FTRACE_ENTRY63#undef FTRACE_ENTRY
63#define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter) \64#define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \
64struct ____ftrace_##name { \65struct ____ftrace_##name { \
65 tstruct \66 tstruct \
66}; \67}; \
@@ -73,76 +74,46 @@ static void __always_unused ____ftrace_check_##name(void) \ · 6 unmodified lines
73}74}
74 75
75#undef FTRACE_ENTRY_DUP76#undef FTRACE_ENTRY_DUP
76#define FTRACE_ENTRY_DUP(name, struct_name, id, tstruct, print, filter) \77#define FTRACE_ENTRY_DUP(name, struct_name, id, tstruct, print) \
77 FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \78 FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print))
78 filter)
79 79
80#include "trace_entries.h"80#include "trace_entries.h"
81 81
82#undef __field_ext
83#define __field_ext(_type, _item, _filter_type) { \
84 .type = #_type, .name = #_item, \
85 .size = sizeof(_type), .align = __alignof__(_type), \
86 is_signed_type(_type), .filter_type = _filter_type },
87
82#undef __field88#undef __field
83#define __field(type, item) \89#define __field(_type, _item) __field_ext(_type, _item, FILTER_OTHER)
84 ret = trace_define_field(event_call, #type, #item, \90
85 offsetof(typeof(field), item), \91#undef __field_fn
86 sizeof(field.item), \92#define __field_fn(_type, _item) __field_ext(_type, _item, FILTER_TRACE_FN)
87 is_signed_type(type), filter_type); \
88 if (ret) \
89 return ret;
90 93
91#undef __field_desc94#undef __field_desc
92#define __field_desc(type, container, item) \95#define __field_desc(_type, _container, _item) __field_ext(_type, _item, FILTER_OTHER)
93 ret = trace_define_field(event_call, #type, #item, \
94 offsetof(typeof(field), \
95 container.item), \
96 sizeof(field.container.item), \
97 is_signed_type(type), filter_type); \
98 if (ret) \
99 return ret;
100 96
101#undef __array97#undef __array
102#define __array(type, item, len) \98#define __array(_type, _item, _len) { \
103 do { \99 .type = #_type"["__stringify(_len)"]", .name = #_item, \
104 char *type_str = #type"["__stringify(len)"]"; \100 .size = sizeof(_type[_len]), .align = __alignof__(_type), \
105 BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \101 is_signed_type(_type), .filter_type = FILTER_OTHER },
106 ret = trace_define_field(event_call, type_str, #item, \
107 offsetof(typeof(field), item), \
108 sizeof(field.item), \
109 is_signed_type(type), filter_type); \
110 if (ret) \
111 return ret; \
112 } while (0);
113 102
114#undef __array_desc103#undef __array_desc
115#define __array_desc(type, container, item, len) \104#define __array_desc(_type, _container, _item, _len) __array(_type, _item, _len)
116 BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \
117 ret = trace_define_field(event_call, #type "[" #len "]", #item, \
118 offsetof(typeof(field), \
119 container.item), \
120 sizeof(field.container.item), \
121 is_signed_type(type), filter_type); \
122 if (ret) \
123 return ret;
124 105
125#undef __dynamic_array106#undef __dynamic_array
126#define __dynamic_array(type, item) \107#define __dynamic_array(_type, _item) { \
127 ret = trace_define_field(event_call, #type "[]", #item, \108 .type = #_type "[]", .name = #_item, \
128 offsetof(typeof(field), item), \109 .size = 0, .align = __alignof__(_type), \
129 0, is_signed_type(type), filter_type);\110 is_signed_type(_type), .filter_type = FILTER_OTHER },
130 if (ret) \
131 return ret;
132 111
133#undef FTRACE_ENTRY112#undef FTRACE_ENTRY
134#define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter) \113#define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \
135static int __init \114static struct trace_event_fields ftrace_event_fields_##name[] = { \
136ftrace_define_fields_##name(struct trace_event_call *event_call) \115 tstruct \
137{ \116 {} };
138 struct struct_name field; \
139 int ret; \
140 int filter_type = filter; \
141 \
142 tstruct; \
143 \
144 return ret; \
145}
146 117
147#include "trace_entries.h"118#include "trace_entries.h"
148 119
@@ -152,6 +123,9 @@ ftrace_define_fields_##name(struct trace_event_call *event_call) \ · 3 unmodified lines
152#undef __field123#undef __field
153#define __field(type, item)124#define __field(type, item)
154 125
126#undef __field_fn
127#define __field_fn(type, item)
128
155#undef __field_desc129#undef __field_desc
156#define __field_desc(type, container, item)130#define __field_desc(type, container, item)
157 131
@@ -168,12 +142,10 @@ ftrace_define_fields_##name(struct trace_event_call *event_call) \ · 10 unmodified lines
168#define F_printk(fmt, args...) __stringify(fmt) ", " __stringify(args)142#define F_printk(fmt, args...) __stringify(fmt) ", " __stringify(args)
169 143
170#undef FTRACE_ENTRY_REG144#undef FTRACE_ENTRY_REG
171#define FTRACE_ENTRY_REG(call, struct_name, etype, tstruct, print, filter,\145#define FTRACE_ENTRY_REG(call, struct_name, etype, tstruct, print, regfn) \
172 regfn) \
173 \
174static struct trace_event_class __refdata event_class_ftrace_##call = { \146static struct trace_event_class __refdata event_class_ftrace_##call = { \
175 .system = __stringify(TRACE_SYSTEM), \147 .system = __stringify(TRACE_SYSTEM), \
176 .define_fields = ftrace_define_fields_##call, \148 .fields_array = ftrace_event_fields_##call, \
177 .fields = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\149 .fields = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
178 .reg = regfn, \150 .reg = regfn, \
179}; \151}; \
@@ -191,9 +163,9 @@ static struct trace_event_call __used \ · 11 unmodified lines
191__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call;163__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call;
192 164
193#undef FTRACE_ENTRY165#undef FTRACE_ENTRY
194#define FTRACE_ENTRY(call, struct_name, etype, tstruct, print, filter) \166#define FTRACE_ENTRY(call, struct_name, etype, tstruct, print) \
195 FTRACE_ENTRY_REG(call, struct_name, etype, \167 FTRACE_ENTRY_REG(call, struct_name, etype, \
196 PARAMS(tstruct), PARAMS(print), filter, NULL)168 PARAMS(tstruct), PARAMS(print), NULL)
197 169
198bool ftrace_event_is_function(struct trace_event_call *call)170bool ftrace_event_is_function(struct trace_event_call *call)
199{171{
kernel/trace/trace_kprobe.c+14−2
@@ -1555,16 +1555,28 @@ static struct trace_event_functions kprobe_funcs = { · 1554 unmodified lines
1555 .trace = print_kprobe_event1555 .trace = print_kprobe_event
1556};1556};
1557 1557
1558static struct trace_event_fields kretprobe_fields_array[] = {
1559 { .type = TRACE_FUNCTION_TYPE,
1560 .define_fields = kretprobe_event_define_fields },
1561 {}
1562};
1563
1564static struct trace_event_fields kprobe_fields_array[] = {
1565 { .type = TRACE_FUNCTION_TYPE,
1566 .define_fields = kprobe_event_define_fields },
1567 {}
1568};
1569
1558static inline void init_trace_event_call(struct trace_kprobe *tk)1570static inline void init_trace_event_call(struct trace_kprobe *tk)
1559{1571{
1560 struct trace_event_call *call = trace_probe_event_call(&tk->tp);1572 struct trace_event_call *call = trace_probe_event_call(&tk->tp);
1561 1573
1562 if (trace_kprobe_is_return(tk)) {1574 if (trace_kprobe_is_return(tk)) {
1563 call->event.funcs = &kretprobe_funcs;1575 call->event.funcs = &kretprobe_funcs;
1564 call->class->define_fields = kretprobe_event_define_fields;1576 call->class->fields_array = kretprobe_fields_array;
1565 } else {1577 } else {
1566 call->event.funcs = &kprobe_funcs;1578 call->event.funcs = &kprobe_funcs;
1567 call->class->define_fields = kprobe_event_define_fields;1579 call->class->fields_array = kprobe_fields_array;
1568 }1580 }
1569 1581
1570 call->flags = TRACE_EVENT_FL_KPROBE;1582 call->flags = TRACE_EVENT_FL_KPROBE;
kernel/trace/trace_syscalls.c+21−30
@@ -203,11 +203,10 @@ print_syscall_exit(struct trace_iterator *iter, int flags, · 202 unmodified lines
203 203
204extern char *__bad_type_size(void);204extern char *__bad_type_size(void);
205 205
206#define SYSCALL_FIELD(type, field, name) \206#define SYSCALL_FIELD(_type, _name) { \
207 sizeof(type) != sizeof(trace.field) ? \207 .type = #_type, .name = #_name, \
208 __bad_type_size() : \208 .size = sizeof(_type), .align = __alignof__(_type), \
209 #type, #name, offsetof(typeof(trace), field), \209 .is_signed = is_signed_type(_type), .filter_type = FILTER_OTHER }
210 sizeof(trace.field), is_signed_type(type)
211 210
212static int __init211static int __init
213__set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len)212__set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len)
@@ -274,42 +273,23 @@ static int __init syscall_enter_define_fields(struct trace_event_call *call) · 60 unmodified lines
274{273{
275 struct syscall_trace_enter trace;274 struct syscall_trace_enter trace;
276 struct syscall_metadata *meta = call->data;275 struct syscall_metadata *meta = call->data;
277 int ret;
278 int i;
279 int offset = offsetof(typeof(trace), args);276 int offset = offsetof(typeof(trace), args);
280 277 int ret = 0;
281 ret = trace_define_field(call, SYSCALL_FIELD(int, nr, __syscall_nr),278 int i;
282 FILTER_OTHER);
283 if (ret)
284 return ret;
285 279
286 for (i = 0; i < meta->nb_args; i++) {280 for (i = 0; i < meta->nb_args; i++) {
287 ret = trace_define_field(call, meta->types[i],281 ret = trace_define_field(call, meta->types[i],
288 meta->args[i], offset,282 meta->args[i], offset,
289 sizeof(unsigned long), 0,283 sizeof(unsigned long), 0,
290 FILTER_OTHER);284 FILTER_OTHER);
285 if (ret)
286 break;
291 offset += sizeof(unsigned long);287 offset += sizeof(unsigned long);
292 }288 }
293 289
294 return ret;290 return ret;
295}291}
296 292
297static int __init syscall_exit_define_fields(struct trace_event_call *call)
298{
299 struct syscall_trace_exit trace;
300 int ret;
301
302 ret = trace_define_field(call, SYSCALL_FIELD(int, nr, __syscall_nr),
303 FILTER_OTHER);
304 if (ret)
305 return ret;
306
307 ret = trace_define_field(call, SYSCALL_FIELD(long, ret, ret),
308 FILTER_OTHER);
309
310 return ret;
311}
312
313static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)293static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
314{294{
315 struct trace_array *tr = data;295 struct trace_array *tr = data;
@@ -507,6 +487,13 @@ static int __init init_syscall_trace(struct trace_event_call *call) · 191 unmodified lines
507 return id;487 return id;
508}488}
509 489
490static struct trace_event_fields __refdata syscall_enter_fields_array[] = {
491 SYSCALL_FIELD(int, __syscall_nr),
492 { .type = TRACE_FUNCTION_TYPE,
493 .define_fields = syscall_enter_define_fields },
494 {}
495};
496
510struct trace_event_functions enter_syscall_print_funcs = {497struct trace_event_functions enter_syscall_print_funcs = {
511 .trace = print_syscall_enter,498 .trace = print_syscall_enter,
512};499};
@@ -518,7 +505,7 @@ struct trace_event_functions exit_syscall_print_funcs = { · 5 unmodified lines
518struct trace_event_class __refdata event_class_syscall_enter = {505struct trace_event_class __refdata event_class_syscall_enter = {
519 .system = "syscalls",506 .system = "syscalls",
520 .reg = syscall_enter_register,507 .reg = syscall_enter_register,
521 .define_fields = syscall_enter_define_fields,508 .fields_array = syscall_enter_fields_array,
522 .get_fields = syscall_get_enter_fields,509 .get_fields = syscall_get_enter_fields,
523 .raw_init = init_syscall_trace,510 .raw_init = init_syscall_trace,
524};511};
@@ -526,7 +513,11 @@ struct trace_event_class __refdata event_class_syscall_enter = { · 1 unmodified line
526struct trace_event_class __refdata event_class_syscall_exit = {513struct trace_event_class __refdata event_class_syscall_exit = {
527 .system = "syscalls",514 .system = "syscalls",
528 .reg = syscall_exit_register,515 .reg = syscall_exit_register,
529 .define_fields = syscall_exit_define_fields,516 .fields_array = (struct trace_event_fields[]){
517 SYSCALL_FIELD(int, __syscall_nr),
518 SYSCALL_FIELD(long, ret),
519 {}
520 },
530 .fields = LIST_HEAD_INIT(event_class_syscall_exit.fields),521 .fields = LIST_HEAD_INIT(event_class_syscall_exit.fields),
531 .raw_init = init_syscall_trace,522 .raw_init = init_syscall_trace,
532};523};
kernel/trace/trace_uprobe.c+7−2
@@ -1528,12 +1528,17 @@ static struct trace_event_functions uprobe_funcs = { · 1527 unmodified lines
1528 .trace = print_uprobe_event1528 .trace = print_uprobe_event
1529};1529};
1530 1530
1531static struct trace_event_fields uprobe_fields_array[] = {
1532 { .type = TRACE_FUNCTION_TYPE,
1533 .define_fields = uprobe_event_define_fields },
1534 {}
1535};
1536
1531static inline void init_trace_event_call(struct trace_uprobe *tu)1537static inline void init_trace_event_call(struct trace_uprobe *tu)
1532{1538{
1533 struct trace_event_call *call = trace_probe_event_call(&tu->tp);1539 struct trace_event_call *call = trace_probe_event_call(&tu->tp);
1534
1535 call->event.funcs = &uprobe_funcs;1540 call->event.funcs = &uprobe_funcs;
1536 call->class->define_fields = uprobe_event_define_fields;1541 call->class->fields_array = uprobe_fields_array;
1537 1542
1538 call->flags = TRACE_EVENT_FL_UPROBE | TRACE_EVENT_FL_CAP_ANY;1543 call->flags = TRACE_EVENT_FL_UPROBE | TRACE_EVENT_FL_CAP_ANY;
1539 call->class->reg = trace_uprobe_register;1544 call->class->reg = trace_uprobe_register;
net/mac80211/trace.h+14−14
@@ -408,20 +408,20 @@ TRACE_EVENT(drv_bss_info_changed, · 407 unmodified lines
408 __field(u32, basic_rates)408 __field(u32, basic_rates)
409 __array(int, mcast_rate, NUM_NL80211_BANDS)409 __array(int, mcast_rate, NUM_NL80211_BANDS)
410 __field(u16, ht_operation_mode)410 __field(u16, ht_operation_mode)
411 __field(s32, cqm_rssi_thold);411 __field(s32, cqm_rssi_thold)
412 __field(s32, cqm_rssi_hyst);412 __field(s32, cqm_rssi_hyst)
413 __field(u32, channel_width);413 __field(u32, channel_width)
414 __field(u32, channel_cfreq1);414 __field(u32, channel_cfreq1)
415 __dynamic_array(u32, arp_addr_list,415 __dynamic_array(u32, arp_addr_list,
416 info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?416 info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
417 IEEE80211_BSS_ARP_ADDR_LIST_LEN :417 IEEE80211_BSS_ARP_ADDR_LIST_LEN :
418 info->arp_addr_cnt);418 info->arp_addr_cnt)
419 __field(int, arp_addr_cnt);419 __field(int, arp_addr_cnt)
420 __field(bool, qos);420 __field(bool, qos)
421 __field(bool, idle);421 __field(bool, idle)
422 __field(bool, ps);422 __field(bool, ps)
423 __dynamic_array(u8, ssid, info->ssid_len);423 __dynamic_array(u8, ssid, info->ssid_len)
424 __field(bool, hidden_ssid);424 __field(bool, hidden_ssid)
425 __field(int, txpower)425 __field(int, txpower)
426 __field(u8, p2p_oppps_ctwindow)426 __field(u8, p2p_oppps_ctwindow)
427 ),427 ),
@@ -1672,8 +1672,8 @@ TRACE_EVENT(drv_start_ap, · 1244 unmodified lines
1672 VIF_ENTRY1672 VIF_ENTRY
1673 __field(u8, dtimper)1673 __field(u8, dtimper)
1674 __field(u16, bcnint)1674 __field(u16, bcnint)
1675 __dynamic_array(u8, ssid, info->ssid_len);1675 __dynamic_array(u8, ssid, info->ssid_len)
1676 __field(bool, hidden_ssid);1676 __field(bool, hidden_ssid)
1677 ),1677 ),
1678 1678
1679 TP_fast_assign(1679 TP_fast_assign(
@@ -1739,7 +1739,7 @@ TRACE_EVENT(drv_join_ibss, · 59 unmodified lines
1739 VIF_ENTRY1739 VIF_ENTRY
1740 __field(u8, dtimper)1740 __field(u8, dtimper)
1741 __field(u16, bcnint)1741 __field(u16, bcnint)
1742 __dynamic_array(u8, ssid, info->ssid_len);1742 __dynamic_array(u8, ssid, info->ssid_len)
1743 ),1743 ),
1744 1744
1745 TP_fast_assign(1745 TP_fast_assign(
net/wireless/trace.h+3−3
@@ -2014,7 +2014,7 @@ TRACE_EVENT(rdev_start_nan, · 2013 unmodified lines
2014 WIPHY_ENTRY2014 WIPHY_ENTRY
2015 WDEV_ENTRY2015 WDEV_ENTRY
2016 __field(u8, master_pref)2016 __field(u8, master_pref)
2017 __field(u8, bands);2017 __field(u8, bands)
2018 ),2018 ),
2019 TP_fast_assign(2019 TP_fast_assign(
2020 WIPHY_ASSIGN;2020 WIPHY_ASSIGN;
@@ -2036,8 +2036,8 @@ TRACE_EVENT(rdev_nan_change_conf, · 15 unmodified lines
2036 WIPHY_ENTRY2036 WIPHY_ENTRY
2037 WDEV_ENTRY2037 WDEV_ENTRY
2038 __field(u8, master_pref)2038 __field(u8, master_pref)
2039 __field(u8, bands);2039 __field(u8, bands)
2040 __field(u32, changes);2040 __field(u32, changes)
2041 ),2041 ),
2042 TP_fast_assign(2042 TP_fast_assign(
2043 WIPHY_ASSIGN;2043 WIPHY_ASSIGN;
tools/build/feature/Makefile+1−1
@@ -197,7 +197,7 @@ $(OUTPUT)test-libcrypto.bin: · 196 unmodified lines
197 $(BUILD) -lcrypto197 $(BUILD) -lcrypto
198 198
199$(OUTPUT)test-gtk2.bin:199$(OUTPUT)test-gtk2.bin:
200 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)200 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) -Wno-deprecated-declarations
201 201
202$(OUTPUT)test-gtk2-infobar.bin:202$(OUTPUT)test-gtk2-infobar.bin:
203 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)203 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
tools/build/feature/test-clang.cpp+6−0
@@ -1,9 +1,15 @@
1// SPDX-License-Identifier: GPL-2.01// SPDX-License-Identifier: GPL-2.0
2#include "clang/Basic/Version.h"
3#if CLANG_VERSION_MAJOR < 8
2#include "clang/Basic/VirtualFileSystem.h"4#include "clang/Basic/VirtualFileSystem.h"
5#endif
3#include "clang/Driver/Driver.h"6#include "clang/Driver/Driver.h"
4#include "clang/Frontend/TextDiagnosticPrinter.h"7#include "clang/Frontend/TextDiagnosticPrinter.h"
5#include "llvm/ADT/IntrusiveRefCntPtr.h"8#include "llvm/ADT/IntrusiveRefCntPtr.h"
6#include "llvm/Support/ManagedStatic.h"9#include "llvm/Support/ManagedStatic.h"
10#if CLANG_VERSION_MAJOR >= 8
11#include "llvm/Support/VirtualFileSystem.h"
12#endif
7#include "llvm/Support/raw_ostream.h"13#include "llvm/Support/raw_ostream.h"
8 14
9using namespace clang;15using namespace clang;
tools/include/linux/bitmap.h+30−0
@@ -15,6 +15,8 @@ void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, · 14 unmodified lines
15 const unsigned long *bitmap2, int bits);15 const unsigned long *bitmap2, int bits);
16int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,16int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
17 const unsigned long *bitmap2, unsigned int bits);17 const unsigned long *bitmap2, unsigned int bits);
18int __bitmap_equal(const unsigned long *bitmap1,
19 const unsigned long *bitmap2, unsigned int bits);
18void bitmap_clear(unsigned long *map, unsigned int start, int len);20void bitmap_clear(unsigned long *map, unsigned int start, int len);
19 21
20#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))22#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
@@ -123,6 +125,15 @@ static inline unsigned long *bitmap_alloc(int nbits) · 102 unmodified lines
123 return calloc(1, BITS_TO_LONGS(nbits) * sizeof(unsigned long));125 return calloc(1, BITS_TO_LONGS(nbits) * sizeof(unsigned long));
124}126}
125 127
128/*
129 * bitmap_free - Free bitmap
130 * @bitmap: pointer to bitmap
131 */
132static inline void bitmap_free(unsigned long *bitmap)
133{
134 free(bitmap);
135}
136
126/*137/*
127 * bitmap_scnprintf - print bitmap list into buffer138 * bitmap_scnprintf - print bitmap list into buffer
128 * @bitmap: bitmap139 * @bitmap: bitmap
@@ -148,4 +159,23 @@ static inline int bitmap_and(unsigned long *dst, const unsigned long *src1, · 19 unmodified lines
148 return __bitmap_and(dst, src1, src2, nbits);159 return __bitmap_and(dst, src1, src2, nbits);
149}160}
150 161
162#ifdef __LITTLE_ENDIAN
163#define BITMAP_MEM_ALIGNMENT 8
164#else
165#define BITMAP_MEM_ALIGNMENT (8 * sizeof(unsigned long))
166#endif
167#define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1)
168#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)
169
170static inline int bitmap_equal(const unsigned long *src1,
171 const unsigned long *src2, unsigned int nbits)
172{
173 if (small_const_nbits(nbits))
174 return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
175 if (__builtin_constant_p(nbits & BITMAP_MEM_MASK) &&
176 IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT))
177 return !memcmp(src1, src2, nbits / 8);
178 return __bitmap_equal(src1, src2, nbits);
179}
180
151#endif /* _PERF_BITOPS_H */181#endif /* _PERF_BITOPS_H */
tools/include/linux/string.h+8−0
@@ -17,7 +17,15 @@ int strtobool(const char *s, bool *res); · 16 unmodified lines
17 * However uClibc headers also define __GLIBC__ hence the hack below17 * However uClibc headers also define __GLIBC__ hence the hack below
18 */18 */
19#if defined(__GLIBC__) && !defined(__UCLIBC__)19#if defined(__GLIBC__) && !defined(__UCLIBC__)
20// pragma diagnostic was introduced in gcc 4.6
21#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
22#pragma GCC diagnostic push
23#pragma GCC diagnostic ignored "-Wredundant-decls"
24#endif
20extern size_t strlcpy(char *dest, const char *src, size_t size);25extern size_t strlcpy(char *dest, const char *src, size_t size);
26#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
27#pragma GCC diagnostic pop
28#endif
21#endif29#endif
22 30
23char *str_error_r(int errnum, char *buf, size_t buflen);31char *str_error_r(int errnum, char *buf, size_t buflen);
tools/lib/api/fs/fs.c+3−1
@@ -210,6 +210,7 @@ static bool fs__env_override(struct fs *fs) · 209 unmodified lines
210 size_t name_len = strlen(fs->name);210 size_t name_len = strlen(fs->name);
211 /* name + "_PATH" + '\0' */211 /* name + "_PATH" + '\0' */
212 char upper_name[name_len + 5 + 1];212 char upper_name[name_len + 5 + 1];
213
213 memcpy(upper_name, fs->name, name_len);214 memcpy(upper_name, fs->name, name_len);
214 mem_toupper(upper_name, name_len);215 mem_toupper(upper_name, name_len);
215 strcpy(&upper_name[name_len], "_PATH");216 strcpy(&upper_name[name_len], "_PATH");
@@ -219,7 +220,8 @@ static bool fs__env_override(struct fs *fs) · 3 unmodified lines
219 return false;220 return false;
220 221
221 fs->found = true;222 fs->found = true;
222 strncpy(fs->path, override_path, sizeof(fs->path));223 strncpy(fs->path, override_path, sizeof(fs->path) - 1);
224 fs->path[sizeof(fs->path) - 1] = '\0';
223 return true;225 return true;
224}226}
225 227
tools/lib/bitmap.c+15−0
@@ -71,3 +71,18 @@ int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, · 70 unmodified lines
71 BITMAP_LAST_WORD_MASK(bits));71 BITMAP_LAST_WORD_MASK(bits));
72 return result != 0;72 return result != 0;
73}73}
74
75int __bitmap_equal(const unsigned long *bitmap1,
76 const unsigned long *bitmap2, unsigned int bits)
77{
78 unsigned int k, lim = bits/BITS_PER_LONG;
79 for (k = 0; k < lim; ++k)
80 if (bitmap1[k] != bitmap2[k])
81 return 0;
82
83 if (bits % BITS_PER_LONG)
84 if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
85 return 0;
86
87 return 1;
88}
tools/lib/perf/Buildrenamed from tools/perf/lib/Build+0−0

File renamed without changes.

tools/lib/perf/Documentation/Makefile+156−0
@@ -0,0 +1,156 @@
1# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2# Most of this file is copied from tools/perf/Documentation/Makefile
3
4include ../../../scripts/Makefile.include
5include ../../../scripts/utilities.mak
6
7MAN3_TXT = libperf.txt
8MAN7_TXT = libperf-counting.txt libperf-sampling.txt
9MAN_EX = examples/*.c
10
11MAN_TXT = $(MAN3_TXT) $(MAN7_TXT)
12
13_MAN_XML = $(patsubst %.txt,%.xml,$(MAN_TXT))
14_MAN_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
15_MAN_3 = $(patsubst %.txt,%.3,$(MAN3_TXT))
16_MAN_7 = $(patsubst %.txt,%.7,$(MAN7_TXT))
17
18MAN_XML = $(addprefix $(OUTPUT),$(_MAN_XML))
19MAN_HTML = $(addprefix $(OUTPUT),$(_MAN_HTML))
20MAN_3 = $(addprefix $(OUTPUT),$(_MAN_3))
21MAN_7 = $(addprefix $(OUTPUT),$(_MAN_7))
22MAN_X = $(MAN_3) $(MAN_7)
23
24# Make the path relative to DESTDIR, not prefix
25ifndef DESTDIR
26 prefix ?=$(HOME)
27endif
28
29mandir ?= $(prefix)/share/man
30man3dir = $(mandir)/man3
31man7dir = $(mandir)/man7
32
33docdir ?= $(prefix)/share/doc/libperf
34htmldir = $(docdir)/html
35exdir = $(docdir)/examples
36
37ASCIIDOC = asciidoc
38ASCIIDOC_EXTRA = --unsafe -f asciidoc.conf
39ASCIIDOC_HTML = xhtml11
40MANPAGE_XSL = manpage-normal.xsl
41XMLTO_EXTRA =
42XMLTO =xmlto
43
44INSTALL ?= install
45RM ?= rm -f
46
47# For asciidoc ...
48# -7.1.2, no extra settings are needed.
49# 8.0-, set ASCIIDOC8.
50#
51
52# For docbook-xsl ...
53# -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0)
54# 1.69.0, no extra settings are needed?
55# 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP?
56# 1.71.1, no extra settings are needed?
57# 1.72.0, set DOCBOOK_XSL_172.
58# 1.73.0-, set ASCIIDOC_NO_ROFF
59
60# If you had been using DOCBOOK_XSL_172 in an attempt to get rid
61# of 'the ".ft C" problem' in your generated manpages, and you
62# instead ended up with weird characters around callouts, try
63# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8).
64
65ifdef ASCIIDOC8
66 ASCIIDOC_EXTRA += -a asciidoc7compatible
67endif
68ifdef DOCBOOK_XSL_172
69 ASCIIDOC_EXTRA += -a libperf-asciidoc-no-roff
70 MANPAGE_XSL = manpage-1.72.xsl
71else
72 ifdef ASCIIDOC_NO_ROFF
73 # docbook-xsl after 1.72 needs the regular XSL, but will not
74 # pass-thru raw roff codes from asciidoc.conf, so turn them off.
75 ASCIIDOC_EXTRA += -a libperf-asciidoc-no-roff
76 endif
77endif
78ifdef MAN_BOLD_LITERAL
79 XMLTO_EXTRA += -m manpage-bold-literal.xsl
80endif
81ifdef DOCBOOK_SUPPRESS_SP
82 XMLTO_EXTRA += -m manpage-suppress-sp.xsl
83endif
84
85DESTDIR ?=
86DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
87
88export DESTDIR DESTDIR_SQ
89
90# Please note that there is a minor bug in asciidoc.
91# The version after 6.0.3 _will_ include the patch found here:
92# http://marc.theaimsgroup.com/?l=libtraceevent&m=111558757202243&w=2
93#
94# Until that version is released you may have to apply the patch
95# yourself - yes, all 6 characters of it!
96
97QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
98QUIET_SUBDIR1 =
99
100ifneq ($(findstring $(MAKEFLAGS),w),w)
101 PRINT_DIR = --no-print-directory
102else # "make -w"
103 NO_SUBDIR = :
104endif
105
106ifneq ($(findstring $(MAKEFLAGS),s),s)
107 ifneq ($(V),1)
108 QUIET_ASCIIDOC = @echo ' ASCIIDOC '$@;
109 QUIET_XMLTO = @echo ' XMLTO '$@;
110 endif
111endif
112
113all: $(MAN_X) $(MAN_HTML)
114
115$(MAN_HTML) $(MAN_X): asciidoc.conf
116
117install-man: all
118 $(call QUIET_INSTALL, man) \
119 $(INSTALL) -d -m 755 $(DESTDIR)$(man3dir); \
120 $(INSTALL) -m 644 $(MAN_3) $(DESTDIR)$(man3dir); \
121 $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir); \
122 $(INSTALL) -m 644 $(MAN_7) $(DESTDIR)$(man7dir);
123
124install-html:
125 $(call QUIET_INSTALL, html) \
126 $(INSTALL) -d -m 755 $(DESTDIR)$(htmldir); \
127 $(INSTALL) -m 644 $(MAN_HTML) $(DESTDIR)$(htmldir); \
128
129install-examples:
130 $(call QUIET_INSTALL, examples) \
131 $(INSTALL) -d -m 755 $(DESTDIR)$(exdir); \
132 $(INSTALL) -m 644 $(MAN_EX) $(DESTDIR)$(exdir); \
133
134CLEAN_FILES = \
135 $(MAN_XML) $(addsuffix +,$(MAN_XML)) \
136 $(MAN_HTML) $(addsuffix +,$(MAN_HTML)) \
137 $(MAN_X)
138
139clean:
140 $(call QUIET_CLEAN, Documentation) $(RM) $(CLEAN_FILES)
141
142$(MAN_3): $(OUTPUT)%.3: %.xml
143 $(QUIET_XMLTO)$(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
144
145$(MAN_7): $(OUTPUT)%.7: %.xml
146 $(QUIET_XMLTO)$(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
147
148$(MAN_XML): $(OUTPUT)%.xml: %.txt
149 $(QUIET_ASCIIDOC)$(ASCIIDOC) -b docbook -d manpage \
150 $(ASCIIDOC_EXTRA) -alibperf_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \
151 mv $@+ $@
152
153$(MAN_HTML): $(OUTPUT)%.html: %.txt
154 $(QUIET_ASCIIDOC)$(ASCIIDOC) -b $(ASCIIDOC_HTML) -d manpage \
155 $(ASCIIDOC_EXTRA) -aperf_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \
156 mv $@+ $@
tools/lib/perf/Documentation/asciidoc.conf+120−0
@@ -0,0 +1,120 @@
1## linktep: macro
2#
3# Usage: linktep:command[manpage-section]
4#
5# Note, {0} is the manpage section, while {target} is the command.
6#
7# Show TEP link as: <command>(<section>); if section is defined, else just show
8# the command.
9
10[macros]
11(?su)[\\]?(?P<name>linktep):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
12
13[attributes]
14asterisk=&#42;
15plus=&#43;
16caret=&#94;
17startsb=&#91;
18endsb=&#93;
19tilde=&#126;
20
21ifdef::backend-docbook[]
22[linktep-inlinemacro]
23{0%{target}}
24{0#<citerefentry>}
25{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
26{0#</citerefentry>}
27endif::backend-docbook[]
28
29ifdef::backend-docbook[]
30ifndef::tep-asciidoc-no-roff[]
31# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
32# v1.72 breaks with this because it replaces dots not in roff requests.
33[listingblock]
34<example><title>{title}</title>
35<literallayout>
36ifdef::doctype-manpage[]
37&#10;.ft C&#10;
38endif::doctype-manpage[]
39|
40ifdef::doctype-manpage[]
41&#10;.ft&#10;
42endif::doctype-manpage[]
43</literallayout>
44{title#}</example>
45endif::tep-asciidoc-no-roff[]
46
47ifdef::tep-asciidoc-no-roff[]
48ifdef::doctype-manpage[]
49# The following two small workarounds insert a simple paragraph after screen
50[listingblock]
51<example><title>{title}</title>
52<literallayout>
53|
54</literallayout><simpara></simpara>
55{title#}</example>
56
57[verseblock]
58<formalpara{id? id="{id}"}><title>{title}</title><para>
59{title%}<literallayout{id? id="{id}"}>
60{title#}<literallayout>
61|
62</literallayout>
63{title#}</para></formalpara>
64{title%}<simpara></simpara>
65endif::doctype-manpage[]
66endif::tep-asciidoc-no-roff[]
67endif::backend-docbook[]
68
69ifdef::doctype-manpage[]
70ifdef::backend-docbook[]
71[header]
72template::[header-declarations]
73<refentry>
74<refmeta>
75<refentrytitle>{mantitle}</refentrytitle>
76<manvolnum>{manvolnum}</manvolnum>
77<refmiscinfo class="source">libperf</refmiscinfo>
78<refmiscinfo class="version">{libperf_version}</refmiscinfo>
79<refmiscinfo class="manual">libperf Manual</refmiscinfo>
80</refmeta>
81<refnamediv>
82 <refname>{manname1}</refname>
83 <refname>{manname2}</refname>
84 <refname>{manname3}</refname>
85 <refname>{manname4}</refname>
86 <refname>{manname5}</refname>
87 <refname>{manname6}</refname>
88 <refname>{manname7}</refname>
89 <refname>{manname8}</refname>
90 <refname>{manname9}</refname>
91 <refname>{manname10}</refname>
92 <refname>{manname11}</refname>
93 <refname>{manname12}</refname>
94 <refname>{manname13}</refname>
95 <refname>{manname14}</refname>
96 <refname>{manname15}</refname>
97 <refname>{manname16}</refname>
98 <refname>{manname17}</refname>
99 <refname>{manname18}</refname>
100 <refname>{manname19}</refname>
101 <refname>{manname20}</refname>
102 <refname>{manname21}</refname>
103 <refname>{manname22}</refname>
104 <refname>{manname23}</refname>
105 <refname>{manname24}</refname>
106 <refname>{manname25}</refname>
107 <refname>{manname26}</refname>
108 <refname>{manname27}</refname>
109 <refname>{manname28}</refname>
110 <refname>{manname29}</refname>
111 <refname>{manname30}</refname>
112 <refpurpose>{manpurpose}</refpurpose>
113</refnamediv>
114endif::backend-docbook[]
115endif::doctype-manpage[]
116
117ifdef::backend-xhtml11[]
118[linktep-inlinemacro]
119<a href="{target}.html">{target}{0?({0})}</a>
120endif::backend-xhtml11[]
tools/lib/perf/Documentation/examples/sampling.c+119−0
@@ -0,0 +1,119 @@
1#include <linux/perf_event.h>
2#include <perf/evlist.h>
3#include <perf/evsel.h>
4#include <perf/cpumap.h>
5#include <perf/threadmap.h>
6#include <perf/mmap.h>
7#include <perf/core.h>
8#include <perf/event.h>
9#include <stdio.h>
10#include <unistd.h>
11
12static int libperf_print(enum libperf_print_level level,
13 const char *fmt, va_list ap)
14{
15 return vfprintf(stderr, fmt, ap);
16}
17
18union u64_swap {
19 __u64 val64;
20 __u32 val32[2];
21};
22
23int main(int argc, char **argv)
24{
25 struct perf_evlist *evlist;
26 struct perf_evsel *evsel;
27 struct perf_mmap *map;
28 struct perf_cpu_map *cpus;
29 struct perf_event_attr attr = {
30 .type = PERF_TYPE_HARDWARE,
31 .config = PERF_COUNT_HW_CPU_CYCLES,
32 .disabled = 1,
33 .freq = 1,
34 .sample_freq = 10,
35 .sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_CPU|PERF_SAMPLE_PERIOD,
36 };
37 int err = -1;
38 union perf_event *event;
39
40 libperf_init(libperf_print);
41
42 cpus = perf_cpu_map__new(NULL);
43 if (!cpus) {
44 fprintf(stderr, "failed to create cpus\n");
45 return -1;
46 }
47
48 evlist = perf_evlist__new();
49 if (!evlist) {
50 fprintf(stderr, "failed to create evlist\n");
51 goto out_cpus;
52 }
53
54 evsel = perf_evsel__new(&attr);
55 if (!evsel) {
56 fprintf(stderr, "failed to create cycles\n");
57 goto out_cpus;
58 }
59
60 perf_evlist__add(evlist, evsel);
61
62 perf_evlist__set_maps(evlist, cpus, NULL);
63
64 err = perf_evlist__open(evlist);
65 if (err) {
66 fprintf(stderr, "failed to open evlist\n");
67 goto out_evlist;
68 }
69
70 err = perf_evlist__mmap(evlist, 4);
71 if (err) {
72 fprintf(stderr, "failed to mmap evlist\n");
73 goto out_evlist;
74 }
75
76 perf_evlist__enable(evlist);
77 sleep(3);
78 perf_evlist__disable(evlist);
79
80 perf_evlist__for_each_mmap(evlist, map, false) {
81 if (perf_mmap__read_init(map) < 0)
82 continue;
83
84 while ((event = perf_mmap__read_event(map)) != NULL) {
85 int cpu, pid, tid;
86 __u64 ip, period, *array;
87 union u64_swap u;
88
89 array = event->sample.array;
90
91 ip = *array;
92 array++;
93
94 u.val64 = *array;
95 pid = u.val32[0];
96 tid = u.val32[1];
97 array++;
98
99 u.val64 = *array;
100 cpu = u.val32[0];
101 array++;
102
103 period = *array;
104
105 fprintf(stdout, "cpu %3d, pid %6d, tid %6d, ip %20llx, period %20llu\n",
106 cpu, pid, tid, ip, period);
107
108 perf_mmap__consume(map);
109 }
110
111 perf_mmap__read_done(map);
112 }
113
114out_evlist:
115 perf_evlist__delete(evlist);
116out_cpus:
117 perf_cpu_map__put(cpus);
118 return err;
119}
tools/lib/perf/Documentation/libperf-counting.txt+211−0
@@ -0,0 +1,211 @@
1libperf-counting(7)
2===================
3
4NAME
5----
6libperf-counting - counting interface
7
8DESCRIPTION
9-----------
10The counting interface provides API to meassure and get count for specific perf events.
11
12The following test tries to explain count on `counting.c` example.
13
14It is by no means complete guide to counting, but shows libperf basic API for counting.
15
16The `counting.c` comes with libbperf package and can be compiled and run like:
17
18[source,bash]
19--
20$ gcc -o counting counting.c -lperf
21$ sudo ./counting
22count 176792, enabled 176944, run 176944
23count 176242, enabled 176242, run 176242
24--
25
26It requires root access, because of the `PERF_COUNT_SW_CPU_CLOCK` event,
27which is available only for root.
28
29The `counting.c` example monitors two events on the current process and displays their count, in a nutshel it:
30
31* creates events
32* adds them to the event list
33* opens and enables events through the event list
34* does some workload
35* disables events
36* reads and displays event counts
37* destroys the event list
38
39The first thing you need to do before using libperf is to call init function:
40
41[source,c]
42--
43 8 static int libperf_print(enum libperf_print_level level,
44 9 const char *fmt, va_list ap)
45 10 {
46 11 return vfprintf(stderr, fmt, ap);
47 12 }
48
49 14 int main(int argc, char **argv)
50 15 {
51 ...
52 35 libperf_init(libperf_print);
53--
54
55It will setup the library and sets function for debug output from library.
56
57The `libperf_print` callback will receive any message with its debug level,
58defined as:
59
60[source,c]
61--
62enum libperf_print_level {
63 LIBPERF_ERR,
64 LIBPERF_WARN,
65 LIBPERF_INFO,
66 LIBPERF_DEBUG,
67 LIBPERF_DEBUG2,
68 LIBPERF_DEBUG3,
69};
70--
71
72Once the setup is complete we start by defining specific events using the `struct perf_event_attr`.
73
74We create software events for cpu and task:
75
76[source,c]
77--
78 20 struct perf_event_attr attr1 = {
79 21 .type = PERF_TYPE_SOFTWARE,
80 22 .config = PERF_COUNT_SW_CPU_CLOCK,
81 23 .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING,
82 24 .disabled = 1,
83 25 };
84 26 struct perf_event_attr attr2 = {
85 27 .type = PERF_TYPE_SOFTWARE,
86 28 .config = PERF_COUNT_SW_TASK_CLOCK,
87 29 .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING,
88 30 .disabled = 1,
89 31 };
90--
91
92The `read_format` setup tells perf to include timing details together with each count.
93
94Next step is to prepare threads map.
95
96In this case we will monitor current process, so we create threads map with single pid (0):
97
98[source,c]
99--
100 37 threads = perf_thread_map__new_dummy();
101 38 if (!threads) {
102 39 fprintf(stderr, "failed to create threads\n");
103 40 return -1;
104 41 }
105 42
106 43 perf_thread_map__set_pid(threads, 0, 0);
107--
108
109Now we create libperf's event list, which will serve as holder for the events we want:
110
111[source,c]
112--
113 45 evlist = perf_evlist__new();
114 46 if (!evlist) {
115 47 fprintf(stderr, "failed to create evlist\n");
116 48 goto out_threads;
117 49 }
118--
119
120We create libperf's events for the attributes we defined earlier and add them to the list:
121
122[source,c]
123--
124 51 evsel = perf_evsel__new(&attr1);
125 52 if (!evsel) {
126 53 fprintf(stderr, "failed to create evsel1\n");
127 54 goto out_evlist;
128 55 }
129 56
130 57 perf_evlist__add(evlist, evsel);
131 58
132 59 evsel = perf_evsel__new(&attr2);
133 60 if (!evsel) {
134 61 fprintf(stderr, "failed to create evsel2\n");
135 62 goto out_evlist;
136 63 }
137 64
138 65 perf_evlist__add(evlist, evsel);
139--
140
141Configure event list with the thread map and open events:
142
143[source,c]
144--
145 67 perf_evlist__set_maps(evlist, NULL, threads);
146 68
147 69 err = perf_evlist__open(evlist);
148 70 if (err) {
149 71 fprintf(stderr, "failed to open evsel\n");
150 72 goto out_evlist;
151 73 }
152--
153
154Both events are created as disabled (note the `disabled = 1` assignment above),
155so we need to enable the whole list explicitely (both events).
156
157From this moment events are counting and we can do our workload.
158
159When we are done we disable the events list.
160
161[source,c]
162--
163 75 perf_evlist__enable(evlist);
164 76
165 77 while (count--);
166 78
167 79 perf_evlist__disable(evlist);
168--
169
170Now we need to get the counts from events, following code iterates throught the events list and read counts:
171
172[source,c]
173--
174 81 perf_evlist__for_each_evsel(evlist, evsel) {
175 82 perf_evsel__read(evsel, 0, 0, &counts);
176 83 fprintf(stdout, "count %llu, enabled %llu, run %llu\n",
177 84 counts.val, counts.ena, counts.run);
178 85 }
179--
180
181And finaly cleanup.
182
183We close the whole events list (both events) and remove it together with the threads map:
184
185[source,c]
186--
187 87 perf_evlist__close(evlist);
188 88
189 89 out_evlist:
190 90 perf_evlist__delete(evlist);
191 91 out_threads:
192 92 perf_thread_map__put(threads);
193 93 return err;
194 94 }
195--
196
197REPORTING BUGS
198--------------
199Report bugs to <linux-perf-users@vger.kernel.org>.
200
201LICENSE
202-------
203libperf is Free Software licensed under the GNU LGPL 2.1
204
205RESOURCES
206---------
207https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
208
209SEE ALSO
210--------
211libperf(3), libperf-sampling(7)
tools/lib/perf/Documentation/libperf-sampling.txt+243−0
@@ -0,0 +1,243 @@
1libperf-sampling(7)
2===================
3
4NAME
5----
6libperf-sampling - sampling interface
7
8
9DESCRIPTION
10-----------
11The sampling interface provides API to meassure and get count for specific perf events.
12
13The following test tries to explain count on `sampling.c` example.
14
15It is by no means complete guide to sampling, but shows libperf basic API for sampling.
16
17The `sampling.c` comes with libbperf package and can be compiled and run like:
18
19[source,bash]
20--
21$ gcc -o sampling sampling.c -lperf
22$ sudo ./sampling
23cpu 0, pid 0, tid 0, ip ffffffffad06c4e6, period 1
24cpu 0, pid 4465, tid 4469, ip ffffffffad118748, period 18322959
25cpu 0, pid 0, tid 0, ip ffffffffad115722, period 33544846
26cpu 0, pid 4465, tid 4470, ip 7f84fe0cdad6, period 23687474
27cpu 0, pid 0, tid 0, ip ffffffffad9e0349, period 34255790
28cpu 0, pid 4465, tid 4469, ip ffffffffad136581, period 38664069
29cpu 0, pid 0, tid 0, ip ffffffffad9e55e2, period 21922384
30cpu 0, pid 4465, tid 4470, ip 7f84fe0ebebf, period 17655175
31...
32--
33
34It requires root access, because it uses hardware cycles event.
35
36The `sampling.c` example profiles/samples all CPUs with hardware cycles, in a nutshel it:
37
38- creates events
39- adds them to the event list
40- opens and enables events through the event list
41- sleeps for 3 seconds
42- disables events
43- reads and displays recorded samples
44- destroys the event list
45
46The first thing you need to do before using libperf is to call init function:
47
48[source,c]
49--
50 12 static int libperf_print(enum libperf_print_level level,
51 13 const char *fmt, va_list ap)
52 14 {
53 15 return vfprintf(stderr, fmt, ap);
54 16 }
55
56 23 int main(int argc, char **argv)
57 24 {
58 ...
59 40 libperf_init(libperf_print);
60--
61
62It will setup the library and sets function for debug output from library.
63
64The `libperf_print` callback will receive any message with its debug level,
65defined as:
66
67[source,c]
68--
69enum libperf_print_level {
70 LIBPERF_ERR,
71 LIBPERF_WARN,
72 LIBPERF_INFO,
73 LIBPERF_DEBUG,
74 LIBPERF_DEBUG2,
75 LIBPERF_DEBUG3,
76};
77--
78
79Once the setup is complete we start by defining cycles event using the `struct perf_event_attr`:
80
81[source,c]
82--
83 29 struct perf_event_attr attr = {
84 30 .type = PERF_TYPE_HARDWARE,
85 31 .config = PERF_COUNT_HW_CPU_CYCLES,
86 32 .disabled = 1,
87 33 .freq = 1,
88 34 .sample_freq = 10,
89 35 .sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_CPU|PERF_SAMPLE_PERIOD,
90 36 };
91--
92
93Next step is to prepare cpus map.
94
95In this case we will monitor all the available CPUs:
96
97[source,c]
98--
99 42 cpus = perf_cpu_map__new(NULL);
100 43 if (!cpus) {
101 44 fprintf(stderr, "failed to create cpus\n");
102 45 return -1;
103 46 }
104--
105
106Now we create libperf's event list, which will serve as holder for the cycles event:
107
108[source,c]
109--
110 48 evlist = perf_evlist__new();
111 49 if (!evlist) {
112 50 fprintf(stderr, "failed to create evlist\n");
113 51 goto out_cpus;
114 52 }
115--
116
117We create libperf's event for the cycles attribute we defined earlier and add it to the list:
118
119[source,c]
120--
121 54 evsel = perf_evsel__new(&attr);
122 55 if (!evsel) {
123 56 fprintf(stderr, "failed to create cycles\n");
124 57 goto out_cpus;
125 58 }
126 59
127 60 perf_evlist__add(evlist, evsel);
128--
129
130Configure event list with the cpus map and open event:
131
132[source,c]
133--
134 62 perf_evlist__set_maps(evlist, cpus, NULL);
135 63
136 64 err = perf_evlist__open(evlist);
137 65 if (err) {
138 66 fprintf(stderr, "failed to open evlist\n");
139 67 goto out_evlist;
140 68 }
141--
142
143Once the events list is open, we can create memory maps AKA perf ring buffers:
144
145[source,c]
146--
147 70 err = perf_evlist__mmap(evlist, 4);
148 71 if (err) {
149 72 fprintf(stderr, "failed to mmap evlist\n");
150 73 goto out_evlist;
151 74 }
152--
153
154The event is created as disabled (note the `disabled = 1` assignment above),
155so we need to enable the events list explicitely.
156
157From this moment the cycles event is sampling.
158
159We will sleep for 3 seconds while the ring buffers get data from all CPUs, then we disable the events list.
160
161[source,c]
162--
163 76 perf_evlist__enable(evlist);
164 77 sleep(3);
165 78 perf_evlist__disable(evlist);
166--
167
168Following code walks through the ring buffers and reads stored events/samples:
169
170[source,c]
171--
172 80 perf_evlist__for_each_mmap(evlist, map, false) {
173 81 if (perf_mmap__read_init(map) < 0)
174 82 continue;
175 83
176 84 while ((event = perf_mmap__read_event(map)) != NULL) {
177
178 /* process event */
179
180108 perf_mmap__consume(map);
181109 }
182110 perf_mmap__read_done(map);
183111 }
184
185--
186
187Each sample needs to get parsed:
188
189[source,c]
190--
191 85 int cpu, pid, tid;
192 86 __u64 ip, period, *array;
193 87 union u64_swap u;
194 88
195 89 array = event->sample.array;
196 90
197 91 ip = *array;
198 92 array++;
199 93
200 94 u.val64 = *array;
201 95 pid = u.val32[0];
202 96 tid = u.val32[1];
203 97 array++;
204 98
205 99 u.val64 = *array;
206100 cpu = u.val32[0];
207101 array++;
208102
209103 period = *array;
210104
211105 fprintf(stdout, "cpu %3d, pid %6d, tid %6d, ip %20llx, period %20llu\n",
212106 cpu, pid, tid, ip, period);
213--
214
215And finaly cleanup.
216
217We close the whole events list (both events) and remove it together with the threads map:
218
219[source,c]
220--
221113 out_evlist:
222114 perf_evlist__delete(evlist);
223115 out_cpus:
224116 perf_cpu_map__put(cpus);
225117 return err;
226118 }
227--
228
229REPORTING BUGS
230--------------
231Report bugs to <linux-perf-users@vger.kernel.org>.
232
233LICENSE
234-------
235libperf is Free Software licensed under the GNU LGPL 2.1
236
237RESOURCES
238---------
239https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
240
241SEE ALSO
242--------
243libperf(3), libperf-counting(7)
tools/lib/perf/Documentation/libperf.txt+246−0
@@ -0,0 +1,246 @@
1libperf(3)
2==========
3
4NAME
5----
6libperf - Linux kernel perf event library
7
8
9SYNOPSIS
10--------
11*Generic API:*
12
13[source,c]
14--
15 #include <perf/core.h>
16
17 enum libperf_print_level {
18 LIBPERF_ERR,
19 LIBPERF_WARN,
20 LIBPERF_INFO,
21 LIBPERF_DEBUG,
22 LIBPERF_DEBUG2,
23 LIBPERF_DEBUG3,
24 };
25
26 typedef int (*libperf_print_fn_t)(enum libperf_print_level level,
27 const char *, va_list ap);
28
29 void libperf_init(libperf_print_fn_t fn);
30--
31
32*API to handle cpu maps:*
33
34[source,c]
35--
36 #include <perf/cpumap.h>
37
38 struct perf_cpu_map;
39
40 struct perf_cpu_map *perf_cpu_map__dummy_new(void);
41 struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
42 struct perf_cpu_map *perf_cpu_map__read(FILE *file);
43 struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
44 struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
45 struct perf_cpu_map *other);
46 void perf_cpu_map__put(struct perf_cpu_map *map);
47 int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
48 int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
49 bool perf_cpu_map__empty(const struct perf_cpu_map *map);
50 int perf_cpu_map__max(struct perf_cpu_map *map);
51
52 #define perf_cpu_map__for_each_cpu(cpu, idx, cpus)
53--
54
55*API to handle thread maps:*
56
57[source,c]
58--
59 #include <perf/threadmap.h>
60
61 struct perf_thread_map;
62
63 struct perf_thread_map *perf_thread_map__new_dummy(void);
64
65 void perf_thread_map__set_pid(struct perf_thread_map *map, int thread, pid_t pid);
66 char *perf_thread_map__comm(struct perf_thread_map *map, int thread);
67 int perf_thread_map__nr(struct perf_thread_map *threads);
68 pid_t perf_thread_map__pid(struct perf_thread_map *map, int thread);
69
70 struct perf_thread_map *perf_thread_map__get(struct perf_thread_map *map);
71 void perf_thread_map__put(struct perf_thread_map *map);
72--
73
74*API to handle event lists:*
75
76[source,c]
77--
78 #include <perf/evlist.h>
79
80 struct perf_evlist;
81
82 void perf_evlist__add(struct perf_evlist *evlist,
83 struct perf_evsel *evsel);
84 void perf_evlist__remove(struct perf_evlist *evlist,
85 struct perf_evsel *evsel);
86 struct perf_evlist *perf_evlist__new(void);
87 void perf_evlist__delete(struct perf_evlist *evlist);
88 struct perf_evsel* perf_evlist__next(struct perf_evlist *evlist,
89 struct perf_evsel *evsel);
90 int perf_evlist__open(struct perf_evlist *evlist);
91 void perf_evlist__close(struct perf_evlist *evlist);
92 void perf_evlist__enable(struct perf_evlist *evlist);
93 void perf_evlist__disable(struct perf_evlist *evlist);
94
95 #define perf_evlist__for_each_evsel(evlist, pos)
96
97 void perf_evlist__set_maps(struct perf_evlist *evlist,
98 struct perf_cpu_map *cpus,
99 struct perf_thread_map *threads);
100 int perf_evlist__poll(struct perf_evlist *evlist, int timeout);
101 int perf_evlist__filter_pollfd(struct perf_evlist *evlist,
102 short revents_and_mask);
103
104 int perf_evlist__mmap(struct perf_evlist *evlist, int pages);
105 void perf_evlist__munmap(struct perf_evlist *evlist);
106
107 struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist,
108 struct perf_mmap *map,
109 bool overwrite);
110
111 #define perf_evlist__for_each_mmap(evlist, pos, overwrite)
112--
113
114*API to handle events:*
115
116[source,c]
117--
118 #include <perf/evsel.h>*
119
120 struct perf_evsel;
121
122 struct perf_counts_values {
123 union {
124 struct {
125 uint64_t val;
126 uint64_t ena;
127 uint64_t run;
128 };
129 uint64_t values[3];
130 };
131 };
132
133 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr);
134 void perf_evsel__delete(struct perf_evsel *evsel);
135 int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
136 struct perf_thread_map *threads);
137 void perf_evsel__close(struct perf_evsel *evsel);
138 void perf_evsel__close_cpu(struct perf_evsel *evsel, int cpu);
139 int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
140 struct perf_counts_values *count);
141 int perf_evsel__enable(struct perf_evsel *evsel);
142 int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu);
143 int perf_evsel__disable(struct perf_evsel *evsel);
144 int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu);
145 struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
146 struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel);
147 struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel);
148--
149
150*API to handle maps (perf ring buffers):*
151
152[source,c]
153--
154 #include <perf/mmap.h>
155
156 struct perf_mmap;
157
158 void perf_mmap__consume(struct perf_mmap *map);
159 int perf_mmap__read_init(struct perf_mmap *map);
160 void perf_mmap__read_done(struct perf_mmap *map);
161 union perf_event *perf_mmap__read_event(struct perf_mmap *map);
162--
163
164*Structures to access perf API events:*
165
166[source,c]
167--
168 #include <perf/event.h>
169
170 struct perf_record_mmap;
171 struct perf_record_mmap2;
172 struct perf_record_comm;
173 struct perf_record_namespaces;
174 struct perf_record_fork;
175 struct perf_record_lost;
176 struct perf_record_lost_samples;
177 struct perf_record_read;
178 struct perf_record_throttle;
179 struct perf_record_ksymbol;
180 struct perf_record_bpf_event;
181 struct perf_record_sample;
182 struct perf_record_switch;
183 struct perf_record_header_attr;
184 struct perf_record_record_cpu_map;
185 struct perf_record_cpu_map_data;
186 struct perf_record_cpu_map;
187 struct perf_record_event_update_cpus;
188 struct perf_record_event_update_scale;
189 struct perf_record_event_update;
190 struct perf_trace_event_type;
191 struct perf_record_header_event_type;
192 struct perf_record_header_tracing_data;
193 struct perf_record_header_build_id;
194 struct perf_record_id_index;
195 struct perf_record_auxtrace_info;
196 struct perf_record_auxtrace;
197 struct perf_record_auxtrace_error;
198 struct perf_record_aux;
199 struct perf_record_itrace_start;
200 struct perf_record_thread_map_entry;
201 struct perf_record_thread_map;
202 struct perf_record_stat_config_entry;
203 struct perf_record_stat_config;
204 struct perf_record_stat;
205 struct perf_record_stat_round;
206 struct perf_record_time_conv;
207 struct perf_record_header_feature;
208 struct perf_record_compressed;
209--
210
211DESCRIPTION
212-----------
213The libperf library provides an API to access the linux kernel perf
214events subsystem.
215
216Following objects are key to the libperf interface:
217
218[horizontal]
219
220struct perf_cpu_map:: Provides a cpu list abstraction.
221
222struct perf_thread_map:: Provides a thread list abstraction.
223
224struct perf_evsel:: Provides an abstraction for single a perf event.
225
226struct perf_evlist:: Gathers several struct perf_evsel object and performs functions on all of them.
227
228struct perf_mmap:: Provides an abstraction for accessing perf ring buffer.
229
230The exported API functions bind these objects together.
231
232REPORTING BUGS
233--------------
234Report bugs to <linux-perf-users@vger.kernel.org>.
235
236LICENSE
237-------
238libperf is Free Software licensed under the GNU LGPL 2.1
239
240RESOURCES
241---------
242https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
243
244SEE ALSO
245--------
246libperf-sampling(7), libperf-counting(7)
tools/lib/perf/Documentation/manpage-1.72.xsl+14−0
@@ -0,0 +1,14 @@
1<!-- manpage-1.72.xsl:
2 special settings for manpages rendered from asciidoc+docbook
3 handles peculiarities in docbook-xsl 1.72.0 -->
4<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5 version="1.0">
6
7<xsl:import href="manpage-base.xsl"/>
8
9<!-- these are the special values for the roff control characters
10 needed for docbook-xsl 1.72.0 -->
11<xsl:param name="git.docbook.backslash">&#x2593;</xsl:param>
12<xsl:param name="git.docbook.dot" >&#x2302;</xsl:param>
13
14</xsl:stylesheet>
tools/lib/perf/Documentation/manpage-base.xsl+35−0
@@ -0,0 +1,35 @@
1<!-- manpage-base.xsl:
2 special formatting for manpages rendered from asciidoc+docbook -->
3<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
4 version="1.0">
5
6<!-- these params silence some output from xmlto -->
7<xsl:param name="man.output.quietly" select="1"/>
8<xsl:param name="refentry.meta.get.quietly" select="1"/>
9
10<!-- convert asciidoc callouts to man page format;
11 git.docbook.backslash and git.docbook.dot params
12 must be supplied by another XSL file or other means -->
13<xsl:template match="co">
14 <xsl:value-of select="concat(
15 $git.docbook.backslash,'fB(',
16 substring-after(@id,'-'),')',
17 $git.docbook.backslash,'fR')"/>
18</xsl:template>
19<xsl:template match="calloutlist">
20 <xsl:value-of select="$git.docbook.dot"/>
21 <xsl:text>sp&#10;</xsl:text>
22 <xsl:apply-templates/>
23 <xsl:text>&#10;</xsl:text>
24</xsl:template>
25<xsl:template match="callout">
26 <xsl:value-of select="concat(
27 $git.docbook.backslash,'fB',
28 substring-after(@arearefs,'-'),
29 '. ',$git.docbook.backslash,'fR')"/>
30 <xsl:apply-templates/>
31 <xsl:value-of select="$git.docbook.dot"/>
32 <xsl:text>br&#10;</xsl:text>
33</xsl:template>
34
35</xsl:stylesheet>
tools/lib/perf/Documentation/manpage-bold-literal.xsl+17−0
@@ -0,0 +1,17 @@
1<!-- manpage-bold-literal.xsl:
2 special formatting for manpages rendered from asciidoc+docbook -->
3<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
4 version="1.0">
5
6<!-- render literal text as bold (instead of plain or monospace);
7 this makes literal text easier to distinguish in manpages
8 viewed on a tty -->
9<xsl:template match="literal">
10 <xsl:value-of select="$git.docbook.backslash"/>
11 <xsl:text>fB</xsl:text>
12 <xsl:apply-templates/>
13 <xsl:value-of select="$git.docbook.backslash"/>
14 <xsl:text>fR</xsl:text>
15</xsl:template>
16
17</xsl:stylesheet>
tools/lib/perf/Documentation/manpage-normal.xsl+13−0
@@ -0,0 +1,13 @@
1<!-- manpage-normal.xsl:
2 special settings for manpages rendered from asciidoc+docbook
3 handles anything we want to keep away from docbook-xsl 1.72.0 -->
4<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5 version="1.0">
6
7<xsl:import href="manpage-base.xsl"/>
8
9<!-- these are the normal values for the roff control characters -->
10<xsl:param name="git.docbook.backslash">\</xsl:param>
11<xsl:param name="git.docbook.dot" >.</xsl:param>
12
13</xsl:stylesheet>
tools/lib/perf/Documentation/manpage-suppress-sp.xsl+21−0
@@ -0,0 +1,21 @@
1<!-- manpage-suppress-sp.xsl:
2 special settings for manpages rendered from asciidoc+docbook
3 handles erroneous, inline .sp in manpage output of some
4 versions of docbook-xsl -->
5<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
6 version="1.0">
7
8<!-- attempt to work around spurious .sp at the tail of the line
9 that some versions of docbook stylesheets seem to add -->
10<xsl:template match="simpara">
11 <xsl:variable name="content">
12 <xsl:apply-templates/>
13 </xsl:variable>
14 <xsl:value-of select="normalize-space($content)"/>
15 <xsl:if test="not(ancestor::authorblurb) and
16 not(ancestor::personblurb)">
17 <xsl:text>&#10;&#10;</xsl:text>
18 </xsl:if>
19</xsl:template>
20
21</xsl:stylesheet>
tools/lib/perf/Makefilerenamed from tools/perf/lib/Makefile+5−2
@@ -60,7 +60,7 @@ else · 59 unmodified lines
60endif60endif
61 61
62INCLUDES = \62INCLUDES = \
63-I$(srctree)/tools/perf/lib/include \63-I$(srctree)/tools/lib/perf/include \
64-I$(srctree)/tools/lib/ \64-I$(srctree)/tools/lib/ \
65-I$(srctree)/tools/include \65-I$(srctree)/tools/include \
66-I$(srctree)/tools/arch/$(SRCARCH)/include/ \66-I$(srctree)/tools/arch/$(SRCARCH)/include/ \
@@ -181,7 +181,10 @@ install_pkgconfig: $(LIBPERF_PC) · 114 unmodified lines
181 $(call QUIET_INSTALL, $(LIBPERF_PC)) \181 $(call QUIET_INSTALL, $(LIBPERF_PC)) \
182 $(call do_install,$(LIBPERF_PC),$(libdir_SQ)/pkgconfig,644)182 $(call do_install,$(LIBPERF_PC),$(libdir_SQ)/pkgconfig,644)
183 183
184install: install_lib install_headers install_pkgconfig184install_doc:
185 $(Q)$(MAKE) -C Documentation install-man install-html install-examples
186
187install: install_lib install_headers install_pkgconfig install_doc
185 188
186FORCE:189FORCE:
187 190
tools/lib/perf/core.crenamed from tools/perf/lib/core.c+0−0

File renamed without changes.

tools/lib/perf/cpumap.crenamed from tools/perf/lib/cpumap.c+0−0

File renamed without changes.

tools/lib/perf/evlist.crenamed from tools/perf/lib/evlist.c+3−0
@@ -164,6 +164,9 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, · 163 unmodified lines
164 evlist->threads = perf_thread_map__get(threads);164 evlist->threads = perf_thread_map__get(threads);
165 }165 }
166 166
167 if (!evlist->all_cpus && cpus)
168 evlist->all_cpus = perf_cpu_map__get(cpus);
169
167 perf_evlist__propagate_maps(evlist);170 perf_evlist__propagate_maps(evlist);
168}171}
169 172
tools/lib/perf/evsel.crenamed from tools/perf/lib/evsel.c+0−0

File renamed without changes.

tools/lib/perf/include/internal/cpumap.hrenamed from tools/perf/lib/include/internal/cpumap.h+0−0

File renamed without changes.

tools/lib/perf/include/internal/evlist.hrenamed from tools/perf/lib/include/internal/evlist.h+0−0

File renamed without changes.

tools/lib/perf/include/internal/evsel.hrenamed from tools/perf/lib/include/internal/evsel.h+0−0

File renamed without changes.

tools/lib/perf/include/internal/lib.hrenamed from tools/perf/lib/include/internal/lib.h+0−0

File renamed without changes.

tools/lib/perf/include/internal/mmap.hrenamed from tools/perf/lib/include/internal/mmap.h+0−0

File renamed without changes.

tools/lib/perf/include/internal/tests.hrenamed from tools/perf/lib/include/internal/tests.h+0−0

File renamed without changes.

tools/lib/perf/include/internal/threadmap.hrenamed from tools/perf/lib/include/internal/threadmap.h+0−0

File renamed without changes.

tools/lib/perf/include/internal/xyarray.hrenamed from tools/perf/lib/include/internal/xyarray.h+0−0

File renamed without changes.

tools/lib/perf/include/perf/core.hrenamed from tools/perf/lib/include/perf/core.h+0−0

File renamed without changes.

tools/lib/perf/include/perf/cpumap.hrenamed from tools/perf/lib/include/perf/cpumap.h+0−0

File renamed without changes.

tools/lib/perf/include/perf/event.hrenamed from tools/perf/lib/include/perf/event.h+0−0

File renamed without changes.

tools/lib/perf/include/perf/evlist.hrenamed from tools/perf/lib/include/perf/evlist.h+0−0

File renamed without changes.

tools/lib/perf/include/perf/evsel.hrenamed from tools/perf/lib/include/perf/evsel.h+0−0

File renamed without changes.

tools/lib/perf/include/perf/mmap.hrenamed from tools/perf/lib/include/perf/mmap.h+0−0

File renamed without changes.

tools/lib/perf/include/perf/threadmap.hrenamed from tools/perf/lib/include/perf/threadmap.h+0−0

File renamed without changes.

tools/lib/perf/internal.hrenamed from tools/perf/lib/internal.h+0−0

File renamed without changes.

tools/lib/perf/lib.crenamed from tools/perf/lib/lib.c+0−0

File renamed without changes.

tools/lib/perf/libperf.maprenamed from tools/perf/lib/libperf.map+0−0

File renamed without changes.

tools/lib/perf/libperf.pc.templaterenamed from tools/perf/lib/libperf.pc.template+0−0

File renamed without changes.

tools/lib/perf/mmap.crenamed from tools/perf/lib/mmap.c+0−0

File renamed without changes.

tools/lib/perf/tests/Makefilerenamed from tools/perf/lib/tests/Makefile+1−1
@@ -16,7 +16,7 @@ all: · 15 unmodified lines
16 16
17include $(srctree)/tools/scripts/Makefile.include17include $(srctree)/tools/scripts/Makefile.include
18 18
19INCLUDE = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include -I$(srctree)/tools/lib19INCLUDE = -I$(srctree)/tools/lib/perf/include -I$(srctree)/tools/include -I$(srctree)/tools/lib
20 20
21$(TESTS_A): FORCE21$(TESTS_A): FORCE
22 $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a $(LIBAPI)22 $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a $(LIBAPI)
tools/lib/perf/tests/test-cpumap.crenamed from tools/perf/lib/tests/test-cpumap.c+0−0

File renamed without changes.

tools/lib/perf/tests/test-evlist.crenamed from tools/perf/lib/tests/test-evlist.c+0−0

File renamed without changes.

tools/lib/perf/tests/test-evsel.crenamed from tools/perf/lib/tests/test-evsel.c+0−0

File renamed without changes.

tools/lib/perf/tests/test-threadmap.crenamed from tools/perf/lib/tests/test-threadmap.c+0−0

File renamed without changes.

tools/lib/perf/threadmap.crenamed from tools/perf/lib/threadmap.c+0−0

File renamed without changes.

tools/lib/perf/xyarray.crenamed from tools/perf/lib/xyarray.c+0−0

File renamed without changes.

tools/lib/string.c+7−0
@@ -96,6 +96,10 @@ int strtobool(const char *s, bool *res) · 95 unmodified lines
96 * If libc has strlcpy() then that version will override this96 * If libc has strlcpy() then that version will override this
97 * implementation:97 * implementation:
98 */98 */
99#ifdef __clang__
100#pragma clang diagnostic push
101#pragma clang diagnostic ignored "-Wignored-attributes"
102#endif
99size_t __weak strlcpy(char *dest, const char *src, size_t size)103size_t __weak strlcpy(char *dest, const char *src, size_t size)
100{104{
101 size_t ret = strlen(src);105 size_t ret = strlen(src);
@@ -107,6 +111,9 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size) · 5 unmodified lines
107 }111 }
108 return ret;112 return ret;
109}113}
114#ifdef __clang__
115#pragma clang diagnostic pop
116#endif
110 117
111/**118/**
112 * skip_spaces - Removes leading whitespace from @str.119 * skip_spaces - Removes leading whitespace from @str.
tools/perf/Documentation/perf-annotate.txt+6−0
@@ -112,6 +112,12 @@ OPTIONS · 111 unmodified lines
112--objdump=<path>::112--objdump=<path>::
113 Path to objdump binary.113 Path to objdump binary.
114 114
115--prefix=PREFIX::
116--prefix-strip=N::
117 Remove first N entries from source file path names in executables
118 and add PREFIX. This allows to display source code compiled on systems
119 with different file system layout.
120
115--skip-missing::121--skip-missing::
116 Skip symbols that cannot be annotated.122 Skip symbols that cannot be annotated.
117 123
tools/perf/Documentation/perf-report.txt+6−0
@@ -367,6 +367,12 @@ OPTIONS · 366 unmodified lines
367--objdump=<path>::367--objdump=<path>::
368 Path to objdump binary.368 Path to objdump binary.
369 369
370--prefix=PREFIX::
371--prefix-strip=N::
372 Remove first N entries from source file path names in executables
373 and add PREFIX. This allows to display source code compiled on systems
374 with different file system layout.
375
370--group::376--group::
371 Show event group information together. It forces group output also377 Show event group information together. It forces group output also
372 if there are no groups defined in data file.378 if there are no groups defined in data file.
tools/perf/Documentation/perf-sched.txt+4−0
@@ -110,6 +110,10 @@ OPTIONS for 'perf sched timehist' · 109 unmodified lines
110--max-stack::110--max-stack::
111 Maximum number of functions to display in backtrace, default 5.111 Maximum number of functions to display in backtrace, default 5.
112 112
113-C=::
114--cpu=::
115 Only show events for the given CPU(s) (comma separated list).
116
113-p=::117-p=::
114--pid=::118--pid=::
115 Only show events for given process ID (comma separated list).119 Only show events for given process ID (comma separated list).
tools/perf/Documentation/perf-top.txt+6−0
@@ -158,6 +158,12 @@ Default is to monitor all CPUS. · 157 unmodified lines
158-M::158-M::
159--disassembler-style=:: Set disassembler style for objdump.159--disassembler-style=:: Set disassembler style for objdump.
160 160
161--prefix=PREFIX::
162--prefix-strip=N::
163 Remove first N entries from source file path names in executables
164 and add PREFIX. This allows to display source code compiled on systems
165 with different file system layout.
166
161--source::167--source::
162 Interleave source code with assembly code. Enabled by default,168 Interleave source code with assembly code. Enabled by default,
163 disable with --no-source.169 disable with --no-source.
tools/perf/MANIFEST+1−0
@@ -7,6 +7,7 @@ tools/lib/traceevent · 6 unmodified lines
7tools/lib/api7tools/lib/api
8tools/lib/bpf8tools/lib/bpf
9tools/lib/subcmd9tools/lib/subcmd
10tools/lib/perf
10tools/lib/argv_split.c11tools/lib/argv_split.c
11tools/lib/ctype.c12tools/lib/ctype.c
12tools/lib/hweight.c13tools/lib/hweight.c
tools/perf/Makefile.config+1−1
@@ -286,7 +286,7 @@ ifeq ($(DEBUG),0) · 285 unmodified lines
286 endif286 endif
287endif287endif
288 288
289INC_FLAGS += -I$(src-perf)/lib/include289INC_FLAGS += -I$(srctree)/tools/lib/perf/include
290INC_FLAGS += -I$(src-perf)/util/include290INC_FLAGS += -I$(src-perf)/util/include
291INC_FLAGS += -I$(src-perf)/arch/$(SRCARCH)/include291INC_FLAGS += -I$(src-perf)/arch/$(SRCARCH)/include
292INC_FLAGS += -I$(srctree)/tools/include/292INC_FLAGS += -I$(srctree)/tools/include/
tools/perf/Makefile.perf+1−1
@@ -230,7 +230,7 @@ LIB_DIR = $(srctree)/tools/lib/api/ · 229 unmodified lines
230TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/230TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
231BPF_DIR = $(srctree)/tools/lib/bpf/231BPF_DIR = $(srctree)/tools/lib/bpf/
232SUBCMD_DIR = $(srctree)/tools/lib/subcmd/232SUBCMD_DIR = $(srctree)/tools/lib/subcmd/
233LIBPERF_DIR = $(srctree)/tools/perf/lib/233LIBPERF_DIR = $(srctree)/tools/lib/perf/
234 234
235# Set FEATURE_TESTS to 'all' so all possible feature checkers are executed.235# Set FEATURE_TESTS to 'all' so all possible feature checkers are executed.
236# Without this setting the output feature dump file misses some features, for236# Without this setting the output feature dump file misses some features, for
tools/perf/builtin-annotate.c+7−0
@@ -535,6 +535,10 @@ int cmd_annotate(int argc, const char **argv) · 534 unmodified lines
535 "Display raw encoding of assembly instructions (default)"),535 "Display raw encoding of assembly instructions (default)"),
536 OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style",536 OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style",
537 "Specify disassembler style (e.g. -M intel for intel syntax)"),537 "Specify disassembler style (e.g. -M intel for intel syntax)"),
538 OPT_STRING(0, "prefix", &annotate.opts.prefix, "prefix",
539 "Add prefix to source file path names in programs (with --prefix-strip)"),
540 OPT_STRING(0, "prefix-strip", &annotate.opts.prefix_strip, "N",
541 "Strip first N entries of source file path name in programs (with --prefix)"),
538 OPT_STRING(0, "objdump", &annotate.opts.objdump_path, "path",542 OPT_STRING(0, "objdump", &annotate.opts.objdump_path, "path",
539 "objdump binary to use for disassembly and annotations"),543 "objdump binary to use for disassembly and annotations"),
540 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,544 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
@@ -574,6 +578,9 @@ int cmd_annotate(int argc, const char **argv) · 33 unmodified lines
574 annotate.sym_hist_filter = argv[0];578 annotate.sym_hist_filter = argv[0];
575 }579 }
576 580
581 if (annotate_check_args(&annotate.opts) < 0)
582 return -EINVAL;
583
577 if (symbol_conf.show_nr_samples && annotate.use_gtk) {584 if (symbol_conf.show_nr_samples && annotate.use_gtk) {
578 pr_err("--show-nr-samples is not available in --gtk mode at this time\n");585 pr_err("--show-nr-samples is not available in --gtk mode at this time\n");
579 return ret;586 return ret;
tools/perf/builtin-c2c.c+8−6
@@ -595,8 +595,8 @@ tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused, · 594 unmodified lines
595{595{
596 struct c2c_hist_entry *c2c_left;596 struct c2c_hist_entry *c2c_left;
597 struct c2c_hist_entry *c2c_right;597 struct c2c_hist_entry *c2c_right;
598 unsigned int tot_hitm_left;598 uint64_t tot_hitm_left;
599 unsigned int tot_hitm_right;599 uint64_t tot_hitm_right;
600 600
601 c2c_left = container_of(left, struct c2c_hist_entry, he);601 c2c_left = container_of(left, struct c2c_hist_entry, he);
602 c2c_right = container_of(right, struct c2c_hist_entry, he);602 c2c_right = container_of(right, struct c2c_hist_entry, he);
@@ -629,7 +629,8 @@ __f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \ · 26 unmodified lines
629 \629 \
630 c2c_left = container_of(left, struct c2c_hist_entry, he); \630 c2c_left = container_of(left, struct c2c_hist_entry, he); \
631 c2c_right = container_of(right, struct c2c_hist_entry, he); \631 c2c_right = container_of(right, struct c2c_hist_entry, he); \
632 return c2c_left->stats.__f - c2c_right->stats.__f; \632 return (uint64_t) c2c_left->stats.__f - \
633 (uint64_t) c2c_right->stats.__f; \
633}634}
634 635
635#define STAT_FN(__f) \636#define STAT_FN(__f) \
@@ -682,7 +683,8 @@ ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused, · 46 unmodified lines
682 c2c_left = container_of(left, struct c2c_hist_entry, he);683 c2c_left = container_of(left, struct c2c_hist_entry, he);
683 c2c_right = container_of(right, struct c2c_hist_entry, he);684 c2c_right = container_of(right, struct c2c_hist_entry, he);
684 685
685 return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats);686 return (uint64_t) llc_miss(&c2c_left->stats) -
687 (uint64_t) llc_miss(&c2c_right->stats);
686}688}
687 689
688static uint64_t total_records(struct c2c_stats *stats)690static uint64_t total_records(struct c2c_stats *stats)
@@ -2384,7 +2386,7 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he) · 1695 unmodified lines
2384 c2c_browser__update_nr_entries(browser);2386 c2c_browser__update_nr_entries(browser);
2385 2387
2386 while (1) {2388 while (1) {
2387 key = hist_browser__run(browser, "? - help", true);2389 key = hist_browser__run(browser, "? - help", true, 0);
2388 2390
2389 switch (key) {2391 switch (key) {
2390 case 's':2392 case 's':
@@ -2453,7 +2455,7 @@ static int perf_c2c__hists_browse(struct hists *hists) · 62 unmodified lines
2453 c2c_browser__update_nr_entries(browser);2455 c2c_browser__update_nr_entries(browser);
2454 2456
2455 while (1) {2457 while (1) {
2456 key = hist_browser__run(browser, "? - help", true);2458 key = hist_browser__run(browser, "? - help", true, 0);
2457 2459
2458 switch (key) {2460 switch (key) {
2459 case 'q':2461 case 'q':
tools/perf/builtin-record.c+22−6
@@ -62,6 +62,7 @@ · 61 unmodified lines
62#include <linux/string.h>62#include <linux/string.h>
63#include <linux/time64.h>63#include <linux/time64.h>
64#include <linux/zalloc.h>64#include <linux/zalloc.h>
65#include <linux/bitmap.h>
65 66
66struct switch_output {67struct switch_output {
67 bool enabled;68 bool enabled;
@@ -93,7 +94,7 @@ struct record { · 25 unmodified lines
93 bool timestamp_boundary;94 bool timestamp_boundary;
94 struct switch_output switch_output;95 struct switch_output switch_output;
95 unsigned long long samples;96 unsigned long long samples;
96 cpu_set_t affinity_mask;97 struct mmap_cpu_mask affinity_mask;
97 unsigned long output_max_size; /* = 0: unlimited */98 unsigned long output_max_size; /* = 0: unlimited */
98};99};
99 100
@@ -961,10 +962,15 @@ static struct perf_event_header finished_round_event = { · 861 unmodified lines
961static void record__adjust_affinity(struct record *rec, struct mmap *map)962static void record__adjust_affinity(struct record *rec, struct mmap *map)
962{963{
963 if (rec->opts.affinity != PERF_AFFINITY_SYS &&964 if (rec->opts.affinity != PERF_AFFINITY_SYS &&
964 !CPU_EQUAL(&rec->affinity_mask, &map->affinity_mask)) {965 !bitmap_equal(rec->affinity_mask.bits, map->affinity_mask.bits,
965 CPU_ZERO(&rec->affinity_mask);966 rec->affinity_mask.nbits)) {
966 CPU_OR(&rec->affinity_mask, &rec->affinity_mask, &map->affinity_mask);967 bitmap_zero(rec->affinity_mask.bits, rec->affinity_mask.nbits);
967 sched_setaffinity(0, sizeof(rec->affinity_mask), &rec->affinity_mask);968 bitmap_or(rec->affinity_mask.bits, rec->affinity_mask.bits,
969 map->affinity_mask.bits, rec->affinity_mask.nbits);
970 sched_setaffinity(0, MMAP_CPU_MASK_BYTES(&rec->affinity_mask),
971 (cpu_set_t *)rec->affinity_mask.bits);
972 if (verbose == 2)
973 mmap_cpu_mask__scnprintf(&rec->affinity_mask, "thread");
968 }974 }
969}975}
970 976
@@ -2433,7 +2439,6 @@ int cmd_record(int argc, const char **argv) · 1462 unmodified lines
2433# undef REASON2439# undef REASON
2434#endif2440#endif
2435 2441
2436 CPU_ZERO(&rec->affinity_mask);
2437 rec->opts.affinity = PERF_AFFINITY_SYS;2442 rec->opts.affinity = PERF_AFFINITY_SYS;
2438 2443
2439 rec->evlist = evlist__new();2444 rec->evlist = evlist__new();
@@ -2499,6 +2504,16 @@ int cmd_record(int argc, const char **argv) · 59 unmodified lines
2499 2504
2500 symbol__init(NULL);2505 symbol__init(NULL);
2501 2506
2507 if (rec->opts.affinity != PERF_AFFINITY_SYS) {
2508 rec->affinity_mask.nbits = cpu__max_cpu();
2509 rec->affinity_mask.bits = bitmap_alloc(rec->affinity_mask.nbits);
2510 if (!rec->affinity_mask.bits) {
2511 pr_err("Failed to allocate thread mask for %zd cpus\n", rec->affinity_mask.nbits);
2512 return -ENOMEM;
2513 }
2514 pr_debug2("thread mask[%zd]: empty\n", rec->affinity_mask.nbits);
2515 }
2516
2502 err = record__auxtrace_init(rec);2517 err = record__auxtrace_init(rec);
2503 if (err)2518 if (err)
2504 goto out;2519 goto out;
@@ -2613,6 +2628,7 @@ int cmd_record(int argc, const char **argv) · 108 unmodified lines
2613 2628
2614 err = __cmd_record(&record, argc, argv);2629 err = __cmd_record(&record, argc, argv);
2615out:2630out:
2631 bitmap_free(rec->affinity_mask.bits);
2616 evlist__delete(rec->evlist);2632 evlist__delete(rec->evlist);
2617 symbol__exit();2633 symbol__exit();
2618 auxtrace_record__free(rec->itr);2634 auxtrace_record__free(rec->itr);
tools/perf/builtin-report.c+12−4
@@ -412,10 +412,10 @@ static int report__setup_sample_type(struct report *rep) · 411 unmodified lines
412 PERF_SAMPLE_BRANCH_ANY))412 PERF_SAMPLE_BRANCH_ANY))
413 rep->nonany_branch_mode = true;413 rep->nonany_branch_mode = true;
414 414
415#ifndef HAVE_LIBUNWIND_SUPPORT415#if !defined(HAVE_LIBUNWIND_SUPPORT) && !defined(HAVE_DWARF_SUPPORT)
416 if (dwarf_callchain_users) {416 if (dwarf_callchain_users) {
417 ui__warning("Please install libunwind development packages "417 ui__warning("Please install libunwind or libdw "
418 "during the perf build.\n");418 "development packages during the perf build.\n");
419 }419 }
420#endif420#endif
421 421
@@ -1164,7 +1164,8 @@ int cmd_report(int argc, const char **argv) · 742 unmodified lines
1164 report_callchain_help, &report_parse_callchain_opt,1164 report_callchain_help, &report_parse_callchain_opt,
1165 callchain_default_opt),1165 callchain_default_opt),
1166 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,1166 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
1167 "Accumulate callchains of children and show total overhead as well"),1167 "Accumulate callchains of children and show total overhead as well. "
1168 "Enabled by default, use --no-children to disable."),
1168 OPT_INTEGER(0, "max-stack", &report.max_stack,1169 OPT_INTEGER(0, "max-stack", &report.max_stack,
1169 "Set the maximum stack depth when parsing the callchain, "1170 "Set the maximum stack depth when parsing the callchain, "
1170 "anything beyond the specified depth will be ignored. "1171 "anything beyond the specified depth will be ignored. "
@@ -1207,6 +1208,10 @@ int cmd_report(int argc, const char **argv) · 36 unmodified lines
1207 "Display raw encoding of assembly instructions (default)"),1208 "Display raw encoding of assembly instructions (default)"),
1208 OPT_STRING('M', "disassembler-style", &report.annotation_opts.disassembler_style, "disassembler style",1209 OPT_STRING('M', "disassembler-style", &report.annotation_opts.disassembler_style, "disassembler style",
1209 "Specify disassembler style (e.g. -M intel for intel syntax)"),1210 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1211 OPT_STRING(0, "prefix", &report.annotation_opts.prefix, "prefix",
1212 "Add prefix to source file path names in programs (with --prefix-strip)"),
1213 OPT_STRING(0, "prefix-strip", &report.annotation_opts.prefix_strip, "N",
1214 "Strip first N entries of source file path name in programs (with --prefix)"),
1210 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,1215 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1211 "Show a column with the sum of periods"),1216 "Show a column with the sum of periods"),
1212 OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group, &report.group_set,1217 OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group, &report.group_set,
@@ -1286,6 +1291,9 @@ int cmd_report(int argc, const char **argv) · 73 unmodified lines
1286 report.symbol_filter_str = argv[0];1291 report.symbol_filter_str = argv[0];
1287 }1292 }
1288 1293
1294 if (annotate_check_args(&report.annotation_opts) < 0)
1295 return -EINVAL;
1296
1289 if (report.mmaps_mode)1297 if (report.mmaps_mode)
1290 report.tasks_mode = true;1298 report.tasks_mode = true;
1291 1299
tools/perf/builtin-sched.c+13−0
@@ -51,6 +51,9 @@ · 50 unmodified lines
51#define SYM_LEN 12951#define SYM_LEN 129
52#define MAX_PID 102400052#define MAX_PID 1024000
53 53
54static const char *cpu_list;
55static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
56
54struct sched_atom;57struct sched_atom;
55 58
56struct task_desc {59struct task_desc {
@@ -2008,6 +2011,9 @@ static void timehist_print_sample(struct perf_sched *sched, · 1951 unmodified lines
2008 char nstr[30];2011 char nstr[30];
2009 u64 wait_time;2012 u64 wait_time;
2010 2013
2014 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
2015 return;
2016
2011 timestamp__scnprintf_usec(t, tstr, sizeof(tstr));2017 timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
2012 printf("%15s [%04d] ", tstr, sample->cpu);2018 printf("%15s [%04d] ", tstr, sample->cpu);
2013 2019
@@ -2994,6 +3000,12 @@ static int perf_sched__timehist(struct perf_sched *sched) · 980 unmodified lines
2994 if (IS_ERR(session))3000 if (IS_ERR(session))
2995 return PTR_ERR(session);3001 return PTR_ERR(session);
2996 3002
3003 if (cpu_list) {
3004 err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
3005 if (err < 0)
3006 goto out;
3007 }
3008
2997 evlist = session->evlist;3009 evlist = session->evlist;
2998 3010
2999 symbol__init(&session->header.env);3011 symbol__init(&session->header.env);
@@ -3429,6 +3441,7 @@ int cmd_sched(int argc, const char **argv) · 429 unmodified lines
3429 "analyze events only for given process id(s)"),3441 "analyze events only for given process id(s)"),
3430 OPT_STRING('t', "tid", &symbol_conf.tid_list_str, "tid[,tid...]",3442 OPT_STRING('t', "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
3431 "analyze events only for given thread id(s)"),3443 "analyze events only for given thread id(s)"),
3444 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
3432 OPT_PARENT(sched_options)3445 OPT_PARENT(sched_options)
3433 };3446 };
3434 3447
tools/perf/builtin-top.c+7−0
@@ -1512,6 +1512,10 @@ int cmd_top(int argc, const char **argv) · 1511 unmodified lines
1512 "objdump binary to use for disassembly and annotations"),1512 "objdump binary to use for disassembly and annotations"),
1513 OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style",1513 OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style",
1514 "Specify disassembler style (e.g. -M intel for intel syntax)"),1514 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1515 OPT_STRING(0, "prefix", &top.annotation_opts.prefix, "prefix",
1516 "Add prefix to source file path names in programs (with --prefix-strip)"),
1517 OPT_STRING(0, "prefix-strip", &top.annotation_opts.prefix_strip, "N",
1518 "Strip first N entries of source file path name in programs (with --prefix)"),
1515 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),1519 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
1516 OPT_CALLBACK(0, "percent-limit", &top, "percent",1520 OPT_CALLBACK(0, "percent-limit", &top, "percent",
1517 "Don't show entries under that percent", parse_percent_limit),1521 "Don't show entries under that percent", parse_percent_limit),
@@ -1582,6 +1586,9 @@ int cmd_top(int argc, const char **argv) · 64 unmodified lines
1582 if (argc)1586 if (argc)
1583 usage_with_options(top_usage, options);1587 usage_with_options(top_usage, options);
1584 1588
1589 if (annotate_check_args(&top.annotation_opts) < 0)
1590 goto out_delete_evlist;
1591
1585 if (!top.evlist->core.nr_entries &&1592 if (!top.evlist->core.nr_entries &&
1586 perf_evlist__add_default(top.evlist) < 0) {1593 perf_evlist__add_default(top.evlist) < 0) {
1587 pr_err("Not enough memory for event selector list\n");1594 pr_err("Not enough memory for event selector list\n");
tools/perf/lib/Documentation/Makefile+0−7
@@ -1,7 +0,0 @@
1all:
2 rst2man man/libperf.rst > man/libperf.7
3 rst2pdf tutorial/tutorial.rst
4
5clean:
6 rm -f man/libperf.7
7 rm -f tutorial/tutorial.pdf
tools/perf/lib/Documentation/man/libperf.rst+0−100
@@ -1,100 +0,0 @@
1.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2
3libperf
4
5The libperf library provides an API to access the linux kernel perf
6events subsystem. It provides the following high level objects:
7
8 - struct perf_cpu_map
9 - struct perf_thread_map
10 - struct perf_evlist
11 - struct perf_evsel
12
13reference
14=========
15Function reference by header files:
16
17perf/core.h
18-----------
19.. code-block:: c
20
21 typedef int (\*libperf_print_fn_t)(enum libperf_print_level level,
22 const char \*, va_list ap);
23
24 void libperf_set_print(libperf_print_fn_t fn);
25
26perf/cpumap.h
27-------------
28.. code-block:: c
29
30 struct perf_cpu_map \*perf_cpu_map__dummy_new(void);
31 struct perf_cpu_map \*perf_cpu_map__new(const char \*cpu_list);
32 struct perf_cpu_map \*perf_cpu_map__read(FILE \*file);
33 struct perf_cpu_map \*perf_cpu_map__get(struct perf_cpu_map \*map);
34 void perf_cpu_map__put(struct perf_cpu_map \*map);
35 int perf_cpu_map__cpu(const struct perf_cpu_map \*cpus, int idx);
36 int perf_cpu_map__nr(const struct perf_cpu_map \*cpus);
37 perf_cpu_map__for_each_cpu(cpu, idx, cpus)
38
39perf/threadmap.h
40----------------
41.. code-block:: c
42
43 struct perf_thread_map \*perf_thread_map__new_dummy(void);
44 void perf_thread_map__set_pid(struct perf_thread_map \*map, int thread, pid_t pid);
45 char \*perf_thread_map__comm(struct perf_thread_map \*map, int thread);
46 struct perf_thread_map \*perf_thread_map__get(struct perf_thread_map \*map);
47 void perf_thread_map__put(struct perf_thread_map \*map);
48
49perf/evlist.h
50-------------
51.. code-block::
52
53 void perf_evlist__init(struct perf_evlist \*evlist);
54 void perf_evlist__add(struct perf_evlist \*evlist,
55 struct perf_evsel \*evsel);
56 void perf_evlist__remove(struct perf_evlist \*evlist,
57 struct perf_evsel \*evsel);
58 struct perf_evlist \*perf_evlist__new(void);
59 void perf_evlist__delete(struct perf_evlist \*evlist);
60 struct perf_evsel\* perf_evlist__next(struct perf_evlist \*evlist,
61 struct perf_evsel \*evsel);
62 int perf_evlist__open(struct perf_evlist \*evlist);
63 void perf_evlist__close(struct perf_evlist \*evlist);
64 void perf_evlist__enable(struct perf_evlist \*evlist);
65 void perf_evlist__disable(struct perf_evlist \*evlist);
66 perf_evlist__for_each_evsel(evlist, pos)
67 void perf_evlist__set_maps(struct perf_evlist \*evlist,
68 struct perf_cpu_map \*cpus,
69 struct perf_thread_map \*threads);
70
71perf/evsel.h
72------------
73.. code-block:: c
74
75 struct perf_counts_values {
76 union {
77 struct {
78 uint64_t val;
79 uint64_t ena;
80 uint64_t run;
81 };
82 uint64_t values[3];
83 };
84 };
85
86 void perf_evsel__init(struct perf_evsel \*evsel,
87 struct perf_event_attr \*attr);
88 struct perf_evsel \*perf_evsel__new(struct perf_event_attr \*attr);
89 void perf_evsel__delete(struct perf_evsel \*evsel);
90 int perf_evsel__open(struct perf_evsel \*evsel, struct perf_cpu_map \*cpus,
91 struct perf_thread_map \*threads);
92 void perf_evsel__close(struct perf_evsel \*evsel);
93 int perf_evsel__read(struct perf_evsel \*evsel, int cpu, int thread,
94 struct perf_counts_values \*count);
95 int perf_evsel__enable(struct perf_evsel \*evsel);
96 int perf_evsel__disable(struct perf_evsel \*evsel);
97 int perf_evsel__apply_filter(struct perf_evsel \*evsel, const char \*filter);
98 struct perf_cpu_map \*perf_evsel__cpus(struct perf_evsel \*evsel);
99 struct perf_thread_map \*perf_evsel__threads(struct perf_evsel \*evsel);
100 struct perf_event_attr \*perf_evsel__attr(struct perf_evsel \*evsel);
tools/perf/lib/Documentation/tutorial/tutorial.rst+0−123
@@ -1,123 +0,0 @@
1.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2
3libperf tutorial
4================
5
6Compile and install libperf from kernel sources
7===============================================
8.. code-block:: bash
9
10 git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
11 cd linux/tools/perf/lib
12 make
13 sudo make install prefix=/usr
14
15Libperf object
16==============
17The libperf library provides several high level objects:
18
19struct perf_cpu_map
20 Provides a cpu list abstraction.
21
22struct perf_thread_map
23 Provides a thread list abstraction.
24
25struct perf_evsel
26 Provides an abstraction for single a perf event.
27
28struct perf_evlist
29 Gathers several struct perf_evsel object and performs functions on all of them.
30
31The exported API binds these objects together,
32for full reference see the libperf.7 man page.
33
34Examples
35========
36Examples aim to explain libperf functionality on simple use cases.
37They are based in on a checked out linux kernel git tree:
38
39.. code-block:: bash
40
41 $ cd tools/perf/lib/Documentation/tutorial/
42 $ ls -d ex-*
43 ex-1-compile ex-2-evsel-stat ex-3-evlist-stat
44
45ex-1-compile example
46====================
47This example shows the basic usage of *struct perf_cpu_map*,
48how to create it and display its cpus:
49
50.. code-block:: bash
51
52 $ cd ex-1-compile/
53 $ make
54 gcc -o test test.c -lperf
55 $ ./test
56 0 1 2 3 4 5 6 7
57
58
59The full code listing is here:
60
61.. code-block:: c
62
63 1 #include <perf/cpumap.h>
64 2
65 3 int main(int argc, char **Argv)
66 4 {
67 5 struct perf_cpu_map *cpus;
68 6 int cpu, tmp;
69 7
70 8 cpus = perf_cpu_map__new(NULL);
71 9
72 10 perf_cpu_map__for_each_cpu(cpu, tmp, cpus)
73 11 fprintf(stdout, "%d ", cpu);
74 12
75 13 fprintf(stdout, "\n");
76 14
77 15 perf_cpu_map__put(cpus);
78 16 return 0;
79 17 }
80
81
82First you need to include the proper header to have *struct perf_cpumap*
83declaration and functions:
84
85.. code-block:: c
86
87 1 #include <perf/cpumap.h>
88
89
90The *struct perf_cpumap* object is created by *perf_cpu_map__new* call.
91The *NULL* argument asks it to populate the object with the current online CPUs list:
92
93.. code-block:: c
94
95 8 cpus = perf_cpu_map__new(NULL);
96
97This is paired with a *perf_cpu_map__put*, that drops its reference at the end, possibly deleting it.
98
99.. code-block:: c
100
101 15 perf_cpu_map__put(cpus);
102
103The iteration through the *struct perf_cpumap* CPUs is done using the *perf_cpu_map__for_each_cpu*
104macro which requires 3 arguments:
105
106- cpu - the cpu numer
107- tmp - iteration helper variable
108- cpus - the *struct perf_cpumap* object
109
110.. code-block:: c
111
112 10 perf_cpu_map__for_each_cpu(cpu, tmp, cpus)
113 11 fprintf(stdout, "%d ", cpu);
114
115ex-2-evsel-stat example
116=======================
117
118TBD
119
120ex-3-evlist-stat example
121========================
122
123TBD
tools/perf/tests/bp_signal.c+5−5
@@ -263,20 +263,20 @@ int test__bp_signal(struct test *test __maybe_unused, int subtest __maybe_unused · 262 unmodified lines
263 if (count1 == 11)263 if (count1 == 11)
264 pr_debug("failed: RF EFLAG recursion issue detected\n");264 pr_debug("failed: RF EFLAG recursion issue detected\n");
265 else265 else
266 pr_debug("failed: wrong count for bp1%lld\n", count1);266 pr_debug("failed: wrong count for bp1: %lld, expected 1\n", count1);
267 }267 }
268 268
269 if (overflows != 3)269 if (overflows != 3)
270 pr_debug("failed: wrong overflow hit\n");270 pr_debug("failed: wrong overflow (%d) hit, expected 3\n", overflows);
271 271
272 if (overflows_2 != 3)272 if (overflows_2 != 3)
273 pr_debug("failed: wrong overflow_2 hit\n");273 pr_debug("failed: wrong overflow_2 (%d) hit, expected 3\n", overflows_2);
274 274
275 if (count2 != 3)275 if (count2 != 3)
276 pr_debug("failed: wrong count for bp2\n");276 pr_debug("failed: wrong count for bp2 (%lld), expected 3\n", count2);
277 277
278 if (count3 != 2)278 if (count3 != 2)
279 pr_debug("failed: wrong count for bp3\n");279 pr_debug("failed: wrong count for bp3 (%lld), expected 2\n", count3);
280 280
281 return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?281 return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
282 TEST_OK : TEST_FAIL;282 TEST_OK : TEST_FAIL;
tools/perf/trace/beauty/sockaddr.c+1−1
@@ -72,5 +72,5 @@ size_t syscall_arg__scnprintf_sockaddr(char *bf, size_t size, struct syscall_arg · 71 unmodified lines
72 if (arg->augmented.args)72 if (arg->augmented.args)
73 return syscall_arg__scnprintf_augmented_sockaddr(arg, bf, size);73 return syscall_arg__scnprintf_augmented_sockaddr(arg, bf, size);
74 74
75 return scnprintf(bf, size, "%#x", arg->val);75 return scnprintf(bf, size, "%#lx", arg->val);
76}76}
tools/perf/ui/browsers/hists.c+191−86
@@ -18,7 +18,9 @@ · 17 unmodified lines
18#include "../../util/evlist.h"18#include "../../util/evlist.h"
19#include "../../util/header.h"19#include "../../util/header.h"
20#include "../../util/hist.h"20#include "../../util/hist.h"
21#include "../../util/machine.h"
21#include "../../util/map.h"22#include "../../util/map.h"
23#include "../../util/maps.h"
22#include "../../util/symbol.h"24#include "../../util/symbol.h"
23#include "../../util/map_symbol.h"25#include "../../util/map_symbol.h"
24#include "../../util/branch.h"26#include "../../util/branch.h"
@@ -391,6 +393,57 @@ static void hist_entry__init_have_children(struct hist_entry *he) · 366 unmodified lines
391 he->init_have_children = true;393 he->init_have_children = true;
392}394}
393 395
396static bool hist_browser__selection_has_children(struct hist_browser *browser)
397{
398 struct hist_entry *he = browser->he_selection;
399 struct map_symbol *ms = browser->selection;
400
401 if (!he || !ms)
402 return false;
403
404 if (ms == &he->ms)
405 return he->has_children;
406
407 return container_of(ms, struct callchain_list, ms)->has_children;
408}
409
410static bool hist_browser__he_selection_unfolded(struct hist_browser *browser)
411{
412 return browser->he_selection ? browser->he_selection->unfolded : false;
413}
414
415static bool hist_browser__selection_unfolded(struct hist_browser *browser)
416{
417 struct hist_entry *he = browser->he_selection;
418 struct map_symbol *ms = browser->selection;
419
420 if (!he || !ms)
421 return false;
422
423 if (ms == &he->ms)
424 return he->unfolded;
425
426 return container_of(ms, struct callchain_list, ms)->unfolded;
427}
428
429static char *hist_browser__selection_sym_name(struct hist_browser *browser, char *bf, size_t size)
430{
431 struct hist_entry *he = browser->he_selection;
432 struct map_symbol *ms = browser->selection;
433 struct callchain_list *callchain_entry;
434
435 if (!he || !ms)
436 return NULL;
437
438 if (ms == &he->ms) {
439 hist_entry__sym_snprintf(he, bf, size, 0);
440 return bf + 4; // skip the level, e.g. '[k] '
441 }
442
443 callchain_entry = container_of(ms, struct callchain_list, ms);
444 return callchain_list__sym_name(callchain_entry, bf, size, browser->show_dso);
445}
446
394static bool hist_browser__toggle_fold(struct hist_browser *browser)447static bool hist_browser__toggle_fold(struct hist_browser *browser)
395{448{
396 struct hist_entry *he = browser->he_selection;449 struct hist_entry *he = browser->he_selection;
@@ -624,10 +677,81 @@ static int hist_browser__title(struct hist_browser *browser, char *bf, size_t si · 227 unmodified lines
624 return browser->title ? browser->title(browser, bf, size) : 0;677 return browser->title ? browser->title(browser, bf, size) : 0;
625}678}
626 679
680static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_lost_event, char *title, int key)
681{
682 switch (key) {
683 case K_TIMER: {
684 struct hist_browser_timer *hbt = browser->hbt;
685 u64 nr_entries;
686
687 WARN_ON_ONCE(!hbt);
688
689 if (hbt)
690 hbt->timer(hbt->arg);
691
692 if (hist_browser__has_filter(browser) || symbol_conf.report_hierarchy)
693 hist_browser__update_nr_entries(browser);
694
695 nr_entries = hist_browser__nr_entries(browser);
696 ui_browser__update_nr_entries(&browser->b, nr_entries);
697
698 if (warn_lost_event &&
699 (browser->hists->stats.nr_lost_warned !=
700 browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
701 browser->hists->stats.nr_lost_warned =
702 browser->hists->stats.nr_events[PERF_RECORD_LOST];
703 ui_browser__warn_lost_events(&browser->b);
704 }
705
706 hist_browser__title(browser, title, sizeof(title));
707 ui_browser__show_title(&browser->b, title);
708 break;
709 }
710 case 'D': { /* Debug */
711 struct hist_entry *h = rb_entry(browser->b.top, struct hist_entry, rb_node);
712 static int seq;
713
714 ui_helpline__pop();
715 ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
716 seq++, browser->b.nr_entries, browser->hists->nr_entries,
717 browser->b.extra_title_lines, browser->b.rows,
718 browser->b.index, browser->b.top_idx, h->row_offset, h->nr_rows);
719 }
720 break;
721 case 'C':
722 /* Collapse the whole world. */
723 hist_browser__set_folding(browser, false);
724 break;
725 case 'c':
726 /* Collapse the selected entry. */
727 hist_browser__set_folding_selected(browser, false);
728 break;
729 case 'E':
730 /* Expand the whole world. */
731 hist_browser__set_folding(browser, true);
732 break;
733 case 'e':
734 /* Expand the selected entry. */
735 hist_browser__set_folding_selected(browser, !hist_browser__he_selection_unfolded(browser));
736 break;
737 case 'H':
738 browser->show_headers = !browser->show_headers;
739 hist_browser__update_rows(browser);
740 break;
741 case '+':
742 if (hist_browser__toggle_fold(browser))
743 break;
744 /* fall thru */
745 default:
746 return -1;
747 }
748
749 return 0;
750}
751
627int hist_browser__run(struct hist_browser *browser, const char *help,752int hist_browser__run(struct hist_browser *browser, const char *help,
628 bool warn_lost_event)753 bool warn_lost_event, int key)
629{754{
630 int key;
631 char title[160];755 char title[160];
632 struct hist_browser_timer *hbt = browser->hbt;756 struct hist_browser_timer *hbt = browser->hbt;
633 int delay_secs = hbt ? hbt->refresh : 0;757 int delay_secs = hbt ? hbt->refresh : 0;
@@ -640,79 +764,14 @@ int hist_browser__run(struct hist_browser *browser, const char *help, · 6 unmodified lines
640 if (ui_browser__show(&browser->b, title, "%s", help) < 0)764 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
641 return -1;765 return -1;
642 766
767 if (key && hist_browser__handle_hotkey(browser, warn_lost_event, title, key))
768 goto out;
769
643 while (1) {770 while (1) {
644 key = ui_browser__run(&browser->b, delay_secs);771 key = ui_browser__run(&browser->b, delay_secs);
645 772
646 switch (key) {773 if (hist_browser__handle_hotkey(browser, warn_lost_event, title, key))
647 case K_TIMER: {
648 u64 nr_entries;
649
650 WARN_ON_ONCE(!hbt);
651
652 if (hbt)
653 hbt->timer(hbt->arg);
654
655 if (hist_browser__has_filter(browser) ||
656 symbol_conf.report_hierarchy)
657 hist_browser__update_nr_entries(browser);
658
659 nr_entries = hist_browser__nr_entries(browser);
660 ui_browser__update_nr_entries(&browser->b, nr_entries);
661
662 if (warn_lost_event &&
663 (browser->hists->stats.nr_lost_warned !=
664 browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
665 browser->hists->stats.nr_lost_warned =
666 browser->hists->stats.nr_events[PERF_RECORD_LOST];
667 ui_browser__warn_lost_events(&browser->b);
668 }
669
670 hist_browser__title(browser, title, sizeof(title));
671 ui_browser__show_title(&browser->b, title);
672 continue;
673 }
674 case 'D': { /* Debug */
675 static int seq;
676 struct hist_entry *h = rb_entry(browser->b.top,
677 struct hist_entry, rb_node);
678 ui_helpline__pop();
679 ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
680 seq++, browser->b.nr_entries,
681 browser->hists->nr_entries,
682 browser->b.extra_title_lines,
683 browser->b.rows,
684 browser->b.index,
685 browser->b.top_idx,
686 h->row_offset, h->nr_rows);
687 }
688 break;
689 case 'C':
690 /* Collapse the whole world. */
691 hist_browser__set_folding(browser, false);
692 break;
693 case 'c':
694 /* Collapse the selected entry. */
695 hist_browser__set_folding_selected(browser, false);
696 break;774 break;
697 case 'E':
698 /* Expand the whole world. */
699 hist_browser__set_folding(browser, true);
700 break;
701 case 'e':
702 /* Expand the selected entry. */
703 hist_browser__set_folding_selected(browser, true);
704 break;
705 case 'H':
706 browser->show_headers = !browser->show_headers;
707 hist_browser__update_rows(browser);
708 break;
709 case K_ENTER:
710 if (hist_browser__toggle_fold(browser))
711 break;
712 /* fall thru */
713 default:
714 goto out;
715 }
716 }775 }
717out:776out:
718 ui_browser__hide(&browser->b);777 ui_browser__hide(&browser->b);
@@ -2339,7 +2398,7 @@ close_file_and_continue: · 1620 unmodified lines
2339 closedir(pwd_dir);2398 closedir(pwd_dir);
2340 2399
2341 if (nr_options) {2400 if (nr_options) {
2342 choice = ui__popup_menu(nr_options, options);2401 choice = ui__popup_menu(nr_options, options, NULL);
2343 if (choice < nr_options && choice >= 0) {2402 if (choice < nr_options && choice >= 0) {
2344 tmp = strdup(abs_path[choice]);2403 tmp = strdup(abs_path[choice]);
2345 if (tmp) {2404 if (tmp) {
@@ -2411,7 +2470,8 @@ add_annotate_opt(struct hist_browser *browser __maybe_unused, · 65 unmodified lines
2411 struct popup_action *act, char **optstr,2470 struct popup_action *act, char **optstr,
2412 struct map_symbol *ms)2471 struct map_symbol *ms)
2413{2472{
2414 if (ms->sym == NULL || ms->map->dso->annotate_warned)2473 if (ms->sym == NULL || ms->map->dso->annotate_warned ||
2474 symbol__annotation(ms->sym)->src == NULL)
2415 return 0;2475 return 0;
2416 2476
2417 if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0)2477 if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0)
@@ -2484,11 +2544,8 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act, · 66 unmodified lines
2484 return 1;2544 return 1;
2485}2545}
2486 2546
2487static int2547static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map)
2488do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2489{2548{
2490 struct map *map = act->ms.map;
2491
2492 if (!hists__has(browser->hists, dso) || map == NULL)2549 if (!hists__has(browser->hists, dso) || map == NULL)
2493 return 0;2550 return 0;
2494 2551
@@ -2510,6 +2567,12 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) · 15 unmodified lines
2510 return 0;2567 return 0;
2511}2568}
2512 2569
2570static int
2571do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2572{
2573 return hists_browser__zoom_map(browser, act->ms.map);
2574}
2575
2513static int2576static int
2514add_dso_opt(struct hist_browser *browser, struct popup_action *act,2577add_dso_opt(struct hist_browser *browser, struct popup_action *act,
2515 char **optstr, struct map *map)2578 char **optstr, struct map *map)
@@ -2517,7 +2580,7 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act, · 1 unmodified line
2517 if (!hists__has(browser->hists, dso) || map == NULL)2580 if (!hists__has(browser->hists, dso) || map == NULL)
2518 return 0;2581 return 0;
2519 2582
2520 if (asprintf(optstr, "Zoom %s %s DSO",2583 if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)",
2521 browser->hists->dso_filter ? "out of" : "into",2584 browser->hists->dso_filter ? "out of" : "into",
2522 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)2585 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
2523 return 0;2586 return 0;
@@ -2527,6 +2590,28 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act, · 3 unmodified lines
2527 return 1;2590 return 1;
2528}2591}
2529 2592
2593static int do_toggle_callchain(struct hist_browser *browser, struct popup_action *act __maybe_unused)
2594{
2595 hist_browser__toggle_fold(browser);
2596 return 0;
2597}
2598
2599static int add_callchain_toggle_opt(struct hist_browser *browser, struct popup_action *act, char **optstr)
2600{
2601 char sym_name[512];
2602
2603 if (!hist_browser__selection_has_children(browser))
2604 return 0;
2605
2606 if (asprintf(optstr, "%s [%s] callchain (one level, same as '+' hotkey, use 'e'/'c' for the whole main level entry)",
2607 hist_browser__selection_unfolded(browser) ? "Collapse" : "Expand",
2608 hist_browser__selection_sym_name(browser, sym_name, sizeof(sym_name))) < 0)
2609 return 0;
2610
2611 act->fn = do_toggle_callchain;
2612 return 1;
2613}
2614
2530static int2615static int
2531do_browse_map(struct hist_browser *browser __maybe_unused,2616do_browse_map(struct hist_browser *browser __maybe_unused,
2532 struct popup_action *act)2617 struct popup_action *act)
@@ -2858,12 +2943,15 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, · 325 unmodified lines
2858 "For symbolic views (--sort has sym):\n\n" \2943 "For symbolic views (--sort has sym):\n\n" \
2859 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \2944 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
2860 "ESC Zoom out\n" \2945 "ESC Zoom out\n" \
2946 "+ Expand/Collapse one callchain level\n" \
2861 "a Annotate current symbol\n" \2947 "a Annotate current symbol\n" \
2862 "C Collapse all callchains\n" \2948 "C Collapse all callchains\n" \
2863 "d Zoom into current DSO\n" \2949 "d Zoom into current DSO\n" \
2950 "e Expand/Collapse main entry callchains\n" \
2864 "E Expand all callchains\n" \2951 "E Expand all callchains\n" \
2865 "F Toggle percentage of filtered entries\n" \2952 "F Toggle percentage of filtered entries\n" \
2866 "H Display column headers\n" \2953 "H Display column headers\n" \
2954 "k Zoom into the kernel map\n" \
2867 "L Change percent limit\n" \2955 "L Change percent limit\n" \
2868 "m Display context menu\n" \2956 "m Display context menu\n" \
2869 "S Zoom into current Processor Socket\n" \2957 "S Zoom into current Processor Socket\n" \
@@ -2914,13 +3002,13 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, · 44 unmodified lines
2914 while (1) {3002 while (1) {
2915 struct thread *thread = NULL;3003 struct thread *thread = NULL;
2916 struct map *map = NULL;3004 struct map *map = NULL;
2917 int choice = 0;3005 int choice;
2918 int socked_id = -1;3006 int socked_id = -1;
2919 3007
2920 nr_options = 0;3008 key = 0; // reset key
2921 3009do_hotkey: // key came straight from options ui__popup_menu()
2922 key = hist_browser__run(browser, helpline,3010 choice = nr_options = 0;
2923 warn_lost_event);3011 key = hist_browser__run(browser, helpline, warn_lost_event, key);
2924 3012
2925 if (browser->he_selection != NULL) {3013 if (browser->he_selection != NULL) {
2926 thread = hist_browser__selected_thread(browser);3014 thread = hist_browser__selected_thread(browser);
@@ -2950,6 +3038,14 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, · 23 unmodified lines
2950 browser->selection->map->dso->annotate_warned)3038 browser->selection->map->dso->annotate_warned)
2951 continue;3039 continue;
2952 3040
3041 if (symbol__annotation(browser->selection->sym)->src == NULL) {
3042 ui_browser__warning(&browser->b, delay_secs * 2,
3043 "No samples for the \"%s\" symbol.\n\n"
3044 "Probably appeared just in a callchain",
3045 browser->selection->sym->name);
3046 continue;
3047 }
3048
2953 actions->ms.map = browser->selection->map;3049 actions->ms.map = browser->selection->map;
2954 actions->ms.sym = browser->selection->sym;3050 actions->ms.sym = browser->selection->sym;
2955 do_annotate(browser, actions);3051 do_annotate(browser, actions);
@@ -2961,6 +3057,10 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, · 5 unmodified lines
2961 actions->ms.map = map;3057 actions->ms.map = map;
2962 do_zoom_dso(browser, actions);3058 do_zoom_dso(browser, actions);
2963 continue;3059 continue;
3060 case 'k':
3061 if (browser->selection != NULL)
3062 hists_browser__zoom_map(browser, browser->selection->maps->machine->vmlinux_map);
3063 continue;
2964 case 'V':3064 case 'V':
2965 verbose = (verbose + 1) % 4;3065 verbose = (verbose + 1) % 4;
2966 browser->show_dso = verbose > 0;3066 browser->show_dso = verbose > 0;
@@ -3062,6 +3162,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, · 95 unmodified lines
3062 3162
3063 continue;3163 continue;
3064 }3164 }
3165 actions->ms.map = map;
3065 top = pstack__peek(browser->pstack);3166 top = pstack__peek(browser->pstack);
3066 if (top == &browser->hists->dso_filter) {3167 if (top == &browser->hists->dso_filter) {
3067 /*3168 /*
@@ -3135,6 +3236,7 @@ skip_annotation: · 67 unmodified lines
3135 &options[nr_options], thread);3236 &options[nr_options], thread);
3136 nr_options += add_dso_opt(browser, &actions[nr_options],3237 nr_options += add_dso_opt(browser, &actions[nr_options],
3137 &options[nr_options], map);3238 &options[nr_options], map);
3239 nr_options += add_callchain_toggle_opt(browser, &actions[nr_options], &options[nr_options]);
3138 nr_options += add_map_opt(browser, &actions[nr_options],3240 nr_options += add_map_opt(browser, &actions[nr_options],
3139 &options[nr_options],3241 &options[nr_options],
3140 browser->selection ?3242 browser->selection ?
@@ -3193,10 +3295,13 @@ skip_scripting: · 52 unmodified lines
3193 do {3295 do {
3194 struct popup_action *act;3296 struct popup_action *act;
3195 3297
3196 choice = ui__popup_menu(nr_options, options);3298 choice = ui__popup_menu(nr_options, options, &key);
3197 if (choice == -1 || choice >= nr_options)3299 if (choice == -1)
3198 break;3300 break;
3199 3301
3302 if (choice == nr_options)
3303 goto do_hotkey;
3304
3200 act = &actions[choice];3305 act = &actions[choice];
3201 key = act->fn(browser, act);3306 key = act->fn(browser, act);
3202 } while (key == 1);3307 } while (key == 1);
@@ -3492,7 +3597,7 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel, · 289 unmodified lines
3492 memset(&action, 0, sizeof(action));3597 memset(&action, 0, sizeof(action));
3493 3598
3494 while (1) {3599 while (1) {
3495 key = hist_browser__run(browser, "? - help", true);3600 key = hist_browser__run(browser, "? - help", true, 0);
3496 3601
3497 switch (key) {3602 switch (key) {
3498 case 'q':3603 case 'q':
tools/perf/ui/browsers/hists.h+1−1
@@ -34,7 +34,7 @@ struct hist_browser { · 33 unmodified lines
34struct hist_browser *hist_browser__new(struct hists *hists);34struct hist_browser *hist_browser__new(struct hists *hists);
35void hist_browser__delete(struct hist_browser *browser);35void hist_browser__delete(struct hist_browser *browser);
36int hist_browser__run(struct hist_browser *browser, const char *help,36int hist_browser__run(struct hist_browser *browser, const char *help,
37 bool warn_lost_event);37 bool warn_lost_event, int key);
38void hist_browser__init(struct hist_browser *browser,38void hist_browser__init(struct hist_browser *browser,
39 struct hists *hists);39 struct hists *hists);
40#endif /* _PERF_UI_BROWSER_HISTS_H_ */40#endif /* _PERF_UI_BROWSER_HISTS_H_ */
tools/perf/ui/browsers/res_sample.c+1−1
@@ -56,7 +56,7 @@ int res_sample_browse(struct res_sample *res_samples, int num_res, · 55 unmodified lines
56 return -1;56 return -1;
57 }57 }
58 }58 }
59 choice = ui__popup_menu(num_res, names);59 choice = ui__popup_menu(num_res, names, NULL);
60 for (i = 0; i < num_res; i++)60 for (i = 0; i < num_res; i++)
61 zfree(&names[i]);61 zfree(&names[i]);
62 free(names);62 free(names);
tools/perf/ui/browsers/scripts.c+1−1
@@ -126,7 +126,7 @@ static int list_scripts(char *script_name, bool *custom, · 125 unmodified lines
126 SCRIPT_FULLPATH_LEN);126 SCRIPT_FULLPATH_LEN);
127 if (num < 0)127 if (num < 0)
128 num = 0;128 num = 0;
129 choice = ui__popup_menu(num + max_std, (char * const *)names);129 choice = ui__popup_menu(num + max_std, (char * const *)names, NULL);
130 if (choice < 0) {130 if (choice < 0) {
131 ret = -1;131 ret = -1;
132 goto out;132 goto out;
tools/perf/ui/gtk/Build+6−1
@@ -1,4 +1,4 @@
1CFLAGS_gtk += -fPIC $(GTK_CFLAGS)1CFLAGS_gtk += -fPIC $(GTK_CFLAGS) -Wno-deprecated-declarations
2 2
3gtk-y += browser.o3gtk-y += browser.o
4gtk-y += hists.o4gtk-y += hists.o
@@ -7,3 +7,8 @@ gtk-y += util.o · 2 unmodified lines
7gtk-y += helpline.o7gtk-y += helpline.o
8gtk-y += progress.o8gtk-y += progress.o
9gtk-y += annotate.o9gtk-y += annotate.o
10gtk-y += zalloc.o
11
12$(OUTPUT)ui/gtk/zalloc.o: ../lib/zalloc.c FORCE
13 $(call rule_mkdir)
14 $(call if_changed_dep,cc_o_c)
tools/perf/ui/tui/util.c+8−4
@@ -23,7 +23,7 @@ static void ui_browser__argv_write(struct ui_browser *browser, · 22 unmodified lines
23 ui_browser__write_nstring(browser, *arg, browser->width);23 ui_browser__write_nstring(browser, *arg, browser->width);
24}24}
25 25
26static int popup_menu__run(struct ui_browser *menu)26static int popup_menu__run(struct ui_browser *menu, int *keyp)
27{27{
28 int key;28 int key;
29 29
@@ -45,6 +45,11 @@ static int popup_menu__run(struct ui_browser *menu) · 15 unmodified lines
45 key = -1;45 key = -1;
46 break;46 break;
47 default:47 default:
48 if (keyp) {
49 *keyp = key;
50 key = menu->nr_entries;
51 break;
52 }
48 continue;53 continue;
49 }54 }
50 55
@@ -55,7 +60,7 @@ static int popup_menu__run(struct ui_browser *menu) · 4 unmodified lines
55 return key;60 return key;
56}61}
57 62
58int ui__popup_menu(int argc, char * const argv[])63int ui__popup_menu(int argc, char * const argv[], int *keyp)
59{64{
60 struct ui_browser menu = {65 struct ui_browser menu = {
61 .entries = (void *)argv,66 .entries = (void *)argv,
@@ -64,8 +69,7 @@ int ui__popup_menu(int argc, char * const argv[]) · 2 unmodified lines
64 .write = ui_browser__argv_write,69 .write = ui_browser__argv_write,
65 .nr_entries = argc,70 .nr_entries = argc,
66 };71 };
67 72 return popup_menu__run(&menu, keyp);
68 return popup_menu__run(&menu);
69}73}
70 74
71int ui_browser__input_window(const char *title, const char *text, char *input,75int ui_browser__input_window(const char *title, const char *text, char *input,
tools/perf/ui/util.h+1−1
@@ -5,7 +5,7 @@ · 4 unmodified lines
5#include <stdarg.h>5#include <stdarg.h>
6 6
7int ui__getch(int delay_secs);7int ui__getch(int delay_secs);
8int ui__popup_menu(int argc, char * const argv[]);8int ui__popup_menu(int argc, char * const argv[], int *keyp);
9int ui__help_window(const char *text);9int ui__help_window(const char *text);
10int ui__dialog_yesno(const char *msg);10int ui__dialog_yesno(const char *msg);
11void __ui__info_window(const char *title, const char *text, const char *exit_msg);11void __ui__info_window(const char *title, const char *text, const char *exit_msg);
tools/perf/util/annotate.c+17−2
@@ -1966,14 +1966,20 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) · 1965 unmodified lines
1966 err = asprintf(&command,1966 err = asprintf(&command,
1967 "%s %s%s --start-address=0x%016" PRIx641967 "%s %s%s --start-address=0x%016" PRIx64
1968 " --stop-address=0x%016" PRIx641968 " --stop-address=0x%016" PRIx64
1969 " -l -d %s %s -C \"$1\"",1969 " -l -d %s %s %s %c%s%c %s%s -C \"$1\"",
1970 opts->objdump_path ?: "objdump",1970 opts->objdump_path ?: "objdump",
1971 opts->disassembler_style ? "-M " : "",1971 opts->disassembler_style ? "-M " : "",
1972 opts->disassembler_style ?: "",1972 opts->disassembler_style ?: "",
1973 map__rip_2objdump(map, sym->start),1973 map__rip_2objdump(map, sym->start),
1974 map__rip_2objdump(map, sym->end),1974 map__rip_2objdump(map, sym->end),
1975 opts->show_asm_raw ? "" : "--no-show-raw-insn",1975 opts->show_asm_raw ? "" : "--no-show-raw-insn",
1976 opts->annotate_src ? "-S" : "");1976 opts->annotate_src ? "-S" : "",
1977 opts->prefix ? "--prefix " : "",
1978 opts->prefix ? '"' : ' ',
1979 opts->prefix ?: "",
1980 opts->prefix ? '"' : ' ',
1981 opts->prefix_strip ? "--prefix-strip=" : "",
1982 opts->prefix_strip ?: "");
1977 1983
1978 if (err < 0) {1984 if (err < 0) {
1979 pr_err("Failure allocating memory for the command to run\n");1985 pr_err("Failure allocating memory for the command to run\n");
@@ -3204,3 +3210,12 @@ out: · 1224 unmodified lines
3204 free(str1);3210 free(str1);
3205 return err;3211 return err;
3206}3212}
3213
3214int annotate_check_args(struct annotation_options *args)
3215{
3216 if (args->prefix_strip && !args->prefix) {
3217 pr_err("--prefix-strip requires --prefix\n");
3218 return -1;
3219 }
3220 return 0;
3221}
tools/perf/util/annotate.h+5−0
@@ -94,6 +94,8 @@ struct annotation_options { · 93 unmodified lines
94 int context;94 int context;
95 const char *objdump_path;95 const char *objdump_path;
96 const char *disassembler_style;96 const char *disassembler_style;
97 const char *prefix;
98 const char *prefix_strip;
97 unsigned int percent_type;99 unsigned int percent_type;
98};100};
99 101
@@ -415,4 +417,7 @@ void annotation_config__init(void); · 315 unmodified lines
415 417
416int annotate_parse_percent_type(const struct option *opt, const char *_str,418int annotate_parse_percent_type(const struct option *opt, const char *_str,
417 int unset);419 int unset);
420
421int annotate_check_args(struct annotation_options *args);
422
418#endif /* __PERF_ANNOTATE_H */423#endif /* __PERF_ANNOTATE_H */
tools/perf/util/c++/clang.cpp+4−0
@@ -71,7 +71,11 @@ getModuleFromSource(llvm::opt::ArgStringList CFlags, · 70 unmodified lines
71 CompilerInstance Clang;71 CompilerInstance Clang;
72 Clang.createDiagnostics();72 Clang.createDiagnostics();
73 73
74#if CLANG_VERSION_MAJOR < 9
74 Clang.setVirtualFileSystem(&*VFS);75 Clang.setVirtualFileSystem(&*VFS);
76#else
77 Clang.createFileManager(&*VFS);
78#endif
75 79
76#if CLANG_VERSION_MAJOR < 480#if CLANG_VERSION_MAJOR < 4
77 IntrusiveRefCntPtr<CompilerInvocation> CI =81 IntrusiveRefCntPtr<CompilerInvocation> CI =
tools/perf/util/expr.y+2−1
@@ -12,7 +12,8 @@ · 11 unmodified lines
12#define MAXIDLEN 25612#define MAXIDLEN 256
13%}13%}
14 14
15%pure-parser15%define api.pure full
16
16%parse-param { double *final_val }17%parse-param { double *final_val }
17%parse-param { struct parse_ctx *ctx }18%parse-param { struct parse_ctx *ctx }
18%parse-param { const char **pp }19%parse-param { const char **pp }
tools/perf/util/header.c+1−1
@@ -2922,7 +2922,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) · 2921 unmodified lines
2922 if (ret == -1)2922 if (ret == -1)
2923 return -1;2923 return -1;
2924 2924
2925 stctime = st.st_ctime;2925 stctime = st.st_mtime;
2926 fprintf(fp, "# captured on : %s", ctime(&stctime));2926 fprintf(fp, "# captured on : %s", ctime(&stctime));
2927 2927
2928 fprintf(fp, "# header version : %u\n", header->version);2928 fprintf(fp, "# header version : %u\n", header->version);
tools/perf/util/mmap.c+34−6
@@ -23,6 +23,18 @@ · 22 unmodified lines
23#include "mmap.h"23#include "mmap.h"
24#include "../perf.h"24#include "../perf.h"
25#include <internal/lib.h> /* page_size */25#include <internal/lib.h> /* page_size */
26#include <linux/bitmap.h>
27
28#define MASK_SIZE 1023
29void mmap_cpu_mask__scnprintf(struct mmap_cpu_mask *mask, const char *tag)
30{
31 char buf[MASK_SIZE + 1];
32 size_t len;
33
34 len = bitmap_scnprintf(mask->bits, mask->nbits, buf, MASK_SIZE);
35 buf[len] = '\0';
36 pr_debug("%p: %s mask[%zd]: %s\n", mask, tag, mask->nbits, buf);
37}
26 38
27size_t mmap__mmap_len(struct mmap *map)39size_t mmap__mmap_len(struct mmap *map)
28{40{
@@ -207,6 +219,8 @@ static void perf_mmap__aio_munmap(struct mmap *map __maybe_unused) · 178 unmodified lines
207 219
208void mmap__munmap(struct mmap *map)220void mmap__munmap(struct mmap *map)
209{221{
222 bitmap_free(map->affinity_mask.bits);
223
210 perf_mmap__aio_munmap(map);224 perf_mmap__aio_munmap(map);
211 if (map->data != NULL) {225 if (map->data != NULL) {
212 munmap(map->data, mmap__mmap_len(map));226 munmap(map->data, mmap__mmap_len(map));
@@ -215,7 +229,7 @@ void mmap__munmap(struct mmap *map) · 2 unmodified lines
215 auxtrace_mmap__munmap(&map->auxtrace_mmap);229 auxtrace_mmap__munmap(&map->auxtrace_mmap);
216}230}
217 231
218static void build_node_mask(int node, cpu_set_t *mask)232static void build_node_mask(int node, struct mmap_cpu_mask *mask)
219{233{
220 int c, cpu, nr_cpus;234 int c, cpu, nr_cpus;
221 const struct perf_cpu_map *cpu_map = NULL;235 const struct perf_cpu_map *cpu_map = NULL;
@@ -228,17 +242,23 @@ static void build_node_mask(int node, cpu_set_t *mask) · 6 unmodified lines
228 for (c = 0; c < nr_cpus; c++) {242 for (c = 0; c < nr_cpus; c++) {
229 cpu = cpu_map->map[c]; /* map c index to online cpu index */243 cpu = cpu_map->map[c]; /* map c index to online cpu index */
230 if (cpu__get_node(cpu) == node)244 if (cpu__get_node(cpu) == node)
231 CPU_SET(cpu, mask);245 set_bit(cpu, mask->bits);
232 }246 }
233}247}
234 248
235static void perf_mmap__setup_affinity_mask(struct mmap *map, struct mmap_params *mp)249static int perf_mmap__setup_affinity_mask(struct mmap *map, struct mmap_params *mp)
236{250{
237 CPU_ZERO(&map->affinity_mask);251 map->affinity_mask.nbits = cpu__max_cpu();
252 map->affinity_mask.bits = bitmap_alloc(map->affinity_mask.nbits);
253 if (!map->affinity_mask.bits)
254 return -1;
255
238 if (mp->affinity == PERF_AFFINITY_NODE && cpu__max_node() > 1)256 if (mp->affinity == PERF_AFFINITY_NODE && cpu__max_node() > 1)
239 build_node_mask(cpu__get_node(map->core.cpu), &map->affinity_mask);257 build_node_mask(cpu__get_node(map->core.cpu), &map->affinity_mask);
240 else if (mp->affinity == PERF_AFFINITY_CPU)258 else if (mp->affinity == PERF_AFFINITY_CPU)
241 CPU_SET(map->core.cpu, &map->affinity_mask);259 set_bit(map->core.cpu, map->affinity_mask.bits);
260
261 return 0;
242}262}
243 263
244int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu)264int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu)
@@ -249,7 +269,15 @@ int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu) · 4 unmodified lines
249 return -1;269 return -1;
250 }270 }
251 271
252 perf_mmap__setup_affinity_mask(map, mp);272 if (mp->affinity != PERF_AFFINITY_SYS &&
273 perf_mmap__setup_affinity_mask(map, mp)) {
274 pr_debug2("failed to alloc mmap affinity mask, error %d\n",
275 errno);
276 return -1;
277 }
278
279 if (verbose == 2)
280 mmap_cpu_mask__scnprintf(&map->affinity_mask, "mmap");
253 281
254 map->core.flush = mp->flush;282 map->core.flush = mp->flush;
255 283
tools/perf/util/mmap.h+12−1
@@ -15,6 +15,15 @@ · 14 unmodified lines
15#include "event.h"15#include "event.h"
16 16
17struct aiocb;17struct aiocb;
18
19struct mmap_cpu_mask {
20 unsigned long *bits;
21 size_t nbits;
22};
23
24#define MMAP_CPU_MASK_BYTES(m) \
25 (BITS_TO_LONGS(((struct mmap_cpu_mask *)m)->nbits) * sizeof(unsigned long))
26
18/**27/**
19 * struct mmap - perf's ring buffer mmap details28 * struct mmap - perf's ring buffer mmap details
20 *29 *
@@ -31,7 +40,7 @@ struct mmap { · 10 unmodified lines
31 int nr_cblocks;40 int nr_cblocks;
32 } aio;41 } aio;
33#endif42#endif
34 cpu_set_t affinity_mask;43 struct mmap_cpu_mask affinity_mask;
35 void *data;44 void *data;
36 int comp_level;45 int comp_level;
37};46};
@@ -52,4 +61,6 @@ int perf_mmap__push(struct mmap *md, void *to, · 14 unmodified lines
52 61
53size_t mmap__mmap_len(struct mmap *map);62size_t mmap__mmap_len(struct mmap *map);
54 63
64void mmap_cpu_mask__scnprintf(struct mmap_cpu_mask *mask, const char *tag);
65
55#endif /*__PERF_MMAP_H */66#endif /*__PERF_MMAP_H */
tools/perf/util/parse-events.y+1−1
@@ -1,4 +1,4 @@
1%pure-parser1%define api.pure full
2%parse-param {void *_parse_state}2%parse-param {void *_parse_state}
3%parse-param {void *scanner}3%parse-param {void *scanner}
4%lex-param {void* scanner}4%lex-param {void* scanner}
tools/perf/util/sort.c+1−2
@@ -324,8 +324,7 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms, · 323 unmodified lines
324 return ret;324 return ret;
325}325}
326 326
327static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,327int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width)
328 size_t size, unsigned int width)
329{328{
330 return _hist_entry__sym_snprintf(&he->ms, he->ip,329 return _hist_entry__sym_snprintf(&he->ms, he->ip,
331 he->level, bf, size, width);330 he->level, bf, size, width);
tools/perf/util/sort.h+2−0
@@ -164,6 +164,8 @@ static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) · 163 unmodified lines
164 return he->callchain_size != 0;164 return he->callchain_size != 0;
165}165}
166 166
167int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width);
168
167static inline bool hist_entry__has_pairs(struct hist_entry *he)169static inline bool hist_entry__has_pairs(struct hist_entry *he)
168{170{
169 return !list_empty(&he->pairs.node);171 return !list_empty(&he->pairs.node);