linux/arch/riscv/kernel/ptrace.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2010 Tilera Corporation. All Rights Reserved.
   4 * Copyright 2015 Regents of the University of California
   5 * Copyright 2017 SiFive
   6 *
   7 * Copied from arch/tile/kernel/ptrace.c
   8 */
   9
  10#include <asm/ptrace.h>
  11#include <asm/syscall.h>
  12#include <asm/thread_info.h>
  13#include <linux/audit.h>
  14#include <linux/ptrace.h>
  15#include <linux/elf.h>
  16#include <linux/regset.h>
  17#include <linux/sched.h>
  18#include <linux/sched/task_stack.h>
  19#include <linux/tracehook.h>
  20
  21#define CREATE_TRACE_POINTS
  22#include <trace/events/syscalls.h>
  23
  24enum riscv_regset {
  25        REGSET_X,
  26#ifdef CONFIG_FPU
  27        REGSET_F,
  28#endif
  29};
  30
  31static int riscv_gpr_get(struct task_struct *target,
  32                         const struct user_regset *regset,
  33                         struct membuf to)
  34{
  35        return membuf_write(&to, task_pt_regs(target),
  36                            sizeof(struct user_regs_struct));
  37}
  38
  39static int riscv_gpr_set(struct task_struct *target,
  40                         const struct user_regset *regset,
  41                         unsigned int pos, unsigned int count,
  42                         const void *kbuf, const void __user *ubuf)
  43{
  44        int ret;
  45        struct pt_regs *regs;
  46
  47        regs = task_pt_regs(target);
  48        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
  49        return ret;
  50}
  51
  52#ifdef CONFIG_FPU
  53static int riscv_fpr_get(struct task_struct *target,
  54                         const struct user_regset *regset,
  55                         struct membuf to)
  56{
  57        struct __riscv_d_ext_state *fstate = &target->thread.fstate;
  58
  59        membuf_write(&to, fstate, offsetof(struct __riscv_d_ext_state, fcsr));
  60        membuf_store(&to, fstate->fcsr);
  61        return membuf_zero(&to, 4);     // explicitly pad
  62}
  63
  64static int riscv_fpr_set(struct task_struct *target,
  65                         const struct user_regset *regset,
  66                         unsigned int pos, unsigned int count,
  67                         const void *kbuf, const void __user *ubuf)
  68{
  69        int ret;
  70        struct __riscv_d_ext_state *fstate = &target->thread.fstate;
  71
  72        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
  73                                 offsetof(struct __riscv_d_ext_state, fcsr));
  74        if (!ret) {
  75                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
  76                                         offsetof(struct __riscv_d_ext_state, fcsr) +
  77                                         sizeof(fstate->fcsr));
  78        }
  79
  80        return ret;
  81}
  82#endif
  83
  84static const struct user_regset riscv_user_regset[] = {
  85        [REGSET_X] = {
  86                .core_note_type = NT_PRSTATUS,
  87                .n = ELF_NGREG,
  88                .size = sizeof(elf_greg_t),
  89                .align = sizeof(elf_greg_t),
  90                .regset_get = riscv_gpr_get,
  91                .set = riscv_gpr_set,
  92        },
  93#ifdef CONFIG_FPU
  94        [REGSET_F] = {
  95                .core_note_type = NT_PRFPREG,
  96                .n = ELF_NFPREG,
  97                .size = sizeof(elf_fpreg_t),
  98                .align = sizeof(elf_fpreg_t),
  99                .regset_get = riscv_fpr_get,
 100                .set = riscv_fpr_set,
 101        },
 102#endif
 103};
 104
 105static const struct user_regset_view riscv_user_native_view = {
 106        .name = "riscv",
 107        .e_machine = EM_RISCV,
 108        .regsets = riscv_user_regset,
 109        .n = ARRAY_SIZE(riscv_user_regset),
 110};
 111
 112const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 113{
 114        return &riscv_user_native_view;
 115}
 116
 117void ptrace_disable(struct task_struct *child)
 118{
 119        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 120}
 121
 122long arch_ptrace(struct task_struct *child, long request,
 123                 unsigned long addr, unsigned long data)
 124{
 125        long ret = -EIO;
 126
 127        switch (request) {
 128        default:
 129                ret = ptrace_request(child, request, addr, data);
 130                break;
 131        }
 132
 133        return ret;
 134}
 135
 136/*
 137 * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
 138 * {handle,ret_from}_syscall.
 139 */
 140__visible int do_syscall_trace_enter(struct pt_regs *regs)
 141{
 142        if (test_thread_flag(TIF_SYSCALL_TRACE))
 143                if (tracehook_report_syscall_entry(regs))
 144                        return -1;
 145
 146        /*
 147         * Do the secure computing after ptrace; failures should be fast.
 148         * If this fails we might have return value in a0 from seccomp
 149         * (via SECCOMP_RET_ERRNO/TRACE).
 150         */
 151        if (secure_computing() == -1)
 152                return -1;
 153
 154#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 155        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 156                trace_sys_enter(regs, syscall_get_nr(current, regs));
 157#endif
 158
 159        audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3);
 160        return 0;
 161}
 162
 163__visible void do_syscall_trace_exit(struct pt_regs *regs)
 164{
 165        audit_syscall_exit(regs);
 166
 167        if (test_thread_flag(TIF_SYSCALL_TRACE))
 168                tracehook_report_syscall_exit(regs, 0);
 169
 170#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 171        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 172                trace_sys_exit(regs, regs_return_value(regs));
 173#endif
 174}
 175