[PATCH v3 2/2] perf: kretprobes: offset from reloc_sym if kernel supports it

From: Naveen N. Rao
Date: Thu Feb 23 2017 - 06:39:22 EST


We indicate support for accepting sym+offset with kretprobes through a
line in ftrace README. Parse the same to identify support and choose the
appropriate format for kprobe_events.

Signed-off-by: Naveen N. Rao <naveen.n.rao@xxxxxxxxxxxxxxxxxx>
---
tools/perf/util/probe-event.c | 49 ++++++++++++++++++++++++++++++++++++-------
tools/perf/util/probe-event.h | 2 ++
2 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 35f5b7b7715c..dd6b9ce0eef3 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -737,6 +737,43 @@ post_process_module_probe_trace_events(struct probe_trace_event *tevs,
return ret;
}

+bool is_kretprobe_offset_supported(void)
+{
+ FILE *fp;
+ char *buf = NULL;
+ size_t len = 0;
+ bool target_line = false;
+ static int supported = -1;
+ int fd;
+
+ if (supported >= 0)
+ return !!supported;
+
+ fd = open_trace_file("README", false);
+ if (fd < 0)
+ return false;
+
+ fp = fdopen(fd, "r");
+ if (!fp) {
+ close(fd);
+ return false;
+ }
+
+ while (getline(&buf, &len, fp) > 0) {
+ target_line = !!strstr(buf, "place (kretprobe): ");
+ if (!target_line)
+ continue;
+ supported = 1;
+ }
+ if (supported == -1)
+ supported = 0;
+
+ fclose(fp);
+ free(buf);
+
+ return !!supported;
+}
+
static int
post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
int ntevs)
@@ -757,7 +794,9 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
}

for (i = 0; i < ntevs; i++) {
- if (!tevs[i].point.address || tevs[i].point.retprobe)
+ if (!tevs[i].point.address)
+ continue;
+ if (tevs[i].point.retprobe && !is_kretprobe_offset_supported())
continue;
/* If we found a wrong one, mark it by NULL symbol */
if (kprobe_warn_out_range(tevs[i].point.symbol,
@@ -1528,11 +1567,6 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
return -EINVAL;
}

- if (pp->retprobe && !pp->function) {
- semantic_error("Return probe requires an entry function.\n");
- return -EINVAL;
- }
-
if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
semantic_error("Offset/Line/Lazy pattern can't be used with "
"return probe.\n");
@@ -2841,7 +2875,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
}

/* Note that the symbols in the kmodule are not relocated */
- if (!pev->uprobes && !pp->retprobe && !pev->target) {
+ if (!pev->uprobes && !pev->target &&
+ (!pp->retprobe || is_kretprobe_offset_supported())) {
reloc_sym = kernel_get_ref_reloc_sym();
if (!reloc_sym) {
pr_warning("Relocated base symbol is not found!\n");
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5d4e94061402..449d4f311355 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -135,6 +135,8 @@ bool perf_probe_with_var(struct perf_probe_event *pev);
/* Check the perf_probe_event needs debuginfo */
bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);

+bool is_kretprobe_offset_supported(void);
+
/* Release event contents */
void clear_perf_probe_event(struct perf_probe_event *pev);
void clear_probe_trace_event(struct probe_trace_event *tev);
--
2.11.1