Hi, On Fri, 2005-02-18 at 23:44 +0000, Mike Hearn wrote: > On Fri, 2005-02-18 at 23:34 +0100, T.J. Zeeman wrote: > > Warcraft still complains about the CD-rom being MIA though :( I'll see > > if I can dig up a few hints from the log this weekend. > > Make sure your kernel hsa the ptrace regression fixes in. I guess you meant the problems refered to in WWN250 (http://www.winehq.com/?issue=250). I checked and the patch there is only for i386. I ported those to the x86_64 files (see attachments) and tried again to no avail. I also tried the test app as posted by Linus Torvalds here: http://www.winehq.com/hypermail/wine-devel/2004/11/0551.html When trying that on amd64 with the ptrace patches it does not even want to compile (not completely surprising). In the chroot it segfaults. A strace showed the following: x5556c000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=32850, ...}) = 0 old_mmap(NULL, 32850, PROT_READ, MAP_PRIVATE, 3, 0) = 0x5556d000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/tls/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360Y\1"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0644, st_size=1253924, ...}) = 0 old_mmap(NULL, 1260140, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x55576000 old_mmap(0x5569f000, 32768, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x129000) = 0x5569f000 old_mmap(0x556a7000, 10860, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED| MAP_ANONYMOUS, -1, 0) = 0x556a7000 close(3) = 0 old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x556aa000 set_thread_area({entry_number:-1 -> 11, base_addr:0x556aa2a0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 munmap(0x5556d000, 32850) = 0 rt_sigaction(SIGTRAP, {0x8048438, [TRAP], SA_RESTART}, {SIG_DFL}, 8) = 0 mprotect(0x8048000, 4096, PROT_READ|PROT_WRITE) = 0 --- SIGSEGV (Segmentation fault) @ 0 (0) --- +++ killed by SIGSEGV +++ I haven't been this deep into low level code in a long time (and that was 8086 asm simulated on a sparc), but I thought this would work and not segfault. Anybody around here that can comment on that? Or should I take this to another forum to further investigate? If so, where would you suggest I take it? regards, Thomas
--- /usr/src/kernel-source-2.6.10/arch/x86_64/kernel/ptrace.c 2004-12-24 22:34:30.000000000 +0100 +++ ptrace.c 2005-03-01 20:32:29.713639136 +0100 @@ -79,6 +79,28 @@ return 0; } +static void set_singlestep(struct task_struct *child) +{ + long eflags; + + set_tsk_thread_flag(child, TIF_SINGLESTEP); + eflags = get_stack_long(child, EFL_OFFSET); + put_stack_long(child, EFL_OFFSET, eflags | TRAP_FLAG); + child->ptrace |= PT_DTRACE; +} + +static void clear_singlestep(struct task_struct *child) +{ + if (child->ptrace & PT_DTRACE) { + long eflags; + + clear_tsk_thread_flag(child, TIF_SINGLESTEP); + eflags = get_stack_long(child, EFL_OFFSET); + put_stack_long(child, EFL_OFFSET, eflags & ~TRAP_FLAG); + child->ptrace &= ~PT_DTRACE; + } +} + /* * Called by kernel/ptrace.c when detaching.. * @@ -86,11 +108,12 @@ */ void ptrace_disable(struct task_struct *child) { - long tmp; +/* long tmp; clear_tsk_thread_flag(child, TIF_SINGLESTEP); tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; - put_stack_long(child, EFL_OFFSET, tmp); + put_stack_long(child, EFL_OFFSET, tmp); */ + clear_singlestep(child); } static int putreg(struct task_struct *child, @@ -338,8 +361,6 @@ break; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ - long tmp; - ret = -EIO; if ((unsigned long) data > _NSIG) break; @@ -347,12 +368,9 @@ set_tsk_thread_flag(child,TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE); - clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, EFL_OFFSET); - tmp &= ~TRAP_FLAG; - put_stack_long(child, EFL_OFFSET,tmp); + clear_singlestep(child); wake_up_process(child); ret = 0; break; @@ -394,34 +412,23 @@ * exit. */ case PTRACE_KILL: { - long tmp; - ret = 0; if (child->exit_state == EXIT_ZOMBIE) /* already dead */ break; clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; - put_stack_long(child, EFL_OFFSET, tmp); + clear_singlestep(child); wake_up_process(child); break; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ - long tmp; - ret = -EIO; if ((unsigned long) data > _NSIG) break; clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE); - if ((child->ptrace & PT_DTRACE) == 0) { - /* Spurious delayed TF traps may occur */ - child->ptrace |= PT_DTRACE; - } - tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; - put_stack_long(child, EFL_OFFSET, tmp); - set_tsk_thread_flag(child, TIF_SINGLESTEP); + set_singlestep(child); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child);
--- /usr/src/kernel-source-2.6.10/arch/x86_64/kernel/signal.c 2004-12-24 22:35:23.000000000 +0100 +++ signal.c 2005-03-01 20:33:11.425298000 +0100 @@ -205,8 +205,14 @@ err |= __put_user(me->thread.trap_no, &sc->trapno); err |= __put_user(me->thread.error_code, &sc->err); err |= __put_user(regs->rip, &sc->rip); + + /* + * Iff TF was set because the program is being single-stepped by a + * debugger, don't save that information on the signal stack.. We + * don't want debugging to change state. + */ eflags = regs->eflags; - if (current->ptrace & PT_PTRACED) { + if (current->ptrace & PT_DTRACE) { eflags &= ~TF_MASK; } err |= __put_user(eflags, &sc->eflags); @@ -324,12 +330,16 @@ regs->rsp = (unsigned long)frame; set_fs(USER_DS); + /* + * Clear TF when entering the signal handler, but + * notify any tracer that was single-stepping it. + * The tracer may want to single-step inside the + * handler too. + */ if (regs->eflags & TF_MASK) { - if ((current->ptrace & (PT_PTRACED | PT_DTRACE)) == (PT_PTRACED | PT_DTRACE)) { + regs->eflags &= ~TF_MASK; + if (current->ptrace & PT_DTRACE) ptrace_notify(SIGTRAP); - } else { - regs->eflags &= ~TF_MASK; - } } #ifdef DEBUG_SIG