mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 06:24:43 +01:00
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 <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>
This commit is contained in:
parent
7d0ebeb6c0
commit
4e66527f88
12 changed files with 122 additions and 48 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue