提交 8c1df400 编写于 作者: I Ingo Molnar

Merge branch 'perf/core' of...

Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
......@@ -66,6 +66,8 @@ OPTIONS
--force::
Don't complain, do it.
--symfs=<directory>::
Look for files with symbols relative to this directory.
SEE ALSO
--------
......
......@@ -117,7 +117,7 @@ LINE SYNTAX
-----------
Line range is described by following syntax.
"FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]"
"FUNC[:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
FUNC specifies the function name of showing lines. 'RLN' is the start line
number from function entry line, and 'RLN2' is the end line number. As same as
......
......@@ -116,6 +116,9 @@ OPTIONS
--force::
Don't complain, do it.
--symfs=<directory>::
Look for files with symbols relative to this directory.
SEE ALSO
--------
linkperf:perf-stat[1]
......@@ -38,6 +38,8 @@ OPTIONS
--process::
Select the processes to display, by name or PID
--symfs=<directory>::
Look for files with symbols relative to this directory.
SEE ALSO
--------
......
......@@ -375,6 +375,8 @@ static struct perf_event_ops event_ops = {
.mmap = event__process_mmap,
.comm = event__process_comm,
.fork = event__process_task,
.ordered_samples = true,
.ordering_requires_timestamps = true,
};
static int __cmd_annotate(void)
......@@ -382,7 +384,7 @@ static int __cmd_annotate(void)
int ret;
struct perf_session *session;
session = perf_session__new(input_name, O_RDONLY, force, false);
session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
if (session == NULL)
return -ENOMEM;
......
......@@ -39,7 +39,8 @@ 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;
......
......@@ -61,6 +61,8 @@ static struct perf_event_ops event_ops = {
.exit = event__process_task,
.fork = event__process_task,
.lost = event__process_lost,
.ordered_samples = true,
.ordering_requires_timestamps = true,
};
static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
......@@ -142,8 +144,8 @@ static int __cmd_diff(void)
int ret, i;
struct perf_session *session[2];
session[0] = perf_session__new(input_old, O_RDONLY, force, false);
session[1] = perf_session__new(input_new, O_RDONLY, force, false);
session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops);
session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops);
if (session[0] == NULL || session[1] == NULL)
return -ENOMEM;
......@@ -192,6 +194,8 @@ static const struct option options[] = {
OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
"separator for columns, no spaces will be added between "
"columns '.' is reserved."),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
"Look for files with symbols relative to this directory"),
OPT_END()
};
......
......@@ -196,7 +196,7 @@ static int __cmd_inject(void)
inject_ops.tracing_data = event__repipe_tracing_data;
}
session = perf_session__new(input_name, O_RDONLY, false, true);
session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
if (session == NULL)
return -ENOMEM;
......
......@@ -481,7 +481,8 @@ static void sort_result(void)
static int __cmd_kmem(void)
{
int err = -EINVAL;
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false);
struct perf_session *session = perf_session__new(input_name, O_RDONLY,
0, false, &event_ops);
if (session == NULL)
return -ENOMEM;
......
......@@ -858,7 +858,7 @@ static struct perf_event_ops eops = {
static int read_events(void)
{
session = perf_session__new(input_name, O_RDONLY, 0, false);
session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
if (!session)
die("Initializing perf session failed\n");
......
......@@ -285,7 +285,7 @@ static void create_counter(int counter, int cpu)
if (system_wide)
attr->sample_type |= PERF_SAMPLE_CPU;
if (sample_time)
if (sample_time || system_wide || !no_inherit || cpu_list)
attr->sample_type |= PERF_SAMPLE_TIME;
if (raw_samples) {
......@@ -327,6 +327,9 @@ static void create_counter(int counter, int cpu)
* Old kernel, no attr->sample_id_type_all field
*/
sample_id_all_avail = false;
if (!sample_time && !raw_samples)
attr->sample_type &= ~PERF_SAMPLE_TIME;
goto retry_sample_id;
}
......@@ -572,7 +575,7 @@ static int __cmd_record(int argc, const char **argv)
}
session = perf_session__new(output_name, O_WRONLY,
write_mode == WRITE_FORCE, false);
write_mode == WRITE_FORCE, false, NULL);
if (session == NULL) {
pr_err("Not enough memory for reading perf file header\n");
return -1;
......
......@@ -244,6 +244,8 @@ static struct perf_event_ops event_ops = {
.event_type = event__process_event_type,
.tracing_data = event__process_tracing_data,
.build_id = event__process_build_id,
.ordered_samples = true,
.ordering_requires_timestamps = true,
};
extern volatile int session_done;
......@@ -308,7 +310,7 @@ static int __cmd_report(void)
signal(SIGINT, sig_handler);
session = perf_session__new(input_name, O_RDONLY, force, false);
session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
if (session == NULL)
return -ENOMEM;
......@@ -481,6 +483,8 @@ static const struct option options[] = {
"columns '.' is reserved."),
OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
"Only display entries resolved to a symbol"),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
"Look for files with symbols relative to this directory"),
OPT_END()
};
......
......@@ -1643,7 +1643,8 @@ static struct perf_event_ops event_ops = {
static int read_events(void)
{
int err = -EINVAL;
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false);
struct perf_session *session = perf_session__new(input_name, O_RDONLY,
0, false, &event_ops);
if (session == NULL)
return -ENOMEM;
......
......@@ -779,7 +779,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
if (!script_name)
setup_pager();
session = perf_session__new(input_name, O_RDONLY, 0, false);
session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
if (session == NULL)
return -ENOMEM;
......
......@@ -937,7 +937,8 @@ static struct perf_event_ops event_ops = {
static int __cmd_timechart(void)
{
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false);
struct perf_session *session = perf_session__new(input_name, O_RDONLY,
0, false, &event_ops);
int ret = -EINVAL;
if (session == NULL)
......@@ -1021,6 +1022,8 @@ static const struct option options[] = {
OPT_CALLBACK('p', "process", NULL, "process",
"process selector. Pass a pid or process name.",
parse_process),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
"Look for files with symbols relative to this directory"),
OPT_END()
};
......
......@@ -1272,7 +1272,7 @@ static int __cmd_top(void)
* FIXME: perf_session__new should allow passing a O_MMAP, so that all this
* mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
*/
struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false);
struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
if (session == NULL)
return -ENOMEM;
......
......@@ -1092,6 +1092,12 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
FILE *file;
int err = 0;
u64 len;
char symfs_filename[PATH_MAX];
if (filename) {
snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
symbol_conf.symfs, filename);
}
if (filename == NULL) {
if (dso->has_build_id) {
......@@ -1100,9 +1106,9 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
return -ENOMEM;
}
goto fallback;
} else if (readlink(filename, command, sizeof(command)) < 0 ||
} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
strstr(command, "[kernel.kallsyms]") ||
access(filename, R_OK)) {
access(symfs_filename, R_OK)) {
free(filename);
fallback:
/*
......@@ -1111,6 +1117,8 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
* DSO is the same as when 'perf record' ran.
*/
filename = dso->long_name;
snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
symbol_conf.symfs, filename);
free_filename = false;
}
......@@ -1137,7 +1145,7 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
"objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end),
filename, filename);
symfs_filename, filename);
pr_debug("Executing: %s\n", command);
......
......@@ -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:
......@@ -140,7 +140,8 @@ static int open_vmlinux(const char *module)
{
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);
......@@ -217,7 +218,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
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;
}
}
......@@ -286,42 +287,49 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
#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))
if (ferror(fp)) {
pr_warning("Source file is shorter than expected.\n");
else
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.
......@@ -370,7 +378,7 @@ int show_line_range(struct line_range *lr, const char *module)
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) {
......@@ -379,26 +387,30 @@ int show_line_range(struct line_range *lr, const char *module)
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;
......@@ -457,7 +469,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
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;
}
......@@ -517,56 +529,87 @@ int show_available_vars(struct perf_probe_event *pevs __unused,
}
#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 */
......@@ -690,39 +733,40 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
/* 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;
}
......@@ -996,7 +1040,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
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;
}
......@@ -1046,7 +1090,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
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);
......@@ -1787,7 +1831,7 @@ static int del_trace_probe_event(int fd, const char *group,
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;
}
......
......@@ -627,8 +627,8 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
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,13 +674,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
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)
......@@ -695,7 +696,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
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;
}
......@@ -805,8 +806,8 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
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) {
......@@ -953,7 +954,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
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;
}
......@@ -969,7 +970,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
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;
......@@ -1008,7 +1009,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
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;
}
......@@ -1035,7 +1036,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
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;
}
......@@ -1137,7 +1138,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
}
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;
}
......@@ -1195,7 +1196,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
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;
......@@ -1236,8 +1237,8 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
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;
}
......@@ -1279,7 +1280,7 @@ static int find_probes(int fd, struct probe_finder *pf)
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;
}
......@@ -1524,7 +1525,7 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
/* 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;
......@@ -1534,7 +1535,8 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
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;
}
......@@ -1659,7 +1661,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
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;
}
......@@ -1784,7 +1786,7 @@ int find_line_range(int fd, struct line_range *lr)
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;
}
......
......@@ -125,7 +125,9 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
machines__destroy_guest_kernel_maps(&self->machines);
}
struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe)
struct perf_session *perf_session__new(const char *filename, int mode,
bool force, bool repipe,
struct perf_event_ops *ops)
{
size_t len = filename ? strlen(filename) + 1 : 0;
struct perf_session *self = zalloc(sizeof(*self) + len);
......@@ -170,6 +172,13 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
}
perf_session__update_sample_type(self);
if (ops && ops->ordering_requires_timestamps &&
ops->ordered_samples && !self->sample_id_all) {
dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
ops->ordered_samples = false;
}
out:
return self;
out_free:
......
......@@ -78,9 +78,12 @@ struct perf_event_ops {
build_id;
event_op2 finished_round;
bool ordered_samples;
bool ordering_requires_timestamps;
};
struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe);
struct perf_session *perf_session__new(const char *filename, int mode,
bool force, bool repipe,
struct perf_event_ops *ops);
void perf_session__delete(struct perf_session *self);
void perf_event_header__bswap(struct perf_event_header *self);
......
......@@ -41,6 +41,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)
......@@ -839,8 +840,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
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;
......@@ -1452,16 +1456,19 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
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];
......@@ -1473,19 +1480,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
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:
......@@ -1784,17 +1798,20 @@ static 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;
}
......@@ -1872,6 +1889,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
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,
......@@ -2262,9 +2283,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;
......@@ -2277,6 +2295,14 @@ static int vmlinux_path__init(void)
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)
......@@ -2336,6 +2362,8 @@ static int setup_list(struct strlist **list, const char *list_str,
int symbol__init(void)
{
const char *symfs;
if (symbol_conf.initialized)
return 0;
......@@ -2364,6 +2392,18 @@ int symbol__init(void)
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;
......
......@@ -86,6 +86,7 @@ struct symbol_conf {
struct strlist *dso_list,
*comm_list,
*sym_list;
const char *symfs;
};
extern struct symbol_conf symbol_conf;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册