forked from Minki/linux
libtraceevent/core improvements
* Remaining backport of trace-cmd's libparseevent Signed-off-by: Namhyung Kim <namhyung@kernel.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQEcBAABAgAGBQJP88rbAAoJEFn/d4dOiegTG1AH/1jIPpr70Bv7WI3QLFV/lSD4 lzdlfazj8R0KDvC1ySZOuRLOv1k7NIzEPCAo7juFLrwdJgoZ7u8R5KO/qaQSBe1Q sM4ZZFRjMx96JzI5qNF/ewJDcR/tQUaWsQ3QLB/4byof5d/SE8upt8kAw5vsDys3 VnCYvud6IE8CTGKO2zMHAjIl+KMkoOQ+JhxK9ocEJ5tFfrd0cNDS4eOdAOL+W8nV pjJ4EnXR0RFZPEkWcBcbtP8WYYXI6HwVBgnGiEPydL/3pVSmbxrc3oXpawW2riwt yl7obJMOYWm9xTdDvnKnaAGcGGtr5V9oEwdzGsJNxbDydOy1PMWc62OlP+S2qo0= =Lat6 -----END PGP SIGNATURE----- Merge tag 'libtraceevent-core-for-acme' of git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf into perf/core libtraceevent/core improvements * Remaining backport of trace-cmd's libparseevent Signed-off-by: Namhyung Kim <namhyung@kernel.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
commit
81e9b994bb
@ -467,8 +467,10 @@ int pevent_register_function(struct pevent *pevent, char *func,
|
||||
item->mod = NULL;
|
||||
item->addr = addr;
|
||||
|
||||
pevent->funclist = item;
|
||||
if (!item->func || (mod && !item->mod))
|
||||
die("malloc func");
|
||||
|
||||
pevent->funclist = item;
|
||||
pevent->func_count++;
|
||||
|
||||
return 0;
|
||||
@ -511,12 +513,12 @@ struct printk_list {
|
||||
|
||||
static int printk_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct func_map *fa = a;
|
||||
const struct func_map *fb = b;
|
||||
const struct printk_map *pa = a;
|
||||
const struct printk_map *pb = b;
|
||||
|
||||
if (fa->addr < fb->addr)
|
||||
if (pa->addr < pb->addr)
|
||||
return -1;
|
||||
if (fa->addr > fb->addr)
|
||||
if (pa->addr > pb->addr)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@ -583,10 +585,13 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt,
|
||||
item = malloc_or_die(sizeof(*item));
|
||||
|
||||
item->next = pevent->printklist;
|
||||
pevent->printklist = item;
|
||||
item->printk = strdup(fmt);
|
||||
item->addr = addr;
|
||||
|
||||
if (!item->printk)
|
||||
die("malloc fmt");
|
||||
|
||||
pevent->printklist = item;
|
||||
pevent->printk_count++;
|
||||
|
||||
return 0;
|
||||
@ -628,12 +633,8 @@ static void add_event(struct pevent *pevent, struct event_format *event)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!pevent->events)
|
||||
pevent->events = malloc_or_die(sizeof(event));
|
||||
else
|
||||
pevent->events =
|
||||
realloc(pevent->events, sizeof(event) *
|
||||
(pevent->nr_events + 1));
|
||||
pevent->events = realloc(pevent->events, sizeof(event) *
|
||||
(pevent->nr_events + 1));
|
||||
if (!pevent->events)
|
||||
die("Can not allocate events");
|
||||
|
||||
@ -781,6 +782,25 @@ int pevent_peek_char(void)
|
||||
return __peek_char();
|
||||
}
|
||||
|
||||
static int extend_token(char **tok, char *buf, int size)
|
||||
{
|
||||
char *newtok = realloc(*tok, size);
|
||||
|
||||
if (!newtok) {
|
||||
free(*tok);
|
||||
*tok = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!*tok)
|
||||
strcpy(newtok, buf);
|
||||
else
|
||||
strcat(newtok, buf);
|
||||
*tok = newtok;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum event_type force_token(const char *str, char **tok);
|
||||
|
||||
static enum event_type __read_token(char **tok)
|
||||
@ -865,17 +885,10 @@ static enum event_type __read_token(char **tok)
|
||||
do {
|
||||
if (i == (BUFSIZ - 1)) {
|
||||
buf[i] = 0;
|
||||
if (*tok) {
|
||||
*tok = realloc(*tok, tok_size + BUFSIZ);
|
||||
if (!*tok)
|
||||
return EVENT_NONE;
|
||||
strcat(*tok, buf);
|
||||
} else
|
||||
*tok = strdup(buf);
|
||||
|
||||
if (!*tok)
|
||||
return EVENT_NONE;
|
||||
tok_size += BUFSIZ;
|
||||
|
||||
if (extend_token(tok, buf, tok_size) < 0)
|
||||
return EVENT_NONE;
|
||||
i = 0;
|
||||
}
|
||||
last_ch = ch;
|
||||
@ -914,17 +927,10 @@ static enum event_type __read_token(char **tok)
|
||||
while (get_type(__peek_char()) == type) {
|
||||
if (i == (BUFSIZ - 1)) {
|
||||
buf[i] = 0;
|
||||
if (*tok) {
|
||||
*tok = realloc(*tok, tok_size + BUFSIZ);
|
||||
if (!*tok)
|
||||
return EVENT_NONE;
|
||||
strcat(*tok, buf);
|
||||
} else
|
||||
*tok = strdup(buf);
|
||||
|
||||
if (!*tok)
|
||||
return EVENT_NONE;
|
||||
tok_size += BUFSIZ;
|
||||
|
||||
if (extend_token(tok, buf, tok_size) < 0)
|
||||
return EVENT_NONE;
|
||||
i = 0;
|
||||
}
|
||||
ch = __read_char();
|
||||
@ -933,14 +939,7 @@ static enum event_type __read_token(char **tok)
|
||||
|
||||
out:
|
||||
buf[i] = 0;
|
||||
if (*tok) {
|
||||
*tok = realloc(*tok, tok_size + i);
|
||||
if (!*tok)
|
||||
return EVENT_NONE;
|
||||
strcat(*tok, buf);
|
||||
} else
|
||||
*tok = strdup(buf);
|
||||
if (!*tok)
|
||||
if (extend_token(tok, buf, tok_size + i + 1) < 0)
|
||||
return EVENT_NONE;
|
||||
|
||||
if (type == EVENT_ITEM) {
|
||||
@ -1261,9 +1260,15 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||
field->flags |= FIELD_IS_POINTER;
|
||||
|
||||
if (field->type) {
|
||||
field->type = realloc(field->type,
|
||||
strlen(field->type) +
|
||||
strlen(last_token) + 2);
|
||||
char *new_type;
|
||||
new_type = realloc(field->type,
|
||||
strlen(field->type) +
|
||||
strlen(last_token) + 2);
|
||||
if (!new_type) {
|
||||
free(last_token);
|
||||
goto fail;
|
||||
}
|
||||
field->type = new_type;
|
||||
strcat(field->type, " ");
|
||||
strcat(field->type, last_token);
|
||||
free(last_token);
|
||||
@ -1288,6 +1293,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||
if (strcmp(token, "[") == 0) {
|
||||
enum event_type last_type = type;
|
||||
char *brackets = token;
|
||||
char *new_brackets;
|
||||
int len;
|
||||
|
||||
field->flags |= FIELD_IS_ARRAY;
|
||||
@ -1307,9 +1313,14 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||
len = 1;
|
||||
last_type = type;
|
||||
|
||||
brackets = realloc(brackets,
|
||||
strlen(brackets) +
|
||||
strlen(token) + len);
|
||||
new_brackets = realloc(brackets,
|
||||
strlen(brackets) +
|
||||
strlen(token) + len);
|
||||
if (!new_brackets) {
|
||||
free(brackets);
|
||||
goto fail;
|
||||
}
|
||||
brackets = new_brackets;
|
||||
if (len == 2)
|
||||
strcat(brackets, " ");
|
||||
strcat(brackets, token);
|
||||
@ -1325,7 +1336,12 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||
|
||||
free_token(token);
|
||||
|
||||
brackets = realloc(brackets, strlen(brackets) + 2);
|
||||
new_brackets = realloc(brackets, strlen(brackets) + 2);
|
||||
if (!new_brackets) {
|
||||
free(brackets);
|
||||
goto fail;
|
||||
}
|
||||
brackets = new_brackets;
|
||||
strcat(brackets, "]");
|
||||
|
||||
/* add brackets to type */
|
||||
@ -1336,10 +1352,16 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||
* the format: type [] item;
|
||||
*/
|
||||
if (type == EVENT_ITEM) {
|
||||
field->type = realloc(field->type,
|
||||
strlen(field->type) +
|
||||
strlen(field->name) +
|
||||
strlen(brackets) + 2);
|
||||
char *new_type;
|
||||
new_type = realloc(field->type,
|
||||
strlen(field->type) +
|
||||
strlen(field->name) +
|
||||
strlen(brackets) + 2);
|
||||
if (!new_type) {
|
||||
free(brackets);
|
||||
goto fail;
|
||||
}
|
||||
field->type = new_type;
|
||||
strcat(field->type, " ");
|
||||
strcat(field->type, field->name);
|
||||
free_token(field->name);
|
||||
@ -1347,9 +1369,15 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||
field->name = token;
|
||||
type = read_token(&token);
|
||||
} else {
|
||||
field->type = realloc(field->type,
|
||||
strlen(field->type) +
|
||||
strlen(brackets) + 1);
|
||||
char *new_type;
|
||||
new_type = realloc(field->type,
|
||||
strlen(field->type) +
|
||||
strlen(brackets) + 1);
|
||||
if (!new_type) {
|
||||
free(brackets);
|
||||
goto fail;
|
||||
}
|
||||
field->type = new_type;
|
||||
strcat(field->type, brackets);
|
||||
}
|
||||
free(brackets);
|
||||
@ -1732,10 +1760,16 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
|
||||
/* could just be a type pointer */
|
||||
if ((strcmp(arg->op.op, "*") == 0) &&
|
||||
type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
|
||||
char *new_atom;
|
||||
|
||||
if (left->type != PRINT_ATOM)
|
||||
die("bad pointer type");
|
||||
left->atom.atom = realloc(left->atom.atom,
|
||||
new_atom = realloc(left->atom.atom,
|
||||
strlen(left->atom.atom) + 3);
|
||||
if (!new_atom)
|
||||
goto out_free;
|
||||
|
||||
left->atom.atom = new_atom;
|
||||
strcat(left->atom.atom, " *");
|
||||
free(arg->op.op);
|
||||
*arg = *left;
|
||||
@ -2152,6 +2186,8 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char **
|
||||
if (value == NULL)
|
||||
goto out_free;
|
||||
field->value = strdup(value);
|
||||
if (field->value == NULL)
|
||||
goto out_free;
|
||||
|
||||
free_arg(arg);
|
||||
arg = alloc_arg();
|
||||
@ -2165,6 +2201,8 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char **
|
||||
if (value == NULL)
|
||||
goto out_free;
|
||||
field->str = strdup(value);
|
||||
if (field->str == NULL)
|
||||
goto out_free;
|
||||
free_arg(arg);
|
||||
arg = NULL;
|
||||
|
||||
@ -2590,7 +2628,16 @@ process_arg_token(struct event_format *event, struct print_arg *arg,
|
||||
}
|
||||
/* atoms can be more than one token long */
|
||||
while (type == EVENT_ITEM) {
|
||||
atom = realloc(atom, strlen(atom) + strlen(token) + 2);
|
||||
char *new_atom;
|
||||
new_atom = realloc(atom,
|
||||
strlen(atom) + strlen(token) + 2);
|
||||
if (!new_atom) {
|
||||
free(atom);
|
||||
*tok = NULL;
|
||||
free_token(token);
|
||||
return EVENT_ERROR;
|
||||
}
|
||||
atom = new_atom;
|
||||
strcat(atom, " ");
|
||||
strcat(atom, token);
|
||||
free_token(token);
|
||||
@ -2884,7 +2931,7 @@ static int get_common_info(struct pevent *pevent,
|
||||
event = pevent->events[0];
|
||||
field = pevent_find_common_field(event, type);
|
||||
if (!field)
|
||||
die("field '%s' not found", type);
|
||||
return -1;
|
||||
|
||||
*offset = field->offset;
|
||||
*size = field->size;
|
||||
@ -2935,15 +2982,16 @@ static int parse_common_flags(struct pevent *pevent, void *data)
|
||||
|
||||
static int parse_common_lock_depth(struct pevent *pevent, void *data)
|
||||
{
|
||||
int ret;
|
||||
return __parse_common(pevent, data,
|
||||
&pevent->ld_size, &pevent->ld_offset,
|
||||
"common_lock_depth");
|
||||
}
|
||||
|
||||
ret = __parse_common(pevent, data,
|
||||
&pevent->ld_size, &pevent->ld_offset,
|
||||
"common_lock_depth");
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
static int parse_common_migrate_disable(struct pevent *pevent, void *data)
|
||||
{
|
||||
return __parse_common(pevent, data,
|
||||
&pevent->ld_size, &pevent->ld_offset,
|
||||
"common_migrate_disable");
|
||||
}
|
||||
|
||||
static int events_id_cmp(const void *a, const void *b);
|
||||
@ -3370,7 +3418,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
|
||||
break;
|
||||
}
|
||||
case PRINT_BSTRING:
|
||||
trace_seq_printf(s, format, arg->string.string);
|
||||
print_str_to_seq(s, format, len_arg, arg->string.string);
|
||||
break;
|
||||
case PRINT_OP:
|
||||
/*
|
||||
@ -3434,6 +3482,10 @@ process_defined_func(struct trace_seq *s, void *data, int size,
|
||||
string = malloc_or_die(sizeof(*string));
|
||||
string->next = strings;
|
||||
string->str = strdup(str.buffer);
|
||||
if (!string->str)
|
||||
die("malloc str");
|
||||
|
||||
args[i] = (unsigned long long)string->str;
|
||||
strings = string;
|
||||
trace_seq_destroy(&str);
|
||||
break;
|
||||
@ -3471,6 +3523,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||
unsigned long long ip, val;
|
||||
char *ptr;
|
||||
void *bptr;
|
||||
int vsize;
|
||||
|
||||
field = pevent->bprint_buf_field;
|
||||
ip_field = pevent->bprint_ip_field;
|
||||
@ -3519,6 +3572,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||
goto process_again;
|
||||
case '0' ... '9':
|
||||
goto process_again;
|
||||
case '.':
|
||||
goto process_again;
|
||||
case 'p':
|
||||
ls = 1;
|
||||
/* fall through */
|
||||
@ -3526,23 +3581,30 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'i':
|
||||
switch (ls) {
|
||||
case 0:
|
||||
vsize = 4;
|
||||
break;
|
||||
case 1:
|
||||
vsize = pevent->long_size;
|
||||
break;
|
||||
case 2:
|
||||
vsize = 8;
|
||||
break;
|
||||
default:
|
||||
vsize = ls; /* ? */
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case '*':
|
||||
if (*ptr == '*')
|
||||
vsize = 4;
|
||||
|
||||
/* the pointers are always 4 bytes aligned */
|
||||
bptr = (void *)(((unsigned long)bptr + 3) &
|
||||
~3);
|
||||
switch (ls) {
|
||||
case 0:
|
||||
ls = 4;
|
||||
break;
|
||||
case 1:
|
||||
ls = pevent->long_size;
|
||||
break;
|
||||
case 2:
|
||||
ls = 8;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
val = pevent_read_number(pevent, bptr, ls);
|
||||
bptr += ls;
|
||||
val = pevent_read_number(pevent, bptr, vsize);
|
||||
bptr += vsize;
|
||||
arg = alloc_arg();
|
||||
arg->next = NULL;
|
||||
arg->type = PRINT_ATOM;
|
||||
@ -3550,12 +3612,21 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||
sprintf(arg->atom.atom, "%lld", val);
|
||||
*next = arg;
|
||||
next = &arg->next;
|
||||
/*
|
||||
* The '*' case means that an arg is used as the length.
|
||||
* We need to continue to figure out for what.
|
||||
*/
|
||||
if (*ptr == '*')
|
||||
goto process_again;
|
||||
|
||||
break;
|
||||
case 's':
|
||||
arg = alloc_arg();
|
||||
arg->next = NULL;
|
||||
arg->type = PRINT_BSTRING;
|
||||
arg->string.string = strdup(bptr);
|
||||
if (!arg->string.string)
|
||||
break;
|
||||
bptr += strlen(bptr) + 1;
|
||||
*next = arg;
|
||||
next = &arg->next;
|
||||
@ -3841,6 +3912,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
|
||||
} else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
|
||||
print_mac_arg(s, *(ptr+1), data, size, event, arg);
|
||||
ptr++;
|
||||
arg = arg->next;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3877,14 +3949,15 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pevent->long_size == 8 && ls) {
|
||||
if (pevent->long_size == 8 && ls &&
|
||||
sizeof(long) != 8) {
|
||||
char *p;
|
||||
|
||||
ls = 2;
|
||||
/* make %l into %ll */
|
||||
p = strchr(format, 'l');
|
||||
if (p)
|
||||
memmove(p, p+1, strlen(p)+1);
|
||||
memmove(p+1, p, strlen(p)+1);
|
||||
else if (strcmp(format, "%p") == 0)
|
||||
strcpy(format, "0x%llx");
|
||||
}
|
||||
@ -3961,8 +4034,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
|
||||
* pevent_data_lat_fmt - parse the data for the latency format
|
||||
* @pevent: a handle to the pevent
|
||||
* @s: the trace_seq to write to
|
||||
* @data: the raw data to read from
|
||||
* @size: currently unused.
|
||||
* @record: the record to read from
|
||||
*
|
||||
* This parses out the Latency format (interrupts disabled,
|
||||
* need rescheduling, in hard/soft interrupt, preempt count
|
||||
@ -3972,10 +4044,13 @@ void pevent_data_lat_fmt(struct pevent *pevent,
|
||||
struct trace_seq *s, struct pevent_record *record)
|
||||
{
|
||||
static int check_lock_depth = 1;
|
||||
static int check_migrate_disable = 1;
|
||||
static int lock_depth_exists;
|
||||
static int migrate_disable_exists;
|
||||
unsigned int lat_flags;
|
||||
unsigned int pc;
|
||||
int lock_depth;
|
||||
int migrate_disable;
|
||||
int hardirq;
|
||||
int softirq;
|
||||
void *data = record->data;
|
||||
@ -3983,18 +4058,26 @@ void pevent_data_lat_fmt(struct pevent *pevent,
|
||||
lat_flags = parse_common_flags(pevent, data);
|
||||
pc = parse_common_pc(pevent, data);
|
||||
/* lock_depth may not always exist */
|
||||
if (check_lock_depth) {
|
||||
struct format_field *field;
|
||||
struct event_format *event;
|
||||
|
||||
check_lock_depth = 0;
|
||||
event = pevent->events[0];
|
||||
field = pevent_find_common_field(event, "common_lock_depth");
|
||||
if (field)
|
||||
lock_depth_exists = 1;
|
||||
}
|
||||
if (lock_depth_exists)
|
||||
lock_depth = parse_common_lock_depth(pevent, data);
|
||||
else if (check_lock_depth) {
|
||||
lock_depth = parse_common_lock_depth(pevent, data);
|
||||
if (lock_depth < 0)
|
||||
check_lock_depth = 0;
|
||||
else
|
||||
lock_depth_exists = 1;
|
||||
}
|
||||
|
||||
/* migrate_disable may not always exist */
|
||||
if (migrate_disable_exists)
|
||||
migrate_disable = parse_common_migrate_disable(pevent, data);
|
||||
else if (check_migrate_disable) {
|
||||
migrate_disable = parse_common_migrate_disable(pevent, data);
|
||||
if (migrate_disable < 0)
|
||||
check_migrate_disable = 0;
|
||||
else
|
||||
migrate_disable_exists = 1;
|
||||
}
|
||||
|
||||
hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
|
||||
softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
|
||||
@ -4013,6 +4096,13 @@ void pevent_data_lat_fmt(struct pevent *pevent,
|
||||
else
|
||||
trace_seq_putc(s, '.');
|
||||
|
||||
if (migrate_disable_exists) {
|
||||
if (migrate_disable < 0)
|
||||
trace_seq_putc(s, '.');
|
||||
else
|
||||
trace_seq_printf(s, "%d", migrate_disable);
|
||||
}
|
||||
|
||||
if (lock_depth_exists) {
|
||||
if (lock_depth < 0)
|
||||
trace_seq_putc(s, '.');
|
||||
@ -4079,10 +4169,7 @@ const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
|
||||
* pevent_data_comm_from_pid - parse the data into the print format
|
||||
* @s: the trace_seq to write to
|
||||
* @event: the handle to the event
|
||||
* @cpu: the cpu the event was recorded on
|
||||
* @data: the raw data
|
||||
* @size: the size of the raw data
|
||||
* @nsecs: the timestamp of the event
|
||||
* @record: the record to read from
|
||||
*
|
||||
* This parses the raw @data using the given @event information and
|
||||
* writes the print format into the trace_seq.
|
||||
@ -4631,6 +4718,8 @@ int pevent_parse_event(struct pevent *pevent,
|
||||
die("failed to read event id");
|
||||
|
||||
event->system = strdup(sys);
|
||||
if (!event->system)
|
||||
die("failed to allocate system");
|
||||
|
||||
/* Add pevent to event so that it can be referenced */
|
||||
event->pevent = pevent;
|
||||
@ -4672,6 +4761,11 @@ int pevent_parse_event(struct pevent *pevent,
|
||||
list = &arg->next;
|
||||
arg->type = PRINT_FIELD;
|
||||
arg->field.name = strdup(field->name);
|
||||
if (!arg->field.name) {
|
||||
do_warning("failed to allocate field name");
|
||||
event->flags |= EVENT_FL_FAILED;
|
||||
return -1;
|
||||
}
|
||||
arg->field.field = field;
|
||||
}
|
||||
return 0;
|
||||
@ -4843,7 +4937,7 @@ int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
|
||||
* @record: The record with the field name.
|
||||
* @err: print default error if failed.
|
||||
*
|
||||
* Returns: 0 on success, -1 field not fould, or 1 if buffer is full.
|
||||
* Returns: 0 on success, -1 field not found, or 1 if buffer is full.
|
||||
*/
|
||||
int pevent_print_num_field(struct trace_seq *s, const char *fmt,
|
||||
struct event_format *event, const char *name,
|
||||
@ -4885,11 +4979,12 @@ static void free_func_handle(struct pevent_function_handler *func)
|
||||
* pevent_register_print_function - register a helper function
|
||||
* @pevent: the handle to the pevent
|
||||
* @func: the function to process the helper function
|
||||
* @ret_type: the return type of the helper function
|
||||
* @name: the name of the helper function
|
||||
* @parameters: A list of enum pevent_func_arg_type
|
||||
*
|
||||
* Some events may have helper functions in the print format arguments.
|
||||
* This allows a plugin to dynmically create a way to process one
|
||||
* This allows a plugin to dynamically create a way to process one
|
||||
* of these functions.
|
||||
*
|
||||
* The @parameters is a variable list of pevent_func_arg_type enums that
|
||||
@ -4960,12 +5055,13 @@ int pevent_register_print_function(struct pevent *pevent,
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_register_event_handle - register a way to parse an event
|
||||
* pevent_register_event_handler - register a way to parse an event
|
||||
* @pevent: the handle to the pevent
|
||||
* @id: the id of the event to register
|
||||
* @sys_name: the system name the event belongs to
|
||||
* @event_name: the name of the event
|
||||
* @func: the function to call to parse the event information
|
||||
* @context: the data to be passed to @func
|
||||
*
|
||||
* This function allows a developer to override the parsing of
|
||||
* a given event. If for some reason the default print format
|
||||
@ -5015,6 +5111,11 @@ int pevent_register_event_handler(struct pevent *pevent,
|
||||
if (sys_name)
|
||||
handle->sys_name = strdup(sys_name);
|
||||
|
||||
if ((event_name && !handle->event_name) ||
|
||||
(sys_name && !handle->sys_name)) {
|
||||
die("Failed to allocate event/sys name");
|
||||
}
|
||||
|
||||
handle->func = func;
|
||||
handle->next = pevent->handlers;
|
||||
pevent->handlers = handle;
|
||||
|
@ -96,7 +96,7 @@ static enum event_type read_token(char **tok)
|
||||
(strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
|
||||
pevent_peek_char() == '~') {
|
||||
/* append it */
|
||||
*tok = malloc(3);
|
||||
*tok = malloc_or_die(3);
|
||||
sprintf(*tok, "%c%c", *token, '~');
|
||||
free_token(token);
|
||||
/* Now remove the '~' from the buffer */
|
||||
@ -148,17 +148,11 @@ add_filter_type(struct event_filter *filter, int id)
|
||||
if (filter_type)
|
||||
return filter_type;
|
||||
|
||||
if (!filter->filters)
|
||||
filter->event_filters =
|
||||
malloc_or_die(sizeof(*filter->event_filters));
|
||||
else {
|
||||
filter->event_filters =
|
||||
realloc(filter->event_filters,
|
||||
sizeof(*filter->event_filters) *
|
||||
(filter->filters + 1));
|
||||
if (!filter->event_filters)
|
||||
die("Could not allocate filter");
|
||||
}
|
||||
filter->event_filters = realloc(filter->event_filters,
|
||||
sizeof(*filter->event_filters) *
|
||||
(filter->filters + 1));
|
||||
if (!filter->event_filters)
|
||||
die("Could not allocate filter");
|
||||
|
||||
for (i = 0; i < filter->filters; i++) {
|
||||
if (filter->event_filters[i].event_id > id)
|
||||
@ -1480,7 +1474,7 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
{
|
||||
struct filter_type *filter_type;
|
||||
int count = 0;
|
||||
int *ids;
|
||||
int *ids = NULL;
|
||||
int i;
|
||||
|
||||
if (!filter->filters)
|
||||
@ -1504,10 +1498,8 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (count)
|
||||
ids = realloc(ids, sizeof(*ids) * (count + 1));
|
||||
else
|
||||
ids = malloc(sizeof(*ids));
|
||||
|
||||
ids = realloc(ids, sizeof(*ids) * (count + 1));
|
||||
if (!ids)
|
||||
die("Can't allocate ids");
|
||||
ids[count++] = filter_type->event_id;
|
||||
@ -1710,18 +1702,43 @@ static int test_num(struct event_format *event,
|
||||
|
||||
static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
|
||||
{
|
||||
const char *val = record->data + arg->str.field->offset;
|
||||
struct event_format *event;
|
||||
struct pevent *pevent;
|
||||
unsigned long long addr;
|
||||
const char *val = NULL;
|
||||
char hex[64];
|
||||
|
||||
/*
|
||||
* We need to copy the data since we can't be sure the field
|
||||
* is null terminated.
|
||||
*/
|
||||
if (*(val + arg->str.field->size - 1)) {
|
||||
/* copy it */
|
||||
memcpy(arg->str.buffer, val, arg->str.field->size);
|
||||
/* the buffer is already NULL terminated */
|
||||
val = arg->str.buffer;
|
||||
/* If the field is not a string convert it */
|
||||
if (arg->str.field->flags & FIELD_IS_STRING) {
|
||||
val = record->data + arg->str.field->offset;
|
||||
|
||||
/*
|
||||
* We need to copy the data since we can't be sure the field
|
||||
* is null terminated.
|
||||
*/
|
||||
if (*(val + arg->str.field->size - 1)) {
|
||||
/* copy it */
|
||||
memcpy(arg->str.buffer, val, arg->str.field->size);
|
||||
/* the buffer is already NULL terminated */
|
||||
val = arg->str.buffer;
|
||||
}
|
||||
|
||||
} else {
|
||||
event = arg->str.field->event;
|
||||
pevent = event->pevent;
|
||||
addr = get_value(event, arg->str.field, record);
|
||||
|
||||
if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG))
|
||||
/* convert to a kernel symbol */
|
||||
val = pevent_find_function(pevent, addr);
|
||||
|
||||
if (val == NULL) {
|
||||
/* just use the hex of the string name */
|
||||
snprintf(hex, 64, "0x%llx", addr);
|
||||
val = hex;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -2001,11 +2018,13 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||
char *lstr;
|
||||
char *rstr;
|
||||
char *op;
|
||||
char *str;
|
||||
char *str = NULL;
|
||||
int len;
|
||||
|
||||
lstr = arg_to_str(filter, arg->exp.left);
|
||||
rstr = arg_to_str(filter, arg->exp.right);
|
||||
if (!lstr || !rstr)
|
||||
goto out;
|
||||
|
||||
switch (arg->exp.type) {
|
||||
case FILTER_EXP_ADD:
|
||||
@ -2045,6 +2064,7 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||
len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
|
||||
str = malloc_or_die(len);
|
||||
snprintf(str, len, "%s %s %s", lstr, op, rstr);
|
||||
out:
|
||||
free(lstr);
|
||||
free(rstr);
|
||||
|
||||
@ -2061,6 +2081,8 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||
|
||||
lstr = arg_to_str(filter, arg->num.left);
|
||||
rstr = arg_to_str(filter, arg->num.right);
|
||||
if (!lstr || !rstr)
|
||||
goto out;
|
||||
|
||||
switch (arg->num.type) {
|
||||
case FILTER_CMP_EQ:
|
||||
@ -2097,6 +2119,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
free(lstr);
|
||||
free(rstr);
|
||||
return str;
|
||||
@ -2247,7 +2270,12 @@ int pevent_filter_compare(struct event_filter *filter1, struct event_filter *fil
|
||||
/* The best way to compare complex filters is with strings */
|
||||
str1 = arg_to_str(filter1, filter_type1->filter);
|
||||
str2 = arg_to_str(filter2, filter_type2->filter);
|
||||
result = strcmp(str1, str2) != 0;
|
||||
if (str1 && str2)
|
||||
result = strcmp(str1, str2) != 0;
|
||||
else
|
||||
/* bail out if allocation fails */
|
||||
result = 1;
|
||||
|
||||
free(str1);
|
||||
free(str2);
|
||||
if (result)
|
||||
|
Loading…
Reference in New Issue
Block a user