[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260123222209.1181249-2-irogers@google.com>
Date: Fri, 23 Jan 2026 14:22:06 -0800
From: Ian Rogers <irogers@...gle.com>
To: Peter Zijlstra <peterz@...radead.org>, Ingo Molnar <mingo@...hat.com>,
Arnaldo Carvalho de Melo <acme@...nel.org>, Namhyung Kim <namhyung@...nel.org>,
Alexander Shishkin <alexander.shishkin@...ux.intel.com>, Jiri Olsa <jolsa@...nel.org>,
Ian Rogers <irogers@...gle.com>, Adrian Hunter <adrian.hunter@...el.com>,
James Clark <james.clark@...aro.org>, Guo Ren <guoren@...nel.org>,
Tianyou Li <tianyou.li@...el.com>, Athira Rajeev <atrajeev@...ux.ibm.com>,
Stephen Brennan <stephen.s.brennan@...cle.com>, Aditya Bodkhe <aditya.b1@...ux.ibm.com>,
Chun-Tse Shao <ctshao@...gle.com>, Swapnil Sapkal <swapnil.sapkal@....com>,
Howard Chu <howardchu95@...il.com>, Sergei Trofimovich <slyich@...il.com>,
Shimin Guo <shimin.guo@...dio.com>, linux-perf-users@...r.kernel.org,
linux-kernel@...r.kernel.org, linux-csky@...r.kernel.org
Subject: [PATCH v1 1/4] perf dso: Factor out e_machine reading for use in thread
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@...gle.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
Powered by blists - more mailing lists