On Fri, Nov 22, 2019 at 6:32 AM Paul Walmsley paul.walmsley@sifive.com wrote:
On Thu, 21 Nov 2019, Paul Walmsley wrote:
As I understand it, this patch hasn't been signed off on by Patrick. I've sent him an E-mail asking him whether he's willing to add his Signed-off-by:, but haven't heard back from it.
From our discussions, I understand that this patch is based partially on some of his earlier, public, kprobes work. In lieu of any response from Patrick, could you please resend this patch and just note in the commit description that it's partially based on one of his patches, add a Link: line that points to the URL of the patch that it's partially based on, and replace the Signed-off-by: with a Co-developed-by: or something similar?
OK - just looked at the patches more closely, and I think I see what's going on here. This patch looks like a rebased version of this patch:
https://lore.kernel.org/linux-riscv/20181113195804.22825-2-me@packi.ch/
So let's just plan to use an updated version of Patrick's original (below). Please let me know if you have any comments on it or if I missed something -
- Paul
Dear Paul, Due to the rule of mail classification, I do not find this mail in time. I am sorry for that. I think it is good for me.
Thanks and regards Vincent
From: Patrick Stählin me@packi.ch Date: Tue, 13 Nov 2018 20:58:03 +0100 Subject: [PATCH] RISC-V: Implement ptrace regs and stack API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit
Needed for kprobes support. Copied and adapted from arm64 code.
Signed-off-by: Patrick Stählin me@packi.ch [paul.walmsley@sifive.com: updated to apply; fixed checkpatch issues; fixed regs_get_register() kerneldoc] Cc: Vincent Chen vincent.chen@sifive.com Link: https://lore.kernel.org/linux-riscv/20181113195803.CjtBCsUcG9czwiqmPBGKUjvl5... Link: https://lore.kernel.org/linux-riscv/1572919114-3886-1-git-send-email-vincent... Signed-off-by: Paul Walmsley paul.walmsley@sifive.com
arch/riscv/Kconfig | 1 + arch/riscv/include/asm/ptrace.h | 30 ++++++++++ arch/riscv/kernel/ptrace.c | 99 +++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 8eebbc8860bb..d5bbf4223fd2 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -61,6 +61,7 @@ config RISCV select SPARSEMEM_STATIC if 32BIT select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select HAVE_ARCH_MMAP_RND_BITS
select HAVE_REGS_AND_STACK_ACCESS_API
config ARCH_MMAP_RND_BITS_MIN default 18 if 64BIT diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index d48d1e13973c..50d37b123a61 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -8,6 +8,7 @@
#include <uapi/asm/ptrace.h> #include <asm/csr.h> +#include <linux/compiler.h>
#ifndef __ASSEMBLY__
@@ -60,6 +61,7 @@ struct pt_regs {
#define user_mode(regs) (((regs)->sstatus & SR_SPP) == 0)
+#define MAX_REG_OFFSET offsetof(struct pt_regs, orig_a0)
/* Helpers for working with the instruction pointer */ static inline unsigned long instruction_pointer(struct pt_regs *regs) @@ -85,6 +87,12 @@ static inline void user_stack_pointer_set(struct pt_regs *regs, regs->sp = val; }
+/* Valid only for Kernel mode traps. */ +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{
return regs->sp;
+}
/* Helpers for working with the frame pointer */ static inline unsigned long frame_pointer(struct pt_regs *regs) { @@ -101,6 +109,28 @@ static inline unsigned long regs_return_value(struct pt_regs *regs) return regs->a0; }
+int regs_query_register_offset(const char *name); +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
unsigned int n);
+/**
- regs_get_register() - get register value from its offset
- @regs: pt_regs from which register value is gotten
- @offset: offset of the register.
- regs_get_register() returns the value from @regs of a register
- identified by @offset. The @offset is the offset of the register
- in struct pt_regs. If @offset is bigger than MAX_REG_OFFSET, this
- returns 0.
- */
+static inline unsigned long regs_get_register(struct pt_regs *regs,
unsigned int offset)
+{
if (unlikely(offset > MAX_REG_OFFSET))
return 0;
return *(unsigned long *)((unsigned long)regs + offset);
+} #endif /* __ASSEMBLY__ */
#endif /* _ASM_RISCV_PTRACE_H */ diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index 1252113ef8b2..5076b30fe18b 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -125,6 +125,105 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &riscv_user_native_view; }
+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_END {.name = NULL, .offset = 0}
+static const struct pt_regs_offset regoffset_table[] = {
REG_OFFSET_NAME(sepc),
REG_OFFSET_NAME(ra),
REG_OFFSET_NAME(sp),
REG_OFFSET_NAME(gp),
REG_OFFSET_NAME(tp),
REG_OFFSET_NAME(t0),
REG_OFFSET_NAME(t1),
REG_OFFSET_NAME(t2),
REG_OFFSET_NAME(s0),
REG_OFFSET_NAME(s1),
REG_OFFSET_NAME(a0),
REG_OFFSET_NAME(a1),
REG_OFFSET_NAME(a2),
REG_OFFSET_NAME(a3),
REG_OFFSET_NAME(a4),
REG_OFFSET_NAME(a5),
REG_OFFSET_NAME(a6),
REG_OFFSET_NAME(a7),
REG_OFFSET_NAME(s2),
REG_OFFSET_NAME(s3),
REG_OFFSET_NAME(s4),
REG_OFFSET_NAME(s5),
REG_OFFSET_NAME(s6),
REG_OFFSET_NAME(s7),
REG_OFFSET_NAME(s8),
REG_OFFSET_NAME(s9),
REG_OFFSET_NAME(s10),
REG_OFFSET_NAME(s11),
REG_OFFSET_NAME(t3),
REG_OFFSET_NAME(t4),
REG_OFFSET_NAME(t5),
REG_OFFSET_NAME(t6),
REG_OFFSET_NAME(sstatus),
REG_OFFSET_NAME(sbadaddr),
REG_OFFSET_NAME(scause),
REG_OFFSET_NAME(orig_a0),
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; roff++)
if (!strcmp(roff->name, name))
return roff->offset;
return -EINVAL;
+}
+/**
- regs_within_kernel_stack() - check the address in the stack
- @regs: pt_regs which contains kernel stack pointer.
- @addr: address which is checked.
- regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
- If @addr is within the kernel stack, it returns true. If not, returns false.
- */
+static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) +{
return (addr & ~(THREAD_SIZE - 1)) ==
(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
+}
+/**
- regs_get_kernel_stack_nth() - get Nth entry of the stack
- @regs: pt_regs which contains kernel stack pointer.
- @n: stack entry number.
- regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
- is specified by @regs. If the @n th entry is NOT in the kernel stack,
- this returns 0.
- */
+unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) +{
unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
addr += n;
if (regs_within_kernel_stack(regs, (unsigned long)addr))
return *addr;
else
return 0;
+}
void ptrace_disable(struct task_struct *child) { clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -- 2.24.0.rc0