@@ -2,6 +2,7 @@
#define _PERF_BITOPS_H
#include <string.h>
+#include <limits.h>
#include <linux/bitops.h>
#define DECLARE_BITMAP(name,bits) \
@@ -10,6 +11,7 @@
int __bitmap_weight(const unsigned long *bitmap, int bits);
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits);
+void bitmap_from_u64(unsigned long *dst, u64 mask);
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
@@ -29,3 +29,21 @@ void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
for (k = 0; k < nr; k++)
dst[k] = bitmap1[k] | bitmap2[k];
}
+
+/*
+ * bitmap_from_u64 - Check and swap words within u64.
+ * @mask: source bitmap
+ * @dst: destination bitmap
+ *
+ * In 32 bit big endian userspace on a 64bit kernel, 'unsigned long' is 32 bits.
+ * When reading u64 using (u32 *)(&val)[0] and (u32 *)(&val)[1],
+ * we will get wrong value for the mask. That is "(u32 *)(&val)[0]"
+ * gets upper 32 bits of u64, but perf may expect lower 32bits of u64.
+ */
+void bitmap_from_u64(unsigned long *dst, u64 mask)
+{
+ dst[0] = mask & ULONG_MAX;
+
+ if (sizeof(mask) > sizeof(unsigned long))
+ dst[1] = mask >> 32;
+}
@@ -418,11 +418,13 @@ static void print_sample_iregs(struct perf_sample *sample,
struct regs_dump *regs = &sample->intr_regs;
uint64_t mask = attr->sample_regs_intr;
unsigned i = 0, r;
+ DECLARE_BITMAP(_mask, 64);
if (!regs)
return;
- for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {
+ bitmap_from_u64(_mask, mask);
+ for_each_set_bit(r, _mask, sizeof(mask) * 8) {
u64 val = regs->regs[i++];
printf("%5s:0x%"PRIx64" ", perf_reg_name(r), val);
}
@@ -944,8 +944,10 @@ static void branch_stack__printf(struct perf_sample *sample)
static void regs_dump__printf(u64 mask, u64 *regs)
{
unsigned rid, i = 0;
+ DECLARE_BITMAP(_mask, 64);
- for_each_set_bit(rid, (unsigned long *) &mask, sizeof(mask) * 8) {
+ bitmap_from_u64(_mask, mask);
+ for_each_set_bit(rid, _mask, sizeof(mask) * 8) {
u64 val = regs[i++];
printf(".... %-5s 0x%" PRIx64 "\n",