ptrace.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /* MN10300 Process tracing
  2. *
  3. * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
  4. * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
  5. * Modified by David Howells (dhowells@redhat.com)
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public Licence
  9. * as published by the Free Software Foundation; either version
  10. * 2 of the Licence, or (at your option) any later version.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/sched.h>
  14. #include <linux/mm.h>
  15. #include <linux/smp.h>
  16. #include <linux/smp_lock.h>
  17. #include <linux/errno.h>
  18. #include <linux/ptrace.h>
  19. #include <linux/user.h>
  20. #include <linux/regset.h>
  21. #include <linux/elf.h>
  22. #include <linux/tracehook.h>
  23. #include <asm/uaccess.h>
  24. #include <asm/pgtable.h>
  25. #include <asm/system.h>
  26. #include <asm/processor.h>
  27. #include <asm/cacheflush.h>
  28. #include <asm/fpu.h>
  29. #include <asm/asm-offsets.h>
  30. /*
  31. * translate ptrace register IDs into struct pt_regs offsets
  32. */
  33. static const u8 ptrace_regid_to_frame[] = {
  34. [PT_A3 << 2] = REG_A3,
  35. [PT_A2 << 2] = REG_A2,
  36. [PT_D3 << 2] = REG_D3,
  37. [PT_D2 << 2] = REG_D2,
  38. [PT_MCVF << 2] = REG_MCVF,
  39. [PT_MCRL << 2] = REG_MCRL,
  40. [PT_MCRH << 2] = REG_MCRH,
  41. [PT_MDRQ << 2] = REG_MDRQ,
  42. [PT_E1 << 2] = REG_E1,
  43. [PT_E0 << 2] = REG_E0,
  44. [PT_E7 << 2] = REG_E7,
  45. [PT_E6 << 2] = REG_E6,
  46. [PT_E5 << 2] = REG_E5,
  47. [PT_E4 << 2] = REG_E4,
  48. [PT_E3 << 2] = REG_E3,
  49. [PT_E2 << 2] = REG_E2,
  50. [PT_SP << 2] = REG_SP,
  51. [PT_LAR << 2] = REG_LAR,
  52. [PT_LIR << 2] = REG_LIR,
  53. [PT_MDR << 2] = REG_MDR,
  54. [PT_A1 << 2] = REG_A1,
  55. [PT_A0 << 2] = REG_A0,
  56. [PT_D1 << 2] = REG_D1,
  57. [PT_D0 << 2] = REG_D0,
  58. [PT_ORIG_D0 << 2] = REG_ORIG_D0,
  59. [PT_EPSW << 2] = REG_EPSW,
  60. [PT_PC << 2] = REG_PC,
  61. };
  62. static inline int get_stack_long(struct task_struct *task, int offset)
  63. {
  64. return *(unsigned long *)
  65. ((unsigned long) task->thread.uregs + offset);
  66. }
  67. static inline
  68. int put_stack_long(struct task_struct *task, int offset, unsigned long data)
  69. {
  70. unsigned long stack;
  71. stack = (unsigned long) task->thread.uregs + offset;
  72. *(unsigned long *) stack = data;
  73. return 0;
  74. }
  75. /*
  76. * retrieve the contents of MN10300 userspace general registers
  77. */
  78. static int genregs_get(struct task_struct *target,
  79. const struct user_regset *regset,
  80. unsigned int pos, unsigned int count,
  81. void *kbuf, void __user *ubuf)
  82. {
  83. const struct pt_regs *regs = task_pt_regs(target);
  84. int ret;
  85. /* we need to skip regs->next */
  86. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  87. regs, 0, PT_ORIG_D0 * sizeof(long));
  88. if (ret < 0)
  89. return ret;
  90. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  91. &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
  92. NR_PTREGS * sizeof(long));
  93. if (ret < 0)
  94. return ret;
  95. return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  96. NR_PTREGS * sizeof(long), -1);
  97. }
  98. /*
  99. * update the contents of the MN10300 userspace general registers
  100. */
  101. static int genregs_set(struct task_struct *target,
  102. const struct user_regset *regset,
  103. unsigned int pos, unsigned int count,
  104. const void *kbuf, const void __user *ubuf)
  105. {
  106. struct pt_regs *regs = task_pt_regs(target);
  107. unsigned long tmp;
  108. int ret;
  109. /* we need to skip regs->next */
  110. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  111. regs, 0, PT_ORIG_D0 * sizeof(long));
  112. if (ret < 0)
  113. return ret;
  114. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  115. &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
  116. PT_EPSW * sizeof(long));
  117. if (ret < 0)
  118. return ret;
  119. /* we need to mask off changes to EPSW */
  120. tmp = regs->epsw;
  121. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  122. &tmp, PT_EPSW * sizeof(long),
  123. PT_PC * sizeof(long));
  124. tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z;
  125. tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N |
  126. EPSW_FLAG_Z);
  127. regs->epsw = tmp;
  128. if (ret < 0)
  129. return ret;
  130. /* and finally load the PC */
  131. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  132. &regs->pc, PT_PC * sizeof(long),
  133. NR_PTREGS * sizeof(long));
  134. if (ret < 0)
  135. return ret;
  136. return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  137. NR_PTREGS * sizeof(long), -1);
  138. }
  139. /*
  140. * retrieve the contents of MN10300 userspace FPU registers
  141. */
  142. static int fpuregs_get(struct task_struct *target,
  143. const struct user_regset *regset,
  144. unsigned int pos, unsigned int count,
  145. void *kbuf, void __user *ubuf)
  146. {
  147. const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
  148. int ret;
  149. unlazy_fpu(target);
  150. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  151. fpregs, 0, sizeof(*fpregs));
  152. if (ret < 0)
  153. return ret;
  154. return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  155. sizeof(*fpregs), -1);
  156. }
  157. /*
  158. * update the contents of the MN10300 userspace FPU registers
  159. */
  160. static int fpuregs_set(struct task_struct *target,
  161. const struct user_regset *regset,
  162. unsigned int pos, unsigned int count,
  163. const void *kbuf, const void __user *ubuf)
  164. {
  165. struct fpu_state_struct fpu_state = target->thread.fpu_state;
  166. int ret;
  167. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  168. &fpu_state, 0, sizeof(fpu_state));
  169. if (ret < 0)
  170. return ret;
  171. fpu_kill_state(target);
  172. target->thread.fpu_state = fpu_state;
  173. set_using_fpu(target);
  174. return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  175. sizeof(fpu_state), -1);
  176. }
  177. /*
  178. * determine if the FPU registers have actually been used
  179. */
  180. static int fpuregs_active(struct task_struct *target,
  181. const struct user_regset *regset)
  182. {
  183. return is_using_fpu(target) ? regset->n : 0;
  184. }
  185. /*
  186. * Define the register sets available on the MN10300 under Linux
  187. */
  188. enum mn10300_regset {
  189. REGSET_GENERAL,
  190. REGSET_FPU,
  191. };
  192. static const struct user_regset mn10300_regsets[] = {
  193. /*
  194. * General register format is:
  195. * A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
  196. * E1, E0, E7...E2, SP, LAR, LIR, MDR
  197. * A1, A0, D1, D0, ORIG_D0, EPSW, PC
  198. */
  199. [REGSET_GENERAL] = {
  200. .core_note_type = NT_PRSTATUS,
  201. .n = ELF_NGREG,
  202. .size = sizeof(long),
  203. .align = sizeof(long),
  204. .get = genregs_get,
  205. .set = genregs_set,
  206. },
  207. /*
  208. * FPU register format is:
  209. * FS0-31, FPCR
  210. */
  211. [REGSET_FPU] = {
  212. .core_note_type = NT_PRFPREG,
  213. .n = sizeof(struct fpu_state_struct) / sizeof(long),
  214. .size = sizeof(long),
  215. .align = sizeof(long),
  216. .get = fpuregs_get,
  217. .set = fpuregs_set,
  218. .active = fpuregs_active,
  219. },
  220. };
  221. static const struct user_regset_view user_mn10300_native_view = {
  222. .name = "mn10300",
  223. .e_machine = EM_MN10300,
  224. .regsets = mn10300_regsets,
  225. .n = ARRAY_SIZE(mn10300_regsets),
  226. };
  227. const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  228. {
  229. return &user_mn10300_native_view;
  230. }
  231. /*
  232. * set the single-step bit
  233. */
  234. void user_enable_single_step(struct task_struct *child)
  235. {
  236. #ifndef CONFIG_MN10300_USING_JTAG
  237. struct user *dummy = NULL;
  238. long tmp;
  239. tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
  240. tmp |= EPSW_T;
  241. put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
  242. #endif
  243. }
  244. /*
  245. * make sure the single-step bit is not set
  246. */
  247. void user_disable_single_step(struct task_struct *child)
  248. {
  249. #ifndef CONFIG_MN10300_USING_JTAG
  250. struct user *dummy = NULL;
  251. long tmp;
  252. tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
  253. tmp &= ~EPSW_T;
  254. put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
  255. #endif
  256. }
  257. void ptrace_disable(struct task_struct *child)
  258. {
  259. user_disable_single_step(child);
  260. }
  261. /*
  262. * handle the arch-specific side of process tracing
  263. */
  264. long arch_ptrace(struct task_struct *child, long request, long addr, long data)
  265. {
  266. unsigned long tmp;
  267. int ret;
  268. switch (request) {
  269. /* read the word at location addr in the USER area. */
  270. case PTRACE_PEEKUSR:
  271. ret = -EIO;
  272. if ((addr & 3) || addr < 0 ||
  273. addr > sizeof(struct user) - 3)
  274. break;
  275. tmp = 0; /* Default return condition */
  276. if (addr < NR_PTREGS << 2)
  277. tmp = get_stack_long(child,
  278. ptrace_regid_to_frame[addr]);
  279. ret = put_user(tmp, (unsigned long *) data);
  280. break;
  281. /* write the word at location addr in the USER area */
  282. case PTRACE_POKEUSR:
  283. ret = -EIO;
  284. if ((addr & 3) || addr < 0 ||
  285. addr > sizeof(struct user) - 3)
  286. break;
  287. ret = 0;
  288. if (addr < NR_PTREGS << 2)
  289. ret = put_stack_long(child, ptrace_regid_to_frame[addr],
  290. data);
  291. break;
  292. case PTRACE_GETREGS: /* Get all integer regs from the child. */
  293. return copy_regset_to_user(child, &user_mn10300_native_view,
  294. REGSET_GENERAL,
  295. 0, NR_PTREGS * sizeof(long),
  296. (void __user *)data);
  297. case PTRACE_SETREGS: /* Set all integer regs in the child. */
  298. return copy_regset_from_user(child, &user_mn10300_native_view,
  299. REGSET_GENERAL,
  300. 0, NR_PTREGS * sizeof(long),
  301. (const void __user *)data);
  302. case PTRACE_GETFPREGS: /* Get the child FPU state. */
  303. return copy_regset_to_user(child, &user_mn10300_native_view,
  304. REGSET_FPU,
  305. 0, sizeof(struct fpu_state_struct),
  306. (void __user *)data);
  307. case PTRACE_SETFPREGS: /* Set the child FPU state. */
  308. return copy_regset_from_user(child, &user_mn10300_native_view,
  309. REGSET_FPU,
  310. 0, sizeof(struct fpu_state_struct),
  311. (const void __user *)data);
  312. default:
  313. ret = ptrace_request(child, request, addr, data);
  314. break;
  315. }
  316. return ret;
  317. }
  318. /*
  319. * handle tracing of system call entry
  320. * - return the revised system call number or ULONG_MAX to cause ENOSYS
  321. */
  322. asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
  323. {
  324. if (tracehook_report_syscall_entry(regs))
  325. /* tracing decided this syscall should not happen, so
  326. * We'll return a bogus call number to get an ENOSYS
  327. * error, but leave the original number in
  328. * regs->orig_d0
  329. */
  330. return ULONG_MAX;
  331. return regs->orig_d0;
  332. }
  333. /*
  334. * handle tracing of system call exit
  335. */
  336. asmlinkage void syscall_trace_exit(struct pt_regs *regs)
  337. {
  338. tracehook_report_syscall_exit(regs, 0);
  339. }