2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-19 10:44:14 +08:00

perf unwind: Don't show unwind error messages when augmenting frame pointer stack

Commit Fixes: b9f6fbb3b2 ("perf arm64: Inject missing frames when
using 'perf record --call-graph=fp'") intended to add a 'best effort'
DWARF unwind that improved the frame pointer stack in most scenarios.

It's expected that the unwind will fail sometimes, but this shouldn't be
reported as an error. It only works when the return address can be
determined from the contents of the link register alone.

Fix the error shown when the unwinder requires extra registers by adding
a new flag that suppresses error messages. This flag is not set in the
normal --call-graph=dwarf unwind mode so that behavior is not changed.

Fixes: b9f6fbb3b2 ("perf arm64: Inject missing frames when using 'perf record --call-graph=fp'")
Reported-by: John Garry <john.garry@huawei.com>
Signed-off-by: James Clark <james.clark@arm.com>
Tested-by: John Garry <john.garry@huawei.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Truong <alexandre.truong@arm.com>
Cc: German Gomez <german.gomez@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20220406145651.1392529-1-james.clark@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
James Clark 2022-04-06 15:56:51 +01:00 committed by Arnaldo Carvalho de Melo
parent 278aaba2c5
commit fa7095c5c3
8 changed files with 32 additions and 14 deletions

View File

@ -122,7 +122,7 @@ NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__thread(struct thread *thr
}
err = unwind__get_entries(unwind_entry, &cnt, thread,
&sample, MAX_STACK);
&sample, MAX_STACK, false);
if (err)
pr_debug("unwind failed\n");
else if (cnt != MAX_STACK) {

View File

@ -53,7 +53,7 @@ u64 get_leaf_frame_caller_aarch64(struct perf_sample *sample, struct thread *thr
sample->user_regs.cache_regs[PERF_REG_ARM64_SP] = 0;
}
ret = unwind__get_entries(add_entry, &entries, thread, sample, 2);
ret = unwind__get_entries(add_entry, &entries, thread, sample, 2, true);
sample->user_regs = old_regs;
if (ret || entries.length != 2)

View File

@ -2987,7 +2987,7 @@ static int thread__resolve_callchain_unwind(struct thread *thread,
return 0;
return unwind__get_entries(unwind_entry, cursor,
thread, sample, max_stack);
thread, sample, max_stack, false);
}
int thread__resolve_callchain(struct thread *thread,

View File

@ -200,7 +200,8 @@ frame_callback(Dwfl_Frame *state, void *arg)
bool isactivation;
if (!dwfl_frame_pc(state, &pc, NULL)) {
pr_err("%s", dwfl_errmsg(-1));
if (!ui->best_effort)
pr_err("%s", dwfl_errmsg(-1));
return DWARF_CB_ABORT;
}
@ -208,7 +209,8 @@ frame_callback(Dwfl_Frame *state, void *arg)
report_module(pc, ui);
if (!dwfl_frame_pc(state, &pc, &isactivation)) {
pr_err("%s", dwfl_errmsg(-1));
if (!ui->best_effort)
pr_err("%s", dwfl_errmsg(-1));
return DWARF_CB_ABORT;
}
@ -222,7 +224,8 @@ frame_callback(Dwfl_Frame *state, void *arg)
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data,
int max_stack)
int max_stack,
bool best_effort)
{
struct unwind_info *ui, ui_buf = {
.sample = data,
@ -231,6 +234,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
.cb = cb,
.arg = arg,
.max_stack = max_stack,
.best_effort = best_effort
};
Dwarf_Word ip;
int err = -EINVAL, i;

View File

@ -20,6 +20,7 @@ struct unwind_info {
void *arg;
int max_stack;
int idx;
bool best_effort;
struct unwind_entry entries[];
};

View File

@ -96,6 +96,7 @@ struct unwind_info {
struct perf_sample *sample;
struct machine *machine;
struct thread *thread;
bool best_effort;
};
#define dw_read(ptr, type, end) ({ \
@ -553,7 +554,8 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
ret = perf_reg_value(&val, &ui->sample->user_regs, id);
if (ret) {
pr_err("unwind: can't read reg %d\n", regnum);
if (!ui->best_effort)
pr_err("unwind: can't read reg %d\n", regnum);
return ret;
}
@ -666,7 +668,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
return -1;
ret = unw_init_remote(&c, addr_space, ui);
if (ret)
if (ret && !ui->best_effort)
display_error(ret);
while (!ret && (unw_step(&c) > 0) && i < max_stack) {
@ -704,12 +706,14 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack)
struct perf_sample *data, int max_stack,
bool best_effort)
{
struct unwind_info ui = {
.sample = data,
.thread = thread,
.machine = thread->maps->machine,
.best_effort = best_effort
};
if (!data->user_regs.regs)

View File

@ -80,9 +80,11 @@ void unwind__finish_access(struct maps *maps)
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack)
struct perf_sample *data, int max_stack,
bool best_effort)
{
if (thread->maps->unwind_libunwind_ops)
return thread->maps->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack);
return thread->maps->unwind_libunwind_ops->get_entries(cb, arg, thread, data,
max_stack, best_effort);
return 0;
}

View File

@ -23,13 +23,19 @@ struct unwind_libunwind_ops {
void (*finish_access)(struct maps *maps);
int (*get_entries)(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack);
struct perf_sample *data, int max_stack, bool best_effort);
};
#ifdef HAVE_DWARF_UNWIND_SUPPORT
/*
* When best_effort is set, don't report errors and fail silently. This could
* be expanded in the future to be more permissive about things other than
* error messages.
*/
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack);
struct perf_sample *data, int max_stack,
bool best_effort);
/* libunwind specific */
#ifdef HAVE_LIBUNWIND_SUPPORT
#ifndef LIBUNWIND__ARCH_REG_ID
@ -65,7 +71,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
void *arg __maybe_unused,
struct thread *thread __maybe_unused,
struct perf_sample *data __maybe_unused,
int max_stack __maybe_unused)
int max_stack __maybe_unused,
bool best_effort __maybe_unused)
{
return 0;
}