ptrace.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. * arch/score/kernel/ptrace.c
  3. *
  4. * Score Processor version.
  5. *
  6. * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
  7. * Chen Liqin <liqin.chen@sunplusct.com>
  8. * Lennox Wu <lennox.wu@sunplusct.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, see the file COPYING, or write
  22. * to the Free Software Foundation, Inc.,
  23. * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  24. */
  25. #include <linux/elf.h>
  26. #include <linux/kernel.h>
  27. #include <linux/mm.h>
  28. #include <linux/ptrace.h>
  29. #include <linux/regset.h>
  30. #include <linux/sched/task_stack.h>
  31. #include <linux/uaccess.h>
  32. /*
  33. * retrieve the contents of SCORE userspace general registers
  34. */
  35. static int genregs_get(struct task_struct *target,
  36. const struct user_regset *regset,
  37. unsigned int pos, unsigned int count,
  38. void *kbuf, void __user *ubuf)
  39. {
  40. const struct pt_regs *regs = task_pt_regs(target);
  41. int ret;
  42. /* skip 9 * sizeof(unsigned long) not use for pt_regs */
  43. ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  44. 0, offsetof(struct pt_regs, regs));
  45. /* r0 - r31, cel, ceh, sr0, sr1, sr2, epc, ema, psr, ecr, condition */
  46. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  47. regs->regs,
  48. offsetof(struct pt_regs, regs),
  49. offsetof(struct pt_regs, cp0_condition));
  50. if (!ret)
  51. ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  52. sizeof(struct pt_regs), -1);
  53. return ret;
  54. }
  55. /*
  56. * update the contents of the SCORE userspace general registers
  57. */
  58. static int genregs_set(struct task_struct *target,
  59. const struct user_regset *regset,
  60. unsigned int pos, unsigned int count,
  61. const void *kbuf, const void __user *ubuf)
  62. {
  63. struct pt_regs *regs = task_pt_regs(target);
  64. int ret;
  65. /* skip 9 * sizeof(unsigned long) */
  66. ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  67. 0, offsetof(struct pt_regs, regs));
  68. /* r0 - r31, cel, ceh, sr0, sr1, sr2, epc, ema, psr, ecr, condition */
  69. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  70. regs->regs,
  71. offsetof(struct pt_regs, regs),
  72. offsetof(struct pt_regs, cp0_condition));
  73. if (!ret)
  74. ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  75. sizeof(struct pt_regs), -1);
  76. return ret;
  77. }
  78. /*
  79. * Define the register sets available on the score7 under Linux
  80. */
  81. enum score7_regset {
  82. REGSET_GENERAL,
  83. };
  84. static const struct user_regset score7_regsets[] = {
  85. [REGSET_GENERAL] = {
  86. .core_note_type = NT_PRSTATUS,
  87. .n = ELF_NGREG,
  88. .size = sizeof(long),
  89. .align = sizeof(long),
  90. .get = genregs_get,
  91. .set = genregs_set,
  92. },
  93. };
  94. static const struct user_regset_view user_score_native_view = {
  95. .name = "score7",
  96. .e_machine = EM_SCORE7,
  97. .regsets = score7_regsets,
  98. .n = ARRAY_SIZE(score7_regsets),
  99. };
  100. const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  101. {
  102. return &user_score_native_view;
  103. }
  104. static int is_16bitinsn(unsigned long insn)
  105. {
  106. if ((insn & INSN32_MASK) == INSN32_MASK)
  107. return 0;
  108. else
  109. return 1;
  110. }
  111. int
  112. read_tsk_long(struct task_struct *child,
  113. unsigned long addr, unsigned long *res)
  114. {
  115. int copied;
  116. copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE);
  117. return copied != sizeof(*res) ? -EIO : 0;
  118. }
  119. int
  120. read_tsk_short(struct task_struct *child,
  121. unsigned long addr, unsigned short *res)
  122. {
  123. int copied;
  124. copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE);
  125. return copied != sizeof(*res) ? -EIO : 0;
  126. }
  127. static int
  128. write_tsk_short(struct task_struct *child,
  129. unsigned long addr, unsigned short val)
  130. {
  131. int copied;
  132. copied = access_process_vm(child, addr, &val, sizeof(val),
  133. FOLL_FORCE | FOLL_WRITE);
  134. return copied != sizeof(val) ? -EIO : 0;
  135. }
  136. static int
  137. write_tsk_long(struct task_struct *child,
  138. unsigned long addr, unsigned long val)
  139. {
  140. int copied;
  141. copied = access_process_vm(child, addr, &val, sizeof(val),
  142. FOLL_FORCE | FOLL_WRITE);
  143. return copied != sizeof(val) ? -EIO : 0;
  144. }
  145. void user_enable_single_step(struct task_struct *child)
  146. {
  147. /* far_epc is the target of branch */
  148. unsigned int epc, far_epc = 0;
  149. unsigned long epc_insn, far_epc_insn;
  150. int ninsn_type; /* next insn type 0=16b, 1=32b */
  151. unsigned int tmp, tmp2;
  152. struct pt_regs *regs = task_pt_regs(child);
  153. child->thread.single_step = 1;
  154. child->thread.ss_nextcnt = 1;
  155. epc = regs->cp0_epc;
  156. read_tsk_long(child, epc, &epc_insn);
  157. if (is_16bitinsn(epc_insn)) {
  158. if ((epc_insn & J16M) == J16) {
  159. tmp = epc_insn & 0xFFE;
  160. epc = (epc & 0xFFFFF000) | tmp;
  161. } else if ((epc_insn & B16M) == B16) {
  162. child->thread.ss_nextcnt = 2;
  163. tmp = (epc_insn & 0xFF) << 1;
  164. tmp = tmp << 23;
  165. tmp = (unsigned int)((int) tmp >> 23);
  166. far_epc = epc + tmp;
  167. epc += 2;
  168. } else if ((epc_insn & BR16M) == BR16) {
  169. child->thread.ss_nextcnt = 2;
  170. tmp = (epc_insn >> 4) & 0xF;
  171. far_epc = regs->regs[tmp];
  172. epc += 2;
  173. } else
  174. epc += 2;
  175. } else {
  176. if ((epc_insn & J32M) == J32) {
  177. tmp = epc_insn & 0x03FFFFFE;
  178. tmp2 = tmp & 0x7FFF;
  179. tmp = (((tmp >> 16) & 0x3FF) << 15) | tmp2;
  180. epc = (epc & 0xFFC00000) | tmp;
  181. } else if ((epc_insn & B32M) == B32) {
  182. child->thread.ss_nextcnt = 2;
  183. tmp = epc_insn & 0x03FFFFFE; /* discard LK bit */
  184. tmp2 = tmp & 0x3FF;
  185. tmp = (((tmp >> 16) & 0x3FF) << 10) | tmp2; /* 20bit */
  186. tmp = tmp << 12;
  187. tmp = (unsigned int)((int) tmp >> 12);
  188. far_epc = epc + tmp;
  189. epc += 4;
  190. } else if ((epc_insn & BR32M) == BR32) {
  191. child->thread.ss_nextcnt = 2;
  192. tmp = (epc_insn >> 16) & 0x1F;
  193. far_epc = regs->regs[tmp];
  194. epc += 4;
  195. } else
  196. epc += 4;
  197. }
  198. if (child->thread.ss_nextcnt == 1) {
  199. read_tsk_long(child, epc, &epc_insn);
  200. if (is_16bitinsn(epc_insn)) {
  201. write_tsk_short(child, epc, SINGLESTEP16_INSN);
  202. ninsn_type = 0;
  203. } else {
  204. write_tsk_long(child, epc, SINGLESTEP32_INSN);
  205. ninsn_type = 1;
  206. }
  207. if (ninsn_type == 0) { /* 16bits */
  208. child->thread.insn1_type = 0;
  209. child->thread.addr1 = epc;
  210. /* the insn may have 32bit data */
  211. child->thread.insn1 = (short)epc_insn;
  212. } else {
  213. child->thread.insn1_type = 1;
  214. child->thread.addr1 = epc;
  215. child->thread.insn1 = epc_insn;
  216. }
  217. } else {
  218. /* branch! have two target child->thread.ss_nextcnt=2 */
  219. read_tsk_long(child, epc, &epc_insn);
  220. read_tsk_long(child, far_epc, &far_epc_insn);
  221. if (is_16bitinsn(epc_insn)) {
  222. write_tsk_short(child, epc, SINGLESTEP16_INSN);
  223. ninsn_type = 0;
  224. } else {
  225. write_tsk_long(child, epc, SINGLESTEP32_INSN);
  226. ninsn_type = 1;
  227. }
  228. if (ninsn_type == 0) { /* 16bits */
  229. child->thread.insn1_type = 0;
  230. child->thread.addr1 = epc;
  231. /* the insn may have 32bit data */
  232. child->thread.insn1 = (short)epc_insn;
  233. } else {
  234. child->thread.insn1_type = 1;
  235. child->thread.addr1 = epc;
  236. child->thread.insn1 = epc_insn;
  237. }
  238. if (is_16bitinsn(far_epc_insn)) {
  239. write_tsk_short(child, far_epc, SINGLESTEP16_INSN);
  240. ninsn_type = 0;
  241. } else {
  242. write_tsk_long(child, far_epc, SINGLESTEP32_INSN);
  243. ninsn_type = 1;
  244. }
  245. if (ninsn_type == 0) { /* 16bits */
  246. child->thread.insn2_type = 0;
  247. child->thread.addr2 = far_epc;
  248. /* the insn may have 32bit data */
  249. child->thread.insn2 = (short)far_epc_insn;
  250. } else {
  251. child->thread.insn2_type = 1;
  252. child->thread.addr2 = far_epc;
  253. child->thread.insn2 = far_epc_insn;
  254. }
  255. }
  256. }
  257. void user_disable_single_step(struct task_struct *child)
  258. {
  259. if (child->thread.insn1_type == 0)
  260. write_tsk_short(child, child->thread.addr1,
  261. child->thread.insn1);
  262. if (child->thread.insn1_type == 1)
  263. write_tsk_long(child, child->thread.addr1,
  264. child->thread.insn1);
  265. if (child->thread.ss_nextcnt == 2) { /* branch */
  266. if (child->thread.insn1_type == 0)
  267. write_tsk_short(child, child->thread.addr1,
  268. child->thread.insn1);
  269. if (child->thread.insn1_type == 1)
  270. write_tsk_long(child, child->thread.addr1,
  271. child->thread.insn1);
  272. if (child->thread.insn2_type == 0)
  273. write_tsk_short(child, child->thread.addr2,
  274. child->thread.insn2);
  275. if (child->thread.insn2_type == 1)
  276. write_tsk_long(child, child->thread.addr2,
  277. child->thread.insn2);
  278. }
  279. child->thread.single_step = 0;
  280. child->thread.ss_nextcnt = 0;
  281. }
  282. void ptrace_disable(struct task_struct *child)
  283. {
  284. user_disable_single_step(child);
  285. }
  286. long
  287. arch_ptrace(struct task_struct *child, long request,
  288. unsigned long addr, unsigned long data)
  289. {
  290. int ret;
  291. unsigned long __user *datap = (void __user *)data;
  292. switch (request) {
  293. case PTRACE_GETREGS:
  294. ret = copy_regset_to_user(child, &user_score_native_view,
  295. REGSET_GENERAL,
  296. 0, sizeof(struct pt_regs),
  297. datap);
  298. break;
  299. case PTRACE_SETREGS:
  300. ret = copy_regset_from_user(child, &user_score_native_view,
  301. REGSET_GENERAL,
  302. 0, sizeof(struct pt_regs),
  303. datap);
  304. break;
  305. default:
  306. ret = ptrace_request(child, request, addr, data);
  307. break;
  308. }
  309. return ret;
  310. }
  311. /*
  312. * Notification of system call entry/exit
  313. * - triggered by current->work.syscall_trace
  314. */
  315. asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
  316. {
  317. if (!(current->ptrace & PT_PTRACED))
  318. return;
  319. if (!test_thread_flag(TIF_SYSCALL_TRACE))
  320. return;
  321. /* The 0x80 provides a way for the tracing parent to distinguish
  322. between a syscall stop and SIGTRAP delivery. */
  323. ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
  324. 0x80 : 0));
  325. /*
  326. * this isn't the same as continuing with a signal, but it will do
  327. * for normal use. strace only continues with a signal if the
  328. * stopping signal is not SIGTRAP. -brl
  329. */
  330. if (current->exit_code) {
  331. send_sig(current->exit_code, current, 1);
  332. current->exit_code = 0;
  333. }
  334. }