diff options
| -rw-r--r-- | kernel/events/core.c | 11 | ||||
| -rw-r--r-- | kernel/events/hw_breakpoint.c | 13 | ||||
| -rw-r--r-- | tools/perf/Makefile.perf | 14 | ||||
| -rw-r--r-- | tools/perf/arch/arm64/Makefile | 5 | ||||
| -rwxr-xr-x | tools/perf/arch/arm64/entry/syscalls/mksyscalltbl | 6 | ||||
| -rw-r--r-- | tools/perf/arch/powerpc/util/sym-handling.c | 4 | ||||
| -rw-r--r-- | tools/perf/arch/x86/include/arch-tests.h | 1 | ||||
| -rw-r--r-- | tools/perf/arch/x86/tests/Build | 1 | ||||
| -rw-r--r-- | tools/perf/arch/x86/tests/arch-tests.c | 6 | ||||
| -rw-r--r-- | tools/perf/arch/x86/tests/bp-modify.c | 213 | ||||
| -rw-r--r-- | tools/perf/util/annotate.c | 32 | ||||
| -rw-r--r-- | tools/perf/util/annotate.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 5 | ||||
| -rw-r--r-- | tools/perf/util/trace-event-info.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/trace-event-parse.c | 7 |
15 files changed, 282 insertions, 39 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index 2a62b96600ad..abaed4f8bb7f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
| @@ -2867,16 +2867,11 @@ static int perf_event_modify_breakpoint(struct perf_event *bp, | |||
| 2867 | _perf_event_disable(bp); | 2867 | _perf_event_disable(bp); |
| 2868 | 2868 | ||
| 2869 | err = modify_user_hw_breakpoint_check(bp, attr, true); | 2869 | err = modify_user_hw_breakpoint_check(bp, attr, true); |
| 2870 | if (err) { | ||
| 2871 | if (!bp->attr.disabled) | ||
| 2872 | _perf_event_enable(bp); | ||
| 2873 | 2870 | ||
| 2874 | return err; | 2871 | if (!bp->attr.disabled) |
| 2875 | } | ||
| 2876 | |||
| 2877 | if (!attr->disabled) | ||
| 2878 | _perf_event_enable(bp); | 2872 | _perf_event_enable(bp); |
| 2879 | return 0; | 2873 | |
| 2874 | return err; | ||
| 2880 | } | 2875 | } |
| 2881 | 2876 | ||
| 2882 | static int perf_event_modify_attr(struct perf_event *event, | 2877 | static int perf_event_modify_attr(struct perf_event *event, |
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index b3814fce5ecb..d6b56180827c 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c | |||
| @@ -509,6 +509,8 @@ modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *a | |||
| 509 | */ | 509 | */ |
| 510 | int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr) | 510 | int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr) |
| 511 | { | 511 | { |
| 512 | int err; | ||
| 513 | |||
| 512 | /* | 514 | /* |
| 513 | * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it | 515 | * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it |
| 514 | * will not be possible to raise IPIs that invoke __perf_event_disable. | 516 | * will not be possible to raise IPIs that invoke __perf_event_disable. |
| @@ -520,15 +522,12 @@ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *att | |||
| 520 | else | 522 | else |
| 521 | perf_event_disable(bp); | 523 | perf_event_disable(bp); |
| 522 | 524 | ||
| 523 | if (!attr->disabled) { | 525 | err = modify_user_hw_breakpoint_check(bp, attr, false); |
| 524 | int err = modify_user_hw_breakpoint_check(bp, attr, false); | ||
| 525 | 526 | ||
| 526 | if (err) | 527 | if (!bp->attr.disabled) |
| 527 | return err; | ||
| 528 | perf_event_enable(bp); | 528 | perf_event_enable(bp); |
| 529 | bp->attr.disabled = 0; | 529 | |
| 530 | } | 530 | return err; |
| 531 | return 0; | ||
| 532 | } | 531 | } |
| 533 | EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); | 532 | EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); |
| 534 | 533 | ||
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index b3d1b12a5081..5224ade3d5af 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
| @@ -777,14 +777,12 @@ endif | |||
| 777 | $(call QUIET_INSTALL, libexec) \ | 777 | $(call QUIET_INSTALL, libexec) \ |
| 778 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 778 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
| 779 | ifndef NO_LIBBPF | 779 | ifndef NO_LIBBPF |
| 780 | $(call QUIET_INSTALL, lib) \ | 780 | $(call QUIET_INSTALL, bpf-headers) \ |
| 781 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf' | 781 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf'; \ |
| 782 | $(call QUIET_INSTALL, include/bpf) \ | 782 | $(INSTALL) include/bpf/*.h -t '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf' |
| 783 | $(INSTALL) include/bpf/*.h '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf' | 783 | $(call QUIET_INSTALL, bpf-examples) \ |
| 784 | $(call QUIET_INSTALL, lib) \ | 784 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'; \ |
| 785 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' | 785 | $(INSTALL) examples/bpf/*.c -t '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' |
| 786 | $(call QUIET_INSTALL, examples/bpf) \ | ||
| 787 | $(INSTALL) examples/bpf/*.c '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' | ||
| 788 | endif | 786 | endif |
| 789 | $(call QUIET_INSTALL, perf-archive) \ | 787 | $(call QUIET_INSTALL, perf-archive) \ |
| 790 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 788 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile index f013b115dc86..dbef716a1913 100644 --- a/tools/perf/arch/arm64/Makefile +++ b/tools/perf/arch/arm64/Makefile | |||
| @@ -11,7 +11,8 @@ PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 | |||
| 11 | 11 | ||
| 12 | out := $(OUTPUT)arch/arm64/include/generated/asm | 12 | out := $(OUTPUT)arch/arm64/include/generated/asm |
| 13 | header := $(out)/syscalls.c | 13 | header := $(out)/syscalls.c |
| 14 | sysdef := $(srctree)/tools/include/uapi/asm-generic/unistd.h | 14 | incpath := $(srctree)/tools |
| 15 | sysdef := $(srctree)/tools/arch/arm64/include/uapi/asm/unistd.h | ||
| 15 | sysprf := $(srctree)/tools/perf/arch/arm64/entry/syscalls/ | 16 | sysprf := $(srctree)/tools/perf/arch/arm64/entry/syscalls/ |
| 16 | systbl := $(sysprf)/mksyscalltbl | 17 | systbl := $(sysprf)/mksyscalltbl |
| 17 | 18 | ||
| @@ -19,7 +20,7 @@ systbl := $(sysprf)/mksyscalltbl | |||
| 19 | _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') | 20 | _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') |
| 20 | 21 | ||
| 21 | $(header): $(sysdef) $(systbl) | 22 | $(header): $(sysdef) $(systbl) |
| 22 | $(Q)$(SHELL) '$(systbl)' '$(CC)' '$(HOSTCC)' $(sysdef) > $@ | 23 | $(Q)$(SHELL) '$(systbl)' '$(CC)' '$(HOSTCC)' $(incpath) $(sysdef) > $@ |
| 23 | 24 | ||
| 24 | clean:: | 25 | clean:: |
| 25 | $(call QUIET_CLEAN, arm64) $(RM) $(header) | 26 | $(call QUIET_CLEAN, arm64) $(RM) $(header) |
diff --git a/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl b/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl index 52e197317d3e..2dbb8cade048 100755 --- a/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl +++ b/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl | |||
| @@ -11,7 +11,8 @@ | |||
| 11 | 11 | ||
| 12 | gcc=$1 | 12 | gcc=$1 |
| 13 | hostcc=$2 | 13 | hostcc=$2 |
| 14 | input=$3 | 14 | incpath=$3 |
| 15 | input=$4 | ||
| 15 | 16 | ||
| 16 | if ! test -r $input; then | 17 | if ! test -r $input; then |
| 17 | echo "Could not read input file" >&2 | 18 | echo "Could not read input file" >&2 |
| @@ -28,7 +29,6 @@ create_table_from_c() | |||
| 28 | 29 | ||
| 29 | cat <<-_EoHEADER | 30 | cat <<-_EoHEADER |
| 30 | #include <stdio.h> | 31 | #include <stdio.h> |
| 31 | #define __ARCH_WANT_RENAMEAT | ||
| 32 | #include "$input" | 32 | #include "$input" |
| 33 | int main(int argc, char *argv[]) | 33 | int main(int argc, char *argv[]) |
| 34 | { | 34 | { |
| @@ -42,7 +42,7 @@ create_table_from_c() | |||
| 42 | printf "%s\n" " printf(\"#define SYSCALLTBL_ARM64_MAX_ID %d\\n\", __NR_$last_sc);" | 42 | printf "%s\n" " printf(\"#define SYSCALLTBL_ARM64_MAX_ID %d\\n\", __NR_$last_sc);" |
| 43 | printf "}\n" | 43 | printf "}\n" |
| 44 | 44 | ||
| 45 | } | $hostcc -o $create_table_exe -x c - | 45 | } | $hostcc -I $incpath/include/uapi -o $create_table_exe -x c - |
| 46 | 46 | ||
| 47 | $create_table_exe | 47 | $create_table_exe |
| 48 | 48 | ||
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 20e7d74d86cd..10a44e946f77 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c | |||
| @@ -22,15 +22,16 @@ bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) | |||
| 22 | 22 | ||
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | #if !defined(_CALL_ELF) || _CALL_ELF != 2 | ||
| 26 | int arch__choose_best_symbol(struct symbol *syma, | 25 | int arch__choose_best_symbol(struct symbol *syma, |
| 27 | struct symbol *symb __maybe_unused) | 26 | struct symbol *symb __maybe_unused) |
| 28 | { | 27 | { |
| 29 | char *sym = syma->name; | 28 | char *sym = syma->name; |
| 30 | 29 | ||
| 30 | #if !defined(_CALL_ELF) || _CALL_ELF != 2 | ||
| 31 | /* Skip over any initial dot */ | 31 | /* Skip over any initial dot */ |
| 32 | if (*sym == '.') | 32 | if (*sym == '.') |
| 33 | sym++; | 33 | sym++; |
| 34 | #endif | ||
| 34 | 35 | ||
| 35 | /* Avoid "SyS" kernel syscall aliases */ | 36 | /* Avoid "SyS" kernel syscall aliases */ |
| 36 | if (strlen(sym) >= 3 && !strncmp(sym, "SyS", 3)) | 37 | if (strlen(sym) >= 3 && !strncmp(sym, "SyS", 3)) |
| @@ -41,6 +42,7 @@ int arch__choose_best_symbol(struct symbol *syma, | |||
| 41 | return SYMBOL_A; | 42 | return SYMBOL_A; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 45 | #if !defined(_CALL_ELF) || _CALL_ELF != 2 | ||
| 44 | /* Allow matching against dot variants */ | 46 | /* Allow matching against dot variants */ |
| 45 | int arch__compare_symbol_names(const char *namea, const char *nameb) | 47 | int arch__compare_symbol_names(const char *namea, const char *nameb) |
| 46 | { | 48 | { |
diff --git a/tools/perf/arch/x86/include/arch-tests.h b/tools/perf/arch/x86/include/arch-tests.h index c1bd979b957b..613709cfbbd0 100644 --- a/tools/perf/arch/x86/include/arch-tests.h +++ b/tools/perf/arch/x86/include/arch-tests.h | |||
| @@ -9,6 +9,7 @@ struct test; | |||
| 9 | int test__rdpmc(struct test *test __maybe_unused, int subtest); | 9 | int test__rdpmc(struct test *test __maybe_unused, int subtest); |
| 10 | int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest); | 10 | int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest); |
| 11 | int test__insn_x86(struct test *test __maybe_unused, int subtest); | 11 | int test__insn_x86(struct test *test __maybe_unused, int subtest); |
| 12 | int test__bp_modify(struct test *test, int subtest); | ||
| 12 | 13 | ||
| 13 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 14 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
| 14 | struct thread; | 15 | struct thread; |
diff --git a/tools/perf/arch/x86/tests/Build b/tools/perf/arch/x86/tests/Build index 8e2c5a38c3b9..586849ff83a0 100644 --- a/tools/perf/arch/x86/tests/Build +++ b/tools/perf/arch/x86/tests/Build | |||
| @@ -5,3 +5,4 @@ libperf-y += arch-tests.o | |||
| 5 | libperf-y += rdpmc.o | 5 | libperf-y += rdpmc.o |
| 6 | libperf-y += perf-time-to-tsc.o | 6 | libperf-y += perf-time-to-tsc.o |
| 7 | libperf-$(CONFIG_AUXTRACE) += insn-x86.o | 7 | libperf-$(CONFIG_AUXTRACE) += insn-x86.o |
| 8 | libperf-$(CONFIG_X86_64) += bp-modify.o | ||
diff --git a/tools/perf/arch/x86/tests/arch-tests.c b/tools/perf/arch/x86/tests/arch-tests.c index cc1802ff5410..d47d3f8e3c8e 100644 --- a/tools/perf/arch/x86/tests/arch-tests.c +++ b/tools/perf/arch/x86/tests/arch-tests.c | |||
| @@ -24,6 +24,12 @@ struct test arch_tests[] = { | |||
| 24 | .func = test__insn_x86, | 24 | .func = test__insn_x86, |
| 25 | }, | 25 | }, |
| 26 | #endif | 26 | #endif |
| 27 | #if defined(__x86_64__) | ||
| 28 | { | ||
| 29 | .desc = "x86 bp modify", | ||
| 30 | .func = test__bp_modify, | ||
| 31 | }, | ||
| 32 | #endif | ||
| 27 | { | 33 | { |
| 28 | .func = NULL, | 34 | .func = NULL, |
| 29 | }, | 35 | }, |
diff --git a/tools/perf/arch/x86/tests/bp-modify.c b/tools/perf/arch/x86/tests/bp-modify.c new file mode 100644 index 000000000000..f53e4406709f --- /dev/null +++ b/tools/perf/arch/x86/tests/bp-modify.c | |||
| @@ -0,0 +1,213 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <linux/compiler.h> | ||
| 3 | #include <sys/types.h> | ||
| 4 | #include <sys/wait.h> | ||
| 5 | #include <sys/user.h> | ||
| 6 | #include <syscall.h> | ||
| 7 | #include <unistd.h> | ||
| 8 | #include <stdio.h> | ||
| 9 | #include <stdlib.h> | ||
| 10 | #include <sys/ptrace.h> | ||
| 11 | #include <asm/ptrace.h> | ||
| 12 | #include <errno.h> | ||
| 13 | #include "debug.h" | ||
| 14 | #include "tests/tests.h" | ||
| 15 | #include "arch-tests.h" | ||
| 16 | |||
| 17 | static noinline int bp_1(void) | ||
| 18 | { | ||
| 19 | pr_debug("in %s\n", __func__); | ||
| 20 | return 0; | ||
| 21 | } | ||
| 22 | |||
| 23 | static noinline int bp_2(void) | ||
| 24 | { | ||
| 25 | pr_debug("in %s\n", __func__); | ||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | static int spawn_child(void) | ||
| 30 | { | ||
| 31 | int child = fork(); | ||
| 32 | |||
| 33 | if (child == 0) { | ||
| 34 | /* | ||
| 35 | * The child sets itself for as tracee and | ||
| 36 | * waits in signal for parent to trace it, | ||
| 37 | * then it calls bp_1 and quits. | ||
| 38 | */ | ||
| 39 | int err = ptrace(PTRACE_TRACEME, 0, NULL, NULL); | ||
| 40 | |||
| 41 | if (err) { | ||
| 42 | pr_debug("failed to PTRACE_TRACEME\n"); | ||
| 43 | exit(1); | ||
| 44 | } | ||
| 45 | |||
| 46 | raise(SIGCONT); | ||
| 47 | bp_1(); | ||
| 48 | exit(0); | ||
| 49 | } | ||
| 50 | |||
| 51 | return child; | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * This tests creates HW breakpoint, tries to | ||
| 56 | * change it and checks it was properly changed. | ||
| 57 | */ | ||
| 58 | static int bp_modify1(void) | ||
| 59 | { | ||
| 60 | pid_t child; | ||
| 61 | int status; | ||
| 62 | unsigned long rip = 0, dr7 = 1; | ||
| 63 | |||
| 64 | child = spawn_child(); | ||
| 65 | |||
| 66 | waitpid(child, &status, 0); | ||
| 67 | if (WIFEXITED(status)) { | ||
| 68 | pr_debug("tracee exited prematurely 1\n"); | ||
| 69 | return TEST_FAIL; | ||
| 70 | } | ||
| 71 | |||
| 72 | /* | ||
| 73 | * The parent does following steps: | ||
| 74 | * - creates a new breakpoint (id 0) for bp_2 function | ||
| 75 | * - changes that breakponit to bp_1 function | ||
| 76 | * - waits for the breakpoint to hit and checks | ||
| 77 | * it has proper rip of bp_1 function | ||
| 78 | * - detaches the child | ||
| 79 | */ | ||
| 80 | if (ptrace(PTRACE_POKEUSER, child, | ||
| 81 | offsetof(struct user, u_debugreg[0]), bp_2)) { | ||
| 82 | pr_debug("failed to set breakpoint, 1st time: %s\n", | ||
| 83 | strerror(errno)); | ||
| 84 | goto out; | ||
| 85 | } | ||
| 86 | |||
| 87 | if (ptrace(PTRACE_POKEUSER, child, | ||
| 88 | offsetof(struct user, u_debugreg[0]), bp_1)) { | ||
| 89 | pr_debug("failed to set breakpoint, 2nd time: %s\n", | ||
| 90 | strerror(errno)); | ||
| 91 | goto out; | ||
| 92 | } | ||
| 93 | |||
| 94 | if (ptrace(PTRACE_POKEUSER, child, | ||
| 95 | offsetof(struct user, u_debugreg[7]), dr7)) { | ||
| 96 | pr_debug("failed to set dr7: %s\n", strerror(errno)); | ||
| 97 | goto out; | ||
| 98 | } | ||
| 99 | |||
| 100 | if (ptrace(PTRACE_CONT, child, NULL, NULL)) { | ||
| 101 | pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno)); | ||
| 102 | goto out; | ||
| 103 | } | ||
| 104 | |||
| 105 | waitpid(child, &status, 0); | ||
| 106 | if (WIFEXITED(status)) { | ||
| 107 | pr_debug("tracee exited prematurely 2\n"); | ||
| 108 | return TEST_FAIL; | ||
| 109 | } | ||
| 110 | |||
| 111 | rip = ptrace(PTRACE_PEEKUSER, child, | ||
| 112 | offsetof(struct user_regs_struct, rip), NULL); | ||
| 113 | if (rip == (unsigned long) -1) { | ||
| 114 | pr_debug("failed to PTRACE_PEEKUSER: %s\n", | ||
| 115 | strerror(errno)); | ||
| 116 | goto out; | ||
| 117 | } | ||
| 118 | |||
| 119 | pr_debug("rip %lx, bp_1 %p\n", rip, bp_1); | ||
| 120 | |||
| 121 | out: | ||
| 122 | if (ptrace(PTRACE_DETACH, child, NULL, NULL)) { | ||
| 123 | pr_debug("failed to PTRACE_DETACH: %s", strerror(errno)); | ||
| 124 | return TEST_FAIL; | ||
| 125 | } | ||
| 126 | |||
| 127 | return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL; | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | * This tests creates HW breakpoint, tries to | ||
| 132 | * change it to bogus value and checks the original | ||
| 133 | * breakpoint is hit. | ||
| 134 | */ | ||
| 135 | static int bp_modify2(void) | ||
| 136 | { | ||
| 137 | pid_t child; | ||
| 138 | int status; | ||
| 139 | unsigned long rip = 0, dr7 = 1; | ||
| 140 | |||
| 141 | child = spawn_child(); | ||
| 142 | |||
| 143 | waitpid(child, &status, 0); | ||
| 144 | if (WIFEXITED(status)) { | ||
| 145 | pr_debug("tracee exited prematurely 1\n"); | ||
| 146 | return TEST_FAIL; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* | ||
| 150 | * The parent does following steps: | ||
| 151 | * - creates a new breakpoint (id 0) for bp_1 function | ||
| 152 | * - tries to change that breakpoint to (-1) address | ||
| 153 | * - waits for the breakpoint to hit and checks | ||
| 154 | * it has proper rip of bp_1 function | ||
| 155 | * - detaches the child | ||
| 156 | */ | ||
| 157 | if (ptrace(PTRACE_POKEUSER, child, | ||
| 158 | offsetof(struct user, u_debugreg[0]), bp_1)) { | ||
| 159 | pr_debug("failed to set breakpoint: %s\n", | ||
| 160 | strerror(errno)); | ||
| 161 | goto out; | ||
| 162 | } | ||
| 163 | |||
| 164 | if (ptrace(PTRACE_POKEUSER, child, | ||
| 165 | offsetof(struct user, u_debugreg[7]), dr7)) { | ||
| 166 | pr_debug("failed to set dr7: %s\n", strerror(errno)); | ||
| 167 | goto out; | ||
| 168 | } | ||
| 169 | |||
| 170 | if (!ptrace(PTRACE_POKEUSER, child, | ||
| 171 | offsetof(struct user, u_debugreg[0]), (unsigned long) (-1))) { | ||
| 172 | pr_debug("failed, breakpoint set to bogus address\n"); | ||
| 173 | goto out; | ||
| 174 | } | ||
| 175 | |||
| 176 | if (ptrace(PTRACE_CONT, child, NULL, NULL)) { | ||
| 177 | pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno)); | ||
| 178 | goto out; | ||
| 179 | } | ||
| 180 | |||
| 181 | waitpid(child, &status, 0); | ||
| 182 | if (WIFEXITED(status)) { | ||
| 183 | pr_debug("tracee exited prematurely 2\n"); | ||
| 184 | return TEST_FAIL; | ||
| 185 | } | ||
| 186 | |||
| 187 | rip = ptrace(PTRACE_PEEKUSER, child, | ||
| 188 | offsetof(struct user_regs_struct, rip), NULL); | ||
| 189 | if (rip == (unsigned long) -1) { | ||
| 190 | pr_debug("failed to PTRACE_PEEKUSER: %s\n", | ||
| 191 | strerror(errno)); | ||
| 192 | goto out; | ||
| 193 | } | ||
| 194 | |||
| 195 | pr_debug("rip %lx, bp_1 %p\n", rip, bp_1); | ||
| 196 | |||
| 197 | out: | ||
| 198 | if (ptrace(PTRACE_DETACH, child, NULL, NULL)) { | ||
| 199 | pr_debug("failed to PTRACE_DETACH: %s", strerror(errno)); | ||
| 200 | return TEST_FAIL; | ||
| 201 | } | ||
| 202 | |||
| 203 | return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL; | ||
| 204 | } | ||
| 205 | |||
| 206 | int test__bp_modify(struct test *test __maybe_unused, | ||
| 207 | int subtest __maybe_unused) | ||
| 208 | { | ||
| 209 | TEST_ASSERT_VAL("modify test 1 failed\n", !bp_modify1()); | ||
| 210 | TEST_ASSERT_VAL("modify test 2 failed\n", !bp_modify2()); | ||
| 211 | |||
| 212 | return 0; | ||
| 213 | } | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 20061cf42288..28cd6a17491b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
| @@ -246,8 +246,14 @@ find_target: | |||
| 246 | 246 | ||
| 247 | indirect_call: | 247 | indirect_call: |
| 248 | tok = strchr(endptr, '*'); | 248 | tok = strchr(endptr, '*'); |
| 249 | if (tok != NULL) | 249 | if (tok != NULL) { |
| 250 | ops->target.addr = strtoull(tok + 1, NULL, 16); | 250 | endptr++; |
| 251 | |||
| 252 | /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). | ||
| 253 | * Do not parse such instruction. */ | ||
| 254 | if (strstr(endptr, "(%r") == NULL) | ||
| 255 | ops->target.addr = strtoull(endptr, NULL, 16); | ||
| 256 | } | ||
| 251 | goto find_target; | 257 | goto find_target; |
| 252 | } | 258 | } |
| 253 | 259 | ||
| @@ -276,7 +282,19 @@ bool ins__is_call(const struct ins *ins) | |||
| 276 | return ins->ops == &call_ops || ins->ops == &s390_call_ops; | 282 | return ins->ops == &call_ops || ins->ops == &s390_call_ops; |
| 277 | } | 283 | } |
| 278 | 284 | ||
| 279 | static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms) | 285 | /* |
| 286 | * Prevents from matching commas in the comment section, e.g.: | ||
| 287 | * ffff200008446e70: b.cs ffff2000084470f4 <generic_exec_single+0x314> // b.hs, b.nlast | ||
| 288 | */ | ||
| 289 | static inline const char *validate_comma(const char *c, struct ins_operands *ops) | ||
| 290 | { | ||
| 291 | if (ops->raw_comment && c > ops->raw_comment) | ||
| 292 | return NULL; | ||
| 293 | |||
| 294 | return c; | ||
| 295 | } | ||
| 296 | |||
| 297 | static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) | ||
| 280 | { | 298 | { |
| 281 | struct map *map = ms->map; | 299 | struct map *map = ms->map; |
| 282 | struct symbol *sym = ms->sym; | 300 | struct symbol *sym = ms->sym; |
| @@ -285,6 +303,10 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op | |||
| 285 | }; | 303 | }; |
| 286 | const char *c = strchr(ops->raw, ','); | 304 | const char *c = strchr(ops->raw, ','); |
| 287 | u64 start, end; | 305 | u64 start, end; |
| 306 | |||
| 307 | ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char); | ||
| 308 | c = validate_comma(c, ops); | ||
| 309 | |||
| 288 | /* | 310 | /* |
| 289 | * Examples of lines to parse for the _cpp_lex_token@@Base | 311 | * Examples of lines to parse for the _cpp_lex_token@@Base |
| 290 | * function: | 312 | * function: |
| @@ -304,6 +326,7 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op | |||
| 304 | ops->target.addr = strtoull(c, NULL, 16); | 326 | ops->target.addr = strtoull(c, NULL, 16); |
| 305 | if (!ops->target.addr) { | 327 | if (!ops->target.addr) { |
| 306 | c = strchr(c, ','); | 328 | c = strchr(c, ','); |
| 329 | c = validate_comma(c, ops); | ||
| 307 | if (c++ != NULL) | 330 | if (c++ != NULL) |
| 308 | ops->target.addr = strtoull(c, NULL, 16); | 331 | ops->target.addr = strtoull(c, NULL, 16); |
| 309 | } | 332 | } |
| @@ -361,9 +384,12 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, | |||
| 361 | return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); | 384 | return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); |
| 362 | 385 | ||
| 363 | c = strchr(ops->raw, ','); | 386 | c = strchr(ops->raw, ','); |
| 387 | c = validate_comma(c, ops); | ||
| 388 | |||
| 364 | if (c != NULL) { | 389 | if (c != NULL) { |
| 365 | const char *c2 = strchr(c + 1, ','); | 390 | const char *c2 = strchr(c + 1, ','); |
| 366 | 391 | ||
| 392 | c2 = validate_comma(c2, ops); | ||
| 367 | /* check for 3-op insn */ | 393 | /* check for 3-op insn */ |
| 368 | if (c2 != NULL) | 394 | if (c2 != NULL) |
| 369 | c = c2; | 395 | c = c2; |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 005a5fe8a8c6..5399ba2321bb 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
| @@ -22,6 +22,7 @@ struct ins { | |||
| 22 | 22 | ||
| 23 | struct ins_operands { | 23 | struct ins_operands { |
| 24 | char *raw; | 24 | char *raw; |
| 25 | char *raw_comment; | ||
| 25 | struct { | 26 | struct { |
| 26 | char *raw; | 27 | char *raw; |
| 27 | char *name; | 28 | char *name; |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c980bbff6353..1a61628a1c12 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -251,8 +251,9 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) | |||
| 251 | { | 251 | { |
| 252 | struct perf_evsel *evsel = zalloc(perf_evsel__object.size); | 252 | struct perf_evsel *evsel = zalloc(perf_evsel__object.size); |
| 253 | 253 | ||
| 254 | if (evsel != NULL) | 254 | if (!evsel) |
| 255 | perf_evsel__init(evsel, attr, idx); | 255 | return NULL; |
| 256 | perf_evsel__init(evsel, attr, idx); | ||
| 256 | 257 | ||
| 257 | if (perf_evsel__is_bpf_output(evsel)) { | 258 | if (perf_evsel__is_bpf_output(evsel)) { |
| 258 | evsel->attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | | 259 | evsel->attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index c85d0d1a65ed..7b0ca7cbb7de 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
| @@ -377,7 +377,7 @@ out: | |||
| 377 | 377 | ||
| 378 | static int record_saved_cmdline(void) | 378 | static int record_saved_cmdline(void) |
| 379 | { | 379 | { |
| 380 | unsigned int size; | 380 | unsigned long long size; |
| 381 | char *path; | 381 | char *path; |
| 382 | struct stat st; | 382 | struct stat st; |
| 383 | int ret, err = 0; | 383 | int ret, err = 0; |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 920b1d58a068..e76214f8d596 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
| @@ -164,16 +164,15 @@ void parse_ftrace_printk(struct tep_handle *pevent, | |||
| 164 | void parse_saved_cmdline(struct tep_handle *pevent, | 164 | void parse_saved_cmdline(struct tep_handle *pevent, |
| 165 | char *file, unsigned int size __maybe_unused) | 165 | char *file, unsigned int size __maybe_unused) |
| 166 | { | 166 | { |
| 167 | char *comm; | 167 | char comm[17]; /* Max comm length in the kernel is 16. */ |
| 168 | char *line; | 168 | char *line; |
| 169 | char *next = NULL; | 169 | char *next = NULL; |
| 170 | int pid; | 170 | int pid; |
| 171 | 171 | ||
| 172 | line = strtok_r(file, "\n", &next); | 172 | line = strtok_r(file, "\n", &next); |
| 173 | while (line) { | 173 | while (line) { |
| 174 | sscanf(line, "%d %ms", &pid, &comm); | 174 | if (sscanf(line, "%d %16s", &pid, comm) == 2) |
| 175 | tep_register_comm(pevent, comm, pid); | 175 | tep_register_comm(pevent, comm, pid); |
| 176 | free(comm); | ||
| 177 | line = strtok_r(NULL, "\n", &next); | 176 | line = strtok_r(NULL, "\n", &next); |
| 178 | } | 177 | } |
| 179 | } | 178 | } |
