Merge commit 'v2.6.37-rc8' into perf/core
authorIngo Molnar <mingo@elte.hu>
Tue, 4 Jan 2011 07:08:51 +0000 (08:08 +0100)
committerIngo Molnar <mingo@elte.hu>
Tue, 4 Jan 2011 07:08:54 +0000 (08:08 +0100)
Merge reason: pick up latest -rc.

Signed-off-by: Ingo Molnar <mingo@elte.hu>

1  2 
MAINTAINERS
tools/perf/builtin-buildid-list.c
tools/perf/util/header.c
tools/perf/util/probe-event.c
tools/perf/util/probe-finder.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h

diff --combined MAINTAINERS
@@@ -405,7 -405,7 +405,7 @@@ S: Supporte
  F:    drivers/usb/gadget/amd5536udc.*
  
  AMD GEODE PROCESSOR/CHIPSET SUPPORT
- P:    Jordan Crouse
+ P:    Andres Salomon <dilinger@queued.net>
  L:    linux-geode@lists.infradead.org (moderated for non-subscribers)
  W:    http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
  S:    Supported
@@@ -4590,7 -4590,7 +4590,7 @@@ F:      drivers/pcmcia
  F:    include/pcmcia/
  
  PCNET32 NETWORK DRIVER
- M:    Don Fry <pcnet32@verizon.net>
+ M:    Don Fry <pcnet32@frontier.com>
  L:    netdev@vger.kernel.org
  S:    Maintained
  F:    drivers/net/pcnet32.c
@@@ -4612,7 -4612,7 +4612,7 @@@ PERFORMANCE EVENTS SUBSYSTE
  M:    Peter Zijlstra <a.p.zijlstra@chello.nl>
  M:    Paul Mackerras <paulus@samba.org>
  M:    Ingo Molnar <mingo@elte.hu>
 -M:    Arnaldo Carvalho de Melo <acme@redhat.com>
 +M:    Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
  S:    Supported
  F:    kernel/perf_event*.c
  F:    include/linux/perf_event.h
@@@ -36,11 -36,9 +36,10 @@@ static const struct option options[] = 
  
  static int __cmd_buildid_list(void)
  {
-       int err = -1;
        struct perf_session *session;
  
 -      session = perf_session__new(input_name, O_RDONLY, force, false);
 +      session = perf_session__new(input_name, O_RDONLY, force, false,
 +                                  &build_id__mark_dso_hit_ops);
        if (session == NULL)
                return -1;
  
@@@ -50,7 -48,7 +49,7 @@@
        perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
  
        perf_session__delete(session);
-       return err;
+       return 0;
  }
  
  int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
diff --combined tools/perf/util/header.c
@@@ -152,11 -152,6 +152,11 @@@ void perf_header__set_feat(struct perf_
        set_bit(feat, self->adds_features);
  }
  
 +void perf_header__clear_feat(struct perf_header *self, int feat)
 +{
 +      clear_bit(feat, self->adds_features);
 +}
 +
  bool perf_header__has_feat(const struct perf_header *self, int feat)
  {
        return test_bit(feat, self->adds_features);
@@@ -270,15 -265,16 +270,16 @@@ int build_id_cache__add_s(const char *s
                          const char *name, bool is_kallsyms)
  {
        const size_t size = PATH_MAX;
-       char *filename = malloc(size),
+       char *realname = realpath(name, NULL),
+            *filename = malloc(size),
             *linkname = malloc(size), *targetname;
        int len, err = -1;
  
-       if (filename == NULL || linkname == NULL)
+       if (realname == NULL || filename == NULL || linkname == NULL)
                goto out_free;
  
        len = snprintf(filename, size, "%s%s%s",
-                      debugdir, is_kallsyms ? "/" : "", name);
+                      debugdir, is_kallsyms ? "/" : "", realname);
        if (mkdir_p(filename, 0755))
                goto out_free;
  
                if (is_kallsyms) {
                         if (copyfile("/proc/kallsyms", filename))
                                goto out_free;
-               } else if (link(name, filename) && copyfile(name, filename))
+               } else if (link(realname, filename) && copyfile(name, filename))
                        goto out_free;
        }
  
        if (symlink(targetname, linkname) == 0)
                err = 0;
  out_free:
+       free(realname);
        free(filename);
        free(linkname);
        return err;
@@@ -436,10 -433,8 +438,10 @@@ static int perf_header__adds_write(stru
        int idx = 0, err;
  
        session = container_of(self, struct perf_session, header);
 -      if (perf_session__read_build_ids(session, true))
 -              perf_header__set_feat(self, HEADER_BUILD_ID);
 +
 +      if (perf_header__has_feat(self, HEADER_BUILD_ID &&
 +          !perf_session__read_build_ids(session, true)))
 +              perf_header__clear_feat(self, HEADER_BUILD_ID);
  
        nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
        if (!nr_sections)
@@@ -946,24 -941,6 +948,24 @@@ u64 perf_header__sample_type(struct per
        return type;
  }
  
 +bool perf_header__sample_id_all(const struct perf_header *header)
 +{
 +      bool value = false, first = true;
 +      int i;
 +
 +      for (i = 0; i < header->attrs; i++) {
 +              struct perf_header_attr *attr = header->attr[i];
 +
 +              if (first) {
 +                      value = attr->attr.sample_id_all;
 +                      first = false;
 +              } else if (value != attr->attr.sample_id_all)
 +                      die("non matching sample_id_all");
 +      }
 +
 +      return value;
 +}
 +
  struct perf_event_attr *
  perf_header__find_attr(u64 id, struct perf_header *header)
  {
@@@ -1010,23 -987,21 +1012,23 @@@ int event__synthesize_attr(struct perf_
  
        ev = malloc(size);
  
 +      if (ev == NULL)
 +              return -ENOMEM;
 +
        ev->attr.attr = *attr;
        memcpy(ev->attr.id, id, ids * sizeof(u64));
  
        ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
        ev->attr.header.size = size;
  
 -      err = process(ev, session);
 +      err = process(ev, NULL, session);
  
        free(ev);
  
        return err;
  }
  
 -int event__synthesize_attrs(struct perf_header *self,
 -                          event__handler_t process,
 +int event__synthesize_attrs(struct perf_header *self, event__handler_t process,
                            struct perf_session *session)
  {
        struct perf_header_attr *attr;
@@@ -1096,7 -1071,7 +1098,7 @@@ int event__synthesize_event_type(u64 ev
        ev.event_type.header.size = sizeof(ev.event_type) -
                (sizeof(ev.event_type.event_type.name) - size);
  
 -      err = process(&ev, session);
 +      err = process(&ev, NULL, session);
  
        return err;
  }
@@@ -1151,7 -1126,7 +1153,7 @@@ int event__synthesize_tracing_data(int 
        ev.tracing_data.header.size = sizeof(ev.tracing_data);
        ev.tracing_data.size = aligned_size;
  
 -      process(&ev, session);
 +      process(&ev, NULL, session);
  
        err = read_tracing_data(fd, pattrs, nb_events);
        write_padded(fd, NULL, 0, padding);
@@@ -1211,7 -1186,7 +1213,7 @@@ int event__synthesize_build_id(struct d
        ev.build_id.header.size = sizeof(ev.build_id) + len;
        memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
  
 -      err = process(&ev, session);
 +      err = process(&ev, NULL, session);
  
        return err;
  }
@@@ -95,7 -95,7 +95,7 @@@ static int init_vmlinux(void
                goto out;
  
        if (machine__create_kernel_maps(&machine) < 0) {
 -              pr_debug("machine__create_kernel_maps ");
 +              pr_debug("machine__create_kernel_maps() failed.\n");
                goto out;
        }
  out:
@@@ -114,6 -114,8 +114,8 @@@ static struct symbol *__find_kernel_fun
  const char *kernel_get_module_path(const char *module)
  {
        struct dso *dso;
+       struct map *map;
+       const char *vmlinux_name;
  
        if (module) {
                list_for_each_entry(dso, &machine.kernel_dsos, node) {
                }
                pr_debug("Failed to find module %s.\n", module);
                return NULL;
+       }
+       map = machine.vmlinux_maps[MAP__FUNCTION];
+       dso = map->dso;
+       vmlinux_name = symbol_conf.vmlinux_name;
+       if (vmlinux_name) {
+               if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0)
+                       return NULL;
        } else {
-               dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
-               if (dso__load_vmlinux_path(dso,
-                        machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
+               if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
                        pr_debug("Failed to load kernel map.\n");
                        return NULL;
                }
@@@ -140,8 -149,7 +149,8 @@@ static int open_vmlinux(const char *mod
  {
        const char *path = kernel_get_module_path(module);
        if (!path) {
 -              pr_err("Failed to find path of %s module", module ?: "kernel");
 +              pr_err("Failed to find path of %s module.\n",
 +                     module ?: "kernel");
                return -ENOENT;
        }
        pr_debug("Try to open %s\n", path);
@@@ -218,7 -226,7 +227,7 @@@ static int try_to_find_probe_trace_even
                pr_warning("Warning: No dwarf info found in the vmlinux - "
                        "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
                if (!need_dwarf) {
 -                      pr_debug("Trying to use symbols.\nn");
 +                      pr_debug("Trying to use symbols.\n");
                        return 0;
                }
        }
@@@ -287,49 -295,42 +296,49 @@@ static int get_real_path(const char *ra
  #define LINEBUF_SIZE 256
  #define NR_ADDITIONAL_LINES 2
  
 -static int show_one_line(FILE *fp, int l, bool skip, bool show_num)
 +static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
  {
        char buf[LINEBUF_SIZE];
 -      const char *color = PERF_COLOR_BLUE;
 +      const char *color = show_num ? "" : PERF_COLOR_BLUE;
 +      const char *prefix = NULL;
  
 -      if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
 -              goto error;
 -      if (!skip) {
 -              if (show_num)
 -                      fprintf(stdout, "%7d  %s", l, buf);
 -              else
 -                      color_fprintf(stdout, color, "         %s", buf);
 -      }
 -
 -      while (strlen(buf) == LINEBUF_SIZE - 1 &&
 -             buf[LINEBUF_SIZE - 2] != '\n') {
 +      do {
                if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
                        goto error;
 -              if (!skip) {
 -                      if (show_num)
 -                              fprintf(stdout, "%s", buf);
 -                      else
 -                              color_fprintf(stdout, color, "%s", buf);
 +              if (skip)
 +                      continue;
 +              if (!prefix) {
 +                      prefix = show_num ? "%7d  " : "         ";
 +                      color_fprintf(stdout, color, prefix, l);
                }
 -      }
 +              color_fprintf(stdout, color, "%s", buf);
  
 -      return 0;
 +      } while (strchr(buf, '\n') == NULL);
 +
 +      return 1;
  error:
 -      if (feof(fp))
 -              pr_warning("Source file is shorter than expected.\n");
 -      else
 +      if (ferror(fp)) {
                pr_warning("File read error: %s\n", strerror(errno));
 +              return -1;
 +      }
 +      return 0;
 +}
  
 -      return -1;
 +static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
 +{
 +      int rv = __show_one_line(fp, l, skip, show_num);
 +      if (rv == 0) {
 +              pr_warning("Source file is shorter than expected.\n");
 +              rv = -1;
 +      }
 +      return rv;
  }
  
 +#define show_one_line_with_num(f,l)   _show_one_line(f,l,false,true)
 +#define show_one_line(f,l)            _show_one_line(f,l,false,false)
 +#define skip_one_line(f,l)            _show_one_line(f,l,true,false)
 +#define show_one_line_or_eof(f,l)     __show_one_line(f,l,false,false)
 +
  /*
   * Show line-range always requires debuginfo to find source file and
   * line number.
@@@ -378,7 -379,7 +387,7 @@@ int show_line_range(struct line_range *
                fprintf(stdout, "<%s:%d>\n", lr->function,
                        lr->start - lr->offset);
        else
 -              fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
 +              fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
  
        fp = fopen(lr->path, "r");
        if (fp == NULL) {
                return -errno;
        }
        /* Skip to starting line number */
 -      while (l < lr->start && ret >= 0)
 -              ret = show_one_line(fp, l++, true, false);
 -      if (ret < 0)
 -              goto end;
 +      while (l < lr->start) {
 +              ret = skip_one_line(fp, l++);
 +              if (ret < 0)
 +                      goto end;
 +      }
  
        list_for_each_entry(ln, &lr->line_list, list) {
 -              while (ln->line > l && ret >= 0)
 -                      ret = show_one_line(fp, (l++) - lr->offset,
 -                                          false, false);
 -              if (ret >= 0)
 -                      ret = show_one_line(fp, (l++) - lr->offset,
 -                                          false, true);
 +              for (; ln->line > l; l++) {
 +                      ret = show_one_line(fp, l - lr->offset);
 +                      if (ret < 0)
 +                              goto end;
 +              }
 +              ret = show_one_line_with_num(fp, l++ - lr->offset);
                if (ret < 0)
                        goto end;
        }
  
        if (lr->end == INT_MAX)
                lr->end = l + NR_ADDITIONAL_LINES;
 -      while (l <= lr->end && !feof(fp) && ret >= 0)
 -              ret = show_one_line(fp, (l++) - lr->offset, false, false);
 +      while (l <= lr->end) {
 +              ret = show_one_line_or_eof(fp, l++ - lr->offset);
 +              if (ret <= 0)
 +                      break;
 +      }
  end:
        fclose(fp);
        return ret;
@@@ -469,7 -466,7 +478,7 @@@ int show_available_vars(struct perf_pro
  
        fd = open_vmlinux(module);
        if (fd < 0) {
 -              pr_warning("Failed to open debuginfo file.\n");
 +              pr_warning("Failed to open debug information file.\n");
                return fd;
        }
  
@@@ -529,87 -526,56 +538,87 @@@ int show_available_vars(struct perf_pro
  }
  #endif
  
 +static int parse_line_num(char **ptr, int *val, const char *what)
 +{
 +      const char *start = *ptr;
 +
 +      errno = 0;
 +      *val = strtol(*ptr, ptr, 0);
 +      if (errno || *ptr == start) {
 +              semantic_error("'%s' is not a valid number.\n", what);
 +              return -EINVAL;
 +      }
 +      return 0;
 +}
 +
 +/*
 + * Stuff 'lr' according to the line range described by 'arg'.
 + * The line range syntax is described by:
 + *
 + *         SRC[:SLN[+NUM|-ELN]]
 + *         FNC[:SLN[+NUM|-ELN]]
 + */
  int parse_line_range_desc(const char *arg, struct line_range *lr)
  {
 -      const char *ptr;
 -      char *tmp;
 -      /*
 -       * <Syntax>
 -       * SRC:SLN[+NUM|-ELN]
 -       * FUNC[:SLN[+NUM|-ELN]]
 -       */
 -      ptr = strchr(arg, ':');
 -      if (ptr) {
 -              lr->start = (int)strtoul(ptr + 1, &tmp, 0);
 -              if (*tmp == '+') {
 -                      lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
 -                      lr->end--;      /*
 -                                       * Adjust the number of lines here.
 -                                       * If the number of lines == 1, the
 -                                       * the end of line should be equal to
 -                                       * the start of line.
 -                                       */
 -              } else if (*tmp == '-')
 -                      lr->end = (int)strtoul(tmp + 1, &tmp, 0);
 -              else
 -                      lr->end = INT_MAX;
 +      char *range, *name = strdup(arg);
 +      int err;
 +
 +      if (!name)
 +              return -ENOMEM;
 +
 +      lr->start = 0;
 +      lr->end = INT_MAX;
 +
 +      range = strchr(name, ':');
 +      if (range) {
 +              *range++ = '\0';
 +
 +              err = parse_line_num(&range, &lr->start, "start line");
 +              if (err)
 +                      goto err;
 +
 +              if (*range == '+' || *range == '-') {
 +                      const char c = *range++;
 +
 +                      err = parse_line_num(&range, &lr->end, "end line");
 +                      if (err)
 +                              goto err;
 +
 +                      if (c == '+') {
 +                              lr->end += lr->start;
 +                              /*
 +                               * Adjust the number of lines here.
 +                               * If the number of lines == 1, the
 +                               * the end of line should be equal to
 +                               * the start of line.
 +                               */
 +                              lr->end--;
 +                      }
 +              }
 +
                pr_debug("Line range is %d to %d\n", lr->start, lr->end);
 +
 +              err = -EINVAL;
                if (lr->start > lr->end) {
                        semantic_error("Start line must be smaller"
                                       " than end line.\n");
 -                      return -EINVAL;
 +                      goto err;
                }
 -              if (*tmp != '\0') {
 -                      semantic_error("Tailing with invalid character '%d'.\n",
 -                                     *tmp);
 -                      return -EINVAL;
 +              if (*range != '\0') {
 +                      semantic_error("Tailing with invalid str '%s'.\n", range);
 +                      goto err;
                }
 -              tmp = strndup(arg, (ptr - arg));
 -      } else {
 -              tmp = strdup(arg);
 -              lr->end = INT_MAX;
        }
  
 -      if (tmp == NULL)
 -              return -ENOMEM;
 -
 -      if (strchr(tmp, '.'))
 -              lr->file = tmp;
 +      if (strchr(name, '.'))
 +              lr->file = name;
        else
 -              lr->function = tmp;
 +              lr->function = name;
  
        return 0;
 +err:
 +      free(name);
 +      return err;
  }
  
  /* Check the name is good for event/group */
@@@ -733,40 -699,39 +742,40 @@@ static int parse_perf_probe_point(char 
  
        /* Exclusion check */
        if (pp->lazy_line && pp->line) {
 -              semantic_error("Lazy pattern can't be used with line number.");
 +              semantic_error("Lazy pattern can't be used with"
 +                             " line number.\n");
                return -EINVAL;
        }
  
        if (pp->lazy_line && pp->offset) {
 -              semantic_error("Lazy pattern can't be used with offset.");
 +              semantic_error("Lazy pattern can't be used with offset.\n");
                return -EINVAL;
        }
  
        if (pp->line && pp->offset) {
 -              semantic_error("Offset can't be used with line number.");
 +              semantic_error("Offset can't be used with line number.\n");
                return -EINVAL;
        }
  
        if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
                semantic_error("File always requires line number or "
 -                             "lazy pattern.");
 +                             "lazy pattern.\n");
                return -EINVAL;
        }
  
        if (pp->offset && !pp->function) {
 -              semantic_error("Offset requires an entry function.");
 +              semantic_error("Offset requires an entry function.\n");
                return -EINVAL;
        }
  
        if (pp->retprobe && !pp->function) {
 -              semantic_error("Return probe requires an entry function.");
 +              semantic_error("Return probe requires an entry function.\n");
                return -EINVAL;
        }
  
        if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
                semantic_error("Offset/Line/Lazy pattern can't be used with "
 -                             "return probe.");
 +                             "return probe.\n");
                return -EINVAL;
        }
  
@@@ -1040,7 -1005,7 +1049,7 @@@ int synthesize_perf_probe_arg(struct pe
  
        return tmp - buf;
  error:
 -      pr_debug("Failed to synthesize perf probe argument: %s",
 +      pr_debug("Failed to synthesize perf probe argument: %s\n",
                 strerror(-ret));
        return ret;
  }
@@@ -1068,13 -1033,13 +1077,13 @@@ static char *synthesize_perf_probe_poin
                        goto error;
        }
        if (pp->file) {
 -              len = strlen(pp->file) - 31;
 -              if (len < 0)
 -                      len = 0;
 -              tmp = strchr(pp->file + len, '/');
 -              if (!tmp)
 -                      tmp = pp->file + len;
 -              ret = e_snprintf(file, 32, "@%s", tmp + 1);
 +              tmp = pp->file;
 +              len = strlen(tmp);
 +              if (len > 30) {
 +                      tmp = strchr(pp->file + len - 30, '/');
 +                      tmp = tmp ? tmp + 1 : pp->file + len - 30;
 +              }
 +              ret = e_snprintf(file, 32, "@%s", tmp);
                if (ret <= 0)
                        goto error;
        }
  
        return buf;
  error:
 -      pr_debug("Failed to synthesize perf probe point: %s",
 +      pr_debug("Failed to synthesize perf probe point: %s\n",
                 strerror(-ret));
        if (buf)
                free(buf);
@@@ -1831,7 -1796,7 +1840,7 @@@ static int del_trace_probe_event(int fd
  
        ret = e_snprintf(buf, 128, "%s:%s", group, event);
        if (ret < 0) {
 -              pr_err("Failed to copy event.");
 +              pr_err("Failed to copy event.\n");
                return ret;
        }
  
@@@ -117,28 -117,6 +117,6 @@@ static void line_list__free(struct list
  }
  
  /* Dwarf FL wrappers */
- static int __linux_kernel_find_elf(Dwfl_Module *mod,
-                                  void **userdata,
-                                  const char *module_name,
-                                  Dwarf_Addr base,
-                                  char **file_name, Elf **elfp)
- {
-       int fd;
-       const char *path = kernel_get_module_path(module_name);
-       if (path) {
-               fd = open(path, O_RDONLY);
-               if (fd >= 0) {
-                       *file_name = strdup(path);
-                       return fd;
-               }
-       }
-       /* If failed, try to call standard method */
-       return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
-                                         file_name, elfp);
- }
  static char *debuginfo_path;  /* Currently dummy */
  
  static const Dwfl_Callbacks offline_callbacks = {
        .find_elf = dwfl_build_id_find_elf,
  };
  
- static const Dwfl_Callbacks kernel_callbacks = {
-       .find_debuginfo = dwfl_standard_find_debuginfo,
-       .debuginfo_path = &debuginfo_path,
-       .find_elf = __linux_kernel_find_elf,
-       .section_address = dwfl_linux_kernel_module_section_address,
- };
  /* Get a Dwarf from offline image */
  static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
  {
@@@ -185,6 -155,38 +155,38 @@@ error
        return dbg;
  }
  
+ #if _ELFUTILS_PREREQ(0, 148)
+ /* This method is buggy if elfutils is older than 0.148 */
+ static int __linux_kernel_find_elf(Dwfl_Module *mod,
+                                  void **userdata,
+                                  const char *module_name,
+                                  Dwarf_Addr base,
+                                  char **file_name, Elf **elfp)
+ {
+       int fd;
+       const char *path = kernel_get_module_path(module_name);
+       pr_debug2("Use file %s for %s\n", path, module_name);
+       if (path) {
+               fd = open(path, O_RDONLY);
+               if (fd >= 0) {
+                       *file_name = strdup(path);
+                       return fd;
+               }
+       }
+       /* If failed, try to call standard method */
+       return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
+                                         file_name, elfp);
+ }
+ static const Dwfl_Callbacks kernel_callbacks = {
+       .find_debuginfo = dwfl_standard_find_debuginfo,
+       .debuginfo_path = &debuginfo_path,
+       .find_elf = __linux_kernel_find_elf,
+       .section_address = dwfl_linux_kernel_module_section_address,
+ };
  /* Get a Dwarf from live kernel image */
  static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
                                          Dwarf_Addr *bias)
        dbg = dwfl_addrdwarf(*dwflp, addr, bias);
        /* Here, check whether we could get a real dwarf */
        if (!dbg) {
+               pr_debug("Failed to find kernel dwarf at %lx\n",
+                        (unsigned long)addr);
                dwfl_end(*dwflp);
                *dwflp = NULL;
        }
        return dbg;
  }
+ #else
+ /* With older elfutils, this just support kernel module... */
+ static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp,
+                                         Dwarf_Addr *bias)
+ {
+       int fd;
+       const char *path = kernel_get_module_path("kernel");
+       if (!path) {
+               pr_err("Failed to find vmlinux path\n");
+               return NULL;
+       }
+       pr_debug2("Use file %s for debuginfo\n", path);
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return NULL;
+       return dwfl_init_offline_dwarf(fd, dwflp, bias);
+ }
+ #endif
  
  /* Dwarf wrappers */
  
@@@ -627,8 -652,8 +652,8 @@@ static_var
        regs = get_arch_regstr(regn);
        if (!regs) {
                /* This should be a bug in DWARF or this tool */
 -              pr_warning("Mapping for DWARF register number %u "
 -                         "missing on this architecture.", regn);
 +              pr_warning("Mapping for the register number %u "
 +                         "missing on this architecture.\n", regn);
                return -ERANGE;
        }
  
@@@ -674,14 -699,13 +699,14 @@@ static int convert_variable_type(Dwarf_
                if (ret != DW_TAG_pointer_type &&
                    ret != DW_TAG_array_type) {
                        pr_warning("Failed to cast into string: "
 -                                 "%s(%s) is not a pointer nor array.",
 +                                 "%s(%s) is not a pointer nor array.\n",
                                   dwarf_diename(vr_die), dwarf_diename(&type));
                        return -EINVAL;
                }
                if (ret == DW_TAG_pointer_type) {
                        if (die_get_real_type(&type, &type) == NULL) {
 -                              pr_warning("Failed to get a type information.");
 +                              pr_warning("Failed to get a type"
 +                                         " information.\n");
                                return -ENOENT;
                        }
                        while (*ref_ptr)
                if (!die_compare_name(&type, "char") &&
                    !die_compare_name(&type, "unsigned char")) {
                        pr_warning("Failed to cast into string: "
 -                                 "%s is not (unsigned) char *.",
 +                                 "%s is not (unsigned) char *.\n",
                                   dwarf_diename(vr_die));
                        return -EINVAL;
                }
@@@ -806,8 -830,8 +831,8 @@@ static int convert_variable_fields(Dwar
                        return -EINVAL;
                }
                if (field->name[0] == '[') {
 -                      pr_err("Semantic error: %s is not a pointor nor array.",
 -                             varname);
 +                      pr_err("Semantic error: %s is not a pointor"
 +                             " nor array.\n", varname);
                        return -EINVAL;
                }
                if (field->ref) {
@@@ -954,7 -978,7 +979,7 @@@ static int convert_to_trace_point(Dwarf
        name = dwarf_diename(sp_die);
        if (name) {
                if (dwarf_entrypc(sp_die, &eaddr) != 0) {
 -                      pr_warning("Failed to get entry pc of %s\n",
 +                      pr_warning("Failed to get entry address of %s\n",
                                   dwarf_diename(sp_die));
                        return -ENOENT;
                }
        if (retprobe) {
                if (eaddr != paddr) {
                        pr_warning("Return probe must be on the head of"
 -                                 " a real function\n");
 +                                 " a real function.\n");
                        return -EINVAL;
                }
                tp->retprobe = true;
@@@ -1009,7 -1033,7 +1034,7 @@@ static int call_probe_finder(Dwarf_Die 
                Dwarf_Frame *frame;
                if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
                    dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
 -                      pr_warning("Failed to get CFA on 0x%jx\n",
 +                      pr_warning("Failed to get call frame on 0x%jx\n",
                                   (uintmax_t)pf->addr);
                        return -ENOENT;
                }
@@@ -1036,7 -1060,7 +1061,7 @@@ static int find_probe_point_by_line(str
        int ret = 0;
  
        if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
 -              pr_warning("No source lines found in this CU.\n");
 +              pr_warning("No source lines found.\n");
                return -ENOENT;
        }
  
@@@ -1138,7 -1162,7 +1163,7 @@@ static int find_probe_point_lazy(Dwarf_
        }
  
        if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
 -              pr_warning("No source lines found in this CU.\n");
 +              pr_warning("No source lines found.\n");
                return -ENOENT;
        }
  
@@@ -1196,7 -1220,7 +1221,7 @@@ static int probe_point_inline_cb(Dwarf_
        else {
                /* Get probe address */
                if (dwarf_entrypc(in_die, &addr) != 0) {
 -                      pr_warning("Failed to get entry pc of %s.\n",
 +                      pr_warning("Failed to get entry address of %s.\n",
                                   dwarf_diename(in_die));
                        param->retval = -ENOENT;
                        return DWARF_CB_ABORT;
@@@ -1237,8 -1261,8 +1262,8 @@@ static int probe_point_search_cb(Dwarf_
                        param->retval = find_probe_point_lazy(sp_die, pf);
                else {
                        if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
 -                              pr_warning("Failed to get entry pc of %s.\n",
 -                                         dwarf_diename(sp_die));
 +                              pr_warning("Failed to get entry address of "
 +                                         "%s.\n", dwarf_diename(sp_die));
                                param->retval = -ENOENT;
                                return DWARF_CB_ABORT;
                        }
@@@ -1280,7 -1304,7 +1305,7 @@@ static int find_probes(int fd, struct p
  
        dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
        if (!dbg) {
 -              pr_warning("No dwarf info found in the vmlinux - "
 +              pr_warning("No debug information found in the vmlinux - "
                        "please rebuild with CONFIG_DEBUG_INFO=y.\n");
                return -EBADF;
        }
@@@ -1525,7 -1549,7 +1550,7 @@@ int find_perf_probe_point(unsigned lon
        /* Open the live linux kernel */
        dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
        if (!dbg) {
 -              pr_warning("No dwarf info found in the vmlinux - "
 +              pr_warning("No debug information found in the vmlinux - "
                        "please rebuild with CONFIG_DEBUG_INFO=y.\n");
                ret = -EINVAL;
                goto end;
        addr += bias;
        /* Find cu die */
        if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
 -              pr_warning("No CU DIE is found at %lx\n", addr);
 +              pr_warning("Failed to find debug information for address %lx\n",
 +                         addr);
                ret = -EINVAL;
                goto end;
        }
@@@ -1661,7 -1684,7 +1686,7 @@@ static int find_line_range_by_line(Dwar
  
        line_list__init(&lf->lr->line_list);
        if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
 -              pr_warning("No source lines found in this CU.\n");
 +              pr_warning("No source lines found.\n");
                return -ENOENT;
        }
  
@@@ -1786,7 -1809,7 +1811,7 @@@ int find_line_range(int fd, struct line
  
        dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
        if (!dbg) {
 -              pr_warning("No dwarf info found in the vmlinux - "
 +              pr_warning("No debug information found in the vmlinux - "
                        "please rebuild with CONFIG_DEBUG_INFO=y.\n");
                return -EBADF;
        }
diff --combined tools/perf/util/symbol.c
  #include <limits.h>
  #include <sys/utsname.h>
  
 +#ifndef KSYM_NAME_LEN
 +#define KSYM_NAME_LEN 128
 +#endif
 +
  #ifndef NT_GNU_BUILD_ID
  #define NT_GNU_BUILD_ID 3
  #endif
@@@ -45,7 -41,6 +45,7 @@@ struct symbol_conf symbol_conf = 
        .exclude_other    = true,
        .use_modules      = true,
        .try_vmlinux_path = true,
 +      .symfs            = "",
  };
  
  int dso__name_len(const struct dso *self)
@@@ -97,7 -92,7 +97,7 @@@ static void symbols__fixup_end(struct r
                prev = curr;
                curr = rb_entry(nd, struct symbol, rb_node);
  
 -              if (prev->end == prev->start)
 +              if (prev->end == prev->start && prev->end != curr->start)
                        prev->end = curr->start - 1;
        }
  
@@@ -126,7 -121,7 +126,7 @@@ static void __map_groups__fixup_end(str
         * We still haven't the actual symbols, so guess the
         * last map final address.
         */
 -      curr->end = ~0UL;
 +      curr->end = ~0ULL;
  }
  
  static void map_groups__fixup_end(struct map_groups *self)
@@@ -430,25 -425,16 +430,25 @@@ size_t dso__fprintf(struct dso *self, e
  
  int kallsyms__parse(const char *filename, void *arg,
                    int (*process_symbol)(void *arg, const char *name,
 -                                                   char type, u64 start))
 +                                        char type, u64 start, u64 end))
  {
        char *line = NULL;
        size_t n;
 -      int err = 0;
 +      int err = -1;
 +      u64 prev_start = 0;
 +      char prev_symbol_type = 0;
 +      char *prev_symbol_name;
        FILE *file = fopen(filename, "r");
  
        if (file == NULL)
                goto out_failure;
  
 +      prev_symbol_name = malloc(KSYM_NAME_LEN);
 +      if (prev_symbol_name == NULL)
 +              goto out_close;
 +
 +      err = 0;
 +
        while (!feof(file)) {
                u64 start;
                int line_len, len;
                        continue;
  
                symbol_type = toupper(line[len]);
 -              symbol_name = line + len + 2;
 +              len += 2;
 +              symbol_name = line + len;
 +              len = line_len - len;
  
 -              err = process_symbol(arg, symbol_name, symbol_type, start);
 -              if (err)
 +              if (len >= KSYM_NAME_LEN) {
 +                      err = -1;
                        break;
 +              }
 +
 +              if (prev_symbol_type) {
 +                      u64 end = start;
 +                      if (end != prev_start)
 +                              --end;
 +                      err = process_symbol(arg, prev_symbol_name,
 +                                           prev_symbol_type, prev_start, end);
 +                      if (err)
 +                              break;
 +              }
 +
 +              memcpy(prev_symbol_name, symbol_name, len + 1);
 +              prev_symbol_type = symbol_type;
 +              prev_start = start;
        }
  
 +      free(prev_symbol_name);
        free(line);
 +out_close:
        fclose(file);
        return err;
  
@@@ -516,7 -483,7 +516,7 @@@ static u8 kallsyms2elf_type(char type
  }
  
  static int map__process_kallsym_symbol(void *arg, const char *name,
 -                                     char type, u64 start)
 +                                     char type, u64 start, u64 end)
  {
        struct symbol *sym;
        struct process_kallsyms_args *a = arg;
        if (!symbol_type__is_a(type, a->map->type))
                return 0;
  
 -      /*
 -       * Will fix up the end later, when we have all symbols sorted.
 -       */
 -      sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
 -
 +      sym = symbol__new(start, end - start + 1,
 +                        kallsyms2elf_type(type), name);
        if (sym == NULL)
                return -ENOMEM;
        /*
@@@ -679,6 -649,7 +679,6 @@@ int dso__load_kallsyms(struct dso *self
        if (dso__load_all_kallsyms(self, filename, map) < 0)
                return -1;
  
 -      symbols__fixup_end(&self->symbols[map->type]);
        if (self->kernel == DSO_TYPE_GUEST_KERNEL)
                self->origin = DSO__ORIG_GUEST_KERNEL;
        else
@@@ -868,11 -839,8 +868,11 @@@ static int dso__synthesize_plt_symbols(
        char sympltname[1024];
        Elf *elf;
        int nr = 0, symidx, fd, err = 0;
 +      char name[PATH_MAX];
  
 -      fd = open(self->long_name, O_RDONLY);
 +      snprintf(name, sizeof(name), "%s%s",
 +               symbol_conf.symfs, self->long_name);
 +      fd = open(name, O_RDONLY);
        if (fd < 0)
                goto out;
  
@@@ -1484,19 -1452,16 +1484,19 @@@ int dso__load(struct dso *self, struct 
             self->origin++) {
                switch (self->origin) {
                case DSO__ORIG_BUILD_ID_CACHE:
 -                      if (dso__build_id_filename(self, name, size) == NULL)
 +                      /* skip the locally configured cache if a symfs is given */
 +                      if (symbol_conf.symfs[0] ||
 +                          (dso__build_id_filename(self, name, size) == NULL)) {
                                continue;
 +                      }
                        break;
                case DSO__ORIG_FEDORA:
 -                      snprintf(name, size, "/usr/lib/debug%s.debug",
 -                               self->long_name);
 +                      snprintf(name, size, "%s/usr/lib/debug%s.debug",
 +                               symbol_conf.symfs, self->long_name);
                        break;
                case DSO__ORIG_UBUNTU:
 -                      snprintf(name, size, "/usr/lib/debug%s",
 -                               self->long_name);
 +                      snprintf(name, size, "%s/usr/lib/debug%s",
 +                               symbol_conf.symfs, self->long_name);
                        break;
                case DSO__ORIG_BUILDID: {
                        char build_id_hex[BUILD_ID_SIZE * 2 + 1];
                                          sizeof(self->build_id),
                                          build_id_hex);
                        snprintf(name, size,
 -                               "/usr/lib/debug/.build-id/%.2s/%s.debug",
 -                               build_id_hex, build_id_hex + 2);
 +                               "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
 +                               symbol_conf.symfs, build_id_hex, build_id_hex + 2);
                        }
                        break;
                case DSO__ORIG_DSO:
 -                      snprintf(name, size, "%s", self->long_name);
 +                      snprintf(name, size, "%s%s",
 +                           symbol_conf.symfs, self->long_name);
                        break;
                case DSO__ORIG_GUEST_KMODULE:
                        if (map->groups && map->groups->machine)
                                root_dir = map->groups->machine->root_dir;
                        else
                                root_dir = "";
 -                      snprintf(name, size, "%s%s", root_dir, self->long_name);
 +                      snprintf(name, size, "%s%s%s", symbol_conf.symfs,
 +                               root_dir, self->long_name);
 +                      break;
 +
 +              case DSO__ORIG_KMODULE:
 +                      snprintf(name, size, "%s%s", symbol_conf.symfs,
 +                               self->long_name);
                        break;
  
                default:
@@@ -1822,24 -1780,21 +1822,24 @@@ out_failure
        return -1;
  }
  
- static int dso__load_vmlinux(struct dso *self, struct map *map,
-                            const char *vmlinux, symbol_filter_t filter)
+ int dso__load_vmlinux(struct dso *self, struct map *map,
+                     const char *vmlinux, symbol_filter_t filter)
  {
        int err = -1, fd;
 +      char symfs_vmlinux[PATH_MAX];
  
 -      fd = open(vmlinux, O_RDONLY);
 +      snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
 +               symbol_conf.symfs, vmlinux);
 +      fd = open(symfs_vmlinux, O_RDONLY);
        if (fd < 0)
                return -1;
  
        dso__set_loaded(self, map->type);
 -      err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
 +      err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0);
        close(fd);
  
        if (err > 0)
 -              pr_debug("Using %s for symbols\n", vmlinux);
 +              pr_debug("Using %s for symbols\n", symfs_vmlinux);
  
        return err;
  }
@@@ -1881,8 -1836,8 +1881,8 @@@ static int dso__load_kernel_sym(struct 
        const char *kallsyms_filename = NULL;
        char *kallsyms_allocated_filename = NULL;
        /*
 -       * Step 1: if the user specified a vmlinux filename, use it and only
 -       * it, reporting errors to the user if it cannot be used.
 +       * Step 1: if the user specified a kallsyms or vmlinux filename, use
 +       * it and only it, reporting errors to the user if it cannot be used.
         *
         * For instance, try to analyse an ARM perf.data file _without_ a
         * build-id, or if the user specifies the wrong path to the right
         * validation in dso__load_vmlinux and will bail out if they don't
         * match.
         */
 +      if (symbol_conf.kallsyms_name != NULL) {
 +              kallsyms_filename = symbol_conf.kallsyms_name;
 +              goto do_kallsyms;
 +      }
 +
        if (symbol_conf.vmlinux_name != NULL) {
                err = dso__load_vmlinux(self, map,
                                        symbol_conf.vmlinux_name, filter);
                        goto out_fixup;
        }
  
 +      /* do not try local files if a symfs was given */
 +      if (symbol_conf.symfs[0] != 0)
 +              return -1;
 +
        /*
         * Say the kernel DSO was created when processing the build-id header table,
         * we have a build-id, so check if it is the same as the running kernel,
@@@ -2190,7 -2136,7 +2190,7 @@@ struct process_args 
  };
  
  static int symbol__in_kernel(void *arg, const char *name,
 -                           char type __used, u64 start)
 +                           char type __used, u64 start, u64 end __used)
  {
        struct process_args *args = arg;
  
@@@ -2311,6 -2257,9 +2311,6 @@@ static int vmlinux_path__init(void
        struct utsname uts;
        char bf[PATH_MAX];
  
 -      if (uname(&uts) < 0)
 -              return -1;
 -
        vmlinux_path = malloc(sizeof(char *) * 5);
        if (vmlinux_path == NULL)
                return -1;
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
                goto out_fail;
        ++vmlinux_path__nr_entries;
 +
 +      /* only try running kernel version if no symfs was given */
 +      if (symbol_conf.symfs[0] != 0)
 +              return 0;
 +
 +      if (uname(&uts) < 0)
 +              return -1;
 +
        snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
        vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
@@@ -2390,8 -2331,6 +2390,8 @@@ static int setup_list(struct strlist **
  
  int symbol__init(void)
  {
 +      const char *symfs;
 +
        if (symbol_conf.initialized)
                return 0;
  
                       symbol_conf.sym_list_str, "symbol") < 0)
                goto out_free_comm_list;
  
 +      /*
 +       * A path to symbols of "/" is identical to ""
 +       * reset here for simplicity.
 +       */
 +      symfs = realpath(symbol_conf.symfs, NULL);
 +      if (symfs == NULL)
 +              symfs = symbol_conf.symfs;
 +      if (strcmp(symfs, "/") == 0)
 +              symbol_conf.symfs = "";
 +      if (symfs != symbol_conf.symfs)
 +              free((void *)symfs);
 +
        symbol_conf.initialized = true;
        return 0;
  
diff --combined tools/perf/util/symbol.h
@@@ -72,7 -72,6 +72,7 @@@ struct symbol_conf 
                        show_cpu_utilization,
                        initialized;
        const char      *vmlinux_name,
 +                      *kallsyms_name,
                        *source_prefix,
                        *field_sep;
        const char      *default_guest_vmlinux_name,
@@@ -86,7 -85,6 +86,7 @@@
         struct strlist *dso_list,
                        *comm_list,
                        *sym_list;
 +      const char      *symfs;
  };
  
  extern struct symbol_conf symbol_conf;
@@@ -168,6 -166,8 +168,8 @@@ void dso__sort_by_name(struct dso *self
  struct dso *__dsos__findnew(struct list_head *head, const char *name);
  
  int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
+ int dso__load_vmlinux(struct dso *self, struct map *map,
+                     const char *vmlinux, symbol_filter_t filter);
  int dso__load_vmlinux_path(struct dso *self, struct map *map,
                           symbol_filter_t filter);
  int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
@@@ -215,7 -215,7 +217,7 @@@ bool __dsos__read_build_ids(struct list
  int build_id__sprintf(const u8 *self, int len, char *bf);
  int kallsyms__parse(const char *filename, void *arg,
                    int (*process_symbol)(void *arg, const char *name,
 -                                        char type, u64 start));
 +                                        char type, u64 start, u64 end));
  
  void machine__destroy_kernel_maps(struct machine *self);
  int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);