mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	perf probe: Introduce quotation marks support
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.
For example, without quotes, we have to pass it as below
  $ perf probe -x cro3 -L "cro3\:\:cmd\:\:servo\:\:run_show"
  <run_show@/work/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@/work/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 <mhiramat@kernel.org>
Cc: Alexander Lobakin <aleksander.lobakin@intel.com>
Cc: Dima Kogan <dima@secretsauce.net>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Link: https://lore.kernel.org/r/173099116941.2431889.11609129616090100386.stgit@mhiramat.roam.corp.google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									313026f3ce
								
							
						
					
					
						commit
						080e47b2a2
					
				
					 1 changed files with 41 additions and 34 deletions
				
			
		| 
						 | 
					@ -1079,6 +1079,7 @@ static int __show_line_range(struct line_range *lr, const char *module,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = debuginfo__find_line_range(dinfo, lr);
 | 
						ret = debuginfo__find_line_range(dinfo, lr);
 | 
				
			||||||
	if (!ret) {	/* Not found, retry with an alternative */
 | 
						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);
 | 
							ret = get_alternative_line_range(dinfo, lr, module, user);
 | 
				
			||||||
		if (!ret)
 | 
							if (!ret)
 | 
				
			||||||
			ret = debuginfo__find_line_range(dinfo, lr);
 | 
								ret = debuginfo__find_line_range(dinfo, lr);
 | 
				
			||||||
| 
						 | 
					@ -1362,30 +1363,37 @@ static bool is_c_func_name(const char *name)
 | 
				
			||||||
 *         FNC[@SRC][:SLN[+NUM|-ELN]]
 | 
					 *         FNC[@SRC][:SLN[+NUM|-ELN]]
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * FNC@SRC accepts `FNC@*` which forcibly specify FNC as function name.
 | 
					 * FNC@SRC accepts `FNC@*` which forcibly specify FNC as function name.
 | 
				
			||||||
 | 
					 * SRC and FUNC can be quoted by double/single quotes.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int parse_line_range_desc(const char *arg, struct line_range *lr)
 | 
					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;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!name)
 | 
						if (!buf)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lr->start = 0;
 | 
						lr->start = 0;
 | 
				
			||||||
	lr->end = INT_MAX;
 | 
						lr->end = INT_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	range = strpbrk_esc(name, ":");
 | 
						p = strpbrk_esq(buf, ":");
 | 
				
			||||||
	if (range) {
 | 
						if (p) {
 | 
				
			||||||
		*range++ = '\0';
 | 
							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)
 | 
							if (err)
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (*range == '+' || *range == '-') {
 | 
							if (*p == '+' || *p == '-') {
 | 
				
			||||||
			const char c = *range++;
 | 
								const char c = *(p++);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			err = parse_line_num(&range, &lr->end, "end line");
 | 
								err = parse_line_num(&p, &lr->end, "end line");
 | 
				
			||||||
			if (err)
 | 
								if (err)
 | 
				
			||||||
				goto err;
 | 
									goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1409,42 +1417,41 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
 | 
				
			||||||
				       " than end line.\n");
 | 
									       " than end line.\n");
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (*range != '\0') {
 | 
							if (*p != '\0') {
 | 
				
			||||||
			semantic_error("Tailing with invalid str '%s'.\n", range);
 | 
								semantic_error("Tailing with invalid str '%s'.\n", p);
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	file = strpbrk_esc(name, "@");
 | 
						p = strpbrk_esq(buf, "@");
 | 
				
			||||||
	if (file) {
 | 
						if (p) {
 | 
				
			||||||
		*file++ = '\0';
 | 
							*p++ = '\0';
 | 
				
			||||||
		if (strcmp(file, "*")) {
 | 
							if (strcmp(p, "*")) {
 | 
				
			||||||
			lr->file = strdup_esc(file);
 | 
								lr->file = strdup_esq(p);
 | 
				
			||||||
			if (lr->file == NULL) {
 | 
								if (lr->file == NULL) {
 | 
				
			||||||
				err = -ENOMEM;
 | 
									err = -ENOMEM;
 | 
				
			||||||
				goto err;
 | 
									goto err;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (*name != '\0')
 | 
							if (*buf != '\0')
 | 
				
			||||||
			lr->function = name;
 | 
								lr->function = strdup_esq(buf);
 | 
				
			||||||
		if (!lr->function && !lr->file) {
 | 
							if (!lr->function && !lr->file) {
 | 
				
			||||||
			semantic_error("Only '@*' is not allowed.\n");
 | 
								semantic_error("Only '@*' is not allowed.\n");
 | 
				
			||||||
			err = -EINVAL;
 | 
								err = -EINVAL;
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (strpbrk_esc(name, "/."))
 | 
						} else if (strpbrk_esq(buf, "/."))
 | 
				
			||||||
		lr->file = name;
 | 
							lr->file = strdup_esq(buf);
 | 
				
			||||||
	else if (is_c_func_name(name))/* We reuse it for checking funcname */
 | 
						else if (is_c_func_name(buf))/* We reuse it for checking funcname */
 | 
				
			||||||
		lr->function = name;
 | 
							lr->function = strdup_esq(buf);
 | 
				
			||||||
	else {	/* Invalid name */
 | 
						else {	/* Invalid name */
 | 
				
			||||||
		semantic_error("'%s' is not a valid function name.\n", name);
 | 
							semantic_error("'%s' is not a valid function name.\n", buf);
 | 
				
			||||||
		err = -EINVAL;
 | 
							err = -EINVAL;
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
err:
 | 
					err:
 | 
				
			||||||
	free(name);
 | 
						free(buf);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1452,19 +1459,19 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char *ptr;
 | 
						char *ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ptr = strpbrk_esc(*arg, ":");
 | 
						ptr = strpbrk_esq(*arg, ":");
 | 
				
			||||||
	if (ptr) {
 | 
						if (ptr) {
 | 
				
			||||||
		*ptr = '\0';
 | 
							*ptr = '\0';
 | 
				
			||||||
		if (!pev->sdt && !is_c_func_name(*arg))
 | 
							if (!pev->sdt && !is_c_func_name(*arg))
 | 
				
			||||||
			goto ng_name;
 | 
								goto ng_name;
 | 
				
			||||||
		pev->group = strdup_esc(*arg);
 | 
							pev->group = strdup_esq(*arg);
 | 
				
			||||||
		if (!pev->group)
 | 
							if (!pev->group)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		*arg = ptr + 1;
 | 
							*arg = ptr + 1;
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		pev->group = NULL;
 | 
							pev->group = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pev->event = strdup_esc(*arg);
 | 
						pev->event = strdup_esq(*arg);
 | 
				
			||||||
	if (pev->event == NULL)
 | 
						if (pev->event == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1503,7 +1510,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 | 
				
			||||||
			arg++;
 | 
								arg++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ptr = strpbrk_esc(arg, ";=@+%");
 | 
						ptr = strpbrk_esq(arg, ";=@+%");
 | 
				
			||||||
	if (pev->sdt) {
 | 
						if (pev->sdt) {
 | 
				
			||||||
		if (ptr) {
 | 
							if (ptr) {
 | 
				
			||||||
			if (*ptr != '@') {
 | 
								if (*ptr != '@') {
 | 
				
			||||||
| 
						 | 
					@ -1517,7 +1524,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 | 
				
			||||||
				pev->target = build_id_cache__origname(tmp);
 | 
									pev->target = build_id_cache__origname(tmp);
 | 
				
			||||||
				free(tmp);
 | 
									free(tmp);
 | 
				
			||||||
			} else
 | 
								} else
 | 
				
			||||||
				pev->target = strdup_esc(ptr + 1);
 | 
									pev->target = strdup_esq(ptr + 1);
 | 
				
			||||||
			if (!pev->target)
 | 
								if (!pev->target)
 | 
				
			||||||
				return -ENOMEM;
 | 
									return -ENOMEM;
 | 
				
			||||||
			*ptr = '\0';
 | 
								*ptr = '\0';
 | 
				
			||||||
| 
						 | 
					@ -1558,7 +1565,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 | 
				
			||||||
			file_spec = true;
 | 
								file_spec = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ptr = strpbrk_esc(arg, ";:+@%");
 | 
						ptr = strpbrk_esq(arg, ";:+@%");
 | 
				
			||||||
	if (ptr) {
 | 
						if (ptr) {
 | 
				
			||||||
		nc = *ptr;
 | 
							nc = *ptr;
 | 
				
			||||||
		*ptr++ = '\0';
 | 
							*ptr++ = '\0';
 | 
				
			||||||
| 
						 | 
					@ -1567,7 +1574,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 | 
				
			||||||
	if (arg[0] == '\0')
 | 
						if (arg[0] == '\0')
 | 
				
			||||||
		tmp = NULL;
 | 
							tmp = NULL;
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		tmp = strdup_esc(arg);
 | 
							tmp = strdup_esq(arg);
 | 
				
			||||||
		if (tmp == NULL)
 | 
							if (tmp == NULL)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1605,7 +1612,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 | 
				
			||||||
				return -ENOMEM;
 | 
									return -ENOMEM;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ptr = strpbrk_esc(arg, ";:+@%");
 | 
							ptr = strpbrk_esq(arg, ";:+@%");
 | 
				
			||||||
		if (ptr) {
 | 
							if (ptr) {
 | 
				
			||||||
			nc = *ptr;
 | 
								nc = *ptr;
 | 
				
			||||||
			*ptr++ = '\0';
 | 
								*ptr++ = '\0';
 | 
				
			||||||
| 
						 | 
					@ -1634,7 +1641,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (!strcmp(arg, "*"))
 | 
								if (!strcmp(arg, "*"))
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			pp->file = strdup_esc(arg);
 | 
								pp->file = strdup_esq(arg);
 | 
				
			||||||
			if (pp->file == NULL)
 | 
								if (pp->file == NULL)
 | 
				
			||||||
				return -ENOMEM;
 | 
									return -ENOMEM;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue