Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
This commit is contained in:
commit
8c1df4002a
|
@ -66,6 +66,8 @@ OPTIONS
|
||||||
--force::
|
--force::
|
||||||
Don't complain, do it.
|
Don't complain, do it.
|
||||||
|
|
||||||
|
--symfs=<directory>::
|
||||||
|
Look for files with symbols relative to this directory.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -117,7 +117,7 @@ LINE SYNTAX
|
||||||
-----------
|
-----------
|
||||||
Line range is described by following 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
|
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
|
number from function entry line, and 'RLN2' is the end line number. As same as
|
||||||
|
|
|
@ -116,6 +116,9 @@ OPTIONS
|
||||||
--force::
|
--force::
|
||||||
Don't complain, do it.
|
Don't complain, do it.
|
||||||
|
|
||||||
|
--symfs=<directory>::
|
||||||
|
Look for files with symbols relative to this directory.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
linkperf:perf-stat[1]
|
linkperf:perf-stat[1]
|
||||||
|
|
|
@ -38,6 +38,8 @@ OPTIONS
|
||||||
--process::
|
--process::
|
||||||
Select the processes to display, by name or PID
|
Select the processes to display, by name or PID
|
||||||
|
|
||||||
|
--symfs=<directory>::
|
||||||
|
Look for files with symbols relative to this directory.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -375,6 +375,8 @@ static struct perf_event_ops event_ops = {
|
||||||
.mmap = event__process_mmap,
|
.mmap = event__process_mmap,
|
||||||
.comm = event__process_comm,
|
.comm = event__process_comm,
|
||||||
.fork = event__process_task,
|
.fork = event__process_task,
|
||||||
|
.ordered_samples = true,
|
||||||
|
.ordering_requires_timestamps = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __cmd_annotate(void)
|
static int __cmd_annotate(void)
|
||||||
|
@ -382,7 +384,7 @@ static int __cmd_annotate(void)
|
||||||
int ret;
|
int ret;
|
||||||
struct perf_session *session;
|
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)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,8 @@ static int __cmd_buildid_list(void)
|
||||||
int err = -1;
|
int err = -1;
|
||||||
struct perf_session *session;
|
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)
|
if (session == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,8 @@ static struct perf_event_ops event_ops = {
|
||||||
.exit = event__process_task,
|
.exit = event__process_task,
|
||||||
.fork = event__process_task,
|
.fork = event__process_task,
|
||||||
.lost = event__process_lost,
|
.lost = event__process_lost,
|
||||||
|
.ordered_samples = true,
|
||||||
|
.ordering_requires_timestamps = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
|
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;
|
int ret, i;
|
||||||
struct perf_session *session[2];
|
struct perf_session *session[2];
|
||||||
|
|
||||||
session[0] = perf_session__new(input_old, 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);
|
session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops);
|
||||||
if (session[0] == NULL || session[1] == NULL)
|
if (session[0] == NULL || session[1] == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -192,6 +194,8 @@ static const struct option options[] = {
|
||||||
OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
|
OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
|
||||||
"separator for columns, no spaces will be added between "
|
"separator for columns, no spaces will be added between "
|
||||||
"columns '.' is reserved."),
|
"columns '.' is reserved."),
|
||||||
|
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
||||||
|
"Look for files with symbols relative to this directory"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ static int __cmd_inject(void)
|
||||||
inject_ops.tracing_data = event__repipe_tracing_data;
|
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)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -481,7 +481,8 @@ static void sort_result(void)
|
||||||
static int __cmd_kmem(void)
|
static int __cmd_kmem(void)
|
||||||
{
|
{
|
||||||
int err = -EINVAL;
|
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)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -858,7 +858,7 @@ static struct perf_event_ops eops = {
|
||||||
|
|
||||||
static int read_events(void)
|
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)
|
if (!session)
|
||||||
die("Initializing perf session failed\n");
|
die("Initializing perf session failed\n");
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,7 @@ static void create_counter(int counter, int cpu)
|
||||||
if (system_wide)
|
if (system_wide)
|
||||||
attr->sample_type |= PERF_SAMPLE_CPU;
|
attr->sample_type |= PERF_SAMPLE_CPU;
|
||||||
|
|
||||||
if (sample_time)
|
if (sample_time || system_wide || !no_inherit || cpu_list)
|
||||||
attr->sample_type |= PERF_SAMPLE_TIME;
|
attr->sample_type |= PERF_SAMPLE_TIME;
|
||||||
|
|
||||||
if (raw_samples) {
|
if (raw_samples) {
|
||||||
|
@ -327,6 +327,9 @@ try_again:
|
||||||
* Old kernel, no attr->sample_id_type_all field
|
* Old kernel, no attr->sample_id_type_all field
|
||||||
*/
|
*/
|
||||||
sample_id_all_avail = false;
|
sample_id_all_avail = false;
|
||||||
|
if (!sample_time && !raw_samples)
|
||||||
|
attr->sample_type &= ~PERF_SAMPLE_TIME;
|
||||||
|
|
||||||
goto retry_sample_id;
|
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,
|
session = perf_session__new(output_name, O_WRONLY,
|
||||||
write_mode == WRITE_FORCE, false);
|
write_mode == WRITE_FORCE, false, NULL);
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
pr_err("Not enough memory for reading perf file header\n");
|
pr_err("Not enough memory for reading perf file header\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -244,6 +244,8 @@ static struct perf_event_ops event_ops = {
|
||||||
.event_type = event__process_event_type,
|
.event_type = event__process_event_type,
|
||||||
.tracing_data = event__process_tracing_data,
|
.tracing_data = event__process_tracing_data,
|
||||||
.build_id = event__process_build_id,
|
.build_id = event__process_build_id,
|
||||||
|
.ordered_samples = true,
|
||||||
|
.ordering_requires_timestamps = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern volatile int session_done;
|
extern volatile int session_done;
|
||||||
|
@ -308,7 +310,7 @@ static int __cmd_report(void)
|
||||||
|
|
||||||
signal(SIGINT, sig_handler);
|
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)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -481,6 +483,8 @@ static const struct option options[] = {
|
||||||
"columns '.' is reserved."),
|
"columns '.' is reserved."),
|
||||||
OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
|
OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
|
||||||
"Only display entries resolved to a symbol"),
|
"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()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1643,7 +1643,8 @@ static struct perf_event_ops event_ops = {
|
||||||
static int read_events(void)
|
static int read_events(void)
|
||||||
{
|
{
|
||||||
int err = -EINVAL;
|
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)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -779,7 +779,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
|
||||||
if (!script_name)
|
if (!script_name)
|
||||||
setup_pager();
|
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)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -937,7 +937,8 @@ static struct perf_event_ops event_ops = {
|
||||||
|
|
||||||
static int __cmd_timechart(void)
|
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;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
if (session == NULL)
|
if (session == NULL)
|
||||||
|
@ -1021,6 +1022,8 @@ static const struct option options[] = {
|
||||||
OPT_CALLBACK('p', "process", NULL, "process",
|
OPT_CALLBACK('p', "process", NULL, "process",
|
||||||
"process selector. Pass a pid or process name.",
|
"process selector. Pass a pid or process name.",
|
||||||
parse_process),
|
parse_process),
|
||||||
|
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
||||||
|
"Look for files with symbols relative to this directory"),
|
||||||
OPT_END()
|
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
|
* 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.
|
* 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)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -1092,6 +1092,12 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
|
||||||
FILE *file;
|
FILE *file;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u64 len;
|
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 (filename == NULL) {
|
||||||
if (dso->has_build_id) {
|
if (dso->has_build_id) {
|
||||||
|
@ -1100,9 +1106,9 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
goto fallback;
|
goto fallback;
|
||||||
} else if (readlink(filename, command, sizeof(command)) < 0 ||
|
} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
|
||||||
strstr(command, "[kernel.kallsyms]") ||
|
strstr(command, "[kernel.kallsyms]") ||
|
||||||
access(filename, R_OK)) {
|
access(symfs_filename, R_OK)) {
|
||||||
free(filename);
|
free(filename);
|
||||||
fallback:
|
fallback:
|
||||||
/*
|
/*
|
||||||
|
@ -1111,6 +1117,8 @@ fallback:
|
||||||
* DSO is the same as when 'perf record' ran.
|
* DSO is the same as when 'perf record' ran.
|
||||||
*/
|
*/
|
||||||
filename = dso->long_name;
|
filename = dso->long_name;
|
||||||
|
snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
|
||||||
|
symbol_conf.symfs, filename);
|
||||||
free_filename = false;
|
free_filename = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1137,7 +1145,7 @@ fallback:
|
||||||
"objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
|
"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->start),
|
||||||
map__rip_2objdump(map, sym->end),
|
map__rip_2objdump(map, sym->end),
|
||||||
filename, filename);
|
symfs_filename, filename);
|
||||||
|
|
||||||
pr_debug("Executing: %s\n", command);
|
pr_debug("Executing: %s\n", command);
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ static int init_vmlinux(void)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (machine__create_kernel_maps(&machine) < 0) {
|
if (machine__create_kernel_maps(&machine) < 0) {
|
||||||
pr_debug("machine__create_kernel_maps ");
|
pr_debug("machine__create_kernel_maps() failed.\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
@ -140,7 +140,8 @@ static int open_vmlinux(const char *module)
|
||||||
{
|
{
|
||||||
const char *path = kernel_get_module_path(module);
|
const char *path = kernel_get_module_path(module);
|
||||||
if (!path) {
|
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;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
pr_debug("Try to open %s\n", path);
|
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 - "
|
pr_warning("Warning: No dwarf info found in the vmlinux - "
|
||||||
"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
|
"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
|
||||||
if (!need_dwarf) {
|
if (!need_dwarf) {
|
||||||
pr_debug("Trying to use symbols.\nn");
|
pr_debug("Trying to use symbols.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,42 +287,49 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
|
||||||
#define LINEBUF_SIZE 256
|
#define LINEBUF_SIZE 256
|
||||||
#define NR_ADDITIONAL_LINES 2
|
#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];
|
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)
|
do {
|
||||||
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') {
|
|
||||||
if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
|
if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
if (!skip) {
|
if (skip)
|
||||||
if (show_num)
|
continue;
|
||||||
fprintf(stdout, "%s", buf);
|
if (!prefix) {
|
||||||
else
|
prefix = show_num ? "%7d " : " ";
|
||||||
color_fprintf(stdout, color, "%s", buf);
|
color_fprintf(stdout, color, prefix, l);
|
||||||
}
|
}
|
||||||
}
|
color_fprintf(stdout, color, "%s", buf);
|
||||||
|
|
||||||
return 0;
|
} while (strchr(buf, '\n') == NULL);
|
||||||
|
|
||||||
|
return 1;
|
||||||
error:
|
error:
|
||||||
if (feof(fp))
|
if (ferror(fp)) {
|
||||||
pr_warning("Source file is shorter than expected.\n");
|
pr_warning("Source file is shorter than expected.\n");
|
||||||
else
|
return -1;
|
||||||
pr_warning("File read error: %s\n", strerror(errno));
|
}
|
||||||
|
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
|
* Show line-range always requires debuginfo to find source file and
|
||||||
* line number.
|
* line number.
|
||||||
|
@ -370,7 +378,7 @@ int show_line_range(struct line_range *lr, const char *module)
|
||||||
fprintf(stdout, "<%s:%d>\n", lr->function,
|
fprintf(stdout, "<%s:%d>\n", lr->function,
|
||||||
lr->start - lr->offset);
|
lr->start - lr->offset);
|
||||||
else
|
else
|
||||||
fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
|
fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
|
||||||
|
|
||||||
fp = fopen(lr->path, "r");
|
fp = fopen(lr->path, "r");
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
|
@ -379,26 +387,30 @@ int show_line_range(struct line_range *lr, const char *module)
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
/* Skip to starting line number */
|
/* Skip to starting line number */
|
||||||
while (l < lr->start && ret >= 0)
|
while (l < lr->start) {
|
||||||
ret = show_one_line(fp, l++, true, false);
|
ret = skip_one_line(fp, l++);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
list_for_each_entry(ln, &lr->line_list, list) {
|
list_for_each_entry(ln, &lr->line_list, list) {
|
||||||
while (ln->line > l && ret >= 0)
|
for (; ln->line > l; l++) {
|
||||||
ret = show_one_line(fp, (l++) - lr->offset,
|
ret = show_one_line(fp, l - lr->offset);
|
||||||
false, false);
|
if (ret < 0)
|
||||||
if (ret >= 0)
|
goto end;
|
||||||
ret = show_one_line(fp, (l++) - lr->offset,
|
}
|
||||||
false, true);
|
ret = show_one_line_with_num(fp, l++ - lr->offset);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lr->end == INT_MAX)
|
if (lr->end == INT_MAX)
|
||||||
lr->end = l + NR_ADDITIONAL_LINES;
|
lr->end = l + NR_ADDITIONAL_LINES;
|
||||||
while (l <= lr->end && !feof(fp) && ret >= 0)
|
while (l <= lr->end) {
|
||||||
ret = show_one_line(fp, (l++) - lr->offset, false, false);
|
ret = show_one_line_or_eof(fp, l++ - lr->offset);
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
end:
|
end:
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -457,7 +469,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
|
||||||
|
|
||||||
fd = open_vmlinux(module);
|
fd = open_vmlinux(module);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
pr_warning("Failed to open debuginfo file.\n");
|
pr_warning("Failed to open debug information file.\n");
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,56 +529,87 @@ int show_available_vars(struct perf_probe_event *pevs __unused,
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
int parse_line_range_desc(const char *arg, struct line_range *lr)
|
||||||
{
|
{
|
||||||
const char *ptr;
|
char *range, *name = strdup(arg);
|
||||||
char *tmp;
|
int err;
|
||||||
/*
|
|
||||||
* <Syntax>
|
if (!name)
|
||||||
* SRC:SLN[+NUM|-ELN]
|
return -ENOMEM;
|
||||||
* FUNC[:SLN[+NUM|-ELN]]
|
|
||||||
*/
|
lr->start = 0;
|
||||||
ptr = strchr(arg, ':');
|
lr->end = INT_MAX;
|
||||||
if (ptr) {
|
|
||||||
lr->start = (int)strtoul(ptr + 1, &tmp, 0);
|
range = strchr(name, ':');
|
||||||
if (*tmp == '+') {
|
if (range) {
|
||||||
lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
|
*range++ = '\0';
|
||||||
lr->end--; /*
|
|
||||||
* Adjust the number of lines here.
|
err = parse_line_num(&range, &lr->start, "start line");
|
||||||
* If the number of lines == 1, the
|
if (err)
|
||||||
* the end of line should be equal to
|
goto err;
|
||||||
* the start of line.
|
|
||||||
*/
|
if (*range == '+' || *range == '-') {
|
||||||
} else if (*tmp == '-')
|
const char c = *range++;
|
||||||
lr->end = (int)strtoul(tmp + 1, &tmp, 0);
|
|
||||||
else
|
err = parse_line_num(&range, &lr->end, "end line");
|
||||||
lr->end = INT_MAX;
|
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);
|
pr_debug("Line range is %d to %d\n", lr->start, lr->end);
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
if (lr->start > lr->end) {
|
if (lr->start > lr->end) {
|
||||||
semantic_error("Start line must be smaller"
|
semantic_error("Start line must be smaller"
|
||||||
" than end line.\n");
|
" than end line.\n");
|
||||||
return -EINVAL;
|
goto err;
|
||||||
}
|
}
|
||||||
if (*tmp != '\0') {
|
if (*range != '\0') {
|
||||||
semantic_error("Tailing with invalid character '%d'.\n",
|
semantic_error("Tailing with invalid str '%s'.\n", range);
|
||||||
*tmp);
|
goto err;
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
tmp = strndup(arg, (ptr - arg));
|
|
||||||
} else {
|
|
||||||
tmp = strdup(arg);
|
|
||||||
lr->end = INT_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp == NULL)
|
if (strchr(name, '.'))
|
||||||
return -ENOMEM;
|
lr->file = name;
|
||||||
|
|
||||||
if (strchr(tmp, '.'))
|
|
||||||
lr->file = tmp;
|
|
||||||
else
|
else
|
||||||
lr->function = tmp;
|
lr->function = name;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
err:
|
||||||
|
free(name);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the name is good for event/group */
|
/* 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 */
|
/* Exclusion check */
|
||||||
if (pp->lazy_line && pp->line) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pp->lazy_line && pp->offset) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pp->line && pp->offset) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
|
if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
|
||||||
semantic_error("File always requires line number or "
|
semantic_error("File always requires line number or "
|
||||||
"lazy pattern.");
|
"lazy pattern.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pp->offset && !pp->function) {
|
if (pp->offset && !pp->function) {
|
||||||
semantic_error("Offset requires an entry function.");
|
semantic_error("Offset requires an entry function.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pp->retprobe && !pp->function) {
|
if (pp->retprobe && !pp->function) {
|
||||||
semantic_error("Return probe requires an entry function.");
|
semantic_error("Return probe requires an entry function.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
|
if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
|
||||||
semantic_error("Offset/Line/Lazy pattern can't be used with "
|
semantic_error("Offset/Line/Lazy pattern can't be used with "
|
||||||
"return probe.");
|
"return probe.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -996,7 +1040,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
|
||||||
|
|
||||||
return tmp - buf;
|
return tmp - buf;
|
||||||
error:
|
error:
|
||||||
pr_debug("Failed to synthesize perf probe argument: %s",
|
pr_debug("Failed to synthesize perf probe argument: %s\n",
|
||||||
strerror(-ret));
|
strerror(-ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1046,7 +1090,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
error:
|
error:
|
||||||
pr_debug("Failed to synthesize perf probe point: %s",
|
pr_debug("Failed to synthesize perf probe point: %s\n",
|
||||||
strerror(-ret));
|
strerror(-ret));
|
||||||
if (buf)
|
if (buf)
|
||||||
free(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);
|
ret = e_snprintf(buf, 128, "%s:%s", group, event);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_err("Failed to copy event.");
|
pr_err("Failed to copy event.\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -627,8 +627,8 @@ static_var:
|
||||||
regs = get_arch_regstr(regn);
|
regs = get_arch_regstr(regn);
|
||||||
if (!regs) {
|
if (!regs) {
|
||||||
/* This should be a bug in DWARF or this tool */
|
/* This should be a bug in DWARF or this tool */
|
||||||
pr_warning("Mapping for DWARF register number %u "
|
pr_warning("Mapping for the register number %u "
|
||||||
"missing on this architecture.", regn);
|
"missing on this architecture.\n", regn);
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,13 +674,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
|
||||||
if (ret != DW_TAG_pointer_type &&
|
if (ret != DW_TAG_pointer_type &&
|
||||||
ret != DW_TAG_array_type) {
|
ret != DW_TAG_array_type) {
|
||||||
pr_warning("Failed to cast into string: "
|
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));
|
dwarf_diename(vr_die), dwarf_diename(&type));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (ret == DW_TAG_pointer_type) {
|
if (ret == DW_TAG_pointer_type) {
|
||||||
if (die_get_real_type(&type, &type) == NULL) {
|
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;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
while (*ref_ptr)
|
while (*ref_ptr)
|
||||||
|
@ -695,7 +696,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
|
||||||
if (!die_compare_name(&type, "char") &&
|
if (!die_compare_name(&type, "char") &&
|
||||||
!die_compare_name(&type, "unsigned char")) {
|
!die_compare_name(&type, "unsigned char")) {
|
||||||
pr_warning("Failed to cast into string: "
|
pr_warning("Failed to cast into string: "
|
||||||
"%s is not (unsigned) char *.",
|
"%s is not (unsigned) char *.\n",
|
||||||
dwarf_diename(vr_die));
|
dwarf_diename(vr_die));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -805,8 +806,8 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (field->name[0] == '[') {
|
if (field->name[0] == '[') {
|
||||||
pr_err("Semantic error: %s is not a pointor nor array.",
|
pr_err("Semantic error: %s is not a pointor"
|
||||||
varname);
|
" nor array.\n", varname);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (field->ref) {
|
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);
|
name = dwarf_diename(sp_die);
|
||||||
if (name) {
|
if (name) {
|
||||||
if (dwarf_entrypc(sp_die, &eaddr) != 0) {
|
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));
|
dwarf_diename(sp_die));
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
@ -969,7 +970,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
|
||||||
if (retprobe) {
|
if (retprobe) {
|
||||||
if (eaddr != paddr) {
|
if (eaddr != paddr) {
|
||||||
pr_warning("Return probe must be on the head of"
|
pr_warning("Return probe must be on the head of"
|
||||||
" a real function\n");
|
" a real function.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
tp->retprobe = true;
|
tp->retprobe = true;
|
||||||
|
@ -1008,7 +1009,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
|
||||||
Dwarf_Frame *frame;
|
Dwarf_Frame *frame;
|
||||||
if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
|
if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
|
||||||
dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 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);
|
(uintmax_t)pf->addr);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
@ -1035,7 +1036,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 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;
|
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) {
|
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;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1195,7 +1196,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
|
||||||
else {
|
else {
|
||||||
/* Get probe address */
|
/* Get probe address */
|
||||||
if (dwarf_entrypc(in_die, &addr) != 0) {
|
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));
|
dwarf_diename(in_die));
|
||||||
param->retval = -ENOENT;
|
param->retval = -ENOENT;
|
||||||
return DWARF_CB_ABORT;
|
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);
|
param->retval = find_probe_point_lazy(sp_die, pf);
|
||||||
else {
|
else {
|
||||||
if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
|
if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
|
||||||
pr_warning("Failed to get entry pc of %s.\n",
|
pr_warning("Failed to get entry address of "
|
||||||
dwarf_diename(sp_die));
|
"%s.\n", dwarf_diename(sp_die));
|
||||||
param->retval = -ENOENT;
|
param->retval = -ENOENT;
|
||||||
return DWARF_CB_ABORT;
|
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);
|
dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
|
||||||
if (!dbg) {
|
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");
|
"please rebuild with CONFIG_DEBUG_INFO=y.\n");
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
}
|
}
|
||||||
|
@ -1524,7 +1525,7 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
|
||||||
/* Open the live linux kernel */
|
/* Open the live linux kernel */
|
||||||
dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
|
dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
|
||||||
if (!dbg) {
|
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");
|
"please rebuild with CONFIG_DEBUG_INFO=y.\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -1534,7 +1535,8 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
|
||||||
addr += bias;
|
addr += bias;
|
||||||
/* Find cu die */
|
/* Find cu die */
|
||||||
if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
|
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;
|
ret = -EINVAL;
|
||||||
goto end;
|
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);
|
line_list__init(&lf->lr->line_list);
|
||||||
if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
|
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;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1784,7 +1786,7 @@ int find_line_range(int fd, struct line_range *lr)
|
||||||
|
|
||||||
dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
|
dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
|
||||||
if (!dbg) {
|
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");
|
"please rebuild with CONFIG_DEBUG_INFO=y.\n");
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,9 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
|
||||||
machines__destroy_guest_kernel_maps(&self->machines);
|
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;
|
size_t len = filename ? strlen(filename) + 1 : 0;
|
||||||
struct perf_session *self = zalloc(sizeof(*self) + len);
|
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);
|
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:
|
out:
|
||||||
return self;
|
return self;
|
||||||
out_free:
|
out_free:
|
||||||
|
|
|
@ -78,9 +78,12 @@ struct perf_event_ops {
|
||||||
build_id;
|
build_id;
|
||||||
event_op2 finished_round;
|
event_op2 finished_round;
|
||||||
bool ordered_samples;
|
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_session__delete(struct perf_session *self);
|
||||||
|
|
||||||
void perf_event_header__bswap(struct perf_event_header *self);
|
void perf_event_header__bswap(struct perf_event_header *self);
|
||||||
|
|
|
@ -41,6 +41,7 @@ struct symbol_conf symbol_conf = {
|
||||||
.exclude_other = true,
|
.exclude_other = true,
|
||||||
.use_modules = true,
|
.use_modules = true,
|
||||||
.try_vmlinux_path = true,
|
.try_vmlinux_path = true,
|
||||||
|
.symfs = "",
|
||||||
};
|
};
|
||||||
|
|
||||||
int dso__name_len(const struct dso *self)
|
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];
|
char sympltname[1024];
|
||||||
Elf *elf;
|
Elf *elf;
|
||||||
int nr = 0, symidx, fd, err = 0;
|
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)
|
if (fd < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -1452,16 +1456,19 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
||||||
self->origin++) {
|
self->origin++) {
|
||||||
switch (self->origin) {
|
switch (self->origin) {
|
||||||
case DSO__ORIG_BUILD_ID_CACHE:
|
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;
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case DSO__ORIG_FEDORA:
|
case DSO__ORIG_FEDORA:
|
||||||
snprintf(name, size, "/usr/lib/debug%s.debug",
|
snprintf(name, size, "%s/usr/lib/debug%s.debug",
|
||||||
self->long_name);
|
symbol_conf.symfs, self->long_name);
|
||||||
break;
|
break;
|
||||||
case DSO__ORIG_UBUNTU:
|
case DSO__ORIG_UBUNTU:
|
||||||
snprintf(name, size, "/usr/lib/debug%s",
|
snprintf(name, size, "%s/usr/lib/debug%s",
|
||||||
self->long_name);
|
symbol_conf.symfs, self->long_name);
|
||||||
break;
|
break;
|
||||||
case DSO__ORIG_BUILDID: {
|
case DSO__ORIG_BUILDID: {
|
||||||
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
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),
|
sizeof(self->build_id),
|
||||||
build_id_hex);
|
build_id_hex);
|
||||||
snprintf(name, size,
|
snprintf(name, size,
|
||||||
"/usr/lib/debug/.build-id/%.2s/%s.debug",
|
"%s/usr/lib/debug/.build-id/%.2s/%s.debug",
|
||||||
build_id_hex, build_id_hex + 2);
|
symbol_conf.symfs, build_id_hex, build_id_hex + 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DSO__ORIG_DSO:
|
case DSO__ORIG_DSO:
|
||||||
snprintf(name, size, "%s", self->long_name);
|
snprintf(name, size, "%s%s",
|
||||||
|
symbol_conf.symfs, self->long_name);
|
||||||
break;
|
break;
|
||||||
case DSO__ORIG_GUEST_KMODULE:
|
case DSO__ORIG_GUEST_KMODULE:
|
||||||
if (map->groups && map->groups->machine)
|
if (map->groups && map->groups->machine)
|
||||||
root_dir = map->groups->machine->root_dir;
|
root_dir = map->groups->machine->root_dir;
|
||||||
else
|
else
|
||||||
root_dir = "";
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1784,17 +1798,20 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
|
||||||
const char *vmlinux, symbol_filter_t filter)
|
const char *vmlinux, symbol_filter_t filter)
|
||||||
{
|
{
|
||||||
int err = -1, fd;
|
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)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
dso__set_loaded(self, map->type);
|
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);
|
close(fd);
|
||||||
|
|
||||||
if (err > 0)
|
if (err > 0)
|
||||||
pr_debug("Using %s for symbols\n", vmlinux);
|
pr_debug("Using %s for symbols\n", symfs_vmlinux);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1872,6 +1889,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
|
||||||
goto out_fixup;
|
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,
|
* 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,
|
* 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;
|
struct utsname uts;
|
||||||
char bf[PATH_MAX];
|
char bf[PATH_MAX];
|
||||||
|
|
||||||
if (uname(&uts) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
vmlinux_path = malloc(sizeof(char *) * 5);
|
vmlinux_path = malloc(sizeof(char *) * 5);
|
||||||
if (vmlinux_path == NULL)
|
if (vmlinux_path == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2277,6 +2295,14 @@ static int vmlinux_path__init(void)
|
||||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||||
goto out_fail;
|
goto out_fail;
|
||||||
++vmlinux_path__nr_entries;
|
++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);
|
snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
|
||||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
||||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
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)
|
int symbol__init(void)
|
||||||
{
|
{
|
||||||
|
const char *symfs;
|
||||||
|
|
||||||
if (symbol_conf.initialized)
|
if (symbol_conf.initialized)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -2364,6 +2392,18 @@ int symbol__init(void)
|
||||||
symbol_conf.sym_list_str, "symbol") < 0)
|
symbol_conf.sym_list_str, "symbol") < 0)
|
||||||
goto out_free_comm_list;
|
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;
|
symbol_conf.initialized = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ struct symbol_conf {
|
||||||
struct strlist *dso_list,
|
struct strlist *dso_list,
|
||||||
*comm_list,
|
*comm_list,
|
||||||
*sym_list;
|
*sym_list;
|
||||||
|
const char *symfs;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct symbol_conf symbol_conf;
|
extern struct symbol_conf symbol_conf;
|
||||||
|
|
Loading…
Reference in New Issue