lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <ZyktL05NmqRTr213@x1>
Date: Mon, 4 Nov 2024 17:23:11 -0300
From: Arnaldo Carvalho de Melo <acme@...nel.org>
To: "Masami Hiramatsu (Google)" <mhiramat@...nel.org>
Cc: Namhyung Kim <namhyung@...nel.org>,
	Peter Zijlstra <peterz@...radead.org>,
	Ingo Molnar <mingo@...hat.com>, Ian Rogers <irogers@...gle.com>,
	Dima Kogan <dima@...retsauce.net>,
	Alexander Lobakin <aleksander.lobakin@...el.com>,
	Przemek Kitszel <przemyslaw.kitszel@...el.com>,
	linux-perf-users@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 3/4] perf-probe: Introduce quotation marks support

On Tue, Nov 05, 2024 at 01:17:35AM +0900, Masami Hiramatsu (Google) wrote:
> From: Masami Hiramatsu (Google) <mhiramat@...nel.org>
> 
> In non-C languages, it is possible to have ':' in the function names.
> It is possible to escape it with backslashes, but if there are too many
> backslashes, it is annoying.
> This introduce quotation marks (`"` or `'`) support.

Can you please split the patch so that strpbrk_esq() and strdup_esq()
are introduced in different patches?

- Arnaldo
 
> For example, without quotes, we have to pass it as below
> 
> $ perf probe -x cro3 -L "cro3\:\:cmd\:\:servo\:\:run_show"
> <run_show@...rk/cro3/src/cmd/servo.rs:0>
>       0  fn run_show(args: &ArgsShow) -> Result<()> {
>       1      let list = ServoList::discover()?;
>       2      let s = list.find_by_serial(&args.servo)?;
>       3      if args.json {
>       4          println!("{s}");
> 
> With quotes, we can more naturally write the function name as below;
> 
> $ ./perf probe -x cro3 -L \"cro3::cmd::servo::run_show\"
> <run_show@...rk/cro3/src/cmd/servo.rs:0>
>       0  fn run_show(args: &ArgsShow) -> Result<()> {
>       1      let list = ServoList::discover()?;
>       2      let s = list.find_by_serial(&args.servo)?;
>       3      if args.json {
>       4          println!("{s}");
> 
> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@...nel.org>
> ---
>  tools/perf/util/probe-event.c  |   76 ++++++++++++++++--------------
>  tools/perf/util/probe-finder.c |    3 +
>  tools/perf/util/string.c       |  100 ++++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/string2.h      |    2 +
>  4 files changed, 145 insertions(+), 36 deletions(-)
> 
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 913a27cbb5d9..bcba8273204d 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -1065,6 +1065,7 @@ static int __show_line_range(struct line_range *lr, const char *module,
>  
>  	ret = debuginfo__find_line_range(dinfo, lr);
>  	if (!ret) {	/* Not found, retry with an alternative */
> +		pr_debug2("Failed to find line range in debuginfo. Fallback to alternative\n");
>  		ret = get_alternative_line_range(dinfo, lr, module, user);
>  		if (!ret)
>  			ret = debuginfo__find_line_range(dinfo, lr);
> @@ -1078,7 +1079,7 @@ static int __show_line_range(struct line_range *lr, const char *module,
>  		pr_warning("Specified source line is not found.\n");
>  		return -ENOENT;
>  	} else if (ret < 0) {
> -		pr_warning("Debuginfo analysis failed.\n");
> +		pr_warning("Debuginfo analysis failed (%d).\n", ret);
>  		return ret;
>  	}
>  
> @@ -1187,7 +1188,7 @@ static int show_available_vars_at(struct debuginfo *dinfo,
>  			pr_err("Failed to find the address of %s\n", buf);
>  			ret = -ENOENT;
>  		} else
> -			pr_warning("Debuginfo analysis failed.\n");
> +			pr_warning("Debuginfo analysis failed(2).\n");
>  		goto end;
>  	}
>  
> @@ -1343,30 +1344,39 @@ static bool is_c_func_name(const char *name)
>   *
>   *         @SRC[:SLN[+NUM|-ELN]]
>   *         FNC[@SRC][:SLN[+NUM|-ELN]]
> + *
> + * SRC and FUNC can be quoted by double/single quotes.
>   */
>  int parse_line_range_desc(const char *arg, struct line_range *lr)
>  {
> -	char *range, *file, *name = strdup(arg);
> +	char *buf = strdup(arg);
> +	char *p;
>  	int err;
>  
> -	if (!name)
> +	if (!buf)
>  		return -ENOMEM;
>  
>  	lr->start = 0;
>  	lr->end = INT_MAX;
>  
> -	range = strpbrk_esc(name, ":");
> -	if (range) {
> -		*range++ = '\0';
> +	pr_debug2("Input line range: %s\n", buf);
> +	p = strpbrk_esq(buf, ":");
> +	if (p) {
> +		if (p == buf) {
> +			semantic_error("No file/function name in '%s'.\n", p);
> +			err = -EINVAL;
> +			goto err;
> +		}
> +		*(p++) = '\0';
>  
> -		err = parse_line_num(&range, &lr->start, "start line");
> +		err = parse_line_num(&p, &lr->start, "start line");
>  		if (err)
>  			goto err;
>  
> -		if (*range == '+' || *range == '-') {
> -			const char c = *range++;
> +		if (*p == '+' || *p == '-') {
> +			const char c = *(p++);
>  
> -			err = parse_line_num(&range, &lr->end, "end line");
> +			err = parse_line_num(&p, &lr->end, "end line");
>  			if (err)
>  				goto err;
>  
> @@ -1390,28 +1400,22 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
>  				       " than end line.\n");
>  			goto err;
>  		}
> -		if (*range != '\0') {
> -			semantic_error("Tailing with invalid str '%s'.\n", range);
> +		if (*p != '\0') {
> +			semantic_error("Tailing with invalid str '%s'.\n", p);
>  			goto err;
>  		}
>  	}
>  
> -	file = strpbrk_esc(name, "@");
> -	if (file) {
> -		*file = '\0';
> -		lr->file = strdup_esc(++file);
> -		if (lr->file == NULL) {
> -			err = -ENOMEM;
> -			goto err;
> -		}
> -		if (*name != '\0')
> -			lr->function = name;
> -	} else
> -		lr->function = name;
> +	p = strpbrk_esq(buf, "@");
> +	if (p) {
> +		*(p++) = '\0';
> +		lr->file = strdup_esq(p);
> +	}
> +	lr->function = strdup_esq(buf);
> +	err = 0;
>  
> -	return 0;
>  err:
> -	free(name);
> +	free(buf);
>  	return err;
>  }
>  
> @@ -1419,19 +1423,19 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
>  {
>  	char *ptr;
>  
> -	ptr = strpbrk_esc(*arg, ":");
> +	ptr = strpbrk_esq(*arg, ":");
>  	if (ptr) {
>  		*ptr = '\0';
>  		if (!pev->sdt && !is_c_func_name(*arg))
>  			goto ng_name;
> -		pev->group = strdup_esc(*arg);
> +		pev->group = strdup_esq(*arg);
>  		if (!pev->group)
>  			return -ENOMEM;
>  		*arg = ptr + 1;
>  	} else
>  		pev->group = NULL;
>  
> -	pev->event = strdup_esc(*arg);
> +	pev->event = strdup_esq(*arg);
>  	if (pev->event == NULL)
>  		return -ENOMEM;
>  
> @@ -1470,7 +1474,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
>  			arg++;
>  	}
>  
> -	ptr = strpbrk_esc(arg, ";=@+%");
> +	ptr = strpbrk_esq(arg, ";=@+%");
>  	if (pev->sdt) {
>  		if (ptr) {
>  			if (*ptr != '@') {
> @@ -1484,7 +1488,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_esc(ptr + 1);
> +				pev->target = strdup_esq(ptr + 1);
>  			if (!pev->target)
>  				return -ENOMEM;
>  			*ptr = '\0';
> @@ -1518,7 +1522,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
>  		arg++;
>  	}
>  
> -	ptr = strpbrk_esc(arg, ";:+@%");
> +	ptr = strpbrk_esq(arg, ";:+@%");
>  	if (ptr) {
>  		nc = *ptr;
>  		*ptr++ = '\0';
> @@ -1527,7 +1531,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
>  	if (arg[0] == '\0')
>  		tmp = NULL;
>  	else {
> -		tmp = strdup_esc(arg);
> +		tmp = strdup_esq(arg);
>  		if (tmp == NULL)
>  			return -ENOMEM;
>  	}
> @@ -1565,7 +1569,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
>  				return -ENOMEM;
>  			break;
>  		}
> -		ptr = strpbrk_esc(arg, ";:+@%");
> +		ptr = strpbrk_esq(arg, ";:+@%");
>  		if (ptr) {
>  			nc = *ptr;
>  			*ptr++ = '\0';
> @@ -1592,7 +1596,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_esc(arg);
> +			pp->file = strdup_esq(arg);
>  			if (pp->file == NULL)
>  				return -ENOMEM;
>  			break;
> diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
> index 630e16c54ed5..5462b5541a6d 100644
> --- a/tools/perf/util/probe-finder.c
> +++ b/tools/perf/util/probe-finder.c
> @@ -1796,6 +1796,7 @@ int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr)
>  		struct dwarf_callback_param line_range_param = {
>  			.data = (void *)&lf, .retval = 0};
>  
> +		pr_debug2("Start searching function '%s' in getpubname\n", lr->function);
>  		dwarf_getpubnames(dbg->dbg, pubname_search_cb,
>  				  &pubname_param, 0);
>  		if (pubname_param.found) {
> @@ -1803,8 +1804,10 @@ int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr)
>  			if (lf.found)
>  				goto found;
>  		}
> +		pr_debug2("Not found, use DIE tree\n");
>  	}
>  
> +	pr_debug2("Search function '%s' in DIE tree\n", lr->function);
>  	/* Loop on CUs (Compilation Unit) */
>  	while (!lf.found && ret >= 0) {
>  		if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl,
> diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
> index 116a642ad99d..308fc7ec88cc 100644
> --- a/tools/perf/util/string.c
> +++ b/tools/perf/util/string.c
> @@ -263,6 +263,34 @@ char *strpbrk_esc(char *str, const char *stopset)
>  	return ptr;
>  }
>  
> +/* Like strpbrk_esc(), but not break if it is quoted with single/double quotes */
> +char *strpbrk_esq(char *str, const char *stopset)
> +{
> +	char *_stopset = NULL;
> +	char *ptr;
> +	const char *squote = "'";
> +	const char *dquote = "\"";
> +
> +	if (asprintf(&_stopset, "%s%c%c", stopset, *squote, *dquote) < 0)
> +		return NULL;
> +
> +	do {
> +		ptr = strpbrk_esc(str, _stopset);
> +		if (!ptr)
> +			break;
> +		if (*ptr == *squote)
> +			ptr = strpbrk_esc(ptr + 1, squote);
> +		else if (*ptr == *dquote)
> +			ptr = strpbrk_esc(ptr + 1, dquote);
> +		else
> +			break;
> +		str = ptr + 1;
> +	} while (ptr);
> +
> +	free(_stopset);
> +	return ptr;
> +}
> +
>  /* Like strdup, but do not copy a single backslash */
>  char *strdup_esc(const char *str)
>  {
> @@ -293,6 +321,78 @@ char *strdup_esc(const char *str)
>  	return ret;
>  }
>  
> +/* Remove backslash right before quote and return next quote address. */
> +static char *remove_consumed_esc(char *str, int len, int quote)
> +{
> +	char *ptr = str, *end = str + len;
> +
> +	while (*ptr != quote && ptr < end) {
> +		if (*ptr == '\\' && *(ptr + 1) == quote) {
> +			memmove(ptr, ptr + 1, end - (ptr + 1));
> +			/* now *ptr is `quote`. */
> +			end--;
> +		}
> +		ptr++;
> +	}
> +
> +	return *ptr == quote ? ptr : NULL;
> +}
> +
> +/*
> + * Like strdup_esc, but keep quoted string as it is (and single backslash
> + * before quote is removed). If there is no closed quote, return NULL.
> + */
> +char *strdup_esq(const char *str)
> +{
> +	char *d, *ret;
> +
> +	/* If there is no quote, return normal strdup_esc() */
> +	d = strpbrk_esc((char *)str, "\"'");
> +	if (!d)
> +		return strdup_esc(str);
> +
> +	ret = strdup(str);
> +	if (!ret)
> +		return NULL;
> +
> +	d = ret;
> +	do {
> +		d = strpbrk(d, "\\\"\'");
> +		if (!d)
> +			break;
> +
> +		if (*d == '"' || *d == '\'') {
> +			/* This is non-escaped quote */
> +			int quote = *d;
> +			int len = strlen(d + 1) + 1;
> +
> +			/*
> +			 * Remove the start quote and remove consumed escape (backslash
> +			 * before quote) and remove the end quote. If there is no end
> +			 * quote, it is the input error.
> +			 */
> +			memmove(d, d + 1, len);
> +			d = remove_consumed_esc(d, len, quote);
> +			if (!d)
> +				goto error;
> +			memmove(d, d + 1, strlen(d + 1) + 1);
> +		}
> +		if (*d == '\\') {
> +			memmove(d, d + 1, strlen(d + 1) + 1);
> +			if (*d == '\\') {
> +				/* double backslash -- keep the second one. */
> +				d++;
> +			}
> +		}
> +	} while (*d != '\0');
> +
> +	return ret;
> +
> +error:
> +	free(ret);
> +	return NULL;
> +}
> +
>  unsigned int hex(char c)
>  {
>  	if (c >= '0' && c <= '9')
> diff --git a/tools/perf/util/string2.h b/tools/perf/util/string2.h
> index 52cb8ba057c7..4c8bff47cfd3 100644
> --- a/tools/perf/util/string2.h
> +++ b/tools/perf/util/string2.h
> @@ -37,6 +37,8 @@ char *asprintf__tp_filter_pids(size_t npids, pid_t *pids);
>  
>  char *strpbrk_esc(char *str, const char *stopset);
>  char *strdup_esc(const char *str);
> +char *strpbrk_esq(char *str, const char *stopset);
> +char *strdup_esq(const char *str);
>  
>  unsigned int hex(char c);
>  char *strreplace_chars(char needle, const char *haystack, const char *replace);

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ