ptrace.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.ptrace.c 1.14 01/17/02 23:05:50 paulus
  3.  */
  4. /*
  5.  *  linux/arch/ppc/kernel/ptrace.c
  6.  *
  7.  *  PowerPC version
  8.  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  9.  *
  10.  *  Derived from "arch/m68k/kernel/ptrace.c"
  11.  *  Copyright (C) 1994 by Hamish Macdonald
  12.  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
  13.  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
  14.  *
  15.  * Modified by Cort Dougan (cort@hq.fsmlabs.com)
  16.  * and Paul Mackerras (paulus@linuxcare.com.au).
  17.  *
  18.  * This file is subject to the terms and conditions of the GNU General
  19.  * Public License.  Please read the COPYING file for all license details.
  20.  */
  21. #include <linux/kernel.h>
  22. #include <linux/sched.h>
  23. #include <linux/mm.h>
  24. #include <linux/smp.h>
  25. #include <linux/smp_lock.h>
  26. #include <linux/errno.h>
  27. #include <linux/ptrace.h>
  28. #include <linux/user.h>
  29. #include <asm/uaccess.h>
  30. #include <asm/page.h>
  31. #include <asm/pgtable.h>
  32. #include <asm/system.h>
  33. /*
  34.  * Set of msr bits that gdb can change on behalf of a process.
  35.  */
  36. #define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
  37. /*
  38.  * does not yet catch signals sent when the child dies.
  39.  * in exit.c or in signal.c.
  40.  */
  41. /*
  42.  * Get contents of register REGNO in task TASK.
  43.  */
  44. static inline unsigned long get_reg(struct task_struct *task, int regno)
  45. {
  46. if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)
  47.     && task->thread.regs != NULL)
  48. return ((unsigned long *)task->thread.regs)[regno];
  49. return (0);
  50. }
  51. /*
  52.  * Write contents of register REGNO in task TASK.
  53.  */
  54. static inline int put_reg(struct task_struct *task, int regno,
  55.   unsigned long data)
  56. {
  57. if (regno <= PT_MQ && task->thread.regs != NULL) {
  58. if (regno == PT_MSR)
  59. data = (data & MSR_DEBUGCHANGE)
  60. | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
  61. ((unsigned long *)task->thread.regs)[regno] = data;
  62. return 0;
  63. }
  64. return -EIO;
  65. }
  66. #ifdef CONFIG_ALTIVEC
  67. /*
  68.  * Get contents of AltiVec register state in task TASK
  69.  */
  70. static inline int get_vrregs(unsigned long *data, struct task_struct *task)
  71. {
  72. int i, j;
  73. if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long)))
  74. return -EFAULT;
  75. /* copy AltiVec registers VR[0] .. VR[31] */
  76. for (i = 0; i < 32; i++)
  77. for (j = 0; j < 4; j++, data++)
  78. if (__put_user(task->thread.vr[i].u[j], data))
  79. return -EFAULT;
  80. /* copy VSCR */
  81. for (i = 0; i < 4; i++, data++)
  82. if (__put_user(task->thread.vscr.u[i], data))
  83. return -EFAULT;
  84.         /* copy VRSAVE */
  85. if (__put_user(task->thread.vrsave, data))
  86. return -EFAULT;
  87. return 0;
  88. }
  89. /*
  90.  * Write contents of AltiVec register state into task TASK.
  91.  */
  92. static inline int set_vrregs(struct task_struct *task, unsigned long *data)
  93. {
  94. int i, j;
  95. if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long)))
  96. return -EFAULT;
  97. /* copy AltiVec registers VR[0] .. VR[31] */
  98. for (i = 0; i < 32; i++)
  99. for (j = 0; j < 4; j++, data++) 
  100. if (__get_user(task->thread.vr[i].u[j], data))
  101. return -EFAULT;
  102. /* copy VSCR */
  103. for (i = 0; i < 4; i++, data++) 
  104. if (__get_user(task->thread.vscr.u[i], data))
  105. return -EFAULT;
  106. /* copy VRSAVE */
  107. if (__get_user(task->thread.vrsave, data))
  108. return -EFAULT;
  109. return 0;
  110. }
  111. #endif
  112. static inline void
  113. set_single_step(struct task_struct *task)
  114. {
  115. struct pt_regs *regs = task->thread.regs;
  116. if (regs != NULL)
  117. regs->msr |= MSR_SE;
  118. }
  119. static inline void
  120. clear_single_step(struct task_struct *task)
  121. {
  122. struct pt_regs *regs = task->thread.regs;
  123. if (regs != NULL)
  124. regs->msr &= ~MSR_SE;
  125. }
  126. /*
  127.  * Called by kernel/ptrace.c when detaching..
  128.  *
  129.  * Make sure single step bits etc are not set.
  130.  */
  131. void ptrace_disable(struct task_struct *child)
  132. {
  133. /* make sure the single step bit is not set. */
  134. clear_single_step(child);
  135. }
  136. int sys_ptrace(long request, long pid, long addr, long data)
  137. {
  138. struct task_struct *child;
  139. int ret = -EPERM;
  140. lock_kernel();
  141. if (request == PTRACE_TRACEME) {
  142. /* are we already being traced? */
  143. if (current->ptrace & PT_PTRACED)
  144. goto out;
  145. /* set the ptrace bit in the process flags. */
  146. current->ptrace |= PT_PTRACED;
  147. ret = 0;
  148. goto out;
  149. }
  150. ret = -ESRCH;
  151. read_lock(&tasklist_lock);
  152. child = find_task_by_pid(pid);
  153. if (child)
  154. get_task_struct(child);
  155. read_unlock(&tasklist_lock);
  156. if (!child)
  157. goto out;
  158. ret = -EPERM;
  159. if (pid == 1) /* you may not mess with init */
  160. goto out_tsk;
  161. if (request == PTRACE_ATTACH) {
  162. ret = ptrace_attach(child);
  163. goto out_tsk;
  164. }
  165. ret = ptrace_check_attach(child, request == PTRACE_KILL);
  166. if (ret < 0)
  167. goto out_tsk;
  168. switch (request) {
  169. /* when I and D space are separate, these will need to be fixed. */
  170. case PTRACE_PEEKTEXT: /* read word at location addr. */ 
  171. case PTRACE_PEEKDATA: {
  172. unsigned long tmp;
  173. int copied;
  174. copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
  175. ret = -EIO;
  176. if (copied != sizeof(tmp))
  177. break;
  178. ret = put_user(tmp,(unsigned long *) data);
  179. break;
  180. }
  181. /* read the word at location addr in the USER area. */
  182. /* XXX this will need fixing for 64-bit */
  183. case PTRACE_PEEKUSR: {
  184. unsigned long index, tmp;
  185. ret = -EIO;
  186. /* convert to index and check */
  187. index = (unsigned long) addr >> 2;
  188. if ((addr & 3) || index > PT_FPSCR)
  189. break;
  190. if (index < PT_FPR0) {
  191. tmp = get_reg(child, (int) index);
  192. } else {
  193. if (child->thread.regs != NULL
  194.     && child->thread.regs->msr & MSR_FP)
  195. giveup_fpu(child);
  196. tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
  197. }
  198. ret = put_user(tmp,(unsigned long *) data);
  199. break;
  200. }
  201. /* If I and D space are separate, this will have to be fixed. */
  202. case PTRACE_POKETEXT: /* write the word at location addr. */
  203. case PTRACE_POKEDATA:
  204. ret = 0;
  205. if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
  206. break;
  207. ret = -EIO;
  208. break;
  209. /* write the word at location addr in the USER area */
  210. /* XXX this will need fixing for 64-bit */
  211. case PTRACE_POKEUSR: {
  212. unsigned long index;
  213. ret = -EIO;
  214. /* convert to index and check */
  215. index = (unsigned long) addr >> 2;
  216. if ((addr & 3) || index > PT_FPSCR)
  217. break;
  218. if (index == PT_ORIG_R3)
  219. break;
  220. if (index < PT_FPR0) {
  221. ret = put_reg(child, index, data);
  222. } else {
  223. if (child->thread.regs != NULL
  224.     && child->thread.regs->msr & MSR_FP)
  225. giveup_fpu(child);
  226. ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
  227. ret = 0;
  228. }
  229. break;
  230. }
  231. case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
  232. case PTRACE_CONT: { /* restart after signal. */
  233. ret = -EIO;
  234. if ((unsigned long) data > _NSIG)
  235. break;
  236. if (request == PTRACE_SYSCALL)
  237. child->ptrace |= PT_TRACESYS;
  238. else
  239. child->ptrace &= ~PT_TRACESYS;
  240. child->exit_code = data;
  241. /* make sure the single step bit is not set. */
  242. clear_single_step(child);
  243. wake_up_process(child);
  244. ret = 0;
  245. break;
  246. }
  247. /*
  248.  * make the child exit.  Best I can do is send it a sigkill. 
  249.  * perhaps it should be put in the status that it wants to 
  250.  * exit.
  251.  */
  252. case PTRACE_KILL: {
  253. ret = 0;
  254. if (child->state == TASK_ZOMBIE) /* already dead */
  255. break;
  256. child->exit_code = SIGKILL;
  257. /* make sure the single step bit is not set. */
  258. clear_single_step(child);
  259. wake_up_process(child);
  260. break;
  261. }
  262. case PTRACE_SINGLESTEP: {  /* set the trap flag. */
  263. ret = -EIO;
  264. if ((unsigned long) data > _NSIG)
  265. break;
  266. child->ptrace &= ~PT_TRACESYS;
  267. set_single_step(child);
  268. child->exit_code = data;
  269. /* give it a chance to run. */
  270. wake_up_process(child);
  271. ret = 0;
  272. break;
  273. }
  274. case PTRACE_DETACH:
  275. ret = ptrace_detach(child, data);
  276. break;
  277. #ifdef CONFIG_ALTIVEC
  278. case PTRACE_GETVRREGS:
  279. /* Get the child altivec register state. */
  280. if (child->thread.regs->msr & MSR_VEC)
  281. giveup_altivec(child);
  282. ret = get_vrregs((unsigned long *)data, child);
  283. break;
  284. case PTRACE_SETVRREGS:
  285. /* Set the child altivec register state. */
  286. /* this is to clear the MSR_VEC bit to force a reload
  287.  * of register state from memory */
  288. if (child->thread.regs->msr & MSR_VEC)
  289. giveup_altivec(child);
  290. ret = set_vrregs(child, (unsigned long *)data);
  291. break;
  292. #endif
  293. default:
  294. ret = -EIO;
  295. break;
  296. }
  297. out_tsk:
  298. free_task_struct(child);
  299. out:
  300. unlock_kernel();
  301. return ret;
  302. }
  303. void syscall_trace(void)
  304. {
  305. if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
  306. != (PT_PTRACED|PT_TRACESYS))
  307. return;
  308. current->exit_code = SIGTRAP;
  309. current->state = TASK_STOPPED;
  310. notify_parent(current, SIGCHLD);
  311. schedule();
  312. /*
  313.  * this isn't the same as continuing with a signal, but it will do
  314.  * for normal use.  strace only continues with a signal if the
  315.  * stopping signal is not SIGTRAP.  -brl
  316.  */
  317. if (current->exit_code) {
  318. send_sig(current->exit_code, current, 1);
  319. current->exit_code = 0;
  320. }
  321. }