aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-03-24 12:22:44 -0400
committerIngo Molnar <mingo@kernel.org>2015-03-24 12:22:44 -0400
commitbaa5a7bc5dd069bb37de9c8bdb5ea7f4e2e939e9 (patch)
tree50864d78ede1a333b0b6fb8fe09486ed3f3ad1c2 /tools
parent963a70b8a2d65538f7d58b2b84a2ae10a3ecb6ea (diff)
parente03eaa400cf8b8bded86cc5c41018a1c69152f16 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Improve support of compressed kernel modules (Jiri Olsa) - Add --kallsyms option to 'perf diff' (David Ahern) - Add pid/tid filtering to 'report' and 'script' commands (David Ahern) - Add support for __print_array() in libtraceevent (Javi Merino) - Save DSO loading errno to better report errors (Arnaldo Carvalho de Melo) - Fix 'probe' to get ummapped symbol address on kernel (Masami Hiramatsu) - Print big numbers using thousands' group in 'kmem' (Namhyung Kim) - Remove (null) value of "Sort order" for perf mem report (Yunlong Song) Infrastructure changes: - Handle NULL comm name in libtracevent (Josef Bacik) - Libtraceevent synchronization with trace-cmd repo (Steven Rostedt) - Work around lack of sched_getcpu() in glibc < 2.6. (Vinson Lee) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/traceevent/event-parse.c267
-rw-r--r--tools/lib/traceevent/event-parse.h21
-rw-r--r--tools/lib/traceevent/event-plugin.c60
-rw-r--r--tools/lib/traceevent/kbuffer-parse.c12
-rw-r--r--tools/lib/traceevent/kbuffer.h1
-rw-r--r--tools/lib/traceevent/parse-filter.c2
-rw-r--r--tools/perf/Documentation/perf-diff.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt5
-rw-r--r--tools/perf/Documentation/perf-script.txt6
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-kmem.c11
-rw-r--r--tools/perf/builtin-report.c6
-rw-r--r--tools/perf/builtin-script.c4
-rw-r--r--tools/perf/builtin-top.c6
-rw-r--r--tools/perf/util/annotate.c32
-rw-r--r--tools/perf/util/cloexec.c6
-rw-r--r--tools/perf/util/cloexec.h6
-rw-r--r--tools/perf/util/dso.c61
-rw-r--r--tools/perf/util/dso.h31
-rw-r--r--tools/perf/util/header.c2
-rw-r--r--tools/perf/util/machine.c72
-rw-r--r--tools/perf/util/probe-event.c5
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c5
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c5
-rw-r--r--tools/perf/util/sort.h1
-rw-r--r--tools/perf/util/symbol-elf.c57
-rw-r--r--tools/perf/util/symbol-minimal.c7
-rw-r--r--tools/perf/util/symbol.c31
-rw-r--r--tools/perf/util/symbol.h7
-rw-r--r--tools/perf/util/target.c7
-rw-r--r--tools/perf/util/thread.h11
31 files changed, 621 insertions, 131 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index d7c37a7d9255..b6d11eea8a57 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -304,7 +304,10 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
304 if (!item) 304 if (!item)
305 return -1; 305 return -1;
306 306
307 item->comm = strdup(comm); 307 if (comm)
308 item->comm = strdup(comm);
309 else
310 item->comm = strdup("<...>");
308 if (!item->comm) { 311 if (!item->comm) {
309 free(item); 312 free(item);
310 return -1; 313 return -1;
@@ -318,9 +321,14 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
318 return 0; 321 return 0;
319} 322}
320 323
321void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock) 324int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock)
322{ 325{
323 pevent->trace_clock = trace_clock; 326 pevent->trace_clock = strdup(trace_clock);
327 if (!pevent->trace_clock) {
328 errno = ENOMEM;
329 return -1;
330 }
331 return 0;
324} 332}
325 333
326struct func_map { 334struct func_map {
@@ -758,6 +766,11 @@ static void free_arg(struct print_arg *arg)
758 free_arg(arg->hex.field); 766 free_arg(arg->hex.field);
759 free_arg(arg->hex.size); 767 free_arg(arg->hex.size);
760 break; 768 break;
769 case PRINT_INT_ARRAY:
770 free_arg(arg->int_array.field);
771 free_arg(arg->int_array.count);
772 free_arg(arg->int_array.el_size);
773 break;
761 case PRINT_TYPE: 774 case PRINT_TYPE:
762 free(arg->typecast.type); 775 free(arg->typecast.type);
763 free_arg(arg->typecast.item); 776 free_arg(arg->typecast.item);
@@ -2014,6 +2027,38 @@ process_entry(struct event_format *event __maybe_unused, struct print_arg *arg,
2014 return EVENT_ERROR; 2027 return EVENT_ERROR;
2015} 2028}
2016 2029
2030static int alloc_and_process_delim(struct event_format *event, char *next_token,
2031 struct print_arg **print_arg)
2032{
2033 struct print_arg *field;
2034 enum event_type type;
2035 char *token;
2036 int ret = 0;
2037
2038 field = alloc_arg();
2039 if (!field) {
2040 do_warning_event(event, "%s: not enough memory!", __func__);
2041 errno = ENOMEM;
2042 return -1;
2043 }
2044
2045 type = process_arg(event, field, &token);
2046
2047 if (test_type_token(type, token, EVENT_DELIM, next_token)) {
2048 errno = EINVAL;
2049 ret = -1;
2050 free_arg(field);
2051 goto out_free_token;
2052 }
2053
2054 *print_arg = field;
2055
2056out_free_token:
2057 free_token(token);
2058
2059 return ret;
2060}
2061
2017static char *arg_eval (struct print_arg *arg); 2062static char *arg_eval (struct print_arg *arg);
2018 2063
2019static unsigned long long 2064static unsigned long long
@@ -2486,49 +2531,46 @@ out_free:
2486static enum event_type 2531static enum event_type
2487process_hex(struct event_format *event, struct print_arg *arg, char **tok) 2532process_hex(struct event_format *event, struct print_arg *arg, char **tok)
2488{ 2533{
2489 struct print_arg *field;
2490 enum event_type type;
2491 char *token = NULL;
2492
2493 memset(arg, 0, sizeof(*arg)); 2534 memset(arg, 0, sizeof(*arg));
2494 arg->type = PRINT_HEX; 2535 arg->type = PRINT_HEX;
2495 2536
2496 field = alloc_arg(); 2537 if (alloc_and_process_delim(event, ",", &arg->hex.field))
2497 if (!field) { 2538 goto out;
2498 do_warning_event(event, "%s: not enough memory!", __func__);
2499 goto out_free;
2500 }
2501
2502 type = process_arg(event, field, &token);
2503 2539
2504 if (test_type_token(type, token, EVENT_DELIM, ",")) 2540 if (alloc_and_process_delim(event, ")", &arg->hex.size))
2505 goto out_free; 2541 goto free_field;
2506 2542
2507 arg->hex.field = field; 2543 return read_token_item(tok);
2508 2544
2509 free_token(token); 2545free_field:
2546 free_arg(arg->hex.field);
2547out:
2548 *tok = NULL;
2549 return EVENT_ERROR;
2550}
2510 2551
2511 field = alloc_arg(); 2552static enum event_type
2512 if (!field) { 2553process_int_array(struct event_format *event, struct print_arg *arg, char **tok)
2513 do_warning_event(event, "%s: not enough memory!", __func__); 2554{
2514 *tok = NULL; 2555 memset(arg, 0, sizeof(*arg));
2515 return EVENT_ERROR; 2556 arg->type = PRINT_INT_ARRAY;
2516 }
2517 2557
2518 type = process_arg(event, field, &token); 2558 if (alloc_and_process_delim(event, ",", &arg->int_array.field))
2559 goto out;
2519 2560
2520 if (test_type_token(type, token, EVENT_DELIM, ")")) 2561 if (alloc_and_process_delim(event, ",", &arg->int_array.count))
2521 goto out_free; 2562 goto free_field;
2522 2563
2523 arg->hex.size = field; 2564 if (alloc_and_process_delim(event, ")", &arg->int_array.el_size))
2565 goto free_size;
2524 2566
2525 free_token(token); 2567 return read_token_item(tok);
2526 type = read_token_item(tok);
2527 return type;
2528 2568
2529 out_free: 2569free_size:
2530 free_arg(field); 2570 free_arg(arg->int_array.count);
2531 free_token(token); 2571free_field:
2572 free_arg(arg->int_array.field);
2573out:
2532 *tok = NULL; 2574 *tok = NULL;
2533 return EVENT_ERROR; 2575 return EVENT_ERROR;
2534} 2576}
@@ -2828,6 +2870,10 @@ process_function(struct event_format *event, struct print_arg *arg,
2828 free_token(token); 2870 free_token(token);
2829 return process_hex(event, arg, tok); 2871 return process_hex(event, arg, tok);
2830 } 2872 }
2873 if (strcmp(token, "__print_array") == 0) {
2874 free_token(token);
2875 return process_int_array(event, arg, tok);
2876 }
2831 if (strcmp(token, "__get_str") == 0) { 2877 if (strcmp(token, "__get_str") == 0) {
2832 free_token(token); 2878 free_token(token);
2833 return process_str(event, arg, tok); 2879 return process_str(event, arg, tok);
@@ -3356,6 +3402,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
3356 break; 3402 break;
3357 case PRINT_FLAGS: 3403 case PRINT_FLAGS:
3358 case PRINT_SYMBOL: 3404 case PRINT_SYMBOL:
3405 case PRINT_INT_ARRAY:
3359 case PRINT_HEX: 3406 case PRINT_HEX:
3360 break; 3407 break;
3361 case PRINT_TYPE: 3408 case PRINT_TYPE:
@@ -3766,6 +3813,54 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3766 } 3813 }
3767 break; 3814 break;
3768 3815
3816 case PRINT_INT_ARRAY: {
3817 void *num;
3818 int el_size;
3819
3820 if (arg->int_array.field->type == PRINT_DYNAMIC_ARRAY) {
3821 unsigned long offset;
3822 struct format_field *field =
3823 arg->int_array.field->dynarray.field;
3824 offset = pevent_read_number(pevent,
3825 data + field->offset,
3826 field->size);
3827 num = data + (offset & 0xffff);
3828 } else {
3829 field = arg->int_array.field->field.field;
3830 if (!field) {
3831 str = arg->int_array.field->field.name;
3832 field = pevent_find_any_field(event, str);
3833 if (!field)
3834 goto out_warning_field;
3835 arg->int_array.field->field.field = field;
3836 }
3837 num = data + field->offset;
3838 }
3839 len = eval_num_arg(data, size, event, arg->int_array.count);
3840 el_size = eval_num_arg(data, size, event,
3841 arg->int_array.el_size);
3842 for (i = 0; i < len; i++) {
3843 if (i)
3844 trace_seq_putc(s, ' ');
3845
3846 if (el_size == 1) {
3847 trace_seq_printf(s, "%u", *(uint8_t *)num);
3848 } else if (el_size == 2) {
3849 trace_seq_printf(s, "%u", *(uint16_t *)num);
3850 } else if (el_size == 4) {
3851 trace_seq_printf(s, "%u", *(uint32_t *)num);
3852 } else if (el_size == 8) {
3853 trace_seq_printf(s, "%lu", *(uint64_t *)num);
3854 } else {
3855 trace_seq_printf(s, "BAD SIZE:%d 0x%x",
3856 el_size, *(uint8_t *)num);
3857 el_size = 1;
3858 }
3859
3860 num += el_size;
3861 }
3862 break;
3863 }
3769 case PRINT_TYPE: 3864 case PRINT_TYPE:
3770 break; 3865 break;
3771 case PRINT_STRING: { 3866 case PRINT_STRING: {
@@ -3997,6 +4092,10 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
3997 goto process_again; 4092 goto process_again;
3998 case '.': 4093 case '.':
3999 goto process_again; 4094 goto process_again;
4095 case 'z':
4096 case 'Z':
4097 ls = 1;
4098 goto process_again;
4000 case 'p': 4099 case 'p':
4001 ls = 1; 4100 ls = 1;
4002 /* fall through */ 4101 /* fall through */
@@ -4939,6 +5038,96 @@ const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
4939 return comm; 5038 return comm;
4940} 5039}
4941 5040
5041static struct cmdline *
5042pid_from_cmdlist(struct pevent *pevent, const char *comm, struct cmdline *next)
5043{
5044 struct cmdline_list *cmdlist = (struct cmdline_list *)next;
5045
5046 if (cmdlist)
5047 cmdlist = cmdlist->next;
5048 else
5049 cmdlist = pevent->cmdlist;
5050
5051 while (cmdlist && strcmp(cmdlist->comm, comm) != 0)
5052 cmdlist = cmdlist->next;
5053
5054 return (struct cmdline *)cmdlist;
5055}
5056
5057/**
5058 * pevent_data_pid_from_comm - return the pid from a given comm
5059 * @pevent: a handle to the pevent
5060 * @comm: the cmdline to find the pid from
5061 * @next: the cmdline structure to find the next comm
5062 *
5063 * This returns the cmdline structure that holds a pid for a given
5064 * comm, or NULL if none found. As there may be more than one pid for
5065 * a given comm, the result of this call can be passed back into
5066 * a recurring call in the @next paramater, and then it will find the
5067 * next pid.
5068 * Also, it does a linear seach, so it may be slow.
5069 */
5070struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm,
5071 struct cmdline *next)
5072{
5073 struct cmdline *cmdline;
5074
5075 /*
5076 * If the cmdlines have not been converted yet, then use
5077 * the list.
5078 */
5079 if (!pevent->cmdlines)
5080 return pid_from_cmdlist(pevent, comm, next);
5081
5082 if (next) {
5083 /*
5084 * The next pointer could have been still from
5085 * a previous call before cmdlines were created
5086 */
5087 if (next < pevent->cmdlines ||
5088 next >= pevent->cmdlines + pevent->cmdline_count)
5089 next = NULL;
5090 else
5091 cmdline = next++;
5092 }
5093
5094 if (!next)
5095 cmdline = pevent->cmdlines;
5096
5097 while (cmdline < pevent->cmdlines + pevent->cmdline_count) {
5098 if (strcmp(cmdline->comm, comm) == 0)
5099 return cmdline;
5100 cmdline++;
5101 }
5102 return NULL;
5103}
5104
5105/**
5106 * pevent_cmdline_pid - return the pid associated to a given cmdline
5107 * @cmdline: The cmdline structure to get the pid from
5108 *
5109 * Returns the pid for a give cmdline. If @cmdline is NULL, then
5110 * -1 is returned.
5111 */
5112int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline)
5113{
5114 struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline;
5115
5116 if (!cmdline)
5117 return -1;
5118
5119 /*
5120 * If cmdlines have not been created yet, or cmdline is
5121 * not part of the array, then treat it as a cmdlist instead.
5122 */
5123 if (!pevent->cmdlines ||
5124 cmdline < pevent->cmdlines ||
5125 cmdline >= pevent->cmdlines + pevent->cmdline_count)
5126 return cmdlist->pid;
5127
5128 return cmdline->pid;
5129}
5130
4942/** 5131/**
4943 * pevent_data_comm_from_pid - parse the data into the print format 5132 * pevent_data_comm_from_pid - parse the data into the print format
4944 * @s: the trace_seq to write to 5133 * @s: the trace_seq to write to
@@ -5256,6 +5445,15 @@ static void print_args(struct print_arg *args)
5256 print_args(args->hex.size); 5445 print_args(args->hex.size);
5257 printf(")"); 5446 printf(")");
5258 break; 5447 break;
5448 case PRINT_INT_ARRAY:
5449 printf("__print_array(");
5450 print_args(args->int_array.field);
5451 printf(", ");
5452 print_args(args->int_array.count);
5453 printf(", ");
5454 print_args(args->int_array.el_size);
5455 printf(")");
5456 break;
5259 case PRINT_STRING: 5457 case PRINT_STRING:
5260 case PRINT_BSTRING: 5458 case PRINT_BSTRING:
5261 printf("__get_str(%s)", args->string.string); 5459 printf("__get_str(%s)", args->string.string);
@@ -6346,6 +6544,7 @@ void pevent_free(struct pevent *pevent)
6346 free_handler(handle); 6544 free_handler(handle);
6347 } 6545 }
6348 6546
6547 free(pevent->trace_clock);
6349 free(pevent->events); 6548 free(pevent->events);
6350 free(pevent->sort_events); 6549 free(pevent->sort_events);
6351 6550
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 6abda54d76f2..86a5839fb048 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -116,7 +116,7 @@ struct pevent_plugin_option {
116 char *name; 116 char *name;
117 char *plugin_alias; 117 char *plugin_alias;
118 char *description; 118 char *description;
119 char *value; 119 const char *value;
120 void *priv; 120 void *priv;
121 int set; 121 int set;
122}; 122};
@@ -154,6 +154,10 @@ struct pevent_plugin_option {
154 * .plugin_alias is used to give a shorter name to access 154 * .plugin_alias is used to give a shorter name to access
155 * the vairable. Useful if a plugin handles more than one event. 155 * the vairable. Useful if a plugin handles more than one event.
156 * 156 *
157 * If .value is not set, then it is considered a boolean and only
158 * .set will be processed. If .value is defined, then it is considered
159 * a string option and .set will be ignored.
160 *
157 * PEVENT_PLUGIN_ALIAS: (optional) 161 * PEVENT_PLUGIN_ALIAS: (optional)
158 * The name to use for finding options (uses filename if not defined) 162 * The name to use for finding options (uses filename if not defined)
159 */ 163 */
@@ -247,6 +251,12 @@ struct print_arg_hex {
247 struct print_arg *size; 251 struct print_arg *size;
248}; 252};
249 253
254struct print_arg_int_array {
255 struct print_arg *field;
256 struct print_arg *count;
257 struct print_arg *el_size;
258};
259
250struct print_arg_dynarray { 260struct print_arg_dynarray {
251 struct format_field *field; 261 struct format_field *field;
252 struct print_arg *index; 262 struct print_arg *index;
@@ -275,6 +285,7 @@ enum print_arg_type {
275 PRINT_FLAGS, 285 PRINT_FLAGS,
276 PRINT_SYMBOL, 286 PRINT_SYMBOL,
277 PRINT_HEX, 287 PRINT_HEX,
288 PRINT_INT_ARRAY,
278 PRINT_TYPE, 289 PRINT_TYPE,
279 PRINT_STRING, 290 PRINT_STRING,
280 PRINT_BSTRING, 291 PRINT_BSTRING,
@@ -294,6 +305,7 @@ struct print_arg {
294 struct print_arg_flags flags; 305 struct print_arg_flags flags;
295 struct print_arg_symbol symbol; 306 struct print_arg_symbol symbol;
296 struct print_arg_hex hex; 307 struct print_arg_hex hex;
308 struct print_arg_int_array int_array;
297 struct print_arg_func func; 309 struct print_arg_func func;
298 struct print_arg_string string; 310 struct print_arg_string string;
299 struct print_arg_bitmask bitmask; 311 struct print_arg_bitmask bitmask;
@@ -599,7 +611,7 @@ enum trace_flag_type {
599}; 611};
600 612
601int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); 613int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
602void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock); 614int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock);
603int pevent_register_function(struct pevent *pevent, char *name, 615int pevent_register_function(struct pevent *pevent, char *name,
604 unsigned long long addr, char *mod); 616 unsigned long long addr, char *mod);
605int pevent_register_print_string(struct pevent *pevent, const char *fmt, 617int pevent_register_print_string(struct pevent *pevent, const char *fmt,
@@ -678,6 +690,11 @@ int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
678struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type); 690struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
679int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec); 691int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
680const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid); 692const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
693struct cmdline;
694struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm,
695 struct cmdline *next);
696int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline);
697
681void pevent_event_info(struct trace_seq *s, struct event_format *event, 698void pevent_event_info(struct trace_seq *s, struct event_format *event,
682 struct pevent_record *record); 699 struct pevent_record *record);
683int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, 700int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c
index 136162c03af1..a16756ae3526 100644
--- a/tools/lib/traceevent/event-plugin.c
+++ b/tools/lib/traceevent/event-plugin.c
@@ -18,6 +18,7 @@
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */ 19 */
20 20
21#include <ctype.h>
21#include <stdio.h> 22#include <stdio.h>
22#include <string.h> 23#include <string.h>
23#include <dlfcn.h> 24#include <dlfcn.h>
@@ -49,6 +50,52 @@ struct plugin_list {
49 void *handle; 50 void *handle;
50}; 51};
51 52
53static void lower_case(char *str)
54{
55 if (!str)
56 return;
57 for (; *str; str++)
58 *str = tolower(*str);
59}
60
61static int update_option_value(struct pevent_plugin_option *op, const char *val)
62{
63 char *op_val;
64
65 if (!val) {
66 /* toggle, only if option is boolean */
67 if (op->value)
68 /* Warn? */
69 return 0;
70 op->set ^= 1;
71 return 0;
72 }
73
74 /*
75 * If the option has a value then it takes a string
76 * otherwise the option is a boolean.
77 */
78 if (op->value) {
79 op->value = val;
80 return 0;
81 }
82
83 /* Option is boolean, must be either "1", "0", "true" or "false" */
84
85 op_val = strdup(val);
86 if (!op_val)
87 return -1;
88 lower_case(op_val);
89
90 if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
91 op->set = 1;
92 else if (strcmp(val, "0") == 0 || strcmp(val, "false") == 0)
93 op->set = 0;
94 free(op_val);
95
96 return 0;
97}
98
52/** 99/**
53 * traceevent_plugin_list_options - get list of plugin options 100 * traceevent_plugin_list_options - get list of plugin options
54 * 101 *
@@ -120,6 +167,7 @@ update_option(const char *file, struct pevent_plugin_option *option)
120{ 167{
121 struct trace_plugin_options *op; 168 struct trace_plugin_options *op;
122 char *plugin; 169 char *plugin;
170 int ret = 0;
123 171
124 if (option->plugin_alias) { 172 if (option->plugin_alias) {
125 plugin = strdup(option->plugin_alias); 173 plugin = strdup(option->plugin_alias);
@@ -144,9 +192,10 @@ update_option(const char *file, struct pevent_plugin_option *option)
144 if (strcmp(op->option, option->name) != 0) 192 if (strcmp(op->option, option->name) != 0)
145 continue; 193 continue;
146 194
147 option->value = op->value; 195 ret = update_option_value(option, op->value);
148 option->set ^= 1; 196 if (ret)
149 goto out; 197 goto out;
198 break;
150 } 199 }
151 200
152 /* first look for unnamed options */ 201 /* first look for unnamed options */
@@ -156,14 +205,13 @@ update_option(const char *file, struct pevent_plugin_option *option)
156 if (strcmp(op->option, option->name) != 0) 205 if (strcmp(op->option, option->name) != 0)
157 continue; 206 continue;
158 207
159 option->value = op->value; 208 ret = update_option_value(option, op->value);
160 option->set ^= 1;
161 break; 209 break;
162 } 210 }
163 211
164 out: 212 out:
165 free(plugin); 213 free(plugin);
166 return 0; 214 return ret;
167} 215}
168 216
169/** 217/**
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c
index dcc665228c71..3bcada3ae05a 100644
--- a/tools/lib/traceevent/kbuffer-parse.c
+++ b/tools/lib/traceevent/kbuffer-parse.c
@@ -372,7 +372,6 @@ translate_data(struct kbuffer *kbuf, void *data, void **rptr,
372 switch (type_len) { 372 switch (type_len) {
373 case KBUFFER_TYPE_PADDING: 373 case KBUFFER_TYPE_PADDING:
374 *length = read_4(kbuf, data); 374 *length = read_4(kbuf, data);
375 data += *length;
376 break; 375 break;
377 376
378 case KBUFFER_TYPE_TIME_EXTEND: 377 case KBUFFER_TYPE_TIME_EXTEND:
@@ -730,3 +729,14 @@ void kbuffer_set_old_format(struct kbuffer *kbuf)
730 729
731 kbuf->next_event = __old_next_event; 730 kbuf->next_event = __old_next_event;
732} 731}
732
733/**
734 * kbuffer_start_of_data - return offset of where data starts on subbuffer
735 * @kbuf: The kbuffer
736 *
737 * Returns the location on the subbuffer where the data starts.
738 */
739int kbuffer_start_of_data(struct kbuffer *kbuf)
740{
741 return kbuf->start;
742}
diff --git a/tools/lib/traceevent/kbuffer.h b/tools/lib/traceevent/kbuffer.h
index c831f64b17a0..03dce757553f 100644
--- a/tools/lib/traceevent/kbuffer.h
+++ b/tools/lib/traceevent/kbuffer.h
@@ -63,5 +63,6 @@ int kbuffer_missed_events(struct kbuffer *kbuf);
63int kbuffer_subbuffer_size(struct kbuffer *kbuf); 63int kbuffer_subbuffer_size(struct kbuffer *kbuf);
64 64
65void kbuffer_set_old_format(struct kbuffer *kbuf); 65void kbuffer_set_old_format(struct kbuffer *kbuf);
66int kbuffer_start_of_data(struct kbuffer *kbuf);
66 67
67#endif /* _K_BUFFER_H */ 68#endif /* _K_BUFFER_H */
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index b50234402fc2..0144b3d1bb77 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -1058,6 +1058,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1058 *parg = current_op; 1058 *parg = current_op;
1059 else 1059 else
1060 *parg = current_exp; 1060 *parg = current_exp;
1061 free(token);
1061 return PEVENT_ERRNO__UNBALANCED_PAREN; 1062 return PEVENT_ERRNO__UNBALANCED_PAREN;
1062 } 1063 }
1063 break; 1064 break;
@@ -1168,6 +1169,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1168 1169
1169 *parg = current_op; 1170 *parg = current_op;
1170 1171
1172 free(token);
1171 return 0; 1173 return 0;
1172 1174
1173 fail_alloc: 1175 fail_alloc:
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 518266192d67..d1deb573877f 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -31,6 +31,9 @@ OPTIONS
31--dump-raw-trace:: 31--dump-raw-trace::
32 Dump raw trace in ASCII. 32 Dump raw trace in ASCII.
33 33
34--kallsyms=<file>::
35 kallsyms pathname
36
34-m:: 37-m::
35--modules:: 38--modules::
36 Load module symbols. WARNING: use only with -k and LIVE kernel 39 Load module symbols. WARNING: use only with -k and LIVE kernel
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index dd7cccdde498..4879cf638824 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -40,6 +40,11 @@ OPTIONS
40 Only consider symbols in these comms. CSV that understands 40 Only consider symbols in these comms. CSV that understands
41 file://filename entries. This option will affect the percentage of 41 file://filename entries. This option will affect the percentage of
42 the overhead column. See --percentage for more info. 42 the overhead column. See --percentage for more info.
43--pid=::
44 Only show events for given process ID (comma separated list).
45
46--tid=::
47 Only show events for given thread ID (comma separated list).
43-d:: 48-d::
44--dsos=:: 49--dsos=::
45 Only consider symbols in these dsos. CSV that understands 50 Only consider symbols in these dsos. CSV that understands
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index a21eec05bc42..79445750fcb3 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -193,6 +193,12 @@ OPTIONS
193 Only display events for these comms. CSV that understands 193 Only display events for these comms. CSV that understands
194 file://filename entries. 194 file://filename entries.
195 195
196--pid=::
197 Only show events for given process ID (comma separated list).
198
199--tid=::
200 Only show events for given thread ID (comma separated list).
201
196-I:: 202-I::
197--show-info:: 203--show-info::
198 Display extended information about the perf.data file. This adds 204 Display extended information about the perf.data file. This adds
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 473887d1d61a..df6307b4050a 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -791,6 +791,8 @@ static const struct option options[] = {
791 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 791 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
792 "dump raw trace in ASCII"), 792 "dump raw trace in ASCII"),
793 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 793 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
794 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
795 "file", "kallsyms pathname"),
794 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 796 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
795 "load module symbols - WARNING: use only with -k and LIVE kernel"), 797 "load module symbols - WARNING: use only with -k and LIVE kernel"),
796 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 798 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 8c85aeb3327a..64d3623d45a0 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -20,6 +20,7 @@
20 20
21#include <linux/rbtree.h> 21#include <linux/rbtree.h>
22#include <linux/string.h> 22#include <linux/string.h>
23#include <locale.h>
23 24
24struct alloc_stat; 25struct alloc_stat;
25typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); 26typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
@@ -325,13 +326,13 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
325static void print_summary(void) 326static void print_summary(void)
326{ 327{
327 printf("\nSUMMARY\n=======\n"); 328 printf("\nSUMMARY\n=======\n");
328 printf("Total bytes requested: %lu\n", total_requested); 329 printf("Total bytes requested: %'lu\n", total_requested);
329 printf("Total bytes allocated: %lu\n", total_allocated); 330 printf("Total bytes allocated: %'lu\n", total_allocated);
330 printf("Total bytes wasted on internal fragmentation: %lu\n", 331 printf("Total bytes wasted on internal fragmentation: %'lu\n",
331 total_allocated - total_requested); 332 total_allocated - total_requested);
332 printf("Internal fragmentation: %f%%\n", 333 printf("Internal fragmentation: %f%%\n",
333 fragmentation(total_requested, total_allocated)); 334 fragmentation(total_requested, total_allocated));
334 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs); 335 printf("Cross CPU allocations: %'lu/%'lu\n", nr_cross_allocs, nr_allocs);
335} 336}
336 337
337static void print_result(struct perf_session *session) 338static void print_result(struct perf_session *session)
@@ -706,6 +707,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
706 symbol__init(&session->header.env); 707 symbol__init(&session->header.env);
707 708
708 if (!strcmp(argv[0], "stat")) { 709 if (!strcmp(argv[0], "stat")) {
710 setlocale(LC_ALL, "");
711
709 if (cpu__setup_cpunode_map()) 712 if (cpu__setup_cpunode_map())
710 goto out_delete; 713 goto out_delete;
711 714
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 0ae482689e3c..b5b2ad4ca9c4 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -304,7 +304,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
304 304
305 if (rep->mem_mode) { 305 if (rep->mem_mode) {
306 ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events); 306 ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
307 ret += fprintf(fp, "\n# Sort order : %s", sort_order); 307 ret += fprintf(fp, "\n# Sort order : %s", sort_order ? : default_mem_sort_order);
308 } else 308 } else
309 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); 309 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
310 return ret + fprintf(fp, "\n#\n"); 310 return ret + fprintf(fp, "\n#\n");
@@ -669,6 +669,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
669 "only consider symbols in these dsos"), 669 "only consider symbols in these dsos"),
670 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 670 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
671 "only consider symbols in these comms"), 671 "only consider symbols in these comms"),
672 OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
673 "only consider symbols in these pids"),
674 OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
675 "only consider symbols in these tids"),
672 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 676 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
673 "only consider these symbols"), 677 "only consider these symbols"),
674 OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter", 678 OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index f2a348b57b8f..662366ceb572 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1562,6 +1562,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1562 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 1562 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1563 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 1563 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1564 "only display events for these comms"), 1564 "only display events for these comms"),
1565 OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
1566 "only consider symbols in these pids"),
1567 OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
1568 "only consider symbols in these tids"),
1565 OPT_BOOLEAN('I', "show-info", &show_full_info, 1569 OPT_BOOLEAN('I', "show-info", &show_full_info,
1566 "display extended information from perf.data file"), 1570 "display extended information from perf.data file"),
1567 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, 1571 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5fb8723c7128..1cb3436276d1 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -757,8 +757,10 @@ static void perf_event__process_sample(struct perf_tool *tool,
757 al.map == machine->vmlinux_maps[MAP__FUNCTION] && 757 al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
758 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 758 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
759 if (symbol_conf.vmlinux_name) { 759 if (symbol_conf.vmlinux_name) {
760 ui__warning("The %s file can't be used.\n%s", 760 char serr[256];
761 symbol_conf.vmlinux_name, msg); 761 dso__strerror_load(al.map->dso, serr, sizeof(serr));
762 ui__warning("The %s file can't be used: %s\n%s",
763 symbol_conf.vmlinux_name, serr, msg);
762 } else { 764 } else {
763 ui__warning("A vmlinux file was not found.\n%s", 765 ui__warning("A vmlinux file was not found.\n%s",
764 msg); 766 msg);
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 61bf9128e1f2..b72086eca943 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1008,6 +1008,32 @@ fallback:
1008 } 1008 }
1009 filename = symfs_filename; 1009 filename = symfs_filename;
1010 } 1010 }
1011 } else if (dso__needs_decompress(dso)) {
1012 char tmp[PATH_MAX];
1013 struct kmod_path m;
1014 int fd;
1015 bool ret;
1016
1017 if (kmod_path__parse_ext(&m, symfs_filename))
1018 goto out_free_filename;
1019
1020 snprintf(tmp, PATH_MAX, "/tmp/perf-kmod-XXXXXX");
1021
1022 fd = mkstemp(tmp);
1023 if (fd < 0) {
1024 free(m.ext);
1025 goto out_free_filename;
1026 }
1027
1028 ret = decompress_to_file(m.ext, symfs_filename, fd);
1029
1030 free(m.ext);
1031 close(fd);
1032
1033 if (!ret)
1034 goto out_free_filename;
1035
1036 strcpy(symfs_filename, tmp);
1011 } 1037 }
1012 1038
1013 snprintf(command, sizeof(command), 1039 snprintf(command, sizeof(command),
@@ -1027,7 +1053,7 @@ fallback:
1027 1053
1028 file = popen(command, "r"); 1054 file = popen(command, "r");
1029 if (!file) 1055 if (!file)
1030 goto out_free_filename; 1056 goto out_remove_tmp;
1031 1057
1032 while (!feof(file)) 1058 while (!feof(file))
1033 if (symbol__parse_objdump_line(sym, map, file, privsize, 1059 if (symbol__parse_objdump_line(sym, map, file, privsize,
@@ -1042,6 +1068,10 @@ fallback:
1042 delete_last_nop(sym); 1068 delete_last_nop(sym);
1043 1069
1044 pclose(file); 1070 pclose(file);
1071
1072out_remove_tmp:
1073 if (dso__needs_decompress(dso))
1074 unlink(symfs_filename);
1045out_free_filename: 1075out_free_filename:
1046 if (delete_extract) 1076 if (delete_extract)
1047 kcore_extract__delete(&kce); 1077 kcore_extract__delete(&kce);
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c
index 6da965bdbc2c..85b523885f9d 100644
--- a/tools/perf/util/cloexec.c
+++ b/tools/perf/util/cloexec.c
@@ -7,6 +7,12 @@
7 7
8static unsigned long flag = PERF_FLAG_FD_CLOEXEC; 8static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
9 9
10int __weak sched_getcpu(void)
11{
12 errno = ENOSYS;
13 return -1;
14}
15
10static int perf_flag_probe(void) 16static int perf_flag_probe(void)
11{ 17{
12 /* use 'safest' configuration as used in perf_evsel__fallback() */ 18 /* use 'safest' configuration as used in perf_evsel__fallback() */
diff --git a/tools/perf/util/cloexec.h b/tools/perf/util/cloexec.h
index 94a5a7d829d5..68888c29b04a 100644
--- a/tools/perf/util/cloexec.h
+++ b/tools/perf/util/cloexec.h
@@ -3,4 +3,10 @@
3 3
4unsigned long perf_event_open_cloexec_flag(void); 4unsigned long perf_event_open_cloexec_flag(void);
5 5
6#ifdef __GLIBC_PREREQ
7#if !__GLIBC_PREREQ(2, 6)
8extern int sched_getcpu(void) __THROW;
9#endif
10#endif
11
6#endif /* __PERF_CLOEXEC_H */ 12#endif /* __PERF_CLOEXEC_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 7a7c54b42b41..fc0ddd5792a9 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -165,32 +165,14 @@ bool is_supported_compression(const char *ext)
165 return false; 165 return false;
166} 166}
167 167
168bool is_kmodule_extension(const char *ext) 168bool is_kernel_module(const char *pathname)
169{ 169{
170 if (strncmp(ext, "ko", 2)) 170 struct kmod_path m;
171 return false;
172 171
173 if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3))) 172 if (kmod_path__parse(&m, pathname))
174 return true; 173 return NULL;
175
176 return false;
177}
178
179bool is_kernel_module(const char *pathname, bool *compressed)
180{
181 const char *ext = strrchr(pathname, '.');
182
183 if (ext == NULL)
184 return false;
185
186 if (is_supported_compression(ext + 1)) {
187 if (compressed)
188 *compressed = true;
189 ext -= 3;
190 } else if (compressed)
191 *compressed = false;
192 174
193 return is_kmodule_extension(ext + 1); 175 return m.kmod;
194} 176}
195 177
196bool decompress_to_file(const char *ext, const char *filename, int output_fd) 178bool decompress_to_file(const char *ext, const char *filename, int output_fd)
@@ -1155,3 +1137,36 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine)
1155 1137
1156 return dso__type_fd(fd); 1138 return dso__type_fd(fd);
1157} 1139}
1140
1141int dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
1142{
1143 int idx, errnum = dso->load_errno;
1144 /*
1145 * This must have a same ordering as the enum dso_load_errno.
1146 */
1147 static const char *dso_load__error_str[] = {
1148 "Internal tools/perf/ library error",
1149 "Invalid ELF file",
1150 "Can not read build id",
1151 "Mismatching build id",
1152 "Decompression failure",
1153 };
1154
1155 BUG_ON(buflen == 0);
1156
1157 if (errnum >= 0) {
1158 const char *err = strerror_r(errnum, buf, buflen);
1159
1160 if (err != buf)
1161 scnprintf(buf, buflen, "%s", err);
1162
1163 return 0;
1164 }
1165
1166 if (errnum < __DSO_LOAD_ERRNO__START || errnum >= __DSO_LOAD_ERRNO__END)
1167 return -1;
1168
1169 idx = errnum - __DSO_LOAD_ERRNO__START;
1170 scnprintf(buf, buflen, "%s", dso_load__error_str[idx]);
1171 return 0;
1172}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 3c81d8378bc7..e0901b4ed8de 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -60,6 +60,31 @@ enum dso_type {
60 DSO__TYPE_X32BIT, 60 DSO__TYPE_X32BIT,
61}; 61};
62 62
63enum dso_load_errno {
64 DSO_LOAD_ERRNO__SUCCESS = 0,
65
66 /*
67 * Choose an arbitrary negative big number not to clash with standard
68 * errno since SUS requires the errno has distinct positive values.
69 * See 'Issue 6' in the link below.
70 *
71 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
72 */
73 __DSO_LOAD_ERRNO__START = -10000,
74
75 DSO_LOAD_ERRNO__INTERNAL_ERROR = __DSO_LOAD_ERRNO__START,
76
77 /* for symsrc__init() */
78 DSO_LOAD_ERRNO__INVALID_ELF,
79 DSO_LOAD_ERRNO__CANNOT_READ_BUILDID,
80 DSO_LOAD_ERRNO__MISMATCHING_BUILDID,
81
82 /* for decompress_kmodule */
83 DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE,
84
85 __DSO_LOAD_ERRNO__END,
86};
87
63#define DSO__SWAP(dso, type, val) \ 88#define DSO__SWAP(dso, type, val) \
64({ \ 89({ \
65 type ____r = val; \ 90 type ____r = val; \
@@ -113,6 +138,7 @@ struct dso {
113 enum dso_swap_type needs_swap; 138 enum dso_swap_type needs_swap;
114 enum dso_binary_type symtab_type; 139 enum dso_binary_type symtab_type;
115 enum dso_binary_type binary_type; 140 enum dso_binary_type binary_type;
141 enum dso_load_errno load_errno;
116 u8 adjust_symbols:1; 142 u8 adjust_symbols:1;
117 u8 has_build_id:1; 143 u8 has_build_id:1;
118 u8 has_srcline:1; 144 u8 has_srcline:1;
@@ -190,8 +216,7 @@ char dso__symtab_origin(const struct dso *dso);
190int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 216int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
191 char *root_dir, char *filename, size_t size); 217 char *root_dir, char *filename, size_t size);
192bool is_supported_compression(const char *ext); 218bool is_supported_compression(const char *ext);
193bool is_kmodule_extension(const char *ext); 219bool is_kernel_module(const char *pathname);
194bool is_kernel_module(const char *pathname, bool *compressed);
195bool decompress_to_file(const char *ext, const char *filename, int output_fd); 220bool decompress_to_file(const char *ext, const char *filename, int output_fd);
196bool dso__needs_decompress(struct dso *dso); 221bool dso__needs_decompress(struct dso *dso);
197 222
@@ -295,4 +320,6 @@ void dso__free_a2l(struct dso *dso);
295 320
296enum dso_type dso__type(struct dso *dso, struct machine *machine); 321enum dso_type dso__type(struct dso *dso, struct machine *machine);
297 322
323int dso__strerror_load(struct dso *dso, char *buf, size_t buflen);
324
298#endif /* __PERF_DSO */ 325#endif /* __PERF_DSO */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1f407f7352a7..fb432153e2aa 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1266,7 +1266,7 @@ static int __event_process_build_id(struct build_id_event *bev,
1266 1266
1267 dso__set_build_id(dso, &bev->build_id); 1267 dso__set_build_id(dso, &bev->build_id);
1268 1268
1269 if (!is_kernel_module(filename, NULL)) 1269 if (!is_kernel_module(filename))
1270 dso->kernel = dso_type; 1270 dso->kernel = dso_type;
1271 1271
1272 build_id__sprintf(dso->build_id, sizeof(dso->build_id), 1272 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index eb95b883fb44..e3353307330c 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -498,6 +498,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
498 if (kmod_path__parse_name(&m, filename)) 498 if (kmod_path__parse_name(&m, filename))
499 return NULL; 499 return NULL;
500 500
501 map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
502 m.name);
503 if (map)
504 goto out;
505
501 dso = machine__module_dso(machine, &m, filename); 506 dso = machine__module_dso(machine, &m, filename);
502 if (dso == NULL) 507 if (dso == NULL)
503 goto out; 508 goto out;
@@ -851,6 +856,39 @@ static char *get_kernel_version(const char *root_dir)
851 return strdup(name); 856 return strdup(name);
852} 857}
853 858
859static bool is_kmod_dso(struct dso *dso)
860{
861 return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
862 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
863}
864
865static int map_groups__set_module_path(struct map_groups *mg, const char *path,
866 struct kmod_path *m)
867{
868 struct map *map;
869 char *long_name;
870
871 map = map_groups__find_by_name(mg, MAP__FUNCTION, m->name);
872 if (map == NULL)
873 return 0;
874
875 long_name = strdup(path);
876 if (long_name == NULL)
877 return -ENOMEM;
878
879 dso__set_long_name(map->dso, long_name, true);
880 dso__kernel_module_get_build_id(map->dso, "");
881
882 /*
883 * Full name could reveal us kmod compression, so
884 * we need to update the symtab_type if needed.
885 */
886 if (m->comp && is_kmod_dso(map->dso))
887 map->dso->symtab_type++;
888
889 return 0;
890}
891
854static int map_groups__set_modules_path_dir(struct map_groups *mg, 892static int map_groups__set_modules_path_dir(struct map_groups *mg,
855 const char *dir_name, int depth) 893 const char *dir_name, int depth)
856{ 894{
@@ -889,35 +927,19 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
889 if (ret < 0) 927 if (ret < 0)
890 goto out; 928 goto out;
891 } else { 929 } else {
892 char *dot = strrchr(dent->d_name, '.'), 930 struct kmod_path m;
893 dso_name[PATH_MAX];
894 struct map *map;
895 char *long_name;
896
897 if (dot == NULL)
898 continue;
899 931
900 /* On some system, modules are compressed like .ko.gz */ 932 ret = kmod_path__parse_name(&m, dent->d_name);
901 if (is_supported_compression(dot + 1) && 933 if (ret)
902 is_kmodule_extension(dot - 2)) 934 goto out;
903 dot -= 3;
904 935
905 snprintf(dso_name, sizeof(dso_name), "[%.*s]", 936 if (m.kmod)
906 (int)(dot - dent->d_name), dent->d_name); 937 ret = map_groups__set_module_path(mg, path, &m);
907 938
908 strxfrchar(dso_name, '-', '_'); 939 free(m.name);
909 map = map_groups__find_by_name(mg, MAP__FUNCTION,
910 dso_name);
911 if (map == NULL)
912 continue;
913 940
914 long_name = strdup(path); 941 if (ret)
915 if (long_name == NULL) {
916 ret = -1;
917 goto out; 942 goto out;
918 }
919 dso__set_long_name(map->dso, long_name, true);
920 dso__kernel_module_get_build_id(map->dso, "");
921 } 943 }
922 } 944 }
923 945
@@ -1087,7 +1109,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
1087 struct dso *dso; 1109 struct dso *dso;
1088 1110
1089 list_for_each_entry(dso, &machine->kernel_dsos.head, node) { 1111 list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
1090 if (is_kernel_module(dso->long_name, NULL)) 1112 if (is_kernel_module(dso->long_name))
1091 continue; 1113 continue;
1092 1114
1093 kernel = dso; 1115 kernel = dso;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6b95985db5b0..8feac0774c41 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -310,7 +310,10 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
310 310
311 /* Find the address of given function */ 311 /* Find the address of given function */
312 map__for_each_symbol_by_name(map, pp->function, sym) { 312 map__for_each_symbol_by_name(map, pp->function, sym) {
313 address = sym->start; 313 if (uprobes)
314 address = sym->start;
315 else
316 address = map->unmap_ip(map, sym->start);
314 break; 317 break;
315 } 318 }
316 if (!address) { 319 if (!address) {
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 22ebc46226e7..8171fed4136e 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -214,6 +214,11 @@ static void define_event_symbols(struct event_format *event,
214 define_event_symbols(event, ev_name, args->hex.field); 214 define_event_symbols(event, ev_name, args->hex.field);
215 define_event_symbols(event, ev_name, args->hex.size); 215 define_event_symbols(event, ev_name, args->hex.size);
216 break; 216 break;
217 case PRINT_INT_ARRAY:
218 define_event_symbols(event, ev_name, args->int_array.field);
219 define_event_symbols(event, ev_name, args->int_array.count);
220 define_event_symbols(event, ev_name, args->int_array.el_size);
221 break;
217 case PRINT_BSTRING: 222 case PRINT_BSTRING:
218 case PRINT_DYNAMIC_ARRAY: 223 case PRINT_DYNAMIC_ARRAY:
219 case PRINT_STRING: 224 case PRINT_STRING:
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 0c815a40a6e8..2ec5dfb5a456 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -231,6 +231,11 @@ static void define_event_symbols(struct event_format *event,
231 define_event_symbols(event, ev_name, args->hex.field); 231 define_event_symbols(event, ev_name, args->hex.field);
232 define_event_symbols(event, ev_name, args->hex.size); 232 define_event_symbols(event, ev_name, args->hex.size);
233 break; 233 break;
234 case PRINT_INT_ARRAY:
235 define_event_symbols(event, ev_name, args->int_array.field);
236 define_event_symbols(event, ev_name, args->int_array.count);
237 define_event_symbols(event, ev_name, args->int_array.el_size);
238 break;
234 case PRINT_STRING: 239 case PRINT_STRING:
235 break; 240 break;
236 case PRINT_TYPE: 241 case PRINT_TYPE:
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 9c01b83eebca..846036a921dc 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -44,6 +44,7 @@ extern struct sort_entry sort_dso_to;
44extern struct sort_entry sort_sym_from; 44extern struct sort_entry sort_sym_from;
45extern struct sort_entry sort_sym_to; 45extern struct sort_entry sort_sym_to;
46extern enum sort_type sort__first_dimension; 46extern enum sort_type sort__first_dimension;
47extern const char default_mem_sort_order[];
47 48
48struct he_stat { 49struct he_stat {
49 u64 period; 50 u64 period;
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 62742e46c010..476268c99431 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -579,32 +579,37 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
579static int decompress_kmodule(struct dso *dso, const char *name, 579static int decompress_kmodule(struct dso *dso, const char *name,
580 enum dso_binary_type type) 580 enum dso_binary_type type)
581{ 581{
582 int fd; 582 int fd = -1;
583 const char *ext = strrchr(name, '.');
584 char tmpbuf[] = "/tmp/perf-kmod-XXXXXX"; 583 char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
584 struct kmod_path m;
585 585
586 if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP && 586 if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
587 type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP && 587 type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP &&
588 type != DSO_BINARY_TYPE__BUILD_ID_CACHE) 588 type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
589 return -1; 589 return -1;
590 590
591 if (!ext || !is_supported_compression(ext + 1)) { 591 if (type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
592 ext = strrchr(dso->name, '.'); 592 name = dso->long_name;
593 if (!ext || !is_supported_compression(ext + 1))
594 return -1;
595 }
596 593
597 fd = mkstemp(tmpbuf); 594 if (kmod_path__parse_ext(&m, name) || !m.comp)
598 if (fd < 0)
599 return -1; 595 return -1;
600 596
601 if (!decompress_to_file(ext + 1, name, fd)) { 597 fd = mkstemp(tmpbuf);
598 if (fd < 0) {
599 dso->load_errno = errno;
600 goto out;
601 }
602
603 if (!decompress_to_file(m.ext, name, fd)) {
604 dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
602 close(fd); 605 close(fd);
603 fd = -1; 606 fd = -1;
604 } 607 }
605 608
606 unlink(tmpbuf); 609 unlink(tmpbuf);
607 610
611out:
612 free(m.ext);
608 return fd; 613 return fd;
609} 614}
610 615
@@ -633,37 +638,49 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
633 Elf *elf; 638 Elf *elf;
634 int fd; 639 int fd;
635 640
636 if (dso__needs_decompress(dso)) 641 if (dso__needs_decompress(dso)) {
637 fd = decompress_kmodule(dso, name, type); 642 fd = decompress_kmodule(dso, name, type);
638 else 643 if (fd < 0)
644 return -1;
645 } else {
639 fd = open(name, O_RDONLY); 646 fd = open(name, O_RDONLY);
640 647 if (fd < 0) {
641 if (fd < 0) 648 dso->load_errno = errno;
642 return -1; 649 return -1;
650 }
651 }
643 652
644 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 653 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
645 if (elf == NULL) { 654 if (elf == NULL) {
646 pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 655 pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
656 dso->load_errno = DSO_LOAD_ERRNO__INVALID_ELF;
647 goto out_close; 657 goto out_close;
648 } 658 }
649 659
650 if (gelf_getehdr(elf, &ehdr) == NULL) { 660 if (gelf_getehdr(elf, &ehdr) == NULL) {
661 dso->load_errno = DSO_LOAD_ERRNO__INVALID_ELF;
651 pr_debug("%s: cannot get elf header.\n", __func__); 662 pr_debug("%s: cannot get elf header.\n", __func__);
652 goto out_elf_end; 663 goto out_elf_end;
653 } 664 }
654 665
655 if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) 666 if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) {
667 dso->load_errno = DSO_LOAD_ERRNO__INTERNAL_ERROR;
656 goto out_elf_end; 668 goto out_elf_end;
669 }
657 670
658 /* Always reject images with a mismatched build-id: */ 671 /* Always reject images with a mismatched build-id: */
659 if (dso->has_build_id) { 672 if (dso->has_build_id) {
660 u8 build_id[BUILD_ID_SIZE]; 673 u8 build_id[BUILD_ID_SIZE];
661 674
662 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) 675 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) {
676 dso->load_errno = DSO_LOAD_ERRNO__CANNOT_READ_BUILDID;
663 goto out_elf_end; 677 goto out_elf_end;
678 }
664 679
665 if (!dso__build_id_equal(dso, build_id)) 680 if (!dso__build_id_equal(dso, build_id)) {
681 dso->load_errno = DSO_LOAD_ERRNO__MISMATCHING_BUILDID;
666 goto out_elf_end; 682 goto out_elf_end;
683 }
667 } 684 }
668 685
669 ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64); 686 ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
@@ -699,8 +716,10 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
699 } 716 }
700 717
701 ss->name = strdup(name); 718 ss->name = strdup(name);
702 if (!ss->name) 719 if (!ss->name) {
720 dso->load_errno = errno;
703 goto out_elf_end; 721 goto out_elf_end;
722 }
704 723
705 ss->elf = elf; 724 ss->elf = elf;
706 ss->fd = fd; 725 ss->fd = fd;
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index d7efb03b3f9a..fd8477cacf88 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -246,13 +246,12 @@ out:
246 return ret; 246 return ret;
247} 247}
248 248
249int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused, 249int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
250 const char *name,
251 enum dso_binary_type type) 250 enum dso_binary_type type)
252{ 251{
253 int fd = open(name, O_RDONLY); 252 int fd = open(name, O_RDONLY);
254 if (fd < 0) 253 if (fd < 0)
255 return -1; 254 goto out_errno;
256 255
257 ss->name = strdup(name); 256 ss->name = strdup(name);
258 if (!ss->name) 257 if (!ss->name)
@@ -264,6 +263,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
264 return 0; 263 return 0;
265out_close: 264out_close:
266 close(fd); 265 close(fd);
266out_errno:
267 dso->load_errno = errno;
267 return -1; 268 return -1;
268} 269}
269 270
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index a69066865a55..fddeb9073039 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -15,6 +15,7 @@
15#include "machine.h" 15#include "machine.h"
16#include "symbol.h" 16#include "symbol.h"
17#include "strlist.h" 17#include "strlist.h"
18#include "intlist.h"
18#include "header.h" 19#include "header.h"
19 20
20#include <elf.h> 21#include <elf.h>
@@ -1859,6 +1860,20 @@ int setup_list(struct strlist **list, const char *list_str,
1859 return 0; 1860 return 0;
1860} 1861}
1861 1862
1863int setup_intlist(struct intlist **list, const char *list_str,
1864 const char *list_name)
1865{
1866 if (list_str == NULL)
1867 return 0;
1868
1869 *list = intlist__new(list_str);
1870 if (!*list) {
1871 pr_err("problems parsing %s list\n", list_name);
1872 return -1;
1873 }
1874 return 0;
1875}
1876
1862static bool symbol__read_kptr_restrict(void) 1877static bool symbol__read_kptr_restrict(void)
1863{ 1878{
1864 bool value = false; 1879 bool value = false;
@@ -1909,9 +1924,17 @@ int symbol__init(struct perf_session_env *env)
1909 symbol_conf.comm_list_str, "comm") < 0) 1924 symbol_conf.comm_list_str, "comm") < 0)
1910 goto out_free_dso_list; 1925 goto out_free_dso_list;
1911 1926
1927 if (setup_intlist(&symbol_conf.pid_list,
1928 symbol_conf.pid_list_str, "pid") < 0)
1929 goto out_free_comm_list;
1930
1931 if (setup_intlist(&symbol_conf.tid_list,
1932 symbol_conf.tid_list_str, "tid") < 0)
1933 goto out_free_pid_list;
1934
1912 if (setup_list(&symbol_conf.sym_list, 1935 if (setup_list(&symbol_conf.sym_list,
1913 symbol_conf.sym_list_str, "symbol") < 0) 1936 symbol_conf.sym_list_str, "symbol") < 0)
1914 goto out_free_comm_list; 1937 goto out_free_tid_list;
1915 1938
1916 /* 1939 /*
1917 * A path to symbols of "/" is identical to "" 1940 * A path to symbols of "/" is identical to ""
@@ -1930,6 +1953,10 @@ int symbol__init(struct perf_session_env *env)
1930 symbol_conf.initialized = true; 1953 symbol_conf.initialized = true;
1931 return 0; 1954 return 0;
1932 1955
1956out_free_tid_list:
1957 intlist__delete(symbol_conf.tid_list);
1958out_free_pid_list:
1959 intlist__delete(symbol_conf.pid_list);
1933out_free_comm_list: 1960out_free_comm_list:
1934 strlist__delete(symbol_conf.comm_list); 1961 strlist__delete(symbol_conf.comm_list);
1935out_free_dso_list: 1962out_free_dso_list:
@@ -1944,6 +1971,8 @@ void symbol__exit(void)
1944 strlist__delete(symbol_conf.sym_list); 1971 strlist__delete(symbol_conf.sym_list);
1945 strlist__delete(symbol_conf.dso_list); 1972 strlist__delete(symbol_conf.dso_list);
1946 strlist__delete(symbol_conf.comm_list); 1973 strlist__delete(symbol_conf.comm_list);
1974 intlist__delete(symbol_conf.tid_list);
1975 intlist__delete(symbol_conf.pid_list);
1947 vmlinux_path__exit(); 1976 vmlinux_path__exit();
1948 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 1977 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
1949 symbol_conf.initialized = false; 1978 symbol_conf.initialized = false;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index efdaaa544041..09561500164a 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -78,6 +78,7 @@ static inline size_t symbol__size(const struct symbol *sym)
78} 78}
79 79
80struct strlist; 80struct strlist;
81struct intlist;
81 82
82struct symbol_conf { 83struct symbol_conf {
83 unsigned short priv_size; 84 unsigned short priv_size;
@@ -115,6 +116,8 @@ struct symbol_conf {
115 const char *guestmount; 116 const char *guestmount;
116 const char *dso_list_str, 117 const char *dso_list_str,
117 *comm_list_str, 118 *comm_list_str,
119 *pid_list_str,
120 *tid_list_str,
118 *sym_list_str, 121 *sym_list_str,
119 *col_width_list_str; 122 *col_width_list_str;
120 struct strlist *dso_list, 123 struct strlist *dso_list,
@@ -124,6 +127,8 @@ struct symbol_conf {
124 *dso_to_list, 127 *dso_to_list,
125 *sym_from_list, 128 *sym_from_list,
126 *sym_to_list; 129 *sym_to_list;
130 struct intlist *pid_list,
131 *tid_list;
127 const char *symfs; 132 const char *symfs;
128}; 133};
129 134
@@ -295,5 +300,7 @@ int compare_proc_modules(const char *from, const char *to);
295 300
296int setup_list(struct strlist **list, const char *list_str, 301int setup_list(struct strlist **list, const char *list_str,
297 const char *list_name); 302 const char *list_name);
303int setup_intlist(struct intlist **list, const char *list_str,
304 const char *list_name);
298 305
299#endif /* __PERF_SYMBOL */ 306#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
index e74c5963dc7a..a53603b27e52 100644
--- a/tools/perf/util/target.c
+++ b/tools/perf/util/target.c
@@ -123,11 +123,8 @@ int target__strerror(struct target *target, int errnum,
123 if (errnum >= 0) { 123 if (errnum >= 0) {
124 const char *err = strerror_r(errnum, buf, buflen); 124 const char *err = strerror_r(errnum, buf, buflen);
125 125
126 if (err != buf) { 126 if (err != buf)
127 size_t len = strlen(err); 127 scnprintf(buf, buflen, "%s", err);
128 memcpy(buf, err, min(buflen - 1, len));
129 *(buf + min(buflen - 1, len)) = '\0';
130 }
131 128
132 return 0; 129 return 0;
133 } 130 }
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 783b6688d2f7..9b8a54dc34a8 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -7,6 +7,7 @@
7#include <sys/types.h> 7#include <sys/types.h>
8#include "symbol.h" 8#include "symbol.h"
9#include <strlist.h> 9#include <strlist.h>
10#include <intlist.h>
10 11
11struct thread_stack; 12struct thread_stack;
12 13
@@ -100,6 +101,16 @@ static inline bool thread__is_filtered(struct thread *thread)
100 return true; 101 return true;
101 } 102 }
102 103
104 if (symbol_conf.pid_list &&
105 !intlist__has_entry(symbol_conf.pid_list, thread->pid_)) {
106 return true;
107 }
108
109 if (symbol_conf.tid_list &&
110 !intlist__has_entry(symbol_conf.tid_list, thread->tid)) {
111 return true;
112 }
113
103 return false; 114 return false;
104} 115}
105 116