X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Frecord-full.c;h=4d8dd61bcaaa9d18108ec840a60df82f742f7335;hb=e427af1889e6d169c3390f6960f1efdd08dca883;hp=3fb77ef422ae5c870cd8b9b83077739eac323d12;hpb=ecd75fc8eed3bde86036141228074a20e55dcfc9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/record-full.c b/gdb/record-full.c index 3fb77ef422..4d8dd61bca 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -1,6 +1,6 @@ /* Process record and replay target for GDB, the GNU debugger. - Copyright (C) 2013-2014 Free Software Foundation, Inc. + Copyright (C) 2013-2018 Free Software Foundation, Inc. This file is part of GDB. @@ -22,7 +22,6 @@ #include "regcache.h" #include "gdbthread.h" #include "event-top.h" -#include "exceptions.h" #include "completer.h" #include "arch-utils.h" #include "gdbcore.h" @@ -34,7 +33,10 @@ #include "event-loop.h" #include "inf-loop.h" #include "gdb_bfd.h" -#include "observer.h" +#include "observable.h" +#include "infrun.h" +#include "common/gdb_unlinker.h" +#include "common/byte-vector.h" #include @@ -166,7 +168,7 @@ struct record_full_core_buf_entry }; /* Record buf with core target. */ -static gdb_byte *record_full_core_regbuf = NULL; +static detached_regcache *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; @@ -208,6 +210,19 @@ 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; @@ -215,36 +230,10 @@ 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 target_xfer_partial_ftype *record_full_beneath_to_xfer_partial; -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 (const 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. */ @@ -255,9 +244,9 @@ 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); + struct gdbarch *gdbarch = regcache->arch (); - 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); @@ -285,7 +274,7 @@ record_full_mem_alloc (CORE_ADDR addr, int len) { 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; @@ -313,7 +302,7 @@ record_full_end_alloc (void) { 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; @@ -548,26 +537,18 @@ record_full_arch_list_add_end (void) } static void -record_full_check_insn_num (int set_terminal) +record_full_check_insn_num (void) { if (record_full_insn_num == record_full_insn_max_num) { /* Ask user what to do. */ if (record_full_stop_at_limit) { - int q; - - if (set_terminal) - target_terminal_ours (); - q = yquery (_("Do you want to auto delete previous execution " + if (!yquery (_("Do you want to auto delete previous execution " "log entries when record/replay buffer becomes " - "full (record full stop-at-limit)?")); - if (set_terminal) - target_terminal_inferior (); - if (q) - record_full_stop_at_limit = 0; - else + "full (record full stop-at-limit)?"))) error (_("Process record: stopped by user.")); + record_full_stop_at_limit = 0; } } } @@ -584,11 +565,11 @@ record_full_arch_list_cleanups (void *ignore) record the running message of inferior and set them to record_full_arch_list, and add it to record_full_list. */ -static int +static void record_full_message (struct regcache *regcache, enum gdb_signal signal) { int ret; - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); struct cleanup *old_cleanups = make_cleanup (record_full_arch_list_cleanups, 0); @@ -596,7 +577,7 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) record_full_arch_list_tail = NULL; /* Check record_full_insn_num. */ - record_full_check_insn_num (1); + record_full_check_insn_num (); /* If gdb sends a signal value to target_resume, save it in the 'end' field of the previous instruction. @@ -652,35 +633,24 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) 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 +static bool record_full_message_wrapper_safe (struct regcache *regcache, enum gdb_signal signal) { - struct record_full_message_args args; - - args.regcache = regcache; - args.signal = signal; + TRY + { + record_full_message (regcache, signal); + } + CATCH (ex, RETURN_MASK_ALL) + { + exception_print (gdb_stderr, ex); + return false; + } + END_CATCH - return catch_errors (record_full_message_wrapper, &args, NULL, - RETURN_MASK_ALL); + return true; } /* Set to 1 if record_full_store_registers and record_full_xfer_partial @@ -688,20 +658,15 @@ record_full_message_wrapper_safe (struct regcache *regcache, static int record_full_gdb_operation_disable = 0; -struct cleanup * +scoped_restore_tmpl 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; + return make_scoped_restore (&record_full_gdb_operation_disable, 1); } /* 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 @@ -716,7 +681,7 @@ record_full_exec_insn (struct regcache *regcache, { case record_full_reg: /* reg */ { - gdb_byte reg[MAX_REGISTER_SIZE]; + gdb::byte_vector reg (entry->u.reg.len); if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, @@ -725,10 +690,10 @@ record_full_exec_insn (struct regcache *regcache, host_address_to_string (entry), entry->u.reg.num); - regcache_cooked_read (regcache, entry->u.reg.num, reg); + regcache_cooked_read (regcache, entry->u.reg.num, reg.data ()); regcache_cooked_write (regcache, entry->u.reg.num, record_full_get_loc (entry)); - memcpy (record_full_get_loc (entry), reg, entry->u.reg.len); + memcpy (record_full_get_loc (entry), reg.data (), entry->u.reg.len); } break; @@ -737,7 +702,7 @@ record_full_exec_insn (struct regcache *regcache, /* Nothing to do if the entry is flagged not_accessible. */ if (!entry->u.mem.mem_entry_not_accessible) { - gdb_byte *mem = alloca (entry->u.mem.len); + gdb::byte_vector mem (entry->u.mem.len); if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, @@ -748,7 +713,8 @@ record_full_exec_insn (struct regcache *regcache, entry->u.mem.len); if (record_read_memory (gdbarch, - entry->u.mem.addr, mem, entry->u.mem.len)) + entry->u.mem.addr, mem.data (), + entry->u.mem.len)) entry->u.mem.mem_entry_not_accessible = 1; else { @@ -765,7 +731,7 @@ record_full_exec_insn (struct regcache *regcache, } else { - memcpy (record_full_get_loc (entry), mem, + memcpy (record_full_get_loc (entry), mem.data (), entry->u.mem.len); /* We've changed memory --- check if a hardware @@ -777,9 +743,9 @@ record_full_exec_insn (struct regcache *regcache, not doing the change at all if the watchpoint traps. */ if (hardware_watchpoint_inserted_in_range - (get_regcache_aspace (regcache), + (regcache->aspace (), entry->u.mem.addr, entry->u.mem.len)) - record_full_hw_watchpoint = 1; + record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT; } } } @@ -788,28 +754,6 @@ record_full_exec_insn (struct regcache *regcache, } } -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 target_xfer_partial_ftype *tmp_to_xfer_partial; -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 @@ -826,24 +770,24 @@ record_full_async_inferior_event_handler (gdb_client_data data) /* 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)); + int regnum = gdbarch_num_regs (regcache->arch ()); int i; /* Get record_full_core_regbuf. */ target_fetch_registers (regcache, -1); - record_full_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum); + record_full_core_regbuf = new detached_regcache (regcache->arch (), false); + for (i = 0; i < regnum; i ++) - regcache_raw_collect (regcache, i, - record_full_core_regbuf + MAX_REGISTER_SIZE * i); + record_full_core_regbuf->raw_supply (i, *regcache); /* Get record_full_core_start and record_full_core_end. */ if (build_section_table (core_bfd, &record_full_core_start, &record_full_core_end)) { - xfree (record_full_core_regbuf); + delete 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 ())); @@ -856,10 +800,10 @@ record_full_core_open_1 (char *name, int from_tty) /* "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"); + fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open_1\n"); /* check exec */ if (!target_has_execution) @@ -872,26 +816,6 @@ record_full_open_1 (char *name, int from_tty) 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); } @@ -900,69 +824,12 @@ static void record_full_init_record_breakpoints (void); /* "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; @@ -970,21 +837,6 @@ record_full_open (char *name, int from_tty) 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 @@ -997,13 +849,13 @@ record_full_open (char *name, int from_tty) record_full_init_record_breakpoints (); - observer_notify_record_changed (current_inferior (), 1); + gdb::observers::record_changed.notify (current_inferior (), 1, "full", NULL); } /* "to_close" target method. Close the process record target. */ static void -record_full_close (void) +record_full_close (struct target_ops *self) { struct record_full_core_buf_entry *entry; @@ -1015,7 +867,7 @@ record_full_close (void) /* Release record_full_core_regbuf. */ if (record_full_core_regbuf) { - xfree (record_full_core_regbuf); + delete record_full_core_regbuf; record_full_core_regbuf = NULL; } @@ -1035,6 +887,19 @@ record_full_close (void) 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 @@ -1084,43 +949,36 @@ record_full_resume (struct target_ops *ops, ptid_t ptid, int step, } else { - /* This arch support soft sigle step. */ - if (single_step_breakpoints_inserted ()) + /* This arch supports soft single step. */ + if (thread_has_single_step_breakpoints_set (inferior_thread ())) { /* This is a soft single step. */ record_full_resume_step = 1; } else - { - /* This is a continue. - Try to insert a soft single step breakpoint. */ - if (!gdbarch_software_single_step (gdbarch, - get_current_frame ())) - { - /* This system don't want use soft single step. - Use hard sigle step. */ - step = 1; - } - } + step = !insert_single_step_breakpoints (gdbarch); } } /* 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); +} + +/* "to_commit_resume" method for process record target. */ + +static void +record_full_commit_resume (struct target_ops *ops) +{ + if (!RECORD_FULL_IS_REPLAY) + ops->beneath->to_commit_resume (ops->beneath); } static int record_full_get_sig = 0; @@ -1171,7 +1029,8 @@ 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 (); + scoped_restore restore_operation_disable + = record_full_gdb_operation_disable_set (); if (record_debug) fprintf_unfiltered (gdb_stdlog, @@ -1194,13 +1053,14 @@ record_full_wait_1 (struct target_ops *ops, 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 { @@ -1211,8 +1071,9 @@ record_full_wait_1 (struct target_ops *ops, 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) @@ -1222,8 +1083,8 @@ record_full_wait_1 (struct target_ops *ops, 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; @@ -1233,7 +1094,8 @@ record_full_wait_1 (struct target_ops *ops, && status->value.sig == GDB_SIGNAL_TRAP) { 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 @@ -1242,26 +1104,17 @@ record_full_wait_1 (struct target_ops *ops, registers_changed (); regcache = get_current_regcache (); tmp_pc = regcache_read_pc (regcache); - aspace = get_regcache_aspace (regcache); + const struct address_space *aspace = regcache->aspace (); if (target_stopped_by_watchpoint ()) { /* 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 { @@ -1285,9 +1138,9 @@ record_full_wait_1 (struct target_ops *ops, If insert success, set step to 0. */ set_executing (inferior_ptid, 0); reinit_frame_cache (); - if (gdbarch_software_single_step (gdbarch, - get_current_frame ())) - step = 0; + + step = !insert_single_step_breakpoints (gdbarch); + set_executing (inferior_ptid, 1); } @@ -1296,9 +1149,9 @@ record_full_wait_1 (struct target_ops *ops, "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); + ops->beneath->to_commit_resume (ops->beneath); continue; } } @@ -1313,35 +1166,28 @@ record_full_wait_1 (struct target_ops *ops, else { struct regcache *regcache = get_current_regcache (); - struct gdbarch *gdbarch = get_regcache_arch (regcache); - struct address_space *aspace = get_regcache_aspace (regcache); + struct gdbarch *gdbarch = regcache->arch (); + const struct address_space *aspace = regcache->aspace (); int continue_flag = 1; int first_record_full_end = 1; struct cleanup *old_cleanups = make_cleanup (record_full_wait_cleanups, 0); CORE_ADDR tmp_pc; - record_full_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; } } @@ -1350,7 +1196,7 @@ record_full_wait_1 (struct target_ops *ops, And in GDB replay mode, GDB doesn't need to be in terminal_inferior mode, because inferior will not executed. Then set it to terminal_ours to make GDB get the signal. */ - target_terminal_ours (); + target_terminal::ours (); /* In EXEC_FORWARD mode, record_full_list points to the tail of prev instruction. */ @@ -1409,27 +1255,19 @@ record_full_wait_1 (struct target_ops *ops, /* 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, @@ -1474,7 +1312,6 @@ replay_out: signal (SIGINT, handle_sigint); - do_cleanups (set_cleanups); return inferior_ptid; } @@ -1497,12 +1334,12 @@ record_full_wait (struct target_ops *ops, } 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); } static int @@ -1511,7 +1348,41 @@ record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) if (RECORD_FULL_IS_REPLAY) return 0; else - return record_full_beneath_to_stopped_data_address (ops, addr_p); + return ops->beneath->to_stopped_data_address (ops->beneath, addr_p); +} + +/* The to_stopped_by_sw_breakpoint method of target record-full. */ + +static int +record_full_stopped_by_sw_breakpoint (struct target_ops *ops) +{ + return record_full_stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT; +} + +/* The to_supports_stopped_by_sw_breakpoint method of target + record-full. */ + +static int +record_full_supports_stopped_by_sw_breakpoint (struct target_ops *ops) +{ + return 1; +} + +/* The to_stopped_by_hw_breakpoint method of target record-full. */ + +static int +record_full_stopped_by_hw_breakpoint (struct target_ops *ops) +{ + 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_supports_stopped_by_hw_breakpoint (struct target_ops *ops) +{ + return 1; } /* Record registers change (by user or by GDB) to list as an instruction. */ @@ -1520,7 +1391,7 @@ static void record_full_registers_change (struct regcache *regcache, int regnum) { /* Check record_full_insn_num. */ - record_full_check_insn_num (0); + record_full_check_insn_num (); record_full_arch_list_head = NULL; record_full_arch_list_tail = NULL; @@ -1529,7 +1400,7 @@ record_full_registers_change (struct regcache *regcache, int regnum) { int i; - for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++) + for (i = 0; i < gdbarch_num_regs (regcache->arch ()); i++) { if (record_full_arch_list_add_reg (regcache, i)) { @@ -1586,7 +1457,7 @@ record_full_store_registers (struct target_ops *ops, 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), + gdbarch_register_name (regcache->arch (), regno)); if (!n) @@ -1598,7 +1469,7 @@ record_full_store_registers (struct target_ops *ops, int i; for (i = 0; - i < gdbarch_num_regs (get_regcache_arch (regcache)); + i < gdbarch_num_regs (regcache->arch ()); i++) regcache_invalidate (regcache, i); } @@ -1614,8 +1485,7 @@ record_full_store_registers (struct target_ops *ops, 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 @@ -1623,11 +1493,11 @@ record_full_store_registers (struct target_ops *ops, 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 @@ -1647,7 +1517,7 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object, } /* Check record_full_insn_num */ - record_full_check_insn_num (0); + record_full_check_insn_num (); /* Record registers change to list as an instruction. */ record_full_arch_list_head = NULL; @@ -1659,7 +1529,7 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object, fprintf_unfiltered (gdb_stdlog, "Process record: failed to record " "execution log."); - return -1; + return TARGET_XFER_E_IO; } if (record_full_arch_list_add_end ()) { @@ -1668,7 +1538,7 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object, 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; @@ -1680,9 +1550,9 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object, 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 @@ -1745,11 +1615,13 @@ record_full_init_record_breakpoints (void) 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; int in_target_beneath = 0; + int ix; if (!RECORD_FULL_IS_REPLAY) { @@ -1757,13 +1629,12 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch, really need to install regular breakpoints in the inferior. However, we do have to insert software single-step breakpoints, in case the target can't hardware step. To keep - things single, we always insert. */ - struct cleanup *old_cleanups; + things simple, we always insert. */ int ret; - old_cleanups = record_full_gdb_operation_disable_set (); - ret = record_full_beneath_to_insert_breakpoint (gdbarch, bp_tgt); - do_cleanups (old_cleanups); + scoped_restore restore_operation_disable + = record_full_gdb_operation_disable_set (); + ret = ops->beneath->to_insert_breakpoint (ops->beneath, gdbarch, bp_tgt); if (ret != 0) return ret; @@ -1771,6 +1642,22 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch, in_target_beneath = 1; } + /* Use the existing entries if found in order to avoid duplication + in record_full_breakpoints. */ + + for (ix = 0; + VEC_iterate (record_full_breakpoint_p, + record_full_breakpoints, ix, bp); + ++ix) + { + if (bp->addr == bp_tgt->placed_address + && bp->address_space == bp_tgt->placed_address_space) + { + gdb_assert (bp->in_target_beneath == in_target_beneath); + return 0; + } + } + bp = XNEW (struct record_full_breakpoint); bp->addr = bp_tgt->placed_address; bp->address_space = bp_tgt->placed_address_space; @@ -1782,8 +1669,10 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch, /* "to_remove_breakpoint" method for process record target. */ static int -record_full_remove_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) +record_full_remove_breakpoint (struct target_ops *ops, + struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt, + enum remove_bp_reason reason) { struct record_full_breakpoint *bp; int ix; @@ -1798,19 +1687,21 @@ record_full_remove_breakpoint (struct gdbarch *gdbarch, { if (bp->in_target_beneath) { - struct cleanup *old_cleanups; int ret; - old_cleanups = record_full_gdb_operation_disable_set (); - ret = record_full_beneath_to_remove_breakpoint (gdbarch, bp_tgt); - do_cleanups (old_cleanups); - + scoped_restore restore_operation_disable + = record_full_gdb_operation_disable_set (); + ret = ops->beneath->to_remove_breakpoint (ops->beneath, gdbarch, + bp_tgt, reason); if (ret != 0) return ret; } - VEC_unordered_remove (record_full_breakpoint_p, - record_full_breakpoints, ix); + if (reason == REMOVE_BREAKPOINT) + { + VEC_unordered_remove (record_full_breakpoint_p, + record_full_breakpoints, ix); + } return 0; } } @@ -1821,7 +1712,7 @@ record_full_remove_breakpoint (struct gdbarch *gdbarch, /* "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; } @@ -1829,7 +1720,8 @@ record_full_can_execute_reverse (void) /* "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) { char *ret = NULL; @@ -1852,63 +1744,44 @@ record_full_get_bookmark (char *args, int from_tty) /* "to_goto_bookmark" method for process record and prec over core. */ static void -record_full_goto_bookmark (gdb_byte *raw_bookmark, int from_tty) +record_full_goto_bookmark (struct target_ops *self, + const gdb_byte *raw_bookmark, int from_tty) { - char *bookmark = (char *) raw_bookmark; + const char *bookmark = (const char *) raw_bookmark; if (record_debug) fprintf_unfiltered (gdb_stdlog, "record_full_goto_bookmark receives %s\n", bookmark); + std::string name_holder; if (bookmark[0] == '\'' || bookmark[0] == '\"') { 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. */ + name_holder = std::string (bookmark + 1, strlen (bookmark) - 2); + bookmark = name_holder.c_str (); } - cmd_record_goto (bookmark, from_tty); - return; + record_goto (bookmark); } -static void -record_full_async (void (*callback) (enum inferior_event_type event_type, - void *context), void *context) +static enum exec_direction_kind +record_full_execution_direction (struct target_ops *self) { - /* 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); + return record_full_execution_dir; } -static int -record_full_can_async_p (void) -{ - /* We only enable async when the user specifically asks for it. */ - return target_async_permitted; -} +/* The to_record_method method of target record-full. */ -static int -record_full_is_async_p (void) +enum record_method +record_full_record_method (struct target_ops *self, ptid_t ptid) { - /* We only enable async when the user specifically asks for it. */ - return target_async_permitted; -} - -static enum exec_direction_kind -record_full_execution_direction (void) -{ - return record_full_execution_dir; + return RECORD_METHOD_FULL; } static void -record_full_info (void) +record_full_info (struct target_ops *self) { struct record_full_entry *p; @@ -1954,7 +1827,7 @@ record_full_info (void) /* 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); } @@ -1962,11 +1835,23 @@ record_full_delete (void) /* 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; } +/* The "to_record_will_replay" target method. */ + +static int +record_full_will_replay (struct target_ops *self, ptid_t ptid, int dir) +{ + /* We can currently only record when executing forwards. Should we be able + to record when executing backwards on targets that support reverse + execution, this needs to be changed. */ + + return RECORD_FULL_IS_REPLAY || dir == EXEC_REVERSE; +} + /* Go to a specific entry. */ static void @@ -1991,13 +1876,14 @@ record_full_goto_entry (struct record_full_entry *p) registers_changed (); reinit_frame_cache (); + 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; @@ -2011,7 +1897,7 @@ record_full_goto_begin (void) /* 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; @@ -2027,7 +1913,7 @@ record_full_goto_end (void) /* 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; @@ -2038,6 +1924,14 @@ record_full_goto (ULONGEST target_insn) record_full_goto_entry (p); } +/* The "to_record_stop_replaying" target method. */ + +static void +record_full_stop_replaying (struct target_ops *self) +{ + record_full_goto_end (self); +} + static void init_record_full_ops (void) { @@ -2047,32 +1941,41 @@ init_record_full_ops (void) "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_commit_resume = record_full_commit_resume; record_full_ops.to_wait = record_full_wait; record_full_ops.to_disconnect = record_disconnect; record_full_ops.to_detach = record_detach; record_full_ops.to_mourn_inferior = record_mourn_inferior; record_full_ops.to_kill = record_kill; - record_full_ops.to_create_inferior = find_default_create_inferior; 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_record_method = record_full_record_method; 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_record_will_replay = record_full_will_replay; + record_full_ops.to_record_stop_replaying = record_full_stop_replaying; record_full_ops.to_goto_record_begin = record_full_goto_begin; record_full_ops.to_goto_record_end = record_full_goto_end; record_full_ops.to_goto_record = record_full_goto; @@ -2092,12 +1995,7 @@ record_full_core_resume (struct target_ops *ops, ptid_t ptid, int step, /* 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. */ @@ -2120,22 +2018,21 @@ record_full_core_fetch_registers (struct target_ops *ops, { if (regno < 0) { - int num = gdbarch_num_regs (get_regcache_arch (regcache)); + int num = gdbarch_num_regs (regcache->arch ()); int i; for (i = 0; i < num; i ++) - regcache_raw_supply (regcache, i, - record_full_core_regbuf + MAX_REGISTER_SIZE * i); + regcache->raw_supply (i, *record_full_core_regbuf); } else - regcache_raw_supply (regcache, regno, - record_full_core_regbuf + MAX_REGISTER_SIZE * regno); + regcache->raw_supply (regno, *record_full_core_regbuf); } /* "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) { } @@ -2147,20 +2044,19 @@ record_full_core_store_registers (struct target_ops *ops, int regno) { if (record_full_gdb_operation_disable) - regcache_raw_collect (regcache, regno, - record_full_core_regbuf + MAX_REGISTER_SIZE * regno); + record_full_core_regbuf->raw_supply (regno, *regcache); else error (_("You can't do that without a process to debug.")); } /* "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) { @@ -2190,7 +2086,9 @@ record_full_core_xfer_partial (struct target_ops *ops, { 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; @@ -2202,9 +2100,7 @@ record_full_core_xfer_partial (struct target_ops *ops, 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->the_bfd_section->owner, @@ -2212,7 +2108,7 @@ record_full_core_xfer_partial (struct target_ops *ops, &entry->buf)) { xfree (entry); - return 0; + return TARGET_XFER_EOF; } entry->prev = record_full_core_buf_list; record_full_core_buf_list = entry; @@ -2224,34 +2120,37 @@ record_full_core_xfer_partial (struct target_ops *ops, 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; @@ -2260,8 +2159,10 @@ record_full_core_insert_breakpoint (struct gdbarch *gdbarch, /* "to_remove_breakpoint" method for prec over corefile. */ static int -record_full_core_remove_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) +record_full_core_remove_breakpoint (struct target_ops *ops, + struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt, + enum remove_bp_reason reason) { return 0; } @@ -2283,6 +2184,7 @@ init_record_full_core_ops (void) "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; @@ -2298,6 +2200,14 @@ init_record_full_core_ops (void) = 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; @@ -2305,14 +2215,13 @@ init_record_full_core_ops (void) /* 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_record_method = record_full_record_method; record_full_core_ops.to_info_record = record_full_info; record_full_core_ops.to_delete_record = record_full_delete; record_full_core_ops.to_record_is_replaying = record_full_is_replaying; + record_full_core_ops.to_record_will_replay = record_full_will_replay; record_full_core_ops.to_goto_record_begin = record_full_goto_begin; record_full_core_ops.to_goto_record_end = record_full_goto_end; record_full_core_ops.to_goto_record = record_full_goto; @@ -2396,16 +2305,6 @@ netorder32 (uint32_t 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; -} - /* Restore the execution log from a core_bfd file. */ static void record_full_restore (void) @@ -2529,7 +2428,7 @@ record_full_restore (void) 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, @@ -2599,36 +2498,22 @@ bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset) corefile format, with an extra section for our data. */ static void -cmd_record_full_restore (char *args, int from_tty) +cmd_record_full_restore (const 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); -} - /* Save the execution log to a file. We use a modified elf corefile format, with an extra section for our data. */ static void -record_full_save (const char *recfilename) +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; @@ -2639,18 +2524,21 @@ record_full_save (const char *recfilename) recfilename); /* Open the output file. */ - obfd = create_gcore_bfd (recfilename); - old_cleanups = make_cleanup (record_full_save_cleanups, obfd); + gdb_bfd_ref_ptr obfd (create_gcore_bfd (recfilename)); + + /* Arrange to remove the output file on failure. */ + gdb::unlinker unlink_file (recfilename); /* Save the current record entry to "cur_record_full_list". */ cur_record_full_list = record_full_list; /* Get the values of regcache and gdbarch. */ regcache = get_current_regcache (); - gdbarch = get_regcache_arch (regcache); + gdbarch = regcache->arch (); /* Disable the GDB operation record. */ - set_cleanups = record_full_gdb_operation_disable_set (); + scoped_restore restore_operation_disable + = record_full_gdb_operation_disable_set (); /* Reverse execute to the begin of record list. */ while (1) @@ -2683,20 +2571,20 @@ record_full_save (const char *recfilename) } /* Make the new bfd section. */ - osec = bfd_make_section_anyway_with_flags (obfd, "precord", + osec = bfd_make_section_anyway_with_flags (obfd.get (), "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; + bfd_set_section_size (obfd.get (), osec, save_size); + bfd_set_section_vma (obfd.get (), osec, 0); + bfd_set_section_alignment (obfd.get (), osec, 0); + bfd_section_lma (obfd.get (), osec) = 0; /* Save corefile state. */ - write_gcore_file (obfd); + write_gcore_file (obfd.get ()); /* Write out the record log. */ /* Write the magic code. */ @@ -2706,7 +2594,7 @@ record_full_save (const char *recfilename) " 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); + bfdcore_write (obfd.get (), osec, &magic, sizeof (magic), &bfd_offset); /* Save the entries to recfd and forward execute to the end of record list. */ @@ -2721,7 +2609,7 @@ record_full_save (const char *recfilename) uint64_t addr; type = record_full_list->type; - bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset); + bfdcore_write (obfd.get (), osec, &type, sizeof (type), &bfd_offset); switch (record_full_list->type) { @@ -2736,11 +2624,11 @@ record_full_save (const char *recfilename) /* Write regnum. */ regnum = netorder32 (record_full_list->u.reg.num); - bfdcore_write (obfd, osec, ®num, + bfdcore_write (obfd.get (), osec, ®num, sizeof (regnum), &bfd_offset); /* Write regval. */ - bfdcore_write (obfd, osec, + bfdcore_write (obfd.get (), osec, record_full_get_loc (record_full_list), record_full_list->u.reg.len, &bfd_offset); break; @@ -2758,15 +2646,16 @@ record_full_save (const char *recfilename) /* Write memlen. */ len = netorder32 (record_full_list->u.mem.len); - bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset); + bfdcore_write (obfd.get (), osec, &len, sizeof (len), + &bfd_offset); /* Write memaddr. */ addr = netorder64 (record_full_list->u.mem.addr); - bfdcore_write (obfd, osec, &addr, + bfdcore_write (obfd.get (), osec, &addr, sizeof (addr), &bfd_offset); /* Write memval. */ - bfdcore_write (obfd, osec, + bfdcore_write (obfd.get (), osec, record_full_get_loc (record_full_list), record_full_list->u.mem.len, &bfd_offset); break; @@ -2780,12 +2669,12 @@ record_full_save (const char *recfilename) (unsigned long) sizeof (count)); /* Write signal value. */ signal = netorder32 (record_full_list->u.end.sigval); - bfdcore_write (obfd, osec, &signal, + bfdcore_write (obfd.get (), osec, &signal, sizeof (signal), &bfd_offset); /* Write insn count. */ count = netorder32 (record_full_list->u.end.insn_num); - bfdcore_write (obfd, osec, &count, + bfdcore_write (obfd.get (), osec, &count, sizeof (count), &bfd_offset); break; } @@ -2813,9 +2702,7 @@ record_full_save (const char *recfilename) record_full_list = record_full_list->prev; } - do_cleanups (set_cleanups); - gdb_bfd_unref (obfd); - discard_cleanups (old_cleanups); + unlink_file.keep (); /* Succeeded. */ printf_filtered (_("Saved core file %s with execution log.\n"), @@ -2830,9 +2717,10 @@ 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 (); + scoped_restore restore_operation_disable + = record_full_gdb_operation_disable_set (); struct regcache *regcache = get_current_regcache (); - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); /* Assume everything is valid: we will hit the entry, and we will not hit the end of the recording. */ @@ -2848,19 +2736,18 @@ record_full_goto_insn (struct record_full_entry *entry, else record_full_list = record_full_list->next; } while (record_full_list != entry); - do_cleanups (set_cleanups); } /* Alias for "target record-full". */ static void -cmd_record_full_start (char *args, int from_tty) +cmd_record_full_start (const 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, +set_record_full_insn_max_num (const char *args, int from_tty, struct cmd_list_element *c) { if (record_full_insn_num > record_full_insn_max_num) @@ -2877,10 +2764,10 @@ set_record_full_insn_max_num (char *args, int from_tty, /* The "set record full" command. */ static void -set_record_full_command (char *args, int from_tty) +set_record_full_command (const char *args, int from_tty) { printf_unfiltered (_("\"set record full\" must be followed " - "by an apporpriate subcommand.\n")); + "by an appropriate subcommand.\n")); help_list (set_record_full_cmdlist, "set record full ", all_commands, gdb_stdout); } @@ -2888,14 +2775,11 @@ set_record_full_command (char *args, int from_tty) /* The "show record full" command. */ static void -show_record_full_command (char *args, int from_tty) +show_record_full_command (const char *args, int from_tty) { cmd_show_list (show_record_full_cmdlist, from_tty, ""); } -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_record_full; - void _initialize_record_full (void) {