All of lore.kernel.org
 help / color / mirror / Atom feed
From: Masami Hiramatsu <mhiramat@kernel.org>
To: Thomas-Mich Richter <tmricht@linux.vnet.ibm.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>,
	bhargavb <bhargavaramudu@gmail.com>,
	linux-kernel@vger.kernel.org, Paul Clarke <pc@us.ibm.com>,
	Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>,
	linux-rt-users@vger.kernel.org, linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v2 5/5] perf-probe: Support escaped character in parser
Date: Sat, 9 Dec 2017 00:54:43 +0900	[thread overview]
Message-ID: <20171209005443.344d2aa420803809f5427f1f@kernel.org> (raw)
In-Reply-To: <a8d875b5-4273-18e2-7cdf-a75da31f8319@linux.vnet.ibm.com>

On Fri, 8 Dec 2017 12:45:45 +0100
Thomas-Mich Richter <tmricht@linux.vnet.ibm.com> wrote:

> On 12/07/2017 08:21 AM, Masami Hiramatsu wrote:
> > Support the special characters escaped by '\' in parser.
> > This allows user to specify versions directly like below.
> > 
> >   =====
> >   # ./perf probe -x /lib64/libc-2.25.so malloc_get_state\\@GLIBC_2.2.5
> >   Added new event:
> >     probe_libc:malloc_get_state (on malloc_get_state@GLIBC_2.2.5 in /usr/lib64/libc-2.25.so)
> > 
> >   You can now use it in all perf tools, such as:
> > 
> > 	  perf record -e probe_libc:malloc_get_state -aR sleep 1
> > 
> >   =====
> > 
> > Or, you can use separators in source filename, e.g.
> > 
> >   =====
> >   # ./perf probe -x /opt/test/a.out foo+bar.c:3
> >   Semantic error :There is non-digit character in offset.
> >     Error: Command Parse Error.
> >   =====
> > 
> > Usually "+" in source file cause parser error, but
> > 
> >   =====
> >   # ./perf probe -x /opt/test/a.out foo\\+bar.c:4
> >   Added new event:
> >     probe_a:main         (on @foo+bar.c:4 in /opt/test/a.out)
> > 
> >   You can now use it in all perf tools, such as:
> > 
> > 	  perf record -e probe_a:main -aR sleep 1
> >   =====
> > 
> > escaped "\+" allows you to specify that.
> > 
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  Changes in v2:
> >   - Add a description and samples in Documentation/perf-probe.txt
> > ---
> >  tools/perf/Documentation/perf-probe.txt |   16 +++++++++
> >  tools/perf/util/probe-event.c           |   54 +++++++++++++++++++------------
> >  tools/perf/util/string.c                |   46 ++++++++++++++++++++++++++
> >  tools/perf/util/string2.h               |    2 +
> >  4 files changed, 97 insertions(+), 21 deletions(-)
> > 
> > diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
> > index f96382692f42..b6866a05edd2 100644
> > --- a/tools/perf/Documentation/perf-probe.txt
> > +++ b/tools/perf/Documentation/perf-probe.txt
> > @@ -182,6 +182,14 @@ Note that before using the SDT event, the target binary (on which SDT events are
> >  For details of the SDT, see below.
> >  https://sourceware.org/gdb/onlinedocs/gdb/Static-Probe-Points.html
> > 
> > +ESCAPED CHARACTER
> > +-----------------
> > +
> > +In the probe syntax, '=', '@', '+', ':' and ';' are treated as a special character. You can use a backslash ('\') to escape the special characters.
> > +This is useful if you need to probe on a specific versioned symbols, like @GLIBC_... suffixes, or also you need to specify a source file which includes the special characters.
> > +Note that usually single backslash is consumed by shell, so you might need to pass double backslash (\\) or wrapping with single quotes (\'AAA\@BBB').
> > +See EXAMPLES how it is used.
> > +
> >  PROBE ARGUMENT
> >  --------------
> >  Each probe argument follows below syntax.
> > @@ -277,6 +285,14 @@ Add a USDT probe to a target process running in a different mount namespace
> > 
> >   ./perf probe --target-ns <target pid> -x /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.121-0.b13.el7_3.x86_64/jre/lib/amd64/server/libjvm.so %sdt_hotspot:thread__sleep__end
> > 
> > +Add a probe on specific versioned symbol by backslash escape
> > +
> > + ./perf probe -x /lib64/libc-2.25.so 'malloc_get_state\@GLIBC_2.2.5'
> > +
> > +Add a probe in a source file using special characters by backslash escape
> > +
> > + ./perf probe -x /opt/test/a.out 'foo\+bar.c:4'
> > +
> > 
> >  SEE ALSO
> >  --------
> > diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> > index 94acc5846e2a..c082a27982e5 100644
> > --- a/tools/perf/util/probe-event.c
> > +++ b/tools/perf/util/probe-event.c
> > @@ -1325,27 +1325,30 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
> >  {
> >  	char *ptr;
> > 
> > -	ptr = strchr(*arg, ':');
> > +	ptr = strpbrk_esc(*arg, ":");
> >  	if (ptr) {
> >  		*ptr = '\0';
> >  		if (!pev->sdt && !is_c_func_name(*arg))
> >  			goto ng_name;
> > -		pev->group = strdup(*arg);
> > +		pev->group = strdup_esc(*arg);
> >  		if (!pev->group)
> >  			return -ENOMEM;
> >  		*arg = ptr + 1;
> >  	} else
> >  		pev->group = NULL;
> > -	if (!pev->sdt && !is_c_func_name(*arg)) {
> > +
> > +	pev->event = strdup_esc(*arg);
> > +	if (pev->event == NULL)
> > +		return -ENOMEM;
> > +
> > +	if (!pev->sdt && !is_c_func_name(pev->event)) {
> > +		zfree(&pev->event);
> >  ng_name:
> > +		zfree(&pev->group);
> >  		semantic_error("%s is bad for event name -it must "
> >  			       "follow C symbol-naming rule.\n", *arg);
> >  		return -EINVAL;
> >  	}
> > -	pev->event = strdup(*arg);
> > -	if (pev->event == NULL)
> > -		return -ENOMEM;
> > -
> >  	return 0;
> >  }
> > 
> > @@ -1373,7 +1376,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
> >  			arg++;
> >  	}
> > 
> > -	ptr = strpbrk(arg, ";=@+%");
> > +	ptr = strpbrk_esc(arg, ";=@+%");
> >  	if (pev->sdt) {
> >  		if (ptr) {
> >  			if (*ptr != '@') {
> > @@ -1387,7 +1390,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
> >  				pev->target = build_id_cache__origname(tmp);
> >  				free(tmp);
> >  			} else
> > -				pev->target = strdup(ptr + 1);
> > +				pev->target = strdup_esc(ptr + 1);
> >  			if (!pev->target)
> >  				return -ENOMEM;
> >  			*ptr = '\0';
> > @@ -1421,13 +1424,14 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
> >  	 *
> >  	 * Otherwise, we consider arg to be a function specification.
> >  	 */
> > -	if (!strpbrk(arg, "+@%") && (ptr = strpbrk(arg, ";:")) != NULL) {
> > +	if (!strpbrk_esc(arg, "+@%")) {
> > +		ptr = strpbrk_esc(arg, ";:");
> >  		/* This is a file spec if it includes a '.' before ; or : */
> > -		if (memchr(arg, '.', ptr - arg))
> > +		if (ptr && memchr(arg, '.', ptr - arg))
> >  			file_spec = true;
> >  	}
> > 
> > -	ptr = strpbrk(arg, ";:+@%");
> > +	ptr = strpbrk_esc(arg, ";:+@%");
> >  	if (ptr) {
> >  		nc = *ptr;
> >  		*ptr++ = '\0';
> > @@ -1436,7 +1440,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
> >  	if (arg[0] == '\0')
> >  		tmp = NULL;
> >  	else {
> > -		tmp = strdup(arg);
> > +		tmp = strdup_esc(arg);
> >  		if (tmp == NULL)
> >  			return -ENOMEM;
> >  	}
> > @@ -1469,12 +1473,12 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
> >  		arg = ptr;
> >  		c = nc;
> >  		if (c == ';') {	/* Lazy pattern must be the last part */
> > -			pp->lazy_line = strdup(arg);
> > +			pp->lazy_line = strdup(arg); /* let leave escapes */
> >  			if (pp->lazy_line == NULL)
> >  				return -ENOMEM;
> >  			break;
> >  		}
> > -		ptr = strpbrk(arg, ";:+@%");
> > +		ptr = strpbrk_esc(arg, ";:+@%");
> >  		if (ptr) {
> >  			nc = *ptr;
> >  			*ptr++ = '\0';
> > @@ -1501,7 +1505,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
> >  				semantic_error("SRC@SRC is not allowed.\n");
> >  				return -EINVAL;
> >  			}
> > -			pp->file = strdup(arg);
> > +			pp->file = strdup_esc(arg);
> >  			if (pp->file == NULL)
> >  				return -ENOMEM;
> >  			break;
> > @@ -2803,21 +2807,29 @@ static int find_probe_functions(struct map *map, char *name,
> >  	struct rb_node *tmp;
> >  	const char *norm, *ver;
> >  	char *buf = NULL;
> > +	bool cut_version = true;
> > 
> >  	if (map__load(map) < 0)
> >  		return 0;
> > 
> > +	/* If user gives a version, don't cut off the version from symbols */
> > +	if (strchr(name, '@'))
> > +		cut_version = false;
> > +
> >  	map__for_each_symbol(map, sym, tmp) {
> >  		norm = arch__normalize_symbol_name(sym->name);
> 
> Same as before (patch 4)
> 
> >  		if (!norm)
> >  			continue;
> > 
> > -		/* We don't care about default symbol or not */
> > -		ver = strchr(norm, '@');
> > -		if (ver) {
> > -			buf = strndup(norm, ver - norm);
> > -			norm = buf;
> 
> Again strndup() may return a NULL ptr and then strglobmatch() / strchr() below
> dereferences it.

OK, but those will be fixed in patch 4/5.
(Of course below block should be updated)

Anyway, Thank you!

> 
> > +		if (cut_version) {
> > +			/* We don't care about default symbol or not */
> > +			ver = strchr(norm, '@');
> > +			if (ver) {
> > +				buf = strndup(norm, ver - norm);
> > +				norm = buf;
> > +			}
> >  		}
> > +
> >  		if (strglobmatch(norm, name)) {
> >  			found++;
> >  			if (syms && found < probe_conf.max_probes)
> > diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
> > index aaa08ee8c717..d8bfd0c4d2cb 100644
> > --- a/tools/perf/util/string.c
> > +++ b/tools/perf/util/string.c
> > @@ -396,3 +396,49 @@ char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints
> >  	free(expr);
> >  	return NULL;
> >  }
> > +
> > +/* Like strpbrk(), but not break if it is right after a backslash (escaped) */
> > +char *strpbrk_esc(char *str, const char *stopset)
> > +{
> > +	char *ptr;
> > +
> > +	do {
> > +		ptr = strpbrk(str, stopset);
> > +		if (ptr == str ||
> > +		    (ptr == str + 1 && *(ptr - 1) != '\\'))
> > +			break;
> > +		str = ptr + 1;
> > +	} while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\');
> > +
> > +	return ptr;
> > +}
> > +
> > +/* Like strdup, but do not copy a single backslash */
> > +char *strdup_esc(const char *str)
> > +{
> > +	char *s, *d, *p, *ret = strdup(str);
> > +
> > +	if (!ret)
> > +		return NULL;
> > +
> > +	d = strchr(ret, '\\');
> > +	if (!d)
> > +		return ret;
> > +
> > +	s = d + 1;
> > +	do {
> > +		if (*s == '\0') {
> > +			*d = '\0';
> > +			break;
> > +		}
> > +		p = strchr(s + 1, '\\');
> > +		if (p) {
> > +			memmove(d, s, p - s);
> > +			d += p - s;
> > +			s = p + 1;
> > +		} else
> > +			memmove(d, s, strlen(s) + 1);
> > +	} while (p);
> > +
> > +	return ret;
> > +}
> > diff --git a/tools/perf/util/string2.h b/tools/perf/util/string2.h
> > index ee14ca5451ab..4c68a09b97e8 100644
> > --- a/tools/perf/util/string2.h
> > +++ b/tools/perf/util/string2.h
> > @@ -39,5 +39,7 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int
> >  	return asprintf_expr_inout_ints(var, false, nints, ints);
> >  }
> > 
> > +char *strpbrk_esc(char *str, const char *stopset);
> > +char *strdup_esc(const char *str);
> > 
> >  #endif /* PERF_STRING_H */
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-perf-users" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > 
> 
> 
> -- 
> Thomas Richter, Dept 3303, IBM LTC Boeblingen Germany
> --
> Vorsitzende des Aufsichtsrats: Martina Koederitz 
> Geschäftsführung: Dirk Wittkopp
> Sitz der Gesellschaft: Böblingen / Registergericht: Amtsgericht Stuttgart, HRB 243294
> 


-- 
Masami Hiramatsu <mhiramat@kernel.org>

  reply	other threads:[~2017-12-08 15:54 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-07  7:19 [PATCH v2 0/5] perf-probe: Improve probing on versioned symbols Masami Hiramatsu
2017-12-07  7:19 ` [PATCH v2 1/5] perf-probe: Add warning message if there is unexpected event name Masami Hiramatsu
2017-12-07 15:53   ` Arnaldo Carvalho de Melo
2017-12-08  2:48     ` Masami Hiramatsu
2017-12-07  7:20 ` [PATCH v2 2/5] perf-probe: Cut off the version suffix from " Masami Hiramatsu
2017-12-07 16:34   ` Paul Clarke
2017-12-08  3:01     ` Masami Hiramatsu
2017-12-08 14:49       ` Paul Clarke
2017-12-08 16:12         ` Masami Hiramatsu
2017-12-11 18:25         ` Arnaldo Carvalho de Melo
2017-12-12 15:02           ` Masami Hiramatsu
2017-12-07 16:56   ` Arnaldo Carvalho de Melo
2017-12-07 17:24     ` Paul Clarke
2017-12-07 17:55       ` Arnaldo Carvalho de Melo
2017-12-08  3:15     ` Masami Hiramatsu
2017-12-07  7:20 ` [PATCH v2 3/5] perf-probe: Add __return suffix for return events Masami Hiramatsu
2017-12-07  7:21 ` [PATCH v2 4/5] perf-probe: Find versioned symbols from map Masami Hiramatsu
2017-12-08 11:08   ` Thomas-Mich Richter
2017-12-08 14:22     ` Masami Hiramatsu
2017-12-07  7:21 ` [PATCH v2 5/5] perf-probe: Support escaped character in parser Masami Hiramatsu
2017-12-08 11:45   ` Thomas-Mich Richter
2017-12-08 15:54     ` Masami Hiramatsu [this message]
2017-12-07 12:47 ` [PATCH v2 0/5] perf-probe: Improve probing on versioned symbols Ravi Bangoria
2017-12-08 16:24   ` Masami Hiramatsu
2017-12-08 17:13     ` Ravi Bangoria
2017-12-08 11:56 ` Thomas-Mich Richter
2017-12-08 16:12   ` Masami Hiramatsu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171209005443.344d2aa420803809f5427f1f@kernel.org \
    --to=mhiramat@kernel.org \
    --cc=acme@kernel.org \
    --cc=bhargavaramudu@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=linux-rt-users@vger.kernel.org \
    --cc=pc@us.ibm.com \
    --cc=ravi.bangoria@linux.vnet.ibm.com \
    --cc=tmricht@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.