X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdb%2Frecord.c;h=bb0fe5224f643d9ec65b3646984475e1065c0623;hb=a493e3e2e429e4832b8620bd920ad07d0c2892d7;hp=e396262a52e110fa6d9f31a345e9398353e0b359;hpb=0b30217134add051e159a192066a1e568ebd837f;p=thirdparty%2Fbinutils-gdb.git diff --git a/gdb/record.c b/gdb/record.c index e396262a52e..bb0fe5224f6 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) {