diff options
author | Roland McGrath <roland@redhat.com> | 2008-03-07 17:56:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-03-07 22:05:58 -0500 |
commit | 84c6f6046c5a2189160a8f0dca8b90427bf690ea (patch) | |
tree | a3d0942af06abd1daee5e7a0f17944656b464fd2 | |
parent | 60d5bcec7ed6c00e3ec88749fd81229731363221 (diff) |
x86_64: make ptrace always sign-extend orig_ax to 64 bits
This makes 64-bit ptrace calls setting the 64-bit orig_ax field for a
32-bit task sign-extend the low 32 bits up to 64. This matches what a
64-bit debugger expects when tracing a 32-bit task.
This follows on my "x86_64 ia32 syscall restart fix". This didn't
matter until that was fixed.
The debugger ignores or zeros the high half of every register slot it
sets (including the orig_rax pseudo-register) uniformly. It expects
that the setting of the low 32 bits always has the same meaning as a
32-bit debugger setting those same 32 bits with native 32-bit
facilities.
This never arose before because the syscall restart check never
matched any -ERESTART* values due to lack of sign extension. Before
that fix, even 32-bit ptrace setting orig_eax to -1 failed to trigger
the restart check anyway. So this was never noticed as a regression
of 64-bit debuggers vs 32-bit debuggers on the same 64-bit kernel.
Signed-off-by: Roland McGrath <roland@redhat.com>
[ Changed to just do the sign-extension unconditionally on x86-64,
since orig_ax is always just a small integer and doesn't need
the full 64-bit range ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/x86/kernel/ptrace.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index f41fdc98efb1..8f64abe699fd 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -323,6 +323,16 @@ static int putreg(struct task_struct *child, | |||
323 | return set_flags(child, value); | 323 | return set_flags(child, value); |
324 | 324 | ||
325 | #ifdef CONFIG_X86_64 | 325 | #ifdef CONFIG_X86_64 |
326 | /* | ||
327 | * Orig_ax is really just a flag with small positive and | ||
328 | * negative values, so make sure to always sign-extend it | ||
329 | * from 32 bits so that it works correctly regardless of | ||
330 | * whether we come from a 32-bit environment or not. | ||
331 | */ | ||
332 | case offsetof(struct user_regs_struct, orig_ax): | ||
333 | value = (long) (s32) value; | ||
334 | break; | ||
335 | |||
326 | case offsetof(struct user_regs_struct,fs_base): | 336 | case offsetof(struct user_regs_struct,fs_base): |
327 | if (value >= TASK_SIZE_OF(child)) | 337 | if (value >= TASK_SIZE_OF(child)) |
328 | return -EIO; | 338 | return -EIO; |