return 0;
}
-static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, const char *arch,
+static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, uint16_t e_machine,
FILE *fp)
{
unsigned i = 0, r;
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, arch), val);
+ printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r, e_machine), val);
}
return printed;
}
static int perf_sample__fprintf_iregs(struct perf_sample *sample,
- struct perf_event_attr *attr, const char *arch, FILE *fp)
+ struct perf_event_attr *attr, uint16_t e_machine, FILE *fp)
{
if (!sample->intr_regs)
return 0;
return perf_sample__fprintf_regs(perf_sample__intr_regs(sample),
- attr->sample_regs_intr, arch, fp);
+ attr->sample_regs_intr, e_machine, fp);
}
static int perf_sample__fprintf_uregs(struct perf_sample *sample,
- struct perf_event_attr *attr, const char *arch, FILE *fp)
+ struct perf_event_attr *attr, uint16_t e_machine, FILE *fp)
{
if (!sample->user_regs)
return 0;
return perf_sample__fprintf_regs(perf_sample__user_regs(sample),
- attr->sample_regs_user, arch, fp);
+ attr->sample_regs_user, e_machine, fp);
}
static int perf_sample__fprintf_start(struct perf_script *script,
struct evsel_script *es = evsel->priv;
FILE *fp = es->fp;
char str[PAGE_SIZE_NAME_LEN];
- const char *arch = perf_env__arch(machine->env);
if (output[type].fields == 0)
return;
}
if (PRINT_FIELD(IREGS))
- perf_sample__fprintf_iregs(sample, attr, arch, fp);
+ perf_sample__fprintf_iregs(sample, attr, thread__e_machine(thread, machine), fp);
if (PRINT_FIELD(UREGS))
- perf_sample__fprintf_uregs(sample, attr, arch, fp);
+ perf_sample__fprintf_uregs(sample, attr, thread__e_machine(thread, machine), fp);
if (PRINT_FIELD(BRSTACK))
perf_sample__fprintf_brstack(sample, thread, evsel, fp);
#include "callchain.h"
#include "cgroup.h"
#include "counts.h"
+#include "dwarf-regs.h"
#include "event.h"
#include "evsel.h"
#include "time-utils.h"
return ret;
}
+static uint16_t evsel__e_machine(struct evsel *evsel)
+{
+ struct perf_session *session = evsel__session(evsel);
+
+ return session ? perf_session__e_machine(session) : EM_HOST;
+}
+
static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *opts,
struct callchain_param *param)
{
if (param->record_mode == CALLCHAIN_DWARF) {
if (!function) {
- const char *arch = perf_env__arch(evsel__env(evsel));
+ uint16_t e_machine = evsel__e_machine(evsel);
evsel__set_sample_bit(evsel, REGS_USER);
evsel__set_sample_bit(evsel, STACK_USER);
if (opts->sample_user_regs &&
- DWARF_MINIMAL_REGS(arch) != arch__user_reg_mask()) {
- attr->sample_regs_user |= DWARF_MINIMAL_REGS(arch);
+ DWARF_MINIMAL_REGS(e_machine) != arch__user_reg_mask()) {
+ attr->sample_regs_user |= DWARF_MINIMAL_REGS(e_machine);
pr_warning("WARNING: The use of --call-graph=dwarf may require all the user registers, "
"specifying a subset with --user-regs may render DWARF unwinding unreliable, "
"so the minimal registers set (IP, SP) is explicitly forced.\n");
// SPDX-License-Identifier: GPL-2.0
+#include <elf.h>
#include <errno.h>
#include <string.h>
+#include "dwarf-regs.h"
#include "perf_regs.h"
#include "util/sample.h"
#include "debug.h"
return sample_reg_masks;
}
-const char *perf_reg_name(int id, const char *arch)
+const char *perf_reg_name(int id, uint16_t e_machine)
{
const char *reg_name = NULL;
- if (!strcmp(arch, "csky"))
+ switch (e_machine) {
+ case EM_ARM:
+ reg_name = __perf_reg_name_arm(id);
+ break;
+ case EM_AARCH64:
+ reg_name = __perf_reg_name_arm64(id);
+ break;
+ case EM_CSKY:
reg_name = __perf_reg_name_csky(id);
- else if (!strcmp(arch, "loongarch"))
+ break;
+ case EM_LOONGARCH:
reg_name = __perf_reg_name_loongarch(id);
- else if (!strcmp(arch, "mips"))
+ break;
+ case EM_MIPS:
reg_name = __perf_reg_name_mips(id);
- else if (!strcmp(arch, "powerpc"))
+ break;
+ case EM_PPC:
+ case EM_PPC64:
reg_name = __perf_reg_name_powerpc(id);
- else if (!strcmp(arch, "riscv"))
+ break;
+ case EM_RISCV:
reg_name = __perf_reg_name_riscv(id);
- else if (!strcmp(arch, "s390"))
+ break;
+ case EM_S390:
reg_name = __perf_reg_name_s390(id);
- else if (!strcmp(arch, "x86"))
+ break;
+ case EM_386:
+ case EM_X86_64:
reg_name = __perf_reg_name_x86(id);
- else if (!strcmp(arch, "arm"))
- reg_name = __perf_reg_name_arm(id);
- else if (!strcmp(arch, "arm64"))
- reg_name = __perf_reg_name_arm64(id);
+ break;
+ default:
+ break;
+ }
+ if (reg_name)
+ return reg_name;
- return reg_name ?: "unknown";
+ pr_debug("Failed to find register %d for ELF machine type %u\n", id, e_machine);
+ return "unknown";
}
int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
return 0;
}
-uint64_t perf_arch_reg_ip(const char *arch)
+uint64_t perf_arch_reg_ip(uint16_t e_machine)
{
- if (!strcmp(arch, "arm"))
+ switch (e_machine) {
+ case EM_ARM:
return __perf_reg_ip_arm();
- else if (!strcmp(arch, "arm64"))
+ case EM_AARCH64:
return __perf_reg_ip_arm64();
- else if (!strcmp(arch, "csky"))
+ case EM_CSKY:
return __perf_reg_ip_csky();
- else if (!strcmp(arch, "loongarch"))
+ case EM_LOONGARCH:
return __perf_reg_ip_loongarch();
- else if (!strcmp(arch, "mips"))
+ case EM_MIPS:
return __perf_reg_ip_mips();
- else if (!strcmp(arch, "powerpc"))
+ case EM_PPC:
+ case EM_PPC64:
return __perf_reg_ip_powerpc();
- else if (!strcmp(arch, "riscv"))
+ case EM_RISCV:
return __perf_reg_ip_riscv();
- else if (!strcmp(arch, "s390"))
+ case EM_S390:
return __perf_reg_ip_s390();
- else if (!strcmp(arch, "x86"))
+ case EM_386:
+ case EM_X86_64:
return __perf_reg_ip_x86();
-
- pr_err("Fail to find IP register for arch %s, returns 0\n", arch);
- return 0;
+ default:
+ pr_err("Failed to find IP register for ELF machine type %u\n", e_machine);
+ return 0;
+ }
}
-uint64_t perf_arch_reg_sp(const char *arch)
+uint64_t perf_arch_reg_sp(uint16_t e_machine)
{
- if (!strcmp(arch, "arm"))
+ switch (e_machine) {
+ case EM_ARM:
return __perf_reg_sp_arm();
- else if (!strcmp(arch, "arm64"))
+ case EM_AARCH64:
return __perf_reg_sp_arm64();
- else if (!strcmp(arch, "csky"))
+ case EM_CSKY:
return __perf_reg_sp_csky();
- else if (!strcmp(arch, "loongarch"))
+ case EM_LOONGARCH:
return __perf_reg_sp_loongarch();
- else if (!strcmp(arch, "mips"))
+ case EM_MIPS:
return __perf_reg_sp_mips();
- else if (!strcmp(arch, "powerpc"))
+ case EM_PPC:
+ case EM_PPC64:
return __perf_reg_sp_powerpc();
- else if (!strcmp(arch, "riscv"))
+ case EM_RISCV:
return __perf_reg_sp_riscv();
- else if (!strcmp(arch, "s390"))
+ case EM_S390:
return __perf_reg_sp_s390();
- else if (!strcmp(arch, "x86"))
+ case EM_386:
+ case EM_X86_64:
return __perf_reg_sp_x86();
-
- pr_err("Fail to find SP register for arch %s, returns 0\n", arch);
- return 0;
+ default:
+ pr_err("Failed to find SP register for ELF machine type %u\n", e_machine);
+ return 0;
+ }
}
uint64_t arch__user_reg_mask(void);
const struct sample_reg *arch__sample_reg_masks(void);
-const char *perf_reg_name(int id, const char *arch);
+const char *perf_reg_name(int id, uint16_t e_machine);
int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
-uint64_t perf_arch_reg_ip(const char *arch);
-uint64_t perf_arch_reg_sp(const char *arch);
+uint64_t perf_arch_reg_ip(uint16_t e_machine);
+uint64_t perf_arch_reg_sp(uint16_t e_machine);
const char *__perf_reg_name_arm64(int id);
uint64_t __perf_reg_ip_arm64(void);
uint64_t __perf_reg_sp_arm64(void);
uint64_t __perf_reg_ip_x86(void);
uint64_t __perf_reg_sp_x86(void);
-static inline uint64_t DWARF_MINIMAL_REGS(const char *arch)
+static inline uint64_t DWARF_MINIMAL_REGS(uint16_t e_machine)
{
- return (1ULL << perf_arch_reg_ip(arch)) | (1ULL << perf_arch_reg_sp(arch));
+ return (1ULL << perf_arch_reg_ip(e_machine)) | (1ULL << perf_arch_reg_sp(e_machine));
}
#endif /* __PERF_REGS_H */
#include "../thread-stack.h"
#include "../trace-event.h"
#include "../call-path.h"
+#include "dwarf-regs.h"
#include "map.h"
#include "symbol.h"
#include "thread_map.h"
_PyUnicode_FromString(decode));
}
-static void regs_map(struct regs_dump *regs, uint64_t mask, const char *arch, char *bf, int size)
+static void regs_map(struct regs_dump *regs, uint64_t mask, uint16_t e_machine, char *bf, int size)
{
unsigned int i = 0, r;
int printed = 0;
printed += scnprintf(bf + printed, size - printed,
"%5s:0x%" PRIx64 " ",
- perf_reg_name(r, arch), val);
+ perf_reg_name(r, e_machine), val);
}
}
static int set_regs_in_dict(PyObject *dict,
struct perf_sample *sample,
- struct evsel *evsel)
+ struct evsel *evsel,
+ uint16_t e_machine)
{
struct perf_event_attr *attr = &evsel->core.attr;
- const char *arch = perf_env__arch(evsel__env(evsel));
int size = (__sw_hweight64(attr->sample_regs_intr) * MAX_REG_SIZE) + 1;
char *bf = NULL;
if (!bf)
return -1;
- regs_map(sample->intr_regs, attr->sample_regs_intr, arch, bf, size);
+ regs_map(sample->intr_regs, attr->sample_regs_intr, e_machine, bf, size);
pydict_set_item_string_decref(dict, "iregs",
_PyUnicode_FromString(bf));
if (!bf)
return -1;
}
- regs_map(sample->user_regs, attr->sample_regs_user, arch, bf, size);
+ regs_map(sample->user_regs, attr->sample_regs_user, e_machine, bf, size);
pydict_set_item_string_decref(dict, "uregs",
_PyUnicode_FromString(bf));
PyObject *callchain)
{
PyObject *dict, *dict_sample, *brstack, *brstacksym;
+ struct machine *machine;
+ uint16_t e_machine = EM_HOST;
dict = PyDict_New();
if (!dict)
PyLong_FromUnsignedLongLong(sample->cyc_cnt));
}
- if (set_regs_in_dict(dict, sample, evsel))
+ if (al->thread) {
+ machine = maps__machine(thread__maps(al->thread));
+ e_machine = thread__e_machine(al->thread, machine);
+ }
+ if (set_regs_in_dict(dict, sample, evsel, e_machine))
Py_FatalError("Failed to setting regs in dict");
return dict;
#include "map_symbol.h"
#include "branch.h"
#include "debug.h"
+#include "dwarf-regs.h"
#include "env.h"
#include "evlist.h"
#include "evsel.h"
}
}
-static void regs_dump__printf(u64 mask, u64 *regs, const char *arch)
+static void regs_dump__printf(u64 mask, u64 *regs, uint16_t e_machine)
{
unsigned rid, i = 0;
u64 val = regs[i++];
printf(".... %-5s 0x%016" PRIx64 "\n",
- perf_reg_name(rid, arch), val);
+ perf_reg_name(rid, e_machine), val);
}
}
return regs_abi[d->abi];
}
-static void regs__printf(const char *type, struct regs_dump *regs, const char *arch)
+static void regs__printf(const char *type, struct regs_dump *regs, uint16_t e_machine)
{
u64 mask = regs->mask;
mask,
regs_dump_abi(regs));
- regs_dump__printf(mask, regs->regs, arch);
+ regs_dump__printf(mask, regs->regs, e_machine);
}
-static void regs_user__printf(struct perf_sample *sample, const char *arch)
+static void regs_user__printf(struct perf_sample *sample, uint16_t e_machine)
{
struct regs_dump *user_regs;
user_regs = perf_sample__user_regs(sample);
if (user_regs->regs)
- regs__printf("user", user_regs, arch);
+ regs__printf("user", user_regs, e_machine);
}
-static void regs_intr__printf(struct perf_sample *sample, const char *arch)
+static void regs_intr__printf(struct perf_sample *sample, uint16_t e_machine)
{
struct regs_dump *intr_regs;
intr_regs = perf_sample__intr_regs(sample);
if (intr_regs->regs)
- regs__printf("intr", intr_regs, arch);
+ regs__printf("intr", intr_regs, e_machine);
}
static void stack_user__printf(struct stack_dump *dump)
return str;
}
-static void dump_sample(struct evsel *evsel, union perf_event *event,
- struct perf_sample *sample, const char *arch)
+static void dump_sample(struct machine *machine, struct evsel *evsel, union perf_event *event,
+ struct perf_sample *sample)
{
u64 sample_type;
char str[PAGE_SIZE_NAME_LEN];
+ uint16_t e_machine = EM_NONE;
if (!dump_trace)
return;
+ sample_type = evsel->core.attr.sample_type;
+
+ 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);
+ }
+
printf("(IP, 0x%x): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
event->header.misc, sample->pid, sample->tid, sample->ip,
sample->period, sample->addr);
- sample_type = evsel->core.attr.sample_type;
-
if (evsel__has_callchain(evsel))
callchain__printf(evsel, sample);
branch_stack__printf(sample, evsel);
if (sample_type & PERF_SAMPLE_REGS_USER)
- regs_user__printf(sample, arch);
+ regs_user__printf(sample, e_machine);
if (sample_type & PERF_SAMPLE_REGS_INTR)
- regs_intr__printf(sample, arch);
+ regs_intr__printf(sample, e_machine);
if (sample_type & PERF_SAMPLE_STACK_USER)
stack_user__printf(&sample->user_stack);
}
if (machine == NULL) {
++evlist->stats.nr_unprocessable_samples;
- dump_sample(evsel, event, sample, perf_env__arch(NULL));
+ dump_sample(machine, evsel, event, sample);
return 0;
}
- dump_sample(evsel, event, sample, perf_env__arch(machine->env));
+ dump_sample(machine, evsel, event, sample);
if (sample->deferred_callchain && tool->merge_deferred_callchains) {
struct deferred_event *de = malloc(sizeof(*de));
size_t sz = event->header.size;
{
return &session->header.env;
}
+
+static int perf_session__e_machine_cb(struct thread *thread,
+ void *arg __maybe_unused)
+{
+ uint16_t *result = arg;
+ struct machine *machine = maps__machine(thread__maps(thread));
+
+ *result = thread__e_machine(thread, machine);
+ return *result != EM_NONE ? 1 : 0;
+}
+
+/*
+ * Note, a machine may have mixed 32-bit and 64-bit processes and so mixed
+ * e_machines. Use thread__e_machine when this matters.
+ */
+uint16_t perf_session__e_machine(struct perf_session *session)
+{
+ uint16_t e_machine = EM_NONE;
+
+ machines__for_each_thread(&session->machines,
+ perf_session__e_machine_cb,
+ &e_machine);
+
+ return e_machine == EM_NONE ? EM_HOST : e_machine;
+}
struct ordered_events *oe);
struct perf_env *perf_session__env(struct perf_session *session);
+uint16_t perf_session__e_machine(struct perf_session *session);
#endif /* __PERF_SESSION_H */
void *arg)
{
struct unwind_info *ui = arg;
- const char *arch = perf_env__arch(ui->machine->env);
+ uint16_t e_machine = thread__e_machine(ui->thread, ui->machine);
struct stack_dump *stack = &ui->sample->user_stack;
u64 start, end;
int offset;
return false;
ret = perf_reg_value(&start, ui->sample->user_regs,
- perf_arch_reg_sp(arch));
+ perf_arch_reg_sp(e_machine));
if (ret)
return false;
int max_stack,
bool best_effort)
{
+ struct machine *machine = maps__machine(thread__maps(thread));
struct unwind_info *ui, ui_buf = {
.sample = data,
.thread = thread,
- .machine = maps__machine((thread__maps(thread))),
+ .machine = machine,
.cb = cb,
.arg = arg,
.max_stack = max_stack,
.best_effort = best_effort
};
- const char *arch = perf_env__arch(ui_buf.machine->env);
+ uint16_t e_machine = thread__e_machine(thread, machine);
+ const char *arch = perf_env__arch(machine->env);
Dwarf_Word ip;
int err = -EINVAL, i;
const Dwfl_Thread_Callbacks *callbacks;
if (!ui->dwfl)
goto out;
- err = perf_reg_value(&ip, data->user_regs, perf_arch_reg_ip(arch));
+ err = perf_reg_value(&ip, data->user_regs, perf_arch_reg_ip(e_machine));
if (err)
goto out;
int __write, void *arg)
{
struct unwind_info *ui = arg;
- const char *arch = perf_env__arch(ui->machine->env);
struct stack_dump *stack = &ui->sample->user_stack;
u64 start, end;
int offset;
}
ret = perf_reg_value(&start, perf_sample__user_regs(ui->sample),
- perf_arch_reg_sp(arch));
+ perf_arch_reg_sp(thread__e_machine(ui->thread, ui->machine)));
if (ret)
return ret;
static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
void *arg, int max_stack)
{
- const char *arch = perf_env__arch(ui->machine->env);
+ uint16_t e_machine = thread__e_machine(ui->thread, ui->machine);
u64 val;
unw_word_t ips[max_stack];
unw_addr_space_t addr_space;
int ret, i = 0;
ret = perf_reg_value(&val, perf_sample__user_regs(ui->sample),
- perf_arch_reg_ip(arch));
+ perf_arch_reg_ip(e_machine));
if (ret)
return ret;