/* Process record and replay target for GDB, the GNU debugger.
- Copyright (C) 2013-2018 Free Software Foundation, Inc.
+ Copyright (C) 2013-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcmd.h"
#include "regcache.h"
#include "gdbthread.h"
+#include "inferior.h"
#include "event-top.h"
#include "completer.h"
#include "arch-utils.h"
than count of insns presently in execution log). */
static ULONGEST record_full_insn_count;
+static const char record_longname[]
+ = N_("Process record and replay target");
+static const char record_doc[]
+ = N_("Log program while executing and replay execution from log.");
+
/* Base class implementing functionality common to both the
"record-full" and "record-core" targets. */
class record_full_base_target : public target_ops
{
public:
- record_full_base_target ()
- { to_stratum = record_stratum; }
-
- const char *shortname () override = 0;
-
- const char *longname () override
- { return _("Process record and replay target"); }
+ const target_info &info () const override = 0;
- const char *doc () override
- { return _("Log program while executing and replay execution from log."); }
+ strata stratum () const override { return record_stratum; }
- void open (const char *, int) override;
void close () override;
void async (int) override;
ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
- int stopped_by_watchpoint () override;
- int stopped_data_address (CORE_ADDR *) override;
+ bool stopped_by_watchpoint () override;
+ bool stopped_data_address (CORE_ADDR *) override;
- int stopped_by_sw_breakpoint () override;
- int supports_stopped_by_sw_breakpoint () override;
+ bool stopped_by_sw_breakpoint () override;
+ bool supports_stopped_by_sw_breakpoint () override;
- int stopped_by_hw_breakpoint () override;
- int supports_stopped_by_hw_breakpoint () override;
+ bool stopped_by_hw_breakpoint () override;
+ bool supports_stopped_by_hw_breakpoint () override;
- int can_execute_reverse () override;
+ bool can_execute_reverse () override;
/* Add bookmark target methods. */
gdb_byte *get_bookmark (const char *, int) override;
void save_record (const char *filename) override;
bool supports_delete_record () override;
void delete_record () override;
- int record_is_replaying (ptid_t ptid) override;
- int record_will_replay (ptid_t ptid, int dir) override;
+ bool record_is_replaying (ptid_t ptid) override;
+ bool record_will_replay (ptid_t ptid, int dir) override;
void record_stop_replaying () override;
void goto_record_begin () override;
void goto_record_end () override;
/* The "record-full" target. */
+static const target_info record_full_target_info = {
+ "record-full",
+ record_longname,
+ record_doc,
+};
+
class record_full_target final : public record_full_base_target
{
public:
- const char *shortname () override
- { return "record-full"; }
+ const target_info &info () const override
+ { return record_full_target_info; }
void commit_resume () override;
void resume (ptid_t, int, enum gdb_signal) override;
/* The "record-core" target. */
+static const target_info record_full_core_target_info = {
+ "record-core",
+ record_longname,
+ record_doc,
+};
+
class record_full_core_target final : public record_full_base_target
{
public:
- const char *shortname () override
- { return "record-core"; }
+ const target_info &info () const override
+ { return record_full_core_target_info; }
void resume (ptid_t, int, enum gdb_signal) override;
void disconnect (const char *, int) override;
struct bp_target_info *,
enum remove_bp_reason) override;
- int has_execution (ptid_t) override;
+ bool has_execution (ptid_t) override;
};
static record_full_target record_full_ops;
rec = record_full_reg_alloc (regcache, regnum);
- regcache_raw_read (regcache, regnum, record_full_get_loc (rec));
+ regcache->raw_read (regnum, record_full_get_loc (rec));
record_full_arch_list_add (rec);
}
}
-static void
-record_full_arch_list_cleanups (void *ignore)
-{
- record_full_list_release (record_full_arch_list_tail);
-}
-
/* Before inferior step (when GDB record the running message, inferior
only can step), GDB will call this function to record the values to
record_full_list. This function will call gdbarch_process_record to
{
int ret;
struct gdbarch *gdbarch = regcache->arch ();
- struct cleanup *old_cleanups
- = make_cleanup (record_full_arch_list_cleanups, 0);
- record_full_arch_list_head = NULL;
- record_full_arch_list_tail = NULL;
+ try
+ {
+ record_full_arch_list_head = NULL;
+ record_full_arch_list_tail = NULL;
- /* Check record_full_insn_num. */
- record_full_check_insn_num ();
+ /* Check record_full_insn_num. */
+ record_full_check_insn_num ();
- /* If gdb sends a signal value to target_resume,
- save it in the 'end' field of the previous instruction.
+ /* If gdb sends a signal value to target_resume,
+ save it in the 'end' field of the previous instruction.
- Maybe process record should record what really happened,
- rather than what gdb pretends has happened.
+ Maybe process record should record what really happened,
+ rather than what gdb pretends has happened.
- So if Linux delivered the signal to the child process during
- the record mode, we will record it and deliver it again in
- the replay mode.
+ So if Linux delivered the signal to the child process during
+ the record mode, we will record it and deliver it again in
+ the replay mode.
- If user says "ignore this signal" during the record mode, then
- it will be ignored again during the replay mode (no matter if
- the user says something different, like "deliver this signal"
- during the replay mode).
+ If user says "ignore this signal" during the record mode, then
+ it will be ignored again during the replay mode (no matter if
+ the user says something different, like "deliver this signal"
+ during the replay mode).
- User should understand that nothing he does during the replay
- mode will change the behavior of the child. If he tries,
- then that is a user error.
+ User should understand that nothing he does during the replay
+ mode will change the behavior of the child. If he tries,
+ then that is a user error.
- But we should still deliver the signal to gdb during the replay,
- if we delivered it during the recording. Therefore we should
- record the signal during record_full_wait, not
- record_full_resume. */
- if (record_full_list != &record_full_first) /* FIXME better way to check */
+ But we should still deliver the signal to gdb during the replay,
+ if we delivered it during the recording. Therefore we should
+ record the signal during record_full_wait, not
+ record_full_resume. */
+ if (record_full_list != &record_full_first) /* FIXME better way
+ to check */
+ {
+ gdb_assert (record_full_list->type == record_full_end);
+ record_full_list->u.end.sigval = signal;
+ }
+
+ if (signal == GDB_SIGNAL_0
+ || !gdbarch_process_record_signal_p (gdbarch))
+ ret = gdbarch_process_record (gdbarch,
+ regcache,
+ regcache_read_pc (regcache));
+ else
+ ret = gdbarch_process_record_signal (gdbarch,
+ regcache,
+ signal);
+
+ if (ret > 0)
+ error (_("Process record: inferior program stopped."));
+ if (ret < 0)
+ error (_("Process record: failed to record execution log."));
+ }
+ catch (const gdb_exception &ex)
{
- gdb_assert (record_full_list->type == record_full_end);
- record_full_list->u.end.sigval = signal;
+ record_full_list_release (record_full_arch_list_tail);
+ throw;
}
- if (signal == GDB_SIGNAL_0
- || !gdbarch_process_record_signal_p (gdbarch))
- ret = gdbarch_process_record (gdbarch,
- regcache,
- regcache_read_pc (regcache));
- else
- ret = gdbarch_process_record_signal (gdbarch,
- regcache,
- signal);
-
- if (ret > 0)
- error (_("Process record: inferior program stopped."));
- if (ret < 0)
- error (_("Process record: failed to record execution log."));
-
- discard_cleanups (old_cleanups);
-
record_full_list->next = record_full_arch_list_head;
record_full_arch_list_head->prev = record_full_list;
record_full_list = record_full_arch_list_tail;
record_full_message_wrapper_safe (struct regcache *regcache,
enum gdb_signal signal)
{
- TRY
+ try
{
record_full_message (regcache, signal);
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (const gdb_exception &ex)
{
exception_print (gdb_stderr, ex);
return false;
}
- END_CATCH
return true;
}
host_address_to_string (entry),
entry->u.reg.num);
- regcache_cooked_read (regcache, entry->u.reg.num, reg.data ());
- regcache_cooked_write (regcache, entry->u.reg.num,
- record_full_get_loc (entry));
+ regcache->cooked_read (entry->u.reg.num, reg.data ());
+ regcache->cooked_write (entry->u.reg.num, record_full_get_loc (entry));
memcpy (record_full_get_loc (entry), reg.data (), entry->u.reg.len);
}
break;
inferior_event_handler (INF_REG_EVENT, NULL);
}
-/* Open the process record target. */
+/* Open the process record target for 'core' files. */
static void
record_full_core_open_1 (const char *name, int from_tty)
record_full_restore ();
}
-/* "open" target method for 'live' processes. */
+/* Open the process record target for 'live' processes. */
static void
record_full_open_1 (const char *name, int from_tty)
static void record_full_init_record_breakpoints (void);
-/* "open" target method. Open the process record target. */
+/* Open the process record target. */
-void
-record_full_base_target::open (const char *name, int from_tty)
+static void
+record_full_open (const char *name, int from_tty)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
}
/* Release record_full_core_buf_list. */
- if (record_full_core_buf_list)
+ while (record_full_core_buf_list)
{
- for (entry = record_full_core_buf_list->prev; entry;
- entry = entry->prev)
- {
- xfree (record_full_core_buf_list);
- record_full_core_buf_list = entry;
- }
- record_full_core_buf_list = NULL;
+ entry = record_full_core_buf_list;
+ record_full_core_buf_list = record_full_core_buf_list->prev;
+ xfree (entry);
}
if (record_full_async_inferior_event_token)
else
clear_async_event_handler (record_full_async_inferior_event_token);
- beneath->async (enable);
+ beneath ()->async (enable);
}
static int record_full_resume_step = 0;
}
/* Make sure the target beneath reports all signals. */
- target_pass_signals (0, NULL);
+ target_pass_signals ({});
- this->beneath->resume (ptid, step, signal);
+ this->beneath ()->resume (ptid, step, signal);
}
/* We are about to start executing the inferior (or simulate it),
record_full_target::commit_resume ()
{
if (!RECORD_FULL_IS_REPLAY)
- beneath->commit_resume ();
+ beneath ()->commit_resume ();
}
static int record_full_get_sig = 0;
record_full_get_sig = 1;
}
-static void
-record_full_wait_cleanups (void *ignore)
-{
- if (execution_direction == EXEC_REVERSE)
- {
- if (record_full_list->next)
- record_full_list = record_full_list->next;
- }
- else
- record_full_list = record_full_list->prev;
-}
-
/* "wait" target method for process record target.
In record mode, the target is always run in singlestep mode
if (record_full_resume_step)
{
/* This is a single step. */
- return ops->beneath->wait (ptid, status, options);
+ return ops->beneath ()->wait (ptid, status, options);
}
else
{
while (1)
{
- struct thread_info *tp;
-
- ret = ops->beneath->wait (ptid, status, options);
+ ret = ops->beneath ()->wait (ptid, status, options);
if (status->kind == TARGET_WAITKIND_IGNORE)
{
if (record_debug)
return ret;
}
- ALL_NON_EXITED_THREADS (tp)
+ for (thread_info *tp : all_non_exited_threads ())
delete_single_step_breakpoints (tp);
if (record_full_resume_step)
"Process record: record_full_wait "
"issuing one more step in the "
"target beneath\n");
- ops->beneath->resume (ptid, step, GDB_SIGNAL_0);
- ops->beneath->commit_resume ();
+ ops->beneath ()->resume (ptid, step, GDB_SIGNAL_0);
+ ops->beneath ()->commit_resume ();
continue;
}
}
const struct address_space *aspace = regcache->aspace ();
int continue_flag = 1;
int first_record_full_end = 1;
- struct cleanup *old_cleanups
- = make_cleanup (record_full_wait_cleanups, 0);
- CORE_ADDR tmp_pc;
-
- record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
- status->kind = TARGET_WAITKIND_STOPPED;
- /* Check breakpoint when forward execute. */
- if (execution_direction == EXEC_FORWARD)
+ try
{
- tmp_pc = regcache_read_pc (regcache);
- if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
- &record_full_stop_reason))
- {
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: break at %s.\n",
- paddress (gdbarch, tmp_pc));
- goto replay_out;
- }
- }
-
- /* If GDB is in terminal_inferior mode, it will not get the signal.
- And in GDB replay mode, GDB doesn't need to be in terminal_inferior
- mode, because inferior will not executed.
- Then set it to terminal_ours to make GDB get the signal. */
- target_terminal::ours ();
+ CORE_ADDR tmp_pc;
- /* In EXEC_FORWARD mode, record_full_list points to the tail of prev
- instruction. */
- if (execution_direction == EXEC_FORWARD && record_full_list->next)
- record_full_list = record_full_list->next;
+ record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
+ status->kind = TARGET_WAITKIND_STOPPED;
- /* Loop over the record_full_list, looking for the next place to
- stop. */
- do
- {
- /* Check for beginning and end of log. */
- if (execution_direction == EXEC_REVERSE
- && record_full_list == &record_full_first)
- {
- /* Hit beginning of record log in reverse. */
- status->kind = TARGET_WAITKIND_NO_HISTORY;
- break;
- }
- if (execution_direction != EXEC_REVERSE && !record_full_list->next)
+ /* Check breakpoint when forward execute. */
+ if (execution_direction == EXEC_FORWARD)
{
- /* Hit end of record log going forward. */
- status->kind = TARGET_WAITKIND_NO_HISTORY;
- break;
+ tmp_pc = regcache_read_pc (regcache);
+ if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
+ &record_full_stop_reason))
+ {
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: break at %s.\n",
+ paddress (gdbarch, tmp_pc));
+ goto replay_out;
+ }
}
- record_full_exec_insn (regcache, gdbarch, record_full_list);
-
- if (record_full_list->type == record_full_end)
+ /* If GDB is in terminal_inferior mode, it will not get the
+ signal. And in GDB replay mode, GDB doesn't need to be
+ in terminal_inferior mode, because inferior will not
+ executed. Then set it to terminal_ours to make GDB get
+ the signal. */
+ target_terminal::ours ();
+
+ /* In EXEC_FORWARD mode, record_full_list points to the tail of prev
+ instruction. */
+ if (execution_direction == EXEC_FORWARD && record_full_list->next)
+ record_full_list = record_full_list->next;
+
+ /* Loop over the record_full_list, looking for the next place to
+ stop. */
+ do
{
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_end %s to "
- "inferior.\n",
- host_address_to_string (record_full_list));
-
- if (first_record_full_end && execution_direction == EXEC_REVERSE)
+ /* Check for beginning and end of log. */
+ if (execution_direction == EXEC_REVERSE
+ && record_full_list == &record_full_first)
{
- /* When reverse excute, the first record_full_end is the
- part of current instruction. */
- first_record_full_end = 0;
+ /* Hit beginning of record log in reverse. */
+ status->kind = TARGET_WAITKIND_NO_HISTORY;
+ break;
}
- else
+ if (execution_direction != EXEC_REVERSE
+ && !record_full_list->next)
+ {
+ /* Hit end of record log going forward. */
+ status->kind = TARGET_WAITKIND_NO_HISTORY;
+ break;
+ }
+
+ record_full_exec_insn (regcache, gdbarch, record_full_list);
+
+ if (record_full_list->type == record_full_end)
{
- /* In EXEC_REVERSE mode, this is the record_full_end of prev
- instruction.
- In EXEC_FORWARD mode, this is the record_full_end of
- current instruction. */
- /* step */
- if (record_full_resume_step)
+ if (record_debug > 1)
+ fprintf_unfiltered
+ (gdb_stdlog,
+ "Process record: record_full_end %s to "
+ "inferior.\n",
+ host_address_to_string (record_full_list));
+
+ if (first_record_full_end
+ && execution_direction == EXEC_REVERSE)
{
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: step.\n");
- continue_flag = 0;
+ /* When reverse excute, the first
+ record_full_end is the part of current
+ instruction. */
+ first_record_full_end = 0;
}
-
- /* check breakpoint */
- tmp_pc = regcache_read_pc (regcache);
- if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
- &record_full_stop_reason))
+ else
{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: break "
- "at %s.\n",
- paddress (gdbarch, tmp_pc));
+ /* In EXEC_REVERSE mode, this is the
+ record_full_end of prev instruction. In
+ EXEC_FORWARD mode, this is the
+ record_full_end of current instruction. */
+ /* step */
+ if (record_full_resume_step)
+ {
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: step.\n");
+ continue_flag = 0;
+ }
- continue_flag = 0;
- }
+ /* check breakpoint */
+ tmp_pc = regcache_read_pc (regcache);
+ if (record_check_stopped_by_breakpoint
+ (aspace, tmp_pc, &record_full_stop_reason))
+ {
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: break "
+ "at %s.\n",
+ paddress (gdbarch, tmp_pc));
- if (record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
- {
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: hit hw "
- "watchpoint.\n");
- continue_flag = 0;
+ continue_flag = 0;
+ }
+
+ if (record_full_stop_reason
+ == TARGET_STOPPED_BY_WATCHPOINT)
+ {
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: hit hw "
+ "watchpoint.\n");
+ continue_flag = 0;
+ }
+ /* Check target signal */
+ if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
+ /* FIXME: better way to check */
+ continue_flag = 0;
}
- /* Check target signal */
- if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
- /* FIXME: better way to check */
- continue_flag = 0;
}
- }
- if (continue_flag)
- {
- if (execution_direction == EXEC_REVERSE)
+ if (continue_flag)
{
- if (record_full_list->prev)
- record_full_list = record_full_list->prev;
- }
- else
- {
- if (record_full_list->next)
- record_full_list = record_full_list->next;
+ if (execution_direction == EXEC_REVERSE)
+ {
+ if (record_full_list->prev)
+ record_full_list = record_full_list->prev;
+ }
+ else
+ {
+ if (record_full_list->next)
+ record_full_list = record_full_list->next;
+ }
}
}
+ while (continue_flag);
+
+ replay_out:
+ if (record_full_get_sig)
+ status->value.sig = GDB_SIGNAL_INT;
+ else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
+ /* FIXME: better way to check */
+ status->value.sig = record_full_list->u.end.sigval;
+ else
+ status->value.sig = GDB_SIGNAL_TRAP;
}
- while (continue_flag);
-
-replay_out:
- if (record_full_get_sig)
- status->value.sig = GDB_SIGNAL_INT;
- else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
- /* FIXME: better way to check */
- status->value.sig = record_full_list->u.end.sigval;
- else
- status->value.sig = GDB_SIGNAL_TRAP;
+ catch (const gdb_exception &ex)
+ {
+ if (execution_direction == EXEC_REVERSE)
+ {
+ if (record_full_list->next)
+ record_full_list = record_full_list->next;
+ }
+ else
+ record_full_list = record_full_list->prev;
- discard_cleanups (old_cleanups);
+ throw;
+ }
}
signal (SIGINT, handle_sigint);
return return_ptid;
}
-int
+bool
record_full_base_target::stopped_by_watchpoint ()
{
if (RECORD_FULL_IS_REPLAY)
return record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
else
- return beneath->stopped_by_watchpoint ();
+ return beneath ()->stopped_by_watchpoint ();
}
-int
+bool
record_full_base_target::stopped_data_address (CORE_ADDR *addr_p)
{
if (RECORD_FULL_IS_REPLAY)
- return 0;
+ return false;
else
- return this->beneath->stopped_data_address (addr_p);
+ return this->beneath ()->stopped_data_address (addr_p);
}
/* The stopped_by_sw_breakpoint method of target record-full. */
-int
+bool
record_full_base_target::stopped_by_sw_breakpoint ()
{
return record_full_stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
/* The supports_stopped_by_sw_breakpoint method of target
record-full. */
-int
+bool
record_full_base_target::supports_stopped_by_sw_breakpoint ()
{
- return 1;
+ return true;
}
/* The stopped_by_hw_breakpoint method of target record-full. */
-int
+bool
record_full_base_target::stopped_by_hw_breakpoint ()
{
return record_full_stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
/* The supports_stopped_by_sw_breakpoint method of target
record-full. */
-int
+bool
record_full_base_target::supports_stopped_by_hw_breakpoint ()
{
- return 1;
+ return true;
}
/* Record registers change (by user or by GDB) to list as an instruction. */
for (i = 0;
i < gdbarch_num_regs (regcache->arch ());
i++)
- regcache_invalidate (regcache, i);
+ regcache->invalidate (i);
}
else
- regcache_invalidate (regcache, regno);
+ regcache->invalidate (regno);
error (_("Process record canceled the operation."));
}
record_full_registers_change (regcache, regno);
}
- this->beneath->store_registers (regcache, regno);
+ this->beneath ()->store_registers (regcache, regno);
}
/* "xfer_partial" method. Behavior is conditional on
record_full_insn_num++;
}
- return this->beneath->xfer_partial (object, annex, readbuf, writebuf, offset,
- len, xfered_len);
+ return this->beneath ()->xfer_partial (object, annex, readbuf, writebuf,
+ offset, len, xfered_len);
}
/* This structure represents a breakpoint inserted while the record
struct record_full_breakpoint
{
+ record_full_breakpoint (struct address_space *address_space_,
+ CORE_ADDR addr_,
+ bool in_target_beneath_)
+ : address_space (address_space_),
+ addr (addr_),
+ in_target_beneath (in_target_beneath_)
+ {
+ }
+
/* The address and address space the breakpoint was set at. */
struct address_space *address_space;
CORE_ADDR addr;
/* True when the breakpoint has been also installed in the target
beneath. This will be false for breakpoints set during replay or
when recording. */
- int in_target_beneath;
+ bool in_target_beneath;
};
-typedef struct record_full_breakpoint *record_full_breakpoint_p;
-DEF_VEC_P(record_full_breakpoint_p);
-
/* The list of breakpoints inserted while the record target is
active. */
-VEC(record_full_breakpoint_p) *record_full_breakpoints = NULL;
+static std::vector<record_full_breakpoint> record_full_breakpoints;
static void
record_full_sync_record_breakpoints (struct bp_location *loc, void *data)
if (loc->inserted)
{
- struct record_full_breakpoint *bp = XNEW (struct record_full_breakpoint);
-
- bp->addr = loc->target_info.placed_address;
- bp->address_space = loc->target_info.placed_address_space;
-
- bp->in_target_beneath = 1;
-
- VEC_safe_push (record_full_breakpoint_p, record_full_breakpoints, bp);
+ record_full_breakpoints.emplace_back
+ (loc->target_info.placed_address_space,
+ loc->target_info.placed_address,
+ 1);
}
}
static void
record_full_init_record_breakpoints (void)
{
- VEC_free (record_full_breakpoint_p, record_full_breakpoints);
+ record_full_breakpoints.clear ();
iterate_over_bp_locations (record_full_sync_record_breakpoints);
}
record_full_target::insert_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- struct record_full_breakpoint *bp;
- int in_target_beneath = 0;
- int ix;
+ bool in_target_beneath = false;
if (!RECORD_FULL_IS_REPLAY)
{
scoped_restore restore_operation_disable
= record_full_gdb_operation_disable_set ();
- int ret = this->beneath->insert_breakpoint (gdbarch, bp_tgt);
+ int ret = this->beneath ()->insert_breakpoint (gdbarch, bp_tgt);
if (ret != 0)
return ret;
- in_target_beneath = 1;
+ in_target_beneath = true;
}
/* 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)
+ for (const record_full_breakpoint &bp : record_full_breakpoints)
{
- if (bp->addr == bp_tgt->placed_address
- && bp->address_space == bp_tgt->placed_address_space)
+ if (bp.addr == bp_tgt->placed_address
+ && bp.address_space == bp_tgt->placed_address_space)
{
- gdb_assert (bp->in_target_beneath == in_target_beneath);
+ 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;
- bp->in_target_beneath = in_target_beneath;
- VEC_safe_push (record_full_breakpoint_p, record_full_breakpoints, bp);
+ record_full_breakpoints.emplace_back (bp_tgt->placed_address_space,
+ bp_tgt->placed_address,
+ in_target_beneath);
return 0;
}
struct bp_target_info *bp_tgt,
enum remove_bp_reason reason)
{
- struct record_full_breakpoint *bp;
- int ix;
-
- for (ix = 0;
- VEC_iterate (record_full_breakpoint_p,
- record_full_breakpoints, ix, bp);
- ++ix)
+ for (auto iter = record_full_breakpoints.begin ();
+ iter != record_full_breakpoints.end ();
+ ++iter)
{
- if (bp->addr == bp_tgt->placed_address
- && bp->address_space == bp_tgt->placed_address_space)
+ struct record_full_breakpoint &bp = *iter;
+
+ if (bp.addr == bp_tgt->placed_address
+ && bp.address_space == bp_tgt->placed_address_space)
{
- if (bp->in_target_beneath)
+ if (bp.in_target_beneath)
{
scoped_restore restore_operation_disable
= record_full_gdb_operation_disable_set ();
- int ret = this->beneath->remove_breakpoint (gdbarch, bp_tgt,
- reason);
+ int ret = this->beneath ()->remove_breakpoint (gdbarch, bp_tgt,
+ reason);
if (ret != 0)
return ret;
}
if (reason == REMOVE_BREAKPOINT)
- {
- VEC_unordered_remove (record_full_breakpoint_p,
- record_full_breakpoints, ix);
- }
+ unordered_remove (record_full_breakpoints, iter);
return 0;
}
}
/* "can_execute_reverse" method for process record target. */
-int
+bool
record_full_base_target::can_execute_reverse ()
{
- return 1;
+ return true;
}
/* "get_bookmark" method for process record and prec over core. */
/* The "record_is_replaying" target method. */
-int
+bool
record_full_base_target::record_is_replaying (ptid_t ptid)
{
return RECORD_FULL_IS_REPLAY;
/* The "record_will_replay" target method. */
-int
+bool
record_full_base_target::record_will_replay (ptid_t ptid, int dir)
{
/* We can currently only record when executing forwards. Should we be able
registers_changed ();
reinit_frame_cache ();
- stop_pc = regcache_read_pc (get_current_regcache ());
+ inferior_thread ()->suspend.stop_pc
+ = regcache_read_pc (get_current_regcache ());
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
else
{
if (!entry)
- return this->beneath->xfer_partial (object, annex,
- readbuf, writebuf,
- offset, len,
- xfered_len);
+ return this->beneath ()->xfer_partial (object, annex,
+ readbuf, writebuf,
+ offset, len,
+ xfered_len);
memcpy (readbuf, entry->buf + sec_offset,
(size_t) len);
error (_("You can't do that without a process to debug."));
}
- return this->beneath->xfer_partial (object, annex,
- readbuf, writebuf, offset, len,
- xfered_len);
+ return this->beneath ()->xfer_partial (object, annex,
+ readbuf, writebuf, offset, len,
+ xfered_len);
}
/* "insert_breakpoint" method for prec over corefile. */
/* "has_execution" method for prec over corefile. */
-int
+bool
record_full_core_target::has_execution (ptid_t the_ptid)
{
- return 1;
+ return true;
}
/* Record log save-file format
record_full_restore (void)
{
uint32_t magic;
- struct cleanup *old_cleanups;
struct record_full_entry *rec;
asection *osec;
uint32_t osec_size;
record_full_arch_list_head = NULL;
record_full_arch_list_tail = NULL;
record_full_insn_num = 0;
- old_cleanups = make_cleanup (record_full_arch_list_cleanups, 0);
- regcache = get_current_regcache ();
- while (1)
+ try
{
- uint8_t rectype;
- uint32_t regnum, len, signal, count;
- uint64_t addr;
+ regcache = get_current_regcache ();
- /* We are finished when offset reaches osec_size. */
- if (bfd_offset >= osec_size)
- break;
- bfdcore_read (core_bfd, osec, &rectype, sizeof (rectype), &bfd_offset);
+ while (1)
+ {
+ uint8_t rectype;
+ uint32_t regnum, len, signal, count;
+ uint64_t addr;
- switch (rectype)
- {
- case record_full_reg: /* reg */
- /* Get register number to regnum. */
- bfdcore_read (core_bfd, osec, ®num,
- sizeof (regnum), &bfd_offset);
- regnum = netorder32 (regnum);
+ /* We are finished when offset reaches osec_size. */
+ if (bfd_offset >= osec_size)
+ break;
+ bfdcore_read (core_bfd, osec, &rectype, sizeof (rectype), &bfd_offset);
- rec = record_full_reg_alloc (regcache, regnum);
+ switch (rectype)
+ {
+ case record_full_reg: /* reg */
+ /* Get register number to regnum. */
+ bfdcore_read (core_bfd, osec, ®num,
+ sizeof (regnum), &bfd_offset);
+ regnum = netorder32 (regnum);
- /* Get val. */
- bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
- rec->u.reg.len, &bfd_offset);
+ rec = record_full_reg_alloc (regcache, regnum);
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Reading register %d (1 "
- "plus %lu plus %d bytes)\n",
- rec->u.reg.num,
- (unsigned long) sizeof (regnum),
- rec->u.reg.len);
- break;
-
- case record_full_mem: /* mem */
- /* Get len. */
- bfdcore_read (core_bfd, osec, &len,
- sizeof (len), &bfd_offset);
- len = netorder32 (len);
-
- /* Get addr. */
- bfdcore_read (core_bfd, osec, &addr,
- sizeof (addr), &bfd_offset);
- addr = netorder64 (addr);
-
- rec = record_full_mem_alloc (addr, len);
-
- /* Get val. */
- bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
- rec->u.mem.len, &bfd_offset);
+ /* Get val. */
+ bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
+ rec->u.reg.len, &bfd_offset);
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Reading memory %s (1 plus "
- "%lu plus %lu plus %d bytes)\n",
- paddress (get_current_arch (),
- rec->u.mem.addr),
- (unsigned long) sizeof (addr),
- (unsigned long) sizeof (len),
- rec->u.mem.len);
- break;
-
- case record_full_end: /* end */
- rec = record_full_end_alloc ();
- record_full_insn_num ++;
-
- /* Get signal value. */
- bfdcore_read (core_bfd, osec, &signal,
- sizeof (signal), &bfd_offset);
- signal = netorder32 (signal);
- rec->u.end.sigval = (enum gdb_signal) signal;
-
- /* Get insn count. */
- bfdcore_read (core_bfd, osec, &count,
- sizeof (count), &bfd_offset);
- count = netorder32 (count);
- rec->u.end.insn_num = count;
- record_full_insn_count = count + 1;
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Reading record_full_end (1 + "
- "%lu + %lu bytes), offset == %s\n",
- (unsigned long) sizeof (signal),
- (unsigned long) sizeof (count),
- paddress (get_current_arch (),
- bfd_offset));
- break;
-
- default:
- error (_("Bad entry type in core file %s."),
- bfd_get_filename (core_bfd));
- break;
- }
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Reading register %d (1 "
+ "plus %lu plus %d bytes)\n",
+ rec->u.reg.num,
+ (unsigned long) sizeof (regnum),
+ rec->u.reg.len);
+ break;
- /* Add rec to record arch list. */
- record_full_arch_list_add (rec);
- }
+ case record_full_mem: /* mem */
+ /* Get len. */
+ bfdcore_read (core_bfd, osec, &len,
+ sizeof (len), &bfd_offset);
+ len = netorder32 (len);
- discard_cleanups (old_cleanups);
+ /* Get addr. */
+ bfdcore_read (core_bfd, osec, &addr,
+ sizeof (addr), &bfd_offset);
+ addr = netorder64 (addr);
+
+ rec = record_full_mem_alloc (addr, len);
+
+ /* Get val. */
+ bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
+ rec->u.mem.len, &bfd_offset);
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Reading memory %s (1 plus "
+ "%lu plus %lu plus %d bytes)\n",
+ paddress (get_current_arch (),
+ rec->u.mem.addr),
+ (unsigned long) sizeof (addr),
+ (unsigned long) sizeof (len),
+ rec->u.mem.len);
+ break;
+
+ case record_full_end: /* end */
+ rec = record_full_end_alloc ();
+ record_full_insn_num ++;
+
+ /* Get signal value. */
+ bfdcore_read (core_bfd, osec, &signal,
+ sizeof (signal), &bfd_offset);
+ signal = netorder32 (signal);
+ rec->u.end.sigval = (enum gdb_signal) signal;
+
+ /* Get insn count. */
+ bfdcore_read (core_bfd, osec, &count,
+ sizeof (count), &bfd_offset);
+ count = netorder32 (count);
+ rec->u.end.insn_num = count;
+ record_full_insn_count = count + 1;
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Reading record_full_end (1 + "
+ "%lu + %lu bytes), offset == %s\n",
+ (unsigned long) sizeof (signal),
+ (unsigned long) sizeof (count),
+ paddress (get_current_arch (),
+ bfd_offset));
+ break;
+
+ default:
+ error (_("Bad entry type in core file %s."),
+ bfd_get_filename (core_bfd));
+ break;
+ }
+
+ /* Add rec to record arch list. */
+ record_full_arch_list_add (rec);
+ }
+ }
+ catch (const gdb_exception &ex)
+ {
+ record_full_list_release (record_full_arch_list_tail);
+ throw;
+ }
/* Add record_full_arch_list_head to the end of record list. */
record_full_first.next = record_full_arch_list_head;
cmd_record_full_restore (const char *args, int from_tty)
{
core_file_command (args, from_tty);
- record_full_ops.open (args, from_tty);
+ record_full_open (args, from_tty);
}
/* Save the execution log to a file. We use a modified elf corefile
record_full_first.next = NULL;
record_full_first.type = record_full_end;
- add_target (&record_full_ops);
- add_deprecated_target_alias (&record_full_ops, "record");
- add_target (&record_full_core_ops);
+ add_target (record_full_target_info, record_full_open);
+ add_deprecated_target_alias (record_full_target_info, "record");
+ add_target (record_full_core_target_info, record_full_open);
add_prefix_cmd ("full", class_obscure, cmd_record_full_start,
_("Start full execution recording."), &record_full_cmdlist,