Commit b283d2f3 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents fe361cfc 41e12e58
#include "symbol/kallsyms.h"
#include <stdio.h>
#include <stdlib.h>
int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name,
char type, u64 start))
{
char *line = NULL;
size_t n;
int err = -1;
FILE *file = fopen(filename, "r");
if (file == NULL)
goto out_failure;
err = 0;
while (!feof(file)) {
u64 start;
int line_len, len;
char symbol_type;
char *symbol_name;
line_len = getline(&line, &n, file);
if (line_len < 0 || !line)
break;
line[--line_len] = '\0'; /* \n */
len = hex2u64(line, &start);
len++;
if (len + 2 >= line_len)
continue;
symbol_type = line[len];
len += 2;
symbol_name = line + len;
len = line_len - len;
if (len >= KSYM_NAME_LEN) {
err = -1;
break;
}
err = process_symbol(arg, symbol_name, symbol_type, start);
if (err)
break;
}
free(line);
fclose(file);
return err;
out_failure:
return -1;
}
#ifndef __TOOLS_KALLSYMS_H_
#define __TOOLS_KALLSYMS_H_ 1
#include <elf.h>
#include <linux/ctype.h>
#include <linux/types.h>
#ifndef KSYM_NAME_LEN
#define KSYM_NAME_LEN 256
#endif
static inline u8 kallsyms2elf_type(char type)
{
if (type == 'W')
return STB_WEAK;
return isupper(type) ? STB_GLOBAL : STB_LOCAL;
}
int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name,
char type, u64 start));
#endif /* __TOOLS_KALLSYMS_H_ */
...@@ -356,12 +356,35 @@ enum pevent_flag { ...@@ -356,12 +356,35 @@ enum pevent_flag {
_PE(READ_FORMAT_FAILED, "failed to read event format"), \ _PE(READ_FORMAT_FAILED, "failed to read event format"), \
_PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \
_PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\
_PE(INVALID_ARG_TYPE, "invalid argument type") _PE(INVALID_ARG_TYPE, "invalid argument type"), \
_PE(INVALID_EXP_TYPE, "invalid expression type"), \
_PE(INVALID_OP_TYPE, "invalid operator type"), \
_PE(INVALID_EVENT_NAME, "invalid event name"), \
_PE(EVENT_NOT_FOUND, "no event found"), \
_PE(SYNTAX_ERROR, "syntax error"), \
_PE(ILLEGAL_RVALUE, "illegal rvalue"), \
_PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \
_PE(INVALID_REGEX, "regex did not compute"), \
_PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \
_PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \
_PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \
_PE(REPARENT_FAILED, "failed to reparent filter OP"), \
_PE(BAD_FILTER_ARG, "bad arg in filter tree"), \
_PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \
_PE(ILLEGAL_TOKEN, "illegal token"), \
_PE(INVALID_PAREN, "open parenthesis cannot come here"), \
_PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \
_PE(UNKNOWN_TOKEN, "unknown token"), \
_PE(FILTER_NOT_FOUND, "no filter found"), \
_PE(NOT_A_NUMBER, "must have number field"), \
_PE(NO_FILTER, "no filters exists"), \
_PE(FILTER_MISS, "record does not match to filter")
#undef _PE #undef _PE
#define _PE(__code, __str) PEVENT_ERRNO__ ## __code #define _PE(__code, __str) PEVENT_ERRNO__ ## __code
enum pevent_errno { enum pevent_errno {
PEVENT_ERRNO__SUCCESS = 0, PEVENT_ERRNO__SUCCESS = 0,
PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS,
/* /*
* Choose an arbitrary negative big number not to clash with standard * Choose an arbitrary negative big number not to clash with standard
...@@ -836,10 +859,11 @@ struct event_filter { ...@@ -836,10 +859,11 @@ struct event_filter {
struct event_filter *pevent_filter_alloc(struct pevent *pevent); struct event_filter *pevent_filter_alloc(struct pevent *pevent);
#define FILTER_NONE -2 /* for backward compatibility */
#define FILTER_NOEXIST -1 #define FILTER_NONE PEVENT_ERRNO__FILTER_NOT_FOUND
#define FILTER_MISS 0 #define FILTER_NOEXIST PEVENT_ERRNO__NO_FILTER
#define FILTER_MATCH 1 #define FILTER_MISS PEVENT_ERRNO__FILTER_MISS
#define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH
enum filter_trivial_type { enum filter_trivial_type {
FILTER_TRIVIAL_FALSE, FILTER_TRIVIAL_FALSE,
...@@ -847,13 +871,12 @@ enum filter_trivial_type { ...@@ -847,13 +871,12 @@ enum filter_trivial_type {
FILTER_TRIVIAL_BOTH, FILTER_TRIVIAL_BOTH,
}; };
int pevent_filter_add_filter_str(struct event_filter *filter, enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
const char *filter_str, const char *filter_str);
char **error_str);
int pevent_filter_match(struct event_filter *filter, enum pevent_errno pevent_filter_match(struct event_filter *filter,
struct pevent_record *record); struct pevent_record *record);
int pevent_event_filtered(struct event_filter *filter, int pevent_event_filtered(struct event_filter *filter,
int event_id); int event_id);
......
...@@ -56,7 +56,21 @@ static void show_error(char **error_str, const char *fmt, ...) ...@@ -56,7 +56,21 @@ static void show_error(char **error_str, const char *fmt, ...)
index = pevent_get_input_buf_ptr(); index = pevent_get_input_buf_ptr();
len = input ? strlen(input) : 0; len = input ? strlen(input) : 0;
error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3); error = malloc(MAX_ERR_STR_SIZE + (len*2) + 3);
if (error == NULL) {
/*
* Maybe it's due to len is too long.
* Retry without the input buffer part.
*/
len = 0;
error = malloc(MAX_ERR_STR_SIZE);
if (error == NULL) {
/* no memory */
*error_str = NULL;
return;
}
}
if (len) { if (len) {
strcpy(error, input); strcpy(error, input);
...@@ -95,7 +109,11 @@ static enum event_type read_token(char **tok) ...@@ -95,7 +109,11 @@ static enum event_type read_token(char **tok)
(strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
pevent_peek_char() == '~') { pevent_peek_char() == '~') {
/* append it */ /* append it */
*tok = malloc_or_die(3); *tok = malloc(3);
if (*tok == NULL) {
free_token(token);
return EVENT_ERROR;
}
sprintf(*tok, "%c%c", *token, '~'); sprintf(*tok, "%c%c", *token, '~');
free_token(token); free_token(token);
/* Now remove the '~' from the buffer */ /* Now remove the '~' from the buffer */
...@@ -147,11 +165,13 @@ add_filter_type(struct event_filter *filter, int id) ...@@ -147,11 +165,13 @@ add_filter_type(struct event_filter *filter, int id)
if (filter_type) if (filter_type)
return filter_type; return filter_type;
filter->event_filters = realloc(filter->event_filters, filter_type = realloc(filter->event_filters,
sizeof(*filter->event_filters) * sizeof(*filter->event_filters) *
(filter->filters + 1)); (filter->filters + 1));
if (!filter->event_filters) if (!filter_type)
die("Could not allocate filter"); return NULL;
filter->event_filters = filter_type;
for (i = 0; i < filter->filters; i++) { for (i = 0; i < filter->filters; i++) {
if (filter->event_filters[i].event_id > id) if (filter->event_filters[i].event_id > id)
...@@ -195,12 +215,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) ...@@ -195,12 +215,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
static struct filter_arg *allocate_arg(void) static struct filter_arg *allocate_arg(void)
{ {
struct filter_arg *arg; return calloc(1, sizeof(struct filter_arg));
arg = malloc_or_die(sizeof(*arg));
memset(arg, 0, sizeof(*arg));
return arg;
} }
static void free_arg(struct filter_arg *arg) static void free_arg(struct filter_arg *arg)
...@@ -272,7 +287,7 @@ static int event_match(struct event_format *event, ...@@ -272,7 +287,7 @@ static int event_match(struct event_format *event,
!regexec(ereg, event->name, 0, NULL, 0); !regexec(ereg, event->name, 0, NULL, 0);
} }
static int static enum pevent_errno
find_event(struct pevent *pevent, struct event_list **events, find_event(struct pevent *pevent, struct event_list **events,
char *sys_name, char *event_name) char *sys_name, char *event_name)
{ {
...@@ -291,23 +306,31 @@ find_event(struct pevent *pevent, struct event_list **events, ...@@ -291,23 +306,31 @@ find_event(struct pevent *pevent, struct event_list **events,
sys_name = NULL; sys_name = NULL;
} }
reg = malloc_or_die(strlen(event_name) + 3); reg = malloc(strlen(event_name) + 3);
if (reg == NULL)
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
sprintf(reg, "^%s$", event_name); sprintf(reg, "^%s$", event_name);
ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
free(reg); free(reg);
if (ret) if (ret)
return -1; return PEVENT_ERRNO__INVALID_EVENT_NAME;
if (sys_name) { if (sys_name) {
reg = malloc_or_die(strlen(sys_name) + 3); reg = malloc(strlen(sys_name) + 3);
if (reg == NULL) {
regfree(&ereg);
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
}
sprintf(reg, "^%s$", sys_name); sprintf(reg, "^%s$", sys_name);
ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
free(reg); free(reg);
if (ret) { if (ret) {
regfree(&ereg); regfree(&ereg);
return -1; return PEVENT_ERRNO__INVALID_EVENT_NAME;
} }
} }
...@@ -327,9 +350,9 @@ find_event(struct pevent *pevent, struct event_list **events, ...@@ -327,9 +350,9 @@ find_event(struct pevent *pevent, struct event_list **events,
regfree(&sreg); regfree(&sreg);
if (!match) if (!match)
return -1; return PEVENT_ERRNO__EVENT_NOT_FOUND;
if (fail) if (fail)
return -2; return PEVENT_ERRNO__MEM_ALLOC_FAILED;
return 0; return 0;
} }
...@@ -345,14 +368,18 @@ static void free_events(struct event_list *events) ...@@ -345,14 +368,18 @@ static void free_events(struct event_list *events)
} }
} }
static struct filter_arg * static enum pevent_errno
create_arg_item(struct event_format *event, const char *token, create_arg_item(struct event_format *event, const char *token,
enum event_type type, char **error_str) enum event_type type, struct filter_arg **parg, char **error_str)
{ {
struct format_field *field; struct format_field *field;
struct filter_arg *arg; struct filter_arg *arg;
arg = allocate_arg(); arg = allocate_arg();
if (arg == NULL) {
show_error(error_str, "failed to allocate filter arg");
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
}
switch (type) { switch (type) {
...@@ -365,7 +392,7 @@ create_arg_item(struct event_format *event, const char *token, ...@@ -365,7 +392,7 @@ create_arg_item(struct event_format *event, const char *token,
if (!arg->value.str) { if (!arg->value.str) {
free_arg(arg); free_arg(arg);
show_error(error_str, "failed to allocate string filter arg"); show_error(error_str, "failed to allocate string filter arg");
return NULL; return PEVENT_ERRNO__MEM_ALLOC_FAILED;
} }
break; break;
case EVENT_ITEM: case EVENT_ITEM:
...@@ -393,11 +420,11 @@ create_arg_item(struct event_format *event, const char *token, ...@@ -393,11 +420,11 @@ create_arg_item(struct event_format *event, const char *token,
break; break;
default: default:
free_arg(arg); free_arg(arg);
show_error(error_str, "expected a value but found %s", show_error(error_str, "expected a value but found %s", token);
token); return PEVENT_ERRNO__UNEXPECTED_TYPE;
return NULL;
} }
return arg; *parg = arg;
return 0;
} }
static struct filter_arg * static struct filter_arg *
...@@ -406,6 +433,9 @@ create_arg_op(enum filter_op_type btype) ...@@ -406,6 +433,9 @@ create_arg_op(enum filter_op_type btype)
struct filter_arg *arg; struct filter_arg *arg;
arg = allocate_arg(); arg = allocate_arg();
if (!arg)
return NULL;
arg->type = FILTER_ARG_OP; arg->type = FILTER_ARG_OP;
arg->op.type = btype; arg->op.type = btype;
...@@ -418,6 +448,9 @@ create_arg_exp(enum filter_exp_type etype) ...@@ -418,6 +448,9 @@ create_arg_exp(enum filter_exp_type etype)
struct filter_arg *arg; struct filter_arg *arg;
arg = allocate_arg(); arg = allocate_arg();
if (!arg)
return NULL;
arg->type = FILTER_ARG_EXP; arg->type = FILTER_ARG_EXP;
arg->op.type = etype; arg->op.type = etype;
...@@ -430,6 +463,9 @@ create_arg_cmp(enum filter_exp_type etype) ...@@ -430,6 +463,9 @@ create_arg_cmp(enum filter_exp_type etype)
struct filter_arg *arg; struct filter_arg *arg;
arg = allocate_arg(); arg = allocate_arg();
if (!arg)
return NULL;
/* Use NUM and change if necessary */ /* Use NUM and change if necessary */
arg->type = FILTER_ARG_NUM; arg->type = FILTER_ARG_NUM;
arg->op.type = etype; arg->op.type = etype;
...@@ -437,8 +473,8 @@ create_arg_cmp(enum filter_exp_type etype) ...@@ -437,8 +473,8 @@ create_arg_cmp(enum filter_exp_type etype)
return arg; return arg;
} }
static int add_right(struct filter_arg *op, struct filter_arg *arg, static enum pevent_errno
char **error_str) add_right(struct filter_arg *op, struct filter_arg *arg, char **error_str)
{ {
struct filter_arg *left; struct filter_arg *left;
char *str; char *str;
...@@ -469,9 +505,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, ...@@ -469,9 +505,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
case FILTER_ARG_FIELD: case FILTER_ARG_FIELD:
break; break;
default: default:
show_error(error_str, show_error(error_str, "Illegal rvalue");
"Illegal rvalue"); return PEVENT_ERRNO__ILLEGAL_RVALUE;
return -1;
} }
/* /*
...@@ -518,7 +553,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, ...@@ -518,7 +553,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
if (left->type != FILTER_ARG_FIELD) { if (left->type != FILTER_ARG_FIELD) {
show_error(error_str, show_error(error_str,
"Illegal lvalue for string comparison"); "Illegal lvalue for string comparison");
return -1; return PEVENT_ERRNO__ILLEGAL_LVALUE;
} }
/* Make sure this is a valid string compare */ /* 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,25 +572,31 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
show_error(error_str, show_error(error_str,
"RegEx '%s' did not compute", "RegEx '%s' did not compute",
str); str);
return -1; return PEVENT_ERRNO__INVALID_REGEX;
} }
break; break;
default: default:
show_error(error_str, show_error(error_str,
"Illegal comparison for string"); "Illegal comparison for string");
return -1; return PEVENT_ERRNO__ILLEGAL_STRING_CMP;
} }
op->type = FILTER_ARG_STR; op->type = FILTER_ARG_STR;
op->str.type = op_type; op->str.type = op_type;
op->str.field = left->field.field; op->str.field = left->field.field;
op->str.val = strdup(str); op->str.val = strdup(str);
if (!op->str.val) if (!op->str.val) {
die("malloc string"); show_error(error_str, "Failed to allocate string filter");
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
}
/* /*
* Need a buffer to copy data for tests * Need a buffer to copy data for tests
*/ */
op->str.buffer = malloc_or_die(op->str.field->size + 1); op->str.buffer = malloc(op->str.field->size + 1);
if (!op->str.buffer) {
show_error(error_str, "Failed to allocate string filter");
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
}
/* Null terminate this buffer */ /* Null terminate this buffer */
op->str.buffer[op->str.field->size] = 0; op->str.buffer[op->str.field->size] = 0;
...@@ -573,7 +614,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, ...@@ -573,7 +614,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
case FILTER_CMP_NOT_REGEX: case FILTER_CMP_NOT_REGEX:
show_error(error_str, show_error(error_str,
"Op not allowed with integers"); "Op not allowed with integers");
return -1; return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
default: default:
break; break;
...@@ -593,9 +634,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, ...@@ -593,9 +634,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
return 0; return 0;
out_fail: out_fail:
show_error(error_str, show_error(error_str, "Syntax error");
"Syntax error"); return PEVENT_ERRNO__SYNTAX_ERROR;
return -1;
} }
static struct filter_arg * static struct filter_arg *
...@@ -608,7 +648,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b) ...@@ -608,7 +648,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b)
return arg; return arg;
} }
static int add_left(struct filter_arg *op, struct filter_arg *arg) static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg)
{ {
switch (op->type) { switch (op->type) {
case FILTER_ARG_EXP: case FILTER_ARG_EXP:
...@@ -627,11 +667,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg) ...@@ -627,11 +667,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg)
/* left arg of compares must be a field */ /* left arg of compares must be a field */
if (arg->type != FILTER_ARG_FIELD && if (arg->type != FILTER_ARG_FIELD &&
arg->type != FILTER_ARG_BOOLEAN) arg->type != FILTER_ARG_BOOLEAN)
return -1; return PEVENT_ERRNO__INVALID_ARG_TYPE;
op->num.left = arg; op->num.left = arg;
break; break;
default: default:
return -1; return PEVENT_ERRNO__INVALID_ARG_TYPE;
} }
return 0; return 0;
} }
...@@ -744,15 +784,18 @@ enum filter_vals { ...@@ -744,15 +784,18 @@ enum filter_vals {
FILTER_VAL_TRUE, FILTER_VAL_TRUE,
}; };
void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, static enum pevent_errno
struct filter_arg *arg) reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
struct filter_arg *arg, char **error_str)
{ {
struct filter_arg *other_child; struct filter_arg *other_child;
struct filter_arg **ptr; struct filter_arg **ptr;
if (parent->type != FILTER_ARG_OP && if (parent->type != FILTER_ARG_OP &&
arg->type != FILTER_ARG_OP) arg->type != FILTER_ARG_OP) {
die("can not reparent other than OP"); show_error(error_str, "can not reparent other than OP");
return PEVENT_ERRNO__REPARENT_NOT_OP;
}
/* Get the sibling */ /* Get the sibling */
if (old_child->op.right == arg) { if (old_child->op.right == arg) {
...@@ -761,8 +804,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, ...@@ -761,8 +804,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
} else if (old_child->op.left == arg) { } else if (old_child->op.left == arg) {
ptr = &old_child->op.left; ptr = &old_child->op.left;
other_child = old_child->op.right; other_child = old_child->op.right;
} else } else {
die("Error in reparent op, find other child"); show_error(error_str, "Error in reparent op, find other child");
return PEVENT_ERRNO__REPARENT_FAILED;
}
/* Detach arg from old_child */ /* Detach arg from old_child */
*ptr = NULL; *ptr = NULL;
...@@ -773,23 +818,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, ...@@ -773,23 +818,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
*parent = *arg; *parent = *arg;
/* Free arg without recussion */ /* Free arg without recussion */
free(arg); free(arg);
return; return 0;
} }
if (parent->op.right == old_child) if (parent->op.right == old_child)
ptr = &parent->op.right; ptr = &parent->op.right;
else if (parent->op.left == old_child) else if (parent->op.left == old_child)
ptr = &parent->op.left; ptr = &parent->op.left;
else else {
die("Error in reparent op"); show_error(error_str, "Error in reparent op");
return PEVENT_ERRNO__REPARENT_FAILED;
}
*ptr = arg; *ptr = arg;
free_arg(old_child); free_arg(old_child);
return 0;
} }
enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) /* Returns either filter_vals (success) or pevent_errno (failfure) */
static int test_arg(struct filter_arg *parent, struct filter_arg *arg,
char **error_str)
{ {
enum filter_vals lval, rval; int lval, rval;
switch (arg->type) { switch (arg->type) {
...@@ -804,63 +855,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) ...@@ -804,63 +855,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
return FILTER_VAL_NORM; return FILTER_VAL_NORM;
case FILTER_ARG_EXP: case FILTER_ARG_EXP:
lval = test_arg(arg, arg->exp.left); lval = test_arg(arg, arg->exp.left, error_str);
if (lval != FILTER_VAL_NORM) if (lval != FILTER_VAL_NORM)
return lval; return lval;
rval = test_arg(arg, arg->exp.right); rval = test_arg(arg, arg->exp.right, error_str);
if (rval != FILTER_VAL_NORM) if (rval != FILTER_VAL_NORM)
return rval; return rval;
return FILTER_VAL_NORM; return FILTER_VAL_NORM;
case FILTER_ARG_NUM: case FILTER_ARG_NUM:
lval = test_arg(arg, arg->num.left); lval = test_arg(arg, arg->num.left, error_str);
if (lval != FILTER_VAL_NORM) if (lval != FILTER_VAL_NORM)
return lval; return lval;
rval = test_arg(arg, arg->num.right); rval = test_arg(arg, arg->num.right, error_str);
if (rval != FILTER_VAL_NORM) if (rval != FILTER_VAL_NORM)
return rval; return rval;
return FILTER_VAL_NORM; return FILTER_VAL_NORM;
case FILTER_ARG_OP: case FILTER_ARG_OP:
if (arg->op.type != FILTER_OP_NOT) { if (arg->op.type != FILTER_OP_NOT) {
lval = test_arg(arg, arg->op.left); lval = test_arg(arg, arg->op.left, error_str);
switch (lval) { switch (lval) {
case FILTER_VAL_NORM: case FILTER_VAL_NORM:
break; break;
case FILTER_VAL_TRUE: case FILTER_VAL_TRUE:
if (arg->op.type == FILTER_OP_OR) if (arg->op.type == FILTER_OP_OR)
return FILTER_VAL_TRUE; return FILTER_VAL_TRUE;
rval = test_arg(arg, arg->op.right); rval = test_arg(arg, arg->op.right, error_str);
if (rval != FILTER_VAL_NORM) if (rval != FILTER_VAL_NORM)
return rval; return rval;
reparent_op_arg(parent, arg, arg->op.right); return reparent_op_arg(parent, arg, arg->op.right,
return FILTER_VAL_NORM; error_str);
case FILTER_VAL_FALSE: case FILTER_VAL_FALSE:
if (arg->op.type == FILTER_OP_AND) if (arg->op.type == FILTER_OP_AND)
return FILTER_VAL_FALSE; return FILTER_VAL_FALSE;
rval = test_arg(arg, arg->op.right); rval = test_arg(arg, arg->op.right, error_str);
if (rval != FILTER_VAL_NORM) if (rval != FILTER_VAL_NORM)
return rval; return rval;
reparent_op_arg(parent, arg, arg->op.right); return reparent_op_arg(parent, arg, arg->op.right,
return FILTER_VAL_NORM; error_str);
default:
return lval;
} }
} }
rval = test_arg(arg, arg->op.right); rval = test_arg(arg, arg->op.right, error_str);
switch (rval) { switch (rval) {
case FILTER_VAL_NORM: case FILTER_VAL_NORM:
default:
break; break;
case FILTER_VAL_TRUE: case FILTER_VAL_TRUE:
if (arg->op.type == FILTER_OP_OR) if (arg->op.type == FILTER_OP_OR)
return FILTER_VAL_TRUE; return FILTER_VAL_TRUE;
if (arg->op.type == FILTER_OP_NOT) if (arg->op.type == FILTER_OP_NOT)
return FILTER_VAL_FALSE; return FILTER_VAL_FALSE;
reparent_op_arg(parent, arg, arg->op.left); return reparent_op_arg(parent, arg, arg->op.left,
return FILTER_VAL_NORM; error_str);
case FILTER_VAL_FALSE: case FILTER_VAL_FALSE:
if (arg->op.type == FILTER_OP_AND) 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,39 +924,54 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
if (arg->op.type == FILTER_OP_NOT) if (arg->op.type == FILTER_OP_NOT)
return FILTER_VAL_TRUE; return FILTER_VAL_TRUE;
reparent_op_arg(parent, arg, arg->op.left); return reparent_op_arg(parent, arg, arg->op.left,
return FILTER_VAL_NORM; error_str);
} }
return FILTER_VAL_NORM; return rval;
default: default:
die("bad arg in filter tree"); show_error(error_str, "bad arg in filter tree");
return PEVENT_ERRNO__BAD_FILTER_ARG;
} }
return FILTER_VAL_NORM; return FILTER_VAL_NORM;
} }
/* Remove any unknown event fields */ /* Remove any unknown event fields */
static struct filter_arg *collapse_tree(struct filter_arg *arg) static int collapse_tree(struct filter_arg *arg,
struct filter_arg **arg_collapsed, char **error_str)
{ {
enum filter_vals ret; int ret;
ret = test_arg(arg, arg); ret = test_arg(arg, arg, error_str);
switch (ret) { switch (ret) {
case FILTER_VAL_NORM: case FILTER_VAL_NORM:
return arg; break;
case FILTER_VAL_TRUE: case FILTER_VAL_TRUE:
case FILTER_VAL_FALSE: case FILTER_VAL_FALSE:
free_arg(arg); free_arg(arg);
arg = allocate_arg(); arg = allocate_arg();
arg->type = FILTER_ARG_BOOLEAN; if (arg) {
arg->boolean.value = ret == FILTER_VAL_TRUE; arg->type = FILTER_ARG_BOOLEAN;
arg->boolean.value = ret == FILTER_VAL_TRUE;
} else {
show_error(error_str, "Failed to allocate filter arg");
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
}
break;
default:
/* test_arg() already set the error_str */
free_arg(arg);
arg = NULL;
break;
} }
return arg; *arg_collapsed = arg;
return ret;
} }
static int static enum pevent_errno
process_filter(struct event_format *event, struct filter_arg **parg, process_filter(struct event_format *event, struct filter_arg **parg,
char **error_str, int not) char **error_str, int not)
{ {
...@@ -914,7 +985,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -914,7 +985,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
enum filter_op_type btype; enum filter_op_type btype;
enum filter_exp_type etype; enum filter_exp_type etype;
enum filter_cmp_type ctype; enum filter_cmp_type ctype;
int ret; enum pevent_errno ret;
*parg = NULL; *parg = NULL;
...@@ -925,8 +996,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -925,8 +996,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
case EVENT_SQUOTE: case EVENT_SQUOTE:
case EVENT_DQUOTE: case EVENT_DQUOTE:
case EVENT_ITEM: case EVENT_ITEM:
arg = create_arg_item(event, token, type, error_str); ret = create_arg_item(event, token, type, &arg, error_str);
if (!arg) if (ret < 0)
goto fail; goto fail;
if (!left_item) if (!left_item)
left_item = arg; left_item = arg;
...@@ -939,20 +1010,20 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -939,20 +1010,20 @@ process_filter(struct event_format *event, struct filter_arg **parg,
if (not) { if (not) {
arg = NULL; arg = NULL;
if (current_op) if (current_op)
goto fail_print; goto fail_syntax;
free(token); free(token);
*parg = current_exp; *parg = current_exp;
return 0; return 0;
} }
} else } else
goto fail_print; goto fail_syntax;
arg = NULL; arg = NULL;
break; break;
case EVENT_DELIM: case EVENT_DELIM:
if (*token == ',') { if (*token == ',') {
show_error(error_str, show_error(error_str, "Illegal token ','");
"Illegal token ','"); ret = PEVENT_ERRNO__ILLEGAL_TOKEN;
goto fail; goto fail;
} }
...@@ -960,19 +1031,23 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -960,19 +1031,23 @@ process_filter(struct event_format *event, struct filter_arg **parg,
if (left_item) { if (left_item) {
show_error(error_str, show_error(error_str,
"Open paren can not come after item"); "Open paren can not come after item");
ret = PEVENT_ERRNO__INVALID_PAREN;
goto fail; goto fail;
} }
if (current_exp) { if (current_exp) {
show_error(error_str, show_error(error_str,
"Open paren can not come after expression"); "Open paren can not come after expression");
ret = PEVENT_ERRNO__INVALID_PAREN;
goto fail; goto fail;
} }
ret = process_filter(event, &arg, error_str, 0); ret = process_filter(event, &arg, error_str, 0);
if (ret != 1) { if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) {
if (ret == 0) if (ret == 0) {
show_error(error_str, show_error(error_str,
"Unbalanced number of '('"); "Unbalanced number of '('");
ret = PEVENT_ERRNO__UNBALANCED_PAREN;
}
goto fail; goto fail;
} }
ret = 0; ret = 0;
...@@ -980,7 +1055,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -980,7 +1055,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
/* A not wants just one expression */ /* A not wants just one expression */
if (not) { if (not) {
if (current_op) if (current_op)
goto fail_print; goto fail_syntax;
*parg = arg; *parg = arg;
return 0; return 0;
} }
...@@ -995,19 +1070,19 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -995,19 +1070,19 @@ process_filter(struct event_format *event, struct filter_arg **parg,
} else { /* ')' */ } else { /* ')' */
if (!current_op && !current_exp) if (!current_op && !current_exp)
goto fail_print; goto fail_syntax;
/* Make sure everything is finished at this level */ /* Make sure everything is finished at this level */
if (current_exp && !check_op_done(current_exp)) if (current_exp && !check_op_done(current_exp))
goto fail_print; goto fail_syntax;
if (current_op && !check_op_done(current_op)) if (current_op && !check_op_done(current_op))
goto fail_print; goto fail_syntax;
if (current_op) if (current_op)
*parg = current_op; *parg = current_op;
else else
*parg = current_exp; *parg = current_exp;
return 1; return PEVENT_ERRNO__UNBALANCED_PAREN;
} }
break; break;
...@@ -1019,21 +1094,22 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -1019,21 +1094,22 @@ process_filter(struct event_format *event, struct filter_arg **parg,
case OP_BOOL: case OP_BOOL:
/* Logic ops need a left expression */ /* Logic ops need a left expression */
if (!current_exp && !current_op) if (!current_exp && !current_op)
goto fail_print; goto fail_syntax;
/* fall through */ /* fall through */
case OP_NOT: case OP_NOT:
/* logic only processes ops and exp */ /* logic only processes ops and exp */
if (left_item) if (left_item)
goto fail_print; goto fail_syntax;
break; break;
case OP_EXP: case OP_EXP:
case OP_CMP: case OP_CMP:
if (!left_item) if (!left_item)
goto fail_print; goto fail_syntax;
break; break;
case OP_NONE: case OP_NONE:
show_error(error_str, show_error(error_str,
"Unknown op token %s", token); "Unknown op token %s", token);
ret = PEVENT_ERRNO__UNKNOWN_TOKEN;
goto fail; goto fail;
} }
...@@ -1041,6 +1117,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -1041,6 +1117,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
switch (op_type) { switch (op_type) {
case OP_BOOL: case OP_BOOL:
arg = create_arg_op(btype); arg = create_arg_op(btype);
if (arg == NULL)
goto fail_alloc;
if (current_op) if (current_op)
ret = add_left(arg, current_op); ret = add_left(arg, current_op);
else else
...@@ -1051,6 +1129,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -1051,6 +1129,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
case OP_NOT: case OP_NOT:
arg = create_arg_op(btype); arg = create_arg_op(btype);
if (arg == NULL)
goto fail_alloc;
if (current_op) if (current_op)
ret = add_right(current_op, arg, error_str); ret = add_right(current_op, arg, error_str);
if (ret < 0) if (ret < 0)
...@@ -1070,6 +1150,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -1070,6 +1150,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
arg = create_arg_exp(etype); arg = create_arg_exp(etype);
else else
arg = create_arg_cmp(ctype); arg = create_arg_cmp(ctype);
if (arg == NULL)
goto fail_alloc;
if (current_op) if (current_op)
ret = add_right(current_op, arg, error_str); ret = add_right(current_op, arg, error_str);
...@@ -1078,7 +1160,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -1078,7 +1160,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
ret = add_left(arg, left_item); ret = add_left(arg, left_item);
if (ret < 0) { if (ret < 0) {
arg = NULL; arg = NULL;
goto fail_print; goto fail_syntax;
} }
current_exp = arg; current_exp = arg;
break; break;
...@@ -1087,38 +1169,47 @@ process_filter(struct event_format *event, struct filter_arg **parg, ...@@ -1087,38 +1169,47 @@ process_filter(struct event_format *event, struct filter_arg **parg,
} }
arg = NULL; arg = NULL;
if (ret < 0) if (ret < 0)
goto fail_print; goto fail_syntax;
break; break;
case EVENT_NONE: case EVENT_NONE:
break; break;
case EVENT_ERROR:
goto fail_alloc;
default: default:
goto fail_print; goto fail_syntax;
} }
} while (type != EVENT_NONE); } while (type != EVENT_NONE);
if (!current_op && !current_exp) if (!current_op && !current_exp)
goto fail_print; goto fail_syntax;
if (!current_op) if (!current_op)
current_op = current_exp; current_op = current_exp;
current_op = collapse_tree(current_op); ret = collapse_tree(current_op, parg, error_str);
if (ret < 0)
goto fail;
*parg = current_op; *parg = current_op;
return 0; return 0;
fail_print: fail_alloc:
show_error(error_str, "failed to allocate filter arg");
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
goto fail;
fail_syntax:
show_error(error_str, "Syntax error"); show_error(error_str, "Syntax error");
ret = PEVENT_ERRNO__SYNTAX_ERROR;
fail: fail:
free_arg(current_op); free_arg(current_op);
free_arg(current_exp); free_arg(current_exp);
free_arg(arg); free_arg(arg);
free(token); free(token);
return -1; return ret;
} }
static int static enum pevent_errno
process_event(struct event_format *event, const char *filter_str, process_event(struct event_format *event, const char *filter_str,
struct filter_arg **parg, char **error_str) struct filter_arg **parg, char **error_str)
{ {
...@@ -1127,17 +1218,15 @@ process_event(struct event_format *event, const char *filter_str, ...@@ -1127,17 +1218,15 @@ process_event(struct event_format *event, const char *filter_str,
pevent_buffer_init(filter_str, strlen(filter_str)); pevent_buffer_init(filter_str, strlen(filter_str));
ret = process_filter(event, parg, error_str, 0); ret = process_filter(event, parg, error_str, 0);
if (ret == 1) {
show_error(error_str,
"Unbalanced number of ')'");
return -1;
}
if (ret < 0) if (ret < 0)
return ret; return ret;
/* If parg is NULL, then make it into FALSE */ /* If parg is NULL, then make it into FALSE */
if (!*parg) { if (!*parg) {
*parg = allocate_arg(); *parg = allocate_arg();
if (*parg == NULL)
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
(*parg)->type = FILTER_ARG_BOOLEAN; (*parg)->type = FILTER_ARG_BOOLEAN;
(*parg)->boolean.value = FILTER_FALSE; (*parg)->boolean.value = FILTER_FALSE;
} }
...@@ -1145,13 +1234,13 @@ process_event(struct event_format *event, const char *filter_str, ...@@ -1145,13 +1234,13 @@ process_event(struct event_format *event, const char *filter_str,
return 0; return 0;
} }
static int filter_event(struct event_filter *filter, static enum pevent_errno
struct event_format *event, filter_event(struct event_filter *filter, struct event_format *event,
const char *filter_str, char **error_str) const char *filter_str, char **error_str)
{ {
struct filter_type *filter_type; struct filter_type *filter_type;
struct filter_arg *arg; struct filter_arg *arg;
int ret; enum pevent_errno ret;
if (filter_str) { if (filter_str) {
ret = process_event(event, filter_str, &arg, error_str); ret = process_event(event, filter_str, &arg, error_str);
...@@ -1161,11 +1250,17 @@ static int filter_event(struct event_filter *filter, ...@@ -1161,11 +1250,17 @@ static int filter_event(struct event_filter *filter,
} else { } else {
/* just add a TRUE arg */ /* just add a TRUE arg */
arg = allocate_arg(); arg = allocate_arg();
if (arg == NULL)
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
arg->type = FILTER_ARG_BOOLEAN; arg->type = FILTER_ARG_BOOLEAN;
arg->boolean.value = FILTER_TRUE; arg->boolean.value = FILTER_TRUE;
} }
filter_type = add_filter_type(filter, event->id); filter_type = add_filter_type(filter, event->id);
if (filter_type == NULL)
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
if (filter_type->filter) if (filter_type->filter)
free_arg(filter_type->filter); free_arg(filter_type->filter);
filter_type->filter = arg; filter_type->filter = arg;
...@@ -1177,18 +1272,12 @@ static int filter_event(struct event_filter *filter, ...@@ -1177,18 +1272,12 @@ static int filter_event(struct event_filter *filter,
* pevent_filter_add_filter_str - add a new filter * pevent_filter_add_filter_str - add a new filter
* @filter: the event filter to add to * @filter: the event filter to add to
* @filter_str: the filter string that contains the filter * @filter_str: the filter string that contains the filter
* @error_str: string containing reason for failed filter
* *
* Returns 0 if the filter was successfully added * Returns 0 if the filter was successfully added or a
* -1 if there was an error. * negative error code.
*
* On error, if @error_str points to a string pointer,
* it is set to the reason that the filter failed.
* This string must be freed with "free".
*/ */
int pevent_filter_add_filter_str(struct event_filter *filter, enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
const char *filter_str, const char *filter_str)
char **error_str)
{ {
struct pevent *pevent = filter->pevent; struct pevent *pevent = filter->pevent;
struct event_list *event; struct event_list *event;
...@@ -1199,23 +1288,20 @@ int pevent_filter_add_filter_str(struct event_filter *filter, ...@@ -1199,23 +1288,20 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
char *event_name = NULL; char *event_name = NULL;
char *sys_name = NULL; char *sys_name = NULL;
char *sp; char *sp;
int rtn = 0; enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */
int len; int len;
int ret; int ret;
char *error_str = NULL;
/* clear buffer to reset show error */ /* clear buffer to reset show error */
pevent_buffer_init("", 0); pevent_buffer_init("", 0);
if (error_str)
*error_str = NULL;
filter_start = strchr(filter_str, ':'); filter_start = strchr(filter_str, ':');
if (filter_start) if (filter_start)
len = filter_start - filter_str; len = filter_start - filter_str;
else else
len = strlen(filter_str); len = strlen(filter_str);
do { do {
next_event = strchr(filter_str, ','); next_event = strchr(filter_str, ',');
if (next_event && if (next_event &&
...@@ -1228,10 +1314,9 @@ int pevent_filter_add_filter_str(struct event_filter *filter, ...@@ -1228,10 +1314,9 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
this_event = malloc(len + 1); this_event = malloc(len + 1);
if (this_event == NULL) { if (this_event == NULL) {
show_error(error_str, "Memory allocation failure");
/* This can only happen when events is NULL, but still */ /* This can only happen when events is NULL, but still */
free_events(events); free_events(events);
return -1; return PEVENT_ERRNO__MEM_ALLOC_FAILED;
} }
memcpy(this_event, filter_str, len); memcpy(this_event, filter_str, len);
this_event[len] = 0; this_event[len] = 0;
...@@ -1245,27 +1330,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter, ...@@ -1245,27 +1330,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
event_name = strtok_r(NULL, "/", &sp); event_name = strtok_r(NULL, "/", &sp);
if (!sys_name) { if (!sys_name) {
show_error(error_str, "No filter found");
/* This can only happen when events is NULL, but still */ /* This can only happen when events is NULL, but still */
free_events(events); free_events(events);
free(this_event); free(this_event);
return -1; return PEVENT_ERRNO__FILTER_NOT_FOUND;
} }
/* Find this event */ /* Find this event */
ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
if (ret < 0) { if (ret < 0) {
if (event_name)
show_error(error_str,
"No event found under '%s.%s'",
sys_name, event_name);
else
show_error(error_str,
"No event found under '%s'",
sys_name);
free_events(events); free_events(events);
free(this_event); free(this_event);
return -1; return ret;
} }
free(this_event); free(this_event);
} while (filter_str); } while (filter_str);
...@@ -1277,7 +1353,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter, ...@@ -1277,7 +1353,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
/* filter starts here */ /* filter starts here */
for (event = events; event; event = event->next) { for (event = events; event; event = event->next) {
ret = filter_event(filter, event->event, filter_start, ret = filter_event(filter, event->event, filter_start,
error_str); &error_str);
/* Failures are returned if a parse error happened */ /* Failures are returned if a parse error happened */
if (ret < 0) if (ret < 0)
rtn = ret; rtn = ret;
...@@ -1396,6 +1472,9 @@ static int copy_filter_type(struct event_filter *filter, ...@@ -1396,6 +1472,9 @@ static int copy_filter_type(struct event_filter *filter,
if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
/* Add trivial event */ /* Add trivial event */
arg = allocate_arg(); arg = allocate_arg();
if (arg == NULL)
return -1;
arg->type = FILTER_ARG_BOOLEAN; arg->type = FILTER_ARG_BOOLEAN;
if (strcmp(str, "TRUE") == 0) if (strcmp(str, "TRUE") == 0)
arg->boolean.value = 1; arg->boolean.value = 1;
...@@ -1403,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter, ...@@ -1403,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter,
arg->boolean.value = 0; arg->boolean.value = 0;
filter_type = add_filter_type(filter, event->id); filter_type = add_filter_type(filter, event->id);
if (filter_type == NULL)
return -1;
filter_type->filter = arg; filter_type->filter = arg;
free(str); free(str);
...@@ -1596,8 +1678,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter, ...@@ -1596,8 +1678,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter,
} }
} }
static int test_filter(struct event_format *event, static int test_filter(struct event_format *event, struct filter_arg *arg,
struct filter_arg *arg, struct pevent_record *record); struct pevent_record *record, enum pevent_errno *err);
static const char * static const char *
get_comm(struct event_format *event, struct pevent_record *record) get_comm(struct event_format *event, struct pevent_record *record)
...@@ -1643,15 +1725,24 @@ get_value(struct event_format *event, ...@@ -1643,15 +1725,24 @@ get_value(struct event_format *event,
} }
static unsigned long long static unsigned long long
get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); get_arg_value(struct event_format *event, struct filter_arg *arg,
struct pevent_record *record, enum pevent_errno *err);
static unsigned long long static unsigned long long
get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) get_exp_value(struct event_format *event, struct filter_arg *arg,
struct pevent_record *record, enum pevent_errno *err)
{ {
unsigned long long lval, rval; unsigned long long lval, rval;
lval = get_arg_value(event, arg->exp.left, record); lval = get_arg_value(event, arg->exp.left, record, err);
rval = get_arg_value(event, arg->exp.right, record); rval = get_arg_value(event, arg->exp.right, record, err);
if (*err) {
/*
* There was an error, no need to process anymore.
*/
return 0;
}
switch (arg->exp.type) { switch (arg->exp.type) {
case FILTER_EXP_ADD: case FILTER_EXP_ADD:
...@@ -1686,39 +1777,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_ ...@@ -1686,39 +1777,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_
case FILTER_EXP_NOT: case FILTER_EXP_NOT:
default: default:
die("error in exp"); if (!*err)
*err = PEVENT_ERRNO__INVALID_EXP_TYPE;
} }
return 0; return 0;
} }
static unsigned long long static unsigned long long
get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) get_arg_value(struct event_format *event, struct filter_arg *arg,
struct pevent_record *record, enum pevent_errno *err)
{ {
switch (arg->type) { switch (arg->type) {
case FILTER_ARG_FIELD: case FILTER_ARG_FIELD:
return get_value(event, arg->field.field, record); return get_value(event, arg->field.field, record);
case FILTER_ARG_VALUE: case FILTER_ARG_VALUE:
if (arg->value.type != FILTER_NUMBER) if (arg->value.type != FILTER_NUMBER) {
die("must have number field!"); if (!*err)
*err = PEVENT_ERRNO__NOT_A_NUMBER;
}
return arg->value.val; return arg->value.val;
case FILTER_ARG_EXP: case FILTER_ARG_EXP:
return get_exp_value(event, arg, record); return get_exp_value(event, arg, record, err);
default: default:
die("oops in filter"); if (!*err)
*err = PEVENT_ERRNO__INVALID_ARG_TYPE;
} }
return 0; return 0;
} }
static int test_num(struct event_format *event, static int test_num(struct event_format *event, struct filter_arg *arg,
struct filter_arg *arg, struct pevent_record *record) struct pevent_record *record, enum pevent_errno *err)
{ {
unsigned long long lval, rval; unsigned long long lval, rval;
lval = get_arg_value(event, arg->num.left, record); lval = get_arg_value(event, arg->num.left, record, err);
rval = get_arg_value(event, arg->num.right, record); rval = get_arg_value(event, arg->num.right, record, err);
if (*err) {
/*
* There was an error, no need to process anymore.
*/
return 0;
}
switch (arg->num.type) { switch (arg->num.type) {
case FILTER_CMP_EQ: case FILTER_CMP_EQ:
...@@ -1740,7 +1843,8 @@ static int test_num(struct event_format *event, ...@@ -1740,7 +1843,8 @@ static int test_num(struct event_format *event,
return lval <= rval; return lval <= rval;
default: default:
/* ?? */ if (!*err)
*err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
return 0; return 0;
} }
} }
...@@ -1787,8 +1891,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r ...@@ -1787,8 +1891,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
return val; return val;
} }
static int test_str(struct event_format *event, static int test_str(struct event_format *event, struct filter_arg *arg,
struct filter_arg *arg, struct pevent_record *record) struct pevent_record *record, enum pevent_errno *err)
{ {
const char *val; const char *val;
...@@ -1812,48 +1916,57 @@ static int test_str(struct event_format *event, ...@@ -1812,48 +1916,57 @@ static int test_str(struct event_format *event,
return regexec(&arg->str.reg, val, 0, NULL, 0); return regexec(&arg->str.reg, val, 0, NULL, 0);
default: default:
/* ?? */ if (!*err)
*err = PEVENT_ERRNO__ILLEGAL_STRING_CMP;
return 0; return 0;
} }
} }
static int test_op(struct event_format *event, static int test_op(struct event_format *event, struct filter_arg *arg,
struct filter_arg *arg, struct pevent_record *record) struct pevent_record *record, enum pevent_errno *err)
{ {
switch (arg->op.type) { switch (arg->op.type) {
case FILTER_OP_AND: case FILTER_OP_AND:
return test_filter(event, arg->op.left, record) && return test_filter(event, arg->op.left, record, err) &&
test_filter(event, arg->op.right, record); test_filter(event, arg->op.right, record, err);
case FILTER_OP_OR: case FILTER_OP_OR:
return test_filter(event, arg->op.left, record) || return test_filter(event, arg->op.left, record, err) ||
test_filter(event, arg->op.right, record); test_filter(event, arg->op.right, record, err);
case FILTER_OP_NOT: case FILTER_OP_NOT:
return !test_filter(event, arg->op.right, record); return !test_filter(event, arg->op.right, record, err);
default: default:
/* ?? */ if (!*err)
*err = PEVENT_ERRNO__INVALID_OP_TYPE;
return 0; return 0;
} }
} }
static int test_filter(struct event_format *event, static int test_filter(struct event_format *event, struct filter_arg *arg,
struct filter_arg *arg, struct pevent_record *record) struct pevent_record *record, enum pevent_errno *err)
{ {
if (*err) {
/*
* There was an error, no need to process anymore.
*/
return 0;
}
switch (arg->type) { switch (arg->type) {
case FILTER_ARG_BOOLEAN: case FILTER_ARG_BOOLEAN:
/* easy case */ /* easy case */
return arg->boolean.value; return arg->boolean.value;
case FILTER_ARG_OP: case FILTER_ARG_OP:
return test_op(event, arg, record); return test_op(event, arg, record, err);
case FILTER_ARG_NUM: case FILTER_ARG_NUM:
return test_num(event, arg, record); return test_num(event, arg, record, err);
case FILTER_ARG_STR: case FILTER_ARG_STR:
return test_str(event, arg, record); return test_str(event, arg, record, err);
case FILTER_ARG_EXP: case FILTER_ARG_EXP:
case FILTER_ARG_VALUE: case FILTER_ARG_VALUE:
...@@ -1862,11 +1975,11 @@ static int test_filter(struct event_format *event, ...@@ -1862,11 +1975,11 @@ static int test_filter(struct event_format *event,
* Expressions, fields and values evaluate * Expressions, fields and values evaluate
* to true if they return non zero * to true if they return non zero
*/ */
return !!get_arg_value(event, arg, record); return !!get_arg_value(event, arg, record, err);
default: default:
die("oops!"); if (!*err)
/* ?? */ *err = PEVENT_ERRNO__INVALID_ARG_TYPE;
return 0; return 0;
} }
} }
...@@ -1879,8 +1992,7 @@ static int test_filter(struct event_format *event, ...@@ -1879,8 +1992,7 @@ static int test_filter(struct event_format *event,
* Returns 1 if filter found for @event_id * Returns 1 if filter found for @event_id
* otherwise 0; * otherwise 0;
*/ */
int pevent_event_filtered(struct event_filter *filter, int pevent_event_filtered(struct event_filter *filter, int event_id)
int event_id)
{ {
struct filter_type *filter_type; struct filter_type *filter_type;
...@@ -1897,31 +2009,36 @@ int pevent_event_filtered(struct event_filter *filter, ...@@ -1897,31 +2009,36 @@ int pevent_event_filtered(struct event_filter *filter,
* @filter: filter struct with filter information * @filter: filter struct with filter information
* @record: the record to test against the filter * @record: the record to test against the filter
* *
* Returns: * Returns: match result or error code (prefixed with PEVENT_ERRNO__)
* 1 - filter found for event and @record matches * FILTER_MATCH - filter found for event and @record matches
* 0 - filter found for event and @record does not match * FILTER_MISS - filter found for event and @record does not match
* -1 - no filter found for @record's event * FILTER_NOT_FOUND - no filter found for @record's event
* -2 - if no filters exist * NO_FILTER - if no filters exist
* otherwise - error occurred during test
*/ */
int pevent_filter_match(struct event_filter *filter, enum pevent_errno pevent_filter_match(struct event_filter *filter,
struct pevent_record *record) struct pevent_record *record)
{ {
struct pevent *pevent = filter->pevent; struct pevent *pevent = filter->pevent;
struct filter_type *filter_type; struct filter_type *filter_type;
int event_id; int event_id;
int ret;
enum pevent_errno err = 0;
if (!filter->filters) if (!filter->filters)
return FILTER_NONE; return PEVENT_ERRNO__NO_FILTER;
event_id = pevent_data_type(pevent, record); event_id = pevent_data_type(pevent, record);
filter_type = find_filter_type(filter, event_id); filter_type = find_filter_type(filter, event_id);
if (!filter_type) if (!filter_type)
return FILTER_NOEXIST; return PEVENT_ERRNO__FILTER_NOT_FOUND;
ret = test_filter(filter_type->event, filter_type->filter, record, &err);
if (err)
return err;
return test_filter(filter_type->event, filter_type->filter, record) ? return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS;
FILTER_MATCH : FILTER_MISS;
} }
static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
......
...@@ -2,6 +2,8 @@ tools/perf ...@@ -2,6 +2,8 @@ tools/perf
tools/scripts tools/scripts
tools/lib/traceevent tools/lib/traceevent
tools/lib/lk tools/lib/lk
tools/lib/symbol/kallsyms.c
tools/lib/symbol/kallsyms.h
include/linux/const.h include/linux/const.h
include/linux/perf_event.h include/linux/perf_event.h
include/linux/rbtree.h include/linux/rbtree.h
......
...@@ -202,6 +202,7 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c ...@@ -202,6 +202,7 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
LIB_FILE=$(OUTPUT)libperf.a LIB_FILE=$(OUTPUT)libperf.a
LIB_H += ../lib/symbol/kallsyms.h
LIB_H += ../../include/uapi/linux/perf_event.h LIB_H += ../../include/uapi/linux/perf_event.h
LIB_H += ../../include/linux/rbtree.h LIB_H += ../../include/linux/rbtree.h
LIB_H += ../../include/linux/list.h LIB_H += ../../include/linux/list.h
...@@ -312,6 +313,7 @@ LIB_OBJS += $(OUTPUT)util/evlist.o ...@@ -312,6 +313,7 @@ LIB_OBJS += $(OUTPUT)util/evlist.o
LIB_OBJS += $(OUTPUT)util/evsel.o LIB_OBJS += $(OUTPUT)util/evsel.o
LIB_OBJS += $(OUTPUT)util/exec_cmd.o LIB_OBJS += $(OUTPUT)util/exec_cmd.o
LIB_OBJS += $(OUTPUT)util/help.o LIB_OBJS += $(OUTPUT)util/help.o
LIB_OBJS += $(OUTPUT)util/kallsyms.o
LIB_OBJS += $(OUTPUT)util/levenshtein.o LIB_OBJS += $(OUTPUT)util/levenshtein.o
LIB_OBJS += $(OUTPUT)util/parse-options.o LIB_OBJS += $(OUTPUT)util/parse-options.o
LIB_OBJS += $(OUTPUT)util/parse-events.o LIB_OBJS += $(OUTPUT)util/parse-events.o
...@@ -672,6 +674,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS ...@@ -672,6 +674,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
......
...@@ -121,6 +121,10 @@ __perf_main () ...@@ -121,6 +121,10 @@ __perf_main ()
elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
evts=$($cmd list --raw-dump) evts=$($cmd list --raw-dump)
__perfcomp_colon "$evts" "$cur" __perfcomp_colon "$evts" "$cur"
# List subcommands for 'perf kvm'
elif [[ $prev == "kvm" ]]; then
subcmds="top record report diff buildid-list stat"
__perfcomp_colon "$subcmds" "$cur"
# List long option names # List long option names
elif [[ $cur == --* ]]; then elif [[ $cur == --* ]]; then
subcmd=${words[1]} subcmd=${words[1]}
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "strlist.h" #include "strlist.h"
#include "thread.h" #include "thread.h"
#include "thread_map.h" #include "thread_map.h"
#include "symbol/kallsyms.h"
static const char *perf_event__names[] = { static const char *perf_event__names[] = {
[0] = "TOTAL", [0] = "TOTAL",
......
...@@ -1191,8 +1191,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, ...@@ -1191,8 +1191,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
"Error:\t%s.\n" "Error:\t%s.\n"
"Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value)) value = perf_event_paranoid();
break;
printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); printed += scnprintf(buf + printed, size - printed, "\nHint:\t");
...@@ -1213,3 +1212,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, ...@@ -1213,3 +1212,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
return 0; return 0;
} }
void perf_evlist__to_front(struct perf_evlist *evlist,
struct perf_evsel *move_evsel)
{
struct perf_evsel *evsel, *n;
LIST_HEAD(move);
if (move_evsel == perf_evlist__first(evlist))
return;
list_for_each_entry_safe(evsel, n, &evlist->entries, node) {
if (evsel->leader == move_evsel->leader)
list_move_tail(&evsel->node, &move);
}
list_splice(&move, &evlist->entries);
}
...@@ -193,4 +193,9 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md, ...@@ -193,4 +193,9 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md,
pc->data_tail = tail; pc->data_tail = tail;
} }
bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str);
void perf_evlist__to_front(struct perf_evlist *evlist,
struct perf_evsel *move_evsel);
#endif /* __PERF_EVLIST_H */ #endif /* __PERF_EVLIST_H */
...@@ -2327,7 +2327,8 @@ int perf_session__write_header(struct perf_session *session, ...@@ -2327,7 +2327,8 @@ int perf_session__write_header(struct perf_session *session,
} }
} }
header->data_offset = lseek(fd, 0, SEEK_CUR); if (!header->data_offset)
header->data_offset = lseek(fd, 0, SEEK_CUR);
header->feat_offset = header->data_offset + header->data_size; header->feat_offset = header->data_offset + header->data_size;
if (at_exit) { if (at_exit) {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "strlist.h" #include "strlist.h"
#include "thread.h" #include "thread.h"
#include <stdbool.h> #include <stdbool.h>
#include <symbol/kallsyms.h>
#include "unwind.h" #include "unwind.h"
int machine__init(struct machine *machine, const char *root_dir, pid_t pid) int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
......
...@@ -177,3 +177,40 @@ int perf_record_opts__config(struct perf_record_opts *opts) ...@@ -177,3 +177,40 @@ int perf_record_opts__config(struct perf_record_opts *opts)
{ {
return perf_record_opts__config_freq(opts); return perf_record_opts__config_freq(opts);
} }
bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
{
struct perf_evlist *temp_evlist;
struct perf_evsel *evsel;
int err, fd, cpu;
bool ret = false;
temp_evlist = perf_evlist__new();
if (!temp_evlist)
return false;
err = parse_events(temp_evlist, str);
if (err)
goto out_delete;
evsel = perf_evlist__last(temp_evlist);
if (!evlist || cpu_map__empty(evlist->cpus)) {
struct cpu_map *cpus = cpu_map__new(NULL);
cpu = cpus ? cpus->map[0] : 0;
cpu_map__delete(cpus);
} else {
cpu = evlist->cpus->map[0];
}
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
if (fd >= 0) {
close(fd);
ret = true;
}
out_delete:
perf_evlist__delete(temp_evlist);
return ret;
}
...@@ -247,27 +247,6 @@ void perf_tool__fill_defaults(struct perf_tool *tool) ...@@ -247,27 +247,6 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
} }
} }
void mem_bswap_32(void *src, int byte_size)
{
u32 *m = src;
while (byte_size > 0) {
*m = bswap_32(*m);
byte_size -= sizeof(u32);
++m;
}
}
void mem_bswap_64(void *src, int byte_size)
{
u64 *m = src;
while (byte_size > 0) {
*m = bswap_64(*m);
byte_size -= sizeof(u64);
++m;
}
}
static void swap_sample_id_all(union perf_event *event, void *data) static void swap_sample_id_all(union perf_event *event, void *data)
{ {
void *end = (void *) event + event->header.size; void *end = (void *) event + event->header.size;
......
...@@ -74,8 +74,6 @@ int perf_session__resolve_callchain(struct perf_session *session, ...@@ -74,8 +74,6 @@ int perf_session__resolve_callchain(struct perf_session *session,
bool perf_session__has_traces(struct perf_session *session, const char *msg); bool perf_session__has_traces(struct perf_session *session, const char *msg);
void mem_bswap_64(void *src, int byte_size);
void mem_bswap_32(void *src, int byte_size);
void perf_event__attr_swap(struct perf_event_attr *attr); void perf_event__attr_swap(struct perf_event_attr *attr);
int perf_session__create_kernel_maps(struct perf_session *session); int perf_session__create_kernel_maps(struct perf_session *session);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <inttypes.h> #include <inttypes.h>
#include "symbol.h" #include "symbol.h"
#include <symbol/kallsyms.h>
#include "debug.h" #include "debug.h"
#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
......
...@@ -18,12 +18,9 @@ ...@@ -18,12 +18,9 @@
#include <elf.h> #include <elf.h>
#include <limits.h> #include <limits.h>
#include <symbol/kallsyms.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#ifndef KSYM_NAME_LEN
#define KSYM_NAME_LEN 256
#endif
static int dso__load_kernel_sym(struct dso *dso, struct map *map, static int dso__load_kernel_sym(struct dso *dso, struct map *map,
symbol_filter_t filter); symbol_filter_t filter);
static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 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,62 +443,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
return ret; return ret;
} }
int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name,
char type, u64 start))
{
char *line = NULL;
size_t n;
int err = -1;
FILE *file = fopen(filename, "r");
if (file == NULL)
goto out_failure;
err = 0;
while (!feof(file)) {
u64 start;
int line_len, len;
char symbol_type;
char *symbol_name;
line_len = getline(&line, &n, file);
if (line_len < 0 || !line)
break;
line[--line_len] = '\0'; /* \n */
len = hex2u64(line, &start);
len++;
if (len + 2 >= line_len)
continue;
symbol_type = line[len];
len += 2;
symbol_name = line + len;
len = line_len - len;
if (len >= KSYM_NAME_LEN) {
err = -1;
break;
}
err = process_symbol(arg, symbol_name,
symbol_type, start);
if (err)
break;
}
free(line);
fclose(file);
return err;
out_failure:
return -1;
}
int modules__parse(const char *filename, void *arg, int modules__parse(const char *filename, void *arg,
int (*process_module)(void *arg, const char *name, int (*process_module)(void *arg, const char *name,
u64 start)) u64 start))
...@@ -565,14 +506,6 @@ struct process_kallsyms_args { ...@@ -565,14 +506,6 @@ struct process_kallsyms_args {
struct dso *dso; struct dso *dso;
}; };
static u8 kallsyms2elf_type(char type)
{
if (type == 'W')
return STB_WEAK;
return isupper(type) ? STB_GLOBAL : STB_LOCAL;
}
bool symbol__is_idle(struct symbol *sym) bool symbol__is_idle(struct symbol *sym)
{ {
const char * const idle_symbols[] = { const char * const idle_symbols[] = {
......
...@@ -221,9 +221,6 @@ struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); ...@@ -221,9 +221,6 @@ struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
int filename__read_build_id(const char *filename, void *bf, size_t size); int filename__read_build_id(const char *filename, void *bf, size_t size);
int sysfs__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size);
int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name,
char type, u64 start));
int modules__parse(const char *filename, void *arg, int modules__parse(const char *filename, void *arg,
int (*process_module)(void *arg, const char *name, int (*process_module)(void *arg, const char *name,
u64 start)); u64 start));
......
...@@ -126,7 +126,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) ...@@ -126,7 +126,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
if (!comm) if (!comm)
return -ENOMEM; return -ENOMEM;
err = thread__set_comm(thread, comm, timestamp); err = thread__set_comm(thread, comm, timestamp);
if (!err) if (err)
return err; return err;
thread->comm_set = true; thread->comm_set = true;
} }
......
#include "../perf.h" #include "../perf.h"
#include "util.h" #include "util.h"
#include "fs.h"
#include <sys/mman.h> #include <sys/mman.h>
#ifdef HAVE_BACKTRACE_SUPPORT #ifdef HAVE_BACKTRACE_SUPPORT
#include <execinfo.h> #include <execinfo.h>
...@@ -8,6 +9,8 @@ ...@@ -8,6 +9,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <byteswap.h>
#include <linux/kernel.h> #include <linux/kernel.h>
/* /*
...@@ -496,3 +499,41 @@ const char *get_filename_for_perf_kvm(void) ...@@ -496,3 +499,41 @@ const char *get_filename_for_perf_kvm(void)
return filename; return filename;
} }
int perf_event_paranoid(void)
{
char path[PATH_MAX];
const char *procfs = procfs__mountpoint();
int value;
if (!procfs)
return INT_MAX;
scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs);
if (filename__read_int(path, &value))
return INT_MAX;
return value;
}
void mem_bswap_32(void *src, int byte_size)
{
u32 *m = src;
while (byte_size > 0) {
*m = bswap_32(*m);
byte_size -= sizeof(u32);
++m;
}
}
void mem_bswap_64(void *src, int byte_size)
{
u64 *m = src;
while (byte_size > 0) {
*m = bswap_64(*m);
byte_size -= sizeof(u64);
++m;
}
}
...@@ -321,6 +321,10 @@ void free_srcline(char *srcline); ...@@ -321,6 +321,10 @@ void free_srcline(char *srcline);
int filename__read_int(const char *filename, int *value); int filename__read_int(const char *filename, int *value);
int filename__read_str(const char *filename, char **buf, size_t *sizep); int filename__read_str(const char *filename, char **buf, size_t *sizep);
int perf_event_paranoid(void);
void mem_bswap_64(void *src, int byte_size);
void mem_bswap_32(void *src, int byte_size);
const char *get_filename_for_perf_kvm(void); const char *get_filename_for_perf_kvm(void);
#endif /* GIT_COMPAT_UTIL_H */ #endif /* GIT_COMPAT_UTIL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment