perf data: Fix signedness of value
authorWang Nan <wangnan0@huawei.com>
Sat, 18 Apr 2015 15:50:20 +0000 (17:50 +0200)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 29 Apr 2015 13:37:49 +0000 (10:37 -0300)
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: Wang 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: Jiri Olsa <jolsa@kernel.org>
[ s/signess/signedness/g ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/data-convert-bt.c

index 8eda4ed628e758c4858f249522716b67f5a1412b..5bfc1198ab465c1873c7a112eefaa97bf286ee6f 100644 (file)
@@ -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))
-                       ret = bt_ctf_field_unsigned_integer_set_value(
-                                       field, value_int);
-               else
-                       ret = bt_ctf_field_signed_integer_set_value(
-                                       field, value_int);
+               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, adjust_signedness(value_int, len));
+               }
+
                if (ret) {
                        pr_err("failed to set file value %s\n", name);
                        goto err_put_field;