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

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.  * Copyright (C) 2000 Ulf Carlsson
  11.  *
  12.  * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
  13.  * binaries.
  14.  */
  15. #include <linux/config.h>
  16. #include <linux/kernel.h>
  17. #include <linux/sched.h>
  18. #include <linux/mm.h>
  19. #include <linux/errno.h>
  20. #include <linux/ptrace.h>
  21. #include <linux/smp.h>
  22. #include <linux/smp_lock.h>
  23. #include <linux/user.h>
  24. #include <asm/cpu.h>
  25. #include <asm/mipsregs.h>
  26. #include <asm/pgtable.h>
  27. #include <asm/page.h>
  28. #include <asm/system.h>
  29. #include <asm/uaccess.h>
  30. #include <asm/bootinfo.h>
  31. /*
  32.  * Called by kernel/ptrace.c when detaching..
  33.  *
  34.  * Make sure single step bits etc are not set.
  35.  */
  36. void ptrace_disable(struct task_struct *child)
  37. {
  38. /* Nothing to do.. */
  39. }
  40. /*
  41.  * Tracing a 32-bit process with a 64-bit strace and vice versa will not
  42.  * work.  I don't know how to fix this.
  43.  */
  44. asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
  45. {
  46. struct task_struct *child;
  47. int ret;
  48. lock_kernel();
  49. ret = -EPERM;
  50. if (request == PTRACE_TRACEME) {
  51. /* are we already being traced? */
  52. if (current->ptrace & PT_PTRACED)
  53. goto out;
  54. /* set the ptrace bit in the process flags. */
  55. current->ptrace |= PT_PTRACED;
  56. ret = 0;
  57. goto out;
  58. }
  59. ret = -ESRCH;
  60. read_lock(&tasklist_lock);
  61. child = find_task_by_pid(pid);
  62. if (child)
  63. get_task_struct(child);
  64. read_unlock(&tasklist_lock);
  65. if (!child)
  66. goto out;
  67. ret = -EPERM;
  68. if (pid == 1) /* you may not mess with init */
  69. goto out_tsk;
  70. if (request == PTRACE_ATTACH) {
  71. ret = ptrace_attach(child);
  72. goto out_tsk;
  73. }
  74. ret = ptrace_check_attach(child, request == PTRACE_KILL);
  75. if (ret < 0)
  76. goto out_tsk;
  77. switch (request) {
  78. /* when I and D space are separate, these will need to be fixed. */
  79. case PTRACE_PEEKTEXT: /* read word at location addr. */
  80. case PTRACE_PEEKDATA: {
  81. unsigned int 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 int *) (unsigned long) data);
  88. break;
  89. }
  90. /* read the word at location addr in the USER area. */
  91. case PTRACE_PEEKUSR: {
  92. struct pt_regs *regs;
  93. unsigned int tmp;
  94. regs = (struct pt_regs *) ((unsigned long) child +
  95. KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
  96. ret = 0;
  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. #ifndef CONFIG_SMP
  108. if (last_task_used_math == child) {
  109. __enable_fpu();
  110. save_fp(child);
  111. __disable_fpu();
  112. last_task_used_math = NULL;
  113. }
  114. #endif
  115. } else {
  116. fregs = (unsigned long long *)
  117. child->thread.fpu.soft.regs;
  118. }
  119. /*
  120.  * The odd registers are actually the high
  121.  * order bits of the values stored in the even
  122.  * registers.
  123.  */
  124. if (addr & 1)
  125. tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
  126. else
  127. tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
  128. } else {
  129. tmp = -EIO;
  130. }
  131. break;
  132. case PC:
  133. tmp = regs->cp0_epc;
  134. break;
  135. case CAUSE:
  136. tmp = regs->cp0_cause;
  137. break;
  138. case BADVADDR:
  139. tmp = regs->cp0_badvaddr;
  140. break;
  141. case MMHI:
  142. tmp = regs->hi;
  143. break;
  144. case MMLO:
  145. tmp = regs->lo;
  146. break;
  147. case FPC_CSR:
  148. if (mips_cpu.options & MIPS_CPU_FPU)
  149. tmp = child->thread.fpu.hard.control;
  150. else
  151. tmp = child->thread.fpu.soft.sr;
  152. break;
  153. case FPC_EIR: { /* implementation / version register */
  154. unsigned int flags;
  155. __save_flags(flags);
  156. __enable_fpu();
  157. __asm__ __volatile__("cfc1t%0,$0": "=r" (tmp));
  158. __restore_flags(flags);
  159. break;
  160. }
  161. default:
  162. tmp = 0;
  163. ret = -EIO;
  164. goto out_tsk;
  165. }
  166. ret = put_user(tmp, (unsigned *) (unsigned long) data);
  167. break;
  168. }
  169. /* when I and D space are separate, this will have to be fixed. */
  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) == sizeof(data))
  174. break;
  175. ret = -EIO;
  176. break;
  177. case PTRACE_POKEUSR: {
  178. struct pt_regs *regs;
  179. ret = 0;
  180. regs = (struct pt_regs *) ((unsigned long) child +
  181. KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
  182. switch (addr) {
  183. case 0 ... 31:
  184. regs->regs[addr] = data;
  185. break;
  186. case FPR_BASE ... FPR_BASE + 31: {
  187. unsigned long long *fregs;
  188. fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0];
  189. if (child->used_math) {
  190. #ifndef CONFIG_SMP
  191. if (last_task_used_math == child)
  192. if (mips_cpu.options & MIPS_CPU_FPU) {
  193. __enable_fpu();
  194. save_fp(child);
  195. __disable_fpu();
  196. last_task_used_math = NULL;
  197. regs->cp0_status &= ~ST0_CU1;
  198. } else {
  199. fregs = (unsigned long long *)
  200. child->thread.fpu.soft.regs;
  201. }
  202. #endif
  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. if (addr & 1) {
  215. fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
  216. fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long) data) << 32;
  217. } else {
  218. fregs[addr - FPR_BASE] &= ~0xffffffffLL;
  219. fregs[addr - FPR_BASE] |= data;
  220. }
  221. break;
  222. }
  223. case PC:
  224. regs->cp0_epc = data;
  225. break;
  226. case MMHI:
  227. regs->hi = data;
  228. break;
  229. case MMLO:
  230. regs->lo = data;
  231. break;
  232. case FPC_CSR:
  233. if (mips_cpu.options & MIPS_CPU_FPU)
  234. child->thread.fpu.hard.control = data;
  235. else
  236. child->thread.fpu.soft.sr = data;
  237. break;
  238. default:
  239. /* The rest are not allowed. */
  240. ret = -EIO;
  241. break;
  242. }
  243. goto out;
  244. }
  245. case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
  246. case PTRACE_CONT: { /* restart after signal. */
  247. ret = -EIO;
  248. if ((unsigned int) data > _NSIG)
  249. break;
  250. if (request == PTRACE_SYSCALL)
  251. child->ptrace |= PT_TRACESYS;
  252. else
  253. child->ptrace &= ~PT_TRACESYS;
  254. child->exit_code = data;
  255. wake_up_process(child);
  256. ret = 0;
  257. break;
  258. }
  259. /*
  260.  * make the child exit.  Best I can do is send it a sigkill.
  261.  * perhaps it should be put in the status that it wants to
  262.  * exit.
  263.  */
  264. case PTRACE_KILL: {
  265. if (child->state == TASK_ZOMBIE) /* already dead */
  266. break;
  267. child->exit_code = SIGKILL;
  268. wake_up_process(child);
  269. break;
  270. }
  271. case PTRACE_DETACH: /* detach a process that was attached. */
  272. ret = ptrace_detach(child, data);
  273. break;
  274. case PTRACE_SETOPTIONS: {
  275. if (data & PTRACE_O_TRACESYSGOOD)
  276. child->ptrace |= PT_TRACESYSGOOD;
  277. else
  278. child->ptrace &= ~PT_TRACESYSGOOD;
  279. ret = 0;
  280. break;
  281. }
  282. default:
  283. ret = -EIO;
  284. break;
  285. }
  286. out_tsk:
  287. free_task_struct(child);
  288. out:
  289. unlock_kernel();
  290. return ret;
  291. }
  292. asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
  293. {
  294. struct task_struct *child;
  295. int ret;
  296. lock_kernel();
  297. #if 0
  298. printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)n",
  299.        (int) request, (int) pid, (unsigned long) addr,
  300.        (unsigned long) data);
  301. #endif
  302. ret = -EPERM;
  303. if (request == PTRACE_TRACEME) {
  304. /* are we already being traced? */
  305. if (current->ptrace & PT_PTRACED)
  306. goto out;
  307. /* set the ptrace bit in the process flags. */
  308. current->ptrace |= PT_PTRACED;
  309. ret = 0;
  310. goto out;
  311. }
  312. ret = -ESRCH;
  313. read_lock(&tasklist_lock);
  314. child = find_task_by_pid(pid);
  315. if (child)
  316. get_task_struct(child);
  317. read_unlock(&tasklist_lock);
  318. if (!child)
  319. goto out;
  320. ret = -EPERM;
  321. if (pid == 1) /* you may not mess with init */
  322. goto out;
  323. if (request == PTRACE_ATTACH) {
  324. ret = ptrace_attach(child);
  325. goto out_tsk;
  326. }
  327. ret = ptrace_check_attach(child, request == PTRACE_KILL);
  328. if (ret < 0)
  329. goto out_tsk;
  330. switch (request) {
  331. /* when I and D space are separate, these will need to be fixed. */
  332. case PTRACE_PEEKTEXT: /* read word at location addr. */
  333. case PTRACE_PEEKDATA: {
  334. unsigned long tmp;
  335. int copied;
  336. copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
  337. ret = -EIO;
  338. if (copied != sizeof(tmp))
  339. break;
  340. ret = put_user(tmp,(unsigned long *) data);
  341. break;
  342. }
  343. /* read the word at location addr in the USER area. */
  344. case PTRACE_PEEKUSR: {
  345. struct pt_regs *regs;
  346. unsigned long tmp;
  347. regs = (struct pt_regs *) ((unsigned long) child +
  348. KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
  349. ret = 0;
  350. switch (addr) {
  351. case 0 ... 31:
  352. tmp = regs->regs[addr];
  353. break;
  354. case FPR_BASE ... FPR_BASE + 31:
  355. if (child->used_math) {
  356. unsigned long long *fregs
  357. = (unsigned long long *)
  358. &child->thread.fpu.hard.fp_regs[0];
  359. if (mips_cpu.options & MIPS_CPU_FPU) {
  360. #ifndef CONFIG_SMP
  361. if (last_task_used_math == child) {
  362. __enable_fpu();
  363. save_fp(child);
  364. __disable_fpu();
  365. last_task_used_math = NULL;
  366. }
  367. #endif
  368. } else {
  369. fregs = (unsigned long long *)
  370. child->thread.fpu.soft.regs;
  371. }
  372. /*
  373.  * The odd registers are actually the high
  374.  * order bits of the values stored in the even
  375.  * registers.
  376.  */
  377. if (addr & 1)
  378. tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
  379. else
  380. tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
  381. } else {
  382. tmp = -EIO;
  383. }
  384. break;
  385. case PC:
  386. tmp = regs->cp0_epc;
  387. break;
  388. case CAUSE:
  389. tmp = regs->cp0_cause;
  390. break;
  391. case BADVADDR:
  392. tmp = regs->cp0_badvaddr;
  393. break;
  394. case MMHI:
  395. tmp = regs->hi;
  396. break;
  397. case MMLO:
  398. tmp = regs->lo;
  399. break;
  400. case FPC_CSR:
  401. if (mips_cpu.options & MIPS_CPU_FPU)
  402. tmp = child->thread.fpu.hard.control;
  403. else
  404. tmp = child->thread.fpu.soft.sr;
  405. break;
  406. case FPC_EIR: { /* implementation / version register */
  407. unsigned int flags;
  408. __save_flags(flags);
  409. __enable_fpu();
  410. __asm__ __volatile__("cfc1t%0,$0": "=r" (tmp));
  411. __restore_flags(flags);
  412. break;
  413. }
  414. default:
  415. tmp = 0;
  416. ret = -EIO;
  417. goto out_tsk;
  418. }
  419. ret = put_user(tmp, (unsigned long *) data);
  420. break;
  421. }
  422. /* when I and D space are separate, this will have to be fixed. */
  423. case PTRACE_POKETEXT: /* write the word at location addr. */
  424. case PTRACE_POKEDATA:
  425. ret = 0;
  426. if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
  427. break;
  428. ret = -EIO;
  429. break;
  430. case PTRACE_POKEUSR: {
  431. struct pt_regs *regs;
  432. ret = 0;
  433. regs = (struct pt_regs *) ((unsigned long) child +
  434. KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
  435. switch (addr) {
  436. case 0 ... 31:
  437. regs->regs[addr] = data;
  438. break;
  439. case FPR_BASE ... FPR_BASE + 31: {
  440. unsigned long long *fregs = (unsigned long long *)
  441. &child->thread.fpu.hard.fp_regs[0];
  442. if (child->used_math) {
  443. #ifndef CONFIG_SMP
  444. if (mips_cpu.options & MIPS_CPU_FPU) {
  445. if (last_task_used_math == child) {
  446. __enable_fpu();
  447. save_fp(child);
  448. __disable_fpu();
  449. last_task_used_math = NULL;
  450. regs->cp0_status &= ~ST0_CU1;
  451. } else {
  452. fregs = (unsigned long long *)
  453. child->thread.fpu.soft.regs;
  454. }
  455. }
  456. #endif
  457. } else {
  458. /* FP not yet used  */
  459. memset(&child->thread.fpu.hard, ~0,
  460.        sizeof(child->thread.fpu.hard));
  461. child->thread.fpu.hard.control = 0;
  462. }
  463. /*
  464.  * The odd registers are actually the high order bits
  465.  * of the values stored in the even registers - unless
  466.  * we're using r2k_switch.S.
  467.  */
  468. if (addr & 1) {
  469. fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
  470. fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long) data) << 32;
  471. } else {
  472. fregs[addr - FPR_BASE] &= ~0xffffffffLL;
  473. fregs[addr - FPR_BASE] |= data;
  474. }
  475. break;
  476. }
  477. case PC:
  478. regs->cp0_epc = data;
  479. break;
  480. case MMHI:
  481. regs->hi = data;
  482. break;
  483. case MMLO:
  484. regs->lo = data;
  485. break;
  486. case FPC_CSR:
  487. if (mips_cpu.options & MIPS_CPU_FPU)
  488. child->thread.fpu.hard.control = data;
  489. else
  490. child->thread.fpu.soft.sr = data;
  491. break;
  492. default:
  493. /* The rest are not allowed. */
  494. ret = -EIO;
  495. break;
  496. }
  497. goto out;
  498. }
  499. case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
  500. case PTRACE_CONT: { /* restart after signal. */
  501. ret = -EIO;
  502. if ((unsigned long) data > _NSIG)
  503. break;
  504. if (request == PTRACE_SYSCALL)
  505. child->ptrace |= PT_TRACESYS;
  506. else
  507. child->ptrace &= ~PT_TRACESYS;
  508. child->exit_code = data;
  509. wake_up_process(child);
  510. ret = 0;
  511. break;
  512. }
  513. /*
  514.  * make the child exit.  Best I can do is send it a sigkill.
  515.  * perhaps it should be put in the status that it wants to
  516.  * exit.
  517.  */
  518. case PTRACE_KILL: {
  519. if (child->state == TASK_ZOMBIE) /* already dead */
  520. break;
  521. child->exit_code = SIGKILL;
  522. wake_up_process(child);
  523. break;
  524. }
  525. case PTRACE_DETACH: /* detach a process that was attached. */
  526. ret = ptrace_detach(child, data);
  527. break;
  528. case PTRACE_SETOPTIONS: {
  529. if (data & PTRACE_O_TRACESYSGOOD)
  530. child->ptrace |= PT_TRACESYSGOOD;
  531. else
  532. child->ptrace &= ~PT_TRACESYSGOOD;
  533. ret = 0;
  534. break;
  535. }
  536. default:
  537. ret = -EIO;
  538. break;
  539. }
  540. out_tsk:
  541. free_task_struct(child);
  542. out:
  543. unlock_kernel();
  544. return ret;
  545. }
  546. asmlinkage void syscall_trace(void)
  547. {
  548. if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
  549.     != (PT_PTRACED|PT_TRACESYS))
  550. return;
  551. /* The 0x80 provides a way for the tracing parent to distinguish
  552.    between a syscall stop and SIGTRAP delivery */
  553. current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
  554.                                 ? 0x80 : 0);
  555. current->state = TASK_STOPPED;
  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. if (current->exit_code) {
  564. send_sig(current->exit_code, current, 1);
  565. current->exit_code = 0;
  566. }
  567. }