X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdb%2Frecord.c;h=bb0fe5224f643d9ec65b3646984475e1065c0623;hb=a493e3e2e429e4832b8620bd920ad07d0c2892d7;hp=b3d11b6411c6d44dffa4213e29922447172e13e3;hpb=eaaffdf49f698d6f61131e9c8937000363ee950d;p=thirdparty%2Fbinutils-gdb.git diff --git a/gdb/record.c b/gdb/record.c index b3d11b6411c..bb0fe5224f6 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -1,6 +1,6 @@ /* Process record and replay target for GDB, the GNU debugger. - Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2008-2012 Free Software Foundation, Inc. This file is part of GDB. @@ -30,6 +30,8 @@ #include "record.h" #include "elf-bfd.h" #include "gcore.h" +#include "event-loop.h" +#include "inf-loop.h" #include @@ -98,7 +100,7 @@ struct record_reg_entry struct record_end_entry { - enum target_signal sigval; + enum gdb_signal sigval; ULONGEST insn_num; }; @@ -152,6 +154,10 @@ struct record_entry /* This is the debug switch for process record. */ int record_debug = 0; +/* If true, query if PREC cannot record memory + change of next instruction. */ +int record_memory_query = 0; + struct record_core_buf_entry { struct record_core_buf_entry *prev; @@ -203,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 *, @@ -227,6 +233,7 @@ static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *, static int (*record_beneath_to_stopped_by_watchpoint) (void); static int (*record_beneath_to_stopped_data_address) (struct target_ops *, CORE_ADDR *); +static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *); /* Alloc and free functions for record_reg, record_mem, and record_end entries. */ @@ -450,7 +457,7 @@ record_get_loc (struct record_entry *rec) return rec->u.reg.u.buf; case record_end: default: - gdb_assert (0); + gdb_assert_not_reached ("unexpected record_entry type"); return NULL; } } @@ -491,7 +498,7 @@ record_arch_list_add_mem (CORE_ADDR addr, int len) "record list.\n", paddress (target_gdbarch, addr), len); - if (!addr) /* FIXME: Why? Some arch must permit it... */ + if (!addr) /* FIXME: Why? Some arch must permit it... */ return 0; rec = record_mem_alloc (addr, len); @@ -524,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); @@ -574,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); @@ -614,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, @@ -645,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 @@ -658,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; @@ -735,8 +742,8 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, { entry->u.mem.mem_entry_not_accessible = 1; if (record_debug) - warning ("Process record: error reading memory at " - "addr = %s len = %d.", + warning (_("Process record: error reading memory at " + "addr = %s len = %d."), paddress (gdbarch, entry->u.mem.addr), entry->u.mem.len); } @@ -748,8 +755,8 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, { entry->u.mem.mem_entry_not_accessible = 1; if (record_debug) - warning ("Process record: error writing memory at " - "addr = %s len = %d.", + warning (_("Process record: error writing memory at " + "addr = %s len = %d."), paddress (gdbarch, entry->u.mem.addr), entry->u.mem.len); } @@ -779,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 *, @@ -802,9 +809,22 @@ 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_restore (void); +/* Asynchronous signal handle registered as event loop source for when + we have pending events ready to be passed to the core. */ + +static struct async_event_handler *record_async_inferior_event_token; + +static void +record_async_inferior_event_handler (gdb_client_data data) +{ + inferior_event_handler (INF_REG_EVENT, NULL); +} + /* Open the process record target. */ static void @@ -848,9 +868,6 @@ record_open_1 (char *name, int from_tty) if (non_stop) error (_("Process record target can't debug inferior in non-stop mode " "(non-stop).")); - if (target_async_permitted) - error (_("Process record target can't debug inferior in asynchronous " - "mode (target-async).")); if (!gdbarch_process_record_p (target_gdbarch)) error (_("Process record: the current architecture doesn't support " @@ -861,19 +878,26 @@ record_open_1 (char *name, int from_tty) 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.")); + 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.")); + 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.")); + 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.")); + 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.")); + error (_("Could not find 'to_stopped_data_address' " + "method on the target stack.")); push_target (&record_ops); } +static void record_init_record_breakpoints (void); + /* "to_open" target method. Open the process record target. */ static void @@ -902,6 +926,7 @@ record_open (char *name, int from_tty) 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) @@ -934,6 +959,8 @@ record_open (char *name, int from_tty) 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.")); @@ -957,11 +984,19 @@ record_open (char *name, int from_tty) record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint; record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint; record_beneath_to_stopped_data_address = tmp_to_stopped_data_address; + record_beneath_to_async = tmp_to_async; - if (current_target.to_stratum == core_stratum) + if (core_bfd) record_core_open_1 (name, from_tty); else record_open_1 (name, from_tty); + + /* Register extra event sources in the event loop. */ + 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. */ @@ -993,23 +1028,93 @@ record_close (int quitting) } record_core_buf_list = NULL; } + + if (record_async_inferior_event_token) + delete_async_event_handler (&record_async_inferior_event_token); } static int record_resume_step = 0; +/* True if we've been resumed, and so each record_wait call should + advance execution. If this is false, record_wait will return a + TARGET_WAITKIND_IGNORE. */ +static int record_resumed = 0; + +/* The execution direction of the last resume we got. This is + necessary for async mode. Vis (order is not strictly accurate): + + 1. user has the global execution direction set to forward + 2. user does a reverse-step command + 3. record_resume is called with global execution direction + temporarily switched to reverse + 4. GDB's execution direction is reverted back to forward + 5. target record notifies event loop there's an event to handle + 6. infrun asks the target which direction was it going, and switches + the global execution direction accordingly (to reverse) + 7. infrun polls an event out of the record target, and handles it + 8. GDB goes back to the event loop, and goto #4. +*/ +static enum exec_direction_kind record_execution_dir = EXEC_FORWARD; + /* "to_resume" target method. Resume the process record target. */ 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; + record_execution_dir = execution_direction; if (!RECORD_IS_REPLAY) { + struct gdbarch *gdbarch = target_thread_architecture (ptid); + record_message (get_current_regcache (), signal); - record_beneath_to_resume (record_beneath_to_resume_ops, ptid, 1, - signal); + + if (!step) + { + /* This is not hard single step. */ + if (!gdbarch_software_single_step_p (gdbarch)) + { + /* This is a normal continue. */ + step = 1; + } + else + { + /* This arch support soft sigle step. */ + if (single_step_breakpoints_inserted ()) + { + /* This is a soft single step. */ + record_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; + } + } + } + } + + record_beneath_to_resume (record_beneath_to_resume_ops, + 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_wait. */ + mark_async_event_handler (record_async_inferior_event_token); } } @@ -1057,17 +1162,27 @@ record_wait_cleanups (void *ignore) where to stop. */ static ptid_t -record_wait (struct target_ops *ops, - ptid_t ptid, struct target_waitstatus *status, - int options) +record_wait_1 (struct target_ops *ops, + ptid_t ptid, struct target_waitstatus *status, + int options) { struct cleanup *set_cleanups = record_gdb_operation_disable_set (); if (record_debug) fprintf_unfiltered (gdb_stdlog, "Process record: record_wait " - "record_resume_step = %d\n", - record_resume_step); + "record_resume_step = %d, record_resumed = %d, direction=%s\n", + record_resume_step, record_resumed, + record_execution_dir == EXEC_FORWARD ? "forward" : "reverse"); + + if (!record_resumed) + { + gdb_assert ((options & TARGET_WNOHANG) != 0); + + /* No interesting event. */ + status->kind = TARGET_WAITKIND_IGNORE; + return minus_one_ptid; + } record_get_sig = 0; signal (SIGINT, record_sig_handler); @@ -1085,18 +1200,30 @@ record_wait (struct target_ops *ops, /* This is not a single step. */ ptid_t ret; CORE_ADDR tmp_pc; + struct gdbarch *gdbarch = target_thread_architecture (inferior_ptid); while (1) { ret = record_beneath_to_wait (record_beneath_to_wait_ops, ptid, status, options); + if (status->kind == TARGET_WAITKIND_IGNORE) + { + if (record_debug) + fprintf_unfiltered (gdb_stdlog, + "Process record: record_wait " + "target beneath not done yet\n"); + return ret; + } + + if (single_step_breakpoints_inserted ()) + remove_single_step_breakpoints (); if (record_resume_step) - return ret; + return ret; /* 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; @@ -1120,7 +1247,8 @@ record_wait (struct target_ops *ops, handle it. */ if (software_breakpoint_inserted_here_p (aspace, tmp_pc)) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch + = get_regcache_arch (regcache); CORE_ADDR decr_pc_after_break = gdbarch_decr_pc_after_break (gdbarch); if (decr_pc_after_break) @@ -1130,19 +1258,39 @@ record_wait (struct target_ops *ops, } else { - /* This must be a single-step trap. Record the - insn and issue another step. */ + /* This is a single-step trap. Record the + insn and issue another step. + FIXME: this part can be a random SIGTRAP too. + But GDB cannot handle it. */ + 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; } + if (gdbarch_software_single_step_p (gdbarch)) + { + /* Try to insert the software single step breakpoint. + 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; + set_executing (inferior_ptid, 1); + } + + if (record_debug) + fprintf_unfiltered (gdb_stdlog, + "Process record: record_wait " + "issuing one more step in the target beneath\n"); record_beneath_to_resume (record_beneath_to_resume_ops, - ptid, 1, - TARGET_SIGNAL_0); + ptid, step, + GDB_SIGNAL_0); continue; } } @@ -1275,12 +1423,13 @@ record_wait (struct target_ops *ops, if (record_hw_watchpoint) { if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ -Process record: hit hw watchpoint.\n"); + fprintf_unfiltered (gdb_stdlog, + "Process record: hit hw " + "watchpoint.\n"); 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; } @@ -1304,12 +1453,12 @@ Process record: hit hw watchpoint.\n"); 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); } @@ -1320,6 +1469,24 @@ replay_out: return inferior_ptid; } +static ptid_t +record_wait (struct target_ops *ops, + ptid_t ptid, struct target_waitstatus *status, + int options) +{ + ptid_t return_ptid; + + return_ptid = record_wait_1 (ops, ptid, status, options); + if (status->kind != TARGET_WAITKIND_IGNORE) + { + /* We're reporting a stop. Make sure any spurious + target_wait(WNOHANG) doesn't advance the target until the + core wants us resumed again. */ + record_resumed = 0; + } + return return_ptid; +} + static int record_stopped_by_watchpoint (void) { @@ -1555,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; } @@ -1582,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); - return ret; + if (ret != 0) + 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. */ @@ -1654,6 +1912,37 @@ record_goto_bookmark (gdb_byte *bookmark, int from_tty) return; } +static void +record_async (void (*callback) (enum inferior_event_type event_type, + void *context), void *context) +{ + /* 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_beneath_to_async != NULL) + record_beneath_to_async (callback, context); +} + +static int +record_can_async_p (void) +{ + /* We only enable async when the user specifically asks for it. */ + return target_async_permitted; +} + +static int +record_is_async_p (void) +{ + /* We only enable async when the user specifically asks for it. */ + return target_async_permitted; +} + +static enum exec_direction_kind +record_execution_direction (void) +{ + return record_execution_dir; +} + static void init_record_ops (void) { @@ -1681,6 +1970,10 @@ init_record_ops (void) /* Add bookmark target methods. */ record_ops.to_get_bookmark = record_get_bookmark; record_ops.to_goto_bookmark = record_goto_bookmark; + record_ops.to_async = record_async; + record_ops.to_can_async_p = record_can_async_p; + record_ops.to_is_async_p = record_is_async_p; + record_ops.to_execution_direction = record_execution_direction; record_ops.to_magic = OPS_MAGIC; } @@ -1688,9 +1981,21 @@ 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; + record_execution_dir = execution_direction; + + /* 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_async_inferior_event_token); + } } /* "to_kill" method for prec over corefile. */ @@ -1858,8 +2163,8 @@ record_core_remove_breakpoint (struct gdbarch *gdbarch, /* "to_has_execution" method for prec over corefile. */ -int -record_core_has_execution (struct target_ops *ops) +static int +record_core_has_execution (struct target_ops *ops, ptid_t the_ptid) { return 1; } @@ -1890,6 +2195,10 @@ init_record_core_ops (void) /* Add bookmark target methods. */ record_core_ops.to_get_bookmark = record_get_bookmark; record_core_ops.to_goto_bookmark = record_goto_bookmark; + record_core_ops.to_async = record_async; + record_core_ops.to_can_async_p = record_can_async_p; + record_core_ops.to_is_async_p = record_is_async_p; + record_core_ops.to_execution_direction = record_execution_direction; record_core_ops.to_magic = OPS_MAGIC; } @@ -1971,8 +2280,8 @@ static struct cmd_list_element *record_cmdlist, *set_record_cmdlist, static void set_record_command (char *args, int from_tty) { - printf_unfiltered (_("\ -\"set record\" must be followed by an apporpriate subcommand.\n")); + printf_unfiltered (_("\"set record\" must be followed " + "by an apporpriate subcommand.\n")); help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout); } @@ -2089,7 +2398,7 @@ bfdcore_read (bfd *obfd, asection *osec, void *buf, int len, int *offset) if (ret) *offset += len; else - error (_("Failed to read %d bytes from core file %s ('%s').\n"), + error (_("Failed to read %d bytes from core file %s ('%s')."), len, bfd_get_filename (obfd), bfd_errmsg (bfd_get_error ())); } @@ -2149,12 +2458,12 @@ record_restore (void) /* Now need to find our special note section. */ osec = bfd_get_section_by_name (core_bfd, "null0"); - osec_size = bfd_section_size (core_bfd, osec); if (record_debug) fprintf_unfiltered (gdb_stdlog, "Find precord section %s.\n", osec ? "succeeded" : "failed"); if (osec == NULL) return; + osec_size = bfd_section_size (core_bfd, osec); if (record_debug) fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (core_bfd, osec)); @@ -2164,8 +2473,9 @@ record_restore (void) error (_("Version mis-match or file format error in core file %s."), bfd_get_filename (core_bfd)); if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ - Reading 4-byte magic cookie RECORD_FILE_MAGIC (0x%s)\n", + fprintf_unfiltered (gdb_stdlog, + " Reading 4-byte magic cookie " + "RECORD_FILE_MAGIC (0x%s)\n", phex_nz (netorder32 (magic), 4)); /* Restore the entries in recfd into record_arch_list_head and @@ -2202,8 +2512,9 @@ record_restore (void) rec->u.reg.len, &bfd_offset); if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ - Reading register %d (1 plus %lu plus %d bytes)\n", + fprintf_unfiltered (gdb_stdlog, + " Reading register %d (1 " + "plus %lu plus %d bytes)\n", rec->u.reg.num, (unsigned long) sizeof (regnum), rec->u.reg.len); @@ -2227,8 +2538,9 @@ record_restore (void) rec->u.mem.len, &bfd_offset); if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ - Reading memory %s (1 plus %lu plus %lu plus %d bytes)\n", + fprintf_unfiltered (gdb_stdlog, + " Reading memory %s (1 plus " + "%lu plus %lu plus %d bytes)\n", paddress (get_current_arch (), rec->u.mem.addr), (unsigned long) sizeof (addr), @@ -2253,8 +2565,9 @@ record_restore (void) rec->u.end.insn_num = count; record_insn_count = count + 1; if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ - Reading record_end (1 + %lu + %lu bytes), offset == %s\n", + fprintf_unfiltered (gdb_stdlog, + " Reading record_end (1 + " + "%lu + %lu bytes), offset == %s\n", (unsigned long) sizeof (signal), (unsigned long) sizeof (count), paddress (get_current_arch (), @@ -2304,7 +2617,7 @@ bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset) if (ret) *offset += len; else - error (_("Failed to write %d bytes to core file %s ('%s').\n"), + error (_("Failed to write %d bytes to core file %s ('%s')."), len, bfd_get_filename (obfd), bfd_errmsg (bfd_get_error ())); } @@ -2431,8 +2744,9 @@ cmd_record_save (char *args, int from_tty) /* Write the magic code. */ magic = RECORD_FILE_MAGIC; if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ - Writing 4-byte magic cookie RECORD_FILE_MAGIC (0x%s)\n", + fprintf_unfiltered (gdb_stdlog, + " Writing 4-byte magic cookie " + "RECORD_FILE_MAGIC (0x%s)\n", phex_nz (magic, 4)); bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset); @@ -2455,8 +2769,9 @@ cmd_record_save (char *args, int from_tty) { case record_reg: /* reg */ if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ - Writing register %d (1 plus %lu plus %d bytes)\n", + fprintf_unfiltered (gdb_stdlog, + " Writing register %d (1 " + "plus %lu plus %d bytes)\n", record_list->u.reg.num, (unsigned long) sizeof (regnum), record_list->u.reg.len); @@ -2473,8 +2788,9 @@ cmd_record_save (char *args, int from_tty) case record_mem: /* mem */ if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ - Writing memory %s (1 plus %lu plus %lu plus %d bytes)\n", + fprintf_unfiltered (gdb_stdlog, + " Writing memory %s (1 plus " + "%lu plus %lu plus %d bytes)\n", paddress (gdbarch, record_list->u.mem.addr), (unsigned long) sizeof (addr), @@ -2497,8 +2813,9 @@ cmd_record_save (char *args, int from_tty) case record_end: if (record_debug) - fprintf_unfiltered (gdb_stdlog, "\ - Writing record_end (1 + %lu + %lu bytes)\n", + fprintf_unfiltered (gdb_stdlog, + " Writing record_end (1 + " + "%lu + %lu bytes)\n", (unsigned long) sizeof (signal), (unsigned long) sizeof (count)); /* Write signal value. */ @@ -2640,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) { @@ -2710,8 +3030,8 @@ Argument is filename. File must be created with 'record save'."), add_setshow_boolean_cmd ("stop-at-limit", no_class, &record_stop_at_limit, _("\ Set whether record/replay stops when record/replay buffer becomes full."), _("\ -Show whether record/replay stops when record/replay buffer becomes full."), _("\ -Default is ON.\n\ +Show whether record/replay stops when record/replay buffer becomes full."), + _("Default is ON.\n\ When ON, if the record/replay buffer becomes full, ask user what to do.\n\ When OFF, if the record/replay buffer becomes full,\n\ delete the oldest recorded instruction to make room for each new one."), @@ -2730,4 +3050,16 @@ record/replay buffer. Zero means unlimited. Default is 200000."), Restore the program to its state at instruction number N.\n\ Argument is instruction number, as shown by 'info record'."), &record_cmdlist); + + add_setshow_boolean_cmd ("memory-query", no_class, + &record_memory_query, _("\ +Set whether query if PREC cannot record memory change of next instruction."), + _("\ +Show whether query if PREC cannot record memory change of next instruction."), + _("\ +Default is OFF.\n\ +When ON, query if PREC cannot record memory change of next instruction."), + NULL, NULL, + &set_record_cmdlist, &show_record_cmdlist); + }