PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/linux/linux/arch/sparc/kernel/ptrace.c

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