diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-03-24 12:22:44 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-03-24 12:22:44 -0400 |
commit | baa5a7bc5dd069bb37de9c8bdb5ea7f4e2e939e9 (patch) | |
tree | 50864d78ede1a333b0b6fb8fe09486ed3f3ad1c2 /tools | |
parent | 963a70b8a2d65538f7d58b2b84a2ae10a3ecb6ea (diff) | |
parent | e03eaa400cf8b8bded86cc5c41018a1c69152f16 (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')
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 | ||
321 | void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock) | 324 | int 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 | ||
326 | struct func_map { | 334 | struct 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 | ||
2030 | static 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 | |||
2056 | out_free_token: | ||
2057 | free_token(token); | ||
2058 | |||
2059 | return ret; | ||
2060 | } | ||
2061 | |||
2017 | static char *arg_eval (struct print_arg *arg); | 2062 | static char *arg_eval (struct print_arg *arg); |
2018 | 2063 | ||
2019 | static unsigned long long | 2064 | static unsigned long long |
@@ -2486,49 +2531,46 @@ out_free: | |||
2486 | static enum event_type | 2531 | static enum event_type |
2487 | process_hex(struct event_format *event, struct print_arg *arg, char **tok) | 2532 | process_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); | 2545 | free_field: |
2546 | free_arg(arg->hex.field); | ||
2547 | out: | ||
2548 | *tok = NULL; | ||
2549 | return EVENT_ERROR; | ||
2550 | } | ||
2510 | 2551 | ||
2511 | field = alloc_arg(); | 2552 | static enum event_type |
2512 | if (!field) { | 2553 | process_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: | 2569 | free_size: |
2530 | free_arg(field); | 2570 | free_arg(arg->int_array.count); |
2531 | free_token(token); | 2571 | free_field: |
2572 | free_arg(arg->int_array.field); | ||
2573 | out: | ||
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 | ||
5041 | static struct cmdline * | ||
5042 | pid_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 | */ | ||
5070 | struct 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 | */ | ||
5112 | int 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 | ||
254 | struct print_arg_int_array { | ||
255 | struct print_arg *field; | ||
256 | struct print_arg *count; | ||
257 | struct print_arg *el_size; | ||
258 | }; | ||
259 | |||
250 | struct print_arg_dynarray { | 260 | struct 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 | ||
601 | int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); | 613 | int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); |
602 | void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock); | 614 | int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock); |
603 | int pevent_register_function(struct pevent *pevent, char *name, | 615 | int pevent_register_function(struct pevent *pevent, char *name, |
604 | unsigned long long addr, char *mod); | 616 | unsigned long long addr, char *mod); |
605 | int pevent_register_print_string(struct pevent *pevent, const char *fmt, | 617 | int 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); | |||
678 | struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type); | 690 | struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type); |
679 | int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec); | 691 | int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec); |
680 | const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid); | 692 | const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid); |
693 | struct cmdline; | ||
694 | struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm, | ||
695 | struct cmdline *next); | ||
696 | int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline); | ||
697 | |||
681 | void pevent_event_info(struct trace_seq *s, struct event_format *event, | 698 | void pevent_event_info(struct trace_seq *s, struct event_format *event, |
682 | struct pevent_record *record); | 699 | struct pevent_record *record); |
683 | int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, | 700 | int 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 | ||
53 | static void lower_case(char *str) | ||
54 | { | ||
55 | if (!str) | ||
56 | return; | ||
57 | for (; *str; str++) | ||
58 | *str = tolower(*str); | ||
59 | } | ||
60 | |||
61 | static 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 | */ | ||
739 | int 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); | |||
63 | int kbuffer_subbuffer_size(struct kbuffer *kbuf); | 63 | int kbuffer_subbuffer_size(struct kbuffer *kbuf); |
64 | 64 | ||
65 | void kbuffer_set_old_format(struct kbuffer *kbuf); | 65 | void kbuffer_set_old_format(struct kbuffer *kbuf); |
66 | int 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 | ||
24 | struct alloc_stat; | 25 | struct alloc_stat; |
25 | typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); | 26 | typedef 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, | |||
325 | static void print_summary(void) | 326 | static 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 | ||
337 | static void print_result(struct perf_session *session) | 338 | static 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 | |||
1072 | out_remove_tmp: | ||
1073 | if (dso__needs_decompress(dso)) | ||
1074 | unlink(symfs_filename); | ||
1045 | out_free_filename: | 1075 | out_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 | ||
8 | static unsigned long flag = PERF_FLAG_FD_CLOEXEC; | 8 | static unsigned long flag = PERF_FLAG_FD_CLOEXEC; |
9 | 9 | ||
10 | int __weak sched_getcpu(void) | ||
11 | { | ||
12 | errno = ENOSYS; | ||
13 | return -1; | ||
14 | } | ||
15 | |||
10 | static int perf_flag_probe(void) | 16 | static 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 | ||
4 | unsigned long perf_event_open_cloexec_flag(void); | 4 | unsigned long perf_event_open_cloexec_flag(void); |
5 | 5 | ||
6 | #ifdef __GLIBC_PREREQ | ||
7 | #if !__GLIBC_PREREQ(2, 6) | ||
8 | extern 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 | ||
168 | bool is_kmodule_extension(const char *ext) | 168 | bool 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 | |||
179 | bool 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 | ||
196 | bool decompress_to_file(const char *ext, const char *filename, int output_fd) | 178 | bool 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 | |||
1141 | int 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 | ||
63 | enum 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); | |||
190 | int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, | 216 | int 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); |
192 | bool is_supported_compression(const char *ext); | 218 | bool is_supported_compression(const char *ext); |
193 | bool is_kmodule_extension(const char *ext); | 219 | bool is_kernel_module(const char *pathname); |
194 | bool is_kernel_module(const char *pathname, bool *compressed); | ||
195 | bool decompress_to_file(const char *ext, const char *filename, int output_fd); | 220 | bool decompress_to_file(const char *ext, const char *filename, int output_fd); |
196 | bool dso__needs_decompress(struct dso *dso); | 221 | bool dso__needs_decompress(struct dso *dso); |
197 | 222 | ||
@@ -295,4 +320,6 @@ void dso__free_a2l(struct dso *dso); | |||
295 | 320 | ||
296 | enum dso_type dso__type(struct dso *dso, struct machine *machine); | 321 | enum dso_type dso__type(struct dso *dso, struct machine *machine); |
297 | 322 | ||
323 | int 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 | ||
859 | static 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 | |||
865 | static 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 | |||
854 | static int map_groups__set_modules_path_dir(struct map_groups *mg, | 892 | static 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; | |||
44 | extern struct sort_entry sort_sym_from; | 44 | extern struct sort_entry sort_sym_from; |
45 | extern struct sort_entry sort_sym_to; | 45 | extern struct sort_entry sort_sym_to; |
46 | extern enum sort_type sort__first_dimension; | 46 | extern enum sort_type sort__first_dimension; |
47 | extern const char default_mem_sort_order[]; | ||
47 | 48 | ||
48 | struct he_stat { | 49 | struct 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) | |||
579 | static int decompress_kmodule(struct dso *dso, const char *name, | 579 | static 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 | ||
611 | out: | ||
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 | ||
249 | int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused, | 249 | int 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; |
265 | out_close: | 264 | out_close: |
266 | close(fd); | 265 | close(fd); |
266 | out_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 | ||
1863 | int 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 | |||
1862 | static bool symbol__read_kptr_restrict(void) | 1877 | static 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 | ||
1956 | out_free_tid_list: | ||
1957 | intlist__delete(symbol_conf.tid_list); | ||
1958 | out_free_pid_list: | ||
1959 | intlist__delete(symbol_conf.pid_list); | ||
1933 | out_free_comm_list: | 1960 | out_free_comm_list: |
1934 | strlist__delete(symbol_conf.comm_list); | 1961 | strlist__delete(symbol_conf.comm_list); |
1935 | out_free_dso_list: | 1962 | out_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 | ||
80 | struct strlist; | 80 | struct strlist; |
81 | struct intlist; | ||
81 | 82 | ||
82 | struct symbol_conf { | 83 | struct 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 | ||
296 | int setup_list(struct strlist **list, const char *list_str, | 301 | int setup_list(struct strlist **list, const char *list_str, |
297 | const char *list_name); | 302 | const char *list_name); |
303 | int 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 | ||
11 | struct thread_stack; | 12 | struct 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 | ||