/* Process record and replay target for GDB, the GNU debugger.
- Copyright (C) 2013 Free Software Foundation, Inc.
+ Copyright (C) 2013-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include "regcache.h"
#include "gdbthread.h"
#include "event-top.h"
-#include "exceptions.h"
#include "completer.h"
#include "arch-utils.h"
#include "gdbcore.h"
#include "inf-loop.h"
#include "gdb_bfd.h"
#include "observer.h"
+#include "infrun.h"
#include <signal.h>
/* If true, query if PREC cannot record memory
change of next instruction. */
-int record_memory_query = 0;
+int record_full_memory_query = 0;
struct record_full_core_buf_entry
{
static unsigned int record_full_insn_max_num
= DEFAULT_RECORD_FULL_INSN_MAX_NUM;
/* Actual count of insns presently in execution log. */
-static int record_full_insn_num = 0;
+static unsigned int record_full_insn_num = 0;
/* Count of insns logged so far (may be larger
than count of insns presently in execution log). */
static ULONGEST record_full_insn_count;
static struct target_ops record_full_ops;
static struct target_ops record_full_core_ops;
+/* See record-full.h. */
+
+int
+record_full_is_used (void)
+{
+ struct target_ops *t;
+
+ t = find_record_target ();
+ return (t == &record_full_ops
+ || t == &record_full_core_ops);
+}
+
+
/* Command lists for "set/show record full". */
static struct cmd_list_element *set_record_full_cmdlist;
static struct cmd_list_element *show_record_full_cmdlist;
/* Command list for "record full". */
static struct cmd_list_element *record_full_cmdlist;
-/* The beneath function pointers. */
-static struct target_ops *record_full_beneath_to_resume_ops;
-static void (*record_full_beneath_to_resume) (struct target_ops *, ptid_t, int,
- enum gdb_signal);
-static struct target_ops *record_full_beneath_to_wait_ops;
-static ptid_t (*record_full_beneath_to_wait) (struct target_ops *, ptid_t,
- struct target_waitstatus *,
- int);
-static struct target_ops *record_full_beneath_to_store_registers_ops;
-static void (*record_full_beneath_to_store_registers) (struct target_ops *,
- struct regcache *,
- int regno);
-static struct target_ops *record_full_beneath_to_xfer_partial_ops;
-static LONGEST
- (*record_full_beneath_to_xfer_partial) (struct target_ops *ops,
- enum target_object object,
- const char *annex,
- gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset,
- LONGEST len);
-static int
- (*record_full_beneath_to_insert_breakpoint) (struct gdbarch *,
- struct bp_target_info *);
-static int
- (*record_full_beneath_to_remove_breakpoint) (struct gdbarch *,
- struct bp_target_info *);
-static int (*record_full_beneath_to_stopped_by_watchpoint) (void);
-static int (*record_full_beneath_to_stopped_data_address) (struct target_ops *,
- CORE_ADDR *);
-static void
- (*record_full_beneath_to_async) (void (*) (enum inferior_event_type, void *),
- void *);
-
static void record_full_goto_insn (struct record_full_entry *entry,
enum exec_direction_kind dir);
-static void record_full_save (char *recfilename);
+static void record_full_save (struct target_ops *self,
+ const char *recfilename);
/* Alloc and free functions for record_full_reg, record_full_mem, and
record_full_end entries. */
struct record_full_entry *rec;
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- rec = xcalloc (1, sizeof (struct record_full_entry));
+ rec = XCNEW (struct record_full_entry);
rec->type = record_full_reg;
rec->u.reg.num = regnum;
rec->u.reg.len = register_size (gdbarch, regnum);
{
struct record_full_entry *rec;
- rec = xcalloc (1, sizeof (struct record_full_entry));
+ rec = XCNEW (struct record_full_entry);
rec->type = record_full_mem;
rec->u.mem.addr = addr;
rec->u.mem.len = len;
{
struct record_full_entry *rec;
- rec = xcalloc (1, sizeof (struct record_full_entry));
+ rec = XCNEW (struct record_full_entry);
rec->type = record_full_end;
return rec;
/* Record the value of a register NUM to record_full_arch_list. */
int
-record_arch_list_add_reg (struct regcache *regcache, int regnum)
+record_full_arch_list_add_reg (struct regcache *regcache, int regnum)
{
struct record_full_entry *rec;
length is LEN to record_full_arch_list. */
int
-record_arch_list_add_mem (CORE_ADDR addr, int len)
+record_full_arch_list_add_mem (CORE_ADDR addr, int len)
{
struct record_full_entry *rec;
record_full_arch_list. */
int
-record_arch_list_add_end (void)
+record_full_arch_list_add_end (void)
{
struct record_full_entry *rec;
static void
record_full_check_insn_num (int set_terminal)
{
- if (record_full_insn_max_num)
+ if (record_full_insn_num == record_full_insn_max_num)
{
- gdb_assert (record_full_insn_num <= record_full_insn_max_num);
- if (record_full_insn_num == record_full_insn_max_num)
+ /* Ask user what to do. */
+ if (record_full_stop_at_limit)
{
- /* 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 "
- "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
- error (_("Process record: stopped by user."));
- }
+ int q;
+
+ if (set_terminal)
+ target_terminal_ours ();
+ q = 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
+ error (_("Process record: stopped by user."));
}
}
}
record_full_arch_list_head->prev = record_full_list;
record_full_list = record_full_arch_list_tail;
- if (record_full_insn_num == record_full_insn_max_num
- && record_full_insn_max_num)
+ if (record_full_insn_num == record_full_insn_max_num)
record_full_list_release_first ();
else
record_full_insn_num++;
static int record_full_gdb_operation_disable = 0;
struct cleanup *
-record_gdb_operation_disable_set (void)
+record_full_gdb_operation_disable_set (void)
{
struct cleanup *old_cleanups = NULL;
}
/* Flag set to TRUE for target_stopped_by_watchpoint. */
-static int record_full_hw_watchpoint = 0;
+static enum target_stop_reason record_full_stop_reason
+ = TARGET_STOPPED_BY_NO_REASON;
/* Execute one instruction from the record log. Each instruction in
the log will be represented by an arbitrary sequence of register
if (hardware_watchpoint_inserted_in_range
(get_regcache_aspace (regcache),
entry->u.mem.addr, entry->u.mem.len))
- record_full_hw_watchpoint = 1;
+ record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
}
}
}
}
}
-static struct target_ops *tmp_to_resume_ops;
-static void (*tmp_to_resume) (struct target_ops *, ptid_t, int,
- enum gdb_signal);
-static struct target_ops *tmp_to_wait_ops;
-static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t,
- struct target_waitstatus *,
- int);
-static struct target_ops *tmp_to_store_registers_ops;
-static void (*tmp_to_store_registers) (struct target_ops *,
- struct regcache *,
- int regno);
-static struct target_ops *tmp_to_xfer_partial_ops;
-static LONGEST (*tmp_to_xfer_partial) (struct target_ops *ops,
- enum target_object object,
- const char *annex,
- gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset,
- LONGEST len);
-static int (*tmp_to_insert_breakpoint) (struct gdbarch *,
- 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 int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
-static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *);
-
static void record_full_restore (void);
/* Asynchronous signal handle registered as event loop source for when
/* Open the process record target. */
static void
-record_full_core_open_1 (char *name, int from_tty)
+record_full_core_open_1 (const char *name, int from_tty)
{
struct regcache *regcache = get_current_regcache ();
int regnum = gdbarch_num_regs (get_regcache_arch (regcache));
/* "to_open" target method for 'live' processes. */
static void
-record_full_open_1 (char *name, int from_tty)
+record_full_open_1 (const char *name, int from_tty)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
error (_("Process record: the current architecture doesn't support "
"record function."));
- if (!tmp_to_resume)
- error (_("Could not find 'to_resume' method on the target stack."));
- if (!tmp_to_wait)
- error (_("Could not find 'to_wait' method on the target stack."));
- if (!tmp_to_store_registers)
- error (_("Could not find 'to_store_registers' "
- "method on the target stack."));
- if (!tmp_to_insert_breakpoint)
- error (_("Could not find 'to_insert_breakpoint' "
- "method on the target stack."));
- if (!tmp_to_remove_breakpoint)
- error (_("Could not find 'to_remove_breakpoint' "
- "method on the target stack."));
- if (!tmp_to_stopped_by_watchpoint)
- error (_("Could not find 'to_stopped_by_watchpoint' "
- "method on the target stack."));
- if (!tmp_to_stopped_data_address)
- error (_("Could not find 'to_stopped_data_address' "
- "method on the target stack."));
-
push_target (&record_full_ops);
}
/* "to_open" target method. Open the process record target. */
static void
-record_full_open (char *name, int from_tty)
+record_full_open (const char *name, int from_tty)
{
struct target_ops *t;
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
- /* Check if record target is already running. */
- if (current_target.to_stratum == record_stratum)
- error (_("Process record target already running. Use \"record stop\" to "
- "stop record target first."));
-
- /* Reset the tmp beneath pointers. */
- tmp_to_resume_ops = NULL;
- tmp_to_resume = NULL;
- tmp_to_wait_ops = NULL;
- tmp_to_wait = NULL;
- tmp_to_store_registers_ops = NULL;
- tmp_to_store_registers = NULL;
- tmp_to_xfer_partial_ops = NULL;
- tmp_to_xfer_partial = NULL;
- tmp_to_insert_breakpoint = NULL;
- tmp_to_remove_breakpoint = NULL;
- tmp_to_stopped_by_watchpoint = NULL;
- tmp_to_stopped_data_address = NULL;
- tmp_to_async = NULL;
-
- /* Set the beneath function pointers. */
- for (t = current_target.beneath; t != NULL; t = t->beneath)
- {
- if (!tmp_to_resume)
- {
- tmp_to_resume = t->to_resume;
- tmp_to_resume_ops = t;
- }
- if (!tmp_to_wait)
- {
- tmp_to_wait = t->to_wait;
- tmp_to_wait_ops = t;
- }
- if (!tmp_to_store_registers)
- {
- tmp_to_store_registers = t->to_store_registers;
- tmp_to_store_registers_ops = t;
- }
- if (!tmp_to_xfer_partial)
- {
- tmp_to_xfer_partial = t->to_xfer_partial;
- tmp_to_xfer_partial_ops = t;
- }
- if (!tmp_to_insert_breakpoint)
- 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_async)
- tmp_to_async = t->to_async;
- }
- if (!tmp_to_xfer_partial)
- error (_("Could not find 'to_xfer_partial' method on the target stack."));
+ record_preopen ();
/* Reset */
record_full_insn_num = 0;
record_full_list = &record_full_first;
record_full_list->next = NULL;
- /* Set the tmp beneath pointers to beneath pointers. */
- record_full_beneath_to_resume_ops = tmp_to_resume_ops;
- record_full_beneath_to_resume = tmp_to_resume;
- record_full_beneath_to_wait_ops = tmp_to_wait_ops;
- record_full_beneath_to_wait = tmp_to_wait;
- record_full_beneath_to_store_registers_ops = tmp_to_store_registers_ops;
- record_full_beneath_to_store_registers = tmp_to_store_registers;
- record_full_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops;
- record_full_beneath_to_xfer_partial = tmp_to_xfer_partial;
- record_full_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
- record_full_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
- record_full_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
- record_full_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
- record_full_beneath_to_async = tmp_to_async;
-
if (core_bfd)
record_full_core_open_1 (name, from_tty);
else
/* "to_close" target method. Close the process record target. */
static void
-record_full_close (int quitting)
+record_full_close (struct target_ops *self)
{
struct record_full_core_buf_entry *entry;
delete_async_event_handler (&record_full_async_inferior_event_token);
}
+/* "to_async" target method. */
+
+static void
+record_full_async (struct target_ops *ops, int enable)
+{
+ if (enable)
+ mark_async_event_handler (record_full_async_inferior_event_token);
+ else
+ clear_async_event_handler (record_full_async_inferior_event_token);
+
+ ops->beneath->to_async (ops->beneath, enable);
+}
+
static int record_full_resume_step = 0;
/* True if we've been resumed, and so each record_full_wait call should
else
{
/* This arch support soft sigle step. */
- if (single_step_breakpoints_inserted ())
+ if (thread_has_single_step_breakpoints_set (inferior_thread ()))
{
/* This is a soft single step. */
record_full_resume_step = 1;
/* Make sure the target beneath reports all signals. */
target_pass_signals (0, NULL);
- record_full_beneath_to_resume (record_full_beneath_to_resume_ops,
- ptid, step, signal);
+ ops->beneath->to_resume (ops->beneath, ptid, step, signal);
}
/* We are about to start executing the inferior (or simulate it),
let's register it with the event loop. */
if (target_can_async_p ())
- {
- target_async (inferior_event_handler, 0);
- /* Notify the event loop there's an event to wait for. We do
- most of the work in record_full_wait. */
- mark_async_event_handler (record_full_async_inferior_event_token);
- }
+ target_async (1);
}
static int record_full_get_sig = 0;
ptid_t ptid, struct target_waitstatus *status,
int options)
{
- struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
+ struct cleanup *set_cleanups = record_full_gdb_operation_disable_set ();
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
record_full_get_sig = 0;
signal (SIGINT, record_full_sig_handler);
+ record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
+
if (!RECORD_FULL_IS_REPLAY && ops != &record_full_core_ops)
{
if (record_full_resume_step)
{
/* This is a single step. */
- return record_full_beneath_to_wait (record_full_beneath_to_wait_ops,
- ptid, status, options);
+ return ops->beneath->to_wait (ops->beneath, ptid, status, options);
}
else
{
while (1)
{
- ret = record_full_beneath_to_wait
- (record_full_beneath_to_wait_ops, ptid, status, options);
+ struct thread_info *tp;
+
+ ret = ops->beneath->to_wait (ops->beneath, ptid, status, options);
if (status->kind == TARGET_WAITKIND_IGNORE)
{
if (record_debug)
return ret;
}
- if (single_step_breakpoints_inserted ())
- remove_single_step_breakpoints ();
+ ALL_NON_EXITED_THREADS (tp)
+ delete_single_step_breakpoints (tp);
if (record_full_resume_step)
return ret;
{
struct regcache *regcache;
struct address_space *aspace;
+ enum target_stop_reason *stop_reason_p
+ = &record_full_stop_reason;
/* Yes -- this is likely our single-step finishing,
but check if there's any reason the core would be
{
/* Always interested in watchpoints. */
}
- else if (breakpoint_inserted_here_p (aspace, tmp_pc))
+ else if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
+ stop_reason_p))
{
/* There is a breakpoint here. Let the core
handle it. */
- if (software_breakpoint_inserted_here_p (aspace, tmp_pc))
- {
- struct gdbarch *gdbarch
- = get_regcache_arch (regcache);
- CORE_ADDR decr_pc_after_break
- = gdbarch_decr_pc_after_break (gdbarch);
- if (decr_pc_after_break)
- regcache_write_pc (regcache,
- tmp_pc + decr_pc_after_break);
- }
}
else
{
"Process record: record_full_wait "
"issuing one more step in the "
"target beneath\n");
- record_full_beneath_to_resume
- (record_full_beneath_to_resume_ops, ptid, step,
- GDB_SIGNAL_0);
+ ops->beneath->to_resume (ops->beneath, ptid, step,
+ GDB_SIGNAL_0);
continue;
}
}
= make_cleanup (record_full_wait_cleanups, 0);
CORE_ADDR tmp_pc;
- record_full_hw_watchpoint = 0;
+ record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
status->kind = TARGET_WAITKIND_STOPPED;
/* Check breakpoint when forward execute. */
if (execution_direction == EXEC_FORWARD)
{
tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (aspace, tmp_pc))
+ if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
+ &record_full_stop_reason))
{
- int decr_pc_after_break = gdbarch_decr_pc_after_break (gdbarch);
-
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"Process record: break at %s.\n",
paddress (gdbarch, tmp_pc));
-
- if (decr_pc_after_break
- && !record_full_resume_step
- && software_breakpoint_inserted_here_p (aspace, tmp_pc))
- regcache_write_pc (regcache,
- tmp_pc + decr_pc_after_break);
goto replay_out;
}
}
/* check breakpoint */
tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (aspace, tmp_pc))
+ if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
+ &record_full_stop_reason))
{
- int decr_pc_after_break
- = gdbarch_decr_pc_after_break (gdbarch);
-
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"Process record: break "
"at %s.\n",
paddress (gdbarch, tmp_pc));
- if (decr_pc_after_break
- && execution_direction == EXEC_FORWARD
- && !record_full_resume_step
- && software_breakpoint_inserted_here_p (aspace,
- tmp_pc))
- regcache_write_pc (regcache,
- tmp_pc + decr_pc_after_break);
+
continue_flag = 0;
}
- if (record_full_hw_watchpoint)
+ if (record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
}
static int
-record_full_stopped_by_watchpoint (void)
+record_full_stopped_by_watchpoint (struct target_ops *ops)
{
if (RECORD_FULL_IS_REPLAY)
- return record_full_hw_watchpoint;
+ return record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
else
- return record_full_beneath_to_stopped_by_watchpoint ();
+ return ops->beneath->to_stopped_by_watchpoint (ops->beneath);
}
-/* "to_disconnect" method for process record target. */
-
-static void
-record_full_disconnect (struct target_ops *target, char *args, int from_tty)
+static int
+record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_disconnect\n");
-
- unpush_target (&record_full_ops);
- target_disconnect (args, from_tty);
+ if (RECORD_FULL_IS_REPLAY)
+ return 0;
+ else
+ return ops->beneath->to_stopped_data_address (ops->beneath, addr_p);
}
-/* "to_detach" method for process record target. */
+/* The to_stopped_by_sw_breakpoint method of target record-full. */
-static void
-record_full_detach (struct target_ops *ops, char *args, int from_tty)
+static int
+record_full_stopped_by_sw_breakpoint (struct target_ops *ops)
{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_full_detach\n");
-
- unpush_target (&record_full_ops);
- target_detach (args, from_tty);
+ return record_full_stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
}
-/* "to_mourn_inferior" method for process record target. */
+/* The to_supports_stopped_by_sw_breakpoint method of target
+ record-full. */
-static void
-record_full_mourn_inferior (struct target_ops *ops)
+static int
+record_full_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: "
- "record_full_mourn_inferior\n");
-
- unpush_target (&record_full_ops);
- target_mourn_inferior ();
+ return 1;
}
-/* Close process record target before killing the inferior process. */
+/* The to_stopped_by_hw_breakpoint method of target record-full. */
-static void
-record_full_kill (struct target_ops *ops)
+static int
+record_full_stopped_by_hw_breakpoint (struct target_ops *ops)
{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_full_kill\n");
-
- unpush_target (&record_full_ops);
- target_kill ();
+ return record_full_stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
}
+/* The to_supports_stopped_by_sw_breakpoint method of target
+ record-full. */
+
static int
-record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+record_full_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
{
- if (RECORD_FULL_IS_REPLAY)
- return 0;
- else
- return record_full_beneath_to_stopped_data_address (ops, addr_p);
+ return 1;
}
/* Record registers change (by user or by GDB) to list as an instruction. */
for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
{
- if (record_arch_list_add_reg (regcache, i))
+ if (record_full_arch_list_add_reg (regcache, i))
{
record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
}
else
{
- if (record_arch_list_add_reg (regcache, regnum))
+ if (record_full_arch_list_add_reg (regcache, regnum))
{
record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
}
}
- if (record_arch_list_add_end ())
+ if (record_full_arch_list_add_end ())
{
record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
record_full_arch_list_head->prev = record_full_list;
record_full_list = record_full_arch_list_tail;
- if (record_full_insn_num == record_full_insn_max_num
- && record_full_insn_max_num)
+ if (record_full_insn_num == record_full_insn_max_num)
record_full_list_release_first ();
else
record_full_insn_num++;
record_full_registers_change (regcache, regno);
}
- record_full_beneath_to_store_registers
- (record_full_beneath_to_store_registers_ops, regcache, regno);
+ ops->beneath->to_store_registers (ops->beneath, regcache, regno);
}
/* "to_xfer_partial" method. Behavior is conditional on
In replay mode, we cannot write memory unles we are willing to
invalidate the record/replay log from this point forward. */
-static LONGEST
+static enum target_xfer_status
record_full_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
const gdb_byte *writebuf, ULONGEST offset,
- LONGEST len)
+ ULONGEST len, ULONGEST *xfered_len)
{
if (!record_full_gdb_operation_disable
&& (object == TARGET_OBJECT_MEMORY
/* Record registers change to list as an instruction. */
record_full_arch_list_head = NULL;
record_full_arch_list_tail = NULL;
- if (record_arch_list_add_mem (offset, len))
+ if (record_full_arch_list_add_mem (offset, len))
{
record_full_list_release (record_full_arch_list_tail);
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"Process record: failed to record "
"execution log.");
- return -1;
+ return TARGET_XFER_E_IO;
}
- if (record_arch_list_add_end ())
+ if (record_full_arch_list_add_end ())
{
record_full_list_release (record_full_arch_list_tail);
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"Process record: failed to record "
"execution log.");
- return -1;
+ return TARGET_XFER_E_IO;
}
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;
- if (record_full_insn_num == record_full_insn_max_num
- && record_full_insn_max_num)
+ if (record_full_insn_num == record_full_insn_max_num)
record_full_list_release_first ();
else
record_full_insn_num++;
}
- return record_full_beneath_to_xfer_partial
- (record_full_beneath_to_xfer_partial_ops, object, annex,
- readbuf, writebuf, offset, len);
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset,
+ len, xfered_len);
}
/* This structure represents a breakpoint inserted while the record
when recording. */
static int
-record_full_insert_breakpoint (struct gdbarch *gdbarch,
+record_full_insert_breakpoint (struct target_ops *ops,
+ struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
struct record_full_breakpoint *bp;
struct cleanup *old_cleanups;
int ret;
- old_cleanups = record_gdb_operation_disable_set ();
- ret = record_full_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
+ old_cleanups = record_full_gdb_operation_disable_set ();
+ ret = ops->beneath->to_insert_breakpoint (ops->beneath, gdbarch, bp_tgt);
do_cleanups (old_cleanups);
if (ret != 0)
/* "to_remove_breakpoint" method for process record target. */
static int
-record_full_remove_breakpoint (struct gdbarch *gdbarch,
+record_full_remove_breakpoint (struct target_ops *ops,
+ struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
struct record_full_breakpoint *bp;
struct cleanup *old_cleanups;
int ret;
- old_cleanups = record_gdb_operation_disable_set ();
- ret = record_full_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
+ old_cleanups = record_full_gdb_operation_disable_set ();
+ ret = ops->beneath->to_remove_breakpoint (ops->beneath, gdbarch,
+ bp_tgt);
do_cleanups (old_cleanups);
if (ret != 0)
/* "to_can_execute_reverse" method for process record target. */
static int
-record_full_can_execute_reverse (void)
+record_full_can_execute_reverse (struct target_ops *self)
{
return 1;
}
/* "to_get_bookmark" method for process record and prec over core. */
static gdb_byte *
-record_full_get_bookmark (char *args, int from_tty)
+record_full_get_bookmark (struct target_ops *self, const char *args,
+ int from_tty)
{
- gdb_byte *ret = NULL;
+ char *ret = NULL;
/* Return stringified form of instruction count. */
if (record_full_list && record_full_list->type == record_full_end)
fprintf_unfiltered (gdb_stdlog,
"record_full_get_bookmark returns NULL\n");
}
- return ret;
+ return (gdb_byte *) ret;
}
/* "to_goto_bookmark" method for process record and prec over core. */
static void
-record_full_goto_bookmark (gdb_byte *bookmark, int from_tty)
+record_full_goto_bookmark (struct target_ops *self,
+ const gdb_byte *raw_bookmark, int from_tty)
{
+ const char *bookmark = (const char *) raw_bookmark;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"record_full_goto_bookmark receives %s\n", bookmark);
if (bookmark[0] == '\'' || bookmark[0] == '\"')
{
+ char *copy;
+
if (bookmark[strlen (bookmark) - 1] != bookmark[0])
error (_("Unbalanced quotes: %s"), bookmark);
- /* Strip trailing quote. */
- bookmark[strlen (bookmark) - 1] = '\0';
- /* Strip leading quote. */
- bookmark++;
- /* Pass along to cmd_record_full_goto. */
+
+ copy = savestring (bookmark + 1, strlen (bookmark) - 2);
+ make_cleanup (xfree, copy);
+ bookmark = copy;
}
- cmd_record_goto ((char *) bookmark, from_tty);
- return;
-}
+ record_goto (bookmark);
-static void
-record_full_async (void (*callback) (enum inferior_event_type event_type,
- void *context), void *context)
-{
- /* If we're on top of a line target (e.g., linux-nat, remote), then
- set it to async mode as well. Will be NULL if we're sitting on
- top of the core target, for "record restore". */
- if (record_full_beneath_to_async != NULL)
- record_full_beneath_to_async (callback, context);
-}
-
-static int
-record_full_can_async_p (void)
-{
- /* We only enable async when the user specifically asks for it. */
- return target_async_permitted;
-}
-
-static int
-record_full_is_async_p (void)
-{
- /* We only enable async when the user specifically asks for it. */
- return target_async_permitted;
+ do_cleanups (cleanup);
}
static enum exec_direction_kind
-record_full_execution_direction (void)
+record_full_execution_direction (struct target_ops *self)
{
return record_full_execution_dir;
}
static void
-record_full_info (void)
+record_full_info (struct target_ops *self)
{
struct record_full_entry *p;
pulongest (record_full_insn_count));
/* Display log count. */
- printf_filtered (_("Log contains %d instructions.\n"),
+ printf_filtered (_("Log contains %u instructions.\n"),
record_full_insn_num);
}
else
printf_filtered (_("No instructions have been logged.\n"));
/* Display max log size. */
- printf_filtered (_("Max logged instructions is %d.\n"),
+ printf_filtered (_("Max logged instructions is %u.\n"),
record_full_insn_max_num);
}
/* The "to_record_delete" target method. */
static void
-record_full_delete (void)
+record_full_delete (struct target_ops *self)
{
record_full_list_release_following (record_full_list);
}
/* The "to_record_is_replaying" target method. */
static int
-record_full_is_replaying (void)
+record_full_is_replaying (struct target_ops *self, ptid_t ptid)
{
return RECORD_FULL_IS_REPLAY;
}
registers_changed ();
reinit_frame_cache ();
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ stop_pc = regcache_read_pc (get_current_regcache ());
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
/* The "to_goto_record_begin" target method. */
static void
-record_full_goto_begin (void)
+record_full_goto_begin (struct target_ops *self)
{
struct record_full_entry *p = NULL;
/* The "to_goto_record_end" target method. */
static void
-record_full_goto_end (void)
+record_full_goto_end (struct target_ops *self)
{
struct record_full_entry *p = NULL;
/* The "to_goto_record" target method. */
static void
-record_full_goto (ULONGEST target_insn)
+record_full_goto (struct target_ops *self, ULONGEST target_insn)
{
struct record_full_entry *p = NULL;
"Log program while executing and replay execution from log.";
record_full_ops.to_open = record_full_open;
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_wait = record_full_wait;
- record_full_ops.to_disconnect = record_full_disconnect;
- record_full_ops.to_detach = record_full_detach;
- record_full_ops.to_mourn_inferior = record_full_mourn_inferior;
- record_full_ops.to_kill = record_full_kill;
- record_full_ops.to_create_inferior = find_default_create_inferior;
+ record_full_ops.to_disconnect = record_disconnect;
+ record_full_ops.to_detach = record_detach;
+ record_full_ops.to_mourn_inferior = record_mourn_inferior;
+ record_full_ops.to_kill = record_kill;
record_full_ops.to_store_registers = record_full_store_registers;
record_full_ops.to_xfer_partial = record_full_xfer_partial;
record_full_ops.to_insert_breakpoint = record_full_insert_breakpoint;
record_full_ops.to_remove_breakpoint = record_full_remove_breakpoint;
record_full_ops.to_stopped_by_watchpoint = record_full_stopped_by_watchpoint;
record_full_ops.to_stopped_data_address = record_full_stopped_data_address;
+ record_full_ops.to_stopped_by_sw_breakpoint
+ = record_full_stopped_by_sw_breakpoint;
+ record_full_ops.to_supports_stopped_by_sw_breakpoint
+ = record_full_supports_stopped_by_sw_breakpoint;
+ record_full_ops.to_stopped_by_hw_breakpoint
+ = record_full_stopped_by_hw_breakpoint;
+ record_full_ops.to_supports_stopped_by_hw_breakpoint
+ = record_full_supports_stopped_by_hw_breakpoint;
record_full_ops.to_can_execute_reverse = record_full_can_execute_reverse;
record_full_ops.to_stratum = record_stratum;
/* Add bookmark target methods. */
record_full_ops.to_get_bookmark = record_full_get_bookmark;
record_full_ops.to_goto_bookmark = record_full_goto_bookmark;
- record_full_ops.to_async = record_full_async;
- record_full_ops.to_can_async_p = record_full_can_async_p;
- record_full_ops.to_is_async_p = record_full_is_async_p;
record_full_ops.to_execution_direction = record_full_execution_direction;
record_full_ops.to_info_record = record_full_info;
record_full_ops.to_save_record = record_full_save;
/* We are about to start executing the inferior (or simulate it),
let's register it with the event loop. */
if (target_can_async_p ())
- {
- target_async (inferior_event_handler, 0);
-
- /* Notify the event loop there's an event to wait for. */
- mark_async_event_handler (record_full_async_inferior_event_token);
- }
+ target_async (1);
}
/* "to_kill" method for prec over corefile. */
/* "to_prepare_to_store" method for prec over corefile. */
static void
-record_full_core_prepare_to_store (struct regcache *regcache)
+record_full_core_prepare_to_store (struct target_ops *self,
+ struct regcache *regcache)
{
}
/* "to_xfer_partial" method for prec over corefile. */
-static LONGEST
+static enum target_xfer_status
record_full_core_xfer_partial (struct target_ops *ops,
enum target_object object,
const char *annex, gdb_byte *readbuf,
const gdb_byte *writebuf, ULONGEST offset,
- LONGEST len)
+ ULONGEST len, ULONGEST *xfered_len)
{
if (object == TARGET_OBJECT_MEMORY)
{
{
if (readbuf)
memset (readbuf, 0, len);
- return len;
+
+ *xfered_len = len;
+ return TARGET_XFER_OK;
}
/* Get record_full_core_buf_entry. */
for (entry = record_full_core_buf_list; entry;
if (!entry)
{
/* Add a new entry. */
- entry = (struct record_full_core_buf_entry *)
- xmalloc
- (sizeof (struct record_full_core_buf_entry));
+ entry = XNEW (struct record_full_core_buf_entry);
entry->p = p;
- if (!bfd_malloc_and_get_section (p->bfd,
- p->the_bfd_section,
- &entry->buf))
+ if (!bfd_malloc_and_get_section
+ (p->the_bfd_section->owner,
+ p->the_bfd_section,
+ &entry->buf))
{
xfree (entry);
- return 0;
+ return TARGET_XFER_EOF;
}
entry->prev = record_full_core_buf_list;
record_full_core_buf_list = entry;
else
{
if (!entry)
- return record_full_beneath_to_xfer_partial
- (record_full_beneath_to_xfer_partial_ops,
- object, annex, readbuf, writebuf,
- offset, len);
+ return ops->beneath->to_xfer_partial (ops->beneath,
+ object, annex,
+ readbuf, writebuf,
+ offset, len,
+ xfered_len);
memcpy (readbuf, entry->buf + sec_offset,
(size_t) len);
}
- return len;
+ *xfered_len = len;
+ return TARGET_XFER_OK;
}
}
- return -1;
+ return TARGET_XFER_E_IO;
}
else
error (_("You can't do that without a process to debug."));
}
- return record_full_beneath_to_xfer_partial
- (record_full_beneath_to_xfer_partial_ops, object, annex,
- readbuf, writebuf, offset, len);
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len,
+ xfered_len);
}
/* "to_insert_breakpoint" method for prec over corefile. */
static int
-record_full_core_insert_breakpoint (struct gdbarch *gdbarch,
+record_full_core_insert_breakpoint (struct target_ops *ops,
+ struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
return 0;
/* "to_remove_breakpoint" method for prec over corefile. */
static int
-record_full_core_remove_breakpoint (struct gdbarch *gdbarch,
+record_full_core_remove_breakpoint (struct target_ops *ops,
+ struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
return 0;
"Log program while executing and replay execution from log.";
record_full_core_ops.to_open = record_full_open;
record_full_core_ops.to_close = record_full_close;
+ record_full_core_ops.to_async = record_full_async;
record_full_core_ops.to_resume = record_full_core_resume;
record_full_core_ops.to_wait = record_full_wait;
record_full_core_ops.to_kill = record_full_core_kill;
= record_full_stopped_by_watchpoint;
record_full_core_ops.to_stopped_data_address
= record_full_stopped_data_address;
+ record_full_core_ops.to_stopped_by_sw_breakpoint
+ = record_full_stopped_by_sw_breakpoint;
+ record_full_core_ops.to_supports_stopped_by_sw_breakpoint
+ = record_full_supports_stopped_by_sw_breakpoint;
+ record_full_core_ops.to_stopped_by_hw_breakpoint
+ = record_full_stopped_by_hw_breakpoint;
+ record_full_core_ops.to_supports_stopped_by_hw_breakpoint
+ = record_full_supports_stopped_by_hw_breakpoint;
record_full_core_ops.to_can_execute_reverse
= record_full_can_execute_reverse;
record_full_core_ops.to_has_execution = record_full_core_has_execution;
/* Add bookmark target methods. */
record_full_core_ops.to_get_bookmark = record_full_get_bookmark;
record_full_core_ops.to_goto_bookmark = record_full_goto_bookmark;
- record_full_core_ops.to_async = record_full_async;
- record_full_core_ops.to_can_async_p = record_full_can_async_p;
- record_full_core_ops.to_is_async_p = record_full_is_async_p;
record_full_core_ops.to_execution_direction
= record_full_execution_direction;
record_full_core_ops.to_info_record = record_full_info;
bfdcore_read (core_bfd, osec, &signal,
sizeof (signal), &bfd_offset);
signal = netorder32 (signal);
- rec->u.end.sigval = signal;
+ rec->u.end.sigval = (enum gdb_signal) signal;
/* Get insn count. */
bfdcore_read (core_bfd, osec, &count,
if (record_full_insn_num > record_full_insn_max_num)
{
record_full_insn_max_num = record_full_insn_num;
- warning (_("Auto increase record/replay buffer limit to %d."),
+ warning (_("Auto increase record/replay buffer limit to %u."),
record_full_insn_max_num);
}
printf_filtered (_("Restored records from core file %s.\n"),
bfd_get_filename (core_bfd));
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
/* bfdcore_write -- write bytes into a core file section. */
format, with an extra section for our data. */
static void
-record_full_save (char *recfilename)
+record_full_save (struct target_ops *self, const char *recfilename)
{
struct record_full_entry *cur_record_full_list;
uint32_t magic;
gdbarch = get_regcache_arch (regcache);
/* Disable the GDB operation record. */
- set_cleanups = record_gdb_operation_disable_set ();
+ set_cleanups = record_full_gdb_operation_disable_set ();
/* Reverse execute to the begin of record list. */
while (1)
record_full_goto_insn (struct record_full_entry *entry,
enum exec_direction_kind dir)
{
- struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
+ struct cleanup *set_cleanups = record_full_gdb_operation_disable_set ();
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
set_record_full_insn_max_num (char *args, int from_tty,
struct cmd_list_element *c)
{
- if (record_full_insn_num > record_full_insn_max_num
- && record_full_insn_max_num)
+ if (record_full_insn_num > record_full_insn_max_num)
{
/* Count down record_full_insn_num while releasing records from list. */
while (record_full_insn_num > record_full_insn_max_num)
_("Set record/replay buffer limit."),
_("Show record/replay buffer limit."), _("\
Set the maximum number of instructions to be stored in the\n\
-record/replay buffer. Zero means unlimited. Default is 200000."),
+record/replay buffer. A value of either \"unlimited\" or zero means no\n\
+limit. Default is 200000."),
set_record_full_insn_max_num,
NULL, &set_record_full_cmdlist,
&show_record_full_cmdlist);
deprecate_cmd (c, "show record full insn-number-max");
add_setshow_boolean_cmd ("memory-query", no_class,
- &record_memory_query, _("\
+ &record_full_memory_query, _("\
Set whether query if PREC cannot record memory change of next instruction."),
_("\
Show whether query if PREC cannot record memory change of next instruction."),