Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* unwind support for Linux 2.6 vsyscall DSO
@ 2003-10-03  8:27 Roland McGrath
  2003-10-03 23:44 ` Jim Blandy
  2003-10-06 19:31 ` Elena Zannoni
  0 siblings, 2 replies; 56+ messages in thread
From: Roland McGrath @ 2003-10-03  8:27 UTC (permalink / raw)
  To: gdb-patches

In the past (during this spring and summer) there were some discussions
about the need to find unwind info in the vsyscall DSO image implicitly
loaded in processes on Linux 2.5/2.6 on some platforms.  I honestly don't
recall which mailing lists this was on.  If people are not clear on the
issues, I can try to dig up the various summaries of the details I have
posted before.  This was tabled for a while when I had other priorities
since it didn't turn out to be an issue with any kernel version used by
Red Hat production systems.

Now Linux 2.6 is getting firmed up, and it's time to revisit this.  On
Linux 2.6 kernels, backtraces from programs stopped in system calls do not
work using current glibc on x86 and AMD64 machines.  The same issue exists
on IA64 in Linux 2.6, and glibc will before long make use of the feature so
that system call backtraces need the same solutions for IA64.

My changes to export the auxv information in core dumps and /proc are now
making their way into Linux 2.6, and this gives us the tools we need to
solve the problem in gdb.

The following patches are some kludges I have tried out.  They are not fit
for inclusion, but demonstrate what needs to be done.  I hope they can
stimulate some advice on where such code should actually go.

This patch relies on the symbol_file_add_from_memory function introduced by
the patch I just posted a little earlier.  Please review that patch first
as context for what I'm doing here.  With that patch plus this one, on a Linux
2.6 kernel with the very latest patches you surely don't have quite yet, a
backtrace starting in the vsyscall entry point is unwound correctly from a
core file and when using attach.

Basically what needs to happen is a few places that should implicitly call
symbol_file_add_from_memory on the address the kernel supplied with the
AT_SYSINFO_EHDR tag on process startup.  On examining a core file, the
NT_AUXV note contains this info, and BFD makes it available as a ".auxv"
fake section.  On running or attaching to a live process, the
/proc/PID/auxv fake file provided by the target kernel contains the info.  

The auxv_parse function below does the work of interpreting the auxv block
(from a core file's NT_AUXV/.auxv or from /proc/PID/auxv).  That little bit
of code is about right as it is.  The issues are when to call it.

Questions for the core file case:

1 Where should this call go in the order of operations?  

  I plopped the check in the middle of core_open because it seemed like it
  ought to come between the bfd opening and the register diddling that
  includes some calls about the grokking of the stack frame.  I don't know
  how loading a symfile interacts with that diddling.  Would it work to
  have the symbol_file_add_from_memory done after core_open?

2 Where should this support go in the target/generic code split?

  This code, and the need for it, is Linux-specific but not machine-specific.
  Linux 2.6 currently requires it on x86, IA64, and AMD64 (in both native and
  IA32 emulation versions).  The user-level support for the preloaded DSO
  image is machine-independent in the glibc implementation; no other Linux
  platform will overload the AT_SYSINFO_EHDR tag value for another purpose.
  I would like to have this implemented in gdb in a place that doesn't
  require duplication for the three existing platforms requiring the support,
  and will cover any other Linux target where kernels start using the same
  feature.  I don't see any obvious place like a common linux-tdep.c; where
  is the right place?  Should it be a different to_core_open hook that wraps
  the generic one?  Or maybe extend struct core_fns?  (But core_fns is
  redefined only in machine-specific files, and it appears inconsistently
  so--sometimes in *-nat.c and sometimes in *-tdep.c; what's the story?)

3 When and how should I unload the symbols on detaching from the core file?

  The solib symbols are cleared in core_close from what I can see.
  Is that the right spot to drop the symfile added from reading NT_AUXV?
  How do I clear it all out properly?  Do I just call free_objfile?
  Is remove_target_sections required as clear_solib does?

Similar questions for the live process case:

4 Where to make the call?

  The patch below does it in linux-nat.c's child_post_attach.  That makes
  it work for attach, but it is probably the wrong place.  I really have
  no idea where the right place to insert this is for the "run" case.  It
  needs to happen after the break-on-exec, the same time you would first
  insert breakpoints in the program.  Where is the right place to make
  that happen?  Is there one place that's right for both run and attach?

5 Same as #2, in context.

  linux-nat.c seems like it ought to be the right source file for the
  /proc parsing, or perhaps linux-proc.c; the auxv_parse function
  (renamed) should be shared between the core and live handling cases, it
  belongs in a linux-tdep sort of file logically.  

6 Same as #3, in context.

  I can't figure out where things get cleared out when a process dies or
  you detach.  Do they?  I see objfile_purge_solibs is called from
  run_command.  I think that will get the symfile I create.  Is that
  sufficient?  Do solibs get cleared on detach/attach?



Thanks,
Roland


Index: corelow.c
===================================================================
RCS file: /cvs/src/src/gdb/corelow.c,v
retrieving revision 1.30
diff -p -b -u -r1.30 corelow.c
--- corelow.c	21 Sep 2003 01:26:44 -0000	1.30
+++ corelow.c	3 Oct 2003 05:39:55 -0000
@@ -252,6 +252,63 @@ add_to_thread_list (bfd *abfd, asection 
     inferior_ptid = pid_to_ptid (thread_id);	/* Yes, make it current */
 }
 
+#include <elf/common.h>
+#include <elf/external.h>
+
+int
+auxv_parse (bfd *abfd, char *contents, bfd_size_type size, int from_tty)
+{
+  bfd_vma sysinfo_ehdr = 0;
+
+  switch (bfd_arch_bits_per_address (abfd))
+    {
+    default:
+      return 0;
+
+    case 32:
+      {
+	Elf32_External_Auxv *av;
+	for (av = (Elf32_External_Auxv *) contents;
+	     (char *) av < contents + size;
+	     ++av)
+	  {
+	    const bfd_vma type = bfd_get_32 (abfd, av->a_type);
+	    if (type == AT_NULL)
+	      break;
+	    if (type == AT_SYSINFO_EHDR)
+	      {
+		sysinfo_ehdr = bfd_get_32 (abfd, av->a_val);
+		break;
+	      }
+	  }
+	break;
+      }
+    case 64:
+      {
+	Elf64_External_Auxv *av;
+	for (av = (Elf64_External_Auxv *) contents;
+	     (char *) av < contents + size;
+	     ++av)
+	  {
+	    const bfd_vma type = bfd_get_64 (abfd, av->a_type);
+	    if (type == AT_NULL)
+	      break;
+	    if (type == AT_SYSINFO_EHDR)
+	      {
+		sysinfo_ehdr = bfd_get_64 (abfd, av->a_val);
+		break;
+	      }
+	  }
+	break;
+      }
+    }
+
+  if (sysinfo_ehdr != 0)
+    (void) symbol_file_add_from_memory (abfd, sysinfo_ehdr, from_tty);
+
+  return 1;
+}
+
 /* This routine opens and sets up the core file bfd.  */
 
 static void
@@ -264,6 +321,7 @@ core_open (char *filename, int from_tty)
   bfd *temp_bfd;
   int ontop;
   int scratch_chan;
+  asection *section;
 
   target_preopen (from_tty);
   if (!filename)
@@ -344,6 +402,22 @@ core_open (char *filename, int from_tty)
     printf_filtered ("Program terminated with signal %d, %s.\n", siggy,
 		     target_signal_to_string (target_signal_from_host (siggy)));
 
+  section = bfd_get_section_by_name (core_bfd, ".auxv");
+  if (section != NULL)
+    {
+      bfd_size_type size;
+      char *contents;
+      size = bfd_section_size (core_bfd, section);
+      contents = alloca (size);
+      if (! bfd_get_section_contents (core_bfd, section, contents,
+				      (file_ptr) 0, size))
+	warning ("Couldn't read NT_AUXV note in core file.");
+      else
+	{
+	  auxv_parse (core_bfd, contents, size, from_tty);
+	}
+    }
+
   /* Build up thread list from BFD sections. */
 
   init_thread_list ();
Index: linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.5
diff -p -b -u -r1.5 linux-nat.c
--- linux-nat.c	17 Aug 2003 20:17:02 -0000	1.5
+++ linux-nat.c	3 Oct 2003 05:39:56 -0000
@@ -24,6 +24,7 @@
 
 #include "gdb_wait.h"
 #include <sys/ptrace.h>
+#include <fcntl.h>
 
 #include "linux-nat.h"
 
@@ -234,10 +235,30 @@ linux_enable_event_reporting (ptid_t pti
   ptrace (PTRACE_SETOPTIONS, pid, 0, options);
 }
 
+static void
+linux_add_sysinfo_symbols (int pid)
+{
+  extern bfd *exec_bfd;		/* exec.c */
+  char filename[64];
+  int fd;
+  char contents[1024];
+  int size;
+
+  sprintf (filename, "/proc/%d/auxv", pid);
+  fd = open (filename, O_RDONLY);
+  if (fd < 0)
+    return;
+  size = read (fd, contents, sizeof contents);
+  close (fd);
+
+  auxv_parse (exec_bfd, contents, size, 0);
+}
+
 void
 child_post_attach (int pid)
 {
   linux_enable_event_reporting (pid_to_ptid (pid));
+  linux_add_sysinfo_symbols (pid);
 }
 
 void


^ permalink raw reply	[flat|nested] 56+ messages in thread
* Re: unwind support for Linux 2.6 vsyscall DSO
@ 2003-10-07  3:33 Roland McGrath
  0 siblings, 0 replies; 56+ messages in thread
From: Roland McGrath @ 2003-10-07  3:33 UTC (permalink / raw)
  To: Elena Zannoni; +Cc: gdb-patches

Here is an alternate version of my patch, omitting the Solaris parts.  This
uses an iterator interface as you requested.  I didn't add a utility
function but duplicated the code that might be in one.  This also works
(writes a good NT_AUXV note), but the core file writing additions are now
rather clunky, and that code has to be duplicated for Solaris (or factored
out).  I prefer the first version.


Thanks,
Roland


Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.55
diff -b -p -u -r1.55 target.c
--- target.c	2 Oct 2003 20:28:30 -0000	1.55
+++ target.c	7 Oct 2003 03:29:27 -0000
@@ -624,6 +624,7 @@ update_current_target (void)
       INHERIT (to_async, t);
       INHERIT (to_async_mask_value, t);
       INHERIT (to_find_memory_regions, t);
+      INHERIT (to_read_aux_vector, t);
       INHERIT (to_make_corefile_notes, t);
       INHERIT (to_get_thread_local_address, t);
       INHERIT (to_magic, t);
@@ -1500,6 +1501,13 @@ static int dummy_find_memory_regions (in
   return 0;
 }
 
+/* Error-catcher for target_read_aux_vector */
+static int dummy_read_aux_vector (int (*ignore1) (), void *ignore2)
+{
+  error ("No target.");
+  return 0;
+}
+
 /* Error-catcher for target_make_corefile_notes */
 static char * dummy_make_corefile_notes (bfd *ignore1, int *ignore2)
 {
@@ -1521,6 +1529,7 @@ init_dummy_target (void)
   dummy_target.to_pid_to_str = normal_pid_to_str;
   dummy_target.to_stratum = dummy_stratum;
   dummy_target.to_find_memory_regions = dummy_find_memory_regions;
+  dummy_target.to_read_aux_vector = dummy_read_aux_vector;
   dummy_target.to_make_corefile_notes = dummy_make_corefile_notes;
   dummy_target.to_magic = OPS_MAGIC;
 }
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.41
diff -b -p -u -r1.41 target.h
--- target.h	17 Jun 2003 20:28:13 -0000	1.41
+++ target.h	7 Oct 2003 03:29:27 -0000
@@ -322,6 +322,7 @@ struct target_ops
 					    int, int, int, 
 					    void *), 
 				   void *);
+    int (*to_read_aux_vector) (int (*) (const void *, void *), void *);
     char * (*to_make_corefile_notes) (bfd *, int *);
 
     /* Return the thread-local address at OFFSET in the
@@ -939,6 +940,14 @@ extern void (*target_new_objfile_hook) (
      (current_target.to_find_memory_regions) (FUNC, DATA)
 
 /*
+ * Function to read target startup auxilliary vector (ELF-specific).
+ * Returns a malloc'd buffer of ELF auxv data, and sets *LENP to its size.
+ */
+
+#define target_read_aux_vector(FUNC, DATA) \
+     (current_target.to_read_aux_vector) (FUNC, DATA)
+
+/*
  * Compose corefile .note section.
  */
 
Index: inftarg.c
===================================================================
RCS file: /cvs/src/src/gdb/inftarg.c,v
retrieving revision 1.18
diff -b -p -u -r1.18 inftarg.c
--- inftarg.c	21 Sep 2003 01:26:45 -0000	1.18
+++ inftarg.c	7 Oct 2003 03:29:27 -0000
@@ -628,6 +628,14 @@ inftarg_set_find_memory_regions (int (*f
   child_ops.to_find_memory_regions = func;
 }
 
+/* Take over the 'read_aux_vector' vector from inftarg.c. */
+void
+inftarg_set_read_aux_vector (int (*func) (int (*) (const void *, void *),
+					  void *))
+{
+  child_ops.to_read_aux_vector = func;
+}
+
 /* Take over the 'make_corefile_notes' vector from inftarg.c. */
 extern void 
 inftarg_set_make_corefile_notes (char * (*func) (bfd *, int *))
Index: linux-proc.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-proc.c,v
retrieving revision 1.20
diff -b -p -u -r1.20 linux-proc.c
--- linux-proc.c	1 Oct 2003 20:36:56 -0000	1.20
+++ linux-proc.c	7 Oct 2003 03:29:27 -0000
@@ -161,6 +161,72 @@ linux_find_memory_regions (int (*func) (
   return 0;
 }
 
+static int
+procfs_read_aux_vector (int (*func) (const Elf_Internal_Auxv *, void *),
+			void *data)
+{
+  char pathname[MAXPATHLEN];
+  union
+  {
+    Elf32_External_Auxv av32[20];
+    Elf64_External_Auxv av64[10];
+  } buf;
+  int fd, n, ret;
+
+  sprintf (pathname, "/proc/%d/auxv", PIDGET (inferior_ptid));
+  fd = open (pathname, O_RDONLY);
+  if (fd < 0)
+    return 0;			/* XXX Call error here? */
+
+  ret = 0;
+  while (1)
+    {
+      n = read (fd, &buf, sizeof buf);
+      if (n <= 0)		/* Hit EOF or read error.  */
+	return 0;
+
+      switch (bfd_arch_bits_per_address (exec_bfd))
+	{
+	default:
+	  break;
+
+	case 32:
+	  {
+	    const Elf32_External_Auxv *av;
+	    for (av = buf.av32; (char *) av < (char *) &buf + n; ++av)
+	      {
+		Elf_Internal_Auxv elt;
+		elt.a_type = bfd_get_32 (exec_bfd, av->a_type);
+		elt.a_val = bfd_get_32 (exec_bfd, av->a_val);
+		ret = (*func) (&elt, data);
+		if (ret != 0)
+		  break;
+	      }
+	    continue;
+	  }
+	case 64:
+	  {
+	    const Elf64_External_Auxv *av;
+	    for (av = buf.av64; (char *) av < (char *) &buf + n; ++av)
+	      {
+		Elf_Internal_Auxv elt;
+		elt.a_type = bfd_get_64 (exec_bfd, av->a_type);
+		elt.a_val = bfd_get_64 (exec_bfd, av->a_val);
+		ret = (*func) (&elt, data);
+		if (ret != 0)
+		  break;
+	      }
+	    continue;
+	  }
+	}
+
+      break;
+    }
+
+  close (fd);
+  return ret;
+}
+
 /* Function: linux_do_thread_registers
  *
  * Records the thread's register state for the corefile note section.
@@ -255,6 +321,46 @@ linux_do_registers (bfd *obfd, ptid_t pt
   return note_data;
 }
 
+static int
+linux_auxv_count (const void *av, void *data)
+{
+  ++*(int *) data;
+  return 0;
+}
+
+static int
+linux_auxv_reconstruct (const void *internal, void *data)
+{
+  const Elf_Internal_Auxv *av = internal;
+  bfd_byte **ptr = data;
+
+  switch (bfd_arch_bits_per_address (exec_bfd))
+    {
+    default:
+      break;
+
+    case 32:
+      {
+	bfd_put_32 (exec_bfd, av->a_type, *ptr);
+	*ptr += 4;
+	bfd_put_32 (exec_bfd, av->a_val, *ptr);
+	*ptr += 4;
+	break;
+      }
+
+    case 64:
+      {
+	bfd_put_64 (exec_bfd, av->a_type, *ptr);
+	*ptr += 8;
+	bfd_put_64 (exec_bfd, av->a_val, *ptr);
+	*ptr += 8;
+	break;
+      }
+    }
+
+  return 0;
+}
+
 /* Function: linux_make_note_section
  *
  * Fills the "to_make_corefile_note" target vector.
@@ -271,6 +377,7 @@ linux_make_note_section (bfd *obfd, int 
   char psargs[80] = { '\0' };
   char *note_data = NULL;
   ptid_t current_ptid = inferior_ptid;
+  int auxv_len;
 
   if (get_exec_file (0))
     {
@@ -305,6 +412,19 @@ linux_make_note_section (bfd *obfd, int 
       note_data = thread_args.note_data;
     }
 
+  auxv_len = 0;
+  target_read_aux_vector (linux_auxv_count, &auxv_len);
+  if (auxv_len != 0)
+    {
+      bfd_byte *auxv, *auxvptr;
+      auxv = alloca (auxv_len * 2
+		     * (bfd_arch_bits_per_address (exec_bfd) / 8));
+      auxvptr = auxv;
+      target_read_aux_vector (linux_auxv_reconstruct, &auxvptr);
+      note_data = elfcore_write_note (obfd, note_data, note_size,
+				      "CORE", NT_AUXV, auxv, auxvptr - auxv);
+    }
+
   make_cleanup (xfree, note_data);
   return note_data;
 }
@@ -593,9 +713,11 @@ _initialize_linux_proc (void)
 {
   extern void inftarg_set_find_memory_regions ();
   extern void inftarg_set_make_corefile_notes ();
+  extern void inftarg_set_read_aux_vector ();
 
   inftarg_set_find_memory_regions (linux_find_memory_regions);
   inftarg_set_make_corefile_notes (linux_make_note_section);
+  inftarg_set_read_aux_vector (procfs_read_aux_vector);
 
   add_info ("proc", linux_info_proc_cmd,
 	    "Show /proc process information about any running process.\n\
Index: corelow.c
===================================================================
RCS file: /cvs/src/src/gdb/corelow.c,v
retrieving revision 1.30
diff -b -p -u -r1.30 corelow.c
--- corelow.c	21 Sep 2003 01:26:44 -0000	1.30
+++ corelow.c	7 Oct 2003 03:29:27 -0000
@@ -474,6 +550,69 @@ core_files_info (struct target_ops *t)
   print_section_info (t, core_bfd);
 }
 \f
+static int
+core_read_aux_vector (int (*func) (const void *, void *), void *data)
+{
+  sec_ptr section;
+  bfd_size_type size;
+  char *contents;
+  int ret;
+
+  section = bfd_get_section_by_name (core_bfd, ".auxv");
+  if (section == NULL)
+    return 0;
+
+  size = bfd_section_size (core_bfd, section);
+  contents = (char *) alloca (size);
+  if (! bfd_get_section_contents (core_bfd, section, contents,
+				  (file_ptr) 0, size))
+    {
+      warning ("Couldn't read NT_AUXV note in core file.");
+      return 0;
+    }
+
+  switch (bfd_arch_bits_per_address (core_bfd))
+    {
+    default:
+      return 0;
+
+    case 32:
+      {
+	Elf32_External_Auxv *av;
+	for (av = (Elf32_External_Auxv *) contents;
+	     (char *) av < contents + size;
+	     ++av)
+	  {
+	    Elf_Internal_Auxv elt;
+	    elt.a_type = bfd_get_32 (core_bfd, av->a_type);
+	    elt.a_val = bfd_get_32 (core_bfd, av->a_val);
+	    ret = (*func) (&elt, data);
+	    if (ret != 0)
+	      return ret;
+	  }
+	break;
+      }
+    case 64:
+      {
+	Elf64_External_Auxv *av;
+	for (av = (Elf64_External_Auxv *) contents;
+	     (char *) av < contents + size;
+	     ++av)
+	  {
+	    Elf_Internal_Auxv elt;
+	    elt.a_type = bfd_get_64 (core_bfd, av->a_type);
+	    elt.a_val = bfd_get_64 (core_bfd, av->a_val);
+	    ret = (*func) (&elt, data);
+	    if (ret != 0)
+	      return ret;
+	  }
+	break;
+      }
+    }
+
+  return 0;
+}
+\f
 /* If mourn is being called in all the right places, this could be say
    `gdb internal error' (since generic_mourn calls breakpoint_init_inferior).  */
 
@@ -520,6 +659,7 @@ init_core_ops (void)
   core_ops.to_has_memory = 1;
   core_ops.to_has_stack = 1;
   core_ops.to_has_registers = 1;
+  core_ops.to_read_aux_vector = core_read_aux_vector;
   core_ops.to_magic = OPS_MAGIC;
 }


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

end of thread, other threads:[~2003-10-15  4:33 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-10-03  8:27 unwind support for Linux 2.6 vsyscall DSO Roland McGrath
2003-10-03 23:44 ` Jim Blandy
2003-10-04  0:10   ` Roland McGrath
2003-10-04  7:28     ` Jim Blandy
2003-10-04 20:27       ` Roland McGrath
2003-10-04 21:14         ` Daniel Jacobowitz
2003-10-04 22:01           ` Roland McGrath
2003-10-04 23:28             ` Daniel Jacobowitz
2003-10-06 17:14         ` Jim Blandy
2003-10-06 19:35       ` Elena Zannoni
2003-10-06 19:31 ` Elena Zannoni
2003-10-06 20:24   ` Roland McGrath
2003-10-06 21:48     ` Elena Zannoni
2003-10-06 23:59       ` Roland McGrath
2003-10-07  0:13         ` Roland McGrath
2003-10-07  2:30           ` Elena Zannoni
2003-10-07  2:40             ` Roland McGrath
2003-10-07  2:47               ` Roland McGrath
2003-10-07  3:53           ` Andrew Cagney
2003-10-07  4:07             ` Daniel Jacobowitz
2003-10-07  4:17               ` Andrew Cagney
2003-10-07  4:28             ` Roland McGrath
2003-10-08  0:02               ` Michael Snyder
2003-10-08  0:46                 ` Roland McGrath
2003-10-08 18:27                   ` Andrew Cagney
2003-10-08 21:00               ` Andrew Cagney
2003-10-08 21:47                 ` Roland McGrath
2003-10-08 23:25                   ` Elena Zannoni
2003-10-09  0:45                     ` Roland McGrath
2003-10-08 23:10                 ` Elena Zannoni
2003-10-09  0:50                   ` Roland McGrath
2003-10-08 23:53                 ` Daniel Jacobowitz
2003-10-07  0:17         ` Daniel Jacobowitz
2003-10-07 23:54         ` Michael Snyder
2003-10-08  0:07           ` Roland McGrath
2003-10-07  4:43     ` Jim Blandy
2003-10-07  4:45       ` Roland McGrath
2003-10-09 19:58         ` Kevin Buettner
2003-10-09 20:02           ` Daniel Jacobowitz
2003-10-09 20:10             ` Jim Blandy
2003-10-09 22:20               ` Roland McGrath
2003-10-09 22:49                 ` Kevin Buettner
2003-10-10  0:12                   ` Michael Snyder
2003-10-11  1:44                   ` Roland McGrath
2003-10-09 23:04                 ` Kevin Buettner
2003-10-11  1:47                   ` Roland McGrath
2003-10-15  4:33                     ` Kevin Buettner
2003-10-09 20:21             ` Kevin Buettner
2003-10-09 20:23               ` Daniel Jacobowitz
2003-10-09 20:46                 ` Kevin Buettner
2003-10-09 22:32                   ` Roland McGrath
2003-10-09 22:46                     ` Kevin Buettner
2003-10-11  1:40                       ` Roland McGrath
2003-10-09 22:07           ` Roland McGrath
2003-10-09 22:32             ` Kevin Buettner
2003-10-07  3:33 Roland McGrath

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