ptrace_32.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* ptrace.c: Sparc process tracing support.
  3. *
  4. * Copyright (C) 1996, 2008 David S. Miller ([email protected])
  5. *
  6. * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
  7. * and David Mosberger.
  8. *
  9. * Added Linux support -miguel (weird, eh?, the original code was meant
  10. * to emulate SunOS).
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/sched.h>
  14. #include <linux/mm.h>
  15. #include <linux/errno.h>
  16. #include <linux/ptrace.h>
  17. #include <linux/user.h>
  18. #include <linux/smp.h>
  19. #include <linux/security.h>
  20. #include <linux/signal.h>
  21. #include <linux/regset.h>
  22. #include <linux/elf.h>
  23. #include <linux/uaccess.h>
  24. #include <asm/cacheflush.h>
  25. #include "kernel.h"
  26. /* #define ALLOW_INIT_TRACING */
  27. /*
  28. * Called by kernel/ptrace.c when detaching..
  29. *
  30. * Make sure single step bits etc are not set.
  31. */
  32. void ptrace_disable(struct task_struct *child)
  33. {
  34. /* nothing to do */
  35. }
  36. enum sparc_regset {
  37. REGSET_GENERAL,
  38. REGSET_FP,
  39. };
  40. static int regwindow32_get(struct task_struct *target,
  41. const struct pt_regs *regs,
  42. u32 *uregs)
  43. {
  44. unsigned long reg_window = regs->u_regs[UREG_I6];
  45. int size = 16 * sizeof(u32);
  46. if (target == current) {
  47. if (copy_from_user(uregs, (void __user *)reg_window, size))
  48. return -EFAULT;
  49. } else {
  50. if (access_process_vm(target, reg_window, uregs, size,
  51. FOLL_FORCE) != size)
  52. return -EFAULT;
  53. }
  54. return 0;
  55. }
  56. static int regwindow32_set(struct task_struct *target,
  57. const struct pt_regs *regs,
  58. u32 *uregs)
  59. {
  60. unsigned long reg_window = regs->u_regs[UREG_I6];
  61. int size = 16 * sizeof(u32);
  62. if (target == current) {
  63. if (copy_to_user((void __user *)reg_window, uregs, size))
  64. return -EFAULT;
  65. } else {
  66. if (access_process_vm(target, reg_window, uregs, size,
  67. FOLL_FORCE | FOLL_WRITE) != size)
  68. return -EFAULT;
  69. }
  70. return 0;
  71. }
  72. static int genregs32_get(struct task_struct *target,
  73. const struct user_regset *regset,
  74. struct membuf to)
  75. {
  76. const struct pt_regs *regs = target->thread.kregs;
  77. u32 uregs[16];
  78. if (target == current)
  79. flush_user_windows();
  80. membuf_write(&to, regs->u_regs, 16 * sizeof(u32));
  81. if (!to.left)
  82. return 0;
  83. if (regwindow32_get(target, regs, uregs))
  84. return -EFAULT;
  85. membuf_write(&to, uregs, 16 * sizeof(u32));
  86. membuf_store(&to, regs->psr);
  87. membuf_store(&to, regs->pc);
  88. membuf_store(&to, regs->npc);
  89. membuf_store(&to, regs->y);
  90. return membuf_zero(&to, 2 * sizeof(u32));
  91. }
  92. static int genregs32_set(struct task_struct *target,
  93. const struct user_regset *regset,
  94. unsigned int pos, unsigned int count,
  95. const void *kbuf, const void __user *ubuf)
  96. {
  97. struct pt_regs *regs = target->thread.kregs;
  98. u32 uregs[16];
  99. u32 psr;
  100. int ret;
  101. if (target == current)
  102. flush_user_windows();
  103. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  104. regs->u_regs,
  105. 0, 16 * sizeof(u32));
  106. if (ret || !count)
  107. return ret;
  108. if (regwindow32_get(target, regs, uregs))
  109. return -EFAULT;
  110. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  111. uregs,
  112. 16 * sizeof(u32), 32 * sizeof(u32));
  113. if (ret)
  114. return ret;
  115. if (regwindow32_set(target, regs, uregs))
  116. return -EFAULT;
  117. if (!count)
  118. return 0;
  119. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  120. &psr,
  121. 32 * sizeof(u32), 33 * sizeof(u32));
  122. if (ret)
  123. return ret;
  124. regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
  125. (psr & (PSR_ICC | PSR_SYSCALL));
  126. if (!count)
  127. return 0;
  128. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  129. &regs->pc,
  130. 33 * sizeof(u32), 34 * sizeof(u32));
  131. if (ret || !count)
  132. return ret;
  133. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  134. &regs->npc,
  135. 34 * sizeof(u32), 35 * sizeof(u32));
  136. if (ret || !count)
  137. return ret;
  138. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  139. &regs->y,
  140. 35 * sizeof(u32), 36 * sizeof(u32));
  141. if (ret || !count)
  142. return ret;
  143. return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  144. 36 * sizeof(u32), 38 * sizeof(u32));
  145. }
  146. static int fpregs32_get(struct task_struct *target,
  147. const struct user_regset *regset,
  148. struct membuf to)
  149. {
  150. #if 0
  151. if (target == current)
  152. save_and_clear_fpu();
  153. #endif
  154. membuf_write(&to, target->thread.float_regs, 32 * sizeof(u32));
  155. membuf_zero(&to, sizeof(u32));
  156. membuf_write(&to, &target->thread.fsr, sizeof(u32));
  157. membuf_store(&to, (u32)((1 << 8) | (8 << 16)));
  158. return membuf_zero(&to, 64 * sizeof(u32));
  159. }
  160. static int fpregs32_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. unsigned long *fpregs = target->thread.float_regs;
  166. int ret;
  167. #if 0
  168. if (target == current)
  169. save_and_clear_fpu();
  170. #endif
  171. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  172. fpregs,
  173. 0, 32 * sizeof(u32));
  174. if (!ret)
  175. user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  176. 32 * sizeof(u32),
  177. 33 * sizeof(u32));
  178. if (!ret)
  179. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  180. &target->thread.fsr,
  181. 33 * sizeof(u32),
  182. 34 * sizeof(u32));
  183. if (!ret)
  184. ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  185. 34 * sizeof(u32), -1);
  186. return ret;
  187. }
  188. static const struct user_regset sparc32_regsets[] = {
  189. /* Format is:
  190. * G0 --> G7
  191. * O0 --> O7
  192. * L0 --> L7
  193. * I0 --> I7
  194. * PSR, PC, nPC, Y, WIM, TBR
  195. */
  196. [REGSET_GENERAL] = {
  197. .core_note_type = NT_PRSTATUS,
  198. .n = 38,
  199. .size = sizeof(u32), .align = sizeof(u32),
  200. .regset_get = genregs32_get, .set = genregs32_set
  201. },
  202. /* Format is:
  203. * F0 --> F31
  204. * empty 32-bit word
  205. * FSR (32--bit word)
  206. * FPU QUEUE COUNT (8-bit char)
  207. * FPU QUEUE ENTRYSIZE (8-bit char)
  208. * FPU ENABLED (8-bit char)
  209. * empty 8-bit char
  210. * FPU QUEUE (64 32-bit ints)
  211. */
  212. [REGSET_FP] = {
  213. .core_note_type = NT_PRFPREG,
  214. .n = 99,
  215. .size = sizeof(u32), .align = sizeof(u32),
  216. .regset_get = fpregs32_get, .set = fpregs32_set
  217. },
  218. };
  219. static int getregs_get(struct task_struct *target,
  220. const struct user_regset *regset,
  221. struct membuf to)
  222. {
  223. const struct pt_regs *regs = target->thread.kregs;
  224. if (target == current)
  225. flush_user_windows();
  226. membuf_store(&to, regs->psr);
  227. membuf_store(&to, regs->pc);
  228. membuf_store(&to, regs->npc);
  229. membuf_store(&to, regs->y);
  230. return membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u32));
  231. }
  232. static int setregs_set(struct task_struct *target,
  233. const struct user_regset *regset,
  234. unsigned int pos, unsigned int count,
  235. const void *kbuf, const void __user *ubuf)
  236. {
  237. struct pt_regs *regs = target->thread.kregs;
  238. u32 v[4];
  239. int ret;
  240. if (target == current)
  241. flush_user_windows();
  242. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  243. v,
  244. 0, 4 * sizeof(u32));
  245. if (ret)
  246. return ret;
  247. regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
  248. (v[0] & (PSR_ICC | PSR_SYSCALL));
  249. regs->pc = v[1];
  250. regs->npc = v[2];
  251. regs->y = v[3];
  252. return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  253. regs->u_regs + 1,
  254. 4 * sizeof(u32) , 19 * sizeof(u32));
  255. }
  256. static int getfpregs_get(struct task_struct *target,
  257. const struct user_regset *regset,
  258. struct membuf to)
  259. {
  260. #if 0
  261. if (target == current)
  262. save_and_clear_fpu();
  263. #endif
  264. membuf_write(&to, &target->thread.float_regs, 32 * sizeof(u32));
  265. membuf_write(&to, &target->thread.fsr, sizeof(u32));
  266. return membuf_zero(&to, 35 * sizeof(u32));
  267. }
  268. static int setfpregs_set(struct task_struct *target,
  269. const struct user_regset *regset,
  270. unsigned int pos, unsigned int count,
  271. const void *kbuf, const void __user *ubuf)
  272. {
  273. unsigned long *fpregs = target->thread.float_regs;
  274. int ret;
  275. #if 0
  276. if (target == current)
  277. save_and_clear_fpu();
  278. #endif
  279. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  280. fpregs,
  281. 0, 32 * sizeof(u32));
  282. if (ret)
  283. return ret;
  284. return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  285. &target->thread.fsr,
  286. 32 * sizeof(u32),
  287. 33 * sizeof(u32));
  288. }
  289. static const struct user_regset ptrace32_regsets[] = {
  290. [REGSET_GENERAL] = {
  291. .n = 19, .size = sizeof(u32),
  292. .regset_get = getregs_get, .set = setregs_set,
  293. },
  294. [REGSET_FP] = {
  295. .n = 68, .size = sizeof(u32),
  296. .regset_get = getfpregs_get, .set = setfpregs_set,
  297. },
  298. };
  299. static const struct user_regset_view ptrace32_view = {
  300. .regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
  301. };
  302. static const struct user_regset_view user_sparc32_view = {
  303. .name = "sparc", .e_machine = EM_SPARC,
  304. .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
  305. };
  306. const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  307. {
  308. return &user_sparc32_view;
  309. }
  310. struct fps {
  311. unsigned long regs[32];
  312. unsigned long fsr;
  313. unsigned long flags;
  314. unsigned long extra;
  315. unsigned long fpqd;
  316. struct fq {
  317. unsigned long *insnaddr;
  318. unsigned long insn;
  319. } fpq[16];
  320. };
  321. long arch_ptrace(struct task_struct *child, long request,
  322. unsigned long addr, unsigned long data)
  323. {
  324. unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
  325. void __user *addr2p;
  326. struct pt_regs __user *pregs;
  327. struct fps __user *fps;
  328. int ret;
  329. addr2p = (void __user *) addr2;
  330. pregs = (struct pt_regs __user *) addr;
  331. fps = (struct fps __user *) addr;
  332. switch(request) {
  333. case PTRACE_GETREGS: {
  334. ret = copy_regset_to_user(child, &ptrace32_view,
  335. REGSET_GENERAL, 0,
  336. 19 * sizeof(u32),
  337. pregs);
  338. break;
  339. }
  340. case PTRACE_SETREGS: {
  341. ret = copy_regset_from_user(child, &ptrace32_view,
  342. REGSET_GENERAL, 0,
  343. 19 * sizeof(u32),
  344. pregs);
  345. break;
  346. }
  347. case PTRACE_GETFPREGS: {
  348. ret = copy_regset_to_user(child, &ptrace32_view,
  349. REGSET_FP, 0,
  350. 68 * sizeof(u32),
  351. fps);
  352. break;
  353. }
  354. case PTRACE_SETFPREGS: {
  355. ret = copy_regset_from_user(child, &ptrace32_view,
  356. REGSET_FP, 0,
  357. 33 * sizeof(u32),
  358. fps);
  359. break;
  360. }
  361. case PTRACE_READTEXT:
  362. case PTRACE_READDATA:
  363. ret = ptrace_readdata(child, addr, addr2p, data);
  364. if (ret == data)
  365. ret = 0;
  366. else if (ret >= 0)
  367. ret = -EIO;
  368. break;
  369. case PTRACE_WRITETEXT:
  370. case PTRACE_WRITEDATA:
  371. ret = ptrace_writedata(child, addr2p, addr, data);
  372. if (ret == data)
  373. ret = 0;
  374. else if (ret >= 0)
  375. ret = -EIO;
  376. break;
  377. default:
  378. if (request == PTRACE_SPARC_DETACH)
  379. request = PTRACE_DETACH;
  380. ret = ptrace_request(child, request, addr, data);
  381. break;
  382. }
  383. return ret;
  384. }
  385. asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
  386. {
  387. int ret = 0;
  388. if (test_thread_flag(TIF_SYSCALL_TRACE)) {
  389. if (syscall_exit_p)
  390. ptrace_report_syscall_exit(regs, 0);
  391. else
  392. ret = ptrace_report_syscall_entry(regs);
  393. }
  394. return ret;
  395. }