]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf dso: Factor out e_machine reading for use in thread
authorIan Rogers <irogers@google.com>
Fri, 23 Jan 2026 22:22:06 +0000 (14:22 -0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 26 Jan 2026 21:21:20 +0000 (18:21 -0300)
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>
Cc: Aditya Bodkhe <aditya.b1@linux.ibm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Chun-Tse Shao <ctshao@google.com>
Cc: Guo Ren <guoren@kernel.org>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sergei Trofimovich <slyich@gmail.com>
Cc: Shimin Guo <shimin.guo@skydio.com>
Cc: Stephen Brennan <stephen.s.brennan@oracle.com>
Cc: Swapnil Sapkal <swapnil.sapkal@amd.com>
Cc: Tianyou Li <tianyou.li@intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/thread.c

index 3b272a6fae24289047841934f92984013c34c171..91c9f7cb9d8ce8afdcf94efe76d4672e878f9477 100644 (file)
@@ -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;
 }
 
index ac725bc8ea749dea3bd562a8f4f5fbaafcd75f69..a95fee7d634b3105cff57aed76af254d1c7dbb42 100644 (file)
@@ -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,
index aa9c58bbf9d32c3a4f12e5c8ba210b4d958ff450..3642858e6cbc33e2ac80f3a7f0e157b116f5edf2 100644 (file)
@@ -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;