Correct shell compatibility issue detected with pkgsrc.
[deliverable/binutils-gdb.git] / gdb / record-full.c
index 43e8be23b6c775618df0e3b8c2e274995002a426..7f6ecc71530bca618d35f82f874b987aabd2ec93 100644 (file)
@@ -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-2017 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -35,6 +35,8 @@
 #include "gdb_bfd.h"
 #include "observer.h"
 #include "infrun.h"
+#include "common/gdb_unlinker.h"
+#include "common/byte-vector.h"
 
 #include <signal.h>
 
@@ -244,7 +246,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 +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;
@@ -300,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;
@@ -535,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;
        }
     }
 }
@@ -583,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.
@@ -651,7 +645,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 +661,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);
 }
 
@@ -704,7 +699,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,
@@ -713,10 +708,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;
 
@@ -725,7 +720,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,
@@ -770,6 +766,8 @@ record_full_exec_insn (struct regcache *regcache,
                      record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
                  }
               }
+
+           do_cleanups (cleanup);
           }
       }
       break;
@@ -800,7 +798,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);
@@ -825,7 +823,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)
@@ -873,7 +871,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.  */
@@ -973,24 +971,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);
             }
         }
 
@@ -1006,6 +994,15 @@ record_full_resume (struct target_ops *ops, ptid_t ptid, int step,
     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;
 
 /* SIGINT signal handler, registered by "to_wait" method.  */
@@ -1163,9 +1160,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);
                        }
 
@@ -1176,6 +1173,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;
                    }
                }
@@ -1416,7 +1414,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;
@@ -1542,7 +1540,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;
@@ -1646,6 +1644,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)
     {
@@ -1653,7 +1652,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;
 
@@ -1667,6 +1666,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;
@@ -1680,7 +1695,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;
@@ -1700,15 +1716,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;
        }
     }
@@ -1785,6 +1804,14 @@ record_full_execution_direction (struct target_ops *self)
   return record_full_execution_dir;
 }
 
+/* The to_record_method method of target record-full.  */
+
+enum record_method
+record_full_record_method (struct target_ops *self, ptid_t ptid)
+{
+  return RECORD_METHOD_FULL;
+}
+
 static void
 record_full_info (struct target_ops *self)
 {
@@ -1840,11 +1867,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
@@ -1869,6 +1908,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);
 }
 
@@ -1916,6 +1956,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)
 {
@@ -1927,6 +1975,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;
@@ -1952,10 +2001,13 @@ init_record_full_ops (void)
   record_full_ops.to_get_bookmark = record_full_get_bookmark;
   record_full_ops.to_goto_bookmark = record_full_goto_bookmark;
   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;
@@ -2083,9 +2135,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,
@@ -2146,7 +2196,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;
 }
@@ -2201,9 +2252,11 @@ init_record_full_core_ops (void)
   record_full_core_ops.to_goto_bookmark = record_full_goto_bookmark;
   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;
@@ -2287,16 +2340,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)
@@ -2420,7 +2463,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, 
@@ -2496,17 +2539,6 @@ cmd_record_full_restore (char *args, int 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.  */
 
@@ -2517,9 +2549,7 @@ record_full_save (struct target_ops *self, const char *recfilename)
   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;
@@ -2530,8 +2560,10 @@ record_full_save (struct target_ops *self, 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;
@@ -2574,20 +2606,20 @@ record_full_save (struct target_ops *self, 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.  */
@@ -2597,7 +2629,7 @@ record_full_save (struct target_ops *self, 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.  */
@@ -2612,7 +2644,7 @@ record_full_save (struct target_ops *self, 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)
             {
@@ -2627,11 +2659,11 @@ record_full_save (struct target_ops *self, const char *recfilename)
 
               /* Write regnum.  */
               regnum = netorder32 (record_full_list->u.reg.num);
-              bfdcore_write (obfd, osec, &regnum,
+              bfdcore_write (obfd.get (), osec, &regnum,
                             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;
@@ -2649,15 +2681,16 @@ record_full_save (struct target_ops *self, 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;
@@ -2671,12 +2704,12 @@ record_full_save (struct target_ops *self, 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;
             }
@@ -2705,8 +2738,7 @@ record_full_save (struct target_ops *self, const char *recfilename)
     }
 
   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"),
@@ -2747,7 +2779,7 @@ record_full_goto_insn (struct record_full_entry *entry,
 static void
 cmd_record_full_start (char *args, int from_tty)
 {
-  execute_command ("target record-full", from_tty);
+  execute_command ((char *) "target record-full", from_tty);
 }
 
 static void
This page took 0.034556 seconds and 4 git commands to generate.