[PATCH 0/2] Add support for Guile 3.0 and 2.2

classic Classic list List threaded Threaded
40 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[PATCH 0/2] Add support for Guile 3.0 and 2.2

Ludovic Courtès-3
Hello,

This is a long overdue update to the Guile bindings to support versions
2.2 (legacy) and 3.0 (current stable), in addition to the old 2.0.

For the record, the last 2.0 release was made in February 2017, but I
think keeping 2.0 support for a while will make the transition smoother.

Most of the work is about updating code that uses Guile’s I/O ports to
the new API that was introduced in Guile 2.2.  The new API leads to more
concise and less error-prone code but of course, since we’re also keeping
the 2.0 version, we’d only adding code at this point.

Tested with Guile 3.0.2, 2.2.7, and 2.0.14 on x86_64-linux-gnu (GNU Guix).
Specifically, this passes for all three versions:

  make check -C gdb TESTS=gdb.guile/*.exp

Let me know what you think!

Thanks,
Ludo’.

Ludovic Courtès (2):
  guile: Add support for Guile 2.2.
  guile: Add support for Guile 3.0.

 gdb/configure                            |   2 +-
 gdb/configure.ac                         |   2 +-
 gdb/doc/guile.texi                       |  23 +-
 gdb/guile/scm-math.c                     |   4 +-
 gdb/guile/scm-ports.c                    | 545 ++++++++++++++++-------
 gdb/testsuite/gdb.guile/scm-error.exp    |   2 +-
 gdb/testsuite/gdb.guile/scm-ports.exp    |   2 +-
 gdb/testsuite/gdb.guile/source2.scm      |   2 +-
 gdb/testsuite/gdb.guile/types-module.exp |   6 +-
 9 files changed, 400 insertions(+), 188 deletions(-)

--
2.26.2

Reply | Threaded
Open this post in threaded view
|

[PATCH 1/2] guile: Add support for Guile 2.2.

Ludovic Courtès-3
This primarily updates code that uses the I/O port API of Guile.

gdb/ChangeLog:

        * guile/scm-ports.c (USING_GUILE_BEFORE_2_2): New macro.
        (ioscm_memory_port)[read_buf_size, write_buf_size]: Wrap in #if
        USING_GUILE_BEFORE_2_2.
        (stdio_port_desc, memory_port_desc) [!USING_GUILE_BEFORE_2_2]:
        Change type to 'scm_t_port_type *'.
        (ioscm_open_port) [!USING_GUILE_BEFORE_2_2]: New function.
        (ioscm_read_from_port, ioscm_write) [!USING_GUILE_BEFORE_2_2]: New
        functions.
        (ioscm_fill_input, ioscm_input_waiting, ioscm_flush): Wrap in #if
        USING_GUILE_BEFORE_2_2.
        (ioscm_init_gdb_stdio_port) [!USING_GUILE_BEFORE_2_2]: Use
        'ioscm_read_from_port'.  Call 'scm_set_port_read_wait_fd'.
        (ioscm_init_stdio_buffers) [!USING_GUILE_BEFORE_2_2]: New function.
        (gdbscm_stdio_port_p) [!USING_GUILE_BEFORE_2_2]: Use 'SCM_PORTP'
        and 'SCM_PORT_TYPE'.
        (gdbscm_memory_port_end_input, gdbscm_memory_port_seek)
        (ioscm_reinit_memory_port): Wrap in #if USING_GUILE_BEFORE_2_2.
        (gdbscm_memory_port_read, gdbscm_memory_port_write)
        (gdbscm_memory_port_seek, gdbscm_memory_port_close)
        [!USING_GUILE_BEFORE_2_2]: New functions.
        (gdbscm_memory_port_print): Remove use of 'SCM_PTOB_NAME'.
        (ioscm_init_memory_port_type) [!USING_GUILE_BEFORE_2_2]: Use
        'gdbscm_memory_port_read'.
        Wrap 'scm_set_port_end_input', 'scm_set_port_flush', and
        'scm_set_port_free' calls in #if USING_GUILE_BEFORE_2_2.
        (ioscm_init_memory_port): Wrap buffer-related code in #if
        USING_GUILE_BEFORE_2_2.
        (gdbscm_memory_port_read_buffer_size) [!USING_GUILE_BEFORE_2_2]:
        Return scm_from_uint (0).
        (gdbscm_set_memory_port_read_buffer_size_x)
        [!USING_GUILE_BEFORE_2_2]: Call 'scm_setvbuf'.
        (gdbscm_memory_port_write_buffer_size) [!USING_GUILE_BEFORE_2_2]:
        Return scm_from_uint (0).
        (gdbscm_set_memory_port_write_buffer_size_x)
        [!USING_GUILE_BEFORE_2_2]: Call 'scm_setvbuf'.
        * testsuite/gdb.guile/scm-error.exp ("source
        $remote_guile_file_1"): Relax error regexp to match on Guile 2.2.
        * testsuite/gdb.guile/scm-ports.exp (test_mem_port_rw): Pass
        "r0+" instead of "r+" to 'open-memory' so make it explicitly
        unbuffered (it's buffered by default on 2.2/3.0).
        * configure.ac (try_guile_versions): Add "guile-2.2".
        * configure: Regenerate.
        * doc/guile.texi (Memory Ports in Guile): Remove
        documentation of 'memory-port-read-buffer-size',
        'set-memory-port-read-buffer-size!',
        'memory-port-write-buffer-size',
        'set-memory-port-read-buffer-size!', which are no longer
        supported with Guile 2.2/3.0 and superseded by 'setvbuf'.
        * doc/guile.texi (Guile Introduction): Clarify which Guile
        versions are supported.
---
 gdb/configure                         |   2 +-
 gdb/configure.ac                      |   2 +-
 gdb/doc/guile.texi                    |  23 +-
 gdb/guile/scm-ports.c                 | 545 ++++++++++++++++++--------
 gdb/testsuite/gdb.guile/scm-error.exp |   2 +-
 gdb/testsuite/gdb.guile/scm-ports.exp |   2 +-
 6 files changed, 394 insertions(+), 182 deletions(-)

diff --git a/gdb/configure b/gdb/configure
index ef10aa717f..bd12695291 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -10954,7 +10954,7 @@ fi
 
 
 
-try_guile_versions="guile-2.0"
+try_guile_versions="guile-2.2 guile-2.0"
 have_libguile=no
 case "${with_guile}" in
 no)
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 62750804fa..87afc26581 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1088,7 +1088,7 @@ AC_MSG_RESULT([$with_guile])
 dnl We check guile with pkg-config.
 AC_PATH_PROG(pkg_config_prog_path, pkg-config, missing)
 
-try_guile_versions="guile-2.0"
+try_guile_versions="guile-2.2 guile-2.0"
 have_libguile=no
 case "${with_guile}" in
 no)
diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index c0bff7972f..0e6c74ef8b 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -38,8 +38,7 @@ Guile support in @value{GDBN} follows the Python support in @value{GDBN}
 reasonably closely, so concepts there should carry over.
 However, some things are done differently where it makes sense.
 
-@value{GDBN} requires Guile version 2.0 or greater.
-Older versions are not supported.
+@value{GDBN} requires Guile version 2.2 or 2.0.
 
 @cindex guile scripts directory
 Guile scripts used by @value{GDBN} should be installed in
@@ -3556,26 +3555,6 @@ of two elements: @code{(start end)}.  The range is @var{start} to @var{end}
 inclusive.
 @end deffn
 
-@deffn {Scheme Procedure} memory-port-read-buffer-size memory-port
-Return the size of the read buffer of @code{<gdb:memory-port>}
-@var{memory-port}.
-@end deffn
-
-@deffn {Scheme Procedure} set-memory-port-read-buffer-size! memory-port size
-Set the size of the read buffer of @code{<gdb:memory-port>}
-@var{memory-port} to @var{size}.  The result is unspecified.
-@end deffn
-
-@deffn {Scheme Procedure} memory-port-write-buffer-size memory-port
-Return the size of the write buffer of @code{<gdb:memory-port>}
-@var{memory-port}.
-@end deffn
-
-@deffn {Scheme Procedure} set-memory-port-write-buffer-size! memory-port size
-Set the size of the write buffer of @code{<gdb:memory-port>}
-@var{memory-port} to @var{size}.  The result is unspecified.
-@end deffn
-
 A memory port is closed like any other port, with @code{close-port}.
 
 Combined with Guile's @code{bytevectors}, memory ports provide a lot
diff --git a/gdb/guile/scm-ports.c b/gdb/guile/scm-ports.c
index 407d1d36f1..5c39cc1ddf 100644
--- a/gdb/guile/scm-ports.c
+++ b/gdb/guile/scm-ports.c
@@ -36,6 +36,13 @@
 #endif
 #endif
 
+/* Whether we're using Guile < 2.2 and its clumsy port API.  */
+
+#define USING_GUILE_BEFORE_2_2 \
+  (SCM_MAJOR_VERSION < 2 \
+   || (SCM_MAJOR_VERSION == 2 && SCM_MINOR_VERSION == 0))
+
+
 /* A ui-file for sending output to Guile.  */
 
 class ioscm_file_port : public ui_file
@@ -66,12 +73,14 @@ typedef struct
      This value is always in the range [0, size].  */
   ULONGEST current;
 
+#if USING_GUILE_BEFORE_2_2
   /* The size of the internal r/w buffers.
      Scheme ports aren't a straightforward mapping to memory r/w.
      Generally the user specifies how much to r/w and all access is
      unbuffered.  We don't try to provide equivalent access, but we allow
      the user to specify these values to help get something similar.  */
   unsigned read_buf_size, write_buf_size;
+#endif
 } ioscm_memory_port;
 
 /* Copies of the original system input/output/error ports.
@@ -81,7 +90,11 @@ static SCM orig_output_port_scm;
 static SCM orig_error_port_scm;
 
 /* This is the stdio port descriptor, scm_ptob_descriptor.  */
+#if USING_GUILE_BEFORE_2_2
 static scm_t_bits stdio_port_desc;
+#else
+static scm_t_port_type *stdio_port_desc;
+#endif
 
 /* Note: scm_make_port_type takes a char * instead of a const char *.  */
 static /*const*/ char stdio_port_desc_name[] = "gdb:stdio-port";
@@ -102,7 +115,11 @@ static SCM error_port_scm;
 enum oport { GDB_STDOUT, GDB_STDERR };
 
 /* This is the memory port descriptor, scm_ptob_descriptor.  */
+#if USING_GUILE_BEFORE_2_2
 static scm_t_bits memory_port_desc;
+#else
+static scm_t_port_type *memory_port_desc;
+#endif
 
 /* Note: scm_make_port_type takes a char * instead of a const char *.  */
 static /*const*/ char memory_port_desc_name[] = "gdb:memory-port";
@@ -131,6 +148,8 @@ static SCM size_keyword;
 /* Helper to do the low level work of opening a port.
    Newer versions of Guile (2.1.x) have scm_c_make_port.  */
 
+#if USING_GUILE_BEFORE_2_2
+
 static SCM
 ioscm_open_port (scm_t_bits port_type, long mode_bits)
 {
@@ -150,9 +169,39 @@ ioscm_open_port (scm_t_bits port_type, long mode_bits)
 
   return port;
 }
+
+#else
+
+static SCM
+ioscm_open_port (scm_t_port_type *port_type, long mode_bits)
+{
+  return scm_c_make_port (port_type, mode_bits, 0);
+}
+
+#endif
+
 
 /* Support for connecting Guile's stdio ports to GDB's stdio ports.  */
 
+/* Like fputstrn_filtered, but don't escape characters, except nul.
+   Also like fputs_filtered, but a length is specified.  */
+
+static void
+fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
+{
+  size_t i;
+
+  for (i = 0; i < size; ++i)
+    {
+      if (s[i] == '\0')
+ fputs_filtered ("\\000", stream);
+      else
+ fputc_filtered (s[i], stream);
+    }
+}
+
+#if USING_GUILE_BEFORE_2_2
+
 /* The scm_t_ptob_descriptor.input_waiting "method".
    Return a lower bound on the number of bytes available for input.  */
 
@@ -245,23 +294,6 @@ ioscm_fill_input (SCM port)
   return *pt->read_buf;
 }
 
-/* Like fputstrn_filtered, but don't escape characters, except nul.
-   Also like fputs_filtered, but a length is specified.  */
-
-static void
-fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
-{
-  size_t i;
-
-  for (i = 0; i < size; ++i)
-    {
-      if (s[i] == '\0')
- fputs_filtered ("\\000", stream);
-      else
- fputc_filtered (s[i], stream);
-    }
-}
-
 /* Write to gdb's stdout or stderr.  */
 
 static void
@@ -302,6 +334,62 @@ ioscm_flush (SCM port)
     gdb_flush (gdb_stdout);
 }
 
+#else /* !USING_GUILE_BEFORE_2_2 */
+
+/* Read up to COUNT bytes into bytevector DST at offset START.  Return the
+   number of bytes read, zero for the end of file.  */
+
+static size_t
+ioscm_read_from_port (SCM port, SCM dst, size_t start, size_t count)
+{
+  long read;
+  char *read_buf;
+
+  /* If we're called on stdout,stderr, punt.  */
+  if (! scm_is_eq (port, input_port_scm))
+    return 0;
+
+  gdb_flush (gdb_stdout);
+  gdb_flush (gdb_stderr);
+
+  read_buf = (char *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
+  read = gdb_stdin->read (read_buf, count);
+  if (read == -1)
+    scm_syserror (FUNC_NAME);
+
+  return (size_t) read;
+}
+
+/* Write to gdb's stdout or stderr.  */
+
+static size_t
+ioscm_write (SCM port, SCM src, size_t start, size_t count)
+{
+  const char *data = (char *) SCM_BYTEVECTOR_CONTENTS (src) + start;
+
+  /* If we're called on stdin, punt.  */
+  if (scm_is_eq (port, input_port_scm))
+    return 0;
+
+  gdbscm_gdb_exception exc {};
+  try
+    {
+      if (scm_is_eq (port, error_port_scm))
+ fputsn_filtered ((const char *) data, count, gdb_stderr);
+      else
+ fputsn_filtered ((const char *) data, count, gdb_stdout);
+    }
+  catch (const gdb_exception &except)
+    {
+      exc = unpack (except);
+    }
+  GDBSCM_HANDLE_GDB_EXCEPTION (exc);
+
+  return count;
+}
+
+#endif /* !USING_GUILE_BEFORE_2_2 */
+
 /* Initialize the gdb stdio port type.
 
    N.B. isatty? will fail on these ports, it is only supported for file
@@ -311,12 +399,25 @@ static void
 ioscm_init_gdb_stdio_port (void)
 {
   stdio_port_desc = scm_make_port_type (stdio_port_desc_name,
- ioscm_fill_input, ioscm_write);
+#if USING_GUILE_BEFORE_2_2
+ ioscm_fill_input,
+#else
+ ioscm_read_from_port,
+#endif
+ ioscm_write);
 
+#if USING_GUILE_BEFORE_2_2
   scm_set_port_input_waiting (stdio_port_desc, ioscm_input_waiting);
   scm_set_port_flush (stdio_port_desc, ioscm_flush);
+#else
+  scm_set_port_read_wait_fd (stdio_port_desc, STDIN_FILENO);
+#endif
 }
 
+#define GDB_STDIO_BUFFER_DEFAULT_SIZE 1024
+
+#if USING_GUILE_BEFORE_2_2
+
 /* Subroutine of ioscm_make_gdb_stdio_port to simplify it.
    Set up the buffers of port PORT.
    MODE_BITS are the mode bits of PORT.  */
@@ -325,7 +426,6 @@ static void
 ioscm_init_stdio_buffers (SCM port, long mode_bits)
 {
   scm_t_port *pt = SCM_PTAB_ENTRY (port);
-#define GDB_STDIO_BUFFER_DEFAULT_SIZE 1024
   int size = mode_bits & SCM_BUF0 ? 0 : GDB_STDIO_BUFFER_DEFAULT_SIZE;
   int writing = (mode_bits & SCM_WRTNG) != 0;
 
@@ -359,6 +459,20 @@ ioscm_init_stdio_buffers (SCM port, long mode_bits)
   pt->write_end = pt->write_buf + pt->write_buf_size;
 }
 
+#else
+
+static void
+ioscm_init_stdio_buffers (SCM port, long mode_bits)
+{
+  if (mode_bits & SCM_BUF0)
+    scm_setvbuf (port, scm_from_utf8_symbol ("none"), scm_from_size_t (0));
+  else
+    scm_setvbuf (port, scm_from_utf8_symbol ("block"),
+ scm_from_size_t (GDB_STDIO_BUFFER_DEFAULT_SIZE));
+}
+
+#endif
+
 /* Create a gdb stdio port.  */
 
 static SCM
@@ -403,9 +517,14 @@ ioscm_make_gdb_stdio_port (int fd)
 static SCM
 gdbscm_stdio_port_p (SCM scm)
 {
+#if USING_GUILE_BEFORE_2_2
   /* This is copied from SCM_FPORTP.  */
   return scm_from_bool (!SCM_IMP (scm)
  && (SCM_TYP16 (scm) == stdio_port_desc));
+#else
+  return scm_from_bool (SCM_PORTP (scm)
+ && (SCM_PORT_TYPE (scm) == stdio_port_desc));
+#endif
 }
 
 /* GDB's ports are accessed via functions to keep them read-only.  */
@@ -568,6 +687,8 @@ ioscm_lseek_address (ioscm_memory_port *iomem, LONGEST offset, int whence)
   return 1;
 }
 
+#if USING_GUILE_BEFORE_2_2
+
 /* "fill_input" method for memory ports.  */
 
 static int
@@ -661,73 +782,6 @@ gdbscm_memory_port_flush (SCM port)
   pt->rw_active = SCM_PORT_NEITHER;
 }
 
-/* "write" method for memory ports.  */
-
-static void
-gdbscm_memory_port_write (SCM port, const void *void_data, size_t size)
-{
-  scm_t_port *pt = SCM_PTAB_ENTRY (port);
-  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
-  const gdb_byte *data = (const gdb_byte *) void_data;
-
-  /* There's no way to indicate a short write, so if the request goes past
-     the end of the port's memory range, flag an error.  */
-  if (size > iomem->size - iomem->current)
-    {
-      gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size),
- _("writing beyond end of memory range"));
-    }
-
-  if (pt->write_buf == &pt->shortbuf)
-    {
-      /* Unbuffered port.  */
-      if (target_write_memory (iomem->start + iomem->current, data, size) != 0)
- gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
-      iomem->current += size;
-      return;
-    }
-
-  /* Note: The edge case of what to do when the buffer exactly fills is
-     debatable.  Guile flushes when the buffer exactly fills up, so we
-     do too.  It's counter-intuitive to my mind, but in case there's a
-     subtlety somewhere that depends on this, we do the same.  */
-
-  {
-    size_t space = pt->write_end - pt->write_pos;
-
-    if (size < space)
-      {
- /* Data fits in buffer, and does not fill it.  */
- memcpy (pt->write_pos, data, size);
- pt->write_pos += size;
-      }
-    else
-      {
- memcpy (pt->write_pos, data, space);
- pt->write_pos = pt->write_end;
- gdbscm_memory_port_flush (port);
- {
-  const gdb_byte *ptr = data + space;
-  size_t remaining = size - space;
-
-  if (remaining >= pt->write_buf_size)
-    {
-      if (target_write_memory (iomem->start + iomem->current, ptr,
-       remaining) != 0)
- gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
-     SCM_EOL);
-      iomem->current += remaining;
-    }
-  else
-    {
-      memcpy (pt->write_pos, ptr, remaining);
-      pt->write_pos += remaining;
-    }
- }
-      }
-  }
-}
-
 /* "seek" method for memory ports.  */
 
 static scm_t_off
@@ -820,6 +874,73 @@ gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
   return result;
 }
 
+/* "write" method for memory ports.  */
+
+static void
+gdbscm_memory_port_write (SCM port, const void *void_data, size_t size)
+{
+  scm_t_port *pt = SCM_PTAB_ENTRY (port);
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+  const gdb_byte *data = (const gdb_byte *) void_data;
+
+  /* There's no way to indicate a short write, so if the request goes past
+     the end of the port's memory range, flag an error.  */
+  if (size > iomem->size - iomem->current)
+    {
+      gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size),
+ _("writing beyond end of memory range"));
+    }
+
+  if (pt->write_buf == &pt->shortbuf)
+    {
+      /* Unbuffered port.  */
+      if (target_write_memory (iomem->start + iomem->current, data, size) != 0)
+ gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
+      iomem->current += size;
+      return;
+    }
+
+  /* Note: The edge case of what to do when the buffer exactly fills is
+     debatable.  Guile flushes when the buffer exactly fills up, so we
+     do too.  It's counter-intuitive to my mind, but in case there's a
+     subtlety somewhere that depends on this, we do the same.  */
+
+  {
+    size_t space = pt->write_end - pt->write_pos;
+
+    if (size < space)
+      {
+ /* Data fits in buffer, and does not fill it.  */
+ memcpy (pt->write_pos, data, size);
+ pt->write_pos += size;
+      }
+    else
+      {
+ memcpy (pt->write_pos, data, space);
+ pt->write_pos = pt->write_end;
+ gdbscm_memory_port_flush (port);
+ {
+  const gdb_byte *ptr = data + space;
+  size_t remaining = size - space;
+
+  if (remaining >= pt->write_buf_size)
+    {
+      if (target_write_memory (iomem->start + iomem->current, ptr,
+       remaining) != 0)
+ gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
+     SCM_EOL);
+      iomem->current += remaining;
+    }
+  else
+    {
+      memcpy (pt->write_pos, ptr, remaining);
+      pt->write_pos += remaining;
+    }
+ }
+      }
+  }
+}
+
 /* "close" method for memory ports.  */
 
 static int
@@ -851,18 +972,166 @@ gdbscm_memory_port_free (SCM port)
   return 0;
 }
 
+/* Re-initialize a memory port, updating its read/write buffer sizes.
+   An exception is thrown if the port is unbuffered.
+   TODO: Allow switching buffered/unbuffered.
+   An exception is also thrown if data is still buffered, except in the case
+   where the buffer size isn't changing (since that's just a nop).  */
+
+static void
+ioscm_reinit_memory_port (SCM port, size_t read_buf_size,
+  size_t write_buf_size, const char *func_name)
+{
+  scm_t_port *pt = SCM_PTAB_ENTRY (port);
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+
+  gdb_assert (read_buf_size >= min_memory_port_buf_size
+      && read_buf_size <= max_memory_port_buf_size);
+  gdb_assert (write_buf_size >= min_memory_port_buf_size
+      && write_buf_size <= max_memory_port_buf_size);
+
+  /* First check if the port is unbuffered.  */
+
+  if (pt->read_buf == &pt->shortbuf)
+    {
+      gdb_assert (pt->write_buf == &pt->shortbuf);
+      scm_misc_error (func_name, _("port is unbuffered: ~a"),
+      scm_list_1 (port));
+    }
+
+  /* Next check if anything is buffered.  */
+
+  if (read_buf_size != pt->read_buf_size
+      && pt->read_end != pt->read_buf)
+    {
+      scm_misc_error (func_name, _("read buffer not empty: ~a"),
+      scm_list_1 (port));
+    }
+
+  if (write_buf_size != pt->write_buf_size
+      && pt->write_pos != pt->write_buf)
+    {
+      scm_misc_error (func_name, _("write buffer not empty: ~a"),
+      scm_list_1 (port));
+    }
+
+  /* Now we can update the buffer sizes, but only if the size has changed.  */
+
+  if (read_buf_size != pt->read_buf_size)
+    {
+      iomem->read_buf_size = read_buf_size;
+      pt->read_buf_size = read_buf_size;
+      xfree (pt->read_buf);
+      pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
+      pt->read_pos = pt->read_end = pt->read_buf;
+    }
+
+  if (write_buf_size != pt->write_buf_size)
+    {
+      iomem->write_buf_size = write_buf_size;
+      pt->write_buf_size = write_buf_size;
+      xfree (pt->write_buf);
+      pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
+      pt->write_pos = pt->write_buf;
+      pt->write_end = pt->write_buf + pt->write_buf_size;
+    }
+}
+
+#else /* !USING_GUILE_BEFORE_2_2 */
+
+/* Read up to COUNT bytes into bytevector DST at offset START.  Return the
+   number of bytes read, zero for the end of file.  */
+
+static size_t
+gdbscm_memory_port_read (SCM port, SCM dst, size_t start, size_t count)
+{
+  gdb_byte *read_buf;
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+
+  /* "current" is the offset of the first byte we want to read.  */
+  gdb_assert (iomem->current <= iomem->size);
+  if (iomem->current == iomem->size)
+    return 0;
+
+  /* Don't read outside the allowed memory range.  */
+  if (count > iomem->size - iomem->current)
+    count = iomem->size - iomem->current;
+
+  read_buf = (gdb_byte *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
+  if (target_read_memory (iomem->start + iomem->current, read_buf,
+  count) != 0)
+    gdbscm_memory_error (FUNC_NAME, _("error reading memory"), SCM_EOL);
+
+  iomem->current += count;
+  return count;
+}
+
+static size_t
+gdbscm_memory_port_write (SCM port, SCM src, size_t start, size_t count)
+{
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+  const gdb_byte *data =
+    (const gdb_byte *) SCM_BYTEVECTOR_CONTENTS (src) + start;
+
+  /* If the request goes past the end of the port's memory range, flag an
+     error.  */
+  if (count > iomem->size - iomem->current)
+    gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_size_t (count),
+       _("writing beyond end of memory range"));
+
+  if (target_write_memory (iomem->start + iomem->current, data,
+   count) != 0)
+    gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
+ SCM_EOL);
+
+  iomem->current += count;
+
+  return count;
+}
+
+static scm_t_off
+gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
+{
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+  CORE_ADDR result;
+  int rc;
+
+  rc = ioscm_lseek_address (iomem, offset, whence);
+  result = iomem->current;
+
+  if (rc == 0)
+    gdbscm_out_of_range_error (FUNC_NAME, 0,
+       gdbscm_scm_from_longest (offset),
+       _("bad seek"));
+
+  /* TODO: The Guile API doesn't support 32x64.  We can't fix that here,
+     and there's no need to throw an error if the new address can't be
+     represented in a scm_t_off.  But we could return something less
+     clumsy.  */
+  return result;
+}
+
+static void
+gdbscm_memory_port_close (SCM port)
+{
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+  scm_gc_free (iomem, sizeof (*iomem), "memory port");
+  SCM_SETSTREAM (port, NULL);
+}
+
+#endif /* !USING_GUILE_BEFORE_2_2 */
+
 /* "print" method for memory ports.  */
 
 static int
 gdbscm_memory_port_print (SCM exp, SCM port, scm_print_state *pstate)
 {
   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (exp);
-  char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
 
   scm_puts ("#<", port);
   scm_print_port_mode (exp, port);
   /* scm_print_port_mode includes a trailing space.  */
-  gdbscm_printf (port, "%s %s-%s", type,
+  gdbscm_printf (port, "%s %s-%s", memory_port_desc_name,
  hex_string (iomem->start), hex_string (iomem->end));
   scm_putc ('>', port);
   return 1;
@@ -874,14 +1143,20 @@ static void
 ioscm_init_memory_port_type (void)
 {
   memory_port_desc = scm_make_port_type (memory_port_desc_name,
+#if USING_GUILE_BEFORE_2_2
  gdbscm_memory_port_fill_input,
+#else
+ gdbscm_memory_port_read,
+#endif
  gdbscm_memory_port_write);
 
+#if USING_GUILE_BEFORE_2_2
   scm_set_port_end_input (memory_port_desc, gdbscm_memory_port_end_input);
   scm_set_port_flush (memory_port_desc, gdbscm_memory_port_flush);
+  scm_set_port_free (memory_port_desc, gdbscm_memory_port_free);
+#endif
   scm_set_port_seek (memory_port_desc, gdbscm_memory_port_seek);
   scm_set_port_close (memory_port_desc, gdbscm_memory_port_close);
-  scm_set_port_free (memory_port_desc, gdbscm_memory_port_free);
   scm_set_port_print (memory_port_desc, gdbscm_memory_port_print);
 }
 
@@ -930,9 +1205,7 @@ ioscm_parse_mode_bits (const char *func_name, const char *mode)
 static void
 ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
 {
-  scm_t_port *pt;
   ioscm_memory_port *iomem;
-  int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0;
 
   gdb_assert (start <= end);
 
@@ -943,6 +1216,9 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
   iomem->end = end;
   iomem->size = end - start;
   iomem->current = 0;
+
+#if USING_GUILE_BEFORE_2_2
+  int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0;
   if (buffered)
     {
       iomem->read_buf_size = default_read_buf_size;
@@ -954,7 +1230,7 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
       iomem->write_buf_size = 1;
     }
 
-  pt = SCM_PTAB_ENTRY (port);
+  scm_t_port *pt = SCM_PTAB_ENTRY (port);
   /* Match the expectation of `binary-port?'.  */
   pt->encoding = NULL;
   pt->rw_random = 1;
@@ -973,74 +1249,11 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
   pt->read_pos = pt->read_end = pt->read_buf;
   pt->write_pos = pt->write_buf;
   pt->write_end = pt->write_buf + pt->write_buf_size;
+#endif
 
   SCM_SETSTREAM (port, iomem);
 }
 
-/* Re-initialize a memory port, updating its read/write buffer sizes.
-   An exception is thrown if the port is unbuffered.
-   TODO: Allow switching buffered/unbuffered.
-   An exception is also thrown if data is still buffered, except in the case
-   where the buffer size isn't changing (since that's just a nop).  */
-
-static void
-ioscm_reinit_memory_port (SCM port, size_t read_buf_size,
-  size_t write_buf_size, const char *func_name)
-{
-  scm_t_port *pt = SCM_PTAB_ENTRY (port);
-  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
-
-  gdb_assert (read_buf_size >= min_memory_port_buf_size
-      && read_buf_size <= max_memory_port_buf_size);
-  gdb_assert (write_buf_size >= min_memory_port_buf_size
-      && write_buf_size <= max_memory_port_buf_size);
-
-  /* First check if the port is unbuffered.  */
-
-  if (pt->read_buf == &pt->shortbuf)
-    {
-      gdb_assert (pt->write_buf == &pt->shortbuf);
-      scm_misc_error (func_name, _("port is unbuffered: ~a"),
-      scm_list_1 (port));
-    }
-
-  /* Next check if anything is buffered.  */
-
-  if (read_buf_size != pt->read_buf_size
-      && pt->read_end != pt->read_buf)
-    {
-      scm_misc_error (func_name, _("read buffer not empty: ~a"),
-      scm_list_1 (port));
-    }
-
-  if (write_buf_size != pt->write_buf_size
-      && pt->write_pos != pt->write_buf)
-    {
-      scm_misc_error (func_name, _("write buffer not empty: ~a"),
-      scm_list_1 (port));
-    }
-
-  /* Now we can update the buffer sizes, but only if the size has changed.  */
-
-  if (read_buf_size != pt->read_buf_size)
-    {
-      iomem->read_buf_size = read_buf_size;
-      pt->read_buf_size = read_buf_size;
-      xfree (pt->read_buf);
-      pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
-      pt->read_pos = pt->read_end = pt->read_buf;
-    }
-
-  if (write_buf_size != pt->write_buf_size)
-    {
-      iomem->write_buf_size = write_buf_size;
-      pt->write_buf_size = write_buf_size;
-      xfree (pt->write_buf);
-      pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
-      pt->write_pos = pt->write_buf;
-      pt->write_end = pt->write_buf + pt->write_buf_size;
-    }
-}
 
 /* (open-memory [#:mode string] [#:start address] [#:size integer]) -> port
    Return a port that can be used for reading and writing memory.
@@ -1124,7 +1337,11 @@ gdbscm_open_memory (SCM rest)
 static int
 gdbscm_is_memory_port (SCM obj)
 {
+#if USING_GUILE_BEFORE_2_2
   return !SCM_IMP (obj) && (SCM_TYP16 (obj) == memory_port_desc);
+#else
+  return SCM_PORTP (obj) && (SCM_PORT_TYPE (obj) == memory_port_desc);
+#endif
 }
 
 /* (memory-port? obj) -> boolean */
@@ -1155,6 +1372,7 @@ gdbscm_memory_port_range (SCM port)
 static SCM
 gdbscm_memory_port_read_buffer_size (SCM port)
 {
+#if USING_GUILE_BEFORE_2_2
   ioscm_memory_port *iomem;
 
   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
@@ -1162,6 +1380,9 @@ gdbscm_memory_port_read_buffer_size (SCM port)
 
   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   return scm_from_uint (iomem->read_buf_size);
+#else
+  return scm_from_uint (0);
+#endif
 }
 
 /* (set-memory-port-read-buffer-size! port size) -> unspecified
@@ -1171,6 +1392,7 @@ gdbscm_memory_port_read_buffer_size (SCM port)
 static SCM
 gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
 {
+#if USING_GUILE_BEFORE_2_2
   ioscm_memory_port *iomem;
 
   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
@@ -1190,6 +1412,9 @@ gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
     FUNC_NAME);
 
   return SCM_UNSPECIFIED;
+#else
+  return scm_setvbuf (port, scm_from_utf8_symbol ("block"), size);
+#endif
 }
 
 /* (memory-port-write-buffer-size port) -> integer */
@@ -1197,6 +1422,7 @@ gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
 static SCM
 gdbscm_memory_port_write_buffer_size (SCM port)
 {
+#if USING_GUILE_BEFORE_2_2
   ioscm_memory_port *iomem;
 
   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
@@ -1204,6 +1430,9 @@ gdbscm_memory_port_write_buffer_size (SCM port)
 
   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   return scm_from_uint (iomem->write_buf_size);
+#else
+  return scm_from_uint (0);
+#endif
 }
 
 /* (set-memory-port-write-buffer-size! port size) -> unspecified
@@ -1213,6 +1442,7 @@ gdbscm_memory_port_write_buffer_size (SCM port)
 static SCM
 gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size)
 {
+#if USING_GUILE_BEFORE_2_2
   ioscm_memory_port *iomem;
 
   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
@@ -1232,6 +1462,9 @@ gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size)
     FUNC_NAME);
 
   return SCM_UNSPECIFIED;
+#else
+  return scm_setvbuf (port, scm_from_utf8_symbol ("block"), size);
+#endif
 }
 
 /* Initialize gdb ports.  */
diff --git a/gdb/testsuite/gdb.guile/scm-error.exp b/gdb/testsuite/gdb.guile/scm-error.exp
index 799bfe5db0..f073200b6e 100644
--- a/gdb/testsuite/gdb.guile/scm-error.exp
+++ b/gdb/testsuite/gdb.guile/scm-error.exp
@@ -34,7 +34,7 @@ set remote_guile_file_2 [gdb_remote_download host \
      ${srcdir}/${subdir}/${testfile}-2.scm]
 
 gdb_test "source $remote_guile_file_1" \
-    "(ERROR: )?In procedure \[+\]: Wrong type: #f.*" \
+    "(ERROR: )?In procedure \[+\]: Wrong type.*: #f.*" \
     "error loading scm file caught"
 
 gdb_test "p 1" " = 1" "no delayed error"
diff --git a/gdb/testsuite/gdb.guile/scm-ports.exp b/gdb/testsuite/gdb.guile/scm-ports.exp
index b2835ddc75..47da3d43d3 100644
--- a/gdb/testsuite/gdb.guile/scm-ports.exp
+++ b/gdb/testsuite/gdb.guile/scm-ports.exp
@@ -154,7 +154,7 @@ test_mem_port_rw unbuffered
 
 # Test zero-length memory ports.
 
-gdb_test_no_output "guile (define zero-mem-port (open-memory #:start 0 #:size 0 #:mode \"r+\"))" \
+gdb_test_no_output "guile (define zero-mem-port (open-memory #:start 0 #:size 0 #:mode \"r0+\"))" \
     "create zero length memory port"
 gdb_test "guile (print (read-char zero-mem-port))" \
     "= #<eof>"
--
2.26.2

Reply | Threaded
Open this post in threaded view
|

[PATCH 2/2] guile: Add support for Guile 3.0.

Ludovic Courtès-3
In reply to this post by Ludovic Courtès-3
gdb/ChangeLog:

        * guile/scm-math.c (vlscm_integer_fits_p): Use 'uintmax_t'
        and 'intmax_t' instead of 'scm_t_uintmax' and 'scm_t_intmax',
        which are deprecated in Guile 3.0.
        * testsuite/gdb.guile/source2.scm: Add #f first argument to
        'format'.
        * testsuite/gdb.guile/types-module.exp: Remove "ERROR:" from
        regexps since Guile 3.0 no longer prints that.
        * configure.ac (try_guile_versions): Add "guile-3.0".
        * configure (try_guile_versions): Regenerate.
        * doc/guile.texi (Guile Introduction): Mention Guile 3.0.
---
 gdb/configure                            | 2 +-
 gdb/configure.ac                         | 2 +-
 gdb/doc/guile.texi                       | 2 +-
 gdb/guile/scm-math.c                     | 4 ++--
 gdb/testsuite/gdb.guile/source2.scm      | 2 +-
 gdb/testsuite/gdb.guile/types-module.exp | 6 +++---
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/gdb/configure b/gdb/configure
index bd12695291..5ad1e53ac4 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -10954,7 +10954,7 @@ fi
 
 
 
-try_guile_versions="guile-2.2 guile-2.0"
+try_guile_versions="guile-3.0 guile-2.2 guile-2.0"
 have_libguile=no
 case "${with_guile}" in
 no)
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 87afc26581..d8cef1e914 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1088,7 +1088,7 @@ AC_MSG_RESULT([$with_guile])
 dnl We check guile with pkg-config.
 AC_PATH_PROG(pkg_config_prog_path, pkg-config, missing)
 
-try_guile_versions="guile-2.2 guile-2.0"
+try_guile_versions="guile-3.0 guile-2.2 guile-2.0"
 have_libguile=no
 case "${with_guile}" in
 no)
diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index 0e6c74ef8b..45c8f3f197 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -38,7 +38,7 @@ Guile support in @value{GDBN} follows the Python support in @value{GDBN}
 reasonably closely, so concepts there should carry over.
 However, some things are done differently where it makes sense.
 
-@value{GDBN} requires Guile version 2.2 or 2.0.
+@value{GDBN} requires Guile version 3.0, 2.2, or 2.0.
 
 @cindex guile scripts directory
 Guile scripts used by @value{GDBN} should be installed in
diff --git a/gdb/guile/scm-math.c b/gdb/guile/scm-math.c
index 7c63fa2ae0..419f5099bf 100644
--- a/gdb/guile/scm-math.c
+++ b/gdb/guile/scm-math.c
@@ -578,7 +578,7 @@ vlscm_integer_fits_p (SCM obj, struct type *type)
       ULONGEST max;
 
       /* If scm_is_unsigned_integer can't work with this type, just punt.  */
-      if (TYPE_LENGTH (type) > sizeof (scm_t_uintmax))
+      if (TYPE_LENGTH (type) > sizeof (uintmax_t))
  return 0;
       get_unsigned_type_max (type, &max);
       return scm_is_unsigned_integer (obj, 0, max);
@@ -588,7 +588,7 @@ vlscm_integer_fits_p (SCM obj, struct type *type)
       LONGEST min, max;
 
       /* If scm_is_signed_integer can't work with this type, just punt.  */
-      if (TYPE_LENGTH (type) > sizeof (scm_t_intmax))
+      if (TYPE_LENGTH (type) > sizeof (intmax_t))
  return 0;
       get_signed_type_minmax (type, &min, &max);
       return scm_is_signed_integer (obj, min, max);
diff --git a/gdb/testsuite/gdb.guile/source2.scm b/gdb/testsuite/gdb.guile/source2.scm
index 39638053d9..c39f03801a 100644
--- a/gdb/testsuite/gdb.guile/source2.scm
+++ b/gdb/testsuite/gdb.guile/source2.scm
@@ -15,5 +15,5 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-(display (format "y~As" "e"))
+(display (format #f "y~As" "e"))
 (newline)
diff --git a/gdb/testsuite/gdb.guile/types-module.exp b/gdb/testsuite/gdb.guile/types-module.exp
index 5a631dca8e..8ced6fbffb 100644
--- a/gdb/testsuite/gdb.guile/types-module.exp
+++ b/gdb/testsuite/gdb.guile/types-module.exp
@@ -44,7 +44,7 @@ gdb_test "guile (print (type-has-field-deep? d \"base_member\"))" \
     "= #t" "type-has-field-deep? member in baseclass"
 
 gdb_test "guile (print (type-has-field-deep? (lookup-type \"int\") \"base_member\"))" \
-    "ERROR: .*Wrong type argument in position 1 \\(expecting struct or union\\): #<gdb:type int>.*" \
+    "Wrong type argument in position 1 \\(expecting struct or union\\): #<gdb:type int>.*" \
     "type-has-field-deep? from int"
 
 gdb_scm_test_silent_cmd "guile (define enum-htab (make-enum-hashtable (lookup-type \"enum_type\")))" \
@@ -54,9 +54,9 @@ gdb_test "guile (print (hash-ref enum-htab \"B\"))" \
     "= 1" "verify make-enum-hashtable"
 
 gdb_test "guile (define bad-enum-htab (make-enum-hashtable #f))" \
-    "ERROR: .*Wrong type argument in position 1 \\(expecting gdb:type\\): #f.*" \
+    "Wrong type argument in position 1 \\(expecting gdb:type\\): #f.*" \
     "make-enum-hashtable from #f"
 
 gdb_test "guile (define bad-enum-htab (make-enum-hashtable (lookup-type \"int\")))" \
-    "ERROR: .*Wrong type argument in position 1 \\(expecting enum\\): #<gdb:type int>.*" \
+    "Wrong type argument in position 1 \\(expecting enum\\): #<gdb:type int>.*" \
     "make-enum-hashtable from int"
--
2.26.2

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/2] guile: Add support for Guile 2.2.

Eli Zaretskii
In reply to this post by Ludovic Courtès-3
> From: Ludovic Courtès <[hidden email]>
> Date: Fri, 12 Jun 2020 15:27:09 +0200
> Cc: Ludovic Courtès <[hidden email]>
>
> This primarily updates code that uses the I/O port API of Guile.
>
> * doc/guile.texi (Memory Ports in Guile): Remove
> documentation of 'memory-port-read-buffer-size',
> 'set-memory-port-read-buffer-size!',
> 'memory-port-write-buffer-size',
> 'set-memory-port-read-buffer-size!', which are no longer
> supported with Guile 2.2/3.0 and superseded by 'setvbuf'.
> * doc/guile.texi (Guile Introduction): Clarify which Guile
> versions are supported.

gdb/doc/ has a separate ChangeLog file; please use that to describe
changes in the manual.

More importantly, I don't understand why we'd want to remove the
documentation of these functions.  Are we removing the functions as
well (I don't think I saw the code being removed)?  If we are not
removing the functions, why remove their docs?  You say that the
corresponding Guile functionality is superseded by setvbuf, but
doesn't it mean the GDB-specific capability based on that will be
rewritten using the new Guile features, and we can continue supporting
them?

Sorry for my confusion; perhaps more detailed log messages would have
prevented that.

Also, does any of this need to be called out in NEWS?

Thanks.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/2] guile: Add support for Guile 2.2.

Ludovic Courtès-3
Hello,

Eli Zaretskii <[hidden email]> skribis:

>> From: Ludovic Courtès <[hidden email]>
>> Date: Fri, 12 Jun 2020 15:27:09 +0200
>> Cc: Ludovic Courtès <[hidden email]>
>>
>> This primarily updates code that uses the I/O port API of Guile.
>>
>> * doc/guile.texi (Memory Ports in Guile): Remove
>> documentation of 'memory-port-read-buffer-size',
>> 'set-memory-port-read-buffer-size!',
>> 'memory-port-write-buffer-size',
>> 'set-memory-port-read-buffer-size!', which are no longer
>> supported with Guile 2.2/3.0 and superseded by 'setvbuf'.
>> * doc/guile.texi (Guile Introduction): Clarify which Guile
>> versions are supported.
>
> gdb/doc/ has a separate ChangeLog file; please use that to describe
> changes in the manual.

Oops, will do.

> More importantly, I don't understand why we'd want to remove the
> documentation of these functions.  Are we removing the functions as
> well (I don't think I saw the code being removed)?  If we are not
> removing the functions, why remove their docs?  You say that the
> corresponding Guile functionality is superseded by setvbuf, but
> doesn't it mean the GDB-specific capability based on that will be
> rewritten using the new Guile features, and we can continue supporting
> them?

These four functions are not used in tests, in documented examples, nor
in Guile’s own GDB plugin.

‘setvbuf’ is not entirely a drop-in replacement because: (1) it doesn’t
allow you to query a port’s buffer size, only to change it, and (2) it
doesn’t distinguish between the read and write buffers.  Consequently,
these functions cannot be implemented on 2.2/3.0, or at least not
easily.

Since they are unused, and I can’t see a valid use case for those over
‘setvbuf’, I chose to remove them from the manual as a way to deprecate
them.

WDYT?

> Also, does any of this need to be called out in NEWS?

Oh sure.  Should that go in a separate commit or in the same?

I’ll wait for additional feedback and send a v2 afterwards, if that’s
fine with you.

Thanks for the quick reply,
Ludo’.

PS: I lost Git access to sourceware.org some years ago because my
    registered SSH key was DSA, IIRC.  Should I apply to restore it?
    What’s the procedure?
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/2] guile: Add support for Guile 2.2.

Tom de Vries
In reply to this post by Ludovic Courtès-3
On 12-06-2020 15:27, Ludovic Courtès wrote:
> This primarily updates code that uses the I/O port API of Guile.
>
> gdb/ChangeLog:
>

It looks like you could claim fixing PR guile/21104 here.

Thanks,
- Tom

> * guile/scm-ports.c (USING_GUILE_BEFORE_2_2): New macro.
> (ioscm_memory_port)[read_buf_size, write_buf_size]: Wrap in #if
> USING_GUILE_BEFORE_2_2.
> (stdio_port_desc, memory_port_desc) [!USING_GUILE_BEFORE_2_2]:
> Change type to 'scm_t_port_type *'.
> (ioscm_open_port) [!USING_GUILE_BEFORE_2_2]: New function.
> (ioscm_read_from_port, ioscm_write) [!USING_GUILE_BEFORE_2_2]: New
> functions.
> (ioscm_fill_input, ioscm_input_waiting, ioscm_flush): Wrap in #if
> USING_GUILE_BEFORE_2_2.
> (ioscm_init_gdb_stdio_port) [!USING_GUILE_BEFORE_2_2]: Use
> 'ioscm_read_from_port'.  Call 'scm_set_port_read_wait_fd'.
> (ioscm_init_stdio_buffers) [!USING_GUILE_BEFORE_2_2]: New function.
> (gdbscm_stdio_port_p) [!USING_GUILE_BEFORE_2_2]: Use 'SCM_PORTP'
> and 'SCM_PORT_TYPE'.
> (gdbscm_memory_port_end_input, gdbscm_memory_port_seek)
> (ioscm_reinit_memory_port): Wrap in #if USING_GUILE_BEFORE_2_2.
> (gdbscm_memory_port_read, gdbscm_memory_port_write)
> (gdbscm_memory_port_seek, gdbscm_memory_port_close)
> [!USING_GUILE_BEFORE_2_2]: New functions.
> (gdbscm_memory_port_print): Remove use of 'SCM_PTOB_NAME'.
> (ioscm_init_memory_port_type) [!USING_GUILE_BEFORE_2_2]: Use
> 'gdbscm_memory_port_read'.
> Wrap 'scm_set_port_end_input', 'scm_set_port_flush', and
> 'scm_set_port_free' calls in #if USING_GUILE_BEFORE_2_2.
> (ioscm_init_memory_port): Wrap buffer-related code in #if
> USING_GUILE_BEFORE_2_2.
> (gdbscm_memory_port_read_buffer_size) [!USING_GUILE_BEFORE_2_2]:
> Return scm_from_uint (0).
> (gdbscm_set_memory_port_read_buffer_size_x)
> [!USING_GUILE_BEFORE_2_2]: Call 'scm_setvbuf'.
> (gdbscm_memory_port_write_buffer_size) [!USING_GUILE_BEFORE_2_2]:
> Return scm_from_uint (0).
> (gdbscm_set_memory_port_write_buffer_size_x)
> [!USING_GUILE_BEFORE_2_2]: Call 'scm_setvbuf'.
> * testsuite/gdb.guile/scm-error.exp ("source
> $remote_guile_file_1"): Relax error regexp to match on Guile 2.2.
> * testsuite/gdb.guile/scm-ports.exp (test_mem_port_rw): Pass
> "r0+" instead of "r+" to 'open-memory' so make it explicitly
> unbuffered (it's buffered by default on 2.2/3.0).
> * configure.ac (try_guile_versions): Add "guile-2.2".
> * configure: Regenerate.
> * doc/guile.texi (Memory Ports in Guile): Remove
> documentation of 'memory-port-read-buffer-size',
> 'set-memory-port-read-buffer-size!',
> 'memory-port-write-buffer-size',
> 'set-memory-port-read-buffer-size!', which are no longer
> supported with Guile 2.2/3.0 and superseded by 'setvbuf'.
> * doc/guile.texi (Guile Introduction): Clarify which Guile
> versions are supported.
> ---
>  gdb/configure                         |   2 +-
>  gdb/configure.ac                      |   2 +-
>  gdb/doc/guile.texi                    |  23 +-
>  gdb/guile/scm-ports.c                 | 545 ++++++++++++++++++--------
>  gdb/testsuite/gdb.guile/scm-error.exp |   2 +-
>  gdb/testsuite/gdb.guile/scm-ports.exp |   2 +-
>  6 files changed, 394 insertions(+), 182 deletions(-)
>
> diff --git a/gdb/configure b/gdb/configure
> index ef10aa717f..bd12695291 100755
> --- a/gdb/configure
> +++ b/gdb/configure
> @@ -10954,7 +10954,7 @@ fi
>  
>  
>  
> -try_guile_versions="guile-2.0"
> +try_guile_versions="guile-2.2 guile-2.0"
>  have_libguile=no
>  case "${with_guile}" in
>  no)
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index 62750804fa..87afc26581 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -1088,7 +1088,7 @@ AC_MSG_RESULT([$with_guile])
>  dnl We check guile with pkg-config.
>  AC_PATH_PROG(pkg_config_prog_path, pkg-config, missing)
>  
> -try_guile_versions="guile-2.0"
> +try_guile_versions="guile-2.2 guile-2.0"
>  have_libguile=no
>  case "${with_guile}" in
>  no)
> diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
> index c0bff7972f..0e6c74ef8b 100644
> --- a/gdb/doc/guile.texi
> +++ b/gdb/doc/guile.texi
> @@ -38,8 +38,7 @@ Guile support in @value{GDBN} follows the Python support in @value{GDBN}
>  reasonably closely, so concepts there should carry over.
>  However, some things are done differently where it makes sense.
>  
> -@value{GDBN} requires Guile version 2.0 or greater.
> -Older versions are not supported.
> +@value{GDBN} requires Guile version 2.2 or 2.0.
>  
>  @cindex guile scripts directory
>  Guile scripts used by @value{GDBN} should be installed in
> @@ -3556,26 +3555,6 @@ of two elements: @code{(start end)}.  The range is @var{start} to @var{end}
>  inclusive.
>  @end deffn
>  
> -@deffn {Scheme Procedure} memory-port-read-buffer-size memory-port
> -Return the size of the read buffer of @code{<gdb:memory-port>}
> -@var{memory-port}.
> -@end deffn
> -
> -@deffn {Scheme Procedure} set-memory-port-read-buffer-size! memory-port size
> -Set the size of the read buffer of @code{<gdb:memory-port>}
> -@var{memory-port} to @var{size}.  The result is unspecified.
> -@end deffn
> -
> -@deffn {Scheme Procedure} memory-port-write-buffer-size memory-port
> -Return the size of the write buffer of @code{<gdb:memory-port>}
> -@var{memory-port}.
> -@end deffn
> -
> -@deffn {Scheme Procedure} set-memory-port-write-buffer-size! memory-port size
> -Set the size of the write buffer of @code{<gdb:memory-port>}
> -@var{memory-port} to @var{size}.  The result is unspecified.
> -@end deffn
> -
>  A memory port is closed like any other port, with @code{close-port}.
>  
>  Combined with Guile's @code{bytevectors}, memory ports provide a lot
> diff --git a/gdb/guile/scm-ports.c b/gdb/guile/scm-ports.c
> index 407d1d36f1..5c39cc1ddf 100644
> --- a/gdb/guile/scm-ports.c
> +++ b/gdb/guile/scm-ports.c
> @@ -36,6 +36,13 @@
>  #endif
>  #endif
>  
> +/* Whether we're using Guile < 2.2 and its clumsy port API.  */
> +
> +#define USING_GUILE_BEFORE_2_2 \
> +  (SCM_MAJOR_VERSION < 2 \
> +   || (SCM_MAJOR_VERSION == 2 && SCM_MINOR_VERSION == 0))
> +
> +
>  /* A ui-file for sending output to Guile.  */
>  
>  class ioscm_file_port : public ui_file
> @@ -66,12 +73,14 @@ typedef struct
>       This value is always in the range [0, size].  */
>    ULONGEST current;
>  
> +#if USING_GUILE_BEFORE_2_2
>    /* The size of the internal r/w buffers.
>       Scheme ports aren't a straightforward mapping to memory r/w.
>       Generally the user specifies how much to r/w and all access is
>       unbuffered.  We don't try to provide equivalent access, but we allow
>       the user to specify these values to help get something similar.  */
>    unsigned read_buf_size, write_buf_size;
> +#endif
>  } ioscm_memory_port;
>  
>  /* Copies of the original system input/output/error ports.
> @@ -81,7 +90,11 @@ static SCM orig_output_port_scm;
>  static SCM orig_error_port_scm;
>  
>  /* This is the stdio port descriptor, scm_ptob_descriptor.  */
> +#if USING_GUILE_BEFORE_2_2
>  static scm_t_bits stdio_port_desc;
> +#else
> +static scm_t_port_type *stdio_port_desc;
> +#endif
>  
>  /* Note: scm_make_port_type takes a char * instead of a const char *.  */
>  static /*const*/ char stdio_port_desc_name[] = "gdb:stdio-port";
> @@ -102,7 +115,11 @@ static SCM error_port_scm;
>  enum oport { GDB_STDOUT, GDB_STDERR };
>  
>  /* This is the memory port descriptor, scm_ptob_descriptor.  */
> +#if USING_GUILE_BEFORE_2_2
>  static scm_t_bits memory_port_desc;
> +#else
> +static scm_t_port_type *memory_port_desc;
> +#endif
>  
>  /* Note: scm_make_port_type takes a char * instead of a const char *.  */
>  static /*const*/ char memory_port_desc_name[] = "gdb:memory-port";
> @@ -131,6 +148,8 @@ static SCM size_keyword;
>  /* Helper to do the low level work of opening a port.
>     Newer versions of Guile (2.1.x) have scm_c_make_port.  */
>  
> +#if USING_GUILE_BEFORE_2_2
> +
>  static SCM
>  ioscm_open_port (scm_t_bits port_type, long mode_bits)
>  {
> @@ -150,9 +169,39 @@ ioscm_open_port (scm_t_bits port_type, long mode_bits)
>  
>    return port;
>  }
> +
> +#else
> +
> +static SCM
> +ioscm_open_port (scm_t_port_type *port_type, long mode_bits)
> +{
> +  return scm_c_make_port (port_type, mode_bits, 0);
> +}
> +
> +#endif
> +
>  
>  /* Support for connecting Guile's stdio ports to GDB's stdio ports.  */
>  
> +/* Like fputstrn_filtered, but don't escape characters, except nul.
> +   Also like fputs_filtered, but a length is specified.  */
> +
> +static void
> +fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
> +{
> +  size_t i;
> +
> +  for (i = 0; i < size; ++i)
> +    {
> +      if (s[i] == '\0')
> + fputs_filtered ("\\000", stream);
> +      else
> + fputc_filtered (s[i], stream);
> +    }
> +}
> +
> +#if USING_GUILE_BEFORE_2_2
> +
>  /* The scm_t_ptob_descriptor.input_waiting "method".
>     Return a lower bound on the number of bytes available for input.  */
>  
> @@ -245,23 +294,6 @@ ioscm_fill_input (SCM port)
>    return *pt->read_buf;
>  }
>  
> -/* Like fputstrn_filtered, but don't escape characters, except nul.
> -   Also like fputs_filtered, but a length is specified.  */
> -
> -static void
> -fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
> -{
> -  size_t i;
> -
> -  for (i = 0; i < size; ++i)
> -    {
> -      if (s[i] == '\0')
> - fputs_filtered ("\\000", stream);
> -      else
> - fputc_filtered (s[i], stream);
> -    }
> -}
> -
>  /* Write to gdb's stdout or stderr.  */
>  
>  static void
> @@ -302,6 +334,62 @@ ioscm_flush (SCM port)
>      gdb_flush (gdb_stdout);
>  }
>  
> +#else /* !USING_GUILE_BEFORE_2_2 */
> +
> +/* Read up to COUNT bytes into bytevector DST at offset START.  Return the
> +   number of bytes read, zero for the end of file.  */
> +
> +static size_t
> +ioscm_read_from_port (SCM port, SCM dst, size_t start, size_t count)
> +{
> +  long read;
> +  char *read_buf;
> +
> +  /* If we're called on stdout,stderr, punt.  */
> +  if (! scm_is_eq (port, input_port_scm))
> +    return 0;
> +
> +  gdb_flush (gdb_stdout);
> +  gdb_flush (gdb_stderr);
> +
> +  read_buf = (char *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
> +  read = gdb_stdin->read (read_buf, count);
> +  if (read == -1)
> +    scm_syserror (FUNC_NAME);
> +
> +  return (size_t) read;
> +}
> +
> +/* Write to gdb's stdout or stderr.  */
> +
> +static size_t
> +ioscm_write (SCM port, SCM src, size_t start, size_t count)
> +{
> +  const char *data = (char *) SCM_BYTEVECTOR_CONTENTS (src) + start;
> +
> +  /* If we're called on stdin, punt.  */
> +  if (scm_is_eq (port, input_port_scm))
> +    return 0;
> +
> +  gdbscm_gdb_exception exc {};
> +  try
> +    {
> +      if (scm_is_eq (port, error_port_scm))
> + fputsn_filtered ((const char *) data, count, gdb_stderr);
> +      else
> + fputsn_filtered ((const char *) data, count, gdb_stdout);
> +    }
> +  catch (const gdb_exception &except)
> +    {
> +      exc = unpack (except);
> +    }
> +  GDBSCM_HANDLE_GDB_EXCEPTION (exc);
> +
> +  return count;
> +}
> +
> +#endif /* !USING_GUILE_BEFORE_2_2 */
> +
>  /* Initialize the gdb stdio port type.
>  
>     N.B. isatty? will fail on these ports, it is only supported for file
> @@ -311,12 +399,25 @@ static void
>  ioscm_init_gdb_stdio_port (void)
>  {
>    stdio_port_desc = scm_make_port_type (stdio_port_desc_name,
> - ioscm_fill_input, ioscm_write);
> +#if USING_GUILE_BEFORE_2_2
> + ioscm_fill_input,
> +#else
> + ioscm_read_from_port,
> +#endif
> + ioscm_write);
>  
> +#if USING_GUILE_BEFORE_2_2
>    scm_set_port_input_waiting (stdio_port_desc, ioscm_input_waiting);
>    scm_set_port_flush (stdio_port_desc, ioscm_flush);
> +#else
> +  scm_set_port_read_wait_fd (stdio_port_desc, STDIN_FILENO);
> +#endif
>  }
>  
> +#define GDB_STDIO_BUFFER_DEFAULT_SIZE 1024
> +
> +#if USING_GUILE_BEFORE_2_2
> +
>  /* Subroutine of ioscm_make_gdb_stdio_port to simplify it.
>     Set up the buffers of port PORT.
>     MODE_BITS are the mode bits of PORT.  */
> @@ -325,7 +426,6 @@ static void
>  ioscm_init_stdio_buffers (SCM port, long mode_bits)
>  {
>    scm_t_port *pt = SCM_PTAB_ENTRY (port);
> -#define GDB_STDIO_BUFFER_DEFAULT_SIZE 1024
>    int size = mode_bits & SCM_BUF0 ? 0 : GDB_STDIO_BUFFER_DEFAULT_SIZE;
>    int writing = (mode_bits & SCM_WRTNG) != 0;
>  
> @@ -359,6 +459,20 @@ ioscm_init_stdio_buffers (SCM port, long mode_bits)
>    pt->write_end = pt->write_buf + pt->write_buf_size;
>  }
>  
> +#else
> +
> +static void
> +ioscm_init_stdio_buffers (SCM port, long mode_bits)
> +{
> +  if (mode_bits & SCM_BUF0)
> +    scm_setvbuf (port, scm_from_utf8_symbol ("none"), scm_from_size_t (0));
> +  else
> +    scm_setvbuf (port, scm_from_utf8_symbol ("block"),
> + scm_from_size_t (GDB_STDIO_BUFFER_DEFAULT_SIZE));
> +}
> +
> +#endif
> +
>  /* Create a gdb stdio port.  */
>  
>  static SCM
> @@ -403,9 +517,14 @@ ioscm_make_gdb_stdio_port (int fd)
>  static SCM
>  gdbscm_stdio_port_p (SCM scm)
>  {
> +#if USING_GUILE_BEFORE_2_2
>    /* This is copied from SCM_FPORTP.  */
>    return scm_from_bool (!SCM_IMP (scm)
>   && (SCM_TYP16 (scm) == stdio_port_desc));
> +#else
> +  return scm_from_bool (SCM_PORTP (scm)
> + && (SCM_PORT_TYPE (scm) == stdio_port_desc));
> +#endif
>  }
>  
>  /* GDB's ports are accessed via functions to keep them read-only.  */
> @@ -568,6 +687,8 @@ ioscm_lseek_address (ioscm_memory_port *iomem, LONGEST offset, int whence)
>    return 1;
>  }
>  
> +#if USING_GUILE_BEFORE_2_2
> +
>  /* "fill_input" method for memory ports.  */
>  
>  static int
> @@ -661,73 +782,6 @@ gdbscm_memory_port_flush (SCM port)
>    pt->rw_active = SCM_PORT_NEITHER;
>  }
>  
> -/* "write" method for memory ports.  */
> -
> -static void
> -gdbscm_memory_port_write (SCM port, const void *void_data, size_t size)
> -{
> -  scm_t_port *pt = SCM_PTAB_ENTRY (port);
> -  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
> -  const gdb_byte *data = (const gdb_byte *) void_data;
> -
> -  /* There's no way to indicate a short write, so if the request goes past
> -     the end of the port's memory range, flag an error.  */
> -  if (size > iomem->size - iomem->current)
> -    {
> -      gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size),
> - _("writing beyond end of memory range"));
> -    }
> -
> -  if (pt->write_buf == &pt->shortbuf)
> -    {
> -      /* Unbuffered port.  */
> -      if (target_write_memory (iomem->start + iomem->current, data, size) != 0)
> - gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
> -      iomem->current += size;
> -      return;
> -    }
> -
> -  /* Note: The edge case of what to do when the buffer exactly fills is
> -     debatable.  Guile flushes when the buffer exactly fills up, so we
> -     do too.  It's counter-intuitive to my mind, but in case there's a
> -     subtlety somewhere that depends on this, we do the same.  */
> -
> -  {
> -    size_t space = pt->write_end - pt->write_pos;
> -
> -    if (size < space)
> -      {
> - /* Data fits in buffer, and does not fill it.  */
> - memcpy (pt->write_pos, data, size);
> - pt->write_pos += size;
> -      }
> -    else
> -      {
> - memcpy (pt->write_pos, data, space);
> - pt->write_pos = pt->write_end;
> - gdbscm_memory_port_flush (port);
> - {
> -  const gdb_byte *ptr = data + space;
> -  size_t remaining = size - space;
> -
> -  if (remaining >= pt->write_buf_size)
> -    {
> -      if (target_write_memory (iomem->start + iomem->current, ptr,
> -       remaining) != 0)
> - gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
> -     SCM_EOL);
> -      iomem->current += remaining;
> -    }
> -  else
> -    {
> -      memcpy (pt->write_pos, ptr, remaining);
> -      pt->write_pos += remaining;
> -    }
> - }
> -      }
> -  }
> -}
> -
>  /* "seek" method for memory ports.  */
>  
>  static scm_t_off
> @@ -820,6 +874,73 @@ gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
>    return result;
>  }
>  
> +/* "write" method for memory ports.  */
> +
> +static void
> +gdbscm_memory_port_write (SCM port, const void *void_data, size_t size)
> +{
> +  scm_t_port *pt = SCM_PTAB_ENTRY (port);
> +  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
> +  const gdb_byte *data = (const gdb_byte *) void_data;
> +
> +  /* There's no way to indicate a short write, so if the request goes past
> +     the end of the port's memory range, flag an error.  */
> +  if (size > iomem->size - iomem->current)
> +    {
> +      gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size),
> + _("writing beyond end of memory range"));
> +    }
> +
> +  if (pt->write_buf == &pt->shortbuf)
> +    {
> +      /* Unbuffered port.  */
> +      if (target_write_memory (iomem->start + iomem->current, data, size) != 0)
> + gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
> +      iomem->current += size;
> +      return;
> +    }
> +
> +  /* Note: The edge case of what to do when the buffer exactly fills is
> +     debatable.  Guile flushes when the buffer exactly fills up, so we
> +     do too.  It's counter-intuitive to my mind, but in case there's a
> +     subtlety somewhere that depends on this, we do the same.  */
> +
> +  {
> +    size_t space = pt->write_end - pt->write_pos;
> +
> +    if (size < space)
> +      {
> + /* Data fits in buffer, and does not fill it.  */
> + memcpy (pt->write_pos, data, size);
> + pt->write_pos += size;
> +      }
> +    else
> +      {
> + memcpy (pt->write_pos, data, space);
> + pt->write_pos = pt->write_end;
> + gdbscm_memory_port_flush (port);
> + {
> +  const gdb_byte *ptr = data + space;
> +  size_t remaining = size - space;
> +
> +  if (remaining >= pt->write_buf_size)
> +    {
> +      if (target_write_memory (iomem->start + iomem->current, ptr,
> +       remaining) != 0)
> + gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
> +     SCM_EOL);
> +      iomem->current += remaining;
> +    }
> +  else
> +    {
> +      memcpy (pt->write_pos, ptr, remaining);
> +      pt->write_pos += remaining;
> +    }
> + }
> +      }
> +  }
> +}
> +
>  /* "close" method for memory ports.  */
>  
>  static int
> @@ -851,18 +972,166 @@ gdbscm_memory_port_free (SCM port)
>    return 0;
>  }
>  
> +/* Re-initialize a memory port, updating its read/write buffer sizes.
> +   An exception is thrown if the port is unbuffered.
> +   TODO: Allow switching buffered/unbuffered.
> +   An exception is also thrown if data is still buffered, except in the case
> +   where the buffer size isn't changing (since that's just a nop).  */
> +
> +static void
> +ioscm_reinit_memory_port (SCM port, size_t read_buf_size,
> +  size_t write_buf_size, const char *func_name)
> +{
> +  scm_t_port *pt = SCM_PTAB_ENTRY (port);
> +  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
> +
> +  gdb_assert (read_buf_size >= min_memory_port_buf_size
> +      && read_buf_size <= max_memory_port_buf_size);
> +  gdb_assert (write_buf_size >= min_memory_port_buf_size
> +      && write_buf_size <= max_memory_port_buf_size);
> +
> +  /* First check if the port is unbuffered.  */
> +
> +  if (pt->read_buf == &pt->shortbuf)
> +    {
> +      gdb_assert (pt->write_buf == &pt->shortbuf);
> +      scm_misc_error (func_name, _("port is unbuffered: ~a"),
> +      scm_list_1 (port));
> +    }
> +
> +  /* Next check if anything is buffered.  */
> +
> +  if (read_buf_size != pt->read_buf_size
> +      && pt->read_end != pt->read_buf)
> +    {
> +      scm_misc_error (func_name, _("read buffer not empty: ~a"),
> +      scm_list_1 (port));
> +    }
> +
> +  if (write_buf_size != pt->write_buf_size
> +      && pt->write_pos != pt->write_buf)
> +    {
> +      scm_misc_error (func_name, _("write buffer not empty: ~a"),
> +      scm_list_1 (port));
> +    }
> +
> +  /* Now we can update the buffer sizes, but only if the size has changed.  */
> +
> +  if (read_buf_size != pt->read_buf_size)
> +    {
> +      iomem->read_buf_size = read_buf_size;
> +      pt->read_buf_size = read_buf_size;
> +      xfree (pt->read_buf);
> +      pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
> +      pt->read_pos = pt->read_end = pt->read_buf;
> +    }
> +
> +  if (write_buf_size != pt->write_buf_size)
> +    {
> +      iomem->write_buf_size = write_buf_size;
> +      pt->write_buf_size = write_buf_size;
> +      xfree (pt->write_buf);
> +      pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
> +      pt->write_pos = pt->write_buf;
> +      pt->write_end = pt->write_buf + pt->write_buf_size;
> +    }
> +}
> +
> +#else /* !USING_GUILE_BEFORE_2_2 */
> +
> +/* Read up to COUNT bytes into bytevector DST at offset START.  Return the
> +   number of bytes read, zero for the end of file.  */
> +
> +static size_t
> +gdbscm_memory_port_read (SCM port, SCM dst, size_t start, size_t count)
> +{
> +  gdb_byte *read_buf;
> +  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
> +
> +  /* "current" is the offset of the first byte we want to read.  */
> +  gdb_assert (iomem->current <= iomem->size);
> +  if (iomem->current == iomem->size)
> +    return 0;
> +
> +  /* Don't read outside the allowed memory range.  */
> +  if (count > iomem->size - iomem->current)
> +    count = iomem->size - iomem->current;
> +
> +  read_buf = (gdb_byte *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
> +  if (target_read_memory (iomem->start + iomem->current, read_buf,
> +  count) != 0)
> +    gdbscm_memory_error (FUNC_NAME, _("error reading memory"), SCM_EOL);
> +
> +  iomem->current += count;
> +  return count;
> +}
> +
> +static size_t
> +gdbscm_memory_port_write (SCM port, SCM src, size_t start, size_t count)
> +{
> +  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
> +  const gdb_byte *data =
> +    (const gdb_byte *) SCM_BYTEVECTOR_CONTENTS (src) + start;
> +
> +  /* If the request goes past the end of the port's memory range, flag an
> +     error.  */
> +  if (count > iomem->size - iomem->current)
> +    gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_size_t (count),
> +       _("writing beyond end of memory range"));
> +
> +  if (target_write_memory (iomem->start + iomem->current, data,
> +   count) != 0)
> +    gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
> + SCM_EOL);
> +
> +  iomem->current += count;
> +
> +  return count;
> +}
> +
> +static scm_t_off
> +gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
> +{
> +  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
> +  CORE_ADDR result;
> +  int rc;
> +
> +  rc = ioscm_lseek_address (iomem, offset, whence);
> +  result = iomem->current;
> +
> +  if (rc == 0)
> +    gdbscm_out_of_range_error (FUNC_NAME, 0,
> +       gdbscm_scm_from_longest (offset),
> +       _("bad seek"));
> +
> +  /* TODO: The Guile API doesn't support 32x64.  We can't fix that here,
> +     and there's no need to throw an error if the new address can't be
> +     represented in a scm_t_off.  But we could return something less
> +     clumsy.  */
> +  return result;
> +}
> +
> +static void
> +gdbscm_memory_port_close (SCM port)
> +{
> +  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
> +  scm_gc_free (iomem, sizeof (*iomem), "memory port");
> +  SCM_SETSTREAM (port, NULL);
> +}
> +
> +#endif /* !USING_GUILE_BEFORE_2_2 */
> +
>  /* "print" method for memory ports.  */
>  
>  static int
>  gdbscm_memory_port_print (SCM exp, SCM port, scm_print_state *pstate)
>  {
>    ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (exp);
> -  char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
>  
>    scm_puts ("#<", port);
>    scm_print_port_mode (exp, port);
>    /* scm_print_port_mode includes a trailing space.  */
> -  gdbscm_printf (port, "%s %s-%s", type,
> +  gdbscm_printf (port, "%s %s-%s", memory_port_desc_name,
>   hex_string (iomem->start), hex_string (iomem->end));
>    scm_putc ('>', port);
>    return 1;
> @@ -874,14 +1143,20 @@ static void
>  ioscm_init_memory_port_type (void)
>  {
>    memory_port_desc = scm_make_port_type (memory_port_desc_name,
> +#if USING_GUILE_BEFORE_2_2
>   gdbscm_memory_port_fill_input,
> +#else
> + gdbscm_memory_port_read,
> +#endif
>   gdbscm_memory_port_write);
>  
> +#if USING_GUILE_BEFORE_2_2
>    scm_set_port_end_input (memory_port_desc, gdbscm_memory_port_end_input);
>    scm_set_port_flush (memory_port_desc, gdbscm_memory_port_flush);
> +  scm_set_port_free (memory_port_desc, gdbscm_memory_port_free);
> +#endif
>    scm_set_port_seek (memory_port_desc, gdbscm_memory_port_seek);
>    scm_set_port_close (memory_port_desc, gdbscm_memory_port_close);
> -  scm_set_port_free (memory_port_desc, gdbscm_memory_port_free);
>    scm_set_port_print (memory_port_desc, gdbscm_memory_port_print);
>  }
>  
> @@ -930,9 +1205,7 @@ ioscm_parse_mode_bits (const char *func_name, const char *mode)
>  static void
>  ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
>  {
> -  scm_t_port *pt;
>    ioscm_memory_port *iomem;
> -  int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0;
>  
>    gdb_assert (start <= end);
>  
> @@ -943,6 +1216,9 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
>    iomem->end = end;
>    iomem->size = end - start;
>    iomem->current = 0;
> +
> +#if USING_GUILE_BEFORE_2_2
> +  int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0;
>    if (buffered)
>      {
>        iomem->read_buf_size = default_read_buf_size;
> @@ -954,7 +1230,7 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
>        iomem->write_buf_size = 1;
>      }
>  
> -  pt = SCM_PTAB_ENTRY (port);
> +  scm_t_port *pt = SCM_PTAB_ENTRY (port);
>    /* Match the expectation of `binary-port?'.  */
>    pt->encoding = NULL;
>    pt->rw_random = 1;
> @@ -973,74 +1249,11 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
>    pt->read_pos = pt->read_end = pt->read_buf;
>    pt->write_pos = pt->write_buf;
>    pt->write_end = pt->write_buf + pt->write_buf_size;
> +#endif
>  
>    SCM_SETSTREAM (port, iomem);
>  }
>  
> -/* Re-initialize a memory port, updating its read/write buffer sizes.
> -   An exception is thrown if the port is unbuffered.
> -   TODO: Allow switching buffered/unbuffered.
> -   An exception is also thrown if data is still buffered, except in the case
> -   where the buffer size isn't changing (since that's just a nop).  */
> -
> -static void
> -ioscm_reinit_memory_port (SCM port, size_t read_buf_size,
> -  size_t write_buf_size, const char *func_name)
> -{
> -  scm_t_port *pt = SCM_PTAB_ENTRY (port);
> -  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
> -
> -  gdb_assert (read_buf_size >= min_memory_port_buf_size
> -      && read_buf_size <= max_memory_port_buf_size);
> -  gdb_assert (write_buf_size >= min_memory_port_buf_size
> -      && write_buf_size <= max_memory_port_buf_size);
> -
> -  /* First check if the port is unbuffered.  */
> -
> -  if (pt->read_buf == &pt->shortbuf)
> -    {
> -      gdb_assert (pt->write_buf == &pt->shortbuf);
> -      scm_misc_error (func_name, _("port is unbuffered: ~a"),
> -      scm_list_1 (port));
> -    }
> -
> -  /* Next check if anything is buffered.  */
> -
> -  if (read_buf_size != pt->read_buf_size
> -      && pt->read_end != pt->read_buf)
> -    {
> -      scm_misc_error (func_name, _("read buffer not empty: ~a"),
> -      scm_list_1 (port));
> -    }
> -
> -  if (write_buf_size != pt->write_buf_size
> -      && pt->write_pos != pt->write_buf)
> -    {
> -      scm_misc_error (func_name, _("write buffer not empty: ~a"),
> -      scm_list_1 (port));
> -    }
> -
> -  /* Now we can update the buffer sizes, but only if the size has changed.  */
> -
> -  if (read_buf_size != pt->read_buf_size)
> -    {
> -      iomem->read_buf_size = read_buf_size;
> -      pt->read_buf_size = read_buf_size;
> -      xfree (pt->read_buf);
> -      pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
> -      pt->read_pos = pt->read_end = pt->read_buf;
> -    }
> -
> -  if (write_buf_size != pt->write_buf_size)
> -    {
> -      iomem->write_buf_size = write_buf_size;
> -      pt->write_buf_size = write_buf_size;
> -      xfree (pt->write_buf);
> -      pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
> -      pt->write_pos = pt->write_buf;
> -      pt->write_end = pt->write_buf + pt->write_buf_size;
> -    }
> -}
>  
>  /* (open-memory [#:mode string] [#:start address] [#:size integer]) -> port
>     Return a port that can be used for reading and writing memory.
> @@ -1124,7 +1337,11 @@ gdbscm_open_memory (SCM rest)
>  static int
>  gdbscm_is_memory_port (SCM obj)
>  {
> +#if USING_GUILE_BEFORE_2_2
>    return !SCM_IMP (obj) && (SCM_TYP16 (obj) == memory_port_desc);
> +#else
> +  return SCM_PORTP (obj) && (SCM_PORT_TYPE (obj) == memory_port_desc);
> +#endif
>  }
>  
>  /* (memory-port? obj) -> boolean */
> @@ -1155,6 +1372,7 @@ gdbscm_memory_port_range (SCM port)
>  static SCM
>  gdbscm_memory_port_read_buffer_size (SCM port)
>  {
> +#if USING_GUILE_BEFORE_2_2
>    ioscm_memory_port *iomem;
>  
>    SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
> @@ -1162,6 +1380,9 @@ gdbscm_memory_port_read_buffer_size (SCM port)
>  
>    iomem = (ioscm_memory_port *) SCM_STREAM (port);
>    return scm_from_uint (iomem->read_buf_size);
> +#else
> +  return scm_from_uint (0);
> +#endif
>  }
>  
>  /* (set-memory-port-read-buffer-size! port size) -> unspecified
> @@ -1171,6 +1392,7 @@ gdbscm_memory_port_read_buffer_size (SCM port)
>  static SCM
>  gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
>  {
> +#if USING_GUILE_BEFORE_2_2
>    ioscm_memory_port *iomem;
>  
>    SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
> @@ -1190,6 +1412,9 @@ gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
>      FUNC_NAME);
>  
>    return SCM_UNSPECIFIED;
> +#else
> +  return scm_setvbuf (port, scm_from_utf8_symbol ("block"), size);
> +#endif
>  }
>  
>  /* (memory-port-write-buffer-size port) -> integer */
> @@ -1197,6 +1422,7 @@ gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
>  static SCM
>  gdbscm_memory_port_write_buffer_size (SCM port)
>  {
> +#if USING_GUILE_BEFORE_2_2
>    ioscm_memory_port *iomem;
>  
>    SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
> @@ -1204,6 +1430,9 @@ gdbscm_memory_port_write_buffer_size (SCM port)
>  
>    iomem = (ioscm_memory_port *) SCM_STREAM (port);
>    return scm_from_uint (iomem->write_buf_size);
> +#else
> +  return scm_from_uint (0);
> +#endif
>  }
>  
>  /* (set-memory-port-write-buffer-size! port size) -> unspecified
> @@ -1213,6 +1442,7 @@ gdbscm_memory_port_write_buffer_size (SCM port)
>  static SCM
>  gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size)
>  {
> +#if USING_GUILE_BEFORE_2_2
>    ioscm_memory_port *iomem;
>  
>    SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
> @@ -1232,6 +1462,9 @@ gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size)
>      FUNC_NAME);
>  
>    return SCM_UNSPECIFIED;
> +#else
> +  return scm_setvbuf (port, scm_from_utf8_symbol ("block"), size);
> +#endif
>  }
>  
>  /* Initialize gdb ports.  */
> diff --git a/gdb/testsuite/gdb.guile/scm-error.exp b/gdb/testsuite/gdb.guile/scm-error.exp
> index 799bfe5db0..f073200b6e 100644
> --- a/gdb/testsuite/gdb.guile/scm-error.exp
> +++ b/gdb/testsuite/gdb.guile/scm-error.exp
> @@ -34,7 +34,7 @@ set remote_guile_file_2 [gdb_remote_download host \
>       ${srcdir}/${subdir}/${testfile}-2.scm]
>  
>  gdb_test "source $remote_guile_file_1" \
> -    "(ERROR: )?In procedure \[+\]: Wrong type: #f.*" \
> +    "(ERROR: )?In procedure \[+\]: Wrong type.*: #f.*" \
>      "error loading scm file caught"
>  
>  gdb_test "p 1" " = 1" "no delayed error"
> diff --git a/gdb/testsuite/gdb.guile/scm-ports.exp b/gdb/testsuite/gdb.guile/scm-ports.exp
> index b2835ddc75..47da3d43d3 100644
> --- a/gdb/testsuite/gdb.guile/scm-ports.exp
> +++ b/gdb/testsuite/gdb.guile/scm-ports.exp
> @@ -154,7 +154,7 @@ test_mem_port_rw unbuffered
>  
>  # Test zero-length memory ports.
>  
> -gdb_test_no_output "guile (define zero-mem-port (open-memory #:start 0 #:size 0 #:mode \"r+\"))" \
> +gdb_test_no_output "guile (define zero-mem-port (open-memory #:start 0 #:size 0 #:mode \"r0+\"))" \
>      "create zero length memory port"
>  gdb_test "guile (print (read-char zero-mem-port))" \
>      "= #<eof>"
>
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/2] guile: Add support for Guile 2.2.

Ludovic Courtès-3
Tom de Vries <[hidden email]> skribis:

> On 12-06-2020 15:27, Ludovic Courtès wrote:
>> This primarily updates code that uses the I/O port API of Guile.
>>
>> gdb/ChangeLog:
>>
>
> It looks like you could claim fixing PR guile/21104 here.

Yes, thanks for the heads-up!  I’ll add it to the commit log.

Ludo’.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/2] guile: Add support for Guile 2.2.

Eli Zaretskii
In reply to this post by Ludovic Courtès-3
> From: Ludovic Courtès <[hidden email]>
> Cc: [hidden email]
> Date: Fri, 12 Jun 2020 16:04:22 +0200
>
> > More importantly, I don't understand why we'd want to remove the
> > documentation of these functions.  Are we removing the functions as
> > well (I don't think I saw the code being removed)?  If we are not
> > removing the functions, why remove their docs?  You say that the
> > corresponding Guile functionality is superseded by setvbuf, but
> > doesn't it mean the GDB-specific capability based on that will be
> > rewritten using the new Guile features, and we can continue supporting
> > them?
>
> These four functions are not used in tests, in documented examples, nor
> in Guile’s own GDB plugin.
>
> ‘setvbuf’ is not entirely a drop-in replacement because: (1) it doesn’t
> allow you to query a port’s buffer size, only to change it, and (2) it
> doesn’t distinguish between the read and write buffers.  Consequently,
> these functions cannot be implemented on 2.2/3.0, or at least not
> easily.
>
> Since they are unused, and I can’t see a valid use case for those over
> ‘setvbuf’, I chose to remove them from the manual as a way to deprecate
> them.
>
> WDYT?

So what is the plan wrt GDB accessing memory of the inferior via
Guile?  Specifically, which parts of the features described in "Memory
Ports in Guile" in the manual will continue be supported with Guile 2.2
and later?  can we make at least the accessors work with those newer
versions of Guile?

In any case, I don't like the method of deprecating features by
removing their documentation.  I think we should say explicitly in
that section which methods are deprecated and why.  The fact that they
are deprecated should also be in NEWS.  This all assumes that other
GDB developers agree that they are not needed; I don't have enough
relevant experience to have an opinion.  Maybe Doug (CC'ed) could
chime in.

I also think that Guile should provide proper replacements for the
functionality you mentioned, because evidently at least GDB thought
they could be put to good use.  But this is outside of the scope of
GDB maintenance, something for the Guile developers to consider.

> > Also, does any of this need to be called out in NEWS?
>
> Oh sure.  Should that go in a separate commit or in the same?

The same is better.

> PS: I lost Git access to sourceware.org some years ago because my
>     registered SSH key was DSA, IIRC.  Should I apply to restore it?
>     What’s the procedure?

I think you should write to [hidden email] and ask them what
to do.

Thanks.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/2] guile: Add support for Guile 2.2.

Ludovic Courtès-3
Hi,

In the meantime I found that Doug had already done that work in 2018:

  https://sourceware.org/bugzilla/show_bug.cgi?id=21104#c8

Too bad I didn’t notice earlier.  I’ll check if there are significant
differences between the two.

Eli Zaretskii <[hidden email]> skribis:

>> These four functions are not used in tests, in documented examples, nor
>> in Guile’s own GDB plugin.
>>
>> ‘setvbuf’ is not entirely a drop-in replacement because: (1) it doesn’t
>> allow you to query a port’s buffer size, only to change it, and (2) it
>> doesn’t distinguish between the read and write buffers.  Consequently,
>> these functions cannot be implemented on 2.2/3.0, or at least not
>> easily.
>>
>> Since they are unused, and I can’t see a valid use case for those over
>> ‘setvbuf’, I chose to remove them from the manual as a way to deprecate
>> them.
>>
>> WDYT?
>
> So what is the plan wrt GDB accessing memory of the inferior via
> Guile?  Specifically, which parts of the features described in "Memory
> Ports in Guile" in the manual will continue be supported with Guile 2.2
> and later?  can we make at least the accessors work with those newer
> versions of Guile?

Yes, everything remains supported, it’s just setting read/write
buffering size in that way that is unsupported.

In most cases, I suspect one just wants an unbuffered memory port
anyway.

> In any case, I don't like the method of deprecating features by
> removing their documentation.  I think we should say explicitly in
> that section which methods are deprecated and why.  The fact that they
> are deprecated should also be in NEWS.  This all assumes that other
> GDB developers agree that they are not needed; I don't have enough
> relevant experience to have an opinion.  Maybe Doug (CC'ed) could
> chime in.

Yes, I think we should mention it in ‘NEWS’.

> I also think that Guile should provide proper replacements for the
> functionality you mentioned, because evidently at least GDB thought
> they could be put to good use.  But this is outside of the scope of
> GDB maintenance, something for the Guile developers to consider.

Right.  For I/O ports in general, I don’t think this functionality would
be very useful.  (Even for GDB memory ports, I think ‘setvbuf’ is
enough.)

>> > Also, does any of this need to be called out in NEWS?
>>
>> Oh sure.  Should that go in a separate commit or in the same?
>
> The same is better.

Sounds good.

Thanks,
Ludo’.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] guile: Add support for Guile 3.0.

Tom Tromey-2
In reply to this post by Ludovic Courtès-3
>>>>> "Ludovic" == Ludovic Courtès <[hidden email]> writes:

Ludovic> * testsuite/gdb.guile/source2.scm: Add #f first argument to
Ludovic> 'format'.
Ludovic> * testsuite/gdb.guile/types-module.exp: Remove "ERROR:" from
Ludovic> regexps since Guile 3.0 no longer prints that.

testsuite/ (unfortunately IMO) has its own ChangeLog.

Ludovic>        /* If scm_is_unsigned_integer can't work with this type, just punt.  */
Ludovic> -      if (TYPE_LENGTH (type) > sizeof (scm_t_uintmax))
Ludovic> +      if (TYPE_LENGTH (type) > sizeof (uintmax_t))

I suppose these can't differ in Guile 2.0 or 2.2?

Anyway, this patch seems fine to me.

Tom
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 0/2] Add support for Guile 3.0 and 2.2

Ludovic Courtès-3
In reply to this post by Ludovic Courtès-3
Hi,

Here’s v2 of these patches.  Changes since v1:

  • Add natural buffer size function as implemented by Doug
    in <https://sourceware.org/legacy-ml/gdb-patches/2018-01/msg00438.html>.
    That, in turn, means we no longer need to open ‘zero-mem-port’
    in ‘gdb.guile/scm-ports.exp’ as explicitly unbuffered like I
    did in v1.  (I added Doug as co-author in the ChangeLog entry.)

  • Add NEWS entry, documenting procedure deprecation.

  • Separate ChangeLog entry for gdb/doc, and claim PR gdb/21104.

Doug, I feel stupid for redoing the work you had done two years ago—I’ll do
my homework better next time!—but hopefully we’ll soon be done with it.

Thanks,
Ludo’.

Ludovic Courtès (2):
  guile: Add support for Guile 2.2.
  guile: Add support for Guile 3.0.

 gdb/NEWS                                 |  10 +
 gdb/configure                            |   2 +-
 gdb/configure.ac                         |   2 +-
 gdb/doc/guile.texi                       |  23 +-
 gdb/guile/scm-math.c                     |   4 +-
 gdb/guile/scm-ports.c                    | 619 ++++++++++++++++-------
 gdb/testsuite/gdb.guile/scm-error.exp    |   2 +-
 gdb/testsuite/gdb.guile/source2.scm      |   2 +-
 gdb/testsuite/gdb.guile/types-module.exp |   6 +-
 9 files changed, 469 insertions(+), 201 deletions(-)

--
2.26.2

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 1/2] guile: Add support for Guile 2.2.

Ludovic Courtès-3
This primarily updates code that uses the I/O port API of Guile.

gdb/ChangeLog
2020-06-15  Ludovic Courtès  <[hidden email]>
            Doug Evans  <[hidden email]>

        PR gdb/21104
        * guile/scm-ports.c (USING_GUILE_BEFORE_2_2): New macro.
        (ioscm_memory_port)[read_buf_size, write_buf_size]: Wrap in #if
        USING_GUILE_BEFORE_2_2.
        (stdio_port_desc, memory_port_desc) [!USING_GUILE_BEFORE_2_2]:
        Change type to 'scm_t_port_type *'.
        (natural_buffer_size) [!USING_GUILE_BEFORE_2_2]: New variable.
        (ioscm_open_port) [USING_GUILE_BEFORE_2_2]: Add 'stream'
        parameter and honor it.  Update callers.
        (ioscm_open_port) [!USING_GUILE_BEFORE_2_2]: New function.
        (ioscm_read_from_port, ioscm_write) [!USING_GUILE_BEFORE_2_2]: New
        functions.
        (ioscm_fill_input, ioscm_input_waiting, ioscm_flush): Wrap in #if
        USING_GUILE_BEFORE_2_2.
        (ioscm_init_gdb_stdio_port) [!USING_GUILE_BEFORE_2_2]: Use
        'ioscm_read_from_port'.  Call 'scm_set_port_read_wait_fd'.
        (ioscm_init_stdio_buffers) [!USING_GUILE_BEFORE_2_2]: New function.
        (gdbscm_stdio_port_p) [!USING_GUILE_BEFORE_2_2]: Use 'SCM_PORTP'
        and 'SCM_PORT_TYPE'.
        (gdbscm_memory_port_end_input, gdbscm_memory_port_seek)
        (ioscm_reinit_memory_port): Wrap in #if USING_GUILE_BEFORE_2_2.
        (gdbscm_memory_port_read, gdbscm_memory_port_write)
        (gdbscm_memory_port_seek, gdbscm_memory_port_close)
        [!USING_GUILE_BEFORE_2_2]: New functions.
        (gdbscm_memory_port_print): Remove use of 'SCM_PTOB_NAME'.
        (ioscm_init_memory_port_type) [!USING_GUILE_BEFORE_2_2]: Use
        'gdbscm_memory_port_read'.
        Wrap 'scm_set_port_end_input', 'scm_set_port_flush', and
        'scm_set_port_free' calls in #if USING_GUILE_BEFORE_2_2.
        (gdbscm_get_natural_buffer_sizes) [!USING_GUILE_BEFORE_2_2]: New
        function.
        (ioscm_init_memory_port): Remove.
        (ioscm_init_memory_port_stream): New function
        (ioscm_init_memory_port_buffers) [USING_GUILE_BEFORE_2_2]: New
        function.
        (gdbscm_memory_port_read_buffer_size) [!USING_GUILE_BEFORE_2_2]:
        Return scm_from_uint (0).
        (gdbscm_set_memory_port_read_buffer_size_x)
        [!USING_GUILE_BEFORE_2_2]: Call 'scm_setvbuf'.
        (gdbscm_memory_port_write_buffer_size) [!USING_GUILE_BEFORE_2_2]:
        Return scm_from_uint (0).
        (gdbscm_set_memory_port_write_buffer_size_x)
        [!USING_GUILE_BEFORE_2_2]: Call 'scm_setvbuf'.
        * testsuite/gdb.guile/scm-error.exp ("source
        $remote_guile_file_1"): Relax error regexp to match on Guile 2.2.
        * configure.ac (try_guile_versions): Add "guile-2.2".
        * configure: Regenerate.
        * NEWS: Add entry.

gdb/doc/ChangeLog
2020-06-15  Ludovic Courtès  <[hidden email]>

        * guile.texi (Memory Ports in Guile): Remove
        documentation of 'memory-port-read-buffer-size',
        'set-memory-port-read-buffer-size!',
        'memory-port-write-buffer-size',
        'set-memory-port-read-buffer-size!', which are no longer
        supported with Guile 2.2/3.0 and superseded by 'setvbuf'.
        * doc/guile.texi (Guile Introduction): Clarify which Guile
        versions are supported.
---
 gdb/NEWS                              |  10 +
 gdb/configure                         |   2 +-
 gdb/configure.ac                      |   2 +-
 gdb/doc/guile.texi                    |  23 +-
 gdb/guile/scm-ports.c                 | 619 +++++++++++++++++++-------
 gdb/testsuite/gdb.guile/scm-error.exp |   2 +-
 6 files changed, 463 insertions(+), 195 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 9ef85ab3ca..d8a9de4179 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -83,6 +83,16 @@ GNU/Linux/RISC-V (gdbserver) riscv*-*-linux*
   ** Commands written in Python can be in the "TUI" help class by
      registering with the new constant gdb.COMMAND_TUI.
 
+* Guile API
+
+  ** GDB can now be built with GNU Guile 2.2 in addition to 2.0.
+
+  ** Procedures 'memory-port-read-buffer-size',
+     'set-memory-port-read-buffer-size!', 'memory-port-write-buffer-size',
+     and 'set-memory-port-write-buffer-size!' are deprecated.  When
+     using Guile 2.2 and later, users who need to control the size of
+     a memory port's internal buffer can use the 'setvbuf' procedure.
+
 *** Changes in GDB 9
 
 * 'thread-exited' event is now available in the annotations interface.
diff --git a/gdb/configure b/gdb/configure
index ef10aa717f..bd12695291 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -10954,7 +10954,7 @@ fi
 
 
 
-try_guile_versions="guile-2.0"
+try_guile_versions="guile-2.2 guile-2.0"
 have_libguile=no
 case "${with_guile}" in
 no)
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 62750804fa..87afc26581 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1088,7 +1088,7 @@ AC_MSG_RESULT([$with_guile])
 dnl We check guile with pkg-config.
 AC_PATH_PROG(pkg_config_prog_path, pkg-config, missing)
 
-try_guile_versions="guile-2.0"
+try_guile_versions="guile-2.2 guile-2.0"
 have_libguile=no
 case "${with_guile}" in
 no)
diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index c0bff7972f..0e6c74ef8b 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -38,8 +38,7 @@ Guile support in @value{GDBN} follows the Python support in @value{GDBN}
 reasonably closely, so concepts there should carry over.
 However, some things are done differently where it makes sense.
 
-@value{GDBN} requires Guile version 2.0 or greater.
-Older versions are not supported.
+@value{GDBN} requires Guile version 2.2 or 2.0.
 
 @cindex guile scripts directory
 Guile scripts used by @value{GDBN} should be installed in
@@ -3556,26 +3555,6 @@ of two elements: @code{(start end)}.  The range is @var{start} to @var{end}
 inclusive.
 @end deffn
 
-@deffn {Scheme Procedure} memory-port-read-buffer-size memory-port
-Return the size of the read buffer of @code{<gdb:memory-port>}
-@var{memory-port}.
-@end deffn
-
-@deffn {Scheme Procedure} set-memory-port-read-buffer-size! memory-port size
-Set the size of the read buffer of @code{<gdb:memory-port>}
-@var{memory-port} to @var{size}.  The result is unspecified.
-@end deffn
-
-@deffn {Scheme Procedure} memory-port-write-buffer-size memory-port
-Return the size of the write buffer of @code{<gdb:memory-port>}
-@var{memory-port}.
-@end deffn
-
-@deffn {Scheme Procedure} set-memory-port-write-buffer-size! memory-port size
-Set the size of the write buffer of @code{<gdb:memory-port>}
-@var{memory-port} to @var{size}.  The result is unspecified.
-@end deffn
-
 A memory port is closed like any other port, with @code{close-port}.
 
 Combined with Guile's @code{bytevectors}, memory ports provide a lot
diff --git a/gdb/guile/scm-ports.c b/gdb/guile/scm-ports.c
index 407d1d36f1..36b339ecff 100644
--- a/gdb/guile/scm-ports.c
+++ b/gdb/guile/scm-ports.c
@@ -36,6 +36,13 @@
 #endif
 #endif
 
+/* Whether we're using Guile < 2.2 and its clumsy port API.  */
+
+#define USING_GUILE_BEFORE_2_2 \
+  (SCM_MAJOR_VERSION < 2 \
+   || (SCM_MAJOR_VERSION == 2 && SCM_MINOR_VERSION == 0))
+
+
 /* A ui-file for sending output to Guile.  */
 
 class ioscm_file_port : public ui_file
@@ -66,12 +73,14 @@ typedef struct
      This value is always in the range [0, size].  */
   ULONGEST current;
 
+#if USING_GUILE_BEFORE_2_2
   /* The size of the internal r/w buffers.
      Scheme ports aren't a straightforward mapping to memory r/w.
      Generally the user specifies how much to r/w and all access is
      unbuffered.  We don't try to provide equivalent access, but we allow
      the user to specify these values to help get something similar.  */
   unsigned read_buf_size, write_buf_size;
+#endif
 } ioscm_memory_port;
 
 /* Copies of the original system input/output/error ports.
@@ -81,7 +90,11 @@ static SCM orig_output_port_scm;
 static SCM orig_error_port_scm;
 
 /* This is the stdio port descriptor, scm_ptob_descriptor.  */
+#if USING_GUILE_BEFORE_2_2
 static scm_t_bits stdio_port_desc;
+#else
+static scm_t_port_type *stdio_port_desc;
+#endif
 
 /* Note: scm_make_port_type takes a char * instead of a const char *.  */
 static /*const*/ char stdio_port_desc_name[] = "gdb:stdio-port";
@@ -102,11 +115,17 @@ static SCM error_port_scm;
 enum oport { GDB_STDOUT, GDB_STDERR };
 
 /* This is the memory port descriptor, scm_ptob_descriptor.  */
+#if USING_GUILE_BEFORE_2_2
 static scm_t_bits memory_port_desc;
+#else
+static scm_t_port_type *memory_port_desc;
+#endif
 
 /* Note: scm_make_port_type takes a char * instead of a const char *.  */
 static /*const*/ char memory_port_desc_name[] = "gdb:memory-port";
 
+#if USING_GUILE_BEFORE_2_2
+
 /* The default amount of memory to fetch for each read/write request.
    Scheme ports don't provide a way to specify the size of a read,
    which is important to us to minimize the number of inferior interactions,
@@ -123,16 +142,24 @@ static const unsigned max_memory_port_buf_size = 4096;
 /* "out of range" error message for buf sizes.  */
 static char *out_of_range_buf_size;
 
+#else
+
+/* The maximum values to use for get_natural_buffer_sizes.  */
+static const unsigned natural_buf_size = 16;
+
+#endif
+
 /* Keywords used by open-memory.  */
 static SCM mode_keyword;
 static SCM start_keyword;
 static SCM size_keyword;
 
-/* Helper to do the low level work of opening a port.
-   Newer versions of Guile (2.1.x) have scm_c_make_port.  */
+/* Helper to do the low level work of opening a port.  */
+
+#if USING_GUILE_BEFORE_2_2
 
 static SCM
-ioscm_open_port (scm_t_bits port_type, long mode_bits)
+ioscm_open_port (scm_t_bits port_type, long mode_bits, scm_t_bits stream)
 {
   SCM port;
 
@@ -143,6 +170,7 @@ ioscm_open_port (scm_t_bits port_type, long mode_bits)
   port = scm_new_port_table_entry (port_type);
 
   SCM_SET_CELL_TYPE (port, port_type | mode_bits);
+  SCM_SETSTREAM (port, stream);
 
 #if 0 /* TODO: Guile doesn't export this.  What to do?  */
   scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
@@ -150,9 +178,39 @@ ioscm_open_port (scm_t_bits port_type, long mode_bits)
 
   return port;
 }
+
+#else
+
+static SCM
+ioscm_open_port (scm_t_port_type *port_type, long mode_bits, scm_t_bits stream)
+{
+  return scm_c_make_port (port_type, mode_bits, stream);
+}
+
+#endif
+
 
 /* Support for connecting Guile's stdio ports to GDB's stdio ports.  */
 
+/* Like fputstrn_filtered, but don't escape characters, except nul.
+   Also like fputs_filtered, but a length is specified.  */
+
+static void
+fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
+{
+  size_t i;
+
+  for (i = 0; i < size; ++i)
+    {
+      if (s[i] == '\0')
+ fputs_filtered ("\\000", stream);
+      else
+ fputc_filtered (s[i], stream);
+    }
+}
+
+#if USING_GUILE_BEFORE_2_2
+
 /* The scm_t_ptob_descriptor.input_waiting "method".
    Return a lower bound on the number of bytes available for input.  */
 
@@ -245,23 +303,6 @@ ioscm_fill_input (SCM port)
   return *pt->read_buf;
 }
 
-/* Like fputstrn_filtered, but don't escape characters, except nul.
-   Also like fputs_filtered, but a length is specified.  */
-
-static void
-fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
-{
-  size_t i;
-
-  for (i = 0; i < size; ++i)
-    {
-      if (s[i] == '\0')
- fputs_filtered ("\\000", stream);
-      else
- fputc_filtered (s[i], stream);
-    }
-}
-
 /* Write to gdb's stdout or stderr.  */
 
 static void
@@ -302,6 +343,62 @@ ioscm_flush (SCM port)
     gdb_flush (gdb_stdout);
 }
 
+#else /* !USING_GUILE_BEFORE_2_2 */
+
+/* Read up to COUNT bytes into bytevector DST at offset START.  Return the
+   number of bytes read, zero for the end of file.  */
+
+static size_t
+ioscm_read_from_port (SCM port, SCM dst, size_t start, size_t count)
+{
+  long read;
+  char *read_buf;
+
+  /* If we're called on stdout,stderr, punt.  */
+  if (! scm_is_eq (port, input_port_scm))
+    return 0;
+
+  gdb_flush (gdb_stdout);
+  gdb_flush (gdb_stderr);
+
+  read_buf = (char *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
+  read = gdb_stdin->read (read_buf, count);
+  if (read == -1)
+    scm_syserror (FUNC_NAME);
+
+  return (size_t) read;
+}
+
+/* Write to gdb's stdout or stderr.  */
+
+static size_t
+ioscm_write (SCM port, SCM src, size_t start, size_t count)
+{
+  const char *data = (char *) SCM_BYTEVECTOR_CONTENTS (src) + start;
+
+  /* If we're called on stdin, punt.  */
+  if (scm_is_eq (port, input_port_scm))
+    return 0;
+
+  gdbscm_gdb_exception exc {};
+  try
+    {
+      if (scm_is_eq (port, error_port_scm))
+ fputsn_filtered ((const char *) data, count, gdb_stderr);
+      else
+ fputsn_filtered ((const char *) data, count, gdb_stdout);
+    }
+  catch (const gdb_exception &except)
+    {
+      exc = unpack (except);
+    }
+  GDBSCM_HANDLE_GDB_EXCEPTION (exc);
+
+  return count;
+}
+
+#endif /* !USING_GUILE_BEFORE_2_2 */
+
 /* Initialize the gdb stdio port type.
 
    N.B. isatty? will fail on these ports, it is only supported for file
@@ -311,12 +408,25 @@ static void
 ioscm_init_gdb_stdio_port (void)
 {
   stdio_port_desc = scm_make_port_type (stdio_port_desc_name,
- ioscm_fill_input, ioscm_write);
+#if USING_GUILE_BEFORE_2_2
+ ioscm_fill_input,
+#else
+ ioscm_read_from_port,
+#endif
+ ioscm_write);
 
+#if USING_GUILE_BEFORE_2_2
   scm_set_port_input_waiting (stdio_port_desc, ioscm_input_waiting);
   scm_set_port_flush (stdio_port_desc, ioscm_flush);
+#else
+  scm_set_port_read_wait_fd (stdio_port_desc, STDIN_FILENO);
+#endif
 }
 
+#define GDB_STDIO_BUFFER_DEFAULT_SIZE 1024
+
+#if USING_GUILE_BEFORE_2_2
+
 /* Subroutine of ioscm_make_gdb_stdio_port to simplify it.
    Set up the buffers of port PORT.
    MODE_BITS are the mode bits of PORT.  */
@@ -325,7 +435,6 @@ static void
 ioscm_init_stdio_buffers (SCM port, long mode_bits)
 {
   scm_t_port *pt = SCM_PTAB_ENTRY (port);
-#define GDB_STDIO_BUFFER_DEFAULT_SIZE 1024
   int size = mode_bits & SCM_BUF0 ? 0 : GDB_STDIO_BUFFER_DEFAULT_SIZE;
   int writing = (mode_bits & SCM_WRTNG) != 0;
 
@@ -359,6 +468,20 @@ ioscm_init_stdio_buffers (SCM port, long mode_bits)
   pt->write_end = pt->write_buf + pt->write_buf_size;
 }
 
+#else
+
+static void
+ioscm_init_stdio_buffers (SCM port, long mode_bits)
+{
+  if (mode_bits & SCM_BUF0)
+    scm_setvbuf (port, scm_from_utf8_symbol ("none"), scm_from_size_t (0));
+  else
+    scm_setvbuf (port, scm_from_utf8_symbol ("block"),
+ scm_from_size_t (GDB_STDIO_BUFFER_DEFAULT_SIZE));
+}
+
+#endif
+
 /* Create a gdb stdio port.  */
 
 static SCM
@@ -389,7 +512,7 @@ ioscm_make_gdb_stdio_port (int fd)
     }
 
   mode_bits = scm_mode_bits ((char *) mode_str);
-  port = ioscm_open_port (stdio_port_desc, mode_bits);
+  port = ioscm_open_port (stdio_port_desc, mode_bits, 0);
 
   scm_set_port_filename_x (port, gdbscm_scm_from_c_string (name));
 
@@ -403,9 +526,14 @@ ioscm_make_gdb_stdio_port (int fd)
 static SCM
 gdbscm_stdio_port_p (SCM scm)
 {
+#if USING_GUILE_BEFORE_2_2
   /* This is copied from SCM_FPORTP.  */
   return scm_from_bool (!SCM_IMP (scm)
  && (SCM_TYP16 (scm) == stdio_port_desc));
+#else
+  return scm_from_bool (SCM_PORTP (scm)
+ && (SCM_PORT_TYPE (scm) == stdio_port_desc));
+#endif
 }
 
 /* GDB's ports are accessed via functions to keep them read-only.  */
@@ -568,6 +696,8 @@ ioscm_lseek_address (ioscm_memory_port *iomem, LONGEST offset, int whence)
   return 1;
 }
 
+#if USING_GUILE_BEFORE_2_2
+
 /* "fill_input" method for memory ports.  */
 
 static int
@@ -661,73 +791,6 @@ gdbscm_memory_port_flush (SCM port)
   pt->rw_active = SCM_PORT_NEITHER;
 }
 
-/* "write" method for memory ports.  */
-
-static void
-gdbscm_memory_port_write (SCM port, const void *void_data, size_t size)
-{
-  scm_t_port *pt = SCM_PTAB_ENTRY (port);
-  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
-  const gdb_byte *data = (const gdb_byte *) void_data;
-
-  /* There's no way to indicate a short write, so if the request goes past
-     the end of the port's memory range, flag an error.  */
-  if (size > iomem->size - iomem->current)
-    {
-      gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size),
- _("writing beyond end of memory range"));
-    }
-
-  if (pt->write_buf == &pt->shortbuf)
-    {
-      /* Unbuffered port.  */
-      if (target_write_memory (iomem->start + iomem->current, data, size) != 0)
- gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
-      iomem->current += size;
-      return;
-    }
-
-  /* Note: The edge case of what to do when the buffer exactly fills is
-     debatable.  Guile flushes when the buffer exactly fills up, so we
-     do too.  It's counter-intuitive to my mind, but in case there's a
-     subtlety somewhere that depends on this, we do the same.  */
-
-  {
-    size_t space = pt->write_end - pt->write_pos;
-
-    if (size < space)
-      {
- /* Data fits in buffer, and does not fill it.  */
- memcpy (pt->write_pos, data, size);
- pt->write_pos += size;
-      }
-    else
-      {
- memcpy (pt->write_pos, data, space);
- pt->write_pos = pt->write_end;
- gdbscm_memory_port_flush (port);
- {
-  const gdb_byte *ptr = data + space;
-  size_t remaining = size - space;
-
-  if (remaining >= pt->write_buf_size)
-    {
-      if (target_write_memory (iomem->start + iomem->current, ptr,
-       remaining) != 0)
- gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
-     SCM_EOL);
-      iomem->current += remaining;
-    }
-  else
-    {
-      memcpy (pt->write_pos, ptr, remaining);
-      pt->write_pos += remaining;
-    }
- }
-      }
-  }
-}
-
 /* "seek" method for memory ports.  */
 
 static scm_t_off
@@ -820,6 +883,73 @@ gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
   return result;
 }
 
+/* "write" method for memory ports.  */
+
+static void
+gdbscm_memory_port_write (SCM port, const void *void_data, size_t size)
+{
+  scm_t_port *pt = SCM_PTAB_ENTRY (port);
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+  const gdb_byte *data = (const gdb_byte *) void_data;
+
+  /* There's no way to indicate a short write, so if the request goes past
+     the end of the port's memory range, flag an error.  */
+  if (size > iomem->size - iomem->current)
+    {
+      gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size),
+ _("writing beyond end of memory range"));
+    }
+
+  if (pt->write_buf == &pt->shortbuf)
+    {
+      /* Unbuffered port.  */
+      if (target_write_memory (iomem->start + iomem->current, data, size) != 0)
+ gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
+      iomem->current += size;
+      return;
+    }
+
+  /* Note: The edge case of what to do when the buffer exactly fills is
+     debatable.  Guile flushes when the buffer exactly fills up, so we
+     do too.  It's counter-intuitive to my mind, but in case there's a
+     subtlety somewhere that depends on this, we do the same.  */
+
+  {
+    size_t space = pt->write_end - pt->write_pos;
+
+    if (size < space)
+      {
+ /* Data fits in buffer, and does not fill it.  */
+ memcpy (pt->write_pos, data, size);
+ pt->write_pos += size;
+      }
+    else
+      {
+ memcpy (pt->write_pos, data, space);
+ pt->write_pos = pt->write_end;
+ gdbscm_memory_port_flush (port);
+ {
+  const gdb_byte *ptr = data + space;
+  size_t remaining = size - space;
+
+  if (remaining >= pt->write_buf_size)
+    {
+      if (target_write_memory (iomem->start + iomem->current, ptr,
+       remaining) != 0)
+ gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
+     SCM_EOL);
+      iomem->current += remaining;
+    }
+  else
+    {
+      memcpy (pt->write_pos, ptr, remaining);
+      pt->write_pos += remaining;
+    }
+ }
+      }
+  }
+}
+
 /* "close" method for memory ports.  */
 
 static int
@@ -851,18 +981,178 @@ gdbscm_memory_port_free (SCM port)
   return 0;
 }
 
+/* Re-initialize a memory port, updating its read/write buffer sizes.
+   An exception is thrown if the port is unbuffered.
+   TODO: Allow switching buffered/unbuffered.
+   An exception is also thrown if data is still buffered, except in the case
+   where the buffer size isn't changing (since that's just a nop).  */
+
+static void
+ioscm_reinit_memory_port (SCM port, size_t read_buf_size,
+  size_t write_buf_size, const char *func_name)
+{
+  scm_t_port *pt = SCM_PTAB_ENTRY (port);
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+
+  gdb_assert (read_buf_size >= min_memory_port_buf_size
+      && read_buf_size <= max_memory_port_buf_size);
+  gdb_assert (write_buf_size >= min_memory_port_buf_size
+      && write_buf_size <= max_memory_port_buf_size);
+
+  /* First check if the port is unbuffered.  */
+
+  if (pt->read_buf == &pt->shortbuf)
+    {
+      gdb_assert (pt->write_buf == &pt->shortbuf);
+      scm_misc_error (func_name, _("port is unbuffered: ~a"),
+      scm_list_1 (port));
+    }
+
+  /* Next check if anything is buffered.  */
+
+  if (read_buf_size != pt->read_buf_size
+      && pt->read_end != pt->read_buf)
+    {
+      scm_misc_error (func_name, _("read buffer not empty: ~a"),
+      scm_list_1 (port));
+    }
+
+  if (write_buf_size != pt->write_buf_size
+      && pt->write_pos != pt->write_buf)
+    {
+      scm_misc_error (func_name, _("write buffer not empty: ~a"),
+      scm_list_1 (port));
+    }
+
+  /* Now we can update the buffer sizes, but only if the size has changed.  */
+
+  if (read_buf_size != pt->read_buf_size)
+    {
+      iomem->read_buf_size = read_buf_size;
+      pt->read_buf_size = read_buf_size;
+      xfree (pt->read_buf);
+      pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
+      pt->read_pos = pt->read_end = pt->read_buf;
+    }
+
+  if (write_buf_size != pt->write_buf_size)
+    {
+      iomem->write_buf_size = write_buf_size;
+      pt->write_buf_size = write_buf_size;
+      xfree (pt->write_buf);
+      pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
+      pt->write_pos = pt->write_buf;
+      pt->write_end = pt->write_buf + pt->write_buf_size;
+    }
+}
+
+#else /* !USING_GUILE_BEFORE_2_2 */
+
+/* The semantics get weird if the buffer size is larger than the port range,
+   so provide a better default buffer size.  */
+
+static void
+gdbscm_get_natural_buffer_sizes (SCM port, size_t *read_size,
+ size_t *write_size)
+{
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+
+  size_t size = natural_buf_size;
+  if (iomem != NULL && iomem->size < size)
+    size = iomem->size;
+  *read_size = *write_size = size;
+}
+
+/* Read up to COUNT bytes into bytevector DST at offset START.  Return the
+   number of bytes read, zero for the end of file.  */
+
+static size_t
+gdbscm_memory_port_read (SCM port, SCM dst, size_t start, size_t count)
+{
+  gdb_byte *read_buf;
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+
+  /* "current" is the offset of the first byte we want to read.  */
+  gdb_assert (iomem->current <= iomem->size);
+  if (iomem->current == iomem->size)
+    return 0;
+
+  /* Don't read outside the allowed memory range.  */
+  if (count > iomem->size - iomem->current)
+    count = iomem->size - iomem->current;
+
+  read_buf = (gdb_byte *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
+  if (target_read_memory (iomem->start + iomem->current, read_buf,
+  count) != 0)
+    gdbscm_memory_error (FUNC_NAME, _("error reading memory"), SCM_EOL);
+
+  iomem->current += count;
+  return count;
+}
+
+static size_t
+gdbscm_memory_port_write (SCM port, SCM src, size_t start, size_t count)
+{
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+  const gdb_byte *data =
+    (const gdb_byte *) SCM_BYTEVECTOR_CONTENTS (src) + start;
+
+  /* If the request goes past the end of the port's memory range, flag an
+     error.  */
+  if (count > iomem->size - iomem->current)
+    gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_size_t (count),
+       _("writing beyond end of memory range"));
+
+  if (target_write_memory (iomem->start + iomem->current, data,
+   count) != 0)
+    gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
+ SCM_EOL);
+
+  iomem->current += count;
+
+  return count;
+}
+
+static scm_t_off
+gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
+{
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+  int rc;
+
+  rc = ioscm_lseek_address (iomem, offset, whence);
+  if (rc == 0)
+    gdbscm_out_of_range_error (FUNC_NAME, 0,
+       gdbscm_scm_from_longest (offset),
+       _("bad seek"));
+
+  /* TODO: The Guile API doesn't support 32x64.  We can't fix that here,
+     and there's no need to throw an error if the new address can't be
+     represented in a scm_t_off.  But we could return something less
+     clumsy.  */
+  return iomem->current;
+}
+
+static void
+gdbscm_memory_port_close (SCM port)
+{
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+  scm_gc_free (iomem, sizeof (*iomem), "memory port");
+  SCM_SETSTREAM (port, NULL);
+}
+
+#endif /* !USING_GUILE_BEFORE_2_2 */
+
 /* "print" method for memory ports.  */
 
 static int
 gdbscm_memory_port_print (SCM exp, SCM port, scm_print_state *pstate)
 {
   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (exp);
-  char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
 
   scm_puts ("#<", port);
   scm_print_port_mode (exp, port);
   /* scm_print_port_mode includes a trailing space.  */
-  gdbscm_printf (port, "%s %s-%s", type,
+  gdbscm_printf (port, "%s %s-%s", memory_port_desc_name,
  hex_string (iomem->start), hex_string (iomem->end));
   scm_putc ('>', port);
   return 1;
@@ -874,14 +1164,23 @@ static void
 ioscm_init_memory_port_type (void)
 {
   memory_port_desc = scm_make_port_type (memory_port_desc_name,
+#if USING_GUILE_BEFORE_2_2
  gdbscm_memory_port_fill_input,
+#else
+ gdbscm_memory_port_read,
+#endif
  gdbscm_memory_port_write);
 
+#if USING_GUILE_BEFORE_2_2
   scm_set_port_end_input (memory_port_desc, gdbscm_memory_port_end_input);
   scm_set_port_flush (memory_port_desc, gdbscm_memory_port_flush);
+  scm_set_port_free (memory_port_desc, gdbscm_memory_port_free);
+#else
+  scm_set_port_get_natural_buffer_sizes (memory_port_desc,
+ gdbscm_get_natural_buffer_sizes);
+#endif
   scm_set_port_seek (memory_port_desc, gdbscm_memory_port_seek);
   scm_set_port_close (memory_port_desc, gdbscm_memory_port_close);
-  scm_set_port_free (memory_port_desc, gdbscm_memory_port_free);
   scm_set_port_print (memory_port_desc, gdbscm_memory_port_print);
 }
 
@@ -922,17 +1221,13 @@ ioscm_parse_mode_bits (const char *func_name, const char *mode)
   return mode_bits;
 }
 
-/* Helper for gdbscm_open_memory to finish initializing the port.
-   The port has address range [start,end).
-   This means that address of 0xff..ff is not accessible.
-   I can live with that.  */
+/* Return the memory object to be used as a "stream" associated with a memory
+   port for the START--END range.  */
 
-static void
-ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
+static ioscm_memory_port *
+ioscm_init_memory_port_stream (CORE_ADDR start, CORE_ADDR end)
 {
-  scm_t_port *pt;
   ioscm_memory_port *iomem;
-  int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0;
 
   gdb_assert (start <= end);
 
@@ -943,6 +1238,23 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
   iomem->end = end;
   iomem->size = end - start;
   iomem->current = 0;
+
+  return iomem;
+}
+
+#if USING_GUILE_BEFORE_2_2
+
+/* Helper for gdbscm_open_memory to finish initializing the port.
+   The port has address range [start,end).
+   This means that address of 0xff..ff is not accessible.
+   I can live with that.  */
+
+static void
+ioscm_init_memory_port_buffers (SCM port)
+{
+  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
+
+  int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0;
   if (buffered)
     {
       iomem->read_buf_size = default_read_buf_size;
@@ -954,7 +1266,7 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
       iomem->write_buf_size = 1;
     }
 
-  pt = SCM_PTAB_ENTRY (port);
+  scm_t_port *pt = SCM_PTAB_ENTRY (port);
   /* Match the expectation of `binary-port?'.  */
   pt->encoding = NULL;
   pt->rw_random = 1;
@@ -973,74 +1285,9 @@ ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
   pt->read_pos = pt->read_end = pt->read_buf;
   pt->write_pos = pt->write_buf;
   pt->write_end = pt->write_buf + pt->write_buf_size;
-
-  SCM_SETSTREAM (port, iomem);
 }
 
-/* Re-initialize a memory port, updating its read/write buffer sizes.
-   An exception is thrown if the port is unbuffered.
-   TODO: Allow switching buffered/unbuffered.
-   An exception is also thrown if data is still buffered, except in the case
-   where the buffer size isn't changing (since that's just a nop).  */
-
-static void
-ioscm_reinit_memory_port (SCM port, size_t read_buf_size,
-  size_t write_buf_size, const char *func_name)
-{
-  scm_t_port *pt = SCM_PTAB_ENTRY (port);
-  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
-
-  gdb_assert (read_buf_size >= min_memory_port_buf_size
-      && read_buf_size <= max_memory_port_buf_size);
-  gdb_assert (write_buf_size >= min_memory_port_buf_size
-      && write_buf_size <= max_memory_port_buf_size);
-
-  /* First check if the port is unbuffered.  */
-
-  if (pt->read_buf == &pt->shortbuf)
-    {
-      gdb_assert (pt->write_buf == &pt->shortbuf);
-      scm_misc_error (func_name, _("port is unbuffered: ~a"),
-      scm_list_1 (port));
-    }
-
-  /* Next check if anything is buffered.  */
-
-  if (read_buf_size != pt->read_buf_size
-      && pt->read_end != pt->read_buf)
-    {
-      scm_misc_error (func_name, _("read buffer not empty: ~a"),
-      scm_list_1 (port));
-    }
-
-  if (write_buf_size != pt->write_buf_size
-      && pt->write_pos != pt->write_buf)
-    {
-      scm_misc_error (func_name, _("write buffer not empty: ~a"),
-      scm_list_1 (port));
-    }
-
-  /* Now we can update the buffer sizes, but only if the size has changed.  */
-
-  if (read_buf_size != pt->read_buf_size)
-    {
-      iomem->read_buf_size = read_buf_size;
-      pt->read_buf_size = read_buf_size;
-      xfree (pt->read_buf);
-      pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
-      pt->read_pos = pt->read_end = pt->read_buf;
-    }
-
-  if (write_buf_size != pt->write_buf_size)
-    {
-      iomem->write_buf_size = write_buf_size;
-      pt->write_buf_size = write_buf_size;
-      xfree (pt->write_buf);
-      pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
-      pt->write_pos = pt->write_buf;
-      pt->write_end = pt->write_buf + pt->write_buf_size;
-    }
-}
+#endif
 
 /* (open-memory [#:mode string] [#:start address] [#:size integer]) -> port
    Return a port that can be used for reading and writing memory.
@@ -1109,9 +1356,19 @@ gdbscm_open_memory (SCM rest)
 
   mode_bits = ioscm_parse_mode_bits (FUNC_NAME, mode);
 
-  port = ioscm_open_port (memory_port_desc, mode_bits);
+  /* Edge case: empty range -> unbuffered.
+     There's no need to disallow empty ranges, but we need an unbuffered port
+     to get the semantics right.  */
+  if (size == 0)
+    mode_bits |= SCM_BUF0;
+
+  auto stream = ioscm_init_memory_port_stream (start, end);
+  port = ioscm_open_port (memory_port_desc, mode_bits,
+  (scm_t_bits) stream);
 
-  ioscm_init_memory_port (port, start, end);
+#if USING_GUILE_BEFORE_2_2
+  ioscm_init_memory_port_buffers (port);
+#endif
 
   scm_dynwind_end ();
 
@@ -1124,7 +1381,11 @@ gdbscm_open_memory (SCM rest)
 static int
 gdbscm_is_memory_port (SCM obj)
 {
+#if USING_GUILE_BEFORE_2_2
   return !SCM_IMP (obj) && (SCM_TYP16 (obj) == memory_port_desc);
+#else
+  return SCM_PORTP (obj) && (SCM_PORT_TYPE (obj) == memory_port_desc);
+#endif
 }
 
 /* (memory-port? obj) -> boolean */
@@ -1155,6 +1416,7 @@ gdbscm_memory_port_range (SCM port)
 static SCM
 gdbscm_memory_port_read_buffer_size (SCM port)
 {
+#if USING_GUILE_BEFORE_2_2
   ioscm_memory_port *iomem;
 
   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
@@ -1162,6 +1424,9 @@ gdbscm_memory_port_read_buffer_size (SCM port)
 
   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   return scm_from_uint (iomem->read_buf_size);
+#else
+  return scm_from_uint (0);
+#endif
 }
 
 /* (set-memory-port-read-buffer-size! port size) -> unspecified
@@ -1171,6 +1436,7 @@ gdbscm_memory_port_read_buffer_size (SCM port)
 static SCM
 gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
 {
+#if USING_GUILE_BEFORE_2_2
   ioscm_memory_port *iomem;
 
   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
@@ -1190,6 +1456,9 @@ gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
     FUNC_NAME);
 
   return SCM_UNSPECIFIED;
+#else
+  return scm_setvbuf (port, scm_from_utf8_symbol ("block"), size);
+#endif
 }
 
 /* (memory-port-write-buffer-size port) -> integer */
@@ -1197,6 +1466,7 @@ gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
 static SCM
 gdbscm_memory_port_write_buffer_size (SCM port)
 {
+#if USING_GUILE_BEFORE_2_2
   ioscm_memory_port *iomem;
 
   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
@@ -1204,6 +1474,9 @@ gdbscm_memory_port_write_buffer_size (SCM port)
 
   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   return scm_from_uint (iomem->write_buf_size);
+#else
+  return scm_from_uint (0);
+#endif
 }
 
 /* (set-memory-port-write-buffer-size! port size) -> unspecified
@@ -1213,6 +1486,7 @@ gdbscm_memory_port_write_buffer_size (SCM port)
 static SCM
 gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size)
 {
+#if USING_GUILE_BEFORE_2_2
   ioscm_memory_port *iomem;
 
   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
@@ -1232,6 +1506,9 @@ gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size)
     FUNC_NAME);
 
   return SCM_UNSPECIFIED;
+#else
+  return scm_setvbuf (port, scm_from_utf8_symbol ("block"), size);
+#endif
 }
 
 /* Initialize gdb ports.  */
@@ -1366,9 +1643,11 @@ gdbscm_initialize_ports (void)
   start_keyword = scm_from_latin1_keyword ("start");
   size_keyword = scm_from_latin1_keyword ("size");
 
+#if USING_GUILE_BEFORE_2_2
   /* Error message text for "out of range" memory port buffer sizes.  */
 
   out_of_range_buf_size = xstrprintf ("size not between %u - %u",
       min_memory_port_buf_size,
       max_memory_port_buf_size);
+#endif
 }
diff --git a/gdb/testsuite/gdb.guile/scm-error.exp b/gdb/testsuite/gdb.guile/scm-error.exp
index 799bfe5db0..f073200b6e 100644
--- a/gdb/testsuite/gdb.guile/scm-error.exp
+++ b/gdb/testsuite/gdb.guile/scm-error.exp
@@ -34,7 +34,7 @@ set remote_guile_file_2 [gdb_remote_download host \
      ${srcdir}/${subdir}/${testfile}-2.scm]
 
 gdb_test "source $remote_guile_file_1" \
-    "(ERROR: )?In procedure \[+\]: Wrong type: #f.*" \
+    "(ERROR: )?In procedure \[+\]: Wrong type.*: #f.*" \
     "error loading scm file caught"
 
 gdb_test "p 1" " = 1" "no delayed error"
--
2.26.2

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 2/2] guile: Add support for Guile 3.0.

Ludovic Courtès-3
In reply to this post by Ludovic Courtès-3
gdb/ChangeLog
2020-06-15  Ludovic Courtès  <[hidden email]>

        * guile/scm-math.c (vlscm_integer_fits_p): Use 'uintmax_t'
        and 'intmax_t' instead of 'scm_t_uintmax' and 'scm_t_intmax',
        which are deprecated in Guile 3.0.
        * testsuite/gdb.guile/source2.scm: Add #f first argument to
        'format'.
        * testsuite/gdb.guile/types-module.exp: Remove "ERROR:" from
        regexps since Guile 3.0 no longer prints that.
        * configure.ac (try_guile_versions): Add "guile-3.0".
        * configure (try_guile_versions): Regenerate.
        * NEWS: Update entry.

gdb/doc/ChangeLog
2020-06-15  Ludovic Courtès  <[hidden email]>

        * doc/guile.texi (Guile Introduction): Mention Guile 3.0.
---
 gdb/NEWS                                 | 2 +-
 gdb/configure                            | 2 +-
 gdb/configure.ac                         | 2 +-
 gdb/doc/guile.texi                       | 2 +-
 gdb/guile/scm-math.c                     | 4 ++--
 gdb/testsuite/gdb.guile/source2.scm      | 2 +-
 gdb/testsuite/gdb.guile/types-module.exp | 6 +++---
 7 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index d8a9de4179..23705e1c65 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -85,7 +85,7 @@ GNU/Linux/RISC-V (gdbserver) riscv*-*-linux*
 
 * Guile API
 
-  ** GDB can now be built with GNU Guile 2.2 in addition to 2.0.
+  ** GDB can now be built with GNU Guile 3.0 and 2.2 in addition to 2.0.
 
   ** Procedures 'memory-port-read-buffer-size',
      'set-memory-port-read-buffer-size!', 'memory-port-write-buffer-size',
diff --git a/gdb/configure b/gdb/configure
index bd12695291..5ad1e53ac4 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -10954,7 +10954,7 @@ fi
 
 
 
-try_guile_versions="guile-2.2 guile-2.0"
+try_guile_versions="guile-3.0 guile-2.2 guile-2.0"
 have_libguile=no
 case "${with_guile}" in
 no)
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 87afc26581..d8cef1e914 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1088,7 +1088,7 @@ AC_MSG_RESULT([$with_guile])
 dnl We check guile with pkg-config.
 AC_PATH_PROG(pkg_config_prog_path, pkg-config, missing)
 
-try_guile_versions="guile-2.2 guile-2.0"
+try_guile_versions="guile-3.0 guile-2.2 guile-2.0"
 have_libguile=no
 case "${with_guile}" in
 no)
diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index 0e6c74ef8b..45c8f3f197 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -38,7 +38,7 @@ Guile support in @value{GDBN} follows the Python support in @value{GDBN}
 reasonably closely, so concepts there should carry over.
 However, some things are done differently where it makes sense.
 
-@value{GDBN} requires Guile version 2.2 or 2.0.
+@value{GDBN} requires Guile version 3.0, 2.2, or 2.0.
 
 @cindex guile scripts directory
 Guile scripts used by @value{GDBN} should be installed in
diff --git a/gdb/guile/scm-math.c b/gdb/guile/scm-math.c
index 7c63fa2ae0..419f5099bf 100644
--- a/gdb/guile/scm-math.c
+++ b/gdb/guile/scm-math.c
@@ -578,7 +578,7 @@ vlscm_integer_fits_p (SCM obj, struct type *type)
       ULONGEST max;
 
       /* If scm_is_unsigned_integer can't work with this type, just punt.  */
-      if (TYPE_LENGTH (type) > sizeof (scm_t_uintmax))
+      if (TYPE_LENGTH (type) > sizeof (uintmax_t))
  return 0;
       get_unsigned_type_max (type, &max);
       return scm_is_unsigned_integer (obj, 0, max);
@@ -588,7 +588,7 @@ vlscm_integer_fits_p (SCM obj, struct type *type)
       LONGEST min, max;
 
       /* If scm_is_signed_integer can't work with this type, just punt.  */
-      if (TYPE_LENGTH (type) > sizeof (scm_t_intmax))
+      if (TYPE_LENGTH (type) > sizeof (intmax_t))
  return 0;
       get_signed_type_minmax (type, &min, &max);
       return scm_is_signed_integer (obj, min, max);
diff --git a/gdb/testsuite/gdb.guile/source2.scm b/gdb/testsuite/gdb.guile/source2.scm
index 39638053d9..c39f03801a 100644
--- a/gdb/testsuite/gdb.guile/source2.scm
+++ b/gdb/testsuite/gdb.guile/source2.scm
@@ -15,5 +15,5 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-(display (format "y~As" "e"))
+(display (format #f "y~As" "e"))
 (newline)
diff --git a/gdb/testsuite/gdb.guile/types-module.exp b/gdb/testsuite/gdb.guile/types-module.exp
index 5a631dca8e..8ced6fbffb 100644
--- a/gdb/testsuite/gdb.guile/types-module.exp
+++ b/gdb/testsuite/gdb.guile/types-module.exp
@@ -44,7 +44,7 @@ gdb_test "guile (print (type-has-field-deep? d \"base_member\"))" \
     "= #t" "type-has-field-deep? member in baseclass"
 
 gdb_test "guile (print (type-has-field-deep? (lookup-type \"int\") \"base_member\"))" \
-    "ERROR: .*Wrong type argument in position 1 \\(expecting struct or union\\): #<gdb:type int>.*" \
+    "Wrong type argument in position 1 \\(expecting struct or union\\): #<gdb:type int>.*" \
     "type-has-field-deep? from int"
 
 gdb_scm_test_silent_cmd "guile (define enum-htab (make-enum-hashtable (lookup-type \"enum_type\")))" \
@@ -54,9 +54,9 @@ gdb_test "guile (print (hash-ref enum-htab \"B\"))" \
     "= 1" "verify make-enum-hashtable"
 
 gdb_test "guile (define bad-enum-htab (make-enum-hashtable #f))" \
-    "ERROR: .*Wrong type argument in position 1 \\(expecting gdb:type\\): #f.*" \
+    "Wrong type argument in position 1 \\(expecting gdb:type\\): #f.*" \
     "make-enum-hashtable from #f"
 
 gdb_test "guile (define bad-enum-htab (make-enum-hashtable (lookup-type \"int\")))" \
-    "ERROR: .*Wrong type argument in position 1 \\(expecting enum\\): #<gdb:type int>.*" \
+    "Wrong type argument in position 1 \\(expecting enum\\): #<gdb:type int>.*" \
     "make-enum-hashtable from int"
--
2.26.2

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] guile: Add support for Guile 3.0.

Ludovic Courtès-3
In reply to this post by Tom Tromey-2
Hi,

Tom Tromey <[hidden email]> skribis:

>>>>>> "Ludovic" == Ludovic Courtès <[hidden email]> writes:
>
> Ludovic> * testsuite/gdb.guile/source2.scm: Add #f first argument to
> Ludovic> 'format'.
> Ludovic> * testsuite/gdb.guile/types-module.exp: Remove "ERROR:" from
> Ludovic> regexps since Guile 3.0 no longer prints that.
>
> testsuite/ (unfortunately IMO) has its own ChangeLog.

Oops, will change it.

> Ludovic>        /* If scm_is_unsigned_integer can't work with this type, just punt.  */
> Ludovic> -      if (TYPE_LENGTH (type) > sizeof (scm_t_uintmax))
> Ludovic> +      if (TYPE_LENGTH (type) > sizeof (uintmax_t))
>
> I suppose these can't differ in Guile 2.0 or 2.2?

Correct.  ‘scm_t_uintmax’ used to be provided by Guile but it no longer
makes sense now that C99 <stdint.h> and its C++ counterpart are widely
available.

> Anyway, this patch seems fine to me.

Thanks,
Ludo’.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 1/2] guile: Add support for Guile 2.2.

Eli Zaretskii
In reply to this post by Ludovic Courtès-3
> From: Ludovic Courtès <[hidden email]>
> Date: Mon, 15 Jun 2020 17:14:52 +0200
> Cc: Ludovic Courtès <[hidden email]>
>
> This primarily updates code that uses the I/O port API of Guile.
>
> gdb/ChangeLog
> 2020-06-15  Ludovic Courtès  <[hidden email]>
>             Doug Evans  <[hidden email]>
>
> PR gdb/21104
> * guile/scm-ports.c (USING_GUILE_BEFORE_2_2): New macro.
> (ioscm_memory_port)[read_buf_size, write_buf_size]: Wrap in #if
> USING_GUILE_BEFORE_2_2.
> (stdio_port_desc, memory_port_desc) [!USING_GUILE_BEFORE_2_2]:
> Change type to 'scm_t_port_type *'.
> (natural_buffer_size) [!USING_GUILE_BEFORE_2_2]: New variable.
> (ioscm_open_port) [USING_GUILE_BEFORE_2_2]: Add 'stream'
> parameter and honor it.  Update callers.
> (ioscm_open_port) [!USING_GUILE_BEFORE_2_2]: New function.
> (ioscm_read_from_port, ioscm_write) [!USING_GUILE_BEFORE_2_2]: New
> functions.
> (ioscm_fill_input, ioscm_input_waiting, ioscm_flush): Wrap in #if
> USING_GUILE_BEFORE_2_2.
> (ioscm_init_gdb_stdio_port) [!USING_GUILE_BEFORE_2_2]: Use
> 'ioscm_read_from_port'.  Call 'scm_set_port_read_wait_fd'.
> (ioscm_init_stdio_buffers) [!USING_GUILE_BEFORE_2_2]: New function.
> (gdbscm_stdio_port_p) [!USING_GUILE_BEFORE_2_2]: Use 'SCM_PORTP'
> and 'SCM_PORT_TYPE'.
> (gdbscm_memory_port_end_input, gdbscm_memory_port_seek)
> (ioscm_reinit_memory_port): Wrap in #if USING_GUILE_BEFORE_2_2.
> (gdbscm_memory_port_read, gdbscm_memory_port_write)
> (gdbscm_memory_port_seek, gdbscm_memory_port_close)
> [!USING_GUILE_BEFORE_2_2]: New functions.
> (gdbscm_memory_port_print): Remove use of 'SCM_PTOB_NAME'.
> (ioscm_init_memory_port_type) [!USING_GUILE_BEFORE_2_2]: Use
> 'gdbscm_memory_port_read'.
> Wrap 'scm_set_port_end_input', 'scm_set_port_flush', and
> 'scm_set_port_free' calls in #if USING_GUILE_BEFORE_2_2.
> (gdbscm_get_natural_buffer_sizes) [!USING_GUILE_BEFORE_2_2]: New
> function.
> (ioscm_init_memory_port): Remove.
> (ioscm_init_memory_port_stream): New function
> (ioscm_init_memory_port_buffers) [USING_GUILE_BEFORE_2_2]: New
> function.
> (gdbscm_memory_port_read_buffer_size) [!USING_GUILE_BEFORE_2_2]:
> Return scm_from_uint (0).
> (gdbscm_set_memory_port_read_buffer_size_x)
> [!USING_GUILE_BEFORE_2_2]: Call 'scm_setvbuf'.
> (gdbscm_memory_port_write_buffer_size) [!USING_GUILE_BEFORE_2_2]:
> Return scm_from_uint (0).
> (gdbscm_set_memory_port_write_buffer_size_x)
> [!USING_GUILE_BEFORE_2_2]: Call 'scm_setvbuf'.
> * testsuite/gdb.guile/scm-error.exp ("source
> $remote_guile_file_1"): Relax error regexp to match on Guile 2.2.
> * configure.ac (try_guile_versions): Add "guile-2.2".
> * configure: Regenerate.
> * NEWS: Add entry.
>
> gdb/doc/ChangeLog
> 2020-06-15  Ludovic Courtès  <[hidden email]>
>
> * guile.texi (Memory Ports in Guile): Remove
> documentation of 'memory-port-read-buffer-size',
> 'set-memory-port-read-buffer-size!',
> 'memory-port-write-buffer-size',
> 'set-memory-port-read-buffer-size!', which are no longer
> supported with Guile 2.2/3.0 and superseded by 'setvbuf'.
> * doc/guile.texi (Guile Introduction): Clarify which Guile
> versions are supported.

The documentation parts are okay, thanks.

I still am not convinced we should remove the description of those
functions from the manual, but I'll let others speak up if they have
an opinion.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] guile: Add support for Guile 3.0.

Ludovic Courtès-3
In reply to this post by Tom Tromey-2
Hello Tom & Eli,

Tom Tromey <[hidden email]> skribis:

>>>>>> "Ludovic" == Ludovic Courtès <[hidden email]> writes:

[...]

> Anyway, this patch seems fine to me.

[...]

> The documentation parts are okay, thanks.
>
> I still am not convinced we should remove the description of those
> functions from the manual, but I'll let others speak up if they have
> an opinion.

We haven’t gotten more feedback.

Should I interpret your messages above as formal approval?  For the
first patch or both?  (I can also wait for more feedback, I just want to
make sure there’s no misunderstanding.)

Thanks,
Ludo’.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] guile: Add support for Guile 3.0.

Eli Zaretskii
> From: Ludovic Courtès <[hidden email]>
> Cc: [hidden email]
> Date: Wed, 17 Jun 2020 18:58:15 +0200
>
> > Anyway, this patch seems fine to me.
>
> [...]
>
> > The documentation parts are okay, thanks.
> >
> > I still am not convinced we should remove the description of those
> > functions from the manual, but I'll let others speak up if they have
> > an opinion.
>
> We haven’t gotten more feedback.
>
> Should I interpret your messages above as formal approval?  For the
> first patch or both?  (I can also wait for more feedback, I just want to
> make sure there’s no misunderstanding.)

I approved the documentation parts.  I'll leave it to Tom to decide
whether we need to wait for more opinions.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 1/2] guile: Add support for Guile 2.2.

Tom Tromey-2
In reply to this post by Eli Zaretskii
>>>>> "Eli" == Eli Zaretskii <[hidden email]> writes:

Eli> I still am not convinced we should remove the description of those
Eli> functions from the manual, but I'll let others speak up if they have
Eli> an opinion.

When do we plan to remove them?

Maybe it would be better to leave the docs and say "these will be
removed in gdb 11", then once 10 branches we could go ahead with that.

IIUC maybe they are sometimes needed by Guile 2.0?  How long is that
expected to be around?

Tom
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 1/2] guile: Add support for Guile 2.2.

Eli Zaretskii
> From: Tom Tromey <[hidden email]>
> Cc: Ludovic Courtès <[hidden email]>,
>   [hidden email]
> Date: Thu, 18 Jun 2020 14:31:51 -0600
>
> >>>>> "Eli" == Eli Zaretskii <[hidden email]> writes:
>
> Eli> I still am not convinced we should remove the description of those
> Eli> functions from the manual, but I'll let others speak up if they have
> Eli> an opinion.
>
> When do we plan to remove them?
>
> Maybe it would be better to leave the docs and say "these will be
> removed in gdb 11", then once 10 branches we could go ahead with that.

Those were my thoughts, yes.  And also to state that they are only
available with Guile 2.0.

> IIUC maybe they are sometimes needed by Guile 2.0?  How long is that
> expected to be around?

Something for Ludo to answer, I guess.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 1/2] guile: Add support for Guile 2.2.

Ludovic Courtès-3
Hi,

Eli Zaretskii <[hidden email]> skribis:

>> >>>>> "Eli" == Eli Zaretskii <[hidden email]> writes:
>>
>> Eli> I still am not convinced we should remove the description of those
>> Eli> functions from the manual, but I'll let others speak up if they have
>> Eli> an opinion.
>>
>> When do we plan to remove them?
>>
>> Maybe it would be better to leave the docs and say "these will be
>> removed in gdb 11", then once 10 branches we could go ahead with that.
>
> Those were my thoughts, yes.  And also to state that they are only
> available with Guile 2.0.

OK, sounds good to me.

>> IIUC maybe they are sometimes needed by Guile 2.0?

They’re the only way to change the size of the memory port’s internal
buffer on 2.0, but I can’t think of a use case where one really needs
that control.

>> How long is that expected to be around?

If this goes into gdb 10, my suggestion is to remove Guile 2.0 support
in gdb 11.  We’re keeping it just to make the transition smoother.

Thanks,
Ludo’.
12