Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf script: Fix script_fetch_insn for more than just x86

The script_fetch_insn code was only supported on natively running x86.

Implement a crude elf_machine_max_instruction_length function and use to
give an instruction length on more than just x86.

Use the ELF machine to determine the length to use to support
cross-architecture development.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shimin Guo <shimin.guo@skydio.com>
Cc: Yujie Liu <yujie.liu@intel.com>
[ Conditionally define EM_CSKY and EM_LOONGARCH for older distros ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
7ce6dfc6 0a6fb660

+87 -78
-1
tools/perf/arch/x86/util/Build
··· 14 14 perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o 15 15 16 16 perf-util-y += auxtrace.o 17 - perf-util-y += archinsn.o 18 17 perf-util-y += intel-pt.o 19 18 perf-util-y += intel-bts.o
-27
tools/perf/arch/x86/util/archinsn.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include "archinsn.h" 3 - #include "event.h" 4 - #include "machine.h" 5 - #include "thread.h" 6 - #include "symbol.h" 7 - #include "../../../../arch/x86/include/asm/insn.h" 8 - 9 - void arch_fetch_insn(struct perf_sample *sample, 10 - struct thread *thread, 11 - struct machine *machine) 12 - { 13 - struct insn insn; 14 - int len, ret; 15 - bool is64bit = false; 16 - 17 - if (!sample->ip) 18 - return; 19 - len = thread__memcpy(thread, machine, sample->insn, sample->ip, sizeof(sample->insn), &is64bit); 20 - if (len <= 0) 21 - return; 22 - 23 - ret = insn_decode(&insn, sample->insn, len, 24 - is64bit ? INSN_MODE_64 : INSN_MODE_32); 25 - if (ret >= 0 && insn.length <= len) 26 - sample->insn_len = insn.length; 27 - }
+1 -15
tools/perf/builtin-script.c
··· 37 37 #include "ui/ui.h" 38 38 #include "print_binary.h" 39 39 #include "print_insn.h" 40 - #include "archinsn.h" 41 40 #include <linux/bitmap.h> 42 41 #include <linux/compiler.h> 43 42 #include <linux/kernel.h> ··· 89 90 static const char *cpu_list; 90 91 static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 91 92 static int max_blocks; 92 - static bool native_arch; 93 93 static struct dlfilter *dlfilter; 94 94 static int dlargc; 95 95 static char **dlargv; ··· 1625 1627 { 1626 1628 int printed = 0; 1627 1629 1628 - script_fetch_insn(sample, thread, machine, native_arch); 1630 + perf_sample__fetch_insn(sample, thread, machine); 1629 1631 1630 1632 if (PRINT_FIELD(INSNLEN)) 1631 1633 printed += fprintf(fp, " ilen: %d", sample->insn_len); ··· 4032 4034 .set = false, 4033 4035 .default_no_sample = true, 4034 4036 }; 4035 - struct utsname uts; 4036 4037 char *script_path = NULL; 4037 4038 const char *dlfilter_file = NULL; 4038 4039 const char **__argv; ··· 4452 4455 4453 4456 if (symbol__init(env) < 0) 4454 4457 goto out_delete; 4455 - 4456 - uname(&uts); 4457 - if (data.is_pipe) { /* Assume pipe_mode indicates native_arch */ 4458 - native_arch = true; 4459 - } else if (env->arch) { 4460 - if (!strcmp(uts.machine, env->arch)) 4461 - native_arch = true; 4462 - else if (!strcmp(uts.machine, "x86_64") && 4463 - !strcmp(env->arch, "i386")) 4464 - native_arch = true; 4465 - } 4466 4458 4467 4459 script.session = session; 4468 4460 script__setup_sample_type(&script);
+1 -1
tools/perf/scripts/python/Perf-Trace-Util/Context.c
··· 93 93 if (c->sample->ip && !c->sample->insn_len && thread__maps(c->al->thread)) { 94 94 struct machine *machine = maps__machine(thread__maps(c->al->thread)); 95 95 96 - script_fetch_insn(c->sample, c->al->thread, machine, /*native_arch=*/true); 96 + perf_sample__fetch_insn(c->sample, c->al->thread, machine); 97 97 } 98 98 if (!c->sample->insn_len) 99 99 Py_RETURN_NONE; /* N.B. This is a return statement */
-1
tools/perf/tests/dlfilter-test.c
··· 30 30 #include "symbol.h" 31 31 #include "synthetic-events.h" 32 32 #include "util.h" 33 - #include "archinsn.h" 34 33 #include "dlfilter.h" 35 34 #include "tests.h" 36 35 #include "util/sample.h"
-12
tools/perf/util/archinsn.h
··· 1 - #ifndef INSN_H 2 - #define INSN_H 1 3 - 4 - struct perf_sample; 5 - struct machine; 6 - struct thread; 7 - 8 - void arch_fetch_insn(struct perf_sample *sample, 9 - struct thread *thread, 10 - struct machine *machine); 11 - 12 - #endif
+1 -2
tools/perf/util/dlfilter.c
··· 234 234 struct machine *machine = maps__machine(thread__maps(al->thread)); 235 235 236 236 if (machine) 237 - script_fetch_insn(d->sample, al->thread, machine, 238 - /*native_arch=*/true); 237 + perf_sample__fetch_insn(d->sample, al->thread, machine); 239 238 } 240 239 } 241 240
+77
tools/perf/util/sample.c
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 #include "sample.h" 3 3 #include "debug.h" 4 + #include "thread.h" 5 + #include <elf.h> 6 + #ifndef EM_CSKY 7 + #define EM_CSKY 252 8 + #endif 9 + #ifndef EM_LOONGARCH 10 + #define EM_LOONGARCH 258 11 + #endif 4 12 #include <linux/zalloc.h> 5 13 #include <stdlib.h> 6 14 #include <string.h> 15 + #include "../../arch/x86/include/asm/insn.h" 7 16 8 17 void perf_sample__init(struct perf_sample *sample, bool all) 9 18 { ··· 49 40 pr_err("Failure to allocate sample intr_regs"); 50 41 } 51 42 return sample->intr_regs; 43 + } 44 + 45 + static int elf_machine_max_instruction_length(uint16_t e_machine) 46 + { 47 + switch (e_machine) { 48 + /* Fixed 4-byte (32-bit) architectures */ 49 + case EM_AARCH64: 50 + case EM_PPC: 51 + case EM_PPC64: 52 + case EM_MIPS: 53 + case EM_SPARC: 54 + case EM_SPARCV9: 55 + case EM_ALPHA: 56 + case EM_LOONGARCH: 57 + case EM_PARISC: 58 + case EM_SH: 59 + return 4; 60 + 61 + /* Variable length or mixed-mode architectures */ 62 + case EM_ARM: /* Variable due to Thumb/Thumb-2 */ 63 + case EM_RISCV: /* Variable due to Compressed (C) extension */ 64 + case EM_CSKY: /* Variable (16 or 32 bit) */ 65 + case EM_ARC: /* Variable (ARCompact) */ 66 + return 4; 67 + case EM_S390: /* Variable (2, 4, or 6 bytes) */ 68 + return 6; 69 + case EM_68K: 70 + return 10; 71 + case EM_386: 72 + case EM_X86_64: 73 + return 15; 74 + case EM_XTENSA: /* Variable (FLIX) */ 75 + return 16; 76 + default: 77 + return MAX_INSN; 78 + } 79 + } 80 + 81 + void perf_sample__fetch_insn(struct perf_sample *sample, 82 + struct thread *thread, 83 + struct machine *machine) 84 + { 85 + int ret, len; 86 + bool is64bit = false; 87 + uint16_t e_machine; 88 + 89 + if (!sample->ip || sample->insn_len != 0) 90 + return; 91 + 92 + e_machine = thread__e_machine(thread, machine); 93 + len = elf_machine_max_instruction_length(e_machine); 94 + len = thread__memcpy(thread, machine, sample->insn, 95 + sample->ip, len, 96 + &is64bit); 97 + if (len <= 0) 98 + return; 99 + 100 + sample->insn_len = len; 101 + 102 + if (e_machine == EM_386 || e_machine == EM_X86_64) { 103 + /* Refine the x86 instruction length with the decoder. */ 104 + struct insn insn; 105 + 106 + ret = insn_decode(&insn, sample->insn, len, 107 + is64bit ? INSN_MODE_64 : INSN_MODE_32); 108 + if (ret >= 0 && insn.length <= len) 109 + sample->insn_len = insn.length; 110 + } 52 111 }
+7
tools/perf/util/sample.h
··· 5 5 #include <linux/perf_event.h> 6 6 #include <linux/types.h> 7 7 8 + struct machine; 9 + struct thread; 10 + 8 11 /* number of register is bound by the number of bits in regs_dump::mask (64) */ 9 12 #define PERF_SAMPLE_REGS_CACHE_SIZE (8 * sizeof(u64)) 10 13 ··· 129 126 void perf_sample__exit(struct perf_sample *sample); 130 127 struct regs_dump *perf_sample__user_regs(struct perf_sample *sample); 131 128 struct regs_dump *perf_sample__intr_regs(struct perf_sample *sample); 129 + 130 + void perf_sample__fetch_insn(struct perf_sample *sample, 131 + struct thread *thread, 132 + struct machine *machine); 132 133 133 134 /* 134 135 * raw_data is always 4 bytes from an 8-byte boundary, so subtract 4 to get
-16
tools/perf/util/trace-event-scripting.c
··· 13 13 #include <event-parse.h> 14 14 #endif 15 15 16 - #include "archinsn.h" 17 16 #include "debug.h" 18 17 #include "event.h" 19 18 #include "trace-event.h" ··· 272 273 } 273 274 #endif 274 275 #endif 275 - 276 - #if !defined(__i386__) && !defined(__x86_64__) 277 - void arch_fetch_insn(struct perf_sample *sample __maybe_unused, 278 - struct thread *thread __maybe_unused, 279 - struct machine *machine __maybe_unused) 280 - { 281 - } 282 - #endif 283 - 284 - void script_fetch_insn(struct perf_sample *sample, struct thread *thread, 285 - struct machine *machine, bool native_arch) 286 - { 287 - if (sample->insn_len == 0 && native_arch) 288 - arch_fetch_insn(sample, thread, machine); 289 - } 290 276 291 277 static const struct { 292 278 u32 flags;
-3
tools/perf/util/trace-event.h
··· 116 116 struct scripting_ops *script_spec__lookup(const char *spec); 117 117 int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec)); 118 118 119 - void script_fetch_insn(struct perf_sample *sample, struct thread *thread, 120 - struct machine *machine, bool native_arch); 121 - 122 119 void setup_perl_scripting(void); 123 120 void setup_python_scripting(void); 124 121