@@ -4,10 +4,12 @@
#include <string.h>
#include <linux/bitops.h>
#include <stdlib.h>
+#include <limits.h>
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
+void bitmap_from_u64(unsigned long *dst, u64 mask);
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);
@@ -73,3 +73,21 @@ int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
BITMAP_LAST_WORD_MASK(bits));
return result != 0;
}
+
+/*
+ * 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;
+}
@@ -421,11 +421,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",