X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fi386-nat.c;h=0a5deb06ca1869f9e7751cae5eab0f429fe4ed45;hb=c1357578b3f2cd7c151f74bde1d3751c32e50966;hp=eb16687ddb23dd6f706f2bec1d006543c2ca699f;hpb=fc5abaaec148bdcc57222b797b0746e93f88ce81;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c index eb16687ddb..0a5deb06ca 100644 --- a/gdb/i386-nat.c +++ b/gdb/i386-nat.c @@ -1,7 +1,6 @@ /* Native-dependent code for the i386. - Copyright (C) 2001, 2004, 2005, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -18,13 +17,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "i386-nat.h" #include "defs.h" +#include "i386-nat.h" #include "breakpoint.h" #include "command.h" #include "gdbcmd.h" #include "target.h" #include "gdb_assert.h" +#include "inferior.h" /* Support for hardware watchpoints and breakpoints using the i386 debug registers. @@ -43,11 +43,6 @@ struct i386_dr_low_type i386_dr_low; /* Support for 8-byte wide hw watchpoints. */ #define TARGET_HAS_DR_LEN_8 (i386_dr_low.debug_register_length == 8) -/* Debug registers' indices. */ -#define DR_NADDR 4 /* The number of debug address registers. */ -#define DR_STATUS 6 /* Index of debug status register (DR6). */ -#define DR_CONTROL 7 /* Index of debug control register (DR7). */ - /* DR7 Debug Control register fields. */ /* How many bits to skip in DR7 to get to R/W and LEN fields. */ @@ -111,45 +106,150 @@ struct i386_dr_low_type i386_dr_low; /* The I'th debug register is vacant if its Local and Global Enable bits are reset in the Debug Control register. */ -#define I386_DR_VACANT(i) \ - ((dr_control_mirror & (3 << (DR_ENABLE_SIZE * (i)))) == 0) +#define I386_DR_VACANT(state, i) \ + (((state)->dr_control_mirror & (3 << (DR_ENABLE_SIZE * (i)))) == 0) /* Locally enable the break/watchpoint in the I'th debug register. */ -#define I386_DR_LOCAL_ENABLE(i) \ - dr_control_mirror |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))) +#define I386_DR_LOCAL_ENABLE(state, i) \ + do { \ + (state)->dr_control_mirror |= \ + (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))); \ + } while (0) /* Globally enable the break/watchpoint in the I'th debug register. */ -#define I386_DR_GLOBAL_ENABLE(i) \ - dr_control_mirror |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))) +#define I386_DR_GLOBAL_ENABLE(state, i) \ + do { \ + (state)->dr_control_mirror |= \ + (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))); \ + } while (0) /* Disable the break/watchpoint in the I'th debug register. */ -#define I386_DR_DISABLE(i) \ - dr_control_mirror &= ~(3 << (DR_ENABLE_SIZE * (i))) +#define I386_DR_DISABLE(state, i) \ + do { \ + (state)->dr_control_mirror &= \ + ~(3 << (DR_ENABLE_SIZE * (i))); \ + } while (0) /* Set in DR7 the RW and LEN fields for the I'th debug register. */ -#define I386_DR_SET_RW_LEN(i,rwlen) \ +#define I386_DR_SET_RW_LEN(state, i, rwlen) \ do { \ - dr_control_mirror &= ~(0x0f << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \ - dr_control_mirror |= ((rwlen) << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \ + (state)->dr_control_mirror &= \ + ~(0x0f << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))); \ + (state)->dr_control_mirror |= \ + ((rwlen) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))); \ } while (0) /* Get from DR7 the RW and LEN fields for the I'th debug register. */ -#define I386_DR_GET_RW_LEN(i) \ - ((dr_control_mirror >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f) +#define I386_DR_GET_RW_LEN(dr7, i) \ + (((dr7) \ + >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f) + +/* Mask that this I'th watchpoint has triggered. */ +#define I386_DR_WATCH_MASK(i) (1 << (i)) /* Did the watchpoint whose address is in the I'th register break? */ -#define I386_DR_WATCH_HIT(i) (dr_status_mirror & (1 << (i))) +#define I386_DR_WATCH_HIT(dr6, i) ((dr6) & (1 << (i))) /* A macro to loop over all debug registers. */ #define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++) -/* Mirror the inferior's DRi registers. We keep the status and - control registers separated because they don't hold addresses. */ -static CORE_ADDR dr_mirror[DR_NADDR]; -static unsigned long dr_status_mirror, dr_control_mirror; +/* Per-process data. We don't bind this to a per-inferior registry + because of targets like x86 GNU/Linux that need to keep track of + processes that aren't bound to any inferior (e.g., fork children, + checkpoints). */ + +struct i386_process_info +{ + /* Linked list. */ + struct i386_process_info *next; + + /* The process identifier. */ + pid_t pid; + + /* Copy of i386 hardware debug registers. */ + struct i386_debug_reg_state state; +}; + +static struct i386_process_info *i386_process_list = NULL; + +/* Find process data for process PID. */ + +static struct i386_process_info * +i386_find_process_pid (pid_t pid) +{ + struct i386_process_info *proc; + + for (proc = i386_process_list; proc; proc = proc->next) + if (proc->pid == pid) + return proc; + + return NULL; +} + +/* Add process data for process PID. Returns newly allocated info + object. */ + +static struct i386_process_info * +i386_add_process (pid_t pid) +{ + struct i386_process_info *proc; + + proc = xcalloc (1, sizeof (*proc)); + proc->pid = pid; + + proc->next = i386_process_list; + i386_process_list = proc; + + return proc; +} + +/* Get data specific info for process PID, creating it if necessary. + Never returns NULL. */ + +static struct i386_process_info * +i386_process_info_get (pid_t pid) +{ + struct i386_process_info *proc; + + proc = i386_find_process_pid (pid); + if (proc == NULL) + proc = i386_add_process (pid); + + return proc; +} + +/* Get debug registers state for process PID. */ + +struct i386_debug_reg_state * +i386_debug_reg_state (pid_t pid) +{ + return &i386_process_info_get (pid)->state; +} + +/* See declaration in i386-nat.h. */ -/* Reference counts for each debug register. */ -static int dr_ref_count[DR_NADDR]; +void +i386_forget_process (pid_t pid) +{ + struct i386_process_info *proc, **proc_link; + + proc = i386_process_list; + proc_link = &i386_process_list; + + while (proc != NULL) + { + if (proc->pid == pid) + { + *proc_link = proc->next; + + xfree (proc); + return; + } + + proc_link = &proc->next; + proc = *proc_link; + } +} /* Whether or not to print the mirrored debug registers. */ static int maint_show_dr; @@ -169,7 +269,8 @@ static unsigned i386_length_and_rw_bits (int len, enum target_hw_bp_type type); value of the bit-field from DR7 which describes the length and access type of the region to be watched by this watchpoint. Return 0 on success, -1 on failure. */ -static int i386_insert_aligned_watchpoint (CORE_ADDR addr, +static int i386_insert_aligned_watchpoint (struct i386_debug_reg_state *state, + CORE_ADDR addr, unsigned len_rw_bits); /* Remove a watchpoint at address ADDR, which is assumed to be aligned @@ -177,7 +278,8 @@ static int i386_insert_aligned_watchpoint (CORE_ADDR addr, value of the bits from DR7 which describes the length and access type of the region watched by this watchpoint. Return 0 on success, -1 on failure. */ -static int i386_remove_aligned_watchpoint (CORE_ADDR addr, +static int i386_remove_aligned_watchpoint (struct i386_debug_reg_state *state, + CORE_ADDR addr, unsigned len_rw_bits); /* Insert or remove a (possibly non-aligned) watchpoint, or count the @@ -186,7 +288,8 @@ static int i386_remove_aligned_watchpoint (CORE_ADDR addr, successful insertion or removal, a positive number when queried about the number of registers, or -1 on failure. If WHAT is not a valid value, bombs through internal_error. */ -static int i386_handle_nonaligned_watchpoint (i386_wp_op_t what, +static int i386_handle_nonaligned_watchpoint (struct i386_debug_reg_state *state, + i386_wp_op_t what, CORE_ADDR addr, int len, enum target_hw_bp_type type); @@ -198,15 +301,8 @@ static int i386_handle_nonaligned_watchpoint (i386_wp_op_t what, void i386_cleanup_dregs (void) { - int i; - - ALL_DEBUG_REGISTERS(i) - { - dr_mirror[i] = 0; - dr_ref_count[i] = 0; - } - dr_control_mirror = 0; - dr_status_mirror = 0; + /* Starting from scratch has the same effect. */ + i386_forget_process (ptid_get_pid (inferior_ptid)); } /* Print the values of the mirrored debug registers. This is called @@ -214,10 +310,11 @@ i386_cleanup_dregs (void) show-debug-regs" at GDB's prompt. */ static void -i386_show_dr (const char *func, CORE_ADDR addr, +i386_show_dr (struct i386_debug_reg_state *state, + const char *func, CORE_ADDR addr, int len, enum target_hw_bp_type type) { - int addr_size = gdbarch_addr_bit (target_gdbarch) / 8; + int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8; int i; puts_unfiltered (func); @@ -236,13 +333,16 @@ i386_show_dr (const char *func, CORE_ADDR addr, : "??unknown??")))); puts_unfiltered (":\n"); printf_unfiltered ("\tCONTROL (DR7): %s STATUS (DR6): %s\n", - phex (dr_control_mirror, 8), phex (dr_status_mirror, 8)); + phex (state->dr_control_mirror, 8), + phex (state->dr_status_mirror, 8)); ALL_DEBUG_REGISTERS(i) { printf_unfiltered ("\ \tDR%d: addr=0x%s, ref.count=%d DR%d: addr=0x%s, ref.count=%d\n", - i, phex (dr_mirror[i], addr_size), dr_ref_count[i], - i+1, phex (dr_mirror[i+1], addr_size), dr_ref_count[i+1]); + i, phex (state->dr_mirror[i], addr_size), + state->dr_ref_count[i], + i + 1, phex (state->dr_mirror[i + 1], addr_size), + state->dr_ref_count[i+1]); i++; } } @@ -265,7 +365,9 @@ i386_length_and_rw_bits (int len, enum target_hw_bp_type type) rw = DR_RW_WRITE; break; case hw_read: - /* The i386 doesn't support data-read watchpoints. */ + internal_error (__FILE__, __LINE__, + _("The i386 doesn't support " + "data-read watchpoints.\n")); case hw_access: rw = DR_RW_READ; break; @@ -292,6 +394,7 @@ Invalid hardware breakpoint type %d in i386_length_and_rw_bits.\n"), case 8: if (TARGET_HAS_DR_LEN_8) return (DR_LEN_8 | rw); + /* ELSE FALL THROUGH */ default: internal_error (__FILE__, __LINE__, _("\ Invalid hardware breakpoint length %d in i386_length_and_rw_bits.\n"), len); @@ -305,7 +408,8 @@ Invalid hardware breakpoint length %d in i386_length_and_rw_bits.\n"), len); success, -1 on failure. */ static int -i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) +i386_insert_aligned_watchpoint (struct i386_debug_reg_state *state, + CORE_ADDR addr, unsigned len_rw_bits) { int i; @@ -317,11 +421,11 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) reuse it for this watchpoint as well (and save a register). */ ALL_DEBUG_REGISTERS(i) { - if (!I386_DR_VACANT (i) - && dr_mirror[i] == addr - && I386_DR_GET_RW_LEN (i) == len_rw_bits) + if (!I386_DR_VACANT (state, i) + && state->dr_mirror[i] == addr + && I386_DR_GET_RW_LEN (state->dr_control_mirror, i) == len_rw_bits) { - dr_ref_count[i]++; + state->dr_ref_count[i]++; return 0; } } @@ -329,7 +433,7 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) /* Next, look for a vacant debug register. */ ALL_DEBUG_REGISTERS(i) { - if (I386_DR_VACANT (i)) + if (I386_DR_VACANT (state, i)) break; } @@ -340,9 +444,9 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) /* Now set up the register I to watch our region. */ /* Record the info in our local mirrored array. */ - dr_mirror[i] = addr; - dr_ref_count[i] = 1; - I386_DR_SET_RW_LEN (i, len_rw_bits); + state->dr_mirror[i] = addr; + state->dr_ref_count[i] = 1; + I386_DR_SET_RW_LEN (state, i, len_rw_bits); /* Note: we only enable the watchpoint locally, i.e. in the current task. Currently, no i386 target allows or supports global watchpoints; however, if any target would want that in the @@ -350,13 +454,9 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) to enable watchpoints globally or locally, and the code below should use global or local enable and slow-down flags as appropriate. */ - I386_DR_LOCAL_ENABLE (i); - dr_control_mirror |= DR_LOCAL_SLOWDOWN; - dr_control_mirror &= I386_DR_CONTROL_MASK; - - /* Finally, actually pass the info to the inferior. */ - i386_dr_low.set_addr (i, addr); - i386_dr_low.set_control (dr_control_mirror); + I386_DR_LOCAL_ENABLE (state, i); + state->dr_control_mirror |= DR_LOCAL_SLOWDOWN; + state->dr_control_mirror &= I386_DR_CONTROL_MASK; return 0; } @@ -368,25 +468,22 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) success, -1 on failure. */ static int -i386_remove_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) +i386_remove_aligned_watchpoint (struct i386_debug_reg_state *state, + CORE_ADDR addr, unsigned len_rw_bits) { int i, retval = -1; ALL_DEBUG_REGISTERS(i) { - if (!I386_DR_VACANT (i) - && dr_mirror[i] == addr - && I386_DR_GET_RW_LEN (i) == len_rw_bits) + if (!I386_DR_VACANT (state, i) + && state->dr_mirror[i] == addr + && I386_DR_GET_RW_LEN (state->dr_control_mirror, i) == len_rw_bits) { - if (--dr_ref_count[i] == 0) /* no longer in use? */ + if (--state->dr_ref_count[i] == 0) /* no longer in use? */ { /* Reset our mirror. */ - dr_mirror[i] = 0; - I386_DR_DISABLE (i); - /* Reset it in the inferior. */ - i386_dr_low.set_control (dr_control_mirror); - if (i386_dr_low.reset_addr) - i386_dr_low.reset_addr (i); + state->dr_mirror[i] = 0; + I386_DR_DISABLE (state, i); } retval = 0; } @@ -403,10 +500,11 @@ i386_remove_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) valid value, bombs through internal_error. */ static int -i386_handle_nonaligned_watchpoint (i386_wp_op_t what, CORE_ADDR addr, int len, +i386_handle_nonaligned_watchpoint (struct i386_debug_reg_state *state, + i386_wp_op_t what, CORE_ADDR addr, int len, enum target_hw_bp_type type) { - int retval = 0, status = 0; + int retval = 0; int max_wp_len = TARGET_HAS_DR_LEN_8 ? 8 : 4; static int size_try_array[8][8] = @@ -444,24 +542,15 @@ i386_handle_nonaligned_watchpoint (i386_wp_op_t what, CORE_ADDR addr, int len, unsigned len_rw = i386_length_and_rw_bits (size, type); if (what == WP_INSERT) - status = i386_insert_aligned_watchpoint (addr, len_rw); + retval = i386_insert_aligned_watchpoint (state, addr, len_rw); else if (what == WP_REMOVE) - status = i386_remove_aligned_watchpoint (addr, len_rw); + retval = i386_remove_aligned_watchpoint (state, addr, len_rw); else internal_error (__FILE__, __LINE__, _("\ Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n"), (int)what); - /* We keep the loop going even after a failure, because some - of the other aligned watchpoints might still succeed - (e.g. if they watch addresses that are already watched, - in which case we just increment the reference counts of - occupied debug registers). If we break out of the loop - too early, we could cause those addresses watched by - other watchpoints to be disabled when breakpoint.c reacts - to our failure to insert this watchpoint and tries to - remove it. */ - if (status) - retval = status; + if (retval) + break; } addr += size; @@ -471,27 +560,65 @@ Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n"), return retval; } +/* Update the inferior's debug registers with the new debug registers + state, in NEW_STATE, and then update our local mirror to match. */ + +static void +i386_update_inferior_debug_regs (struct i386_debug_reg_state *new_state) +{ + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); + int i; + + ALL_DEBUG_REGISTERS (i) + { + if (I386_DR_VACANT (new_state, i) != I386_DR_VACANT (state, i)) + i386_dr_low.set_addr (i, new_state->dr_mirror[i]); + else + gdb_assert (new_state->dr_mirror[i] == state->dr_mirror[i]); + } + + if (new_state->dr_control_mirror != state->dr_control_mirror) + i386_dr_low.set_control (new_state->dr_control_mirror); + + *state = *new_state; +} + /* Insert a watchpoint to watch a memory region which starts at address ADDR and whose length is LEN bytes. Watch memory accesses of the type TYPE. Return 0 on success, -1 on failure. */ static int -i386_insert_watchpoint (CORE_ADDR addr, int len, int type) +i386_insert_watchpoint (CORE_ADDR addr, int len, int type, + struct expression *cond) { + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); int retval; + /* Work on a local copy of the debug registers, and on success, + commit the change back to the inferior. */ + struct i386_debug_reg_state local_state = *state; + + if (type == hw_read) + return 1; /* unsupported */ if (((len != 1 && len !=2 && len !=4) && !(TARGET_HAS_DR_LEN_8 && len == 8)) || addr % len != 0) - retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type); + retval = i386_handle_nonaligned_watchpoint (&local_state, + WP_INSERT, addr, len, type); else { unsigned len_rw = i386_length_and_rw_bits (len, type); - retval = i386_insert_aligned_watchpoint (addr, len_rw); + retval = i386_insert_aligned_watchpoint (&local_state, + addr, len_rw); } + if (retval == 0) + i386_update_inferior_debug_regs (&local_state); + if (maint_show_dr) - i386_show_dr ("insert_watchpoint", addr, len, type); + i386_show_dr (state, "insert_watchpoint", addr, len, type); return retval; } @@ -500,22 +627,33 @@ i386_insert_watchpoint (CORE_ADDR addr, int len, int type) address ADDR, whose length is LEN bytes, and for accesses of the type TYPE. Return 0 on success, -1 on failure. */ static int -i386_remove_watchpoint (CORE_ADDR addr, int len, int type) +i386_remove_watchpoint (CORE_ADDR addr, int len, int type, + struct expression *cond) { + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); int retval; + /* Work on a local copy of the debug registers, and on success, + commit the change back to the inferior. */ + struct i386_debug_reg_state local_state = *state; if (((len != 1 && len !=2 && len !=4) && !(TARGET_HAS_DR_LEN_8 && len == 8)) || addr % len != 0) - retval = i386_handle_nonaligned_watchpoint (WP_REMOVE, addr, len, type); + retval = i386_handle_nonaligned_watchpoint (&local_state, + WP_REMOVE, addr, len, type); else { unsigned len_rw = i386_length_and_rw_bits (len, type); - retval = i386_remove_aligned_watchpoint (addr, len_rw); + retval = i386_remove_aligned_watchpoint (&local_state, + addr, len_rw); } + if (retval == 0) + i386_update_inferior_debug_regs (&local_state); + if (maint_show_dr) - i386_show_dr ("remove_watchpoint", addr, len, type); + i386_show_dr (state, "remove_watchpoint", addr, len, type); return retval; } @@ -526,48 +664,91 @@ i386_remove_watchpoint (CORE_ADDR addr, int len, int type) static int i386_region_ok_for_watchpoint (CORE_ADDR addr, int len) { + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); int nregs; /* Compute how many aligned watchpoints we would need to cover this region. */ - nregs = i386_handle_nonaligned_watchpoint (WP_COUNT, addr, len, hw_write); + nregs = i386_handle_nonaligned_watchpoint (state, + WP_COUNT, addr, len, hw_write); return nregs <= DR_NADDR ? 1 : 0; } /* If the inferior has some watchpoint that triggered, set the - address associated with that watchpoint and return non-zero. + address associated with that watchpoint and return non-zero. Otherwise, return zero. */ static int i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) { + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); CORE_ADDR addr = 0; int i; int rc = 0; - - dr_status_mirror = i386_dr_low.get_status (); + /* The current thread's DR_STATUS. We always need to read this to + check whether some watchpoint caused the trap. */ + unsigned status; + /* We need DR_CONTROL as well, but only iff DR_STATUS indicates a + data breakpoint trap. Only fetch it when necessary, to avoid an + unnecessary extra syscall when no watchpoint triggered. */ + int control_p = 0; + unsigned control = 0; + + /* In non-stop/async, threads can be running while we change the + STATE (and friends). Say, we set a watchpoint, and let threads + resume. Now, say you delete the watchpoint, or add/remove + watchpoints such that STATE changes while threads are running. + On targets that support non-stop, inserting/deleting watchpoints + updates the STATE only. It does not update the real thread's + debug registers; that's only done prior to resume. Instead, if + threads are running when the mirror changes, a temporary and + transparent stop on all threads is forced so they can get their + copy of the debug registers updated on re-resume. Now, say, + a thread hit a watchpoint before having been updated with the new + STATE contents, and we haven't yet handled the corresponding + SIGTRAP. If we trusted STATE below, we'd mistake the real + trapped address (from the last time we had updated debug + registers in the thread) with whatever was currently in STATE. + So to fix this, STATE always represents intention, what we _want_ + threads to have in debug registers. To get at the address and + cause of the trap, we need to read the state the thread still has + in its debug registers. + + In sum, always get the current debug register values the current + thread has, instead of trusting the global mirror. If the thread + was running when we last changed watchpoints, the mirror no + longer represents what was set in this thread's debug + registers. */ + status = i386_dr_low.get_status (); ALL_DEBUG_REGISTERS(i) { - if (I386_DR_WATCH_HIT (i) - /* This second condition makes sure DRi is set up for a data - watchpoint, not a hardware breakpoint. The reason is - that GDB doesn't call the target_stopped_data_address - method except for data watchpoints. In other words, I'm - being paranoiac. */ - && I386_DR_GET_RW_LEN (i) != 0 - /* This third condition makes sure DRi is not vacant, this - avoids false positives in windows-nat.c. */ - && !I386_DR_VACANT (i)) + if (!I386_DR_WATCH_HIT (status, i)) + continue; + + if (!control_p) { - addr = dr_mirror[i]; + control = i386_dr_low.get_control (); + control_p = 1; + } + + /* This second condition makes sure DRi is set up for a data + watchpoint, not a hardware breakpoint. The reason is that + GDB doesn't call the target_stopped_data_address method + except for data watchpoints. In other words, I'm being + paranoiac. */ + if (I386_DR_GET_RW_LEN (control, i) != 0) + { + addr = i386_dr_low.get_addr (i); rc = 1; if (maint_show_dr) - i386_show_dr ("watchpoint_hit", addr, -1, hw_write); + i386_show_dr (state, "watchpoint_hit", addr, -1, hw_write); } } if (maint_show_dr && addr == 0) - i386_show_dr ("stopped_data_addr", 0, 0, hw_write); + i386_show_dr (state, "stopped_data_addr", 0, 0, hw_write); if (rc) *addr_p = addr; @@ -587,12 +768,21 @@ static int i386_insert_hw_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt) { + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); unsigned len_rw = i386_length_and_rw_bits (1, hw_execute); CORE_ADDR addr = bp_tgt->placed_address; - int retval = i386_insert_aligned_watchpoint (addr, len_rw) ? EBUSY : 0; + /* Work on a local copy of the debug registers, and on success, + commit the change back to the inferior. */ + struct i386_debug_reg_state local_state = *state; + int retval = i386_insert_aligned_watchpoint (&local_state, + addr, len_rw) ? EBUSY : 0; + + if (retval == 0) + i386_update_inferior_debug_regs (&local_state); if (maint_show_dr) - i386_show_dr ("insert_hwbp", addr, 1, hw_execute); + i386_show_dr (state, "insert_hwbp", addr, 1, hw_execute); return retval; } @@ -604,12 +794,21 @@ static int i386_remove_hw_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt) { + struct i386_debug_reg_state *state + = i386_debug_reg_state (ptid_get_pid (inferior_ptid)); unsigned len_rw = i386_length_and_rw_bits (1, hw_execute); CORE_ADDR addr = bp_tgt->placed_address; - int retval = i386_remove_aligned_watchpoint (addr, len_rw); + /* Work on a local copy of the debug registers, and on success, + commit the change back to the inferior. */ + struct i386_debug_reg_state local_state = *state; + int retval = i386_remove_aligned_watchpoint (&local_state, + addr, len_rw); + + if (retval == 0) + i386_update_inferior_debug_regs (&local_state); if (maint_show_dr) - i386_show_dr ("remove_hwbp", addr, 1, hw_execute); + i386_show_dr (state, "remove_hwbp", addr, 1, hw_execute); return retval; }