ptrace.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. /* ptrace.c: Sparc process tracing support.
  2. *
  3. * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
  4. *
  5. * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
  6. * and David Mosberger.
  7. *
  8. * Added Linux support -miguel (weird, eh?, the original code was meant
  9. * to emulate SunOS).
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/sched.h>
  13. #include <linux/mm.h>
  14. #include <linux/errno.h>
  15. #include <linux/ptrace.h>
  16. #include <linux/user.h>
  17. #include <linux/smp.h>
  18. #include <linux/smp_lock.h>
  19. #include <linux/security.h>
  20. #include <linux/signal.h>
  21. #include <linux/regset.h>
  22. #include <linux/elf.h>
  23. #include <asm/pgtable.h>
  24. #include <asm/system.h>
  25. #include <asm/uaccess.h>
  26. #define MAGIC_CONSTANT 0x80000000
  27. /* Returning from ptrace is a bit tricky because the syscall return
  28. * low level code assumes any value returned which is negative and
  29. * is a valid errno will mean setting the condition codes to indicate
  30. * an error return. This doesn't work, so we have this hook.
  31. */
  32. static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
  33. {
  34. regs->u_regs[UREG_I0] = error;
  35. regs->psr |= PSR_C;
  36. regs->pc = regs->npc;
  37. regs->npc += 4;
  38. }
  39. static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
  40. {
  41. regs->u_regs[UREG_I0] = value;
  42. regs->psr &= ~PSR_C;
  43. regs->pc = regs->npc;
  44. regs->npc += 4;
  45. }
  46. static void
  47. pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr)
  48. {
  49. if (put_user(value, addr)) {
  50. pt_error_return(regs, EFAULT);
  51. return;
  52. }
  53. regs->u_regs[UREG_I0] = 0;
  54. regs->psr &= ~PSR_C;
  55. regs->pc = regs->npc;
  56. regs->npc += 4;
  57. }
  58. static void
  59. pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr)
  60. {
  61. if (current->personality == PER_SUNOS)
  62. pt_succ_return (regs, val);
  63. else
  64. pt_succ_return_linux (regs, val, addr);
  65. }
  66. /* Fuck me gently with a chainsaw... */
  67. static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
  68. struct task_struct *tsk, long __user *addr)
  69. {
  70. struct pt_regs *cregs = tsk->thread.kregs;
  71. struct thread_info *t = task_thread_info(tsk);
  72. int v;
  73. if(offset >= 1024)
  74. offset -= 1024; /* whee... */
  75. if(offset & ((sizeof(unsigned long) - 1))) {
  76. pt_error_return(regs, EIO);
  77. return;
  78. }
  79. if(offset >= 16 && offset < 784) {
  80. offset -= 16; offset >>= 2;
  81. pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
  82. return;
  83. }
  84. if(offset >= 784 && offset < 832) {
  85. offset -= 784; offset >>= 2;
  86. pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
  87. return;
  88. }
  89. switch(offset) {
  90. case 0:
  91. v = t->ksp;
  92. break;
  93. case 4:
  94. v = t->kpc;
  95. break;
  96. case 8:
  97. v = t->kpsr;
  98. break;
  99. case 12:
  100. v = t->uwinmask;
  101. break;
  102. case 832:
  103. v = t->w_saved;
  104. break;
  105. case 896:
  106. v = cregs->u_regs[UREG_I0];
  107. break;
  108. case 900:
  109. v = cregs->u_regs[UREG_I1];
  110. break;
  111. case 904:
  112. v = cregs->u_regs[UREG_I2];
  113. break;
  114. case 908:
  115. v = cregs->u_regs[UREG_I3];
  116. break;
  117. case 912:
  118. v = cregs->u_regs[UREG_I4];
  119. break;
  120. case 916:
  121. v = cregs->u_regs[UREG_I5];
  122. break;
  123. case 920:
  124. v = cregs->u_regs[UREG_I6];
  125. break;
  126. case 924:
  127. if(tsk->thread.flags & MAGIC_CONSTANT)
  128. v = cregs->u_regs[UREG_G1];
  129. else
  130. v = 0;
  131. break;
  132. case 940:
  133. v = cregs->u_regs[UREG_I0];
  134. break;
  135. case 944:
  136. v = cregs->u_regs[UREG_I1];
  137. break;
  138. case 948:
  139. /* Isn't binary compatibility _fun_??? */
  140. if(cregs->psr & PSR_C)
  141. v = cregs->u_regs[UREG_I0] << 24;
  142. else
  143. v = 0;
  144. break;
  145. /* Rest of them are completely unsupported. */
  146. default:
  147. printk("%s [%d]: Wants to read user offset %ld\n",
  148. current->comm, task_pid_nr(current), offset);
  149. pt_error_return(regs, EIO);
  150. return;
  151. }
  152. if (current->personality == PER_SUNOS)
  153. pt_succ_return (regs, v);
  154. else
  155. pt_succ_return_linux (regs, v, addr);
  156. return;
  157. }
  158. static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
  159. struct task_struct *tsk)
  160. {
  161. struct pt_regs *cregs = tsk->thread.kregs;
  162. struct thread_info *t = task_thread_info(tsk);
  163. unsigned long value = regs->u_regs[UREG_I3];
  164. if(offset >= 1024)
  165. offset -= 1024; /* whee... */
  166. if(offset & ((sizeof(unsigned long) - 1)))
  167. goto failure;
  168. if(offset >= 16 && offset < 784) {
  169. offset -= 16; offset >>= 2;
  170. *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
  171. goto success;
  172. }
  173. if(offset >= 784 && offset < 832) {
  174. offset -= 784; offset >>= 2;
  175. *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
  176. goto success;
  177. }
  178. switch(offset) {
  179. case 896:
  180. cregs->u_regs[UREG_I0] = value;
  181. break;
  182. case 900:
  183. cregs->u_regs[UREG_I1] = value;
  184. break;
  185. case 904:
  186. cregs->u_regs[UREG_I2] = value;
  187. break;
  188. case 908:
  189. cregs->u_regs[UREG_I3] = value;
  190. break;
  191. case 912:
  192. cregs->u_regs[UREG_I4] = value;
  193. break;
  194. case 916:
  195. cregs->u_regs[UREG_I5] = value;
  196. break;
  197. case 920:
  198. cregs->u_regs[UREG_I6] = value;
  199. break;
  200. case 924:
  201. cregs->u_regs[UREG_I7] = value;
  202. break;
  203. case 940:
  204. cregs->u_regs[UREG_I0] = value;
  205. break;
  206. case 944:
  207. cregs->u_regs[UREG_I1] = value;
  208. break;
  209. /* Rest of them are completely unsupported or "no-touch". */
  210. default:
  211. printk("%s [%d]: Wants to write user offset %ld\n",
  212. current->comm, task_pid_nr(current), offset);
  213. goto failure;
  214. }
  215. success:
  216. pt_succ_return(regs, 0);
  217. return;
  218. failure:
  219. pt_error_return(regs, EIO);
  220. return;
  221. }
  222. /* #define ALLOW_INIT_TRACING */
  223. /*
  224. * Called by kernel/ptrace.c when detaching..
  225. *
  226. * Make sure single step bits etc are not set.
  227. */
  228. void ptrace_disable(struct task_struct *child)
  229. {
  230. /* nothing to do */
  231. }
  232. enum sparc_regset {
  233. REGSET_GENERAL,
  234. REGSET_FP,
  235. };
  236. static int genregs32_get(struct task_struct *target,
  237. const struct user_regset *regset,
  238. unsigned int pos, unsigned int count,
  239. void *kbuf, void __user *ubuf)
  240. {
  241. const struct pt_regs *regs = target->thread.kregs;
  242. unsigned long __user *reg_window;
  243. unsigned long *k = kbuf;
  244. unsigned long __user *u = ubuf;
  245. unsigned long reg;
  246. if (target == current)
  247. flush_user_windows();
  248. pos /= sizeof(reg);
  249. count /= sizeof(reg);
  250. if (kbuf) {
  251. for (; count > 0 && pos < 16; count--)
  252. *k++ = regs->u_regs[pos++];
  253. reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
  254. for (; count > 0 && pos < 32; count--) {
  255. if (get_user(*k++, &reg_window[pos++]))
  256. return -EFAULT;
  257. }
  258. } else {
  259. for (; count > 0 && pos < 16; count--) {
  260. if (put_user(regs->u_regs[pos++], u++))
  261. return -EFAULT;
  262. }
  263. reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
  264. for (; count > 0 && pos < 32; count--) {
  265. if (get_user(reg, &reg_window[pos++]) ||
  266. put_user(reg, u++))
  267. return -EFAULT;
  268. }
  269. }
  270. while (count > 0) {
  271. switch (pos) {
  272. case 32: /* PSR */
  273. reg = regs->psr;
  274. break;
  275. case 33: /* PC */
  276. reg = regs->pc;
  277. break;
  278. case 34: /* NPC */
  279. reg = regs->npc;
  280. break;
  281. case 35: /* Y */
  282. reg = regs->y;
  283. break;
  284. case 36: /* WIM */
  285. case 37: /* TBR */
  286. reg = 0;
  287. break;
  288. default:
  289. goto finish;
  290. }
  291. if (kbuf)
  292. *k++ = reg;
  293. else if (put_user(reg, u++))
  294. return -EFAULT;
  295. pos++;
  296. count--;
  297. }
  298. finish:
  299. pos *= sizeof(reg);
  300. count *= sizeof(reg);
  301. return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  302. 38 * sizeof(reg), -1);
  303. }
  304. static int genregs32_set(struct task_struct *target,
  305. const struct user_regset *regset,
  306. unsigned int pos, unsigned int count,
  307. const void *kbuf, const void __user *ubuf)
  308. {
  309. struct pt_regs *regs = target->thread.kregs;
  310. unsigned long __user *reg_window;
  311. const unsigned long *k = kbuf;
  312. const unsigned long __user *u = ubuf;
  313. unsigned long reg;
  314. if (target == current)
  315. flush_user_windows();
  316. pos /= sizeof(reg);
  317. count /= sizeof(reg);
  318. if (kbuf) {
  319. for (; count > 0 && pos < 16; count--)
  320. regs->u_regs[pos++] = *k++;
  321. reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
  322. for (; count > 0 && pos < 32; count--) {
  323. if (put_user(*k++, &reg_window[pos++]))
  324. return -EFAULT;
  325. }
  326. } else {
  327. for (; count > 0 && pos < 16; count--) {
  328. if (get_user(reg, u++))
  329. return -EFAULT;
  330. regs->u_regs[pos++] = reg;
  331. }
  332. reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
  333. for (; count > 0 && pos < 32; count--) {
  334. if (get_user(reg, u++) ||
  335. put_user(reg, &reg_window[pos++]))
  336. return -EFAULT;
  337. }
  338. }
  339. while (count > 0) {
  340. unsigned long psr;
  341. if (kbuf)
  342. reg = *k++;
  343. else if (get_user(reg, u++))
  344. return -EFAULT;
  345. switch (pos) {
  346. case 32: /* PSR */
  347. psr = regs->psr;
  348. psr &= ~PSR_ICC;
  349. psr |= (reg & PSR_ICC);
  350. regs->psr = psr;
  351. break;
  352. case 33: /* PC */
  353. regs->pc = reg;
  354. break;
  355. case 34: /* NPC */
  356. regs->npc = reg;
  357. break;
  358. case 35: /* Y */
  359. regs->y = reg;
  360. break;
  361. case 36: /* WIM */
  362. case 37: /* TBR */
  363. break;
  364. default:
  365. goto finish;
  366. }
  367. pos++;
  368. count--;
  369. }
  370. finish:
  371. pos *= sizeof(reg);
  372. count *= sizeof(reg);
  373. return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  374. 38 * sizeof(reg), -1);
  375. }
  376. static int fpregs32_get(struct task_struct *target,
  377. const struct user_regset *regset,
  378. unsigned int pos, unsigned int count,
  379. void *kbuf, void __user *ubuf)
  380. {
  381. const unsigned long *fpregs = target->thread.float_regs;
  382. int ret = 0;
  383. #if 0
  384. if (target == current)
  385. save_and_clear_fpu();
  386. #endif
  387. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  388. fpregs,
  389. 0, 32 * sizeof(u32));
  390. if (!ret)
  391. ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  392. 32 * sizeof(u32),
  393. 33 * sizeof(u32));
  394. if (!ret)
  395. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  396. &target->thread.fsr,
  397. 33 * sizeof(u32),
  398. 34 * sizeof(u32));
  399. if (!ret) {
  400. unsigned long val;
  401. val = (1 << 8) | (8 << 16);
  402. ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  403. &val,
  404. 34 * sizeof(u32),
  405. 35 * sizeof(u32));
  406. }
  407. if (!ret)
  408. ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  409. 35 * sizeof(u32), -1);
  410. return ret;
  411. }
  412. static int fpregs32_set(struct task_struct *target,
  413. const struct user_regset *regset,
  414. unsigned int pos, unsigned int count,
  415. const void *kbuf, const void __user *ubuf)
  416. {
  417. unsigned long *fpregs = target->thread.float_regs;
  418. int ret;
  419. #if 0
  420. if (target == current)
  421. save_and_clear_fpu();
  422. #endif
  423. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  424. fpregs,
  425. 0, 32 * sizeof(u32));
  426. if (!ret)
  427. user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  428. 32 * sizeof(u32),
  429. 33 * sizeof(u32));
  430. if (!ret && count > 0) {
  431. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  432. &target->thread.fsr,
  433. 33 * sizeof(u32),
  434. 34 * sizeof(u32));
  435. }
  436. if (!ret)
  437. ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  438. 34 * sizeof(u32), -1);
  439. return ret;
  440. }
  441. static const struct user_regset sparc32_regsets[] = {
  442. /* Format is:
  443. * G0 --> G7
  444. * O0 --> O7
  445. * L0 --> L7
  446. * I0 --> I7
  447. * PSR, PC, nPC, Y, WIM, TBR
  448. */
  449. [REGSET_GENERAL] = {
  450. .core_note_type = NT_PRSTATUS,
  451. .n = 38 * sizeof(u32),
  452. .size = sizeof(u32), .align = sizeof(u32),
  453. .get = genregs32_get, .set = genregs32_set
  454. },
  455. /* Format is:
  456. * F0 --> F31
  457. * empty 32-bit word
  458. * FSR (32--bit word)
  459. * FPU QUEUE COUNT (8-bit char)
  460. * FPU QUEUE ENTRYSIZE (8-bit char)
  461. * FPU ENABLED (8-bit char)
  462. * empty 8-bit char
  463. * FPU QUEUE (64 32-bit ints)
  464. */
  465. [REGSET_FP] = {
  466. .core_note_type = NT_PRFPREG,
  467. .n = 99 * sizeof(u32),
  468. .size = sizeof(u32), .align = sizeof(u32),
  469. .get = fpregs32_get, .set = fpregs32_set
  470. },
  471. };
  472. static const struct user_regset_view user_sparc32_view = {
  473. .name = "sparc", .e_machine = EM_SPARC,
  474. .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
  475. };
  476. const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  477. {
  478. return &user_sparc32_view;
  479. }
  480. asmlinkage void do_ptrace(struct pt_regs *regs)
  481. {
  482. unsigned long request = regs->u_regs[UREG_I0];
  483. unsigned long pid = regs->u_regs[UREG_I1];
  484. unsigned long addr = regs->u_regs[UREG_I2];
  485. unsigned long data = regs->u_regs[UREG_I3];
  486. unsigned long addr2 = regs->u_regs[UREG_I4];
  487. struct task_struct *child;
  488. int ret;
  489. lock_kernel();
  490. if (request == PTRACE_TRACEME) {
  491. ret = ptrace_traceme();
  492. if (ret < 0)
  493. pt_error_return(regs, -ret);
  494. else
  495. pt_succ_return(regs, 0);
  496. goto out;
  497. }
  498. child = ptrace_get_task_struct(pid);
  499. if (IS_ERR(child)) {
  500. ret = PTR_ERR(child);
  501. pt_error_return(regs, -ret);
  502. goto out;
  503. }
  504. if (request == PTRACE_ATTACH) {
  505. if (ptrace_attach(child)) {
  506. pt_error_return(regs, EPERM);
  507. goto out_tsk;
  508. }
  509. pt_succ_return(regs, 0);
  510. goto out_tsk;
  511. }
  512. ret = ptrace_check_attach(child, request == PTRACE_KILL);
  513. if (ret < 0) {
  514. pt_error_return(regs, -ret);
  515. goto out_tsk;
  516. }
  517. switch(request) {
  518. case PTRACE_PEEKTEXT: /* read word at location addr. */
  519. case PTRACE_PEEKDATA: {
  520. unsigned long tmp;
  521. if (access_process_vm(child, addr,
  522. &tmp, sizeof(tmp), 0) == sizeof(tmp))
  523. pt_os_succ_return(regs, tmp, (long __user *)data);
  524. else
  525. pt_error_return(regs, EIO);
  526. goto out_tsk;
  527. }
  528. case PTRACE_PEEKUSR:
  529. read_sunos_user(regs, addr, child, (long __user *) data);
  530. goto out_tsk;
  531. case PTRACE_POKEUSR:
  532. write_sunos_user(regs, addr, child);
  533. goto out_tsk;
  534. case PTRACE_POKETEXT: /* write the word at location addr. */
  535. case PTRACE_POKEDATA: {
  536. if (access_process_vm(child, addr,
  537. &data, sizeof(data), 1) == sizeof(data))
  538. pt_succ_return(regs, 0);
  539. else
  540. pt_error_return(regs, EIO);
  541. goto out_tsk;
  542. }
  543. case PTRACE_GETREGS: {
  544. struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
  545. struct pt_regs *cregs = child->thread.kregs;
  546. int rval;
  547. if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
  548. rval = -EFAULT;
  549. pt_error_return(regs, -rval);
  550. goto out_tsk;
  551. }
  552. __put_user(cregs->psr, (&pregs->psr));
  553. __put_user(cregs->pc, (&pregs->pc));
  554. __put_user(cregs->npc, (&pregs->npc));
  555. __put_user(cregs->y, (&pregs->y));
  556. for(rval = 1; rval < 16; rval++)
  557. __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
  558. pt_succ_return(regs, 0);
  559. goto out_tsk;
  560. }
  561. case PTRACE_SETREGS: {
  562. struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
  563. struct pt_regs *cregs = child->thread.kregs;
  564. unsigned long psr, pc, npc, y;
  565. int i;
  566. /* Must be careful, tracing process can only set certain
  567. * bits in the psr.
  568. */
  569. if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
  570. pt_error_return(regs, EFAULT);
  571. goto out_tsk;
  572. }
  573. __get_user(psr, (&pregs->psr));
  574. __get_user(pc, (&pregs->pc));
  575. __get_user(npc, (&pregs->npc));
  576. __get_user(y, (&pregs->y));
  577. psr &= PSR_ICC;
  578. cregs->psr &= ~PSR_ICC;
  579. cregs->psr |= psr;
  580. if (!((pc | npc) & 3)) {
  581. cregs->pc = pc;
  582. cregs->npc =npc;
  583. }
  584. cregs->y = y;
  585. for(i = 1; i < 16; i++)
  586. __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
  587. pt_succ_return(regs, 0);
  588. goto out_tsk;
  589. }
  590. case PTRACE_GETFPREGS: {
  591. struct fps {
  592. unsigned long regs[32];
  593. unsigned long fsr;
  594. unsigned long flags;
  595. unsigned long extra;
  596. unsigned long fpqd;
  597. struct fq {
  598. unsigned long *insnaddr;
  599. unsigned long insn;
  600. } fpq[16];
  601. };
  602. struct fps __user *fps = (struct fps __user *) addr;
  603. int i;
  604. if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
  605. i = -EFAULT;
  606. pt_error_return(regs, -i);
  607. goto out_tsk;
  608. }
  609. for(i = 0; i < 32; i++)
  610. __put_user(child->thread.float_regs[i], (&fps->regs[i]));
  611. __put_user(child->thread.fsr, (&fps->fsr));
  612. __put_user(child->thread.fpqdepth, (&fps->fpqd));
  613. __put_user(0, (&fps->flags));
  614. __put_user(0, (&fps->extra));
  615. for(i = 0; i < 16; i++) {
  616. __put_user(child->thread.fpqueue[i].insn_addr,
  617. (&fps->fpq[i].insnaddr));
  618. __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
  619. }
  620. pt_succ_return(regs, 0);
  621. goto out_tsk;
  622. }
  623. case PTRACE_SETFPREGS: {
  624. struct fps {
  625. unsigned long regs[32];
  626. unsigned long fsr;
  627. unsigned long flags;
  628. unsigned long extra;
  629. unsigned long fpqd;
  630. struct fq {
  631. unsigned long *insnaddr;
  632. unsigned long insn;
  633. } fpq[16];
  634. };
  635. struct fps __user *fps = (struct fps __user *) addr;
  636. int i;
  637. if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
  638. i = -EFAULT;
  639. pt_error_return(regs, -i);
  640. goto out_tsk;
  641. }
  642. copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
  643. __get_user(child->thread.fsr, (&fps->fsr));
  644. __get_user(child->thread.fpqdepth, (&fps->fpqd));
  645. for(i = 0; i < 16; i++) {
  646. __get_user(child->thread.fpqueue[i].insn_addr,
  647. (&fps->fpq[i].insnaddr));
  648. __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
  649. }
  650. pt_succ_return(regs, 0);
  651. goto out_tsk;
  652. }
  653. case PTRACE_READTEXT:
  654. case PTRACE_READDATA: {
  655. int res = ptrace_readdata(child, addr,
  656. (void __user *) addr2, data);
  657. if (res == data) {
  658. pt_succ_return(regs, 0);
  659. goto out_tsk;
  660. }
  661. /* Partial read is an IO failure */
  662. if (res >= 0)
  663. res = -EIO;
  664. pt_error_return(regs, -res);
  665. goto out_tsk;
  666. }
  667. case PTRACE_WRITETEXT:
  668. case PTRACE_WRITEDATA: {
  669. int res = ptrace_writedata(child, (void __user *) addr2,
  670. addr, data);
  671. if (res == data) {
  672. pt_succ_return(regs, 0);
  673. goto out_tsk;
  674. }
  675. /* Partial write is an IO failure */
  676. if (res >= 0)
  677. res = -EIO;
  678. pt_error_return(regs, -res);
  679. goto out_tsk;
  680. }
  681. case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
  682. addr = 1;
  683. case PTRACE_CONT: { /* restart after signal. */
  684. if (!valid_signal(data)) {
  685. pt_error_return(regs, EIO);
  686. goto out_tsk;
  687. }
  688. if (request == PTRACE_SYSCALL)
  689. set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  690. else
  691. clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  692. child->exit_code = data;
  693. wake_up_process(child);
  694. pt_succ_return(regs, 0);
  695. goto out_tsk;
  696. }
  697. /*
  698. * make the child exit. Best I can do is send it a sigkill.
  699. * perhaps it should be put in the status that it wants to
  700. * exit.
  701. */
  702. case PTRACE_KILL: {
  703. if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
  704. pt_succ_return(regs, 0);
  705. goto out_tsk;
  706. }
  707. wake_up_process(child);
  708. child->exit_code = SIGKILL;
  709. pt_succ_return(regs, 0);
  710. goto out_tsk;
  711. }
  712. default: {
  713. int err = ptrace_request(child, request, addr, data);
  714. if (err)
  715. pt_error_return(regs, -err);
  716. else
  717. pt_succ_return(regs, 0);
  718. goto out_tsk;
  719. }
  720. }
  721. out_tsk:
  722. if (child)
  723. put_task_struct(child);
  724. out:
  725. unlock_kernel();
  726. }
  727. asmlinkage void syscall_trace(void)
  728. {
  729. if (!test_thread_flag(TIF_SYSCALL_TRACE))
  730. return;
  731. if (!(current->ptrace & PT_PTRACED))
  732. return;
  733. current->thread.flags ^= MAGIC_CONSTANT;
  734. ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
  735. ? 0x80 : 0));
  736. /*
  737. * this isn't the same as continuing with a signal, but it will do
  738. * for normal use. strace only continues with a signal if the
  739. * stopping signal is not SIGTRAP. -brl
  740. */
  741. if (current->exit_code) {
  742. send_sig (current->exit_code, current, 1);
  743. current->exit_code = 0;
  744. }
  745. }