mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00: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
@ -1079,6 +1079,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);
|
||||
@ -1362,30 +1363,37 @@ static bool is_c_func_name(const char *name)
|
||||
* FNC[@SRC][:SLN[+NUM|-ELN]]
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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';
|
||||
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;
|
||||
|
||||
@ -1409,42 +1417,41 @@ 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';
|
||||
if (strcmp(file, "*")) {
|
||||
lr->file = strdup_esc(file);
|
||||
p = strpbrk_esq(buf, "@");
|
||||
if (p) {
|
||||
*p++ = '\0';
|
||||
if (strcmp(p, "*")) {
|
||||
lr->file = strdup_esq(p);
|
||||
if (lr->file == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (*name != '\0')
|
||||
lr->function = name;
|
||||
if (*buf != '\0')
|
||||
lr->function = strdup_esq(buf);
|
||||
if (!lr->function && !lr->file) {
|
||||
semantic_error("Only '@*' is not allowed.\n");
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
} else if (strpbrk_esc(name, "/."))
|
||||
lr->file = name;
|
||||
else if (is_c_func_name(name))/* We reuse it for checking funcname */
|
||||
lr->function = name;
|
||||
} else if (strpbrk_esq(buf, "/."))
|
||||
lr->file = strdup_esq(buf);
|
||||
else if (is_c_func_name(buf))/* We reuse it for checking funcname */
|
||||
lr->function = strdup_esq(buf);
|
||||
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;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
free(name);
|
||||
free(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1452,19 +1459,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;
|
||||
|
||||
@ -1503,7 +1510,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 != '@') {
|
||||
@ -1517,7 +1524,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';
|
||||
@ -1558,7 +1565,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
|
||||
file_spec = true;
|
||||
}
|
||||
|
||||
ptr = strpbrk_esc(arg, ";:+@%");
|
||||
ptr = strpbrk_esq(arg, ";:+@%");
|
||||
if (ptr) {
|
||||
nc = *ptr;
|
||||
*ptr++ = '\0';
|
||||
@ -1567,7 +1574,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;
|
||||
}
|
||||
@ -1605,7 +1612,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';
|
||||
@ -1634,7 +1641,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
|
||||
}
|
||||
if (!strcmp(arg, "*"))
|
||||
break;
|
||||
pp->file = strdup_esc(arg);
|
||||
pp->file = strdup_esq(arg);
|
||||
if (pp->file == NULL)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user