I'm trying to set a hardware breakpoint by using ptrace to set the x86
debug registers, and I just can't seem to get it to work.
I have attached my code below, and it compiles with -Wall without any
warnings. The output is also shown below, and it appears that the
breakpoint has no effect. From what I have read of the Linux kernel
source code, I would have expected the child process to get a SIGTRAP,
which would cause the parent to awaken from the waidpid call.
However, this doesn't happen.
Can someone tell me what I'm doing wrong? Or, if there's a newsgroup
that would be better-suited to this kind of question, please let me
know.
Thanks in advance!
---- output ----
P: Attaching
C: Waiting
P: Waiting
P: Setting debug regs
setup_control_reg before: 00000000
setup_control_reg after: 00f0000c
Confirm: dr1 is 08049c9c
Confirm: dr7 is 00f0000c
P: Continuing the child
P: Waiting
P: Continuing the child
P: Waiting
C: Firing the watchpoint on 0x8049c9c
C: Done
P: Done
---- code ----
/* Note that this DOES NOT WORK */
#include <sys/ptrace.h> /* ptrace */
#include <asm/user.h> /* struct user */
#include <unistd.h> /* getpid */
#include <errno.h> /* errno */
#include <stddef.h> /* offsetof */
#include <stdio.h> /* perror */
#include <signal.h> /* kill */
#include <wait.h> /* waitpid */
#include <assert.h> /* assert */
int safe_ptrace(int request, int pid, int addr, void * data){
int result;
errno = 0;
result = ptrace(request, pid, addr, data);
if(errno != 0){
perror("ptrace");
exit(1);
}else{
return result;
}
}
static int debug_reg(int pid, int regnum){
return safe_ptrace(
PTRACE_PEEKUSER, pid,
offsetof(struct user, u_debugreg[regnum]), 0
);
}
static void set_debug_reg(int pid, int regnum, int value){
safe_ptrace(
PTRACE_POKEUSER, pid,
offsetof(struct user, u_debugreg[regnum]), (void*)value
);
}
static int bit_replace(int old_val, int lsb, int size, int new_val){
int mask = (-1 << (size+lsb)) | ((1 << lsb) - 1);
return (old_val & mask) | (new_val << lsb);
}
static void setup_control_reg(int pid, int regnum, int len, int when){
int dr7 = debug_reg(pid, 7);
printf("setup_control_reg before: %8.8x\n", dr7);
dr7 = bit_replace(dr7, 18 + 4*regnum, 2, len-1);
dr7 = bit_replace(dr7, 16 + 4*regnum, 2, when);
dr7 |= 3 << (2*regnum);
printf("setup_control_reg after: %8.8x\n", dr7);
set_debug_reg(pid, 7, dr7);
}
enum { EXECUTE=0, WRITE=1, READ_WRITE=3 };
int x;
int main(){
int child;
if((child=fork())){
/* Parent */
int reg_idx, len, when;
int returned_pid, status;
/* Attach to child */
printf("P: Attaching\n");
safe_ptrace(PTRACE_ATTACH, child, 0, 0);
printf("P: Waiting\n");
returned_pid = waitpid(child, &status, WUNTRACED);
assert(returned_pid == child);
/* Set the parameters */
reg_idx = 1;
len = sizeof(x);
when = READ_WRITE;
/* Set the hardware breakpoint */
printf("P: Setting debug regs\n");
set_debug_reg(child, reg_idx, (int)&x);
setup_control_reg(child, reg_idx, len, when);
printf("Confirm: dr%d is %8.8x\n", reg_idx, debug_reg(child, reg_idx));
printf("Confirm: dr7 is %8.8x\n", debug_reg(child, 7));
/* Let the child continue */
while(!WIFEXITED(status)){
printf("P: Continuing the child\n");
safe_ptrace(PTRACE_CONT, child, 0, (void*)SIGCONT);
printf("P: Waiting\n");
returned_pid = waitpid(child, &status, WUNTRACED);
assert(returned_pid == child);
}
printf("P: Done\n");
}else{
/* Child */
/* Wait for parent to set things up */
printf("C: Waiting\n");
kill(getpid(), SIGSTOP);
/* Now fire the watchpoint */
printf("C: Firing the watchpoint on %p\n", &x);
x = 5;
printf("C: Done\n");
}
return 0;
}
--
--
Patrick Doyle
doy...@eecg.toronto.edu
Does anyone have a hardware breakpoint example that works?
BTW, I have already looked at the gdb source, and I think I am doing
exactly what they do. I have done an strace and the system calls seem
to be the same.
Thanks in advance. (My original code is included below.)
--
Patrick Doyle
doy...@eecg.toronto.edu
In article <GvJts...@ecf.utoronto.ca>,
--
Patrick Doyle
doy...@eecg.toronto.edu
In article <Gvp3n...@ecf.utoronto.ca>,
I don't.
--
Kasper Dupont -- der bruger for meget tid på usenet.
For sending spam use mailto:razor-...@daimi.au.dk
I did some work a _long_ time ago adding hw bkpt functionality to an
Interactive Unix kernel way back. Off the top of my head I cannot see
the fault in your code.
Since gdb supports this just fine, why dont you strace it to see if
what it does agrees with what your app does. Pretty sure its going to
be something silly that you have omitted to do.
Once I moved to another machine, the code below produced the results I
had expected.
--
Patrick Doyle
doy...@eecg.toronto.edu