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>
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-y += auxtrace.o
-perf-util-y += archinsn.o
perf-util-y += intel-pt.o
perf-util-y += intel-bts.o
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-#include "archinsn.h"
-#include "event.h"
-#include "machine.h"
-#include "thread.h"
-#include "symbol.h"
-#include "../../../../arch/x86/include/asm/insn.h"
-
-void arch_fetch_insn(struct perf_sample *sample,
- struct thread *thread,
- struct machine *machine)
-{
- struct insn insn;
- int len, ret;
- bool is64bit = false;
-
- if (!sample->ip)
- return;
- len = thread__memcpy(thread, machine, sample->insn, sample->ip, sizeof(sample->insn), &is64bit);
- if (len <= 0)
- return;
-
- ret = insn_decode(&insn, sample->insn, len,
- is64bit ? INSN_MODE_64 : INSN_MODE_32);
- if (ret >= 0 && insn.length <= len)
- sample->insn_len = insn.length;
-}
#include "ui/ui.h"
#include "print_binary.h"
#include "print_insn.h"
-#include "archinsn.h"
#include <linux/bitmap.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
static const char *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
static int max_blocks;
-static bool native_arch;
static struct dlfilter *dlfilter;
static int dlargc;
static char **dlargv;
{
int printed = 0;
- script_fetch_insn(sample, thread, machine, native_arch);
+ perf_sample__fetch_insn(sample, thread, machine);
if (PRINT_FIELD(INSNLEN))
printed += fprintf(fp, " ilen: %d", sample->insn_len);
.set = false,
.default_no_sample = true,
};
- struct utsname uts;
char *script_path = NULL;
const char *dlfilter_file = NULL;
const char **__argv;
if (symbol__init(env) < 0)
goto out_delete;
- uname(&uts);
- if (data.is_pipe) { /* Assume pipe_mode indicates native_arch */
- native_arch = true;
- } else if (env->arch) {
- if (!strcmp(uts.machine, env->arch))
- native_arch = true;
- else if (!strcmp(uts.machine, "x86_64") &&
- !strcmp(env->arch, "i386"))
- native_arch = true;
- }
-
script.session = session;
script__setup_sample_type(&script);
if (c->sample->ip && !c->sample->insn_len && thread__maps(c->al->thread)) {
struct machine *machine = maps__machine(thread__maps(c->al->thread));
- script_fetch_insn(c->sample, c->al->thread, machine, /*native_arch=*/true);
+ perf_sample__fetch_insn(c->sample, c->al->thread, machine);
}
if (!c->sample->insn_len)
Py_RETURN_NONE; /* N.B. This is a return statement */
#include "symbol.h"
#include "synthetic-events.h"
#include "util.h"
-#include "archinsn.h"
#include "dlfilter.h"
#include "tests.h"
#include "util/sample.h"
+++ /dev/null
-#ifndef INSN_H
-#define INSN_H 1
-
-struct perf_sample;
-struct machine;
-struct thread;
-
-void arch_fetch_insn(struct perf_sample *sample,
- struct thread *thread,
- struct machine *machine);
-
-#endif
struct machine *machine = maps__machine(thread__maps(al->thread));
if (machine)
- script_fetch_insn(d->sample, al->thread, machine,
- /*native_arch=*/true);
+ perf_sample__fetch_insn(d->sample, al->thread, machine);
}
}
/* SPDX-License-Identifier: GPL-2.0 */
#include "sample.h"
#include "debug.h"
+#include "thread.h"
+#include <elf.h>
+#ifndef EM_CSKY
+#define EM_CSKY 252
+#endif
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH 258
+#endif
#include <linux/zalloc.h>
#include <stdlib.h>
#include <string.h>
+#include "../../arch/x86/include/asm/insn.h"
void perf_sample__init(struct perf_sample *sample, bool all)
{
}
return sample->intr_regs;
}
+
+static int elf_machine_max_instruction_length(uint16_t e_machine)
+{
+ switch (e_machine) {
+ /* Fixed 4-byte (32-bit) architectures */
+ case EM_AARCH64:
+ case EM_PPC:
+ case EM_PPC64:
+ case EM_MIPS:
+ case EM_SPARC:
+ case EM_SPARCV9:
+ case EM_ALPHA:
+ case EM_LOONGARCH:
+ case EM_PARISC:
+ case EM_SH:
+ return 4;
+
+ /* Variable length or mixed-mode architectures */
+ case EM_ARM: /* Variable due to Thumb/Thumb-2 */
+ case EM_RISCV: /* Variable due to Compressed (C) extension */
+ case EM_CSKY: /* Variable (16 or 32 bit) */
+ case EM_ARC: /* Variable (ARCompact) */
+ return 4;
+ case EM_S390: /* Variable (2, 4, or 6 bytes) */
+ return 6;
+ case EM_68K:
+ return 10;
+ case EM_386:
+ case EM_X86_64:
+ return 15;
+ case EM_XTENSA: /* Variable (FLIX) */
+ return 16;
+ default:
+ return MAX_INSN;
+ }
+}
+
+void perf_sample__fetch_insn(struct perf_sample *sample,
+ struct thread *thread,
+ struct machine *machine)
+{
+ int ret, len;
+ bool is64bit = false;
+ uint16_t e_machine;
+
+ if (!sample->ip || sample->insn_len != 0)
+ return;
+
+ e_machine = thread__e_machine(thread, machine);
+ len = elf_machine_max_instruction_length(e_machine);
+ len = thread__memcpy(thread, machine, sample->insn,
+ sample->ip, len,
+ &is64bit);
+ if (len <= 0)
+ return;
+
+ sample->insn_len = len;
+
+ if (e_machine == EM_386 || e_machine == EM_X86_64) {
+ /* Refine the x86 instruction length with the decoder. */
+ struct insn insn;
+
+ ret = insn_decode(&insn, sample->insn, len,
+ is64bit ? INSN_MODE_64 : INSN_MODE_32);
+ if (ret >= 0 && insn.length <= len)
+ sample->insn_len = insn.length;
+ }
+}
#include <linux/perf_event.h>
#include <linux/types.h>
+struct machine;
+struct thread;
+
/* number of register is bound by the number of bits in regs_dump::mask (64) */
#define PERF_SAMPLE_REGS_CACHE_SIZE (8 * sizeof(u64))
struct regs_dump *perf_sample__user_regs(struct perf_sample *sample);
struct regs_dump *perf_sample__intr_regs(struct perf_sample *sample);
+void perf_sample__fetch_insn(struct perf_sample *sample,
+ struct thread *thread,
+ struct machine *machine);
+
/*
* raw_data is always 4 bytes from an 8-byte boundary, so subtract 4 to get
* 8-byte alignment.
#include <event-parse.h>
#endif
-#include "archinsn.h"
#include "debug.h"
#include "event.h"
#include "trace-event.h"
#endif
#endif
-#if !defined(__i386__) && !defined(__x86_64__)
-void arch_fetch_insn(struct perf_sample *sample __maybe_unused,
- struct thread *thread __maybe_unused,
- struct machine *machine __maybe_unused)
-{
-}
-#endif
-
-void script_fetch_insn(struct perf_sample *sample, struct thread *thread,
- struct machine *machine, bool native_arch)
-{
- if (sample->insn_len == 0 && native_arch)
- arch_fetch_insn(sample, thread, machine);
-}
-
static const struct {
u32 flags;
const char *name;
struct scripting_ops *script_spec__lookup(const char *spec);
int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec));
-void script_fetch_insn(struct perf_sample *sample, struct thread *thread,
- struct machine *machine, bool native_arch);
-
void setup_perl_scripting(void);
void setup_python_scripting(void);