* [PATCH 1/3] ARM64: perf: add support for perf registers API
[not found] <1387212562-8128-1-git-send-email-y>
@ 2013-12-16 16:49 ` jean.pihet
2013-12-17 11:11 ` Will Deacon
2013-12-16 16:49 ` [PATCH 2/3] ARM64: perf: wire up perf_regs and unwind support jean.pihet
2013-12-16 16:49 ` [PATCH 3/3] ARM64: perf: add support for frame pointer unwinding in compat mode jean.pihet
2 siblings, 1 reply; 12+ messages in thread
From: jean.pihet @ 2013-12-16 16:49 UTC (permalink / raw)
To: linux-kernel, linaro-kernel, Arnaldo, Will Deacon
Cc: patches, Jiri Olsa, Ingo Molnar, Jean Pihet
From: Jean Pihet <jean.pihet@linaro.org>
This patch implements the functions required for the perf registers API,
allowing the perf tool to interface kernel register dumps with libunwind
in order to provide userspace backtracing.
Compat mode is also supported.
Only the general purpose user space registers are exported, i.e.:
PERF_REG_ARM_X0,
...
PERF_REG_ARM_X28,
PERF_REG_ARM_FP,
PERF_REG_ARM_LR,
PERF_REG_ARM_SP,
PERF_REG_ARM_PC
and not the PERF_REG_ARM_V* registers.
Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/Kconfig | 2 ++
arch/arm64/include/asm/ptrace.h | 1 +
arch/arm64/include/uapi/asm/Kbuild | 1 +
arch/arm64/include/uapi/asm/perf_regs.h | 40 ++++++++++++++++++++++++++++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/perf_regs.c | 46 +++++++++++++++++++++++++++++++++
6 files changed, 91 insertions(+)
create mode 100644 arch/arm64/include/uapi/asm/perf_regs.h
create mode 100644 arch/arm64/kernel/perf_regs.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 88c8b6c1..f8609dc 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -28,6 +28,8 @@ config ARM64
select HAVE_HW_BREAKPOINT if PERF_EVENTS
select HAVE_MEMBLOCK
select HAVE_PERF_EVENTS
+ select HAVE_PERF_REGS
+ select HAVE_PERF_USER_STACK_DUMP
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select NO_BOOTMEM
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 0e7fa49..fbb0020 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -68,6 +68,7 @@
/* Architecturally defined mapping between AArch32 and AArch64 registers */
#define compat_usr(x) regs[(x)]
+#define compat_fp regs[11]
#define compat_sp regs[13]
#define compat_lr regs[14]
#define compat_sp_hyp regs[15]
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index e4b78bd..942376d 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -9,6 +9,7 @@ header-y += byteorder.h
header-y += fcntl.h
header-y += hwcap.h
header-y += kvm_para.h
+header-y += perf_regs.h
header-y += param.h
header-y += ptrace.h
header-y += setup.h
diff --git a/arch/arm64/include/uapi/asm/perf_regs.h b/arch/arm64/include/uapi/asm/perf_regs.h
new file mode 100644
index 0000000..06bf360
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/perf_regs.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_ARM_PERF_REGS_H
+#define _ASM_ARM_PERF_REGS_H
+
+enum perf_event_arm_regs {
+ PERF_REG_ARM_X0,
+ PERF_REG_ARM_X1,
+ PERF_REG_ARM_X2,
+ PERF_REG_ARM_X3,
+ PERF_REG_ARM_X4,
+ PERF_REG_ARM_X5,
+ PERF_REG_ARM_X6,
+ PERF_REG_ARM_X7,
+ PERF_REG_ARM_X8,
+ PERF_REG_ARM_X9,
+ PERF_REG_ARM_X10,
+ PERF_REG_ARM_X11,
+ PERF_REG_ARM_X12,
+ PERF_REG_ARM_X13,
+ PERF_REG_ARM_X14,
+ PERF_REG_ARM_X15,
+ PERF_REG_ARM_X16,
+ PERF_REG_ARM_X17,
+ PERF_REG_ARM_X18,
+ PERF_REG_ARM_X19,
+ PERF_REG_ARM_X20,
+ PERF_REG_ARM_X21,
+ PERF_REG_ARM_X22,
+ PERF_REG_ARM_X23,
+ PERF_REG_ARM_X24,
+ PERF_REG_ARM_X25,
+ PERF_REG_ARM_X26,
+ PERF_REG_ARM_X27,
+ PERF_REG_ARM_X28,
+ PERF_REG_ARM_FP,
+ PERF_REG_ARM_LR,
+ PERF_REG_ARM_SP,
+ PERF_REG_ARM_PC,
+ PERF_REG_ARM_MAX,
+};
+#endif /* _ASM_ARM_PERF_REGS_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 5ba2fd4..dffdd93 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -15,6 +15,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
+arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/arm64/kernel/perf_regs.c b/arch/arm64/kernel/perf_regs.c
new file mode 100644
index 0000000..d5c8fd7
--- /dev/null
+++ b/arch/arm64/kernel/perf_regs.c
@@ -0,0 +1,46 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+ if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM_MAX))
+ return 0;
+
+ /*
+ * Compat (i.e. 32 bit) mode:
+ * - PC has been set in the pt_regs struct in kernel_entry,
+ * - Handle FP, SP and LR here.
+ */
+ if (compat_user_mode(regs)) {
+ if ((u32)idx == PERF_REG_ARM_FP)
+ return regs->compat_fp;
+ if ((u32)idx == PERF_REG_ARM_SP)
+ return regs->compat_sp;
+ if ((u32)idx == PERF_REG_ARM_LR)
+ return regs->compat_lr;
+ }
+
+ return regs->regs[idx];
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_ARM_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+ if (!mask || mask & REG_RESERVED)
+ return -EINVAL;
+
+ return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+ if (test_tsk_thread_flag(task, TIF_32BIT))
+ return PERF_SAMPLE_REGS_ABI_32;
+ else
+ return PERF_SAMPLE_REGS_ABI_64;
+}
--
1.7.11.7
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/3] ARM64: perf: wire up perf_regs and unwind support
[not found] <1387212562-8128-1-git-send-email-y>
2013-12-16 16:49 ` [PATCH 1/3] ARM64: perf: add support for perf registers API jean.pihet
@ 2013-12-16 16:49 ` jean.pihet
2013-12-17 11:44 ` Will Deacon
2013-12-16 16:49 ` [PATCH 3/3] ARM64: perf: add support for frame pointer unwinding in compat mode jean.pihet
2 siblings, 1 reply; 12+ messages in thread
From: jean.pihet @ 2013-12-16 16:49 UTC (permalink / raw)
To: linux-kernel, linaro-kernel, Arnaldo, Will Deacon
Cc: patches, Jiri Olsa, Ingo Molnar, Jean Pihet
From: Jean Pihet <jean.pihet@linaro.org>
This patch hooks in the perf_regs and libunwind code for ARM64.
The tools/perf/arch/arm64 is created; it contains the arch specific
code for DWARF unwinding.
Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
Cc: Will Deacon <will.deacon@arm.com>
---
tools/perf/arch/arm64/Makefile | 7 +++
tools/perf/arch/arm64/include/perf_regs.h | 88 +++++++++++++++++++++++++++++++
tools/perf/arch/arm64/util/dwarf-regs.c | 81 ++++++++++++++++++++++++++++
tools/perf/arch/arm64/util/unwind.c | 82 ++++++++++++++++++++++++++++
tools/perf/config/Makefile | 8 ++-
5 files changed, 265 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/arch/arm64/Makefile
create mode 100644 tools/perf/arch/arm64/include/perf_regs.h
create mode 100644 tools/perf/arch/arm64/util/dwarf-regs.c
create mode 100644 tools/perf/arch/arm64/util/unwind.c
diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile
new file mode 100644
index 0000000..fe9b61e
--- /dev/null
+++ b/tools/perf/arch/arm64/Makefile
@@ -0,0 +1,7 @@
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+endif
+ifndef NO_LIBUNWIND
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+endif
diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h
new file mode 100644
index 0000000..a8a9683
--- /dev/null
+++ b/tools/perf/arch/arm64/include/perf_regs.h
@@ -0,0 +1,88 @@
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include "../../util/types.h"
+#include <asm/perf_regs.h>
+
+#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM_MAX) - 1)
+#define PERF_REG_IP PERF_REG_ARM_PC
+#define PERF_REG_SP PERF_REG_ARM_SP
+
+static inline const char *perf_reg_name(int id)
+{
+ switch (id) {
+ case PERF_REG_ARM_X0:
+ return "x0";
+ case PERF_REG_ARM_X1:
+ return "x1";
+ case PERF_REG_ARM_X2:
+ return "x2";
+ case PERF_REG_ARM_X3:
+ return "x3";
+ case PERF_REG_ARM_X4:
+ return "x4";
+ case PERF_REG_ARM_X5:
+ return "x5";
+ case PERF_REG_ARM_X6:
+ return "x6";
+ case PERF_REG_ARM_X7:
+ return "x7";
+ case PERF_REG_ARM_X8:
+ return "x8";
+ case PERF_REG_ARM_X9:
+ return "x9";
+ case PERF_REG_ARM_X10:
+ return "x10";
+ case PERF_REG_ARM_X11:
+ return "x11";
+ case PERF_REG_ARM_X12:
+ return "x12";
+ case PERF_REG_ARM_X13:
+ return "x13";
+ case PERF_REG_ARM_X14:
+ return "x14";
+ case PERF_REG_ARM_X15:
+ return "x15";
+ case PERF_REG_ARM_X16:
+ return "x16";
+ case PERF_REG_ARM_X17:
+ return "x17";
+ case PERF_REG_ARM_X18:
+ return "x18";
+ case PERF_REG_ARM_X19:
+ return "x19";
+ case PERF_REG_ARM_X20:
+ return "x20";
+ case PERF_REG_ARM_X21:
+ return "x21";
+ case PERF_REG_ARM_X22:
+ return "x22";
+ case PERF_REG_ARM_X23:
+ return "x23";
+ case PERF_REG_ARM_X24:
+ return "x24";
+ case PERF_REG_ARM_X25:
+ return "x25";
+ case PERF_REG_ARM_X26:
+ return "x26";
+ case PERF_REG_ARM_X27:
+ return "x27";
+ case PERF_REG_ARM_X28:
+ return "x28";
+ case PERF_REG_ARM_FP:
+ return "fp";
+ case PERF_REG_ARM_SP:
+ return "sp";
+ case PERF_REG_ARM_LR:
+ return "lr";
+ case PERF_REG_ARM_PC:
+ return "pc";
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c
new file mode 100644
index 0000000..23d319e
--- /dev/null
+++ b/tools/perf/arch/arm64/util/dwarf-regs.c
@@ -0,0 +1,81 @@
+/*
+ * Mapping of DWARF debug register numbers into register names.
+ *
+ * Copyright (C) 2010 Will Deacon, ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stddef.h>
+#include <dwarf-regs.h>
+
+struct pt_regs_dwarfnum {
+ const char *name;
+ unsigned int dwarfnum;
+};
+
+#define STR(s) #s
+#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
+#define GPR_DWARFNUM_NAME(num) \
+ {.name = STR(%r##num), .dwarfnum = num}
+#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
+
+/*
+ * Reference:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf
+ */
+static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
+ GPR_DWARFNUM_NAME(0),
+ GPR_DWARFNUM_NAME(1),
+ GPR_DWARFNUM_NAME(2),
+ GPR_DWARFNUM_NAME(3),
+ GPR_DWARFNUM_NAME(4),
+ GPR_DWARFNUM_NAME(5),
+ GPR_DWARFNUM_NAME(6),
+ GPR_DWARFNUM_NAME(7),
+ GPR_DWARFNUM_NAME(8),
+ GPR_DWARFNUM_NAME(9),
+ GPR_DWARFNUM_NAME(10),
+ GPR_DWARFNUM_NAME(11),
+ GPR_DWARFNUM_NAME(12),
+ GPR_DWARFNUM_NAME(13),
+ GPR_DWARFNUM_NAME(14),
+ GPR_DWARFNUM_NAME(15),
+ GPR_DWARFNUM_NAME(16),
+ GPR_DWARFNUM_NAME(17),
+ GPR_DWARFNUM_NAME(18),
+ GPR_DWARFNUM_NAME(19),
+ GPR_DWARFNUM_NAME(20),
+ GPR_DWARFNUM_NAME(21),
+ GPR_DWARFNUM_NAME(22),
+ GPR_DWARFNUM_NAME(23),
+ GPR_DWARFNUM_NAME(24),
+ GPR_DWARFNUM_NAME(25),
+ GPR_DWARFNUM_NAME(26),
+ GPR_DWARFNUM_NAME(27),
+ GPR_DWARFNUM_NAME(28),
+ REG_DWARFNUM_NAME("%fp", 29),
+ REG_DWARFNUM_NAME("%lr", 30),
+ REG_DWARFNUM_NAME("%sp", 31),
+ REG_DWARFNUM_NAME("%pc", 32),
+ REG_DWARFNUM_END,
+};
+
+/**
+ * get_arch_regstr() - lookup register name from it's DWARF register number
+ * @n: the DWARF register number
+ *
+ * get_arch_regstr() returns the name of the register in struct
+ * regdwarfnum_table from it's DWARF register number. If the register is not
+ * found in the table, this returns NULL;
+ */
+const char *get_arch_regstr(unsigned int n)
+{
+ const struct pt_regs_dwarfnum *roff;
+ for (roff = regdwarfnum_table; roff->name != NULL; roff++)
+ if (roff->dwarfnum == n)
+ return roff->name;
+ return NULL;
+}
diff --git a/tools/perf/arch/arm64/util/unwind.c b/tools/perf/arch/arm64/util/unwind.c
new file mode 100644
index 0000000..490bd5b
--- /dev/null
+++ b/tools/perf/arch/arm64/util/unwind.c
@@ -0,0 +1,82 @@
+
+#include <errno.h>
+#include <libunwind.h>
+#include "perf_regs.h"
+#include "../../util/unwind.h"
+
+int unwind__arch_reg_id(int regnum)
+{
+ switch (regnum) {
+ case UNW_AARCH64_X0:
+ return PERF_REG_ARM_X0;
+ case UNW_AARCH64_X1:
+ return PERF_REG_ARM_X1;
+ case UNW_AARCH64_X2:
+ return PERF_REG_ARM_X2;
+ case UNW_AARCH64_X3:
+ return PERF_REG_ARM_X3;
+ case UNW_AARCH64_X4:
+ return PERF_REG_ARM_X4;
+ case UNW_AARCH64_X5:
+ return PERF_REG_ARM_X5;
+ case UNW_AARCH64_X6:
+ return PERF_REG_ARM_X6;
+ case UNW_AARCH64_X7:
+ return PERF_REG_ARM_X7;
+ case UNW_AARCH64_X8:
+ return PERF_REG_ARM_X8;
+ case UNW_AARCH64_X9:
+ return PERF_REG_ARM_X9;
+ case UNW_AARCH64_X10:
+ return PERF_REG_ARM_X10;
+ case UNW_AARCH64_X11:
+ return PERF_REG_ARM_X11;
+ case UNW_AARCH64_X12:
+ return PERF_REG_ARM_X12;
+ case UNW_AARCH64_X13:
+ return PERF_REG_ARM_X13;
+ case UNW_AARCH64_X14:
+ return PERF_REG_ARM_X14;
+ case UNW_AARCH64_X15:
+ return PERF_REG_ARM_X15;
+ case UNW_AARCH64_X16:
+ return PERF_REG_ARM_X16;
+ case UNW_AARCH64_X17:
+ return PERF_REG_ARM_X17;
+ case UNW_AARCH64_X18:
+ return PERF_REG_ARM_X18;
+ case UNW_AARCH64_X19:
+ return PERF_REG_ARM_X19;
+ case UNW_AARCH64_X20:
+ return PERF_REG_ARM_X20;
+ case UNW_AARCH64_X21:
+ return PERF_REG_ARM_X21;
+ case UNW_AARCH64_X22:
+ return PERF_REG_ARM_X22;
+ case UNW_AARCH64_X23:
+ return PERF_REG_ARM_X23;
+ case UNW_AARCH64_X24:
+ return PERF_REG_ARM_X24;
+ case UNW_AARCH64_X25:
+ return PERF_REG_ARM_X25;
+ case UNW_AARCH64_X26:
+ return PERF_REG_ARM_X26;
+ case UNW_AARCH64_X27:
+ return PERF_REG_ARM_X27;
+ case UNW_AARCH64_X28:
+ return PERF_REG_ARM_X28;
+ case UNW_AARCH64_X29:
+ return PERF_REG_ARM_FP;
+ case UNW_AARCH64_X30:
+ return PERF_REG_ARM_LR;
+ case UNW_AARCH64_SP:
+ return PERF_REG_ARM_SP;
+ case UNW_AARCH64_PC:
+ return PERF_REG_ARM_PC;
+ default:
+ pr_err("unwind: invalid reg id %d\n", regnum);
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index f7d11a8..658295c 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -31,11 +31,17 @@ ifeq ($(ARCH),x86_64)
endif
NO_PERF_REGS := 0
endif
+
ifeq ($(ARCH),arm)
NO_PERF_REGS := 0
LIBUNWIND_LIBS = -lunwind -lunwind-arm
endif
+ifeq ($(ARCH),arm64)
+ NO_PERF_REGS := 0
+ LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
+endif
+
ifeq ($(NO_PERF_REGS),0)
CFLAGS += -DHAVE_PERF_REGS_SUPPORT
endif
@@ -329,7 +335,7 @@ ifndef NO_LIBUNWIND
msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
NO_LIBUNWIND := 1
else
- ifeq ($(ARCH),arm)
+ ifeq ($(ARCH),$(filter $(ARCH),arm arm64))
$(call feature_check,libunwind-debug-frame)
ifneq ($(feature-libunwind-debug-frame), 1)
msg := $(warning No debug_frame support found in libunwind);
--
1.7.11.7
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/3] ARM64: perf: add support for frame pointer unwinding in compat mode
[not found] <1387212562-8128-1-git-send-email-y>
2013-12-16 16:49 ` [PATCH 1/3] ARM64: perf: add support for perf registers API jean.pihet
2013-12-16 16:49 ` [PATCH 2/3] ARM64: perf: wire up perf_regs and unwind support jean.pihet
@ 2013-12-16 16:49 ` jean.pihet
2 siblings, 0 replies; 12+ messages in thread
From: jean.pihet @ 2013-12-16 16:49 UTC (permalink / raw)
To: linux-kernel, linaro-kernel, Arnaldo, Will Deacon
Cc: patches, Jiri Olsa, Ingo Molnar, Jean Pihet
From: Jean Pihet <jean.pihet@linaro.org>
When profiling a 32-bit application, user space callchain unwinding
using the frame pointer is performed in compat mode. The code is taken
over from the AARCH32 code and adapted to work on AARCH64.
Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
---
arch/arm64/kernel/perf_event.c | 75 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 67 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 0e63c98..ac055be 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -1300,8 +1300,8 @@ early_initcall(init_hw_perf_events);
* Callchain handling code.
*/
struct frame_tail {
- struct frame_tail __user *fp;
- unsigned long lr;
+ struct frame_tail __user *fp;
+ unsigned long lr;
} __attribute__((packed));
/*
@@ -1338,22 +1338,80 @@ user_backtrace(struct frame_tail __user *tail,
return buftail.fp;
}
+/*
+ * The registers we're interested in are at the end of the variable
+ * length saved register structure. The fp points at the end of this
+ * structure so the address of this struct is:
+ * (struct compat_frame_tail *)(xxx->fp)-1
+ *
+ * This code has been adapted from the ARM OProfile support.
+ */
+struct compat_frame_tail {
+ compat_uptr_t fp; // Is a (struct compat_frame_tail *) in compat mode
+ u32 sp;
+ u32 lr;
+} __attribute__((packed));
+
+static struct compat_frame_tail __user *
+compat_user_backtrace(struct compat_frame_tail __user *tail,
+ struct perf_callchain_entry *entry)
+{
+ struct compat_frame_tail buftail;
+ unsigned long err;
+
+ /* Also check accessibility of one struct frame_tail beyond */
+ if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
+ return NULL;
+
+ pagefault_disable();
+ err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
+ pagefault_enable();
+
+ if (err)
+ return NULL;
+
+ perf_callchain_store(entry, buftail.lr);
+
+ /*
+ * Frame pointers should strictly progress back up the stack
+ * (towards higher addresses).
+ */
+ if (tail + 1 >= (struct compat_frame_tail __user *)
+ compat_ptr(buftail.fp))
+ return NULL;
+
+ return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
+}
+
void perf_callchain_user(struct perf_callchain_entry *entry,
struct pt_regs *regs)
{
- struct frame_tail __user *tail;
-
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
/* We don't support guest os callchain now */
return;
}
perf_callchain_store(entry, regs->pc);
- tail = (struct frame_tail __user *)regs->regs[29];
- while (entry->nr < PERF_MAX_STACK_DEPTH &&
- tail && !((unsigned long)tail & 0xf))
- tail = user_backtrace(tail, entry);
+ if (!compat_user_mode(regs)) {
+ /* AARCH64 mode */
+ struct frame_tail __user *tail;
+
+ tail = (struct frame_tail __user *)regs->regs[29];
+
+ while (entry->nr < PERF_MAX_STACK_DEPTH &&
+ tail && !((unsigned long)tail & 0xf))
+ tail = user_backtrace(tail, entry);
+ } else {
+ /* AARCH32 compat mode */
+ struct compat_frame_tail __user *tail;
+
+ tail = (struct compat_frame_tail __user *)regs->compat_fp - 1;
+
+ while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
+ tail && !((unsigned long)tail & 0x3))
+ tail = compat_user_backtrace(tail, entry);
+ }
}
/*
@@ -1381,6 +1439,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
frame.fp = regs->regs[29];
frame.sp = regs->sp;
frame.pc = regs->pc;
+
walk_stackframe(&frame, callchain_trace, entry);
}
--
1.7.11.7
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] ARM64: perf: add support for perf registers API
2013-12-16 16:49 ` [PATCH 1/3] ARM64: perf: add support for perf registers API jean.pihet
@ 2013-12-17 11:11 ` Will Deacon
0 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2013-12-17 11:11 UTC (permalink / raw)
To: jean.pihet@linaro.org
Cc: linux-kernel@vger.kernel.org, linaro-kernel@lists.linaro.org,
Arnaldo, patches@linaro.org, Jiri Olsa, Ingo Molnar
Hi Jean,
On Mon, Dec 16, 2013 at 04:49:20PM +0000, jean.pihet@linaro.org wrote:
> From: Jean Pihet <jean.pihet@linaro.org>
>
> This patch implements the functions required for the perf registers API,
> allowing the perf tool to interface kernel register dumps with libunwind
> in order to provide userspace backtracing.
> Compat mode is also supported.
>
> Only the general purpose user space registers are exported, i.e.:
> PERF_REG_ARM_X0,
> ...
> PERF_REG_ARM_X28,
> PERF_REG_ARM_FP,
> PERF_REG_ARM_LR,
> PERF_REG_ARM_SP,
> PERF_REG_ARM_PC
> and not the PERF_REG_ARM_V* registers.
>
> Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
> Cc: Will Deacon <will.deacon@arm.com>
> ---
> arch/arm64/Kconfig | 2 ++
> arch/arm64/include/asm/ptrace.h | 1 +
> arch/arm64/include/uapi/asm/Kbuild | 1 +
> arch/arm64/include/uapi/asm/perf_regs.h | 40 ++++++++++++++++++++++++++++
> arch/arm64/kernel/Makefile | 1 +
> arch/arm64/kernel/perf_regs.c | 46 +++++++++++++++++++++++++++++++++
> 6 files changed, 91 insertions(+)
> create mode 100644 arch/arm64/include/uapi/asm/perf_regs.h
> create mode 100644 arch/arm64/kernel/perf_regs.c
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 88c8b6c1..f8609dc 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -28,6 +28,8 @@ config ARM64
> select HAVE_HW_BREAKPOINT if PERF_EVENTS
> select HAVE_MEMBLOCK
> select HAVE_PERF_EVENTS
> + select HAVE_PERF_REGS
> + select HAVE_PERF_USER_STACK_DUMP
> select IRQ_DOMAIN
> select MODULES_USE_ELF_RELA
> select NO_BOOTMEM
> diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
> index 0e7fa49..fbb0020 100644
> --- a/arch/arm64/include/asm/ptrace.h
> +++ b/arch/arm64/include/asm/ptrace.h
> @@ -68,6 +68,7 @@
>
> /* Architecturally defined mapping between AArch32 and AArch64 registers */
> #define compat_usr(x) regs[(x)]
> +#define compat_fp regs[11]
> #define compat_sp regs[13]
> #define compat_lr regs[14]
> #define compat_sp_hyp regs[15]
> diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
> index e4b78bd..942376d 100644
> --- a/arch/arm64/include/uapi/asm/Kbuild
> +++ b/arch/arm64/include/uapi/asm/Kbuild
> @@ -9,6 +9,7 @@ header-y += byteorder.h
> header-y += fcntl.h
> header-y += hwcap.h
> header-y += kvm_para.h
> +header-y += perf_regs.h
> header-y += param.h
> header-y += ptrace.h
> header-y += setup.h
> diff --git a/arch/arm64/include/uapi/asm/perf_regs.h b/arch/arm64/include/uapi/asm/perf_regs.h
> new file mode 100644
> index 0000000..06bf360
> --- /dev/null
> +++ b/arch/arm64/include/uapi/asm/perf_regs.h
> @@ -0,0 +1,40 @@
> +#ifndef _ASM_ARM_PERF_REGS_H
> +#define _ASM_ARM_PERF_REGS_H
> +
> +enum perf_event_arm_regs {
> + PERF_REG_ARM_X0,
> + PERF_REG_ARM_X1,
> + PERF_REG_ARM_X2,
> + PERF_REG_ARM_X3,
> + PERF_REG_ARM_X4,
> + PERF_REG_ARM_X5,
> + PERF_REG_ARM_X6,
> + PERF_REG_ARM_X7,
> + PERF_REG_ARM_X8,
> + PERF_REG_ARM_X9,
> + PERF_REG_ARM_X10,
> + PERF_REG_ARM_X11,
> + PERF_REG_ARM_X12,
> + PERF_REG_ARM_X13,
> + PERF_REG_ARM_X14,
> + PERF_REG_ARM_X15,
> + PERF_REG_ARM_X16,
> + PERF_REG_ARM_X17,
> + PERF_REG_ARM_X18,
> + PERF_REG_ARM_X19,
> + PERF_REG_ARM_X20,
> + PERF_REG_ARM_X21,
> + PERF_REG_ARM_X22,
> + PERF_REG_ARM_X23,
> + PERF_REG_ARM_X24,
> + PERF_REG_ARM_X25,
> + PERF_REG_ARM_X26,
> + PERF_REG_ARM_X27,
> + PERF_REG_ARM_X28,
> + PERF_REG_ARM_FP,
> + PERF_REG_ARM_LR,
> + PERF_REG_ARM_SP,
> + PERF_REG_ARM_PC,
> + PERF_REG_ARM_MAX,
I think these should be PERF_REG_ARM64_* to avoid name conflicts with
arch/arm/.
> +};
> +#endif /* _ASM_ARM_PERF_REGS_H */
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index 5ba2fd4..dffdd93 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -15,6 +15,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
> sys_compat.o
> arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
> arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
> +arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
> arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
> arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
> arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
> diff --git a/arch/arm64/kernel/perf_regs.c b/arch/arm64/kernel/perf_regs.c
> new file mode 100644
> index 0000000..d5c8fd7
> --- /dev/null
> +++ b/arch/arm64/kernel/perf_regs.c
> @@ -0,0 +1,46 @@
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/perf_event.h>
> +#include <linux/bug.h>
> +#include <asm/perf_regs.h>
> +#include <asm/ptrace.h>
> +
> +u64 perf_reg_value(struct pt_regs *regs, int idx)
> +{
> + if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM_MAX))
> + return 0;
> +
> + /*
> + * Compat (i.e. 32 bit) mode:
> + * - PC has been set in the pt_regs struct in kernel_entry,
> + * - Handle FP, SP and LR here.
> + */
> + if (compat_user_mode(regs)) {
> + if ((u32)idx == PERF_REG_ARM_FP)
This doesn't look right to me... why would a compat task be asking for
PERF_REG_ARM_FP, where that is greater than the arch/arm/ definition of
PERF_REG_ARM_MAX?
> + return regs->compat_fp;
Also, why are you treating FP specially? The hardware doesn't do anything
special with it.
> + if ((u32)idx == PERF_REG_ARM_SP)
> + return regs->compat_sp;
> + if ((u32)idx == PERF_REG_ARM_LR)
> + return regs->compat_lr;
> + }
> +
> + return regs->regs[idx];
> +}
> +
> +#define REG_RESERVED (~((1ULL << PERF_REG_ARM_MAX) - 1))
> +
> +int perf_reg_validate(u64 mask)
> +{
> + if (!mask || mask & REG_RESERVED)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +u64 perf_reg_abi(struct task_struct *task)
> +{
> + if (test_tsk_thread_flag(task, TIF_32BIT))
is_compat_thread(task_thread_info(task)) ?
Will
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/3] ARM64: perf: wire up perf_regs and unwind support
2013-12-16 16:49 ` [PATCH 2/3] ARM64: perf: wire up perf_regs and unwind support jean.pihet
@ 2013-12-17 11:44 ` Will Deacon
0 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2013-12-17 11:44 UTC (permalink / raw)
To: jean.pihet@linaro.org
Cc: linux-kernel@vger.kernel.org, linaro-kernel@lists.linaro.org,
Arnaldo, patches@linaro.org, Jiri Olsa, Ingo Molnar
On Mon, Dec 16, 2013 at 04:49:21PM +0000, jean.pihet@linaro.org wrote:
> From: Jean Pihet <jean.pihet@linaro.org>
>
> This patch hooks in the perf_regs and libunwind code for ARM64.
> The tools/perf/arch/arm64 is created; it contains the arch specific
> code for DWARF unwinding.
>
> Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
> Cc: Will Deacon <will.deacon@arm.com>
> ---
> tools/perf/arch/arm64/Makefile | 7 +++
> tools/perf/arch/arm64/include/perf_regs.h | 88 +++++++++++++++++++++++++++++++
> tools/perf/arch/arm64/util/dwarf-regs.c | 81 ++++++++++++++++++++++++++++
> tools/perf/arch/arm64/util/unwind.c | 82 ++++++++++++++++++++++++++++
> tools/perf/config/Makefile | 8 ++-
> 5 files changed, 265 insertions(+), 1 deletion(-)
> create mode 100644 tools/perf/arch/arm64/Makefile
> create mode 100644 tools/perf/arch/arm64/include/perf_regs.h
> create mode 100644 tools/perf/arch/arm64/util/dwarf-regs.c
> create mode 100644 tools/perf/arch/arm64/util/unwind.c
[...]
> diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h
> new file mode 100644
> index 0000000..a8a9683
> --- /dev/null
> +++ b/tools/perf/arch/arm64/include/perf_regs.h
> @@ -0,0 +1,88 @@
> +#ifndef ARCH_PERF_REGS_H
> +#define ARCH_PERF_REGS_H
> +
> +#include <stdlib.h>
> +#include "../../util/types.h"
> +#include <asm/perf_regs.h>
> +
> +#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM_MAX) - 1)
> +#define PERF_REG_IP PERF_REG_ARM_PC
> +#define PERF_REG_SP PERF_REG_ARM_SP
> +
> +static inline const char *perf_reg_name(int id)
> +{
> + switch (id) {
> + case PERF_REG_ARM_X0:
> + return "x0";
> + case PERF_REG_ARM_X1:
> + return "x1";
[...]
> + case PERF_REG_ARM_X28:
> + return "x28";
> + case PERF_REG_ARM_FP:
> + return "fp";
Again, I'd just treat this as x29. There's nothing special about the frame
pointer as far as the hardware/architecture is concerned. GAS won't even
accept it as a register name.
> + case PERF_REG_ARM_SP:
> + return "sp";
> + case PERF_REG_ARM_LR:
> + return "lr";
> + case PERF_REG_ARM_PC:
> + return "pc";
> + default:
> + return NULL;
> + }
> +
> + return NULL;
> +}
> +
> +#endif /* ARCH_PERF_REGS_H */
> diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c
> new file mode 100644
> index 0000000..23d319e
> --- /dev/null
> +++ b/tools/perf/arch/arm64/util/dwarf-regs.c
> @@ -0,0 +1,81 @@
> +/*
> + * Mapping of DWARF debug register numbers into register names.
> + *
> + * Copyright (C) 2010 Will Deacon, ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <stddef.h>
> +#include <dwarf-regs.h>
> +
> +struct pt_regs_dwarfnum {
> + const char *name;
> + unsigned int dwarfnum;
> +};
> +
> +#define STR(s) #s
> +#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
> +#define GPR_DWARFNUM_NAME(num) \
> + {.name = STR(%r##num), .dwarfnum = num}
Surely you want 'x' instead of 'r'?
> +#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
> +
> +/*
> + * Reference:
> + * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf
So, according to that document...
> + */
> +static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
> + GPR_DWARFNUM_NAME(0),
> + GPR_DWARFNUM_NAME(1),
> + GPR_DWARFNUM_NAME(2),
> + GPR_DWARFNUM_NAME(3),
> + GPR_DWARFNUM_NAME(4),
> + GPR_DWARFNUM_NAME(5),
> + GPR_DWARFNUM_NAME(6),
> + GPR_DWARFNUM_NAME(7),
> + GPR_DWARFNUM_NAME(8),
> + GPR_DWARFNUM_NAME(9),
> + GPR_DWARFNUM_NAME(10),
> + GPR_DWARFNUM_NAME(11),
> + GPR_DWARFNUM_NAME(12),
> + GPR_DWARFNUM_NAME(13),
> + GPR_DWARFNUM_NAME(14),
> + GPR_DWARFNUM_NAME(15),
> + GPR_DWARFNUM_NAME(16),
> + GPR_DWARFNUM_NAME(17),
> + GPR_DWARFNUM_NAME(18),
> + GPR_DWARFNUM_NAME(19),
> + GPR_DWARFNUM_NAME(20),
> + GPR_DWARFNUM_NAME(21),
> + GPR_DWARFNUM_NAME(22),
> + GPR_DWARFNUM_NAME(23),
> + GPR_DWARFNUM_NAME(24),
> + GPR_DWARFNUM_NAME(25),
> + GPR_DWARFNUM_NAME(26),
> + GPR_DWARFNUM_NAME(27),
> + GPR_DWARFNUM_NAME(28),
> + REG_DWARFNUM_NAME("%fp", 29),
> + REG_DWARFNUM_NAME("%lr", 30),
> + REG_DWARFNUM_NAME("%sp", 31),
> + REG_DWARFNUM_NAME("%pc", 32),
...register name 32 is `Reserved'. I don't think we should be using it here.
In fact, the PC isn't even described in that spec. Do we need to expose it
here?
Will
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/3] ARM64: perf: add support for perf registers API
2013-12-30 16:25 [PATCH v4 0/3] perf: add AARCH64 arch support Jean Pihet
@ 2013-12-30 16:25 ` Jean Pihet
2014-01-06 18:30 ` Will Deacon
0 siblings, 1 reply; 12+ messages in thread
From: Jean Pihet @ 2013-12-30 16:25 UTC (permalink / raw)
To: linux-kernel, linaro-kernel, Jiri Olsa, Ingo Molnar, Arnaldo,
Will Deacon
Cc: patches, Jean Pihet, Jean Pihet
From: Jean Pihet <jean.pihet@newoldbits.com>
This patch implements the functions required for the perf registers API,
allowing the perf tool to interface kernel register dumps with libunwind
in order to provide userspace backtracing.
Compat mode is also supported.
Only the general purpose user space registers are exported, i.e.:
PERF_REG_ARM_X0,
...
PERF_REG_ARM_X28,
PERF_REG_ARM_FP,
PERF_REG_ARM_LR,
PERF_REG_ARM_SP,
PERF_REG_ARM_PC
and not the PERF_REG_ARM_V* registers.
Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/Kconfig | 2 ++
arch/arm64/include/asm/ptrace.h | 1 +
arch/arm64/include/uapi/asm/Kbuild | 1 +
arch/arm64/include/uapi/asm/perf_regs.h | 40 ++++++++++++++++++++++++++++++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/perf_regs.c | 44 +++++++++++++++++++++++++++++++++
6 files changed, 89 insertions(+)
create mode 100644 arch/arm64/include/uapi/asm/perf_regs.h
create mode 100644 arch/arm64/kernel/perf_regs.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 88c8b6c1..f8609dc 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -28,6 +28,8 @@ config ARM64
select HAVE_HW_BREAKPOINT if PERF_EVENTS
select HAVE_MEMBLOCK
select HAVE_PERF_EVENTS
+ select HAVE_PERF_REGS
+ select HAVE_PERF_USER_STACK_DUMP
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select NO_BOOTMEM
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 0e7fa49..fbb0020 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -68,6 +68,7 @@
/* Architecturally defined mapping between AArch32 and AArch64 registers */
#define compat_usr(x) regs[(x)]
+#define compat_fp regs[11]
#define compat_sp regs[13]
#define compat_lr regs[14]
#define compat_sp_hyp regs[15]
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index e4b78bd..942376d 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -9,6 +9,7 @@ header-y += byteorder.h
header-y += fcntl.h
header-y += hwcap.h
header-y += kvm_para.h
+header-y += perf_regs.h
header-y += param.h
header-y += ptrace.h
header-y += setup.h
diff --git a/arch/arm64/include/uapi/asm/perf_regs.h b/arch/arm64/include/uapi/asm/perf_regs.h
new file mode 100644
index 0000000..172b831
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/perf_regs.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_ARM64_PERF_REGS_H
+#define _ASM_ARM64_PERF_REGS_H
+
+enum perf_event_arm_regs {
+ PERF_REG_ARM64_X0,
+ PERF_REG_ARM64_X1,
+ PERF_REG_ARM64_X2,
+ PERF_REG_ARM64_X3,
+ PERF_REG_ARM64_X4,
+ PERF_REG_ARM64_X5,
+ PERF_REG_ARM64_X6,
+ PERF_REG_ARM64_X7,
+ PERF_REG_ARM64_X8,
+ PERF_REG_ARM64_X9,
+ PERF_REG_ARM64_X10,
+ PERF_REG_ARM64_X11,
+ PERF_REG_ARM64_X12,
+ PERF_REG_ARM64_X13,
+ PERF_REG_ARM64_X14,
+ PERF_REG_ARM64_X15,
+ PERF_REG_ARM64_X16,
+ PERF_REG_ARM64_X17,
+ PERF_REG_ARM64_X18,
+ PERF_REG_ARM64_X19,
+ PERF_REG_ARM64_X20,
+ PERF_REG_ARM64_X21,
+ PERF_REG_ARM64_X22,
+ PERF_REG_ARM64_X23,
+ PERF_REG_ARM64_X24,
+ PERF_REG_ARM64_X25,
+ PERF_REG_ARM64_X26,
+ PERF_REG_ARM64_X27,
+ PERF_REG_ARM64_X28,
+ PERF_REG_ARM64_X29,
+ PERF_REG_ARM64_LR,
+ PERF_REG_ARM64_SP,
+ PERF_REG_ARM64_PC,
+ PERF_REG_ARM64_MAX,
+};
+#endif /* _ASM_ARM64_PERF_REGS_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 5ba2fd4..dffdd93 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -15,6 +15,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
+arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/arm64/kernel/perf_regs.c b/arch/arm64/kernel/perf_regs.c
new file mode 100644
index 0000000..f2d6f0a
--- /dev/null
+++ b/arch/arm64/kernel/perf_regs.c
@@ -0,0 +1,44 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+ if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
+ return 0;
+
+ /*
+ * Compat (i.e. 32 bit) mode:
+ * - PC has been set in the pt_regs struct in kernel_entry,
+ * - Handle SP and LR here.
+ */
+ if (compat_user_mode(regs)) {
+ if ((u32)idx == PERF_REG_ARM64_SP)
+ return regs->compat_sp;
+ if ((u32)idx == PERF_REG_ARM64_LR)
+ return regs->compat_lr;
+ }
+
+ return regs->regs[idx];
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_ARM64_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+ if (!mask || mask & REG_RESERVED)
+ return -EINVAL;
+
+ return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+ if (is_compat_thread(task_thread_info(task)))
+ return PERF_SAMPLE_REGS_ABI_32;
+ else
+ return PERF_SAMPLE_REGS_ABI_64;
+}
--
1.7.11.7
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] ARM64: perf: add support for perf registers API
2013-12-30 16:25 ` [PATCH 1/3] ARM64: perf: add support for perf registers API Jean Pihet
@ 2014-01-06 18:30 ` Will Deacon
2014-01-07 8:49 ` Jean Pihet
2014-01-15 10:30 ` Jean Pihet
0 siblings, 2 replies; 12+ messages in thread
From: Will Deacon @ 2014-01-06 18:30 UTC (permalink / raw)
To: Jean Pihet
Cc: linux-kernel@vger.kernel.org, linaro-kernel@lists.linaro.org,
Jiri Olsa, Ingo Molnar, Arnaldo, patches@linaro.org, Jean Pihet
Hi Jean,
Thanks for the updated patches. One minor comment on this one.
On Mon, Dec 30, 2013 at 04:25:30PM +0000, Jean Pihet wrote:
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> This patch implements the functions required for the perf registers API,
> allowing the perf tool to interface kernel register dumps with libunwind
> in order to provide userspace backtracing.
> Compat mode is also supported.
[...]
> +u64 perf_reg_value(struct pt_regs *regs, int idx)
> +{
> + if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
> + return 0;
While this is probably fine, I'd feel more comfortable if you had separate
limit checks for native and compat...
> + /*
> + * Compat (i.e. 32 bit) mode:
> + * - PC has been set in the pt_regs struct in kernel_entry,
> + * - Handle SP and LR here.
> + */
> + if (compat_user_mode(regs)) {
i.e. have a WARN_ON_ONCE here for the compat structure size.
> + if ((u32)idx == PERF_REG_ARM64_SP)
> + return regs->compat_sp;
> + if ((u32)idx == PERF_REG_ARM64_LR)
> + return regs->compat_lr;
> + }
then stick an else here with the original check.
Make sense?
Will
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] ARM64: perf: add support for perf registers API
2014-01-06 18:30 ` Will Deacon
@ 2014-01-07 8:49 ` Jean Pihet
2014-01-15 10:30 ` Jean Pihet
1 sibling, 0 replies; 12+ messages in thread
From: Jean Pihet @ 2014-01-07 8:49 UTC (permalink / raw)
To: Will Deacon
Cc: linux-kernel@vger.kernel.org, linaro-kernel@lists.linaro.org,
Jiri Olsa, Ingo Molnar, Arnaldo, patches@linaro.org, Jean Pihet
Hi Will,
On 6 January 2014 19:30, Will Deacon <will.deacon@arm.com> wrote:
> Hi Jean,
>
> Thanks for the updated patches. One minor comment on this one.
Thanks for reviewing!
> On Mon, Dec 30, 2013 at 04:25:30PM +0000, Jean Pihet wrote:
>> From: Jean Pihet <jean.pihet@newoldbits.com>
>>
>> This patch implements the functions required for the perf registers API,
>> allowing the perf tool to interface kernel register dumps with libunwind
>> in order to provide userspace backtracing.
>> Compat mode is also supported.
>
> [...]
>
>> +u64 perf_reg_value(struct pt_regs *regs, int idx)
>> +{
>> + if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
>> + return 0;
>
> While this is probably fine, I'd feel more comfortable if you had separate
> limit checks for native and compat...
>
>> + /*
>> + * Compat (i.e. 32 bit) mode:
>> + * - PC has been set in the pt_regs struct in kernel_entry,
>> + * - Handle SP and LR here.
>> + */
>> + if (compat_user_mode(regs)) {
>
> i.e. have a WARN_ON_ONCE here for the compat structure size.
>
>> + if ((u32)idx == PERF_REG_ARM64_SP)
>> + return regs->compat_sp;
>> + if ((u32)idx == PERF_REG_ARM64_LR)
>> + return regs->compat_lr;
>> + }
>
> then stick an else here with the original check.
>
> Make sense?
Yes
I will resend an updated version asap.
>
> Will
Jean
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] ARM64: perf: add support for perf registers API
2014-01-06 18:30 ` Will Deacon
2014-01-07 8:49 ` Jean Pihet
@ 2014-01-15 10:30 ` Jean Pihet
2014-01-15 11:07 ` Will Deacon
1 sibling, 1 reply; 12+ messages in thread
From: Jean Pihet @ 2014-01-15 10:30 UTC (permalink / raw)
To: Will Deacon
Cc: linux-kernel@vger.kernel.org, linaro-kernel@lists.linaro.org,
Jiri Olsa, Ingo Molnar, Arnaldo, patches@linaro.org, Jean Pihet
Hi Will,
On 6 January 2014 19:30, Will Deacon <will.deacon@arm.com> wrote:
> Hi Jean,
>
> Thanks for the updated patches. One minor comment on this one.
>
> On Mon, Dec 30, 2013 at 04:25:30PM +0000, Jean Pihet wrote:
>> From: Jean Pihet <jean.pihet@newoldbits.com>
>>
>> This patch implements the functions required for the perf registers API,
>> allowing the perf tool to interface kernel register dumps with libunwind
>> in order to provide userspace backtracing.
>> Compat mode is also supported.
>
> [...]
>
>> +u64 perf_reg_value(struct pt_regs *regs, int idx)
>> +{
>> + if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
>> + return 0;
>
> While this is probably fine, I'd feel more comfortable if you had separate
> limit checks for native and compat...
In fact in the native and compat modes the same set of registers are
accessed, based on the native regs that are registered to the perf
event core, cf. the definition of PERF_REGS_MASK in
tools/perf/arch/arm64/include/perf_regs.h.
The regs set could be registered differently based on the binary to
trace, but unfortunately the perf core code does not allow that.
I would leave the code as is, what do you think?
Cheers,
Jean
>
>> + /*
>> + * Compat (i.e. 32 bit) mode:
>> + * - PC has been set in the pt_regs struct in kernel_entry,
>> + * - Handle SP and LR here.
>> + */
>> + if (compat_user_mode(regs)) {
>
> i.e. have a WARN_ON_ONCE here for the compat structure size.
>
>> + if ((u32)idx == PERF_REG_ARM64_SP)
>> + return regs->compat_sp;
>> + if ((u32)idx == PERF_REG_ARM64_LR)
>> + return regs->compat_lr;
>> + }
>
> then stick an else here with the original check.
>
> Make sense?
>
> Will
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] ARM64: perf: add support for perf registers API
2014-01-15 10:30 ` Jean Pihet
@ 2014-01-15 11:07 ` Will Deacon
2014-01-16 14:49 ` Jean Pihet
0 siblings, 1 reply; 12+ messages in thread
From: Will Deacon @ 2014-01-15 11:07 UTC (permalink / raw)
To: Jean Pihet
Cc: linux-kernel@vger.kernel.org, linaro-kernel@lists.linaro.org,
Jiri Olsa, Ingo Molnar, Arnaldo, patches@linaro.org, Jean Pihet
On Wed, Jan 15, 2014 at 10:30:48AM +0000, Jean Pihet wrote:
> Hi Will,
Hi Jean,
> On 6 January 2014 19:30, Will Deacon <will.deacon@arm.com> wrote:
> > On Mon, Dec 30, 2013 at 04:25:30PM +0000, Jean Pihet wrote:
> >> From: Jean Pihet <jean.pihet@newoldbits.com>
> >>
> >> This patch implements the functions required for the perf registers API,
> >> allowing the perf tool to interface kernel register dumps with libunwind
> >> in order to provide userspace backtracing.
> >> Compat mode is also supported.
> >
> > [...]
> >
> >> +u64 perf_reg_value(struct pt_regs *regs, int idx)
> >> +{
> >> + if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
> >> + return 0;
> >
> > While this is probably fine, I'd feel more comfortable if you had separate
> > limit checks for native and compat...
> In fact in the native and compat modes the same set of registers are
> accessed, based on the native regs that are registered to the perf
> event core, cf. the definition of PERF_REGS_MASK in
> tools/perf/arch/arm64/include/perf_regs.h.
>
> The regs set could be registered differently based on the binary to
> trace, but unfortunately the perf core code does not allow that.
>
> I would leave the code as is, what do you think?
Well, what business would a compat task have accessing registers beyond the
compat subset? Since we don't expose the PC, we can simply lower the limit
as the compat registers form a prefix of the native registers, no?
Will
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] ARM64: perf: add support for perf registers API
2014-01-15 11:07 ` Will Deacon
@ 2014-01-16 14:49 ` Jean Pihet
0 siblings, 0 replies; 12+ messages in thread
From: Jean Pihet @ 2014-01-16 14:49 UTC (permalink / raw)
To: Will Deacon
Cc: linux-kernel@vger.kernel.org, linaro-kernel@lists.linaro.org,
Jiri Olsa, Ingo Molnar, Arnaldo, patches@linaro.org, Jean Pihet
Will,
On 15 January 2014 12:07, Will Deacon <will.deacon@arm.com> wrote:
> On Wed, Jan 15, 2014 at 10:30:48AM +0000, Jean Pihet wrote:
>> Hi Will,
>
> Hi Jean,
>
>> On 6 January 2014 19:30, Will Deacon <will.deacon@arm.com> wrote:
>> > On Mon, Dec 30, 2013 at 04:25:30PM +0000, Jean Pihet wrote:
>> >> From: Jean Pihet <jean.pihet@newoldbits.com>
>> >>
>> >> This patch implements the functions required for the perf registers API,
>> >> allowing the perf tool to interface kernel register dumps with libunwind
>> >> in order to provide userspace backtracing.
>> >> Compat mode is also supported.
>> >
>> > [...]
>> >
>> >> +u64 perf_reg_value(struct pt_regs *regs, int idx)
>> >> +{
>> >> + if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
>> >> + return 0;
>> >
>> > While this is probably fine, I'd feel more comfortable if you had separate
>> > limit checks for native and compat...
>> In fact in the native and compat modes the same set of registers are
>> accessed, based on the native regs that are registered to the perf
>> event core, cf. the definition of PERF_REGS_MASK in
>> tools/perf/arch/arm64/include/perf_regs.h.
>>
>> The regs set could be registered differently based on the binary to
>> trace, but unfortunately the perf core code does not allow that.
>>
>> I would leave the code as is, what do you think?
>
> Well, what business would a compat task have accessing registers beyond the
> compat subset? Since we don't expose the PC, we can simply lower the limit
> as the compat registers form a prefix of the native registers, no?
Yes it is a good thing to clamp the range of registers, based on the
compat mode.
Unfortunately the perf core code does not handle the compat mode,
instead it always accesses all _native_ registers.
Here is the proposal (after our discussion on IRC):
- use the current patches on ARM64 so that we have a working solution
that one can test/stress/use on real workloads,
- re-factor the perf core code later to make able to handle multiple
ABIs and corresponding registers sets.
Are you ok with that?
Regards,
Jean
>
> Will
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/3] ARM64: perf: add support for perf registers API
2014-02-03 18:18 [PATCH v6 0/3] perf: AARCH64 arch support Jean Pihet
@ 2014-02-03 18:18 ` Jean Pihet
0 siblings, 0 replies; 12+ messages in thread
From: Jean Pihet @ 2014-02-03 18:18 UTC (permalink / raw)
To: linux-kernel, linaro-kernel, linux-arm-kernel, Will Deacon
Cc: Arnaldo, Ingo Molnar, Jiri Olsa, patches, Jean Pihet
This patch implements the functions required for the perf registers API,
allowing the perf tool to interface kernel register dumps with libunwind
in order to provide userspace backtracing.
Compat mode is also supported.
Only the general purpose user space registers are exported, i.e.:
PERF_REG_ARM_X0,
...
PERF_REG_ARM_X28,
PERF_REG_ARM_FP,
PERF_REG_ARM_LR,
PERF_REG_ARM_SP,
PERF_REG_ARM_PC
and not the PERF_REG_ARM_V* registers.
Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
Acked-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/Kconfig | 2 ++
arch/arm64/include/asm/ptrace.h | 1 +
arch/arm64/include/uapi/asm/Kbuild | 1 +
arch/arm64/include/uapi/asm/perf_regs.h | 40 ++++++++++++++++++++++++++++++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/perf_regs.c | 44 +++++++++++++++++++++++++++++++++
6 files changed, 89 insertions(+)
create mode 100644 arch/arm64/include/uapi/asm/perf_regs.h
create mode 100644 arch/arm64/kernel/perf_regs.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index dd4327f..e9899bb 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -37,6 +37,8 @@ config ARM64
select HAVE_HW_BREAKPOINT if PERF_EVENTS
select HAVE_MEMBLOCK
select HAVE_PERF_EVENTS
+ select HAVE_PERF_REGS
+ select HAVE_PERF_USER_STACK_DUMP
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select NO_BOOTMEM
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 0e7fa49..fbb0020 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -68,6 +68,7 @@
/* Architecturally defined mapping between AArch32 and AArch64 registers */
#define compat_usr(x) regs[(x)]
+#define compat_fp regs[11]
#define compat_sp regs[13]
#define compat_lr regs[14]
#define compat_sp_hyp regs[15]
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index e4b78bd..942376d 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -9,6 +9,7 @@ header-y += byteorder.h
header-y += fcntl.h
header-y += hwcap.h
header-y += kvm_para.h
+header-y += perf_regs.h
header-y += param.h
header-y += ptrace.h
header-y += setup.h
diff --git a/arch/arm64/include/uapi/asm/perf_regs.h b/arch/arm64/include/uapi/asm/perf_regs.h
new file mode 100644
index 0000000..172b831
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/perf_regs.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_ARM64_PERF_REGS_H
+#define _ASM_ARM64_PERF_REGS_H
+
+enum perf_event_arm_regs {
+ PERF_REG_ARM64_X0,
+ PERF_REG_ARM64_X1,
+ PERF_REG_ARM64_X2,
+ PERF_REG_ARM64_X3,
+ PERF_REG_ARM64_X4,
+ PERF_REG_ARM64_X5,
+ PERF_REG_ARM64_X6,
+ PERF_REG_ARM64_X7,
+ PERF_REG_ARM64_X8,
+ PERF_REG_ARM64_X9,
+ PERF_REG_ARM64_X10,
+ PERF_REG_ARM64_X11,
+ PERF_REG_ARM64_X12,
+ PERF_REG_ARM64_X13,
+ PERF_REG_ARM64_X14,
+ PERF_REG_ARM64_X15,
+ PERF_REG_ARM64_X16,
+ PERF_REG_ARM64_X17,
+ PERF_REG_ARM64_X18,
+ PERF_REG_ARM64_X19,
+ PERF_REG_ARM64_X20,
+ PERF_REG_ARM64_X21,
+ PERF_REG_ARM64_X22,
+ PERF_REG_ARM64_X23,
+ PERF_REG_ARM64_X24,
+ PERF_REG_ARM64_X25,
+ PERF_REG_ARM64_X26,
+ PERF_REG_ARM64_X27,
+ PERF_REG_ARM64_X28,
+ PERF_REG_ARM64_X29,
+ PERF_REG_ARM64_LR,
+ PERF_REG_ARM64_SP,
+ PERF_REG_ARM64_PC,
+ PERF_REG_ARM64_MAX,
+};
+#endif /* _ASM_ARM64_PERF_REGS_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 2d4554b..9a5d592 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -15,6 +15,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
+arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/arm64/kernel/perf_regs.c b/arch/arm64/kernel/perf_regs.c
new file mode 100644
index 0000000..f2d6f0a
--- /dev/null
+++ b/arch/arm64/kernel/perf_regs.c
@@ -0,0 +1,44 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+ if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
+ return 0;
+
+ /*
+ * Compat (i.e. 32 bit) mode:
+ * - PC has been set in the pt_regs struct in kernel_entry,
+ * - Handle SP and LR here.
+ */
+ if (compat_user_mode(regs)) {
+ if ((u32)idx == PERF_REG_ARM64_SP)
+ return regs->compat_sp;
+ if ((u32)idx == PERF_REG_ARM64_LR)
+ return regs->compat_lr;
+ }
+
+ return regs->regs[idx];
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_ARM64_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+ if (!mask || mask & REG_RESERVED)
+ return -EINVAL;
+
+ return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+ if (is_compat_thread(task_thread_info(task)))
+ return PERF_SAMPLE_REGS_ABI_32;
+ else
+ return PERF_SAMPLE_REGS_ABI_64;
+}
--
1.7.11.7
^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2014-02-03 18:19 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1387212562-8128-1-git-send-email-y>
2013-12-16 16:49 ` [PATCH 1/3] ARM64: perf: add support for perf registers API jean.pihet
2013-12-17 11:11 ` Will Deacon
2013-12-16 16:49 ` [PATCH 2/3] ARM64: perf: wire up perf_regs and unwind support jean.pihet
2013-12-17 11:44 ` Will Deacon
2013-12-16 16:49 ` [PATCH 3/3] ARM64: perf: add support for frame pointer unwinding in compat mode jean.pihet
2013-12-30 16:25 [PATCH v4 0/3] perf: add AARCH64 arch support Jean Pihet
2013-12-30 16:25 ` [PATCH 1/3] ARM64: perf: add support for perf registers API Jean Pihet
2014-01-06 18:30 ` Will Deacon
2014-01-07 8:49 ` Jean Pihet
2014-01-15 10:30 ` Jean Pihet
2014-01-15 11:07 ` Will Deacon
2014-01-16 14:49 ` Jean Pihet
-- strict thread matches above, loose matches on Subject: below --
2014-02-03 18:18 [PATCH v6 0/3] perf: AARCH64 arch support Jean Pihet
2014-02-03 18:18 ` [PATCH 1/3] ARM64: perf: add support for perf registers API Jean Pihet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox