ptrace.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:14k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  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 %ldn",
  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 %ldn",
  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. "TRACEME",
  221. "PEEKTEXT",
  222. "PEEKDATA",
  223. "PEEKUSR",
  224. "POKETEXT",
  225. "POKEDATA",
  226. "POKEUSR",
  227. "CONT",
  228. "KILL",
  229. "SINGLESTEP",
  230. "SUNATTACH",
  231. "SUNDETACH",
  232. "GETREGS",
  233. "SETREGS",
  234. "GETFPREGS",
  235. "SETFPREGS",
  236. "READDATA",
  237. "WRITEDATA",
  238. "READTEXT",
  239. "WRITETEXT",
  240. "GETFPAREGS",
  241. "SETFPAREGS",
  242. ""
  243. };
  244. #endif
  245. /*
  246.  * Called by kernel/ptrace.c when detaching..
  247.  *
  248.  * Make sure single step bits etc are not set.
  249.  */
  250. void ptrace_disable(struct task_struct *child)
  251. {
  252. /* nothing to do */
  253. }
  254. asmlinkage void do_ptrace(struct pt_regs *regs)
  255. {
  256. unsigned long request = regs->u_regs[UREG_I0];
  257. unsigned long pid = regs->u_regs[UREG_I1];
  258. unsigned long addr = regs->u_regs[UREG_I2];
  259. unsigned long data = regs->u_regs[UREG_I3];
  260. unsigned long addr2 = regs->u_regs[UREG_I4];
  261. struct task_struct *child;
  262. lock_kernel();
  263. #ifdef DEBUG_PTRACE
  264. {
  265. char *s;
  266. if ((request > 0) && (request < 21))
  267. s = pt_rq [request];
  268. else
  269. s = "unknown";
  270. if (request == PTRACE_POKEDATA && data == 0x91d02001){
  271. printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lxn",
  272. pid, addr, addr2);
  273. } else 
  274. printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lxn",
  275.        s, (int) request, (int) pid, addr, data, addr2);
  276. }
  277. #endif
  278. if(request == PTRACE_TRACEME) {
  279. /* are we already being traced? */
  280. if (current->ptrace & PT_PTRACED) {
  281. pt_error_return(regs, EPERM);
  282. goto out;
  283. }
  284. /* set the ptrace bit in the process flags. */
  285. current->ptrace |= PT_PTRACED;
  286. pt_succ_return(regs, 0);
  287. goto out;
  288. }
  289. #ifndef ALLOW_INIT_TRACING
  290. if(pid == 1) {
  291. /* Can't dork with init. */
  292. pt_error_return(regs, EPERM);
  293. goto out;
  294. }
  295. #endif
  296. read_lock(&tasklist_lock);
  297. child = find_task_by_pid(pid);
  298. if (child)
  299. get_task_struct(child);
  300. read_unlock(&tasklist_lock);
  301. if (!child) {
  302. pt_error_return(regs, ESRCH);
  303. goto out;
  304. }
  305. if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
  306.     || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
  307. if (ptrace_attach(child)) {
  308. pt_error_return(regs, EPERM);
  309. goto out_tsk;
  310. }
  311. pt_succ_return(regs, 0);
  312. goto out_tsk;
  313. }
  314. if (!(child->ptrace & PT_PTRACED)) {
  315. pt_error_return(regs, ESRCH);
  316. goto out_tsk;
  317. }
  318. if(child->state != TASK_STOPPED) {
  319. if(request != PTRACE_KILL) {
  320. pt_error_return(regs, ESRCH);
  321. goto out_tsk;
  322. }
  323. }
  324. if(child->p_pptr != current) {
  325. pt_error_return(regs, ESRCH);
  326. goto out_tsk;
  327. }
  328. switch(request) {
  329. case PTRACE_PEEKTEXT: /* read word at location addr. */ 
  330. case PTRACE_PEEKDATA: {
  331. unsigned long tmp;
  332. if (access_process_vm(child, addr,
  333.       &tmp, sizeof(tmp), 0) == sizeof(tmp))
  334. pt_os_succ_return(regs, tmp, (long *)data);
  335. else
  336. pt_error_return(regs, EIO);
  337. goto out_tsk;
  338. }
  339. case PTRACE_PEEKUSR:
  340. read_sunos_user(regs, addr, child, (long *) data);
  341. goto out_tsk;
  342. case PTRACE_POKEUSR:
  343. write_sunos_user(regs, addr, child);
  344. goto out_tsk;
  345. case PTRACE_POKETEXT: /* write the word at location addr. */
  346. case PTRACE_POKEDATA: {
  347. if (access_process_vm(child, addr,
  348.       &data, sizeof(data), 1) == sizeof(data))
  349. pt_succ_return(regs, 0);
  350. else
  351. pt_error_return(regs, EIO);
  352. goto out_tsk;
  353. }
  354. case PTRACE_GETREGS: {
  355. struct pt_regs *pregs = (struct pt_regs *) addr;
  356. struct pt_regs *cregs = child->thread.kregs;
  357. int rval;
  358. rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs));
  359. if(rval) {
  360. pt_error_return(regs, -rval);
  361. goto out_tsk;
  362. }
  363. __put_user(cregs->psr, (&pregs->psr));
  364. __put_user(cregs->pc, (&pregs->pc));
  365. __put_user(cregs->npc, (&pregs->npc));
  366. __put_user(cregs->y, (&pregs->y));
  367. for(rval = 1; rval < 16; rval++)
  368. __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
  369. pt_succ_return(regs, 0);
  370. #ifdef DEBUG_PTRACE
  371. printk ("PC=%x nPC=%x o7=%xn", cregs->pc, cregs->npc, cregs->u_regs [15]);
  372. #endif
  373. goto out_tsk;
  374. }
  375. case PTRACE_SETREGS: {
  376. struct pt_regs *pregs = (struct pt_regs *) addr;
  377. struct pt_regs *cregs = child->thread.kregs;
  378. unsigned long psr, pc, npc, y;
  379. int i;
  380. /* Must be careful, tracing process can only set certain
  381.  * bits in the psr.
  382.  */
  383. i = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs));
  384. if(i) {
  385. pt_error_return(regs, -i);
  386. goto out_tsk;
  387. }
  388. __get_user(psr, (&pregs->psr));
  389. __get_user(pc, (&pregs->pc));
  390. __get_user(npc, (&pregs->npc));
  391. __get_user(y, (&pregs->y));
  392. psr &= PSR_ICC;
  393. cregs->psr &= ~PSR_ICC;
  394. cregs->psr |= psr;
  395. if(!((pc | npc) & 3)) {
  396. cregs->pc = pc;
  397. cregs->npc =npc;
  398. }
  399. cregs->y = y;
  400. for(i = 1; i < 16; i++)
  401. __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
  402. pt_succ_return(regs, 0);
  403. goto out_tsk;
  404. }
  405. case PTRACE_GETFPREGS: {
  406. struct fps {
  407. unsigned long regs[32];
  408. unsigned long fsr;
  409. unsigned long flags;
  410. unsigned long extra;
  411. unsigned long fpqd;
  412. struct fq {
  413. unsigned long *insnaddr;
  414. unsigned long insn;
  415. } fpq[16];
  416. } *fps = (struct fps *) addr;
  417. int i;
  418. i = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
  419. if(i) {
  420. pt_error_return(regs, -i);
  421. goto out_tsk;
  422. }
  423. for(i = 0; i < 32; i++)
  424. __put_user(child->thread.float_regs[i], (&fps->regs[i]));
  425. __put_user(child->thread.fsr, (&fps->fsr));
  426. __put_user(child->thread.fpqdepth, (&fps->fpqd));
  427. __put_user(0, (&fps->flags));
  428. __put_user(0, (&fps->extra));
  429. for(i = 0; i < 16; i++) {
  430. __put_user(child->thread.fpqueue[i].insn_addr,
  431.    (&fps->fpq[i].insnaddr));
  432. __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
  433. }
  434. pt_succ_return(regs, 0);
  435. goto out_tsk;
  436. }
  437. case PTRACE_SETFPREGS: {
  438. struct fps {
  439. unsigned long regs[32];
  440. unsigned long fsr;
  441. unsigned long flags;
  442. unsigned long extra;
  443. unsigned long fpqd;
  444. struct fq {
  445. unsigned long *insnaddr;
  446. unsigned long insn;
  447. } fpq[16];
  448. } *fps = (struct fps *) addr;
  449. int i;
  450. i = verify_area(VERIFY_READ, fps, sizeof(struct fps));
  451. if(i) {
  452. pt_error_return(regs, -i);
  453. goto out_tsk;
  454. }
  455. copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
  456. __get_user(child->thread.fsr, (&fps->fsr));
  457. __get_user(child->thread.fpqdepth, (&fps->fpqd));
  458. for(i = 0; i < 16; i++) {
  459. __get_user(child->thread.fpqueue[i].insn_addr,
  460.    (&fps->fpq[i].insnaddr));
  461. __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
  462. }
  463. pt_succ_return(regs, 0);
  464. goto out_tsk;
  465. }
  466. case PTRACE_READTEXT:
  467. case PTRACE_READDATA: {
  468. int res = ptrace_readdata(child, addr, (void *) addr2, data);
  469. if (res == data) {
  470. pt_succ_return(regs, 0);
  471. goto out_tsk;
  472. }
  473. /* Partial read is an IO failure */
  474. if (res >= 0)
  475. res = -EIO;
  476. pt_error_return(regs, -res);
  477. goto out_tsk;
  478. }
  479. case PTRACE_WRITETEXT:
  480. case PTRACE_WRITEDATA: {
  481. int res = ptrace_writedata(child, (void *) addr2, addr, data);
  482. if (res == data) {
  483. pt_succ_return(regs, 0);
  484. goto out_tsk;
  485. }
  486. /* Partial write is an IO failure */
  487. if (res >= 0)
  488. res = -EIO;
  489. pt_error_return(regs, -res);
  490. goto out_tsk;
  491. }
  492. case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
  493. addr = 1;
  494. case PTRACE_CONT: { /* restart after signal. */
  495. if ((unsigned long) data > _NSIG) {
  496. pt_error_return(regs, EIO);
  497. goto out_tsk;
  498. }
  499. if (addr != 1) {
  500. if (addr & 3) {
  501. pt_error_return(regs, EINVAL);
  502. goto out_tsk;
  503. }
  504. #ifdef DEBUG_PTRACE
  505. printk ("Original: %08lx %08lxn", child->thread.kregs->pc, child->thread.kregs->npc);
  506. printk ("Continuing with %08lx %08lxn", addr, addr+4);
  507. #endif
  508. child->thread.kregs->pc = addr;
  509. child->thread.kregs->npc = addr + 4;
  510. }
  511. if (request == PTRACE_SYSCALL)
  512. child->ptrace |= PT_TRACESYS;
  513. else
  514. child->ptrace &= ~PT_TRACESYS;
  515. child->exit_code = data;
  516. #ifdef DEBUG_PTRACE
  517. printk("CONT: %s [%d]: set exit_code = %x %x %xn", child->comm,
  518. child->pid, child->exit_code,
  519. child->thread.kregs->pc,
  520. child->thread.kregs->npc);
  521.        
  522. #endif
  523. wake_up_process(child);
  524. pt_succ_return(regs, 0);
  525. goto out_tsk;
  526. }
  527. /*
  528.  * make the child exit.  Best I can do is send it a sigkill. 
  529.  * perhaps it should be put in the status that it wants to 
  530.  * exit.
  531.  */
  532. case PTRACE_KILL: {
  533. if (child->state == TASK_ZOMBIE) { /* already dead */
  534. pt_succ_return(regs, 0);
  535. goto out_tsk;
  536. }
  537. wake_up_process(child);
  538. child->exit_code = SIGKILL;
  539. pt_succ_return(regs, 0);
  540. goto out_tsk;
  541. }
  542. case PTRACE_SUNDETACH: { /* detach a process that was attached. */
  543. int err = ptrace_detach(child, data);
  544. if (err) {
  545. pt_error_return(regs, EIO);
  546. goto out_tsk;
  547. }
  548. pt_succ_return(regs, 0);
  549. goto out_tsk;
  550. }
  551. /* PTRACE_DUMPCORE unsupported... */
  552. default:
  553. pt_error_return(regs, EIO);
  554. goto out_tsk;
  555. }
  556. out_tsk:
  557. if (child)
  558. free_task_struct(child);
  559. out:
  560. unlock_kernel();
  561. }
  562. asmlinkage void syscall_trace(void)
  563. {
  564. #ifdef DEBUG_PTRACE
  565. printk("%s [%d]: syscall_tracen", current->comm, current->pid);
  566. #endif
  567. if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
  568. != (PT_PTRACED|PT_TRACESYS))
  569. return;
  570. current->exit_code = SIGTRAP;
  571. current->state = TASK_STOPPED;
  572. current->thread.flags ^= MAGIC_CONSTANT;
  573. notify_parent(current, SIGCHLD);
  574. schedule();
  575. /*
  576.  * this isn't the same as continuing with a signal, but it will do
  577.  * for normal use.  strace only continues with a signal if the
  578.  * stopping signal is not SIGTRAP.  -brl
  579.  */
  580. #ifdef DEBUG_PTRACE
  581. printk("%s [%d]: syscall_trace exit= %xn", current->comm,
  582. current->pid, current->exit_code);
  583. #endif
  584. if (current->exit_code) {
  585. send_sig (current->exit_code, current, 1);
  586. current->exit_code = 0;
  587. }
  588. }