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};
  32
  33static int riscv_gpr_get(struct task_struct *target,
  34                         const struct user_regset *regset,
  35                         unsigned int pos, unsigned int count,
  36                         void *kbuf, void __user *ubuf)
  37{
  38        struct pt_regs *regs;
  39
  40        regs = task_pt_regs(target);
  41        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
  42}
  43
  44static int riscv_gpr_set(struct task_struct *target,
  45                         const struct user_regset *regset,
  46                         unsigned int pos, unsigned int count,
  47                         const void *kbuf, const void __user *ubuf)
  48{
  49        int ret;
  50        struct pt_regs *regs;
  51
  52        regs = task_pt_regs(target);
  53        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
  54        return ret;
  55}
  56
  57
  58static const struct user_regset riscv_user_regset[] = {
  59        [REGSET_X] = {
  60                .core_note_type = NT_PRSTATUS,
  61                .n = ELF_NGREG,
  62                .size = sizeof(elf_greg_t),
  63                .align = sizeof(elf_greg_t),
  64                .get = &riscv_gpr_get,
  65                .set = &riscv_gpr_set,
  66        },
  67};
  68
  69static const struct user_regset_view riscv_user_native_view = {
  70        .name = "riscv",
  71        .e_machine = EM_RISCV,
  72        .regsets = riscv_user_regset,
  73        .n = ARRAY_SIZE(riscv_user_regset),
  74};
  75
  76const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  77{
  78        return &riscv_user_native_view;
  79}
  80
  81void ptrace_disable(struct task_struct *child)
  82{
  83        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  84}
  85
  86long arch_ptrace(struct task_struct *child, long request,
  87                 unsigned long addr, unsigned long data)
  88{
  89        long ret = -EIO;
  90
  91        switch (request) {
  92        default:
  93                ret = ptrace_request(child, request, addr, data);
  94                break;
  95        }
  96
  97        return ret;
  98}
  99
 100/*
 101 * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
 102 * {handle,ret_from}_syscall.
 103 */
 104void do_syscall_trace_enter(struct pt_regs *regs)
 105{
 106        if (test_thread_flag(TIF_SYSCALL_TRACE))
 107                if (tracehook_report_syscall_entry(regs))
 108                        syscall_set_nr(current, regs, -1);
 109
 110#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 111        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 112                trace_sys_enter(regs, syscall_get_nr(current, regs));
 113#endif
 114}
 115
 116void do_syscall_trace_exit(struct pt_regs *regs)
 117{
 118        if (test_thread_flag(TIF_SYSCALL_TRACE))
 119                tracehook_report_syscall_exit(regs, 0);
 120
 121#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 122        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 123                trace_sys_exit(regs, regs->regs[0]);
 124#endif
 125}
 126