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

Michael Snyder
2009-10-17T17:14:50Z

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

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.

[-- Attachment #2: tmp2b.txt --]
[-- Type: text/plain, Size: 16722 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.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."),