diff options
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 084805ab7323..ef349ff170a7 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/ptrace.h> | 15 | #include <linux/ptrace.h> |
16 | #include <linux/regset.h> | ||
16 | #include <linux/user.h> | 17 | #include <linux/user.h> |
17 | #include <linux/security.h> | 18 | #include <linux/security.h> |
18 | #include <linux/audit.h> | 19 | #include <linux/audit.h> |
@@ -368,6 +369,59 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset) | |||
368 | return *pt_regs_access(task_pt_regs(task), offset); | 369 | return *pt_regs_access(task_pt_regs(task), offset); |
369 | } | 370 | } |
370 | 371 | ||
372 | static int genregs_get(struct task_struct *target, | ||
373 | const struct user_regset *regset, | ||
374 | unsigned int pos, unsigned int count, | ||
375 | void *kbuf, void __user *ubuf) | ||
376 | { | ||
377 | if (kbuf) { | ||
378 | unsigned long *k = kbuf; | ||
379 | while (count > 0) { | ||
380 | *k++ = getreg(target, pos); | ||
381 | count -= sizeof(*k); | ||
382 | pos += sizeof(*k); | ||
383 | } | ||
384 | } else { | ||
385 | unsigned long __user *u = ubuf; | ||
386 | while (count > 0) { | ||
387 | if (__put_user(getreg(target, pos), u++)) | ||
388 | return -EFAULT; | ||
389 | count -= sizeof(*u); | ||
390 | pos += sizeof(*u); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int genregs_set(struct task_struct *target, | ||
398 | const struct user_regset *regset, | ||
399 | unsigned int pos, unsigned int count, | ||
400 | const void *kbuf, const void __user *ubuf) | ||
401 | { | ||
402 | int ret = 0; | ||
403 | if (kbuf) { | ||
404 | const unsigned long *k = kbuf; | ||
405 | while (count > 0 && !ret) { | ||
406 | ret = putreg(target, pos, *k++); | ||
407 | count -= sizeof(*k); | ||
408 | pos += sizeof(*k); | ||
409 | } | ||
410 | } else { | ||
411 | const unsigned long __user *u = ubuf; | ||
412 | while (count > 0 && !ret) { | ||
413 | unsigned long word; | ||
414 | ret = __get_user(word, u++); | ||
415 | if (ret) | ||
416 | break; | ||
417 | ret = putreg(target, pos, word); | ||
418 | count -= sizeof(*u); | ||
419 | pos += sizeof(*u); | ||
420 | } | ||
421 | } | ||
422 | return ret; | ||
423 | } | ||
424 | |||
371 | /* | 425 | /* |
372 | * This function is trivial and will be inlined by the compiler. | 426 | * This function is trivial and will be inlined by the compiler. |
373 | * Having it separates the implementation details of debug | 427 | * Having it separates the implementation details of debug |
@@ -1008,6 +1062,61 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val) | |||
1008 | #undef R32 | 1062 | #undef R32 |
1009 | #undef SEG32 | 1063 | #undef SEG32 |
1010 | 1064 | ||
1065 | static int genregs32_get(struct task_struct *target, | ||
1066 | const struct user_regset *regset, | ||
1067 | unsigned int pos, unsigned int count, | ||
1068 | void *kbuf, void __user *ubuf) | ||
1069 | { | ||
1070 | if (kbuf) { | ||
1071 | compat_ulong_t *k = kbuf; | ||
1072 | while (count > 0) { | ||
1073 | getreg32(target, pos, k++); | ||
1074 | count -= sizeof(*k); | ||
1075 | pos += sizeof(*k); | ||
1076 | } | ||
1077 | } else { | ||
1078 | compat_ulong_t __user *u = ubuf; | ||
1079 | while (count > 0) { | ||
1080 | compat_ulong_t word; | ||
1081 | getreg32(target, pos, &word); | ||
1082 | if (__put_user(word, u++)) | ||
1083 | return -EFAULT; | ||
1084 | count -= sizeof(*u); | ||
1085 | pos += sizeof(*u); | ||
1086 | } | ||
1087 | } | ||
1088 | |||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | static int genregs32_set(struct task_struct *target, | ||
1093 | const struct user_regset *regset, | ||
1094 | unsigned int pos, unsigned int count, | ||
1095 | const void *kbuf, const void __user *ubuf) | ||
1096 | { | ||
1097 | int ret = 0; | ||
1098 | if (kbuf) { | ||
1099 | const compat_ulong_t *k = kbuf; | ||
1100 | while (count > 0 && !ret) { | ||
1101 | ret = putreg(target, pos, *k++); | ||
1102 | count -= sizeof(*k); | ||
1103 | pos += sizeof(*k); | ||
1104 | } | ||
1105 | } else { | ||
1106 | const compat_ulong_t __user *u = ubuf; | ||
1107 | while (count > 0 && !ret) { | ||
1108 | compat_ulong_t word; | ||
1109 | ret = __get_user(word, u++); | ||
1110 | if (ret) | ||
1111 | break; | ||
1112 | ret = putreg(target, pos, word); | ||
1113 | count -= sizeof(*u); | ||
1114 | pos += sizeof(*u); | ||
1115 | } | ||
1116 | } | ||
1117 | return ret; | ||
1118 | } | ||
1119 | |||
1011 | static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data) | 1120 | static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data) |
1012 | { | 1121 | { |
1013 | siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t)); | 1122 | siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t)); |