X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fx86_64%2Fkernel%2Fptrace.c;h=57bf883a7d8e5a77d3d27cd63f3acb7bc89ea07e;hb=refs%2Fheads%2Fvserver;hp=280bc88f2c9b973a12abed8c89b428a032ed4b54;hpb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;p=linux-2.6.git diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 280bc88f2..57bf883a7 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -119,17 +119,17 @@ unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *r return addr; } -static int is_at_popf(struct task_struct *child, struct pt_regs *regs) +static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs) { int i, copied; - unsigned char opcode[16]; + unsigned char opcode[15]; unsigned long addr = convert_rip_to_linear(child, regs); copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0); for (i = 0; i < copied; i++) { switch (opcode[i]) { - /* popf */ - case 0x9d: + /* popf and iret */ + case 0x9d: case 0xcf: return 1; /* CHECKME: 64 65 */ @@ -141,14 +141,17 @@ static int is_at_popf(struct task_struct *child, struct pt_regs *regs) case 0x26: case 0x2e: case 0x36: case 0x3e: case 0x64: case 0x65: - case 0xf0: case 0xf2: case 0xf3: + case 0xf2: case 0xf3: continue; - /* REX prefixes */ case 0x40 ... 0x4f: + if (regs->cs != __USER_CS) + /* 32-bit mode: register increment */ + return 0; + /* 64-bit mode: REX prefix */ continue; - /* CHECKME: f0, f2, f3 */ + /* CHECKME: f2, f3 */ /* * pushf: NOTE! We should probably not let @@ -189,10 +192,8 @@ void tracehook_enable_single_step(struct task_struct *child) * ..but if TF is changed by the instruction we will trace, * don't mark it as being "us" that set it, so that we * won't clear it by hand later. - * - * AK: this is not enough, LAHF and IRET can change TF in user space too. */ - if (is_at_popf(child, regs)) + if (is_setting_trap_flag(child, regs)) return; set_tsk_thread_flag(child, TIF_FORCED_TF); @@ -424,6 +425,7 @@ dbregs_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { + unsigned long maxaddr = TASK_SIZE_OF(target); maxaddr -= test_tsk_thread_flag(target, TIF_IA32) ? 3 : 7; @@ -487,6 +489,10 @@ dbregs_set(struct task_struct *target, if ((0x5554 >> ((val >> (16 + 4*i)) & 0xf)) & 1) return -EIO; + if (val) + set_tsk_thread_flag(target, TIF_DEBUG); + else + clear_tsk_thread_flag(target, TIF_DEBUG); SET_DBREG(7); break; #undef SET_DBREG @@ -512,7 +518,7 @@ fpregs_get(struct task_struct *target, if (tsk_used_math(target)) { if (target == current) unlazy_fpu(target); - } + } else init_fpu(target); @@ -669,8 +675,7 @@ static const struct utrace_regset native_regsets[] = { const struct utrace_regset_view utrace_x86_64_native = { .name = "x86-64", .e_machine = EM_X86_64, - .regsets = native_regsets, - .n = sizeof native_regsets / sizeof native_regsets[0], + .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) }; EXPORT_SYMBOL_GPL(utrace_x86_64_native); @@ -678,16 +683,16 @@ EXPORT_SYMBOL_GPL(utrace_x86_64_native); #ifdef CONFIG_PTRACE static const struct ptrace_layout_segment x86_64_uarea[] = { {0, sizeof(struct user_regs_struct), 0, 0}, + {sizeof(struct user_regs_struct), + offsetof(struct user, u_debugreg[0]), -1, 0}, {offsetof(struct user, u_debugreg[0]), - offsetof(struct user, u_debugreg[4]), 3, 0}, - {offsetof(struct user, u_debugreg[6]), - offsetof(struct user, u_debugreg[8]), 3, 6 * sizeof(long)}, + offsetof(struct user, u_debugreg[8]), 3, 0}, {0, 0, -1, 0} }; -fastcall int arch_ptrace(long *req, struct task_struct *child, - struct utrace_attached_engine *engine, - unsigned long addr, unsigned long data, long *val) +int arch_ptrace(long *req, struct task_struct *child, + struct utrace_attached_engine *engine, + unsigned long addr, unsigned long data, long *val) { switch (*req) { case PTRACE_PEEKUSR: