diff options
author | Ingo Molnar <mingo@kernel.org> | 2013-12-16 08:52:03 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-12-16 08:52:03 -0500 |
commit | b283d2f3b74bc98174e8453c0be41dfcda3cae1b (patch) | |
tree | e9af6975920c4bf2eb4b8cdb35f88726f3db1e77 | |
parent | fe361cfcf40ad4612226347573a8669cd0d44799 (diff) | |
parent | 41e12e580a7b0c151199f927193548b84d3e874c (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:
Fixes:
* Fix inverted error verification bug in thread__fork, from David Ahern.
New features:
* Shell completion for 'perf kvm', from Ramkumar Ramachandra.
Refactorings:
* Get rid of panic() like calls in libtraceevent, from Namyung Kim.
* Start carving out symbol parsing routines from perf, just moving routines to
topic files in tools/lib/symbol/, tools that want to use it need to integrate
it directly, i.e. no tools/lib/symbol/Makefile is provided.
* Assorted refactoring patches, moving code around and adding
utility evlist methods that will be used in the IPT patchset,
from Adrian Hunter.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/lib/symbol/kallsyms.c | 58 | ||||
-rw-r--r-- | tools/lib/symbol/kallsyms.h | 24 | ||||
-rw-r--r-- | tools/lib/traceevent/event-parse.h | 43 | ||||
-rw-r--r-- | tools/lib/traceevent/parse-filter.c | 507 | ||||
-rw-r--r-- | tools/perf/MANIFEST | 2 | ||||
-rw-r--r-- | tools/perf/Makefile.perf | 5 | ||||
-rw-r--r-- | tools/perf/perf-completion.sh | 4 | ||||
-rw-r--r-- | tools/perf/util/event.c | 1 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 20 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 5 | ||||
-rw-r--r-- | tools/perf/util/header.c | 3 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 1 | ||||
-rw-r--r-- | tools/perf/util/record.c | 37 | ||||
-rw-r--r-- | tools/perf/util/session.c | 21 | ||||
-rw-r--r-- | tools/perf/util/session.h | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 1 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 69 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 3 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 2 | ||||
-rw-r--r-- | tools/perf/util/util.c | 41 | ||||
-rw-r--r-- | tools/perf/util/util.h | 4 |
21 files changed, 550 insertions, 303 deletions
diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c new file mode 100644 index 000000000000..18bc271a4bbc --- /dev/null +++ b/tools/lib/symbol/kallsyms.c | |||
@@ -0,0 +1,58 @@ | |||
1 | #include "symbol/kallsyms.h" | ||
2 | #include <stdio.h> | ||
3 | #include <stdlib.h> | ||
4 | |||
5 | int kallsyms__parse(const char *filename, void *arg, | ||
6 | int (*process_symbol)(void *arg, const char *name, | ||
7 | char type, u64 start)) | ||
8 | { | ||
9 | char *line = NULL; | ||
10 | size_t n; | ||
11 | int err = -1; | ||
12 | FILE *file = fopen(filename, "r"); | ||
13 | |||
14 | if (file == NULL) | ||
15 | goto out_failure; | ||
16 | |||
17 | err = 0; | ||
18 | |||
19 | while (!feof(file)) { | ||
20 | u64 start; | ||
21 | int line_len, len; | ||
22 | char symbol_type; | ||
23 | char *symbol_name; | ||
24 | |||
25 | line_len = getline(&line, &n, file); | ||
26 | if (line_len < 0 || !line) | ||
27 | break; | ||
28 | |||
29 | line[--line_len] = '\0'; /* \n */ | ||
30 | |||
31 | len = hex2u64(line, &start); | ||
32 | |||
33 | len++; | ||
34 | if (len + 2 >= line_len) | ||
35 | continue; | ||
36 | |||
37 | symbol_type = line[len]; | ||
38 | len += 2; | ||
39 | symbol_name = line + len; | ||
40 | len = line_len - len; | ||
41 | |||
42 | if (len >= KSYM_NAME_LEN) { | ||
43 | err = -1; | ||
44 | break; | ||
45 | } | ||
46 | |||
47 | err = process_symbol(arg, symbol_name, symbol_type, start); | ||
48 | if (err) | ||
49 | break; | ||
50 | } | ||
51 | |||
52 | free(line); | ||
53 | fclose(file); | ||
54 | return err; | ||
55 | |||
56 | out_failure: | ||
57 | return -1; | ||
58 | } | ||
diff --git a/tools/lib/symbol/kallsyms.h b/tools/lib/symbol/kallsyms.h new file mode 100644 index 000000000000..6084f5e18b3c --- /dev/null +++ b/tools/lib/symbol/kallsyms.h | |||
@@ -0,0 +1,24 @@ | |||
1 | #ifndef __TOOLS_KALLSYMS_H_ | ||
2 | #define __TOOLS_KALLSYMS_H_ 1 | ||
3 | |||
4 | #include <elf.h> | ||
5 | #include <linux/ctype.h> | ||
6 | #include <linux/types.h> | ||
7 | |||
8 | #ifndef KSYM_NAME_LEN | ||
9 | #define KSYM_NAME_LEN 256 | ||
10 | #endif | ||
11 | |||
12 | static inline u8 kallsyms2elf_type(char type) | ||
13 | { | ||
14 | if (type == 'W') | ||
15 | return STB_WEAK; | ||
16 | |||
17 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | ||
18 | } | ||
19 | |||
20 | int kallsyms__parse(const char *filename, void *arg, | ||
21 | int (*process_symbol)(void *arg, const char *name, | ||
22 | char type, u64 start)); | ||
23 | |||
24 | #endif /* __TOOLS_KALLSYMS_H_ */ | ||
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 6e23f197175f..3ad784f5f647 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -356,12 +356,35 @@ enum pevent_flag { | |||
356 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ | 356 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ |
357 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ | 357 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ |
358 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ | 358 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ |
359 | _PE(INVALID_ARG_TYPE, "invalid argument type") | 359 | _PE(INVALID_ARG_TYPE, "invalid argument type"), \ |
360 | _PE(INVALID_EXP_TYPE, "invalid expression type"), \ | ||
361 | _PE(INVALID_OP_TYPE, "invalid operator type"), \ | ||
362 | _PE(INVALID_EVENT_NAME, "invalid event name"), \ | ||
363 | _PE(EVENT_NOT_FOUND, "no event found"), \ | ||
364 | _PE(SYNTAX_ERROR, "syntax error"), \ | ||
365 | _PE(ILLEGAL_RVALUE, "illegal rvalue"), \ | ||
366 | _PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \ | ||
367 | _PE(INVALID_REGEX, "regex did not compute"), \ | ||
368 | _PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \ | ||
369 | _PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \ | ||
370 | _PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \ | ||
371 | _PE(REPARENT_FAILED, "failed to reparent filter OP"), \ | ||
372 | _PE(BAD_FILTER_ARG, "bad arg in filter tree"), \ | ||
373 | _PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \ | ||
374 | _PE(ILLEGAL_TOKEN, "illegal token"), \ | ||
375 | _PE(INVALID_PAREN, "open parenthesis cannot come here"), \ | ||
376 | _PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \ | ||
377 | _PE(UNKNOWN_TOKEN, "unknown token"), \ | ||
378 | _PE(FILTER_NOT_FOUND, "no filter found"), \ | ||
379 | _PE(NOT_A_NUMBER, "must have number field"), \ | ||
380 | _PE(NO_FILTER, "no filters exists"), \ | ||
381 | _PE(FILTER_MISS, "record does not match to filter") | ||
360 | 382 | ||
361 | #undef _PE | 383 | #undef _PE |
362 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code | 384 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code |
363 | enum pevent_errno { | 385 | enum pevent_errno { |
364 | PEVENT_ERRNO__SUCCESS = 0, | 386 | PEVENT_ERRNO__SUCCESS = 0, |
387 | PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS, | ||
365 | 388 | ||
366 | /* | 389 | /* |
367 | * Choose an arbitrary negative big number not to clash with standard | 390 | * Choose an arbitrary negative big number not to clash with standard |
@@ -836,10 +859,11 @@ struct event_filter { | |||
836 | 859 | ||
837 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); | 860 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); |
838 | 861 | ||
839 | #define FILTER_NONE -2 | 862 | /* for backward compatibility */ |
840 | #define FILTER_NOEXIST -1 | 863 | #define FILTER_NONE PEVENT_ERRNO__FILTER_NOT_FOUND |
841 | #define FILTER_MISS 0 | 864 | #define FILTER_NOEXIST PEVENT_ERRNO__NO_FILTER |
842 | #define FILTER_MATCH 1 | 865 | #define FILTER_MISS PEVENT_ERRNO__FILTER_MISS |
866 | #define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH | ||
843 | 867 | ||
844 | enum filter_trivial_type { | 868 | enum filter_trivial_type { |
845 | FILTER_TRIVIAL_FALSE, | 869 | FILTER_TRIVIAL_FALSE, |
@@ -847,13 +871,12 @@ enum filter_trivial_type { | |||
847 | FILTER_TRIVIAL_BOTH, | 871 | FILTER_TRIVIAL_BOTH, |
848 | }; | 872 | }; |
849 | 873 | ||
850 | int pevent_filter_add_filter_str(struct event_filter *filter, | 874 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
851 | const char *filter_str, | 875 | const char *filter_str); |
852 | char **error_str); | ||
853 | 876 | ||
854 | 877 | ||
855 | int pevent_filter_match(struct event_filter *filter, | 878 | enum pevent_errno pevent_filter_match(struct event_filter *filter, |
856 | struct pevent_record *record); | 879 | struct pevent_record *record); |
857 | 880 | ||
858 | int pevent_event_filtered(struct event_filter *filter, | 881 | int pevent_event_filtered(struct event_filter *filter, |
859 | int event_id); | 882 | int event_id); |
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index ab402fb2dcf7..9303c55128db 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -56,7 +56,21 @@ static void show_error(char **error_str, const char *fmt, ...) | |||
56 | index = pevent_get_input_buf_ptr(); | 56 | index = pevent_get_input_buf_ptr(); |
57 | len = input ? strlen(input) : 0; | 57 | len = input ? strlen(input) : 0; |
58 | 58 | ||
59 | error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3); | 59 | error = malloc(MAX_ERR_STR_SIZE + (len*2) + 3); |
60 | if (error == NULL) { | ||
61 | /* | ||
62 | * Maybe it's due to len is too long. | ||
63 | * Retry without the input buffer part. | ||
64 | */ | ||
65 | len = 0; | ||
66 | |||
67 | error = malloc(MAX_ERR_STR_SIZE); | ||
68 | if (error == NULL) { | ||
69 | /* no memory */ | ||
70 | *error_str = NULL; | ||
71 | return; | ||
72 | } | ||
73 | } | ||
60 | 74 | ||
61 | if (len) { | 75 | if (len) { |
62 | strcpy(error, input); | 76 | strcpy(error, input); |
@@ -95,7 +109,11 @@ static enum event_type read_token(char **tok) | |||
95 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && | 109 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && |
96 | pevent_peek_char() == '~') { | 110 | pevent_peek_char() == '~') { |
97 | /* append it */ | 111 | /* append it */ |
98 | *tok = malloc_or_die(3); | 112 | *tok = malloc(3); |
113 | if (*tok == NULL) { | ||
114 | free_token(token); | ||
115 | return EVENT_ERROR; | ||
116 | } | ||
99 | sprintf(*tok, "%c%c", *token, '~'); | 117 | sprintf(*tok, "%c%c", *token, '~'); |
100 | free_token(token); | 118 | free_token(token); |
101 | /* Now remove the '~' from the buffer */ | 119 | /* Now remove the '~' from the buffer */ |
@@ -147,11 +165,13 @@ add_filter_type(struct event_filter *filter, int id) | |||
147 | if (filter_type) | 165 | if (filter_type) |
148 | return filter_type; | 166 | return filter_type; |
149 | 167 | ||
150 | filter->event_filters = realloc(filter->event_filters, | 168 | filter_type = realloc(filter->event_filters, |
151 | sizeof(*filter->event_filters) * | 169 | sizeof(*filter->event_filters) * |
152 | (filter->filters + 1)); | 170 | (filter->filters + 1)); |
153 | if (!filter->event_filters) | 171 | if (!filter_type) |
154 | die("Could not allocate filter"); | 172 | return NULL; |
173 | |||
174 | filter->event_filters = filter_type; | ||
155 | 175 | ||
156 | for (i = 0; i < filter->filters; i++) { | 176 | for (i = 0; i < filter->filters; i++) { |
157 | if (filter->event_filters[i].event_id > id) | 177 | if (filter->event_filters[i].event_id > id) |
@@ -195,12 +215,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) | |||
195 | 215 | ||
196 | static struct filter_arg *allocate_arg(void) | 216 | static struct filter_arg *allocate_arg(void) |
197 | { | 217 | { |
198 | struct filter_arg *arg; | 218 | return calloc(1, sizeof(struct filter_arg)); |
199 | |||
200 | arg = malloc_or_die(sizeof(*arg)); | ||
201 | memset(arg, 0, sizeof(*arg)); | ||
202 | |||
203 | return arg; | ||
204 | } | 219 | } |
205 | 220 | ||
206 | static void free_arg(struct filter_arg *arg) | 221 | static void free_arg(struct filter_arg *arg) |
@@ -272,7 +287,7 @@ static int event_match(struct event_format *event, | |||
272 | !regexec(ereg, event->name, 0, NULL, 0); | 287 | !regexec(ereg, event->name, 0, NULL, 0); |
273 | } | 288 | } |
274 | 289 | ||
275 | static int | 290 | static enum pevent_errno |
276 | find_event(struct pevent *pevent, struct event_list **events, | 291 | find_event(struct pevent *pevent, struct event_list **events, |
277 | char *sys_name, char *event_name) | 292 | char *sys_name, char *event_name) |
278 | { | 293 | { |
@@ -291,23 +306,31 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
291 | sys_name = NULL; | 306 | sys_name = NULL; |
292 | } | 307 | } |
293 | 308 | ||
294 | reg = malloc_or_die(strlen(event_name) + 3); | 309 | reg = malloc(strlen(event_name) + 3); |
310 | if (reg == NULL) | ||
311 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
312 | |||
295 | sprintf(reg, "^%s$", event_name); | 313 | sprintf(reg, "^%s$", event_name); |
296 | 314 | ||
297 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); | 315 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); |
298 | free(reg); | 316 | free(reg); |
299 | 317 | ||
300 | if (ret) | 318 | if (ret) |
301 | return -1; | 319 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
302 | 320 | ||
303 | if (sys_name) { | 321 | if (sys_name) { |
304 | reg = malloc_or_die(strlen(sys_name) + 3); | 322 | reg = malloc(strlen(sys_name) + 3); |
323 | if (reg == NULL) { | ||
324 | regfree(&ereg); | ||
325 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
326 | } | ||
327 | |||
305 | sprintf(reg, "^%s$", sys_name); | 328 | sprintf(reg, "^%s$", sys_name); |
306 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); | 329 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); |
307 | free(reg); | 330 | free(reg); |
308 | if (ret) { | 331 | if (ret) { |
309 | regfree(&ereg); | 332 | regfree(&ereg); |
310 | return -1; | 333 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
311 | } | 334 | } |
312 | } | 335 | } |
313 | 336 | ||
@@ -327,9 +350,9 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
327 | regfree(&sreg); | 350 | regfree(&sreg); |
328 | 351 | ||
329 | if (!match) | 352 | if (!match) |
330 | return -1; | 353 | return PEVENT_ERRNO__EVENT_NOT_FOUND; |
331 | if (fail) | 354 | if (fail) |
332 | return -2; | 355 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; |
333 | 356 | ||
334 | return 0; | 357 | return 0; |
335 | } | 358 | } |
@@ -345,14 +368,18 @@ static void free_events(struct event_list *events) | |||
345 | } | 368 | } |
346 | } | 369 | } |
347 | 370 | ||
348 | static struct filter_arg * | 371 | static enum pevent_errno |
349 | create_arg_item(struct event_format *event, const char *token, | 372 | create_arg_item(struct event_format *event, const char *token, |
350 | enum event_type type, char **error_str) | 373 | enum event_type type, struct filter_arg **parg, char **error_str) |
351 | { | 374 | { |
352 | struct format_field *field; | 375 | struct format_field *field; |
353 | struct filter_arg *arg; | 376 | struct filter_arg *arg; |
354 | 377 | ||
355 | arg = allocate_arg(); | 378 | arg = allocate_arg(); |
379 | if (arg == NULL) { | ||
380 | show_error(error_str, "failed to allocate filter arg"); | ||
381 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
382 | } | ||
356 | 383 | ||
357 | switch (type) { | 384 | switch (type) { |
358 | 385 | ||
@@ -365,7 +392,7 @@ create_arg_item(struct event_format *event, const char *token, | |||
365 | if (!arg->value.str) { | 392 | if (!arg->value.str) { |
366 | free_arg(arg); | 393 | free_arg(arg); |
367 | show_error(error_str, "failed to allocate string filter arg"); | 394 | show_error(error_str, "failed to allocate string filter arg"); |
368 | return NULL; | 395 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; |
369 | } | 396 | } |
370 | break; | 397 | break; |
371 | case EVENT_ITEM: | 398 | case EVENT_ITEM: |
@@ -393,11 +420,11 @@ create_arg_item(struct event_format *event, const char *token, | |||
393 | break; | 420 | break; |
394 | default: | 421 | default: |
395 | free_arg(arg); | 422 | free_arg(arg); |
396 | show_error(error_str, "expected a value but found %s", | 423 | show_error(error_str, "expected a value but found %s", token); |
397 | token); | 424 | return PEVENT_ERRNO__UNEXPECTED_TYPE; |
398 | return NULL; | ||
399 | } | 425 | } |
400 | return arg; | 426 | *parg = arg; |
427 | return 0; | ||
401 | } | 428 | } |
402 | 429 | ||
403 | static struct filter_arg * | 430 | static struct filter_arg * |
@@ -406,6 +433,9 @@ create_arg_op(enum filter_op_type btype) | |||
406 | struct filter_arg *arg; | 433 | struct filter_arg *arg; |
407 | 434 | ||
408 | arg = allocate_arg(); | 435 | arg = allocate_arg(); |
436 | if (!arg) | ||
437 | return NULL; | ||
438 | |||
409 | arg->type = FILTER_ARG_OP; | 439 | arg->type = FILTER_ARG_OP; |
410 | arg->op.type = btype; | 440 | arg->op.type = btype; |
411 | 441 | ||
@@ -418,6 +448,9 @@ create_arg_exp(enum filter_exp_type etype) | |||
418 | struct filter_arg *arg; | 448 | struct filter_arg *arg; |
419 | 449 | ||
420 | arg = allocate_arg(); | 450 | arg = allocate_arg(); |
451 | if (!arg) | ||
452 | return NULL; | ||
453 | |||
421 | arg->type = FILTER_ARG_EXP; | 454 | arg->type = FILTER_ARG_EXP; |
422 | arg->op.type = etype; | 455 | arg->op.type = etype; |
423 | 456 | ||
@@ -430,6 +463,9 @@ create_arg_cmp(enum filter_exp_type etype) | |||
430 | struct filter_arg *arg; | 463 | struct filter_arg *arg; |
431 | 464 | ||
432 | arg = allocate_arg(); | 465 | arg = allocate_arg(); |
466 | if (!arg) | ||
467 | return NULL; | ||
468 | |||
433 | /* Use NUM and change if necessary */ | 469 | /* Use NUM and change if necessary */ |
434 | arg->type = FILTER_ARG_NUM; | 470 | arg->type = FILTER_ARG_NUM; |
435 | arg->op.type = etype; | 471 | arg->op.type = etype; |
@@ -437,8 +473,8 @@ create_arg_cmp(enum filter_exp_type etype) | |||
437 | return arg; | 473 | return arg; |
438 | } | 474 | } |
439 | 475 | ||
440 | static int add_right(struct filter_arg *op, struct filter_arg *arg, | 476 | static enum pevent_errno |
441 | char **error_str) | 477 | add_right(struct filter_arg *op, struct filter_arg *arg, char **error_str) |
442 | { | 478 | { |
443 | struct filter_arg *left; | 479 | struct filter_arg *left; |
444 | char *str; | 480 | char *str; |
@@ -469,9 +505,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
469 | case FILTER_ARG_FIELD: | 505 | case FILTER_ARG_FIELD: |
470 | break; | 506 | break; |
471 | default: | 507 | default: |
472 | show_error(error_str, | 508 | show_error(error_str, "Illegal rvalue"); |
473 | "Illegal rvalue"); | 509 | return PEVENT_ERRNO__ILLEGAL_RVALUE; |
474 | return -1; | ||
475 | } | 510 | } |
476 | 511 | ||
477 | /* | 512 | /* |
@@ -518,7 +553,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
518 | if (left->type != FILTER_ARG_FIELD) { | 553 | if (left->type != FILTER_ARG_FIELD) { |
519 | show_error(error_str, | 554 | show_error(error_str, |
520 | "Illegal lvalue for string comparison"); | 555 | "Illegal lvalue for string comparison"); |
521 | return -1; | 556 | return PEVENT_ERRNO__ILLEGAL_LVALUE; |
522 | } | 557 | } |
523 | 558 | ||
524 | /* Make sure this is a valid string compare */ | 559 | /* Make sure this is a valid string compare */ |
@@ -537,25 +572,31 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
537 | show_error(error_str, | 572 | show_error(error_str, |
538 | "RegEx '%s' did not compute", | 573 | "RegEx '%s' did not compute", |
539 | str); | 574 | str); |
540 | return -1; | 575 | return PEVENT_ERRNO__INVALID_REGEX; |
541 | } | 576 | } |
542 | break; | 577 | break; |
543 | default: | 578 | default: |
544 | show_error(error_str, | 579 | show_error(error_str, |
545 | "Illegal comparison for string"); | 580 | "Illegal comparison for string"); |
546 | return -1; | 581 | return PEVENT_ERRNO__ILLEGAL_STRING_CMP; |
547 | } | 582 | } |
548 | 583 | ||
549 | op->type = FILTER_ARG_STR; | 584 | op->type = FILTER_ARG_STR; |
550 | op->str.type = op_type; | 585 | op->str.type = op_type; |
551 | op->str.field = left->field.field; | 586 | op->str.field = left->field.field; |
552 | op->str.val = strdup(str); | 587 | op->str.val = strdup(str); |
553 | if (!op->str.val) | 588 | if (!op->str.val) { |
554 | die("malloc string"); | 589 | show_error(error_str, "Failed to allocate string filter"); |
590 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
591 | } | ||
555 | /* | 592 | /* |
556 | * Need a buffer to copy data for tests | 593 | * Need a buffer to copy data for tests |
557 | */ | 594 | */ |
558 | op->str.buffer = malloc_or_die(op->str.field->size + 1); | 595 | op->str.buffer = malloc(op->str.field->size + 1); |
596 | if (!op->str.buffer) { | ||
597 | show_error(error_str, "Failed to allocate string filter"); | ||
598 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
599 | } | ||
559 | /* Null terminate this buffer */ | 600 | /* Null terminate this buffer */ |
560 | op->str.buffer[op->str.field->size] = 0; | 601 | op->str.buffer[op->str.field->size] = 0; |
561 | 602 | ||
@@ -573,7 +614,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
573 | case FILTER_CMP_NOT_REGEX: | 614 | case FILTER_CMP_NOT_REGEX: |
574 | show_error(error_str, | 615 | show_error(error_str, |
575 | "Op not allowed with integers"); | 616 | "Op not allowed with integers"); |
576 | return -1; | 617 | return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; |
577 | 618 | ||
578 | default: | 619 | default: |
579 | break; | 620 | break; |
@@ -593,9 +634,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
593 | return 0; | 634 | return 0; |
594 | 635 | ||
595 | out_fail: | 636 | out_fail: |
596 | show_error(error_str, | 637 | show_error(error_str, "Syntax error"); |
597 | "Syntax error"); | 638 | return PEVENT_ERRNO__SYNTAX_ERROR; |
598 | return -1; | ||
599 | } | 639 | } |
600 | 640 | ||
601 | static struct filter_arg * | 641 | static struct filter_arg * |
@@ -608,7 +648,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b) | |||
608 | return arg; | 648 | return arg; |
609 | } | 649 | } |
610 | 650 | ||
611 | static int add_left(struct filter_arg *op, struct filter_arg *arg) | 651 | static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg) |
612 | { | 652 | { |
613 | switch (op->type) { | 653 | switch (op->type) { |
614 | case FILTER_ARG_EXP: | 654 | case FILTER_ARG_EXP: |
@@ -627,11 +667,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg) | |||
627 | /* left arg of compares must be a field */ | 667 | /* left arg of compares must be a field */ |
628 | if (arg->type != FILTER_ARG_FIELD && | 668 | if (arg->type != FILTER_ARG_FIELD && |
629 | arg->type != FILTER_ARG_BOOLEAN) | 669 | arg->type != FILTER_ARG_BOOLEAN) |
630 | return -1; | 670 | return PEVENT_ERRNO__INVALID_ARG_TYPE; |
631 | op->num.left = arg; | 671 | op->num.left = arg; |
632 | break; | 672 | break; |
633 | default: | 673 | default: |
634 | return -1; | 674 | return PEVENT_ERRNO__INVALID_ARG_TYPE; |
635 | } | 675 | } |
636 | return 0; | 676 | return 0; |
637 | } | 677 | } |
@@ -744,15 +784,18 @@ enum filter_vals { | |||
744 | FILTER_VAL_TRUE, | 784 | FILTER_VAL_TRUE, |
745 | }; | 785 | }; |
746 | 786 | ||
747 | void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | 787 | static enum pevent_errno |
748 | struct filter_arg *arg) | 788 | reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, |
789 | struct filter_arg *arg, char **error_str) | ||
749 | { | 790 | { |
750 | struct filter_arg *other_child; | 791 | struct filter_arg *other_child; |
751 | struct filter_arg **ptr; | 792 | struct filter_arg **ptr; |
752 | 793 | ||
753 | if (parent->type != FILTER_ARG_OP && | 794 | if (parent->type != FILTER_ARG_OP && |
754 | arg->type != FILTER_ARG_OP) | 795 | arg->type != FILTER_ARG_OP) { |
755 | die("can not reparent other than OP"); | 796 | show_error(error_str, "can not reparent other than OP"); |
797 | return PEVENT_ERRNO__REPARENT_NOT_OP; | ||
798 | } | ||
756 | 799 | ||
757 | /* Get the sibling */ | 800 | /* Get the sibling */ |
758 | if (old_child->op.right == arg) { | 801 | if (old_child->op.right == arg) { |
@@ -761,8 +804,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | |||
761 | } else if (old_child->op.left == arg) { | 804 | } else if (old_child->op.left == arg) { |
762 | ptr = &old_child->op.left; | 805 | ptr = &old_child->op.left; |
763 | other_child = old_child->op.right; | 806 | other_child = old_child->op.right; |
764 | } else | 807 | } else { |
765 | die("Error in reparent op, find other child"); | 808 | show_error(error_str, "Error in reparent op, find other child"); |
809 | return PEVENT_ERRNO__REPARENT_FAILED; | ||
810 | } | ||
766 | 811 | ||
767 | /* Detach arg from old_child */ | 812 | /* Detach arg from old_child */ |
768 | *ptr = NULL; | 813 | *ptr = NULL; |
@@ -773,23 +818,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | |||
773 | *parent = *arg; | 818 | *parent = *arg; |
774 | /* Free arg without recussion */ | 819 | /* Free arg without recussion */ |
775 | free(arg); | 820 | free(arg); |
776 | return; | 821 | return 0; |
777 | } | 822 | } |
778 | 823 | ||
779 | if (parent->op.right == old_child) | 824 | if (parent->op.right == old_child) |
780 | ptr = &parent->op.right; | 825 | ptr = &parent->op.right; |
781 | else if (parent->op.left == old_child) | 826 | else if (parent->op.left == old_child) |
782 | ptr = &parent->op.left; | 827 | ptr = &parent->op.left; |
783 | else | 828 | else { |
784 | die("Error in reparent op"); | 829 | show_error(error_str, "Error in reparent op"); |
830 | return PEVENT_ERRNO__REPARENT_FAILED; | ||
831 | } | ||
832 | |||
785 | *ptr = arg; | 833 | *ptr = arg; |
786 | 834 | ||
787 | free_arg(old_child); | 835 | free_arg(old_child); |
836 | return 0; | ||
788 | } | 837 | } |
789 | 838 | ||
790 | enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | 839 | /* Returns either filter_vals (success) or pevent_errno (failfure) */ |
840 | static int test_arg(struct filter_arg *parent, struct filter_arg *arg, | ||
841 | char **error_str) | ||
791 | { | 842 | { |
792 | enum filter_vals lval, rval; | 843 | int lval, rval; |
793 | 844 | ||
794 | switch (arg->type) { | 845 | switch (arg->type) { |
795 | 846 | ||
@@ -804,63 +855,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | |||
804 | return FILTER_VAL_NORM; | 855 | return FILTER_VAL_NORM; |
805 | 856 | ||
806 | case FILTER_ARG_EXP: | 857 | case FILTER_ARG_EXP: |
807 | lval = test_arg(arg, arg->exp.left); | 858 | lval = test_arg(arg, arg->exp.left, error_str); |
808 | if (lval != FILTER_VAL_NORM) | 859 | if (lval != FILTER_VAL_NORM) |
809 | return lval; | 860 | return lval; |
810 | rval = test_arg(arg, arg->exp.right); | 861 | rval = test_arg(arg, arg->exp.right, error_str); |
811 | if (rval != FILTER_VAL_NORM) | 862 | if (rval != FILTER_VAL_NORM) |
812 | return rval; | 863 | return rval; |
813 | return FILTER_VAL_NORM; | 864 | return FILTER_VAL_NORM; |
814 | 865 | ||
815 | case FILTER_ARG_NUM: | 866 | case FILTER_ARG_NUM: |
816 | lval = test_arg(arg, arg->num.left); | 867 | lval = test_arg(arg, arg->num.left, error_str); |
817 | if (lval != FILTER_VAL_NORM) | 868 | if (lval != FILTER_VAL_NORM) |
818 | return lval; | 869 | return lval; |
819 | rval = test_arg(arg, arg->num.right); | 870 | rval = test_arg(arg, arg->num.right, error_str); |
820 | if (rval != FILTER_VAL_NORM) | 871 | if (rval != FILTER_VAL_NORM) |
821 | return rval; | 872 | return rval; |
822 | return FILTER_VAL_NORM; | 873 | return FILTER_VAL_NORM; |
823 | 874 | ||
824 | case FILTER_ARG_OP: | 875 | case FILTER_ARG_OP: |
825 | if (arg->op.type != FILTER_OP_NOT) { | 876 | if (arg->op.type != FILTER_OP_NOT) { |
826 | lval = test_arg(arg, arg->op.left); | 877 | lval = test_arg(arg, arg->op.left, error_str); |
827 | switch (lval) { | 878 | switch (lval) { |
828 | case FILTER_VAL_NORM: | 879 | case FILTER_VAL_NORM: |
829 | break; | 880 | break; |
830 | case FILTER_VAL_TRUE: | 881 | case FILTER_VAL_TRUE: |
831 | if (arg->op.type == FILTER_OP_OR) | 882 | if (arg->op.type == FILTER_OP_OR) |
832 | return FILTER_VAL_TRUE; | 883 | return FILTER_VAL_TRUE; |
833 | rval = test_arg(arg, arg->op.right); | 884 | rval = test_arg(arg, arg->op.right, error_str); |
834 | if (rval != FILTER_VAL_NORM) | 885 | if (rval != FILTER_VAL_NORM) |
835 | return rval; | 886 | return rval; |
836 | 887 | ||
837 | reparent_op_arg(parent, arg, arg->op.right); | 888 | return reparent_op_arg(parent, arg, arg->op.right, |
838 | return FILTER_VAL_NORM; | 889 | error_str); |
839 | 890 | ||
840 | case FILTER_VAL_FALSE: | 891 | case FILTER_VAL_FALSE: |
841 | if (arg->op.type == FILTER_OP_AND) | 892 | if (arg->op.type == FILTER_OP_AND) |
842 | return FILTER_VAL_FALSE; | 893 | return FILTER_VAL_FALSE; |
843 | rval = test_arg(arg, arg->op.right); | 894 | rval = test_arg(arg, arg->op.right, error_str); |
844 | if (rval != FILTER_VAL_NORM) | 895 | if (rval != FILTER_VAL_NORM) |
845 | return rval; | 896 | return rval; |
846 | 897 | ||
847 | reparent_op_arg(parent, arg, arg->op.right); | 898 | return reparent_op_arg(parent, arg, arg->op.right, |
848 | return FILTER_VAL_NORM; | 899 | error_str); |
900 | |||
901 | default: | ||
902 | return lval; | ||
849 | } | 903 | } |
850 | } | 904 | } |
851 | 905 | ||
852 | rval = test_arg(arg, arg->op.right); | 906 | rval = test_arg(arg, arg->op.right, error_str); |
853 | switch (rval) { | 907 | switch (rval) { |
854 | case FILTER_VAL_NORM: | 908 | case FILTER_VAL_NORM: |
909 | default: | ||
855 | break; | 910 | break; |
911 | |||
856 | case FILTER_VAL_TRUE: | 912 | case FILTER_VAL_TRUE: |
857 | if (arg->op.type == FILTER_OP_OR) | 913 | if (arg->op.type == FILTER_OP_OR) |
858 | return FILTER_VAL_TRUE; | 914 | return FILTER_VAL_TRUE; |
859 | if (arg->op.type == FILTER_OP_NOT) | 915 | if (arg->op.type == FILTER_OP_NOT) |
860 | return FILTER_VAL_FALSE; | 916 | return FILTER_VAL_FALSE; |
861 | 917 | ||
862 | reparent_op_arg(parent, arg, arg->op.left); | 918 | return reparent_op_arg(parent, arg, arg->op.left, |
863 | return FILTER_VAL_NORM; | 919 | error_str); |
864 | 920 | ||
865 | case FILTER_VAL_FALSE: | 921 | case FILTER_VAL_FALSE: |
866 | if (arg->op.type == FILTER_OP_AND) | 922 | if (arg->op.type == FILTER_OP_AND) |
@@ -868,39 +924,54 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | |||
868 | if (arg->op.type == FILTER_OP_NOT) | 924 | if (arg->op.type == FILTER_OP_NOT) |
869 | return FILTER_VAL_TRUE; | 925 | return FILTER_VAL_TRUE; |
870 | 926 | ||
871 | reparent_op_arg(parent, arg, arg->op.left); | 927 | return reparent_op_arg(parent, arg, arg->op.left, |
872 | return FILTER_VAL_NORM; | 928 | error_str); |
873 | } | 929 | } |
874 | 930 | ||
875 | return FILTER_VAL_NORM; | 931 | return rval; |
876 | default: | 932 | default: |
877 | die("bad arg in filter tree"); | 933 | show_error(error_str, "bad arg in filter tree"); |
934 | return PEVENT_ERRNO__BAD_FILTER_ARG; | ||
878 | } | 935 | } |
879 | return FILTER_VAL_NORM; | 936 | return FILTER_VAL_NORM; |
880 | } | 937 | } |
881 | 938 | ||
882 | /* Remove any unknown event fields */ | 939 | /* Remove any unknown event fields */ |
883 | static struct filter_arg *collapse_tree(struct filter_arg *arg) | 940 | static int collapse_tree(struct filter_arg *arg, |
941 | struct filter_arg **arg_collapsed, char **error_str) | ||
884 | { | 942 | { |
885 | enum filter_vals ret; | 943 | int ret; |
886 | 944 | ||
887 | ret = test_arg(arg, arg); | 945 | ret = test_arg(arg, arg, error_str); |
888 | switch (ret) { | 946 | switch (ret) { |
889 | case FILTER_VAL_NORM: | 947 | case FILTER_VAL_NORM: |
890 | return arg; | 948 | break; |
891 | 949 | ||
892 | case FILTER_VAL_TRUE: | 950 | case FILTER_VAL_TRUE: |
893 | case FILTER_VAL_FALSE: | 951 | case FILTER_VAL_FALSE: |
894 | free_arg(arg); | 952 | free_arg(arg); |
895 | arg = allocate_arg(); | 953 | arg = allocate_arg(); |
896 | arg->type = FILTER_ARG_BOOLEAN; | 954 | if (arg) { |
897 | arg->boolean.value = ret == FILTER_VAL_TRUE; | 955 | arg->type = FILTER_ARG_BOOLEAN; |
956 | arg->boolean.value = ret == FILTER_VAL_TRUE; | ||
957 | } else { | ||
958 | show_error(error_str, "Failed to allocate filter arg"); | ||
959 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
960 | } | ||
961 | break; | ||
962 | |||
963 | default: | ||
964 | /* test_arg() already set the error_str */ | ||
965 | free_arg(arg); | ||
966 | arg = NULL; | ||
967 | break; | ||
898 | } | 968 | } |
899 | 969 | ||
900 | return arg; | 970 | *arg_collapsed = arg; |
971 | return ret; | ||
901 | } | 972 | } |
902 | 973 | ||
903 | static int | 974 | static enum pevent_errno |
904 | process_filter(struct event_format *event, struct filter_arg **parg, | 975 | process_filter(struct event_format *event, struct filter_arg **parg, |
905 | char **error_str, int not) | 976 | char **error_str, int not) |
906 | { | 977 | { |
@@ -914,7 +985,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
914 | enum filter_op_type btype; | 985 | enum filter_op_type btype; |
915 | enum filter_exp_type etype; | 986 | enum filter_exp_type etype; |
916 | enum filter_cmp_type ctype; | 987 | enum filter_cmp_type ctype; |
917 | int ret; | 988 | enum pevent_errno ret; |
918 | 989 | ||
919 | *parg = NULL; | 990 | *parg = NULL; |
920 | 991 | ||
@@ -925,8 +996,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
925 | case EVENT_SQUOTE: | 996 | case EVENT_SQUOTE: |
926 | case EVENT_DQUOTE: | 997 | case EVENT_DQUOTE: |
927 | case EVENT_ITEM: | 998 | case EVENT_ITEM: |
928 | arg = create_arg_item(event, token, type, error_str); | 999 | ret = create_arg_item(event, token, type, &arg, error_str); |
929 | if (!arg) | 1000 | if (ret < 0) |
930 | goto fail; | 1001 | goto fail; |
931 | if (!left_item) | 1002 | if (!left_item) |
932 | left_item = arg; | 1003 | left_item = arg; |
@@ -939,20 +1010,20 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
939 | if (not) { | 1010 | if (not) { |
940 | arg = NULL; | 1011 | arg = NULL; |
941 | if (current_op) | 1012 | if (current_op) |
942 | goto fail_print; | 1013 | goto fail_syntax; |
943 | free(token); | 1014 | free(token); |
944 | *parg = current_exp; | 1015 | *parg = current_exp; |
945 | return 0; | 1016 | return 0; |
946 | } | 1017 | } |
947 | } else | 1018 | } else |
948 | goto fail_print; | 1019 | goto fail_syntax; |
949 | arg = NULL; | 1020 | arg = NULL; |
950 | break; | 1021 | break; |
951 | 1022 | ||
952 | case EVENT_DELIM: | 1023 | case EVENT_DELIM: |
953 | if (*token == ',') { | 1024 | if (*token == ',') { |
954 | show_error(error_str, | 1025 | show_error(error_str, "Illegal token ','"); |
955 | "Illegal token ','"); | 1026 | ret = PEVENT_ERRNO__ILLEGAL_TOKEN; |
956 | goto fail; | 1027 | goto fail; |
957 | } | 1028 | } |
958 | 1029 | ||
@@ -960,19 +1031,23 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
960 | if (left_item) { | 1031 | if (left_item) { |
961 | show_error(error_str, | 1032 | show_error(error_str, |
962 | "Open paren can not come after item"); | 1033 | "Open paren can not come after item"); |
1034 | ret = PEVENT_ERRNO__INVALID_PAREN; | ||
963 | goto fail; | 1035 | goto fail; |
964 | } | 1036 | } |
965 | if (current_exp) { | 1037 | if (current_exp) { |
966 | show_error(error_str, | 1038 | show_error(error_str, |
967 | "Open paren can not come after expression"); | 1039 | "Open paren can not come after expression"); |
1040 | ret = PEVENT_ERRNO__INVALID_PAREN; | ||
968 | goto fail; | 1041 | goto fail; |
969 | } | 1042 | } |
970 | 1043 | ||
971 | ret = process_filter(event, &arg, error_str, 0); | 1044 | ret = process_filter(event, &arg, error_str, 0); |
972 | if (ret != 1) { | 1045 | if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) { |
973 | if (ret == 0) | 1046 | if (ret == 0) { |
974 | show_error(error_str, | 1047 | show_error(error_str, |
975 | "Unbalanced number of '('"); | 1048 | "Unbalanced number of '('"); |
1049 | ret = PEVENT_ERRNO__UNBALANCED_PAREN; | ||
1050 | } | ||
976 | goto fail; | 1051 | goto fail; |
977 | } | 1052 | } |
978 | ret = 0; | 1053 | ret = 0; |
@@ -980,7 +1055,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
980 | /* A not wants just one expression */ | 1055 | /* A not wants just one expression */ |
981 | if (not) { | 1056 | if (not) { |
982 | if (current_op) | 1057 | if (current_op) |
983 | goto fail_print; | 1058 | goto fail_syntax; |
984 | *parg = arg; | 1059 | *parg = arg; |
985 | return 0; | 1060 | return 0; |
986 | } | 1061 | } |
@@ -995,19 +1070,19 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
995 | 1070 | ||
996 | } else { /* ')' */ | 1071 | } else { /* ')' */ |
997 | if (!current_op && !current_exp) | 1072 | if (!current_op && !current_exp) |
998 | goto fail_print; | 1073 | goto fail_syntax; |
999 | 1074 | ||
1000 | /* Make sure everything is finished at this level */ | 1075 | /* Make sure everything is finished at this level */ |
1001 | if (current_exp && !check_op_done(current_exp)) | 1076 | if (current_exp && !check_op_done(current_exp)) |
1002 | goto fail_print; | 1077 | goto fail_syntax; |
1003 | if (current_op && !check_op_done(current_op)) | 1078 | if (current_op && !check_op_done(current_op)) |
1004 | goto fail_print; | 1079 | goto fail_syntax; |
1005 | 1080 | ||
1006 | if (current_op) | 1081 | if (current_op) |
1007 | *parg = current_op; | 1082 | *parg = current_op; |
1008 | else | 1083 | else |
1009 | *parg = current_exp; | 1084 | *parg = current_exp; |
1010 | return 1; | 1085 | return PEVENT_ERRNO__UNBALANCED_PAREN; |
1011 | } | 1086 | } |
1012 | break; | 1087 | break; |
1013 | 1088 | ||
@@ -1019,21 +1094,22 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1019 | case OP_BOOL: | 1094 | case OP_BOOL: |
1020 | /* Logic ops need a left expression */ | 1095 | /* Logic ops need a left expression */ |
1021 | if (!current_exp && !current_op) | 1096 | if (!current_exp && !current_op) |
1022 | goto fail_print; | 1097 | goto fail_syntax; |
1023 | /* fall through */ | 1098 | /* fall through */ |
1024 | case OP_NOT: | 1099 | case OP_NOT: |
1025 | /* logic only processes ops and exp */ | 1100 | /* logic only processes ops and exp */ |
1026 | if (left_item) | 1101 | if (left_item) |
1027 | goto fail_print; | 1102 | goto fail_syntax; |
1028 | break; | 1103 | break; |
1029 | case OP_EXP: | 1104 | case OP_EXP: |
1030 | case OP_CMP: | 1105 | case OP_CMP: |
1031 | if (!left_item) | 1106 | if (!left_item) |
1032 | goto fail_print; | 1107 | goto fail_syntax; |
1033 | break; | 1108 | break; |
1034 | case OP_NONE: | 1109 | case OP_NONE: |
1035 | show_error(error_str, | 1110 | show_error(error_str, |
1036 | "Unknown op token %s", token); | 1111 | "Unknown op token %s", token); |
1112 | ret = PEVENT_ERRNO__UNKNOWN_TOKEN; | ||
1037 | goto fail; | 1113 | goto fail; |
1038 | } | 1114 | } |
1039 | 1115 | ||
@@ -1041,6 +1117,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1041 | switch (op_type) { | 1117 | switch (op_type) { |
1042 | case OP_BOOL: | 1118 | case OP_BOOL: |
1043 | arg = create_arg_op(btype); | 1119 | arg = create_arg_op(btype); |
1120 | if (arg == NULL) | ||
1121 | goto fail_alloc; | ||
1044 | if (current_op) | 1122 | if (current_op) |
1045 | ret = add_left(arg, current_op); | 1123 | ret = add_left(arg, current_op); |
1046 | else | 1124 | else |
@@ -1051,6 +1129,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1051 | 1129 | ||
1052 | case OP_NOT: | 1130 | case OP_NOT: |
1053 | arg = create_arg_op(btype); | 1131 | arg = create_arg_op(btype); |
1132 | if (arg == NULL) | ||
1133 | goto fail_alloc; | ||
1054 | if (current_op) | 1134 | if (current_op) |
1055 | ret = add_right(current_op, arg, error_str); | 1135 | ret = add_right(current_op, arg, error_str); |
1056 | if (ret < 0) | 1136 | if (ret < 0) |
@@ -1070,6 +1150,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1070 | arg = create_arg_exp(etype); | 1150 | arg = create_arg_exp(etype); |
1071 | else | 1151 | else |
1072 | arg = create_arg_cmp(ctype); | 1152 | arg = create_arg_cmp(ctype); |
1153 | if (arg == NULL) | ||
1154 | goto fail_alloc; | ||
1073 | 1155 | ||
1074 | if (current_op) | 1156 | if (current_op) |
1075 | ret = add_right(current_op, arg, error_str); | 1157 | ret = add_right(current_op, arg, error_str); |
@@ -1078,7 +1160,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1078 | ret = add_left(arg, left_item); | 1160 | ret = add_left(arg, left_item); |
1079 | if (ret < 0) { | 1161 | if (ret < 0) { |
1080 | arg = NULL; | 1162 | arg = NULL; |
1081 | goto fail_print; | 1163 | goto fail_syntax; |
1082 | } | 1164 | } |
1083 | current_exp = arg; | 1165 | current_exp = arg; |
1084 | break; | 1166 | break; |
@@ -1087,38 +1169,47 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1087 | } | 1169 | } |
1088 | arg = NULL; | 1170 | arg = NULL; |
1089 | if (ret < 0) | 1171 | if (ret < 0) |
1090 | goto fail_print; | 1172 | goto fail_syntax; |
1091 | break; | 1173 | break; |
1092 | case EVENT_NONE: | 1174 | case EVENT_NONE: |
1093 | break; | 1175 | break; |
1176 | case EVENT_ERROR: | ||
1177 | goto fail_alloc; | ||
1094 | default: | 1178 | default: |
1095 | goto fail_print; | 1179 | goto fail_syntax; |
1096 | } | 1180 | } |
1097 | } while (type != EVENT_NONE); | 1181 | } while (type != EVENT_NONE); |
1098 | 1182 | ||
1099 | if (!current_op && !current_exp) | 1183 | if (!current_op && !current_exp) |
1100 | goto fail_print; | 1184 | goto fail_syntax; |
1101 | 1185 | ||
1102 | if (!current_op) | 1186 | if (!current_op) |
1103 | current_op = current_exp; | 1187 | current_op = current_exp; |
1104 | 1188 | ||
1105 | current_op = collapse_tree(current_op); | 1189 | ret = collapse_tree(current_op, parg, error_str); |
1190 | if (ret < 0) | ||
1191 | goto fail; | ||
1106 | 1192 | ||
1107 | *parg = current_op; | 1193 | *parg = current_op; |
1108 | 1194 | ||
1109 | return 0; | 1195 | return 0; |
1110 | 1196 | ||
1111 | fail_print: | 1197 | fail_alloc: |
1198 | show_error(error_str, "failed to allocate filter arg"); | ||
1199 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1200 | goto fail; | ||
1201 | fail_syntax: | ||
1112 | show_error(error_str, "Syntax error"); | 1202 | show_error(error_str, "Syntax error"); |
1203 | ret = PEVENT_ERRNO__SYNTAX_ERROR; | ||
1113 | fail: | 1204 | fail: |
1114 | free_arg(current_op); | 1205 | free_arg(current_op); |
1115 | free_arg(current_exp); | 1206 | free_arg(current_exp); |
1116 | free_arg(arg); | 1207 | free_arg(arg); |
1117 | free(token); | 1208 | free(token); |
1118 | return -1; | 1209 | return ret; |
1119 | } | 1210 | } |
1120 | 1211 | ||
1121 | static int | 1212 | static enum pevent_errno |
1122 | process_event(struct event_format *event, const char *filter_str, | 1213 | process_event(struct event_format *event, const char *filter_str, |
1123 | struct filter_arg **parg, char **error_str) | 1214 | struct filter_arg **parg, char **error_str) |
1124 | { | 1215 | { |
@@ -1127,17 +1218,15 @@ process_event(struct event_format *event, const char *filter_str, | |||
1127 | pevent_buffer_init(filter_str, strlen(filter_str)); | 1218 | pevent_buffer_init(filter_str, strlen(filter_str)); |
1128 | 1219 | ||
1129 | ret = process_filter(event, parg, error_str, 0); | 1220 | ret = process_filter(event, parg, error_str, 0); |
1130 | if (ret == 1) { | ||
1131 | show_error(error_str, | ||
1132 | "Unbalanced number of ')'"); | ||
1133 | return -1; | ||
1134 | } | ||
1135 | if (ret < 0) | 1221 | if (ret < 0) |
1136 | return ret; | 1222 | return ret; |
1137 | 1223 | ||
1138 | /* If parg is NULL, then make it into FALSE */ | 1224 | /* If parg is NULL, then make it into FALSE */ |
1139 | if (!*parg) { | 1225 | if (!*parg) { |
1140 | *parg = allocate_arg(); | 1226 | *parg = allocate_arg(); |
1227 | if (*parg == NULL) | ||
1228 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1229 | |||
1141 | (*parg)->type = FILTER_ARG_BOOLEAN; | 1230 | (*parg)->type = FILTER_ARG_BOOLEAN; |
1142 | (*parg)->boolean.value = FILTER_FALSE; | 1231 | (*parg)->boolean.value = FILTER_FALSE; |
1143 | } | 1232 | } |
@@ -1145,13 +1234,13 @@ process_event(struct event_format *event, const char *filter_str, | |||
1145 | return 0; | 1234 | return 0; |
1146 | } | 1235 | } |
1147 | 1236 | ||
1148 | static int filter_event(struct event_filter *filter, | 1237 | static enum pevent_errno |
1149 | struct event_format *event, | 1238 | filter_event(struct event_filter *filter, struct event_format *event, |
1150 | const char *filter_str, char **error_str) | 1239 | const char *filter_str, char **error_str) |
1151 | { | 1240 | { |
1152 | struct filter_type *filter_type; | 1241 | struct filter_type *filter_type; |
1153 | struct filter_arg *arg; | 1242 | struct filter_arg *arg; |
1154 | int ret; | 1243 | enum pevent_errno ret; |
1155 | 1244 | ||
1156 | if (filter_str) { | 1245 | if (filter_str) { |
1157 | ret = process_event(event, filter_str, &arg, error_str); | 1246 | ret = process_event(event, filter_str, &arg, error_str); |
@@ -1161,11 +1250,17 @@ static int filter_event(struct event_filter *filter, | |||
1161 | } else { | 1250 | } else { |
1162 | /* just add a TRUE arg */ | 1251 | /* just add a TRUE arg */ |
1163 | arg = allocate_arg(); | 1252 | arg = allocate_arg(); |
1253 | if (arg == NULL) | ||
1254 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1255 | |||
1164 | arg->type = FILTER_ARG_BOOLEAN; | 1256 | arg->type = FILTER_ARG_BOOLEAN; |
1165 | arg->boolean.value = FILTER_TRUE; | 1257 | arg->boolean.value = FILTER_TRUE; |
1166 | } | 1258 | } |
1167 | 1259 | ||
1168 | filter_type = add_filter_type(filter, event->id); | 1260 | filter_type = add_filter_type(filter, event->id); |
1261 | if (filter_type == NULL) | ||
1262 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1263 | |||
1169 | if (filter_type->filter) | 1264 | if (filter_type->filter) |
1170 | free_arg(filter_type->filter); | 1265 | free_arg(filter_type->filter); |
1171 | filter_type->filter = arg; | 1266 | filter_type->filter = arg; |
@@ -1177,18 +1272,12 @@ static int filter_event(struct event_filter *filter, | |||
1177 | * pevent_filter_add_filter_str - add a new filter | 1272 | * pevent_filter_add_filter_str - add a new filter |
1178 | * @filter: the event filter to add to | 1273 | * @filter: the event filter to add to |
1179 | * @filter_str: the filter string that contains the filter | 1274 | * @filter_str: the filter string that contains the filter |
1180 | * @error_str: string containing reason for failed filter | ||
1181 | * | 1275 | * |
1182 | * Returns 0 if the filter was successfully added | 1276 | * Returns 0 if the filter was successfully added or a |
1183 | * -1 if there was an error. | 1277 | * negative error code. |
1184 | * | ||
1185 | * On error, if @error_str points to a string pointer, | ||
1186 | * it is set to the reason that the filter failed. | ||
1187 | * This string must be freed with "free". | ||
1188 | */ | 1278 | */ |
1189 | int pevent_filter_add_filter_str(struct event_filter *filter, | 1279 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
1190 | const char *filter_str, | 1280 | const char *filter_str) |
1191 | char **error_str) | ||
1192 | { | 1281 | { |
1193 | struct pevent *pevent = filter->pevent; | 1282 | struct pevent *pevent = filter->pevent; |
1194 | struct event_list *event; | 1283 | struct event_list *event; |
@@ -1199,23 +1288,20 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1199 | char *event_name = NULL; | 1288 | char *event_name = NULL; |
1200 | char *sys_name = NULL; | 1289 | char *sys_name = NULL; |
1201 | char *sp; | 1290 | char *sp; |
1202 | int rtn = 0; | 1291 | enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */ |
1203 | int len; | 1292 | int len; |
1204 | int ret; | 1293 | int ret; |
1294 | char *error_str = NULL; | ||
1205 | 1295 | ||
1206 | /* clear buffer to reset show error */ | 1296 | /* clear buffer to reset show error */ |
1207 | pevent_buffer_init("", 0); | 1297 | pevent_buffer_init("", 0); |
1208 | 1298 | ||
1209 | if (error_str) | ||
1210 | *error_str = NULL; | ||
1211 | |||
1212 | filter_start = strchr(filter_str, ':'); | 1299 | filter_start = strchr(filter_str, ':'); |
1213 | if (filter_start) | 1300 | if (filter_start) |
1214 | len = filter_start - filter_str; | 1301 | len = filter_start - filter_str; |
1215 | else | 1302 | else |
1216 | len = strlen(filter_str); | 1303 | len = strlen(filter_str); |
1217 | 1304 | ||
1218 | |||
1219 | do { | 1305 | do { |
1220 | next_event = strchr(filter_str, ','); | 1306 | next_event = strchr(filter_str, ','); |
1221 | if (next_event && | 1307 | if (next_event && |
@@ -1228,10 +1314,9 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1228 | 1314 | ||
1229 | this_event = malloc(len + 1); | 1315 | this_event = malloc(len + 1); |
1230 | if (this_event == NULL) { | 1316 | if (this_event == NULL) { |
1231 | show_error(error_str, "Memory allocation failure"); | ||
1232 | /* This can only happen when events is NULL, but still */ | 1317 | /* This can only happen when events is NULL, but still */ |
1233 | free_events(events); | 1318 | free_events(events); |
1234 | return -1; | 1319 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; |
1235 | } | 1320 | } |
1236 | memcpy(this_event, filter_str, len); | 1321 | memcpy(this_event, filter_str, len); |
1237 | this_event[len] = 0; | 1322 | this_event[len] = 0; |
@@ -1245,27 +1330,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1245 | event_name = strtok_r(NULL, "/", &sp); | 1330 | event_name = strtok_r(NULL, "/", &sp); |
1246 | 1331 | ||
1247 | if (!sys_name) { | 1332 | if (!sys_name) { |
1248 | show_error(error_str, "No filter found"); | ||
1249 | /* This can only happen when events is NULL, but still */ | 1333 | /* This can only happen when events is NULL, but still */ |
1250 | free_events(events); | 1334 | free_events(events); |
1251 | free(this_event); | 1335 | free(this_event); |
1252 | return -1; | 1336 | return PEVENT_ERRNO__FILTER_NOT_FOUND; |
1253 | } | 1337 | } |
1254 | 1338 | ||
1255 | /* Find this event */ | 1339 | /* Find this event */ |
1256 | ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); | 1340 | ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); |
1257 | if (ret < 0) { | 1341 | if (ret < 0) { |
1258 | if (event_name) | ||
1259 | show_error(error_str, | ||
1260 | "No event found under '%s.%s'", | ||
1261 | sys_name, event_name); | ||
1262 | else | ||
1263 | show_error(error_str, | ||
1264 | "No event found under '%s'", | ||
1265 | sys_name); | ||
1266 | free_events(events); | 1342 | free_events(events); |
1267 | free(this_event); | 1343 | free(this_event); |
1268 | return -1; | 1344 | return ret; |
1269 | } | 1345 | } |
1270 | free(this_event); | 1346 | free(this_event); |
1271 | } while (filter_str); | 1347 | } while (filter_str); |
@@ -1277,7 +1353,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1277 | /* filter starts here */ | 1353 | /* filter starts here */ |
1278 | for (event = events; event; event = event->next) { | 1354 | for (event = events; event; event = event->next) { |
1279 | ret = filter_event(filter, event->event, filter_start, | 1355 | ret = filter_event(filter, event->event, filter_start, |
1280 | error_str); | 1356 | &error_str); |
1281 | /* Failures are returned if a parse error happened */ | 1357 | /* Failures are returned if a parse error happened */ |
1282 | if (ret < 0) | 1358 | if (ret < 0) |
1283 | rtn = ret; | 1359 | rtn = ret; |
@@ -1396,6 +1472,9 @@ static int copy_filter_type(struct event_filter *filter, | |||
1396 | if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { | 1472 | if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { |
1397 | /* Add trivial event */ | 1473 | /* Add trivial event */ |
1398 | arg = allocate_arg(); | 1474 | arg = allocate_arg(); |
1475 | if (arg == NULL) | ||
1476 | return -1; | ||
1477 | |||
1399 | arg->type = FILTER_ARG_BOOLEAN; | 1478 | arg->type = FILTER_ARG_BOOLEAN; |
1400 | if (strcmp(str, "TRUE") == 0) | 1479 | if (strcmp(str, "TRUE") == 0) |
1401 | arg->boolean.value = 1; | 1480 | arg->boolean.value = 1; |
@@ -1403,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter, | |||
1403 | arg->boolean.value = 0; | 1482 | arg->boolean.value = 0; |
1404 | 1483 | ||
1405 | filter_type = add_filter_type(filter, event->id); | 1484 | filter_type = add_filter_type(filter, event->id); |
1485 | if (filter_type == NULL) | ||
1486 | return -1; | ||
1487 | |||
1406 | filter_type->filter = arg; | 1488 | filter_type->filter = arg; |
1407 | 1489 | ||
1408 | free(str); | 1490 | free(str); |
@@ -1596,8 +1678,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter, | |||
1596 | } | 1678 | } |
1597 | } | 1679 | } |
1598 | 1680 | ||
1599 | static int test_filter(struct event_format *event, | 1681 | static int test_filter(struct event_format *event, struct filter_arg *arg, |
1600 | struct filter_arg *arg, struct pevent_record *record); | 1682 | struct pevent_record *record, enum pevent_errno *err); |
1601 | 1683 | ||
1602 | static const char * | 1684 | static const char * |
1603 | get_comm(struct event_format *event, struct pevent_record *record) | 1685 | get_comm(struct event_format *event, struct pevent_record *record) |
@@ -1643,15 +1725,24 @@ get_value(struct event_format *event, | |||
1643 | } | 1725 | } |
1644 | 1726 | ||
1645 | static unsigned long long | 1727 | static unsigned long long |
1646 | get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); | 1728 | get_arg_value(struct event_format *event, struct filter_arg *arg, |
1729 | struct pevent_record *record, enum pevent_errno *err); | ||
1647 | 1730 | ||
1648 | static unsigned long long | 1731 | static unsigned long long |
1649 | get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) | 1732 | get_exp_value(struct event_format *event, struct filter_arg *arg, |
1733 | struct pevent_record *record, enum pevent_errno *err) | ||
1650 | { | 1734 | { |
1651 | unsigned long long lval, rval; | 1735 | unsigned long long lval, rval; |
1652 | 1736 | ||
1653 | lval = get_arg_value(event, arg->exp.left, record); | 1737 | lval = get_arg_value(event, arg->exp.left, record, err); |
1654 | rval = get_arg_value(event, arg->exp.right, record); | 1738 | rval = get_arg_value(event, arg->exp.right, record, err); |
1739 | |||
1740 | if (*err) { | ||
1741 | /* | ||
1742 | * There was an error, no need to process anymore. | ||
1743 | */ | ||
1744 | return 0; | ||
1745 | } | ||
1655 | 1746 | ||
1656 | switch (arg->exp.type) { | 1747 | switch (arg->exp.type) { |
1657 | case FILTER_EXP_ADD: | 1748 | case FILTER_EXP_ADD: |
@@ -1686,39 +1777,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_ | |||
1686 | 1777 | ||
1687 | case FILTER_EXP_NOT: | 1778 | case FILTER_EXP_NOT: |
1688 | default: | 1779 | default: |
1689 | die("error in exp"); | 1780 | if (!*err) |
1781 | *err = PEVENT_ERRNO__INVALID_EXP_TYPE; | ||
1690 | } | 1782 | } |
1691 | return 0; | 1783 | return 0; |
1692 | } | 1784 | } |
1693 | 1785 | ||
1694 | static unsigned long long | 1786 | static unsigned long long |
1695 | get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) | 1787 | get_arg_value(struct event_format *event, struct filter_arg *arg, |
1788 | struct pevent_record *record, enum pevent_errno *err) | ||
1696 | { | 1789 | { |
1697 | switch (arg->type) { | 1790 | switch (arg->type) { |
1698 | case FILTER_ARG_FIELD: | 1791 | case FILTER_ARG_FIELD: |
1699 | return get_value(event, arg->field.field, record); | 1792 | return get_value(event, arg->field.field, record); |
1700 | 1793 | ||
1701 | case FILTER_ARG_VALUE: | 1794 | case FILTER_ARG_VALUE: |
1702 | if (arg->value.type != FILTER_NUMBER) | 1795 | if (arg->value.type != FILTER_NUMBER) { |
1703 | die("must have number field!"); | 1796 | if (!*err) |
1797 | *err = PEVENT_ERRNO__NOT_A_NUMBER; | ||
1798 | } | ||
1704 | return arg->value.val; | 1799 | return arg->value.val; |
1705 | 1800 | ||
1706 | case FILTER_ARG_EXP: | 1801 | case FILTER_ARG_EXP: |
1707 | return get_exp_value(event, arg, record); | 1802 | return get_exp_value(event, arg, record, err); |
1708 | 1803 | ||
1709 | default: | 1804 | default: |
1710 | die("oops in filter"); | 1805 | if (!*err) |
1806 | *err = PEVENT_ERRNO__INVALID_ARG_TYPE; | ||
1711 | } | 1807 | } |
1712 | return 0; | 1808 | return 0; |
1713 | } | 1809 | } |
1714 | 1810 | ||
1715 | static int test_num(struct event_format *event, | 1811 | static int test_num(struct event_format *event, struct filter_arg *arg, |
1716 | struct filter_arg *arg, struct pevent_record *record) | 1812 | struct pevent_record *record, enum pevent_errno *err) |
1717 | { | 1813 | { |
1718 | unsigned long long lval, rval; | 1814 | unsigned long long lval, rval; |
1719 | 1815 | ||
1720 | lval = get_arg_value(event, arg->num.left, record); | 1816 | lval = get_arg_value(event, arg->num.left, record, err); |
1721 | rval = get_arg_value(event, arg->num.right, record); | 1817 | rval = get_arg_value(event, arg->num.right, record, err); |
1818 | |||
1819 | if (*err) { | ||
1820 | /* | ||
1821 | * There was an error, no need to process anymore. | ||
1822 | */ | ||
1823 | return 0; | ||
1824 | } | ||
1722 | 1825 | ||
1723 | switch (arg->num.type) { | 1826 | switch (arg->num.type) { |
1724 | case FILTER_CMP_EQ: | 1827 | case FILTER_CMP_EQ: |
@@ -1740,7 +1843,8 @@ static int test_num(struct event_format *event, | |||
1740 | return lval <= rval; | 1843 | return lval <= rval; |
1741 | 1844 | ||
1742 | default: | 1845 | default: |
1743 | /* ?? */ | 1846 | if (!*err) |
1847 | *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; | ||
1744 | return 0; | 1848 | return 0; |
1745 | } | 1849 | } |
1746 | } | 1850 | } |
@@ -1787,8 +1891,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r | |||
1787 | return val; | 1891 | return val; |
1788 | } | 1892 | } |
1789 | 1893 | ||
1790 | static int test_str(struct event_format *event, | 1894 | static int test_str(struct event_format *event, struct filter_arg *arg, |
1791 | struct filter_arg *arg, struct pevent_record *record) | 1895 | struct pevent_record *record, enum pevent_errno *err) |
1792 | { | 1896 | { |
1793 | const char *val; | 1897 | const char *val; |
1794 | 1898 | ||
@@ -1812,48 +1916,57 @@ static int test_str(struct event_format *event, | |||
1812 | return regexec(&arg->str.reg, val, 0, NULL, 0); | 1916 | return regexec(&arg->str.reg, val, 0, NULL, 0); |
1813 | 1917 | ||
1814 | default: | 1918 | default: |
1815 | /* ?? */ | 1919 | if (!*err) |
1920 | *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP; | ||
1816 | return 0; | 1921 | return 0; |
1817 | } | 1922 | } |
1818 | } | 1923 | } |
1819 | 1924 | ||
1820 | static int test_op(struct event_format *event, | 1925 | static int test_op(struct event_format *event, struct filter_arg *arg, |
1821 | struct filter_arg *arg, struct pevent_record *record) | 1926 | struct pevent_record *record, enum pevent_errno *err) |
1822 | { | 1927 | { |
1823 | switch (arg->op.type) { | 1928 | switch (arg->op.type) { |
1824 | case FILTER_OP_AND: | 1929 | case FILTER_OP_AND: |
1825 | return test_filter(event, arg->op.left, record) && | 1930 | return test_filter(event, arg->op.left, record, err) && |
1826 | test_filter(event, arg->op.right, record); | 1931 | test_filter(event, arg->op.right, record, err); |
1827 | 1932 | ||
1828 | case FILTER_OP_OR: | 1933 | case FILTER_OP_OR: |
1829 | return test_filter(event, arg->op.left, record) || | 1934 | return test_filter(event, arg->op.left, record, err) || |
1830 | test_filter(event, arg->op.right, record); | 1935 | test_filter(event, arg->op.right, record, err); |
1831 | 1936 | ||
1832 | case FILTER_OP_NOT: | 1937 | case FILTER_OP_NOT: |
1833 | return !test_filter(event, arg->op.right, record); | 1938 | return !test_filter(event, arg->op.right, record, err); |
1834 | 1939 | ||
1835 | default: | 1940 | default: |
1836 | /* ?? */ | 1941 | if (!*err) |
1942 | *err = PEVENT_ERRNO__INVALID_OP_TYPE; | ||
1837 | return 0; | 1943 | return 0; |
1838 | } | 1944 | } |
1839 | } | 1945 | } |
1840 | 1946 | ||
1841 | static int test_filter(struct event_format *event, | 1947 | static int test_filter(struct event_format *event, struct filter_arg *arg, |
1842 | struct filter_arg *arg, struct pevent_record *record) | 1948 | struct pevent_record *record, enum pevent_errno *err) |
1843 | { | 1949 | { |
1950 | if (*err) { | ||
1951 | /* | ||
1952 | * There was an error, no need to process anymore. | ||
1953 | */ | ||
1954 | return 0; | ||
1955 | } | ||
1956 | |||
1844 | switch (arg->type) { | 1957 | switch (arg->type) { |
1845 | case FILTER_ARG_BOOLEAN: | 1958 | case FILTER_ARG_BOOLEAN: |
1846 | /* easy case */ | 1959 | /* easy case */ |
1847 | return arg->boolean.value; | 1960 | return arg->boolean.value; |
1848 | 1961 | ||
1849 | case FILTER_ARG_OP: | 1962 | case FILTER_ARG_OP: |
1850 | return test_op(event, arg, record); | 1963 | return test_op(event, arg, record, err); |
1851 | 1964 | ||
1852 | case FILTER_ARG_NUM: | 1965 | case FILTER_ARG_NUM: |
1853 | return test_num(event, arg, record); | 1966 | return test_num(event, arg, record, err); |
1854 | 1967 | ||
1855 | case FILTER_ARG_STR: | 1968 | case FILTER_ARG_STR: |
1856 | return test_str(event, arg, record); | 1969 | return test_str(event, arg, record, err); |
1857 | 1970 | ||
1858 | case FILTER_ARG_EXP: | 1971 | case FILTER_ARG_EXP: |
1859 | case FILTER_ARG_VALUE: | 1972 | case FILTER_ARG_VALUE: |
@@ -1862,11 +1975,11 @@ static int test_filter(struct event_format *event, | |||
1862 | * Expressions, fields and values evaluate | 1975 | * Expressions, fields and values evaluate |
1863 | * to true if they return non zero | 1976 | * to true if they return non zero |
1864 | */ | 1977 | */ |
1865 | return !!get_arg_value(event, arg, record); | 1978 | return !!get_arg_value(event, arg, record, err); |
1866 | 1979 | ||
1867 | default: | 1980 | default: |
1868 | die("oops!"); | 1981 | if (!*err) |
1869 | /* ?? */ | 1982 | *err = PEVENT_ERRNO__INVALID_ARG_TYPE; |
1870 | return 0; | 1983 | return 0; |
1871 | } | 1984 | } |
1872 | } | 1985 | } |
@@ -1879,8 +1992,7 @@ static int test_filter(struct event_format *event, | |||
1879 | * Returns 1 if filter found for @event_id | 1992 | * Returns 1 if filter found for @event_id |
1880 | * otherwise 0; | 1993 | * otherwise 0; |
1881 | */ | 1994 | */ |
1882 | int pevent_event_filtered(struct event_filter *filter, | 1995 | int pevent_event_filtered(struct event_filter *filter, int event_id) |
1883 | int event_id) | ||
1884 | { | 1996 | { |
1885 | struct filter_type *filter_type; | 1997 | struct filter_type *filter_type; |
1886 | 1998 | ||
@@ -1897,31 +2009,36 @@ int pevent_event_filtered(struct event_filter *filter, | |||
1897 | * @filter: filter struct with filter information | 2009 | * @filter: filter struct with filter information |
1898 | * @record: the record to test against the filter | 2010 | * @record: the record to test against the filter |
1899 | * | 2011 | * |
1900 | * Returns: | 2012 | * Returns: match result or error code (prefixed with PEVENT_ERRNO__) |
1901 | * 1 - filter found for event and @record matches | 2013 | * FILTER_MATCH - filter found for event and @record matches |
1902 | * 0 - filter found for event and @record does not match | 2014 | * FILTER_MISS - filter found for event and @record does not match |
1903 | * -1 - no filter found for @record's event | 2015 | * FILTER_NOT_FOUND - no filter found for @record's event |
1904 | * -2 - if no filters exist | 2016 | * NO_FILTER - if no filters exist |
2017 | * otherwise - error occurred during test | ||
1905 | */ | 2018 | */ |
1906 | int pevent_filter_match(struct event_filter *filter, | 2019 | enum pevent_errno pevent_filter_match(struct event_filter *filter, |
1907 | struct pevent_record *record) | 2020 | struct pevent_record *record) |
1908 | { | 2021 | { |
1909 | struct pevent *pevent = filter->pevent; | 2022 | struct pevent *pevent = filter->pevent; |
1910 | struct filter_type *filter_type; | 2023 | struct filter_type *filter_type; |
1911 | int event_id; | 2024 | int event_id; |
2025 | int ret; | ||
2026 | enum pevent_errno err = 0; | ||
1912 | 2027 | ||
1913 | if (!filter->filters) | 2028 | if (!filter->filters) |
1914 | return FILTER_NONE; | 2029 | return PEVENT_ERRNO__NO_FILTER; |
1915 | 2030 | ||
1916 | event_id = pevent_data_type(pevent, record); | 2031 | event_id = pevent_data_type(pevent, record); |
1917 | 2032 | ||
1918 | filter_type = find_filter_type(filter, event_id); | 2033 | filter_type = find_filter_type(filter, event_id); |
1919 | |||
1920 | if (!filter_type) | 2034 | if (!filter_type) |
1921 | return FILTER_NOEXIST; | 2035 | return PEVENT_ERRNO__FILTER_NOT_FOUND; |
2036 | |||
2037 | ret = test_filter(filter_type->event, filter_type->filter, record, &err); | ||
2038 | if (err) | ||
2039 | return err; | ||
1922 | 2040 | ||
1923 | return test_filter(filter_type->event, filter_type->filter, record) ? | 2041 | return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS; |
1924 | FILTER_MATCH : FILTER_MISS; | ||
1925 | } | 2042 | } |
1926 | 2043 | ||
1927 | static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | 2044 | static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 025de796067c..3170a7ff5782 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -2,6 +2,8 @@ tools/perf | |||
2 | tools/scripts | 2 | tools/scripts |
3 | tools/lib/traceevent | 3 | tools/lib/traceevent |
4 | tools/lib/lk | 4 | tools/lib/lk |
5 | tools/lib/symbol/kallsyms.c | ||
6 | tools/lib/symbol/kallsyms.h | ||
5 | include/linux/const.h | 7 | include/linux/const.h |
6 | include/linux/perf_event.h | 8 | include/linux/perf_event.h |
7 | include/linux/rbtree.h | 9 | include/linux/rbtree.h |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 9a8cf376f874..fad61079e795 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -202,6 +202,7 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c | |||
202 | 202 | ||
203 | LIB_FILE=$(OUTPUT)libperf.a | 203 | LIB_FILE=$(OUTPUT)libperf.a |
204 | 204 | ||
205 | LIB_H += ../lib/symbol/kallsyms.h | ||
205 | LIB_H += ../../include/uapi/linux/perf_event.h | 206 | LIB_H += ../../include/uapi/linux/perf_event.h |
206 | LIB_H += ../../include/linux/rbtree.h | 207 | LIB_H += ../../include/linux/rbtree.h |
207 | LIB_H += ../../include/linux/list.h | 208 | LIB_H += ../../include/linux/list.h |
@@ -312,6 +313,7 @@ LIB_OBJS += $(OUTPUT)util/evlist.o | |||
312 | LIB_OBJS += $(OUTPUT)util/evsel.o | 313 | LIB_OBJS += $(OUTPUT)util/evsel.o |
313 | LIB_OBJS += $(OUTPUT)util/exec_cmd.o | 314 | LIB_OBJS += $(OUTPUT)util/exec_cmd.o |
314 | LIB_OBJS += $(OUTPUT)util/help.o | 315 | LIB_OBJS += $(OUTPUT)util/help.o |
316 | LIB_OBJS += $(OUTPUT)util/kallsyms.o | ||
315 | LIB_OBJS += $(OUTPUT)util/levenshtein.o | 317 | LIB_OBJS += $(OUTPUT)util/levenshtein.o |
316 | LIB_OBJS += $(OUTPUT)util/parse-options.o | 318 | LIB_OBJS += $(OUTPUT)util/parse-options.o |
317 | LIB_OBJS += $(OUTPUT)util/parse-events.o | 319 | LIB_OBJS += $(OUTPUT)util/parse-events.o |
@@ -672,6 +674,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS | |||
672 | $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS | 674 | $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS |
673 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | 675 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< |
674 | 676 | ||
677 | $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS | ||
678 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< | ||
679 | |||
675 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS | 680 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS |
676 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 681 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
677 | 682 | ||
diff --git a/tools/perf/perf-completion.sh b/tools/perf/perf-completion.sh index 49494882d9bb..496e2abb5482 100644 --- a/tools/perf/perf-completion.sh +++ b/tools/perf/perf-completion.sh | |||
@@ -121,6 +121,10 @@ __perf_main () | |||
121 | elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then | 121 | elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then |
122 | evts=$($cmd list --raw-dump) | 122 | evts=$($cmd list --raw-dump) |
123 | __perfcomp_colon "$evts" "$cur" | 123 | __perfcomp_colon "$evts" "$cur" |
124 | # List subcommands for 'perf kvm' | ||
125 | elif [[ $prev == "kvm" ]]; then | ||
126 | subcmds="top record report diff buildid-list stat" | ||
127 | __perfcomp_colon "$subcmds" "$cur" | ||
124 | # List long option names | 128 | # List long option names |
125 | elif [[ $cur == --* ]]; then | 129 | elif [[ $cur == --* ]]; then |
126 | subcmd=${words[1]} | 130 | subcmd=${words[1]} |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index c77814bf01e1..694876877ae2 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "strlist.h" | 7 | #include "strlist.h" |
8 | #include "thread.h" | 8 | #include "thread.h" |
9 | #include "thread_map.h" | 9 | #include "thread_map.h" |
10 | #include "symbol/kallsyms.h" | ||
10 | 11 | ||
11 | static const char *perf_event__names[] = { | 12 | static const char *perf_event__names[] = { |
12 | [0] = "TOTAL", | 13 | [0] = "TOTAL", |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index af250556b33f..0b31cee34874 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -1191,8 +1191,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1191 | "Error:\t%s.\n" | 1191 | "Error:\t%s.\n" |
1192 | "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); | 1192 | "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); |
1193 | 1193 | ||
1194 | if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value)) | 1194 | value = perf_event_paranoid(); |
1195 | break; | ||
1196 | 1195 | ||
1197 | printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); | 1196 | printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); |
1198 | 1197 | ||
@@ -1213,3 +1212,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1213 | 1212 | ||
1214 | return 0; | 1213 | return 0; |
1215 | } | 1214 | } |
1215 | |||
1216 | void perf_evlist__to_front(struct perf_evlist *evlist, | ||
1217 | struct perf_evsel *move_evsel) | ||
1218 | { | ||
1219 | struct perf_evsel *evsel, *n; | ||
1220 | LIST_HEAD(move); | ||
1221 | |||
1222 | if (move_evsel == perf_evlist__first(evlist)) | ||
1223 | return; | ||
1224 | |||
1225 | list_for_each_entry_safe(evsel, n, &evlist->entries, node) { | ||
1226 | if (evsel->leader == move_evsel->leader) | ||
1227 | list_move_tail(&evsel->node, &move); | ||
1228 | } | ||
1229 | |||
1230 | list_splice(&move, &evlist->entries); | ||
1231 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 649d6ea98a84..9f64ede3ecbd 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -193,4 +193,9 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md, | |||
193 | pc->data_tail = tail; | 193 | pc->data_tail = tail; |
194 | } | 194 | } |
195 | 195 | ||
196 | bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str); | ||
197 | void perf_evlist__to_front(struct perf_evlist *evlist, | ||
198 | struct perf_evsel *move_evsel); | ||
199 | |||
200 | |||
196 | #endif /* __PERF_EVLIST_H */ | 201 | #endif /* __PERF_EVLIST_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 0bb830f6b49c..61c54213704b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -2327,7 +2327,8 @@ int perf_session__write_header(struct perf_session *session, | |||
2327 | } | 2327 | } |
2328 | } | 2328 | } |
2329 | 2329 | ||
2330 | header->data_offset = lseek(fd, 0, SEEK_CUR); | 2330 | if (!header->data_offset) |
2331 | header->data_offset = lseek(fd, 0, SEEK_CUR); | ||
2331 | header->feat_offset = header->data_offset + header->data_size; | 2332 | header->feat_offset = header->data_offset + header->data_size; |
2332 | 2333 | ||
2333 | if (at_exit) { | 2334 | if (at_exit) { |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 751454bcde69..c78cc84f433e 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "strlist.h" | 9 | #include "strlist.h" |
10 | #include "thread.h" | 10 | #include "thread.h" |
11 | #include <stdbool.h> | 11 | #include <stdbool.h> |
12 | #include <symbol/kallsyms.h> | ||
12 | #include "unwind.h" | 13 | #include "unwind.h" |
13 | 14 | ||
14 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 15 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index c8845b107f60..e5104538c354 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
@@ -177,3 +177,40 @@ int perf_record_opts__config(struct perf_record_opts *opts) | |||
177 | { | 177 | { |
178 | return perf_record_opts__config_freq(opts); | 178 | return perf_record_opts__config_freq(opts); |
179 | } | 179 | } |
180 | |||
181 | bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) | ||
182 | { | ||
183 | struct perf_evlist *temp_evlist; | ||
184 | struct perf_evsel *evsel; | ||
185 | int err, fd, cpu; | ||
186 | bool ret = false; | ||
187 | |||
188 | temp_evlist = perf_evlist__new(); | ||
189 | if (!temp_evlist) | ||
190 | return false; | ||
191 | |||
192 | err = parse_events(temp_evlist, str); | ||
193 | if (err) | ||
194 | goto out_delete; | ||
195 | |||
196 | evsel = perf_evlist__last(temp_evlist); | ||
197 | |||
198 | if (!evlist || cpu_map__empty(evlist->cpus)) { | ||
199 | struct cpu_map *cpus = cpu_map__new(NULL); | ||
200 | |||
201 | cpu = cpus ? cpus->map[0] : 0; | ||
202 | cpu_map__delete(cpus); | ||
203 | } else { | ||
204 | cpu = evlist->cpus->map[0]; | ||
205 | } | ||
206 | |||
207 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); | ||
208 | if (fd >= 0) { | ||
209 | close(fd); | ||
210 | ret = true; | ||
211 | } | ||
212 | |||
213 | out_delete: | ||
214 | perf_evlist__delete(temp_evlist); | ||
215 | return ret; | ||
216 | } | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e748f29c53cf..989b2e377626 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -247,27 +247,6 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
247 | } | 247 | } |
248 | } | 248 | } |
249 | 249 | ||
250 | void mem_bswap_32(void *src, int byte_size) | ||
251 | { | ||
252 | u32 *m = src; | ||
253 | while (byte_size > 0) { | ||
254 | *m = bswap_32(*m); | ||
255 | byte_size -= sizeof(u32); | ||
256 | ++m; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | void mem_bswap_64(void *src, int byte_size) | ||
261 | { | ||
262 | u64 *m = src; | ||
263 | |||
264 | while (byte_size > 0) { | ||
265 | *m = bswap_64(*m); | ||
266 | byte_size -= sizeof(u64); | ||
267 | ++m; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | static void swap_sample_id_all(union perf_event *event, void *data) | 250 | static void swap_sample_id_all(union perf_event *event, void *data) |
272 | { | 251 | { |
273 | void *end = (void *) event + event->header.size; | 252 | void *end = (void *) event + event->header.size; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 2a3955ea4fd8..9c25d49900af 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -74,8 +74,6 @@ int perf_session__resolve_callchain(struct perf_session *session, | |||
74 | 74 | ||
75 | bool perf_session__has_traces(struct perf_session *session, const char *msg); | 75 | bool perf_session__has_traces(struct perf_session *session, const char *msg); |
76 | 76 | ||
77 | void mem_bswap_64(void *src, int byte_size); | ||
78 | void mem_bswap_32(void *src, int byte_size); | ||
79 | void perf_event__attr_swap(struct perf_event_attr *attr); | 77 | void perf_event__attr_swap(struct perf_event_attr *attr); |
80 | 78 | ||
81 | int perf_session__create_kernel_maps(struct perf_session *session); | 79 | int perf_session__create_kernel_maps(struct perf_session *session); |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index eed0b96302af..bf0ce29567b6 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <inttypes.h> | 6 | #include <inttypes.h> |
7 | 7 | ||
8 | #include "symbol.h" | 8 | #include "symbol.h" |
9 | #include <symbol/kallsyms.h> | ||
9 | #include "debug.h" | 10 | #include "debug.h" |
10 | 11 | ||
11 | #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT | 12 | #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e377c2e96191..61eb1cddf01a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -18,12 +18,9 @@ | |||
18 | 18 | ||
19 | #include <elf.h> | 19 | #include <elf.h> |
20 | #include <limits.h> | 20 | #include <limits.h> |
21 | #include <symbol/kallsyms.h> | ||
21 | #include <sys/utsname.h> | 22 | #include <sys/utsname.h> |
22 | 23 | ||
23 | #ifndef KSYM_NAME_LEN | ||
24 | #define KSYM_NAME_LEN 256 | ||
25 | #endif | ||
26 | |||
27 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, | 24 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
28 | symbol_filter_t filter); | 25 | symbol_filter_t filter); |
29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | 26 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
@@ -446,62 +443,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso, | |||
446 | return ret; | 443 | return ret; |
447 | } | 444 | } |
448 | 445 | ||
449 | int kallsyms__parse(const char *filename, void *arg, | ||
450 | int (*process_symbol)(void *arg, const char *name, | ||
451 | char type, u64 start)) | ||
452 | { | ||
453 | char *line = NULL; | ||
454 | size_t n; | ||
455 | int err = -1; | ||
456 | FILE *file = fopen(filename, "r"); | ||
457 | |||
458 | if (file == NULL) | ||
459 | goto out_failure; | ||
460 | |||
461 | err = 0; | ||
462 | |||
463 | while (!feof(file)) { | ||
464 | u64 start; | ||
465 | int line_len, len; | ||
466 | char symbol_type; | ||
467 | char *symbol_name; | ||
468 | |||
469 | line_len = getline(&line, &n, file); | ||
470 | if (line_len < 0 || !line) | ||
471 | break; | ||
472 | |||
473 | line[--line_len] = '\0'; /* \n */ | ||
474 | |||
475 | len = hex2u64(line, &start); | ||
476 | |||
477 | len++; | ||
478 | if (len + 2 >= line_len) | ||
479 | continue; | ||
480 | |||
481 | symbol_type = line[len]; | ||
482 | len += 2; | ||
483 | symbol_name = line + len; | ||
484 | len = line_len - len; | ||
485 | |||
486 | if (len >= KSYM_NAME_LEN) { | ||
487 | err = -1; | ||
488 | break; | ||
489 | } | ||
490 | |||
491 | err = process_symbol(arg, symbol_name, | ||
492 | symbol_type, start); | ||
493 | if (err) | ||
494 | break; | ||
495 | } | ||
496 | |||
497 | free(line); | ||
498 | fclose(file); | ||
499 | return err; | ||
500 | |||
501 | out_failure: | ||
502 | return -1; | ||
503 | } | ||
504 | |||
505 | int modules__parse(const char *filename, void *arg, | 446 | int modules__parse(const char *filename, void *arg, |
506 | int (*process_module)(void *arg, const char *name, | 447 | int (*process_module)(void *arg, const char *name, |
507 | u64 start)) | 448 | u64 start)) |
@@ -565,14 +506,6 @@ struct process_kallsyms_args { | |||
565 | struct dso *dso; | 506 | struct dso *dso; |
566 | }; | 507 | }; |
567 | 508 | ||
568 | static u8 kallsyms2elf_type(char type) | ||
569 | { | ||
570 | if (type == 'W') | ||
571 | return STB_WEAK; | ||
572 | |||
573 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | ||
574 | } | ||
575 | |||
576 | bool symbol__is_idle(struct symbol *sym) | 509 | bool symbol__is_idle(struct symbol *sym) |
577 | { | 510 | { |
578 | const char * const idle_symbols[] = { | 511 | const char * const idle_symbols[] = { |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 6de9c2b8a601..8a9d910c5345 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -221,9 +221,6 @@ struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); | |||
221 | 221 | ||
222 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 222 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
223 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 223 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
224 | int kallsyms__parse(const char *filename, void *arg, | ||
225 | int (*process_symbol)(void *arg, const char *name, | ||
226 | char type, u64 start)); | ||
227 | int modules__parse(const char *filename, void *arg, | 224 | int modules__parse(const char *filename, void *arg, |
228 | int (*process_module)(void *arg, const char *name, | 225 | int (*process_module)(void *arg, const char *name, |
229 | u64 start)); | 226 | u64 start)); |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 49eaf1d7d89d..e3948612543e 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -126,7 +126,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) | |||
126 | if (!comm) | 126 | if (!comm) |
127 | return -ENOMEM; | 127 | return -ENOMEM; |
128 | err = thread__set_comm(thread, comm, timestamp); | 128 | err = thread__set_comm(thread, comm, timestamp); |
129 | if (!err) | 129 | if (err) |
130 | return err; | 130 | return err; |
131 | thread->comm_set = true; | 131 | thread->comm_set = true; |
132 | } | 132 | } |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 4a57609c0b43..42ad667bb317 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "../perf.h" | 1 | #include "../perf.h" |
2 | #include "util.h" | 2 | #include "util.h" |
3 | #include "fs.h" | ||
3 | #include <sys/mman.h> | 4 | #include <sys/mman.h> |
4 | #ifdef HAVE_BACKTRACE_SUPPORT | 5 | #ifdef HAVE_BACKTRACE_SUPPORT |
5 | #include <execinfo.h> | 6 | #include <execinfo.h> |
@@ -8,6 +9,8 @@ | |||
8 | #include <stdlib.h> | 9 | #include <stdlib.h> |
9 | #include <string.h> | 10 | #include <string.h> |
10 | #include <errno.h> | 11 | #include <errno.h> |
12 | #include <limits.h> | ||
13 | #include <byteswap.h> | ||
11 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
12 | 15 | ||
13 | /* | 16 | /* |
@@ -496,3 +499,41 @@ const char *get_filename_for_perf_kvm(void) | |||
496 | 499 | ||
497 | return filename; | 500 | return filename; |
498 | } | 501 | } |
502 | |||
503 | int perf_event_paranoid(void) | ||
504 | { | ||
505 | char path[PATH_MAX]; | ||
506 | const char *procfs = procfs__mountpoint(); | ||
507 | int value; | ||
508 | |||
509 | if (!procfs) | ||
510 | return INT_MAX; | ||
511 | |||
512 | scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs); | ||
513 | |||
514 | if (filename__read_int(path, &value)) | ||
515 | return INT_MAX; | ||
516 | |||
517 | return value; | ||
518 | } | ||
519 | |||
520 | void mem_bswap_32(void *src, int byte_size) | ||
521 | { | ||
522 | u32 *m = src; | ||
523 | while (byte_size > 0) { | ||
524 | *m = bswap_32(*m); | ||
525 | byte_size -= sizeof(u32); | ||
526 | ++m; | ||
527 | } | ||
528 | } | ||
529 | |||
530 | void mem_bswap_64(void *src, int byte_size) | ||
531 | { | ||
532 | u64 *m = src; | ||
533 | |||
534 | while (byte_size > 0) { | ||
535 | *m = bswap_64(*m); | ||
536 | byte_size -= sizeof(u64); | ||
537 | ++m; | ||
538 | } | ||
539 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 0171213d1d4d..a1eea3e809a3 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -321,6 +321,10 @@ void free_srcline(char *srcline); | |||
321 | 321 | ||
322 | int filename__read_int(const char *filename, int *value); | 322 | int filename__read_int(const char *filename, int *value); |
323 | int filename__read_str(const char *filename, char **buf, size_t *sizep); | 323 | int filename__read_str(const char *filename, char **buf, size_t *sizep); |
324 | int perf_event_paranoid(void); | ||
325 | |||
326 | void mem_bswap_64(void *src, int byte_size); | ||
327 | void mem_bswap_32(void *src, int byte_size); | ||
324 | 328 | ||
325 | const char *get_filename_for_perf_kvm(void); | 329 | const char *get_filename_for_perf_kvm(void); |
326 | #endif /* GIT_COMPAT_UTIL_H */ | 330 | #endif /* GIT_COMPAT_UTIL_H */ |