* [PATCH v1 0/4] perf e_flags support for CSKY
@ 2026-01-23 22:22 Ian Rogers
2026-01-23 22:22 ` [PATCH v1 1/4] perf dso: Factor out e_machine reading for use in thread Ian Rogers
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Ian Rogers @ 2026-01-23 22:22 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Guo Ren, Tianyou Li, Athira Rajeev,
Stephen Brennan, Aditya Bodkhe, Chun-Tse Shao, Swapnil Sapkal,
Howard Chu, Sergei Trofimovich, Shimin Guo, linux-perf-users,
linux-kernel, linux-csky
The ELF machine type for CSKY is insufficent to describe the perf
registers, the e_flags from the ELF header is also required. Expand
the thread__e_machine and associated APIs to optionally fill in an
e_flags output field. For uses in `perf trace` the e_flags doesn't
matter and the e_flags needn't be computed. For `perf annotate` the
e_flags are computed and passed around, however, this is optimized so
the e_flags are only read for EM_CSKY. Call chain unwinding needs to
know about perf registers during recording and in the unwinding logic,
this is similarly wired up with the e_flags.
Ian Rogers (4):
perf dso: Factor out e_machine reading for use in thread
perf thread: Add optional e_flags output argument to thread__e_machine
perf perf_regs: Accurately compute register names for CSKY
perf unwind-libdw: Wire up e_flags for CSKY
tools/perf/builtin-script.c | 38 +++--
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 | 139 ++++++++++++------
tools/perf/util/dso.h | 12 +-
tools/perf/util/parse-regs-options.c | 4 +-
.../perf/util/perf-regs-arch/perf_regs_csky.c | 13 +-
tools/perf/util/perf_regs.c | 4 +-
tools/perf/util/perf_regs.h | 4 +-
.../scripting-engines/trace-event-python.c | 17 ++-
tools/perf/util/session.c | 26 ++--
tools/perf/util/thread.c | 62 +++++---
tools/perf/util/thread.h | 16 +-
tools/perf/util/unwind-libdw.c | 9 +-
tools/perf/util/unwind-libdw.h | 1 +
17 files changed, 244 insertions(+), 125 deletions(-)
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v1 1/4] perf dso: Factor out e_machine reading for use in thread
2026-01-23 22:22 [PATCH v1 0/4] perf e_flags support for CSKY Ian Rogers
@ 2026-01-23 22:22 ` Ian Rogers
2026-01-23 22:22 ` [PATCH v1 2/4] perf thread: Add optional e_flags output argument to thread__e_machine Ian Rogers
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Ian Rogers @ 2026-01-23 22:22 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Guo Ren, Tianyou Li, Athira Rajeev,
Stephen Brennan, Aditya Bodkhe, Chun-Tse Shao, Swapnil Sapkal,
Howard Chu, Sergei Trofimovich, Shimin Guo, linux-perf-users,
linux-kernel, linux-csky
Factor out the resilient e_machine reading code in dso so that it may
be used in thread. As there is no dso in that case, make the dso
optional. This makes some minor other changes as the swap type from
the dso cannot be ascertained.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/dso.c | 110 ++++++++++++++++++++++++---------------
tools/perf/util/dso.h | 10 ++--
tools/perf/util/thread.c | 5 +-
3 files changed, 75 insertions(+), 50 deletions(-)
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 3b272a6fae24..91c9f7cb9d8c 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1203,6 +1203,68 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
return data_read_write_offset(dso, machine, offset, data, size, true);
}
+static enum dso_swap_type dso_swap_type__from_elf_data(unsigned char eidata)
+{
+ static const unsigned int endian = 1;
+
+ switch (eidata) {
+ case ELFDATA2LSB:
+ /* We are big endian, DSO is little endian. */
+ return (*(unsigned char const *)&endian != 1) ? DSO_SWAP__YES : DSO_SWAP__NO;
+ case ELFDATA2MSB:
+ /* We are little endian, DSO is big endian. */
+ return (*(unsigned char const *)&endian != 0) ? DSO_SWAP__YES : DSO_SWAP__NO;
+ default:
+ return DSO_SWAP__UNSET;
+ }
+}
+
+/* Reads e_machine from fd, optionally caching data in dso. */
+uint16_t dso__read_e_machine(struct dso *optional_dso, int fd)
+{
+ uint16_t e_machine = EM_NONE;
+ unsigned char e_ident[EI_NIDENT];
+ enum dso_swap_type swap_type;
+
+ _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.
+
+ if (memcmp(e_ident, ELFMAG, SELFMAG) != 0)
+ return EM_NONE; // Not an ELF file.
+
+ if (e_ident[EI_CLASS] == ELFCLASSNONE || e_ident[EI_CLASS] >= ELFCLASSNUM)
+ return EM_NONE; // Bad ELF class (32 or 64-bit objects).
+
+ if (e_ident[EI_VERSION] != EV_CURRENT)
+ return EM_NONE; // Bad ELF version.
+
+ swap_type = dso_swap_type__from_elf_data(e_ident[EI_DATA]);
+ if (swap_type == DSO_SWAP__UNSET)
+ return EM_NONE; // Bad ELF data encoding.
+
+ /* Cache the need for swapping. */
+ if (optional_dso) {
+ assert(dso__needs_swap(optional_dso) == DSO_SWAP__UNSET ||
+ dso__needs_swap(optional_dso) == swap_type);
+ dso__set_needs_swap(optional_dso, swap_type);
+ }
+
+ {
+ _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.
+ }
+
+ e_machine = DSO_SWAP_TYPE__SWAP(swap_type, uint16_t, e_machine);
+ if (e_machine >= EM_NUM)
+ return EM_NONE; // Bad ELF machine number.
+
+ return e_machine;
+}
+
uint16_t dso__e_machine(struct dso *dso, struct machine *machine)
{
uint16_t e_machine = EM_NONE;
@@ -1248,30 +1310,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) {
- unsigned char e_ident[EI_NIDENT];
-
- _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) &&
- memcmp(e_ident, ELFMAG, SELFMAG) == 0 &&
- e_ident[EI_CLASS] > ELFCLASSNONE && e_ident[EI_CLASS] < ELFCLASSNUM &&
- e_ident[EI_DATA] > ELFDATANONE && e_ident[EI_DATA] < ELFDATANUM &&
- e_ident[EI_VERSION] == EV_CURRENT) {
- _Static_assert(offsetof(Elf32_Ehdr, e_machine) == 18, "Unexpected offset");
- _Static_assert(offsetof(Elf64_Ehdr, e_machine) == 18, "Unexpected offset");
-
- if (dso__needs_swap(dso) == DSO_SWAP__UNSET)
- dso__swap_init(dso, e_ident[EI_DATA]);
-
- if (dso__needs_swap(dso) != DSO_SWAP__UNSET &&
- pread(fd, &e_machine, sizeof(e_machine), 18) == sizeof(e_machine) &&
- e_machine < EM_NUM)
- e_machine = DSO__SWAP(dso, uint16_t, e_machine);
- else
- e_machine = EM_NONE;
- }
- }
+ if (fd >= 0)
+ e_machine = dso__read_e_machine(dso, fd);
+
mutex_unlock(dso__data_open_lock());
return e_machine;
}
@@ -1656,28 +1697,13 @@ void dso__put(struct dso *dso)
int dso__swap_init(struct dso *dso, unsigned char eidata)
{
- static unsigned int const endian = 1;
-
- dso__set_needs_swap(dso, DSO_SWAP__NO);
+ enum dso_swap_type type = dso_swap_type__from_elf_data(eidata);
- switch (eidata) {
- case ELFDATA2LSB:
- /* We are big endian, DSO is little endian. */
- if (*(unsigned char const *)&endian != 1)
- dso__set_needs_swap(dso, DSO_SWAP__YES);
- break;
-
- case ELFDATA2MSB:
- /* We are little endian, DSO is big endian. */
- if (*(unsigned char const *)&endian != 0)
- dso__set_needs_swap(dso, DSO_SWAP__YES);
- break;
-
- default:
+ dso__set_needs_swap(dso, type);
+ if (type == DSO_SWAP__UNSET) {
pr_err("unrecognized DSO data encoding %d\n", eidata);
return -EINVAL;
}
-
return 0;
}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ac725bc8ea74..a95fee7d634b 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -160,12 +160,11 @@ enum dso_load_errno {
__DSO_LOAD_ERRNO__END,
};
-#define DSO__SWAP(dso, type, val) \
+#define DSO_SWAP_TYPE__SWAP(swap_type, type, val) \
({ \
type ____r = val; \
- enum dso_swap_type ___dst = dso__needs_swap(dso); \
- BUG_ON(___dst == DSO_SWAP__UNSET); \
- if (___dst == DSO_SWAP__YES) { \
+ BUG_ON(swap_type == DSO_SWAP__UNSET); \
+ if (swap_type == DSO_SWAP__YES) { \
switch (sizeof(____r)) { \
case 2: \
____r = bswap_16(val); \
@@ -183,6 +182,8 @@ enum dso_load_errno {
____r; \
})
+#define DSO__SWAP(dso, type, val) DSO_SWAP_TYPE__SWAP(dso__needs_swap(dso), type, val)
+
#define DSO__DATA_CACHE_SIZE 4096
#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
@@ -865,6 +866,7 @@ 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);
ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
struct machine *machine, u64 addr,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index aa9c58bbf9d3..3642858e6cbc 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -458,10 +458,7 @@ 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) {
- _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))
- e_machine = EM_NONE;
+ e_machine = dso__read_e_machine(/*optional_dso=*/NULL, fd);
close(fd);
}
return e_machine;
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v1 2/4] perf thread: Add optional e_flags output argument to thread__e_machine
2026-01-23 22:22 [PATCH v1 0/4] perf e_flags support for CSKY Ian Rogers
2026-01-23 22:22 ` [PATCH v1 1/4] perf dso: Factor out e_machine reading for use in thread Ian Rogers
@ 2026-01-23 22:22 ` Ian Rogers
2026-01-23 22:22 ` [PATCH v1 3/4] perf perf_regs: Accurately compute register names for CSKY Ian Rogers
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Ian Rogers @ 2026-01-23 22:22 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Guo Ren, Tianyou Li, Athira Rajeev,
Stephen Brennan, Aditya Bodkhe, Chun-Tse Shao, Swapnil Sapkal,
Howard Chu, Sergei Trofimovich, Shimin Guo, linux-perf-users,
linux-kernel, linux-csky
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 <irogers@google.com>
---
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 +-
.../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(-)
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;
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v1 3/4] perf perf_regs: Accurately compute register names for CSKY
2026-01-23 22:22 [PATCH v1 0/4] perf e_flags support for CSKY Ian Rogers
2026-01-23 22:22 ` [PATCH v1 1/4] perf dso: Factor out e_machine reading for use in thread Ian Rogers
2026-01-23 22:22 ` [PATCH v1 2/4] perf thread: Add optional e_flags output argument to thread__e_machine Ian Rogers
@ 2026-01-23 22:22 ` Ian Rogers
2026-01-23 22:22 ` [PATCH v1 4/4] perf unwind-libdw: Wire up e_flags " Ian Rogers
2026-01-26 20:51 ` [PATCH v1 0/4] perf e_flags support " Arnaldo Carvalho de Melo
4 siblings, 0 replies; 6+ messages in thread
From: Ian Rogers @ 2026-01-23 22:22 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Guo Ren, Tianyou Li, Athira Rajeev,
Stephen Brennan, Aditya Bodkhe, Chun-Tse Shao, Swapnil Sapkal,
Howard Chu, Sergei Trofimovich, Shimin Guo, linux-perf-users,
linux-kernel, linux-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 <irogers@google.com>
---
tools/perf/builtin-script.c | 28 +++++++++++++------
tools/perf/util/parse-regs-options.c | 4 +--
.../perf/util/perf-regs-arch/perf_regs_csky.c | 13 +++++----
tools/perf/util/perf_regs.c | 4 +--
tools/perf/util/perf_regs.h | 4 +--
.../scripting-engines/trace-event-python.c | 17 ++++++-----
tools/perf/util/session.c | 24 ++++++++--------
7 files changed, 56 insertions(+), 38 deletions(-)
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 @@ static int perf_session__check_output_opt(struct perf_session *session)
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..d685b3fe418f 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,15 @@
// SPDX-License-Identifier: GPL-2.0
-
+#include <elf.h>
#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 +45,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 +81,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);
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v1 4/4] perf unwind-libdw: Wire up e_flags for CSKY
2026-01-23 22:22 [PATCH v1 0/4] perf e_flags support for CSKY Ian Rogers
` (2 preceding siblings ...)
2026-01-23 22:22 ` [PATCH v1 3/4] perf perf_regs: Accurately compute register names for CSKY Ian Rogers
@ 2026-01-23 22:22 ` Ian Rogers
2026-01-26 20:51 ` [PATCH v1 0/4] perf e_flags support " Arnaldo Carvalho de Melo
4 siblings, 0 replies; 6+ messages in thread
From: Ian Rogers @ 2026-01-23 22:22 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Guo Ren, Tianyou Li, Athira Rajeev,
Stephen Brennan, Aditya Bodkhe, Chun-Tse Shao, Swapnil Sapkal,
Howard Chu, Sergei Trofimovich, Shimin Guo, linux-perf-users,
linux-kernel, linux-csky
Wire up the e_flags now it can be read for a thread. The e_flags
encode the CSKY ABI level and this can impact which perf registers
need setting up for unwinding.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/unwind-libdw.c | 9 +++++----
tools/perf/util/unwind-libdw.h | 1 +
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 3fdcfa06bf22..05e8e68bd49c 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -213,7 +213,6 @@ 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, /*e_flags=*/NULL);
struct stack_dump *stack = &ui->sample->user_stack;
u64 start, end;
int offset;
@@ -223,7 +222,7 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
return false;
ret = perf_reg_value(&start, ui->sample->user_regs,
- perf_arch_reg_sp(e_machine));
+ perf_arch_reg_sp(ui->e_machine));
if (ret)
return false;
@@ -260,7 +259,7 @@ static bool libdw_set_initial_registers(Dwfl_Thread *thread, void *arg)
int max_dwarf_reg = 0;
bool ret;
uint16_t e_machine = ui->e_machine;
- int e_flags = 0;
+ int e_flags = ui->e_flags;
uint64_t ip_perf_reg = perf_arch_reg_ip(e_machine);
Dwarf_Word val = 0;
@@ -348,7 +347,8 @@ 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, /*e_flags=*/NULL);
+ uint32_t e_flags = 0;
+ uint16_t e_machine = thread__e_machine(thread, machine, &e_flags);
struct dwfl_ui_thread_info *dwfl_ui_ti;
static struct unwind_info *ui;
Dwfl *dwfl;
@@ -370,6 +370,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
.arg = arg,
.max_stack = max_stack,
.e_machine = e_machine,
+ .e_flags = e_flags,
.best_effort = best_effort
};
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
index 3dec0ab8bd50..6423bf5a2492 100644
--- a/tools/perf/util/unwind-libdw.h
+++ b/tools/perf/util/unwind-libdw.h
@@ -20,6 +20,7 @@ struct unwind_info {
void *arg;
int max_stack;
int idx;
+ uint32_t e_flags;
uint16_t e_machine;
bool best_effort;
struct unwind_entry entries[];
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v1 0/4] perf e_flags support for CSKY
2026-01-23 22:22 [PATCH v1 0/4] perf e_flags support for CSKY Ian Rogers
` (3 preceding siblings ...)
2026-01-23 22:22 ` [PATCH v1 4/4] perf unwind-libdw: Wire up e_flags " Ian Rogers
@ 2026-01-26 20:51 ` Arnaldo Carvalho de Melo
4 siblings, 0 replies; 6+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-01-26 20:51 UTC (permalink / raw)
To: Ian Rogers
Cc: Peter Zijlstra, Ingo Molnar, Namhyung Kim, Alexander Shishkin,
Jiri Olsa, Adrian Hunter, James Clark, Guo Ren, Tianyou Li,
Athira Rajeev, Stephen Brennan, Aditya Bodkhe, Chun-Tse Shao,
Swapnil Sapkal, Howard Chu, Sergei Trofimovich, Shimin Guo,
linux-perf-users, linux-kernel, linux-csky
On Fri, Jan 23, 2026 at 02:22:05PM -0800, Ian Rogers wrote:
> The ELF machine type for CSKY is insufficent to describe the perf
> registers, the e_flags from the ELF header is also required. Expand
> the thread__e_machine and associated APIs to optionally fill in an
> e_flags output field. For uses in `perf trace` the e_flags doesn't
> matter and the e_flags needn't be computed. For `perf annotate` the
> e_flags are computed and passed around, however, this is optimized so
> the e_flags are only read for EM_CSKY. Call chain unwinding needs to
> know about perf registers during recording and in the unwinding logic,
> this is similarly wired up with the e_flags.
>
> Ian Rogers (4):
> perf dso: Factor out e_machine reading for use in thread
> perf thread: Add optional e_flags output argument to thread__e_machine
> perf perf_regs: Accurately compute register names for CSKY
> perf unwind-libdw: Wire up e_flags for CSKY
Thanks, applied to perf-tools-next,
- Arnaldo
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-01-26 20:51 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-23 22:22 [PATCH v1 0/4] perf e_flags support for CSKY Ian Rogers
2026-01-23 22:22 ` [PATCH v1 1/4] perf dso: Factor out e_machine reading for use in thread Ian Rogers
2026-01-23 22:22 ` [PATCH v1 2/4] perf thread: Add optional e_flags output argument to thread__e_machine Ian Rogers
2026-01-23 22:22 ` [PATCH v1 3/4] perf perf_regs: Accurately compute register names for CSKY Ian Rogers
2026-01-23 22:22 ` [PATCH v1 4/4] perf unwind-libdw: Wire up e_flags " Ian Rogers
2026-01-26 20:51 ` [PATCH v1 0/4] perf e_flags support " Arnaldo Carvalho de Melo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox