Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 1/4] move core_bfd to program space
  2014-07-18 19:27 [PATCH 0/4] baby step toward multi-target Tom Tromey
@ 2014-07-18 19:27 ` Tom Tromey
  2014-07-18 19:27 ` [PATCH 2/4] simplify target_is_pushed Tom Tromey
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Tom Tromey @ 2014-07-18 19:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This moves the core_bfd global to be a field of the program space.  It
then replaces core_bfd with a macro to avoid a massive patch -- the
same approach taken for various other program space fields.

This patch is a basic transformation for eventual multi-target work.

2014-07-18  Tom Tromey  <tromey@redhat.com>

	* corefile.c (core_bfd): Remove.
	* gdbcore.h (core_bfd): Now a macro.
	* progspace.h (struct program_space) <cbfd>: New field.
---
 gdb/ChangeLog   | 6 ++++++
 gdb/corefile.c  | 4 ----
 gdb/gdbcore.h   | 2 +-
 gdb/progspace.h | 3 +++
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/gdb/corefile.c b/gdb/corefile.c
index 8a96d75..6b62e13 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -57,10 +57,6 @@ static hook_type *exec_file_extra_hooks;	/* Array of additional
 						   hooks.  */
 static int exec_file_hook_count = 0;		/* Size of array.  */
 
-/* Binary file diddling handle for the core file.  */
-
-bfd *core_bfd = NULL;
-
 /* corelow.c target.  It is never NULL after GDB initialization.  */
 
 struct target_ops *core_target;
diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h
index 3f81791..c48067e 100644
--- a/gdb/gdbcore.h
+++ b/gdb/gdbcore.h
@@ -138,7 +138,7 @@ extern void specify_exec_file_hook (void (*hook) (char *filename));
 
 /* Binary File Diddler for the core file.  */
 
-extern bfd *core_bfd;
+#define core_bfd (current_program_space->cbfd)
 
 extern struct target_ops *core_target;
 
diff --git a/gdb/progspace.h b/gdb/progspace.h
index 08e04eb..852d38a 100644
--- a/gdb/progspace.h
+++ b/gdb/progspace.h
@@ -206,6 +206,9 @@ struct program_space
        This is so we can properly report solib changes to the user.  */
     VEC (char_ptr) *deleted_solibs;
 
+    /* Binary file diddling handle for the core file.  */
+    bfd *cbfd;
+
     /* Per pspace data-pointers required by other GDB modules.  */
     REGISTRY_FIELDS;
   };
-- 
1.9.3


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 0/4] baby step toward multi-target
@ 2014-07-18 19:27 Tom Tromey
  2014-07-18 19:27 ` [PATCH 1/4] move core_bfd to program space Tom Tromey
                   ` (5 more replies)
  0 siblings, 6 replies; 17+ messages in thread
From: Tom Tromey @ 2014-07-18 19:27 UTC (permalink / raw)
  To: gdb-patches

My multi-target branch is basically dead, I think, mostly due to heavy
conflicts with all the other target changes that have happened in the
meantime.  However recently I realized that there is a less invasive
way to achieve many of the same effects, and a way to salvage some of
the smaller cleanups done there.

In particular on the branch I attempted to split target_ops into a
vtable-like object and a target state object.  As you might imagine
this patch touches a large amount of code and is hard both to keep up
to date, and to test.

This little series, on the other hand, takes a less invasive approach.
The idea here is that rather than doing a huge target_ops split,
instead just sometimes make copies of the target_ops when pushing.
This lets the copies keep their own state; copies are needed in the
long run because multiple target stacks will be active and a given
target_ops only has one "beneath" pointer.

Here corelow is used as the example of how to do a conversion.
There's a bit of cleanup and infrastructure initially, and then the
final patch moves the corelow global state into a new subclass of
target_ops, which is instantiated and pushed.

If this approach seems reasonable then it's not too hard to pull over
some of the other target conversions from the branch.

This series also shows the spots to change if you want to make the
debug target wrap each stratum in the target stack -- each wrapping
debug target would be to_xclose-ish, and spots like target_is_pushed
would be taught to unwrap.

Built and regtested on x86-64 Fedora 20.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 2/4] simplify target_is_pushed
  2014-07-18 19:27 [PATCH 0/4] baby step toward multi-target Tom Tromey
  2014-07-18 19:27 ` [PATCH 1/4] move core_bfd to program space Tom Tromey
@ 2014-07-18 19:27 ` Tom Tromey
  2014-07-29 13:22   ` Joel Brobecker
  2014-07-18 19:45 ` [PATCH 3/4] add to_identity Tom Tromey
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 17+ messages in thread
From: Tom Tromey @ 2014-07-18 19:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

While working on target_is_pushed, I noticed that it is written in a
strange way.  The code currently keeps an extra indirection, where a
simple linked list traversal is all that is needed.  It seems likely
this was done by copying and pasting other code.  However, there is no
reason to do this and the more obvious code is simpler to reason
about.  So, this patch change the implementation.

2014-07-18  Tom Tromey  <tromey@redhat.com>

	* target.c (target_is_pushed): Simplify.
---
 gdb/ChangeLog | 4 ++++
 gdb/target.c  | 6 +++---
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/gdb/target.c b/gdb/target.c
index b9310cf..3d28f85 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -654,7 +654,7 @@ pop_all_targets (void)
 int
 target_is_pushed (struct target_ops *t)
 {
-  struct target_ops **cur;
+  struct target_ops *cur;
 
   /* Check magic number.  If wrong, it probably means someone changed
      the struct definition, but not all the places that initialize one.  */
@@ -667,8 +667,8 @@ target_is_pushed (struct target_ops *t)
 		      _("failed internal consistency check"));
     }
 
-  for (cur = &target_stack; (*cur) != NULL; cur = &(*cur)->beneath)
-    if (*cur == t)
+  for (cur = target_stack; cur != NULL; cur = cur->beneath)
+    if (cur == t)
       return 1;
 
   return 0;
-- 
1.9.3


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 3/4] add to_identity
  2014-07-18 19:27 [PATCH 0/4] baby step toward multi-target Tom Tromey
  2014-07-18 19:27 ` [PATCH 1/4] move core_bfd to program space Tom Tromey
  2014-07-18 19:27 ` [PATCH 2/4] simplify target_is_pushed Tom Tromey
@ 2014-07-18 19:45 ` Tom Tromey
  2014-07-29 14:56   ` Joel Brobecker
  2014-07-18 20:44 ` [PATCH 4/4] convert corelow to to_xclose Tom Tromey
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 17+ messages in thread
From: Tom Tromey @ 2014-07-18 19:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

Right now a target_ops has an odd sense of identity.

Most times some identity is needed, a pointer to a static object is
passed in.  For example, calls to unpush_target generally work like
this:

    unpush_target (&exec_ops);

Conceptually this is a kind of "instanceof" checking.

Now, consider this with "to_xclose" targets.  In this case the
target_ops is allocated on the heap and there's no good way to talk
about the identity.  Code could remember the pointer, of course, but
this usually just begs the question.

For example in a to_open implementation it is reasonably normal to
check target_is_pushed and then do nothing if the target is pushed.
However, there's no reasonable way way to do this with a to_xclose
target.

This patch introduces a to_identity field that just points to the
"prototype" implementation of a target_ops.  This lets us convert
targets to to_xclose without difficulty.

2014-07-18  Tom Tromey  <tromey@redhat.com>

	* bfd-target.c (target_bfd_reopen): Set to_identity.
	* target.c (complete_target_initialization): Set to_identity.
	(unpush_target): Check to_identity.  Call target_close on the real
	target.
	(target_is_pushed): Check to_identity.
	* target.h (struct target_ops) <to_identity>: New field.
---
 gdb/ChangeLog    | 9 +++++++++
 gdb/bfd-target.c | 1 +
 gdb/target.c     | 8 +++++---
 gdb/target.h     | 6 ++++++
 4 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/gdb/bfd-target.c b/gdb/bfd-target.c
index 519d5e7..d392762 100644
--- a/gdb/bfd-target.c
+++ b/gdb/bfd-target.c
@@ -98,6 +98,7 @@ target_bfd_reopen (struct bfd *abfd)
   t->to_xclose = target_bfd_xclose;
   t->to_data = data;
   t->to_magic = OPS_MAGIC;
+  t->to_identity = t;
 
   return t;
 }
diff --git a/gdb/target.c b/gdb/target.c
index 3d28f85..6a10c04 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -342,6 +342,8 @@ complete_target_initialization (struct target_ops *t)
   gdb_assert (t->to_can_run == NULL || (t->to_can_async_p != NULL
 					&& t->to_supports_non_stop != NULL));
 
+  t->to_identity = t;
+
   install_delegators (t);
 }
 
@@ -602,7 +604,7 @@ unpush_target (struct target_ops *t)
 
   for (cur = &target_stack; (*cur) != NULL; cur = &(*cur)->beneath)
     {
-      if ((*cur) == t)
+      if ((*cur) == t || (*cur)->to_identity == t)
 	break;
     }
 
@@ -621,7 +623,7 @@ unpush_target (struct target_ops *t)
   /* Finally close the target.  Note we do this after unchaining, so
      any target method calls from within the target_close
      implementation don't end up in T anymore.  */
-  target_close (t);
+  target_close (tmp);
 
   return 1;
 }
@@ -668,7 +670,7 @@ target_is_pushed (struct target_ops *t)
     }
 
   for (cur = target_stack; cur != NULL; cur = cur->beneath)
-    if (cur == t)
+    if (cur == t || cur->to_identity == t)
       return 1;
 
   return 0;
diff --git a/gdb/target.h b/gdb/target.h
index 92572ff..58c7b30 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1135,6 +1135,12 @@ struct target_ops
     void (*to_done_generating_core) (struct target_ops *)
       TARGET_DEFAULT_IGNORE ();
 
+    /* This points to an "original" target_ops from which a particular
+       instance may have been cloned.  This is usedful if a to_xclose
+       target clones some other target_ops, but still wants to call
+       target_is_pushed or unpush_target.  */
+    struct target_ops *to_identity;
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
-- 
1.9.3


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 4/4] convert corelow to to_xclose
  2014-07-18 19:27 [PATCH 0/4] baby step toward multi-target Tom Tromey
                   ` (2 preceding siblings ...)
  2014-07-18 19:45 ` [PATCH 3/4] add to_identity Tom Tromey
@ 2014-07-18 20:44 ` Tom Tromey
  2014-07-29 15:11 ` [PATCH 0/4] baby step toward multi-target Pedro Alves
  2014-08-10 20:02 ` Doug Evans
  5 siblings, 0 replies; 17+ messages in thread
From: Tom Tromey @ 2014-07-18 20:44 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This converts corelow to be a to_xclose target.  It moves all the
corelow-related globals into a new subclass of target_ops and arranges
for core_open to push an instance of this.

This is preparatory work for multi-target.  After this patch, corelow
doesn't rely on global state and multiple instances can readily be
instantiated.

2014-07-18  Tom Tromey  <tromey@redhat.com>

	* corelow.c (struct core_target_ops_with_data): New struct.
	(core_vec, core_gdbarch, core_data): Remove.  Now fields of
	core_target_ops_with_data.
	(sniff_core_bfd): Add core_gdbarch parameter.
	(get_core_target_ops): New function.
	(core_xclose): Rename from core_close.  Update for
	core_target_ops_with_data.  Free the target.
	(core_close_cleanup): Rename parameter.  Update.
	(core_open): Use TARGET_NEW.  Update.
	(get_core_register_section, get_core_registers, core_files_info)
	(core_xfer_partial, core_read_description, core_pid_to_str): Use
	get_core_target_ops.  Update.
	(init_core_ops): Set to_xclose, not to_close.
	* target.c (allocate_target): New function.
	* target.h (allocate_target): Declare.
	(TARGET_NEW): New macro.
---
 gdb/ChangeLog |  19 +++++++
 gdb/corelow.c | 175 +++++++++++++++++++++++++++++++++++-----------------------
 gdb/target.c  |  20 +++++++
 gdb/target.h  |  15 +++++
 4 files changed, 160 insertions(+), 69 deletions(-)

diff --git a/gdb/corelow.c b/gdb/corelow.c
index 1775a66..212665d 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -60,34 +60,39 @@
 
 static struct core_fns *core_file_fns = NULL;
 
-/* The core_fns for a core file handler that is prepared to read the
-   core file currently open on core_bfd.  */
+/* A subclass of target_ops that also holds data for a core
+   target.  */
 
-static struct core_fns *core_vec = NULL;
+struct core_target_ops_with_data
+{
+  /* The base class.  */
 
-/* FIXME: kettenis/20031023: Eventually this variable should
-   disappear.  */
+  struct target_ops base;
 
-static struct gdbarch *core_gdbarch = NULL;
+  /* The core_fns for a core file handler that is prepared to read the
+     core file currently open on core_bfd.  */
 
-/* Per-core data.  Currently, only the section table.  Note that these
-   target sections are *not* mapped in the current address spaces' set
-   of target sections --- those should come only from pure executable
-   or shared library bfds.  The core bfd sections are an
-   implementation detail of the core target, just like ptrace is for
-   unix child targets.  */
-static struct target_section_table *core_data;
+  struct core_fns *core_vec;
 
-static void core_files_info (struct target_ops *);
+  /* FIXME: kettenis/20031023: Eventually this variable should
+     disappear.  */
+
+  struct gdbarch *core_gdbarch;
+
+  /* The section table.  Note that these target sections are *not*
+     mapped in the current address spaces' set of target sections ---
+     those should come only from pure executable or shared library
+     bfds.  The core bfd sections are an implementation detail of the
+     core target, just like ptrace is for unix child targets.  */
+  struct target_section_table core_data;
+};
 
-static struct core_fns *sniff_core_bfd (bfd *);
+static void core_files_info (struct target_ops *);
 
 static int gdb_check_format (bfd *);
 
 static void core_open (char *, int);
 
-static void core_close (struct target_ops *self);
-
 static void core_close_cleanup (void *ignore);
 
 static void add_to_thread_list (bfd *, asection *, void *);
@@ -131,7 +136,7 @@ default_core_sniffer (struct core_fns *our_fns, bfd *abfd)
    selected.  */
 
 static struct core_fns *
-sniff_core_bfd (bfd *abfd)
+sniff_core_bfd (bfd *abfd, struct gdbarch *core_gdbarch)
 {
   struct core_fns *cf;
   struct core_fns *yummy = NULL;
@@ -189,12 +194,35 @@ gdb_check_format (bfd *abfd)
   return (0);
 }
 
+\f
+
+/* Return the core_target_ops_with_data for the current target stack,
+   if any.  */
+
+static struct core_target_ops_with_data *
+get_core_target_ops (void)
+{
+  struct target_ops *targ = find_target_at (process_stratum);
+
+  if (targ == NULL || targ->to_identity != &core_ops)
+    return NULL;
+
+  /* Downcast.  */
+  return (struct core_target_ops_with_data *) targ;
+}
+
 /* Discard all vestiges of any previous core file and mark data and
    stack spaces as empty.  */
 
 static void
-core_close (struct target_ops *self)
+core_xclose (struct target_ops *self)
 {
+  /* Downcast.  */
+  struct core_target_ops_with_data *cops
+    = (struct core_target_ops_with_data *) self;
+
+  gdb_assert (self->to_identity == &core_ops);
+
   if (core_bfd)
     {
       int pid = ptid_get_pid (inferior_ptid);
@@ -207,24 +235,18 @@ core_close (struct target_ops *self)
          comments in clear_solib in solib.c.  */
       clear_solib ();
 
-      if (core_data)
-	{
-	  xfree (core_data->sections);
-	  xfree (core_data);
-	  core_data = NULL;
-	}
-
       gdb_bfd_unref (core_bfd);
       core_bfd = NULL;
     }
-  core_vec = NULL;
-  core_gdbarch = NULL;
+
+  xfree (cops->core_data.sections);
+  xfree (cops);
 }
 
 static void
-core_close_cleanup (void *ignore)
+core_close_cleanup (void *arg)
 {
-  core_close (NULL);
+  core_xclose (arg);
 }
 
 /* Look for sections whose names start with `.reg/' so that we can
@@ -285,6 +307,7 @@ core_open (char *filename, int from_tty)
   int scratch_chan;
   int flags;
   volatile struct gdb_exception except;
+  struct core_target_ops_with_data *cops;
 
   target_preopen (from_tty);
   if (!filename)
@@ -340,21 +363,21 @@ core_open (char *filename, int from_tty)
   do_cleanups (old_chain);
   unpush_target (&core_ops);
   core_bfd = temp_bfd;
-  old_chain = make_cleanup (core_close_cleanup, 0 /*ignore*/);
 
-  core_gdbarch = gdbarch_from_bfd (core_bfd);
+  cops = TARGET_NEW (struct core_target_ops_with_data, &core_ops);
+  old_chain = make_cleanup (core_close_cleanup, cops);
+
+  cops->core_gdbarch = gdbarch_from_bfd (core_bfd);
 
   /* Find a suitable core file handler to munch on core_bfd */
-  core_vec = sniff_core_bfd (core_bfd);
+  cops->core_vec = sniff_core_bfd (core_bfd, cops->core_gdbarch);
 
   validate_files ();
 
-  core_data = XCNEW (struct target_section_table);
-
   /* Find the data section */
   if (build_section_table (core_bfd,
-			   &core_data->sections,
-			   &core_data->sections_end))
+			   &cops->core_data.sections,
+			   &cops->core_data.sections_end))
     error (_("\"%s\": Can't find sections: %s"),
 	   bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
 
@@ -365,7 +388,7 @@ core_open (char *filename, int from_tty)
   if (!exec_bfd)
     set_gdbarch_from_file (core_bfd);
 
-  push_target (&core_ops);
+  push_target (&cops->base);
   discard_cleanups (old_chain);
 
   /* Do this before acknowledging the inferior, so if
@@ -410,7 +433,7 @@ core_open (char *filename, int from_tty)
 	switch_to_thread (thread->ptid);
     }
 
-  post_create_inferior (&core_ops, from_tty);
+  post_create_inferior (&cops->base, from_tty);
 
   /* Now go through the target stack looking for threads since there
      may be a thread_stratum target loaded on top of target core by
@@ -440,11 +463,11 @@ core_open (char *filename, int from_tty)
 	 implementation for that gdbarch, as a fallback measure,
 	 assume the host signal mapping.  It'll be correct for native
 	 cores, but most likely incorrect for cross-cores.  */
-      enum gdb_signal sig = (core_gdbarch != NULL
-			     && gdbarch_gdb_signal_from_target_p (core_gdbarch)
-			     ? gdbarch_gdb_signal_from_target (core_gdbarch,
-							       siggy)
-			     : gdb_signal_from_host (siggy));
+      enum gdb_signal sig
+	= (cops->core_gdbarch != NULL
+	   && gdbarch_gdb_signal_from_target_p (cops->core_gdbarch)
+	   ? gdbarch_gdb_signal_from_target (cops->core_gdbarch, siggy)
+	   : gdb_signal_from_host (siggy));
 
       printf_filtered (_("Program terminated with signal %s, %s.\n"),
 		       gdb_signal_to_name (sig), gdb_signal_to_string (sig));
@@ -502,6 +525,7 @@ get_core_register_section (struct regcache *regcache,
   struct bfd_section *section;
   bfd_size_type size;
   char *contents;
+  struct core_target_ops_with_data *cops = get_core_target_ops ();
 
   xfree (section_name);
 
@@ -530,11 +554,12 @@ get_core_register_section (struct regcache *regcache,
       return;
     }
 
-  if (core_gdbarch && gdbarch_regset_from_core_section_p (core_gdbarch))
+  if (cops->core_gdbarch
+      && gdbarch_regset_from_core_section_p (cops->core_gdbarch))
     {
       const struct regset *regset;
 
-      regset = gdbarch_regset_from_core_section (core_gdbarch,
+      regset = gdbarch_regset_from_core_section (cops->core_gdbarch,
 						 name, size);
       if (regset == NULL)
 	{
@@ -548,10 +573,10 @@ get_core_register_section (struct regcache *regcache,
       return;
     }
 
-  gdb_assert (core_vec);
-  core_vec->core_read_registers (regcache, contents, size, which,
-				 ((CORE_ADDR)
-				  bfd_section_vma (core_bfd, section)));
+  gdb_assert (cops->core_vec);
+  cops->core_vec->core_read_registers (regcache, contents, size, which,
+				       ((CORE_ADDR)
+					bfd_section_vma (core_bfd, section)));
 }
 
 
@@ -568,9 +593,12 @@ get_core_registers (struct target_ops *ops,
 {
   struct core_regset_section *sect_list;
   int i;
+  struct core_target_ops_with_data *cops = get_core_target_ops ();
 
-  if (!(core_gdbarch && gdbarch_regset_from_core_section_p (core_gdbarch))
-      && (core_vec == NULL || core_vec->core_read_registers == NULL))
+  if (!(cops->core_gdbarch
+	&& gdbarch_regset_from_core_section_p (cops->core_gdbarch))
+      && (cops->core_vec == NULL
+	  || cops->core_vec->core_read_registers == NULL))
     {
       fprintf_filtered (gdb_stderr,
 		     "Can't fetch registers from this type of core file\n");
@@ -611,7 +639,9 @@ get_core_registers (struct target_ops *ops,
 static void
 core_files_info (struct target_ops *t)
 {
-  print_section_info (core_data, core_bfd);
+  struct core_target_ops_with_data *cops = get_core_target_ops ();
+
+  print_section_info (&cops->core_data, core_bfd);
 }
 \f
 struct spuid_list
@@ -679,13 +709,15 @@ core_xfer_partial (struct target_ops *ops, enum target_object object,
 		   const gdb_byte *writebuf, ULONGEST offset,
 		   ULONGEST len, ULONGEST *xfered_len)
 {
+  struct core_target_ops_with_data *cops = get_core_target_ops ();
+
   switch (object)
     {
     case TARGET_OBJECT_MEMORY:
       return section_table_xfer_memory_partial (readbuf, writebuf,
 						offset, len, xfered_len,
-						core_data->sections,
-						core_data->sections_end,
+						cops->core_data.sections,
+						cops->core_data.sections_end,
 						NULL);
 
     case TARGET_OBJECT_AUXV:
@@ -759,16 +791,17 @@ core_xfer_partial (struct target_ops *ops, enum target_object object,
       return TARGET_XFER_E_IO;
 
     case TARGET_OBJECT_LIBRARIES:
-      if (core_gdbarch
-	  && gdbarch_core_xfer_shared_libraries_p (core_gdbarch))
+      if (cops->core_gdbarch
+	  && gdbarch_core_xfer_shared_libraries_p (cops->core_gdbarch))
 	{
 	  if (writebuf)
 	    return TARGET_XFER_E_IO;
 	  else
 	    {
-	      *xfered_len = gdbarch_core_xfer_shared_libraries (core_gdbarch,
-								readbuf,
-								offset, len);
+	      *xfered_len
+		= gdbarch_core_xfer_shared_libraries (cops->core_gdbarch,
+						      readbuf,
+						      offset, len);
 
 	      if (*xfered_len == 0)
 		return TARGET_XFER_EOF;
@@ -779,15 +812,15 @@ core_xfer_partial (struct target_ops *ops, enum target_object object,
       /* FALL THROUGH */
 
     case TARGET_OBJECT_LIBRARIES_AIX:
-      if (core_gdbarch
-	  && gdbarch_core_xfer_shared_libraries_aix_p (core_gdbarch))
+      if (cops->core_gdbarch
+	  && gdbarch_core_xfer_shared_libraries_aix_p (cops->core_gdbarch))
 	{
 	  if (writebuf)
 	    return TARGET_XFER_E_IO;
 	  else
 	    {
 	      *xfered_len
-		= gdbarch_core_xfer_shared_libraries_aix (core_gdbarch,
+		= gdbarch_core_xfer_shared_libraries_aix (cops->core_gdbarch,
 							  readbuf, offset,
 							  len);
 
@@ -913,11 +946,14 @@ core_thread_alive (struct target_ops *ops, ptid_t ptid)
 static const struct target_desc *
 core_read_description (struct target_ops *target)
 {
-  if (core_gdbarch && gdbarch_core_read_description_p (core_gdbarch))
+  struct core_target_ops_with_data *cops = get_core_target_ops ();
+
+  if (cops->core_gdbarch
+      && gdbarch_core_read_description_p (cops->core_gdbarch))
     {
       const struct target_desc *result;
 
-      result = gdbarch_core_read_description (core_gdbarch, 
+      result = gdbarch_core_read_description (cops->core_gdbarch, 
 					      target, core_bfd);
       if (result != NULL)
 	return result;
@@ -932,12 +968,13 @@ core_pid_to_str (struct target_ops *ops, ptid_t ptid)
   static char buf[64];
   struct inferior *inf;
   int pid;
+  struct core_target_ops_with_data *cops = get_core_target_ops ();
 
   /* The preferred way is to have a gdbarch/OS specific
      implementation.  */
-  if (core_gdbarch
-      && gdbarch_core_pid_to_str_p (core_gdbarch))
-    return gdbarch_core_pid_to_str (core_gdbarch, ptid);
+  if (cops->core_gdbarch
+      && gdbarch_core_pid_to_str_p (cops->core_gdbarch))
+    return gdbarch_core_pid_to_str (cops->core_gdbarch, ptid);
 
   /* Otherwise, if we don't have one, we'll just fallback to
      "process", with normal_pid_to_str.  */
@@ -1000,7 +1037,7 @@ init_core_ops (void)
   core_ops.to_doc =
     "Use a core file as a target.  Specify the filename of the core file.";
   core_ops.to_open = core_open;
-  core_ops.to_close = core_close;
+  core_ops.to_xclose = core_xclose;
   core_ops.to_detach = core_detach;
   core_ops.to_fetch_registers = get_core_registers;
   core_ops.to_xfer_partial = core_xfer_partial;
diff --git a/gdb/target.c b/gdb/target.c
index 6a10c04..6f5396f 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -586,6 +586,26 @@ push_target (struct target_ops *t)
   update_current_target ();
 }
 
+/* See target.h.  */
+
+struct target_ops *
+allocate_target (struct target_ops *ops, size_t alloc)
+{
+  char *mem;
+
+  gdb_assert (ops->to_identity != NULL);
+  gdb_assert (ops->to_xclose != NULL);
+  gdb_assert (alloc >= sizeof (struct target_ops));
+
+  mem = xmalloc (alloc);
+  memcpy (mem, ops, sizeof (struct target_ops));
+  if (alloc > sizeof (struct target_ops))
+    memset (&mem[sizeof (struct target_ops)], 0,
+	    alloc - sizeof (struct target_ops));
+
+  return (struct target_ops *) mem;
+}
+
 /* Remove a target_ops vector from the stack, wherever it may be.
    Return how many times it was removed (0 or 1).  */
 
diff --git a/gdb/target.h b/gdb/target.h
index 58c7b30..60dc287 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -2091,6 +2091,21 @@ extern void push_target (struct target_ops *);
 
 extern int unpush_target (struct target_ops *);
 
+/* Allocate a new target object.  OPS is the "prototype"
+   implementation of the new target; it is copied into the new object.
+   ALLOC is the number of bytes to allocate.  It may be larger than
+   sizeof (struct target_ops) if the target subclasses target_ops to
+   store extra data.  Returns the new target object.  Extra space
+   beyond the initial OPS component of the result is zeroed.  */
+
+extern struct target_ops *allocate_target (struct target_ops *ops,
+					   size_t alloc);
+
+/* A typed convenience wrapper for allocate_target.  T is the type of
+   the subclass of target_ops to allocate.  */
+
+#define TARGET_NEW(T, OPS) ((T *) (allocate_target ((OPS), sizeof (T))))
+
 extern void target_pre_inferior (int);
 
 extern void target_preopen (int);
-- 
1.9.3


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] simplify target_is_pushed
  2014-07-18 19:27 ` [PATCH 2/4] simplify target_is_pushed Tom Tromey
@ 2014-07-29 13:22   ` Joel Brobecker
  2014-07-29 15:16     ` Tom Tromey
  0 siblings, 1 reply; 17+ messages in thread
From: Joel Brobecker @ 2014-07-29 13:22 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> While working on target_is_pushed, I noticed that it is written in a
> strange way.  The code currently keeps an extra indirection, where a
> simple linked list traversal is all that is needed.  It seems likely
> this was done by copying and pasting other code.  However, there is no
> reason to do this and the more obvious code is simpler to reason
> about.  So, this patch change the implementation.
> 
> 2014-07-18  Tom Tromey  <tromey@redhat.com>
> 
> 	* target.c (target_is_pushed): Simplify.

Indeed. It looks like this one could go in on its own...

-- 
Joel


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 3/4] add to_identity
  2014-07-18 19:45 ` [PATCH 3/4] add to_identity Tom Tromey
@ 2014-07-29 14:56   ` Joel Brobecker
  2014-07-29 15:11     ` Tom Tromey
  0 siblings, 1 reply; 17+ messages in thread
From: Joel Brobecker @ 2014-07-29 14:56 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi Tom,

I just happened to notice a small typo:

> +    /* This points to an "original" target_ops from which a particular
> +       instance may have been cloned.  This is usedful if a to_xclose
                                                  ^^^^^^^

-- 
Joel


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 3/4] add to_identity
  2014-07-29 14:56   ` Joel Brobecker
@ 2014-07-29 15:11     ` Tom Tromey
  0 siblings, 0 replies; 17+ messages in thread
From: Tom Tromey @ 2014-07-29 15:11 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

Joel> I just happened to notice a small typo:

>> +    /* This points to an "original" target_ops from which a particular
>> +       instance may have been cloned.  This is usedful if a to_xclose

Thanks, Joel.
I've fixed this locally.

Tom


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] baby step toward multi-target
  2014-07-18 19:27 [PATCH 0/4] baby step toward multi-target Tom Tromey
                   ` (3 preceding siblings ...)
  2014-07-18 20:44 ` [PATCH 4/4] convert corelow to to_xclose Tom Tromey
@ 2014-07-29 15:11 ` Pedro Alves
  2014-07-29 15:15   ` Tom Tromey
  2014-07-29 15:40   ` Doug Evans
  2014-08-10 20:02 ` Doug Evans
  5 siblings, 2 replies; 17+ messages in thread
From: Pedro Alves @ 2014-07-29 15:11 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 07/18/2014 08:27 PM, Tom Tromey wrote:

> If this approach seems reasonable then it's not too hard to pull over
> some of the other target conversions from the branch.

Seems reasonable.  We may or not end up doing things completely
different wrt to the identify issue and target is pushed/not pushed,
but meanwhile this lets us progress with making it possible to have
different instances of a target, so it seems good forward progress.

The series looked good to me.

-- 
Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] baby step toward multi-target
  2014-07-29 15:11 ` [PATCH 0/4] baby step toward multi-target Pedro Alves
@ 2014-07-29 15:15   ` Tom Tromey
  2014-07-29 16:32     ` Pedro Alves
  2014-07-29 15:40   ` Doug Evans
  1 sibling, 1 reply; 17+ messages in thread
From: Tom Tromey @ 2014-07-29 15:15 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Tom> If this approach seems reasonable then it's not too hard to pull over
Tom> some of the other target conversions from the branch.

Pedro> Seems reasonable.  We may or not end up doing things completely
Pedro> different wrt to the identify issue and target is pushed/not pushed,
Pedro> but meanwhile this lets us progress with making it possible to have
Pedro> different instances of a target, so it seems good forward progress.

Pedro> The series looked good to me.

Thanks for looking.

I actually went a bit farther down this path on my branch, adding:

    0249cca turn remote into a to_xclose target
    84e2677 turn linux-thread-db into a to_xclose target
    9fdaa64 fix exec_close to be multi-target-aware
    7fd03ff introduce the target stack
    698a56f convert current_target to be a pointer
    68520c8 convert exec target to to_xclose

These are all things pulled over from the mostly-defunct multi-target
branch.

I probably wouldn't be inclined to put these -- or maybe even the bulk
of the "baby step" series -- in right now.  They aren't really that
useful until some other things are finished, like adding the target ID
to ptid.

However, it's probably useful as a starting point for the next attempt
at multi-target.  In particular it's much less invasive than the earlier
approach, and the "convert current_target to be a pointer" patch (the
biggest one) was mostly done with a perl one-liner.

Tom


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] simplify target_is_pushed
  2014-07-29 13:22   ` Joel Brobecker
@ 2014-07-29 15:16     ` Tom Tromey
  0 siblings, 0 replies; 17+ messages in thread
From: Tom Tromey @ 2014-07-29 15:16 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

>> 2014-07-18  Tom Tromey  <tromey@redhat.com>
>> 
>> * target.c (target_is_pushed): Simplify.

Joel> Indeed. It looks like this one could go in on its own...

Yeah.  I'll push this one soon.  Thanks.

Tom


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] baby step toward multi-target
  2014-07-29 15:11 ` [PATCH 0/4] baby step toward multi-target Pedro Alves
  2014-07-29 15:15   ` Tom Tromey
@ 2014-07-29 15:40   ` Doug Evans
  1 sibling, 0 replies; 17+ messages in thread
From: Doug Evans @ 2014-07-29 15:40 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tom Tromey, gdb-patches

On Tue, Jul 29, 2014 at 7:23 AM, Pedro Alves <palves@redhat.com> wrote:
> On 07/18/2014 08:27 PM, Tom Tromey wrote:
>
>> If this approach seems reasonable then it's not too hard to pull over
>> some of the other target conversions from the branch.
>
> Seems reasonable.  We may or not end up doing things completely
> different wrt to the identify issue and target is pushed/not pushed,
> but meanwhile this lets us progress with making it possible to have
> different instances of a target, so it seems good forward progress.
>
> The series looked good to me.

I'd like to review this for a bit more.

I'd like to understand the tradeoffs of this more:

>>This little series, on the other hand, takes a less invasive approach.
>>The idea here is that rather than doing a huge target_ops split,
>>instead just sometimes make copies of the target_ops when pushing.
>>This lets the copies keep their own state; copies are needed in the
>>long run because multiple target stacks will be active and a given
>>target_ops only has one "beneath" pointer.

Thanks.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] baby step toward multi-target
  2014-07-29 15:15   ` Tom Tromey
@ 2014-07-29 16:32     ` Pedro Alves
  2014-07-29 19:04       ` Tom Tromey
  0 siblings, 1 reply; 17+ messages in thread
From: Pedro Alves @ 2014-07-29 16:32 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 07/29/2014 03:49 PM, Tom Tromey wrote:

> However, it's probably useful as a starting point for the next attempt
> at multi-target.  In particular it's much less invasive than the earlier
> approach, and the "convert current_target to be a pointer" patch (the
> biggest one) was mostly done with a perl one-liner.

Yeah.

Hmm, kind of orthogonal, but not really, I wonder how far are we
to getting rid of the remaining target stack annoyances.  Like:

 #1 - Convert the remaining data fields to methods.  That seems it'll
      just be boring work.
 #2 - making the debug target a wrapping target around each target layer
      (as you suggested elsewhere).  That'll require make-target-delegates
      hacking.

That'd then make it possible to:

 #3 - eliminate the squashed current_target, replacing it with a pointer
      to the topmost target in the stack (mostly the same as your
      perl one-liner).

Is that in line with what you've been thinking?  I'm wondering whether
you found out in the more invasive branch that it's useful if
current_target is more than a struct target_ops pointer ?
(or "struct target *" after vtable-ification.)

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] baby step toward multi-target
  2014-07-29 16:32     ` Pedro Alves
@ 2014-07-29 19:04       ` Tom Tromey
  2014-07-29 21:32         ` Doug Evans
  0 siblings, 1 reply; 17+ messages in thread
From: Tom Tromey @ 2014-07-29 19:04 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Tom> However, it's probably useful as a starting point for the next attempt
Tom> at multi-target.  In particular it's much less invasive than the earlier
Tom> approach, and the "convert current_target to be a pointer" patch (the
Tom> biggest one) was mostly done with a perl one-liner.

Pedro> Yeah.

Pedro> Hmm, kind of orthogonal, but not really, I wonder how far are we
Pedro> to getting rid of the remaining target stack annoyances.  Like:

Pedro>  #1 - Convert the remaining data fields to methods.  That seems it'll
Pedro>       just be boring work.

Agreed.

Pedro>  #2 - making the debug target a wrapping target around each
Pedro>  target layer (as you suggested elsewhere).  That'll require
Pedro>  make-target-delegates hacking.

And a bit of hacking in the same spots touched by the "identity" patch
in this series.

It doesn't seem very hard.

Pedro> That'd then make it possible to:

Pedro>  #3 - eliminate the squashed current_target, replacing it with a pointer
Pedro>       to the topmost target in the stack (mostly the same as your
Pedro>       perl one-liner).

Pedro> Is that in line with what you've been thinking?  I'm wondering whether
Pedro> you found out in the more invasive branch that it's useful if
Pedro> current_target is more than a struct target_ops pointer ?
Pedro> (or "struct target *" after vtable-ification.)

I think it's reasonable to try to get there.
Certainly at this point the squashed target is not extremely useful.
You can see this by looking at how few uses of INHERIT remain.

This would also let us zap the uses of "current_target.beneath" that we
discussed yesterday.


The more invasive branch took a different approach to target identity.
Rather than the to_identity field, it split target_ops into a const
vtable part and a payload part.  Then it aimed to require all targets to
instantiate a new object.

This obviously has to touch a lot of code.  And, it runs into some
difficulties where the target code must work with uninstantiated
targets.

I don't think this is as much of an issue on the new branch.
At least from what I recall the uninstantiated business isn't a big
issue because this only affects a subset of methods, which can simply
avoid looking at the payload.  Also perhaps the target delegation
changes cleaned things up a bit too, I forget.

On the new branch, having current_target be a pointer is preferable just
because it makes target-swapping cheap -- it just means redirecting two
pointers (it could be one pointer, but I chose to keep current_target a
global, always pointing into the current target_stack object; this means
the target stack can be opaque).

I didn't consider making current_target have some other type.

Tom


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] baby step toward multi-target
  2014-07-29 19:04       ` Tom Tromey
@ 2014-07-29 21:32         ` Doug Evans
  2014-08-11  5:54           ` Doug Evans
  0 siblings, 1 reply; 17+ messages in thread
From: Doug Evans @ 2014-07-29 21:32 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Pedro Alves, gdb-patches

On Tue, Jul 29, 2014 at 10:45 AM, Tom Tromey <tromey@redhat.com> wrote:
> The more invasive branch took a different approach to target identity.
> Rather than the to_identity field, it split target_ops into a const
> vtable part and a payload part.  Then it aimed to require all targets to
> instantiate a new object.

Hi.  I'd like to understand this more.
By way of analogy, are you talking about something akin to RTTI, or
something else?
[How would the problem of target identity be solved if one went with
the "all targets instantiate a new object" approach?]

> This obviously has to touch a lot of code.  And, it runs into some
> difficulties where the target code must work with uninstantiated
> targets.

By way of analogy, is all such code akin to static methods?

> I don't think this is as much of an issue on the new branch.
> At least from what I recall the uninstantiated business isn't a big
> issue because this only affects a subset of methods, which can simply
> avoid looking at the payload.

Avoid looking at the payload how?
Do you mean said "methods" would get passed an argument they are
explicitly not supposed to touch?


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] baby step toward multi-target
  2014-07-18 19:27 [PATCH 0/4] baby step toward multi-target Tom Tromey
                   ` (4 preceding siblings ...)
  2014-07-29 15:11 ` [PATCH 0/4] baby step toward multi-target Pedro Alves
@ 2014-08-10 20:02 ` Doug Evans
  5 siblings, 0 replies; 17+ messages in thread
From: Doug Evans @ 2014-08-10 20:02 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Tom Tromey <tromey@redhat.com> writes:
> My multi-target branch is basically dead, I think, mostly due to heavy
> conflicts with all the other target changes that have happened in the
> meantime.

This is an important bit of functionality that needs to be done.
Since we just released 7.8, and in order to prevent such things
happening again, I think it would be reasonable to put more
resources into getting this done, and delay other things for awhile.
[Assuming various factors like it won't take an inordinate amount
of time, and the end result is the more preferred one, and probably
a few others :-).]

$0.02

> However recently I realized that there is a less invasive
> way to achieve many of the same effects, and a way to salvage some of
> the smaller cleanups done there.
>
> In particular on the branch I attempted to split target_ops into a
> vtable-like object and a target state object.  As you might imagine
> this patch touches a large amount of code and is hard both to keep up
> to date, and to test.

That was my understanding of where we were headed.

> This little series, on the other hand, takes a less invasive approach.
> The idea here is that rather than doing a huge target_ops split,
> instead just sometimes make copies of the target_ops when pushing.
> This lets the copies keep their own state; copies are needed in the
> long run because multiple target stacks will be active and a given
> target_ops only has one "beneath" pointer.

Which version of the long run?
Wouldn't dynamic properties of the object be kept in the object
and not the vtable?

Or is some custom dynamic interitance being done here?
I can imagine that being useful to facilitate inserting
debug targets into the mix.

By way of analogy, I'd be curious how this would be done in c++.

[Just trying to understand the situation better.]

> Here corelow is used as the example of how to do a conversion.
> There's a bit of cleanup and infrastructure initially, and then the
> final patch moves the corelow global state into a new subclass of
> target_ops, which is instantiated and pushed.
>
> If this approach seems reasonable then it's not too hard to pull over
> some of the other target conversions from the branch.
>
> This series also shows the spots to change if you want to make the
> debug target wrap each stratum in the target stack -- each wrapping
> debug target would be to_xclose-ish, and spots like target_is_pushed
> would be taught to unwrap.
>
> Built and regtested on x86-64 Fedora 20.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] baby step toward multi-target
  2014-07-29 21:32         ` Doug Evans
@ 2014-08-11  5:54           ` Doug Evans
  0 siblings, 0 replies; 17+ messages in thread
From: Doug Evans @ 2014-08-11  5:54 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Pedro Alves, gdb-patches

Doug Evans <dje@google.com> writes:
> On Tue, Jul 29, 2014 at 10:45 AM, Tom Tromey <tromey@redhat.com> wrote:
>> The more invasive branch took a different approach to target identity.
>> Rather than the to_identity field, it split target_ops into a const
>> vtable part and a payload part.  Then it aimed to require all targets to
>> instantiate a new object.
>
> Hi.  I'd like to understand this more.
> By way of analogy, are you talking about something akin to RTTI, or
> something else?
> [How would the problem of target identity be solved if one went with
> the "all targets instantiate a new object" approach?]
>
>> This obviously has to touch a lot of code.  And, it runs into some
>> difficulties where the target code must work with uninstantiated
>> targets.
>
> By way of analogy, is all such code akin to static methods?
>
>> I don't think this is as much of an issue on the new branch.
>> At least from what I recall the uninstantiated business isn't a big
>> issue because this only affects a subset of methods, which can simply
>> avoid looking at the payload.
>
> Avoid looking at the payload how?
> Do you mean said "methods" would get passed an argument they are
> explicitly not supposed to touch?

Regarding avoiding looking at the payload ...

I noticed this in 4/4.  I think(!) it's unrelated, though I'm still
unclear on what you're referring to.  At any rate, the following is odd.

Several "methods" take a "self" or "ops" pointer but then don't use it
and instead go search the target stack for what I'd expect to be the
same thing.

E.g.,

diff --git a/gdb/corelow.c b/gdb/corelow.c
index 1775a66..212665d 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -611,7 +639,9 @@ get_core_registers (struct target_ops *ops,
 static void
 core_files_info (struct target_ops *t)
 {
-  print_section_info (core_data, core_bfd);
+  struct core_target_ops_with_data *cops = get_core_target_ops ();
+
+  print_section_info (&cops->core_data, core_bfd);
 }
 \f
 struct spuid_list

The intuitive thing to do here is assert t is a core ops,
and then use it.  Instead the code calls get_core_target_ops.
Why?

I realize you mentioned in another email that you probably wouldn't
be inclined to check this in.  But if corelow is to be the example
on which other targets are based I'd like to understand all the
oddities I find.  [Maybe the above is just oversight, in which case
no worries.  But gdb's target support isn't always intuitive, and
I don't always trust my intuition with it.]


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2014-08-11  5:54 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-18 19:27 [PATCH 0/4] baby step toward multi-target Tom Tromey
2014-07-18 19:27 ` [PATCH 1/4] move core_bfd to program space Tom Tromey
2014-07-18 19:27 ` [PATCH 2/4] simplify target_is_pushed Tom Tromey
2014-07-29 13:22   ` Joel Brobecker
2014-07-29 15:16     ` Tom Tromey
2014-07-18 19:45 ` [PATCH 3/4] add to_identity Tom Tromey
2014-07-29 14:56   ` Joel Brobecker
2014-07-29 15:11     ` Tom Tromey
2014-07-18 20:44 ` [PATCH 4/4] convert corelow to to_xclose Tom Tromey
2014-07-29 15:11 ` [PATCH 0/4] baby step toward multi-target Pedro Alves
2014-07-29 15:15   ` Tom Tromey
2014-07-29 16:32     ` Pedro Alves
2014-07-29 19:04       ` Tom Tromey
2014-07-29 21:32         ` Doug Evans
2014-08-11  5:54           ` Doug Evans
2014-07-29 15:40   ` Doug Evans
2014-08-10 20:02 ` Doug Evans

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox