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