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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Kernel support for the ptrace() and syscall tracing interfaces.
  3.  *
  4.  * Copyright (C) 2000 Hewlett-Packard Co, Linuxcare Inc.
  5.  * Copyright (C) 2000 Matthew Wilcox <matthew@wil.cx>
  6.  * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
  7.  */
  8. #include <linux/kernel.h>
  9. #include <linux/sched.h>
  10. #include <linux/mm.h>
  11. #include <linux/smp.h>
  12. #include <linux/smp_lock.h>
  13. #include <linux/errno.h>
  14. #include <linux/ptrace.h>
  15. #include <linux/user.h>
  16. #include <asm/uaccess.h>
  17. #include <asm/pgtable.h>
  18. #include <asm/system.h>
  19. #include <asm/processor.h>
  20. #include <asm/offset.h>
  21. /* These are used in entry.S, syscall_restore_rfi.  We need to record the
  22.  * current stepping mode somewhere other than in PSW, because there is no
  23.  * concept of saving and restoring the users PSW over a syscall.  We choose
  24.  * to use these two bits in task->ptrace.  These bits must not clash with
  25.  * any PT_* defined in include/linux/sched.h, and must match with the bit
  26.  * tests in entry.S
  27.  */
  28. #define PT_SINGLESTEP 0x10000
  29. #define PT_BLOCKSTEP 0x20000
  30. /*
  31.  * Called by kernel/ptrace.c when detaching..
  32.  *
  33.  * Make sure single step bits etc are not set.
  34.  */
  35. void ptrace_disable(struct task_struct *child)
  36. {
  37. /* make sure the trap bits are not set */
  38. pa_psw(child)->r = 0;
  39. pa_psw(child)->t = 0;
  40. pa_psw(child)->h = 0;
  41. pa_psw(child)->l = 0;
  42. }
  43. long sys_ptrace(long request, pid_t pid, long addr, long data)
  44. {
  45. struct task_struct *child;
  46. long ret;
  47. lock_kernel();
  48. ret = -EPERM;
  49. if (request == PTRACE_TRACEME) {
  50. /* are we already being traced? */
  51. if (current->ptrace & PT_PTRACED)
  52. goto out;
  53. /* set the ptrace bit in the process flags. */
  54. current->ptrace |= PT_PTRACED;
  55. ret = 0;
  56. goto out;
  57. }
  58. ret = -ESRCH;
  59. read_lock(&tasklist_lock);
  60. child = find_task_by_pid(pid);
  61. if (child)
  62. get_task_struct(child);
  63. read_unlock(&tasklist_lock);
  64. if (!child)
  65. goto out;
  66. ret = -EPERM;
  67. if (pid == 1) /* no messing around with init! */
  68. goto out_tsk;
  69. if (request == PTRACE_ATTACH) {
  70. ret = ptrace_attach(child);
  71. goto out_tsk;
  72. }
  73. ret = -ESRCH;
  74. if (!(child->ptrace & PT_PTRACED))
  75. goto out_tsk;
  76. if (child->state != TASK_STOPPED) {
  77. if (request != PTRACE_KILL)
  78. goto out_tsk;
  79. }
  80. if (child->p_pptr != current)
  81. goto out_tsk;
  82. switch (request) {
  83. case PTRACE_PEEKTEXT: /* read word at location addr. */ 
  84. case PTRACE_PEEKDATA: {
  85. unsigned long tmp;
  86. int copied;
  87. copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
  88. ret = -EIO;
  89. if (copied != sizeof(tmp))
  90. goto out_tsk;
  91. ret = put_user(tmp,(unsigned long *) data);
  92. goto out_tsk;
  93. }
  94. /* when I and D space are separate, this will have to be fixed. */
  95. case PTRACE_POKETEXT: /* write the word at location addr. */
  96. case PTRACE_POKEDATA:
  97. ret = 0;
  98. if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
  99. goto out_tsk;
  100. ret = -EIO;
  101. goto out_tsk;
  102. /* Read the word at location addr in the USER area.  This will need
  103.    to change when the kernel no longer saves all regs on a syscall. */
  104. case PTRACE_PEEKUSR: {
  105. unsigned long tmp;
  106. ret = -EIO;
  107. if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
  108. goto out_tsk;
  109. tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
  110. ret = put_user(tmp, (unsigned long *) data);
  111. goto out_tsk;
  112. }
  113. /* Write the word at location addr in the USER area.  This will need
  114.    to change when the kernel no longer saves all regs on a syscall.
  115.    FIXME.  There is a problem at the moment in that r3-r18 are only
  116.    saved if the process is ptraced on syscall entry, and even then
  117.    those values are overwritten by actual register values on syscall
  118.    exit. */
  119. case PTRACE_POKEUSR:
  120. ret = -EIO;
  121. if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
  122. goto out_tsk;
  123. /* XXX This test probably needs adjusting.  We probably want to
  124.  * allow writes to some bits of PSW, and may want to block writes
  125.  * to (some) space registers.  Some register values written here
  126.  * may be ignored in entry.S:syscall_restore_rfi; e.g. iaoq is
  127.  * written with r31/r31+4, and not with the values in pt_regs.
  128.  */
  129. /* Allow writing of gr1-gr31, fr*, sr*, iasq*, iaoq*, sar */
  130. if (addr == PT_PSW || (addr > PT_IAOQ1 && addr != PT_SAR))
  131. goto out_tsk;
  132. *(unsigned long *) ((char *) task_regs(child) + addr) = data;
  133. ret = 0;
  134. goto out_tsk;
  135. case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
  136. case PTRACE_CONT:
  137. ret = -EIO;
  138. if ((unsigned long) data > _NSIG)
  139. goto out_tsk;
  140. child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
  141. if (request == PTRACE_SYSCALL)
  142. child->ptrace |= PT_TRACESYS;
  143. else
  144. child->ptrace &= ~PT_TRACESYS;
  145. child->exit_code = data;
  146. goto out_wake_notrap;
  147. case PTRACE_KILL:
  148. /*
  149.  * make the child exit.  Best I can do is send it a
  150.  * sigkill.  perhaps it should be put in the status
  151.  * that it wants to exit.
  152.  */
  153. if (child->state == TASK_ZOMBIE) /* already dead */
  154. goto out_tsk;
  155. child->exit_code = SIGKILL;
  156. goto out_wake_notrap;
  157. case PTRACE_SINGLEBLOCK:
  158. ret = -EIO;
  159. if ((unsigned long) data > _NSIG)
  160. goto out_tsk;
  161. child->ptrace &= ~(PT_TRACESYS|PT_SINGLESTEP);
  162. child->ptrace |= PT_BLOCKSTEP;
  163. child->exit_code = data;
  164. /* Enable taken branch trap. */
  165. pa_psw(child)->r = 0;
  166. pa_psw(child)->t = 1;
  167. pa_psw(child)->h = 0;
  168. pa_psw(child)->l = 0;
  169. goto out_wake;
  170. case PTRACE_SINGLESTEP:
  171. ret = -EIO;
  172. if ((unsigned long) data > _NSIG)
  173. goto out_tsk;
  174. child->ptrace &= ~(PT_TRACESYS|PT_BLOCKSTEP);
  175. child->ptrace |= PT_SINGLESTEP;
  176. child->exit_code = data;
  177. if (pa_psw(child)->n) {
  178. struct siginfo si;
  179. /* Nullified, just crank over the queue. */
  180. task_regs(child)->iaoq[0] = task_regs(child)->iaoq[1];
  181. task_regs(child)->iasq[0] = task_regs(child)->iasq[1];
  182. task_regs(child)->iaoq[1] = task_regs(child)->iaoq[0] + 4;
  183. pa_psw(child)->n = 0;
  184. pa_psw(child)->x = 0;
  185. pa_psw(child)->y = 0;
  186. pa_psw(child)->z = 0;
  187. pa_psw(child)->b = 0;
  188. pa_psw(child)->r = 0;
  189. pa_psw(child)->t = 0;
  190. pa_psw(child)->h = 0;
  191. pa_psw(child)->l = 0;
  192. /* Don't wake up the child, but let the
  193.    parent know something happened. */
  194. si.si_code = TRAP_TRACE;
  195. si.si_addr = (void *) (task_regs(child)->iaoq[0] & ~3);
  196. si.si_signo = SIGTRAP;
  197. si.si_errno = 0;
  198. force_sig_info(SIGTRAP, &si, child);
  199. //notify_parent(child, SIGCHLD);
  200. //ret = 0;
  201. goto out_wake;
  202. }
  203. /* Enable recovery counter traps.  The recovery counter
  204.  * itself will be set to zero on a task switch.  If the
  205.  * task is suspended on a syscall then the syscall return
  206.  * path will overwrite the recovery counter with a suitable
  207.  * value such that it traps once back in user space.  We
  208.  * disable interrupts in the childs PSW here also, to avoid
  209.  * interrupts while the recovery counter is decrementing.
  210.  */
  211. pa_psw(child)->r = 1;
  212. pa_psw(child)->t = 0;
  213. pa_psw(child)->h = 0;
  214. pa_psw(child)->l = 0;
  215. /* give it a chance to run. */
  216. goto out_wake;
  217. case PTRACE_DETACH:
  218. ret = ptrace_detach(child, data);
  219. goto out_tsk;
  220. default:
  221. ret = -EIO;
  222. goto out_tsk;
  223. }
  224. out_wake_notrap:
  225. /* make sure the trap bits are not set */
  226. pa_psw(child)->r = 0;
  227. pa_psw(child)->t = 0;
  228. pa_psw(child)->h = 0;
  229. pa_psw(child)->l = 0;
  230. out_wake:
  231. wake_up_process(child);
  232. ret = 0;
  233. out_tsk:
  234. free_task_struct(child);
  235. out:
  236. unlock_kernel();
  237. return ret;
  238. }
  239. void syscall_trace(void)
  240. {
  241. if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
  242. (PT_PTRACED|PT_TRACESYS))
  243. return;
  244. current->exit_code = SIGTRAP;
  245. current->state = TASK_STOPPED;
  246. notify_parent(current, SIGCHLD);
  247. schedule();
  248. /*
  249.  * this isn't the same as continuing with a signal, but it will do
  250.  * for normal use.  strace only continues with a signal if the
  251.  * stopping signal is not SIGTRAP.  -brl
  252.  */
  253. if (current->exit_code) {
  254. send_sig(current->exit_code, current, 1);
  255. current->exit_code = 0;
  256. }
  257. }