| Index: gdb/record.c
|
| diff --git a/gdb/record.c b/gdb/record.c
|
| index e396262a52e110fa6d9f31a345e9398353e0b359..bb0fe5224f643d9ec65b3646984475e1065c0623 100644
|
| --- a/gdb/record.c
|
| +++ b/gdb/record.c
|
| @@ -100,7 +100,7 @@ struct record_reg_entry
|
|
|
| struct record_end_entry
|
| {
|
| - enum target_signal sigval;
|
| + enum gdb_signal sigval;
|
| ULONGEST insn_num;
|
| };
|
|
|
| @@ -209,7 +209,7 @@ static struct target_ops record_core_ops;
|
| /* The beneath function pointers. */
|
| static struct target_ops *record_beneath_to_resume_ops;
|
| static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int,
|
| - enum target_signal);
|
| + enum gdb_signal);
|
| static struct target_ops *record_beneath_to_wait_ops;
|
| static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t,
|
| struct target_waitstatus *,
|
| @@ -531,7 +531,7 @@ record_arch_list_add_end (void)
|
| "Process record: add end to arch list.\n");
|
|
|
| rec = record_end_alloc ();
|
| - rec->u.end.sigval = TARGET_SIGNAL_0;
|
| + rec->u.end.sigval = GDB_SIGNAL_0;
|
| rec->u.end.insn_num = ++record_insn_count;
|
|
|
| record_arch_list_add (rec);
|
| @@ -581,7 +581,7 @@ record_arch_list_cleanups (void *ignore)
|
| record_arch_list, and add it to record_list. */
|
|
|
| static int
|
| -record_message (struct regcache *regcache, enum target_signal signal)
|
| +record_message (struct regcache *regcache, enum gdb_signal signal)
|
| {
|
| int ret;
|
| struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
| @@ -621,7 +621,7 @@ record_message (struct regcache *regcache, enum target_signal signal)
|
| record_list->u.end.sigval = signal;
|
| }
|
|
|
| - if (signal == TARGET_SIGNAL_0
|
| + if (signal == GDB_SIGNAL_0
|
| || !gdbarch_process_record_signal_p (gdbarch))
|
| ret = gdbarch_process_record (gdbarch,
|
| regcache,
|
| @@ -652,7 +652,7 @@ record_message (struct regcache *regcache, enum target_signal signal)
|
|
|
| struct record_message_args {
|
| struct regcache *regcache;
|
| - enum target_signal signal;
|
| + enum gdb_signal signal;
|
| };
|
|
|
| static int
|
| @@ -665,7 +665,7 @@ record_message_wrapper (void *args)
|
|
|
| static int
|
| record_message_wrapper_safe (struct regcache *regcache,
|
| - enum target_signal signal)
|
| + enum gdb_signal signal)
|
| {
|
| struct record_message_args args;
|
|
|
| @@ -786,7 +786,7 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
|
|
|
| static struct target_ops *tmp_to_resume_ops;
|
| static void (*tmp_to_resume) (struct target_ops *, ptid_t, int,
|
| - enum target_signal);
|
| + 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 *,
|
| @@ -896,6 +896,8 @@ record_open_1 (char *name, int from_tty)
|
| push_target (&record_ops);
|
| }
|
|
|
| +static void record_init_record_breakpoints (void);
|
| +
|
| /* "to_open" target method. Open the process record target. */
|
|
|
| static void
|
| @@ -993,6 +995,8 @@ record_open (char *name, int from_tty)
|
| record_async_inferior_event_token
|
| = create_async_event_handler (record_async_inferior_event_handler,
|
| NULL);
|
| +
|
| + record_init_record_breakpoints ();
|
| }
|
|
|
| /* "to_close" target method. Close the process record target. */
|
| @@ -1056,7 +1060,7 @@ static enum exec_direction_kind record_execution_dir = EXEC_FORWARD;
|
|
|
| static void
|
| record_resume (struct target_ops *ops, ptid_t ptid, int step,
|
| - enum target_signal signal)
|
| + enum gdb_signal signal)
|
| {
|
| record_resume_step = step;
|
| record_resumed = 1;
|
| @@ -1219,7 +1223,7 @@ record_wait_1 (struct target_ops *ops,
|
|
|
| /* Is this a SIGTRAP? */
|
| if (status->kind == TARGET_WAITKIND_STOPPED
|
| - && status->value.sig == TARGET_SIGNAL_TRAP)
|
| + && status->value.sig == GDB_SIGNAL_TRAP)
|
| {
|
| struct regcache *regcache;
|
| struct address_space *aspace;
|
| @@ -1261,10 +1265,10 @@ record_wait_1 (struct target_ops *ops,
|
| int step = 1;
|
|
|
| if (!record_message_wrapper_safe (regcache,
|
| - TARGET_SIGNAL_0))
|
| + GDB_SIGNAL_0))
|
| {
|
| status->kind = TARGET_WAITKIND_STOPPED;
|
| - status->value.sig = TARGET_SIGNAL_0;
|
| + status->value.sig = GDB_SIGNAL_0;
|
| break;
|
| }
|
|
|
| @@ -1286,7 +1290,7 @@ record_wait_1 (struct target_ops *ops,
|
| "issuing one more step in the target beneath\n");
|
| record_beneath_to_resume (record_beneath_to_resume_ops,
|
| ptid, step,
|
| - TARGET_SIGNAL_0);
|
| + GDB_SIGNAL_0);
|
| continue;
|
| }
|
| }
|
| @@ -1425,7 +1429,7 @@ record_wait_1 (struct target_ops *ops,
|
| continue_flag = 0;
|
| }
|
| /* Check target signal */
|
| - if (record_list->u.end.sigval != TARGET_SIGNAL_0)
|
| + if (record_list->u.end.sigval != GDB_SIGNAL_0)
|
| /* FIXME: better way to check */
|
| continue_flag = 0;
|
| }
|
| @@ -1449,12 +1453,12 @@ record_wait_1 (struct target_ops *ops,
|
|
|
| replay_out:
|
| if (record_get_sig)
|
| - status->value.sig = TARGET_SIGNAL_INT;
|
| - else if (record_list->u.end.sigval != TARGET_SIGNAL_0)
|
| + status->value.sig = GDB_SIGNAL_INT;
|
| + else if (record_list->u.end.sigval != GDB_SIGNAL_0)
|
| /* FIXME: better way to check */
|
| status->value.sig = record_list->u.end.sigval;
|
| else
|
| - status->value.sig = TARGET_SIGNAL_TRAP;
|
| + status->value.sig = GDB_SIGNAL_TRAP;
|
|
|
| discard_cleanups (old_cleanups);
|
| }
|
| @@ -1718,24 +1722,97 @@ record_xfer_partial (struct target_ops *ops, enum target_object object,
|
| offset, len);
|
| }
|
|
|
| -/* Behavior is conditional on RECORD_IS_REPLAY.
|
| - We will not actually insert or remove breakpoints when replaying,
|
| - nor when recording. */
|
| +/* This structure represents a breakpoint inserted while the record
|
| + target is active. We use this to know when to install/remove
|
| + breakpoints in/from the target beneath. For example, a breakpoint
|
| + may be inserted while recording, but removed when not replaying nor
|
| + recording. In that case, the breakpoint had not been inserted on
|
| + the target beneath, so we should not try to remove it there. */
|
| +
|
| +struct record_breakpoint
|
| +{
|
| + /* The address and address space the breakpoint was set at. */
|
| + struct address_space *address_space;
|
| + CORE_ADDR addr;
|
| +
|
| + /* True when the breakpoint has been also installed in the target
|
| + beneath. This will be false for breakpoints set during replay or
|
| + when recording. */
|
| + int in_target_beneath;
|
| +};
|
| +
|
| +typedef struct record_breakpoint *record_breakpoint_p;
|
| +DEF_VEC_P(record_breakpoint_p);
|
| +
|
| +/* The list of breakpoints inserted while the record target is
|
| + active. */
|
| +VEC(record_breakpoint_p) *record_breakpoints = NULL;
|
| +
|
| +static void
|
| +record_sync_record_breakpoints (struct bp_location *loc, void *data)
|
| +{
|
| + if (loc->loc_type != bp_loc_software_breakpoint)
|
| + return;
|
| +
|
| + if (loc->inserted)
|
| + {
|
| + struct record_breakpoint *bp = XNEW (struct record_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_breakpoint_p, record_breakpoints, bp);
|
| + }
|
| +}
|
| +
|
| +/* Sync existing breakpoints to record_breakpoints. */
|
| +
|
| +static void
|
| +record_init_record_breakpoints (void)
|
| +{
|
| + VEC_free (record_breakpoint_p, record_breakpoints);
|
| +
|
| + iterate_over_bp_locations (record_sync_record_breakpoints);
|
| +}
|
| +
|
| +/* Behavior is conditional on RECORD_IS_REPLAY. We will not actually
|
| + insert or remove breakpoints in the real target when replaying, nor
|
| + when recording. */
|
|
|
| static int
|
| record_insert_breakpoint (struct gdbarch *gdbarch,
|
| struct bp_target_info *bp_tgt)
|
| {
|
| + struct record_breakpoint *bp;
|
| + int in_target_beneath = 0;
|
| +
|
| if (!RECORD_IS_REPLAY)
|
| {
|
| - struct cleanup *old_cleanups = record_gdb_operation_disable_set ();
|
| - int ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
|
| -
|
| + /* When recording, we currently always single-step, so we don't
|
| + 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;
|
| + int ret;
|
| +
|
| + old_cleanups = record_gdb_operation_disable_set ();
|
| + ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
|
| do_cleanups (old_cleanups);
|
|
|
| - return ret;
|
| + if (ret != 0)
|
| + return ret;
|
| +
|
| + in_target_beneath = 1;
|
| }
|
|
|
| + bp = XNEW (struct record_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_breakpoint_p, record_breakpoints, bp);
|
| return 0;
|
| }
|
|
|
| @@ -1745,17 +1822,35 @@ static int
|
| record_remove_breakpoint (struct gdbarch *gdbarch,
|
| struct bp_target_info *bp_tgt)
|
| {
|
| - if (!RECORD_IS_REPLAY)
|
| + struct record_breakpoint *bp;
|
| + int ix;
|
| +
|
| + for (ix = 0;
|
| + VEC_iterate (record_breakpoint_p, record_breakpoints, ix, bp);
|
| + ++ix)
|
| {
|
| - struct cleanup *old_cleanups = record_gdb_operation_disable_set ();
|
| - int ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
|
| + 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;
|
|
|
| - do_cleanups (old_cleanups);
|
| + old_cleanups = record_gdb_operation_disable_set ();
|
| + ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
|
| + do_cleanups (old_cleanups);
|
| +
|
| + if (ret != 0)
|
| + return ret;
|
| + }
|
|
|
| - return ret;
|
| + VEC_unordered_remove (record_breakpoint_p, record_breakpoints, ix);
|
| + return 0;
|
| + }
|
| }
|
|
|
| - return 0;
|
| + gdb_assert_not_reached ("removing unknown breakpoint");
|
| }
|
|
|
| /* "to_can_execute_reverse" method for process record target. */
|
| @@ -1886,7 +1981,7 @@ init_record_ops (void)
|
|
|
| static void
|
| record_core_resume (struct target_ops *ops, ptid_t ptid, int step,
|
| - enum target_signal signal)
|
| + enum gdb_signal signal)
|
| {
|
| record_resume_step = step;
|
| record_resumed = 1;
|
| @@ -2862,6 +2957,9 @@ cmd_record_goto (char *arg, int from_tty)
|
| print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
|
| }
|
|
|
| +/* Provide a prototype to silence -Wmissing-prototypes. */
|
| +extern initialize_file_ftype _initialize_record;
|
| +
|
| void
|
| _initialize_record (void)
|
| {
|
|
|