ptrace.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /* ptrace.c: Sparc process tracing support.
  2. *
  3. * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
  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 orignal 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 <asm/pgtable.h>
  22. #include <asm/system.h>
  23. #include <asm/uaccess.h>
  24. #define MAGIC_CONSTANT 0x80000000
  25. /* Returning from ptrace is a bit tricky because the syscall return
  26. * low level code assumes any value returned which is negative and
  27. * is a valid errno will mean setting the condition codes to indicate
  28. * an error return. This doesn't work, so we have this hook.
  29. */
  30. static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
  31. {
  32. regs->u_regs[UREG_I0] = error;
  33. regs->psr |= PSR_C;
  34. regs->pc = regs->npc;
  35. regs->npc += 4;
  36. }
  37. static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
  38. {
  39. regs->u_regs[UREG_I0] = value;
  40. regs->psr &= ~PSR_C;
  41. regs->pc = regs->npc;
  42. regs->npc += 4;
  43. }
  44. static void
  45. pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr)
  46. {
  47. if (put_user(value, addr)) {
  48. pt_error_return(regs, EFAULT);
  49. return;
  50. }
  51. regs->u_regs[UREG_I0] = 0;
  52. regs->psr &= ~PSR_C;
  53. regs->pc = regs->npc;
  54. regs->npc += 4;
  55. }
  56. static void
  57. pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr)
  58. {
  59. if (current->personality == PER_SUNOS)
  60. pt_succ_return (regs, val);
  61. else
  62. pt_succ_return_linux (regs, val, addr);
  63. }
  64. /* Fuck me gently with a chainsaw... */
  65. static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
  66. struct task_struct *tsk, long __user *addr)
  67. {
  68. struct pt_regs *cregs = tsk->thread.kregs;
  69. struct thread_info *t = task_thread_info(tsk);
  70. int v;
  71. if(offset >= 1024)
  72. offset -= 1024; /* whee... */
  73. if(offset & ((sizeof(unsigned long) - 1))) {
  74. pt_error_return(regs, EIO);
  75. return;
  76. }
  77. if(offset >= 16 && offset < 784) {
  78. offset -= 16; offset >>= 2;
  79. pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
  80. return;
  81. }
  82. if(offset >= 784 && offset < 832) {
  83. offset -= 784; offset >>= 2;
  84. pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
  85. return;
  86. }
  87. switch(offset) {
  88. case 0:
  89. v = t->ksp;
  90. break;
  91. case 4:
  92. v = t->kpc;
  93. break;
  94. case 8:
  95. v = t->kpsr;
  96. break;
  97. case 12:
  98. v = t->uwinmask;
  99. break;
  100. case 832:
  101. v = t->w_saved;
  102. break;
  103. case 896:
  104. v = cregs->u_regs[UREG_I0];
  105. break;
  106. case 900:
  107. v = cregs->u_regs[UREG_I1];
  108. break;
  109. case 904:
  110. v = cregs->u_regs[UREG_I2];
  111. break;
  112. case 908:
  113. v = cregs->u_regs[UREG_I3];
  114. break;
  115. case 912:
  116. v = cregs->u_regs[UREG_I4];
  117. break;
  118. case 916:
  119. v = cregs->u_regs[UREG_I5];
  120. break;
  121. case 920:
  122. v = cregs->u_regs[UREG_I6];
  123. break;
  124. case 924:
  125. if(tsk->thread.flags & MAGIC_CONSTANT)
  126. v = cregs->u_regs[UREG_G1];
  127. else
  128. v = 0;
  129. break;
  130. case 940:
  131. v = cregs->u_regs[UREG_I0];
  132. break;
  133. case 944:
  134. v = cregs->u_regs[UREG_I1];
  135. break;
  136. case 948:
  137. /* Isn't binary compatibility _fun_??? */
  138. if(cregs->psr & PSR_C)
  139. v = cregs->u_regs[UREG_I0] << 24;
  140. else
  141. v = 0;
  142. break;
  143. /* Rest of them are completely unsupported. */
  144. default:
  145. printk("%s [%d]: Wants to read user offset %ld\n",
  146. current->comm, current->pid, offset);
  147. pt_error_return(regs, EIO);
  148. return;
  149. }
  150. if (current->personality == PER_SUNOS)
  151. pt_succ_return (regs, v);
  152. else
  153. pt_succ_return_linux (regs, v, addr);
  154. return;
  155. }
  156. static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
  157. struct task_struct *tsk)
  158. {
  159. struct pt_regs *cregs = tsk->thread.kregs;
  160. struct thread_info *t = task_thread_info(tsk);
  161. unsigned long value = regs->u_regs[UREG_I3];
  162. if(offset >= 1024)
  163. offset -= 1024; /* whee... */
  164. if(offset & ((sizeof(unsigned long) - 1)))
  165. goto failure;
  166. if(offset >= 16 && offset < 784) {
  167. offset -= 16; offset >>= 2;
  168. *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
  169. goto success;
  170. }
  171. if(offset >= 784 && offset < 832) {
  172. offset -= 784; offset >>= 2;
  173. *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
  174. goto success;
  175. }
  176. switch(offset) {
  177. case 896:
  178. cregs->u_regs[UREG_I0] = value;
  179. break;
  180. case 900:
  181. cregs->u_regs[UREG_I1] = value;
  182. break;
  183. case 904:
  184. cregs->u_regs[UREG_I2] = value;
  185. break;
  186. case 908:
  187. cregs->u_regs[UREG_I3] = value;
  188. break;
  189. case 912:
  190. cregs->u_regs[UREG_I4] = value;
  191. break;
  192. case 916:
  193. cregs->u_regs[UREG_I5] = value;
  194. break;
  195. case 920:
  196. cregs->u_regs[UREG_I6] = value;
  197. break;
  198. case 924:
  199. cregs->u_regs[UREG_I7] = value;
  200. break;
  201. case 940:
  202. cregs->u_regs[UREG_I0] = value;
  203. break;
  204. case 944:
  205. cregs->u_regs[UREG_I1] = value;
  206. break;
  207. /* Rest of them are completely unsupported or "no-touch". */
  208. default:
  209. printk("%s [%d]: Wants to write user offset %ld\n",
  210. current->comm, current->pid, offset);
  211. goto failure;
  212. }
  213. success:
  214. pt_succ_return(regs, 0);
  215. return;
  216. failure:
  217. pt_error_return(regs, EIO);
  218. return;
  219. }
  220. /* #define ALLOW_INIT_TRACING */
  221. /* #define DEBUG_PTRACE */
  222. #ifdef DEBUG_PTRACE
  223. char *pt_rq [] = {
  224. /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
  225. /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
  226. /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
  227. /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
  228. /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
  229. /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
  230. /* 24 */ "SYSCALL", ""
  231. };
  232. #endif
  233. /*
  234. * Called by kernel/ptrace.c when detaching..
  235. *
  236. * Make sure single step bits etc are not set.
  237. */
  238. void ptrace_disable(struct task_struct *child)
  239. {
  240. /* nothing to do */
  241. }
  242. asmlinkage void do_ptrace(struct pt_regs *regs)
  243. {
  244. unsigned long request = regs->u_regs[UREG_I0];
  245. unsigned long pid = regs->u_regs[UREG_I1];
  246. unsigned long addr = regs->u_regs[UREG_I2];
  247. unsigned long data = regs->u_regs[UREG_I3];
  248. unsigned long addr2 = regs->u_regs[UREG_I4];
  249. struct task_struct *child;
  250. int ret;
  251. lock_kernel();
  252. #ifdef DEBUG_PTRACE
  253. {
  254. char *s;
  255. if ((request >= 0) && (request <= 24))
  256. s = pt_rq [request];
  257. else
  258. s = "unknown";
  259. if (request == PTRACE_POKEDATA && data == 0x91d02001){
  260. printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n",
  261. pid, addr, addr2);
  262. } else
  263. printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
  264. s, (int) request, (int) pid, addr, data, addr2);
  265. }
  266. #endif
  267. if (request == PTRACE_TRACEME) {
  268. ret = ptrace_traceme();
  269. pt_succ_return(regs, 0);
  270. goto out;
  271. }
  272. child = ptrace_get_task_struct(pid);
  273. if (IS_ERR(child)) {
  274. ret = PTR_ERR(child);
  275. pt_error_return(regs, -ret);
  276. goto out;
  277. }
  278. if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
  279. || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
  280. if (ptrace_attach(child)) {
  281. pt_error_return(regs, EPERM);
  282. goto out_tsk;
  283. }
  284. pt_succ_return(regs, 0);
  285. goto out_tsk;
  286. }
  287. ret = ptrace_check_attach(child, request == PTRACE_KILL);
  288. if (ret < 0) {
  289. pt_error_return(regs, -ret);
  290. goto out_tsk;
  291. }
  292. switch(request) {
  293. case PTRACE_PEEKTEXT: /* read word at location addr. */
  294. case PTRACE_PEEKDATA: {
  295. unsigned long tmp;
  296. if (access_process_vm(child, addr,
  297. &tmp, sizeof(tmp), 0) == sizeof(tmp))
  298. pt_os_succ_return(regs, tmp, (long __user *)data);
  299. else
  300. pt_error_return(regs, EIO);
  301. goto out_tsk;
  302. }
  303. case PTRACE_PEEKUSR:
  304. read_sunos_user(regs, addr, child, (long __user *) data);
  305. goto out_tsk;
  306. case PTRACE_POKEUSR:
  307. write_sunos_user(regs, addr, child);
  308. goto out_tsk;
  309. case PTRACE_POKETEXT: /* write the word at location addr. */
  310. case PTRACE_POKEDATA: {
  311. if (access_process_vm(child, addr,
  312. &data, sizeof(data), 1) == sizeof(data))
  313. pt_succ_return(regs, 0);
  314. else
  315. pt_error_return(regs, EIO);
  316. goto out_tsk;
  317. }
  318. case PTRACE_GETREGS: {
  319. struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
  320. struct pt_regs *cregs = child->thread.kregs;
  321. int rval;
  322. if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
  323. rval = -EFAULT;
  324. pt_error_return(regs, -rval);
  325. goto out_tsk;
  326. }
  327. __put_user(cregs->psr, (&pregs->psr));
  328. __put_user(cregs->pc, (&pregs->pc));
  329. __put_user(cregs->npc, (&pregs->npc));
  330. __put_user(cregs->y, (&pregs->y));
  331. for(rval = 1; rval < 16; rval++)
  332. __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
  333. pt_succ_return(regs, 0);
  334. #ifdef DEBUG_PTRACE
  335. printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
  336. #endif
  337. goto out_tsk;
  338. }
  339. case PTRACE_SETREGS: {
  340. struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
  341. struct pt_regs *cregs = child->thread.kregs;
  342. unsigned long psr, pc, npc, y;
  343. int i;
  344. /* Must be careful, tracing process can only set certain
  345. * bits in the psr.
  346. */
  347. if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
  348. pt_error_return(regs, EFAULT);
  349. goto out_tsk;
  350. }
  351. __get_user(psr, (&pregs->psr));
  352. __get_user(pc, (&pregs->pc));
  353. __get_user(npc, (&pregs->npc));
  354. __get_user(y, (&pregs->y));
  355. psr &= PSR_ICC;
  356. cregs->psr &= ~PSR_ICC;
  357. cregs->psr |= psr;
  358. if (!((pc | npc) & 3)) {
  359. cregs->pc = pc;
  360. cregs->npc =npc;
  361. }
  362. cregs->y = y;
  363. for(i = 1; i < 16; i++)
  364. __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
  365. pt_succ_return(regs, 0);
  366. goto out_tsk;
  367. }
  368. case PTRACE_GETFPREGS: {
  369. struct fps {
  370. unsigned long regs[32];
  371. unsigned long fsr;
  372. unsigned long flags;
  373. unsigned long extra;
  374. unsigned long fpqd;
  375. struct fq {
  376. unsigned long *insnaddr;
  377. unsigned long insn;
  378. } fpq[16];
  379. };
  380. struct fps __user *fps = (struct fps __user *) addr;
  381. int i;
  382. if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
  383. i = -EFAULT;
  384. pt_error_return(regs, -i);
  385. goto out_tsk;
  386. }
  387. for(i = 0; i < 32; i++)
  388. __put_user(child->thread.float_regs[i], (&fps->regs[i]));
  389. __put_user(child->thread.fsr, (&fps->fsr));
  390. __put_user(child->thread.fpqdepth, (&fps->fpqd));
  391. __put_user(0, (&fps->flags));
  392. __put_user(0, (&fps->extra));
  393. for(i = 0; i < 16; i++) {
  394. __put_user(child->thread.fpqueue[i].insn_addr,
  395. (&fps->fpq[i].insnaddr));
  396. __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
  397. }
  398. pt_succ_return(regs, 0);
  399. goto out_tsk;
  400. }
  401. case PTRACE_SETFPREGS: {
  402. struct fps {
  403. unsigned long regs[32];
  404. unsigned long fsr;
  405. unsigned long flags;
  406. unsigned long extra;
  407. unsigned long fpqd;
  408. struct fq {
  409. unsigned long *insnaddr;
  410. unsigned long insn;
  411. } fpq[16];
  412. };
  413. struct fps __user *fps = (struct fps __user *) addr;
  414. int i;
  415. if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
  416. i = -EFAULT;
  417. pt_error_return(regs, -i);
  418. goto out_tsk;
  419. }
  420. copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
  421. __get_user(child->thread.fsr, (&fps->fsr));
  422. __get_user(child->thread.fpqdepth, (&fps->fpqd));
  423. for(i = 0; i < 16; i++) {
  424. __get_user(child->thread.fpqueue[i].insn_addr,
  425. (&fps->fpq[i].insnaddr));
  426. __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
  427. }
  428. pt_succ_return(regs, 0);
  429. goto out_tsk;
  430. }
  431. case PTRACE_READTEXT:
  432. case PTRACE_READDATA: {
  433. int res = ptrace_readdata(child, addr,
  434. (void __user *) addr2, data);
  435. if (res == data) {
  436. pt_succ_return(regs, 0);
  437. goto out_tsk;
  438. }
  439. /* Partial read is an IO failure */
  440. if (res >= 0)
  441. res = -EIO;
  442. pt_error_return(regs, -res);
  443. goto out_tsk;
  444. }
  445. case PTRACE_WRITETEXT:
  446. case PTRACE_WRITEDATA: {
  447. int res = ptrace_writedata(child, (void __user *) addr2,
  448. addr, data);
  449. if (res == data) {
  450. pt_succ_return(regs, 0);
  451. goto out_tsk;
  452. }
  453. /* Partial write is an IO failure */
  454. if (res >= 0)
  455. res = -EIO;
  456. pt_error_return(regs, -res);
  457. goto out_tsk;
  458. }
  459. case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
  460. addr = 1;
  461. case PTRACE_CONT: { /* restart after signal. */
  462. if (!valid_signal(data)) {
  463. pt_error_return(regs, EIO);
  464. goto out_tsk;
  465. }
  466. if (request == PTRACE_SYSCALL)
  467. set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  468. else
  469. clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  470. child->exit_code = data;
  471. #ifdef DEBUG_PTRACE
  472. printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
  473. child->comm, child->pid, child->exit_code,
  474. child->thread.kregs->pc,
  475. child->thread.kregs->npc);
  476. #endif
  477. wake_up_process(child);
  478. pt_succ_return(regs, 0);
  479. goto out_tsk;
  480. }
  481. /*
  482. * make the child exit. Best I can do is send it a sigkill.
  483. * perhaps it should be put in the status that it wants to
  484. * exit.
  485. */
  486. case PTRACE_KILL: {
  487. if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
  488. pt_succ_return(regs, 0);
  489. goto out_tsk;
  490. }
  491. wake_up_process(child);
  492. child->exit_code = SIGKILL;
  493. pt_succ_return(regs, 0);
  494. goto out_tsk;
  495. }
  496. case PTRACE_SUNDETACH: { /* detach a process that was attached. */
  497. int err = ptrace_detach(child, data);
  498. if (err) {
  499. pt_error_return(regs, EIO);
  500. goto out_tsk;
  501. }
  502. pt_succ_return(regs, 0);
  503. goto out_tsk;
  504. }
  505. /* PTRACE_DUMPCORE unsupported... */
  506. default: {
  507. int err = ptrace_request(child, request, addr, data);
  508. if (err)
  509. pt_error_return(regs, -err);
  510. else
  511. pt_succ_return(regs, 0);
  512. goto out_tsk;
  513. }
  514. }
  515. out_tsk:
  516. if (child)
  517. put_task_struct(child);
  518. out:
  519. unlock_kernel();
  520. }
  521. asmlinkage void syscall_trace(void)
  522. {
  523. #ifdef DEBUG_PTRACE
  524. printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
  525. #endif
  526. if (!test_thread_flag(TIF_SYSCALL_TRACE))
  527. return;
  528. if (!(current->ptrace & PT_PTRACED))
  529. return;
  530. current->thread.flags ^= MAGIC_CONSTANT;
  531. ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
  532. ? 0x80 : 0));
  533. /*
  534. * this isn't the same as continuing with a signal, but it will do
  535. * for normal use. strace only continues with a signal if the
  536. * stopping signal is not SIGTRAP. -brl
  537. */
  538. #ifdef DEBUG_PTRACE
  539. printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
  540. current->pid, current->exit_code);
  541. #endif
  542. if (current->exit_code) {
  543. send_sig (current->exit_code, current, 1);
  544. current->exit_code = 0;
  545. }
  546. }