parisc: Add HAVE_REGS_AND_STACK_ACCESS_API feature
authorHelge Deller <deller@gmx.de>
Thu, 28 Jun 2018 20:47:11 +0000 (22:47 +0200)
committerHelge Deller <deller@gmx.de>
Mon, 13 Aug 2018 07:30:50 +0000 (09:30 +0200)
Some parts of the HAVE_REGS_AND_STACK_ACCESS_API feature is needed for
the rseq syscall. This patch adds the most important parts, and as long
as we don't support kprobes, we should be fine.

Signed-off-by: Helge Deller <deller@gmx.de>
arch/parisc/Kconfig
arch/parisc/include/asm/ptrace.h
arch/parisc/kernel/ptrace.c

index 1fcdf1565b23b318c16c1d2703b692aaea6a1021..e21751fb24aa72dd4db64b86699094e5dd087f5f 100644 (file)
@@ -45,6 +45,7 @@ config PARISC
        select HAVE_ARCH_HASH
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
+       select HAVE_REGS_AND_STACK_ACCESS_API
        select GENERIC_SCHED_CLOCK
        select HAVE_UNSTABLE_SCHED_CLOCK if SMP
        select GENERIC_CLOCKEVENTS
index 46da07670c2bea266084945fd9ff4f5a42b25c58..2a27b275ab092cc60b3d003250aaaf647aa9c916 100644 (file)
@@ -25,4 +25,15 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
        return regs->gr[20];
 }
 
+static inline void instruction_pointer_set(struct pt_regs *regs,
+                                               unsigned long val)
+{
+        regs->iaoq[0] = val;
+}
+
+/* Query offset/name of register from its name/offset */
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+#define MAX_REG_OFFSET (offsetof(struct pt_regs, ipsw))
+
 #endif
index 7aa1d4d0d4442a50792e2d3f467af106a8febca4..2582df1c529bbcbb00262bba3f4e9534439766df 100644 (file)
@@ -676,3 +676,103 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 #endif
        return &user_parisc_native_view;
 }
+
+
+/* HAVE_REGS_AND_STACK_ACCESS_API feature */
+
+struct pt_regs_offset {
+       const char *name;
+       int offset;
+};
+
+#define REG_OFFSET_NAME(r)    {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REG_OFFSET_INDEX(r,i) {.name = #r#i, .offset = offsetof(struct pt_regs, r[i])}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+static const struct pt_regs_offset regoffset_table[] = {
+       REG_OFFSET_INDEX(gr,0),
+       REG_OFFSET_INDEX(gr,1),
+       REG_OFFSET_INDEX(gr,2),
+       REG_OFFSET_INDEX(gr,3),
+       REG_OFFSET_INDEX(gr,4),
+       REG_OFFSET_INDEX(gr,5),
+       REG_OFFSET_INDEX(gr,6),
+       REG_OFFSET_INDEX(gr,7),
+       REG_OFFSET_INDEX(gr,8),
+       REG_OFFSET_INDEX(gr,9),
+       REG_OFFSET_INDEX(gr,10),
+       REG_OFFSET_INDEX(gr,11),
+       REG_OFFSET_INDEX(gr,12),
+       REG_OFFSET_INDEX(gr,13),
+       REG_OFFSET_INDEX(gr,14),
+       REG_OFFSET_INDEX(gr,15),
+       REG_OFFSET_INDEX(gr,16),
+       REG_OFFSET_INDEX(gr,17),
+       REG_OFFSET_INDEX(gr,18),
+       REG_OFFSET_INDEX(gr,19),
+       REG_OFFSET_INDEX(gr,20),
+       REG_OFFSET_INDEX(gr,21),
+       REG_OFFSET_INDEX(gr,22),
+       REG_OFFSET_INDEX(gr,23),
+       REG_OFFSET_INDEX(gr,24),
+       REG_OFFSET_INDEX(gr,25),
+       REG_OFFSET_INDEX(gr,26),
+       REG_OFFSET_INDEX(gr,27),
+       REG_OFFSET_INDEX(gr,28),
+       REG_OFFSET_INDEX(gr,29),
+       REG_OFFSET_INDEX(gr,30),
+       REG_OFFSET_INDEX(gr,31),
+       REG_OFFSET_INDEX(sr,0),
+       REG_OFFSET_INDEX(sr,1),
+       REG_OFFSET_INDEX(sr,2),
+       REG_OFFSET_INDEX(sr,3),
+       REG_OFFSET_INDEX(sr,4),
+       REG_OFFSET_INDEX(sr,5),
+       REG_OFFSET_INDEX(sr,6),
+       REG_OFFSET_INDEX(sr,7),
+       REG_OFFSET_INDEX(iasq,0),
+       REG_OFFSET_INDEX(iasq,1),
+       REG_OFFSET_INDEX(iaoq,0),
+       REG_OFFSET_INDEX(iaoq,1),
+       REG_OFFSET_NAME(cr27),
+       REG_OFFSET_NAME(ksp),
+       REG_OFFSET_NAME(kpc),
+       REG_OFFSET_NAME(sar),
+       REG_OFFSET_NAME(iir),
+       REG_OFFSET_NAME(isr),
+       REG_OFFSET_NAME(ior),
+       REG_OFFSET_NAME(ipsw),
+       REG_OFFSET_END,
+};
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name:      the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+       const struct pt_regs_offset *roff;
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (!strcmp(roff->name, name))
+                       return roff->offset;
+       return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset:    the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+       const struct pt_regs_offset *roff;
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (roff->offset == offset)
+                       return roff->name;
+       return NULL;
+}