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