Commit 408cf677 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo-20160520' of...

Merge tag 'perf-core-for-mingo-20160520' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

- We should not use the current value of the kernel.perf_event_max_stack as the
  default value for --max-stack in tools that can process perf.data files, they
  will only match if that sysctl wasn't changed from its default value at the
  time the perf.data file was recorded, fix it.

  This fixes a bug where a 'perf record -a --call-graph dwarf ; perf report'
  produces a glibc invalid free backtrace (Arnaldo Carvalho de Melo)

- Provide a better warning when running 'perf trace' on a system where the
  kernel.kptr_restrict is set to 1, similar to the one produced by 'perf record',
  noticed on ubuntu 16.04 where this is the default kptr_restrict setting.
  (Arnaldo Carvalho de Melo)

- Fix ordering of instructions in the annotation code, noticed when annotating
  ARM binaries, now that table is auto-ordered at first use, to avoid more such
  problems (Chris Ryder)

- Set buildid dir under symfs when --symfs is provided (He Kuang)

- Fix the 'exit_group()' syscall output in 'perf trace' (Arnaldo Carvalho de Melo)

- Only auto set call-graph to "dwarf" in 'perf trace' when syscalls are being
  traced (Arnaldo Carvalho de Melo)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 1ab94188 a7066709
...@@ -248,7 +248,7 @@ OPTIONS ...@@ -248,7 +248,7 @@ OPTIONS
Note that when using the --itrace option the synthesized callchain size Note that when using the --itrace option the synthesized callchain size
will override this value if the synthesized callchain size is bigger. will override this value if the synthesized callchain size is bigger.
Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. Default: 127
-G:: -G::
--inverted:: --inverted::
......
...@@ -267,7 +267,7 @@ include::itrace.txt[] ...@@ -267,7 +267,7 @@ include::itrace.txt[]
Note that when using the --itrace option the synthesized callchain size Note that when using the --itrace option the synthesized callchain size
will override this value if the synthesized callchain size is bigger. will override this value if the synthesized callchain size is bigger.
Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. Default: 127
--ns:: --ns::
Use 9 decimal places when displaying time (i.e. show the nanoseconds) Use 9 decimal places when displaying time (i.e. show the nanoseconds)
......
...@@ -143,7 +143,8 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. ...@@ -143,7 +143,8 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
Implies '--call-graph dwarf' when --call-graph not present on the Implies '--call-graph dwarf' when --call-graph not present on the
command line, on systems where DWARF unwinding was built in. command line, on systems where DWARF unwinding was built in.
Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. Default: /proc/sys/kernel/perf_event_max_stack when present for
live sessions (without --input/-i), 127 otherwise.
--min-stack:: --min-stack::
Set the stack depth limit when parsing the callchain, anything Set the stack depth limit when parsing the callchain, anything
......
...@@ -324,8 +324,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -324,8 +324,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
"Skip symbols that cannot be annotated"), "Skip symbols that cannot be annotated"),
OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", OPT_CALLBACK(0, "symfs", NULL, "directory",
"Look for files with symbols relative to this directory"), "Look for files with symbols relative to this directory",
symbol__config_symfs),
OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
"Interleave source code with assembly code (default)"), "Interleave source code with assembly code (default)"),
OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
......
...@@ -812,8 +812,9 @@ static const struct option options[] = { ...@@ -812,8 +812,9 @@ static const struct option options[] = {
OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator", OPT_STRING_NOEMPTY('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", OPT_CALLBACK(0, "symfs", NULL, "directory",
"Look for files with symbols relative to this directory"), "Look for files with symbols relative to this directory",
symbol__config_symfs),
OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
"How to display percentage of filtered entries", parse_filter_percentage), "How to display percentage of filtered entries", parse_filter_percentage),
......
...@@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
.ordered_events = true, .ordered_events = true,
.ordering_requires_timestamps = true, .ordering_requires_timestamps = true,
}, },
.max_stack = sysctl_perf_event_max_stack, .max_stack = PERF_MAX_STACK_DEPTH,
.pretty_printing_style = "normal", .pretty_printing_style = "normal",
.socket_filter = -1, .socket_filter = -1,
}; };
...@@ -770,8 +770,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -770,8 +770,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"columns '.' is reserved."), "columns '.' is reserved."),
OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved, OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved,
"Only display entries resolved to a symbol"), "Only display entries resolved to a symbol"),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", OPT_CALLBACK(0, "symfs", NULL, "directory",
"Look for files with symbols relative to this directory"), "Look for files with symbols relative to this directory",
symbol__config_symfs),
OPT_STRING('C', "cpu", &report.cpu_list, "cpu", OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
"list of cpus to profile"), "list of cpus to profile"),
OPT_BOOLEAN('I', "show-info", &report.show_full_info, OPT_BOOLEAN('I', "show-info", &report.show_full_info,
......
...@@ -2010,8 +2010,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -2010,8 +2010,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
"file", "kallsyms pathname"), "file", "kallsyms pathname"),
OPT_BOOLEAN('G', "hide-call-graph", &no_callchain, OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
"When printing symbols do not display call chain"), "When printing symbols do not display call chain"),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", OPT_CALLBACK(0, "symfs", NULL, "directory",
"Look for files with symbols relative to this directory"), "Look for files with symbols relative to this directory",
symbol__config_symfs),
OPT_CALLBACK('F', "fields", NULL, "str", OPT_CALLBACK('F', "fields", NULL, "str",
"comma separated output fields prepend with 'type:'. " "comma separated output fields prepend with 'type:'. "
"Valid types: hw,sw,trace,raw. " "Valid types: hw,sw,trace,raw. "
...@@ -2067,8 +2068,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -2067,8 +2068,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
NULL NULL
}; };
scripting_max_stack = sysctl_perf_event_max_stack;
setup_scripting(); setup_scripting();
argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage,
......
...@@ -1945,8 +1945,9 @@ int cmd_timechart(int argc, const char **argv, ...@@ -1945,8 +1945,9 @@ int cmd_timechart(int argc, const char **argv,
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", OPT_CALLBACK(0, "symfs", NULL, "directory",
"Look for files with symbols relative to this directory"), "Look for files with symbols relative to this directory",
symbol__config_symfs),
OPT_INTEGER('n', "proc-num", &tchart.proc_num, OPT_INTEGER('n', "proc-num", &tchart.proc_num,
"min. number of tasks to print"), "min. number of tasks to print"),
OPT_BOOLEAN('t', "topology", &tchart.topology, OPT_BOOLEAN('t', "topology", &tchart.topology,
......
...@@ -732,7 +732,7 @@ static void perf_event__process_sample(struct perf_tool *tool, ...@@ -732,7 +732,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
if (machine__resolve(machine, &al, sample) < 0) if (machine__resolve(machine, &al, sample) < 0)
return; return;
if (!top->kptr_restrict_warned && if (!machine->kptr_restrict_warned &&
symbol_conf.kptr_restrict && symbol_conf.kptr_restrict &&
al.cpumode == PERF_RECORD_MISC_KERNEL) { al.cpumode == PERF_RECORD_MISC_KERNEL) {
ui__warning( ui__warning(
...@@ -743,7 +743,7 @@ static void perf_event__process_sample(struct perf_tool *tool, ...@@ -743,7 +743,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
" modules" : ""); " modules" : "");
if (use_browser <= 0) if (use_browser <= 0)
sleep(5); sleep(5);
top->kptr_restrict_warned = true; machine->kptr_restrict_warned = true;
} }
if (al.sym == NULL) { if (al.sym == NULL) {
...@@ -759,7 +759,7 @@ static void perf_event__process_sample(struct perf_tool *tool, ...@@ -759,7 +759,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
* --hide-kernel-symbols, even if the user specifies an * --hide-kernel-symbols, even if the user specifies an
* invalid --vmlinux ;-) * invalid --vmlinux ;-)
*/ */
if (!top->kptr_restrict_warned && !top->vmlinux_warned && if (!machine->kptr_restrict_warned && !top->vmlinux_warned &&
al.map == machine->vmlinux_maps[MAP__FUNCTION] && al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
if (symbol_conf.vmlinux_name) { if (symbol_conf.vmlinux_name) {
......
...@@ -1160,6 +1160,24 @@ static int trace__tool_process(struct perf_tool *tool, ...@@ -1160,6 +1160,24 @@ static int trace__tool_process(struct perf_tool *tool,
return trace__process_event(trace, machine, event, sample); return trace__process_event(trace, machine, event, sample);
} }
static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
{
struct machine *machine = vmachine;
if (machine->kptr_restrict_warned)
return NULL;
if (symbol_conf.kptr_restrict) {
pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
"Check /proc/sys/kernel/kptr_restrict.\n\n"
"Kernel samples will not be resolved.\n");
machine->kptr_restrict_warned = true;
return NULL;
}
return machine__resolve_kernel_addr(vmachine, addrp, modp);
}
static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
{ {
int err = symbol__init(NULL); int err = symbol__init(NULL);
...@@ -1171,7 +1189,7 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) ...@@ -1171,7 +1189,7 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
if (trace->host == NULL) if (trace->host == NULL)
return -ENOMEM; return -ENOMEM;
if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0) if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
return -errno; return -errno;
err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target, err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
...@@ -1534,7 +1552,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, ...@@ -1534,7 +1552,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
if (sc->is_exit) { if (sc->is_exit) {
if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
fprintf(trace->output, "%-70s\n", ttrace->entry_str); fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
} }
} else { } else {
ttrace->entry_pending = true; ttrace->entry_pending = true;
...@@ -2887,12 +2905,12 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -2887,12 +2905,12 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
mmap_pages_user_set = false; mmap_pages_user_set = false;
if (trace.max_stack == UINT_MAX) { if (trace.max_stack == UINT_MAX) {
trace.max_stack = sysctl_perf_event_max_stack; trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
max_stack_user_set = false; max_stack_user_set = false;
} }
#ifdef HAVE_DWARF_UNWIND_SUPPORT #ifdef HAVE_DWARF_UNWIND_SUPPORT
if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false); record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
#endif #endif
......
...@@ -354,9 +354,6 @@ static struct ins_ops nop_ops = { ...@@ -354,9 +354,6 @@ static struct ins_ops nop_ops = {
.scnprintf = nop__scnprintf, .scnprintf = nop__scnprintf,
}; };
/*
* Must be sorted by name!
*/
static struct ins instructions[] = { static struct ins instructions[] = {
{ .name = "add", .ops = &mov_ops, }, { .name = "add", .ops = &mov_ops, },
{ .name = "addl", .ops = &mov_ops, }, { .name = "addl", .ops = &mov_ops, },
...@@ -372,8 +369,8 @@ static struct ins instructions[] = { ...@@ -372,8 +369,8 @@ static struct ins instructions[] = {
{ .name = "bgt", .ops = &jump_ops, }, { .name = "bgt", .ops = &jump_ops, },
{ .name = "bhi", .ops = &jump_ops, }, { .name = "bhi", .ops = &jump_ops, },
{ .name = "bl", .ops = &call_ops, }, { .name = "bl", .ops = &call_ops, },
{ .name = "blt", .ops = &jump_ops, },
{ .name = "bls", .ops = &jump_ops, }, { .name = "bls", .ops = &jump_ops, },
{ .name = "blt", .ops = &jump_ops, },
{ .name = "blx", .ops = &call_ops, }, { .name = "blx", .ops = &call_ops, },
{ .name = "bne", .ops = &jump_ops, }, { .name = "bne", .ops = &jump_ops, },
#endif #endif
...@@ -449,18 +446,39 @@ static struct ins instructions[] = { ...@@ -449,18 +446,39 @@ static struct ins instructions[] = {
{ .name = "xbeginq", .ops = &jump_ops, }, { .name = "xbeginq", .ops = &jump_ops, },
}; };
static int ins__cmp(const void *name, const void *insp) static int ins__key_cmp(const void *name, const void *insp)
{ {
const struct ins *ins = insp; const struct ins *ins = insp;
return strcmp(name, ins->name); return strcmp(name, ins->name);
} }
static int ins__cmp(const void *a, const void *b)
{
const struct ins *ia = a;
const struct ins *ib = b;
return strcmp(ia->name, ib->name);
}
static void ins__sort(void)
{
const int nmemb = ARRAY_SIZE(instructions);
qsort(instructions, nmemb, sizeof(struct ins), ins__cmp);
}
static struct ins *ins__find(const char *name) static struct ins *ins__find(const char *name)
{ {
const int nmemb = ARRAY_SIZE(instructions); const int nmemb = ARRAY_SIZE(instructions);
static bool sorted;
if (!sorted) {
ins__sort();
sorted = true;
}
return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp); return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp);
} }
int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym) int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym)
......
...@@ -298,8 +298,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe, ...@@ -298,8 +298,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
*/ */
callchain_param.order = ORDER_CALLER; callchain_param.order = ORDER_CALLER;
err = thread__resolve_callchain(thread, &callchain_cursor, evsel, err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
sample, NULL, NULL, sample, NULL, NULL, PERF_MAX_STACK_DEPTH);
sysctl_perf_event_max_stack);
if (err) { if (err) {
callchain_param.order = saved_order; callchain_param.order = saved_order;
return NULL; return NULL;
......
...@@ -63,9 +63,7 @@ int dso__read_binary_type_filename(const struct dso *dso, ...@@ -63,9 +63,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
} }
break; break;
case DSO_BINARY_TYPE__BUILD_ID_CACHE: case DSO_BINARY_TYPE__BUILD_ID_CACHE:
/* skip the locally configured cache if a symfs is given */ if (dso__build_id_filename(dso, filename, size) == NULL)
if (symbol_conf.symfs[0] ||
(dso__build_id_filename(dso, filename, size) == NULL))
ret = -1; ret = -1;
break; break;
......
...@@ -43,6 +43,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) ...@@ -43,6 +43,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->symbol_filter = NULL; machine->symbol_filter = NULL;
machine->id_hdr_size = 0; machine->id_hdr_size = 0;
machine->kptr_restrict_warned = false;
machine->comm_exec = false; machine->comm_exec = false;
machine->kernel_start = 0; machine->kernel_start = 0;
...@@ -1135,10 +1136,10 @@ int machine__create_kernel_maps(struct machine *machine) ...@@ -1135,10 +1136,10 @@ int machine__create_kernel_maps(struct machine *machine)
{ {
struct dso *kernel = machine__get_kernel(machine); struct dso *kernel = machine__get_kernel(machine);
const char *name; const char *name;
u64 addr = machine__get_running_kernel_start(machine, &name); u64 addr;
int ret; int ret;
if (!addr || kernel == NULL) if (kernel == NULL)
return -1; return -1;
ret = __machine__create_kernel_maps(machine, kernel); ret = __machine__create_kernel_maps(machine, kernel);
...@@ -1160,8 +1161,9 @@ int machine__create_kernel_maps(struct machine *machine) ...@@ -1160,8 +1161,9 @@ int machine__create_kernel_maps(struct machine *machine)
*/ */
map_groups__fixup_end(&machine->kmaps); map_groups__fixup_end(&machine->kmaps);
if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr = machine__get_running_kernel_start(machine, &name);
addr)) { if (!addr) {
} else if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) {
machine__destroy_kernel_maps(machine); machine__destroy_kernel_maps(machine);
return -1; return -1;
} }
...@@ -1769,11 +1771,6 @@ static int resolve_lbr_callchain_sample(struct thread *thread, ...@@ -1769,11 +1771,6 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
*/ */
int mix_chain_nr = i + 1 + lbr_nr + 1; int mix_chain_nr = i + 1 + lbr_nr + 1;
if (mix_chain_nr > (int)sysctl_perf_event_max_stack + PERF_MAX_BRANCH_DEPTH) {
pr_warning("corrupted callchain. skipping...\n");
return 0;
}
for (j = 0; j < mix_chain_nr; j++) { for (j = 0; j < mix_chain_nr; j++) {
if (callchain_param.order == ORDER_CALLEE) { if (callchain_param.order == ORDER_CALLEE) {
if (j < i + 1) if (j < i + 1)
...@@ -1813,7 +1810,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, ...@@ -1813,7 +1810,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
struct ip_callchain *chain = sample->callchain; struct ip_callchain *chain = sample->callchain;
int chain_nr = chain->nr; int chain_nr = chain->nr;
u8 cpumode = PERF_RECORD_MISC_USER; u8 cpumode = PERF_RECORD_MISC_USER;
int i, j, err, nr_entries, nr_contexts; int i, j, err, nr_entries;
int skip_idx = -1; int skip_idx = -1;
int first_call = 0; int first_call = 0;
...@@ -1828,8 +1825,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, ...@@ -1828,8 +1825,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
* Based on DWARF debug information, some architectures skip * Based on DWARF debug information, some architectures skip
* a callchain entry saved by the kernel. * a callchain entry saved by the kernel.
*/ */
if (chain_nr < sysctl_perf_event_max_stack) skip_idx = arch_skip_callchain_idx(thread, chain);
skip_idx = arch_skip_callchain_idx(thread, chain);
/* /*
* Add branches to call stack for easier browsing. This gives * Add branches to call stack for easier browsing. This gives
...@@ -1889,7 +1885,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, ...@@ -1889,7 +1885,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
} }
check_calls: check_calls:
for (i = first_call, nr_entries = 0, nr_contexts = 0; for (i = first_call, nr_entries = 0;
i < chain_nr && nr_entries < max_stack; i++) { i < chain_nr && nr_entries < max_stack; i++) {
u64 ip; u64 ip;
...@@ -1904,13 +1900,8 @@ static int thread__resolve_callchain_sample(struct thread *thread, ...@@ -1904,13 +1900,8 @@ static int thread__resolve_callchain_sample(struct thread *thread,
#endif #endif
ip = chain->ips[j]; ip = chain->ips[j];
if (ip >= PERF_CONTEXT_MAX) { if (ip < PERF_CONTEXT_MAX)
if (++nr_contexts > sysctl_perf_event_max_contexts_per_stack) ++nr_entries;
goto out_corrupted_callchain;
} else {
if (++nr_entries > sysctl_perf_event_max_stack)
goto out_corrupted_callchain;
}
err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip);
...@@ -1919,10 +1910,6 @@ static int thread__resolve_callchain_sample(struct thread *thread, ...@@ -1919,10 +1910,6 @@ static int thread__resolve_callchain_sample(struct thread *thread,
} }
return 0; return 0;
out_corrupted_callchain:
pr_warning("corrupted callchain. skipping...\n");
return 0;
} }
static int unwind_entry(struct unwind_entry *entry, void *arg) static int unwind_entry(struct unwind_entry *entry, void *arg)
......
...@@ -28,6 +28,7 @@ struct machine { ...@@ -28,6 +28,7 @@ struct machine {
pid_t pid; pid_t pid;
u16 id_hdr_size; u16 id_hdr_size;
bool comm_exec; bool comm_exec;
bool kptr_restrict_warned;
char *root_dir; char *root_dir;
struct rb_root threads; struct rb_root threads;
pthread_rwlock_t threads_lock; pthread_rwlock_t threads_lock;
......
...@@ -264,8 +264,7 @@ static SV *perl_process_callchain(struct perf_sample *sample, ...@@ -264,8 +264,7 @@ static SV *perl_process_callchain(struct perf_sample *sample,
goto exit; goto exit;
if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel, if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel,
sample, NULL, NULL, sample, NULL, NULL, scripting_max_stack) != 0) {
sysctl_perf_event_max_stack) != 0) {
pr_err("Failed to resolve callchain. Skipping\n"); pr_err("Failed to resolve callchain. Skipping\n");
goto exit; goto exit;
} }
......
...@@ -2033,3 +2033,26 @@ void symbol__exit(void) ...@@ -2033,3 +2033,26 @@ void symbol__exit(void)
symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
symbol_conf.initialized = false; symbol_conf.initialized = false;
} }
int symbol__config_symfs(const struct option *opt __maybe_unused,
const char *dir, int unset __maybe_unused)
{
char *bf = NULL;
int ret;
symbol_conf.symfs = strdup(dir);
if (symbol_conf.symfs == NULL)
return -ENOMEM;
/* skip the locally configured cache if a symfs is given, and
* config buildid dir to symfs/.debug
*/
ret = asprintf(&bf, "%s/%s", dir, ".debug");
if (ret < 0)
return -ENOMEM;
set_buildid_dir(bf);
free(bf);
return 0;
}
...@@ -290,6 +290,8 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type); ...@@ -290,6 +290,8 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type);
bool symbol__restricted_filename(const char *filename, bool symbol__restricted_filename(const char *filename,
const char *restricted_filename); const char *restricted_filename);
bool symbol__is_idle(struct symbol *sym); bool symbol__is_idle(struct symbol *sym);
int symbol__config_symfs(const struct option *opt __maybe_unused,
const char *dir, int unset __maybe_unused);
int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
struct symsrc *runtime_ss, symbol_filter_t filter, struct symsrc *runtime_ss, symbol_filter_t filter,
......
...@@ -27,7 +27,6 @@ struct perf_top { ...@@ -27,7 +27,6 @@ struct perf_top {
int max_stack; int max_stack;
bool hide_kernel_symbols, hide_user_symbols, zero; bool hide_kernel_symbols, hide_user_symbols, zero;
bool use_tui, use_stdio; bool use_tui, use_stdio;
bool kptr_restrict_warned;
bool vmlinux_warned; bool vmlinux_warned;
bool dump_symtab; bool dump_symtab;
struct hist_entry *sym_filter_entry; struct hist_entry *sym_filter_entry;
......
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