Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81e9b994 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo
Browse files

Merge tag 'libtraceevent-core-for-acme' of...

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: default avatarNamhyung Kim <namhyung@kernel.org>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parents 1dc12760 f6ced60f
Loading
Loading
Loading
Loading
+194 −93
Original line number Diff line number Diff line
@@ -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,11 +633,7 @@ 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->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);
				tok_size += BUFSIZ;

				if (!*tok)
				if (extend_token(tok, buf, tok_size) < 0)
					return EVENT_NONE;
				tok_size += BUFSIZ;
				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);
			tok_size += BUFSIZ;

			if (!*tok)
			if (extend_token(tok, buf, tok_size) < 0)
				return EVENT_NONE;
			tok_size += BUFSIZ;
			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,
					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,
				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,
				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,
				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;

	ret = __parse_common(pevent, data,
	return __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':
				/* the pointers are always 4 bytes aligned */
				bptr = (void *)(((unsigned long)bptr + 3) &
						~3);
				switch (ls) {
				case 0:
					ls = 4;
					vsize = 4;
					break;
				case 1:
					ls = pevent->long_size;
					vsize = pevent->long_size;
					break;
				case 2:
					ls = 8;
					vsize = 8;
					break;
				default:
					vsize = ls; /* ? */
					break;
				}
				val = pevent_read_number(pevent, bptr, ls);
				bptr += ls;
			/* fall through */
			case '*':
				if (*ptr == '*')
					vsize = 4;

				/* the pointers are always 4 bytes aligned */
				bptr = (void *)(((unsigned long)bptr + 3) &
						~3);
				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;

	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;
		event = pevent->events[0];
		field = pevent_find_common_field(event, "common_lock_depth");
		if (field)
		else
			lock_depth_exists = 1;
	}
	if (lock_depth_exists)
		lock_depth = parse_common_lock_depth(pevent, data);

	/* 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;
+57 −29
Original line number Diff line number Diff line
@@ -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,
	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));
		if (!ids)
			die("Can't allocate ids");
		ids[count++] = filter_type->event_id;
@@ -1710,7 +1702,15 @@ 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];

	/* 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
@@ -1722,6 +1722,23 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
			/* 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);
		if (str1 && str2)
			result = strcmp(str1, str2) != 0;
		else
			/* bail out if allocation fails */
			result = 1;

		free(str1);
		free(str2);
		if (result)