/* Process record and replay target for GDB, the GNU debugger.
- Copyright (C) 2013-2015 Free Software Foundation, Inc.
+ Copyright (C) 2013-2017 Free Software Foundation, Inc.
This file is part of GDB.
}
static void
-record_full_check_insn_num (int set_terminal)
+record_full_check_insn_num (void)
{
if (record_full_insn_num == record_full_insn_max_num)
{
/* Ask user what to do. */
if (record_full_stop_at_limit)
{
- int q;
-
- if (set_terminal)
- target_terminal_ours ();
- q = yquery (_("Do you want to auto delete previous execution "
+ if (!yquery (_("Do you want to auto delete previous execution "
"log entries when record/replay buffer becomes "
- "full (record full stop-at-limit)?"));
- if (set_terminal)
- target_terminal_inferior ();
- if (q)
- record_full_stop_at_limit = 0;
- else
+ "full (record full stop-at-limit)?")))
error (_("Process record: stopped by user."));
+ record_full_stop_at_limit = 0;
}
}
}
record_full_arch_list_tail = NULL;
/* Check record_full_insn_num. */
- record_full_check_insn_num (1);
+ record_full_check_insn_num ();
/* If gdb sends a signal value to target_resume,
save it in the 'end' field of the previous instruction.
static int
record_full_message_wrapper (void *args)
{
- struct record_full_message_args *record_full_args = args;
+ struct record_full_message_args *record_full_args
+ = (struct record_full_message_args *) args;
return record_full_message (record_full_args->regcache,
record_full_args->signal);
args.regcache = regcache;
args.signal = signal;
- return catch_errors (record_full_message_wrapper, &args, NULL,
+ return catch_errors (record_full_message_wrapper, &args, "",
RETURN_MASK_ALL);
}
/* Nothing to do if the entry is flagged not_accessible. */
if (!entry->u.mem.mem_entry_not_accessible)
{
- gdb_byte *mem = alloca (entry->u.mem.len);
+ gdb_byte *mem = (gdb_byte *) xmalloc (entry->u.mem.len);
+ struct cleanup *cleanup = make_cleanup (xfree, mem);
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
}
}
+
+ do_cleanups (cleanup);
}
}
break;
/* Get record_full_core_regbuf. */
target_fetch_registers (regcache, -1);
- record_full_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
+ record_full_core_regbuf = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE * regnum);
for (i = 0; i < regnum; i ++)
regcache_raw_collect (regcache, i,
record_full_core_regbuf + MAX_REGISTER_SIZE * i);
record_full_open_1 (const char *name, int from_tty)
{
if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open_1\n");
/* check exec */
if (!target_has_execution)
record_full_init_record_breakpoints ();
- observer_notify_record_changed (current_inferior (), 1);
+ observer_notify_record_changed (current_inferior (), 1, "full", NULL);
}
/* "to_close" target method. Close the process record target. */
}
else
{
- /* This arch support soft sigle step. */
+ /* This arch supports soft single step. */
if (thread_has_single_step_breakpoints_set (inferior_thread ()))
{
/* This is a soft single step. */
record_full_resume_step = 1;
}
else
- {
- /* This is a continue.
- Try to insert a soft single step breakpoint. */
- if (!gdbarch_software_single_step (gdbarch,
- get_current_frame ()))
- {
- /* This system don't want use soft single step.
- Use hard sigle step. */
- step = 1;
- }
- }
+ step = !insert_single_step_breakpoints (gdbarch);
}
}
target_async (1);
}
+/* "to_commit_resume" method for process record target. */
+
+static void
+record_full_commit_resume (struct target_ops *ops)
+{
+ if (!RECORD_FULL_IS_REPLAY)
+ ops->beneath->to_commit_resume (ops->beneath);
+}
+
static int record_full_get_sig = 0;
/* SIGINT signal handler, registered by "to_wait" method. */
If insert success, set step to 0. */
set_executing (inferior_ptid, 0);
reinit_frame_cache ();
- if (gdbarch_software_single_step (gdbarch,
- get_current_frame ()))
- step = 0;
+
+ step = !insert_single_step_breakpoints (gdbarch);
+
set_executing (inferior_ptid, 1);
}
"target beneath\n");
ops->beneath->to_resume (ops->beneath, ptid, step,
GDB_SIGNAL_0);
+ ops->beneath->to_commit_resume (ops->beneath);
continue;
}
}
record_full_registers_change (struct regcache *regcache, int regnum)
{
/* Check record_full_insn_num. */
- record_full_check_insn_num (0);
+ record_full_check_insn_num ();
record_full_arch_list_head = NULL;
record_full_arch_list_tail = NULL;
}
/* Check record_full_insn_num */
- record_full_check_insn_num (0);
+ record_full_check_insn_num ();
/* Record registers change to list as an instruction. */
record_full_arch_list_head = NULL;
{
struct record_full_breakpoint *bp;
int in_target_beneath = 0;
+ int ix;
if (!RECORD_FULL_IS_REPLAY)
{
really need to install regular breakpoints in the inferior.
However, we do have to insert software single-step
breakpoints, in case the target can't hardware step. To keep
- things single, we always insert. */
+ things simple, we always insert. */
struct cleanup *old_cleanups;
int ret;
in_target_beneath = 1;
}
+ /* Use the existing entries if found in order to avoid duplication
+ in record_full_breakpoints. */
+
+ for (ix = 0;
+ VEC_iterate (record_full_breakpoint_p,
+ record_full_breakpoints, ix, bp);
+ ++ix)
+ {
+ if (bp->addr == bp_tgt->placed_address
+ && bp->address_space == bp_tgt->placed_address_space)
+ {
+ gdb_assert (bp->in_target_beneath == in_target_beneath);
+ return 0;
+ }
+ }
+
bp = XNEW (struct record_full_breakpoint);
bp->addr = bp_tgt->placed_address;
bp->address_space = bp_tgt->placed_address_space;
static int
record_full_remove_breakpoint (struct target_ops *ops,
struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
+ struct bp_target_info *bp_tgt,
+ enum remove_bp_reason reason)
{
struct record_full_breakpoint *bp;
int ix;
old_cleanups = record_full_gdb_operation_disable_set ();
ret = ops->beneath->to_remove_breakpoint (ops->beneath, gdbarch,
- bp_tgt);
+ bp_tgt, reason);
do_cleanups (old_cleanups);
if (ret != 0)
return ret;
}
- VEC_unordered_remove (record_full_breakpoint_p,
- record_full_breakpoints, ix);
+ if (reason == REMOVE_BREAKPOINT)
+ {
+ VEC_unordered_remove (record_full_breakpoint_p,
+ record_full_breakpoints, ix);
+ }
return 0;
}
}
return RECORD_FULL_IS_REPLAY;
}
+/* The "to_record_will_replay" target method. */
+
+static int
+record_full_will_replay (struct target_ops *self, ptid_t ptid, int dir)
+{
+ /* We can currently only record when executing forwards. Should we be able
+ to record when executing backwards on targets that support reverse
+ execution, this needs to be changed. */
+
+ return RECORD_FULL_IS_REPLAY || dir == EXEC_REVERSE;
+}
+
/* Go to a specific entry. */
static void
record_full_goto_entry (p);
}
+/* The "to_record_stop_replaying" target method. */
+
+static void
+record_full_stop_replaying (struct target_ops *self)
+{
+ record_full_goto_end (self);
+}
+
static void
init_record_full_ops (void)
{
record_full_ops.to_close = record_full_close;
record_full_ops.to_async = record_full_async;
record_full_ops.to_resume = record_full_resume;
+ record_full_ops.to_commit_resume = record_full_commit_resume;
record_full_ops.to_wait = record_full_wait;
record_full_ops.to_disconnect = record_disconnect;
record_full_ops.to_detach = record_detach;
record_full_ops.to_save_record = record_full_save;
record_full_ops.to_delete_record = record_full_delete;
record_full_ops.to_record_is_replaying = record_full_is_replaying;
+ record_full_ops.to_record_will_replay = record_full_will_replay;
+ record_full_ops.to_record_stop_replaying = record_full_stop_replaying;
record_full_ops.to_goto_record_begin = record_full_goto_begin;
record_full_ops.to_goto_record_end = record_full_goto_end;
record_full_ops.to_goto_record = record_full_goto;
static int
record_full_core_remove_breakpoint (struct target_ops *ops,
struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
+ struct bp_target_info *bp_tgt,
+ enum remove_bp_reason reason)
{
return 0;
}
record_full_core_ops.to_info_record = record_full_info;
record_full_core_ops.to_delete_record = record_full_delete;
record_full_core_ops.to_record_is_replaying = record_full_is_replaying;
+ record_full_core_ops.to_record_will_replay = record_full_will_replay;
record_full_core_ops.to_goto_record_begin = record_full_goto_begin;
record_full_core_ops.to_goto_record_end = record_full_goto_end;
record_full_core_ops.to_goto_record = record_full_goto;
static void
record_full_save_cleanups (void *data)
{
- bfd *obfd = data;
+ bfd *obfd = (bfd *) data;
char *pathname = xstrdup (bfd_get_filename (obfd));
gdb_bfd_unref (obfd);
recfilename);
/* Open the output file. */
- obfd = create_gcore_bfd (recfilename);
+ obfd = create_gcore_bfd (recfilename).release ();
old_cleanups = make_cleanup (record_full_save_cleanups, obfd);
/* Save the current record entry to "cur_record_full_list". */