ptrace.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  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 = tsk->thread_info;
  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 = tsk->thread_info;
  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. int my_ret;
  269. /* are we already being traced? */
  270. if (current->ptrace & PT_PTRACED) {
  271. pt_error_return(regs, EPERM);
  272. goto out;
  273. }
  274. my_ret = security_ptrace(current->parent, current);
  275. if (my_ret) {
  276. pt_error_return(regs, -my_ret);
  277. goto out;
  278. }
  279. /* set the ptrace bit in the process flags. */
  280. current->ptrace |= PT_PTRACED;
  281. pt_succ_return(regs, 0);
  282. goto out;
  283. }
  284. #ifndef ALLOW_INIT_TRACING
  285. if (pid == 1) {
  286. /* Can't dork with init. */
  287. pt_error_return(regs, EPERM);
  288. goto out;
  289. }
  290. #endif
  291. read_lock(&tasklist_lock);
  292. child = find_task_by_pid(pid);
  293. if (child)
  294. get_task_struct(child);
  295. read_unlock(&tasklist_lock);
  296. if (!child) {
  297. pt_error_return(regs, ESRCH);
  298. goto out;
  299. }
  300. if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
  301. || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
  302. if (ptrace_attach(child)) {
  303. pt_error_return(regs, EPERM);
  304. goto out_tsk;
  305. }
  306. pt_succ_return(regs, 0);
  307. goto out_tsk;
  308. }
  309. ret = ptrace_check_attach(child, request == PTRACE_KILL);
  310. if (ret < 0) {
  311. pt_error_return(regs, -ret);
  312. goto out_tsk;
  313. }
  314. switch(request) {
  315. case PTRACE_PEEKTEXT: /* read word at location addr. */
  316. case PTRACE_PEEKDATA: {
  317. unsigned long tmp;
  318. if (access_process_vm(child, addr,
  319. &tmp, sizeof(tmp), 0) == sizeof(tmp))
  320. pt_os_succ_return(regs, tmp, (long __user *)data);
  321. else
  322. pt_error_return(regs, EIO);
  323. goto out_tsk;
  324. }
  325. case PTRACE_PEEKUSR:
  326. read_sunos_user(regs, addr, child, (long __user *) data);
  327. goto out_tsk;
  328. case PTRACE_POKEUSR:
  329. write_sunos_user(regs, addr, child);
  330. goto out_tsk;
  331. case PTRACE_POKETEXT: /* write the word at location addr. */
  332. case PTRACE_POKEDATA: {
  333. if (access_process_vm(child, addr,
  334. &data, sizeof(data), 1) == sizeof(data))
  335. pt_succ_return(regs, 0);
  336. else
  337. pt_error_return(regs, EIO);
  338. goto out_tsk;
  339. }
  340. case PTRACE_GETREGS: {
  341. struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
  342. struct pt_regs *cregs = child->thread.kregs;
  343. int rval;
  344. if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
  345. rval = -EFAULT;
  346. pt_error_return(regs, -rval);
  347. goto out_tsk;
  348. }
  349. __put_user(cregs->psr, (&pregs->psr));
  350. __put_user(cregs->pc, (&pregs->pc));
  351. __put_user(cregs->npc, (&pregs->npc));
  352. __put_user(cregs->y, (&pregs->y));
  353. for(rval = 1; rval < 16; rval++)
  354. __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
  355. pt_succ_return(regs, 0);
  356. #ifdef DEBUG_PTRACE
  357. printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
  358. #endif
  359. goto out_tsk;
  360. }
  361. case PTRACE_SETREGS: {
  362. struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
  363. struct pt_regs *cregs = child->thread.kregs;
  364. unsigned long psr, pc, npc, y;
  365. int i;
  366. /* Must be careful, tracing process can only set certain
  367. * bits in the psr.
  368. */
  369. if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
  370. pt_error_return(regs, EFAULT);
  371. goto out_tsk;
  372. }
  373. __get_user(psr, (&pregs->psr));
  374. __get_user(pc, (&pregs->pc));
  375. __get_user(npc, (&pregs->npc));
  376. __get_user(y, (&pregs->y));
  377. psr &= PSR_ICC;
  378. cregs->psr &= ~PSR_ICC;
  379. cregs->psr |= psr;
  380. if (!((pc | npc) & 3)) {
  381. cregs->pc = pc;
  382. cregs->npc =npc;
  383. }
  384. cregs->y = y;
  385. for(i = 1; i < 16; i++)
  386. __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
  387. pt_succ_return(regs, 0);
  388. goto out_tsk;
  389. }
  390. case PTRACE_GETFPREGS: {
  391. struct fps {
  392. unsigned long regs[32];
  393. unsigned long fsr;
  394. unsigned long flags;
  395. unsigned long extra;
  396. unsigned long fpqd;
  397. struct fq {
  398. unsigned long *insnaddr;
  399. unsigned long insn;
  400. } fpq[16];
  401. };
  402. struct fps __user *fps = (struct fps __user *) addr;
  403. int i;
  404. if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
  405. i = -EFAULT;
  406. pt_error_return(regs, -i);
  407. goto out_tsk;
  408. }
  409. for(i = 0; i < 32; i++)
  410. __put_user(child->thread.float_regs[i], (&fps->regs[i]));
  411. __put_user(child->thread.fsr, (&fps->fsr));
  412. __put_user(child->thread.fpqdepth, (&fps->fpqd));
  413. __put_user(0, (&fps->flags));
  414. __put_user(0, (&fps->extra));
  415. for(i = 0; i < 16; i++) {
  416. __put_user(child->thread.fpqueue[i].insn_addr,
  417. (&fps->fpq[i].insnaddr));
  418. __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
  419. }
  420. pt_succ_return(regs, 0);
  421. goto out_tsk;
  422. }
  423. case PTRACE_SETFPREGS: {
  424. struct fps {
  425. unsigned long regs[32];
  426. unsigned long fsr;
  427. unsigned long flags;
  428. unsigned long extra;
  429. unsigned long fpqd;
  430. struct fq {
  431. unsigned long *insnaddr;
  432. unsigned long insn;
  433. } fpq[16];
  434. };
  435. struct fps __user *fps = (struct fps __user *) addr;
  436. int i;
  437. if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
  438. i = -EFAULT;
  439. pt_error_return(regs, -i);
  440. goto out_tsk;
  441. }
  442. copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
  443. __get_user(child->thread.fsr, (&fps->fsr));
  444. __get_user(child->thread.fpqdepth, (&fps->fpqd));
  445. for(i = 0; i < 16; i++) {
  446. __get_user(child->thread.fpqueue[i].insn_addr,
  447. (&fps->fpq[i].insnaddr));
  448. __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
  449. }
  450. pt_succ_return(regs, 0);
  451. goto out_tsk;
  452. }
  453. case PTRACE_READTEXT:
  454. case PTRACE_READDATA: {
  455. int res = ptrace_readdata(child, addr,
  456. (void __user *) addr2, data);
  457. if (res == data) {
  458. pt_succ_return(regs, 0);
  459. goto out_tsk;
  460. }
  461. /* Partial read is an IO failure */
  462. if (res >= 0)
  463. res = -EIO;
  464. pt_error_return(regs, -res);
  465. goto out_tsk;
  466. }
  467. case PTRACE_WRITETEXT:
  468. case PTRACE_WRITEDATA: {
  469. int res = ptrace_writedata(child, (void __user *) addr2,
  470. addr, data);
  471. if (res == data) {
  472. pt_succ_return(regs, 0);
  473. goto out_tsk;
  474. }
  475. /* Partial write is an IO failure */
  476. if (res >= 0)
  477. res = -EIO;
  478. pt_error_return(regs, -res);
  479. goto out_tsk;
  480. }
  481. case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
  482. addr = 1;
  483. case PTRACE_CONT: { /* restart after signal. */
  484. if (!valid_signal(data)) {
  485. pt_error_return(regs, EIO);
  486. goto out_tsk;
  487. }
  488. if (request == PTRACE_SYSCALL)
  489. set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  490. else
  491. clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  492. child->exit_code = data;
  493. #ifdef DEBUG_PTRACE
  494. printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
  495. child->comm, child->pid, child->exit_code,
  496. child->thread.kregs->pc,
  497. child->thread.kregs->npc);
  498. #endif
  499. wake_up_process(child);
  500. pt_succ_return(regs, 0);
  501. goto out_tsk;
  502. }
  503. /*
  504. * make the child exit. Best I can do is send it a sigkill.
  505. * perhaps it should be put in the status that it wants to
  506. * exit.
  507. */
  508. case PTRACE_KILL: {
  509. if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
  510. pt_succ_return(regs, 0);
  511. goto out_tsk;
  512. }
  513. wake_up_process(child);
  514. child->exit_code = SIGKILL;
  515. pt_succ_return(regs, 0);
  516. goto out_tsk;
  517. }
  518. case PTRACE_SUNDETACH: { /* detach a process that was attached. */
  519. int err = ptrace_detach(child, data);
  520. if (err) {
  521. pt_error_return(regs, EIO);
  522. goto out_tsk;
  523. }
  524. pt_succ_return(regs, 0);
  525. goto out_tsk;
  526. }
  527. /* PTRACE_DUMPCORE unsupported... */
  528. default: {
  529. int err = ptrace_request(child, request, addr, data);
  530. if (err)
  531. pt_error_return(regs, -err);
  532. else
  533. pt_succ_return(regs, 0);
  534. goto out_tsk;
  535. }
  536. }
  537. out_tsk:
  538. if (child)
  539. put_task_struct(child);
  540. out:
  541. unlock_kernel();
  542. }
  543. asmlinkage void syscall_trace(void)
  544. {
  545. #ifdef DEBUG_PTRACE
  546. printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
  547. #endif
  548. if (!test_thread_flag(TIF_SYSCALL_TRACE))
  549. return;
  550. if (!(current->ptrace & PT_PTRACED))
  551. return;
  552. current->thread.flags ^= MAGIC_CONSTANT;
  553. ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
  554. ? 0x80 : 0));
  555. /*
  556. * this isn't the same as continuing with a signal, but it will do
  557. * for normal use. strace only continues with a signal if the
  558. * stopping signal is not SIGTRAP. -brl
  559. */
  560. #ifdef DEBUG_PTRACE
  561. printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
  562. current->pid, current->exit_code);
  563. #endif
  564. if (current->exit_code) {
  565. send_sig (current->exit_code, current, 1);
  566. current->exit_code = 0;
  567. }
  568. }