Skip to content

Commit fa7095c

Browse files
James-A-Clarkacmel
authored andcommitted
perf unwind: Don't show unwind error messages when augmenting frame pointer stack
Commit Fixes: b9f6fbb ("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: b9f6fbb ("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>
1 parent 278aaba commit fa7095c

File tree

8 files changed

+32
-14
lines changed

8 files changed

+32
-14
lines changed

tools/perf/tests/dwarf-unwind.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__thread(struct thread *thr
122122
}
123123

124124
err = unwind__get_entries(unwind_entry, &cnt, thread,
125-
&sample, MAX_STACK);
125+
&sample, MAX_STACK, false);
126126
if (err)
127127
pr_debug("unwind failed\n");
128128
else if (cnt != MAX_STACK) {

tools/perf/util/arm64-frame-pointer-unwind-support.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ u64 get_leaf_frame_caller_aarch64(struct perf_sample *sample, struct thread *thr
5353
sample->user_regs.cache_regs[PERF_REG_ARM64_SP] = 0;
5454
}
5555

56-
ret = unwind__get_entries(add_entry, &entries, thread, sample, 2);
56+
ret = unwind__get_entries(add_entry, &entries, thread, sample, 2, true);
5757
sample->user_regs = old_regs;
5858

5959
if (ret || entries.length != 2)

tools/perf/util/machine.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2987,7 +2987,7 @@ static int thread__resolve_callchain_unwind(struct thread *thread,
29872987
return 0;
29882988

29892989
return unwind__get_entries(unwind_entry, cursor,
2990-
thread, sample, max_stack);
2990+
thread, sample, max_stack, false);
29912991
}
29922992

29932993
int thread__resolve_callchain(struct thread *thread,

tools/perf/util/unwind-libdw.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,17 @@ frame_callback(Dwfl_Frame *state, void *arg)
200200
bool isactivation;
201201

202202
if (!dwfl_frame_pc(state, &pc, NULL)) {
203-
pr_err("%s", dwfl_errmsg(-1));
203+
if (!ui->best_effort)
204+
pr_err("%s", dwfl_errmsg(-1));
204205
return DWARF_CB_ABORT;
205206
}
206207

207208
// report the module before we query for isactivation
208209
report_module(pc, ui);
209210

210211
if (!dwfl_frame_pc(state, &pc, &isactivation)) {
211-
pr_err("%s", dwfl_errmsg(-1));
212+
if (!ui->best_effort)
213+
pr_err("%s", dwfl_errmsg(-1));
212214
return DWARF_CB_ABORT;
213215
}
214216

@@ -222,7 +224,8 @@ frame_callback(Dwfl_Frame *state, void *arg)
222224
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
223225
struct thread *thread,
224226
struct perf_sample *data,
225-
int max_stack)
227+
int max_stack,
228+
bool best_effort)
226229
{
227230
struct unwind_info *ui, ui_buf = {
228231
.sample = data,
@@ -231,6 +234,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
231234
.cb = cb,
232235
.arg = arg,
233236
.max_stack = max_stack,
237+
.best_effort = best_effort
234238
};
235239
Dwarf_Word ip;
236240
int err = -EINVAL, i;

tools/perf/util/unwind-libdw.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct unwind_info {
2020
void *arg;
2121
int max_stack;
2222
int idx;
23+
bool best_effort;
2324
struct unwind_entry entries[];
2425
};
2526

tools/perf/util/unwind-libunwind-local.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ struct unwind_info {
9696
struct perf_sample *sample;
9797
struct machine *machine;
9898
struct thread *thread;
99+
bool best_effort;
99100
};
100101

101102
#define dw_read(ptr, type, end) ({ \
@@ -553,7 +554,8 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
553554

554555
ret = perf_reg_value(&val, &ui->sample->user_regs, id);
555556
if (ret) {
556-
pr_err("unwind: can't read reg %d\n", regnum);
557+
if (!ui->best_effort)
558+
pr_err("unwind: can't read reg %d\n", regnum);
557559
return ret;
558560
}
559561

@@ -666,7 +668,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
666668
return -1;
667669

668670
ret = unw_init_remote(&c, addr_space, ui);
669-
if (ret)
671+
if (ret && !ui->best_effort)
670672
display_error(ret);
671673

672674
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,
704706

705707
static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
706708
struct thread *thread,
707-
struct perf_sample *data, int max_stack)
709+
struct perf_sample *data, int max_stack,
710+
bool best_effort)
708711
{
709712
struct unwind_info ui = {
710713
.sample = data,
711714
.thread = thread,
712715
.machine = thread->maps->machine,
716+
.best_effort = best_effort
713717
};
714718

715719
if (!data->user_regs.regs)

tools/perf/util/unwind-libunwind.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,11 @@ void unwind__finish_access(struct maps *maps)
8080

8181
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
8282
struct thread *thread,
83-
struct perf_sample *data, int max_stack)
83+
struct perf_sample *data, int max_stack,
84+
bool best_effort)
8485
{
8586
if (thread->maps->unwind_libunwind_ops)
86-
return thread->maps->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack);
87+
return thread->maps->unwind_libunwind_ops->get_entries(cb, arg, thread, data,
88+
max_stack, best_effort);
8789
return 0;
8890
}

tools/perf/util/unwind.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,19 @@ struct unwind_libunwind_ops {
2323
void (*finish_access)(struct maps *maps);
2424
int (*get_entries)(unwind_entry_cb_t cb, void *arg,
2525
struct thread *thread,
26-
struct perf_sample *data, int max_stack);
26+
struct perf_sample *data, int max_stack, bool best_effort);
2727
};
2828

2929
#ifdef HAVE_DWARF_UNWIND_SUPPORT
30+
/*
31+
* When best_effort is set, don't report errors and fail silently. This could
32+
* be expanded in the future to be more permissive about things other than
33+
* error messages.
34+
*/
3035
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
3136
struct thread *thread,
32-
struct perf_sample *data, int max_stack);
37+
struct perf_sample *data, int max_stack,
38+
bool best_effort);
3339
/* libunwind specific */
3440
#ifdef HAVE_LIBUNWIND_SUPPORT
3541
#ifndef LIBUNWIND__ARCH_REG_ID
@@ -65,7 +71,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
6571
void *arg __maybe_unused,
6672
struct thread *thread __maybe_unused,
6773
struct perf_sample *data __maybe_unused,
68-
int max_stack __maybe_unused)
74+
int max_stack __maybe_unused,
75+
bool best_effort __maybe_unused)
6976
{
7077
return 0;
7178
}

0 commit comments

Comments
 (0)