ptrace.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. #include <asm/ptrace.h>
  18. #include <asm/syscall.h>
  19. #include <asm/thread_info.h>
  20. #include <linux/ptrace.h>
  21. #include <linux/elf.h>
  22. #include <linux/regset.h>
  23. #include <linux/sched.h>
  24. #include <linux/sched/task_stack.h>
  25. #include <linux/tracehook.h>
  26. #include <trace/events/syscalls.h>
  27. enum riscv_regset {
  28. REGSET_X,
  29. #ifdef CONFIG_FPU
  30. REGSET_F,
  31. #endif
  32. };
  33. static 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. regs = task_pt_regs(target);
  40. return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
  41. }
  42. static int riscv_gpr_set(struct task_struct *target,
  43. const struct user_regset *regset,
  44. unsigned int pos, unsigned int count,
  45. const void *kbuf, const void __user *ubuf)
  46. {
  47. int ret;
  48. struct pt_regs *regs;
  49. regs = task_pt_regs(target);
  50. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
  51. return ret;
  52. }
  53. #ifdef CONFIG_FPU
  54. static int riscv_fpr_get(struct task_struct *target,
  55. const struct user_regset *regset,
  56. unsigned int pos, unsigned int count,
  57. void *kbuf, void __user *ubuf)
  58. {
  59. int ret;
  60. struct __riscv_d_ext_state *fstate = &target->thread.fstate;
  61. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0,
  62. offsetof(struct __riscv_d_ext_state, fcsr));
  63. if (!ret) {
  64. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0,
  65. offsetof(struct __riscv_d_ext_state, fcsr) +
  66. sizeof(fstate->fcsr));
  67. }
  68. return ret;
  69. }
  70. static int riscv_fpr_set(struct task_struct *target,
  71. const struct user_regset *regset,
  72. unsigned int pos, unsigned int count,
  73. const void *kbuf, const void __user *ubuf)
  74. {
  75. int ret;
  76. struct __riscv_d_ext_state *fstate = &target->thread.fstate;
  77. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
  78. offsetof(struct __riscv_d_ext_state, fcsr));
  79. if (!ret) {
  80. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
  81. offsetof(struct __riscv_d_ext_state, fcsr) +
  82. sizeof(fstate->fcsr));
  83. }
  84. return ret;
  85. }
  86. #endif
  87. static const struct user_regset riscv_user_regset[] = {
  88. [REGSET_X] = {
  89. .core_note_type = NT_PRSTATUS,
  90. .n = ELF_NGREG,
  91. .size = sizeof(elf_greg_t),
  92. .align = sizeof(elf_greg_t),
  93. .get = &riscv_gpr_get,
  94. .set = &riscv_gpr_set,
  95. },
  96. #ifdef CONFIG_FPU
  97. [REGSET_F] = {
  98. .core_note_type = NT_PRFPREG,
  99. .n = ELF_NFPREG,
  100. .size = sizeof(elf_fpreg_t),
  101. .align = sizeof(elf_fpreg_t),
  102. .get = &riscv_fpr_get,
  103. .set = &riscv_fpr_set,
  104. },
  105. #endif
  106. };
  107. static const struct user_regset_view riscv_user_native_view = {
  108. .name = "riscv",
  109. .e_machine = EM_RISCV,
  110. .regsets = riscv_user_regset,
  111. .n = ARRAY_SIZE(riscv_user_regset),
  112. };
  113. const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  114. {
  115. return &riscv_user_native_view;
  116. }
  117. void ptrace_disable(struct task_struct *child)
  118. {
  119. clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  120. }
  121. long arch_ptrace(struct task_struct *child, long request,
  122. unsigned long addr, unsigned long data)
  123. {
  124. long ret = -EIO;
  125. switch (request) {
  126. default:
  127. ret = ptrace_request(child, request, addr, data);
  128. break;
  129. }
  130. return ret;
  131. }
  132. /*
  133. * Allows PTRACE_SYSCALL to work. These are called from entry.S in
  134. * {handle,ret_from}_syscall.
  135. */
  136. void do_syscall_trace_enter(struct pt_regs *regs)
  137. {
  138. if (test_thread_flag(TIF_SYSCALL_TRACE))
  139. if (tracehook_report_syscall_entry(regs))
  140. syscall_set_nr(current, regs, -1);
  141. #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
  142. if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
  143. trace_sys_enter(regs, syscall_get_nr(current, regs));
  144. #endif
  145. }
  146. void do_syscall_trace_exit(struct pt_regs *regs)
  147. {
  148. if (test_thread_flag(TIF_SYSCALL_TRACE))
  149. tracehook_report_syscall_exit(regs, 0);
  150. #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
  151. if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
  152. trace_sys_exit(regs, regs->regs[0]);
  153. #endif
  154. }