History

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

Commit Fixes: b9f6fbb3b2c29736 ("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.

James Clark committed 4 years ago

Commit fa7095c1 parent 278aaba8 files · +32 −14Browse files

Unified · Split

8 files
  1. tools/perf/tests/dwarf-unwind.c +1 −1
  2. tools/perf/util/arm64-frame-pointer-unwind-support.c +1 −1
  3. tools/perf/util/machine.c +1 −1
  4. tools/perf/util/unwind-libdw.c +7 −3
  5. tools/perf/util/unwind-libdw.h +1 −0
  6. tools/perf/util/unwind-libunwind-local.c +7 −3
  7. tools/perf/util/unwind-libunwind.c +4 −2
  8. tools/perf/util/unwind.h +10 −3
tools/perf/tests/dwarf-unwind.c+1−1
@@ -122,7 +122,7 @@ NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__thread(struct thread *thr · 121 unmodified lines
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+1−1
@@ -53,7 +53,7 @@ u64 get_leaf_frame_caller_aarch64(struct perf_sample *sample, struct thread *thr · 52 unmodified lines
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+1−1
@@ -2987,7 +2987,7 @@ static int thread__resolve_callchain_unwind(struct thread *thread, · 2986 unmodified lines
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+7−3
@@ -200,7 +200,8 @@ frame_callback(Dwfl_Frame *state, void *arg) · 199 unmodified lines
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
@@ -208,7 +209,8 @@ frame_callback(Dwfl_Frame *state, void *arg) · 1 unmodified line
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) · 7 unmodified lines
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, · 2 unmodified lines
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+1−0
@@ -20,6 +20,7 @@ struct unwind_info { · 19 unmodified lines
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+7−3
@@ -96,6 +96,7 @@ struct unwind_info { · 95 unmodified lines
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, · 451 unmodified lines
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, · 106 unmodified lines
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, · 31 unmodified lines
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+4−2
@@ -80,9 +80,11 @@ void unwind__finish_access(struct maps *maps) · 79 unmodified lines
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+10−3
@@ -23,13 +23,19 @@ struct unwind_libunwind_ops { · 22 unmodified lines
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, · 29 unmodified lines
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 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t