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