Merge reason: pick up latest -rc.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
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
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
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
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;
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)
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);
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;
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)
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)
{
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;
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;
}
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);
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;
}
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:
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;
}
{
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);
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;
}
}
#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.
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;
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;
}
}
#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 */
/* 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;
}
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;
}
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);
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;
}
}
/* 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)
{
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 */
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;
}
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;
}
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) {
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;
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;
}
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;
}
}
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;
}
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;
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;
}
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;
}
/* 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;
}
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;
}
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;
}
#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
.exclude_other = true,
.use_modules = true,
.try_vmlinux_path = true,
+ .symfs = "",
};
int dso__name_len(const struct dso *self)
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;
}
* 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)
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;
}
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;
/*
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
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;
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:
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;
}
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,
};
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;
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)
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;
show_cpu_utilization,
initialized;
const char *vmlinux_name,
+ *kallsyms_name,
*source_prefix,
*field_sep;
const char *default_guest_vmlinux_name,
struct strlist *dso_list,
*comm_list,
*sym_list;
+ const char *symfs;
};
extern struct symbol_conf symbol_conf;
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,
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);