scm-ports.c revision 1.5
1/* Support for connecting Guile's stdio to GDB's.
2   as well as r/w memory via ports.
3
4   Copyright (C) 2014-2017 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 "gdb_select.h"
26#include "top.h"
27#include "target.h"
28#include "guile-internal.h"
29
30#ifdef HAVE_POLL
31#if defined (HAVE_POLL_H)
32#include <poll.h>
33#elif defined (HAVE_SYS_POLL_H)
34#include <sys/poll.h>
35#endif
36#endif
37
38/* A ui-file for sending output to Guile.  */
39
40class ioscm_file_port : public ui_file
41{
42public:
43  /* Return a ui_file that writes to PORT.  */
44  explicit ioscm_file_port (SCM port);
45
46  void flush () override;
47  void write (const char *buf, long length_buf) override;
48
49private:
50  SCM m_port;
51};
52
53/* Data for a memory port.  */
54
55typedef struct
56{
57  /* Bounds of memory range this port is allowed to access: [start, end).
58     This means that 0xff..ff is not accessible.  I can live with that.  */
59  CORE_ADDR start, end;
60
61  /* (end - start), recorded for convenience.  */
62  ULONGEST size;
63
64  /* Think of this as the lseek value maintained by the kernel.
65     This value is always in the range [0, size].  */
66  ULONGEST current;
67
68  /* The size of the internal r/w buffers.
69     Scheme ports aren't a straightforward mapping to memory r/w.
70     Generally the user specifies how much to r/w and all access is
71     unbuffered.  We don't try to provide equivalent access, but we allow
72     the user to specify these values to help get something similar.  */
73  unsigned read_buf_size, write_buf_size;
74} ioscm_memory_port;
75
76/* Copies of the original system input/output/error ports.
77   These are recorded for debugging purposes.  */
78static SCM orig_input_port_scm;
79static SCM orig_output_port_scm;
80static SCM orig_error_port_scm;
81
82/* This is the stdio port descriptor, scm_ptob_descriptor.  */
83static scm_t_bits stdio_port_desc;
84
85/* Note: scm_make_port_type takes a char * instead of a const char *.  */
86static /*const*/ char stdio_port_desc_name[] = "gdb:stdio-port";
87
88/* Names of each gdb port.  */
89static const char input_port_name[] = "gdb:stdin";
90static const char output_port_name[] = "gdb:stdout";
91static const char error_port_name[] = "gdb:stderr";
92
93/* This is the actual port used from Guile.
94   We don't expose these to the user though, to ensure they're not
95   overwritten.  */
96static SCM input_port_scm;
97static SCM output_port_scm;
98static SCM error_port_scm;
99
100/* Magic number to identify port ui-files.
101   Actually, the address of this variable is the magic number.  */
102static int file_port_magic;
103
104/* Internal enum for specifying output port.  */
105enum oport { GDB_STDOUT, GDB_STDERR };
106
107/* This is the memory port descriptor, scm_ptob_descriptor.  */
108static scm_t_bits memory_port_desc;
109
110/* Note: scm_make_port_type takes a char * instead of a const char *.  */
111static /*const*/ char memory_port_desc_name[] = "gdb:memory-port";
112
113/* The default amount of memory to fetch for each read/write request.
114   Scheme ports don't provide a way to specify the size of a read,
115   which is important to us to minimize the number of inferior interactions,
116   which over a remote link can be important.  To compensate we augment the
117   port API with a new function that let's the user specify how much the next
118   read request should fetch.  This is the initial value for each new port.  */
119static const unsigned default_read_buf_size = 16;
120static const unsigned default_write_buf_size = 16;
121
122/* Arbitrarily limit memory port buffers to 1 byte to 4K.  */
123static const unsigned min_memory_port_buf_size = 1;
124static const unsigned max_memory_port_buf_size = 4096;
125
126/* "out of range" error message for buf sizes.  */
127static char *out_of_range_buf_size;
128
129/* Keywords used by open-memory.  */
130static SCM mode_keyword;
131static SCM start_keyword;
132static SCM size_keyword;
133
134/* Helper to do the low level work of opening a port.
135   Newer versions of Guile (2.1.x) have scm_c_make_port.  */
136
137static SCM
138ioscm_open_port (scm_t_bits port_type, long mode_bits)
139{
140  SCM port;
141
142#if 0 /* TODO: Guile doesn't export this.  What to do?  */
143  scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
144#endif
145
146  port = scm_new_port_table_entry (port_type);
147
148  SCM_SET_CELL_TYPE (port, port_type | mode_bits);
149
150#if 0 /* TODO: Guile doesn't export this.  What to do?  */
151  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
152#endif
153
154  return port;
155}
156
157/* Support for connecting Guile's stdio ports to GDB's stdio ports.  */
158
159/* The scm_t_ptob_descriptor.input_waiting "method".
160   Return a lower bound on the number of bytes available for input.  */
161
162static int
163ioscm_input_waiting (SCM port)
164{
165  int fdes = 0;
166
167  if (! scm_is_eq (port, input_port_scm))
168    return 0;
169
170#ifdef HAVE_POLL
171  {
172    /* This is copied from libguile/fports.c.  */
173    struct pollfd pollfd = { fdes, POLLIN, 0 };
174    static int use_poll = -1;
175
176    if (use_poll < 0)
177      {
178	/* This is copied from event-loop.c: poll cannot be used for stdin on
179	   m68k-motorola-sysv.  */
180	struct pollfd test_pollfd = { fdes, POLLIN, 0 };
181
182	if (poll (&test_pollfd, 1, 0) == 1 && (test_pollfd.revents & POLLNVAL))
183	  use_poll = 0;
184	else
185	  use_poll = 1;
186      }
187
188    if (use_poll)
189      {
190	/* Guile doesn't export SIGINT hooks like Python does.
191	   For now pass EINTR to scm_syserror, that's what fports.c does.  */
192	if (poll (&pollfd, 1, 0) < 0)
193	  scm_syserror (FUNC_NAME);
194
195	return pollfd.revents & POLLIN ? 1 : 0;
196      }
197  }
198  /* Fall through.  */
199#endif
200
201  {
202    struct timeval timeout;
203    fd_set input_fds;
204    int num_fds = fdes + 1;
205    int num_found;
206
207    memset (&timeout, 0, sizeof (timeout));
208    FD_ZERO (&input_fds);
209    FD_SET (fdes, &input_fds);
210
211    num_found = interruptible_select (num_fds,
212				      &input_fds, NULL, NULL,
213				      &timeout);
214    if (num_found < 0)
215      {
216	/* Guile doesn't export SIGINT hooks like Python does.
217	   For now pass EINTR to scm_syserror, that's what fports.c does.  */
218        scm_syserror (FUNC_NAME);
219      }
220    return num_found > 0 && FD_ISSET (fdes, &input_fds);
221  }
222}
223
224/* The scm_t_ptob_descriptor.fill_input "method".  */
225
226static int
227ioscm_fill_input (SCM port)
228{
229  /* Borrowed from libguile/fports.c.  */
230  long count;
231  scm_t_port *pt = SCM_PTAB_ENTRY (port);
232
233  /* If we're called on stdout,stderr, punt.  */
234  if (! scm_is_eq (port, input_port_scm))
235    return (scm_t_wchar) EOF; /* Set errno and return -1?  */
236
237  gdb_flush (gdb_stdout);
238  gdb_flush (gdb_stderr);
239
240  count = ui_file_read (gdb_stdin, (char *) pt->read_buf, pt->read_buf_size);
241  if (count == -1)
242    scm_syserror (FUNC_NAME);
243  if (count == 0)
244    return (scm_t_wchar) EOF;
245
246  pt->read_pos = pt->read_buf;
247  pt->read_end = pt->read_buf + count;
248  return *pt->read_buf;
249}
250
251/* Like fputstrn_filtered, but don't escape characters, except nul.
252   Also like fputs_filtered, but a length is specified.  */
253
254static void
255fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
256{
257  size_t i;
258
259  for (i = 0; i < size; ++i)
260    {
261      if (s[i] == '\0')
262	fputs_filtered ("\\000", stream);
263      else
264	fputc_filtered (s[i], stream);
265    }
266}
267
268/* Write to gdb's stdout or stderr.  */
269
270static void
271ioscm_write (SCM port, const void *data, size_t size)
272{
273
274  /* If we're called on stdin, punt.  */
275  if (scm_is_eq (port, input_port_scm))
276    return;
277
278  TRY
279    {
280      if (scm_is_eq (port, error_port_scm))
281	fputsn_filtered ((const char *) data, size, gdb_stderr);
282      else
283	fputsn_filtered ((const char *) data, size, gdb_stdout);
284    }
285  CATCH (except, RETURN_MASK_ALL)
286    {
287      GDBSCM_HANDLE_GDB_EXCEPTION (except);
288    }
289  END_CATCH
290}
291
292/* Flush gdb's stdout or stderr.  */
293
294static void
295ioscm_flush (SCM port)
296{
297  /* If we're called on stdin, punt.  */
298  if (scm_is_eq (port, input_port_scm))
299    return;
300
301  if (scm_is_eq (port, error_port_scm))
302    gdb_flush (gdb_stderr);
303  else
304    gdb_flush (gdb_stdout);
305}
306
307/* Initialize the gdb stdio port type.
308
309   N.B. isatty? will fail on these ports, it is only supported for file
310   ports.  IWBN if we could "subclass" file ports.  */
311
312static void
313ioscm_init_gdb_stdio_port (void)
314{
315  stdio_port_desc = scm_make_port_type (stdio_port_desc_name,
316					ioscm_fill_input, ioscm_write);
317
318  scm_set_port_input_waiting (stdio_port_desc, ioscm_input_waiting);
319  scm_set_port_flush (stdio_port_desc, ioscm_flush);
320}
321
322/* Subroutine of ioscm_make_gdb_stdio_port to simplify it.
323   Set up the buffers of port PORT.
324   MODE_BITS are the mode bits of PORT.  */
325
326static void
327ioscm_init_stdio_buffers (SCM port, long mode_bits)
328{
329  scm_t_port *pt = SCM_PTAB_ENTRY (port);
330#define GDB_STDIO_BUFFER_DEFAULT_SIZE 1024
331  int size = mode_bits & SCM_BUF0 ? 0 : GDB_STDIO_BUFFER_DEFAULT_SIZE;
332  int writing = (mode_bits & SCM_WRTNG) != 0;
333
334  /* This is heavily copied from scm_fport_buffer_add.  */
335
336  if (!writing && size > 0)
337    {
338      pt->read_buf
339	= (unsigned char *) scm_gc_malloc_pointerless (size, "port buffer");
340      pt->read_pos = pt->read_end = pt->read_buf;
341      pt->read_buf_size = size;
342    }
343  else
344    {
345      pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
346      pt->read_buf_size = 1;
347    }
348
349  if (writing && size > 0)
350    {
351      pt->write_buf
352	= (unsigned char *) scm_gc_malloc_pointerless (size, "port buffer");
353      pt->write_pos = pt->write_buf;
354      pt->write_buf_size = size;
355    }
356  else
357    {
358      pt->write_buf = pt->write_pos = &pt->shortbuf;
359      pt->write_buf_size = 1;
360    }
361  pt->write_end = pt->write_buf + pt->write_buf_size;
362}
363
364/* Create a gdb stdio port.  */
365
366static SCM
367ioscm_make_gdb_stdio_port (int fd)
368{
369  int is_a_tty = isatty (fd);
370  const char *name;
371  const char *mode_str;
372  long mode_bits;
373  SCM port;
374
375  switch (fd)
376    {
377    case 0:
378      name = input_port_name;
379      mode_str = is_a_tty ? "r0" : "r";
380      break;
381    case 1:
382      name = output_port_name;
383      mode_str = is_a_tty ? "w0" : "w";
384      break;
385    case 2:
386      name = error_port_name;
387      mode_str = is_a_tty ? "w0" : "w";
388      break;
389    default:
390      gdb_assert_not_reached ("bad stdio file descriptor");
391    }
392
393  mode_bits = scm_mode_bits ((char *) mode_str);
394  port = ioscm_open_port (stdio_port_desc, mode_bits);
395
396  scm_set_port_filename_x (port, gdbscm_scm_from_c_string (name));
397
398  ioscm_init_stdio_buffers (port, mode_bits);
399
400  return port;
401}
402
403/* (stdio-port? object) -> boolean */
404
405static SCM
406gdbscm_stdio_port_p (SCM scm)
407{
408  /* This is copied from SCM_FPORTP.  */
409  return scm_from_bool (!SCM_IMP (scm)
410			&& (SCM_TYP16 (scm) == stdio_port_desc));
411}
412
413/* GDB's ports are accessed via functions to keep them read-only.  */
414
415/* (input-port) -> port */
416
417static SCM
418gdbscm_input_port (void)
419{
420  return input_port_scm;
421}
422
423/* (output-port) -> port */
424
425static SCM
426gdbscm_output_port (void)
427{
428  return output_port_scm;
429}
430
431/* (error-port) -> port */
432
433static SCM
434gdbscm_error_port (void)
435{
436  return error_port_scm;
437}
438
439/* Support for sending GDB I/O to Guile ports.  */
440
441ioscm_file_port::ioscm_file_port (SCM port)
442  : m_port (port)
443{}
444
445void
446ioscm_file_port::flush ()
447{
448}
449
450void
451ioscm_file_port::write (const char *buffer, long length_buffer)
452{
453  scm_c_write (m_port, buffer, length_buffer);
454}
455
456
457/* Helper routine for with-{output,error}-to-port.  */
458
459static SCM
460ioscm_with_output_to_port_worker (SCM port, SCM thunk, enum oport oport,
461				  const char *func_name)
462{
463  struct cleanup *cleanups;
464  SCM result;
465
466  SCM_ASSERT_TYPE (gdbscm_is_true (scm_output_port_p (port)), port,
467		   SCM_ARG1, func_name, _("output port"));
468  SCM_ASSERT_TYPE (gdbscm_is_true (scm_thunk_p (thunk)), thunk,
469		   SCM_ARG2, func_name, _("thunk"));
470
471  cleanups = set_batch_flag_and_make_cleanup_restore_page_info ();
472
473  scoped_restore restore_async = make_scoped_restore (&current_ui->async, 0);
474
475  ui_file_up port_file (new ioscm_file_port (port));
476
477  scoped_restore save_file = make_scoped_restore (oport == GDB_STDERR
478						  ? &gdb_stderr : &gdb_stdout);
479
480  if (oport == GDB_STDERR)
481    gdb_stderr = port_file.get ();
482  else
483    {
484      current_uiout->redirect (port_file.get ());
485      make_cleanup_ui_out_redirect_pop (current_uiout);
486
487      gdb_stdout = port_file.get ();
488    }
489
490  result = gdbscm_safe_call_0 (thunk, NULL);
491
492  do_cleanups (cleanups);
493
494  if (gdbscm_is_exception (result))
495    gdbscm_throw (result);
496
497  return result;
498}
499
500/* (%with-gdb-output-to-port port thunk) -> object
501   This function is experimental.
502   IWBN to not include "gdb" in the name, but it would collide with a standard
503   procedure, and it's common to import the gdb module without a prefix.
504   There are ways around this, but they're more cumbersome.
505
506   This has % in the name because it's experimental, and we want the
507   user-visible version to come from module (gdb experimental).  */
508
509static SCM
510gdbscm_percent_with_gdb_output_to_port (SCM port, SCM thunk)
511{
512  return ioscm_with_output_to_port_worker (port, thunk, GDB_STDOUT, FUNC_NAME);
513}
514
515/* (%with-gdb-error-to-port port thunk) -> object
516   This function is experimental.
517   IWBN to not include "gdb" in the name, but it would collide with a standard
518   procedure, and it's common to import the gdb module without a prefix.
519   There are ways around this, but they're more cumbersome.
520
521   This has % in the name because it's experimental, and we want the
522   user-visible version to come from module (gdb experimental).  */
523
524static SCM
525gdbscm_percent_with_gdb_error_to_port (SCM port, SCM thunk)
526{
527  return ioscm_with_output_to_port_worker (port, thunk, GDB_STDERR, FUNC_NAME);
528}
529
530/* Support for r/w memory via ports.  */
531
532/* Perform an "lseek" to OFFSET,WHENCE on memory port IOMEM.
533   OFFSET must be in the range [0,size].
534   The result is non-zero for success, zero for failure.  */
535
536static int
537ioscm_lseek_address (ioscm_memory_port *iomem, LONGEST offset, int whence)
538{
539  CORE_ADDR new_current;
540
541  gdb_assert (iomem->current <= iomem->size);
542
543  switch (whence)
544    {
545    case SEEK_CUR:
546      /* Catch over/underflow.  */
547      if ((offset < 0 && iomem->current + offset > iomem->current)
548	  || (offset > 0 && iomem->current + offset < iomem->current))
549	return 0;
550      new_current = iomem->current + offset;
551      break;
552    case SEEK_SET:
553      new_current = offset;
554      break;
555    case SEEK_END:
556      if (offset == 0)
557	{
558	  new_current = iomem->size;
559	  break;
560	}
561      /* TODO: Not supported yet.  */
562      return 0;
563    default:
564      return 0;
565    }
566
567  if (new_current > iomem->size)
568    return 0;
569  iomem->current = new_current;
570  return 1;
571}
572
573/* "fill_input" method for memory ports.  */
574
575static int
576gdbscm_memory_port_fill_input (SCM port)
577{
578  scm_t_port *pt = SCM_PTAB_ENTRY (port);
579  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
580  size_t to_read;
581
582  /* "current" is the offset of the first byte we want to read.  */
583  gdb_assert (iomem->current <= iomem->size);
584  if (iomem->current == iomem->size)
585    return EOF;
586
587  /* Don't read outside the allowed memory range.  */
588  to_read = pt->read_buf_size;
589  if (to_read > iomem->size - iomem->current)
590    to_read = iomem->size - iomem->current;
591
592  if (target_read_memory (iomem->start + iomem->current, pt->read_buf,
593			  to_read) != 0)
594    gdbscm_memory_error (FUNC_NAME, _("error reading memory"), SCM_EOL);
595
596  iomem->current += to_read;
597  pt->read_pos = pt->read_buf;
598  pt->read_end = pt->read_buf + to_read;
599  return *pt->read_buf;
600}
601
602/* "end_input" method for memory ports.
603   Clear the read buffer and adjust the file position for unread bytes.  */
604
605static void
606gdbscm_memory_port_end_input (SCM port, int offset)
607{
608  scm_t_port *pt = SCM_PTAB_ENTRY (port);
609  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
610  size_t remaining = pt->read_end - pt->read_pos;
611
612  /* Note: Use of "int offset" is specified by Guile ports API.  */
613  if ((offset < 0 && remaining + offset > remaining)
614      || (offset > 0 && remaining + offset < remaining))
615    {
616      gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_int (offset),
617				 _("overflow in offset calculation"));
618    }
619  offset += remaining;
620
621  if (offset > 0)
622    {
623      pt->read_pos = pt->read_end;
624      /* Throw error if unread-char used at beginning of file
625	 then attempting to write.  Seems correct.  */
626      if (!ioscm_lseek_address (iomem, -offset, SEEK_CUR))
627	{
628	  gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_int (offset),
629				     _("bad offset"));
630	}
631    }
632
633  pt->rw_active = SCM_PORT_NEITHER;
634}
635
636/* "flush" method for memory ports.  */
637
638static void
639gdbscm_memory_port_flush (SCM port)
640{
641  scm_t_port *pt = SCM_PTAB_ENTRY (port);
642  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
643  size_t to_write = pt->write_pos - pt->write_buf;
644
645  if (to_write == 0)
646    return;
647
648  /* There's no way to indicate a short write, so if the request goes past
649     the end of the port's memory range, flag an error.  */
650  if (to_write > iomem->size - iomem->current)
651    {
652      gdbscm_out_of_range_error (FUNC_NAME, 0,
653				 gdbscm_scm_from_ulongest (to_write),
654				 _("writing beyond end of memory range"));
655    }
656
657  if (target_write_memory (iomem->start + iomem->current, pt->write_buf,
658			   to_write) != 0)
659    gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
660
661  iomem->current += to_write;
662  pt->write_pos = pt->write_buf;
663  pt->rw_active = SCM_PORT_NEITHER;
664}
665
666/* "write" method for memory ports.  */
667
668static void
669gdbscm_memory_port_write (SCM port, const void *void_data, size_t size)
670{
671  scm_t_port *pt = SCM_PTAB_ENTRY (port);
672  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
673  const gdb_byte *data = (const gdb_byte *) void_data;
674
675  /* There's no way to indicate a short write, so if the request goes past
676     the end of the port's memory range, flag an error.  */
677  if (size > iomem->size - iomem->current)
678    {
679      gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size),
680				 _("writing beyond end of memory range"));
681    }
682
683  if (pt->write_buf == &pt->shortbuf)
684    {
685      /* Unbuffered port.  */
686      if (target_write_memory (iomem->start + iomem->current, data, size) != 0)
687	gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL);
688      iomem->current += size;
689      return;
690    }
691
692  /* Note: The edge case of what to do when the buffer exactly fills is
693     debatable.  Guile flushes when the buffer exactly fills up, so we
694     do too.  It's counter-intuitive to my mind, but in case there's a
695     subtlety somewhere that depends on this, we do the same.  */
696
697  {
698    size_t space = pt->write_end - pt->write_pos;
699
700    if (size < space)
701      {
702	/* Data fits in buffer, and does not fill it.  */
703	memcpy (pt->write_pos, data, size);
704	pt->write_pos += size;
705      }
706    else
707      {
708	memcpy (pt->write_pos, data, space);
709	pt->write_pos = pt->write_end;
710	gdbscm_memory_port_flush (port);
711	{
712	  const gdb_byte *ptr = data + space;
713	  size_t remaining = size - space;
714
715	  if (remaining >= pt->write_buf_size)
716	    {
717	      if (target_write_memory (iomem->start + iomem->current, ptr,
718				       remaining) != 0)
719		gdbscm_memory_error (FUNC_NAME, _("error writing memory"),
720				     SCM_EOL);
721	      iomem->current += remaining;
722	    }
723	  else
724	    {
725	      memcpy (pt->write_pos, ptr, remaining);
726	      pt->write_pos += remaining;
727	    }
728	}
729      }
730  }
731}
732
733/* "seek" method for memory ports.  */
734
735static scm_t_off
736gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence)
737{
738  scm_t_port *pt = SCM_PTAB_ENTRY (port);
739  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
740  CORE_ADDR result;
741  int rc;
742
743  if (pt->rw_active == SCM_PORT_WRITE)
744    {
745      if (offset != 0 || whence != SEEK_CUR)
746	{
747	  gdbscm_memory_port_flush (port);
748	  rc = ioscm_lseek_address (iomem, offset, whence);
749	  result = iomem->current;
750	}
751      else
752	{
753	  /* Read current position without disturbing the buffer,
754	     but flag an error if what's in the buffer goes outside the
755	     allowed range.  */
756	  CORE_ADDR current = iomem->current;
757	  size_t delta = pt->write_pos - pt->write_buf;
758
759	  if (current + delta < current
760	      || current + delta > iomem->size)
761	    rc = 0;
762	  else
763	    {
764	      result = current + delta;
765	      rc = 1;
766	    }
767	}
768    }
769  else if (pt->rw_active == SCM_PORT_READ)
770    {
771      if (offset != 0 || whence != SEEK_CUR)
772	{
773	  scm_end_input (port);
774	  rc = ioscm_lseek_address (iomem, offset, whence);
775	  result = iomem->current;
776	}
777      else
778	{
779	  /* Read current position without disturbing the buffer
780	     (particularly the unread-char buffer).  */
781	  CORE_ADDR current = iomem->current;
782	  size_t remaining = pt->read_end - pt->read_pos;
783
784	  if (current - remaining > current
785	      || current - remaining < iomem->start)
786	    rc = 0;
787	  else
788	    {
789	      result = current - remaining;
790	      rc = 1;
791	    }
792
793	  if (rc != 0 && pt->read_buf == pt->putback_buf)
794	    {
795	      size_t saved_remaining = pt->saved_read_end - pt->saved_read_pos;
796
797	      if (result - saved_remaining > result
798		  || result - saved_remaining < iomem->start)
799		rc = 0;
800	      else
801		result -= saved_remaining;
802	    }
803	}
804    }
805  else /* SCM_PORT_NEITHER */
806    {
807      rc = ioscm_lseek_address (iomem, offset, whence);
808      result = iomem->current;
809    }
810
811  if (rc == 0)
812    {
813      gdbscm_out_of_range_error (FUNC_NAME, 0,
814				 gdbscm_scm_from_longest (offset),
815				 _("bad seek"));
816    }
817
818  /* TODO: The Guile API doesn't support 32x64.  We can't fix that here,
819     and there's no need to throw an error if the new address can't be
820     represented in a scm_t_off.  But we could return something less
821     clumsy.  */
822  return result;
823}
824
825/* "close" method for memory ports.  */
826
827static int
828gdbscm_memory_port_close (SCM port)
829{
830  scm_t_port *pt = SCM_PTAB_ENTRY (port);
831  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port);
832
833  gdbscm_memory_port_flush (port);
834
835  if (pt->read_buf == pt->putback_buf)
836    pt->read_buf = pt->saved_read_buf;
837  if (pt->read_buf != &pt->shortbuf)
838    xfree (pt->read_buf);
839  if (pt->write_buf != &pt->shortbuf)
840    xfree (pt->write_buf);
841  scm_gc_free (iomem, sizeof (*iomem), "memory port");
842
843  return 0;
844}
845
846/* "free" method for memory ports.  */
847
848static size_t
849gdbscm_memory_port_free (SCM port)
850{
851  gdbscm_memory_port_close (port);
852
853  return 0;
854}
855
856/* "print" method for memory ports.  */
857
858static int
859gdbscm_memory_port_print (SCM exp, SCM port, scm_print_state *pstate)
860{
861  ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (exp);
862  char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
863
864  scm_puts ("#<", port);
865  scm_print_port_mode (exp, port);
866  /* scm_print_port_mode includes a trailing space.  */
867  gdbscm_printf (port, "%s %s-%s", type,
868		 hex_string (iomem->start), hex_string (iomem->end));
869  scm_putc ('>', port);
870  return 1;
871}
872
873/* Create the port type used for memory.  */
874
875static void
876ioscm_init_memory_port_type (void)
877{
878  memory_port_desc = scm_make_port_type (memory_port_desc_name,
879					 gdbscm_memory_port_fill_input,
880					 gdbscm_memory_port_write);
881
882  scm_set_port_end_input (memory_port_desc, gdbscm_memory_port_end_input);
883  scm_set_port_flush (memory_port_desc, gdbscm_memory_port_flush);
884  scm_set_port_seek (memory_port_desc, gdbscm_memory_port_seek);
885  scm_set_port_close (memory_port_desc, gdbscm_memory_port_close);
886  scm_set_port_free (memory_port_desc, gdbscm_memory_port_free);
887  scm_set_port_print (memory_port_desc, gdbscm_memory_port_print);
888}
889
890/* Helper for gdbscm_open_memory to parse the mode bits.
891   An exception is thrown if MODE is invalid.  */
892
893static long
894ioscm_parse_mode_bits (const char *func_name, const char *mode)
895{
896  const char *p;
897  long mode_bits;
898
899  if (*mode != 'r' && *mode != 'w')
900    {
901      gdbscm_out_of_range_error (func_name, 0,
902				 gdbscm_scm_from_c_string (mode),
903				 _("bad mode string"));
904    }
905  for (p = mode + 1; *p != '\0'; ++p)
906    {
907      switch (*p)
908	{
909	case '0':
910	case 'b':
911	case '+':
912	  break;
913	default:
914	  gdbscm_out_of_range_error (func_name, 0,
915				     gdbscm_scm_from_c_string (mode),
916				     _("bad mode string"));
917	}
918    }
919
920  /* Kinda awkward to convert the mode from SCM -> string only to have Guile
921     convert it back to SCM, but that's the API we have to work with.  */
922  mode_bits = scm_mode_bits ((char *) mode);
923
924  return mode_bits;
925}
926
927/* Helper for gdbscm_open_memory to finish initializing the port.
928   The port has address range [start,end).
929   This means that address of 0xff..ff is not accessible.
930   I can live with that.  */
931
932static void
933ioscm_init_memory_port (SCM port, CORE_ADDR start, CORE_ADDR end)
934{
935  scm_t_port *pt;
936  ioscm_memory_port *iomem;
937  int buffered = (SCM_CELL_WORD_0 (port) & SCM_BUF0) == 0;
938
939  gdb_assert (start <= end);
940
941  iomem = (ioscm_memory_port *) scm_gc_malloc_pointerless (sizeof (*iomem),
942							   "memory port");
943
944  iomem->start = start;
945  iomem->end = end;
946  iomem->size = end - start;
947  iomem->current = 0;
948  if (buffered)
949    {
950      iomem->read_buf_size = default_read_buf_size;
951      iomem->write_buf_size = default_write_buf_size;
952    }
953  else
954    {
955      iomem->read_buf_size = 1;
956      iomem->write_buf_size = 1;
957    }
958
959  pt = SCM_PTAB_ENTRY (port);
960  /* Match the expectation of `binary-port?'.  */
961  pt->encoding = NULL;
962  pt->rw_random = 1;
963  pt->read_buf_size = iomem->read_buf_size;
964  pt->write_buf_size = iomem->write_buf_size;
965  if (buffered)
966    {
967      pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size);
968      pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size);
969    }
970  else
971    {
972      pt->read_buf = &pt->shortbuf;
973      pt->write_buf = &pt->shortbuf;
974    }
975  pt->read_pos = pt->read_end = pt->read_buf;
976  pt->write_pos = pt->write_buf;
977  pt->write_end = pt->write_buf + pt->write_buf_size;
978
979  SCM_SETSTREAM (port, iomem);
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/* (open-memory [#:mode string] [#:start address] [#:size integer]) -> port
1048   Return a port that can be used for reading and writing memory.
1049   MODE is a string, and must be one of "r", "w", or "r+".
1050   "0" may be appended to MODE to mark the port as unbuffered.
1051   For compatibility "b" (binary) may also be appended, but we ignore it:
1052   memory ports are binary only.
1053
1054   The chunk of memory that can be accessed can be bounded.
1055   If both START,SIZE are unspecified, all of memory can be accessed
1056   (except 0xff..ff).  If only START is specified, all of memory from that
1057   point on can be accessed (except 0xff..ff).  If only SIZE if specified,
1058   all memory in [0,SIZE) can be accessed.  If both are specified, all memory
1059   in [START,START+SIZE) can be accessed.
1060
1061   Note: If it becomes useful enough we can later add #:end as an alternative
1062   to #:size.  For now it is left out.
1063
1064   The result is a Scheme port, and its semantics are a bit odd for accessing
1065   memory (e.g., unget), but we don't try to hide this.  It's a port.
1066
1067   N.B. Seeks on the port must be in the range [0,size].
1068   This is for similarity with bytevector ports, and so that one can seek
1069   to the first byte.  */
1070
1071static SCM
1072gdbscm_open_memory (SCM rest)
1073{
1074  const SCM keywords[] = {
1075    mode_keyword, start_keyword, size_keyword, SCM_BOOL_F
1076  };
1077  char *mode = NULL;
1078  CORE_ADDR start = 0;
1079  CORE_ADDR end;
1080  int mode_arg_pos = -1, start_arg_pos = -1, size_arg_pos = -1;
1081  ULONGEST size;
1082  SCM port;
1083  long mode_bits;
1084
1085  gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, keywords, "#sUU", rest,
1086			      &mode_arg_pos, &mode,
1087			      &start_arg_pos, &start,
1088			      &size_arg_pos, &size);
1089
1090  scm_dynwind_begin ((scm_t_dynwind_flags) 0);
1091
1092  if (mode == NULL)
1093    mode = xstrdup ("r");
1094  scm_dynwind_free (mode);
1095
1096  if (size_arg_pos > 0)
1097    {
1098      /* For now be strict about start+size overflowing.  If it becomes
1099	 a nuisance we can relax things later.  */
1100      if (start + size < start)
1101	{
1102	  gdbscm_out_of_range_error (FUNC_NAME, 0,
1103				scm_list_2 (gdbscm_scm_from_ulongest (start),
1104					    gdbscm_scm_from_ulongest (size)),
1105				     _("start+size overflows"));
1106	}
1107      end = start + size;
1108    }
1109  else
1110    end = ~(CORE_ADDR) 0;
1111
1112  mode_bits = ioscm_parse_mode_bits (FUNC_NAME, mode);
1113
1114  port = ioscm_open_port (memory_port_desc, mode_bits);
1115
1116  ioscm_init_memory_port (port, start, end);
1117
1118  scm_dynwind_end ();
1119
1120  /* TODO: Set the file name as "memory-start-end"?  */
1121  return port;
1122}
1123
1124/* Return non-zero if OBJ is a memory port.  */
1125
1126static int
1127gdbscm_is_memory_port (SCM obj)
1128{
1129  return !SCM_IMP (obj) && (SCM_TYP16 (obj) == memory_port_desc);
1130}
1131
1132/* (memory-port? obj) -> boolean */
1133
1134static SCM
1135gdbscm_memory_port_p (SCM obj)
1136{
1137  return scm_from_bool (gdbscm_is_memory_port (obj));
1138}
1139
1140/* (memory-port-range port) -> (start end) */
1141
1142static SCM
1143gdbscm_memory_port_range (SCM port)
1144{
1145  ioscm_memory_port *iomem;
1146
1147  SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
1148		   memory_port_desc_name);
1149
1150  iomem = (ioscm_memory_port *) SCM_STREAM (port);
1151  return scm_list_2 (gdbscm_scm_from_ulongest (iomem->start),
1152		     gdbscm_scm_from_ulongest (iomem->end));
1153}
1154
1155/* (memory-port-read-buffer-size port) -> integer */
1156
1157static SCM
1158gdbscm_memory_port_read_buffer_size (SCM port)
1159{
1160  ioscm_memory_port *iomem;
1161
1162  SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
1163		   memory_port_desc_name);
1164
1165  iomem = (ioscm_memory_port *) SCM_STREAM (port);
1166  return scm_from_uint (iomem->read_buf_size);
1167}
1168
1169/* (set-memory-port-read-buffer-size! port size) -> unspecified
1170   An exception is thrown if read data is still buffered or if the port
1171   is unbuffered.  */
1172
1173static SCM
1174gdbscm_set_memory_port_read_buffer_size_x (SCM port, SCM size)
1175{
1176  ioscm_memory_port *iomem;
1177
1178  SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
1179		   memory_port_desc_name);
1180  SCM_ASSERT_TYPE (scm_is_integer (size), size, SCM_ARG2, FUNC_NAME,
1181		   _("integer"));
1182
1183  if (!scm_is_unsigned_integer (size, min_memory_port_buf_size,
1184				max_memory_port_buf_size))
1185    {
1186      gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, size,
1187				 out_of_range_buf_size);
1188    }
1189
1190  iomem = (ioscm_memory_port *) SCM_STREAM (port);
1191  ioscm_reinit_memory_port (port, scm_to_uint (size), iomem->write_buf_size,
1192			    FUNC_NAME);
1193
1194  return SCM_UNSPECIFIED;
1195}
1196
1197/* (memory-port-write-buffer-size port) -> integer */
1198
1199static SCM
1200gdbscm_memory_port_write_buffer_size (SCM port)
1201{
1202  ioscm_memory_port *iomem;
1203
1204  SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
1205		   memory_port_desc_name);
1206
1207  iomem = (ioscm_memory_port *) SCM_STREAM (port);
1208  return scm_from_uint (iomem->write_buf_size);
1209}
1210
1211/* (set-memory-port-write-buffer-size! port size) -> unspecified
1212   An exception is thrown if write data is still buffered or if the port
1213   is unbuffered.  */
1214
1215static SCM
1216gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size)
1217{
1218  ioscm_memory_port *iomem;
1219
1220  SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME,
1221		   memory_port_desc_name);
1222  SCM_ASSERT_TYPE (scm_is_integer (size), size, SCM_ARG2, FUNC_NAME,
1223		   _("integer"));
1224
1225  if (!scm_is_unsigned_integer (size, min_memory_port_buf_size,
1226				max_memory_port_buf_size))
1227    {
1228      gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, size,
1229				 out_of_range_buf_size);
1230    }
1231
1232  iomem = (ioscm_memory_port *) SCM_STREAM (port);
1233  ioscm_reinit_memory_port (port, iomem->read_buf_size, scm_to_uint (size),
1234			    FUNC_NAME);
1235
1236  return SCM_UNSPECIFIED;
1237}
1238
1239/* Initialize gdb ports.  */
1240
1241static const scheme_function port_functions[] =
1242{
1243  { "input-port", 0, 0, 0, as_a_scm_t_subr (gdbscm_input_port),
1244    "\
1245Return gdb's input port." },
1246
1247  { "output-port", 0, 0, 0, as_a_scm_t_subr (gdbscm_output_port),
1248    "\
1249Return gdb's output port." },
1250
1251  { "error-port", 0, 0, 0, as_a_scm_t_subr (gdbscm_error_port),
1252    "\
1253Return gdb's error port." },
1254
1255  { "stdio-port?", 1, 0, 0, as_a_scm_t_subr (gdbscm_stdio_port_p),
1256    "\
1257Return #t if the object is a gdb:stdio-port." },
1258
1259  { "open-memory", 0, 0, 1, as_a_scm_t_subr (gdbscm_open_memory),
1260    "\
1261Return a port that can be used for reading/writing inferior memory.\n\
1262\n\
1263  Arguments: [#:mode string] [#:start address] [#:size integer]\n\
1264  Returns: A port object." },
1265
1266  { "memory-port?", 1, 0, 0, as_a_scm_t_subr (gdbscm_memory_port_p),
1267    "\
1268Return #t if the object is a memory port." },
1269
1270  { "memory-port-range", 1, 0, 0, as_a_scm_t_subr (gdbscm_memory_port_range),
1271    "\
1272Return the memory range of the port as (start end)." },
1273
1274  { "memory-port-read-buffer-size", 1, 0, 0,
1275    as_a_scm_t_subr (gdbscm_memory_port_read_buffer_size),
1276    "\
1277Return the size of the read buffer for the memory port." },
1278
1279  { "set-memory-port-read-buffer-size!", 2, 0, 0,
1280    as_a_scm_t_subr (gdbscm_set_memory_port_read_buffer_size_x),
1281    "\
1282Set the size of the read buffer for the memory port.\n\
1283\n\
1284  Arguments: port integer\n\
1285  Returns: unspecified." },
1286
1287  { "memory-port-write-buffer-size", 1, 0, 0,
1288    as_a_scm_t_subr (gdbscm_memory_port_write_buffer_size),
1289    "\
1290Return the size of the write buffer for the memory port." },
1291
1292  { "set-memory-port-write-buffer-size!", 2, 0, 0,
1293    as_a_scm_t_subr (gdbscm_set_memory_port_write_buffer_size_x),
1294    "\
1295Set the size of the write buffer for the memory port.\n\
1296\n\
1297  Arguments: port integer\n\
1298  Returns: unspecified." },
1299
1300  END_FUNCTIONS
1301};
1302
1303static const scheme_function private_port_functions[] =
1304{
1305#if 0 /* TODO */
1306  { "%with-gdb-input-from-port", 2, 0, 0,
1307    as_a_scm_t_subr (gdbscm_percent_with_gdb_input_from_port),
1308    "\
1309Temporarily set GDB's input port to PORT and then invoke THUNK.\n\
1310\n\
1311  Arguments: port thunk\n\
1312  Returns: The result of calling THUNK.\n\
1313\n\
1314This procedure is experimental." },
1315#endif
1316
1317  { "%with-gdb-output-to-port", 2, 0, 0,
1318    as_a_scm_t_subr (gdbscm_percent_with_gdb_output_to_port),
1319    "\
1320Temporarily set GDB's output port to PORT and then invoke THUNK.\n\
1321\n\
1322  Arguments: port thunk\n\
1323  Returns: The result of calling THUNK.\n\
1324\n\
1325This procedure is experimental." },
1326
1327  { "%with-gdb-error-to-port", 2, 0, 0,
1328    as_a_scm_t_subr (gdbscm_percent_with_gdb_error_to_port),
1329    "\
1330Temporarily set GDB's error port to PORT and then invoke THUNK.\n\
1331\n\
1332  Arguments: port thunk\n\
1333  Returns: The result of calling THUNK.\n\
1334\n\
1335This procedure is experimental." },
1336
1337  END_FUNCTIONS
1338};
1339
1340void
1341gdbscm_initialize_ports (void)
1342{
1343  /* Save the original stdio ports for debugging purposes.  */
1344
1345  orig_input_port_scm = scm_current_input_port ();
1346  orig_output_port_scm = scm_current_output_port ();
1347  orig_error_port_scm = scm_current_error_port ();
1348
1349  /* Set up the stdio ports.  */
1350
1351  ioscm_init_gdb_stdio_port ();
1352  input_port_scm = ioscm_make_gdb_stdio_port (0);
1353  output_port_scm = ioscm_make_gdb_stdio_port (1);
1354  error_port_scm = ioscm_make_gdb_stdio_port (2);
1355
1356  /* Set up memory ports.  */
1357
1358  ioscm_init_memory_port_type ();
1359
1360  /* Install the accessor functions.  */
1361
1362  gdbscm_define_functions (port_functions, 1);
1363  gdbscm_define_functions (private_port_functions, 0);
1364
1365  /* Keyword args for open-memory.  */
1366
1367  mode_keyword = scm_from_latin1_keyword ("mode");
1368  start_keyword = scm_from_latin1_keyword ("start");
1369  size_keyword = scm_from_latin1_keyword ("size");
1370
1371  /* Error message text for "out of range" memory port buffer sizes.  */
1372
1373  out_of_range_buf_size = xstrprintf ("size not between %u - %u",
1374				      min_memory_port_buf_size,
1375				      max_memory_port_buf_size);
1376}
1377