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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Copyright (C) 1992 Ross Biro
  7.  * Copyright (C) Linus Torvalds
  8.  * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
  9.  * Copyright (C) 1996 David S. Miller
  10.  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  11.  * Copyright (C) 1999 MIPS Technologies, Inc.
  12.  */
  13. #include <linux/config.h>
  14. #include <linux/kernel.h>
  15. #include <linux/sched.h>
  16. #include <linux/mm.h>
  17. #include <linux/errno.h>
  18. #include <linux/ptrace.h>
  19. #include <linux/smp.h>
  20. #include <linux/smp_lock.h>
  21. #include <linux/user.h>
  22. #include <asm/mipsregs.h>
  23. #include <asm/pgtable.h>
  24. #include <asm/page.h>
  25. #include <asm/system.h>
  26. #include <asm/uaccess.h>
  27. #include <asm/bootinfo.h>
  28. #include <asm/cpu.h>
  29. /*
  30.  * Called by kernel/ptrace.c when detaching..
  31.  *
  32.  * Make sure single step bits etc are not set.
  33.  */
  34. void ptrace_disable(struct task_struct *child)
  35. {
  36. /* Nothing to do.. */
  37. }
  38. asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
  39. {
  40. struct task_struct *child;
  41. int ret;
  42. extern void save_fp(struct task_struct *);
  43. lock_kernel();
  44. #if 0
  45. printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)n",
  46.        (int) request, (int) pid, (unsigned long) addr,
  47.        (unsigned long) data);
  48. #endif
  49. if (request == PTRACE_TRACEME) {
  50. /* are we already being traced? */
  51. if (current->ptrace & PT_PTRACED) {
  52. ret = -EPERM;
  53. goto out;
  54. }
  55. /* set the ptrace bit in the process flags. */
  56. current->ptrace |= PT_PTRACED;
  57. ret = 0;
  58. goto out;
  59. }
  60. ret = -ESRCH;
  61. read_lock(&tasklist_lock);
  62. child = find_task_by_pid(pid);
  63. if (child)
  64. get_task_struct(child);
  65. read_unlock(&tasklist_lock);
  66. if (!child)
  67. goto out;
  68. ret = -EPERM;
  69. if (pid == 1) /* you may not mess with init */
  70. goto out;
  71. if (request == PTRACE_ATTACH) {
  72. ret = ptrace_attach(child);
  73. goto out_tsk;
  74. }
  75. ret = ptrace_check_attach(child, request == PTRACE_KILL);
  76. if (ret < 0)
  77. goto out_tsk;
  78. switch (request) {
  79. case PTRACE_PEEKTEXT: /* read word at location addr. */
  80. case PTRACE_PEEKDATA: {
  81. unsigned long tmp;
  82. int copied;
  83. copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
  84. ret = -EIO;
  85. if (copied != sizeof(tmp))
  86. break;
  87. ret = put_user(tmp,(unsigned long *) data);
  88. goto out;
  89. }
  90. /* Read the word at location addr in the USER area.  */
  91. case PTRACE_PEEKUSR: {
  92. struct pt_regs *regs;
  93. unsigned long tmp;
  94. regs = (struct pt_regs *) ((unsigned long) child +
  95.        KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
  96. tmp = 0;  /* Default return value. */
  97. switch(addr) {
  98. case 0 ... 31:
  99. tmp = regs->regs[addr];
  100. break;
  101. case FPR_BASE ... FPR_BASE + 31:
  102. if (child->used_math) {
  103.         unsigned long long *fregs
  104. = (unsigned long long *)
  105.     &child->thread.fpu.hard.fp_regs[0];
  106.   if(!(mips_cpu.options & MIPS_CPU_FPU)) {
  107. fregs = (unsigned long long *)
  108. child->thread.fpu.soft.regs;
  109. } else
  110. if (last_task_used_math == child) {
  111. __enable_fpu();
  112. save_fp(child);
  113. __disable_fpu();
  114. last_task_used_math = NULL;
  115. regs->cp0_status &= ~ST0_CU1;
  116. }
  117. /*
  118.  * The odd registers are actually the high
  119.  * order bits of the values stored in the even
  120.  * registers - unless we're using r2k_switch.S.
  121.  */
  122. if (addr & 1)
  123. tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
  124. else
  125. tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
  126. } else {
  127. tmp = -1; /* FP not yet used  */
  128. }
  129. break;
  130. case PC:
  131. tmp = regs->cp0_epc;
  132. break;
  133. case CAUSE:
  134. tmp = regs->cp0_cause;
  135. break;
  136. case BADVADDR:
  137. tmp = regs->cp0_badvaddr;
  138. break;
  139. case MMHI:
  140. tmp = regs->hi;
  141. break;
  142. case MMLO:
  143. tmp = regs->lo;
  144. break;
  145. case FPC_CSR:
  146. if (!(mips_cpu.options & MIPS_CPU_FPU))
  147. tmp = child->thread.fpu.soft.sr;
  148. else
  149. tmp = child->thread.fpu.hard.control;
  150. break;
  151. case FPC_EIR: { /* implementation / version register */
  152. unsigned int flags;
  153. if (!(mips_cpu.options & MIPS_CPU_FPU)) {
  154. break;
  155. }
  156. __save_flags(flags);
  157. __enable_fpu();
  158. __asm__ __volatile__("cfc1t%0,$0": "=r" (tmp));
  159. __restore_flags(flags);
  160. break;
  161. }
  162. default:
  163. tmp = 0;
  164. ret = -EIO;
  165. goto out;
  166. }
  167. ret = put_user(tmp, (unsigned long *) data);
  168. goto out;
  169. }
  170. case PTRACE_POKETEXT: /* write the word at location addr. */
  171. case PTRACE_POKEDATA:
  172. ret = 0;
  173. if (access_process_vm(child, addr, &data, sizeof(data), 1)
  174.     == sizeof(data))
  175. break;
  176. ret = -EIO;
  177. goto out;
  178. case PTRACE_POKEUSR: {
  179. struct pt_regs *regs;
  180. ret = 0;
  181. regs = (struct pt_regs *) ((unsigned long) child +
  182.        KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
  183. switch (addr) {
  184. case 0 ... 31:
  185. regs->regs[addr] = data;
  186. break;
  187. case FPR_BASE ... FPR_BASE + 31: {
  188. unsigned long long *fregs;
  189. fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0];
  190. if (child->used_math) {
  191. if (last_task_used_math == child) {
  192. if(!(mips_cpu.options & MIPS_CPU_FPU)) {
  193. fregs = (unsigned long long *)
  194. child->thread.fpu.soft.regs;
  195. } else {
  196. __enable_fpu();
  197. save_fp(child);
  198. __disable_fpu();
  199. last_task_used_math = NULL;
  200. regs->cp0_status &= ~ST0_CU1;
  201. }
  202. }
  203. } else {
  204. /* FP not yet used  */
  205. memset(&child->thread.fpu.hard, ~0,
  206.        sizeof(child->thread.fpu.hard));
  207. child->thread.fpu.hard.control = 0;
  208. }
  209. /*
  210.  * The odd registers are actually the high order bits
  211.  * of the values stored in the even registers - unless
  212.  * we're using r2k_switch.S.
  213.  */
  214. #ifdef CONFIG_CPU_R3000
  215. if (mips_cpu.options & MIPS_CPU_FPU)
  216. *(unsigned long *)(fregs + addr) = data;
  217. else
  218. #endif
  219. if (addr & 1) {
  220. fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
  221. fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
  222. } else {
  223. fregs[addr - FPR_BASE] &= ~0xffffffffLL;
  224. fregs[addr - FPR_BASE] |= data;
  225. }
  226. break;
  227. }
  228. case PC:
  229. regs->cp0_epc = data;
  230. break;
  231. case MMHI:
  232. regs->hi = data;
  233. break;
  234. case MMLO:
  235. regs->lo = data;
  236. break;
  237. case FPC_CSR:
  238. if (!(mips_cpu.options & MIPS_CPU_FPU))
  239. child->thread.fpu.soft.sr = data;
  240. else
  241. child->thread.fpu.hard.control = data;
  242. break;
  243. default:
  244. /* The rest are not allowed. */
  245. ret = -EIO;
  246. break;
  247. }
  248. break;
  249. }
  250. case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
  251. case PTRACE_CONT: { /* restart after signal. */
  252. ret = -EIO;
  253. if ((unsigned long) data > _NSIG)
  254. break;
  255. if (request == PTRACE_SYSCALL)
  256. child->ptrace |= PT_TRACESYS;
  257. else
  258. child->ptrace &= ~PT_TRACESYS;
  259. child->exit_code = data;
  260. wake_up_process(child);
  261. ret = 0;
  262. break;
  263. }
  264. /*
  265.  * make the child exit.  Best I can do is send it a sigkill.
  266.  * perhaps it should be put in the status that it wants to
  267.  * exit.
  268.  */
  269. case PTRACE_KILL:
  270. ret = 0;
  271. if (child->state == TASK_ZOMBIE) /* already dead */
  272. break;
  273. child->exit_code = SIGKILL;
  274. wake_up_process(child);
  275. break;
  276. case PTRACE_DETACH: /* detach a process that was attached. */
  277. ret = ptrace_detach(child, data);
  278. break;
  279. case PTRACE_SETOPTIONS:
  280. if (data & PTRACE_O_TRACESYSGOOD)
  281. child->ptrace |= PT_TRACESYSGOOD;
  282. else
  283. child->ptrace &= ~PT_TRACESYSGOOD;
  284. ret = 0;
  285. break;
  286. default:
  287. ret = -EIO;
  288. goto out;
  289. }
  290. out_tsk:
  291. free_task_struct(child);
  292. out:
  293. unlock_kernel();
  294. return ret;
  295. }
  296. asmlinkage void syscall_trace(void)
  297. {
  298. if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
  299. != (PT_PTRACED|PT_TRACESYS))
  300. return;
  301. /* The 0x80 provides a way for the tracing parent to distinguish
  302.    between a syscall stop and SIGTRAP delivery */
  303. current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
  304.                                 ? 0x80 : 0);
  305. current->state = TASK_STOPPED;
  306. notify_parent(current, SIGCHLD);
  307. schedule();
  308. /*
  309.  * this isn't the same as continuing with a signal, but it will do
  310.  * for normal use.  strace only continues with a signal if the
  311.  * stopping signal is not SIGTRAP.  -brl
  312.  */
  313. if (current->exit_code) {
  314. send_sig(current->exit_code, current, 1);
  315. current->exit_code = 0;
  316. }
  317. }