/* set the thread x86 registers */ void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags ) { int pid = get_ptrace_tid(thread); struct dbreg dbregs; /* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); if (!suspend_for_ptrace( thread )) return; #ifdef DBREG_DRX /* needed for FreeBSD, the structure fields have changed under 5.x */ DBREG_DRX((&dbregs), 0) = context->debug.i386_regs.dr0; DBREG_DRX((&dbregs), 1) = context->debug.i386_regs.dr1; DBREG_DRX((&dbregs), 2) = context->debug.i386_regs.dr2; DBREG_DRX((&dbregs), 3) = context->debug.i386_regs.dr3; DBREG_DRX((&dbregs), 4) = 0; DBREG_DRX((&dbregs), 5) = 0; DBREG_DRX((&dbregs), 6) = context->debug.i386_regs.dr6; DBREG_DRX((&dbregs), 7) = context->debug.i386_regs.dr7; #else dbregs.dr0 = context->debug.i386_regs.dr0; dbregs.dr1 = context->debug.i386_regs.dr1; dbregs.dr2 = context->debug.i386_regs.dr2; dbregs.dr3 = context->debug.i386_regs.dr3; dbregs.dr4 = 0; dbregs.dr5 = 0; dbregs.dr6 = context->debug.i386_regs.dr6; dbregs.dr7 = context->debug.i386_regs.dr7; #endif if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error(); else if (thread->context) thread->context->debug.i386_regs = context->debug.i386_regs; /* update the cached values */ resume_after_ptrace( thread ); }
/* retrieve the thread x86 registers */ void get_thread_context( struct thread *thread, context_t *context, unsigned int flags ) { int pid = get_ptrace_tid(thread); struct dbreg dbregs; /* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); if (!suspend_for_ptrace( thread )) return; if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error(); else { #ifdef DBREG_DRX /* needed for FreeBSD, the structure fields have changed under 5.x */ context->debug.i386_regs.dr0 = DBREG_DRX((&dbregs), 0); context->debug.i386_regs.dr1 = DBREG_DRX((&dbregs), 1); context->debug.i386_regs.dr2 = DBREG_DRX((&dbregs), 2); context->debug.i386_regs.dr3 = DBREG_DRX((&dbregs), 3); context->debug.i386_regs.dr6 = DBREG_DRX((&dbregs), 6); context->debug.i386_regs.dr7 = DBREG_DRX((&dbregs), 7); #else context->debug.i386_regs.dr0 = dbregs.dr0; context->debug.i386_regs.dr1 = dbregs.dr1; context->debug.i386_regs.dr2 = dbregs.dr2; context->debug.i386_regs.dr3 = dbregs.dr3; context->debug.i386_regs.dr6 = dbregs.dr6; context->debug.i386_regs.dr7 = dbregs.dr7; #endif context->flags |= SERVER_CTX_DEBUG_REGISTERS; } resume_after_ptrace( thread ); }
/* set the thread x86 registers */ void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags ) { int pid = get_ptrace_tid( thread ); /* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); if (!suspend_for_ptrace( thread )) return; switch (context->cpu) { case CPU_x86: /* Linux 2.6.33+ does DR0-DR3 alignment validation, so it has to know LEN bits first */ if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 & 0xffff0000 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.i386_regs.dr0 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr0 = context->debug.i386_regs.dr0; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.i386_regs.dr1 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr1 = context->debug.i386_regs.dr1; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.i386_regs.dr2 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr2 = context->debug.i386_regs.dr2; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.i386_regs.dr3 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr3 = context->debug.i386_regs.dr3; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.i386_regs.dr6 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr6 = context->debug.i386_regs.dr6; /* Linux 2.6.33+ needs enable bits set briefly to update value returned by PEEKUSER later */ ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 | 0x55 ); if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr7 = context->debug.i386_regs.dr7; break; case CPU_x86_64: if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 & 0xffff0000 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.x86_64_regs.dr0 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr0 = context->debug.x86_64_regs.dr0; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.x86_64_regs.dr1 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr1 = context->debug.x86_64_regs.dr1; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.x86_64_regs.dr2 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr2 = context->debug.x86_64_regs.dr2; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.x86_64_regs.dr3 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr3 = context->debug.x86_64_regs.dr3; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.x86_64_regs.dr6 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr6 = context->debug.x86_64_regs.dr6; ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 | 0x55 ); if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr7 = context->debug.x86_64_regs.dr7; break; default: set_error( STATUS_INVALID_PARAMETER ); } resume_after_ptrace( thread ); return; error: file_set_error(); resume_after_ptrace( thread ); }
/* set the thread x86 registers */ void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags ) { int pid = get_ptrace_tid( thread ); /* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); if (!suspend_for_ptrace( thread )) return; switch (context->cpu) { case CPU_x86: if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.i386_regs.dr0 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr0 = context->debug.i386_regs.dr0; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.i386_regs.dr1 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr1 = context->debug.i386_regs.dr1; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.i386_regs.dr2 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr2 = context->debug.i386_regs.dr2; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.i386_regs.dr3 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr3 = context->debug.i386_regs.dr3; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.i386_regs.dr6 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr6 = context->debug.i386_regs.dr6; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr7 = context->debug.i386_regs.dr7; break; case CPU_x86_64: if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.x86_64_regs.dr0 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr0 = context->debug.x86_64_regs.dr0; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.x86_64_regs.dr1 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr1 = context->debug.x86_64_regs.dr1; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.x86_64_regs.dr2 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr2 = context->debug.x86_64_regs.dr2; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.x86_64_regs.dr3 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr3 = context->debug.x86_64_regs.dr3; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.x86_64_regs.dr6 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr6 = context->debug.x86_64_regs.dr6; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr7 = context->debug.x86_64_regs.dr7; break; default: set_error( STATUS_INVALID_PARAMETER ); } resume_after_ptrace( thread ); return; error: file_set_error(); resume_after_ptrace( thread ); }
/* retrieve the thread x86 registers */ void get_thread_context( struct thread *thread, context_t *context, unsigned int flags ) { int i, pid = get_ptrace_tid(thread); long data[8]; /* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); if (!suspend_for_ptrace( thread )) return; for (i = 0; i < 8; i++) { if (i == 4 || i == 5) continue; errno = 0; data[i] = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(i), 0 ); if ((data[i] == -1) && errno) { file_set_error(); goto done; } } switch (context->cpu) { case CPU_x86: context->debug.i386_regs.dr0 = data[0]; context->debug.i386_regs.dr1 = data[1]; context->debug.i386_regs.dr2 = data[2]; context->debug.i386_regs.dr3 = data[3]; context->debug.i386_regs.dr6 = data[6]; context->debug.i386_regs.dr7 = data[7]; break; case CPU_x86_64: context->debug.x86_64_regs.dr0 = data[0]; context->debug.x86_64_regs.dr1 = data[1]; context->debug.x86_64_regs.dr2 = data[2]; context->debug.x86_64_regs.dr3 = data[3]; context->debug.x86_64_regs.dr6 = data[6]; context->debug.x86_64_regs.dr7 = data[7]; break; default: set_error( STATUS_INVALID_PARAMETER ); goto done; } context->flags |= SERVER_CTX_DEBUG_REGISTERS; done: resume_after_ptrace( thread ); }