+2009-11-22 Pedro Alves <pedro@codesourcery.com>
+ Michael Snyder <msnyder@vmware.com>
+
+ Make hardware watchpoints work for process record.
+
+ * breakpoint.c (hardware_watchpoint_inserted_in_range): New.
+ * breakpoint.h (hardware_watchpoint_inserted_in_range): Declare.
+ * record.c (record_beneath_to_stopped_by_watchpoint)
+ (record_beneath_to_stopped_data_address, record_hw_watchpoint):
+ New globals.
+ (record_exec_insn): Check for watchpoint hits.
+ (tmp_to_stopped_by_watchpoint, tmp_to_stopped_data_address): New
+ globals.
+ (record_open): Set tmp_to_stopped_by_watchpoint,
+ tmp_to_stopped_data_address,
+ record_beneath_to_stopped_by_watchpoint and
+ record_beneath_to_stopped_data_address.
+ (record_wait): Report watchpoint hits to the core. Update and
+ extend comments.
+ (record_stopped_by_watchpoint): New.
+ (record_stopped_data_address): New.
+ (init_record_ops): Install them.
+ (init_record_core_ops): Ditto.
+
2009-11-21 Pedro Alves <pedro@codesourcery.com>
* breakpoint.c (update_watchpoint): Skip creating locations and
struct bp_target_info *);
static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *,
struct bp_target_info *);
+static int (*record_beneath_to_stopped_by_watchpoint) (void);
+static int (*record_beneath_to_stopped_data_address) (struct target_ops *,
+ CORE_ADDR *);
/* Alloc and free functions for record_reg, record_mem, and record_end
entries. */
return old_cleanups;
}
+/* Flag set to TRUE for target_stopped_by_watchpoint. */
+static int record_hw_watchpoint = 0;
+
/* Execute one instruction from the record log. Each instruction in
the log will be represented by an arbitrary sequence of register
entries and memory entries, followed by an 'end' entry. */
entry->u.mem.len);
}
else
- memcpy (record_get_loc (entry), mem, entry->u.mem.len);
+ {
+ memcpy (record_get_loc (entry), mem, entry->u.mem.len);
+
+ /* We've changed memory --- check if a hardware
+ watchpoint should trap. Note that this
+ presently assumes the target beneath supports
+ continuable watchpoints. On non-continuable
+ watchpoints target, we'll want to check this
+ _before_ actually doing the memory change, and
+ not doing the change at all if the watchpoint
+ traps. */
+ if (hardware_watchpoint_inserted_in_range
+ (get_regcache_aspace (regcache),
+ entry->u.mem.addr, entry->u.mem.len))
+ record_hw_watchpoint = 1;
+ }
}
}
}
struct bp_target_info *);
static int (*tmp_to_remove_breakpoint) (struct gdbarch *,
struct bp_target_info *);
+static int (*tmp_to_stopped_by_watchpoint) (void);
+static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
static void record_restore (void);
tmp_to_insert_breakpoint = t->to_insert_breakpoint;
if (!tmp_to_remove_breakpoint)
tmp_to_remove_breakpoint = t->to_remove_breakpoint;
+ if (!tmp_to_stopped_by_watchpoint)
+ tmp_to_stopped_by_watchpoint = t->to_stopped_by_watchpoint;
+ if (!tmp_to_stopped_data_address)
+ tmp_to_stopped_data_address = t->to_stopped_data_address;
}
if (!tmp_to_xfer_partial)
error (_("Could not find 'to_xfer_partial' method on the target stack."));
record_beneath_to_xfer_partial = tmp_to_xfer_partial;
record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
+ record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
+ record_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
if (current_target.to_stratum == core_stratum)
record_core_open_1 (name, from_tty);
{
struct regcache *regcache;
- /* Yes -- check if there is a breakpoint. */
+ /* Yes -- this is likely our single-step finishing,
+ but check if there's any reason the core would be
+ interested in the event. */
+
registers_changed ();
regcache = get_current_regcache ();
tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
- tmp_pc))
+
+ if (target_stopped_by_watchpoint ())
+ {
+ /* Always interested in watchpoints. */
+ }
+ else if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ tmp_pc))
{
- /* There is a breakpoint. GDB will want to stop. */
+ /* There is a breakpoint here. Let the core
+ handle it. */
struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR decr_pc_after_break
= gdbarch_decr_pc_after_break (gdbarch);
}
else
{
- /* There is not a breakpoint, and gdb is not
- stepping, therefore gdb will not stop.
- Therefore we will not return to gdb.
- Record the insn and resume. */
+ /* This must be a single-step trap. Record the
+ insn and issue another step. */
if (!do_record_message (regcache, TARGET_SIGNAL_0))
break;
struct cleanup *old_cleanups = make_cleanup (record_wait_cleanups, 0);
CORE_ADDR tmp_pc;
+ record_hw_watchpoint = 0;
status->kind = TARGET_WAITKIND_STOPPED;
/* Check breakpoint when forward execute. */
gdbarch_decr_pc_after_break (gdbarch));
continue_flag = 0;
}
+
+ if (record_hw_watchpoint)
+ {
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: hit hw watchpoint.\n");
+ continue_flag = 0;
+ }
/* Check target signal */
if (record_list->u.end.sigval != TARGET_SIGNAL_0)
/* FIXME: better way to check */
return inferior_ptid;
}
+static int
+record_stopped_by_watchpoint (void)
+{
+ if (RECORD_IS_REPLAY)
+ return record_hw_watchpoint;
+ else
+ return record_beneath_to_stopped_by_watchpoint ();
+}
+
+static int
+record_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+{
+ if (RECORD_IS_REPLAY)
+ return 0;
+ else
+ return record_beneath_to_stopped_data_address (ops, addr_p);
+}
+
/* "to_disconnect" method for process record target. */
static void
record_ops.to_xfer_partial = record_xfer_partial;
record_ops.to_insert_breakpoint = record_insert_breakpoint;
record_ops.to_remove_breakpoint = record_remove_breakpoint;
+ record_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint;
record_ops.to_can_execute_reverse = record_can_execute_reverse;
record_ops.to_stratum = record_stratum;
/* Add bookmark target methods. */
record_core_ops.to_xfer_partial = record_core_xfer_partial;
record_core_ops.to_insert_breakpoint = record_core_insert_breakpoint;
record_core_ops.to_remove_breakpoint = record_core_remove_breakpoint;
+ record_core_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint;
record_core_ops.to_can_execute_reverse = record_can_execute_reverse;
record_core_ops.to_has_execution = record_core_has_execution;
record_core_ops.to_stratum = record_stratum;