ptrace.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  3. * Licensed under the GPL
  4. */
  5. #include "linux/mm.h"
  6. #include "linux/sched.h"
  7. #include "asm/uaccess.h"
  8. extern int arch_switch_tls(struct task_struct *from, struct task_struct *to);
  9. void arch_switch_to(struct task_struct *from, struct task_struct *to)
  10. {
  11. int err = arch_switch_tls(from, to);
  12. if (!err)
  13. return;
  14. if (err != -EINVAL)
  15. printk(KERN_WARNING "arch_switch_tls failed, errno %d, "
  16. "not EINVAL\n", -err);
  17. else
  18. printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
  19. }
  20. int is_syscall(unsigned long addr)
  21. {
  22. unsigned short instr;
  23. int n;
  24. n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
  25. if (n) {
  26. /* access_process_vm() grants access to vsyscall and stub,
  27. * while copy_from_user doesn't. Maybe access_process_vm is
  28. * slow, but that doesn't matter, since it will be called only
  29. * in case of singlestepping, if copy_from_user failed.
  30. */
  31. n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
  32. if (n != sizeof(instr)) {
  33. printk(KERN_ERR "is_syscall : failed to read "
  34. "instruction from 0x%lx\n", addr);
  35. return 1;
  36. }
  37. }
  38. /* int 0x80 or sysenter */
  39. return (instr == 0x80cd) || (instr == 0x340f);
  40. }
  41. /* determines which flags the user has access to. */
  42. /* 1 = access 0 = no access */
  43. #define FLAG_MASK 0x00044dd5
  44. int putreg(struct task_struct *child, int regno, unsigned long value)
  45. {
  46. regno >>= 2;
  47. switch (regno) {
  48. case FS:
  49. if (value && (value & 3) != 3)
  50. return -EIO;
  51. PT_REGS_FS(&child->thread.regs) = value;
  52. return 0;
  53. case GS:
  54. if (value && (value & 3) != 3)
  55. return -EIO;
  56. PT_REGS_GS(&child->thread.regs) = value;
  57. return 0;
  58. case DS:
  59. case ES:
  60. if (value && (value & 3) != 3)
  61. return -EIO;
  62. value &= 0xffff;
  63. break;
  64. case SS:
  65. case CS:
  66. if ((value & 3) != 3)
  67. return -EIO;
  68. value &= 0xffff;
  69. break;
  70. case EFL:
  71. value &= FLAG_MASK;
  72. value |= PT_REGS_EFLAGS(&child->thread.regs);
  73. break;
  74. }
  75. PT_REGS_SET(&child->thread.regs, regno, value);
  76. return 0;
  77. }
  78. int poke_user(struct task_struct *child, long addr, long data)
  79. {
  80. if ((addr & 3) || addr < 0)
  81. return -EIO;
  82. if (addr < MAX_REG_OFFSET)
  83. return putreg(child, addr, data);
  84. else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
  85. (addr <= offsetof(struct user, u_debugreg[7]))) {
  86. addr -= offsetof(struct user, u_debugreg[0]);
  87. addr = addr >> 2;
  88. if ((addr == 4) || (addr == 5))
  89. return -EIO;
  90. child->thread.arch.debugregs[addr] = data;
  91. return 0;
  92. }
  93. return -EIO;
  94. }
  95. unsigned long getreg(struct task_struct *child, int regno)
  96. {
  97. unsigned long retval = ~0UL;
  98. regno >>= 2;
  99. switch (regno) {
  100. case FS:
  101. case GS:
  102. case DS:
  103. case ES:
  104. case SS:
  105. case CS:
  106. retval = 0xffff;
  107. /* fall through */
  108. default:
  109. retval &= PT_REG(&child->thread.regs, regno);
  110. }
  111. return retval;
  112. }
  113. /* read the word at location addr in the USER area. */
  114. int peek_user(struct task_struct *child, long addr, long data)
  115. {
  116. unsigned long tmp;
  117. if ((addr & 3) || addr < 0)
  118. return -EIO;
  119. tmp = 0; /* Default return condition */
  120. if (addr < MAX_REG_OFFSET) {
  121. tmp = getreg(child, addr);
  122. }
  123. else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
  124. (addr <= offsetof(struct user, u_debugreg[7]))) {
  125. addr -= offsetof(struct user, u_debugreg[0]);
  126. addr = addr >> 2;
  127. tmp = child->thread.arch.debugregs[addr];
  128. }
  129. return put_user(tmp, (unsigned long __user *) data);
  130. }
  131. struct i387_fxsave_struct {
  132. unsigned short cwd;
  133. unsigned short swd;
  134. unsigned short twd;
  135. unsigned short fop;
  136. long fip;
  137. long fcs;
  138. long foo;
  139. long fos;
  140. long mxcsr;
  141. long reserved;
  142. long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
  143. long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
  144. long padding[56];
  145. };
  146. /*
  147. * FPU tag word conversions.
  148. */
  149. static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
  150. {
  151. unsigned int tmp; /* to avoid 16 bit prefixes in the code */
  152. /* Transform each pair of bits into 01 (valid) or 00 (empty) */
  153. tmp = ~twd;
  154. tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
  155. /* and move the valid bits to the lower byte. */
  156. tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
  157. tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
  158. tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
  159. return tmp;
  160. }
  161. static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
  162. {
  163. struct _fpxreg *st = NULL;
  164. unsigned long twd = (unsigned long) fxsave->twd;
  165. unsigned long tag;
  166. unsigned long ret = 0xffff0000;
  167. int i;
  168. #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
  169. for ( i = 0 ; i < 8 ; i++ ) {
  170. if ( twd & 0x1 ) {
  171. st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
  172. switch ( st->exponent & 0x7fff ) {
  173. case 0x7fff:
  174. tag = 2; /* Special */
  175. break;
  176. case 0x0000:
  177. if ( !st->significand[0] &&
  178. !st->significand[1] &&
  179. !st->significand[2] &&
  180. !st->significand[3] ) {
  181. tag = 1; /* Zero */
  182. } else {
  183. tag = 2; /* Special */
  184. }
  185. break;
  186. default:
  187. if ( st->significand[3] & 0x8000 ) {
  188. tag = 0; /* Valid */
  189. } else {
  190. tag = 2; /* Special */
  191. }
  192. break;
  193. }
  194. } else {
  195. tag = 3; /* Empty */
  196. }
  197. ret |= (tag << (2 * i));
  198. twd = twd >> 1;
  199. }
  200. return ret;
  201. }
  202. static inline int convert_fxsr_to_user(struct _fpstate __user *buf,
  203. struct pt_regs *regs)
  204. {
  205. return 0;
  206. }
  207. static inline int convert_fxsr_from_user(struct pt_regs *regs,
  208. struct _fpstate __user *buf)
  209. {
  210. return 0;
  211. }
  212. int get_fpregs(unsigned long buf, struct task_struct *child)
  213. {
  214. int err;
  215. err = convert_fxsr_to_user((struct _fpstate __user *) buf,
  216. &child->thread.regs);
  217. if (err)
  218. return -EFAULT;
  219. return 0;
  220. }
  221. int set_fpregs(unsigned long buf, struct task_struct *child)
  222. {
  223. int err;
  224. err = convert_fxsr_from_user(&child->thread.regs,
  225. (struct _fpstate __user *) buf);
  226. if (err)
  227. return -EFAULT;
  228. return 0;
  229. }
  230. int get_fpxregs(unsigned long buf, struct task_struct *tsk)
  231. {
  232. return 0;
  233. }
  234. int set_fpxregs(unsigned long buf, struct task_struct *tsk)
  235. {
  236. return 0;
  237. }
  238. #ifdef notdef
  239. int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
  240. {
  241. fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) |
  242. (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff));
  243. fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
  244. fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs));
  245. fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
  246. fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs));
  247. fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs));
  248. fpu->fos = 0;
  249. memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)),
  250. sizeof(fpu->st_space));
  251. return 1;
  252. }
  253. #endif
  254. int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
  255. {
  256. return 1;
  257. }