mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
perf env, dso, thread: Add _endian variants for e_machine helpers
Add perf_arch_is_big_endian(), dso__read_e_machine_endian(), dso__e_machine_endian(), and thread__e_machine_endian() to support bi-endianness and cross-architecture analysis without breaking the existing API. These helpers allow querying the absolute endianness of a DSO or thread, which is required for tools like Capstone that need to set the correct disassembly mode. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers <irogers@google.com> Acked-by: Namhyung Kim <namhyung@kernel.org> Cc: Alexander Gordeev <agordeev@linux.ibm.com> Cc: Heiko Carstens <hca@linux.ibm.com> Cc: Honglei Wang <jameshongleiwang@126.com> Cc: Jan Polensky <japo@linux.ibm.com> Cc: Sumanth Korikkar <sumanthk@linux.ibm.com> Cc: Thomas Richter <tmricht@linux.ibm.com> Cc: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
4ccbc91df9
commit
f7c6e4b99d
|
|
@ -1220,7 +1220,8 @@ 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, uint32_t *e_flags)
|
||||
uint16_t dso__read_e_machine_endian(struct dso *optional_dso, int fd, uint32_t *e_flags,
|
||||
bool *is_big_endian)
|
||||
{
|
||||
uint16_t e_machine = EM_NONE;
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
|
|
@ -1250,6 +1251,9 @@ uint16_t dso__read_e_machine(struct dso *optional_dso, int fd, uint32_t *e_flags
|
|||
if (swap_type == DSO_SWAP__UNSET)
|
||||
return EM_NONE; // Bad ELF data encoding.
|
||||
|
||||
if (is_big_endian)
|
||||
*is_big_endian = (e_ident[EI_DATA] == ELFDATA2MSB);
|
||||
|
||||
/* Cache the need for swapping. */
|
||||
if (optional_dso) {
|
||||
assert(dso__needs_swap(optional_dso) == DSO_SWAP__UNSET ||
|
||||
|
|
@ -1288,7 +1292,8 @@ uint16_t dso__read_e_machine(struct dso *optional_dso, int fd, uint32_t *e_flags
|
|||
return e_machine;
|
||||
}
|
||||
|
||||
uint16_t dso__e_machine(struct dso *dso, struct machine *machine, uint32_t *e_flags)
|
||||
uint16_t dso__e_machine_endian(struct dso *dso, struct machine *machine, uint32_t *e_flags,
|
||||
bool *is_big_endian)
|
||||
{
|
||||
uint16_t e_machine = EM_NONE;
|
||||
int fd;
|
||||
|
|
@ -1308,9 +1313,11 @@ uint16_t dso__e_machine(struct dso *dso, struct machine *machine, uint32_t *e_fl
|
|||
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;
|
||||
if (is_big_endian) {
|
||||
*is_big_endian = perf_arch_is_big_endian(
|
||||
machine && machine->env ? perf_env__arch(machine->env) : NULL);
|
||||
}
|
||||
return perf_env__e_machine(machine ? machine->env : NULL, e_flags);
|
||||
case DSO_BINARY_TYPE__DEBUGLINK:
|
||||
case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
||||
case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
|
||||
|
|
@ -1338,7 +1345,7 @@ uint16_t dso__e_machine(struct dso *dso, struct machine *machine, uint32_t *e_fl
|
|||
try_to_open_dso(dso, machine);
|
||||
fd = dso__data(dso)->fd;
|
||||
if (fd >= 0)
|
||||
e_machine = dso__read_e_machine(dso, fd, e_flags);
|
||||
e_machine = dso__read_e_machine_endian(dso, fd, e_flags, is_big_endian);
|
||||
else if (e_flags)
|
||||
*e_flags = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -866,8 +866,18 @@ 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, uint32_t *e_flags);
|
||||
uint16_t dso__e_machine(struct dso *dso, struct machine *machine, uint32_t *e_flags);
|
||||
uint16_t dso__read_e_machine_endian(struct dso *optional_dso, int fd, uint32_t *e_flags,
|
||||
bool *is_big_endian);
|
||||
static inline uint16_t dso__read_e_machine(struct dso *optional_dso, int fd, uint32_t *e_flags)
|
||||
{
|
||||
return dso__read_e_machine_endian(optional_dso, fd, e_flags, NULL);
|
||||
}
|
||||
uint16_t dso__e_machine_endian(struct dso *dso, struct machine *machine, uint32_t *e_flags,
|
||||
bool *is_big_endian);
|
||||
static inline uint16_t dso__e_machine(struct dso *dso, struct machine *machine, uint32_t *e_flags)
|
||||
{
|
||||
return dso__e_machine_endian(dso, machine, e_flags, NULL);
|
||||
}
|
||||
ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
|
||||
struct machine *machine, u64 addr,
|
||||
u8 *data, ssize_t size);
|
||||
|
|
|
|||
|
|
@ -342,6 +342,22 @@ int perf_env__kernel_is_64_bit(struct perf_env *env)
|
|||
return env->kernel_is_64_bit;
|
||||
}
|
||||
|
||||
bool perf_arch_is_big_endian(const char *arch)
|
||||
{
|
||||
if (!arch)
|
||||
return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
|
||||
|
||||
if (str_ends_with(arch, "_be") || !strcmp(arch, "sparc") || !strcmp(arch, "sparc64") ||
|
||||
!strcmp(arch, "s390") || !strcmp(arch, "s390x") || !strcmp(arch, "powerpc") ||
|
||||
!strcmp(arch, "ppc") || !strcmp(arch, "ppc64") ||
|
||||
!strcmp(arch, "mips") || !strcmp(arch, "mips64") || !strcmp(arch, "parisc") ||
|
||||
!strcmp(arch, "parisc64") || !strcmp(arch, "m68k") ||
|
||||
!strcmp(arch, "armeb") || !strcmp(arch, "mipseb") || !strcmp(arch, "mips64eb"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ void free_cpu_domain_info(struct cpu_domain_map **cd_map, u32 schedstat_version,
|
|||
void perf_env__exit(struct perf_env *env);
|
||||
|
||||
int perf_env__kernel_is_64_bit(struct perf_env *env);
|
||||
bool perf_arch_is_big_endian(const char *arch);
|
||||
|
||||
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
|
|||
thread__set_cpu(thread, -1);
|
||||
thread__set_guest_cpu(thread, -1);
|
||||
thread__set_e_machine(thread, EM_NONE);
|
||||
thread__set_e_is_big_endian(thread, false);
|
||||
thread__set_lbr_stitch_enable(thread, false);
|
||||
INIT_LIST_HEAD(thread__namespaces_list(thread));
|
||||
INIT_LIST_HEAD(thread__comm_list(thread));
|
||||
|
|
@ -429,7 +430,7 @@ void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
|
|||
}
|
||||
}
|
||||
|
||||
static uint16_t read_proc_e_machine_for_pid(pid_t pid, uint32_t *e_flags)
|
||||
static uint16_t read_proc_e_machine_for_pid(pid_t pid, uint32_t *e_flags, bool *is_big_endian)
|
||||
{
|
||||
char path[6 /* "/proc/" */ + 11 /* max length of pid */ + 5 /* "/exe\0" */];
|
||||
int fd;
|
||||
|
|
@ -438,7 +439,8 @@ static uint16_t read_proc_e_machine_for_pid(pid_t pid, uint32_t *e_flags)
|
|||
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_flags);
|
||||
e_machine = dso__read_e_machine_endian(/*optional_dso=*/NULL, fd, e_flags,
|
||||
is_big_endian);
|
||||
close(fd);
|
||||
}
|
||||
return e_machine;
|
||||
|
|
@ -448,6 +450,7 @@ struct thread__e_machine_callback_args {
|
|||
struct machine *machine;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_machine;
|
||||
bool is_big_endian;
|
||||
};
|
||||
|
||||
static int thread__e_machine_callback(struct map *map, void *_args)
|
||||
|
|
@ -458,24 +461,38 @@ static int thread__e_machine_callback(struct map *map, void *_args)
|
|||
if (!dso)
|
||||
return 0; // No dso, continue search.
|
||||
|
||||
args->e_machine = dso__e_machine(dso, args->machine, &args->e_flags);
|
||||
args->e_machine =
|
||||
dso__e_machine_endian(dso, args->machine, &args->e_flags, &args->is_big_endian);
|
||||
return args->e_machine != EM_NONE ? 1 /* stop search */ : 0 /* continue search */;
|
||||
}
|
||||
|
||||
uint16_t thread__e_machine(struct thread *thread, struct machine *machine, uint32_t *e_flags)
|
||||
uint16_t thread__e_machine_endian(struct thread *thread, struct machine *machine, uint32_t *e_flags,
|
||||
bool *is_big_endian)
|
||||
{
|
||||
pid_t tid, pid;
|
||||
uint16_t e_machine = RC_CHK_ACCESS(thread)->e_machine;
|
||||
uint16_t e_machine;
|
||||
uint32_t local_e_flags = 0;
|
||||
struct thread__e_machine_callback_args args = {
|
||||
.machine = machine,
|
||||
.e_flags = 0,
|
||||
.e_machine = EM_NONE,
|
||||
};
|
||||
struct thread__e_machine_callback_args args;
|
||||
|
||||
if (!thread) {
|
||||
if (is_big_endian) {
|
||||
*is_big_endian = perf_arch_is_big_endian(
|
||||
machine && machine->env ? perf_env__arch(machine->env) : NULL);
|
||||
}
|
||||
return perf_env__e_machine(machine ? machine->env : NULL, e_flags);
|
||||
}
|
||||
|
||||
e_machine = RC_CHK_ACCESS(thread)->e_machine;
|
||||
args.machine = machine;
|
||||
args.e_flags = 0;
|
||||
args.e_machine = EM_NONE;
|
||||
args.is_big_endian = false;
|
||||
|
||||
if (e_machine != EM_NONE) {
|
||||
if (e_flags)
|
||||
*e_flags = thread__e_flags(thread);
|
||||
if (is_big_endian)
|
||||
*is_big_endian = thread__e_is_big_endian(thread);
|
||||
return e_machine;
|
||||
}
|
||||
|
||||
|
|
@ -483,6 +500,7 @@ uint16_t thread__e_machine(struct thread *thread, struct machine *machine, uint3
|
|||
struct maps *maps = thread__maps(thread);
|
||||
|
||||
machine = maps__machine(maps);
|
||||
args.machine = machine;
|
||||
}
|
||||
tid = thread__tid(thread);
|
||||
pid = thread__pid(thread);
|
||||
|
|
@ -490,7 +508,8 @@ uint16_t thread__e_machine(struct thread *thread, struct machine *machine, uint3
|
|||
struct thread *parent = machine__findnew_thread(machine, pid, pid);
|
||||
|
||||
if (parent) {
|
||||
e_machine = thread__e_machine(parent, machine, &local_e_flags);
|
||||
e_machine = thread__e_machine_endian(parent, machine, &local_e_flags,
|
||||
&args.is_big_endian);
|
||||
thread__put(parent);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -515,16 +534,27 @@ uint16_t thread__e_machine(struct thread *thread, struct machine *machine, uint3
|
|||
is_live = !!session->data;
|
||||
}
|
||||
/* Read from /proc/pid/exe if live. */
|
||||
if (is_live)
|
||||
e_machine = read_proc_e_machine_for_pid(pid, &local_e_flags);
|
||||
if (is_live) {
|
||||
e_machine = read_proc_e_machine_for_pid(pid, &local_e_flags,
|
||||
&args.is_big_endian);
|
||||
} else if (machine && machine->env) {
|
||||
/* Offline analysis: fallback to environment metadata. */
|
||||
e_machine = perf_env__e_machine(machine->env, &local_e_flags);
|
||||
args.is_big_endian = perf_arch_is_big_endian(perf_env__arch(machine->env));
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (e_machine != EM_NONE) {
|
||||
thread__set_e_machine(thread, e_machine);
|
||||
thread__set_e_flags(thread, local_e_flags);
|
||||
thread__set_e_is_big_endian(thread, args.is_big_endian);
|
||||
thread__set_e_machine(thread, e_machine);
|
||||
if (is_big_endian)
|
||||
*is_big_endian = args.is_big_endian;
|
||||
} else {
|
||||
e_machine = EM_HOST;
|
||||
local_e_flags = EF_HOST;
|
||||
if (is_big_endian)
|
||||
*is_big_endian = (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
|
||||
}
|
||||
if (e_flags)
|
||||
*e_flags = local_e_flags;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,11 @@ DECLARE_RC_STRUCT(thread) {
|
|||
* computed.
|
||||
*/
|
||||
uint16_t e_machine;
|
||||
/**
|
||||
* @e_is_big_endian: True if the ELF architecture of the thread is big endian.
|
||||
* Valid if e_machine != EM_NONE.
|
||||
*/
|
||||
bool e_is_big_endian;
|
||||
/* LBR call stack stitch */
|
||||
bool lbr_stitch_enable;
|
||||
struct lbr_stitch *lbr_stitch;
|
||||
|
|
@ -311,7 +316,13 @@ 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, uint32_t *e_flags);
|
||||
uint16_t thread__e_machine_endian(struct thread *thread, struct machine *machine, uint32_t *e_flags,
|
||||
bool *is_big_endian);
|
||||
static inline uint16_t thread__e_machine(struct thread *thread, struct machine *machine,
|
||||
uint32_t *e_flags)
|
||||
{
|
||||
return thread__e_machine_endian(thread, machine, e_flags, NULL);
|
||||
}
|
||||
|
||||
static inline void thread__set_e_machine(struct thread *thread, uint16_t e_machine)
|
||||
{
|
||||
|
|
@ -328,6 +339,16 @@ 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__e_is_big_endian(const struct thread *thread)
|
||||
{
|
||||
return RC_CHK_ACCESS(thread)->e_is_big_endian;
|
||||
}
|
||||
|
||||
static inline void thread__set_e_is_big_endian(struct thread *thread, bool is_big_endian)
|
||||
{
|
||||
RC_CHK_ACCESS(thread)->e_is_big_endian = is_big_endian;
|
||||
}
|
||||
|
||||
|
||||
static inline bool thread__lbr_stitch_enable(const struct thread *thread)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user