perf probe: Introduce quotation marks support
authorMasami Hiramatsu (Google) <mhiramat@kernel.org>
Thu, 7 Nov 2024 14:52:49 +0000 (23:52 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 14 Nov 2024 19:56:32 +0000 (16:56 -0300)
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>
tools/perf/util/probe-event.c

index c287e89dabcb1246ba286dbb032030082c73446e..1d5184697871718928b283d76c99582d525e5d69 100644 (file)
@@ -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;