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

Commit d4ae4213 authored by Wang Nan's avatar Wang Nan Committed by Arnaldo Carvalho de Melo
Browse files

perf data: Fix signedness of value



When converting int values, perf first extractes it to a ulonglong, then
feeds it to babeltrace as a signed value.

For negative 32 bit values (for example, return values of failed
syscalls), the extracted data should be something like 0xfffffffe (-2).
It becomes a large int64 value.

Babeltrace denies to insert it with bt_ctf_field_signed_integer_set_value()
because it is larger than 0x7fffffff, the largest positive value a
 32 bit int can be.

This patch introduces adjust_signedness(), which fills high bits of
ulonglong with 1 if the value is negative.

Signed-off-by: default avatarWang Nan <wangnan0@huawei.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jeremie Galarneau <jgalar@efficios.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Tom Zanussi <tzanussi@gmail.com>
Link: http://lkml.kernel.org/r/1429372220-6406-8-git-send-email-jolsa@kernel.org


Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
[ s/signess/signedness/g ]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent e0a7cce5
Loading
Loading
Loading
Loading
+52 −12
Original line number Diff line number Diff line
@@ -166,6 +166,43 @@ get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
		return cw->data.u32;
}

static unsigned long long adjust_signedness(unsigned long long value_int, int size)
{
	unsigned long long value_mask;

	/*
	 * value_mask = (1 << (size * 8 - 1)) - 1.
	 * Directly set value_mask for code readers.
	 */
	switch (size) {
	case 1:
		value_mask = 0x7fULL;
		break;
	case 2:
		value_mask = 0x7fffULL;
		break;
	case 4:
		value_mask = 0x7fffffffULL;
		break;
	case 8:
		/*
		 * For 64 bit value, return it self. There is no need
		 * to fill high bit.
		 */
		/* Fall through */
	default:
		/* BUG! */
		return value_int;
	}

	/* If it is a positive value, don't adjust. */
	if ((value_int & (~0ULL - value_mask)) == 0)
		return value_int;

	/* Fill upper part of value_int with 1 to make it a negative long long. */
	return (value_int & value_mask) | ~value_mask;
}

static int add_tracepoint_field_value(struct ctf_writer *cw,
				      struct bt_ctf_event_class *event_class,
				      struct bt_ctf_event *event,
@@ -177,7 +214,6 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
	struct bt_ctf_field *field;
	const char *name = fmtf->name;
	void *data = sample->raw_data;
	unsigned long long value_int;
	unsigned long flags = fmtf->flags;
	unsigned int n_items;
	unsigned int i;
@@ -222,11 +258,6 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
	type = get_tracepoint_field_type(cw, fmtf);

	for (i = 0; i < n_items; i++) {
		if (!(flags & FIELD_IS_STRING))
			value_int = pevent_read_number(
					fmtf->event->pevent,
					data + offset + i * len, len);

		if (flags & FIELD_IS_ARRAY)
			field = bt_ctf_field_array_get_field(array_field, i);
		else
@@ -240,12 +271,21 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
		if (flags & FIELD_IS_STRING)
			ret = bt_ctf_field_string_set_value(field,
					data + offset + i * len);
		else if (!(flags & FIELD_IS_SIGNED))
		else {
			unsigned long long value_int;

			value_int = pevent_read_number(
					fmtf->event->pevent,
					data + offset + i * len, len);

			if (!(flags & FIELD_IS_SIGNED))
				ret = bt_ctf_field_unsigned_integer_set_value(
						field, value_int);
			else
				ret = bt_ctf_field_signed_integer_set_value(
					field, value_int);
						field, adjust_signedness(value_int, len));
		}

		if (ret) {
			pr_err("failed to set file value %s\n", name);
			goto err_put_field;