ptrace.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * Copyright (C) 2014 Altera Corporation
  3. * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
  4. *
  5. * This file is subject to the terms and conditions of the GNU General
  6. * Public License. See the file COPYING in the main directory of this
  7. * archive for more details.
  8. */
  9. #include <linux/elf.h>
  10. #include <linux/errno.h>
  11. #include <linux/kernel.h>
  12. #include <linux/mm.h>
  13. #include <linux/ptrace.h>
  14. #include <linux/regset.h>
  15. #include <linux/sched.h>
  16. #include <linux/sched/task_stack.h>
  17. #include <linux/tracehook.h>
  18. #include <linux/uaccess.h>
  19. #include <linux/user.h>
  20. static int genregs_get(struct task_struct *target,
  21. const struct user_regset *regset,
  22. unsigned int pos, unsigned int count,
  23. void *kbuf, void __user *ubuf)
  24. {
  25. const struct pt_regs *regs = task_pt_regs(target);
  26. const struct switch_stack *sw = (struct switch_stack *)regs - 1;
  27. int ret = 0;
  28. #define REG_O_ZERO_RANGE(START, END) \
  29. if (!ret) \
  30. ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
  31. START * 4, (END * 4) + 4);
  32. #define REG_O_ONE(PTR, LOC) \
  33. if (!ret) \
  34. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
  35. LOC * 4, (LOC * 4) + 4);
  36. #define REG_O_RANGE(PTR, START, END) \
  37. if (!ret) \
  38. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
  39. START * 4, (END * 4) + 4);
  40. REG_O_ZERO_RANGE(PTR_R0, PTR_R0);
  41. REG_O_RANGE(&regs->r1, PTR_R1, PTR_R7);
  42. REG_O_RANGE(&regs->r8, PTR_R8, PTR_R15);
  43. REG_O_RANGE(sw, PTR_R16, PTR_R23);
  44. REG_O_ZERO_RANGE(PTR_R24, PTR_R25); /* et and bt */
  45. REG_O_ONE(&regs->gp, PTR_GP);
  46. REG_O_ONE(&regs->sp, PTR_SP);
  47. REG_O_ONE(&regs->fp, PTR_FP);
  48. REG_O_ONE(&regs->ea, PTR_EA);
  49. REG_O_ZERO_RANGE(PTR_BA, PTR_BA);
  50. REG_O_ONE(&regs->ra, PTR_RA);
  51. REG_O_ONE(&regs->ea, PTR_PC); /* use ea for PC */
  52. if (!ret)
  53. ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  54. PTR_STATUS * 4, -1);
  55. return ret;
  56. }
  57. /*
  58. * Set the thread state from a regset passed in via ptrace
  59. */
  60. static int genregs_set(struct task_struct *target,
  61. const struct user_regset *regset,
  62. unsigned int pos, unsigned int count,
  63. const void *kbuf, const void __user *ubuf)
  64. {
  65. struct pt_regs *regs = task_pt_regs(target);
  66. const struct switch_stack *sw = (struct switch_stack *)regs - 1;
  67. int ret = 0;
  68. #define REG_IGNORE_RANGE(START, END) \
  69. if (!ret) \
  70. ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
  71. START * 4, (END * 4) + 4);
  72. #define REG_IN_ONE(PTR, LOC) \
  73. if (!ret) \
  74. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
  75. (void *)(PTR), LOC * 4, (LOC * 4) + 4);
  76. #define REG_IN_RANGE(PTR, START, END) \
  77. if (!ret) \
  78. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
  79. (void *)(PTR), START * 4, (END * 4) + 4);
  80. REG_IGNORE_RANGE(PTR_R0, PTR_R0);
  81. REG_IN_RANGE(&regs->r1, PTR_R1, PTR_R7);
  82. REG_IN_RANGE(&regs->r8, PTR_R8, PTR_R15);
  83. REG_IN_RANGE(sw, PTR_R16, PTR_R23);
  84. REG_IGNORE_RANGE(PTR_R24, PTR_R25); /* et and bt */
  85. REG_IN_ONE(&regs->gp, PTR_GP);
  86. REG_IN_ONE(&regs->sp, PTR_SP);
  87. REG_IN_ONE(&regs->fp, PTR_FP);
  88. REG_IN_ONE(&regs->ea, PTR_EA);
  89. REG_IGNORE_RANGE(PTR_BA, PTR_BA);
  90. REG_IN_ONE(&regs->ra, PTR_RA);
  91. REG_IN_ONE(&regs->ea, PTR_PC); /* use ea for PC */
  92. if (!ret)
  93. ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  94. PTR_STATUS * 4, -1);
  95. return ret;
  96. }
  97. /*
  98. * Define the register sets available on Nios2 under Linux
  99. */
  100. enum nios2_regset {
  101. REGSET_GENERAL,
  102. };
  103. static const struct user_regset nios2_regsets[] = {
  104. [REGSET_GENERAL] = {
  105. .core_note_type = NT_PRSTATUS,
  106. .n = NUM_PTRACE_REG,
  107. .size = sizeof(unsigned long),
  108. .align = sizeof(unsigned long),
  109. .get = genregs_get,
  110. .set = genregs_set,
  111. }
  112. };
  113. static const struct user_regset_view nios2_user_view = {
  114. .name = "nios2",
  115. .e_machine = ELF_ARCH,
  116. .ei_osabi = ELF_OSABI,
  117. .regsets = nios2_regsets,
  118. .n = ARRAY_SIZE(nios2_regsets)
  119. };
  120. const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  121. {
  122. return &nios2_user_view;
  123. }
  124. void ptrace_disable(struct task_struct *child)
  125. {
  126. }
  127. long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
  128. unsigned long data)
  129. {
  130. return ptrace_request(child, request, addr, data);
  131. }
  132. asmlinkage int do_syscall_trace_enter(void)
  133. {
  134. int ret = 0;
  135. if (test_thread_flag(TIF_SYSCALL_TRACE))
  136. ret = tracehook_report_syscall_entry(task_pt_regs(current));
  137. return ret;
  138. }
  139. asmlinkage void do_syscall_trace_exit(void)
  140. {
  141. if (test_thread_flag(TIF_SYSCALL_TRACE))
  142. tracehook_report_syscall_exit(task_pt_regs(current), 0);
  143. }