/* places a single char in the input buffer. */ static int sf_fill_input (SCM port) { SCM p = SCM_PACK (SCM_STREAM (port)); SCM ans; scm_t_port *pt; ans = scm_call_0 (SCM_SIMPLE_VECTOR_REF (p, 3)); /* get char. */ if (scm_is_false (ans) || SCM_EOF_OBJECT_P (ans)) return EOF; SCM_ASSERT (SCM_CHARP (ans), ans, SCM_ARG1, "sf_fill_input"); pt = SCM_PTAB_ENTRY (port); if (pt->encoding == NULL) { scm_t_port *pt = SCM_PTAB_ENTRY (port); *pt->read_buf = SCM_CHAR (ans); pt->read_pos = pt->read_buf; pt->read_end = pt->read_buf + 1; return *pt->read_buf; } else scm_ungetc_unlocked (SCM_CHAR (ans), port); return SCM_CHAR (ans); }
static void gdbscm_memory_port_end_input (SCM port, int offset) { scm_t_port *pt = SCM_PTAB_ENTRY (port); ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); size_t remaining = pt->read_end - pt->read_pos; /* Note: Use of "int offset" is specified by Guile ports API. */ if ((offset < 0 && remaining + offset > remaining) || (offset > 0 && remaining + offset < remaining)) { gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_int (offset), _("overflow in offset calculation")); } offset += remaining; if (offset > 0) { pt->read_pos = pt->read_end; /* Throw error if unread-char used at beginning of file then attempting to write. Seems correct. */ if (!ioscm_lseek_address (iomem, -offset, SEEK_CUR)) { gdbscm_out_of_range_error (FUNC_NAME, 0, scm_from_int (offset), _("bad offset")); } } pt->rw_active = SCM_PORT_NEITHER; }
static void gdbscm_memory_port_flush (SCM port) { scm_t_port *pt = SCM_PTAB_ENTRY (port); ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); size_t to_write = pt->write_pos - pt->write_buf; if (to_write == 0) return; /* There's no way to indicate a short write, so if the request goes past the end of the port's memory range, flag an error. */ if (to_write > iomem->size - iomem->current) { gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (to_write), _("writing beyond end of memory range")); } if (target_write_memory (iomem->start + iomem->current, pt->write_buf, to_write) != 0) gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL); iomem->current += to_write; pt->write_pos = pt->write_buf; pt->rw_active = SCM_PORT_NEITHER; }
static int gdbscm_memory_port_fill_input (SCM port) { scm_t_port *pt = SCM_PTAB_ENTRY (port); ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); size_t to_read; /* "current" is the offset of the first byte we want to read. */ gdb_assert (iomem->current <= iomem->size); if (iomem->current == iomem->size) return EOF; /* Don't read outside the allowed memory range. */ to_read = pt->read_buf_size; if (to_read > iomem->size - iomem->current) to_read = iomem->size - iomem->current; if (target_read_memory (iomem->start + iomem->current, pt->read_buf, to_read) != 0) gdbscm_memory_error (FUNC_NAME, _("error reading memory"), SCM_EOL); iomem->current += to_read; pt->read_pos = pt->read_buf; pt->read_end = pt->read_buf + to_read; return *pt->read_buf; }
static void ioscm_reinit_memory_port (SCM port, size_t read_buf_size, size_t write_buf_size, const char *func_name) { scm_t_port *pt = SCM_PTAB_ENTRY (port); ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); gdb_assert (read_buf_size >= min_memory_port_buf_size && read_buf_size <= max_memory_port_buf_size); gdb_assert (write_buf_size >= min_memory_port_buf_size && write_buf_size <= max_memory_port_buf_size); /* First check if the port is unbuffered. */ if (pt->read_buf == &pt->shortbuf) { gdb_assert (pt->write_buf == &pt->shortbuf); scm_misc_error (func_name, _("port is unbuffered: ~a"), scm_list_1 (port)); } /* Next check if anything is buffered. */ if (read_buf_size != pt->read_buf_size && pt->read_end != pt->read_buf) { scm_misc_error (func_name, _("read buffer not empty: ~a"), scm_list_1 (port)); } if (write_buf_size != pt->write_buf_size && pt->write_pos != pt->write_buf) { scm_misc_error (func_name, _("write buffer not empty: ~a"), scm_list_1 (port)); } /* Now we can update the buffer sizes, but only if the size has changed. */ if (read_buf_size != pt->read_buf_size) { iomem->read_buf_size = read_buf_size; pt->read_buf_size = read_buf_size; xfree (pt->read_buf); pt->read_buf = (unsigned char *) xmalloc (pt->read_buf_size); pt->read_pos = pt->read_end = pt->read_buf; } if (write_buf_size != pt->write_buf_size) { iomem->write_buf_size = write_buf_size; pt->write_buf_size = write_buf_size; xfree (pt->write_buf); pt->write_buf = (unsigned char *) xmalloc (pt->write_buf_size); pt->write_pos = pt->write_buf; pt->write_end = pt->write_buf + pt->write_buf_size; } }
static int sf_close (SCM port) { SCM p = SCM_PACK (SCM_STREAM (port)); SCM f = SCM_SIMPLE_VECTOR_REF (p, 4); if (scm_is_false (f)) return 0; f = scm_call_0 (f); errno = 0; return scm_is_false (f) ? EOF : 0; }
static SCM gdbscm_memory_port_write_buffer_size (SCM port) { ioscm_memory_port *iomem; SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME, memory_port_desc_name); iomem = (ioscm_memory_port *) SCM_STREAM (port); return scm_from_uint (iomem->write_buf_size); }
static void sf_write (SCM port, const void *data, size_t size) { SCM p = SCM_PACK (SCM_STREAM (port)); /* DATA is assumed to be a locale-encoded C string, which makes it hard to reliably pass binary data to a soft port. It can be achieved by choosing a Latin-1 locale, though, but the recommended approach is to use an R6RS "custom binary output port" instead. */ scm_call_1 (SCM_SIMPLE_VECTOR_REF (p, 1), scm_from_locale_stringn ((char *) data, size)); }
static SCM gdbscm_memory_port_range (SCM port) { ioscm_memory_port *iomem; SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME, memory_port_desc_name); iomem = (ioscm_memory_port *) SCM_STREAM (port); return scm_list_2 (gdbscm_scm_from_ulongest (iomem->start), gdbscm_scm_from_ulongest (iomem->end)); }
static int sf_input_waiting (SCM port) { SCM p = SCM_PACK (SCM_STREAM (port)); if (SCM_SIMPLE_VECTOR_LENGTH (p) >= 6) { SCM f = SCM_SIMPLE_VECTOR_REF (p, 5); if (scm_is_true (f)) return scm_to_int (scm_call_0 (f)); } /* Default is such that char-ready? for soft ports returns #t, as it did before this extension was implemented. */ return 1; }
static int gdbscm_memory_port_print (SCM exp, SCM port, scm_print_state *pstate) { ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (exp); char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp)); scm_puts ("#<", port); scm_print_port_mode (exp, port); /* scm_print_port_mode includes a trailing space. */ gdbscm_printf (port, "%s %s-%s", type, hex_string (iomem->start), hex_string (iomem->end)); scm_putc ('>', port); return 1; }
static int gdbscm_memory_port_close (SCM port) { scm_t_port *pt = SCM_PTAB_ENTRY (port); ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); gdbscm_memory_port_flush (port); if (pt->read_buf == pt->putback_buf) pt->read_buf = pt->saved_read_buf; if (pt->read_buf != &pt->shortbuf) xfree (pt->read_buf); if (pt->write_buf != &pt->shortbuf) xfree (pt->write_buf); scm_gc_free (iomem, sizeof (*iomem), "memory port"); return 0; }
/* Read one byte from PORT. */ static int fill_input (SCM port) { int result; scm_t_port *c_port = SCM_PTAB_ENTRY (port); /* Make sure that C_PORT's internal buffer wasn't changed behind our back. See http://lists.gnu.org/archive/html/guile-devel/2008-11/msg00042.html for an example where this assumption matters. */ assert (c_port->read_buf == (unsigned char *) SCM_STREAM (port)); assert (c_port->read_buf_size == PORT_BUFFER_SIZE); if (c_port->read_pos >= c_port->read_end) result = EOF; else result = (int) *c_port->read_pos++; return result; }
static SCM gdbscm_set_memory_port_write_buffer_size_x (SCM port, SCM size) { ioscm_memory_port *iomem; SCM_ASSERT_TYPE (gdbscm_is_memory_port (port), port, SCM_ARG1, FUNC_NAME, memory_port_desc_name); SCM_ASSERT_TYPE (scm_is_integer (size), size, SCM_ARG2, FUNC_NAME, _("integer")); if (!scm_is_unsigned_integer (size, min_memory_port_buf_size, max_memory_port_buf_size)) { gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, size, out_of_range_buf_size); } iomem = (ioscm_memory_port *) SCM_STREAM (port); ioscm_reinit_memory_port (port, iomem->read_buf_size, scm_to_uint (size), FUNC_NAME); return SCM_UNSPECIFIED; }
static scm_t_off gdbscm_memory_port_seek (SCM port, scm_t_off offset, int whence) { scm_t_port *pt = SCM_PTAB_ENTRY (port); ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); CORE_ADDR result; int rc; if (pt->rw_active == SCM_PORT_WRITE) { if (offset != 0 || whence != SEEK_CUR) { gdbscm_memory_port_flush (port); rc = ioscm_lseek_address (iomem, offset, whence); result = iomem->current; } else { /* Read current position without disturbing the buffer, but flag an error if what's in the buffer goes outside the allowed range. */ CORE_ADDR current = iomem->current; size_t delta = pt->write_pos - pt->write_buf; if (current + delta < current || current + delta > iomem->size) rc = 0; else { result = current + delta; rc = 1; } } } else if (pt->rw_active == SCM_PORT_READ) { if (offset != 0 || whence != SEEK_CUR) { scm_end_input (port); rc = ioscm_lseek_address (iomem, offset, whence); result = iomem->current; } else { /* Read current position without disturbing the buffer (particularly the unread-char buffer). */ CORE_ADDR current = iomem->current; size_t remaining = pt->read_end - pt->read_pos; if (current - remaining > current || current - remaining < iomem->start) rc = 0; else { result = current - remaining; rc = 1; } if (rc != 0 && pt->read_buf == pt->putback_buf) { size_t saved_remaining = pt->saved_read_end - pt->saved_read_pos; if (result - saved_remaining > result || result - saved_remaining < iomem->start) rc = 0; else result -= saved_remaining; } } } else /* SCM_PORT_NEITHER */ { rc = ioscm_lseek_address (iomem, offset, whence); result = iomem->current; } if (rc == 0) { gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_longest (offset), _("bad seek")); } /* TODO: The Guile API doesn't support 32x64. We can't fix that here, and there's no need to throw an error if the new address can't be represented in a scm_t_off. But we could return something less clumsy. */ return result; }
static void gdbscm_memory_port_write (SCM port, const void *void_data, size_t size) { scm_t_port *pt = SCM_PTAB_ENTRY (port); ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); const gdb_byte *data = (const gdb_byte *) void_data; /* There's no way to indicate a short write, so if the request goes past the end of the port's memory range, flag an error. */ if (size > iomem->size - iomem->current) { gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size), _("writing beyond end of memory range")); } if (pt->write_buf == &pt->shortbuf) { /* Unbuffered port. */ if (target_write_memory (iomem->start + iomem->current, data, size) != 0) gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL); iomem->current += size; return; } /* Note: The edge case of what to do when the buffer exactly fills is debatable. Guile flushes when the buffer exactly fills up, so we do too. It's counter-intuitive to my mind, but in case there's a subtlety somewhere that depends on this, we do the same. */ { size_t space = pt->write_end - pt->write_pos; if (size < space) { /* Data fits in buffer, and does not fill it. */ memcpy (pt->write_pos, data, size); pt->write_pos += size; } else { memcpy (pt->write_pos, data, space); pt->write_pos = pt->write_end; gdbscm_memory_port_flush (port); { const gdb_byte *ptr = data + space; size_t remaining = size - space; if (remaining >= pt->write_buf_size) { if (target_write_memory (iomem->start + iomem->current, ptr, remaining) != 0) gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL); iomem->current += remaining; } else { memcpy (pt->write_pos, ptr, remaining); pt->write_pos += remaining; } } } } }