Commit 8c1df400 authored by Ingo Molnar's avatar 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
parents 6c529a26 21dd9ae5
...@@ -66,6 +66,8 @@ OPTIONS ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 = { ...@@ -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) ...@@ -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) ...@@ -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 = { ...@@ -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) ...@@ -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[] = { ...@@ -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) ...@@ -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) ...@@ -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 = { ...@@ -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) ...@@ -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 @@ static void create_counter(int counter, int cpu) ...@@ -327,6 +327,9 @@ static void create_counter(int counter, int cpu)
* 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) ...@@ -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 = { ...@@ -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) ...@@ -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[] = { ...@@ -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 = { ...@@ -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) ...@@ -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 = { ...@@ -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[] = { ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head, ...@@ -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. * 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 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head, ...@@ -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", "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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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 int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, ...@@ -627,8 +627,8 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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 { ...@@ -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 = { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 { ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment