gdb/record-full.c - gdb
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
- #include "defs.h"
- #include "gdbcmd.h"
- #include "regcache.h"
- #include "gdbthread.h"
- #include "event-top.h"
- #include "completer.h"
- #include "arch-utils.h"
- #include "gdbcore.h"
- #include "exec.h"
- #include "record.h"
- #include "record-full.h"
- #include "elf-bfd.h"
- #include "gcore.h"
- #include "event-loop.h"
- #include "inf-loop.h"
- #include "gdb_bfd.h"
- #include "observer.h"
- #include "infrun.h"
- #include <signal.h>
- #define DEFAULT_RECORD_FULL_INSN_MAX_NUM 200000
- #define RECORD_FULL_IS_REPLAY \
- (record_full_list->next || execution_direction == EXEC_REVERSE)
- #define RECORD_FULL_FILE_MAGIC netorder32(0x20091016)
- struct record_full_mem_entry
- {
- CORE_ADDR addr;
- int len;
-
- int mem_entry_not_accessible;
- union
- {
- gdb_byte *ptr;
- gdb_byte buf[sizeof (gdb_byte *)];
- } u;
- };
- struct record_full_reg_entry
- {
- unsigned short num;
- unsigned short len;
- union
- {
- gdb_byte *ptr;
- gdb_byte buf[2 * sizeof (gdb_byte *)];
- } u;
- };
- struct record_full_end_entry
- {
- enum gdb_signal sigval;
- ULONGEST insn_num;
- };
- enum record_full_type
- {
- record_full_end = 0,
- record_full_reg,
- record_full_mem
- };
- struct record_full_entry
- {
- struct record_full_entry *prev;
- struct record_full_entry *next;
- enum record_full_type type;
- union
- {
-
- struct record_full_reg_entry reg;
-
- struct record_full_mem_entry mem;
-
- struct record_full_end_entry end;
- } u;
- };
- int record_full_memory_query = 0;
- struct record_full_core_buf_entry
- {
- struct record_full_core_buf_entry *prev;
- struct target_section *p;
- bfd_byte *buf;
- };
- static gdb_byte *record_full_core_regbuf = NULL;
- static struct target_section *record_full_core_start;
- static struct target_section *record_full_core_end;
- static struct record_full_core_buf_entry *record_full_core_buf_list = NULL;
- static struct record_full_entry record_full_first;
- static struct record_full_entry *record_full_list = &record_full_first;
- static struct record_full_entry *record_full_arch_list_head = NULL;
- static struct record_full_entry *record_full_arch_list_tail = NULL;
- static int record_full_stop_at_limit = 1;
- static unsigned int record_full_insn_max_num
- = DEFAULT_RECORD_FULL_INSN_MAX_NUM;
- static unsigned int record_full_insn_num = 0;
- static ULONGEST record_full_insn_count;
- static struct target_ops record_full_ops;
- static struct target_ops record_full_core_ops;
- int
- record_full_is_used (void)
- {
- struct target_ops *t;
- t = find_record_target ();
- return (t == &record_full_ops
- || t == &record_full_core_ops);
- }
- static struct cmd_list_element *set_record_full_cmdlist;
- static struct cmd_list_element *show_record_full_cmdlist;
- static struct cmd_list_element *record_full_cmdlist;
- static void record_full_goto_insn (struct record_full_entry *entry,
- enum exec_direction_kind dir);
- static void record_full_save (struct target_ops *self,
- const char *recfilename);
- static inline struct record_full_entry *
- record_full_reg_alloc (struct regcache *regcache, int regnum)
- {
- struct record_full_entry *rec;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- rec = xcalloc (1, sizeof (struct record_full_entry));
- rec->type = record_full_reg;
- rec->u.reg.num = regnum;
- rec->u.reg.len = register_size (gdbarch, regnum);
- if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
- rec->u.reg.u.ptr = (gdb_byte *) xmalloc (rec->u.reg.len);
- return rec;
- }
- static inline void
- record_full_reg_release (struct record_full_entry *rec)
- {
- gdb_assert (rec->type == record_full_reg);
- if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
- xfree (rec->u.reg.u.ptr);
- xfree (rec);
- }
- static inline struct record_full_entry *
- record_full_mem_alloc (CORE_ADDR addr, int len)
- {
- struct record_full_entry *rec;
- rec = xcalloc (1, sizeof (struct record_full_entry));
- rec->type = record_full_mem;
- rec->u.mem.addr = addr;
- rec->u.mem.len = len;
- if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
- rec->u.mem.u.ptr = (gdb_byte *) xmalloc (len);
- return rec;
- }
- static inline void
- record_full_mem_release (struct record_full_entry *rec)
- {
- gdb_assert (rec->type == record_full_mem);
- if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
- xfree (rec->u.mem.u.ptr);
- xfree (rec);
- }
- static inline struct record_full_entry *
- record_full_end_alloc (void)
- {
- struct record_full_entry *rec;
- rec = xcalloc (1, sizeof (struct record_full_entry));
- rec->type = record_full_end;
- return rec;
- }
- static inline void
- record_full_end_release (struct record_full_entry *rec)
- {
- xfree (rec);
- }
- static inline enum record_full_type
- record_full_entry_release (struct record_full_entry *rec)
- {
- enum record_full_type type = rec->type;
- switch (type) {
- case record_full_reg:
- record_full_reg_release (rec);
- break;
- case record_full_mem:
- record_full_mem_release (rec);
- break;
- case record_full_end:
- record_full_end_release (rec);
- break;
- }
- return type;
- }
- static void
- record_full_list_release (struct record_full_entry *rec)
- {
- if (!rec)
- return;
- while (rec->next)
- rec = rec->next;
- while (rec->prev)
- {
- rec = rec->prev;
- record_full_entry_release (rec->next);
- }
- if (rec == &record_full_first)
- {
- record_full_insn_num = 0;
- record_full_first.next = NULL;
- }
- else
- record_full_entry_release (rec);
- }
- static void
- record_full_list_release_following (struct record_full_entry *rec)
- {
- struct record_full_entry *tmp = rec->next;
- rec->next = NULL;
- while (tmp)
- {
- rec = tmp->next;
- if (record_full_entry_release (tmp) == record_full_end)
- {
- record_full_insn_num--;
- record_full_insn_count--;
- }
- tmp = rec;
- }
- }
- static void
- record_full_list_release_first (void)
- {
- struct record_full_entry *tmp;
- if (!record_full_first.next)
- return;
-
- while (1)
- {
-
- tmp = record_full_first.next;
- record_full_first.next = tmp->next;
- tmp->next->prev = &record_full_first;
-
- if (record_full_entry_release (tmp) == record_full_end)
- break;
- if (!record_full_first.next)
- {
- gdb_assert (record_full_insn_num == 1);
- break;
- }
- }
- }
- static void
- record_full_arch_list_add (struct record_full_entry *rec)
- {
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_arch_list_add %s.\n",
- host_address_to_string (rec));
- if (record_full_arch_list_tail)
- {
- record_full_arch_list_tail->next = rec;
- rec->prev = record_full_arch_list_tail;
- record_full_arch_list_tail = rec;
- }
- else
- {
- record_full_arch_list_head = rec;
- record_full_arch_list_tail = rec;
- }
- }
- static inline gdb_byte *
- record_full_get_loc (struct record_full_entry *rec)
- {
- switch (rec->type) {
- case record_full_mem:
- if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
- return rec->u.mem.u.ptr;
- else
- return rec->u.mem.u.buf;
- case record_full_reg:
- if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
- return rec->u.reg.u.ptr;
- else
- return rec->u.reg.u.buf;
- case record_full_end:
- default:
- gdb_assert_not_reached ("unexpected record_full_entry type");
- return NULL;
- }
- }
- int
- record_full_arch_list_add_reg (struct regcache *regcache, int regnum)
- {
- struct record_full_entry *rec;
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: add register num = %d to "
- "record list.\n",
- regnum);
- rec = record_full_reg_alloc (regcache, regnum);
- regcache_raw_read (regcache, regnum, record_full_get_loc (rec));
- record_full_arch_list_add (rec);
- return 0;
- }
- int
- record_full_arch_list_add_mem (CORE_ADDR addr, int len)
- {
- struct record_full_entry *rec;
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: add mem addr = %s len = %d to "
- "record list.\n",
- paddress (target_gdbarch (), addr), len);
- if (!addr) FIXME
- return 0;
- rec = record_full_mem_alloc (addr, len);
- if (record_read_memory (target_gdbarch (), addr,
- record_full_get_loc (rec), len))
- {
- record_full_mem_release (rec);
- return -1;
- }
- record_full_arch_list_add (rec);
- return 0;
- }
- int
- record_full_arch_list_add_end (void)
- {
- struct record_full_entry *rec;
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: add end to arch list.\n");
- rec = record_full_end_alloc ();
- rec->u.end.sigval = GDB_SIGNAL_0;
- rec->u.end.insn_num = ++record_full_insn_count;
- record_full_arch_list_add (rec);
- return 0;
- }
- static void
- record_full_check_insn_num (int set_terminal)
- {
- if (record_full_insn_num == record_full_insn_max_num)
- {
-
- 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."));
- }
- }
- }
- static void
- record_full_arch_list_cleanups (void *ignore)
- {
- record_full_list_release (record_full_arch_list_tail);
- }
- static int
- record_full_message (struct regcache *regcache, enum gdb_signal signal)
- {
- int ret;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct cleanup *old_cleanups
- = make_cleanup (record_full_arch_list_cleanups, 0);
- record_full_arch_list_head = NULL;
- record_full_arch_list_tail = NULL;
-
- record_full_check_insn_num (1);
-
- if (record_full_list != &record_full_first) FIXME
- {
- 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."));
- 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;
- if (record_full_insn_num == record_full_insn_max_num)
- record_full_list_release_first ();
- else
- record_full_insn_num++;
- return 1;
- }
- struct record_full_message_args {
- struct regcache *regcache;
- enum gdb_signal signal;
- };
- static int
- record_full_message_wrapper (void *args)
- {
- struct record_full_message_args *record_full_args = args;
- return record_full_message (record_full_args->regcache,
- record_full_args->signal);
- }
- static int
- record_full_message_wrapper_safe (struct regcache *regcache,
- enum gdb_signal signal)
- {
- struct record_full_message_args args;
- args.regcache = regcache;
- args.signal = signal;
- return catch_errors (record_full_message_wrapper, &args, NULL,
- RETURN_MASK_ALL);
- }
- static int record_full_gdb_operation_disable = 0;
- struct cleanup *
- record_full_gdb_operation_disable_set (void)
- {
- struct cleanup *old_cleanups = NULL;
- old_cleanups =
- make_cleanup_restore_integer (&record_full_gdb_operation_disable);
- record_full_gdb_operation_disable = 1;
- return old_cleanups;
- }
- static int record_full_hw_watchpoint = 0;
- static inline void
- record_full_exec_insn (struct regcache *regcache,
- struct gdbarch *gdbarch,
- struct record_full_entry *entry)
- {
- switch (entry->type)
- {
- case record_full_reg:
- {
- gdb_byte reg[MAX_REGISTER_SIZE];
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_reg %s to "
- "inferior num = %d.\n",
- host_address_to_string (entry),
- entry->u.reg.num);
- regcache_cooked_read (regcache, entry->u.reg.num, reg);
- regcache_cooked_write (regcache, entry->u.reg.num,
- record_full_get_loc (entry));
- memcpy (record_full_get_loc (entry), reg, entry->u.reg.len);
- }
- break;
- case record_full_mem:
- {
-
- if (!entry->u.mem.mem_entry_not_accessible)
- {
- gdb_byte *mem = alloca (entry->u.mem.len);
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_mem %s to "
- "inferior addr = %s len = %d.\n",
- host_address_to_string (entry),
- paddress (gdbarch, entry->u.mem.addr),
- entry->u.mem.len);
- if (record_read_memory (gdbarch,
- entry->u.mem.addr, mem, entry->u.mem.len))
- entry->u.mem.mem_entry_not_accessible = 1;
- else
- {
- if (target_write_memory (entry->u.mem.addr,
- record_full_get_loc (entry),
- entry->u.mem.len))
- {
- entry->u.mem.mem_entry_not_accessible = 1;
- if (record_debug)
- warning (_("Process record: error writing memory at "
- "addr = %s len = %d."),
- paddress (gdbarch, entry->u.mem.addr),
- entry->u.mem.len);
- }
- else
- {
- memcpy (record_full_get_loc (entry), mem,
- entry->u.mem.len);
-
- if (hardware_watchpoint_inserted_in_range
- (get_regcache_aspace (regcache),
- entry->u.mem.addr, entry->u.mem.len))
- record_full_hw_watchpoint = 1;
- }
- }
- }
- }
- break;
- }
- }
- static void record_full_restore (void);
- static struct async_event_handler *record_full_async_inferior_event_token;
- static void
- record_full_async_inferior_event_handler (gdb_client_data data)
- {
- inferior_event_handler (INF_REG_EVENT, NULL);
- }
- static void
- 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));
- int i;
-
- target_fetch_registers (regcache, -1);
- record_full_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
- for (i = 0; i < regnum; i ++)
- regcache_raw_collect (regcache, i,
- record_full_core_regbuf + MAX_REGISTER_SIZE * i);
-
- if (build_section_table (core_bfd, &record_full_core_start,
- &record_full_core_end))
- {
- xfree (record_full_core_regbuf);
- record_full_core_regbuf = NULL;
- error (_("\"%s\": Can't find sections: %s"),
- bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
- }
- push_target (&record_full_core_ops);
- record_full_restore ();
- }
- static void
- record_full_open_1 (const char *name, int from_tty)
- {
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
-
- if (!target_has_execution)
- error (_("Process record: the program is not being run."));
- if (non_stop)
- error (_("Process record target can't debug inferior in non-stop mode "
- "(non-stop)."));
- if (!gdbarch_process_record_p (target_gdbarch ()))
- error (_("Process record: the current architecture doesn't support "
- "record function."));
- push_target (&record_full_ops);
- }
- static void record_full_init_record_breakpoints (void);
- static void
- 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");
- record_preopen ();
-
- record_full_insn_num = 0;
- record_full_insn_count = 0;
- record_full_list = &record_full_first;
- record_full_list->next = NULL;
- if (core_bfd)
- record_full_core_open_1 (name, from_tty);
- else
- record_full_open_1 (name, from_tty);
-
- record_full_async_inferior_event_token
- = create_async_event_handler (record_full_async_inferior_event_handler,
- NULL);
- record_full_init_record_breakpoints ();
- observer_notify_record_changed (current_inferior (), 1);
- }
- static void
- record_full_close (struct target_ops *self)
- {
- struct record_full_core_buf_entry *entry;
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_full_close\n");
- record_full_list_release (record_full_list);
-
- if (record_full_core_regbuf)
- {
- xfree (record_full_core_regbuf);
- record_full_core_regbuf = NULL;
- }
-
- if (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;
- }
- if (record_full_async_inferior_event_token)
- delete_async_event_handler (&record_full_async_inferior_event_token);
- }
- static int record_full_resume_step = 0;
- static int record_full_resumed = 0;
- static enum exec_direction_kind record_full_execution_dir = EXEC_FORWARD;
- static void
- record_full_resume (struct target_ops *ops, ptid_t ptid, int step,
- enum gdb_signal signal)
- {
- record_full_resume_step = step;
- record_full_resumed = 1;
- record_full_execution_dir = execution_direction;
- if (!RECORD_FULL_IS_REPLAY)
- {
- struct gdbarch *gdbarch = target_thread_architecture (ptid);
- record_full_message (get_current_regcache (), signal);
- if (!step)
- {
-
- if (!gdbarch_software_single_step_p (gdbarch))
- {
-
- step = 1;
- }
- else
- {
-
- if (thread_has_single_step_breakpoints_set (inferior_thread ()))
- {
-
- record_full_resume_step = 1;
- }
- else
- {
-
- if (!gdbarch_software_single_step (gdbarch,
- get_current_frame ()))
- {
-
- step = 1;
- }
- }
- }
- }
-
- target_pass_signals (0, NULL);
- ops->beneath->to_resume (ops->beneath, ptid, step, signal);
- }
-
- if (target_can_async_p ())
- {
- target_async (inferior_event_handler, 0);
-
- mark_async_event_handler (record_full_async_inferior_event_token);
- }
- }
- static int record_full_get_sig = 0;
- static void
- record_full_sig_handler (int signo)
- {
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: get a signal\n");
-
- record_full_resume_step = 1;
-
- 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;
- }
- static ptid_t
- record_full_wait_1 (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status,
- int options)
- {
- struct cleanup *set_cleanups = record_full_gdb_operation_disable_set ();
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_wait "
- "record_full_resume_step = %d, "
- "record_full_resumed = %d, direction=%s\n",
- record_full_resume_step, record_full_resumed,
- record_full_execution_dir == EXEC_FORWARD
- ? "forward" : "reverse");
- if (!record_full_resumed)
- {
- gdb_assert ((options & TARGET_WNOHANG) != 0);
-
- status->kind = TARGET_WAITKIND_IGNORE;
- return minus_one_ptid;
- }
- record_full_get_sig = 0;
- signal (SIGINT, record_full_sig_handler);
- if (!RECORD_FULL_IS_REPLAY && ops != &record_full_core_ops)
- {
- if (record_full_resume_step)
- {
-
- return ops->beneath->to_wait (ops->beneath, ptid, status, options);
- }
- else
- {
-
- ptid_t ret;
- CORE_ADDR tmp_pc;
- struct gdbarch *gdbarch = target_thread_architecture (inferior_ptid);
- while (1)
- {
- struct thread_info *tp;
- ret = ops->beneath->to_wait (ops->beneath, ptid, status, options);
- if (status->kind == TARGET_WAITKIND_IGNORE)
- {
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_wait "
- "target beneath not done yet\n");
- return ret;
- }
- ALL_NON_EXITED_THREADS (tp)
- delete_single_step_breakpoints (tp);
- if (record_full_resume_step)
- return ret;
-
- if (status->kind == TARGET_WAITKIND_STOPPED
- && status->value.sig == GDB_SIGNAL_TRAP)
- {
- struct regcache *regcache;
- struct address_space *aspace;
-
- registers_changed ();
- regcache = get_current_regcache ();
- tmp_pc = regcache_read_pc (regcache);
- aspace = get_regcache_aspace (regcache);
- if (target_stopped_by_watchpoint ())
- {
-
- }
- else if (breakpoint_inserted_here_p (aspace, tmp_pc))
- {
-
- if (software_breakpoint_inserted_here_p (aspace, tmp_pc))
- {
- struct gdbarch *gdbarch
- = get_regcache_arch (regcache);
- CORE_ADDR decr_pc_after_break
- = target_decr_pc_after_break (gdbarch);
- if (decr_pc_after_break)
- regcache_write_pc (regcache,
- tmp_pc + decr_pc_after_break);
- }
- }
- else
- {
-
- FIXME
- int step = 1;
- if (!record_full_message_wrapper_safe (regcache,
- GDB_SIGNAL_0))
- {
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = GDB_SIGNAL_0;
- break;
- }
- if (gdbarch_software_single_step_p (gdbarch))
- {
-
- set_executing (inferior_ptid, 0);
- reinit_frame_cache ();
- if (gdbarch_software_single_step (gdbarch,
- get_current_frame ()))
- step = 0;
- set_executing (inferior_ptid, 1);
- }
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_wait "
- "issuing one more step in the "
- "target beneath\n");
- ops->beneath->to_resume (ops->beneath, ptid, step,
- GDB_SIGNAL_0);
- continue;
- }
- }
-
- break;
- }
- return ret;
- }
- }
- else
- {
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct address_space *aspace = get_regcache_aspace (regcache);
- 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_hw_watchpoint = 0;
- status->kind = TARGET_WAITKIND_STOPPED;
-
- if (execution_direction == EXEC_FORWARD)
- {
- tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (aspace, tmp_pc))
- {
- int decr_pc_after_break = target_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;
- }
- }
-
- target_terminal_ours ();
-
- if (execution_direction == EXEC_FORWARD && record_full_list->next)
- record_full_list = record_full_list->next;
-
- do
- {
-
- if (execution_direction == EXEC_REVERSE
- && record_full_list == &record_full_first)
- {
-
- status->kind = TARGET_WAITKIND_NO_HISTORY;
- break;
- }
- if (execution_direction != EXEC_REVERSE && !record_full_list->next)
- {
-
- status->kind = TARGET_WAITKIND_NO_HISTORY;
- break;
- }
- record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (record_full_list->type == record_full_end)
- {
- 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)
- {
-
- first_record_full_end = 0;
- }
- else
- {
-
-
- if (record_full_resume_step)
- {
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: step.\n");
- continue_flag = 0;
- }
-
- tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (aspace, tmp_pc))
- {
- int decr_pc_after_break
- = target_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_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: hit hw "
- "watchpoint.\n");
- continue_flag = 0;
- }
-
- if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
- FIXME
- continue_flag = 0;
- }
- }
- if (continue_flag)
- {
- 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
- status->value.sig = record_full_list->u.end.sigval;
- else
- status->value.sig = GDB_SIGNAL_TRAP;
- discard_cleanups (old_cleanups);
- }
- signal (SIGINT, handle_sigint);
- do_cleanups (set_cleanups);
- return inferior_ptid;
- }
- static ptid_t
- record_full_wait (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status,
- int options)
- {
- ptid_t return_ptid;
- return_ptid = record_full_wait_1 (ops, ptid, status, options);
- if (status->kind != TARGET_WAITKIND_IGNORE)
- {
-
- record_full_resumed = 0;
- }
- return return_ptid;
- }
- static int
- record_full_stopped_by_watchpoint (struct target_ops *ops)
- {
- if (RECORD_FULL_IS_REPLAY)
- return record_full_hw_watchpoint;
- else
- return ops->beneath->to_stopped_by_watchpoint (ops->beneath);
- }
- static int
- record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
- {
- if (RECORD_FULL_IS_REPLAY)
- return 0;
- else
- return ops->beneath->to_stopped_data_address (ops->beneath, addr_p);
- }
- static void
- record_full_registers_change (struct regcache *regcache, int regnum)
- {
-
- record_full_check_insn_num (0);
- record_full_arch_list_head = NULL;
- record_full_arch_list_tail = NULL;
- if (regnum < 0)
- {
- int i;
- for (i = 0; i < gdbarch_num_regs (get_regcache_arch (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_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_full_arch_list_add_end ())
- {
- record_full_list_release (record_full_arch_list_tail);
- error (_("Process record: failed to record execution log."));
- }
- 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_list_release_first ();
- else
- record_full_insn_num++;
- }
- static void
- record_full_store_registers (struct target_ops *ops,
- struct regcache *regcache,
- int regno)
- {
- if (!record_full_gdb_operation_disable)
- {
- if (RECORD_FULL_IS_REPLAY)
- {
- int n;
-
- if (regno < 0)
- n =
- query (_("Because GDB is in replay mode, changing the "
- "value of a register will make the execution "
- "log unusable from this point onward. "
- "Change all registers?"));
- else
- n =
- query (_("Because GDB is in replay mode, changing the value "
- "of a register will make the execution log unusable "
- "from this point onward. Change register %s?"),
- gdbarch_register_name (get_regcache_arch (regcache),
- regno));
- if (!n)
- {
-
- if (regno < 0)
- {
- int i;
- for (i = 0;
- i < gdbarch_num_regs (get_regcache_arch (regcache));
- i++)
- regcache_invalidate (regcache, i);
- }
- else
- regcache_invalidate (regcache, regno);
- error (_("Process record canceled the operation."));
- }
-
- record_full_list_release_following (record_full_list);
- }
- record_full_registers_change (regcache, regno);
- }
- ops->beneath->to_store_registers (ops->beneath, regcache, regno);
- }
- 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,
- ULONGEST len, ULONGEST *xfered_len)
- {
- if (!record_full_gdb_operation_disable
- && (object == TARGET_OBJECT_MEMORY
- || object == TARGET_OBJECT_RAW_MEMORY) && writebuf)
- {
- if (RECORD_FULL_IS_REPLAY)
- {
-
- if (!query (_("Because GDB is in replay mode, writing to memory "
- "will make the execution log unusable from this "
- "point onward. Write memory at address %s?"),
- paddress (target_gdbarch (), offset)))
- error (_("Process record canceled the operation."));
-
- record_full_list_release_following (record_full_list);
- }
-
- record_full_check_insn_num (0);
-
- record_full_arch_list_head = NULL;
- record_full_arch_list_tail = NULL;
- 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 TARGET_XFER_E_IO;
- }
- 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 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_list_release_first ();
- else
- record_full_insn_num++;
- }
- return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
- readbuf, writebuf, offset,
- len, xfered_len);
- }
- struct record_full_breakpoint
- {
-
- struct address_space *address_space;
- CORE_ADDR addr;
-
- int in_target_beneath;
- };
- typedef struct record_full_breakpoint *record_full_breakpoint_p;
- DEF_VEC_P(record_full_breakpoint_p);
- VEC(record_full_breakpoint_p) *record_full_breakpoints = NULL;
- static void
- record_full_sync_record_breakpoints (struct bp_location *loc, void *data)
- {
- if (loc->loc_type != bp_loc_software_breakpoint)
- return;
- 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);
- }
- }
- static void
- record_full_init_record_breakpoints (void)
- {
- VEC_free (record_full_breakpoint_p, record_full_breakpoints);
- iterate_over_bp_locations (record_full_sync_record_breakpoints);
- }
- static int
- record_full_insert_breakpoint (struct target_ops *ops,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- struct record_full_breakpoint *bp;
- int in_target_beneath = 0;
- if (!RECORD_FULL_IS_REPLAY)
- {
-
- struct cleanup *old_cleanups;
- int ret;
- 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)
- return ret;
- in_target_beneath = 1;
- }
- 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);
- return 0;
- }
- static int
- record_full_remove_breakpoint (struct target_ops *ops,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- struct record_full_breakpoint *bp;
- int ix;
- 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)
- {
- if (bp->in_target_beneath)
- {
- struct cleanup *old_cleanups;
- int ret;
- 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)
- return ret;
- }
- VEC_unordered_remove (record_full_breakpoint_p,
- record_full_breakpoints, ix);
- return 0;
- }
- }
- gdb_assert_not_reached ("removing unknown breakpoint");
- }
- static int
- record_full_can_execute_reverse (struct target_ops *self)
- {
- return 1;
- }
- static gdb_byte *
- record_full_get_bookmark (struct target_ops *self, const char *args,
- int from_tty)
- {
- char *ret = NULL;
-
- if (record_full_list && record_full_list->type == record_full_end)
- ret = xstrdup (pulongest (record_full_list->u.end.insn_num));
- if (record_debug)
- {
- if (ret)
- fprintf_unfiltered (gdb_stdlog,
- "record_full_get_bookmark returns %s\n", ret);
- else
- fprintf_unfiltered (gdb_stdlog,
- "record_full_get_bookmark returns NULL\n");
- }
- return (gdb_byte *) ret;
- }
- static void
- 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);
- copy = savestring (bookmark + 1, strlen (bookmark) - 2);
- make_cleanup (xfree, copy);
- bookmark = copy;
- }
- record_goto (bookmark);
- do_cleanups (cleanup);
- }
- static enum exec_direction_kind
- record_full_execution_direction (struct target_ops *self)
- {
- return record_full_execution_dir;
- }
- static void
- record_full_info (struct target_ops *self)
- {
- struct record_full_entry *p;
- if (RECORD_FULL_IS_REPLAY)
- printf_filtered (_("Replay mode:\n"));
- else
- printf_filtered (_("Record mode:\n"));
-
- for (p = record_full_first.next;
- p != NULL && p->type != record_full_end;
- p = p->next)
- ;
-
- if (p != NULL && p->type == record_full_end)
- {
-
- printf_filtered (_("Lowest recorded instruction number is %s.\n"),
- pulongest (p->u.end.insn_num));
-
- if (RECORD_FULL_IS_REPLAY)
- printf_filtered (_("Current instruction number is %s.\n"),
- pulongest (record_full_list->u.end.insn_num));
-
- printf_filtered (_("Highest recorded instruction number is %s.\n"),
- pulongest (record_full_insn_count));
-
- printf_filtered (_("Log contains %u instructions.\n"),
- record_full_insn_num);
- }
- else
- printf_filtered (_("No instructions have been logged.\n"));
-
- printf_filtered (_("Max logged instructions is %u.\n"),
- record_full_insn_max_num);
- }
- static void
- record_full_delete (struct target_ops *self)
- {
- record_full_list_release_following (record_full_list);
- }
- static int
- record_full_is_replaying (struct target_ops *self)
- {
- return RECORD_FULL_IS_REPLAY;
- }
- static void
- record_full_goto_entry (struct record_full_entry *p)
- {
- if (p == NULL)
- error (_("Target insn not found."));
- else if (p == record_full_list)
- error (_("Already at target insn."));
- else if (p->u.end.insn_num > record_full_list->u.end.insn_num)
- {
- printf_filtered (_("Go forward to insn number %s\n"),
- pulongest (p->u.end.insn_num));
- record_full_goto_insn (p, EXEC_FORWARD);
- }
- else
- {
- printf_filtered (_("Go backward to insn number %s\n"),
- pulongest (p->u.end.insn_num));
- record_full_goto_insn (p, EXEC_REVERSE);
- }
- registers_changed ();
- reinit_frame_cache ();
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
- }
- static void
- record_full_goto_begin (struct target_ops *self)
- {
- struct record_full_entry *p = NULL;
- for (p = &record_full_first; p != NULL; p = p->next)
- if (p->type == record_full_end)
- break;
- record_full_goto_entry (p);
- }
- static void
- record_full_goto_end (struct target_ops *self)
- {
- struct record_full_entry *p = NULL;
- for (p = record_full_list; p->next != NULL; p = p->next)
- ;
- for (; p!= NULL; p = p->prev)
- if (p->type == record_full_end)
- break;
- record_full_goto_entry (p);
- }
- static void
- record_full_goto (struct target_ops *self, ULONGEST target_insn)
- {
- struct record_full_entry *p = NULL;
- for (p = &record_full_first; p != NULL; p = p->next)
- if (p->type == record_full_end && p->u.end.insn_num == target_insn)
- break;
- record_full_goto_entry (p);
- }
- static void
- init_record_full_ops (void)
- {
- record_full_ops.to_shortname = "record-full";
- record_full_ops.to_longname = "Process record and replay target";
- record_full_ops.to_doc =
- "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_resume = record_full_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_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_can_execute_reverse = record_full_can_execute_reverse;
- record_full_ops.to_stratum = record_stratum;
-
- record_full_ops.to_get_bookmark = record_full_get_bookmark;
- record_full_ops.to_goto_bookmark = record_full_goto_bookmark;
- 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;
- record_full_ops.to_delete_record = record_full_delete;
- record_full_ops.to_record_is_replaying = record_full_is_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;
- record_full_ops.to_magic = OPS_MAGIC;
- }
- static void
- record_full_core_resume (struct target_ops *ops, ptid_t ptid, int step,
- enum gdb_signal signal)
- {
- record_full_resume_step = step;
- record_full_resumed = 1;
- record_full_execution_dir = execution_direction;
-
- if (target_can_async_p ())
- {
- target_async (inferior_event_handler, 0);
-
- mark_async_event_handler (record_full_async_inferior_event_token);
- }
- }
- static void
- record_full_core_kill (struct target_ops *ops)
- {
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_full_core_kill\n");
- unpush_target (&record_full_core_ops);
- }
- static void
- record_full_core_fetch_registers (struct target_ops *ops,
- struct regcache *regcache,
- int regno)
- {
- if (regno < 0)
- {
- int num = gdbarch_num_regs (get_regcache_arch (regcache));
- int i;
- for (i = 0; i < num; i ++)
- regcache_raw_supply (regcache, i,
- record_full_core_regbuf + MAX_REGISTER_SIZE * i);
- }
- else
- regcache_raw_supply (regcache, regno,
- record_full_core_regbuf + MAX_REGISTER_SIZE * regno);
- }
- static void
- record_full_core_prepare_to_store (struct target_ops *self,
- struct regcache *regcache)
- {
- }
- static void
- record_full_core_store_registers (struct target_ops *ops,
- struct regcache *regcache,
- int regno)
- {
- if (record_full_gdb_operation_disable)
- regcache_raw_collect (regcache, regno,
- record_full_core_regbuf + MAX_REGISTER_SIZE * regno);
- else
- error (_("You can't do that without a process to debug."));
- }
- 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,
- ULONGEST len, ULONGEST *xfered_len)
- {
- if (object == TARGET_OBJECT_MEMORY)
- {
- if (record_full_gdb_operation_disable || !writebuf)
- {
- struct target_section *p;
- for (p = record_full_core_start; p < record_full_core_end; p++)
- {
- if (offset >= p->addr)
- {
- struct record_full_core_buf_entry *entry;
- ULONGEST sec_offset;
- if (offset >= p->endaddr)
- continue;
- if (offset + len > p->endaddr)
- len = p->endaddr - offset;
- sec_offset = offset - p->addr;
-
-
- if (p->the_bfd_section->flags & SEC_CONSTRUCTOR
- || (p->the_bfd_section->flags & SEC_HAS_CONTENTS) == 0)
- {
- if (readbuf)
- memset (readbuf, 0, len);
- *xfered_len = len;
- return TARGET_XFER_OK;
- }
-
- for (entry = record_full_core_buf_list; entry;
- entry = entry->prev)
- if (entry->p == p)
- break;
- if (writebuf)
- {
- if (!entry)
- {
-
- entry = (struct record_full_core_buf_entry *)
- xmalloc
- (sizeof (struct record_full_core_buf_entry));
- entry->p = p;
- if (!bfd_malloc_and_get_section
- (p->the_bfd_section->owner,
- p->the_bfd_section,
- &entry->buf))
- {
- xfree (entry);
- return TARGET_XFER_EOF;
- }
- entry->prev = record_full_core_buf_list;
- record_full_core_buf_list = entry;
- }
- memcpy (entry->buf + sec_offset, writebuf,
- (size_t) len);
- }
- else
- {
- if (!entry)
- 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);
- }
- *xfered_len = len;
- return TARGET_XFER_OK;
- }
- }
- return TARGET_XFER_E_IO;
- }
- else
- error (_("You can't do that without a process to debug."));
- }
- return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
- readbuf, writebuf, offset, len,
- xfered_len);
- }
- static int
- record_full_core_insert_breakpoint (struct target_ops *ops,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- return 0;
- }
- static int
- record_full_core_remove_breakpoint (struct target_ops *ops,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- return 0;
- }
- static int
- record_full_core_has_execution (struct target_ops *ops, ptid_t the_ptid)
- {
- return 1;
- }
- static void
- init_record_full_core_ops (void)
- {
- record_full_core_ops.to_shortname = "record-core";
- record_full_core_ops.to_longname = "Process record and replay target";
- record_full_core_ops.to_doc =
- "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_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_core_ops.to_fetch_registers = record_full_core_fetch_registers;
- record_full_core_ops.to_prepare_to_store = record_full_core_prepare_to_store;
- record_full_core_ops.to_store_registers = record_full_core_store_registers;
- record_full_core_ops.to_xfer_partial = record_full_core_xfer_partial;
- record_full_core_ops.to_insert_breakpoint
- = record_full_core_insert_breakpoint;
- record_full_core_ops.to_remove_breakpoint
- = record_full_core_remove_breakpoint;
- record_full_core_ops.to_stopped_by_watchpoint
- = record_full_stopped_by_watchpoint;
- record_full_core_ops.to_stopped_data_address
- = record_full_stopped_data_address;
- 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;
- record_full_core_ops.to_stratum = record_stratum;
-
- 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_execution_direction
- = record_full_execution_direction;
- 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_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;
- record_full_core_ops.to_magic = OPS_MAGIC;
- }
- static inline void
- bfdcore_read (bfd *obfd, asection *osec, void *buf, int len, int *offset)
- {
- int ret = bfd_get_section_contents (obfd, osec, buf, *offset, len);
- if (ret)
- *offset += len;
- else
- error (_("Failed to read %d bytes from core file %s ('%s')."),
- len, bfd_get_filename (obfd),
- bfd_errmsg (bfd_get_error ()));
- }
- static inline uint64_t
- netorder64 (uint64_t input)
- {
- uint64_t ret;
- store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
- BFD_ENDIAN_BIG, input);
- return ret;
- }
- static inline uint32_t
- netorder32 (uint32_t input)
- {
- uint32_t ret;
- store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
- BFD_ENDIAN_BIG, input);
- return ret;
- }
- static inline uint16_t
- netorder16 (uint16_t input)
- {
- uint16_t ret;
- store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
- BFD_ENDIAN_BIG, input);
- return ret;
- }
- static void
- record_full_restore (void)
- {
- uint32_t magic;
- struct cleanup *old_cleanups;
- struct record_full_entry *rec;
- asection *osec;
- uint32_t osec_size;
- int bfd_offset = 0;
- struct regcache *regcache;
-
- if (core_bfd == NULL)
- return;
-
- gdb_assert (record_full_first.next == NULL);
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Restoring recording from core file.\n");
-
- osec = bfd_get_section_by_name (core_bfd, "null0");
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Find precord section %s.\n",
- osec ? "succeeded" : "failed");
- if (osec == NULL)
- return;
- osec_size = bfd_section_size (core_bfd, osec);
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (core_bfd, osec));
-
- bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset);
- if (magic != RECORD_FULL_FILE_MAGIC)
- error (_("Version mis-match or file format error in core file %s."),
- bfd_get_filename (core_bfd));
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Reading 4-byte magic cookie "
- "RECORD_FULL_FILE_MAGIC (0x%s)\n",
- phex_nz (netorder32 (magic), 4));
-
- 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)
- {
- uint8_t rectype;
- uint32_t regnum, len, signal, count;
- uint64_t addr;
-
- if (bfd_offset >= osec_size)
- break;
- bfdcore_read (core_bfd, osec, &rectype, sizeof (rectype), &bfd_offset);
- switch (rectype)
- {
- case record_full_reg:
-
- bfdcore_read (core_bfd, osec, ®num,
- sizeof (regnum), &bfd_offset);
- regnum = netorder32 (regnum);
- rec = record_full_reg_alloc (regcache, regnum);
-
- bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
- rec->u.reg.len, &bfd_offset);
- 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:
-
- bfdcore_read (core_bfd, osec, &len,
- sizeof (len), &bfd_offset);
- len = netorder32 (len);
-
- bfdcore_read (core_bfd, osec, &addr,
- sizeof (addr), &bfd_offset);
- addr = netorder64 (addr);
- rec = record_full_mem_alloc (addr, len);
-
- 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:
- rec = record_full_end_alloc ();
- record_full_insn_num ++;
-
- bfdcore_read (core_bfd, osec, &signal,
- sizeof (signal), &bfd_offset);
- signal = netorder32 (signal);
- rec->u.end.sigval = signal;
-
- 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;
- }
-
- record_full_arch_list_add (rec);
- }
- discard_cleanups (old_cleanups);
-
- record_full_first.next = record_full_arch_list_head;
- record_full_arch_list_head->prev = &record_full_first;
- record_full_arch_list_tail->next = NULL;
- record_full_list = &record_full_first;
-
- 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 %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, 1);
- }
- static inline void
- bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset)
- {
- int ret = bfd_set_section_contents (obfd, osec, buf, *offset, len);
- if (ret)
- *offset += len;
- else
- error (_("Failed to write %d bytes to core file %s ('%s')."),
- len, bfd_get_filename (obfd),
- bfd_errmsg (bfd_get_error ()));
- }
- static void
- cmd_record_full_restore (char *args, int from_tty)
- {
- core_file_command (args, from_tty);
- record_full_open (args, from_tty);
- }
- static void
- record_full_save_cleanups (void *data)
- {
- bfd *obfd = data;
- char *pathname = xstrdup (bfd_get_filename (obfd));
- gdb_bfd_unref (obfd);
- unlink (pathname);
- xfree (pathname);
- }
- static void
- record_full_save (struct target_ops *self, const char *recfilename)
- {
- struct record_full_entry *cur_record_full_list;
- uint32_t magic;
- struct regcache *regcache;
- struct gdbarch *gdbarch;
- struct cleanup *old_cleanups;
- struct cleanup *set_cleanups;
- bfd *obfd;
- int save_size = 0;
- asection *osec = NULL;
- int bfd_offset = 0;
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Saving execution log to core file '%s'\n",
- recfilename);
-
- obfd = create_gcore_bfd (recfilename);
- old_cleanups = make_cleanup (record_full_save_cleanups, obfd);
-
- cur_record_full_list = record_full_list;
-
- regcache = get_current_regcache ();
- gdbarch = get_regcache_arch (regcache);
-
- set_cleanups = record_full_gdb_operation_disable_set ();
-
- while (1)
- {
-
- if (record_full_list == &record_full_first)
- break;
- record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (record_full_list->prev)
- record_full_list = record_full_list->prev;
- }
-
- save_size = 4;
- for (record_full_list = record_full_first.next; record_full_list;
- record_full_list = record_full_list->next)
- switch (record_full_list->type)
- {
- case record_full_end:
- save_size += 1 + 4 + 4;
- break;
- case record_full_reg:
- save_size += 1 + 4 + record_full_list->u.reg.len;
- break;
- case record_full_mem:
- save_size += 1 + 4 + 8 + record_full_list->u.mem.len;
- break;
- }
-
- osec = bfd_make_section_anyway_with_flags (obfd, "precord",
- SEC_HAS_CONTENTS
- | SEC_READONLY);
- if (osec == NULL)
- error (_("Failed to create 'precord' section for corefile %s: %s"),
- recfilename,
- bfd_errmsg (bfd_get_error ()));
- bfd_set_section_size (obfd, osec, save_size);
- bfd_set_section_vma (obfd, osec, 0);
- bfd_set_section_alignment (obfd, osec, 0);
- bfd_section_lma (obfd, osec) = 0;
-
- write_gcore_file (obfd);
-
-
- magic = RECORD_FULL_FILE_MAGIC;
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Writing 4-byte magic cookie "
- "RECORD_FULL_FILE_MAGIC (0x%s)\n",
- phex_nz (magic, 4));
- bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset);
-
- record_full_list = &record_full_first;
- while (1)
- {
-
- if (record_full_list != &record_full_first)
- {
- uint8_t type;
- uint32_t regnum, len, signal, count;
- uint64_t addr;
- type = record_full_list->type;
- bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset);
- switch (record_full_list->type)
- {
- case record_full_reg:
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Writing register %d (1 "
- "plus %lu plus %d bytes)\n",
- record_full_list->u.reg.num,
- (unsigned long) sizeof (regnum),
- record_full_list->u.reg.len);
-
- regnum = netorder32 (record_full_list->u.reg.num);
- bfdcore_write (obfd, osec, ®num,
- sizeof (regnum), &bfd_offset);
-
- bfdcore_write (obfd, osec,
- record_full_get_loc (record_full_list),
- record_full_list->u.reg.len, &bfd_offset);
- break;
- case record_full_mem:
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Writing memory %s (1 plus "
- "%lu plus %lu plus %d bytes)\n",
- paddress (gdbarch,
- record_full_list->u.mem.addr),
- (unsigned long) sizeof (addr),
- (unsigned long) sizeof (len),
- record_full_list->u.mem.len);
-
- len = netorder32 (record_full_list->u.mem.len);
- bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset);
-
- addr = netorder64 (record_full_list->u.mem.addr);
- bfdcore_write (obfd, osec, &addr,
- sizeof (addr), &bfd_offset);
-
- bfdcore_write (obfd, osec,
- record_full_get_loc (record_full_list),
- record_full_list->u.mem.len, &bfd_offset);
- break;
- case record_full_end:
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Writing record_full_end (1 + "
- "%lu + %lu bytes)\n",
- (unsigned long) sizeof (signal),
- (unsigned long) sizeof (count));
-
- signal = netorder32 (record_full_list->u.end.sigval);
- bfdcore_write (obfd, osec, &signal,
- sizeof (signal), &bfd_offset);
-
- count = netorder32 (record_full_list->u.end.insn_num);
- bfdcore_write (obfd, osec, &count,
- sizeof (count), &bfd_offset);
- break;
- }
- }
-
- record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (record_full_list->next)
- record_full_list = record_full_list->next;
- else
- break;
- }
-
- while (1)
- {
-
- if (record_full_list == cur_record_full_list)
- break;
- record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (record_full_list->prev)
- record_full_list = record_full_list->prev;
- }
- do_cleanups (set_cleanups);
- gdb_bfd_unref (obfd);
- discard_cleanups (old_cleanups);
-
- printf_filtered (_("Saved core file %s with execution log.\n"),
- recfilename);
- }
- static void
- record_full_goto_insn (struct record_full_entry *entry,
- enum exec_direction_kind dir)
- {
- struct cleanup *set_cleanups = record_full_gdb_operation_disable_set ();
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
-
- if (dir == EXEC_FORWARD)
- record_full_list = record_full_list->next;
- do
- {
- record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (dir == EXEC_REVERSE)
- record_full_list = record_full_list->prev;
- else
- record_full_list = record_full_list->next;
- } while (record_full_list != entry);
- do_cleanups (set_cleanups);
- }
- static void
- cmd_record_full_start (char *args, int from_tty)
- {
- execute_command ("target record-full", from_tty);
- }
- static void
- 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)
- {
-
- while (record_full_insn_num > record_full_insn_max_num)
- {
- record_full_list_release_first ();
- record_full_insn_num--;
- }
- }
- }
- static void
- set_record_full_command (char *args, int from_tty)
- {
- printf_unfiltered (_("\"set record full\" must be followed "
- "by an apporpriate subcommand.\n"));
- help_list (set_record_full_cmdlist, "set record full ", all_commands,
- gdb_stdout);
- }
- static void
- show_record_full_command (char *args, int from_tty)
- {
- cmd_show_list (show_record_full_cmdlist, from_tty, "");
- }
- extern initialize_file_ftype _initialize_record_full;
- void
- _initialize_record_full (void)
- {
- struct cmd_list_element *c;
-
- record_full_first.prev = NULL;
- record_full_first.next = NULL;
- record_full_first.type = record_full_end;
- init_record_full_ops ();
- add_target (&record_full_ops);
- add_deprecated_target_alias (&record_full_ops, "record");
- init_record_full_core_ops ();
- add_target (&record_full_core_ops);
- add_prefix_cmd ("full", class_obscure, cmd_record_full_start,
- _("Start full execution recording."), &record_full_cmdlist,
- "record full ", 0, &record_cmdlist);
- c = add_cmd ("restore", class_obscure, cmd_record_full_restore,
- _("Restore the execution log from a file.\n\
- Argument is filename. File must be created with 'record save'."),
- &record_full_cmdlist);
- set_cmd_completer (c, filename_completer);
-
- c = add_alias_cmd ("restore", "full restore", class_obscure, 1,
- &record_cmdlist);
- set_cmd_completer (c, filename_completer);
- deprecate_cmd (c, "record full restore");
- add_prefix_cmd ("full", class_support, set_record_full_command,
- _("Set record options"), &set_record_full_cmdlist,
- "set record full ", 0, &set_record_cmdlist);
- add_prefix_cmd ("full", class_support, show_record_full_command,
- _("Show record options"), &show_record_full_cmdlist,
- "show record full ", 0, &show_record_cmdlist);
-
- add_setshow_boolean_cmd ("stop-at-limit", no_class,
- &record_full_stop_at_limit, _("\
- Set whether record/replay stops when record/replay buffer becomes full."), _("\
- Show whether record/replay stops when record/replay buffer becomes full."),
- _("Default is ON.\n\
- When ON, if the record/replay buffer becomes full, ask user what to do.\n\
- When OFF, if the record/replay buffer becomes full,\n\
- delete the oldest recorded instruction to make room for each new one."),
- NULL, NULL,
- &set_record_full_cmdlist, &show_record_full_cmdlist);
- c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", no_class, 1,
- &set_record_cmdlist);
- deprecate_cmd (c, "set record full stop-at-limit");
- c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", no_class, 1,
- &show_record_cmdlist);
- deprecate_cmd (c, "show record full stop-at-limit");
- add_setshow_uinteger_cmd ("insn-number-max", no_class,
- &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. 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);
- c = add_alias_cmd ("insn-number-max", "full insn-number-max", no_class, 1,
- &set_record_cmdlist);
- deprecate_cmd (c, "set record full insn-number-max");
- c = add_alias_cmd ("insn-number-max", "full insn-number-max", no_class, 1,
- &show_record_cmdlist);
- deprecate_cmd (c, "show record full insn-number-max");
- add_setshow_boolean_cmd ("memory-query", no_class,
- &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."),
- _("\
- Default is OFF.\n\
- When ON, query if PREC cannot record memory change of next instruction."),
- NULL, NULL,
- &set_record_full_cmdlist,
- &show_record_full_cmdlist);
- c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1,
- &set_record_cmdlist);
- deprecate_cmd (c, "set record full memory-query");
- c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1,
- &show_record_cmdlist);
- deprecate_cmd (c, "show record full memory-query");
- }