diff options
Diffstat (limited to 'tools/perf')
82 files changed, 908 insertions, 764 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 97a2145e4cc6..3638b0bd20dc 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -489,6 +489,7 @@ ifndef NO_SLANG LIB_OBJS += $(OUTPUT)ui/browsers/hists.o LIB_OBJS += $(OUTPUT)ui/browsers/map.o LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o + LIB_OBJS += $(OUTPUT)ui/browsers/header.o LIB_OBJS += $(OUTPUT)ui/tui/setup.o LIB_OBJS += $(OUTPUT)ui/tui/util.o LIB_OBJS += $(OUTPUT)ui/tui/helpline.o diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index aacef07ebf31..42faf369211c 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -154,8 +154,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env, } if (lookup_path(buf)) goto out; - free(buf); - buf = NULL; + zfree(&buf); } if (!strcmp(arch, "arm")) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6fd52c8fa682..ab65057a0317 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -69,15 +69,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, if (he == NULL) return -ENOMEM; - ret = 0; - if (he->ms.sym != NULL) { - struct annotation *notes = symbol__annotation(he->ms.sym); - if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) - return -ENOMEM; - - ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); - } - + ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); evsel->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); return ret; @@ -188,8 +180,7 @@ find_next: * symbol, free he->ms.sym->src to signal we already * processed this symbol. */ - free(notes->src); - notes->src = NULL; + zfree(¬es->src); } } } diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 2a85cc9a2d09..e6a0844bc2f0 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -654,7 +654,7 @@ static void data__free(struct data__file *d) for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) { struct diff_hpp_fmt *fmt = &d->fmt[col]; - free(fmt->header); + zfree(&fmt->header); } } diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 6a2508589460..c9f6d74e1fd7 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -22,14 +22,13 @@ #include <linux/list.h> struct perf_inject { - struct perf_tool tool; - bool build_ids; - bool sched_stat; - const char *input_name; - int pipe_output, - output; - u64 bytes_written; - struct list_head samples; + struct perf_tool tool; + bool build_ids; + bool sched_stat; + const char *input_name; + struct perf_data_file output; + u64 bytes_written; + struct list_head samples; }; struct event_entry { @@ -42,21 +41,14 @@ static int perf_event__repipe_synth(struct perf_tool *tool, union perf_event *event) { struct perf_inject *inject = container_of(tool, struct perf_inject, tool); - uint32_t size; - void *buf = event; + ssize_t size; - size = event->header.size; - - while (size) { - int ret = write(inject->output, buf, size); - if (ret < 0) - return -errno; - - size -= ret; - buf += ret; - inject->bytes_written += ret; - } + size = perf_data_file__write(&inject->output, event, + event->header.size); + if (size < 0) + return -errno; + inject->bytes_written += size; return 0; } @@ -80,7 +72,7 @@ static int perf_event__repipe_attr(struct perf_tool *tool, if (ret) return ret; - if (!inject->pipe_output) + if (&inject->output.is_pipe) return 0; return perf_event__repipe_synth(tool, event); @@ -355,6 +347,7 @@ static int __cmd_inject(struct perf_inject *inject) .path = inject->input_name, .mode = PERF_DATA_MODE_READ, }; + struct perf_data_file *file_out = &inject->output; signal(SIGINT, sig_handler); @@ -391,14 +384,14 @@ static int __cmd_inject(struct perf_inject *inject) } } - if (!inject->pipe_output) - lseek(inject->output, session->header.data_offset, SEEK_SET); + if (!file_out->is_pipe) + lseek(file_out->fd, session->header.data_offset, SEEK_SET); ret = perf_session__process_events(session, &inject->tool); - if (!inject->pipe_output) { + if (!file_out->is_pipe) { session->header.data_size = inject->bytes_written; - perf_session__write_header(session, session->evlist, inject->output, true); + perf_session__write_header(session, session->evlist, file_out->fd, true); } perf_session__delete(session); @@ -427,14 +420,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) }, .input_name = "-", .samples = LIST_HEAD_INIT(inject.samples), + .output = { + .path = "-", + .mode = PERF_DATA_MODE_WRITE, + }, }; - const char *output_name = "-"; const struct option options[] = { OPT_BOOLEAN('b', "build-ids", &inject.build_ids, "Inject build-ids into the output stream"), OPT_STRING('i', "input", &inject.input_name, "file", "input file name"), - OPT_STRING('o', "output", &output_name, "file", + OPT_STRING('o', "output", &inject.output.path, "file", "output file name"), OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, "Merge sched-stat and sched-switch for getting events " @@ -456,16 +452,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) if (argc) usage_with_options(inject_usage, options); - if (!strcmp(output_name, "-")) { - inject.pipe_output = 1; - inject.output = STDOUT_FILENO; - } else { - inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC, - S_IRUSR | S_IWUSR); - if (inject.output < 0) { - perror("failed to create output file"); - return -1; - } + if (perf_data_file__open(&inject.output)) { + perror("failed to create output file"); + return -1; } if (symbol__init() < 0) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 154b397a5d27..a6ec1052c291 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -89,7 +89,7 @@ struct exit_reasons_table { struct perf_kvm_stat { struct perf_tool tool; - struct perf_record_opts opts; + struct record_opts opts; struct perf_evlist *evlist; struct perf_session *session; @@ -1158,9 +1158,7 @@ out: if (kvm->timerfd >= 0) close(kvm->timerfd); - if (pollfds) - free(pollfds); - + free(pollfds); return err; } diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 31c00f186da1..2e3ade69a58e 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -62,7 +62,6 @@ static int dump_raw_samples(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel __maybe_unused, struct machine *machine) { struct perf_mem *mem = container_of(tool, struct perf_mem, tool); @@ -112,10 +111,10 @@ dump_raw_samples(struct perf_tool *tool, static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct perf_evsel *evsel __maybe_unused, struct machine *machine) { - return dump_raw_samples(tool, event, sample, evsel, machine); + return dump_raw_samples(tool, event, sample, machine); } static int report_raw_events(struct perf_mem *mem) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c98ccb570509..43ff33d0007b 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -169,6 +169,7 @@ static int opt_set_target(const struct option *opt, const char *str, int unset __maybe_unused) { int ret = -ENOENT; + char *tmp; if (str && !params.target) { if (!strcmp(opt->long_name, "exec")) @@ -180,7 +181,19 @@ static int opt_set_target(const struct option *opt, const char *str, else return ret; - params.target = str; + /* Expand given path to absolute path, except for modulename */ + if (params.uprobes || strchr(str, '/')) { + tmp = realpath(str, NULL); + if (!tmp) { + pr_warning("Failed to get the absolute path of %s: %m\n", str); + return ret; + } + } else { + tmp = strdup(str); + if (!tmp) + return -ENOMEM; + } + params.target = tmp; ret = 0; } @@ -411,7 +424,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) } #ifdef HAVE_DWARF_SUPPORT - if (params.show_lines && !params.uprobes) { + if (params.show_lines) { if (params.mod_events) { pr_err(" Error: Don't use --line with" " --add/--del.\n"); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index c1c1200d2f0a..6ec0cbc2a5d5 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -62,9 +62,9 @@ static void __handle_on_exit_funcs(void) } #endif -struct perf_record { +struct record { struct perf_tool tool; - struct perf_record_opts opts; + struct record_opts opts; u64 bytes_written; struct perf_data_file file; struct perf_evlist *evlist; @@ -76,24 +76,14 @@ struct perf_record { long samples; }; -static int perf_record__write(struct perf_record *rec, void *buf, size_t size) +static int record__write(struct record *rec, void *bf, size_t size) { - struct perf_data_file *file = &rec->file; - - while (size) { - ssize_t ret = write(file->fd, buf, size); - - if (ret < 0) { - pr_err("failed to write perf data, error: %m\n"); - return -1; - } - - size -= ret; - buf += ret; - - rec->bytes_written += ret; + if (perf_data_file__write(rec->session->file, bf, size) < 0) { + pr_err("failed to write perf data, error: %m\n"); + return -1; } + rec->bytes_written += size; return 0; } @@ -102,12 +92,11 @@ static int process_synthesized_event(struct perf_tool *tool, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct perf_record *rec = container_of(tool, struct perf_record, tool); - return perf_record__write(rec, event, event->header.size); + struct record *rec = container_of(tool, struct record, tool); + return record__write(rec, event, event->header.size); } -static int perf_record__mmap_read(struct perf_record *rec, - struct perf_mmap *md) +static int record__mmap_read(struct record *rec, struct perf_mmap *md) { unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; @@ -128,7 +117,7 @@ static int perf_record__mmap_read(struct perf_record *rec, size = md->mask + 1 - (old & md->mask); old += size; - if (perf_record__write(rec, buf, size) < 0) { + if (record__write(rec, buf, size) < 0) { rc = -1; goto out; } @@ -138,7 +127,7 @@ static int perf_record__mmap_read(struct perf_record *rec, size = head - old; old += size; - if (perf_record__write(rec, buf, size) < 0) { + if (record__write(rec, buf, size) < 0) { rc = -1; goto out; } @@ -163,9 +152,9 @@ static void sig_handler(int sig) signr = sig; } -static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) +static void record__sig_exit(int exit_status __maybe_unused, void *arg) { - struct perf_record *rec = arg; + struct record *rec = arg; int status; if (rec->evlist->workload.pid > 0) { @@ -183,13 +172,13 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) signal(signr, SIG_DFL); } -static int perf_record__open(struct perf_record *rec) +static int record__open(struct record *rec) { char msg[512]; struct perf_evsel *pos; struct perf_evlist *evlist = rec->evlist; struct perf_session *session = rec->session; - struct perf_record_opts *opts = &rec->opts; + struct record_opts *opts = &rec->opts; int rc = 0; perf_evlist__config(evlist, opts); @@ -239,7 +228,7 @@ out: return rc; } -static int process_buildids(struct perf_record *rec) +static int process_buildids(struct record *rec) { struct perf_data_file *file = &rec->file; struct perf_session *session = rec->session; @@ -254,9 +243,9 @@ static int process_buildids(struct perf_record *rec) size, &build_id__mark_dso_hit_ops); } -static void perf_record__exit(int status, void *arg) +static void record__exit(int status, void *arg) { - struct perf_record *rec = arg; + struct record *rec = arg; struct perf_data_file *file = &rec->file; if (status != 0) @@ -312,14 +301,14 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; -static int perf_record__mmap_read_all(struct perf_record *rec) +static int record__mmap_read_all(struct record *rec) { int i; int rc = 0; for (i = 0; i < rec->evlist->nr_mmaps; i++) { if (rec->evlist->mmap[i].base) { - if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { + if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { rc = -1; goto out; } @@ -327,14 +316,13 @@ static int perf_record__mmap_read_all(struct perf_record *rec) } if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) - rc = perf_record__write(rec, &finished_round_event, - sizeof(finished_round_event)); + rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); out: return rc; } -static void perf_record__init_features(struct perf_record *rec) +static void record__init_features(struct record *rec) { struct perf_evlist *evsel_list = rec->evlist; struct perf_session *session = rec->session; @@ -353,14 +341,14 @@ static void perf_record__init_features(struct perf_record *rec) perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); } -static int __cmd_record(struct perf_record *rec, int argc, const char **argv) +static int __cmd_record(struct record *rec, int argc, const char **argv) { int err; unsigned long waking = 0; const bool forks = argc > 0; struct machine *machine; struct perf_tool *tool = &rec->tool; - struct perf_record_opts *opts = &rec->opts; + struct record_opts *opts = &rec->opts; struct perf_evlist *evsel_list = rec->evlist; struct perf_data_file *file = &rec->file; struct perf_session *session; @@ -368,7 +356,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) rec->progname = argv[0]; - on_exit(perf_record__sig_exit, rec); + on_exit(record__sig_exit, rec); signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); signal(SIGUSR1, sig_handler); @@ -382,7 +370,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) rec->session = session; - perf_record__init_features(rec); + record__init_features(rec); if (forks) { err = perf_evlist__prepare_workload(evsel_list, &opts->target, @@ -394,7 +382,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) } } - if (perf_record__open(rec) != 0) { + if (record__open(rec) != 0) { err = -1; goto out_delete_session; } @@ -403,9 +391,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); /* - * perf_session__delete(session) will be called at perf_record__exit() + * perf_session__delete(session) will be called at record__exit() */ - on_exit(perf_record__exit, rec); + on_exit(record__exit, rec); if (file->is_pipe) { err = perf_header__write_pipe(file->fd); @@ -510,7 +498,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) for (;;) { int hits = rec->samples; - if (perf_record__mmap_read_all(rec) < 0) { + if (record__mmap_read_all(rec) < 0) { err = -1; goto out_delete_session; } @@ -669,7 +657,7 @@ static int get_stack_size(char *str, unsigned long *_size) } #endif /* HAVE_LIBUNWIND_SUPPORT */ -int record_parse_callchain(const char *arg, struct perf_record_opts *opts) +int record_parse_callchain(const char *arg, struct record_opts *opts) { char *tok, *name, *saveptr = NULL; char *buf; @@ -725,7 +713,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts) return ret; } -static void callchain_debug(struct perf_record_opts *opts) +static void callchain_debug(struct record_opts *opts) { pr_debug("callchain: type %d\n", opts->call_graph); @@ -738,7 +726,7 @@ int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset) { - struct perf_record_opts *opts = opt->value; + struct record_opts *opts = opt->value; int ret; /* --no-call-graph */ @@ -759,7 +747,7 @@ int record_callchain_opt(const struct option *opt, const char *arg __maybe_unused, int unset __maybe_unused) { - struct perf_record_opts *opts = opt->value; + struct record_opts *opts = opt->value; if (opts->call_graph == CALLCHAIN_NONE) opts->call_graph = CALLCHAIN_FP; @@ -775,8 +763,8 @@ static const char * const record_usage[] = { }; /* - * XXX Ideally would be local to cmd_record() and passed to a perf_record__new - * because we need to have access to it in perf_record__exit, that is called + * XXX Ideally would be local to cmd_record() and passed to a record__new + * because we need to have access to it in record__exit, that is called * after cmd_record() exits, but since record_options need to be accessible to * builtin-script, leave it here. * @@ -784,7 +772,7 @@ static const char * const record_usage[] = { * * Just say no to tons of global variables, sigh. */ -static struct perf_record record = { +static struct record record = { .opts = { .mmap_pages = UINT_MAX, .user_freq = UINT_MAX, @@ -808,7 +796,7 @@ const char record_callchain_help[] = CALLCHAIN_HELP "fp"; /* * XXX Will stay a global variable till we fix builtin-script.c to stop messing * with it and switch to use the library functions in perf_evlist that came - * from builtin-record.c, i.e. use perf_record_opts, + * from builtin-record.c, i.e. use record_opts, * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', * using pipes, etc. */ @@ -891,7 +879,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) { int err = -ENOMEM; struct perf_evlist *evsel_list; - struct perf_record *rec = &record; + struct record *rec = &record; char errbuf[BUFSIZ]; evsel_list = perf_evlist__new(); @@ -956,7 +944,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) usage_with_options(record_usage, record_options); - if (perf_record_opts__config(&rec->opts)) { + if (record_opts__config(&rec->opts)) { err = -EINVAL; goto out_free_fd; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3a14dbed387c..bf8dd2e893e4 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -39,7 +39,7 @@ #include <dlfcn.h> #include <linux/bitmap.h> -struct perf_report { +struct report { struct perf_tool tool; struct perf_session *session; bool force, use_tui, use_gtk, use_stdio; @@ -60,14 +60,14 @@ struct perf_report { DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); }; -static int perf_report_config(const char *var, const char *value, void *cb) +static int report__config(const char *var, const char *value, void *cb) { if (!strcmp(var, "report.group")) { symbol_conf.event_group = perf_config_bool(var, value); return 0; } if (!strcmp(var, "report.percent-limit")) { - struct perf_report *rep = cb; + struct report *rep = cb; rep->min_percent = strtof(value, NULL); return 0; } @@ -75,31 +75,40 @@ static int perf_report_config(const char *var, const char *value, void *cb) return perf_default_config(var, value, cb); } -static int perf_report__add_mem_hist_entry(struct perf_tool *tool, - struct addr_location *al, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine, - union perf_event *event) +static int report__resolve_callchain(struct report *rep, struct symbol **parent, + struct perf_evsel *evsel, struct addr_location *al, + struct perf_sample *sample) { - struct perf_report *rep = container_of(tool, struct perf_report, tool); + if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { + return machine__resolve_callchain(al->machine, evsel, al->thread, sample, + parent, al, rep->max_stack); + } + return 0; +} + +static int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) +{ + if (!symbol_conf.use_callchain) + return 0; + return callchain_append(he->callchain, &callchain_cursor, sample->period); +} + +static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al, + struct perf_sample *sample, struct perf_evsel *evsel, + union perf_event *event) +{ + struct report *rep = container_of(tool, struct report, tool); struct symbol *parent = NULL; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - int err = 0; struct hist_entry *he; struct mem_info *mi, *mx; uint64_t cost; + int err = report__resolve_callchain(rep, &parent, evsel, al, sample); - if ((sort__has_parent || symbol_conf.use_callchain) && - sample->callchain) { - err = machine__resolve_callchain(machine, evsel, al->thread, - sample, &parent, al, - rep->max_stack); - if (err) - return err; - } + if (err) + return err; - mi = machine__resolve_mem(machine, al->thread, sample, cpumode); + mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode); if (!mi) return -ENOMEM; @@ -122,77 +131,36 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool, if (!he) return -ENOMEM; - /* - * In the TUI browser, we are doing integrated annotation, - * so we don't allocate the extra space needed because the stdio - * code will not use it. - */ - if (sort__has_sym && he->ms.sym && use_browser > 0) { - struct annotation *notes = symbol__annotation(he->ms.sym); - - assert(evsel != NULL); - - if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) - goto out; - - err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); - if (err) - goto out; - } - - if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) { - struct annotation *notes; - - mx = he->mem_info; + err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); + if (err) + goto out; - notes = symbol__annotation(mx->daddr.sym); - if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0) - goto out; - - err = symbol__inc_addr_samples(mx->daddr.sym, - mx->daddr.map, - evsel->idx, - mx->daddr.al_addr); - if (err) - goto out; - } + mx = he->mem_info; + err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx); + if (err) + goto out; evsel->hists.stats.total_period += cost; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); - err = 0; - - if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, - &callchain_cursor, - sample->period); - } + err = hist_entry__append_callchain(he, sample); out: return err; } -static int perf_report__add_branch_hist_entry(struct perf_tool *tool, - struct addr_location *al, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine) +static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al, + struct perf_sample *sample, struct perf_evsel *evsel) { - struct perf_report *rep = container_of(tool, struct perf_report, tool); + struct report *rep = container_of(tool, struct report, tool); struct symbol *parent = NULL; - int err = 0; unsigned i; struct hist_entry *he; struct branch_info *bi, *bx; + int err = report__resolve_callchain(rep, &parent, evsel, al, sample); - if ((sort__has_parent || symbol_conf.use_callchain) - && sample->callchain) { - err = machine__resolve_callchain(machine, evsel, al->thread, - sample, &parent, al, - rep->max_stack); - if (err) - return err; - } + if (err) + return err; - bi = machine__resolve_bstack(machine, al->thread, + bi = machine__resolve_bstack(al->machine, al->thread, sample->branch_stack); if (!bi) return -ENOMEM; @@ -214,35 +182,15 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, 1, 1, 0); if (he) { - struct annotation *notes; bx = he->branch_info; - if (bx->from.sym && use_browser == 1 && sort__has_sym) { - notes = symbol__annotation(bx->from.sym); - if (!notes->src - && symbol__alloc_hist(bx->from.sym) < 0) - goto out; - - err = symbol__inc_addr_samples(bx->from.sym, - bx->from.map, - evsel->idx, - bx->from.al_addr); - if (err) - goto out; - } + err = addr_map_symbol__inc_samples(&bx->from, evsel->idx); + if (err) + goto out; + + err = addr_map_symbol__inc_samples(&bx->to, evsel->idx); + if (err) + goto out; - if (bx->to.sym && use_browser == 1 && sort__has_sym) { - notes = symbol__annotation(bx->to.sym); - if (!notes->src - && symbol__alloc_hist(bx->to.sym) < 0) - goto out; - - err = symbol__inc_addr_samples(bx->to.sym, - bx->to.map, - evsel->idx, - bx->to.al_addr); - if (err) - goto out; - } evsel->hists.stats.total_period += 1; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); } else @@ -254,24 +202,16 @@ out: return err; } -static int perf_evsel__add_hist_entry(struct perf_tool *tool, - struct perf_evsel *evsel, - struct addr_location *al, - struct perf_sample *sample, - struct machine *machine) +static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel, + struct addr_location *al, struct perf_sample *sample) { - struct perf_report *rep = container_of(tool, struct perf_report, tool); + struct report *rep = container_of(tool, struct report, tool); struct symbol *parent = NULL; - int err = 0; struct hist_entry *he; + int err = report__resolve_callchain(rep, &parent, evsel, al, sample); - if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - err = machine__resolve_callchain(machine, evsel, al->thread, - sample, &parent, al, - rep->max_stack); - if (err) - return err; - } + if (err) + return err; he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, sample->period, sample->weight, @@ -279,30 +219,11 @@ static int perf_evsel__add_hist_entry(struct perf_tool *tool, if (he == NULL) return -ENOMEM; - if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, - &callchain_cursor, - sample->period); - if (err) - return err; - } - /* - * Only in the TUI browser we are doing integrated annotation, - * so we don't allocated the extra space needed because the stdio - * code will not use it. - */ - if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) { - struct annotation *notes = symbol__annotation(he->ms.sym); - - assert(evsel != NULL); - - err = -ENOMEM; - if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) - goto out; - - err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); - } + err = hist_entry__append_callchain(he, sample); + if (err) + goto out; + err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); evsel->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); out: @@ -316,13 +237,13 @@ static int process_sample_event(struct perf_tool *tool, struct perf_evsel *evsel, struct machine *machine) { - struct perf_report *rep = container_of(tool, struct perf_report, tool); + struct report *rep = container_of(tool, struct report, tool); struct addr_location al; int ret; if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { - fprintf(stderr, "problem processing %d event, skipping it.\n", - event->header.type); + pr_debug("problem processing %d event, skipping it.\n", + event->header.type); return -1; } @@ -333,21 +254,18 @@ static int process_sample_event(struct perf_tool *tool, return 0; if (sort__mode == SORT_MODE__BRANCH) { - ret = perf_report__add_branch_hist_entry(tool, &al, sample, - evsel, machine); + ret = report__add_branch_hist_entry(tool, &al, sample, evsel); if (ret < 0) pr_debug("problem adding lbr entry, skipping event\n"); } else if (rep->mem_mode == 1) { - ret = perf_report__add_mem_hist_entry(tool, &al, sample, - evsel, machine, event); + ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event); if (ret < 0) pr_debug("problem adding mem entry, skipping event\n"); } else { if (al.map != NULL) al.map->dso->hit = 1; - ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample, - machine); + ret = report__add_hist_entry(tool, evsel, &al, sample); if (ret < 0) pr_debug("problem incrementing symbol period, skipping event\n"); } @@ -360,7 +278,7 @@ static int process_read_event(struct perf_tool *tool, struct perf_evsel *evsel, struct machine *machine __maybe_unused) { - struct perf_report *rep = container_of(tool, struct perf_report, tool); + struct report *rep = container_of(tool, struct report, tool); if (rep->show_threads) { const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; @@ -379,7 +297,7 @@ static int process_read_event(struct perf_tool *tool, } /* For pipe mode, sample_type is not currently set */ -static int perf_report__setup_sample_type(struct perf_report *rep) +static int report__setup_sample_type(struct report *rep) { struct perf_session *session = rep->session; u64 sample_type = perf_evlist__combined_sample_type(session->evlist); @@ -424,8 +342,7 @@ static void sig_handler(int sig __maybe_unused) session_done = 1; } -static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, - struct hists *hists, +static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep, const char *evname, FILE *fp) { size_t ret; @@ -462,7 +379,7 @@ static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, } static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, - struct perf_report *rep, + struct report *rep, const char *help) { struct perf_evsel *pos; @@ -475,7 +392,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, !perf_evsel__is_group_leader(pos)) continue; - hists__fprintf_nr_sample_events(rep, hists, evname, stdout); + hists__fprintf_nr_sample_events(hists, rep, evname, stdout); hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); fprintf(stdout, "\n\n"); } @@ -495,7 +412,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, return 0; } -static int __cmd_report(struct perf_report *rep) +static int __cmd_report(struct report *rep) { int ret = -EINVAL; u64 nr_samples; @@ -519,7 +436,7 @@ static int __cmd_report(struct perf_report *rep) if (rep->show_threads) perf_read_values_init(&rep->show_threads_values); - ret = perf_report__setup_sample_type(rep); + ret = report__setup_sample_type(rep); if (ret) return ret; @@ -552,15 +469,17 @@ static int __cmd_report(struct perf_report *rep) desc); } - if (verbose > 3) - perf_session__fprintf(session, stdout); + if (use_browser == 0) { + if (verbose > 3) + perf_session__fprintf(session, stdout); - if (verbose > 2) - perf_session__fprintf_dsos(session, stdout); + if (verbose > 2) + perf_session__fprintf_dsos(session, stdout); - if (dump_trace) { - perf_session__fprintf_nr_events(session, stdout); - return 0; + if (dump_trace) { + perf_session__fprintf_nr_events(session, stdout); + return 0; + } } nr_samples = 0; @@ -638,7 +557,7 @@ static int __cmd_report(struct perf_report *rep) static int parse_callchain_opt(const struct option *opt, const char *arg, int unset) { - struct perf_report *rep = (struct perf_report *)opt->value; + struct report *rep = (struct report *)opt->value; char *tok, *tok2; char *endptr; @@ -720,7 +639,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) return -1; setup: if (callchain_register_param(&callchain_param) < 0) { - fprintf(stderr, "Can't register callchain params\n"); + pr_err("Can't register callchain params\n"); return -1; } return 0; @@ -758,7 +677,7 @@ static int parse_percent_limit(const struct option *opt, const char *str, int unset __maybe_unused) { - struct perf_report *rep = opt->value; + struct report *rep = opt->value; rep->min_percent = strtof(str, NULL); return 0; @@ -776,7 +695,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "perf report [<options>]", NULL }; - struct perf_report report = { + struct report report = { .tool = { .sample = process_sample_event, .mmap = perf_event__process_mmap, @@ -892,7 +811,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) .mode = PERF_DATA_MODE_READ, }; - perf_config(perf_report_config, &report); + perf_config(report__config, &report); argc = parse_options(argc, argv, options, report_usage, 0); @@ -942,7 +861,7 @@ repeat: } if (report.mem_mode) { if (sort__mode == SORT_MODE__BRANCH) { - fprintf(stderr, "branch and mem mode incompatible\n"); + pr_err("branch and mem mode incompatible\n"); goto error; } sort__mode = SORT_MODE__MEMORY; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 0f3c65518a2c..6a76a07b6789 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -469,7 +469,7 @@ static void *thread_func(void *ctx) char comm2[22]; int fd; - free(parms); + zfree(&parms); sprintf(comm2, ":%s", this_task->comm); prctl(PR_SET_NAME, comm2); diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index f8ab125aac48..6040000bdfa6 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -423,7 +423,6 @@ static void print_sample_addr(union perf_event *event, static void print_sample_bts(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine, struct thread *thread, struct addr_location *al) { @@ -435,7 +434,7 @@ static void print_sample_bts(union perf_event *event, printf(" "); else printf("\n"); - perf_evsel__print_ip(evsel, sample, machine, al, + perf_evsel__print_ip(evsel, sample, al, output[attr->type].print_ip_opts, PERF_MAX_STACK_DEPTH); } @@ -446,14 +445,13 @@ static void print_sample_bts(union perf_event *event, if (PRINT_FIELD(ADDR) || ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && !output[attr->type].user_set)) - print_sample_addr(event, sample, machine, thread, attr); + print_sample_addr(event, sample, al->machine, thread, attr); printf("\n"); } static void process_event(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, struct machine *machine, - struct thread *thread, + struct perf_evsel *evsel, struct thread *thread, struct addr_location *al) { struct perf_event_attr *attr = &evsel->attr; @@ -469,7 +467,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, } if (is_bts_event(attr)) { - print_sample_bts(event, sample, evsel, machine, thread, al); + print_sample_bts(event, sample, evsel, thread, al); return; } @@ -477,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, event_format__print(evsel->tp_format, sample->cpu, sample->raw_data, sample->raw_size); if (PRINT_FIELD(ADDR)) - print_sample_addr(event, sample, machine, thread, attr); + print_sample_addr(event, sample, al->machine, thread, attr); if (PRINT_FIELD(IP)) { if (!symbol_conf.use_callchain) @@ -485,7 +483,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, else printf("\n"); - perf_evsel__print_ip(evsel, sample, machine, al, + perf_evsel__print_ip(evsel, sample, al, output[attr->type].print_ip_opts, PERF_MAX_STACK_DEPTH); } @@ -574,7 +572,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) return 0; - scripting_ops->process_event(event, sample, evsel, machine, thread, &al); + scripting_ops->process_event(event, sample, evsel, thread, &al); evsel->hists.stats.total_period += sample->period; return 0; @@ -1104,9 +1102,9 @@ static struct script_desc *script_desc__new(const char *name) static void script_desc__delete(struct script_desc *s) { - free(s->name); - free(s->half_liner); - free(s->args); + zfree(&s->name); + zfree(&s->half_liner); + zfree(&s->args); free(s); } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index dab98b50c9fe..106a5e5b7842 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -185,8 +185,7 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) { - free(evsel->priv); - evsel->priv = NULL; + zfree(&evsel->priv); } static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) @@ -208,8 +207,7 @@ static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) { - free(evsel->prev_raw_counts); - evsel->prev_raw_counts = NULL; + zfree(&evsel->prev_raw_counts); } static void perf_evlist__free_stats(struct perf_evlist *evlist) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 20d4212fa337..652af0b66a62 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -488,8 +488,7 @@ static const char *cat_backtrace(union perf_event *event, * It seems the callchain is corrupted. * Discard all. */ - free(p); - p = NULL; + zfree(&p); goto exit; } continue; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 03d37a76c612..172e91a9ce62 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -189,21 +189,18 @@ static void perf_top__record_precise_ip(struct perf_top *top, if (pthread_mutex_trylock(¬es->lock)) return; - if (notes->src == NULL && symbol__alloc_hist(sym) < 0) { - pthread_mutex_unlock(¬es->lock); - pr_err("Not enough memory for annotating '%s' symbol!\n", - sym->name); - sleep(1); - return; - } - ip = he->ms.map->map_ip(he->ms.map, ip); - err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip); + err = hist_entry__inc_addr_samples(he, counter, ip); pthread_mutex_unlock(¬es->lock); if (err == -ERANGE && !he->ms.map->erange_warned) ui__warn_map_erange(he->ms.map, sym, ip); + else if (err == -ENOMEM) { + pr_err("Not enough memory for annotating '%s' symbol!\n", + sym->name); + sleep(1); + } } static void perf_top__show_details(struct perf_top *top) @@ -857,7 +854,7 @@ static int perf_top__start_counters(struct perf_top *top) char msg[512]; struct perf_evsel *counter; struct perf_evlist *evlist = top->evlist; - struct perf_record_opts *opts = &top->record_opts; + struct record_opts *opts = &top->record_opts; perf_evlist__config(evlist, opts); @@ -909,7 +906,7 @@ static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused) static int __cmd_top(struct perf_top *top) { - struct perf_record_opts *opts = &top->record_opts; + struct record_opts *opts = &top->record_opts; pthread_t thread; int ret; @@ -1031,7 +1028,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) .max_stack = PERF_MAX_STACK_DEPTH, .sym_pcnt_filter = 5, }; - struct perf_record_opts *opts = &top.record_opts; + struct record_opts *opts = &top.record_opts; struct target *target = &opts->target; const struct option options[] = { OPT_CALLBACK('e', "event", &top.evlist, "event", @@ -1182,7 +1179,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (top.delay_secs < 1) top.delay_secs = 1; - if (perf_record_opts__config(opts)) { + if (record_opts__config(opts)) { status = -EINVAL; goto out_delete_maps; } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 56bbca5bc2dc..c5b4bc51175c 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -146,8 +146,7 @@ static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel, static void perf_evsel__delete_priv(struct perf_evsel *evsel) { - free(evsel->priv); - evsel->priv = NULL; + zfree(&evsel->priv); perf_evsel__delete(evsel); } @@ -165,8 +164,7 @@ static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler) return -ENOMEM; out_delete: - free(evsel->priv); - evsel->priv = NULL; + zfree(&evsel->priv); return -ENOENT; } @@ -1159,7 +1157,7 @@ struct trace { int max; struct syscall *table; } syscalls; - struct perf_record_opts opts; + struct record_opts opts; struct machine *host; u64 base_time; bool full_time; @@ -1278,10 +1276,8 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size, size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); struct thread_trace *ttrace = arg->thread->priv; - if (ttrace && fd >= 0 && fd <= ttrace->paths.max) { - free(ttrace->paths.table[fd]); - ttrace->paths.table[fd] = NULL; - } + if (ttrace && fd >= 0 && fd <= ttrace->paths.max) + zfree(&ttrace->paths.table[fd]); return printed; } diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 5a1f4df3c3a8..14faeeb0d752 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -126,7 +126,7 @@ endif feature_check = $(eval $(feature_check_code)) define feature_check_code - 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) + 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.bin >/dev/null 2>/dev/null && echo 1 || echo 0) endef feature_set = $(eval $(feature_set_code)) @@ -173,7 +173,7 @@ CORE_FEATURE_TESTS = \ # to skip the print-out of the long features list if the file # existed before and after it was built: # -ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all),) +ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all.bin),) test-all-failed := 1 else test-all-failed := 0 @@ -203,7 +203,7 @@ ifeq ($(feature-all), 1) # $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) else - $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1) + $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(addsuffix .bin,$(CORE_FEATURE_TESTS)) >/dev/null 2>&1) $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) endif diff --git a/tools/perf/config/feature-checks/.gitignore b/tools/perf/config/feature-checks/.gitignore new file mode 100644 index 000000000000..80f3da0c3515 --- /dev/null +++ b/tools/perf/config/feature-checks/.gitignore @@ -0,0 +1,2 @@ +*.d +*.bin diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index bc86462e80a2..7cf6fcdacebe 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile @@ -1,90 +1,90 @@ FILES= \ - test-all \ - test-backtrace \ - test-bionic \ - test-dwarf \ - test-fortify-source \ - test-glibc \ - test-gtk2 \ - test-gtk2-infobar \ - test-hello \ - test-libaudit \ - test-libbfd \ - test-liberty \ - test-liberty-z \ - test-cplus-demangle \ - test-libelf \ - test-libelf-getphdrnum \ - test-libelf-mmap \ - test-libnuma \ - test-libperl \ - test-libpython \ - test-libpython-version \ - test-libslang \ - test-libunwind \ - test-libunwind-debug-frame \ - test-on-exit \ - test-stackprotector-all \ - test-timerfd + test-all.bin \ + test-backtrace.bin \ + test-bionic.bin \ + test-dwarf.bin \ + test-fortify-source.bin \ + test-glibc.bin \ + test-gtk2.bin \ + test-gtk2-infobar.bin \ + test-hello.bin \ + test-libaudit.bin \ + test-libbfd.bin \ + test-liberty.bin \ + test-liberty-z.bin \ + test-cplus-demangle.bin \ + test-libelf.bin \ + test-libelf-getphdrnum.bin \ + test-libelf-mmap.bin \ + test-libnuma.bin \ + test-libperl.bin \ + test-libpython.bin \ + test-libpython-version.bin \ + test-libslang.bin \ + test-libunwind.bin \ + test-libunwind-debug-frame.bin \ + test-on-exit.bin \ + test-stackprotector-all.bin \ + test-timerfd.bin CC := $(CC) -MD all: $(FILES) -BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $@.c $(LDFLAGS) +BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) ############################### -test-all: +test-all.bin: $(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: +test-hello.bin: $(BUILD) -test-stackprotector-all: +test-stackprotector-all.bin: $(BUILD) -Werror -fstack-protector-all -test-fortify-source: +test-fortify-source.bin: $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 -test-bionic: +test-bionic.bin: $(BUILD) -test-libelf: +test-libelf.bin: $(BUILD) -lelf -test-glibc: +test-glibc.bin: $(BUILD) -test-dwarf: +test-dwarf.bin: $(BUILD) -ldw -test-libelf-mmap: +test-libelf-mmap.bin: $(BUILD) -lelf -test-libelf-getphdrnum: +test-libelf-getphdrnum.bin: $(BUILD) -lelf -test-libnuma: +test-libnuma.bin: $(BUILD) -lnuma -test-libunwind: +test-libunwind.bin: $(BUILD) -lelf -test-libunwind-debug-frame: +test-libunwind-debug-frame.bin: $(BUILD) -lelf -test-libaudit: +test-libaudit.bin: $(BUILD) -laudit -test-libslang: +test-libslang.bin: $(BUILD) -I/usr/include/slang -lslang -test-gtk2: +test-gtk2.bin: $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) -test-gtk2-infobar: +test-gtk2-infobar.bin: $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) grep-libs = $(filter -l%,$(1)) @@ -96,7 +96,7 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) -test-libperl: +test-libperl.bin: $(BUILD) $(FLAGS_PERL_EMBED) override PYTHON := python @@ -113,31 +113,31 @@ PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) -test-libpython: +test-libpython.bin: $(BUILD) $(FLAGS_PYTHON_EMBED) -test-libpython-version: +test-libpython-version.bin: $(BUILD) $(FLAGS_PYTHON_EMBED) -test-libbfd: +test-libbfd.bin: $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl -test-liberty: +test-liberty.bin: $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -test-liberty-z: +test-liberty-z.bin: $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz -test-cplus-demangle: +test-cplus-demangle.bin: $(BUILD) -liberty -test-on-exit: +test-on-exit.bin: $(BUILD) -test-backtrace: +test-backtrace.bin: $(BUILD) -test-timerfd: +test-timerfd.bin: $(BUILD) -include *.d diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index f168debc5be2..4d985e0f03f5 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak @@ -178,10 +178,3 @@ endef _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) _gea_warn = $(warning The path '$(1)' is not executable.) _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) - -ifneq ($(findstring $(MAKEFLAGS),s),s) - ifneq ($(V),1) - QUIET_CLEAN = @printf ' CLEAN %s\n' $1; - QUIET_INSTALL = @printf ' INSTALL %s\n' $1; - endif -endif diff --git a/tools/perf/perf.h b/tools/perf/perf.h index b23fed527514..b1cc84b01d5b 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -247,7 +247,7 @@ enum perf_call_graph_mode { CALLCHAIN_DWARF }; -struct perf_record_opts { +struct record_opts { struct target target; int call_graph; bool group; diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 85d4919dd623..4248d1e96848 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -391,7 +391,7 @@ static int do_test_code_reading(bool try_kcore) struct machines machines; struct machine *machine; struct thread *thread; - struct perf_record_opts opts = { + struct record_opts opts = { .mmap_pages = UINT_MAX, .user_freq = UINT_MAX, .user_interval = ULLONG_MAX, diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 376c35608534..27eb75142b88 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c @@ -51,7 +51,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm) */ int test__keep_tracking(void) { - struct perf_record_opts opts = { + struct record_opts opts = { .mmap_pages = UINT_MAX, .user_freq = UINT_MAX, .user_interval = ULLONG_MAX, diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 2ca0abf1b2b6..f641c35f2321 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -106,10 +106,36 @@ test_make_python_perf_so := test -f $(PERF)/python/perf.so test_make_perf_o := test -f $(PERF)/perf.o test_make_util_map_o := test -f $(PERF)/util/map.o -test_make_install := test -x $$TMP_DEST/bin/perf -test_make_install_O := $(test_make_install) -test_make_install_bin := $(test_make_install) -test_make_install_bin_O := $(test_make_install) +define test_dest_files + for file in $(1); do \ + if [ ! -x $$TMP_DEST/$$file ]; then \ + echo " failed to find: $$file"; \ + fi \ + done +endef + +installed_files_bin := bin/perf +installed_files_bin += etc/bash_completion.d/perf +installed_files_bin += libexec/perf-core/perf-archive + +installed_files_plugins := lib64/traceevent/plugins/plugin_cfg80211.so +installed_files_plugins += lib64/traceevent/plugins/plugin_scsi.so +installed_files_plugins += lib64/traceevent/plugins/plugin_xen.so +installed_files_plugins += lib64/traceevent/plugins/plugin_function.so +installed_files_plugins += lib64/traceevent/plugins/plugin_sched_switch.so +installed_files_plugins += lib64/traceevent/plugins/plugin_mac80211.so +installed_files_plugins += lib64/traceevent/plugins/plugin_kvm.so +installed_files_plugins += lib64/traceevent/plugins/plugin_kmem.so +installed_files_plugins += lib64/traceevent/plugins/plugin_hrtimer.so +installed_files_plugins += lib64/traceevent/plugins/plugin_jbd2.so + +installed_files_all := $(installed_files_bin) +installed_files_all += $(installed_files_plugins) + +test_make_install := $(call test_dest_files,$(installed_files_all)) +test_make_install_O := $(call test_dest_files,$(installed_files_all)) +test_make_install_bin := $(call test_dest_files,$(installed_files_bin)) +test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin)) # FIXME nothing gets installed test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 @@ -162,7 +188,7 @@ $(run): cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \ echo "- $@: $$cmd" && echo $$cmd > $@ && \ ( eval $$cmd ) >> $@ 2>&1; \ - echo " test: $(call test,$@)"; \ + echo " test: $(call test,$@)" >> $@ 2>&1; \ $(call test,$@) && \ rm -f $@ \ rm -rf $$TMP_DEST @@ -174,7 +200,7 @@ $(run_O): cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ echo "- $@: $$cmd" && echo $$cmd > $@ && \ ( eval $$cmd ) >> $@ 2>&1 && \ - echo " test: $(call test_O,$@)"; \ + echo " test: $(call test_O,$@)" >> $@ 2>&1; \ $(call test_O,$@) && \ rm -f $@ && \ rm -rf $$TMP_O \ diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index 41cc0badb74b..774620a5aecb 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c @@ -6,7 +6,7 @@ int test__syscall_open_tp_fields(void) { - struct perf_record_opts opts = { + struct record_opts opts = { .target = { .uid = UINT_MAX, .uses_mmap = true, diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 93a62b06c3af..eeba562920e9 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -34,7 +34,7 @@ realloc: int test__PERF_RECORD(void) { - struct perf_record_opts opts = { + struct record_opts opts = { .target = { .uid = UINT_MAX, .uses_mmap = true, diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index 4ca1b938f6a6..c6398b90e897 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c @@ -46,7 +46,7 @@ static u64 rdtsc(void) */ int test__perf_time_to_tsc(void) { - struct perf_record_opts opts = { + struct record_opts opts = { .mmap_pages = UINT_MAX, .user_freq = UINT_MAX, .user_interval = ULLONG_MAX, diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index cbaa7af45513..d11541d4d7d7 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -256,8 +256,7 @@ int ui_browser__show(struct ui_browser *browser, const char *title, __ui_browser__show_title(browser, title); browser->title = title; - free(browser->helpline); - browser->helpline = NULL; + zfree(&browser->helpline); va_start(ap, helpline); err = vasprintf(&browser->helpline, helpline, ap); @@ -268,12 +267,11 @@ int ui_browser__show(struct ui_browser *browser, const char *title, return err ? 0 : -1; } -void ui_browser__hide(struct ui_browser *browser __maybe_unused) +void ui_browser__hide(struct ui_browser *browser) { pthread_mutex_lock(&ui__lock); ui_helpline__pop(); - free(browser->helpline); - browser->helpline = NULL; + zfree(&browser->helpline); pthread_mutex_unlock(&ui__lock); } diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index 7d45d2f53601..118cca29dd26 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -59,6 +59,8 @@ int ui_browser__help_window(struct ui_browser *browser, const char *text); bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); int ui_browser__input_window(const char *title, const char *text, char *input, const char *exit_msg, int delay_sec); +struct perf_session_env; +int tui__header_window(struct perf_session_env *env); void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); unsigned int ui_browser__argv_refresh(struct ui_browser *browser); diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c new file mode 100644 index 000000000000..89c16b988618 --- /dev/null +++ b/tools/perf/ui/browsers/header.c @@ -0,0 +1,127 @@ +#include "util/cache.h" +#include "util/debug.h" +#include "ui/browser.h" +#include "ui/ui.h" +#include "ui/util.h" +#include "ui/libslang.h" +#include "util/header.h" +#include "util/session.h" + +static void ui_browser__argv_write(struct ui_browser *browser, + void *entry, int row) +{ + char **arg = entry; + char *str = *arg; + char empty[] = " "; + bool current_entry = ui_browser__is_current_entry(browser, row); + unsigned long offset = (unsigned long)browser->priv; + + if (offset >= strlen(str)) + str = empty; + else + str = str + offset; + + ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : + HE_COLORSET_NORMAL); + + slsmg_write_nstring(str, browser->width); +} + +static int list_menu__run(struct ui_browser *menu) +{ + int key; + unsigned long offset; + const char help[] = + "h/?/F1 Show this window\n" + "UP/DOWN/PGUP\n" + "PGDN/SPACE\n" + "LEFT/RIGHT Navigate\n" + "q/ESC/CTRL+C Exit browser"; + + if (ui_browser__show(menu, "Header information", "Press 'q' to exit") < 0) + return -1; + + while (1) { + key = ui_browser__run(menu, 0); + + switch (key) { + case K_RIGHT: + offset = (unsigned long)menu->priv; + offset += 10; + menu->priv = (void *)offset; + continue; + case K_LEFT: + offset = (unsigned long)menu->priv; + if (offset >= 10) + offset -= 10; + menu->priv = (void *)offset; + continue; + case K_F1: + case 'h': + case '?': + ui_browser__help_window(menu, help); + continue; + case K_ESC: + case 'q': + case CTRL('c'): + key = -1; + break; + default: + continue; + } + + break; + } + + ui_browser__hide(menu); + return key; +} + +static int ui__list_menu(int argc, char * const argv[]) +{ + struct ui_browser menu = { + .entries = (void *)argv, + .refresh = ui_browser__argv_refresh, + .seek = ui_browser__argv_seek, + .write = ui_browser__argv_write, + .nr_entries = argc, + }; + + return list_menu__run(&menu); +} + +int tui__header_window(struct perf_session_env *env) +{ + int i, argc = 0; + char **argv; + struct perf_session *session; + char *ptr, *pos; + size_t size; + FILE *fp = open_memstream(&ptr, &size); + + session = container_of(env, struct perf_session, header.env); + perf_header__fprintf_info(session, fp, true); + fclose(fp); + + for (pos = ptr, argc = 0; (pos = strchr(pos, '\n')) != NULL; pos++) + argc++; + + argv = calloc(argc + 1, sizeof(*argv)); + if (argv == NULL) + goto out; + + argv[0] = pos = ptr; + for (i = 1; (pos = strchr(pos, '\n')) != NULL; i++) { + *pos++ = '\0'; + argv[i] = pos; + } + + BUG_ON(i != argc + 1); + + ui__list_menu(argc, argv); + +out: + free(argv); + free(ptr); + return 0; +} diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a440e03cd8c2..a7045ea6d1d5 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1267,10 +1267,8 @@ static inline void free_popup_options(char **options, int n) { int i; - for (i = 0; i < n; ++i) { - free(options[i]); - options[i] = NULL; - } + for (i = 0; i < n; ++i) + zfree(&options[i]); } /* Check whether the browser is for 'top' or 'report' */ @@ -1329,7 +1327,7 @@ static int switch_data_file(void) abs_path[nr_options] = strdup(path); if (!abs_path[nr_options]) { - free(options[nr_options]); + zfree(&options[nr_options]); ui__warning("Can't search all data files due to memory shortage.\n"); fclose(file); break; @@ -1400,6 +1398,36 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, char script_opt[64]; int delay_secs = hbt ? hbt->refresh : 0; +#define HIST_BROWSER_HELP_COMMON \ + "h/?/F1 Show this window\n" \ + "UP/DOWN/PGUP\n" \ + "PGDN/SPACE Navigate\n" \ + "q/ESC/CTRL+C Exit browser\n\n" \ + "For multiple event sessions:\n\n" \ + "TAB/UNTAB Switch events\n\n" \ + "For symbolic views (--sort has sym):\n\n" \ + "-> Zoom into DSO/Threads & Annotate current symbol\n" \ + "<- Zoom out\n" \ + "a Annotate current symbol\n" \ + "C Collapse all callchains\n" \ + "d Zoom into current DSO\n" \ + "E Expand all callchains\n" \ + + /* help messages are sorted by lexical order of the hotkey */ + const char report_help[] = HIST_BROWSER_HELP_COMMON + "i Show header information\n" + "P Print histograms to perf.hist.N\n" + "r Run available scripts\n" + "s Switch to another data file in PWD\n" + "t Zoom into current Thread\n" + "V Verbose (DSO names in callchains, etc)\n" + "/ Filter symbol by name"; + const char top_help[] = HIST_BROWSER_HELP_COMMON + "P Print histograms to perf.hist.N\n" + "t Zoom into current Thread\n" + "V Verbose (DSO names in callchains, etc)\n" + "/ Filter symbol by name"; + if (browser == NULL) return -1; @@ -1484,29 +1512,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, if (is_report_browser(hbt)) goto do_data_switch; continue; + case 'i': + /* env->arch is NULL for live-mode (i.e. perf top) */ + if (env->arch) + tui__header_window(env); + continue; case K_F1: case 'h': case '?': ui_browser__help_window(&browser->b, - "h/?/F1 Show this window\n" - "UP/DOWN/PGUP\n" - "PGDN/SPACE Navigate\n" - "q/ESC/CTRL+C Exit browser\n\n" - "For multiple event sessions:\n\n" - "TAB/UNTAB Switch events\n\n" - "For symbolic views (--sort has sym):\n\n" - "-> Zoom into DSO/Threads & Annotate current symbol\n" - "<- Zoom out\n" - "a Annotate current symbol\n" - "C Collapse all callchains\n" - "E Expand all callchains\n" - "d Zoom into current DSO\n" - "t Zoom into current Thread\n" - "r Run available scripts('perf report' only)\n" - "s Switch to another data file in PWD ('perf report' only)\n" - "P Print histograms to perf.hist.N\n" - "V Verbose (DSO names in callchains, etc)\n" - "/ Filter symbol by name"); + is_report_browser(hbt) ? report_help : top_help); continue; case K_ENTER: case K_RIGHT: diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index d63c68ea02a8..402d2bd30b09 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c @@ -173,8 +173,7 @@ int script_browse(const char *script_opt) if (script.b.width > AVERAGE_LINE_LEN) script.b.width = AVERAGE_LINE_LEN; - if (line) - free(line); + free(line); pclose(fp); script.nr_lines = nr_entries; diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index 696c1fbe4248..52e7fc48af9f 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c @@ -23,8 +23,7 @@ int perf_gtk__deactivate_context(struct perf_gtk_context **ctx) if (!perf_gtk__is_active_context(*ctx)) return -1; - free(*ctx); - *ctx = NULL; + zfree(ctx); return 0; } diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index c244cb524ef2..831fbb77d1ff 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -510,7 +510,7 @@ print_entries: free(line); out: - free(rem_sq_bracket); + zfree(&rem_sq_bracket); return ret; } diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c index 092902e30cee..bf890f72fe80 100644 --- a/tools/perf/ui/tui/util.c +++ b/tools/perf/ui/tui/util.c @@ -92,6 +92,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input, t = sep + 1; } + pthread_mutex_lock(&ui__lock); + max_len += 2; nr_lines += 8; y = SLtt_Screen_Rows / 2 - nr_lines / 2; @@ -120,13 +122,19 @@ int ui_browser__input_window(const char *title, const char *text, char *input, SLsmg_write_nstring((char *)exit_msg, max_len); SLsmg_refresh(); + pthread_mutex_unlock(&ui__lock); + x += 2; len = 0; key = ui__getch(delay_secs); while (key != K_TIMER && key != K_ENTER && key != K_ESC) { + pthread_mutex_lock(&ui__lock); + if (key == K_BKSPC) { - if (len == 0) + if (len == 0) { + pthread_mutex_unlock(&ui__lock); goto next_key; + } SLsmg_gotorc(y, x + --len); SLsmg_write_char(' '); } else { @@ -136,6 +144,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input, } SLsmg_refresh(); + pthread_mutex_unlock(&ui__lock); + /* XXX more graceful overflow handling needed */ if (len == sizeof(buf) - 1) { ui_helpline__push("maximum size of symbol name reached!"); @@ -174,6 +184,8 @@ int ui__question_window(const char *title, const char *text, t = sep + 1; } + pthread_mutex_lock(&ui__lock); + max_len += 2; nr_lines += 4; y = SLtt_Screen_Rows / 2 - nr_lines / 2, @@ -195,6 +207,9 @@ int ui__question_window(const char *title, const char *text, SLsmg_gotorc(y + nr_lines - 1, x); SLsmg_write_nstring((char *)exit_msg, max_len); SLsmg_refresh(); + + pthread_mutex_unlock(&ui__lock); + return ui__getch(delay_secs); } @@ -215,9 +230,7 @@ static int __ui__warning(const char *title, const char *format, va_list args) if (vasprintf(&s, format, args) > 0) { int key; - pthread_mutex_lock(&ui__lock); key = ui__question_window(title, s, "Press any key...", 0); - pthread_mutex_unlock(&ui__lock); free(s); return key; } diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c index e6d134773d0a..c0b43ee40d95 100644 --- a/tools/perf/util/alias.c +++ b/tools/perf/util/alias.c @@ -55,8 +55,7 @@ int split_cmdline(char *cmdline, const char ***argv) src++; c = cmdline[src]; if (!c) { - free(*argv); - *argv = NULL; + zfree(argv); return error("cmdline ends with \\"); } } @@ -68,8 +67,7 @@ int split_cmdline(char *cmdline, const char ***argv) cmdline[dst] = 0; if (quoted) { - free(*argv); - *argv = NULL; + zfree(argv); return error("unclosed quote"); } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0fcd81ea31ae..469eb679fb9d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -26,10 +26,10 @@ static int disasm_line__parse(char *line, char **namep, char **rawp); static void ins__delete(struct ins_operands *ops) { - free(ops->source.raw); - free(ops->source.name); - free(ops->target.raw); - free(ops->target.name); + zfree(&ops->source.raw); + zfree(&ops->source.name); + zfree(&ops->target.raw); + zfree(&ops->target.name); } static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, @@ -185,8 +185,7 @@ static int lock__parse(struct ins_operands *ops) return 0; out_free_ops: - free(ops->locked.ops); - ops->locked.ops = NULL; + zfree(&ops->locked.ops); return 0; } @@ -205,9 +204,9 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size, static void lock__delete(struct ins_operands *ops) { - free(ops->locked.ops); - free(ops->target.raw); - free(ops->target.name); + zfree(&ops->locked.ops); + zfree(&ops->target.raw); + zfree(&ops->target.name); } static struct ins_ops lock_ops = { @@ -256,8 +255,7 @@ static int mov__parse(struct ins_operands *ops) return 0; out_free_source: - free(ops->source.raw); - ops->source.raw = NULL; + zfree(&ops->source.raw); return -1; } @@ -464,17 +462,12 @@ void symbol__annotate_zero_histograms(struct symbol *sym) pthread_mutex_unlock(¬es->lock); } -int symbol__inc_addr_samples(struct symbol *sym, struct map *map, - int evidx, u64 addr) +static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, + struct annotation *notes, int evidx, u64 addr) { unsigned offset; - struct annotation *notes; struct sym_hist *h; - notes = symbol__annotation(sym); - if (notes->src == NULL) - return -ENOMEM; - pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); if (addr < sym->start || addr > sym->end) @@ -491,6 +484,33 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, return 0; } +static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, + int evidx, u64 addr) +{ + struct annotation *notes; + + if (sym == NULL || use_browser != 1 || !sort__has_sym) + return 0; + + notes = symbol__annotation(sym); + if (notes->src == NULL) { + if (symbol__alloc_hist(sym) < 0) + return -ENOMEM; + } + + return __symbol__inc_addr_samples(sym, map, notes, evidx, addr); +} + +int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx) +{ + return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr); +} + +int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) +{ + return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); +} + static void disasm_line__init_ins(struct disasm_line *dl) { dl->ins = ins__find(dl->name); @@ -538,8 +558,7 @@ static int disasm_line__parse(char *line, char **namep, char **rawp) return 0; out_free_name: - free(*namep); - *namep = NULL; + zfree(namep); return -1; } @@ -564,7 +583,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs return dl; out_free_line: - free(dl->line); + zfree(&dl->line); out_delete: free(dl); return NULL; @@ -572,8 +591,8 @@ out_delete: void disasm_line__free(struct disasm_line *dl) { - free(dl->line); - free(dl->name); + zfree(&dl->line); + zfree(&dl->name); if (dl->ins && dl->ins->ops->free) dl->ins->ops->free(&dl->ops); else @@ -1091,8 +1110,7 @@ static void symbol__free_source_line(struct symbol *sym, int len) src_line = (void *)src_line + sizeof_src_line; } - free(notes->src->lines); - notes->src->lines = NULL; + zfree(¬es->src->lines); } /* Get the filename:line for the colored entries */ @@ -1376,3 +1394,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, return 0; } + +int hist_entry__annotate(struct hist_entry *he, size_t privsize) +{ + return symbol__annotate(he->ms.sym, he->ms.map, privsize); +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 834b7b57b788..b2aef59d6bb2 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -132,12 +132,17 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) return &a->annotation; } -int symbol__inc_addr_samples(struct symbol *sym, struct map *map, - int evidx, u64 addr); +int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx); + +int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); + int symbol__alloc_hist(struct symbol *sym); void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); + +int hist_entry__annotate(struct hist_entry *he, size_t privsize); + int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); int symbol__annotate_printf(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool full_paths, diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 4f7f989876ec..08b25af9eea1 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -146,7 +146,7 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) struct option; -int record_parse_callchain(const char *arg, struct perf_record_opts *opts); +int record_parse_callchain(const char *arg, struct record_opts *opts); int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); int record_callchain_opt(const struct option *opt, const char *arg, int unset); diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 96bbda1ddb83..0922aa4218c2 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -133,7 +133,7 @@ void close_cgroup(struct cgroup_sel *cgrp) /* XXX: not reentrant */ if (--cgrp->refcnt == 0) { close(cgrp->fd); - free(cgrp->name); + zfree(&cgrp->name); free(cgrp); } } diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index ee0df0e24cdb..67d1e404c0cb 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c @@ -21,7 +21,7 @@ static void comm_str__put(struct comm_str *cs) { if (!--cs->ref) { rb_erase(&cs->rb_node, &comm_str_root); - free(cs->str); + zfree(&cs->str); free(cs); } } diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 8640a9121e72..299b55586502 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -25,7 +25,6 @@ static int _eprintf(int level, const char *fmt, va_list args) ui_helpline__vshow(fmt, args); else ret = vfprintf(stderr, fmt, args); - va_end(args); } return ret; diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 4ddeecb9ff85..4045d086d9d9 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -497,21 +497,18 @@ void dso__delete(struct dso *dso) symbols__delete(&dso->symbols[i]); if (dso->short_name_allocated) { - free((char *)dso->short_name); - dso->short_name = NULL; + zfree((char **)&dso->short_name); dso->short_name_allocated = false; } if (dso->long_name_allocated) { - free((char *)dso->long_name); - dso->long_name = NULL; + zfree((char **)&dso->long_name); dso->long_name_allocated = false; } dso_cache__free(&dso->cache); dso__free_a2l(dso); - free(dso->symsrc_filename); - dso->symsrc_filename = NULL; + zfree(&dso->symsrc_filename); free(dso); } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 694876877ae2..45a76c69a9ed 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -106,8 +106,12 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, memset(&event->comm, 0, sizeof(event->comm)); - tgid = perf_event__get_comm_tgid(pid, event->comm.comm, - sizeof(event->comm.comm)); + if (machine__is_host(machine)) + tgid = perf_event__get_comm_tgid(pid, event->comm.comm, + sizeof(event->comm.comm)); + else + tgid = machine->pid; + if (tgid < 0) goto out; @@ -129,7 +133,11 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, goto out; } - snprintf(filename, sizeof(filename), "/proc/%d/task", pid); + if (machine__is_default_guest(machine)) + return 0; + + snprintf(filename, sizeof(filename), "%s/proc/%d/task", + machine->root_dir, pid); tasks = opendir(filename); if (tasks == NULL) { @@ -178,7 +186,11 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, FILE *fp; int rc = 0; - snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); + if (machine__is_default_guest(machine)) + return 0; + + snprintf(filename, sizeof(filename), "%s/proc/%d/maps", + machine->root_dir, pid); fp = fopen(filename, "r"); if (fp == NULL) { @@ -218,7 +230,10 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, /* * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c */ - event->header.misc = PERF_RECORD_MISC_USER; + if (machine__is_host(machine)) + event->header.misc = PERF_RECORD_MISC_USER; + else + event->header.misc = PERF_RECORD_MISC_GUEST_USER; if (prot[2] != 'x') { if (!mmap_data || prot[0] != 'r') @@ -387,6 +402,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, struct machine *machine, bool mmap_data) { DIR *proc; + char proc_path[PATH_MAX]; struct dirent dirent, *next; union perf_event *comm_event, *mmap_event; int err = -1; @@ -399,7 +415,12 @@ int perf_event__synthesize_threads(struct perf_tool *tool, if (mmap_event == NULL) goto out_free_comm; - proc = opendir("/proc"); + if (machine__is_default_guest(machine)) + return 0; + + snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); + proc = opendir(proc_path); + if (proc == NULL) goto out_free_mmap; @@ -638,6 +659,7 @@ void thread__find_addr_map(struct thread *thread, struct map_groups *mg = &thread->mg; bool load_map = false; + al->machine = machine; al->thread = thread; al->addr = addr; al->cpumode = cpumode; @@ -658,15 +680,10 @@ void thread__find_addr_map(struct thread *thread, al->level = 'g'; mg = &machine->kmaps; load_map = true; + } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) { + al->level = 'u'; } else { - /* - * 'u' means guest os user space. - * TODO: We don't support guest user space. Might support late. - */ - if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) - al->level = 'u'; - else - al->level = 'H'; + al->level = 'H'; al->map = NULL; if ((cpumode == PERF_RECORD_MISC_GUEST_USER || diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index da3182914984..b08a7ecdcea1 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -101,10 +101,8 @@ static void perf_evlist__purge(struct perf_evlist *evlist) void perf_evlist__exit(struct perf_evlist *evlist) { - free(evlist->mmap); - free(evlist->pollfd); - evlist->mmap = NULL; - evlist->pollfd = NULL; + zfree(&evlist->mmap); + zfree(&evlist->pollfd); } void perf_evlist__delete(struct perf_evlist *evlist) @@ -587,8 +585,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist) for (i = 0; i < evlist->nr_mmaps; i++) __perf_evlist__munmap(evlist, i); - free(evlist->mmap); - evlist->mmap = NULL; + zfree(&evlist->mmap); } static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 9f64ede3ecbd..2fe51958ed85 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -12,7 +12,7 @@ struct pollfd; struct thread_map; struct cpu_map; -struct perf_record_opts; +struct record_opts; #define PERF_EVLIST__HLIST_BITS 8 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) @@ -97,9 +97,8 @@ void perf_evlist__close(struct perf_evlist *evlist); void perf_evlist__set_id_pos(struct perf_evlist *evlist); bool perf_can_sample_identifier(void); -void perf_evlist__config(struct perf_evlist *evlist, - struct perf_record_opts *opts); -int perf_record_opts__config(struct perf_record_opts *opts); +void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts); +int record_opts__config(struct record_opts *opts); int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 01ff4cfde1f5..ade8d9c1c431 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -208,7 +208,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int return evsel; out_free: - free(evsel->name); + zfree(&evsel->name); free(evsel); return NULL; } @@ -528,8 +528,7 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) * enable/disable events specifically, as there's no * initial traced exec call. */ -void perf_evsel__config(struct perf_evsel *evsel, - struct perf_record_opts *opts) +void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) { struct perf_evsel *leader = evsel->leader; struct perf_event_attr *attr = &evsel->attr; @@ -751,8 +750,7 @@ void perf_evsel__free_id(struct perf_evsel *evsel) { xyarray__delete(evsel->sample_id); evsel->sample_id = NULL; - free(evsel->id); - evsel->id = NULL; + zfree(&evsel->id); } void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) @@ -768,7 +766,7 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) void perf_evsel__free_counts(struct perf_evsel *evsel) { - free(evsel->counts); + zfree(&evsel->counts); } void perf_evsel__exit(struct perf_evsel *evsel) @@ -782,10 +780,10 @@ void perf_evsel__delete(struct perf_evsel *evsel) { perf_evsel__exit(evsel); close_cgroup(evsel->cgrp); - free(evsel->group_name); + zfree(&evsel->group_name); if (evsel->tp_format) pevent_free_format(evsel->tp_format); - free(evsel->name); + zfree(&evsel->name); free(evsel); } @@ -1961,8 +1959,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, evsel->attr.type = PERF_TYPE_SOFTWARE; evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; - free(evsel->name); - evsel->name = NULL; + zfree(&evsel->name); return true; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 8120eeb86ac1..f1b325665aae 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -96,7 +96,7 @@ struct perf_evsel { struct cpu_map; struct thread_map; struct perf_evlist; -struct perf_record_opts; +struct record_opts; struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); @@ -120,7 +120,7 @@ void perf_evsel__exit(struct perf_evsel *evsel); void perf_evsel__delete(struct perf_evsel *evsel); void perf_evsel__config(struct perf_evsel *evsel, - struct perf_record_opts *opts); + struct record_opts *opts); int __perf_evsel__sample_size(u64 sample_type); void perf_evsel__calc_id_pos(struct perf_evsel *evsel); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 61c54213704b..a4a60b7887ee 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -800,10 +800,10 @@ static void free_cpu_topo(struct cpu_topo *tp) return; for (i = 0 ; i < tp->core_sib; i++) - free(tp->core_siblings[i]); + zfree(&tp->core_siblings[i]); for (i = 0 ; i < tp->thread_sib; i++) - free(tp->thread_siblings[i]); + zfree(&tp->thread_siblings[i]); free(tp); } @@ -1232,10 +1232,8 @@ static void free_event_desc(struct perf_evsel *events) return; for (evsel = events; evsel->attr.size; evsel++) { - if (evsel->name) - free(evsel->name); - if (evsel->id) - free(evsel->id); + zfree(&evsel->name); + zfree(&evsel->id); } free(events); @@ -1326,8 +1324,7 @@ read_event_desc(struct perf_header *ph, int fd) } } out: - if (buf) - free(buf); + free(buf); return events; error: if (events) @@ -2108,7 +2105,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, ret = 0; out_free: for (i = 0; i < nr_groups; i++) - free(desc[i].name); + zfree(&desc[i].name); free(desc); return ret; diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c index 8b1f6e891b8a..86c37c472263 100644 --- a/tools/perf/util/help.c +++ b/tools/perf/util/help.c @@ -22,8 +22,8 @@ static void clean_cmdnames(struct cmdnames *cmds) unsigned int i; for (i = 0; i < cmds->cnt; ++i) - free(cmds->names[i]); - free(cmds->names); + zfree(&cmds->names[i]); + zfree(&cmds->names); cmds->cnt = 0; cmds->alloc = 0; } @@ -263,9 +263,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) for (i = 0; i < old->cnt; i++) cmds->names[cmds->cnt++] = old->names[i]; - free(old->names); + zfree(&old->names); old->cnt = 0; - old->names = NULL; } const char *help_unknown_cmd(const char *cmd) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 822903eaa201..4ed3e883240d 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1,4 +1,3 @@ -#include "annotate.h" #include "util.h" #include "build-id.h" #include "hist.h" @@ -342,15 +341,15 @@ static u8 symbol__parent_filter(const struct symbol *parent) } static struct hist_entry *add_hist_entry(struct hists *hists, - struct hist_entry *entry, - struct addr_location *al, - u64 period, - u64 weight) + struct hist_entry *entry, + struct addr_location *al) { struct rb_node **p; struct rb_node *parent = NULL; struct hist_entry *he; int64_t cmp; + u64 period = entry->stat.period; + u64 weight = entry->stat.weight; p = &hists->entries_in->rb_node; @@ -373,7 +372,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, * This mem info was allocated from machine__resolve_mem * and will not be used anymore. */ - free(entry->mem_info); + zfree(&entry->mem_info); /* If the map of an existing hist_entry has * become out-of-date due to an exec() or @@ -437,7 +436,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, .transaction = transaction, }; - return add_hist_entry(hists, &entry, al, period, weight); + return add_hist_entry(hists, &entry, al); } int64_t @@ -476,8 +475,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) void hist_entry__free(struct hist_entry *he) { - free(he->branch_info); - free(he->mem_info); + zfree(&he->branch_info); + zfree(&he->mem_info); free_srcline(he->srcline); free(he); } @@ -807,16 +806,6 @@ void hists__filter_by_symbol(struct hists *hists) } } -int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) -{ - return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); -} - -int hist_entry__annotate(struct hist_entry *he, size_t privsize) -{ - return symbol__annotate(he->ms.sym, he->ms.map, privsize); -} - void events_stats__inc(struct events_stats *stats, u32 type) { ++stats->nr_events[0]; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index b621347a1585..a59743fa3ef7 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -111,9 +111,6 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, float min_pcnt, FILE *fp); -int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); -int hist_entry__annotate(struct hist_entry *he, size_t privsize); - void hists__filter_by_dso(struct hists *hists); void hists__filter_by_thread(struct hists *hists); void hists__filter_by_symbol(struct hists *hists); diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index c78cc84f433e..a98538dc465a 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -102,8 +102,7 @@ void machine__exit(struct machine *machine) map_groups__exit(&machine->kmaps); dsos__delete(&machine->user_dsos); dsos__delete(&machine->kernel_dsos); - free(machine->root_dir); - machine->root_dir = NULL; + zfree(&machine->root_dir); } void machine__delete(struct machine *machine) @@ -562,11 +561,10 @@ void machine__destroy_kernel_maps(struct machine *machine) * on one of them. */ if (type == MAP__FUNCTION) { - free((char *)kmap->ref_reloc_sym->name); - kmap->ref_reloc_sym->name = NULL; - free(kmap->ref_reloc_sym); - } - kmap->ref_reloc_sym = NULL; + zfree((char **)&kmap->ref_reloc_sym->name); + zfree(&kmap->ref_reloc_sym); + } else + kmap->ref_reloc_sym = NULL; } map__delete(machine->vmlinux_maps[type]); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 094c28ba2fae..0153435b8427 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -204,7 +204,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) } path->name = malloc(MAX_EVENT_LENGTH); if (!path->name) { - free(path->system); + zfree(&path->system); free(path); return NULL; } @@ -236,8 +236,8 @@ struct tracepoint_path *tracepoint_name_to_path(const char *name) path->name = strdup(str+1); if (path->system == NULL || path->name == NULL) { - free(path->system); - free(path->name); + zfree(&path->system); + zfree(&path->name); free(path); path = NULL; } @@ -917,7 +917,7 @@ int parse_events_terms(struct list_head *terms, const char *str) ret = parse_events__scanner(str, &data, PE_START_TERMS); if (!ret) { list_splice(data.terms, terms); - free(data.terms); + zfree(&data.terms); return 0; } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 56fc10a5e288..0934d645ebdc 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -755,7 +755,7 @@ void print_pmu_events(const char *event_glob, bool name_only) continue; } printf(" %-50s [Kernel PMU event]\n", aliases[j]); - free(aliases[j]); + zfree(&aliases[j]); printed++; } if (printed) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 544ac1898a9f..86ed8580c3cb 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -172,6 +172,52 @@ const char *kernel_get_module_path(const char *module) return (dso) ? dso->long_name : NULL; } +/* Copied from unwind.c */ +static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, + GElf_Shdr *shp, const char *name) +{ + Elf_Scn *sec = NULL; + + while ((sec = elf_nextscn(elf, sec)) != NULL) { + char *str; + + gelf_getshdr(sec, shp); + str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); + if (!strcmp(name, str)) + break; + } + + return sec; +} + +static int get_text_start_address(const char *exec, unsigned long *address) +{ + Elf *elf; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + int fd, ret = -ENOENT; + + fd = open(exec, O_RDONLY); + if (fd < 0) + return -errno; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) + return -EINVAL; + + if (gelf_getehdr(elf, &ehdr) == NULL) + goto out; + + if (!elf_section_by_name(elf, &ehdr, &shdr, ".text")) + goto out; + + *address = shdr.sh_addr - shdr.sh_offset; + ret = 0; +out: + elf_end(elf); + return ret; +} + static int init_user_exec(void) { int ret = 0; @@ -186,6 +232,37 @@ static int init_user_exec(void) return ret; } +static int convert_exec_to_group(const char *exec, char **result) +{ + char *ptr1, *ptr2, *exec_copy; + char buf[64]; + int ret; + + exec_copy = strdup(exec); + if (!exec_copy) + return -ENOMEM; + + ptr1 = basename(exec_copy); + if (!ptr1) { + ret = -EINVAL; + goto out; + } + + ptr2 = strpbrk(ptr1, "-._"); + if (ptr2) + *ptr2 = '\0'; + ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); + if (ret < 0) + goto out; + + *result = strdup(buf); + ret = *result ? 0 : -ENOMEM; + +out: + free(exec_copy); + return ret; +} + static int convert_to_perf_probe_point(struct probe_trace_point *tp, struct perf_probe_point *pp) { @@ -261,6 +338,40 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, return 0; } +static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, + int ntevs, const char *exec) +{ + int i, ret = 0; + unsigned long offset, stext = 0; + char buf[32]; + + if (!exec) + return 0; + + ret = get_text_start_address(exec, &stext); + if (ret < 0) + return ret; + + for (i = 0; i < ntevs && ret >= 0; i++) { + offset = tevs[i].point.address - stext; + offset += tevs[i].point.offset; + tevs[i].point.offset = 0; + zfree(&tevs[i].point.symbol); + ret = e_snprintf(buf, 32, "0x%lx", offset); + if (ret < 0) + break; + tevs[i].point.module = strdup(exec); + tevs[i].point.symbol = strdup(buf); + if (!tevs[i].point.symbol || !tevs[i].point.module) { + ret = -ENOMEM; + break; + } + tevs[i].uprobes = true; + } + + return ret; +} + static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, int ntevs, const char *module) { @@ -290,9 +401,7 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, } } - if (tmp) - free(tmp); - + free(tmp); return ret; } @@ -305,15 +414,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, struct debuginfo *dinfo; int ntevs, ret = 0; - if (pev->uprobes) { - if (need_dwarf) { - pr_warning("Debuginfo-analysis is not yet supported" - " with -x/--exec option.\n"); - return -ENOSYS; - } - return convert_name_to_addr(pev, target); - } - dinfo = open_debuginfo(target); if (!dinfo) { @@ -332,9 +432,14 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, if (ntevs > 0) { /* Succeeded to find trace events */ pr_debug("find %d probe_trace_events.\n", ntevs); - if (target) - ret = add_module_to_probe_trace_events(*tevs, ntevs, - target); + if (target) { + if (pev->uprobes) + ret = add_exec_to_probe_trace_events(*tevs, + ntevs, target); + else + ret = add_module_to_probe_trace_events(*tevs, + ntevs, target); + } return ret < 0 ? ret : ntevs; } @@ -401,15 +506,13 @@ static int get_real_path(const char *raw_path, const char *comp_dir, case EFAULT: raw_path = strchr(++raw_path, '/'); if (!raw_path) { - free(*new_path); - *new_path = NULL; + zfree(new_path); return -ENOENT; } continue; default: - free(*new_path); - *new_path = NULL; + zfree(new_path); return -errno; } } @@ -580,7 +683,7 @@ static int show_available_vars_at(struct debuginfo *dinfo, */ fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, vl->point.offset); - free(vl->point.symbol); + zfree(&vl->point.symbol); nvars = 0; if (vl->vars) { strlist__for_each(node, vl->vars) { @@ -654,9 +757,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, return -ENOSYS; } - if (pev->uprobes) - return convert_name_to_addr(pev, target); - return 0; } @@ -1278,8 +1378,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) error: pr_debug("Failed to synthesize perf probe point: %s\n", strerror(-ret)); - if (buf) - free(buf); + free(buf); return NULL; } @@ -1480,34 +1579,25 @@ void clear_perf_probe_event(struct perf_probe_event *pev) struct perf_probe_arg_field *field, *next; int i; - if (pev->event) - free(pev->event); - if (pev->group) - free(pev->group); - if (pp->file) - free(pp->file); - if (pp->function) - free(pp->function); - if (pp->lazy_line) - free(pp->lazy_line); + free(pev->event); + free(pev->group); + free(pp->file); + free(pp->function); + free(pp->lazy_line); + for (i = 0; i < pev->nargs; i++) { - if (pev->args[i].name) - free(pev->args[i].name); - if (pev->args[i].var) - free(pev->args[i].var); - if (pev->args[i].type) - free(pev->args[i].type); + free(pev->args[i].name); + free(pev->args[i].var); + free(pev->args[i].type); field = pev->args[i].field; while (field) { next = field->next; - if (field->name) - free(field->name); + zfree(&field->name); free(field); field = next; } } - if (pev->args) - free(pev->args); + free(pev->args); memset(pev, 0, sizeof(*pev)); } @@ -1516,21 +1606,14 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) struct probe_trace_arg_ref *ref, *next; int i; - if (tev->event) - free(tev->event); - if (tev->group) - free(tev->group); - if (tev->point.symbol) - free(tev->point.symbol); - if (tev->point.module) - free(tev->point.module); + free(tev->event); + free(tev->group); + free(tev->point.symbol); + free(tev->point.module); for (i = 0; i < tev->nargs; i++) { - if (tev->args[i].name) - free(tev->args[i].name); - if (tev->args[i].value) - free(tev->args[i].value); - if (tev->args[i].type) - free(tev->args[i].type); + free(tev->args[i].name); + free(tev->args[i].value); + free(tev->args[i].type); ref = tev->args[i].ref; while (ref) { next = ref->next; @@ -1538,8 +1621,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) ref = next; } } - if (tev->args) - free(tev->args); + free(tev->args); memset(tev, 0, sizeof(*tev)); } @@ -1913,14 +1995,29 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, int max_tevs, const char *target) { struct symbol *sym; - int ret = 0, i; + int ret, i; struct probe_trace_event *tev; + if (pev->uprobes && !pev->group) { + /* Replace group name if not given */ + ret = convert_exec_to_group(target, &pev->group); + if (ret != 0) { + pr_warning("Failed to make a group name.\n"); + return ret; + } + } + /* Convert perf_probe_event with debuginfo */ ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); if (ret != 0) return ret; /* Found in debuginfo or got an error */ + if (pev->uprobes) { + ret = convert_name_to_addr(pev, target); + if (ret < 0) + return ret; + } + /* Allocate trace event buffer */ tev = *tevs = zalloc(sizeof(struct probe_trace_event)); if (tev == NULL) @@ -2056,7 +2153,7 @@ end: for (i = 0; i < npevs; i++) { for (j = 0; j < pkgs[i].ntevs; j++) clear_probe_trace_event(&pkgs[i].tevs[j]); - free(pkgs[i].tevs); + zfree(&pkgs[i].tevs); } free(pkgs); @@ -2281,7 +2378,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) struct perf_probe_point *pp = &pev->point; struct symbol *sym; struct map *map = NULL; - char *function = NULL, *name = NULL; + char *function = NULL; int ret = -EINVAL; unsigned long long vaddr = 0; @@ -2297,12 +2394,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) goto out; } - name = realpath(exec, NULL); - if (!name) { - pr_warning("Cannot find realpath for %s.\n", exec); - goto out; - } - map = dso__new_map(name); + map = dso__new_map(exec); if (!map) { pr_warning("Cannot find appropriate DSO for %s.\n", exec); goto out; @@ -2367,7 +2459,5 @@ out: } if (function) free(function); - if (name) - free(name); return ret; } diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index f9f3de8b4220..d481c46e0796 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -12,6 +12,7 @@ struct probe_trace_point { char *symbol; /* Base symbol */ char *module; /* Module name */ unsigned long offset; /* Offset from symbol */ + unsigned long address; /* Actual address of the trace point */ bool retprobe; /* Return probe flag */ }; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ffb657ffd327..061edb162b5b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -226,10 +226,8 @@ struct debuginfo *debuginfo__new(const char *path) if (!dbg) return NULL; - if (debuginfo__init_offline_dwarf(dbg, path) < 0) { - free(dbg); - dbg = NULL; - } + if (debuginfo__init_offline_dwarf(dbg, path) < 0) + zfree(&dbg); return dbg; } @@ -241,10 +239,8 @@ struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) if (!dbg) return NULL; - if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) { - free(dbg); - dbg = NULL; - } + if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) + zfree(&dbg); return dbg; } @@ -729,6 +725,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, return -ENOENT; } tp->offset = (unsigned long)(paddr - sym.st_value); + tp->address = (unsigned long)paddr; tp->symbol = strdup(symbol); if (!tp->symbol) return -ENOMEM; @@ -1301,8 +1298,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, ret = debuginfo__find_probes(dbg, &tf.pf); if (ret < 0) { - free(*tevs); - *tevs = NULL; + zfree(tevs); return ret; } @@ -1413,13 +1409,10 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, if (ret < 0) { /* Free vlist for error */ while (af.nvls--) { - if (af.vls[af.nvls].point.symbol) - free(af.vls[af.nvls].point.symbol); - if (af.vls[af.nvls].vars) - strlist__delete(af.vls[af.nvls].vars); + zfree(&af.vls[af.nvls].point.symbol); + strlist__delete(af.vls[af.nvls].vars); } - free(af.vls); - *vls = NULL; + zfree(vls); return ret; } @@ -1523,10 +1516,7 @@ post: if (fname) { ppt->file = strdup(fname); if (ppt->file == NULL) { - if (ppt->function) { - free(ppt->function); - ppt->function = NULL; - } + zfree(&ppt->function); ret = -ENOMEM; goto end; } @@ -1580,8 +1570,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) else ret = 0; /* Lines are not found */ else { - free(lf->lr->path); - lf->lr->path = NULL; + zfree(&lf->lr->path); } return ret; } diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index e5104538c354..104a47563d39 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -74,8 +74,7 @@ bool perf_can_sample_identifier(void) return perf_probe_api(perf_probe_sample_identifier); } -void perf_evlist__config(struct perf_evlist *evlist, - struct perf_record_opts *opts) +void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) { struct perf_evsel *evsel; bool use_sample_identifier = false; @@ -123,7 +122,7 @@ static int get_max_rate(unsigned int *rate) return filename__read_int(path, (int *) rate); } -static int perf_record_opts__config_freq(struct perf_record_opts *opts) +static int record_opts__config_freq(struct record_opts *opts) { bool user_freq = opts->user_freq != UINT_MAX; unsigned int max_rate; @@ -173,9 +172,9 @@ static int perf_record_opts__config_freq(struct perf_record_opts *opts) return 0; } -int perf_record_opts__config(struct perf_record_opts *opts) +int record_opts__config(struct record_opts *opts) { - return perf_record_opts__config_freq(opts); + return record_opts__config_freq(opts); } bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index d5e5969f6fea..e108207c5de0 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -194,8 +194,7 @@ static void define_event_symbols(struct event_format *event, zero_flag_atom = 0; break; case PRINT_FIELD: - if (cur_field_name) - free(cur_field_name); + free(cur_field_name); cur_field_name = strdup(args->field.name); break; case PRINT_FLAGS: @@ -257,12 +256,9 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel) return event; } -static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, - struct perf_sample *sample, +static void perl_process_tracepoint(struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine __maybe_unused, - struct thread *thread, - struct addr_location *al) + struct thread *thread) { struct format_field *field; static char handler[256]; @@ -349,10 +345,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, static void perl_process_event_generic(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine __maybe_unused, - struct thread *thread __maybe_unused, - struct addr_location *al __maybe_unused) + struct perf_evsel *evsel) { dSP; @@ -377,12 +370,11 @@ static void perl_process_event_generic(union perf_event *event, static void perl_process_event(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine, struct thread *thread, - struct addr_location *al) + struct addr_location *al __maybe_unused) { - perl_process_tracepoint(event, sample, evsel, machine, thread, al); - perl_process_event_generic(event, sample, evsel, machine, thread, al); + perl_process_tracepoint(sample, evsel, thread); + perl_process_event_generic(event, sample, evsel); } static void run_start_sub(void) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 53c20e7fd900..cd9774df3750 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -161,8 +161,7 @@ static void define_event_symbols(struct event_format *event, zero_flag_atom = 0; break; case PRINT_FIELD: - if (cur_field_name) - free(cur_field_name); + free(cur_field_name); cur_field_name = strdup(args->field.name); break; case PRINT_FLAGS: @@ -231,13 +230,10 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel) return event; } -static void python_process_tracepoint(union perf_event *perf_event - __maybe_unused, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine __maybe_unused, - struct thread *thread, - struct addr_location *al) +static void python_process_tracepoint(struct perf_sample *sample, + struct perf_evsel *evsel, + struct thread *thread, + struct addr_location *al) { PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; static char handler_name[256]; @@ -351,11 +347,8 @@ static void python_process_tracepoint(union perf_event *perf_event Py_DECREF(t); } -static void python_process_general_event(union perf_event *perf_event - __maybe_unused, - struct perf_sample *sample, +static void python_process_general_event(struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine __maybe_unused, struct thread *thread, struct addr_location *al) { @@ -411,22 +404,19 @@ exit: Py_DECREF(t); } -static void python_process_event(union perf_event *perf_event, +static void python_process_event(union perf_event *event __maybe_unused, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine, struct thread *thread, struct addr_location *al) { switch (evsel->attr.type) { case PERF_TYPE_TRACEPOINT: - python_process_tracepoint(perf_event, sample, evsel, - machine, thread, al); + python_process_tracepoint(sample, evsel, thread, al); break; /* Reserve for future process_hw/sw/raw APIs */ default: - python_process_general_event(perf_event, sample, evsel, - machine, thread, al); + python_process_general_event(sample, evsel, thread, al); } } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 989b2e377626..8ffe29c55d0f 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -132,18 +132,18 @@ static void perf_session__delete_threads(struct perf_session *session) static void perf_session_env__delete(struct perf_session_env *env) { - free(env->hostname); - free(env->os_release); - free(env->version); - free(env->arch); - free(env->cpu_desc); - free(env->cpuid); + zfree(&env->hostname); + zfree(&env->os_release); + zfree(&env->version); + zfree(&env->arch); + zfree(&env->cpu_desc); + zfree(&env->cpuid); - free(env->cmdline); - free(env->sibling_cores); - free(env->sibling_threads); - free(env->numa_nodes); - free(env->pmu_mappings); + zfree(&env->cmdline); + zfree(&env->sibling_cores); + zfree(&env->sibling_threads); + zfree(&env->numa_nodes); + zfree(&env->pmu_mappings); } void perf_session__delete(struct perf_session *session) @@ -830,6 +830,7 @@ static struct machine * struct perf_sample *sample) { const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + struct machine *machine; if (perf_guest && ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || @@ -842,7 +843,11 @@ static struct machine * else pid = sample->pid; - return perf_session__findnew_machine(session, pid); + machine = perf_session__find_machine(session, pid); + if (!machine) + machine = perf_session__findnew_machine(session, + DEFAULT_GUEST_KERNEL_ID); + return machine; } return &session->machines.host; @@ -1467,7 +1472,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, } void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, - struct machine *machine, struct addr_location *al, + struct addr_location *al, unsigned int print_opts, unsigned int stack_depth) { struct callchain_cursor_node *node; @@ -1482,7 +1487,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, if (symbol_conf.use_callchain && sample->callchain) { struct addr_location node_al; - if (machine__resolve_callchain(machine, evsel, al->thread, + if (machine__resolve_callchain(al->machine, evsel, al->thread, sample, NULL, NULL, PERF_MAX_STACK_DEPTH) != 0) { if (verbose) diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 9c25d49900af..3140f8ae6148 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -106,7 +106,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type); void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, - struct machine *machine, struct addr_location *al, + struct addr_location *al, unsigned int print_opts, unsigned int stack_depth); int perf_session__cpu_bitmap(struct perf_session *session, diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 8b0bb1f4494a..635cd8f8b22e 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -13,6 +13,7 @@ int have_ignore_callees = 0; int sort__need_collapse = 0; int sort__has_parent = 0; int sort__has_sym = 0; +int sort__has_dso = 0; enum sort_mode sort__mode = SORT_MODE__NORMAL; enum sort_type sort__first_dimension; @@ -161,6 +162,11 @@ struct sort_entry sort_dso = { /* --sort symbol */ +static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip) +{ + return (int64_t)(right_ip - left_ip); +} + static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) { u64 ip_l, ip_r; @@ -183,15 +189,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) int64_t ret; if (!left->ms.sym && !right->ms.sym) - return right->level - left->level; + return _sort__addr_cmp(left->ip, right->ip); /* * comparing symbol address alone is not enough since it's a * relative address within a dso. */ - ret = sort__dso_cmp(left, right); - if (ret != 0) - return ret; + if (!sort__has_dso) { + ret = sort__dso_cmp(left, right); + if (ret != 0) + return ret; + } return _sort__sym_cmp(left->ms.sym, right->ms.sym); } @@ -372,7 +380,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) struct addr_map_symbol *from_r = &right->branch_info->from; if (!from_l->sym && !from_r->sym) - return right->level - left->level; + return _sort__addr_cmp(from_l->addr, from_r->addr); return _sort__sym_cmp(from_l->sym, from_r->sym); } @@ -384,7 +392,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) struct addr_map_symbol *to_r = &right->branch_info->to; if (!to_l->sym && !to_r->sym) - return right->level - left->level; + return _sort__addr_cmp(to_l->addr, to_r->addr); return _sort__sym_cmp(to_l->sym, to_r->sym); } @@ -1056,6 +1064,8 @@ int sort_dimension__add(const char *tok) sort__has_parent = 1; } else if (sd->entry == &sort_sym) { sort__has_sym = 1; + } else if (sd->entry == &sort_dso) { + sort__has_dso = 1; } __sort_dimension__add(sd, i); diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 58b2bd8f38c9..7e67879ebd25 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -129,7 +129,7 @@ static struct a2l_data *addr2line_init(const char *path) out: if (a2l) { - free((void *)a2l->input); + zfree((void **)&a2l->input); free(a2l); } bfd_close(abfd); @@ -140,8 +140,8 @@ static void addr2line_cleanup(struct a2l_data *a2l) { if (a2l->abfd) bfd_close(a2l->abfd); - free((void *)a2l->input); - free(a2l->syms); + zfree((void **)&a2l->input); + zfree(&a2l->syms); free(a2l); } diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index cfa906882e2c..4abe23550c73 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -28,7 +28,7 @@ void strbuf_init(struct strbuf *sb, ssize_t hint) void strbuf_release(struct strbuf *sb) { if (sb->alloc) { - free(sb->buf); + zfree(&sb->buf); strbuf_init(sb, 0); } } diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c index 3edd0538161f..79a757a2a15c 100644 --- a/tools/perf/util/strfilter.c +++ b/tools/perf/util/strfilter.c @@ -14,7 +14,7 @@ static void strfilter_node__delete(struct strfilter_node *node) { if (node) { if (node->p && !is_operator(*node->p)) - free((char *)node->p); + zfree((char **)&node->p); strfilter_node__delete(node->l); strfilter_node__delete(node->r); free(node); diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index f0b0c008c507..2553e5b55b89 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c @@ -128,7 +128,7 @@ void argv_free(char **argv) { char **p; for (p = argv; *p; p++) - free(*p); + zfree(p); free(argv); } diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index eabdce0a2daa..61a90bf24b4d 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c @@ -5,6 +5,7 @@ */ #include "strlist.h" +#include "util.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -38,7 +39,7 @@ out_delete: static void str_node__delete(struct str_node *snode, bool dupstr) { if (dupstr) - free((void *)snode->s); + zfree((void **)&snode->s); free(snode); } diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 56a84f2cc46d..43262b83c541 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -21,6 +21,7 @@ #include "perf.h" #include "svghelper.h" +#include "util.h" #include "cpumap.h" static u64 first_time, last_time; @@ -708,8 +709,8 @@ int svg_build_topology_map(char *sib_core, int sib_core_nr, return 0; exit: - free(t.sib_core); - free(t.sib_thr); + zfree(&t.sib_core); + zfree(&t.sib_thr); return -1; } diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index bf0ce29567b6..4b0a127a4d3b 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -554,7 +554,7 @@ bool symsrc__has_symtab(struct symsrc *ss) void symsrc__destroy(struct symsrc *ss) { - free(ss->name); + zfree(&ss->name); elf_end(ss->elf); close(ss->fd); } diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index ac7070a2f2b6..bd15f490d04f 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -1,4 +1,5 @@ #include "symbol.h" +#include "util.h" #include <stdio.h> #include <fcntl.h> @@ -275,7 +276,7 @@ bool symsrc__has_symtab(struct symsrc *ss __maybe_unused) void symsrc__destroy(struct symsrc *ss) { - free(ss->name); + zfree(&ss->name); close(ss->fd); } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 923d00040bbf..39ce9adbaaf0 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -796,7 +796,7 @@ static void delete_modules(struct rb_root *modules) mi = rb_entry(next, struct module_info, rb_node); next = rb_next(&mi->rb_node); rb_erase(&mi->rb_node, modules); - free(mi->name); + zfree(&mi->name); free(mi); } } @@ -1621,13 +1621,10 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, static void vmlinux_path__exit(void) { - while (--vmlinux_path__nr_entries >= 0) { - free(vmlinux_path[vmlinux_path__nr_entries]); - vmlinux_path[vmlinux_path__nr_entries] = NULL; - } + while (--vmlinux_path__nr_entries >= 0) + zfree(&vmlinux_path[vmlinux_path__nr_entries]); - free(vmlinux_path); - vmlinux_path = NULL; + zfree(&vmlinux_path); } static int vmlinux_path__init(void) diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 8a9d910c5345..cbd680361806 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -164,6 +164,7 @@ struct mem_info { }; struct addr_location { + struct machine *machine; struct thread *thread; struct map *map; struct symbol *sym; diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 9b5f856cc280..5d3215912105 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -9,6 +9,7 @@ #include "strlist.h" #include <string.h> #include "thread_map.h" +#include "util.h" /* Skip "." and ".." directories */ static int filter(const struct dirent *dir) @@ -40,7 +41,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) } for (i=0; i<items; i++) - free(namelist[i]); + zfree(&namelist[i]); free(namelist); return threads; @@ -117,7 +118,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) threads->map[threads->nr + i] = atoi(namelist[i]->d_name); for (i = 0; i < items; i++) - free(namelist[i]); + zfree(&namelist[i]); free(namelist); threads->nr += items; @@ -134,12 +135,11 @@ out_free_threads: out_free_namelist: for (i = 0; i < items; i++) - free(namelist[i]); + zfree(&namelist[i]); free(namelist); out_free_closedir: - free(threads); - threads = NULL; + zfree(&threads); goto out_closedir; } @@ -194,7 +194,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) for (i = 0; i < items; i++) { threads->map[j++] = atoi(namelist[i]->d_name); - free(namelist[i]); + zfree(&namelist[i]); } threads->nr = total_tasks; free(namelist); @@ -206,12 +206,11 @@ out: out_free_namelist: for (i = 0; i < items; i++) - free(namelist[i]); + zfree(&namelist[i]); free(namelist); out_free_threads: - free(threads); - threads = NULL; + zfree(&threads); goto out; } @@ -262,8 +261,7 @@ out: return threads; out_free_threads: - free(threads); - threads = NULL; + zfree(&threads); goto out; } diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index ce793c7dd23c..8e517def925b 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -26,7 +26,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) float samples_per_sec; float ksamples_per_sec; float esamples_percent; - struct perf_record_opts *opts = &top->record_opts; + struct record_opts *opts = &top->record_opts; struct target *target = &opts->target; size_t ret = 0; diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 88cfeaff600b..dab14d0ad3d0 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -14,7 +14,7 @@ struct perf_session; struct perf_top { struct perf_tool tool; struct perf_evlist *evlist; - struct perf_record_opts record_opts; + struct record_opts record_opts; /* * Symbols will be added here in perf_event__process_sample and will * get out after decayed. diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index c354b95a2348..7e6fcfe8b438 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -397,8 +397,8 @@ put_tracepoints_path(struct tracepoint_path *tps) struct tracepoint_path *t = tps; tps = tps->next; - free(t->name); - free(t->system); + zfree(&t->name); + zfree(&t->system); free(t); } } @@ -562,10 +562,8 @@ out: output_fd = fd; } - if (err) { - free(tdata); - tdata = NULL; - } + if (err) + zfree(&tdata); put_tracepoints_path(tps); return tdata; diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 95199e4eea97..57aaccc1692e 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -38,9 +38,8 @@ static int stop_script_unsupported(void) static void process_event_unsupported(union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, struct perf_evsel *evsel __maybe_unused, - struct machine *machine __maybe_unused, struct thread *thread __maybe_unused, - struct addr_location *al __maybe_unused) + struct addr_location *al __maybe_unused) { } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 3a01618c5b87..7b6d68688327 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -68,7 +68,6 @@ struct scripting_ops { void (*process_event) (union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine, struct thread *thread, struct addr_location *al); int (*generate_script) (struct pevent *pevent, const char *outfile); diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 9a2c268ad718..6995d66f225c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -186,6 +186,8 @@ static inline void *zalloc(size_t size) return calloc(1, size); } +#define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) + static inline int has_extension(const char *filename, const char *ext) { size_t len = strlen(filename); diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index 697c8b4e59cc..0fb3c1fcd3e6 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c @@ -31,14 +31,14 @@ void perf_read_values_destroy(struct perf_read_values *values) return; for (i = 0; i < values->threads; i++) - free(values->value[i]); - free(values->value); - free(values->pid); - free(values->tid); - free(values->counterrawid); + zfree(&values->value[i]); + zfree(&values->value); + zfree(&values->pid); + zfree(&values->tid); + zfree(&values->counterrawid); for (i = 0; i < values->counters; i++) - free(values->countername[i]); - free(values->countername); + zfree(&values->countername[i]); + zfree(&values->countername); } static void perf_read_values__enlarge_threads(struct perf_read_values *values) |