diff options
43 files changed, 798 insertions, 300 deletions
diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h index d62b56cf8c12..a30fad536f52 100644 --- a/tools/include/linux/string.h +++ b/tools/include/linux/string.h @@ -1,8 +1,8 @@ #ifndef _TOOLS_LINUX_STRING_H_ #define _TOOLS_LINUX_STRING_H_ - #include <linux/types.h> /* for size_t */ +#include <string.h> void *memdup(const void *src, size_t len); @@ -18,6 +18,14 @@ extern size_t strlcpy(char *dest, const char *src, size_t size); char *str_error_r(int errnum, char *buf, size_t buflen); -int prefixcmp(const char *str, const char *prefix); +/** + * strstarts - does @str start with @prefix? + * @str: string to examine + * @prefix: prefix to look for. + */ +static inline bool strstarts(const char *str, const char *prefix) +{ + return strncmp(str, prefix, strlen(prefix)) == 0; +} #endif /* _LINUX_STRING_H_ */ diff --git a/tools/include/uapi/linux/sched.h b/tools/include/uapi/linux/sched.h new file mode 100644 index 000000000000..e2a6c7b3510b --- /dev/null +++ b/tools/include/uapi/linux/sched.h @@ -0,0 +1,52 @@ +#ifndef _UAPI_LINUX_SCHED_H +#define _UAPI_LINUX_SCHED_H + +/* + * cloning flags: + */ +#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ +#define CLONE_VM 0x00000100 /* set if VM shared between processes */ +#define CLONE_FS 0x00000200 /* set if fs info shared between processes */ +#define CLONE_FILES 0x00000400 /* set if open files shared between processes */ +#define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */ +#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ +#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ +#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ +#define CLONE_THREAD 0x00010000 /* Same thread group? */ +#define CLONE_NEWNS 0x00020000 /* New mount namespace group */ +#define CLONE_SYSVSEM 0x00040000 /* share system V SEM_UNDO semantics */ +#define CLONE_SETTLS 0x00080000 /* create a new TLS for the child */ +#define CLONE_PARENT_SETTID 0x00100000 /* set the TID in the parent */ +#define CLONE_CHILD_CLEARTID 0x00200000 /* clear the TID in the child */ +#define CLONE_DETACHED 0x00400000 /* Unused, ignored */ +#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ +#define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ +#define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ +#define CLONE_NEWUTS 0x04000000 /* New utsname namespace */ +#define CLONE_NEWIPC 0x08000000 /* New ipc namespace */ +#define CLONE_NEWUSER 0x10000000 /* New user namespace */ +#define CLONE_NEWPID 0x20000000 /* New pid namespace */ +#define CLONE_NEWNET 0x40000000 /* New network namespace */ +#define CLONE_IO 0x80000000 /* Clone io context */ + +/* + * Scheduling policies + */ +#define SCHED_NORMAL 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 +#define SCHED_BATCH 3 +/* SCHED_ISO: reserved but not implemented yet */ +#define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 + +/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */ +#define SCHED_RESET_ON_FORK 0x40000000 + +/* + * For the sched_{set,get}attr() calls + */ +#define SCHED_FLAG_RESET_ON_FORK 0x01 +#define SCHED_FLAG_RECLAIM 0x02 + +#endif /* _UAPI_LINUX_SCHED_H */ diff --git a/tools/lib/string.c b/tools/lib/string.c index 8e678af1c6ee..a4246f14ded1 100644 --- a/tools/lib/string.c +++ b/tools/lib/string.c @@ -39,27 +39,45 @@ void *memdup(const void *src, size_t len) * @s: input string * @res: result * - * This routine returns 0 iff the first character is one of 'Yy1Nn0'. - * Otherwise it will return -EINVAL. Value pointed to by res is - * updated upon finding a match. + * This routine returns 0 iff the first character is one of 'Yy1Nn0', or + * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value + * pointed to by res is updated upon finding a match. */ int strtobool(const char *s, bool *res) { + if (!s) + return -EINVAL; + switch (s[0]) { case 'y': case 'Y': case '1': *res = true; - break; + return 0; case 'n': case 'N': case '0': *res = false; - break; + return 0; + case 'o': + case 'O': + switch (s[1]) { + case 'n': + case 'N': + *res = true; + return 0; + case 'f': + case 'F': + *res = false; + return 0; + default: + break; + } default: - return -EINVAL; + break; } - return 0; + + return -EINVAL; } /** @@ -87,12 +105,3 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size) } return ret; } - -int prefixcmp(const char *str, const char *prefix) -{ - for (; ; str++, prefix++) - if (!*prefix) - return 0; - else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} diff --git a/tools/lib/subcmd/help.c b/tools/lib/subcmd/help.c index ba970a73d053..0310520f918e 100644 --- a/tools/lib/subcmd/help.c +++ b/tools/lib/subcmd/help.c @@ -171,7 +171,7 @@ static void list_commands_in_dir(struct cmdnames *cmds, while ((de = readdir(dir)) != NULL) { int entlen; - if (prefixcmp(de->d_name, prefix)) + if (!strstarts(de->d_name, prefix)) continue; astrcat(&buf, de->d_name); diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c index 359bfa77f39c..2bd6fd0c1d40 100644 --- a/tools/lib/subcmd/parse-options.c +++ b/tools/lib/subcmd/parse-options.c @@ -368,7 +368,7 @@ retry: return 0; } if (!rest) { - if (!prefixcmp(options->long_name, "no-")) { + if (strstarts(options->long_name, "no-")) { /* * The long name itself starts with "no-", so * accept the option without "no-" so that users @@ -381,7 +381,7 @@ retry: goto match; } /* Abbreviated case */ - if (!prefixcmp(options->long_name + 3, arg)) { + if (strstarts(options->long_name + 3, arg)) { flags |= OPT_UNSET; goto is_abbreviated; } @@ -406,7 +406,7 @@ is_abbreviated: continue; } /* negated and abbreviated very much? */ - if (!prefixcmp("no-", arg)) { + if (strstarts("no-", arg)) { flags |= OPT_UNSET; goto is_abbreviated; } @@ -416,7 +416,7 @@ is_abbreviated: flags |= OPT_UNSET; rest = skip_prefix(arg + 3, options->long_name); /* abbreviated and negated? */ - if (!rest && !prefixcmp(options->long_name, arg + 3)) + if (!rest && strstarts(options->long_name, arg + 3)) goto is_abbreviated; if (!rest) continue; @@ -456,7 +456,7 @@ static void check_typos(const char *arg, const struct option *options) if (strlen(arg) < 3) return; - if (!prefixcmp(arg, "no-")) { + if (strstarts(arg, "no-")) { fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg); exit(129); } @@ -464,7 +464,7 @@ static void check_typos(const char *arg, const struct option *options) for (; options->type != OPTION_END; options++) { if (!options->long_name) continue; - if (!prefixcmp(options->long_name, arg)) { + if (strstarts(options->long_name, arg)) { fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg); exit(129); } @@ -933,10 +933,10 @@ opt: if (opts->long_name == NULL) continue; - if (!prefixcmp(opts->long_name, optstr)) + if (strstarts(opts->long_name, optstr)) print_option_help(opts, 0); - if (!prefixcmp("no-", optstr) && - !prefixcmp(opts->long_name, optstr + 3)) + if (strstarts("no-", optstr) && + strstarts(opts->long_name, optstr + 3)) print_option_help(opts, 0); } diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index e71d63843f45..d864ea6fd367 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -237,6 +237,10 @@ Default is to monitor all CPUS. --hierarchy:: Enable hierarchy output. +--force:: + Don't do ownership validation. + + INTERACTIVE PROMPTING KEYS -------------------------- diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index a29da46d180f..705bdb147e73 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -70,6 +70,7 @@ tools/include/linux/hash.h tools/include/linux/kernel.h tools/include/linux/list.h tools/include/linux/log2.h +tools/include/uapi/asm-generic/fcntl.h tools/include/uapi/asm-generic/mman-common.h tools/include/uapi/asm-generic/mman.h tools/include/uapi/linux/bpf.h @@ -78,6 +79,7 @@ tools/include/uapi/linux/fcntl.h tools/include/uapi/linux/hw_breakpoint.h tools/include/uapi/linux/mman.h tools/include/uapi/linux/perf_event.h +tools/include/uapi/linux/sched.h tools/include/uapi/linux/stat.h tools/include/linux/poison.h tools/include/linux/rbtree.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 5008f51a08a2..d66f90e6be5c 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -33,6 +33,11 @@ include ../scripts/utilities.mak # # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. # +# Define EXCLUDE_EXTLIBS=-lmylib to exclude libmylib from the auto-generated +# EXTLIBS. +# +# Define EXTRA_PERFLIBS to pass extra libraries to PERFLIBS. +# # Define NO_DWARF if you do not want debug-info analysis feature at all. # # Define WERROR=0 to disable treating any warnings as errors. @@ -352,7 +357,8 @@ ifdef ASCIIDOC8 export ASCIIDOC8 endif -LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group +EXTLIBS := $(call filter-out,$(EXCLUDE_EXTLIBS),$(EXTLIBS)) +LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group ifeq ($(USE_CLANG), 1) CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization @@ -512,7 +518,7 @@ $(LIBJVMTI_IN): FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=jvmti obj=jvmti $(OUTPUT)$(LIBJVMTI): $(LIBJVMTI_IN) - $(QUIET_LINK)$(CC) -shared -Wl,-soname -Wl,$(LIBJVMTI) -o $@ $< -lelf -lrt + $(QUIET_LINK)$(CC) -shared -Wl,-soname -Wl,$(LIBJVMTI) -o $@ $< endif $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build index 5bd7b9260cc0..bd518b623d7a 100644 --- a/tools/perf/arch/s390/util/Build +++ b/tools/perf/arch/s390/util/Build @@ -1,4 +1,5 @@ libperf-y += header.o +libperf-y += sym-handling.o libperf-y += kvm-stat.o libperf-$(CONFIG_DWARF) += dwarf-regs.o diff --git a/tools/perf/arch/s390/util/sym-handling.c b/tools/perf/arch/s390/util/sym-handling.c new file mode 100644 index 000000000000..b6cd056ccf71 --- /dev/null +++ b/tools/perf/arch/s390/util/sym-handling.c @@ -0,0 +1,22 @@ +/* + * Architecture specific ELF symbol handling and relocation mapping. + * + * Copyright 2017 IBM Corp. + * Author(s): Thomas Richter <tmricht@linux.vnet.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ + +#include "symbol.h" + +#ifdef HAVE_LIBELF_SUPPORT +bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) +{ + if (ehdr.e_type == ET_EXEC) + return false; + return ehdr.e_type == ET_REL || ehdr.e_type == ET_DYN; +} + +#endif diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index 9535be57033f..db0ba8caf5a2 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -701,6 +701,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, perf_evsel__set_sample_bit(switch_evsel, TID); perf_evsel__set_sample_bit(switch_evsel, TIME); perf_evsel__set_sample_bit(switch_evsel, CPU); + perf_evsel__reset_sample_bit(switch_evsel, BRANCH_STACK); opts->record_switch_events = false; ptr->have_sched_switch = 3; @@ -752,6 +753,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, tracking_evsel->attr.freq = 0; tracking_evsel->attr.sample_period = 1; + tracking_evsel->no_aux_samples = true; if (need_immediate) tracking_evsel->immediate = true; @@ -761,6 +763,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, /* And the CPU for switch events */ perf_evsel__set_sample_bit(tracking_evsel, CPU); } + perf_evsel__reset_sample_bit(tracking_evsel, BRANCH_STACK); } /* diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5205408e795b..6db782dfce96 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -177,14 +177,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, */ process_branch_stack(sample->branch_stack, al, sample); - sample->period = 1; sample->weight = 1; he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); if (he == NULL) return -ENOMEM; - ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); + ret = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); hists__inc_nr_samples(hists, true); return ret; } @@ -397,6 +396,7 @@ int cmd_annotate(int argc, const char **argv) .namespaces = perf_event__process_namespaces, .attr = perf_event__process_attr, .build_id = perf_event__process_build_id, + .tracing_data = perf_event__process_tracing_data, .feature = perf_event__process_feature, .ordered_events = true, .ordering_requires_timestamps = true, diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index ece45582a48d..3ddcc6e2abeb 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -13,6 +13,7 @@ #include "util/util.h" #include "util/debug.h" #include "util/config.h" +#include <linux/string.h> static bool use_system_config, use_user_config; @@ -79,7 +80,7 @@ static int show_spec_config(struct perf_config_set *set, const char *var) return -1; perf_config_items__for_each_entry(&set->sections, section) { - if (prefixcmp(var, section->name) != 0) + if (!strstarts(var, section->name)) continue; perf_config_items__for_each_entry(§ion->items, item) { diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index dd26c62c9893..25a42acabee1 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -381,7 +381,7 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb) { struct perf_ftrace *ftrace = cb; - if (prefixcmp(var, "ftrace.")) + if (!strstarts(var, "ftrace.")) return 0; if (strcmp(var, "ftrace.tracer")) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 530a7f2fa0f3..dbe4e4153bcf 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -90,7 +90,7 @@ static int check_emacsclient_version(void) */ finish_command(&ec_process); - if (prefixcmp(buffer.buf, "emacsclient")) { + if (!strstarts(buffer.buf, "emacsclient")) { fprintf(stderr, "Failed to parse emacsclient version.\n"); goto out; } @@ -283,7 +283,7 @@ static int perf_help_config(const char *var, const char *value, void *cb) add_man_viewer(value); return 0; } - if (!prefixcmp(var, "man.")) + if (!strstarts(var, "man.")) return add_man_viewer_info(var, value); return 0; @@ -313,7 +313,7 @@ static const char *cmd_to_page(const char *perf_cmd) if (!perf_cmd) return "perf"; - else if (!prefixcmp(perf_cmd, "perf")) + else if (!strstarts(perf_cmd, "perf")) return perf_cmd; return asprintf(&s, "perf-%s", perf_cmd) < 0 ? NULL : s; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cea25d03f4dd..bace3429c030 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -115,37 +115,38 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, struct report *rep = arg; struct hist_entry *he = iter->he; struct perf_evsel *evsel = iter->evsel; + struct perf_sample *sample = iter->sample; struct mem_info *mi; struct branch_info *bi; if (!ui__has_annotation()) return 0; - hist__account_cycles(iter->sample->branch_stack, al, iter->sample, + hist__account_cycles(sample->branch_stack, al, sample, rep->nonany_branch_mode); if (sort__mode == SORT_MODE__BRANCH) { bi = he->branch_info; - err = addr_map_symbol__inc_samples(&bi->from, evsel->idx); + err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); if (err) goto out; - err = addr_map_symbol__inc_samples(&bi->to, evsel->idx); + err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); } else if (rep->mem_mode) { mi = he->mem_info; - err = addr_map_symbol__inc_samples(&mi->daddr, evsel->idx); + err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel->idx); if (err) goto out; - err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); + err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); } else if (symbol_conf.cumulate_callchain) { if (single) - err = hist_entry__inc_addr_samples(he, evsel->idx, + err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); } else { - err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); + err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); } out: @@ -278,10 +279,11 @@ static int report__setup_sample_type(struct report *rep) "'perf record' without -g?\n"); return -EINVAL; } - if (symbol_conf.use_callchain) { - ui__error("Selected -g or --branch-history but no " - "callchain data. Did\n" - "you call 'perf record' without -g?\n"); + if (symbol_conf.use_callchain && + !symbol_conf.show_branchflag_count) { + ui__error("Selected -g or --branch-history.\n" + "But no callchain or branch data.\n" + "Did you call 'perf record' without -g or -b?\n"); return -1; } } else if (!callchain_param.enabled && @@ -416,7 +418,8 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, hists__fprintf_nr_sample_events(hists, rep, evname, stdout); hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout, - symbol_conf.use_callchain); + symbol_conf.use_callchain || + symbol_conf.show_branchflag_count); fprintf(stdout, "\n\n"); } diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index d430ff42208a..378f76cdf923 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2199,16 +2199,11 @@ static struct script_desc *script_desc__findnew(const char *name) s = script_desc__new(name); if (!s) - goto out_delete_desc; + return NULL; script_desc__add(s); return s; - -out_delete_desc: - script_desc__delete(s); - - return NULL; } static const char *ends_with(const char *str, const char *suffix) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 022486dc67f5..ee954bde7e3e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -183,6 +183,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) static void perf_top__record_precise_ip(struct perf_top *top, struct hist_entry *he, + struct perf_sample *sample, int counter, u64 ip) { struct annotation *notes; @@ -199,7 +200,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, if (pthread_mutex_trylock(¬es->lock)) return; - err = hist_entry__inc_addr_samples(he, counter, ip); + err = hist_entry__inc_addr_samples(he, sample, counter, ip); pthread_mutex_unlock(¬es->lock); @@ -586,6 +587,13 @@ static void *display_thread_tui(void *arg) .refresh = top->delay_secs, }; + /* In order to read symbols from other namespaces perf to needs to call + * setns(2). This isn't permitted if the struct_fs has multiple users. + * unshare(2) the fs so that we may continue to setns into namespaces + * that we're observing. + */ + unshare(CLONE_FS); + perf_top__sort_new_samples(top); /* @@ -627,6 +635,13 @@ static void *display_thread(void *arg) struct perf_top *top = arg; int delay_msecs, c; + /* In order to read symbols from other namespaces perf to needs to call + * setns(2). This isn't permitted if the struct_fs has multiple users. + * unshare(2) the fs so that we may continue to setns into namespaces + * that we're observing. + */ + unshare(CLONE_FS); + display_setup_sig(); pthread__unblock_sigwinch(); repeat: @@ -671,7 +686,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, struct perf_evsel *evsel = iter->evsel; if (perf_hpp_list.sym && single) - perf_top__record_precise_ip(top, he, evsel->idx, al->addr); + perf_top__record_precise_ip(top, he, iter->sample, evsel->idx, al->addr); hist__account_cycles(iter->sample->branch_stack, al, iter->sample, !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); @@ -1205,6 +1220,7 @@ int cmd_top(int argc, const char **argv) "Show raw trace event output (do not use print fmt or plugins)"), OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, "Show entries in a hierarchy"), + OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"), OPT_END() }; const char * const top_usage[] = { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 1e4c0657b712..05d24b6570ee 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -604,6 +604,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, struct syscall_arg_fmt { size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); void *parm; + const char *name; bool show_zero; }; @@ -611,6 +612,7 @@ static struct syscall_fmt { const char *name; const char *alias; struct syscall_arg_fmt arg[6]; + u8 nr_args; bool errpid; bool timeout; bool hexret; @@ -624,7 +626,12 @@ static struct syscall_fmt { .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, }, { .name = "clock_gettime", .arg = { [0] = STRARRAY(clk_id, clockid), }, }, - { .name = "clone", .errpid = true, }, + { .name = "clone", .errpid = true, .nr_args = 5, + .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, }, + [1] = { .name = "child_stack", .scnprintf = SCA_HEX, }, + [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, }, + [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, }, + [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, }, { .name = "close", .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, }, { .name = "epoll_ctl", @@ -1165,22 +1172,34 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) return err; } -static int syscall__set_arg_fmts(struct syscall *sc) +static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args) { - struct format_field *field; - int idx = 0, len; + int idx; + + if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0) + nr_args = sc->fmt->nr_args; - sc->arg_fmt = calloc(sc->nr_args, sizeof(*sc->arg_fmt)); + sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt)); if (sc->arg_fmt == NULL) return -1; - for (field = sc->args; field; field = field->next, ++idx) { - if (sc->fmt) { + for (idx = 0; idx < nr_args; ++idx) { + if (sc->fmt) sc->arg_fmt[idx] = sc->fmt->arg[idx]; + } - if (sc->fmt->arg[idx].scnprintf) - continue; - } + sc->nr_args = nr_args; + return 0; +} + +static int syscall__set_arg_fmts(struct syscall *sc) +{ + struct format_field *field; + int idx = 0, len; + + for (field = sc->args; field; field = field->next, ++idx) { + if (sc->fmt && sc->fmt->arg[idx].scnprintf) + continue; if (strcmp(field->type, "const char *") == 0 && (strcmp(field->name, "filename") == 0 || @@ -1251,11 +1270,13 @@ static int trace__read_syscall_info(struct trace *trace, int id) sc->tp_format = trace_event__tp_format("syscalls", tp_name); } + if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields)) + return -1; + if (IS_ERR(sc->tp_format)) return -1; sc->args = sc->tp_format->format.fields; - sc->nr_args = sc->tp_format->format.nr_fields; /* * We need to check and discard the first variable '__syscall_nr' * or 'nr' that mean the syscall nu |