X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Frecord-full.c;h=5608e70e8294e2a95c869e6394fe2b82595e08a0;hb=abe7c33b45288b407e6d001aad713183d4bab5c6;hp=c660743a40742cb23f86df9a5d7a716087f2c5f9;hpb=b7d2e91626b0e587f3fd5023e79b5079da6baed5;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/record-full.c b/gdb/record-full.c index c660743a40..5608e70e82 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-2015 Free Software Foundation, Inc. + Copyright (C) 2013-2016 Free Software Foundation, Inc. This file is part of GDB. @@ -244,7 +244,7 @@ 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 = XCNEW (struct record_full_entry); rec->type = record_full_reg; rec->u.reg.num = regnum; rec->u.reg.len = register_size (gdbarch, regnum); @@ -272,7 +272,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; @@ -300,7 +300,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; @@ -535,26 +535,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; } } } @@ -583,7 +575,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. @@ -651,7 +643,8 @@ struct record_full_message_args { static int record_full_message_wrapper (void *args) { - struct record_full_message_args *record_full_args = args; + struct record_full_message_args *record_full_args + = (struct record_full_message_args *) args; return record_full_message (record_full_args->regcache, record_full_args->signal); @@ -666,7 +659,7 @@ record_full_message_wrapper_safe (struct regcache *regcache, args.regcache = regcache; args.signal = signal; - return catch_errors (record_full_message_wrapper, &args, NULL, + return catch_errors (record_full_message_wrapper, &args, "", RETURN_MASK_ALL); } @@ -688,7 +681,8 @@ record_full_gdb_operation_disable_set (void) } /* 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 @@ -724,7 +718,8 @@ 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 *mem = (gdb_byte *) xmalloc (entry->u.mem.len); + struct cleanup *cleanup = make_cleanup (xfree, mem); if (record_debug > 1) fprintf_unfiltered (gdb_stdlog, @@ -766,9 +761,11 @@ record_full_exec_insn (struct regcache *regcache, if (hardware_watchpoint_inserted_in_range (get_regcache_aspace (regcache), entry->u.mem.addr, entry->u.mem.len)) - record_full_hw_watchpoint = 1; + record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT; } } + + do_cleanups (cleanup); } } break; @@ -799,7 +796,7 @@ record_full_core_open_1 (const char *name, int from_tty) /* Get record_full_core_regbuf. */ target_fetch_registers (regcache, -1); - record_full_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum); + record_full_core_regbuf = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE * regnum); for (i = 0; i < regnum; i ++) regcache_raw_collect (regcache, i, record_full_core_regbuf + MAX_REGISTER_SIZE * i); @@ -824,7 +821,7 @@ 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"); + fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open_1\n"); /* check exec */ if (!target_has_execution) @@ -872,7 +869,7 @@ record_full_open (const char *name, int from_tty) record_full_init_record_breakpoints (); - observer_notify_record_changed (current_inferior (), 1); + observer_notify_record_changed (current_inferior (), 1, "full", NULL); } /* "to_close" target method. Close the process record target. */ @@ -913,17 +910,14 @@ record_full_close (struct target_ops *self) /* "to_async" target method. */ static void -record_full_async (struct target_ops *ops, - void (*callback) (enum inferior_event_type event_type, - void *context), - void *context) +record_full_async (struct target_ops *ops, int enable) { - if (callback != NULL) + 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, callback, context); + ops->beneath->to_async (ops->beneath, enable); } static int record_full_resume_step = 0; @@ -975,24 +969,14 @@ record_full_resume (struct target_ops *ops, ptid_t ptid, int step, } else { - /* This arch support soft sigle step. */ + /* 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); } } @@ -1005,7 +989,16 @@ record_full_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); + 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; @@ -1079,6 +1072,8 @@ 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) @@ -1119,6 +1114,8 @@ record_full_wait_1 (struct target_ops *ops, { 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 @@ -1133,20 +1130,11 @@ record_full_wait_1 (struct target_ops *ops, { /* 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 - = target_decr_pc_after_break (gdbarch); - if (decr_pc_after_break) - regcache_write_pc (regcache, - tmp_pc + decr_pc_after_break); - } } else { @@ -1170,9 +1158,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); } @@ -1183,6 +1171,7 @@ record_full_wait_1 (struct target_ops *ops, "target beneath\n"); ops->beneath->to_resume (ops->beneath, ptid, step, GDB_SIGNAL_0); + ops->beneath->to_commit_resume (ops->beneath); continue; } } @@ -1205,27 +1194,20 @@ record_full_wait_1 (struct target_ops *ops, = 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 = 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; } } @@ -1293,27 +1275,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 - = 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_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT) { if (record_debug) fprintf_unfiltered (gdb_stdlog, @@ -1384,7 +1358,7 @@ static int 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 ops->beneath->to_stopped_by_watchpoint (ops->beneath); } @@ -1398,13 +1372,47 @@ record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *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. */ 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; @@ -1530,7 +1538,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; @@ -1634,6 +1642,7 @@ record_full_insert_breakpoint (struct target_ops *ops, { struct record_full_breakpoint *bp; int in_target_beneath = 0; + int ix; if (!RECORD_FULL_IS_REPLAY) { @@ -1641,7 +1650,7 @@ record_full_insert_breakpoint (struct target_ops *ops, 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. */ + things simple, we always insert. */ struct cleanup *old_cleanups; int ret; @@ -1655,6 +1664,22 @@ record_full_insert_breakpoint (struct target_ops *ops, 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; @@ -1668,7 +1693,8 @@ record_full_insert_breakpoint (struct target_ops *ops, static int record_full_remove_breakpoint (struct target_ops *ops, struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) + struct bp_target_info *bp_tgt, + enum remove_bp_reason reason) { struct record_full_breakpoint *bp; int ix; @@ -1688,15 +1714,18 @@ record_full_remove_breakpoint (struct target_ops *ops, old_cleanups = record_full_gdb_operation_disable_set (); ret = ops->beneath->to_remove_breakpoint (ops->beneath, gdbarch, - bp_tgt); + bp_tgt, reason); do_cleanups (old_cleanups); 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; } } @@ -1828,11 +1857,23 @@ record_full_delete (struct target_ops *self) /* The "to_record_is_replaying" target method. */ static int -record_full_is_replaying (struct target_ops *self) +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 @@ -1857,6 +1898,7 @@ 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); } @@ -1904,6 +1946,14 @@ record_full_goto (struct target_ops *self, 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) { @@ -1915,6 +1965,7 @@ init_record_full_ops (void) 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; @@ -1926,6 +1977,14 @@ init_record_full_ops (void) 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. */ @@ -1936,6 +1995,8 @@ init_record_full_ops (void) 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; @@ -1955,7 +2016,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); + target_async (1); } /* "to_kill" method for prec over corefile. */ @@ -2063,9 +2124,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, @@ -2126,7 +2185,8 @@ record_full_core_insert_breakpoint (struct target_ops *ops, static int record_full_core_remove_breakpoint (struct target_ops *ops, struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) + struct bp_target_info *bp_tgt, + enum remove_bp_reason reason) { return 0; } @@ -2164,6 +2224,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; @@ -2176,6 +2244,7 @@ init_record_full_core_ops (void) 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; @@ -2392,7 +2461,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, @@ -2471,7 +2540,7 @@ cmd_record_full_restore (char *args, int from_tty) static void record_full_save_cleanups (void *data) { - bfd *obfd = data; + bfd *obfd = (bfd *) data; char *pathname = xstrdup (bfd_get_filename (obfd)); gdb_bfd_unref (obfd);