Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a5e3d3c authored by Ravi Bangoria's avatar Ravi Bangoria Committed by Steven Rostedt (VMware)
Browse files

perf probe: Support SDT markers having reference counter (semaphore)

With this, perf buildid-cache will save SDT markers with reference
counter in probe cache. Perf probe will be able to probe markers
having reference counter. Ex,

  # readelf -n /tmp/tick | grep -A1 loop2
    Name: loop2
    ... Semaphore: 0x0000000010020036

  # ./perf buildid-cache --add /tmp/tick
  # ./perf probe sdt_tick:loop2
  # ./perf stat -e sdt_tick:loop2 /tmp/tick
    hi: 0
    hi: 1
    hi: 2
    ^C
     Performance counter stats for '/tmp/tick':
                 3      sdt_tick:loop2
       2.561851452 seconds time elapsed

Link: http://lkml.kernel.org/r/20180820044250.11659-5-ravi.bangoria@linux.ibm.com



Acked-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Acked-by: default avatarSrikar Dronamraju <srikar@linux.vnet.ibm.com>
Reviewed-by: default avatarSong Liu <songliubraving@fb.com>
Tested-by: default avatarSong Liu <songliubraving@fb.com>
Signed-off-by: default avatarRavi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent ccea8727
Loading
Loading
Loading
Loading
+35 −4
Original line number Diff line number Diff line
@@ -1819,6 +1819,12 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
			tp->offset = strtoul(fmt2_str, NULL, 10);
	}

	if (tev->uprobes) {
		fmt2_str = strchr(p, '(');
		if (fmt2_str)
			tp->ref_ctr_offset = strtoul(fmt2_str + 1, NULL, 0);
	}

	tev->nargs = argc - 2;
	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
	if (tev->args == NULL) {
@@ -2012,6 +2018,22 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
	return err;
}

static int
synthesize_uprobe_trace_def(struct probe_trace_event *tev, struct strbuf *buf)
{
	struct probe_trace_point *tp = &tev->point;
	int err;

	err = strbuf_addf(buf, "%s:0x%lx", tp->module, tp->address);

	if (err >= 0 && tp->ref_ctr_offset) {
		if (!uprobe_ref_ctr_is_supported())
			return -1;
		err = strbuf_addf(buf, "(0x%lx)", tp->ref_ctr_offset);
	}
	return err >= 0 ? 0 : -1;
}

char *synthesize_probe_trace_command(struct probe_trace_event *tev)
{
	struct probe_trace_point *tp = &tev->point;
@@ -2041,15 +2063,17 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
	}

	/* Use the tp->address for uprobes */
	if (tev->uprobes)
		err = strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address);
	else if (!strncmp(tp->symbol, "0x", 2))
	if (tev->uprobes) {
		err = synthesize_uprobe_trace_def(tev, &buf);
	} else if (!strncmp(tp->symbol, "0x", 2)) {
		/* Absolute address. See try_to_find_absolute_address() */
		err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "",
				  tp->module ? ":" : "", tp->address);
	else
	} else {
		err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "",
				tp->module ? ":" : "", tp->symbol, tp->offset);
	}

	if (err)
		goto error;

@@ -2633,6 +2657,13 @@ static void warn_uprobe_event_compat(struct probe_trace_event *tev)
{
	int i;
	char *buf = synthesize_probe_trace_command(tev);
	struct probe_trace_point *tp = &tev->point;

	if (tp->ref_ctr_offset && !uprobe_ref_ctr_is_supported()) {
		pr_warning("A semaphore is associated with %s:%s and "
			   "seems your kernel doesn't support it.\n",
			   tev->group, tev->event);
	}

	/* Old uprobe event doesn't support memory dereference */
	if (!tev->uprobes || tev->nargs == 0 || !buf)
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ struct probe_trace_point {
	char		*symbol;	/* Base symbol */
	char		*module;	/* Module name */
	unsigned long	offset;		/* Offset from symbol */
	unsigned long	ref_ctr_offset;	/* SDT reference counter offset */
	unsigned long	address;	/* Actual address of the trace point */
	bool		retprobe;	/* Return probe flag */
};
+28 −6
Original line number Diff line number Diff line
@@ -696,8 +696,16 @@ int probe_cache__add_entry(struct probe_cache *pcache,
#ifdef HAVE_GELF_GETNOTE_SUPPORT
static unsigned long long sdt_note__get_addr(struct sdt_note *note)
{
	return note->bit32 ? (unsigned long long)note->addr.a32[0]
		 : (unsigned long long)note->addr.a64[0];
	return note->bit32 ?
		(unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] :
		(unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC];
}

static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note)
{
	return note->bit32 ?
		(unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] :
		(unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR];
}

static const char * const type_to_suffix[] = {
@@ -775,14 +783,21 @@ static char *synthesize_sdt_probe_command(struct sdt_note *note,
{
	struct strbuf buf;
	char *ret = NULL, **args;
	int i, args_count;
	int i, args_count, err;
	unsigned long long ref_ctr_offset;

	if (strbuf_init(&buf, 32) < 0)
		return NULL;

	if (strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
	err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
			sdtgrp, note->name, pathname,
				sdt_note__get_addr(note)) < 0)
			sdt_note__get_addr(note));

	ref_ctr_offset = sdt_note__get_ref_ctr_offset(note);
	if (ref_ctr_offset && err >= 0)
		err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset);

	if (err < 0)
		goto error;

	if (!note->args)
@@ -998,6 +1013,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)
enum ftrace_readme {
	FTRACE_README_PROBE_TYPE_X = 0,
	FTRACE_README_KRETPROBE_OFFSET,
	FTRACE_README_UPROBE_REF_CTR,
	FTRACE_README_END,
};

@@ -1009,6 +1025,7 @@ static struct {
	[idx] = {.pattern = pat, .avail = false}
	DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
	DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
	DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"),
};

static bool scan_ftrace_readme(enum ftrace_readme type)
@@ -1064,3 +1081,8 @@ bool kretprobe_offset_is_supported(void)
{
	return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
}

bool uprobe_ref_ctr_is_supported(void)
{
	return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR);
}
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
int probe_cache__show_all_caches(struct strfilter *filter);
bool probe_type_is_available(enum probe_type type);
bool kretprobe_offset_is_supported(void);
bool uprobe_ref_ctr_is_supported(void);
#else	/* ! HAVE_LIBELF_SUPPORT */
static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused, struct nsinfo *nsi __maybe_unused)
{
+34 −12
Original line number Diff line number Diff line
@@ -1947,6 +1947,34 @@ void kcore_extract__delete(struct kcore_extract *kce)
}

#ifdef HAVE_GELF_GETNOTE_SUPPORT

static void sdt_adjust_loc(struct sdt_note *tmp, GElf_Addr base_off)
{
	if (!base_off)
		return;

	if (tmp->bit32)
		tmp->addr.a32[SDT_NOTE_IDX_LOC] =
			tmp->addr.a32[SDT_NOTE_IDX_LOC] + base_off -
			tmp->addr.a32[SDT_NOTE_IDX_BASE];
	else
		tmp->addr.a64[SDT_NOTE_IDX_LOC] =
			tmp->addr.a64[SDT_NOTE_IDX_LOC] + base_off -
			tmp->addr.a64[SDT_NOTE_IDX_BASE];
}

static void sdt_adjust_refctr(struct sdt_note *tmp, GElf_Addr base_addr,
			      GElf_Addr base_off)
{
	if (!base_off)
		return;

	if (tmp->bit32 && tmp->addr.a32[SDT_NOTE_IDX_REFCTR])
		tmp->addr.a32[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off);
	else if (tmp->addr.a64[SDT_NOTE_IDX_REFCTR])
		tmp->addr.a64[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off);
}

/**
 * populate_sdt_note : Parse raw data and identify SDT note
 * @elf: elf of the opened file
@@ -1964,7 +1992,6 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len,
	const char *provider, *name, *args;
	struct sdt_note *tmp = NULL;
	GElf_Ehdr ehdr;
	GElf_Addr base_off = 0;
	GElf_Shdr shdr;
	int ret = -EINVAL;

@@ -2060,17 +2087,12 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len,
	 * base address in the description of the SDT note. If its different,
	 * then accordingly, adjust the note location.
	 */
	if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) {
		base_off = shdr.sh_offset;
		if (base_off) {
			if (tmp->bit32)
				tmp->addr.a32[0] = tmp->addr.a32[0] + base_off -
					tmp->addr.a32[1];
			else
				tmp->addr.a64[0] = tmp->addr.a64[0] + base_off -
					tmp->addr.a64[1];
		}
	}
	if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL))
		sdt_adjust_loc(tmp, shdr.sh_offset);

	/* Adjust reference counter offset */
	if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_PROBES_SCN, NULL))
		sdt_adjust_refctr(tmp, shdr.sh_addr, shdr.sh_offset);

	list_add_tail(&tmp->note_list, sdt_notes);
	return 0;
Loading