Em Fri, Jun 30, 2017 at 07:18:55PM -0700, Krister Johansen escreveu:
> Teaches perf how to place a uprobe on a file that's in a different mount
> namespace.  The user must add the probe using the --target-ns argument
> to perf probe.  Once it has been placed, it may be recorded against
> without further namespace-specific commands.
> 
> Signed-off-by: Krister Johansen <k...@templeofstupid.com>
> ---
>  tools/perf/builtin-probe.c    | 44 ++++++++++++++++++++++--
>  tools/perf/util/probe-event.c | 79 
> +++++++++++++++++++++++++++++--------------
>  tools/perf/util/probe-event.h | 10 ++++--
>  3 files changed, 101 insertions(+), 32 deletions(-)
> 
> diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
> index cf9f9e9..5ab2e00 100644
> --- a/tools/perf/builtin-probe.c
> +++ b/tools/perf/builtin-probe.c
> @@ -58,6 +58,7 @@ static struct {
>       struct line_range line_range;
>       char *target;
>       struct strfilter *filter;
> +     struct nsinfo *nsi;
>  } params;
>  
>  /* Parse an event definition. Note that any error must die. */
> @@ -80,6 +81,9 @@ static int parse_probe_event(const char *str)
>               params.target_used = true;
>       }
>  
> +     if (params.nsi)
> +             pev->nsi = nsinfo__get(params.nsi);
> +
>       /* Parse a perf-probe command into event */
>       ret = parse_perf_probe_command(str, pev);
>       pr_debug("%d arguments\n", pev->nargs);
> @@ -178,6 +182,7 @@ static int opt_set_target(const struct option *opt, const 
> char *str,
>  {
>       int ret = -ENOENT;
>       char *tmp;
> +     struct nscookie nsc;
>  
>       if  (str) {
>               if (!strcmp(opt->long_name, "exec"))
> @@ -189,7 +194,9 @@ static int opt_set_target(const struct option *opt, const 
> char *str,
>  
>               /* Expand given path to absolute path, except for modulename */
>               if (params.uprobes || strchr(str, '/')) {
> +                     nsinfo__mountns_enter(params.nsi, &nsc);
>                       tmp = realpath(str, NULL);
> +                     nsinfo__mountns_exit(&nsc);

Perhaps have a nsinfo__realpath()? Don't know if this will be used
elsewhere, but looks shorter.

>                       if (!tmp) {
>                               pr_warning("Failed to get the absolute path of 
> %s: %m\n", str);
>                               return ret;
> @@ -208,6 +215,34 @@ static int opt_set_target(const struct option *opt, 
> const char *str,
>       return ret;
>  }
>  
> +static int opt_set_target_ns(const struct option *opt __maybe_unused,
> +                          const char *str, int unset __maybe_unused)
> +{
> +     int ret = -ENOENT;
> +     pid_t ns_pid;
> +     struct nsinfo *nsip;
> +
> +     if (str) {
> +             errno = 0;
> +             ns_pid = (pid_t)strtol(str, NULL, 10);
> +             if (errno != 0) {
> +                     ret = -errno;
> +                     pr_warning("Failed to parse %s as a pid: %s\n", str,
> +                                strerror(errno));
> +                     return ret;
> +             }
> +             nsip = nsinfo__new(ns_pid);
> +             if (nsip && nsip->need_setns)
> +                     params.nsi = nsinfo__get(nsip);
> +             nsinfo__put(nsip);
> +
> +             ret = 0;
> +     }
> +
> +     return ret;
> +}
> +
> +
>  /* Command option callbacks */
>  
>  #ifdef HAVE_DWARF_SUPPORT
> @@ -299,6 +334,7 @@ static void cleanup_params(void)
>       line_range__clear(&params.line_range);
>       free(params.target);
>       strfilter__delete(params.filter);
> +     nsinfo__put(params.nsi);
>       memset(&params, 0, sizeof(params));
>  }
>  
> @@ -554,6 +590,8 @@ __cmd_probe(int argc, const char **argv)
>       OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"),
>       OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
>                  "Look for files with symbols relative to this directory"),
> +     OPT_CALLBACK(0, "target-ns", NULL, "pid",
> +                  "target pid for namespace information", opt_set_target_ns),
>       OPT_END()
>       };
>       int ret;
> @@ -634,15 +672,15 @@ __cmd_probe(int argc, const char **argv)
>                       pr_err_with_code("  Error: Failed to show event list.", 
> ret);
>               return ret;
>       case 'F':
> -             ret = show_available_funcs(params.target, params.filter,
> -                                     params.uprobes);
> +             ret = show_available_funcs(params.target, params.nsi,
> +                                        params.filter, params.uprobes);
>               if (ret < 0)
>                       pr_err_with_code("  Error: Failed to show functions.", 
> ret);
>               return ret;
>  #ifdef HAVE_DWARF_SUPPORT
>       case 'L':
>               ret = show_line_range(&params.line_range, params.target,
> -                                   params.uprobes);
> +                                   params.nsi, params.uprobes);
>               if (ret < 0)
>                       pr_err_with_code("  Error: Failed to show lines.", ret);
>               return ret;
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 84e7e69..dce4f12 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -184,13 +184,19 @@ static struct map *kernel_get_module_map(const char 
> *module)
>       return NULL;
>  }
>  
> -struct map *get_target_map(const char *target, bool user)
> +struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)
>  {
>       /* Init maps of given executable or kernel */
> -     if (user)
> -             return dso__new_map(target);
> -     else
> +     if (user) {
> +             struct map *map;
> +
> +             map = dso__new_map(target);
> +             if (map && map->dso)
> +                     map->dso->nsinfo = nsinfo__get(nsi);
> +             return map;
> +     } else {
>               return kernel_get_module_map(target);
> +     }
>  }
>  
>  static int convert_exec_to_group(const char *exec, char **result)
> @@ -366,7 +372,8 @@ static int kernel_get_module_dso(const char *module, 
> struct dso **pdso)
>  static int find_alternative_probe_point(struct debuginfo *dinfo,
>                                       struct perf_probe_point *pp,
>                                       struct perf_probe_point *result,
> -                                     const char *target, bool uprobes)
> +                                     const char *target, struct nsinfo *nsi,
> +                                     bool uprobes)
>  {
>       struct map *map = NULL;
>       struct symbol *sym;
> @@ -377,7 +384,7 @@ static int find_alternative_probe_point(struct debuginfo 
> *dinfo,
>       if (!pp->function || pp->file)
>               return -ENOTSUP;
>  
> -     map = get_target_map(target, uprobes);
> +     map = get_target_map(target, nsi, uprobes);
>       if (!map)
>               return -EINVAL;
>  
> @@ -421,8 +428,8 @@ static int get_alternative_probe_event(struct debuginfo 
> *dinfo,
>  
>       memcpy(tmp, &pev->point, sizeof(*tmp));
>       memset(&pev->point, 0, sizeof(pev->point));
> -     ret = find_alternative_probe_point(dinfo, tmp, &pev->point,
> -                                        pev->target, pev->uprobes);
> +     ret = find_alternative_probe_point(dinfo, tmp, &pev->point, pev->target,
> +                                        pev->nsi, pev->uprobes);
>       if (ret < 0)
>               memcpy(&pev->point, tmp, sizeof(*tmp));
>  
> @@ -444,7 +451,7 @@ static int get_alternative_line_range(struct debuginfo 
> *dinfo,
>       if (lr->end != INT_MAX)
>               len = lr->end - lr->start;
>       ret = find_alternative_probe_point(dinfo, &pp, &result,
> -                                        target, user);
> +                                        target, NULL, user);
>       if (!ret) {
>               lr->function = result.function;
>               lr->file = result.file;
> @@ -457,12 +464,14 @@ static int get_alternative_line_range(struct debuginfo 
> *dinfo,
>  }
>  
>  /* Open new debuginfo of given module */
> -static struct debuginfo *open_debuginfo(const char *module, bool silent)
> +static struct debuginfo *open_debuginfo(const char *module, struct nsinfo 
> *nsi,
> +                                     bool silent)
>  {
>       const char *path = module;
>       char reason[STRERR_BUFSIZE];
>       struct debuginfo *ret = NULL;
>       struct dso *dso = NULL;
> +     struct nscookie nsc;
>       int err;
>  
>       if (!module || !strchr(module, '/')) {
> @@ -480,6 +489,7 @@ static struct debuginfo *open_debuginfo(const char 
> *module, bool silent)
>               }
>               path = dso->long_name;
>       }
> +     nsinfo__mountns_enter(nsi, &nsc);
>       ret = debuginfo__new(path);
>       if (!ret && !silent) {
>               pr_warning("The %s file has no debug information.\n", path);
> @@ -489,6 +499,7 @@ static struct debuginfo *open_debuginfo(const char 
> *module, bool silent)
>                       pr_warning("Rebuild with -g, ");
>               pr_warning("or install an appropriate debuginfo package.\n");
>       }
> +     nsinfo__mountns_exit(&nsc);
>       return ret;
>  }
>  
> @@ -516,7 +527,7 @@ static struct debuginfo *debuginfo_cache__open(const char 
> *module, bool silent)
>               goto out;
>       }
>  
> -     debuginfo_cache = open_debuginfo(module, silent);
> +     debuginfo_cache = open_debuginfo(module, NULL, silent);
>       if (!debuginfo_cache)
>               zfree(&debuginfo_cache_path);
>  out:
> @@ -531,14 +542,18 @@ static void debuginfo_cache__exit(void)
>  }
>  
>  
> -static int get_text_start_address(const char *exec, unsigned long *address)
> +static int get_text_start_address(const char *exec, unsigned long *address,
> +                               struct nsinfo *nsi)
>  {
>       Elf *elf;
>       GElf_Ehdr ehdr;
>       GElf_Shdr shdr;
>       int fd, ret = -ENOENT;
> +     struct nscookie nsc;
>  
> +     nsinfo__mountns_enter(nsi, &nsc);
>       fd = open(exec, O_RDONLY);
> +     nsinfo__mountns_exit(&nsc);
>       if (fd < 0)
>               return -errno;
>  
> @@ -582,7 +597,7 @@ static int find_perf_probe_point_from_dwarf(struct 
> probe_trace_point *tp,
>                       ret = -EINVAL;
>                       goto error;
>               }
> -             ret = get_text_start_address(tp->module, &stext);
> +             ret = get_text_start_address(tp->module, &stext, NULL);
>               if (ret < 0)
>                       goto error;
>               addr += stext;
> @@ -659,7 +674,7 @@ post_process_offline_probe_trace_events(struct 
> probe_trace_event *tevs,
>  
>       /* Prepare a map for offline binary */
>       map = dso__new_map(pathname);
> -     if (!map || get_text_start_address(pathname, &stext) < 0) {
> +     if (!map || get_text_start_address(pathname, &stext, NULL) < 0) {
>               pr_warning("Failed to get ELF symbols for %s\n", pathname);
>               return -EINVAL;
>       }
> @@ -676,7 +691,8 @@ post_process_offline_probe_trace_events(struct 
> probe_trace_event *tevs,
>  }
>  
>  static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
> -                                       int ntevs, const char *exec)
> +                                       int ntevs, const char *exec,
> +                                       struct nsinfo *nsi)
>  {
>       int i, ret = 0;
>       unsigned long stext = 0;
> @@ -684,7 +700,7 @@ static int add_exec_to_probe_trace_events(struct 
> probe_trace_event *tevs,
>       if (!exec)
>               return 0;
>  
> -     ret = get_text_start_address(exec, &stext);
> +     ret = get_text_start_address(exec, &stext, nsi);
>       if (ret < 0)
>               return ret;
>  
> @@ -715,7 +731,7 @@ post_process_module_probe_trace_events(struct 
> probe_trace_event *tevs,
>       if (!module)
>               return 0;
>  
> -     map = get_target_map(module, false);
> +     map = get_target_map(module, NULL, false);
>       if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) {
>               pr_warning("Failed to get ELF symbols for %s\n", module);
>               return -EINVAL;
> @@ -802,7 +818,8 @@ static int post_process_probe_trace_events(struct 
> perf_probe_event *pev,
>       int ret;
>  
>       if (uprobe)
> -             ret = add_exec_to_probe_trace_events(tevs, ntevs, module);
> +             ret = add_exec_to_probe_trace_events(tevs, ntevs, module,
> +                                                  pev->nsi);
>       else if (module)
>               /* Currently ref_reloc_sym based probe is not for drivers */
>               ret = post_process_module_probe_trace_events(tevs, ntevs,
> @@ -825,7 +842,7 @@ static int try_to_find_probe_trace_events(struct 
> perf_probe_event *pev,
>       struct debuginfo *dinfo;
>       int ntevs, ret = 0;
>  
> -     dinfo = open_debuginfo(pev->target, !need_dwarf);
> +     dinfo = open_debuginfo(pev->target, pev->nsi, !need_dwarf);
>       if (!dinfo) {
>               if (need_dwarf)
>                       return -ENOENT;
> @@ -945,7 +962,7 @@ static int __show_line_range(struct line_range *lr, const 
> char *module,
>       char sbuf[STRERR_BUFSIZE];
>  
>       /* Search a line range */
> -     dinfo = open_debuginfo(module, false);
> +     dinfo = open_debuginfo(module, NULL, false);
>       if (!dinfo)
>               return -ENOENT;
>  
> @@ -1021,14 +1038,18 @@ static int __show_line_range(struct line_range *lr, 
> const char *module,
>       return ret;
>  }
>  
> -int show_line_range(struct line_range *lr, const char *module, bool user)
> +int show_line_range(struct line_range *lr, const char *module,
> +                 struct nsinfo *nsi, bool user)
>  {
>       int ret;
> +     struct nscookie nsc;
>  
>       ret = init_probe_symbol_maps(user);
>       if (ret < 0)
>               return ret;
> +     nsinfo__mountns_enter(nsi, &nsc);
>       ret = __show_line_range(lr, module, user);
> +     nsinfo__mountns_exit(&nsc);
>       exit_probe_symbol_maps();
>  
>       return ret;
> @@ -1111,7 +1132,7 @@ int show_available_vars(struct perf_probe_event *pevs, 
> int npevs,
>       if (ret < 0)
>               return ret;
>  
> -     dinfo = open_debuginfo(pevs->target, false);
> +     dinfo = open_debuginfo(pevs->target, pevs->nsi, false);
>       if (!dinfo) {
>               ret = -ENOENT;
>               goto out;
> @@ -2703,6 +2724,7 @@ static int __add_probe_trace_events(struct 
> perf_probe_event *pev,
>       struct probe_trace_event *tev = NULL;
>       struct probe_cache *cache = NULL;
>       struct strlist *namelist[2] = {NULL, NULL};
> +     struct nscookie nsc;
>  
>       up = pev->uprobes ? 1 : 0;
>       fd[up] = __open_probe_file_and_namelist(up, &namelist[up]);
> @@ -2729,7 +2751,9 @@ static int __add_probe_trace_events(struct 
> perf_probe_event *pev,
>               if (ret < 0)
>                       break;
>  
> +             nsinfo__mountns_enter(pev->nsi, &nsc);
>               ret = probe_file__add_event(fd[up], tev);
> +             nsinfo__mountns_exit(&nsc);
>               if (ret < 0)
>                       break;
>  
> @@ -2805,7 +2829,7 @@ static int find_probe_trace_events_from_map(struct 
> perf_probe_event *pev,
>       int ret, i, j, skipped = 0;
>       char *mod_name;
>  
> -     map = get_target_map(pev->target, pev->uprobes);
> +     map = get_target_map(pev->target, pev->nsi, pev->uprobes);
>       if (!map) {
>               ret = -EINVAL;
>               goto out;
> @@ -3345,13 +3369,16 @@ int apply_perf_probe_events(struct perf_probe_event 
> *pevs, int npevs)
>  void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs)
>  {
>       int i, j;
> +     struct perf_probe_event *pev;
>  
>       /* Loop 3: cleanup and free trace events  */
>       for (i = 0; i < npevs; i++) {
> +             pev = &pevs[i];
>               for (j = 0; j < pevs[i].ntevs; j++)
>                       clear_probe_trace_event(&pevs[i].tevs[j]);
>               zfree(&pevs[i].tevs);
>               pevs[i].ntevs = 0;
> +             nsinfo__zput(pev->nsi);
>               clear_perf_probe_event(&pevs[i]);
>       }
>  }
> @@ -3409,8 +3436,8 @@ int del_perf_probe_events(struct strfilter *filter)
>       return ret;
>  }
>  
> -int show_available_funcs(const char *target, struct strfilter *_filter,
> -                                     bool user)
> +int show_available_funcs(const char *target, struct nsinfo *nsi,
> +                      struct strfilter *_filter, bool user)
>  {
>          struct rb_node *nd;
>       struct map *map;
> @@ -3421,7 +3448,7 @@ int show_available_funcs(const char *target, struct 
> strfilter *_filter,
>               return ret;
>  
>       /* Get a symbol map */
> -     map = get_target_map(target, user);
> +     map = get_target_map(target, nsi, user);
>       if (!map) {
>               pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
>               return -EINVAL;
> diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
> index 5812947..078681d 100644
> --- a/tools/perf/util/probe-event.h
> +++ b/tools/perf/util/probe-event.h
> @@ -4,6 +4,7 @@
>  #include <linux/compiler.h>
>  #include <stdbool.h>
>  #include "intlist.h"
> +#include "namespaces.h"
>  
>  /* Probe related configurations */
>  struct probe_conf {
> @@ -92,6 +93,7 @@ struct perf_probe_event {
>       struct perf_probe_arg   *args;  /* Arguments */
>       struct probe_trace_event *tevs;
>       int                     ntevs;
> +     struct nsinfo           *nsi;   /* Target namespace */
>  };
>  
>  /* Line range */
> @@ -163,10 +165,12 @@ int show_perf_probe_event(const char *group, const char 
> *event,
>                         struct perf_probe_event *pev,
>                         const char *module, bool use_stdout);
>  int show_perf_probe_events(struct strfilter *filter);
> -int show_line_range(struct line_range *lr, const char *module, bool user);
> +int show_line_range(struct line_range *lr, const char *module,
> +                 struct nsinfo *nsi, bool user);
>  int show_available_vars(struct perf_probe_event *pevs, int npevs,
>                       struct strfilter *filter);
> -int show_available_funcs(const char *module, struct strfilter *filter, bool 
> user);
> +int show_available_funcs(const char *module, struct nsinfo *nsi,
> +                      struct strfilter *filter, bool user);
>  void arch__fix_tev_from_maps(struct perf_probe_event *pev,
>                            struct probe_trace_event *tev, struct map *map,
>                            struct symbol *sym);
> @@ -180,7 +184,7 @@ int e_snprintf(char *str, size_t size, const char 
> *format, ...) __printf(3, 4);
>  int copy_to_probe_trace_arg(struct probe_trace_arg *tvar,
>                           struct perf_probe_arg *pvar);
>  
> -struct map *get_target_map(const char *target, bool user);
> +struct map *get_target_map(const char *target, struct nsinfo *nsi, bool 
> user);
>  
>  void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
>                                          int ntevs);
> -- 
> 2.7.4

Reply via email to