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
122 }122 }
123 123
124 err = unwind__get_entries(unwind_entry, &cnt, thread,124 err = unwind__get_entries(unwind_entry, &cnt, thread,
125 &sample, MAX_STACK);125 &sample, MAX_STACK, false);
126 if (err)126 if (err)
127 pr_debug("unwind failed\n");127 pr_debug("unwind failed\n");
128 else if (cnt != MAX_STACK) {128 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
53 sample->user_regs.cache_regs[PERF_REG_ARM64_SP] = 0;53 sample->user_regs.cache_regs[PERF_REG_ARM64_SP] = 0;
54 }54 }
55 55
56 ret = unwind__get_entries(add_entry, &entries, thread, sample, 2);56 ret = unwind__get_entries(add_entry, &entries, thread, sample, 2, true);
57 sample->user_regs = old_regs;57 sample->user_regs = old_regs;
58 58
59 if (ret || entries.length != 2)59 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
2987 return 0;2987 return 0;
2988 2988
2989 return unwind__get_entries(unwind_entry, cursor,2989 return unwind__get_entries(unwind_entry, cursor,
2990 thread, sample, max_stack);2990 thread, sample, max_stack, false);
2991}2991}
2992 2992
2993int thread__resolve_callchain(struct thread *thread,2993int 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
200 bool isactivation;200 bool isactivation;
201 201
202 if (!dwfl_frame_pc(state, &pc, NULL)) {202 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));
204 return DWARF_CB_ABORT;205 return DWARF_CB_ABORT;
205 }206 }
206 207
@@ -208,7 +209,8 @@ frame_callback(Dwfl_Frame *state, void *arg) · 1 unmodified line
208 report_module(pc, ui);209 report_module(pc, ui);
209 210
210 if (!dwfl_frame_pc(state, &pc, &isactivation)) {211 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));
212 return DWARF_CB_ABORT;214 return DWARF_CB_ABORT;
213 }215 }
214 216
@@ -222,7 +224,8 @@ frame_callback(Dwfl_Frame *state, void *arg) · 7 unmodified lines
222int unwind__get_entries(unwind_entry_cb_t cb, void *arg,224int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
223 struct thread *thread,225 struct thread *thread,
224 struct perf_sample *data,226 struct perf_sample *data,
225 int max_stack)227 int max_stack,
228 bool best_effort)
226{229{
227 struct unwind_info *ui, ui_buf = {230 struct unwind_info *ui, ui_buf = {
228 .sample = data,231 .sample = data,
@@ -231,6 +234,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, · 2 unmodified lines
231 .cb = cb,234 .cb = cb,
232 .arg = arg,235 .arg = arg,
233 .max_stack = max_stack,236 .max_stack = max_stack,
237 .best_effort = best_effort
234 };238 };
235 Dwarf_Word ip;239 Dwarf_Word ip;
236 int err = -EINVAL, i;240 int err = -EINVAL, i;
tools/perf/util/unwind-libdw.h+1−0
@@ -20,6 +20,7 @@ struct unwind_info { · 19 unmodified lines
20 void *arg;20 void *arg;
21 int max_stack;21 int max_stack;
22 int idx;22 int idx;
23 bool best_effort;
23 struct unwind_entry entries[];24 struct unwind_entry entries[];
24};25};
25 26
tools/perf/util/unwind-libunwind-local.c+7−3
@@ -96,6 +96,7 @@ struct unwind_info { · 95 unmodified lines
96 struct perf_sample *sample;96 struct perf_sample *sample;
97 struct machine *machine;97 struct machine *machine;
98 struct thread *thread;98 struct thread *thread;
99 bool best_effort;
99};100};
100 101
101#define dw_read(ptr, type, end) ({ \102#define dw_read(ptr, type, end) ({ \
@@ -553,7 +554,8 @@ static int access_reg(unw_addr_space_t __maybe_unused as, · 451 unmodified lines
553 554
554 ret = perf_reg_value(&val, &ui->sample->user_regs, id);555 ret = perf_reg_value(&val, &ui->sample->user_regs, id);
555 if (ret) {556 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);
557 return ret;559 return ret;
558 }560 }
559 561
@@ -666,7 +668,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, · 106 unmodified lines
666 return -1;668 return -1;
667 669
668 ret = unw_init_remote(&c, addr_space, ui);670 ret = unw_init_remote(&c, addr_space, ui);
669 if (ret)671 if (ret && !ui->best_effort)
670 display_error(ret);672 display_error(ret);
671 673
672 while (!ret && (unw_step(&c) > 0) && i < max_stack) {674 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
704 706
705static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,707static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
706 struct thread *thread,708 struct thread *thread,
707 struct perf_sample *data, int max_stack)709 struct perf_sample *data, int max_stack,
710 bool best_effort)
708{711{
709 struct unwind_info ui = {712 struct unwind_info ui = {
710 .sample = data,713 .sample = data,
711 .thread = thread,714 .thread = thread,
712 .machine = thread->maps->machine,715 .machine = thread->maps->machine,
716 .best_effort = best_effort
713 };717 };
714 718
715 if (!data->user_regs.regs)719 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
80 80
81int unwind__get_entries(unwind_entry_cb_t cb, void *arg,81int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
82 struct thread *thread,82 struct thread *thread,
83 struct perf_sample *data, int max_stack)83 struct perf_sample *data, int max_stack,
84 bool best_effort)
84{85{
85 if (thread->maps->unwind_libunwind_ops)86 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);
87 return 0;89 return 0;
88}90}
tools/perf/util/unwind.h+10−3
@@ -23,13 +23,19 @@ struct unwind_libunwind_ops { · 22 unmodified lines
23 void (*finish_access)(struct maps *maps);23 void (*finish_access)(struct maps *maps);
24 int (*get_entries)(unwind_entry_cb_t cb, void *arg,24 int (*get_entries)(unwind_entry_cb_t cb, void *arg,
25 struct thread *thread,25 struct thread *thread,
26 struct perf_sample *data, int max_stack);26 struct perf_sample *data, int max_stack, bool best_effort);
27};27};
28 28
29#ifdef HAVE_DWARF_UNWIND_SUPPORT29#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 */
30int unwind__get_entries(unwind_entry_cb_t cb, void *arg,35int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
31 struct thread *thread,36 struct thread *thread,
32 struct perf_sample *data, int max_stack);37 struct perf_sample *data, int max_stack,
38 bool best_effort);
33/* libunwind specific */39/* libunwind specific */
34#ifdef HAVE_LIBUNWIND_SUPPORT40#ifdef HAVE_LIBUNWIND_SUPPORT
35#ifndef LIBUNWIND__ARCH_REG_ID41#ifndef LIBUNWIND__ARCH_REG_ID
@@ -65,7 +71,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, · 29 unmodified lines
65 void *arg __maybe_unused,71 void *arg __maybe_unused,
66 struct thread *thread __maybe_unused,72 struct thread *thread __maybe_unused,
67 struct perf_sample *data __maybe_unused,73 struct perf_sample *data __maybe_unused,
68 int max_stack __maybe_unused)74 int max_stack __maybe_unused,
75 bool best_effort __maybe_unused)
69{76{
70 return 0;77 return 0;
71}78}

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