Home | History | Annotate | Line # | Download | only in guile
      1  1.1  christos /* Support for connecting Guile's stdio to GDB's.
      2  1.1  christos    as well as r/w memory via ports.
      3  1.1  christos 
      4  1.9  christos    Copyright (C) 2014-2024 Free Software Foundation, Inc.
      5  1.1  christos 
      6  1.1  christos    This file is part of GDB.
      7  1.1  christos 
      8  1.1  christos    This program is free software; you can redistribute it and/or modify
      9  1.1  christos    it under the terms of the GNU General Public License as published by
     10  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     11  1.1  christos    (at your option) any later version.
     12  1.1  christos 
     13  1.1  christos    This program is distributed in the hope that it will be useful,
     14  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  1.1  christos    GNU General Public License for more details.
     17  1.1  christos 
     18  1.1  christos    You should have received a copy of the GNU General Public License
     19  1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     20  1.1  christos 
     21  1.1  christos /* See README file in this directory for implementation notes, coding
     22  1.1  christos    conventions, et.al.  */
     23  1.1  christos 
     24  1.7  christos #include "gdbsupport/gdb_select.h"
     25  1.9  christos #include "ui.h"
     26  1.1  christos #include "target.h"
     27  1.1  christos #include "guile-internal.h"
     28  1.9  christos #include <optional>
     29  1.1  christos 
     30  1.1  christos #ifdef HAVE_POLL
     31  1.1  christos #if defined (HAVE_POLL_H)
     32  1.1  christos #include <poll.h>
     33  1.1  christos #elif defined (HAVE_SYS_POLL_H)
     34  1.1  christos #include <sys/poll.h>
     35  1.1  christos #endif
     36  1.1  christos #endif
     37  1.1  christos 
     38  1.7  christos /* Whether we're using Guile < 2.2 and its clumsy port API.  */
     39  1.7  christos 
     40  1.7  christos #define USING_GUILE_BEFORE_2_2				\
     41  1.7  christos   (SCM_MAJOR_VERSION == 2 && SCM_MINOR_VERSION == 0)
     42  1.7  christos 
     43  1.7  christos 
     44  1.1  christos /* A ui-file for sending output to Guile.  */
     45  1.1  christos 
     46  1.5  christos class ioscm_file_port : public ui_file
     47  1.1  christos {
     48  1.5  christos public:
     49  1.5  christos   /* Return a ui_file that writes to PORT.  */
     50  1.5  christos   explicit ioscm_file_port (SCM port);
     51  1.5  christos 
     52  1.5  christos   void flush () override;
     53  1.5  christos   void write (const char *buf, long length_buf) override;
     54  1.5  christos 
     55  1.5  christos private:
     56  1.5  christos   SCM m_port;
     57  1.5  christos };
     58  1.1  christos 
     59  1.1  christos /* Data for a memory port.  */
     60  1.1  christos 
     61  1.8  christos struct ioscm_memory_port
     62  1.1  christos {
     63  1.3  christos   /* Bounds of memory range this port is allowed to access: [start, end).
     64  1.3  christos      This means that 0xff..ff is not accessible.  I can live with that.  */
     65  1.1  christos   CORE_ADDR start, end;
     66  1.1  christos 
     67  1.3  christos   /* (end - start), recorded for convenience.  */
     68  1.1  christos   ULONGEST size;
     69  1.1  christos 
     70  1.1  christos   /* Think of this as the lseek value maintained by the kernel.
     71  1.1  christos      This value is always in the range [0, size].  */
     72  1.1  christos   ULONGEST current;
     73  1.1  christos 
     74  1.7  christos #if USING_GUILE_BEFORE_2_2
     75  1.1  christos   /* The size of the internal r/w buffers.
     76  1.1  christos      Scheme ports aren't a straightforward mapping to memory r/w.
     77  1.1  christos      Generally the user specifies how much to r/w and all access is
     78  1.1  christos      unbuffered.  We don't try to provide equivalent access, but we allow
     79  1.1  christos      the user to specify these values to help get something similar.  */
     80  1.1  christos   unsigned read_buf_size, write_buf_size;
     81  1.7  christos #endif
     82  1.8  christos };
     83  1.1  christos 
     84  1.1  christos /* Copies of the original system input/output/error ports.
     85  1.1  christos    These are recorded for debugging purposes.  */
     86  1.1  christos static SCM orig_input_port_scm;
     87  1.1  christos static SCM orig_output_port_scm;
     88  1.1  christos static SCM orig_error_port_scm;
     89  1.1  christos 
     90  1.1  christos /* This is the stdio port descriptor, scm_ptob_descriptor.  */
     91  1.7  christos #if USING_GUILE_BEFORE_2_2
     92  1.1  christos static scm_t_bits stdio_port_desc;
     93  1.7  christos #else
     94  1.7  christos static scm_t_port_type *stdio_port_desc;
     95  1.7  christos #endif
     96  1.1  christos 
     97  1.1  christos /* Note: scm_make_port_type takes a char * instead of a const char *.  */
     98  1.1  christos static /*const*/ char stdio_port_desc_name[] = "gdb:stdio-port";
     99  1.1  christos 
    100  1.1  christos /* Names of each gdb port.  */
    101  1.1  christos static const char input_port_name[] = "gdb:stdin";
    102  1.1  christos static const char output_port_name[] = "gdb:stdout";
    103  1.1  christos static const char error_port_name[] = "gdb:stderr";
    104  1.1  christos 
    105  1.1  christos /* This is the actual port used from Guile.
    106  1.1  christos    We don't expose these to the user though, to ensure they're not
    107  1.1  christos    overwritten.  */
    108  1.1  christos static SCM input_port_scm;
    109  1.1  christos static SCM output_port_scm;
    110  1.1  christos static SCM error_port_scm;
    111  1.1  christos 
    112  1.1  christos /* Internal enum for specifying output port.  */
    113  1.1  christos enum oport { GDB_STDOUT, GDB_STDERR };
    114  1.1  christos 
    115  1.1  christos /* This is the memory port descriptor, scm_ptob_descriptor.  */
    116  1.7  christos #if USING_GUILE_BEFORE_2_2
    117  1.1  christos static scm_t_bits memory_port_desc;
    118  1.7  christos #else
    119  1.7  christos static scm_t_port_type *memory_port_desc;
    120  1.7  christos #endif
    121  1.1  christos 
    122  1.1  christos /* Note: scm_make_port_type takes a char * instead of a const char *.  */
    123  1.1  christos static /*const*/ char memory_port_desc_name[] = "gdb:memory-port";
    124  1.1  christos 
    125  1.7  christos #if USING_GUILE_BEFORE_2_2
    126  1.7  christos 
    127  1.1  christos /* The default amount of memory to fetch for each read/write request.
    128  1.1  christos    Scheme ports don't provide a way to specify the size of a read,
    129  1.1  christos    which is important to us to minimize the number of inferior interactions,
    130  1.1  christos    which over a remote link can be important.  To compensate we augment the
    131  1.1  christos    port API with a new function that let's the user specify how much the next
    132  1.1  christos    read request should fetch.  This is the initial value for each new port.  */
    133  1.1  christos static const unsigned default_read_buf_size = 16;
    134  1.1  christos static const unsigned default_write_buf_size = 16;
    135  1.1  christos 
    136  1.1  christos /* Arbitrarily limit memory port buffers to 1 byte to 4K.  */
    137  1.1  christos static const unsigned min_memory_port_buf_size = 1;
    138  1.1  christos static const unsigned max_memory_port_buf_size = 4096;
    139  1.1  christos 
    140  1.1  christos /* "out of range" error message for buf sizes.  */
    141  1.8  christos static gdb::unique_xmalloc_ptr<char> out_of_range_buf_size;
    142  1.1  christos 
    143  1.7  christos #else
    144  1.7  christos 
    145  1.7  christos /* The maximum values to use for get_natural_buffer_sizes.  */
    146  1.7  christos static const unsigned natural_buf_size = 16;
    147  1.7  christos 
    148  1.7  christos #endif
    149  1.7  christos 
    150  1.1  christos /* Keywords used by open-memory.  */
    151  1.1  christos static SCM mode_keyword;
    152  1.1  christos static SCM start_keyword;
    153  1.1  christos static SCM size_keyword;
    154  1.1  christos 
    155  1.7  christos /* Helper to do the low level work of opening a port.  */
    157  1.7  christos 
    158  1.1  christos #if USING_GUILE_BEFORE_2_2
    159  1.1  christos 
    160  1.7  christos static SCM
    161  1.1  christos ioscm_open_port (scm_t_bits port_type, long mode_bits, scm_t_bits stream)
    162  1.1  christos {
    163  1.1  christos   SCM port;
    164  1.1  christos 
    165  1.1  christos #if 0 /* TODO: Guile doesn't export this.  What to do?  */
    166  1.1  christos   scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
    167  1.1  christos #endif
    168  1.1  christos 
    169  1.1  christos   port = scm_new_port_table_entry (port_type);
    170  1.1  christos 
    171  1.7  christos   SCM_SET_CELL_TYPE (port, port_type | mode_bits);
    172  1.1  christos   SCM_SETSTREAM (port, stream);
    173  1.1  christos 
    174  1.1  christos #if 0 /* TODO: Guile doesn't export this.  What to do?  */
    175  1.1  christos   scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
    176  1.1  christos #endif
    177  1.1  christos 
    178  1.1  christos   return port;
    179  1.7  christos }
    180  1.7  christos 
    181  1.7  christos #else
    182  1.7  christos 
    183  1.7  christos static SCM
    184  1.7  christos ioscm_open_port (scm_t_port_type *port_type, long mode_bits, scm_t_bits stream)
    185  1.7  christos {
    186  1.7  christos   return scm_c_make_port (port_type, mode_bits, stream);
    187  1.7  christos }
    188  1.7  christos 
    189  1.7  christos #endif
    190  1.1  christos 
    191  1.1  christos 
    192  1.1  christos /* Support for connecting Guile's stdio ports to GDB's stdio ports.  */
    194  1.8  christos 
    195  1.7  christos /* Print a string S, length SIZE, but don't escape characters, except
    196  1.7  christos    nul.  */
    197  1.7  christos 
    198  1.7  christos static void
    199  1.7  christos fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
    200  1.7  christos {
    201  1.7  christos   size_t i;
    202  1.7  christos 
    203  1.7  christos   for (i = 0; i < size; ++i)
    204  1.8  christos     {
    205  1.7  christos       if (s[i] == '\0')
    206  1.8  christos 	gdb_puts ("\\000", stream);
    207  1.7  christos       else
    208  1.7  christos 	gdb_putc (s[i], stream);
    209  1.7  christos     }
    210  1.7  christos }
    211  1.7  christos 
    212  1.1  christos #if USING_GUILE_BEFORE_2_2
    213  1.1  christos 
    214  1.1  christos /* The scm_t_ptob_descriptor.input_waiting "method".
    215  1.1  christos    Return a lower bound on the number of bytes available for input.  */
    216  1.1  christos 
    217  1.1  christos static int
    218  1.1  christos ioscm_input_waiting (SCM port)
    219  1.1  christos {
    220  1.1  christos   int fdes = 0;
    221  1.1  christos 
    222  1.1  christos   if (! scm_is_eq (port, input_port_scm))
    223  1.1  christos     return 0;
    224  1.1  christos 
    225  1.1  christos #ifdef HAVE_POLL
    226  1.1  christos   {
    227  1.1  christos     /* This is copied from libguile/fports.c.  */
    228  1.1  christos     struct pollfd pollfd = { fdes, POLLIN, 0 };
    229  1.1  christos     static int use_poll = -1;
    230  1.1  christos 
    231  1.1  christos     if (use_poll < 0)
    232  1.1  christos       {
    233  1.1  christos 	/* This is copied from event-loop.c: poll cannot be used for stdin on
    234  1.1  christos 	   m68k-motorola-sysv.  */
    235  1.1  christos 	struct pollfd test_pollfd = { fdes, POLLIN, 0 };
    236  1.1  christos 
    237  1.1  christos 	if (poll (&test_pollfd, 1, 0) == 1 && (test_pollfd.revents & POLLNVAL))
    238  1.1  christos 	  use_poll = 0;
    239  1.1  christos 	else
    240  1.1  christos 	  use_poll = 1;
    241  1.1  christos       }
    242  1.1  christos 
    243  1.1  christos     if (use_poll)
    244  1.1  christos       {
    245  1.1  christos 	/* Guile doesn't export SIGINT hooks like Python does.
    246  1.1  christos 	   For now pass EINTR to scm_syserror, that's what fports.c does.  */
    247  1.1  christos 	if (poll (&pollfd, 1, 0) < 0)
    248  1.1  christos 	  scm_syserror (FUNC_NAME);
    249  1.1  christos 
    250  1.1  christos 	return pollfd.revents & POLLIN ? 1 : 0;
    251  1.1  christos       }
    252  1.1  christos   }
    253  1.1  christos   /* Fall through.  */
    254  1.1  christos #endif
    255  1.1  christos 
    256  1.1  christos   {
    257  1.1  christos     struct timeval timeout;
    258  1.1  christos     fd_set input_fds;
    259  1.1  christos     int num_fds = fdes + 1;
    260  1.1  christos     int num_found;
    261  1.1  christos 
    262  1.1  christos     memset (&timeout, 0, sizeof (timeout));
    263  1.1  christos     FD_ZERO (&input_fds);
    264  1.4  christos     FD_SET (fdes, &input_fds);
    265  1.4  christos 
    266  1.4  christos     num_found = interruptible_select (num_fds,
    267  1.1  christos 				      &input_fds, NULL, NULL,
    268  1.1  christos 				      &timeout);
    269  1.1  christos     if (num_found < 0)
    270  1.1  christos       {
    271  1.8  christos 	/* Guile doesn't export SIGINT hooks like Python does.
    272  1.1  christos 	   For now pass EINTR to scm_syserror, that's what fports.c does.  */
    273  1.1  christos 	scm_syserror (FUNC_NAME);
    274  1.1  christos       }
    275  1.1  christos     return num_found > 0 && FD_ISSET (fdes, &input_fds);
    276  1.1  christos   }
    277  1.1  christos }
    278  1.1  christos 
    279  1.1  christos /* The scm_t_ptob_descriptor.fill_input "method".  */
    280  1.1  christos 
    281  1.1  christos static int
    282  1.1  christos ioscm_fill_input (SCM port)
    283  1.1  christos {
    284  1.1  christos   /* Borrowed from libguile/fports.c.  */
    285  1.1  christos   long count;
    286  1.1  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    287  1.1  christos 
    288  1.1  christos   /* If we're called on stdout,stderr, punt.  */
    289  1.1  christos   if (! scm_is_eq (port, input_port_scm))
    290  1.1  christos     return (scm_t_wchar) EOF; /* Set errno and return -1?  */
    291  1.1  christos 
    292  1.1  christos   gdb_flush (gdb_stdout);
    293  1.7  christos   gdb_flush (gdb_stderr);
    294  1.1  christos 
    295  1.1  christos   count = gdb_stdin->read ((char *) pt->read_buf, pt->read_buf_size);
    296  1.1  christos   if (count == -1)
    297  1.1  christos     scm_syserror (FUNC_NAME);
    298  1.1  christos   if (count == 0)
    299  1.1  christos     return (scm_t_wchar) EOF;
    300  1.1  christos 
    301  1.1  christos   pt->read_pos = pt->read_buf;
    302  1.1  christos   pt->read_end = pt->read_buf + count;
    303  1.1  christos   return *pt->read_buf;
    304  1.1  christos }
    305  1.1  christos 
    306  1.1  christos /* Write to gdb's stdout or stderr.  */
    307  1.1  christos 
    308  1.1  christos static void
    309  1.1  christos ioscm_write (SCM port, const void *data, size_t size)
    310  1.1  christos {
    311  1.1  christos 
    312  1.1  christos   /* If we're called on stdin, punt.  */
    313  1.1  christos   if (scm_is_eq (port, input_port_scm))
    314  1.7  christos     return;
    315  1.7  christos 
    316  1.1  christos   gdbscm_gdb_exception exc {};
    317  1.1  christos   try
    318  1.4  christos     {
    319  1.1  christos       if (scm_is_eq (port, error_port_scm))
    320  1.4  christos 	fputsn_filtered ((const char *) data, size, gdb_stderr);
    321  1.1  christos       else
    322  1.7  christos 	fputsn_filtered ((const char *) data, size, gdb_stdout);
    323  1.3  christos     }
    324  1.7  christos   catch (const gdb_exception &except)
    325  1.3  christos     {
    326  1.7  christos       exc = unpack (except);
    327  1.1  christos     }
    328  1.1  christos   GDBSCM_HANDLE_GDB_EXCEPTION (exc);
    329  1.1  christos }
    330  1.1  christos 
    331  1.1  christos /* Flush gdb's stdout or stderr.  */
    332  1.1  christos 
    333  1.1  christos static void
    334  1.1  christos ioscm_flush (SCM port)
    335  1.1  christos {
    336  1.1  christos   /* If we're called on stdin, punt.  */
    337  1.1  christos   if (scm_is_eq (port, input_port_scm))
    338  1.1  christos     return;
    339  1.1  christos 
    340  1.1  christos   if (scm_is_eq (port, error_port_scm))
    341  1.1  christos     gdb_flush (gdb_stderr);
    342  1.1  christos   else
    343  1.1  christos     gdb_flush (gdb_stdout);
    344  1.7  christos }
    345  1.7  christos 
    346  1.7  christos #else /* !USING_GUILE_BEFORE_2_2 */
    347  1.7  christos 
    348  1.7  christos /* Read up to COUNT bytes into bytevector DST at offset START.  Return the
    349  1.7  christos    number of bytes read, zero for the end of file.  */
    350  1.7  christos 
    351  1.7  christos static size_t
    352  1.7  christos ioscm_read_from_port (SCM port, SCM dst, size_t start, size_t count)
    353  1.7  christos {
    354  1.7  christos   long read;
    355  1.7  christos   char *read_buf;
    356  1.7  christos 
    357  1.7  christos   /* If we're called on stdout,stderr, punt.  */
    358  1.7  christos   if (! scm_is_eq (port, input_port_scm))
    359  1.7  christos     return 0;
    360  1.7  christos 
    361  1.7  christos   gdb_flush (gdb_stdout);
    362  1.7  christos   gdb_flush (gdb_stderr);
    363  1.7  christos 
    364  1.7  christos   read_buf = (char *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
    365  1.7  christos   read = gdb_stdin->read (read_buf, count);
    366  1.7  christos   if (read == -1)
    367  1.7  christos     scm_syserror (FUNC_NAME);
    368  1.7  christos 
    369  1.7  christos   return (size_t) read;
    370  1.7  christos }
    371  1.7  christos 
    372  1.7  christos /* Write to gdb's stdout or stderr.  */
    373  1.7  christos 
    374  1.7  christos static size_t
    375  1.7  christos ioscm_write (SCM port, SCM src, size_t start, size_t count)
    376  1.7  christos {
    377  1.7  christos   const char *data = (char *) SCM_BYTEVECTOR_CONTENTS (src) + start;
    378  1.7  christos 
    379  1.7  christos   /* If we're called on stdin, punt.  */
    380  1.7  christos   if (scm_is_eq (port, input_port_scm))
    381  1.7  christos     return 0;
    382  1.7  christos 
    383  1.7  christos   gdbscm_gdb_exception exc {};
    384  1.7  christos   try
    385  1.7  christos     {
    386  1.7  christos       if (scm_is_eq (port, error_port_scm))
    387  1.7  christos 	fputsn_filtered ((const char *) data, count, gdb_stderr);
    388  1.7  christos       else
    389  1.7  christos 	fputsn_filtered ((const char *) data, count, gdb_stdout);
    390  1.7  christos     }
    391  1.7  christos   catch (const gdb_exception &except)
    392  1.7  christos     {
    393  1.7  christos       exc = unpack (except);
    394  1.7  christos     }
    395  1.7  christos   GDBSCM_HANDLE_GDB_EXCEPTION (exc);
    396  1.7  christos 
    397  1.7  christos   return count;
    398  1.7  christos }
    399  1.7  christos 
    400  1.1  christos #endif /* !USING_GUILE_BEFORE_2_2 */
    401  1.1  christos 
    402  1.1  christos /* Initialize the gdb stdio port type.
    403  1.1  christos 
    404  1.1  christos    N.B. isatty? will fail on these ports, it is only supported for file
    405  1.1  christos    ports.  IWBN if we could "subclass" file ports.  */
    406  1.1  christos 
    407  1.1  christos static void
    408  1.1  christos ioscm_init_gdb_stdio_port (void)
    409  1.7  christos {
    410  1.7  christos   stdio_port_desc = scm_make_port_type (stdio_port_desc_name,
    411  1.7  christos #if USING_GUILE_BEFORE_2_2
    412  1.7  christos 					ioscm_fill_input,
    413  1.7  christos #else
    414  1.7  christos 					ioscm_read_from_port,
    415  1.1  christos #endif
    416  1.7  christos 					ioscm_write);
    417  1.1  christos 
    418  1.1  christos #if USING_GUILE_BEFORE_2_2
    419  1.7  christos   scm_set_port_input_waiting (stdio_port_desc, ioscm_input_waiting);
    420  1.7  christos   scm_set_port_flush (stdio_port_desc, ioscm_flush);
    421  1.7  christos #else
    422  1.1  christos   scm_set_port_read_wait_fd (stdio_port_desc, STDIN_FILENO);
    423  1.1  christos #endif
    424  1.7  christos }
    425  1.7  christos 
    426  1.7  christos #define GDB_STDIO_BUFFER_DEFAULT_SIZE 1024
    427  1.7  christos 
    428  1.1  christos #if USING_GUILE_BEFORE_2_2
    429  1.1  christos 
    430  1.1  christos /* Subroutine of ioscm_make_gdb_stdio_port to simplify it.
    431  1.1  christos    Set up the buffers of port PORT.
    432  1.1  christos    MODE_BITS are the mode bits of PORT.  */
    433  1.1  christos 
    434  1.1  christos static void
    435  1.1  christos ioscm_init_stdio_buffers (SCM port, long mode_bits)
    436  1.1  christos {
    437  1.1  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    438  1.1  christos   int size = mode_bits & SCM_BUF0 ? 0 : GDB_STDIO_BUFFER_DEFAULT_SIZE;
    439  1.1  christos   int writing = (mode_bits & SCM_WRTNG) != 0;
    440  1.1  christos 
    441  1.1  christos   /* This is heavily copied from scm_fport_buffer_add.  */
    442  1.1  christos 
    443  1.4  christos   if (!writing && size > 0)
    444  1.4  christos     {
    445  1.1  christos       pt->read_buf
    446  1.1  christos 	= (unsigned char *) scm_gc_malloc_pointerless (size, "port buffer");
    447  1.1  christos       pt->read_pos = pt->read_end = pt->read_buf;
    448  1.1  christos       pt->read_buf_size = size;
    449  1.1  christos     }
    450  1.1  christos   else
    451  1.1  christos     {
    452  1.1  christos       pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
    453  1.1  christos       pt->read_buf_size = 1;
    454  1.1  christos     }
    455  1.1  christos 
    456  1.4  christos   if (writing && size > 0)
    457  1.4  christos     {
    458  1.1  christos       pt->write_buf
    459  1.1  christos 	= (unsigned char *) scm_gc_malloc_pointerless (size, "port buffer");
    460  1.1  christos       pt->write_pos = pt->write_buf;
    461  1.1  christos       pt->write_buf_size = size;
    462  1.1  christos     }
    463  1.1  christos   else
    464  1.1  christos     {
    465  1.1  christos       pt->write_buf = pt->write_pos = &pt->shortbuf;
    466  1.1  christos       pt->write_buf_size = 1;
    467  1.1  christos     }
    468  1.1  christos   pt->write_end = pt->write_buf + pt->write_buf_size;
    469  1.7  christos }
    470  1.7  christos 
    471  1.7  christos #else
    472  1.7  christos 
    473  1.7  christos static void
    474  1.7  christos ioscm_init_stdio_buffers (SCM port, long mode_bits)
    475  1.7  christos {
    476  1.7  christos   if (mode_bits & SCM_BUF0)
    477  1.7  christos     scm_setvbuf (port, scm_from_utf8_symbol ("none"), scm_from_size_t (0));
    478  1.7  christos   else
    479  1.7  christos     scm_setvbuf (port, scm_from_utf8_symbol ("block"),
    480  1.7  christos 		 scm_from_size_t (GDB_STDIO_BUFFER_DEFAULT_SIZE));
    481  1.7  christos }
    482  1.7  christos 
    483  1.1  christos #endif
    484  1.1  christos 
    485  1.1  christos /* Create a gdb stdio port.  */
    486  1.1  christos 
    487  1.1  christos static SCM
    488  1.1  christos ioscm_make_gdb_stdio_port (int fd)
    489  1.1  christos {
    490  1.4  christos   int is_a_tty = isatty (fd);
    491  1.1  christos   const char *name;
    492  1.1  christos   const char *mode_str;
    493  1.1  christos   long mode_bits;
    494  1.1  christos   SCM port;
    495  1.1  christos 
    496  1.1  christos   switch (fd)
    497  1.1  christos     {
    498  1.4  christos     case 0:
    499  1.1  christos       name = input_port_name;
    500  1.1  christos       mode_str = is_a_tty ? "r0" : "r";
    501  1.1  christos       break;
    502  1.4  christos     case 1:
    503  1.1  christos       name = output_port_name;
    504  1.1  christos       mode_str = is_a_tty ? "w0" : "w";
    505  1.1  christos       break;
    506  1.4  christos     case 2:
    507  1.1  christos       name = error_port_name;
    508  1.1  christos       mode_str = is_a_tty ? "w0" : "w";
    509  1.1  christos       break;
    510  1.1  christos     default:
    511  1.1  christos       gdb_assert_not_reached ("bad stdio file descriptor");
    512  1.4  christos     }
    513  1.7  christos 
    514  1.1  christos   mode_bits = scm_mode_bits ((char *) mode_str);
    515  1.1  christos   port = ioscm_open_port (stdio_port_desc, mode_bits, 0);
    516  1.1  christos 
    517  1.1  christos   scm_set_port_filename_x (port, gdbscm_scm_from_c_string (name));
    518  1.1  christos 
    519  1.1  christos   ioscm_init_stdio_buffers (port, mode_bits);
    520  1.1  christos 
    521  1.1  christos   return port;
    522  1.1  christos }
    523  1.1  christos 
    524  1.1  christos /* (stdio-port? object) -> boolean */
    525  1.1  christos 
    526  1.1  christos static SCM
    527  1.7  christos gdbscm_stdio_port_p (SCM scm)
    528  1.1  christos {
    529  1.1  christos #if USING_GUILE_BEFORE_2_2
    530  1.1  christos   /* This is copied from SCM_FPORTP.  */
    531  1.7  christos   return scm_from_bool (!SCM_IMP (scm)
    532  1.7  christos 			&& (SCM_TYP16 (scm) == stdio_port_desc));
    533  1.7  christos #else
    534  1.7  christos   return scm_from_bool (SCM_PORTP (scm)
    535  1.1  christos 			&& (SCM_PORT_TYPE (scm) == stdio_port_desc));
    536  1.1  christos #endif
    537  1.1  christos }
    538  1.1  christos 
    539  1.1  christos /* GDB's ports are accessed via functions to keep them read-only.  */
    541  1.1  christos 
    542  1.1  christos /* (input-port) -> port */
    543  1.1  christos 
    544  1.1  christos static SCM
    545  1.1  christos gdbscm_input_port (void)
    546  1.1  christos {
    547  1.1  christos   return input_port_scm;
    548  1.1  christos }
    549  1.1  christos 
    550  1.1  christos /* (output-port) -> port */
    551  1.1  christos 
    552  1.1  christos static SCM
    553  1.1  christos gdbscm_output_port (void)
    554  1.1  christos {
    555  1.1  christos   return output_port_scm;
    556  1.1  christos }
    557  1.1  christos 
    558  1.1  christos /* (error-port) -> port */
    559  1.1  christos 
    560  1.1  christos static SCM
    561  1.1  christos gdbscm_error_port (void)
    562  1.1  christos {
    563  1.1  christos   return error_port_scm;
    564  1.1  christos }
    565  1.5  christos 
    566  1.5  christos /* Support for sending GDB I/O to Guile ports.  */
    568  1.1  christos 
    569  1.5  christos ioscm_file_port::ioscm_file_port (SCM port)
    570  1.5  christos   : m_port (port)
    571  1.1  christos {}
    572  1.1  christos 
    573  1.1  christos void
    574  1.5  christos ioscm_file_port::flush ()
    575  1.5  christos {
    576  1.1  christos }
    577  1.5  christos 
    578  1.1  christos void
    579  1.1  christos ioscm_file_port::write (const char *buffer, long length_buffer)
    580  1.1  christos {
    581  1.1  christos   scm_c_write (m_port, buffer, length_buffer);
    582  1.1  christos }
    583  1.1  christos 
    584  1.1  christos 
    585  1.1  christos /* Helper routine for with-{output,error}-to-port.  */
    587  1.1  christos 
    588  1.1  christos static SCM
    589  1.1  christos ioscm_with_output_to_port_worker (SCM port, SCM thunk, enum oport oport,
    590  1.1  christos 				  const char *func_name)
    591  1.1  christos {
    592  1.1  christos   SCM result;
    593  1.1  christos 
    594  1.6  christos   SCM_ASSERT_TYPE (gdbscm_is_true (scm_output_port_p (port)), port,
    595  1.1  christos 		   SCM_ARG1, func_name, _("output port"));
    596  1.5  christos   SCM_ASSERT_TYPE (gdbscm_is_true (scm_thunk_p (thunk)), thunk,
    597  1.1  christos 		   SCM_ARG2, func_name, _("thunk"));
    598  1.5  christos 
    599  1.1  christos   set_batch_flag_and_restore_page_info save_page_info;
    600  1.5  christos 
    601  1.5  christos   scoped_restore restore_async = make_scoped_restore (&current_ui->async, 0);
    602  1.1  christos 
    603  1.6  christos   ui_file_up port_file (new ioscm_file_port (port));
    604  1.9  christos 
    605  1.6  christos   scoped_restore save_file = make_scoped_restore (oport == GDB_STDERR
    606  1.6  christos 						  ? &gdb_stderr : &gdb_stdout);
    607  1.6  christos 
    608  1.6  christos   {
    609  1.8  christos     std::optional<ui_out_redirect_pop> redirect_popper;
    610  1.1  christos     if (oport == GDB_STDERR)
    611  1.6  christos       gdb_stderr = port_file.get ();
    612  1.6  christos     else
    613  1.1  christos       {
    614  1.6  christos 	redirect_popper.emplace (current_uiout, port_file.get ());
    615  1.6  christos 
    616  1.1  christos 	gdb_stdout = port_file.get ();
    617  1.1  christos       }
    618  1.1  christos 
    619  1.1  christos     result = gdbscm_safe_call_0 (thunk, NULL);
    620  1.1  christos   }
    621  1.1  christos 
    622  1.1  christos   if (gdbscm_is_exception (result))
    623  1.1  christos     gdbscm_throw (result);
    624  1.1  christos 
    625  1.1  christos   return result;
    626  1.1  christos }
    627  1.1  christos 
    628  1.1  christos /* (%with-gdb-output-to-port port thunk) -> object
    629  1.1  christos    This function is experimental.
    630  1.1  christos    IWBN to not include "gdb" in the name, but it would collide with a standard
    631  1.1  christos    procedure, and it's common to import the gdb module without a prefix.
    632  1.1  christos    There are ways around this, but they're more cumbersome.
    633  1.1  christos 
    634  1.1  christos    This has % in the name because it's experimental, and we want the
    635  1.1  christos    user-visible version to come from module (gdb experimental).  */
    636  1.1  christos 
    637  1.1  christos static SCM
    638  1.1  christos gdbscm_percent_with_gdb_output_to_port (SCM port, SCM thunk)
    639  1.1  christos {
    640  1.1  christos   return ioscm_with_output_to_port_worker (port, thunk, GDB_STDOUT, FUNC_NAME);
    641  1.1  christos }
    642  1.1  christos 
    643  1.1  christos /* (%with-gdb-error-to-port port thunk) -> object
    644  1.1  christos    This function is experimental.
    645  1.1  christos    IWBN to not include "gdb" in the name, but it would collide with a standard
    646  1.1  christos    procedure, and it's common to import the gdb module without a prefix.
    647  1.1  christos    There are ways around this, but they're more cumbersome.
    648  1.1  christos 
    649  1.1  christos    This has % in the name because it's experimental, and we want the
    650  1.1  christos    user-visible version to come from module (gdb experimental).  */
    651  1.1  christos 
    652  1.1  christos static SCM
    653  1.1  christos gdbscm_percent_with_gdb_error_to_port (SCM port, SCM thunk)
    654  1.1  christos {
    655  1.1  christos   return ioscm_with_output_to_port_worker (port, thunk, GDB_STDERR, FUNC_NAME);
    656  1.1  christos }
    657  1.1  christos 
    658  1.1  christos /* Support for r/w memory via ports.  */
    660  1.1  christos 
    661  1.1  christos /* Perform an "lseek" to OFFSET,WHENCE on memory port IOMEM.
    662  1.1  christos    OFFSET must be in the range [0,size].
    663  1.1  christos    The result is non-zero for success, zero for failure.  */
    664  1.1  christos 
    665  1.1  christos static int
    666  1.1  christos ioscm_lseek_address (ioscm_memory_port *iomem, LONGEST offset, int whence)
    667  1.1  christos {
    668  1.1  christos   CORE_ADDR new_current;
    669  1.1  christos 
    670  1.1  christos   gdb_assert (iomem->current <= iomem->size);
    671  1.3  christos 
    672  1.1  christos   switch (whence)
    673  1.1  christos     {
    674  1.1  christos     case SEEK_CUR:
    675  1.1  christos       /* Catch over/underflow.  */
    676  1.1  christos       if ((offset < 0 && iomem->current + offset > iomem->current)
    677  1.1  christos 	  || (offset > 0 && iomem->current + offset < iomem->current))
    678  1.1  christos 	return 0;
    679  1.1  christos       new_current = iomem->current + offset;
    680  1.1  christos       break;
    681  1.1  christos     case SEEK_SET:
    682  1.1  christos       new_current = offset;
    683  1.1  christos       break;
    684  1.1  christos     case SEEK_END:
    685  1.1  christos       if (offset == 0)
    686  1.1  christos 	{
    687  1.1  christos 	  new_current = iomem->size;
    688  1.1  christos 	  break;
    689  1.1  christos 	}
    690  1.1  christos       /* TODO: Not supported yet.  */
    691  1.1  christos       return 0;
    692  1.1  christos     default:
    693  1.1  christos       return 0;
    694  1.1  christos     }
    695  1.1  christos 
    696  1.7  christos   if (new_current > iomem->size)
    697  1.7  christos     return 0;
    698  1.1  christos   iomem->current = new_current;
    699  1.1  christos   return 1;
    700  1.1  christos }
    701  1.1  christos 
    702  1.1  christos #if USING_GUILE_BEFORE_2_2
    703  1.1  christos 
    704  1.1  christos /* "fill_input" method for memory ports.  */
    705  1.1  christos 
    706  1.1  christos static int
    707  1.1  christos gdbscm_memory_port_fill_input (SCM port)
    708  1.3  christos {
    709  1.3  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    710  1.1  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
    711  1.1  christos   size_t to_read;
    712  1.1  christos 
    713  1.1  christos   /* "current" is the offset of the first byte we want to read.  */
    714  1.1  christos   gdb_assert (iomem->current <= iomem->size);
    715  1.1  christos   if (iomem->current == iomem->size)
    716  1.1  christos     return EOF;
    717  1.1  christos 
    718  1.1  christos   /* Don't read outside the allowed memory range.  */
    719  1.1  christos   to_read = pt->read_buf_size;
    720  1.1  christos   if (to_read > iomem->size - iomem->current)
    721  1.3  christos     to_read = iomem->size - iomem->current;
    722  1.1  christos 
    723  1.1  christos   if (target_read_memory (iomem->start + iomem->current, pt->read_buf,
    724  1.1  christos 			  to_read) != 0)
    725  1.1  christos     gdbscm_memory_error (FUNC_NAME, _("error reading memory"), SCM_EOL);
    726  1.1  christos 
    727  1.1  christos   iomem->current += to_read;
    728  1.1  christos   pt->read_pos = pt->read_buf;
    729  1.1  christos   pt->read_end = pt->read_buf + to_read;
    730  1.1  christos   return *pt->read_buf;
    731  1.1  christos }
    732  1.1  christos 
    733  1.1  christos /* "end_input" method for memory ports.
    734  1.1  christos    Clear the read buffer and adjust the file position for unread bytes.  */
    735  1.1  christos 
    736  1.1  christos static void
    737  1.1  christos gdbscm_memory_port_end_input (SCM port, int offset)
    738  1.1  christos {
    739  1.1  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    740  1.1  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
    741  1.1  christos   size_t remaining = pt->read_end - pt->read_pos;
    742  1.1  christos 
    743  1.1  christos   /* Note: Use of "int offset" is specified by Guile ports API.  */
    744  1.1  christos   if ((offset < 0 && remaining + offset > remaining)
    745  1.1  christos       || (offset > 0 && remaining + offset < remaining))
    746  1.1  christos     {
    747  1.1  christos       gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_int (offset),
    748  1.1  christos 				 _("overflow in offset calculation"));
    749  1.1  christos     }
    750  1.1  christos   offset += remaining;
    751  1.1  christos 
    752  1.1  christos   if (offset > 0)
    753  1.1  christos     {
    754  1.1  christos       pt->read_pos = pt->read_end;
    755  1.1  christos       /* Throw error if unread-char used at beginning of file
    756  1.1  christos 	 then attempting to write.  Seems correct.  */
    757  1.1  christos       if (!ioscm_lseek_address (iomem, -offset, SEEK_CUR))
    758  1.1  christos 	{
    759  1.1  christos 	  gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_int (offset),
    760  1.1  christos 				     _("bad offset"));
    761  1.1  christos 	}
    762  1.1  christos     }
    763  1.1  christos 
    764  1.1  christos   pt->rw_active = SCM_PORT_NEITHER;
    765  1.1  christos }
    766  1.1  christos 
    767  1.1  christos /* "flush" method for memory ports.  */
    768  1.1  christos 
    769  1.1  christos static void
    770  1.1  christos gdbscm_memory_port_flush (SCM port)
    771  1.1  christos {
    772  1.1  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    773  1.1  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
    774  1.1  christos   size_t to_write = pt->write_pos - pt->write_buf;
    775  1.1  christos 
    776  1.1  christos   if (to_write == 0)
    777  1.1  christos     return;
    778  1.1  christos 
    779  1.1  christos   /* There's no way to indicate a short write, so if the request goes past
    780  1.1  christos      the end of the port's memory range, flag an error.  */
    781  1.1  christos   if (to_write > iomem->size - iomem->current)
    782  1.1  christos     {
    783  1.1  christos       gdbscm_out_of_range_error (FUNC_NAME, 0,
    784  1.1  christos 				 gdbscm_scm_from_ulongest (to_write),
    785  1.1  christos 				 _("writing beyond end of memory range"));
    786  1.1  christos     }
    787  1.1  christos 
    788  1.1  christos   if (target_write_memory (iomem->start + iomem->current, pt->write_buf,
    789  1.1  christos 			   to_write) != 0)
    790  1.1  christos     gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
    791  1.1  christos 
    792  1.1  christos   iomem->current += to_write;
    793  1.1  christos   pt->write_pos = pt->write_buf;
    794  1.1  christos   pt->rw_active = SCM_PORT_NEITHER;
    795  1.1  christos }
    796  1.1  christos 
    797  1.1  christos /* "seek" method for memory ports.  */
    798  1.1  christos 
    799  1.1  christos static scm_t_off
    800  1.1  christos gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
    801  1.1  christos {
    802  1.1  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    803  1.1  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
    804  1.1  christos   CORE_ADDR result;
    805  1.1  christos   int rc;
    806  1.1  christos 
    807  1.1  christos   if (pt->rw_active == SCM_PORT_WRITE)
    808  1.1  christos     {
    809  1.1  christos       if (offset != 0 || whence != SEEK_CUR)
    810  1.1  christos 	{
    811  1.1  christos 	  gdbscm_memory_port_flush (port);
    812  1.1  christos 	  rc = ioscm_lseek_address (iomem, offset, whence);
    813  1.1  christos 	  result = iomem->current;
    814  1.1  christos 	}
    815  1.1  christos       else
    816  1.1  christos 	{
    817  1.1  christos 	  /* Read current position without disturbing the buffer,
    818  1.3  christos 	     but flag an error if what's in the buffer goes outside the
    819  1.1  christos 	     allowed range.  */
    820  1.1  christos 	  CORE_ADDR current = iomem->current;
    821  1.1  christos 	  size_t delta = pt->write_pos - pt->write_buf;
    822  1.1  christos 
    823  1.1  christos 	  if (current + delta < current
    824  1.1  christos 	      || current + delta > iomem->size)
    825  1.1  christos 	    rc = 0;
    826  1.1  christos 	  else
    827  1.1  christos 	    {
    828  1.1  christos 	      result = current + delta;
    829  1.1  christos 	      rc = 1;
    830  1.1  christos 	    }
    831  1.1  christos 	}
    832  1.1  christos     }
    833  1.1  christos   else if (pt->rw_active == SCM_PORT_READ)
    834  1.1  christos     {
    835  1.1  christos       if (offset != 0 || whence != SEEK_CUR)
    836  1.1  christos 	{
    837  1.1  christos 	  scm_end_input (port);
    838  1.1  christos 	  rc = ioscm_lseek_address (iomem, offset, whence);
    839  1.1  christos 	  result = iomem->current;
    840  1.1  christos 	}
    841  1.1  christos       else
    842  1.1  christos 	{
    843  1.1  christos 	  /* Read current position without disturbing the buffer
    844  1.1  christos 	     (particularly the unread-char buffer).  */
    845  1.1  christos 	  CORE_ADDR current = iomem->current;
    846  1.1  christos 	  size_t remaining = pt->read_end - pt->read_pos;
    847  1.1  christos 
    848  1.1  christos 	  if (current - remaining > current
    849  1.1  christos 	      || current - remaining < iomem->start)
    850  1.1  christos 	    rc = 0;
    851  1.1  christos 	  else
    852  1.1  christos 	    {
    853  1.1  christos 	      result = current - remaining;
    854  1.1  christos 	      rc = 1;
    855  1.1  christos 	    }
    856  1.1  christos 
    857  1.1  christos 	  if (rc != 0 && pt->read_buf == pt->putback_buf)
    858  1.1  christos 	    {
    859  1.1  christos 	      size_t saved_remaining = pt->saved_read_end - pt->saved_read_pos;
    860  1.1  christos 
    861  1.1  christos 	      if (result - saved_remaining > result
    862  1.1  christos 		  || result - saved_remaining < iomem->start)
    863  1.1  christos 		rc = 0;
    864  1.1  christos 	      else
    865  1.1  christos 		result -= saved_remaining;
    866  1.1  christos 	    }
    867  1.1  christos 	}
    868  1.1  christos     }
    869  1.1  christos   else /* SCM_PORT_NEITHER */
    870  1.1  christos     {
    871  1.1  christos       rc = ioscm_lseek_address (iomem, offset, whence);
    872  1.1  christos       result = iomem->current;
    873  1.1  christos     }
    874  1.1  christos 
    875  1.1  christos   if (rc == 0)
    876  1.1  christos     {
    877  1.1  christos       gdbscm_out_of_range_error (FUNC_NAME, 0,
    878  1.1  christos 				 gdbscm_scm_from_longest (offset),
    879  1.1  christos 				 _("bad seek"));
    880  1.1  christos     }
    881  1.1  christos 
    882  1.1  christos   /* TODO: The Guile API doesn't support 32x64.  We can't fix that here,
    883  1.7  christos      and there's no need to throw an error if the new address can't be
    884  1.7  christos      represented in a scm_t_off.  But we could return something less
    885  1.7  christos      clumsy.  */
    886  1.7  christos   return result;
    887  1.7  christos }
    888  1.7  christos 
    889  1.7  christos /* "write" method for memory ports.  */
    890  1.7  christos 
    891  1.7  christos static void
    892  1.7  christos gdbscm_memory_port_write (SCM port, const void *void_data, size_t size)
    893  1.7  christos {
    894  1.7  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    895  1.7  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
    896  1.7  christos   const gdb_byte *data = (const gdb_byte *) void_data;
    897  1.7  christos 
    898  1.7  christos   /* There's no way to indicate a short write, so if the request goes past
    899  1.7  christos      the end of the port's memory range, flag an error.  */
    900  1.7  christos   if (size > iomem->size - iomem->current)
    901  1.7  christos     {
    902  1.7  christos       gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size),
    903  1.7  christos 				 _("writing beyond end of memory range"));
    904  1.7  christos     }
    905  1.7  christos 
    906  1.7  christos   if (pt->write_buf == &pt->shortbuf)
    907  1.7  christos     {
    908  1.7  christos       /* Unbuffered port.  */
    909  1.7  christos       if (target_write_memory (iomem->start + iomem->current, data, size) != 0)
    910  1.7  christos 	gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
    911  1.7  christos       iomem->current += size;
    912  1.7  christos       return;
    913  1.7  christos     }
    914  1.7  christos 
    915  1.7  christos   /* Note: The edge case of what to do when the buffer exactly fills is
    916  1.7  christos      debatable.  Guile flushes when the buffer exactly fills up, so we
    917  1.7  christos      do too.  It's counter-intuitive to my mind, but in case there's a
    918  1.7  christos      subtlety somewhere that depends on this, we do the same.  */
    919  1.7  christos 
    920  1.7  christos   {
    921  1.7  christos     size_t space = pt->write_end - pt->write_pos;
    922  1.7  christos 
    923  1.7  christos     if (size < space)
    924  1.7  christos       {
    925  1.7  christos 	/* Data fits in buffer, and does not fill it.  */
    926  1.7  christos 	memcpy (pt->write_pos, data, size);
    927  1.7  christos 	pt->write_pos += size;
    928  1.7  christos       }
    929  1.7  christos     else
    930  1.7  christos       {
    931  1.7  christos 	memcpy (pt->write_pos, data, space);
    932  1.7  christos 	pt->write_pos = pt->write_end;
    933  1.7  christos 	gdbscm_memory_port_flush (port);
    934  1.7  christos 	{
    935  1.7  christos 	  const gdb_byte *ptr = data + space;
    936  1.7  christos 	  size_t remaining = size - space;
    937  1.7  christos 
    938  1.7  christos 	  if (remaining >= pt->write_buf_size)
    939  1.7  christos 	    {
    940  1.7  christos 	      if (target_write_memory (iomem->start + iomem->current, ptr,
    941  1.7  christos 				       remaining) != 0)
    942  1.7  christos 		gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
    943  1.7  christos 				     SCM_EOL);
    944  1.7  christos 	      iomem->current += remaining;
    945  1.7  christos 	    }
    946  1.7  christos 	  else
    947  1.7  christos 	    {
    948  1.7  christos 	      memcpy (pt->write_pos, ptr, remaining);
    949  1.7  christos 	      pt->write_pos += remaining;
    950  1.1  christos 	    }
    951  1.1  christos 	}
    952  1.1  christos       }
    953  1.1  christos   }
    954  1.1  christos }
    955  1.1  christos 
    956  1.1  christos /* "close" method for memory ports.  */
    957  1.1  christos 
    958  1.1  christos static int
    959  1.1  christos gdbscm_memory_port_close (SCM port)
    960  1.1  christos {
    961  1.1  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    962  1.3  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
    963  1.3  christos 
    964  1.3  christos   gdbscm_memory_port_flush (port);
    965  1.3  christos 
    966  1.1  christos   if (pt->read_buf == pt->putback_buf)
    967  1.1  christos     pt->read_buf = pt->saved_read_buf;
    968  1.1  christos   if (pt->read_buf != &pt->shortbuf)
    969  1.1  christos     xfree (pt->read_buf);
    970  1.1  christos   if (pt->write_buf != &pt->shortbuf)
    971  1.1  christos     xfree (pt->write_buf);
    972  1.1  christos   scm_gc_free (iomem, sizeof (*iomem), "memory port");
    973  1.1  christos 
    974  1.1  christos   return 0;
    975  1.1  christos }
    976  1.1  christos 
    977  1.1  christos /* "free" method for memory ports.  */
    978  1.1  christos 
    979  1.1  christos static size_t
    980  1.1  christos gdbscm_memory_port_free (SCM port)
    981  1.7  christos {
    982  1.7  christos   gdbscm_memory_port_close (port);
    983  1.7  christos 
    984  1.7  christos   return 0;
    985  1.7  christos }
    986  1.7  christos 
    987  1.7  christos /* Re-initialize a memory port, updating its read/write buffer sizes.
    988  1.7  christos    An exception is thrown if the port is unbuffered.
    989  1.7  christos    TODO: Allow switching buffered/unbuffered.
    990  1.7  christos    An exception is also thrown if data is still buffered, except in the case
    991  1.7  christos    where the buffer size isn't changing (since that's just a nop).  */
    992  1.7  christos 
    993  1.7  christos static void
    994  1.7  christos ioscm_reinit_memory_port (SCM port, size_t read_buf_size,
    995  1.7  christos 			  size_t write_buf_size, const char *func_name)
    996  1.7  christos {
    997  1.7  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
    998  1.7  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
    999  1.7  christos 
   1000  1.7  christos   gdb_assert (read_buf_size >= min_memory_port_buf_size
   1001  1.7  christos 	      && read_buf_size <= max_memory_port_buf_size);
   1002  1.7  christos   gdb_assert (write_buf_size >= min_memory_port_buf_size
   1003  1.7  christos 	      && write_buf_size <= max_memory_port_buf_size);
   1004  1.7  christos 
   1005  1.7  christos   /* First check if the port is unbuffered.  */
   1006  1.7  christos 
   1007  1.7  christos   if (pt->read_buf == &pt->shortbuf)
   1008  1.7  christos     {
   1009  1.7  christos       gdb_assert (pt->write_buf == &pt->shortbuf);
   1010  1.7  christos       scm_misc_error (func_name, _("port is unbuffered: ~a"),
   1011  1.7  christos 		      scm_list_1 (port));
   1012  1.7  christos     }
   1013  1.7  christos 
   1014  1.7  christos   /* Next check if anything is buffered.  */
   1015  1.7  christos 
   1016  1.7  christos   if (read_buf_size != pt->read_buf_size
   1017  1.7  christos       && pt->read_end != pt->read_buf)
   1018  1.7  christos     {
   1019  1.7  christos       scm_misc_error (func_name, _("read buffer not empty: ~a"),
   1020  1.7  christos 		      scm_list_1 (port));
   1021  1.7  christos     }
   1022  1.7  christos 
   1023  1.7  christos   if (write_buf_size != pt->write_buf_size
   1024  1.7  christos       && pt->write_pos != pt->write_buf)
   1025  1.7  christos     {
   1026  1.7  christos       scm_misc_error (func_name, _("write buffer not empty: ~a"),
   1027  1.7  christos 		      scm_list_1 (port));
   1028  1.7  christos     }
   1029  1.7  christos 
   1030  1.7  christos   /* Now we can update the buffer sizes, but only if the size has changed.  */
   1031  1.7  christos 
   1032  1.7  christos   if (read_buf_size != pt->read_buf_size)
   1033  1.7  christos     {
   1034  1.7  christos       iomem->read_buf_size = read_buf_size;
   1035  1.7  christos       pt->read_buf_size = read_buf_size;
   1036  1.7  christos       xfree (pt->read_buf);
   1037  1.7  christos       pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
   1038  1.7  christos       pt->read_pos = pt->read_end = pt->read_buf;
   1039  1.7  christos     }
   1040  1.7  christos 
   1041  1.7  christos   if (write_buf_size != pt->write_buf_size)
   1042  1.7  christos     {
   1043  1.7  christos       iomem->write_buf_size = write_buf_size;
   1044  1.7  christos       pt->write_buf_size = write_buf_size;
   1045  1.7  christos       xfree (pt->write_buf);
   1046  1.7  christos       pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
   1047  1.7  christos       pt->write_pos = pt->write_buf;
   1048  1.7  christos       pt->write_end = pt->write_buf + pt->write_buf_size;
   1049  1.7  christos     }
   1050  1.7  christos }
   1051  1.7  christos 
   1052  1.7  christos #else /* !USING_GUILE_BEFORE_2_2 */
   1053  1.7  christos 
   1054  1.7  christos /* The semantics get weird if the buffer size is larger than the port range,
   1055  1.7  christos    so provide a better default buffer size.  */
   1056  1.7  christos 
   1057  1.7  christos static void
   1058  1.7  christos gdbscm_get_natural_buffer_sizes (SCM port, size_t *read_size,
   1059  1.7  christos 				 size_t *write_size)
   1060  1.7  christos {
   1061  1.7  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1062  1.7  christos 
   1063  1.7  christos   size_t size = natural_buf_size;
   1064  1.7  christos   if (iomem != NULL && iomem->size < size)
   1065  1.7  christos     size = iomem->size;
   1066  1.7  christos   *read_size = *write_size = size;
   1067  1.7  christos }
   1068  1.7  christos 
   1069  1.7  christos /* Read up to COUNT bytes into bytevector DST at offset START.  Return the
   1070  1.7  christos    number of bytes read, zero for the end of file.  */
   1071  1.7  christos 
   1072  1.7  christos static size_t
   1073  1.7  christos gdbscm_memory_port_read (SCM port, SCM dst, size_t start, size_t count)
   1074  1.7  christos {
   1075  1.7  christos   gdb_byte *read_buf;
   1076  1.7  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1077  1.7  christos 
   1078  1.7  christos   /* "current" is the offset of the first byte we want to read.  */
   1079  1.7  christos   gdb_assert (iomem->current <= iomem->size);
   1080  1.7  christos   if (iomem->current == iomem->size)
   1081  1.7  christos     return 0;
   1082  1.7  christos 
   1083  1.7  christos   /* Don't read outside the allowed memory range.  */
   1084  1.7  christos   if (count > iomem->size - iomem->current)
   1085  1.7  christos     count = iomem->size - iomem->current;
   1086  1.7  christos 
   1087  1.7  christos   read_buf = (gdb_byte *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
   1088  1.7  christos   if (target_read_memory (iomem->start + iomem->current, read_buf,
   1089  1.7  christos 			  count) != 0)
   1090  1.7  christos     gdbscm_memory_error (FUNC_NAME, _("error reading memory"), SCM_EOL);
   1091  1.7  christos 
   1092  1.7  christos   iomem->current += count;
   1093  1.7  christos   return count;
   1094  1.7  christos }
   1095  1.7  christos 
   1096  1.7  christos static size_t
   1097  1.7  christos gdbscm_memory_port_write (SCM port, SCM src, size_t start, size_t count)
   1098  1.7  christos {
   1099  1.7  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1100  1.7  christos   const gdb_byte *data =
   1101  1.7  christos     (const gdb_byte *) SCM_BYTEVECTOR_CONTENTS (src) + start;
   1102  1.7  christos 
   1103  1.7  christos   /* If the request goes past the end of the port's memory range, flag an
   1104  1.7  christos      error.  */
   1105  1.7  christos   if (count > iomem->size - iomem->current)
   1106  1.7  christos     gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_size_t (count),
   1107  1.7  christos 			       _("writing beyond end of memory range"));
   1108  1.7  christos 
   1109  1.7  christos   if (target_write_memory (iomem->start + iomem->current, data,
   1110  1.7  christos 			   count) != 0)
   1111  1.7  christos     gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
   1112  1.7  christos 			 SCM_EOL);
   1113  1.7  christos 
   1114  1.7  christos   iomem->current += count;
   1115  1.7  christos 
   1116  1.7  christos   return count;
   1117  1.7  christos }
   1118  1.7  christos 
   1119  1.7  christos static scm_t_off
   1120  1.7  christos gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
   1121  1.7  christos {
   1122  1.7  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1123  1.7  christos   int rc;
   1124  1.7  christos 
   1125  1.7  christos   rc = ioscm_lseek_address (iomem, offset, whence);
   1126  1.7  christos   if (rc == 0)
   1127  1.7  christos     gdbscm_out_of_range_error (FUNC_NAME, 0,
   1128  1.7  christos 			       gdbscm_scm_from_longest (offset),
   1129  1.7  christos 			       _("bad seek"));
   1130  1.7  christos 
   1131  1.7  christos   /* TODO: The Guile API doesn't support 32x64.  We can't fix that here,
   1132  1.7  christos      and there's no need to throw an error if the new address can't be
   1133  1.7  christos      represented in a scm_t_off.  But we could return something less
   1134  1.7  christos      clumsy.  */
   1135  1.7  christos   return iomem->current;
   1136  1.7  christos }
   1137  1.7  christos 
   1138  1.7  christos static void
   1139  1.7  christos gdbscm_memory_port_close (SCM port)
   1140  1.7  christos {
   1141  1.7  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1142  1.1  christos   scm_gc_free (iomem, sizeof (*iomem), "memory port");
   1143  1.1  christos   SCM_SETSTREAM (port, NULL);
   1144  1.1  christos }
   1145  1.1  christos 
   1146  1.1  christos #endif /* !USING_GUILE_BEFORE_2_2 */
   1147  1.1  christos 
   1148  1.1  christos /* "print" method for memory ports.  */
   1149  1.1  christos 
   1150  1.1  christos static int
   1151  1.1  christos gdbscm_memory_port_print (SCM exp, SCM port, scm_print_state *pstate)
   1152  1.7  christos {
   1153  1.1  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (exp);
   1154  1.1  christos 
   1155  1.1  christos   scm_puts ("#<", port);
   1156  1.1  christos   scm_print_port_mode (exp, port);
   1157  1.1  christos   /* scm_print_port_mode includes a trailing space.  */
   1158  1.1  christos   gdbscm_printf (port, "%s %s-%s", memory_port_desc_name,
   1159  1.1  christos 		 hex_string (iomem->start), hex_string (iomem->end));
   1160  1.1  christos   scm_putc ('>', port);
   1161  1.1  christos   return 1;
   1162  1.1  christos }
   1163  1.1  christos 
   1164  1.7  christos /* Create the port type used for memory.  */
   1165  1.1  christos 
   1166  1.7  christos static void
   1167  1.7  christos ioscm_init_memory_port_type (void)
   1168  1.7  christos {
   1169  1.1  christos   memory_port_desc = scm_make_port_type (memory_port_desc_name,
   1170  1.1  christos #if USING_GUILE_BEFORE_2_2
   1171  1.7  christos 					 gdbscm_memory_port_fill_input,
   1172  1.1  christos #else
   1173  1.1  christos 					 gdbscm_memory_port_read,
   1174  1.7  christos #endif
   1175  1.7  christos 					 gdbscm_memory_port_write);
   1176  1.7  christos 
   1177  1.7  christos #if USING_GUILE_BEFORE_2_2
   1178  1.7  christos   scm_set_port_end_input (memory_port_desc, gdbscm_memory_port_end_input);
   1179  1.1  christos   scm_set_port_flush (memory_port_desc, gdbscm_memory_port_flush);
   1180  1.1  christos   scm_set_port_free (memory_port_desc, gdbscm_memory_port_free);
   1181  1.1  christos #else
   1182  1.1  christos   scm_set_port_get_natural_buffer_sizes (memory_port_desc,
   1183  1.1  christos 					 gdbscm_get_natural_buffer_sizes);
   1184  1.1  christos #endif
   1185  1.1  christos   scm_set_port_seek (memory_port_desc, gdbscm_memory_port_seek);
   1186  1.1  christos   scm_set_port_close (memory_port_desc, gdbscm_memory_port_close);
   1187  1.1  christos   scm_set_port_print (memory_port_desc, gdbscm_memory_port_print);
   1188  1.1  christos }
   1189  1.1  christos 
   1190  1.1  christos /* Helper for gdbscm_open_memory to parse the mode bits.
   1191  1.1  christos    An exception is thrown if MODE is invalid.  */
   1192  1.1  christos 
   1193  1.1  christos static long
   1194  1.1  christos ioscm_parse_mode_bits (const char *func_name, const char *mode)
   1195  1.1  christos {
   1196  1.1  christos   const char *p;
   1197  1.1  christos   long mode_bits;
   1198  1.1  christos 
   1199  1.1  christos   if (*mode != 'r' && *mode != 'w')
   1200  1.1  christos     {
   1201  1.1  christos       gdbscm_out_of_range_error (func_name, 0,
   1202  1.1  christos 				 gdbscm_scm_from_c_string (mode),
   1203  1.3  christos 				 _("bad mode string"));
   1204  1.1  christos     }
   1205  1.1  christos   for (p = mode + 1; *p != '\0'; ++p)
   1206  1.1  christos     {
   1207  1.1  christos       switch (*p)
   1208  1.1  christos 	{
   1209  1.1  christos 	case '0':
   1210  1.1  christos 	case 'b':
   1211  1.1  christos 	case '+':
   1212  1.1  christos 	  break;
   1213  1.1  christos 	default:
   1214  1.1  christos 	  gdbscm_out_of_range_error (func_name, 0,
   1215  1.1  christos 				     gdbscm_scm_from_c_string (mode),
   1216  1.1  christos 				     _("bad mode string"));
   1217  1.1  christos 	}
   1218  1.1  christos     }
   1219  1.1  christos 
   1220  1.1  christos   /* Kinda awkward to convert the mode from SCM -> string only to have Guile
   1221  1.7  christos      convert it back to SCM, but that's the API we have to work with.  */
   1222  1.7  christos   mode_bits = scm_mode_bits ((char *) mode);
   1223  1.1  christos 
   1224  1.7  christos   return mode_bits;
   1225  1.7  christos }
   1226  1.1  christos 
   1227  1.1  christos /* Return the memory object to be used as a "stream" associated with a memory
   1228  1.1  christos    port for the START--END range.  */
   1229  1.1  christos 
   1230  1.1  christos static ioscm_memory_port *
   1231  1.1  christos ioscm_init_memory_port_stream (CORE_ADDR start, CORE_ADDR end)
   1232  1.1  christos {
   1233  1.1  christos   ioscm_memory_port *iomem;
   1234  1.1  christos 
   1235  1.1  christos   gdb_assert (start <= end);
   1236  1.3  christos 
   1237  1.1  christos   iomem = (ioscm_memory_port *) scm_gc_malloc_pointerless (sizeof (*iomem),
   1238  1.7  christos 							   "memory port");
   1239  1.7  christos 
   1240  1.7  christos   iomem->start = start;
   1241  1.7  christos   iomem->end = end;
   1242  1.7  christos   iomem->size = end - start;
   1243  1.7  christos   iomem->current = 0;
   1244  1.7  christos 
   1245  1.7  christos   return iomem;
   1246  1.7  christos }
   1247  1.7  christos 
   1248  1.7  christos #if USING_GUILE_BEFORE_2_2
   1249  1.7  christos 
   1250  1.7  christos /* Helper for gdbscm_open_memory to finish initializing the port.
   1251  1.7  christos    The port has address range [start,end).
   1252  1.7  christos    This means that address of 0xff..ff is not accessible.
   1253  1.7  christos    I can live with that.  */
   1254  1.7  christos 
   1255  1.3  christos static void
   1256  1.3  christos ioscm_init_memory_port_buffers (SCM port)
   1257  1.3  christos {
   1258  1.3  christos   ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1259  1.3  christos 
   1260  1.3  christos   int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0;
   1261  1.3  christos   if (buffered)
   1262  1.3  christos     {
   1263  1.3  christos       iomem->read_buf_size = default_read_buf_size;
   1264  1.3  christos       iomem->write_buf_size = default_write_buf_size;
   1265  1.1  christos     }
   1266  1.7  christos   else
   1267  1.1  christos     {
   1268  1.1  christos       iomem->read_buf_size = 1;
   1269  1.1  christos       iomem->write_buf_size = 1;
   1270  1.1  christos     }
   1271  1.3  christos 
   1272  1.3  christos   scm_t_port *pt = SCM_PTAB_ENTRY (port);
   1273  1.3  christos   /* Match the expectation of `binary-port?'.  */
   1274  1.4  christos   pt->encoding = NULL;
   1275  1.4  christos   pt->rw_random = 1;
   1276  1.3  christos   pt->read_buf_size = iomem->read_buf_size;
   1277  1.3  christos   pt->write_buf_size = iomem->write_buf_size;
   1278  1.3  christos   if (buffered)
   1279  1.3  christos     {
   1280  1.3  christos       pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
   1281  1.3  christos       pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
   1282  1.1  christos     }
   1283  1.1  christos   else
   1284  1.1  christos     {
   1285  1.1  christos       pt->read_buf = &pt->shortbuf;
   1286  1.1  christos       pt->write_buf = &pt->shortbuf;
   1287  1.7  christos     }
   1288  1.1  christos   pt->read_pos = pt->read_end = pt->read_buf;
   1289  1.1  christos   pt->write_pos = pt->write_buf;
   1290  1.1  christos   pt->write_end = pt->write_buf + pt->write_buf_size;
   1291  1.1  christos }
   1292  1.3  christos 
   1293  1.3  christos #endif
   1294  1.1  christos 
   1295  1.1  christos /* (open-memory [#:mode string] [#:start address] [#:size integer]) -> port
   1296  1.1  christos    Return a port that can be used for reading and writing memory.
   1297  1.3  christos    MODE is a string, and must be one of "r", "w", or "r+".
   1298  1.3  christos    "0" may be appended to MODE to mark the port as unbuffered.
   1299  1.3  christos    For compatibility "b" (binary) may also be appended, but we ignore it:
   1300  1.3  christos    memory ports are binary only.
   1301  1.3  christos 
   1302  1.1  christos    The chunk of memory that can be accessed can be bounded.
   1303  1.1  christos    If both START,SIZE are unspecified, all of memory can be accessed
   1304  1.1  christos    (except 0xff..ff).  If only START is specified, all of memory from that
   1305  1.1  christos    point on can be accessed (except 0xff..ff).  If only SIZE if specified,
   1306  1.1  christos    all memory in [0,SIZE) can be accessed.  If both are specified, all memory
   1307  1.1  christos    in [START,START+SIZE) can be accessed.
   1308  1.1  christos 
   1309  1.3  christos    Note: If it becomes useful enough we can later add #:end as an alternative
   1310  1.1  christos    to #:size.  For now it is left out.
   1311  1.1  christos 
   1312  1.1  christos    The result is a Scheme port, and its semantics are a bit odd for accessing
   1313  1.1  christos    memory (e.g., unget), but we don't try to hide this.  It's a port.
   1314  1.1  christos 
   1315  1.1  christos    N.B. Seeks on the port must be in the range [0,size].
   1316  1.1  christos    This is for similarity with bytevector ports, and so that one can seek
   1317  1.1  christos    to the first byte.  */
   1318  1.1  christos 
   1319  1.1  christos static SCM
   1320  1.1  christos gdbscm_open_memory (SCM rest)
   1321  1.1  christos {
   1322  1.1  christos   const SCM keywords[] = {
   1323  1.1  christos     mode_keyword, start_keyword, size_keyword, SCM_BOOL_F
   1324  1.1  christos   };
   1325  1.1  christos   char *mode = NULL;
   1326  1.1  christos   CORE_ADDR start = 0;
   1327  1.1  christos   CORE_ADDR end;
   1328  1.1  christos   int mode_arg_pos = -1, start_arg_pos = -1, size_arg_pos = -1;
   1329  1.1  christos   ULONGEST size;
   1330  1.1  christos   SCM port;
   1331  1.1  christos   long mode_bits;
   1332  1.4  christos 
   1333  1.1  christos   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, keywords, "#sUU", rest,
   1334  1.1  christos 			      &mode_arg_pos, &mode,
   1335  1.1  christos 			      &start_arg_pos, &start,
   1336  1.1  christos 			      &size_arg_pos, &size);
   1337  1.1  christos 
   1338  1.1  christos   scm_dynwind_begin ((scm_t_dynwind_flags) 0);
   1339  1.1  christos 
   1340  1.1  christos   if (mode == NULL)
   1341  1.1  christos     mode = xstrdup ("r");
   1342  1.1  christos   scm_dynwind_free (mode);
   1343  1.1  christos 
   1344  1.1  christos   if (size_arg_pos > 0)
   1345  1.1  christos     {
   1346  1.1  christos       /* For now be strict about start+size overflowing.  If it becomes
   1347  1.1  christos 	 a nuisance we can relax things later.  */
   1348  1.1  christos       if (start + size < start)
   1349  1.3  christos 	{
   1350  1.1  christos 	  gdbscm_out_of_range_error (FUNC_NAME, 0,
   1351  1.1  christos 				scm_list_2 (gdbscm_scm_from_ulongest (start),
   1352  1.3  christos 					    gdbscm_scm_from_ulongest (size)),
   1353  1.1  christos 				     _("start+size overflows"));
   1354  1.1  christos 	}
   1355  1.1  christos       end = start + size;
   1356  1.7  christos     }
   1357  1.7  christos   else
   1358  1.7  christos     end = ~(CORE_ADDR) 0;
   1359  1.7  christos 
   1360  1.7  christos   mode_bits = ioscm_parse_mode_bits (FUNC_NAME, mode);
   1361  1.7  christos 
   1362  1.7  christos   /* Edge case: empty range -> unbuffered.
   1363  1.7  christos      There's no need to disallow empty ranges, but we need an unbuffered port
   1364  1.7  christos      to get the semantics right.  */
   1365  1.1  christos   if (size == 0)
   1366  1.7  christos     mode_bits |= SCM_BUF0;
   1367  1.7  christos 
   1368  1.7  christos   auto stream = ioscm_init_memory_port_stream (start, end);
   1369  1.1  christos   port = ioscm_open_port (memory_port_desc, mode_bits,
   1370  1.1  christos 			  (scm_t_bits) stream);
   1371  1.1  christos 
   1372  1.1  christos #if USING_GUILE_BEFORE_2_2
   1373  1.1  christos   ioscm_init_memory_port_buffers (port);
   1374  1.1  christos #endif
   1375  1.1  christos 
   1376  1.1  christos   scm_dynwind_end ();
   1377  1.1  christos 
   1378  1.1  christos   /* TODO: Set the file name as "memory-start-end"?  */
   1379  1.1  christos   return port;
   1380  1.1  christos }
   1381  1.7  christos 
   1382  1.1  christos /* Return non-zero if OBJ is a memory port.  */
   1383  1.7  christos 
   1384  1.7  christos static int
   1385  1.7  christos gdbscm_is_memory_port (SCM obj)
   1386  1.1  christos {
   1387  1.1  christos #if USING_GUILE_BEFORE_2_2
   1388  1.1  christos   return !SCM_IMP (obj) && (SCM_TYP16 (obj) == memory_port_desc);
   1389  1.1  christos #else
   1390  1.1  christos   return SCM_PORTP (obj) && (SCM_PORT_TYPE (obj) == memory_port_desc);
   1391  1.1  christos #endif
   1392  1.1  christos }
   1393  1.1  christos 
   1394  1.1  christos /* (memory-port? obj) -> boolean */
   1395  1.1  christos 
   1396  1.1  christos static SCM
   1397  1.1  christos gdbscm_memory_port_p (SCM obj)
   1398  1.1  christos {
   1399  1.1  christos   return scm_from_bool (gdbscm_is_memory_port (obj));
   1400  1.1  christos }
   1401  1.1  christos 
   1402  1.1  christos /* (memory-port-range port) -> (start end) */
   1403  1.1  christos 
   1404  1.1  christos static SCM
   1405  1.1  christos gdbscm_memory_port_range (SCM port)
   1406  1.1  christos {
   1407  1.1  christos   ioscm_memory_port *iomem;
   1408  1.1  christos 
   1409  1.1  christos   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
   1410  1.1  christos 		   memory_port_desc_name);
   1411  1.1  christos 
   1412  1.1  christos   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1413  1.1  christos   return scm_list_2 (gdbscm_scm_from_ulongest (iomem->start),
   1414  1.1  christos 		     gdbscm_scm_from_ulongest (iomem->end));
   1415  1.1  christos }
   1416  1.7  christos 
   1417  1.1  christos /* (memory-port-read-buffer-size port) -> integer */
   1418  1.1  christos 
   1419  1.1  christos static SCM
   1420  1.1  christos gdbscm_memory_port_read_buffer_size (SCM port)
   1421  1.1  christos {
   1422  1.1  christos #if USING_GUILE_BEFORE_2_2
   1423  1.1  christos   ioscm_memory_port *iomem;
   1424  1.7  christos 
   1425  1.7  christos   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
   1426  1.7  christos 		   memory_port_desc_name);
   1427  1.1  christos 
   1428  1.1  christos   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1429  1.1  christos   return scm_from_uint (iomem->read_buf_size);
   1430  1.3  christos #else
   1431  1.3  christos   return scm_from_uint (0);
   1432  1.1  christos #endif
   1433  1.1  christos }
   1434  1.1  christos 
   1435  1.1  christos /* (set-memory-port-read-buffer-size! port size) -> unspecified
   1436  1.7  christos    An exception is thrown if read data is still buffered or if the port
   1437  1.1  christos    is unbuffered.  */
   1438  1.1  christos 
   1439  1.1  christos static SCM
   1440  1.1  christos gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
   1441  1.1  christos {
   1442  1.1  christos #if USING_GUILE_BEFORE_2_2
   1443  1.1  christos   ioscm_memory_port *iomem;
   1444  1.1  christos 
   1445  1.1  christos   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
   1446  1.1  christos 		   memory_port_desc_name);
   1447  1.1  christos   SCM_ASSERT_TYPE (scm_is_integer (size), size, SCM_ARG2, FUNC_NAME,
   1448  1.8  christos 		   _("integer"));
   1449  1.1  christos 
   1450  1.1  christos   if (!scm_is_unsigned_integer (size, min_memory_port_buf_size,
   1451  1.1  christos 				max_memory_port_buf_size))
   1452  1.1  christos     {
   1453  1.1  christos       gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, size,
   1454  1.1  christos 				 out_of_range_buf_size.get ());
   1455  1.1  christos     }
   1456  1.7  christos 
   1457  1.7  christos   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1458  1.7  christos   ioscm_reinit_memory_port (port, scm_to_uint (size), iomem->write_buf_size,
   1459  1.1  christos 			    FUNC_NAME);
   1460  1.1  christos 
   1461  1.1  christos   return SCM_UNSPECIFIED;
   1462  1.1  christos #else
   1463  1.1  christos   return scm_setvbuf (port, scm_from_utf8_symbol ("block"), size);
   1464  1.1  christos #endif
   1465  1.1  christos }
   1466  1.7  christos 
   1467  1.1  christos /* (memory-port-write-buffer-size port) -> integer */
   1468  1.1  christos 
   1469  1.1  christos static SCM
   1470  1.1  christos gdbscm_memory_port_write_buffer_size (SCM port)
   1471  1.1  christos {
   1472  1.1  christos #if USING_GUILE_BEFORE_2_2
   1473  1.1  christos   ioscm_memory_port *iomem;
   1474  1.7  christos 
   1475  1.7  christos   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
   1476  1.7  christos 		   memory_port_desc_name);
   1477  1.1  christos 
   1478  1.1  christos   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1479  1.1  christos   return scm_from_uint (iomem->write_buf_size);
   1480  1.3  christos #else
   1481  1.3  christos   return scm_from_uint (0);
   1482  1.1  christos #endif
   1483  1.1  christos }
   1484  1.1  christos 
   1485  1.1  christos /* (set-memory-port-write-buffer-size! port size) -> unspecified
   1486  1.7  christos    An exception is thrown if write data is still buffered or if the port
   1487  1.1  christos    is unbuffered.  */
   1488  1.1  christos 
   1489  1.1  christos static SCM
   1490  1.1  christos gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size)
   1491  1.1  christos {
   1492  1.1  christos #if USING_GUILE_BEFORE_2_2
   1493  1.1  christos   ioscm_memory_port *iomem;
   1494  1.1  christos 
   1495  1.1  christos   SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
   1496  1.1  christos 		   memory_port_desc_name);
   1497  1.1  christos   SCM_ASSERT_TYPE (scm_is_integer (size), size, SCM_ARG2, FUNC_NAME,
   1498  1.8  christos 		   _("integer"));
   1499  1.1  christos 
   1500  1.1  christos   if (!scm_is_unsigned_integer (size, min_memory_port_buf_size,
   1501  1.1  christos 				max_memory_port_buf_size))
   1502  1.1  christos     {
   1503  1.1  christos       gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, size,
   1504  1.1  christos 				 out_of_range_buf_size.get ());
   1505  1.1  christos     }
   1506  1.7  christos 
   1507  1.7  christos   iomem = (ioscm_memory_port *) SCM_STREAM (port);
   1508  1.7  christos   ioscm_reinit_memory_port (port, iomem->read_buf_size, scm_to_uint (size),
   1509  1.1  christos 			    FUNC_NAME);
   1510  1.1  christos 
   1511  1.1  christos   return SCM_UNSPECIFIED;
   1512  1.1  christos #else
   1513  1.1  christos   return scm_setvbuf (port, scm_from_utf8_symbol ("block"), size);
   1514  1.1  christos #endif
   1515  1.4  christos }
   1516  1.1  christos 
   1517  1.1  christos /* Initialize gdb ports.  */
   1519  1.4  christos 
   1520  1.1  christos static const scheme_function port_functions[] =
   1521  1.1  christos {
   1522  1.1  christos   { "input-port", 0, 0, 0, as_a_scm_t_subr (gdbscm_input_port),
   1523  1.4  christos     "\
   1524  1.1  christos Return gdb's input port." },
   1525  1.1  christos 
   1526  1.1  christos   { "output-port", 0, 0, 0, as_a_scm_t_subr (gdbscm_output_port),
   1527  1.4  christos     "\
   1528  1.1  christos Return gdb's output port." },
   1529  1.1  christos 
   1530  1.1  christos   { "error-port", 0, 0, 0, as_a_scm_t_subr (gdbscm_error_port),
   1531  1.4  christos     "\
   1532  1.1  christos Return gdb's error port." },
   1533  1.1  christos 
   1534  1.1  christos   { "stdio-port?", 1, 0, 0, as_a_scm_t_subr (gdbscm_stdio_port_p),
   1535  1.1  christos     "\
   1536  1.1  christos Return #t if the object is a gdb:stdio-port." },
   1537  1.1  christos 
   1538  1.4  christos   { "open-memory", 0, 0, 1, as_a_scm_t_subr (gdbscm_open_memory),
   1539  1.1  christos     "\
   1540  1.1  christos Return a port that can be used for reading/writing inferior memory.\n\
   1541  1.1  christos \n\
   1542  1.4  christos   Arguments: [#:mode string] [#:start address] [#:size integer]\n\
   1543  1.1  christos   Returns: A port object." },
   1544  1.1  christos 
   1545  1.1  christos   { "memory-port?", 1, 0, 0, as_a_scm_t_subr (gdbscm_memory_port_p),
   1546  1.1  christos     "\
   1547  1.4  christos Return #t if the object is a memory port." },
   1548  1.1  christos 
   1549  1.1  christos   { "memory-port-range", 1, 0, 0, as_a_scm_t_subr (gdbscm_memory_port_range),
   1550  1.1  christos     "\
   1551  1.1  christos Return the memory range of the port as (start end)." },
   1552  1.4  christos 
   1553  1.1  christos   { "memory-port-read-buffer-size", 1, 0, 0,
   1554  1.1  christos     as_a_scm_t_subr (gdbscm_memory_port_read_buffer_size),
   1555  1.1  christos     "\
   1556  1.1  christos Return the size of the read buffer for the memory port." },
   1557  1.1  christos 
   1558  1.1  christos   { "set-memory-port-read-buffer-size!", 2, 0, 0,
   1559  1.1  christos     as_a_scm_t_subr (gdbscm_set_memory_port_read_buffer_size_x),
   1560  1.4  christos     "\
   1561  1.1  christos Set the size of the read buffer for the memory port.\n\
   1562  1.1  christos \n\
   1563  1.1  christos   Arguments: port integer\n\
   1564  1.1  christos   Returns: unspecified." },
   1565  1.4  christos 
   1566  1.1  christos   { "memory-port-write-buffer-size", 1, 0, 0,
   1567  1.1  christos     as_a_scm_t_subr (gdbscm_memory_port_write_buffer_size),
   1568  1.1  christos     "\
   1569  1.1  christos Return the size of the write buffer for the memory port." },
   1570  1.1  christos 
   1571  1.1  christos   { "set-memory-port-write-buffer-size!", 2, 0, 0,
   1572  1.1  christos     as_a_scm_t_subr (gdbscm_set_memory_port_write_buffer_size_x),
   1573  1.1  christos     "\
   1574  1.1  christos Set the size of the write buffer for the memory port.\n\
   1575  1.1  christos \n\
   1576  1.1  christos   Arguments: port integer\n\
   1577  1.1  christos   Returns: unspecified." },
   1578  1.1  christos 
   1579  1.4  christos   END_FUNCTIONS
   1580  1.1  christos };
   1581  1.1  christos 
   1582  1.1  christos static const scheme_function private_port_functions[] =
   1583  1.1  christos {
   1584  1.1  christos #if 0 /* TODO */
   1585  1.1  christos   { "%with-gdb-input-from-port", 2, 0, 0,
   1586  1.1  christos     as_a_scm_t_subr (gdbscm_percent_with_gdb_input_from_port),
   1587  1.1  christos     "\
   1588  1.1  christos Temporarily set GDB's input port to PORT and then invoke THUNK.\n\
   1589  1.1  christos \n\
   1590  1.4  christos   Arguments: port thunk\n\
   1591  1.1  christos   Returns: The result of calling THUNK.\n\
   1592  1.1  christos \n\
   1593  1.1  christos This procedure is experimental." },
   1594  1.1  christos #endif
   1595  1.1  christos 
   1596  1.1  christos   { "%with-gdb-output-to-port", 2, 0, 0,
   1597  1.1  christos     as_a_scm_t_subr (gdbscm_percent_with_gdb_output_to_port),
   1598  1.1  christos     "\
   1599  1.1  christos Temporarily set GDB's output port to PORT and then invoke THUNK.\n\
   1600  1.4  christos \n\
   1601  1.1  christos   Arguments: port thunk\n\
   1602  1.1  christos   Returns: The result of calling THUNK.\n\
   1603  1.1  christos \n\
   1604  1.1  christos This procedure is experimental." },
   1605  1.1  christos 
   1606  1.1  christos   { "%with-gdb-error-to-port", 2, 0, 0,
   1607  1.1  christos     as_a_scm_t_subr (gdbscm_percent_with_gdb_error_to_port),
   1608  1.1  christos     "\
   1609  1.1  christos Temporarily set GDB's error port to PORT and then invoke THUNK.\n\
   1610  1.1  christos \n\
   1611  1.1  christos   Arguments: port thunk\n\
   1612  1.1  christos   Returns: The result of calling THUNK.\n\
   1613  1.1  christos \n\
   1614  1.1  christos This procedure is experimental." },
   1615  1.1  christos 
   1616  1.1  christos   END_FUNCTIONS
   1617  1.1  christos };
   1618  1.1  christos 
   1619  1.1  christos void
   1620  1.1  christos gdbscm_initialize_ports (void)
   1621  1.1  christos {
   1622  1.1  christos   /* Save the original stdio ports for debugging purposes.  */
   1623  1.1  christos 
   1624  1.1  christos   orig_input_port_scm = scm_current_input_port ();
   1625  1.1  christos   orig_output_port_scm = scm_current_output_port ();
   1626  1.1  christos   orig_error_port_scm = scm_current_error_port ();
   1627  1.1  christos 
   1628  1.1  christos   /* Set up the stdio ports.  */
   1629  1.1  christos 
   1630  1.1  christos   ioscm_init_gdb_stdio_port ();
   1631  1.1  christos   input_port_scm = ioscm_make_gdb_stdio_port (0);
   1632  1.1  christos   output_port_scm = ioscm_make_gdb_stdio_port (1);
   1633  1.1  christos   error_port_scm = ioscm_make_gdb_stdio_port (2);
   1634  1.1  christos 
   1635  1.1  christos   /* Set up memory ports.  */
   1636  1.1  christos 
   1637  1.1  christos   ioscm_init_memory_port_type ();
   1638  1.1  christos 
   1639  1.1  christos   /* Install the accessor functions.  */
   1640  1.1  christos 
   1641  1.1  christos   gdbscm_define_functions (port_functions, 1);
   1642  1.1  christos   gdbscm_define_functions (private_port_functions, 0);
   1643  1.7  christos 
   1644  1.1  christos   /* Keyword args for open-memory.  */
   1645  1.1  christos 
   1646  1.1  christos   mode_keyword = scm_from_latin1_keyword ("mode");
   1647  1.1  christos   start_keyword = scm_from_latin1_keyword ("start");
   1648  1.1  christos   size_keyword = scm_from_latin1_keyword ("size");
   1649  1.7  christos 
   1650  1.1  christos #if USING_GUILE_BEFORE_2_2
   1651                  /* Error message text for "out of range" memory port buffer sizes.  */
   1652                
   1653                  out_of_range_buf_size = xstrprintf ("size not between %u - %u",
   1654                				      min_memory_port_buf_size,
   1655                				      max_memory_port_buf_size);
   1656                #endif
   1657                }
   1658