Re: [RFA, 2 of 3] save/restore process record, part 2 (core ops target)

Hui Zhu
2009-10-18T07:26:49Z

[-- Attachment #1: Type: text/plain, Size: 20667 bytes --]

patch -p0 < ~/Desktop/tmp2b.diff
patching file record.c
Hunk #2 succeeded at 101 (offset -1 lines).
Hunk #3 succeeded at 127 (offset -2 lines).
Hunk #4 succeeded at 675 (offset -3 lines).
Hunk #5 FAILED at 749.
Hunk #6 succeeded at 940 (offset -4 lines).
Hunk #7 succeeded at 1439 (offset -4 lines).
Hunk #8 succeeded at 1735 (offset -21 lines).
1 out of 8 hunks FAILED -- saving rejects to file record.c.rej

On Sun, Oct 18, 2009 at 01:08, Michael Snyder <msnyder@vmware.com> wrote:
> Eli Zaretskii wrote:
>>>
>>> Date: Fri, 16 Oct 2009 18:24:43 -0700
>>> From: Michael Snyder <msnyder@vmware.com>
>>>
>>> +  if (!tmp_to_resume)
>>> +    error (_("Process record can't get to_resume."));
>>> +  if (!tmp_to_wait)
>>> +    error (_("Process record can't get to_wait."));
>>> +  if (!tmp_to_store_registers)
>>> +    error (_("Process record can't get to_store_registers."));
>>> +  if (!tmp_to_insert_breakpoint)
>>> +    error (_("Process record can't get to_insert_breakpoint."));
>>> +  if (!tmp_to_remove_breakpoint)
>>> +    error (_("Process record can't get to_remove_breakpoint."));
>>
>> Can we rephrase these to be more user-friendly?  As written, this text
>> is okay for debug printouts, but not for user-level error messages,
>> IMO.  (Yes, I know this text was in the old version, but still...)
>
> No problem, see revised diff (attached).  However, in the unlikely
> event that these occur, there won't be anything that the user can
> do about it.
>
>
>>> +  //if (strcmp (current_target.to_shortname, "record_core") == 0)
>>> +  //record_load ();
>>
>> C++-style comments?
>
> It is just to comment out a reference to a function that will not
> be present until the third patch.  I'll take it out.
>
> Thanks for your review.
>
>
> 2009-10-16  Hui Zhu  <teawater@gmail.com>
>            Michael Snyder  <msnyder@vmware.com>
>
>        * record.c (record_core_ops): New ops target vector.
>        (record_core_open_1): New function.  Open core target.
>        (record_open_1): New function.  Open normal process record.
>        (record_open): Call one of the above.
>        (record_close): Allow for both core and normal targets.
>        (record_core_resume): New function.
>        (record_core_kill): New function.
>        (record_core_fetch_registers): New function.
>        (record_core_prepare_to_store): New function.
>        (record_core_store_registers): New function.
>        (record_core_xfer_partial): New function.
>        (record_core_insert_breakpoint): New function.
>        (record_core_remove_breakpoint): New function.
>        (record_core_has_execution): New function.
>        (init_record_core_ops): New function.
>        (_initialize_record): Call init_record_core_ops, add_target.
>
> --- record.1b.c 2009-10-17 09:55:13.000000000 -0700
> +++ record.2.c  2009-10-17 10:03:58.000000000 -0700
> @@ -23,6 +23,8 @@
>  #include "gdbthread.h"
>  #include "event-top.h"
>  #include "exceptions.h"
> +#include "gdbcore.h"
> +#include "exec.h"
>  #include "record.h"
>
>  #include <signal.h>
> @@ -100,6 +102,19 @@ struct record_entry
>  /* This is the debug switch for process record.  */
>  int record_debug = 0;
>
> +struct record_core_buf_entry
> +{
> +  struct record_core_buf_entry *prev;
> +  struct target_section *p;
> +  bfd_byte *buf;
> +};
> +
> +/* Record buf with core target.  */
> +static gdb_byte *record_core_regbuf = NULL;
> +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;
> @@ -114,6 +129,7 @@ static unsigned long long record_insn_co
>
>  /* The target_ops of process record.  */
>  static struct target_ops record_ops;
> +static struct target_ops record_core_ops;
>
>  /* The beneath function pointers.  */
>  static struct target_ops *record_beneath_to_resume_ops;
> @@ -662,8 +678,60 @@ record_exec_insn (struct regcache *regca
>     }
>  }
>
> +static struct target_ops *tmp_to_resume_ops;
> +static void (*tmp_to_resume) (struct target_ops *, ptid_t, int,
> +                             enum target_signal);
> +static struct target_ops *tmp_to_wait_ops;
> +static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t,
> +                             struct target_waitstatus *,
> +                             int);
> +static struct target_ops *tmp_to_store_registers_ops;
> +static void (*tmp_to_store_registers) (struct target_ops *,
> +                                      struct regcache *,
> +                                      int regno);
> +static struct target_ops *tmp_to_xfer_partial_ops;
> +static LONGEST (*tmp_to_xfer_partial) (struct target_ops *ops,
> +                                      enum target_object object,
> +                                      const char *annex,
> +                                      gdb_byte *readbuf,
> +                                      const gdb_byte *writebuf,
> +                                      ULONGEST offset,
> +                                      LONGEST len);
> +static int (*tmp_to_insert_breakpoint) (struct gdbarch *,
> +                                       struct bp_target_info *);
> +static int (*tmp_to_remove_breakpoint) (struct gdbarch *,
> +                                       struct bp_target_info *);
> +
> +/* Open the process record target.  */
> +
> +static void
> +record_core_open_1 (char *name, int from_tty)
> +{
> +  struct regcache *regcache = get_current_regcache ();
> +  int regnum = gdbarch_num_regs (get_regcache_arch (regcache));
> +  int i;
> +
> +  /* Get record_core_regbuf.  */
> +  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))
> +    {
> +      xfree (record_core_regbuf);
> +      record_core_regbuf = NULL;
> +      error (_("\"%s\": Can't find sections: %s"),
> +            bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
> +    }
> +
> +  push_target (&record_core_ops);
> +}
> +
>  static void
> -record_open (char *name, int from_tty)
> +record_open_1 (char *name, int from_tty)
>  {
>   struct target_ops *t;
>
> @@ -684,76 +752,127 @@ record_open (char *name, int from_tty)
>     error (_("Process record: the current architecture doesn't support "
>             "record function."));
>
> +  if (!tmp_to_resume)
> +    error (_("Could not find 'to_resume' method on the target stack."));
> +  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."));
> +  if (!tmp_to_insert_breakpoint)
> +    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."));
> +
> +  push_target (&record_ops);
> +}
> +
> +static void
> +record_open (char *name, int from_tty)
> +{
> +  struct target_ops *t;
> +
> +  if (record_debug)
> +    fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
> +
>   /* Check if record target is already running.  */
>   if (current_target.to_stratum == record_stratum)
>     error (_("Process record target already running.  Use \"record stop\" to
> "
>              "stop record target first."));
>
> -  /*Reset the beneath function pointers.  */
> -  record_beneath_to_resume = NULL;
> -  record_beneath_to_wait = NULL;
> -  record_beneath_to_store_registers = NULL;
> -  record_beneath_to_xfer_partial = NULL;
> -  record_beneath_to_insert_breakpoint = NULL;
> -  record_beneath_to_remove_breakpoint = NULL;
> +  /* Reset the tmp beneath pointers.  */
> +  tmp_to_resume_ops = NULL;
> +  tmp_to_resume = NULL;
> +  tmp_to_wait_ops = NULL;
> +  tmp_to_wait = NULL;
> +  tmp_to_store_registers_ops = NULL;
> +  tmp_to_store_registers = NULL;
> +  tmp_to_xfer_partial_ops = NULL;
> +  tmp_to_xfer_partial = NULL;
> +  tmp_to_insert_breakpoint = NULL;
> +  tmp_to_remove_breakpoint = NULL;
>
>   /* Set the beneath function pointers.  */
>   for (t = current_target.beneath; t != NULL; t = t->beneath)
>     {
> -      if (!record_beneath_to_resume)
> +      if (!tmp_to_resume)
>         {
> -         record_beneath_to_resume = t->to_resume;
> -         record_beneath_to_resume_ops = t;
> +         tmp_to_resume = t->to_resume;
> +         tmp_to_resume_ops = t;
>         }
> -      if (!record_beneath_to_wait)
> +      if (!tmp_to_wait)
>         {
> -         record_beneath_to_wait = t->to_wait;
> -         record_beneath_to_wait_ops = t;
> +         tmp_to_wait = t->to_wait;
> +         tmp_to_wait_ops = t;
>         }
> -      if (!record_beneath_to_store_registers)
> +      if (!tmp_to_store_registers)
>         {
> -         record_beneath_to_store_registers = t->to_store_registers;
> -         record_beneath_to_store_registers_ops = t;
> +         tmp_to_store_registers = t->to_store_registers;
> +         tmp_to_store_registers_ops = t;
>         }
> -      if (!record_beneath_to_xfer_partial)
> +      if (!tmp_to_xfer_partial)
>         {
> -         record_beneath_to_xfer_partial = t->to_xfer_partial;
> -         record_beneath_to_xfer_partial_ops = t;
> +         tmp_to_xfer_partial = t->to_xfer_partial;
> +         tmp_to_xfer_partial_ops = t;
>         }
> -      if (!record_beneath_to_insert_breakpoint)
> -       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 (!tmp_to_insert_breakpoint)
> +       tmp_to_insert_breakpoint = t->to_insert_breakpoint;
> +      if (!tmp_to_remove_breakpoint)
> +       tmp_to_remove_breakpoint = t->to_remove_breakpoint;
>     }
> -  if (!record_beneath_to_resume)
> -    error (_("Process record can't get to_resume."));
> -  if (!record_beneath_to_wait)
> -    error (_("Process record can't get to_wait."));
> -  if (!record_beneath_to_store_registers)
> -    error (_("Process record can't get to_store_registers."));
> -  if (!record_beneath_to_xfer_partial)
> +  if (!tmp_to_xfer_partial)
>     error (_("Process record can't get to_xfer_partial."));
> -  if (!record_beneath_to_insert_breakpoint)
> -    error (_("Process record can't get to_insert_breakpoint."));
> -  if (!record_beneath_to_remove_breakpoint)
> -    error (_("Process record can't get to_remove_breakpoint."));
>
> -  push_target (&record_ops);
> +  if (current_target.to_stratum == core_stratum)
> +    record_core_open_1 (name, from_tty);
> +  else
> +    record_open_1 (name, from_tty);
>
>   /* Reset */
>   record_insn_num = 0;
>   record_insn_count = 0;
>   record_list = &record_first;
>   record_list->next = NULL;
> +
> +  /* Set the tmp beneath pointers to beneath pointers.  */
> +  record_beneath_to_resume_ops = tmp_to_resume_ops;
> +  record_beneath_to_resume = tmp_to_resume;
> +  record_beneath_to_wait_ops = tmp_to_wait_ops;
> +  record_beneath_to_wait = tmp_to_wait;
> +  record_beneath_to_store_registers_ops = tmp_to_store_registers_ops;
> +  record_beneath_to_store_registers = tmp_to_store_registers;
> +  record_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops;
> +  record_beneath_to_xfer_partial = tmp_to_xfer_partial;
> +  record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
> +  record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
>  }
>
>  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.  */
> +  if (record_core_regbuf)
> +    {
> +      xfree (record_core_regbuf);
> +      record_core_regbuf = NULL;
> +    }
> +
> +  /* 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;
> @@ -825,7 +944,7 @@ record_wait (struct target_ops *ops,
>                        "record_resume_step = %d\n",
>                        record_resume_step);
>
> -  if (!RECORD_IS_REPLAY)
> +  if (!RECORD_IS_REPLAY && ops != &record_core_ops)
>     {
>       if (record_resume_error)
>        {
> @@ -1324,6 +1443,190 @@ init_record_ops (void)
>  }
>
>  static void
> +record_core_resume (struct target_ops *ops, ptid_t ptid, int step,
> +                    enum target_signal signal)
> +{
> +  record_resume_step = step;
> +}
> +
> +static void
> +record_core_kill (struct target_ops *ops)
> +{
> +  if (record_debug)
> +    fprintf_unfiltered (gdb_stdlog, "Process record: record_core_kill\n");
> +
> +  unpush_target (&record_core_ops);
> +}
> +
> +static void
> +record_core_fetch_registers (struct target_ops *ops,
> +                             struct regcache *regcache,
> +                             int regno)
> +{
> +  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);
> +}
> +
> +static void
> +record_core_prepare_to_store (struct regcache *regcache)
> +{
> +}
> +
> +static void
> +record_core_store_registers (struct target_ops *ops,
> +                             struct regcache *regcache,
> +                             int regno)
> +{
> +  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."));
> +}
> +
> +static LONGEST
> +record_core_xfer_partial (struct target_ops *ops, enum target_object
> object,
> +                         const char *annex, gdb_byte *readbuf,
> +                         const gdb_byte *writebuf, ULONGEST offset,
> +                          LONGEST len)
> +{
> +   if (object == TARGET_OBJECT_MEMORY)
> +     {
> +       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 -1;
> +         }
> +       else
> +         error (_("You can't do that without a process to debug."));
> +     }
> +
> +  return record_beneath_to_xfer_partial
> (record_beneath_to_xfer_partial_ops,
> +                                         object, annex, readbuf, writebuf,
> +                                         offset, len);
> +}
> +
> +static int
> +record_core_insert_breakpoint (struct gdbarch *gdbarch,
> +                              struct bp_target_info *bp_tgt)
> +{
> +  return 0;
> +}
> +
> +static int
> +record_core_remove_breakpoint (struct gdbarch *gdbarch,
> +                              struct bp_target_info *bp_tgt)
> +{
> +  return 0;
> +}
> +
> +int
> +record_core_has_execution (struct target_ops *ops)
> +{
> +  return 1;
> +}
> +
> +static void
> +init_record_core_ops (void)
> +{
> +  record_core_ops.to_shortname = "record_core";
> +  record_core_ops.to_longname = "Process record and replay target";
> +  record_core_ops.to_doc =
> +    "Log program while executing and replay execution from log.";
> +  record_core_ops.to_open = record_open;
> +  record_core_ops.to_close = record_close;
> +  record_core_ops.to_resume = record_core_resume;
> +  record_core_ops.to_wait = record_wait;
> +  record_core_ops.to_kill = record_core_kill;
> +  record_core_ops.to_fetch_registers = record_core_fetch_registers;
> +  record_core_ops.to_prepare_to_store = record_core_prepare_to_store;
> +  record_core_ops.to_store_registers = record_core_store_registers;
> +  record_core_ops.to_xfer_partial = record_core_xfer_partial;
> +  record_core_ops.to_insert_breakpoint = record_core_insert_breakpoint;
> +  record_core_ops.to_remove_breakpoint = record_core_remove_breakpoint;
> +  record_core_ops.to_can_execute_reverse = record_can_execute_reverse;
> +  record_core_ops.to_has_execution = record_core_has_execution;
> +  record_core_ops.to_stratum = record_stratum;
> +  record_core_ops.to_magic = OPS_MAGIC;
> +}
> +
> +static void
>  show_record_debug (struct ui_file *file, int from_tty,
>                   struct cmd_list_element *c, const char *value)
>  {
> @@ -1453,6 +1756,8 @@ _initialize_record (void)
>
>   init_record_ops ();
>   add_target (&record_ops);
> +  init_record_core_ops ();
> +  add_target (&record_core_ops);
>
>   add_setshow_zinteger_cmd ("record", no_class, &record_debug,
>                            _("Set debugging of record/replay feature."),
>
>

[-- Attachment #2: record.c.rej --]
[-- Type: application/octet-stream, Size: 6826 bytes --]

*************** record_open (char *name, int from_tty)
*** 681,756 ****
error (_("Process record: the current architecture doesn't support "
"record function."));

/* Check if record target is already running. */
if (current_target.to_stratum == record_stratum)
error (_("Process record target already running. Use \"record stop\" to "
"stop record target first."));

- /*Reset the beneath function pointers. */
- record_beneath_to_resume = NULL;
- record_beneath_to_wait = NULL;
- record_beneath_to_store_registers = NULL;
- record_beneath_to_xfer_partial = NULL;
- record_beneath_to_insert_breakpoint = NULL;
- record_beneath_to_remove_breakpoint = NULL;

/* Set the beneath function pointers. */
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
- if (!record_beneath_to_resume)
{
- record_beneath_to_resume = t->to_resume;
- record_beneath_to_resume_ops = t;
}
- if (!record_beneath_to_wait)
{
- record_beneath_to_wait = t->to_wait;
- record_beneath_to_wait_ops = t;
}
- if (!record_beneath_to_store_registers)
{
- record_beneath_to_store_registers = t->to_store_registers;
- record_beneath_to_store_registers_ops = t;
}
- if (!record_beneath_to_xfer_partial)
{
- record_beneath_to_xfer_partial = t->to_xfer_partial;
- record_beneath_to_xfer_partial_ops = t;
}
- if (!record_beneath_to_insert_breakpoint)
- 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_resume)
- error (_("Process record can't get to_resume."));
- if (!record_beneath_to_wait)
- error (_("Process record can't get to_wait."));
- if (!record_beneath_to_store_registers)
- 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)
- error (_("Process record can't get to_insert_breakpoint."));
- if (!record_beneath_to_remove_breakpoint)
- error (_("Process record can't get to_remove_breakpoint."));

- push_target (&record_ops);

/* Reset */
record_insn_num = 0;
record_insn_count = 0;
record_list = &record_first;
record_list->next = NULL;
}

static void
record_close (int quitting)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");

record_list_release (record_list);
}

static int record_resume_step = 0;
--- 749,875 ----
error (_("Process record: the current architecture doesn't support "
"record function."));

+ if (!tmp_to_resume)
+ error (_("Could not find 'to_resume' method on the target stack."));
+ 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."));
+ if (!tmp_to_insert_breakpoint)
+ 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."));
+
+ push_target (&record_ops);
+ }
+
+ static void
+ record_open (char *name, int from_tty)
+ {
+ struct target_ops *t;
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
+
/* Check if record target is already running. */
if (current_target.to_stratum == record_stratum)
error (_("Process record target already running. Use \"record stop\" to "
"stop record target first."));

+ /* Reset the tmp beneath pointers. */
+ tmp_to_resume_ops = NULL;
+ tmp_to_resume = NULL;
+ tmp_to_wait_ops = NULL;
+ tmp_to_wait = NULL;
+ tmp_to_store_registers_ops = NULL;
+ tmp_to_store_registers = NULL;
+ tmp_to_xfer_partial_ops = NULL;
+ tmp_to_xfer_partial = NULL;
+ tmp_to_insert_breakpoint = NULL;
+ tmp_to_remove_breakpoint = NULL;

/* Set the beneath function pointers. */
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
+ if (!tmp_to_resume)
{
+ tmp_to_resume = t->to_resume;
+ tmp_to_resume_ops = t;
}
+ if (!tmp_to_wait)
{
+ tmp_to_wait = t->to_wait;
+ tmp_to_wait_ops = t;
}
+ if (!tmp_to_store_registers)
{
+ tmp_to_store_registers = t->to_store_registers;
+ tmp_to_store_registers_ops = t;
}
+ if (!tmp_to_xfer_partial)
{
+ tmp_to_xfer_partial = t->to_xfer_partial;
+ tmp_to_xfer_partial_ops = t;
}
+ if (!tmp_to_insert_breakpoint)
+ tmp_to_insert_breakpoint = t->to_insert_breakpoint;
+ if (!tmp_to_remove_breakpoint)
+ tmp_to_remove_breakpoint = t->to_remove_breakpoint;
}
+ if (!tmp_to_xfer_partial)
error (_("Process record can't get to_xfer_partial."));

+ if (current_target.to_stratum == core_stratum)
+ record_core_open_1 (name, from_tty);
+ else
+ record_open_1 (name, from_tty);

/* Reset */
record_insn_num = 0;
record_insn_count = 0;
record_list = &record_first;
record_list->next = NULL;
+
+ /* Set the tmp beneath pointers to beneath pointers. */
+ record_beneath_to_resume_ops = tmp_to_resume_ops;
+ record_beneath_to_resume = tmp_to_resume;
+ record_beneath_to_wait_ops = tmp_to_wait_ops;
+ record_beneath_to_wait = tmp_to_wait;
+ record_beneath_to_store_registers_ops = tmp_to_store_registers_ops;
+ record_beneath_to_store_registers = tmp_to_store_registers;
+ record_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops;
+ record_beneath_to_xfer_partial = tmp_to_xfer_partial;
+ record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
+ record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
}

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. */
+ if (record_core_regbuf)
+ {
+ xfree (record_core_regbuf);
+ record_core_regbuf = NULL;
+ }
+
+ /* 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;