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

Michael Snyder
2009-10-17T01:30:28Z

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

This is part 2 of the sync-up for process record save/restore,
split into parts for easier review.

This patch introduces a core-ops target to record.c, so that
we can use the core target as a target-beneath. We'll do that
when we restore a saved execution log (patch part 3), because
we use core files as the underlying layer of our save format.

[-- Attachment #2: tmp2.txt --]
[-- Type: text/plain, Size: 17000 bytes --]

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.1.c 2009-10-16 14:32:51.000000000 -0700
+++ record.2.c 2009-10-16 15:09:49.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;
@@ -588,6 +604,8 @@ record_gdb_operation_disable_set (void)
return old_cleanups;
}

+/* Execute one instruction from the record log. */
+
static inline void
record_exec_entry (struct regcache *regcache, struct gdbarch *gdbarch,
struct record_entry *entry)
@@ -658,8 +676,60 @@ record_exec_entry (struct regcache *regc
}
}

+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_open (char *name, int from_tty)
+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_1 (char *name, int from_tty)
{
struct target_ops *t;

@@ -680,76 +750,130 @@ record_open (char *name, int from_tty)
error (_("Process record: the current architecture doesn't support "
"record function."));

+ 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."));
+
+ 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;
+
+ //if (strcmp (current_target.to_shortname, "record_core") == 0)
+ //record_load ();
}

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;
@@ -821,7 +945,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)
{
@@ -1320,6 +1444,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)
{
@@ -1449,6 +1757,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."),