diff options
author | Ingo Molnar | 2013-12-11 11:57:46 +0100 |
---|---|---|
committer | Ingo Molnar | 2013-12-11 11:57:46 +0100 |
commit | 813932149e7847c91f544a03b943a84c5b264f76 (patch) | |
tree | 8e9a5f016e28797e7c07dfa1c16d15822a54a63c | |
parent | 789790791ad254408267eb6a216ae7a90973c05a (diff) | |
parent | 1448fef40af6079de38380c3a81bcf9994a1037d (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
* Add an option in 'perf script' to print the source line number, from Adrian Hunter
* Add --header/--header-only options to 'script' and 'report', the default is not
tho show the header info, but as this has been the default for some time,
leave a single line explaining how to obtain that information, from Jiri Olsa.
* Fix symoff printing in callchains in 'perf script', from Adrian Hunter.
* Assorted mmap_pages handling fixes, from Adrian Hunter.
* Fix summary percentage when processing files in 'perf trace', from David Ahern.
* Handle old kernels where the "raw_syscalls" tracepoints were called plan "syscalls",
in 'perf trace', from David Ahern.
* Several man pages typo fixes from Dongsheng Yang.
* Add '-v' option to 'perf kvm', from Dongsheng Yang.
* Make perf kvm diff support --guestmount, from Dongsheng Yang.
* Get rid of several die() calls in libtraceevent, from Namhyung Kim.
* Use basename() in a more robust way, to avoid problems related to different
system library implementations for that function, from Stephane Eranian.
* Remove open coded management of short_name_allocated member, from Adrian Hunter
* Several cleanups in the "dso" methods, constifying some parameters and
renaming some fields to clarify its purpose. (Arnaldo Carvalho de Melo.)
* Add per-feature check flags, fixing libunwind related build problems on some
architectures, from Jean Pihet.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
35 files changed, 375 insertions, 163 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 9849873265d4..22566c271275 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -2710,7 +2710,6 @@ process_func_handler(struct event_format *event, struct pevent_function_handler struct print_arg *farg; enum event_type type; char *token; - const char *test; int i; arg->type = PRINT_FUNC; @@ -2727,15 +2726,19 @@ process_func_handler(struct event_format *event, struct pevent_function_handler } type = process_arg(event, farg, &token); - if (i < (func->nr_args - 1)) - test = ","; - else - test = ")"; - - if (test_type_token(type, token, EVENT_DELIM, test)) { - free_arg(farg); - free_token(token); - return EVENT_ERROR; + if (i < (func->nr_args - 1)) { + if (type != EVENT_DELIM || strcmp(token, ",") != 0) { + warning("Error: function '%s()' expects %d arguments but event %s only uses %d", + func->name, func->nr_args, + event->name, i + 1); + goto err; + } + } else { + if (type != EVENT_DELIM || strcmp(token, ")") != 0) { + warning("Error: function '%s()' only expects %d arguments but event %s has more", + func->name, func->nr_args, event->name); + goto err; + } } *next_arg = farg; @@ -2747,6 +2750,11 @@ process_func_handler(struct event_format *event, struct pevent_function_handler *tok = token; return type; + +err: + free_arg(farg); + free_token(token); + return EVENT_ERROR; } static enum event_type diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 620c27a72960..6e23f197175f 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -860,7 +860,7 @@ int pevent_event_filtered(struct event_filter *filter, void pevent_filter_reset(struct event_filter *filter); -void pevent_filter_clear_trivial(struct event_filter *filter, +int pevent_filter_clear_trivial(struct event_filter *filter, enum filter_trivial_type type); void pevent_filter_free(struct event_filter *filter); diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 2500e75583fc..ab402fb2dcf7 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c @@ -182,7 +182,10 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) { struct event_filter *filter; - filter = malloc_or_die(sizeof(*filter)); + filter = malloc(sizeof(*filter)); + if (filter == NULL) + return NULL; + memset(filter, 0, sizeof(*filter)); filter->pevent = pevent; pevent_ref(pevent); @@ -242,15 +245,19 @@ static void free_arg(struct filter_arg *arg) free(arg); } -static void add_event(struct event_list **events, +static int add_event(struct event_list **events, struct event_format *event) { struct event_list *list; - list = malloc_or_die(sizeof(*list)); + list = malloc(sizeof(*list)); + if (list == NULL) + return -1; + list->next = *events; *events = list; list->event = event; + return 0; } static int event_match(struct event_format *event, @@ -273,6 +280,7 @@ find_event(struct pevent *pevent, struct event_list **events, regex_t ereg; regex_t sreg; int match = 0; + int fail = 0; char *reg; int ret; int i; @@ -307,7 +315,10 @@ find_event(struct pevent *pevent, struct event_list **events, event = pevent->events[i]; if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { match = 1; - add_event(events, event); + if (add_event(events, event) < 0) { + fail = 1; + break; + } } } @@ -317,6 +328,8 @@ find_event(struct pevent *pevent, struct event_list **events, if (!match) return -1; + if (fail) + return -2; return 0; } @@ -349,8 +362,11 @@ create_arg_item(struct event_format *event, const char *token, arg->value.type = type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; arg->value.str = strdup(token); - if (!arg->value.str) - die("malloc string"); + if (!arg->value.str) { + free_arg(arg); + show_error(error_str, "failed to allocate string filter arg"); + return NULL; + } break; case EVENT_ITEM: /* if it is a number, then convert it */ @@ -1210,7 +1226,13 @@ int pevent_filter_add_filter_str(struct event_filter *filter, else len = strlen(filter_str); - this_event = malloc_or_die(len + 1); + this_event = malloc(len + 1); + if (this_event == NULL) { + show_error(error_str, "Memory allocation failure"); + /* This can only happen when events is NULL, but still */ + free_events(events); + return -1; + } memcpy(this_event, filter_str, len); this_event[len] = 0; @@ -1482,8 +1504,10 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source * @type: remove only true, false, or both * * Removes filters that only contain a TRUE or FALES boolean arg. + * + * Returns 0 on success and -1 if there was a problem. */ -void pevent_filter_clear_trivial(struct event_filter *filter, +int pevent_filter_clear_trivial(struct event_filter *filter, enum filter_trivial_type type) { struct filter_type *filter_type; @@ -1492,13 +1516,15 @@ void pevent_filter_clear_trivial(struct event_filter *filter, int i; if (!filter->filters) - return; + return 0; /* * Two steps, first get all ids with trivial filters. * then remove those ids. */ for (i = 0; i < filter->filters; i++) { + int *new_ids; + filter_type = &filter->event_filters[i]; if (filter_type->filter->type != FILTER_ARG_BOOLEAN) continue; @@ -1513,19 +1539,24 @@ void pevent_filter_clear_trivial(struct event_filter *filter, break; } - ids = realloc(ids, sizeof(*ids) * (count + 1)); - if (!ids) - die("Can't allocate ids"); + new_ids = realloc(ids, sizeof(*ids) * (count + 1)); + if (!new_ids) { + free(ids); + return -1; + } + + ids = new_ids; ids[count++] = filter_type->event_id; } if (!count) - return; + return 0; for (i = 0; i < count; i++) pevent_filter_remove_event(filter, ids[i]); free(ids); + return 0; } /** diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt index 5032a142853e..ac6ecbb3e669 100644 --- a/tools/perf/Documentation/perf-archive.txt +++ b/tools/perf/Documentation/perf-archive.txt @@ -12,9 +12,9 @@ SYNOPSIS DESCRIPTION ----------- -This command runs runs perf-buildid-list --with-hits, and collects the files -with the buildids found so that analysis of perf.data contents can be possible -on another machine. +This command runs perf-buildid-list --with-hits, and collects the files with the +buildids found so that analysis of perf.data contents can be possible on another +machine. SEE ALSO diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index 96a9a1dea727..52276a6d2b75 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt @@ -10,9 +10,9 @@ SYNOPSIS [verse] 'perf kvm' [--host] [--guest] [--guestmount=<path> [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] - {top|record|report|diff|buildid-list} + {top|record|report|diff|buildid-list} [<options>] 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> - | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} + | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} [<options>] 'perf kvm stat [record|report|live] [<options>] DESCRIPTION @@ -93,6 +93,9 @@ OPTIONS kernel module information. Users copy it out from guest os. --guestvmlinux=<path>:: Guest os kernel vmlinux. +-v:: +--verbose:: + Be more verbose (show counter open errors, etc). STAT REPORT OPTIONS ------------------- diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 10a279871251..8eab8a4bdeb8 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -237,6 +237,15 @@ OPTIONS Do not show entries which have an overhead under that percent. (Default: 0). +--header:: + Show header information in the perf.data file. This includes + various information like hostname, OS and perf version, cpu/mem + info, perf command line, event list and so on. Currently only + --stdio output supports this feature. + +--header-only:: + Show only perf.data header (forces --stdio). + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-annotate[1] diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index cfdbb1e045b5..05f9a0a6784c 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -115,7 +115,7 @@ OPTIONS -f:: --fields:: Comma separated list of fields to print. Options are: - comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff. + comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, srcline. Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace @@ -209,6 +209,12 @@ OPTIONS --show-mmap-events Display mmap related events (e.g. MMAP, MMAP2). +--header + Show perf.data header. + +--header-only + Show only perf.data header. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-script-perl[1], diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 4087ab19823c..6fd52c8fa682 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -373,7 +373,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) if (argc) { /* - * Special case: if there's an argument left then assume tha + * Special case: if there's an argument left then assume that * it's a symbol filter: */ if (argc > 1) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 3b67ea2444bd..2a85cc9a2d09 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1000,8 +1000,7 @@ static int data_init(int argc, const char **argv) data__files_cnt = argc; use_default = false; } - } else if (symbol_conf.default_guest_vmlinux_name || - symbol_conf.default_guest_kallsyms) { + } else if (perf_guest) { defaults[0] = "perf.data.host"; defaults[1] = "perf.data.guest"; } diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index f8bf5f244d77..c6fa3cbd45a9 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1232,7 +1232,7 @@ static int read_events(struct perf_kvm_stat *kvm) .ordered_samples = true, }; struct perf_data_file file = { - .path = input_name, + .path = kvm->file_name, .mode = PERF_DATA_MODE_READ, }; @@ -1690,6 +1690,8 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) "file", "file saving guest os /proc/kallsyms"), OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, "file", "file saving guest os /proc/modules"), + OPT_INCR('v', "verbose", &verbose, + "be more verbose (show counter open errors, etc)"), OPT_END() }; @@ -1711,12 +1713,7 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) perf_guest = 1; if (!file_name) { - if (perf_host && !perf_guest) - file_name = strdup("perf.data.host"); - else if (!perf_host && perf_guest) - file_name = strdup("perf.data.guest"); - else - file_name = strdup("perf.data.kvm"); + file_name = get_filename_for_perf_kvm(); if (!file_name) { pr_err("Failed to allocate memory for filename\n"); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d93e2eef0979..c1c1200d2f0a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -224,7 +224,7 @@ try_again: "Consider increasing " "/proc/sys/kernel/perf_event_mlock_kb,\n" "or try again with a smaller value of -m/--mmap_pages.\n" - "(current value: %d)\n", opts->mmap_pages); + "(current value: %u)\n", opts->mmap_pages); rc = -errno; } else { pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8cf8e66ba594..3a14dbed387c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -49,6 +49,8 @@ struct perf_report { bool show_threads; bool inverted_callchain; bool mem_mode; + bool header; + bool header_only; int max_stack; struct perf_read_values show_threads_values; const char *pretty_printing_style; @@ -514,9 +516,6 @@ static int __cmd_report(struct perf_report *rep) return ret; } - if (use_browser <= 0) - perf_session__fprintf_info(session, stdout, rep->show_full_info); - if (rep->show_threads) perf_read_values_init(&rep->show_threads_values); @@ -820,6 +819,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), OPT_BOOLEAN(0, "stdio", &report.use_stdio, "Use the stdio interface"), + OPT_BOOLEAN(0, "header", &report.header, "Show data header."), + OPT_BOOLEAN(0, "header-only", &report.header_only, + "Show only data header."), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," " dso_to, dso_from, symbol_to, symbol_from, mispredict," @@ -963,6 +965,10 @@ repeat: goto error; } + /* Force tty output for header output. */ + if (report.header || report.header_only) + use_browser = 0; + if (strcmp(input_name, "-") != 0) setup_browser(true); else { @@ -970,6 +976,16 @@ repeat: perf_hpp__init(); } + if (report.header || report.header_only) { + perf_session__fprintf_info(session, stdout, + report.show_full_info); + if (report.header_only) + return 0; + } else if (use_browser == 0) { + fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n", + stdout); + } + /* * Only in the TUI browser we are doing integrated annotation, * so don't allocate extra space that won't be used in the stdio diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4484886dcf08..f8ab125aac48 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -43,6 +43,7 @@ enum perf_output_field { PERF_OUTPUT_DSO = 1U << 9, PERF_OUTPUT_ADDR = 1U << 10, PERF_OUTPUT_SYMOFFSET = 1U << 11, + PERF_OUTPUT_SRCLINE = 1U << 12, }; struct output_option { @@ -61,6 +62,7 @@ struct output_option { {.str = "dso", .field = PERF_OUTPUT_DSO}, {.str = "addr", .field = PERF_OUTPUT_ADDR}, {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, + {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, }; /* default set to maintain compatibility with current format */ @@ -210,6 +212,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, "to DSO.\n"); return -EINVAL; } + if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { + pr_err("Display of source line number requested but sample IP is not\n" + "selected. Hence, no address to lookup the source line number.\n"); + return -EINVAL; + } if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", @@ -245,6 +252,9 @@ static void set_print_ip_opts(struct perf_event_attr *attr) if (PRINT_FIELD(SYMOFFSET)) output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; + + if (PRINT_FIELD(SRCLINE)) + output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE; } /* @@ -1484,6 +1494,8 @@ static int have_cmd(int argc, const char **argv) int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) { bool show_full_info = false; + bool header = false; + bool header_only = false; char *rec_script_path = NULL; char *rep_script_path = NULL; struct perf_session *session; @@ -1522,6 +1534,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) OPT_STRING('i', "input", &input_name, "file", "input file name"), OPT_BOOLEAN('d', "debug-mode", &debug_mode, "do various checks like samples ordering and lost events"), + OPT_BOOLEAN(0, "header", &header, "Show data header."), + OPT_BOOLEAN(0, "header-only", &header_only, "Show only data header."), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, @@ -1738,6 +1752,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) if (session == NULL) return -ENOMEM; + if (header || header_only) { + perf_session__fprintf_info(session, stdout, show_full_info); + if (header_only) + return 0; + } + script.session = session; if (cpu_list) { @@ -1745,9 +1765,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) return -1; } - if (!script_name && !generate_script_lang) - perf_session__fprintf_info(session, stdout, show_full_info); - if (!no_callchain) symbol_conf.use_callchain = true; else diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 56afe339661a..56bbca5bc2dc 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -12,6 +12,7 @@ #include "util/thread_map.h" #include "util/stat.h" #include "trace-event.h" +#include "util/parse-events.h" #include <libaudit.h> #include <stdlib.h> @@ -173,6 +174,10 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void { struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); + /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */ + if (evsel == NULL) + evsel = perf_evsel__newtp("syscalls", direction); + if (evsel) { if (perf_evsel__init_syscall_tp(evsel, handler)) goto out_delete; @@ -1765,8 +1770,10 @@ static int trace__process_sample(struct perf_tool *tool, if (!trace->full_time && trace->base_time == 0) trace->base_time = sample->time; - if (handler) + if (handler) { + ++trace->nr_events; handler(trace, evsel, sample); + } return err; } @@ -1801,10 +1808,11 @@ static int trace__record(int argc, const char **argv) "-R", "-m", "1024", "-c", "1", - "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit", + "-e", }; - rec_argc = ARRAY_SIZE(record_args) + argc; + /* +1 is for the event string below */ + rec_argc = ARRAY_SIZE(record_args) + 1 + argc; rec_argv = calloc(rec_argc + 1, sizeof(char *)); if (rec_argv == NULL) @@ -1813,6 +1821,17 @@ static int trace__record(int argc, const char **argv) for (i = 0; i < ARRAY_SIZE(record_args); i++) rec_argv[i] = record_args[i]; + /* event string may be different for older kernels - e.g., RHEL6 */ + if (is_valid_tracepoint("raw_syscalls:sys_enter")) + rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; + else if (is_valid_tracepoint("syscalls:sys_enter")) + rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; + else { + pr_err("Neither raw_syscalls nor syscalls events exist.\n"); + return -1; + } + i++; + for (j = 0; j < (unsigned int)argc; j++, i++) rec_argv[i] = argv[j]; @@ -2048,6 +2067,10 @@ static int trace__replay(struct trace *trace) evsel = perf_evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_enter"); + /* older kernels have syscalls tp versus raw_syscalls */ + if (evsel == NULL) + evsel = perf_evlist__find_tracepoint_by_name(session->evlist, + "syscalls:sys_enter"); if (evsel == NULL) { pr_err("Data file does not have raw_syscalls:sys_enter event\n"); goto out; @@ -2061,6 +2084,9 @@ static int trace__replay(struct trace *trace) evsel = perf_evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_exit"); + if (evsel == NULL) + evsel = perf_evlist__find_tracepoint_by_name(session->evlist, + "syscalls:sys_exit"); if (evsel == NULL) { pr_err("Data file does not have raw_syscalls:sys_exit event\n"); goto out; diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index bae10720a136..5a1f4df3c3a8 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -36,6 +36,30 @@ ifeq ($(ARCH),arm) LIBUNWIND_LIBS = -lunwind -lunwind-arm endif +ifeq ($(LIBUNWIND_LIBS),) + NO_LIBUNWIND := 1 +else + # + # For linking with debug library, run like: + # + # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ + # + ifdef LIBUNWIND_DIR + LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include + LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib + endif + LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS) + + # Set per-feature check compilation flags + FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS) + FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) + FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS) + FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) + # and the flags for the test-all case + FEATURE_CHECK_CFLAGS-all += $(LIBUNWIND_CFLAGS) + FEATURE_CHECK_LDFLAGS-all += $(LIBUNWIND_LDFLAGS) +endif + ifeq ($(NO_PERF_REGS),0) CFLAGS += -DHAVE_PERF_REGS_SUPPORT endif @@ -102,7 +126,7 @@ endif feature_check = $(eval $(feature_check_code)) define feature_check_code - feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBUNWIND_LIBS="$(LIBUNWIND_LIBS)" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0) + feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0) endef feature_set = $(eval $(feature_set_code)) @@ -305,21 +329,7 @@ ifndef NO_LIBELF endif # NO_DWARF endif # NO_LIBELF -ifeq ($(LIBUNWIND_LIBS),) - NO_LIBUNWIND := 1 -endif - ifndef NO_LIBUNWIND - # - # For linking with debug library, run like: - # - # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ - # - ifdef LIBUNWIND_DIR - LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include - LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib - endif - ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1); NO_LIBUNWIND := 1 @@ -334,14 +344,12 @@ ifndef NO_LIBUNWIND # non-ARM has no dwarf_find_debug_frame() function: CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME endif - endif -endif -ifndef NO_LIBUNWIND - CFLAGS += -DHAVE_LIBUNWIND_SUPPORT - EXTLIBS += $(LIBUNWIND_LIBS) - CFLAGS += $(LIBUNWIND_CFLAGS) - LDFLAGS += $(LIBUNWIND_LDFLAGS) + CFLAGS += -DHAVE_LIBUNWIND_SUPPORT + EXTLIBS += $(LIBUNWIND_LIBS) + CFLAGS += $(LIBUNWIND_CFLAGS) + LDFLAGS += $(LIBUNWIND_LDFLAGS) + endif # ifneq ($(feature-libunwind), 1) endif ifndef NO_LIBAUDIT diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index b8bb749c3392..bc86462e80a2 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile @@ -32,12 +32,12 @@ CC := $(CC) -MD all: $(FILES) -BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c +BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $@.c $(LDFLAGS) ############################### test-all: - $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl + $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl test-hello: $(BUILD) @@ -70,10 +70,10 @@ test-libnuma: $(BUILD) -lnuma test-libunwind: - $(BUILD) $(LIBUNWIND_LIBS) -lelf + $(BUILD) -lelf test-libunwind-debug-frame: - $(BUILD) $(LIBUNWIND_LIBS) -lelf + $(BUILD) -lelf test-libaudit: $(BUILD) -laudit diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index cf6242c92ee2..0fcd81ea31ae 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -900,7 +900,7 @@ fallback: * cache, or is just a kallsyms file, well, lets hope that this * DSO is the same as when 'perf record' ran. */ - filename = dso->long_name; + filename = (char *)dso->long_name; snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", symbol_conf.symfs, filename); free_filename = false; diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index a92770c98cc7..6baabe63182b 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -89,7 +89,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf) return raw - build_id; } -char *dso__build_id_filename(struct dso *dso, char *bf, size_t size) +char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size) { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 929f28a7c14d..845ef865eced 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -10,7 +10,7 @@ extern struct perf_tool build_id__mark_dso_hit_ops; struct dso; int build_id__sprintf(const u8 *build_id, int len, char *bf); -char *dso__build_id_filename(struct dso *dso, char *bf, size_t size); +char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index a0c7c591f4b2..436922f1f9d9 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -28,8 +28,8 @@ char dso__symtab_origin(const struct dso *dso) return origin[dso->symtab_type]; } -int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, - char *root_dir, char *file, size_t size) +int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type, + char *root_dir, char *filename, size_t size) { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; int ret = 0; @@ -38,36 +38,36 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, case DSO_BINARY_TYPE__DEBUGLINK: { char *debuglink; - strncpy(file, dso->long_name, size); - debuglink = file + dso->long_name_len; - while (debuglink != file && *debuglink != '/') + strncpy(filename, dso->long_name, size); + debuglink = filename + dso->long_name_len; + while (debuglink != filename && *debuglink != '/') debuglink--; if (*debuglink == '/') debuglink++; filename__read_debuglink(dso->long_name, debuglink, - size - (debuglink - file)); + size - (debuglink - filename)); } break; case DSO_BINARY_TYPE__BUILD_ID_CACHE: /* skip the locally configured cache if a symfs is given */ if (symbol_conf.symfs[0] || - (dso__build_id_filename(dso, file, size) == NULL)) + (dso__build_id_filename(dso, filename, size) == NULL)) ret = -1; break; case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: - snprintf(file, size, "%s/usr/lib/debug%s.debug", + snprintf(filename, size, "%s/usr/lib/debug%s.debug", symbol_conf.symfs, dso->long_name); break; case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: - snprintf(file, size, "%s/usr/lib/debug%s", + snprintf(filename, size, "%s/usr/lib/debug%s", symbol_conf.symfs, dso->long_name); break; case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: { - char *last_slash; + const char *last_slash; size_t len; size_t dir_size; @@ -75,14 +75,14 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, while (last_slash != dso->long_name && *last_slash != '/') last_slash--; - len = scnprintf(file, size, "%s", symbol_conf.symfs); + len = scnprintf(filename, size, "%s", symbol_conf.symfs); dir_size = last_slash - dso->long_name + 2; if (dir_size > (size - len)) { ret = -1; break; } - len += scnprintf(file + len, dir_size, "%s", dso->long_name); - len += scnprintf(file + len , size - len, ".debug%s", + len += scnprintf(filename + len, dir_size, "%s", dso->long_name); + len += scnprintf(filename + len , size - len, ".debug%s", last_slash); break; } @@ -96,7 +96,7 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex); - snprintf(file, size, + snprintf(filename, size, "%s/usr/lib/debug/.build-id/%.2s/%s.debug", symbol_conf.symfs, build_id_hex, build_id_hex + 2); break; @@ -104,23 +104,23 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, case DSO_BINARY_TYPE__VMLINUX: case DSO_BINARY_TYPE__GUEST_VMLINUX: case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: - snprintf(file, size, "%s%s", + snprintf(filename, size, "%s%s", symbol_conf.symfs, dso->long_name); break; case DSO_BINARY_TYPE__GUEST_KMODULE: - snprintf(file, size, "%s%s%s", symbol_conf.symfs, + snprintf(filename, size, "%s%s%s", symbol_conf.symfs, root_dir, dso->long_name); break; case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: - snprintf(file, size, "%s%s", symbol_conf.symfs, + snprintf(filename, size, "%s%s", symbol_conf.symfs, dso->long_name); break; case DSO_BINARY_TYPE__KCORE: case DSO_BINARY_TYPE__GUEST_KCORE: - snprintf(file, size, "%s", dso->long_name); + snprintf(filename, size, "%s", dso->long_name); break; default: @@ -200,11 +200,10 @@ dso_cache__free(struct rb_root *root) } } -static struct dso_cache* -dso_cache__find(struct rb_root *root, u64 offset) +static struct dso_cache *dso_cache__find(const struct rb_root *root, u64 offset) { - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; + struct rb_node * const *p = &root->rb_node; + const struct rb_node *parent = NULL; struct dso_cache *cache; while (*p != NULL) { @@ -379,32 +378,63 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name, * processing we had no idea this was the kernel dso. */ if (dso != NULL) { - dso__set_short_name(dso, short_name); + dso__set_short_name(dso, short_name, false); dso->kernel = dso_type; } return dso; } -void dso__set_long_name(struct dso *dso, char *name) +void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) { if (name == NULL) return; - dso->long_name = name; - dso->long_name_len = strlen(name); + + if (dso->long_name_allocated) + free((char *)dso->long_name); + + dso->long_name = name; + dso->long_name_len = strlen(name); + dso->long_name_allocated = name_allocated; } -void dso__set_short_name(struct dso *dso, const char *name) +void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) { if (name == NULL) return; - dso->short_name = name; - dso->short_name_len = strlen(name); + + if (dso->short_name_allocated) + free((char *)dso->short_name); + + dso->short_name = name; + dso->short_name_len = strlen(name); + dso->short_name_allocated = name_allocated; } static void dso__set_basename(struct dso *dso) { - dso__set_short_name(dso, basename(dso->long_name)); + /* + * basename() may modify path buffer, so we must pass + * a copy. + */ + char *base, *lname = strdup(dso->long_name); + + if (!lname) + return; + + /* + * basename() may return a pointer to internal + * storage which is reused in subsequent calls + * so copy the result. + */ + base = strdup(basename(lname)); + + free(lname); + + if (!base) + return; + + dso__set_short_name(dso, base, true); } int dso__name_len(const struct dso *dso) @@ -439,8 +469,8 @@ struct dso *dso__new(const char *name) if (dso != NULL) { int i; strcpy(dso->name, name); - dso__set_long_name(dso, dso->name); - dso__set_short_name(dso, dso->name); + dso__set_long_name(dso, dso->name, false); + dso__set_short_name(dso, dso->name, false); for (i = 0; i < MAP__NR_TYPES; ++i) dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; dso->cache = RB_ROOT; @@ -465,13 +495,23 @@ void dso__delete(struct dso *dso) int i; for (i = 0; i < MAP__NR_TYPES; ++i) symbols__delete(&dso->symbols[i]); - if (dso->sname_alloc) + + if (dso->short_name_allocated) { free((char *)dso->short_name); - if (dso->lname_alloc) - free(dso->long_name); + dso->short_name = NULL; + dso->short_name_allocated = false; + } + + if (dso->long_name_allocated) { + free((char *)dso->long_name); + dso->long_name = NULL; + dso->long_name_allocated = false; + } + dso_cache__free(&dso->cache); dso__free_a2l(dso); free(dso->symsrc_filename); + dso->symsrc_filename = NULL; free(dso); } @@ -546,7 +586,7 @@ void dsos__add(struct list_head *head, struct dso *dso) list_add_tail(&dso->node, head); } -struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short) +struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short) { struct dso *pos; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 384f2d97e38e..e1cc50698137 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -89,14 +89,14 @@ struct dso { u8 has_srcline:1; u8 hit:1; u8 annotate_warned:1; - u8 sname_alloc:1; - u8 lname_alloc:1; + u8 short_name_allocated:1; + u8 long_name_allocated:1; u8 sorted_by_name; u8 loaded; u8 rel; u8 build_id[BUILD_ID_SIZE]; const char *short_name; - char *long_name; + const char *long_name; u16 long_name_len; u16 short_name_len; char name[0]; @@ -110,8 +110,8 @@ static inline void dso__set_loaded(struct dso *dso, enum map_type type) struct dso *dso__new(const char *name); void dso__delete(struct dso *dso); -void dso__set_short_name(struct dso *dso, const char *name); -void dso__set_long_name(struct dso *dso, char *name); +void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated); +void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated); int dso__name_len(const struct dso *dso); @@ -128,8 +128,8 @@ void dso__read_running_kernel_build_id(struct dso *dso, int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); char dso__symtab_origin(const struct dso *dso); -int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, - char *root_dir, char *file, size_t size); +int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type, + char *root_dir, char *filename, size_t size); int dso__data_fd(struct dso *dso, struct machine *machine); ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, @@ -143,7 +143,7 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name, const char *short_name, int dso_type); void dsos__add(struct list_head *head, struct dso *dso); -struct dso *dsos__find(struct list_head *head, const char *name, +struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short); struct dso *__dsos__findnew(struct list_head *head, const char *name); bool __dsos__read_build_ids(struct list_head *head, bool with_hits); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 7bb6ee1ca19f..af250556b33f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -732,11 +732,13 @@ static long parse_pages_arg(const char *str, unsigned long min, return -EINVAL; } - if ((pages == 0) && (min == 0)) { + if (pages == 0 && min == 0) { /* leave number of pages at 0 */ - } else if (pages < (1UL << 31) && !is_power_of_2(pages)) { + } else if (!is_power_of_2(pages)) { /* round pages up to next power of 2 */ - pages = next_pow2(pages); + pages = next_pow2_l(pages); + if (!pages) + return -EINVAL; pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", pages * page_size, pages); } @@ -754,7 +756,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, unsigned long max = UINT_MAX; long pages; - if (max < SIZE_MAX / page_size) + if (max > SIZE_MAX / page_size) max = SIZE_MAX / page_size; pages = parse_pages_arg(str, 1, max); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 125cdc9250ee..0bb830f6b49c 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -177,7 +177,7 @@ perf_header__set_cmdline(int argc, const char **argv) continue; \ else -static int write_buildid(char *name, size_t name_len, u8 *build_id, +static int write_buildid(const char *name, size_t name_len, u8 *build_id, pid_t pid, u16 misc, int fd) { int err; @@ -209,7 +209,7 @@ static int __dsos__write_buildid_table(struct list_head *head, dsos__for_each_with_build_id(pos, head) { int err; - char *name; + const char *name; size_t name_len; if (!pos->hit) @@ -387,7 +387,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine, { bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; bool is_vdso = is_vdso_map(dso->short_name); - char *name = dso->long_name; + const char *name = dso->long_name; char nm[PATH_MAX]; if (dso__is_kcore(dso)) { diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index bac817ab2068..751454bcde69 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -763,8 +763,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, ret = -1; goto out; } - dso__set_long_name(map->dso, long_name); - map->dso->lname_alloc = 1; + dso__set_long_name(map->dso, long_name, true); dso__kernel_module_get_build_id(map->dso, ""); } } @@ -935,8 +934,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, if (name == NULL) goto out_problem; - map->dso->short_name = name; - map->dso->sname_alloc = 1; + dso__set_short_name(map->dso, name, true); map->end = map->start + event->mmap.len; } else if (is_kernel_mmap) { const char *symbol_name = (event->mmap.filename + diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ef5bc913ca7a..9b9bd719aa19 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -11,6 +11,7 @@ #include "strlist.h" #include "vdso.h" #include "build-id.h" +#include "util.h" #include <linux/string.h> const char *map_type__name[MAP__NR_TYPES] = { @@ -252,6 +253,22 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) return fprintf(fp, "%s", dsoname); } +int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, + FILE *fp) +{ + char *srcline; + int ret = 0; + + if (map && map->dso) { + srcline = get_srcline(map->dso, + map__rip_2objdump(map, addr)); + if (srcline != SRCLINE_UNKNOWN) + ret = fprintf(fp, "%s%s", prefix, srcline); + free_srcline(srcline); + } + return ret; +} + /** * map__rip_2objdump - convert symbol start address to objdump address. * @map: memory map diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index e4e259c3ba16..18068c6b71c1 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -103,6 +103,8 @@ struct map *map__clone(struct map *map); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *map, FILE *fp); size_t map__fprintf_dsoname(struct map *map, FILE *fp); +int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, + FILE *fp); int map__load(struct map *map, symbol_filter_t filter); struct symbol *map__find_symbol(struct map *map, diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 9c6989ca2bea..d7cff57945c2 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -154,7 +154,7 @@ static struct dso *kernel_get_module_dso(const char *module) vmlinux_name = symbol_conf.vmlinux_name; if (vmlinux_name) { - if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) + if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) return NULL; } else { if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8a7da6f4a569..e748f29c53cf 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1497,6 +1497,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, int print_dso = print_opts & PRINT_IP_OPT_DSO; int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; + int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; char s = print_oneline ? ' ' : '\t'; if (symbol_conf.use_callchain && sample->callchain) { @@ -1515,6 +1516,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, node_al = *al; while (stack_depth) { + u64 addr = 0; + node = callchain_cursor_current(&callchain_cursor); if (!node) break; @@ -1525,10 +1528,13 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, if (print_ip) printf("%c%16" PRIx64, s, node->ip); + if (node->map) + addr = node->map->map_ip(node->map, node->ip); + if (print_sym) { printf(" "); if (print_symoffset) { - node_al.addr = node->ip; + node_al.addr = addr; node_al.map = node->map; symbol__fprintf_symname_offs(node->sym, &node_al, stdout); } else @@ -1541,6 +1547,10 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, printf(")"); } + if (print_srcline) + map__fprintf_srcline(node->map, addr, "\n ", + stdout); + if (!print_oneline) printf("\n"); @@ -1570,6 +1580,9 @@ next: map__fprintf_dsoname(al->map, stdout); printf(")"); } + + if (print_srcline) + map__fprintf_srcline(al->map, al->addr, "\n ", stdout); } } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 004d3e8116aa..2a3955ea4fd8 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -45,6 +45,7 @@ struct perf_session { #define PRINT_IP_OPT_DSO (1<<2) #define PRINT_IP_OPT_SYMOFFSET (1<<3) #define PRINT_IP_OPT_ONELINE (1<<4) +#define PRINT_IP_OPT_SRCLINE (1<<5) struct perf_tool; diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 0c075560ad46..58b2bd8f38c9 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -255,7 +255,7 @@ char *get_srcline(struct dso *dso, unsigned long addr) char *file = NULL; unsigned line = 0; char *srcline; - char *dso_name; + const char *dso_name; if (!dso->has_srcline) return SRCLINE_UNKNOWN; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index de87dbac50a0..e377c2e96191 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1159,7 +1159,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; else dso->data_type = DSO_BINARY_TYPE__KCORE; - dso__set_long_name(dso, strdup(kcore_filename)); + dso__set_long_name(dso, strdup(kcore_filename), true); close(fd); @@ -1408,7 +1408,8 @@ struct map *map_groups__find_by_name(struct map_groups *mg, } int dso__load_vmlinux(struct dso *dso, struct map *map, - const char *vmlinux, symbol_filter_t filter) + const char *vmlinux, bool vmlinux_allocated, + symbol_filter_t filter) { int err = -1; struct symsrc ss; @@ -1437,7 +1438,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; else dso->data_type = DSO_BINARY_TYPE__VMLINUX; - dso__set_long_name(dso, (char *)vmlinux); + dso__set_long_name(dso, vmlinux, vmlinux_allocated); dso__set_loaded(dso, map->type); pr_debug("Using %s for symbols\n", symfs_vmlinux); } @@ -1456,21 +1457,16 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, filename = dso__build_id_filename(dso, NULL, 0); if (filename != NULL) { - err = dso__load_vmlinux(dso, map, filename, filter); - if (err > 0) { - dso->lname_alloc = 1; + err = dso__load_vmlinux(dso, map, filename, true, filter); + if (err > 0) goto out; - } free(filename); } for (i = 0; i < vmlinux_path__nr_entries; ++i) { - err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); - if (err > 0) { - dso__set_long_name(dso, strdup(vmlinux_path[i])); - dso->lname_alloc = 1; + err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); + if (err > 0) break; - } } out: return err; @@ -1607,15 +1603,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, } if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { - err = dso__load_vmlinux(dso, map, - symbol_conf.vmlinux_name, filter); - if (err > 0) { - dso__set_long_name(dso, - strdup(symbol_conf.vmlinux_name)); - dso->lname_alloc = 1; - return err; - } - return err; + return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, + false, filter); } if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { @@ -1641,7 +1630,7 @@ do_kallsyms: free(kallsyms_allocated_filename); if (err > 0 && !dso__is_kcore(dso)) { - dso__set_long_name(dso, strdup("[kernel.kallsyms]")); + dso__set_long_name(dso, "[kernel.kallsyms]", false); map__fixup_start(map); map__fixup_end(map); } @@ -1671,7 +1660,8 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, */ if (symbol_conf.default_guest_vmlinux_name != NULL) { err = dso__load_vmlinux(dso, map, - symbol_conf.default_guest_vmlinux_name, filter); + symbol_conf.default_guest_vmlinux_name, + false, filter); return err; } @@ -1688,7 +1678,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, pr_debug("Using %s for symbols\n", kallsyms_filename); if (err > 0 && !dso__is_kcore(dso)) { machine__mmap_name(machine, path, sizeof(path)); - dso__set_long_name(dso, strdup(path)); + dso__set_long_name(dso, strdup(path), true); map__fixup_start(map); map__fixup_end(map); } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index f1031a1358a1..6de9c2b8a601 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -206,7 +206,8 @@ bool symsrc__possibly_runtime(struct symsrc *ss); int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); int dso__load_vmlinux(struct dso *dso, struct map *map, - const char *vmlinux, symbol_filter_t filter); + const char *vmlinux, bool vmlinux_allocated, + symbol_filter_t filter); int dso__load_vmlinux_path(struct dso *dso, struct map *map, symbol_filter_t filter); int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index bae8756a4eb1..4a57609c0b43 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -482,3 +482,17 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) close(fd); return err; } + +const char *get_filename_for_perf_kvm(void) +{ + const char *filename; + + if (perf_host && !perf_guest) + filename = strdup("perf.data.host"); + else if (!perf_host && perf_guest) + filename = strdup("perf.data.guest"); + else + filename = strdup("perf.data.kvm"); + + return filename; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index adb39f251f90..0171213d1d4d 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -73,6 +73,7 @@ #include <sys/ttydefaults.h> #include <lk/debugfs.h> #include <termios.h> +#include <linux/bitops.h> extern const char *graph_line; extern const char *graph_dotted_line; @@ -281,6 +282,17 @@ static inline unsigned next_pow2(unsigned x) return 1ULL << (32 - __builtin_clz(x - 1)); } +static inline unsigned long next_pow2_l(unsigned long x) +{ +#if BITS_PER_LONG == 64 + if (x <= (1UL << 31)) + return next_pow2(x); + return (unsigned long)next_pow2(x >> 32) << 32; +#else + return next_pow2(x); +#endif +} + size_t hex_width(u64 v); int hex2u64(const char *ptr, u64 *val); @@ -309,4 +321,6 @@ void free_srcline(char *srcline); int filename__read_int(const char *filename, int *value); int filename__read_str(const char *filename, char **buf, size_t *sizep); + +const char *get_filename_for_perf_kvm(void); #endif /* GIT_COMPAT_UTIL_H */ diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 39159822d58f..0ddb3b8a89ec 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -103,7 +103,7 @@ struct dso *vdso__dso_findnew(struct list_head *head) dso = dso__new(VDSO__MAP_NAME); if (dso != NULL) { dsos__add(head, dso); - dso__set_long_name(dso, file); + dso__set_long_name(dso, file, false); } } |