This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA/RFC] Add dump and load command to process record (file format etc)


On 2009-08-06, Michael Snyder <msnyder@vmware.com> wrote:
>
>  msnyder:
>
> >
> > > If you look at the code that dumps the file (and I had
> > > to add a bunch of printfs and stuff to figure it out), you'll
> > > see that the dump file looks like this:
> > >
> > > 4 byte magic number
> > > Series of the following:
> > > 1) 1 byte tag (record_end), or
> > > 2) 1 byte tag (record_rec) followed by
> > >  8 byte number (register id), followed by
> > >  MAX_REGISTER_SIZE byte value (register value): or
> > > 3) 1 byte tag (record_mem) followed by
> > >  8 byte number (memory address) followed by
> > >  8 byte number (memory length) followed by
> > >  N byte buffer (memory value).
> > >
> > > If you look for the #if (BYTE_ORDER == BIG_ENDIAN), this is
> > > where Teawater is making the byte orders host-independent.
> > >
> > > I was going to mention the ifdefs eventually.   ;-)
> > >
> >
>
>  Hui Zhu:
>
> > Cool.  It's very clear.  :)
> > Thanks Michael.
> >
> > I make a new version patch to follow the cvs head.  And removed the ifdef.
> > Please help me review it.
> >
>
>  OK, well, let me start out with some thoughts about the
>  idea and the architecture.
>
>  It's a great idea to save and reload a recording log.
>  We need to document the file format, as I've informally
>  done above, maybe by placing a comment in the file.
>  I'll post a suggested comment soon.
>
>  Once that's done, it becomes obvious that we are only saving
>  state changes -- no snapshot of the starting state.  Then it
>  becomes obvious why you need to save and load a corefile as well --
>  that gives you the starting state snapshot, to go with your
>  saved state changes.
>
>  The trouble that I see now is that there is no insurance that
>  the starting state (core file) and the state changes (record file)
>  correspond to one another.  A user could get into trouble by
>  loading one starting state and a DIFFERENT set of state changes.
>  And he would have no way of knowing why his debugging session
>  was producing nonsense results.
>
>  This is a little bit like the problem of storing separate
>  symbol files (separate from the executable file).  We need
>  a way to confirm that the two files correspond with one another.
>
>  I've given it a little thought, and I would like to hear
>  what others think.  Here are some of my ideas:
>
>  1) Store a pointer to the corefile in the record log file.
>  2) Store a checksum, hash, or CRC of the corefile in the log file.

I think this way is easy to implement.

>  3) Store a CRC of the loadable sections, plus a snapshot of the
>    register set, in the log file.
>  4) Store both corefile and log file together in the same file.

For all of this way, I think we have a problem is when we dump the
log, we don't know where is the core file.
Maybe we can extend the record dump command, to let it point out where
is the  core file or let it call gcore too.


>
>  Of course, every time we change the file format, we should
>  change the magic number to insure that a new-format gdb will
>  not attempt to read an old-format file.

Agree with it.


Thanks,
Hui

>
>  Discussion?
>
>
>
> > 2009-08-05  Hui Zhu  <teawater@gmail.com>
> >
> >        Add dump and load command to process record and replay.
> >
> >        * record.c (completer.h, arch-utils.h, gdbcore.h, exec.h,
> >        byteswap.h, netinet/in.h): Include files.
> >        (RECORD_IS_REPLAY): Return true if record_core is true.
> >        (RECORD_FILE_MAGIC): New macro.
> >        (record_core_buf_entry): New struct.
> >        (record_core, record_core_regbuf, record_core_start,
> >        record_core_end, record_core_buf_list,
> >        record_beneath_to_fetch_registers_ops,
> >        record_beneath_to_fetch_registers,
> >        record_beneath_to_store_registers_ops,
> >        record_beneath_to_store_registers,
> >        record_beneath_to_has_execution_ops,
> >        record_beneath_to_has_execution,
> >        record_beneath_to_prepare_to_store): New
> variables.
> >        (record_list_release_first_insn): Change function
> >        record_list_release_first to this name.
> >        (record_arch_list_cleanups): New function.
> >        (record_message_cleanups): Removed.
> >        (record_message): Change to call record_arch_list_cleanups
> >        and record_list_release_first_insn.
> >        (record_exec_entry): New function.
> >        (record_open): Add support for target core.
> >        (record_close): Add support for target core.
> >        (record_wait): Call function 'record_exec_entry'.
> >        (record_kill): Add support for target core.
> >        (record_registers_change): Call
> record_list_release_first_insn.
> >        (record_fetch_registers): New function.
> >        (record_prepare_to_store): New function.
> >        (record_store_registers): Add support for target core.
> >        (record_xfer_partial): Add support for target core.
> >        (record_has_execution): New function.
> >        (init_record_ops): Set record_ops.to_fetch_registers,
> >        record_ops.to_prepare_to_store
> >        and record_ops.to_has_execution.
> >        (cmd_record_fd_cleanups): New function.
> >        (cmd_record_dump): New function.
> >        (cmd_record_load): New function.
> >        (set_record_insn_max_num): Call
> record_list_release_first_insn.
> >        (_initialize_record): Add commands "record dump"
> >        and "record load".
> >
> > ---
> >  record.c |  731
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
> >  1 file changed, 640 insertions(+), 91 deletions(-)
> >
> > --- a/record.c
> > +++ b/record.c
> > @@ -23,14 +23,22 @@
> >  #include "gdbthread.h"
> >  #include "event-top.h"
> >  #include "exceptions.h"
> > +#include "completer.h"
> > +#include "arch-utils.h"
> > +#include "gdbcore.h"
> > +#include "exec.h"
> >  #include "record.h"
> >
> > +#include <byteswap.h>
> >  #include <signal.h>
> > +#include <netinet/in.h>
> >
> >  #define DEFAULT_RECORD_INSN_MAX_NUM    200000
> >
> >  #define RECORD_IS_REPLAY \
> > -     (record_list->next || execution_direction == EXEC_REVERSE)
> > +     (record_list->next || execution_direction == EXEC_REVERSE ||
> record_core)
> > +
> > +#define RECORD_FILE_MAGIC      htonl(0x20090726)
> >
> >  /* These are the core struct of record function.
> >
> > @@ -78,9 +86,23 @@ struct record_entry
> >   } u;
> >  };
> >
> > +struct record_core_buf_entry
> > +{
> > +  struct record_core_buf_entry *prev;
> > +  struct target_section *p;
> > +  bfd_byte *buf;
> > +};
> > +
> >  /* This is the debug switch for process record.  */
> >  int record_debug = 0;
> >
> > +/* Record with core target.  */
> > +static int record_core = 0;
> > +static gdb_byte *record_core_regbuf;
> > +static struct target_section *record_core_start;
> > +static struct target_section *record_core_end;
> > +static struct record_core_buf_entry *record_core_buf_list = NULL;
> > +
> >  /* These list is for execution log.  */
> >  static struct record_entry record_first;
> >  static struct record_entry *record_list = &record_first;
> > @@ -103,6 +125,14 @@ static struct target_ops *record_beneath
> >  static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t,
> >                                         struct target_waitstatus *,
> >                                         int);
> > +static struct target_ops
> *record_beneath_to_fetch_registers_ops;
> > +static void (*record_beneath_to_fetch_registers) (struct
> target_ops *,
> > +                                                  struct regcache *,
> > +                                                 int regno);
> > +static struct target_ops
> *record_beneath_to_store_registers_ops;
> > +static void (*record_beneath_to_store_registers) (struct
> target_ops *,
> > +                                                  struct regcache *,
> > +                                                 int regno);
> >  static struct target_ops
> *record_beneath_to_store_registers_ops;
> >  static void (*record_beneath_to_store_registers) (struct
> target_ops *,
> >                                                   struct regcache *,
> > @@ -119,6 +149,9 @@ static int (*record_beneath_to_insert_br
> >                                                   struct bp_target_info
> *);
> >  static int (*record_beneath_to_remove_breakpoint)
> (struct gdbarch *,
> >                                                   struct bp_target_info
> *);
> > +static struct target_ops
> *record_beneath_to_has_execution_ops;
> > +static int (*record_beneath_to_has_execution) (struct
> target_ops *ops);
> > +static void (*record_beneath_to_prepare_to_store)
> (struct regcache *regcache);
> >
> >  static void
> >  record_list_release (struct record_entry *rec)
> > @@ -169,7 +202,7 @@ record_list_release_next (void)
> >  }
> >
> >  static void
> > -record_list_release_first (void)
> > +record_list_release_first_insn (void)
> >  {
> >   struct record_entry *tmp = NULL;
> >   enum record_type type;
> > @@ -340,30 +373,30 @@ record_check_insn_num (int set_terminal)
> >              if (q)
> >                record_stop_at_limit = 0;
> >              else
> > -               error (_("Process record: inferior program stopped."));
> > +               error (_("Process record: stoped by user."));
> >            }
> >        }
> >     }
> >  }
> >
> > +static void
> > +record_arch_list_cleanups (void *ignore)
> > +{
> > +  record_list_release (record_arch_list_tail);
> > +}
> > +
> >  /* Before inferior step (when GDB record the running message, inferior
> >    only can step), GDB will call this function to record the values to
> >    record_list.  This function will call gdbarch_process_record to
> >    record the running message of inferior and set them to
> >    record_arch_list, and add it to record_list.  */
> >
> > -static void
> > -record_message_cleanups (void *ignore)
> > -{
> > -  record_list_release (record_arch_list_tail);
> > -}
> > -
> >  static int
> >  record_message (void *args)
> >  {
> >   int ret;
> >   struct regcache *regcache = args;
> > -  struct cleanup *old_cleanups = make_cleanup (record_message_cleanups,
> 0);
> > +  struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups,
> 0);
> >
> >   record_arch_list_head = NULL;
> >   record_arch_list_tail = NULL;
> > @@ -386,7 +419,7 @@ record_message (void *args)
> >   record_list = record_arch_list_tail;
> >
> >   if (record_insn_num == record_insn_max_num && record_insn_max_num)
> > -    record_list_release_first ();
> > +    record_list_release_first_insn ();
> >   else
> >     record_insn_num++;
> >
> > @@ -416,6 +449,91 @@ record_gdb_operation_disable_set
> (void)
> >   return old_cleanups;
> >  }
> >
> > +static inline void
> > +record_exec_entry (struct regcache *regcache, struct gdbarch *gdbarch,
> > +                   struct record_entry *entry)
> > +{
> > +  switch (entry->type)
> > +    {
> > +    case record_reg: /* reg */
> > +      {
> > +        gdb_byte reg[MAX_REGISTER_SIZE];
> > +
> > +        if (record_debug > 1)
> > +          fprintf_unfiltered (gdb_stdlog,
> > +                              "Process record: record_reg %s to "
> > +                              "inferior num = %d.\n",
> > +                              host_address_to_string (entry),
> > +                              entry->u.reg.num);
> > +
> > +        regcache_cooked_read (regcache, entry->u.reg.num, reg);
> > +        regcache_cooked_write (regcache, entry->u.reg.num,
> entry->u.reg.val);
> > +        memcpy (entry->u.reg.val, reg, MAX_REGISTER_SIZE);
> > +      }
> > +      break;
> > +
> > +    case record_mem: /* mem */
> > +      {
> > +        if
> (!record_list->u.mem.mem_entry_not_accessible)
> > +          {
> > +            gdb_byte *mem = alloca (entry->u.mem.len);
> > +
> > +            if (record_debug > 1)
> > +              fprintf_unfiltered (gdb_stdlog,
> > +                                  "Process record: record_mem %s to "
> > +                                  "inferior addr = %s len = %d.\n",
> > +                                  host_address_to_string (entry),
> > +                                  paddress (gdbarch, entry->u.mem.addr),
> > +                                  record_list->u.mem.len);
> > +
> > +            if (target_read_memory (entry->u.mem.addr, mem,
> entry->u.mem.len))
> > +              {
> > +                 if ((execution_direction == EXEC_REVERSE &&
> !record_core)
> > +                     || (execution_direction != EXEC_REVERSE &&
> record_core))
> > +                  {
> > +
> record_list->u.mem.mem_entry_not_accessible = 1;
> > +                    if (record_debug)
> > +                      warning (_("Process record: error reading memory at
> "
> > +                                 "addr = %s len = %d."),
> > +                               paddress (gdbarch, entry->u.mem.addr),
> > +                               entry->u.mem.len);
> > +                  }
> > +                else
> > +                  error (_("Process record: error reading memory at "
> > +                           "addr = %s len = %d."),
> > +                         paddress (gdbarch, entry->u.mem.addr),
> > +                        entry->u.mem.len);
> > +              }
> > +            else
> > +              {
> > +                if (target_write_memory (entry->u.mem.addr,
> entry->u.mem.val,
> > +                                         entry->u.mem.len))
> > +                  {
> > +                     if ((execution_direction == EXEC_REVERSE &&
> !record_core)
> > +                         || (execution_direction != EXEC_REVERSE &&
> > record_core))
> > +                      {
> > +
> record_list->u.mem.mem_entry_not_accessible = 1;
> > +                        if (record_debug)
> > +                          warning (_("Process record: error writing
> memory at "
> > +                                     "addr = %s len = %d."),
> > +                                   paddress (gdbarch, entry->u.mem.addr),
> > +                                   entry->u.mem.len);
> > +                      }
> > +                    else
> > +                      error (_("Process record: error writing memory at "
> > +                               "addr = %s len = %d."),
> > +                             paddress (gdbarch, entry->u.mem.addr),
> > +                            entry->u.mem.len);
> > +                  }
> > +              }
> > +
> > +            memcpy (entry->u.mem.val, mem, entry->u.mem.len);
> > +          }
> > +      }
> > +      break;
> > +    }
> > +}
> > +
> >  static void
> >  record_open (char *name, int from_tty)
> >  {
> > @@ -424,8 +542,13 @@ record_open (char *name, int from_tty)
> >   if (record_debug)
> >     fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
> >
> > +  if (!strcmp (current_target.to_shortname, "core"))
> > +    record_core = 1;
> > +  else
> > +    record_core = 0;
> > +
> >   /* check exec */
> > -  if (!target_has_execution)
> > +  if (!target_has_execution && !record_core)
> >     error (_("Process record: the program is not being run."));
> >   if (non_stop)
> >     error (_("Process record target can't debug inferior in non-stop mode
> "
> > @@ -454,6 +577,8 @@ record_open (char *name, int from_tty)
> >   record_beneath_to_xfer_partial = NULL;
> >   record_beneath_to_insert_breakpoint = NULL;
> >   record_beneath_to_remove_breakpoint = NULL;
> > +  record_beneath_to_has_execution = NULL;
> > +  record_beneath_to_prepare_to_store = NULL;
> >
> >   /* Set the beneath function pointers.  */
> >   for (t = current_target.beneath; t != NULL; t = t->beneath)
> > @@ -468,6 +593,11 @@ record_open (char *name, int from_tty)
> >          record_beneath_to_wait = t->to_wait;
> >          record_beneath_to_wait_ops = t;
> >         }
> > +      if (!record_beneath_to_fetch_registers)
> > +        {
> > +         record_beneath_to_fetch_registers =
> t->to_fetch_registers;
> > +         record_beneath_to_fetch_registers_ops = t;
> > +        }
> >       if (!record_beneath_to_store_registers)
> >         {
> >          record_beneath_to_store_registers =
> t->to_store_registers;
> > @@ -482,19 +612,51 @@ record_open (char *name, int from_tty)
> >        record_beneath_to_insert_breakpoint =
> t->to_insert_breakpoint;
> >       if (!record_beneath_to_remove_breakpoint)
> >        record_beneath_to_remove_breakpoint =
> t->to_remove_breakpoint;
> > +      if (!record_beneath_to_has_execution)
> > +        {
> > +          record_beneath_to_has_execution_ops = t;
> > +         record_beneath_to_has_execution =
> t->to_has_execution;
> > +        }
> > +      if (!record_beneath_to_prepare_to_store)
> > +       record_beneath_to_prepare_to_store =
> t->to_prepare_to_store;
> >     }
> > -  if (!record_beneath_to_resume)
> > +  if (!record_beneath_to_resume && !record_core)
> >     error (_("Process record can't get to_resume."));
> > -  if (!record_beneath_to_wait)
> > +  if (!record_beneath_to_wait && !record_core)
> >     error (_("Process record can't get to_wait."));
> > -  if (!record_beneath_to_store_registers)
> > +  if (!record_beneath_to_fetch_registers)
> > +    error (_("Process record can't get to_fetch_registers."));
> > +  if (!record_beneath_to_store_registers &&
> !record_core)
> >     error (_("Process record can't get to_store_registers."));
> >   if (!record_beneath_to_xfer_partial)
> >     error (_("Process record can't get to_xfer_partial."));
> > -  if (!record_beneath_to_insert_breakpoint)
> > +  if (!record_beneath_to_insert_breakpoint &&
> !record_core)
> >     error (_("Process record can't get to_insert_breakpoint."));
> > -  if (!record_beneath_to_remove_breakpoint)
> > +  if (!record_beneath_to_remove_breakpoint &&
> !record_core)
> >     error (_("Process record can't get to_remove_breakpoint."));
> > +  if (!record_beneath_to_has_execution && !record_core)
> > +    error (_("Process record can't get to_has_execution."));
> > +  if (!record_beneath_to_prepare_to_store &&
> !record_core)
> > +    error (_("Process record can't get to_prepare_to_store."));
> > +
> > +  if (record_core)
> > +    {
> > +      /* Get record_core_regbuf.  */
> > +      struct regcache *regcache = get_current_regcache ();
> > +      int regnum = gdbarch_num_regs (get_regcache_arch (regcache));
> > +      int i;
> > +
> > +      target_fetch_registers (regcache, -1);
> > +      record_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
> > +      for (i = 0; i < regnum; i ++)
> > +        regcache_raw_collect (regcache, i,
> > +                              record_core_regbuf + MAX_REGISTER_SIZE *
> i);
> > +
> > +      /* Get record_core_start and record_core_end.  */
> > +      if (build_section_table (core_bfd, &record_core_start,
> &record_core_end))
> > +        error (_("\"%s\": Can't find sections: %s"),
> > +               bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error
> ()));
> > +    }
> >
> >   push_target (&record_ops);
> >
> > @@ -507,10 +669,26 @@ record_open (char *name, int from_tty)
> >  static void
> >  record_close (int quitting)
> >  {
> > +  struct record_core_buf_entry *entry;
> > +
> >   if (record_debug)
> >     fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");
> >
> >   record_list_release (record_list);
> > +
> > +  /* Release record_core_regbuf.  */
> > +  xfree (record_core_regbuf);
> > +
> > +  /* Release record_core_buf_list.  */
> > +  if (record_core_buf_list)
> > +    {
> > +      for (entry = record_core_buf_list->prev; entry; entry =
> entry->prev)
> > +        {
> > +          xfree (record_core_buf_list);
> > +          record_core_buf_list = entry;
> > +        }
> > +      record_core_buf_list = NULL;
> > +    }
> >  }
> >
> >  static int record_resume_step = 0;
> > @@ -712,76 +890,9 @@ record_wait (struct target_ops *ops,
> >              break;
> >            }
> >
> > -         /* Set ptid, register and memory according to record_list.  */
> > -         if (record_list->type == record_reg)
> > -           {
> > -             /* reg */
> > -             gdb_byte reg[MAX_REGISTER_SIZE];
> > -             if (record_debug > 1)
> > -               fprintf_unfiltered (gdb_stdlog,
> > -                                   "Process record: record_reg %s to "
> > -                                   "inferior num = %d.\n",
> > -                                   host_address_to_string (record_list),
> > -                                   record_list->u.reg.num);
> > -             regcache_cooked_read (regcache, record_list->u.reg.num,
> reg);
> > -             regcache_cooked_write (regcache, record_list->u.reg.num,
> > -                                    record_list->u.reg.val);
> > -             memcpy (record_list->u.reg.val, reg, MAX_REGISTER_SIZE);
> > -           }
> > -         else if (record_list->type == record_mem)
> > -           {
> > -             /* mem */
> > -             /* Nothing to do if the entry is flagged not_accessible.  */
> > -             if
> (!record_list->u.mem.mem_entry_not_accessible)
> > -               {
> > -                 gdb_byte *mem = alloca (record_list->u.mem.len);
> > -                 if (record_debug > 1)
> > -                   fprintf_unfiltered (gdb_stdlog,
> > -                                       "Process record: record_mem %s to
> "
> > -                                       "inferior addr = %s len = %d.\n",
> > -                                       host_address_to_string
> (record_list),
> > -                                       paddress (gdbarch,
> > -
> record_list->u.mem.addr),
> > -                                       record_list->u.mem.len);
> > +          record_exec_entry (regcache, gdbarch, record_list);
> >
> > -                 if (target_read_memory (record_list->u.mem.addr, mem,
> > -                                         record_list->u.mem.len))
> > -                   {
> > -                     if (execution_direction != EXEC_REVERSE)
> > -                       error (_("Process record: error reading memory at
> "
> > -                                "addr = %s len = %d."),
> > -                              paddress (gdbarch,
> record_list->u.mem.addr),
> > -                              record_list->u.mem.len);
> > -                     else
> > -                       /* Read failed --
> > -                          flag entry as not_accessible.  */
> > -
> record_list->u.mem.mem_entry_not_accessible = 1;
> > -                   }
> > -                 else
> > -                   {
> > -                     if (target_write_memory (record_list->u.mem.addr,
> > -                                              record_list->u.mem.val,
> > -                                              record_list->u.mem.len))
> > -                       {
> > -                         if (execution_direction != EXEC_REVERSE)
> > -                           error (_("Process record: error writing memory
> at "
> > -                                    "addr = %s len = %d."),
> > -                                  paddress (gdbarch,
> record_list->u.mem.addr),
> > -                                  record_list->u.mem.len);
> > -                         else
> > -                           /* Write failed --
> > -                              flag entry as not_accessible.  */
> > -
> record_list->u.mem.mem_entry_not_accessible = 1;
> > -                       }
> > -                     else
> > -                       {
> > -                         memcpy (record_list->u.mem.val, mem,
> > -                                 record_list->u.mem.len);
> > -                       }
> > -                   }
> > -               }
> > -           }
> > -         else
> > +         if (record_list->type == record_end)
> >            {
> >              if (record_debug > 1)
> >                fprintf_unfiltered (gdb_stdlog,
> > @@ -901,7 +1012,9 @@ record_kill (struct target_ops *ops)
> >     fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n");
> >
> >   unpush_target (&record_ops);
> > -  target_kill ();
> > +
> > +  if (!record_core)
> > +    target_kill ();
> >  }
> >
> >  /* Record registers change (by user or by GDB) to list as an instruction.
>  */
> > @@ -945,15 +1058,58 @@ record_registers_change (struct regcache
> >   record_list = record_arch_list_tail;
> >
> >   if (record_insn_num == record_insn_max_num && record_insn_max_num)
> > -    record_list_release_first ();
> > +    record_list_release_first_insn ();
> >   else
> >     record_insn_num++;
> >  }
> >
> >  static void
> > +record_fetch_registers (struct target_ops *ops, struct regcache
> *regcache,
> > +                        int regno)
> > +{
> > +  if (record_core)
> > +    {
> > +      if (regno < 0)
> > +        {
> > +          int num = gdbarch_num_regs (get_regcache_arch (regcache));
> > +          int i;
> > +
> > +          for (i = 0; i < num; i ++)
> > +            regcache_raw_supply (regcache, i,
> > +                                 record_core_regbuf + MAX_REGISTER_SIZE *
> i);
> > +        }
> > +      else
> > +        regcache_raw_supply (regcache, regno,
> > +                             record_core_regbuf + MAX_REGISTER_SIZE *
> regno);
> > +    }
> > +  else
> > +    record_beneath_to_fetch_registers
> (record_beneath_to_store_registers_ops,
> > +                                       regcache, regno);
> > +}
> > +
> > +static void
> > +record_prepare_to_store (struct regcache *regcache)
> > +{
> > +  if (!record_core)
> > +    record_beneath_to_prepare_to_store (regcache);
> > +}
> > +
> > +static void
> >  record_store_registers (struct target_ops *ops, struct regcache
> *regcache,
> >                         int regno)
> >  {
> > +  if (record_core)
> > +    {
> > +      /* Debug with core.  */
> > +      if (record_gdb_operation_disable)
> > +        regcache_raw_collect (regcache, regno,
> > +                              record_core_regbuf + MAX_REGISTER_SIZE *
> regno);
> > +      else
> > +        error (_("You can't do that without a process to debug."));
> > +
> > +      return;
> > +    }
> > +
> >   if (!record_gdb_operation_disable)
> >     {
> >       if (RECORD_IS_REPLAY)
> > @@ -1000,6 +1156,7 @@ record_store_registers (struct target_op
> >
> >       record_registers_change (regcache, regno);
> >     }
> > +
> >   record_beneath_to_store_registers
> (record_beneath_to_store_registers_ops,
> >                                      regcache, regno);
> >  }
> > @@ -1015,7 +1172,7 @@ record_xfer_partial (struct target_ops *
> >  {
> >   if (!record_gdb_operation_disable
> >       && (object == TARGET_OBJECT_MEMORY
> > -         || object == TARGET_OBJECT_RAW_MEMORY) && writebuf)
> > +         || object == TARGET_OBJECT_RAW_MEMORY) && writebuf &&
> !record_core)
> >     {
> >       if (RECORD_IS_REPLAY)
> >        {
> > @@ -1059,11 +1216,91 @@ record_xfer_partial (struct target_ops *
> >       record_list = record_arch_list_tail;
> >
> >       if (record_insn_num == record_insn_max_num && record_insn_max_num)
> > -       record_list_release_first ();
> > +       record_list_release_first_insn ();
> >       else
> >        record_insn_num++;
> >     }
> >
> > +   if (record_core && object == TARGET_OBJECT_MEMORY)
> > +     {
> > +       /* Debug with core.  */
> > +       if (record_gdb_operation_disable || !writebuf)
> > +         {
> > +           struct target_section *p;
> > +           for (p = record_core_start; p < record_core_end; p++)
> > +             {
> > +               if (offset >= p->addr)
> > +                 {
> > +                   struct record_core_buf_entry *entry;
> > +
> > +                   if (offset >= p->endaddr)
> > +                     continue;
> > +
> > +                   if (offset + len > p->endaddr)
> > +                     len = p->endaddr - offset;
> > +
> > +                   offset -= p->addr;
> > +
> > +                   /* Read readbuf or write writebuf p, offset, len.  */
> > +                   /* Check flags.  */
> > +                   if (p->the_bfd_section->flags & SEC_CONSTRUCTOR
> > +                       || (p->the_bfd_section->flags & SEC_HAS_CONTENTS)
> == 0)
> > +                     {
> > +                       if (readbuf)
> > +                         memset (readbuf, 0, len);
> > +                       return len;
> > +                     }
> > +                   /* Get record_core_buf_entry.  */
> > +                   for (entry = record_core_buf_list; entry;
> > +                        entry = entry->prev)
> > +                     if (entry->p == p)
> > +                       break;
> > +                   if (writebuf)
> > +                     {
> > +                       if (!entry)
> > +                         {
> > +                           /* Add a new entry.  */
> > +                           entry
> > +                             = (struct record_core_buf_entry *)
> > +                                 xmalloc
> > +                                   (sizeof (struct
> record_core_buf_entry));
> > +                           entry->p = p;
> > +                           if (!bfd_malloc_and_get_section (p->bfd,
> > +
> p->the_bfd_section,
> > +                                                            &entry->buf))
> > +                             {
> > +                               xfree (entry);
> > +                               return 0;
> > +                             }
> > +                           entry->prev = record_core_buf_list;
> > +                           record_core_buf_list = entry;
> > +                         }
> > +
> > +                        memcpy (entry->buf + offset, writebuf, (size_t)
> len);
> > +                     }
> > +                   else
> > +                     {
> > +                       if (!entry)
> > +                         return record_beneath_to_xfer_partial
> > +
> (record_beneath_to_xfer_partial_ops,
> > +                                   object, annex, readbuf, writebuf,
> > +                                   offset, len);
> > +
> > +                       memcpy (readbuf, entry->buf + offset, (size_t)
> len);
> > +                     }
> > +
> > +                   return len;
> > +                 }
> > +             }
> > +
> > +           return 0;
> > +         }
> > +       else
> > +         error (_("You can't do that without a process to debug."));
> > +
> > +       return 0;
> > +     }
> > +
> >   return record_beneath_to_xfer_partial
> (record_beneath_to_xfer_partial_ops,
> >                                          object, annex, readbuf, writebuf,
> >                                          offset, len);
> > @@ -1113,6 +1350,15 @@ record_can_execute_reverse (void)
> >   return 1;
> >  }
> >
> > +int
> > +record_has_execution (struct target_ops *ops)
> > +{
> > +  if (record_core)
> > +    return 1;
> > +
> > +  return record_beneath_to_has_execution (ops);
> > +}
> > +
> >  static void
> >  init_record_ops (void)
> >  {
> > @@ -1129,11 +1375,14 @@ init_record_ops (void)
> >   record_ops.to_mourn_inferior = record_mourn_inferior;
> >   record_ops.to_kill = record_kill;
> >   record_ops.to_create_inferior = find_default_create_inferior;
> > +  record_ops.to_fetch_registers = record_fetch_registers;
> > +  record_ops.to_prepare_to_store =
> record_prepare_to_store;
> >   record_ops.to_store_registers = record_store_registers;
> >   record_ops.to_xfer_partial = record_xfer_partial;
> >   record_ops.to_insert_breakpoint =
> record_insert_breakpoint;
> >   record_ops.to_remove_breakpoint =
> record_remove_breakpoint;
> >   record_ops.to_can_execute_reverse =
> record_can_execute_reverse;
> > +  record_ops.to_has_execution = record_has_execution;
> >   record_ops.to_stratum = record_stratum;
> >   record_ops.to_magic = OPS_MAGIC;
> >  }
> > @@ -1154,6 +1403,294 @@ cmd_record_start (char *args, int from_t
> >   execute_command ("target record", from_tty);
> >  }
> >
> > +static void
> > +cmd_record_fd_cleanups (void *recfdp)
> > +{
> > +  int recfd = *(int *) recfdp;
> > +  close (recfd);
> > +}
> > +
> > +static inline void
> > +record_read_dump (char *recfilename, int fildes, void *buf, size_t nbyte)
> > +{
> > +  if (read (fildes, buf, nbyte) != nbyte)
> > +    error (_("Failed to read dump of execution records in '%s'."),
> > +           recfilename);
> > +}
> > +
> > +static inline void
> > +record_write_dump (char *recfilename, int fildes, const void *buf,
> > +                   size_t nbyte)
> > +{
> > +  if (write (fildes, buf, nbyte) != nbyte)
> > +    error (_("Failed to write dump of execution records to '%s'."),
> > +           recfilename);
> > +}
> > +
> > +/* Dump the execution log to a file.  */
> > +
> > +static void
> > +cmd_record_dump (char *args, int from_tty)
> > +{
> > +  char *recfilename, recfilename_buffer[40];
> > +  int recfd;
> > +  struct record_entry *cur_record_list;
> > +  uint32_t magic;
> > +  struct regcache *regcache;
> > +  struct gdbarch *gdbarch;
> > +  struct cleanup *old_cleanups;
> > +  struct cleanup *set_cleanups;
> > +
> > +  if (current_target.to_stratum != record_stratum)
> > +    error (_("Process record is not started.\n"));
> > +
> > +  if (args && *args)
> > +    recfilename = args;
> > +  else
> > +    {
> > +      /* Default corefile name is "gdb_record.PID".  */
> > +      sprintf (recfilename_buffer, "gdb_record.%d", PIDGET
> (inferior_ptid));
> > +      recfilename = recfilename_buffer;
> > +    }
> > +
> > +  /* Open the dump file.  */
> > +  recfd = open (recfilename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
> > +                S_IRUSR | S_IWUSR);
> > +  if (recfd < 0)
> > +    error (_("Failed to open '%s' for dump execution records: %s"),
> > +           recfilename, strerror (errno));
> > +  old_cleanups = make_cleanup (cmd_record_fd_cleanups, &recfd);
> > +
> > +  /* Save the current record entry to "cur_record_list".  */
> > +  cur_record_list = record_list;
> > +
> > +  /* Get the values of regcache and gdbarch.  */
> > +  regcache = get_current_regcache ();
> > +  gdbarch = get_regcache_arch (regcache);
> > +
> > +  /* Disable the GDB operation record.  */
> > +  set_cleanups = record_gdb_operation_disable_set ();
> > +
> > +  /* Write the magic code.  */
> > +  magic = RECORD_FILE_MAGIC;
> > +  record_write_dump (recfilename, recfd, &magic, 4);
> > +
> > +  /* Reverse execute to the begin of record list.  */
> > +  while (1)
> > +    {
> > +      /* Check for beginning and end of log.  */
> > +      if (record_list == &record_first)
> > +        break;
> > +
> > +      record_exec_entry (regcache, gdbarch, record_list);
> > +
> > +      if (record_list->prev)
> > +        record_list = record_list->prev;
> > +    }
> > +
> > +  /* Dump the entries to recfd and forward execute to the end of
> > +     record list.  */
> > +  while (1)
> > +    {
> > +      /* Dump entry.  */
> > +      if (record_list != &record_first)
> > +        {
> > +          uint8_t tmpu8;
> > +          uint64_t tmpu64;
> > +
> > +          tmpu8 = record_list->type;
> > +          record_write_dump (recfilename, recfd, &tmpu8, 1);
> > +
> > +          switch (record_list->type)
> > +            {
> > +            case record_reg: /* reg */
> > +              tmpu64 = record_list->u.reg.num;
> > +              if (BYTE_ORDER == LITTLE_ENDIAN)
> > +                tmpu64 = bswap_64 (tmpu64);
> > +              record_write_dump (recfilename, recfd, &tmpu64, 8);
> > +
> > +              record_write_dump (recfilename, recfd,
> record_list->u.reg.val,
> > +                                 MAX_REGISTER_SIZE);
> > +              break;
> > +            case record_mem: /* mem */
> > +              if
> (!record_list->u.mem.mem_entry_not_accessible)
> > +                {
> > +                  tmpu64 = record_list->u.mem.addr;
> > +                  if (BYTE_ORDER == LITTLE_ENDIAN)
> > +                    tmpu64 = bswap_64 (tmpu64);
> > +                  record_write_dump (recfilename, recfd, &tmpu64, 8);
> > +
> > +                  tmpu64 = record_list->u.mem.len;
> > +                  if (BYTE_ORDER == LITTLE_ENDIAN)
> > +                    tmpu64 = bswap_64 (tmpu64);
> > +                  record_write_dump (recfilename, recfd, &tmpu64, 8);
> > +
> > +                  record_write_dump (recfilename, recfd,
> > +                                     record_list->u.mem.val,
> > +                                     record_list->u.mem.len);
> > +                }
> > +              break;
> > +            }
> > +        }
> > +
> > +      /* Execute entry.  */
> > +      record_exec_entry (regcache, gdbarch, record_list);
> > +
> > +      if (record_list->next)
> > +        record_list = record_list->next;
> > +      else
> > +        break;
> > +    }
> > +
> > +  /* Reverse execute to cur_record_list.  */
> > +  while (1)
> > +    {
> > +      /* Check for beginning and end of log.  */
> > +      if (record_list == cur_record_list)
> > +        break;
> > +
> > +      record_exec_entry (regcache, gdbarch, record_list);
> > +
> > +      if (record_list->prev)
> > +        record_list = record_list->prev;
> > +    }
> > +
> > +  do_cleanups (set_cleanups);
> > +  do_cleanups (old_cleanups);
> > +
> > +  /* Succeeded.  */
> > +  fprintf_filtered (gdb_stdout, _("Saved dump of execution "
> > +                                  "records to `%s'.\n"),
> > +                    recfilename);
> > +}
> > +
> > +/* Load the execution log from a file.  */
> > +
> > +static void
> > +cmd_record_load (char *args, int from_tty)
> > +{
> > +  int recfd;
> > +  uint32_t magic;
> > +  struct cleanup *old_cleanups;
> > +  struct cleanup *old_cleanups2;
> > +  struct record_entry *rec;
> > +  int insn_number = 0;
> > +
> > +  if (current_target.to_stratum != record_stratum)
> > +    {
> > +      cmd_record_start (NULL, from_tty);
> > +      printf_unfiltered (_("Auto start process record.\n"));
> > +    }
> > +
> > +  if (!args || (args && !*args))
> > +    error (_("Argument for filename required.\n"));
> > +
> > +  /* Open the load file.  */
> > +  recfd = open (args, O_RDONLY | O_BINARY);
> > +  if (recfd < 0)
> > +    error (_("Failed to open '%s' for loading execution records: %s"),
> > +           args, strerror (errno));
> > +  old_cleanups = make_cleanup (cmd_record_fd_cleanups, &recfd);
> > +
> > +  /* Check the magic code.  */
> > +  record_read_dump (args, recfd, &magic, 4);
> > +  if (magic != RECORD_FILE_MAGIC)
> > +    error (_("'%s' is not a valid dump of execution records."), args);
> > +
> > +  /* Load the entries in recfd to the record_arch_list_head and
> > +     record_arch_list_tail.  */
> > +  record_arch_list_head = NULL;
> > +  record_arch_list_tail = NULL;
> > +  old_cleanups2 = make_cleanup (record_arch_list_cleanups, 0);
> > +
> > +  while (1)
> > +    {
> > +      int ret;
> > +      uint8_t tmpu8;
> > +      uint64_t tmpu64;
> > +
> > +      ret = read (recfd, &tmpu8, 1);
> > +      if (ret < 0)
> > +        error (_("Failed to read dump of execution records in '%s'."),
> args);
> > +      if (ret == 0)
> > +        break;
> > +
> > +      switch (tmpu8)
> > +        {
> > +        case record_reg: /* reg */
> > +          rec = (struct record_entry *) xmalloc (sizeof (struct
> record_entry));
> > +          rec->u.reg.val = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE);
> > +          rec->prev = NULL;
> > +          rec->next = NULL;
> > +          rec->type = record_reg;
> > +          /* Get num.  */
> > +          record_read_dump (args, recfd, &tmpu64, 8);
> > +          if (BYTE_ORDER == LITTLE_ENDIAN)
> > +            tmpu64 = bswap_64 (tmpu64);
> > +          rec->u.reg.num = tmpu64;
> > +          /* Get val.  */
> > +          record_read_dump (args, recfd, rec->u.reg.val,
> MAX_REGISTER_SIZE);
> > +          record_arch_list_add (rec);
> > +          break;
> > +        case record_mem: /* mem */
> > +          rec = (struct record_entry *) xmalloc (sizeof (struct
> record_entry));
> > +          rec->prev = NULL;
> > +          rec->next = NULL;
> > +          rec->type = record_mem;
> > +          /* Get addr.  */
> > +          record_read_dump (args, recfd, &tmpu64, 8);
> > +          if (BYTE_ORDER == LITTLE_ENDIAN)
> > +            tmpu64 = bswap_64 (tmpu64);
> > +          rec->u.mem.addr = tmpu64;
> > +          /* Get len.  */
> > +          record_read_dump (args, recfd, &tmpu64, 8);
> > +          if (BYTE_ORDER == LITTLE_ENDIAN)
> > +            tmpu64 = bswap_64 (tmpu64);
> > +          rec->u.mem.len = tmpu64;
> > +          rec->u.mem.mem_entry_not_accessible = 0;
> > +          rec->u.mem.val = (gdb_byte *) xmalloc (rec->u.mem.len);
> > +          /* Get val.  */
> > +          record_read_dump (args, recfd, rec->u.mem.val, rec->u.mem.len);
> > +          record_arch_list_add (rec);
> > +          break;
> > +
> > +        case record_end: /* end */
> > +          rec = (struct record_entry *) xmalloc (sizeof (struct
> record_entry));
> > +          rec->prev = NULL;
> > +          rec->next = NULL;
> > +          rec->type = record_end;
> > +          record_arch_list_add (rec);
> > +          insn_number ++;
> > +          break;
> > +
> > +        default:
> > +          error (_("Format of '%s' is not right."), args);
> > +          break;
> > +        }
> > +    }
> > +
> > +  discard_cleanups (old_cleanups2);
> > +
> > +  /* Add record_arch_list_head to the end of record list.  */
> > +  for (rec = record_list; rec->next; rec = rec->next);
> > +  rec->next = record_arch_list_head;
> > +  record_arch_list_head->prev = rec;
> > +
> > +  /* Update record_insn_num and record_insn_max_num.  */
> > +  record_insn_num += insn_number;
> > +  if (record_insn_num > record_insn_max_num)
> > +    {
> > +      record_insn_max_num = record_insn_num;
> > +      warning (_("Auto increase record/replay buffer limit to %d."),
> > +               record_insn_max_num);
> > +    }
> > +
> > +  do_cleanups (old_cleanups);
> > +
> > +  /* Succeeded.  */
> > +  fprintf_filtered (gdb_stdout, "Loaded recfile %s.\n", args);
> > +}
> > +
> >  /* Truncate the record log from the present point
> >    of replay until the end.  */
> >
> > @@ -1204,7 +1741,7 @@ set_record_insn_max_num (char *args, int
> >                           "the first ones?\n"));
> >
> >       while (record_insn_num > record_insn_max_num)
> > -       record_list_release_first ();
> > +       record_list_release_first_insn ();
> >     }
> >  }
> >
> > @@ -1244,6 +1781,8 @@ info_record_command (char *args, int fro
> >  void
> >  _initialize_record (void)
> >  {
> > +  struct cmd_list_element *c;
> > +
> >   /* Init record_first.  */
> >   record_first.prev = NULL;
> >   record_first.next = NULL;
> > @@ -1277,6 +1816,16 @@ _initialize_record (void)
> >                  "info record ", 0, &infolist);
> >   add_alias_cmd ("rec", "record", class_obscure, 1, &infolist);
> >
> > +  c = add_cmd ("dump", class_obscure, cmd_record_dump,
> > +              _("Dump the execution records to a file.\n\
> > +Argument is optional filename.  Default filename is
> > 'gdb_record.<process_id>'."),
> > +               &record_cmdlist);
> > +  set_cmd_completer (c, filename_completer);
> > +  c = add_cmd ("load", class_obscure, cmd_record_load,
> > +              _("Load previously dumped execution records from \
> > +a file given as argument."),
> > +               &record_cmdlist);
> > +  set_cmd_completer (c, filename_completer);
> >
> >   add_cmd ("delete", class_obscure, cmd_record_delete,
> >           _("Delete the rest of execution log and start recording it
> anew."),
> >
> >
> >
> ------------------------------------------------------------------------
> >
> > ---
> >  record.c |  731
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
> >  1 file changed, 640 insertions(+), 91 deletions(-)
> >
> > --- a/record.c
> > +++ b/record.c
> > @@ -23,14 +23,22 @@
> >  #include "gdbthread.h"
> >  #include "event-top.h"
> >  #include "exceptions.h"
> > +#include "completer.h"
> > +#include "arch-utils.h"
> > +#include "gdbcore.h"
> > +#include "exec.h"
> >  #include "record.h"
> >  +#include <byteswap.h>
> >  #include <signal.h>
> > +#include <netinet/in.h>
> >   #define DEFAULT_RECORD_INSN_MAX_NUM    200000
> >   #define RECORD_IS_REPLAY \
> > -     (record_list->next || execution_direction == EXEC_REVERSE)
> > +     (record_list->next || execution_direction == EXEC_REVERSE ||
> record_core)
> > +
> > +#define RECORD_FILE_MAGIC      htonl(0x20090726)
> >   /* These are the core struct of record function.
> >  @@ -78,9 +86,23 @@ struct record_entry
> >   } u;
> >  };
> >  +struct record_core_buf_entry
> > +{
> > +  struct record_core_buf_entry *prev;
> > +  struct target_section *p;
> > +  bfd_byte *buf;
> > +};
> > +
> >  /* This is the debug switch for process record.  */
> >  int record_debug = 0;
> >  +/* Record with core target.  */
> > +static int record_core = 0;
> > +static gdb_byte *record_core_regbuf;
> > +static struct target_section *record_core_start;
> > +static struct target_section *record_core_end;
> > +static struct record_core_buf_entry *record_core_buf_list = NULL;
> > +
> >  /* These list is for execution log.  */
> >  static struct record_entry record_first;
> >  static struct record_entry *record_list = &record_first;
> > @@ -103,6 +125,14 @@ static struct target_ops *record_beneath
> >  static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t,
> >                                         struct target_waitstatus *,
> >                                         int);
> > +static struct target_ops
> *record_beneath_to_fetch_registers_ops;
> > +static void (*record_beneath_to_fetch_registers) (struct
> target_ops *,
> > +                                                  struct regcache *,
> > +                                                 int regno);
> > +static struct target_ops
> *record_beneath_to_store_registers_ops;
> > +static void (*record_beneath_to_store_registers) (struct
> target_ops *,
> > +                                                  struct regcache *,
> > +                                                 int regno);
> >  static struct target_ops
> *record_beneath_to_store_registers_ops;
> >  static void (*record_beneath_to_store_registers) (struct
> target_ops *,
> >                                                   struct regcache *,
> > @@ -119,6 +149,9 @@ static int (*record_beneath_to_insert_br
> >                                                   struct bp_target_info
> *);
> >  static int (*record_beneath_to_remove_breakpoint)
> (struct gdbarch *,
> >                                                   struct bp_target_info
> *);
> > +static struct target_ops
> *record_beneath_to_has_execution_ops;
> > +static int (*record_beneath_to_has_execution) (struct
> target_ops *ops);
> > +static void (*record_beneath_to_prepare_to_store)
> (struct regcache *regcache);
> >   static void
> >  record_list_release (struct record_entry *rec)
> > @@ -169,7 +202,7 @@ record_list_release_next (void)
> >  }
> >   static void
> > -record_list_release_first (void)
> > +record_list_release_first_insn (void)
> >  {
> >   struct record_entry *tmp = NULL;
> >   enum record_type type;
> > @@ -340,30 +373,30 @@ record_check_insn_num (int set_terminal)
> >              if (q)
> >                record_stop_at_limit = 0;
> >              else
> > -               error (_("Process record: inferior program stopped."));
> > +               error (_("Process record: stoped by user."));
> >            }
> >        }
> >     }
> >  }
> >  +static void
> > +record_arch_list_cleanups (void *ignore)
> > +{
> > +  record_list_release (record_arch_list_tail);
> > +}
> > +
> >  /* Before inferior step (when GDB record the running message, inferior
> >    only can step), GDB will call this function to record the values to
> >    record_list.  This function will call gdbarch_process_record to
> >    record the running message of inferior and set them to
> >    record_arch_list, and add it to record_list.  */
> >  -static void
> > -record_message_cleanups (void *ignore)
> > -{
> > -  record_list_release (record_arch_list_tail);
> > -}
> > -
> >  static int
> >  record_message (void *args)
> >  {
> >   int ret;
> >   struct regcache *regcache = args;
> > -  struct cleanup *old_cleanups = make_cleanup (record_message_cleanups,
> 0);
> > +  struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups,
> 0);
> >     record_arch_list_head = NULL;
> >   record_arch_list_tail = NULL;
> > @@ -386,7 +419,7 @@ record_message (void *args)
> >   record_list = record_arch_list_tail;
> >     if (record_insn_num == record_insn_max_num && record_insn_max_num)
> > -    record_list_release_first ();
> > +    record_list_release_first_insn ();
> >   else
> >     record_insn_num++;
> >  @@ -416,6 +449,91 @@ record_gdb_operation_disable_set
> (void)
> >   return old_cleanups;
> >  }
> >  +static inline void
> > +record_exec_entry (struct regcache *regcache, struct gdbarch *gdbarch,
> > +                   struct record_entry *entry)
> > +{
> > +  switch (entry->type)
> > +    {
> > +    case record_reg: /* reg */
> > +      {
> > +        gdb_byte reg[MAX_REGISTER_SIZE];
> > +
> > +        if (record_debug > 1)
> > +          fprintf_unfiltered (gdb_stdlog,
> > +                              "Process record: record_reg %s to "
> > +                              "inferior num = %d.\n",
> > +                              host_address_to_string (entry),
> > +                              entry->u.reg.num);
> > +
> > +        regcache_cooked_read (regcache, entry->u.reg.num, reg);
> > +        regcache_cooked_write (regcache, entry->u.reg.num,
> entry->u.reg.val);
> > +        memcpy (entry->u.reg.val, reg, MAX_REGISTER_SIZE);
> > +      }
> > +      break;
> > +
> > +    case record_mem: /* mem */
> > +      {
> > +        if
> (!record_list->u.mem.mem_entry_not_accessible)
> > +          {
> > +            gdb_byte *mem = alloca (entry->u.mem.len);
> > +
> > +            if (record_debug > 1)
> > +              fprintf_unfiltered (gdb_stdlog,
> > +                                  "Process record: record_mem %s to "
> > +                                  "inferior addr = %s len = %d.\n",
> > +                                  host_address_to_string (entry),
> > +                                  paddress (gdbarch, entry->u.mem.addr),
> > +                                  record_list->u.mem.len);
> > +
> > +            if (target_read_memory (entry->u.mem.addr, mem,
> entry->u.mem.len))
> > +              {
> > +                 if ((execution_direction == EXEC_REVERSE &&
> !record_core)
> > +                     || (execution_direction != EXEC_REVERSE &&
> record_core))
> > +                  {
> > +
> record_list->u.mem.mem_entry_not_accessible = 1;
> > +                    if (record_debug)
> > +                      warning (_("Process record: error reading memory at
> "
> > +                                 "addr = %s len = %d."),
> > +                               paddress (gdbarch, entry->u.mem.addr),
> > +                               entry->u.mem.len);
> > +                  }
> > +                else
> > +                  error (_("Process record: error reading memory at "
> > +                           "addr = %s len = %d."),
> > +                         paddress (gdbarch, entry->u.mem.addr),
> > +                        entry->u.mem.len);
> > +              }
> > +            else
> > +              {
> > +                if (target_write_memory (entry->u.mem.addr,
> entry->u.mem.val,
> > +                                         entry->u.mem.len))
> > +                  {
> > +                     if ((execution_direction == EXEC_REVERSE &&
> !record_core)
> > +                         || (execution_direction != EXEC_REVERSE &&
> record_core))
> > +                      {
> > +
> record_list->u.mem.mem_entry_not_accessible = 1;
> > +                        if (record_debug)
> > +                          warning (_("Process record: error writing
> memory at "
> > +                                     "addr = %s len = %d."),
> > +                                   paddress (gdbarch, entry->u.mem.addr),
> > +                                   entry->u.mem.len);
> > +                      }
> > +                    else
> > +                      error (_("Process record: error writing memory at "
> > +                               "addr = %s len = %d."),
> > +                             paddress (gdbarch, entry->u.mem.addr),
> > +                            entry->u.mem.len);
> > +                  }
> > +              }
> > +
> > +            memcpy (entry->u.mem.val, mem, entry->u.mem.len);
> > +          }
> > +      }
> > +      break;
> > +    }
> > +}
> > +
> >  static void
> >  record_open (char *name, int from_tty)
> >  {
> > @@ -424,8 +542,13 @@ record_open (char *name, int from_tty)
> >   if (record_debug)
> >     fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
> >  +  if (!strcmp (current_target.to_shortname, "core"))
> > +    record_core = 1;
> > +  else
> > +    record_core = 0;
> > +
> >   /* check exec */
> > -  if (!target_has_execution)
> > +  if (!target_has_execution && !record_core)
> >     error (_("Process record: the program is not being run."));
> >   if (non_stop)
> >     error (_("Process record target can't debug inferior in non-stop mode
> "
> > @@ -454,6 +577,8 @@ record_open (char *name, int from_tty)
> >   record_beneath_to_xfer_partial = NULL;
> >   record_beneath_to_insert_breakpoint = NULL;
> >   record_beneath_to_remove_breakpoint = NULL;
> > +  record_beneath_to_has_execution = NULL;
> > +  record_beneath_to_prepare_to_store = NULL;
> >     /* Set the beneath function pointers.  */
> >   for (t = current_target.beneath; t != NULL; t = t->beneath)
> > @@ -468,6 +593,11 @@ record_open (char *name, int from_tty)
> >          record_beneath_to_wait = t->to_wait;
> >          record_beneath_to_wait_ops = t;
> >         }
> > +      if (!record_beneath_to_fetch_registers)
> > +        {
> > +         record_beneath_to_fetch_registers =
> t->to_fetch_registers;
> > +         record_beneath_to_fetch_registers_ops = t;
> > +        }
> >       if (!record_beneath_to_store_registers)
> >         {
> >          record_beneath_to_store_registers =
> t->to_store_registers;
> > @@ -482,19 +612,51 @@ record_open (char *name, int from_tty)
> >        record_beneath_to_insert_breakpoint =
> t->to_insert_breakpoint;
> >       if (!record_beneath_to_remove_breakpoint)
> >        record_beneath_to_remove_breakpoint =
> t->to_remove_breakpoint;
> > +      if (!record_beneath_to_has_execution)
> > +        {
> > +          record_beneath_to_has_execution_ops = t;
> > +         record_beneath_to_has_execution =
> t->to_has_execution;
> > +        }
> > +      if (!record_beneath_to_prepare_to_store)
> > +       record_beneath_to_prepare_to_store =
> t->to_prepare_to_store;
> >     }
> > -  if (!record_beneath_to_resume)
> > +  if (!record_beneath_to_resume && !record_core)
> >     error (_("Process record can't get to_resume."));
> > -  if (!record_beneath_to_wait)
> > +  if (!record_beneath_to_wait && !record_core)
> >     error (_("Process record can't get to_wait."));
> > -  if (!record_beneath_to_store_registers)
> > +  if (!record_beneath_to_fetch_registers)
> > +    error (_("Process record can't get to_fetch_registers."));
> > +  if (!record_beneath_to_store_registers &&
> !record_core)
> >     error (_("Process record can't get to_store_registers."));
> >   if (!record_beneath_to_xfer_partial)
> >     error (_("Process record can't get to_xfer_partial."));
> > -  if (!record_beneath_to_insert_breakpoint)
> > +  if (!record_beneath_to_insert_breakpoint &&
> !record_core)
> >     error (_("Process record can't get to_insert_breakpoint."));
> > -  if (!record_beneath_to_remove_breakpoint)
> > +  if (!record_beneath_to_remove_breakpoint &&
> !record_core)
> >     error (_("Process record can't get to_remove_breakpoint."));
> > +  if (!record_beneath_to_has_execution && !record_core)
> > +    error (_("Process record can't get to_has_execution."));
> > +  if (!record_beneath_to_prepare_to_store &&
> !record_core)
> > +    error (_("Process record can't get to_prepare_to_store."));
> > +
> > +  if (record_core)
> > +    {
> > +      /* Get record_core_regbuf.  */
> > +      struct regcache *regcache = get_current_regcache ();
> > +      int regnum = gdbarch_num_regs (get_regcache_arch (regcache));
> > +      int i;
> > +
> > +      target_fetch_registers (regcache, -1);
> > +      record_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
> > +      for (i = 0; i < regnum; i ++)
> > +        regcache_raw_collect (regcache, i,
> > +                              record_core_regbuf + MAX_REGISTER_SIZE *
> i);
> > +
> > +      /* Get record_core_start and record_core_end.  */
> > +      if (build_section_table (core_bfd, &record_core_start,
> &record_core_end))
> > +        error (_("\"%s\": Can't find sections: %s"),
> > +               bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error
> ()));
> > +    }
> >     push_target (&record_ops);
> >  @@ -507,10 +669,26 @@ record_open (char *name, int from_tty)
> >  static void
> >  record_close (int quitting)
> >  {
> > +  struct record_core_buf_entry *entry;
> > +
> >   if (record_debug)
> >     fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");
> >     record_list_release (record_list);
> > +
> > +  /* Release record_core_regbuf.  */
> > +  xfree (record_core_regbuf);
> > +
> > +  /* Release record_core_buf_list.  */
> > +  if (record_core_buf_list)
> > +    {
> > +      for (entry = record_core_buf_list->prev; entry; entry =
> entry->prev)
> > +        {
> > +          xfree (record_core_buf_list);
> > +          record_core_buf_list = entry;
> > +        }
> > +      record_core_buf_list = NULL;
> > +    }
> >  }
> >   static int record_resume_step = 0;
> > @@ -712,76 +890,9 @@ record_wait (struct target_ops *ops,
> >              break;
> >            }
> >  -         /* Set ptid, register and memory according to record_list.  */
> > -         if (record_list->type == record_reg)
> > -           {
> > -             /* reg */
> > -             gdb_byte reg[MAX_REGISTER_SIZE];
> > -             if (record_debug > 1)
> > -               fprintf_unfiltered (gdb_stdlog,
> > -                                   "Process record: record_reg %s to "
> > -                                   "inferior num = %d.\n",
> > -                                   host_address_to_string (record_list),
> > -                                   record_list->u.reg.num);
> > -             regcache_cooked_read (regcache, record_list->u.reg.num,
> reg);
> > -             regcache_cooked_write (regcache, record_list->u.reg.num,
> > -                                    record_list->u.reg.val);
> > -             memcpy (record_list->u.reg.val, reg, MAX_REGISTER_SIZE);
> > -           }
> > -         else if (record_list->type == record_mem)
> > -           {
> > -             /* mem */
> > -             /* Nothing to do if the entry is flagged not_accessible.  */
> > -             if
> (!record_list->u.mem.mem_entry_not_accessible)
> > -               {
> > -                 gdb_byte *mem = alloca (record_list->u.mem.len);
> > -                 if (record_debug > 1)
> > -                   fprintf_unfiltered (gdb_stdlog,
> > -                                       "Process record: record_mem %s to
> "
> > -                                       "inferior addr = %s len = %d.\n",
> > -                                       host_address_to_string
> (record_list),
> > -                                       paddress (gdbarch,
> > -
> record_list->u.mem.addr),
> > -                                       record_list->u.mem.len);
> > +          record_exec_entry (regcache, gdbarch, record_list);
> >  -                 if (target_read_memory (record_list->u.mem.addr, mem,
> > -                                         record_list->u.mem.len))
> > -                   {
> > -                     if (execution_direction != EXEC_REVERSE)
> > -                       error (_("Process record: error reading memory at
> "
> > -                                "addr = %s len = %d."),
> > -                              paddress (gdbarch,
> record_list->u.mem.addr),
> > -                              record_list->u.mem.len);
> > -                     else
> > -                       /* Read failed -- -                          flag
> entry as not_accessible.  */
> > -
> record_list->u.mem.mem_entry_not_accessible = 1;
> > -                   }
> > -                 else
> > -                   {
> > -                     if (target_write_memory (record_list->u.mem.addr,
> > -                                              record_list->u.mem.val,
> > -                                              record_list->u.mem.len))
> > -                       {
> > -                         if (execution_direction != EXEC_REVERSE)
> > -                           error (_("Process record: error writing memory
> at "
> > -                                    "addr = %s len = %d."),
> > -                                  paddress (gdbarch,
> record_list->u.mem.addr),
> > -                                  record_list->u.mem.len);
> > -                         else
> > -                           /* Write failed -- -
>    flag entry as not_accessible.  */
> > -
> record_list->u.mem.mem_entry_not_accessible = 1;
> > -                       }
> > -                     else
> > -                       {
> > -                         memcpy (record_list->u.mem.val, mem,
> > -                                 record_list->u.mem.len);
> > -                       }
> > -                   }
> > -               }
> > -           }
> > -         else
> > +         if (record_list->type == record_end)
> >            {
> >              if (record_debug > 1)
> >                fprintf_unfiltered (gdb_stdlog,
> > @@ -901,7 +1012,9 @@ record_kill (struct target_ops *ops)
> >     fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n");
> >     unpush_target (&record_ops);
> > -  target_kill ();
> > +
> > +  if (!record_core)
> > +    target_kill ();
> >  }
> >   /* Record registers change (by user or by GDB) to list as an
> instruction.  */
> > @@ -945,15 +1058,58 @@ record_registers_change (struct regcache
> >   record_list = record_arch_list_tail;
> >     if (record_insn_num == record_insn_max_num && record_insn_max_num)
> > -    record_list_release_first ();
> > +    record_list_release_first_insn ();
> >   else
> >     record_insn_num++;
> >  }
> >   static void
> > +record_fetch_registers (struct target_ops *ops, struct regcache
> *regcache,
> > +                        int regno)
> > +{
> > +  if (record_core)
> > +    {
> > +      if (regno < 0)
> > +        {
> > +          int num = gdbarch_num_regs (get_regcache_arch (regcache));
> > +          int i;
> > +
> > +          for (i = 0; i < num; i ++)
> > +            regcache_raw_supply (regcache, i,
> > +                                 record_core_regbuf + MAX_REGISTER_SIZE *
> i);
> > +        }
> > +      else
> > +        regcache_raw_supply (regcache, regno,
> > +                             record_core_regbuf + MAX_REGISTER_SIZE *
> regno);
> > +    }
> > +  else
> > +    record_beneath_to_fetch_registers
> (record_beneath_to_store_registers_ops,
> > +                                       regcache, regno);
> > +}
> > +
> > +static void
> > +record_prepare_to_store (struct regcache *regcache)
> > +{
> > +  if (!record_core)
> > +    record_beneath_to_prepare_to_store (regcache);
> > +}
> > +
> > +static void
> >  record_store_registers (struct target_ops *ops, struct regcache
> *regcache,
> >                         int regno)
> >  {
> > +  if (record_core)
> > +    {
> > +      /* Debug with core.  */
> > +      if (record_gdb_operation_disable)
> > +        regcache_raw_collect (regcache, regno,
> > +
> ...
>
> [Message clipped]


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]