From a457ef08a72cb408318ddb851865c5981b842c63 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 16 Jan 2026 21:28:34 -0800 Subject: perf perf_regs: Switch from arch string to int e_machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The arch string requires multiple strcmp to identify things like the IP and SP. Switch to passing in an e_machine that in the bulk of cases is computed using a current thread load. The e_machine also allows identification of 32-bit vs 64-bit processes. Signed-off-by: Ian Rogers Cc: Aditya Bodkhe Cc: Adrian Hunter Cc: Albert Ou Cc: Alexandre Ghiti Cc: Andi Kleen Cc: Athira Rajeev Cc: Chun-Tse Shao Cc: Dmitriy Vyukov Cc: Dr. David Alan Gilbert Cc: Guo Ren Cc: Haibo Xu Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Krzysztof Ɓopatowski Cc: Leo Yan Cc: Mark Wielaard Cc: Namhyung Kim Cc: Palmer Dabbelt Cc: Paul Walmsley Cc: Peter Zijlstra Cc: Sergei Trofimovich Cc: Shimin Guo Cc: Stephen Brennan Cc: Thomas Falcon Cc: Will Deacon [ Include dwarf-regs.h to get conditional defines for EM_CSKY and EM_LOONGARCH, not available in old distros ] Signed-off-by: Arnaldo Carvalho de Melo --- .../util/scripting-engines/trace-event-python.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/scripting-engines/trace-event-python.c') diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 6655c0bbe0d8..b90edc147796 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -50,6 +50,7 @@ #include "../thread-stack.h" #include "../trace-event.h" #include "../call-path.h" +#include "dwarf-regs.h" #include "map.h" #include "symbol.h" #include "thread_map.h" @@ -713,7 +714,7 @@ static void set_sample_datasrc_in_dict(PyObject *dict, _PyUnicode_FromString(decode)); } -static void regs_map(struct regs_dump *regs, uint64_t mask, const char *arch, char *bf, int size) +static void regs_map(struct regs_dump *regs, uint64_t mask, uint16_t e_machine, char *bf, int size) { unsigned int i = 0, r; int printed = 0; @@ -731,7 +732,7 @@ static void regs_map(struct regs_dump *regs, uint64_t mask, const char *arch, ch printed += scnprintf(bf + printed, size - printed, "%5s:0x%" PRIx64 " ", - perf_reg_name(r, arch), val); + perf_reg_name(r, e_machine), val); } } @@ -739,10 +740,10 @@ static void regs_map(struct regs_dump *regs, uint64_t mask, const char *arch, ch static int set_regs_in_dict(PyObject *dict, struct perf_sample *sample, - struct evsel *evsel) + struct evsel *evsel, + uint16_t e_machine) { struct perf_event_attr *attr = &evsel->core.attr; - const char *arch = perf_env__arch(evsel__env(evsel)); int size = (__sw_hweight64(attr->sample_regs_intr) * MAX_REG_SIZE) + 1; char *bf = NULL; @@ -752,7 +753,7 @@ static int set_regs_in_dict(PyObject *dict, if (!bf) return -1; - regs_map(sample->intr_regs, attr->sample_regs_intr, arch, bf, size); + regs_map(sample->intr_regs, attr->sample_regs_intr, e_machine, bf, size); pydict_set_item_string_decref(dict, "iregs", _PyUnicode_FromString(bf)); @@ -764,7 +765,7 @@ static int set_regs_in_dict(PyObject *dict, if (!bf) return -1; } - regs_map(sample->user_regs, attr->sample_regs_user, arch, bf, size); + regs_map(sample->user_regs, attr->sample_regs_user, e_machine, bf, size); pydict_set_item_string_decref(dict, "uregs", _PyUnicode_FromString(bf)); @@ -834,6 +835,8 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, PyObject *callchain) { PyObject *dict, *dict_sample, *brstack, *brstacksym; + struct machine *machine; + uint16_t e_machine = EM_HOST; dict = PyDict_New(); if (!dict) @@ -920,7 +923,11 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, PyLong_FromUnsignedLongLong(sample->cyc_cnt)); } - if (set_regs_in_dict(dict, sample, evsel)) + if (al->thread) { + machine = maps__machine(thread__maps(al->thread)); + e_machine = thread__e_machine(al->thread, machine); + } + if (set_regs_in_dict(dict, sample, evsel, e_machine)) Py_FatalError("Failed to setting regs in dict"); return dict; -- cgit v1.2.3 From 4e66527f8859a6614a3a8afd11778c832a30ebbb Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 23 Jan 2026 14:22:07 -0800 Subject: perf thread: Add optional e_flags output argument to thread__e_machine The e_flags are needed to accurately compute complete perf register information for CSKY. Add the ability to read and have this value associated with a thread. This change doesn't wire up the use of the e_flags except in disasm where use already exists but just wasn't set up yet. Signed-off-by: Ian Rogers Cc: Aditya Bodkhe Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Chun-Tse Shao Cc: Guo Ren Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Sergei Trofimovich Cc: Shimin Guo Cc: Stephen Brennan Cc: Swapnil Sapkal Cc: Tianyou Li Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 14 +++-- tools/perf/builtin-trace.c | 12 +++-- tools/perf/util/annotate.c | 5 +- tools/perf/util/disasm.c | 5 +- tools/perf/util/disasm.h | 2 +- tools/perf/util/dso.c | 43 +++++++++++++--- tools/perf/util/dso.h | 4 +- .../util/scripting-engines/trace-event-python.c | 2 +- tools/perf/util/session.c | 4 +- tools/perf/util/thread.c | 59 +++++++++++++++------- tools/perf/util/thread.h | 16 +++++- tools/perf/util/unwind-libdw.c | 4 +- 12 files changed, 122 insertions(+), 48 deletions(-) (limited to 'tools/perf/util/scripting-engines/trace-event-python.c') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 372bede30230..8c0de27a9713 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2504,11 +2504,17 @@ static void process_event(struct perf_script *script, symbol_conf.bt_stop_list, fp); } - if (PRINT_FIELD(IREGS)) - perf_sample__fprintf_iregs(sample, attr, thread__e_machine(thread, machine), fp); + if (PRINT_FIELD(IREGS)) { + perf_sample__fprintf_iregs(sample, attr, + thread__e_machine(thread, machine, /*e_flags=*/NULL), + fp); + } - if (PRINT_FIELD(UREGS)) - perf_sample__fprintf_uregs(sample, attr, thread__e_machine(thread, machine), fp); + if (PRINT_FIELD(UREGS)) { + perf_sample__fprintf_uregs(sample, attr, + thread__e_machine(thread, machine, /*e_flags=*/NULL), + fp); + } if (PRINT_FIELD(BRSTACK)) perf_sample__fprintf_brstack(sample, thread, evsel, fp); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8df5ca44e4f9..311d9da9896a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2789,7 +2789,7 @@ static int trace__sys_enter(struct trace *trace, struct evsel *evsel, struct thread_trace *ttrace; thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); - e_machine = thread__e_machine(thread, trace->host); + e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL); sc = trace__syscall_info(trace, evsel, e_machine, id); if (sc == NULL) goto out_put; @@ -2868,7 +2868,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel, thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); - e_machine = thread__e_machine(thread, trace->host); + e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL); sc = trace__syscall_info(trace, evsel, e_machine, id); if (sc == NULL) goto out_put; @@ -2934,7 +2934,7 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel, struct thread_trace *ttrace; thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); - e_machine = thread__e_machine(thread, trace->host); + e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL); sc = trace__syscall_info(trace, evsel, e_machine, id); if (sc == NULL) goto out_put; @@ -3285,7 +3285,9 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel, if (evsel == trace->syscalls.events.bpf_output) { int id = perf_evsel__sc_tp_uint(evsel, id, sample); - int e_machine = thread ? thread__e_machine(thread, trace->host) : EM_HOST; + int e_machine = thread + ? thread__e_machine(thread, trace->host, /*e_flags=*/NULL) + : EM_HOST; struct syscall *sc = trace__syscall_info(trace, evsel, e_machine, id); if (sc) { @@ -4916,7 +4918,7 @@ static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trac { size_t printed = 0; struct thread_trace *ttrace = thread__priv(thread); - int e_machine = thread__e_machine(thread, trace->host); + int e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL); double ratio; if (ttrace == NULL) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index c16c6dfaa959..880b1bd300c2 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -984,6 +984,7 @@ int thread__get_arch(struct thread *thread, const struct arch **parch) { const struct arch *arch; struct machine *machine; + uint32_t e_flags; uint16_t e_machine; if (!thread) { @@ -992,8 +993,8 @@ int thread__get_arch(struct thread *thread, const struct arch **parch) } machine = maps__machine(thread__maps(thread)); - e_machine = thread__e_machine(thread, machine); - arch = arch__find(e_machine, machine->env ? machine->env->cpuid : NULL); + e_machine = thread__e_machine(thread, machine, &e_flags); + arch = arch__find(e_machine, e_flags, machine->env ? machine->env->cpuid : NULL); if (arch == NULL) { pr_err("%s: unsupported arch %d\n", __func__, e_machine); return errno; diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 9b0ba1fc5aec..6b36287f30fe 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -134,7 +134,7 @@ static int arch__cmp(const void *a, const void *b) return e_machine_and_eflags__cmp(&(*aa)->id, &(*ab)->id); } -const struct arch *arch__find(uint16_t e_machine, const char *cpuid) +const struct arch *arch__find(uint16_t e_machine, uint32_t e_flags, const char *cpuid) { static const struct arch *(*const arch_new_fn[])(const struct e_machine_and_e_flags *id, const char *cpuid) = { @@ -157,8 +157,7 @@ const struct arch *arch__find(uint16_t e_machine, const char *cpuid) static size_t num_archs; struct e_machine_and_e_flags key = { .e_machine = e_machine, - // TODO: e_flags should really come from the same source as e_machine. - .e_flags = EF_HOST, + .e_flags = e_flags, }; const struct arch *result = NULL, **tmp; diff --git a/tools/perf/util/disasm.h b/tools/perf/util/disasm.h index 6a1905f9d4fc..a6e478caf61a 100644 --- a/tools/perf/util/disasm.h +++ b/tools/perf/util/disasm.h @@ -108,7 +108,7 @@ struct annotate_args { char *fileloc; }; -const struct arch *arch__find(uint16_t e_machine, const char *cpuid); +const struct arch *arch__find(uint16_t e_machine, uint32_t e_flags, const char *cpuid); bool arch__is_x86(const struct arch *arch); bool arch__is_powerpc(const struct arch *arch); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 91c9f7cb9d8c..b791e1b6b2cf 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1220,14 +1220,20 @@ static enum dso_swap_type dso_swap_type__from_elf_data(unsigned char eidata) } /* Reads e_machine from fd, optionally caching data in dso. */ -uint16_t dso__read_e_machine(struct dso *optional_dso, int fd) +uint16_t dso__read_e_machine(struct dso *optional_dso, int fd, uint32_t *e_flags) { uint16_t e_machine = EM_NONE; unsigned char e_ident[EI_NIDENT]; enum dso_swap_type swap_type; + bool need_e_flags; - _Static_assert(offsetof(Elf32_Ehdr, e_ident) == 0, "Unexpected offset"); - _Static_assert(offsetof(Elf64_Ehdr, e_ident) == 0, "Unexpected offset"); + if (e_flags) + *e_flags = 0; + + { + _Static_assert(offsetof(Elf32_Ehdr, e_ident) == 0, "Unexpected offset"); + _Static_assert(offsetof(Elf64_Ehdr, e_ident) == 0, "Unexpected offset"); + } if (pread(fd, &e_ident, sizeof(e_ident), 0) != sizeof(e_ident)) return EM_NONE; // Read failed. @@ -1254,18 +1260,35 @@ uint16_t dso__read_e_machine(struct dso *optional_dso, int fd) { _Static_assert(offsetof(Elf32_Ehdr, e_machine) == 18, "Unexpected offset"); _Static_assert(offsetof(Elf64_Ehdr, e_machine) == 18, "Unexpected offset"); - if (pread(fd, &e_machine, sizeof(e_machine), 18) != sizeof(e_machine)) - return EM_NONE; // e_machine read failed. } + if (pread(fd, &e_machine, sizeof(e_machine), 18) != sizeof(e_machine)) + return EM_NONE; // e_machine read failed. e_machine = DSO_SWAP_TYPE__SWAP(swap_type, uint16_t, e_machine); if (e_machine >= EM_NUM) return EM_NONE; // Bad ELF machine number. +#ifdef NDEBUG + /* In production code the e_flags are only needed on CSKY. */ + need_e_flags = e_flags && e_machine == EM_CSKY; +#else + /* Debug code will always read the e_flags. */ + need_e_flags = e_flags != NULL; +#endif + if (need_e_flags) { + off_t offset = e_ident[EI_CLASS] == ELFCLASS32 + ? offsetof(Elf32_Ehdr, e_flags) + : offsetof(Elf64_Ehdr, e_flags); + + if (pread(fd, e_flags, sizeof(*e_flags), offset) != sizeof(*e_flags)) { + *e_flags = 0; + return EM_NONE; // e_flags read failed. + } + } return e_machine; } -uint16_t dso__e_machine(struct dso *dso, struct machine *machine) +uint16_t dso__e_machine(struct dso *dso, struct machine *machine, uint32_t *e_flags) { uint16_t e_machine = EM_NONE; int fd; @@ -1285,6 +1308,8 @@ uint16_t dso__e_machine(struct dso *dso, struct machine *machine) case DSO_BINARY_TYPE__BPF_IMAGE: case DSO_BINARY_TYPE__OOL: case DSO_BINARY_TYPE__JAVA_JIT: + if (e_flags) + *e_flags = EF_HOST; return EM_HOST; case DSO_BINARY_TYPE__DEBUGLINK: case DSO_BINARY_TYPE__BUILD_ID_CACHE: @@ -1299,6 +1324,8 @@ uint16_t dso__e_machine(struct dso *dso, struct machine *machine) break; case DSO_BINARY_TYPE__NOT_FOUND: default: + if (e_flags) + *e_flags = 0; return EM_NONE; } @@ -1311,7 +1338,9 @@ uint16_t dso__e_machine(struct dso *dso, struct machine *machine) try_to_open_dso(dso, machine); fd = dso__data(dso)->fd; if (fd >= 0) - e_machine = dso__read_e_machine(dso, fd); + e_machine = dso__read_e_machine(dso, fd, e_flags); + else if (e_flags) + *e_flags = 0; mutex_unlock(dso__data_open_lock()); return e_machine; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index a95fee7d634b..ede691e9a249 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -866,8 +866,8 @@ int dso__data_file_size(struct dso *dso, struct machine *machine); off_t dso__data_size(struct dso *dso, struct machine *machine); ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, u64 offset, u8 *data, ssize_t size); -uint16_t dso__read_e_machine(struct dso *optional_dso, int fd); -uint16_t dso__e_machine(struct dso *dso, struct machine *machine); +uint16_t dso__read_e_machine(struct dso *optional_dso, int fd, uint32_t *e_flags); +uint16_t dso__e_machine(struct dso *dso, struct machine *machine, uint32_t *e_flags); ssize_t dso__data_read_addr(struct dso *dso, struct map *map, struct machine *machine, u64 addr, u8 *data, ssize_t size); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index b90edc147796..50f0d16520cc 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -925,7 +925,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, if (al->thread) { machine = maps__machine(thread__maps(al->thread)); - e_machine = thread__e_machine(al->thread, machine); + e_machine = thread__e_machine(al->thread, machine, /*e_flags=*/NULL); } if (set_regs_in_dict(dict, sample, evsel, e_machine)) Py_FatalError("Failed to setting regs in dict"); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c0231bc000e7..0e8a128d7c04 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1124,7 +1124,7 @@ static void dump_sample(struct machine *machine, struct evsel *evsel, union perf if (sample_type & (PERF_SAMPLE_REGS_USER | PERF_SAMPLE_REGS_INTR)) { struct thread *thread = machine__find_thread(machine, sample->pid, sample->pid); - e_machine = thread__e_machine(thread, machine); + e_machine = thread__e_machine(thread, machine, /*e_flags=*/NULL); } printf("(IP, 0x%x): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n", @@ -2965,7 +2965,7 @@ static int perf_session__e_machine_cb(struct thread *thread, uint16_t *result = arg; struct machine *machine = maps__machine(thread__maps(thread)); - *result = thread__e_machine(thread, machine); + *result = thread__e_machine(thread, machine, /*e_flags=*/NULL); return *result != EM_NONE ? 1 : 0; } diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 3642858e6cbc..618f29afb160 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -449,7 +449,7 @@ void thread__find_cpumode_addr_location(struct thread *thread, u64 addr, } } -static uint16_t read_proc_e_machine_for_pid(pid_t pid) +static uint16_t read_proc_e_machine_for_pid(pid_t pid, uint32_t *e_flags) { char path[6 /* "/proc/" */ + 11 /* max length of pid */ + 5 /* "/exe\0" */]; int fd; @@ -458,30 +458,46 @@ static uint16_t read_proc_e_machine_for_pid(pid_t pid) snprintf(path, sizeof(path), "/proc/%d/exe", pid); fd = open(path, O_RDONLY); if (fd >= 0) { - e_machine = dso__read_e_machine(/*optional_dso=*/NULL, fd); + e_machine = dso__read_e_machine(/*optional_dso=*/NULL, fd, e_flags); close(fd); } return e_machine; } -static int thread__e_machine_callback(struct map *map, void *machine) +struct thread__e_machine_callback_args { + struct machine *machine; + uint32_t e_flags; + uint16_t e_machine; +}; + +static int thread__e_machine_callback(struct map *map, void *_args) { + struct thread__e_machine_callback_args *args = _args; struct dso *dso = map__dso(map); - _Static_assert(0 == EM_NONE, "Unexpected EM_NONE"); if (!dso) - return EM_NONE; + return 0; // No dso, continue search. - return dso__e_machine(dso, machine); + args->e_machine = dso__e_machine(dso, args->machine, &args->e_flags); + return args->e_machine != EM_NONE ? 1 /* stop search */ : 0 /* continue search */; } -uint16_t thread__e_machine(struct thread *thread, struct machine *machine) +uint16_t thread__e_machine(struct thread *thread, struct machine *machine, uint32_t *e_flags) { pid_t tid, pid; uint16_t e_machine = RC_CHK_ACCESS(thread)->e_machine; + uint32_t local_e_flags = 0; + struct thread__e_machine_callback_args args = { + .machine = machine, + .e_flags = 0, + .e_machine = EM_NONE, + }; - if (e_machine != EM_NONE) + if (e_machine != EM_NONE) { + if (e_flags) + *e_flags = thread__e_flags(thread); return e_machine; + } tid = thread__tid(thread); pid = thread__pid(thread); @@ -489,18 +505,19 @@ uint16_t thread__e_machine(struct thread *thread, struct machine *machine) struct thread *parent = machine__findnew_thread(machine, pid, pid); if (parent) { - e_machine = thread__e_machine(parent, machine); + e_machine = thread__e_machine(parent, machine, &local_e_flags); thread__put(parent); - thread__set_e_machine(thread, e_machine); - return e_machine; + goto out; } /* Something went wrong, fallback. */ } /* Reading on the PID thread. First try to find from the maps. */ - e_machine = maps__for_each_map(thread__maps(thread), - thread__e_machine_callback, - machine); - if (e_machine == EM_NONE) { + maps__for_each_map(thread__maps(thread), thread__e_machine_callback, &args); + + if (args.e_machine != EM_NONE) { + e_machine = args.e_machine; + local_e_flags = args.e_flags; + } else { /* Maps failed, perhaps we're live with map events disabled. */ bool is_live = machine->machines == NULL; @@ -514,12 +531,18 @@ uint16_t thread__e_machine(struct thread *thread, struct machine *machine) } /* Read from /proc/pid/exe if live. */ if (is_live) - e_machine = read_proc_e_machine_for_pid(pid); + e_machine = read_proc_e_machine_for_pid(pid, &local_e_flags); } - if (e_machine != EM_NONE) +out: + if (e_machine != EM_NONE) { thread__set_e_machine(thread, e_machine); - else + thread__set_e_flags(thread, local_e_flags); + } else { e_machine = EM_HOST; + local_e_flags = EF_HOST; + } + if (e_flags) + *e_flags = local_e_flags; return e_machine; } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 310eaea344bb..f5792d3e8a16 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -60,6 +60,10 @@ DECLARE_RC_STRUCT(thread) { struct srccode_state srccode_state; bool filter; int filter_entry_depth; + /** + * @e_flags: The ELF EF_* associated with the thread. Valid if e_machine != EM_NONE. + */ + uint16_t e_flags; /** * @e_machine: The ELF EM_* associated with the thread. EM_NONE if not * computed. @@ -307,13 +311,23 @@ static inline void thread__set_filter_entry_depth(struct thread *thread, int dep RC_CHK_ACCESS(thread)->filter_entry_depth = depth; } -uint16_t thread__e_machine(struct thread *thread, struct machine *machine); +uint16_t thread__e_machine(struct thread *thread, struct machine *machine, uint32_t *e_flags); static inline void thread__set_e_machine(struct thread *thread, uint16_t e_machine) { RC_CHK_ACCESS(thread)->e_machine = e_machine; } +static inline uint32_t thread__e_flags(const struct thread *thread) +{ + return RC_CHK_ACCESS(thread)->e_flags; +} + +static inline void thread__set_e_flags(struct thread *thread, uint32_t e_flags) +{ + RC_CHK_ACCESS(thread)->e_flags = e_flags; +} + static inline bool thread__lbr_stitch_enable(const struct thread *thread) { diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 9cb0960ef905..3fdcfa06bf22 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -213,7 +213,7 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word * { struct dwfl_ui_thread_info *dwfl_ui_ti = arg; struct unwind_info *ui = dwfl_ui_ti->ui; - uint16_t e_machine = thread__e_machine(ui->thread, ui->machine); + uint16_t e_machine = thread__e_machine(ui->thread, ui->machine, /*e_flags=*/NULL); struct stack_dump *stack = &ui->sample->user_stack; u64 start, end; int offset; @@ -348,7 +348,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, { struct maps *maps = thread__maps(thread); struct machine *machine = maps__machine(maps); - uint16_t e_machine = thread__e_machine(thread, machine); + uint16_t e_machine = thread__e_machine(thread, machine, /*e_flags=*/NULL); struct dwfl_ui_thread_info *dwfl_ui_ti; static struct unwind_info *ui; Dwfl *dwfl; -- cgit v1.2.3 From 0403930f7b1534e383116f7122539873dad3c6a6 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 23 Jan 2026 14:22:08 -0800 Subject: perf perf_regs: Accurately compute register names for CSKY CSKY needs the e_flags to determine the ABI level and know whether additional registers are encoded or not. Wire this up now that the e_flags for a thread can be determined. Signed-off-by: Ian Rogers Cc: Aditya Bodkhe Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Chun-Tse Shao Cc: Guo Ren Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Sergei Trofimovich Cc: Shimin Guo Cc: Stephen Brennan Cc: Swapnil Sapkal Cc: Tianyou Li [ Conditionally define EF_CSKY_ABIMASK and EF_CSKY_ABIV2 for older distros ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 28 +++++++++++++++------- tools/perf/util/parse-regs-options.c | 4 ++-- tools/perf/util/perf-regs-arch/perf_regs_csky.c | 19 ++++++++++----- tools/perf/util/perf_regs.c | 4 ++-- tools/perf/util/perf_regs.h | 4 ++-- .../util/scripting-engines/trace-event-python.c | 17 +++++++------ tools/perf/util/session.c | 24 ++++++++++--------- 7 files changed, 62 insertions(+), 38 deletions(-) (limited to 'tools/perf/util/scripting-engines/trace-event-python.c') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8c0de27a9713..6ec225c697a4 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -717,7 +717,8 @@ out: return 0; } -static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, uint16_t e_machine, +static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, + uint16_t e_machine, uint32_t e_flags, FILE *fp) { unsigned i = 0, r; @@ -730,7 +731,9 @@ static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, uint for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { u64 val = regs->regs[i++]; - printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r, e_machine), val); + printed += fprintf(fp, "%5s:0x%"PRIx64" ", + perf_reg_name(r, e_machine, e_flags), + val); } return printed; @@ -787,23 +790,29 @@ tod_scnprintf(struct perf_script *script, char *buf, int buflen, } static int perf_sample__fprintf_iregs(struct perf_sample *sample, - struct perf_event_attr *attr, uint16_t e_machine, FILE *fp) + struct perf_event_attr *attr, + uint16_t e_machine, + uint32_t e_flags, + FILE *fp) { if (!sample->intr_regs) return 0; return perf_sample__fprintf_regs(perf_sample__intr_regs(sample), - attr->sample_regs_intr, e_machine, fp); + attr->sample_regs_intr, e_machine, e_flags, fp); } static int perf_sample__fprintf_uregs(struct perf_sample *sample, - struct perf_event_attr *attr, uint16_t e_machine, FILE *fp) + struct perf_event_attr *attr, + uint16_t e_machine, + uint32_t e_flags, + FILE *fp) { if (!sample->user_regs) return 0; return perf_sample__fprintf_regs(perf_sample__user_regs(sample), - attr->sample_regs_user, e_machine, fp); + attr->sample_regs_user, e_machine, e_flags, fp); } static int perf_sample__fprintf_start(struct perf_script *script, @@ -2418,6 +2427,7 @@ static void process_event(struct perf_script *script, struct evsel_script *es = evsel->priv; FILE *fp = es->fp; char str[PAGE_SIZE_NAME_LEN]; + uint32_t e_flags; if (output[type].fields == 0) return; @@ -2506,13 +2516,15 @@ static void process_event(struct perf_script *script, if (PRINT_FIELD(IREGS)) { perf_sample__fprintf_iregs(sample, attr, - thread__e_machine(thread, machine, /*e_flags=*/NULL), + thread__e_machine(thread, machine, &e_flags), + e_flags, fp); } if (PRINT_FIELD(UREGS)) { perf_sample__fprintf_uregs(sample, attr, - thread__e_machine(thread, machine, /*e_flags=*/NULL), + thread__e_machine(thread, machine, &e_flags), + e_flags, fp); } diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c index c0d0ef9fd495..8dd35f50f644 100644 --- a/tools/perf/util/parse-regs-options.c +++ b/tools/perf/util/parse-regs-options.c @@ -21,7 +21,7 @@ static void list_perf_regs(FILE *fp, uint64_t mask) if (((1ULL << reg) & mask) == 0) continue; - name = perf_reg_name(reg, EM_HOST); + name = perf_reg_name(reg, EM_HOST, EF_HOST); if (name && (!last_name || strcmp(last_name, name))) fprintf(fp, "%s%s", reg > 0 ? " " : "", name); last_name = name; @@ -39,7 +39,7 @@ static uint64_t name_to_perf_reg_mask(const char *to_match, uint64_t mask) if (((1ULL << reg) & mask) == 0) continue; - name = perf_reg_name(reg, EM_HOST); + name = perf_reg_name(reg, EM_HOST, EF_HOST); if (!name) continue; diff --git a/tools/perf/util/perf-regs-arch/perf_regs_csky.c b/tools/perf/util/perf-regs-arch/perf_regs_csky.c index 75b461ef2eba..95808f93d45b 100644 --- a/tools/perf/util/perf-regs-arch/perf_regs_csky.c +++ b/tools/perf/util/perf-regs-arch/perf_regs_csky.c @@ -1,10 +1,21 @@ // SPDX-License-Identifier: GPL-2.0 - +#include +#ifndef EF_CSKY_ABIMASK +#define EF_CSKY_ABIMASK 0XF0000000 +#endif +#ifndef EF_CSKY_ABIV2 +#define EF_CSKY_ABIV2 0X20000000 +#endif #include "../perf_regs.h" +#undef __CSKYABIV2__ +#define __CSKYABIV2__ 1 // Always want the V2 register definitions. #include "../../arch/csky/include/uapi/asm/perf_regs.h" -const char *__perf_reg_name_csky(int id) +const char *__perf_reg_name_csky(int id, uint32_t e_flags) { + if (id >= PERF_REG_CSKY_EXREGS0 && (e_flags & EF_CSKY_ABIMASK) == EF_CSKY_ABIV2) + return NULL; + switch (id) { case PERF_REG_CSKY_A0: return "a0"; @@ -40,7 +51,6 @@ const char *__perf_reg_name_csky(int id) return "lr"; case PERF_REG_CSKY_PC: return "pc"; -#if defined(__CSKYABIV2__) case PERF_REG_CSKY_EXREGS0: return "exregs0"; case PERF_REG_CSKY_EXREGS1: @@ -77,12 +87,9 @@ const char *__perf_reg_name_csky(int id) return "hi"; case PERF_REG_CSKY_LO: return "lo"; -#endif default: return NULL; } - - return NULL; } uint64_t __perf_reg_ip_csky(void) diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c index cd5acee3dc62..14b7be30ab20 100644 --- a/tools/perf/util/perf_regs.c +++ b/tools/perf/util/perf_regs.c @@ -23,7 +23,7 @@ uint64_t __weak arch__user_reg_mask(void) return 0; } -const char *perf_reg_name(int id, uint16_t e_machine) +const char *perf_reg_name(int id, uint16_t e_machine, uint32_t e_flags) { const char *reg_name = NULL; @@ -35,7 +35,7 @@ const char *perf_reg_name(int id, uint16_t e_machine) reg_name = __perf_reg_name_arm64(id); break; case EM_CSKY: - reg_name = __perf_reg_name_csky(id); + reg_name = __perf_reg_name_csky(id, e_flags); break; case EM_LOONGARCH: reg_name = __perf_reg_name_loongarch(id); diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 2c2a8de6912d..ed7c1b1358fa 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h @@ -16,7 +16,7 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op); uint64_t arch__intr_reg_mask(void); uint64_t arch__user_reg_mask(void); -const char *perf_reg_name(int id, uint16_t e_machine); +const char *perf_reg_name(int id, uint16_t e_machine, uint32_t e_flags); int perf_reg_value(u64 *valp, struct regs_dump *regs, int id); uint64_t perf_arch_reg_ip(uint16_t e_machine); uint64_t perf_arch_reg_sp(uint16_t e_machine); @@ -26,7 +26,7 @@ uint64_t __perf_reg_sp_arm64(void); const char *__perf_reg_name_arm(int id); uint64_t __perf_reg_ip_arm(void); uint64_t __perf_reg_sp_arm(void); -const char *__perf_reg_name_csky(int id); +const char *__perf_reg_name_csky(int id, uint32_t e_flags); uint64_t __perf_reg_ip_csky(void); uint64_t __perf_reg_sp_csky(void); const char *__perf_reg_name_loongarch(int id); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 50f0d16520cc..62c9c73daef5 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -714,7 +714,8 @@ static void set_sample_datasrc_in_dict(PyObject *dict, _PyUnicode_FromString(decode)); } -static void regs_map(struct regs_dump *regs, uint64_t mask, uint16_t e_machine, char *bf, int size) +static void regs_map(struct regs_dump *regs, uint64_t mask, uint16_t e_machine, uint32_t e_flags, + char *bf, int size) { unsigned int i = 0, r; int printed = 0; @@ -732,7 +733,7 @@ static void regs_map(struct regs_dump *regs, uint64_t mask, uint16_t e_machine, printed += scnprintf(bf + printed, size - printed, "%5s:0x%" PRIx64 " ", - perf_reg_name(r, e_machine), val); + perf_reg_name(r, e_machine, e_flags), val); } } @@ -741,7 +742,8 @@ static void regs_map(struct regs_dump *regs, uint64_t mask, uint16_t e_machine, static int set_regs_in_dict(PyObject *dict, struct perf_sample *sample, struct evsel *evsel, - uint16_t e_machine) + uint16_t e_machine, + uint32_t e_flags) { struct perf_event_attr *attr = &evsel->core.attr; @@ -753,7 +755,7 @@ static int set_regs_in_dict(PyObject *dict, if (!bf) return -1; - regs_map(sample->intr_regs, attr->sample_regs_intr, e_machine, bf, size); + regs_map(sample->intr_regs, attr->sample_regs_intr, e_machine, e_flags, bf, size); pydict_set_item_string_decref(dict, "iregs", _PyUnicode_FromString(bf)); @@ -765,7 +767,7 @@ static int set_regs_in_dict(PyObject *dict, if (!bf) return -1; } - regs_map(sample->user_regs, attr->sample_regs_user, e_machine, bf, size); + regs_map(sample->user_regs, attr->sample_regs_user, e_machine, e_flags, bf, size); pydict_set_item_string_decref(dict, "uregs", _PyUnicode_FromString(bf)); @@ -837,6 +839,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, PyObject *dict, *dict_sample, *brstack, *brstacksym; struct machine *machine; uint16_t e_machine = EM_HOST; + uint32_t e_flags = EF_HOST; dict = PyDict_New(); if (!dict) @@ -925,9 +928,9 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, if (al->thread) { machine = maps__machine(thread__maps(al->thread)); - e_machine = thread__e_machine(al->thread, machine, /*e_flags=*/NULL); + e_machine = thread__e_machine(al->thread, machine, &e_flags); } - if (set_regs_in_dict(dict, sample, evsel, e_machine)) + if (set_regs_in_dict(dict, sample, evsel, e_machine, e_flags)) Py_FatalError("Failed to setting regs in dict"); return dict; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0e8a128d7c04..7c7c65b0f536 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -959,7 +959,7 @@ static void branch_stack__printf(struct perf_sample *sample, } } -static void regs_dump__printf(u64 mask, u64 *regs, uint16_t e_machine) +static void regs_dump__printf(u64 mask, u64 *regs, uint16_t e_machine, uint32_t e_flags) { unsigned rid, i = 0; @@ -967,7 +967,7 @@ static void regs_dump__printf(u64 mask, u64 *regs, uint16_t e_machine) u64 val = regs[i++]; printf(".... %-5s 0x%016" PRIx64 "\n", - perf_reg_name(rid, e_machine), val); + perf_reg_name(rid, e_machine, e_flags), val); } } @@ -985,7 +985,8 @@ static inline const char *regs_dump_abi(struct regs_dump *d) return regs_abi[d->abi]; } -static void regs__printf(const char *type, struct regs_dump *regs, uint16_t e_machine) +static void regs__printf(const char *type, struct regs_dump *regs, + uint16_t e_machine, uint32_t e_flags) { u64 mask = regs->mask; @@ -994,10 +995,10 @@ static void regs__printf(const char *type, struct regs_dump *regs, uint16_t e_ma mask, regs_dump_abi(regs)); - regs_dump__printf(mask, regs->regs, e_machine); + regs_dump__printf(mask, regs->regs, e_machine, e_flags); } -static void regs_user__printf(struct perf_sample *sample, uint16_t e_machine) +static void regs_user__printf(struct perf_sample *sample, uint16_t e_machine, uint32_t e_flags) { struct regs_dump *user_regs; @@ -1007,10 +1008,10 @@ static void regs_user__printf(struct perf_sample *sample, uint16_t e_machine) user_regs = perf_sample__user_regs(sample); if (user_regs->regs) - regs__printf("user", user_regs, e_machine); + regs__printf("user", user_regs, e_machine, e_flags); } -static void regs_intr__printf(struct perf_sample *sample, uint16_t e_machine) +static void regs_intr__printf(struct perf_sample *sample, uint16_t e_machine, uint32_t e_flags) { struct regs_dump *intr_regs; @@ -1020,7 +1021,7 @@ static void regs_intr__printf(struct perf_sample *sample, uint16_t e_machine) intr_regs = perf_sample__intr_regs(sample); if (intr_regs->regs) - regs__printf("intr", intr_regs, e_machine); + regs__printf("intr", intr_regs, e_machine, e_flags); } static void stack_user__printf(struct stack_dump *dump) @@ -1115,6 +1116,7 @@ static void dump_sample(struct machine *machine, struct evsel *evsel, union perf u64 sample_type; char str[PAGE_SIZE_NAME_LEN]; uint16_t e_machine = EM_NONE; + uint32_t e_flags = 0; if (!dump_trace) return; @@ -1124,7 +1126,7 @@ static void dump_sample(struct machine *machine, struct evsel *evsel, union perf if (sample_type & (PERF_SAMPLE_REGS_USER | PERF_SAMPLE_REGS_INTR)) { struct thread *thread = machine__find_thread(machine, sample->pid, sample->pid); - e_machine = thread__e_machine(thread, machine, /*e_flags=*/NULL); + e_machine = thread__e_machine(thread, machine, &e_flags); } printf("(IP, 0x%x): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n", @@ -1138,10 +1140,10 @@ static void dump_sample(struct machine *machine, struct evsel *evsel, union perf branch_stack__printf(sample, evsel); if (sample_type & PERF_SAMPLE_REGS_USER) - regs_user__printf(sample, e_machine); + regs_user__printf(sample, e_machine, e_flags); if (sample_type & PERF_SAMPLE_REGS_INTR) - regs_intr__printf(sample, e_machine); + regs_intr__printf(sample, e_machine, e_flags); if (sample_type & PERF_SAMPLE_STACK_USER) stack_user__printf(&sample->user_stack); -- cgit v1.2.3 From 84cb36da81413c2dff805150b9f4db1524460269 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 3 Feb 2026 10:26:40 -0800 Subject: perf thread: Don't require machine to compute the e_machine The machine can be calculated from a thread via its maps. Don't require the machine argument to simplify callers and also to delay computing the machine until a little later. Signed-off-by: Ian Rogers Cc: Aditya Bodkhe Cc: Adrian Hunter Cc: Albert Ou Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andi Kleen Cc: Andrew Jones Cc: Anubhav Shelat Cc: Anup Patel Cc: Athira Rajeev Cc: Blake Jones Cc: Chun-Tse Shao Cc: Dapeng Mi Cc: Dmitriy Vyukov Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Leo Yan Cc: Namhyung Kim Cc: Palmer Dabbelt Cc: Paul Walmsley Cc: Peter Zijlstra Cc: Quan Zhou Cc: Shimin Guo Cc: Swapnil Sapkal Cc: Thomas Falcon Cc: Will Deacon Cc: Yunseong Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/scripting-engines/trace-event-python.c | 8 +++----- tools/perf/util/session.c | 3 +-- tools/perf/util/thread.c | 5 +++++ 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/scripting-engines/trace-event-python.c') diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 62c9c73daef5..2b0df7bd9a46 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -837,7 +837,6 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, PyObject *callchain) { PyObject *dict, *dict_sample, *brstack, *brstacksym; - struct machine *machine; uint16_t e_machine = EM_HOST; uint32_t e_flags = EF_HOST; @@ -926,10 +925,9 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, PyLong_FromUnsignedLongLong(sample->cyc_cnt)); } - if (al->thread) { - machine = maps__machine(thread__maps(al->thread)); - e_machine = thread__e_machine(al->thread, machine, &e_flags); - } + if (al->thread) + e_machine = thread__e_machine(al->thread, /*machine=*/NULL, &e_flags); + if (set_regs_in_dict(dict, sample, evsel, e_machine, e_flags)) Py_FatalError("Failed to setting regs in dict"); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 53f51c3f9603..4b465abfa36c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2972,9 +2972,8 @@ struct perf_session__e_machine_cb_args { static int perf_session__e_machine_cb(struct thread *thread, void *_args) { struct perf_session__e_machine_cb_args *args = _args; - struct machine *machine = maps__machine(thread__maps(thread)); - args->e_machine = thread__e_machine(thread, machine, &args->e_flags); + args->e_machine = thread__e_machine(thread, /*machine=*/NULL, &args->e_flags); return args->e_machine != EM_NONE ? 1 : 0; } diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 618f29afb160..22be77225bb0 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -499,6 +499,11 @@ uint16_t thread__e_machine(struct thread *thread, struct machine *machine, uint3 return e_machine; } + if (machine == NULL) { + struct maps *maps = thread__maps(thread); + + machine = maps__machine(maps); + } tid = thread__tid(thread); pid = thread__pid(thread); if (pid != tid) { -- cgit v1.2.3