linux/arch/riscv/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
   3 * Copyright 2015 Regents of the University of California
   4 * Copyright 2017 SiFive
   5 *
   6 *   This program is free software; you can redistribute it and/or
   7 *   modify it under the terms of the GNU General Public License
   8 *   as published by the Free Software Foundation, version 2.
   9 *
  10 *   This program is distributed in the hope that it will be useful,
  11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *   GNU General Public License for more details.
  14 *
  15 * Copied from arch/tile/kernel/ptrace.c
  16 */
  17
  18#include <asm/ptrace.h>
  19#include <asm/syscall.h>
  20#include <asm/thread_info.h>
  21#include <linux/ptrace.h>
  22#include <linux/elf.h>
  23#include <linux/regset.h>
  24#include <linux/sched.h>
  25#include <linux/sched/task_stack.h>
  26#include <linux/tracehook.h>
  27#include <trace/events/syscalls.h>
  28
  29enum riscv_regset {
  30        REGSET_X,
  31#ifdef CONFIG_FPU
  32        REGSET_F,
  33#endif
  34};
  35
  36static int riscv_gpr_get(struct task_struct *target,
  37                         const struct user_regset *regset,
  38                         unsigned int pos, unsigned int count,
  39                         void *kbuf, void __user *ubuf)
  40{
  41        struct pt_regs *regs;
  42
  43        regs = task_pt_regs(target);
  44        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
  45}
  46
  47static int riscv_gpr_set(struct task_struct *target,
  48                         const struct user_regset *regset,
  49                         unsigned int pos, unsigned int count,
  50                         const void *kbuf, const void __user *ubuf)
  51{
  52        int ret;
  53        struct pt_regs *regs;
  54
  55        regs = task_pt_regs(target);
  56        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
  57        return ret;
  58}
  59
  60#ifdef CONFIG_FPU
  61static int riscv_fpr_get(struct task_struct *target,
  62                         const struct user_regset *regset,
  63                         unsigned int pos, unsigned int count,
  64                         void *kbuf, void __user *ubuf)
  65{
  66        int ret;
  67        struct __riscv_d_ext_state *fstate = &target->thread.fstate;
  68
  69        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0,
  70                                  offsetof(struct __riscv_d_ext_state, fcsr));
  71        if (!ret) {
  72                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0,
  73                                          offsetof(struct __riscv_d_ext_state, fcsr) +
  74                                          sizeof(fstate->fcsr));
  75        }
  76
  77        return ret;
  78}
  79
  80static int riscv_fpr_set(struct task_struct *target,
  81                         const struct user_regset *regset,
  82                         unsigned int pos, unsigned int count,
  83                         const void *kbuf, const void __user *ubuf)
  84{
  85        int ret;
  86        struct __riscv_d_ext_state *fstate = &target->thread.fstate;
  87
  88        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
  89                                 offsetof(struct __riscv_d_ext_state, fcsr));
  90        if (!ret) {
  91                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
  92                                         offsetof(struct __riscv_d_ext_state, fcsr) +
  93                                         sizeof(fstate->fcsr));
  94        }
  95
  96        return ret;
  97}
  98#endif
  99
 100static const struct user_regset riscv_user_regset[] = {
 101        [REGSET_X] = {
 102                .core_note_type = NT_PRSTATUS,
 103                .n = ELF_NGREG,
 104                .size = sizeof(elf_greg_t),
 105                .align = sizeof(elf_greg_t),
 106                .get = &riscv_gpr_get,
 107                .set = &riscv_gpr_set,
 108        },
 109#ifdef CONFIG_FPU
 110        [REGSET_F] = {
 111                .core_note_type = NT_PRFPREG,
 112                .n = ELF_NFPREG,
 113                .size = sizeof(elf_fpreg_t),
 114                .align = sizeof(elf_fpreg_t),
 115                .get = &riscv_fpr_get,
 116                .set = &riscv_fpr_set,
 117        },
 118#endif
 119};
 120
 121static const struct user_regset_view riscv_user_native_view = {
 122        .name = "riscv",
 123        .e_machine = EM_RISCV,
 124        .regsets = riscv_user_regset,
 125        .n = ARRAY_SIZE(riscv_user_regset),
 126};
 127
 128const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 129{
 130        return &riscv_user_native_view;
 131}
 132
 133void ptrace_disable(struct task_struct *child)
 134{
 135        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 136}
 137
 138long arch_ptrace(struct task_struct *child, long request,
 139                 unsigned long addr, unsigned long data)
 140{
 141        long ret = -EIO;
 142
 143        switch (request) {
 144        default:
 145                ret = ptrace_request(child, request, addr, data);
 146                break;
 147        }
 148
 149        return ret;
 150}
 151
 152/*
 153 * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
 154 * {handle,ret_from}_syscall.
 155 */
 156void do_syscall_trace_enter(struct pt_regs *regs)
 157{
 158        if (test_thread_flag(TIF_SYSCALL_TRACE))
 159                if (tracehook_report_syscall_entry(regs))
 160                        syscall_set_nr(current, regs, -1);
 161
 162#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 163        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 164                trace_sys_enter(regs, syscall_get_nr(current, regs));
 165#endif
 166}
 167
 168void do_syscall_trace_exit(struct pt_regs *regs)
 169{
 170        if (test_thread_flag(TIF_SYSCALL_TRACE))
 171                tracehook_report_syscall_exit(regs, 0);
 172
 173#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 174        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 175                trace_sys_exit(regs, regs->regs[0]);
 176#endif
 177}
 178