* syscall.c (cb_syscall) <case CB_SYS_pipe>: New case.
* callback.c [HAVE_LIMITS_H]: Include limits.h. Include libiberty.h. (os_close, os_read, os_write, os_fstat, os_ftruncate): Support fd being either end of a pipe. (os_pipe, os_pipe_empty, os_pipe_nonempty): New functions. (os_shutdown): Clear pipe state. (default_callback): Initialize new members.
This commit is contained in:
parent
6a7e5cfe8c
commit
97f669eda9
3 changed files with 278 additions and 1 deletions
|
@ -1,5 +1,14 @@
|
||||||
2005-01-28 Hans-Peter Nilsson <hp@axis.com>
|
2005-01-28 Hans-Peter Nilsson <hp@axis.com>
|
||||||
|
|
||||||
|
* syscall.c (cb_syscall) <case CB_SYS_pipe>: New case.
|
||||||
|
* callback.c [HAVE_LIMITS_H]: Include limits.h.
|
||||||
|
Include libiberty.h.
|
||||||
|
(os_close, os_read, os_write, os_fstat, os_ftruncate): Support fd
|
||||||
|
being either end of a pipe.
|
||||||
|
(os_pipe, os_pipe_empty, os_pipe_nonempty): New functions.
|
||||||
|
(os_shutdown): Clear pipe state.
|
||||||
|
(default_callback): Initialize new members.
|
||||||
|
|
||||||
* callback.c (default_callback): Initialize target_endian.
|
* callback.c (default_callback): Initialize target_endian.
|
||||||
(cb_store_target_endian): Renamed from store, new first parameter
|
(cb_store_target_endian): Renamed from store, new first parameter
|
||||||
host_callback *cb, drop last parameter big_p. Take endianness
|
host_callback *cb, drop last parameter big_p. Take endianness
|
||||||
|
|
|
@ -42,6 +42,10 @@
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LIMITS_H
|
||||||
|
/* For PIPE_BUF. */
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -49,6 +53,8 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "gdb/callback.h"
|
#include "gdb/callback.h"
|
||||||
#include "targ-vals.h"
|
#include "targ-vals.h"
|
||||||
|
/* For xmalloc. */
|
||||||
|
#include "libiberty.h"
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -144,7 +150,48 @@ os_close (p, fd)
|
||||||
if (fd != i)
|
if (fd != i)
|
||||||
p->fd_buddy[i] = p->fd_buddy[fd];
|
p->fd_buddy[i] = p->fd_buddy[fd];
|
||||||
else
|
else
|
||||||
result = wrap (p, close (fdmap (p, fd)));
|
{
|
||||||
|
if (p->ispipe[fd])
|
||||||
|
{
|
||||||
|
int other = p->ispipe[fd];
|
||||||
|
int reader, writer;
|
||||||
|
|
||||||
|
if (other > 0)
|
||||||
|
{
|
||||||
|
/* Closing the read side. */
|
||||||
|
reader = fd;
|
||||||
|
writer = other;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Closing the write side. */
|
||||||
|
writer = fd;
|
||||||
|
reader = -other;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there was data in the buffer, make a last "now empty"
|
||||||
|
call, then deallocate data. */
|
||||||
|
if (p->pipe_buffer[writer].buffer != NULL)
|
||||||
|
{
|
||||||
|
(*p->pipe_empty) (p, reader, writer);
|
||||||
|
free (p->pipe_buffer[writer].buffer);
|
||||||
|
p->pipe_buffer[writer].buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear pipe data for this side. */
|
||||||
|
p->pipe_buffer[fd].size = 0;
|
||||||
|
p->ispipe[fd] = 0;
|
||||||
|
|
||||||
|
/* If this was the first close, mark the other side as the
|
||||||
|
only remaining side. */
|
||||||
|
if (fd != abs (other))
|
||||||
|
p->ispipe[abs (other)] = -other;
|
||||||
|
p->fd_buddy[fd] = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = wrap (p, close (fdmap (p, fd)));
|
||||||
|
}
|
||||||
p->fd_buddy[fd] = -1;
|
p->fd_buddy[fd] = -1;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -270,6 +317,47 @@ os_read (p, fd, buf, len)
|
||||||
result = fdbad (p, fd);
|
result = fdbad (p, fd);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
if (p->ispipe[fd])
|
||||||
|
{
|
||||||
|
int writer = p->ispipe[fd];
|
||||||
|
|
||||||
|
/* Can't read from the write-end. */
|
||||||
|
if (writer < 0)
|
||||||
|
{
|
||||||
|
p->last_errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing to read if nothing is written. */
|
||||||
|
if (p->pipe_buffer[writer].size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Truncate read request size to buffer size minus what's already
|
||||||
|
read. */
|
||||||
|
if (len > p->pipe_buffer[writer].size - p->pipe_buffer[fd].size)
|
||||||
|
len = p->pipe_buffer[writer].size - p->pipe_buffer[fd].size;
|
||||||
|
|
||||||
|
memcpy (buf, p->pipe_buffer[writer].buffer + p->pipe_buffer[fd].size,
|
||||||
|
len);
|
||||||
|
|
||||||
|
/* Account for what we just read. */
|
||||||
|
p->pipe_buffer[fd].size += len;
|
||||||
|
|
||||||
|
/* If we've read everything, empty and deallocate the buffer and
|
||||||
|
signal buffer-empty to client. (This isn't expected to be a
|
||||||
|
hot path in the simulator, so we don't hold on to the buffer.) */
|
||||||
|
if (p->pipe_buffer[fd].size == p->pipe_buffer[writer].size)
|
||||||
|
{
|
||||||
|
free (p->pipe_buffer[writer].buffer);
|
||||||
|
p->pipe_buffer[writer].buffer = NULL;
|
||||||
|
p->pipe_buffer[fd].size = 0;
|
||||||
|
p->pipe_buffer[writer].size = 0;
|
||||||
|
(*p->pipe_empty) (p, fd, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
result = wrap (p, read (fdmap (p, fd), buf, len));
|
result = wrap (p, read (fdmap (p, fd), buf, len));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -296,6 +384,49 @@ os_write (p, fd, buf, len)
|
||||||
result = fdbad (p, fd);
|
result = fdbad (p, fd);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
if (p->ispipe[fd])
|
||||||
|
{
|
||||||
|
int reader = -p->ispipe[fd];
|
||||||
|
|
||||||
|
/* Can't write to the read-end. */
|
||||||
|
if (reader < 0)
|
||||||
|
{
|
||||||
|
p->last_errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can't write to pipe with closed read end.
|
||||||
|
FIXME: We should send a SIGPIPE. */
|
||||||
|
if (reader == fd)
|
||||||
|
{
|
||||||
|
p->last_errno = EPIPE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As a sanity-check, we bail out it the buffered contents is much
|
||||||
|
larger than the size of the buffer on the host. We don't want
|
||||||
|
to run out of memory in the simulator due to a target program
|
||||||
|
bug if we can help it. Unfortunately, regarding the value that
|
||||||
|
reaches the simulated program, it's no use returning *less*
|
||||||
|
than the requested amount, because cb_syscall loops calling
|
||||||
|
this function until the whole amount is done. */
|
||||||
|
if (p->pipe_buffer[fd].size + len > 10 * PIPE_BUF)
|
||||||
|
{
|
||||||
|
p->last_errno = EFBIG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->pipe_buffer[fd].buffer
|
||||||
|
= xrealloc (p->pipe_buffer[fd].buffer, p->pipe_buffer[fd].size + len);
|
||||||
|
memcpy (p->pipe_buffer[fd].buffer + p->pipe_buffer[fd].size,
|
||||||
|
buf, len);
|
||||||
|
p->pipe_buffer[fd].size += len;
|
||||||
|
|
||||||
|
(*p->pipe_nonempty) (p, reader, fd);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
real_fd = fdmap (p, fd);
|
real_fd = fdmap (p, fd);
|
||||||
switch (real_fd)
|
switch (real_fd)
|
||||||
{
|
{
|
||||||
|
@ -400,6 +531,36 @@ os_fstat (p, fd, buf)
|
||||||
{
|
{
|
||||||
if (fdbad (p, fd))
|
if (fdbad (p, fd))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (p->ispipe[fd])
|
||||||
|
{
|
||||||
|
time_t t = (*p->time) (p, NULL);
|
||||||
|
|
||||||
|
/* We have to fake the struct stat contents, since the pipe is
|
||||||
|
made up in the simulator. */
|
||||||
|
memset (buf, 0, sizeof (*buf));
|
||||||
|
|
||||||
|
#ifdef HAVE_STRUCT_STAT_ST_MODE
|
||||||
|
buf->st_mode = S_IFIFO;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If more accurate tracking than current-time is needed (for
|
||||||
|
example, on GNU/Linux we get accurate numbers), the p->time
|
||||||
|
callback (which may be something other than os_time) should
|
||||||
|
happen for each read and write, and we'd need to keep track of
|
||||||
|
atime, ctime and mtime. */
|
||||||
|
#ifdef HAVE_STRUCT_STAT_ST_ATIME
|
||||||
|
buf->st_atime = t;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_STRUCT_STAT_ST_CTIME
|
||||||
|
buf->st_ctime = t;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_STRUCT_STAT_ST_MTIME
|
||||||
|
buf->st_mtime = t;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ??? There is an issue of when to translate to the target layout.
|
/* ??? There is an issue of when to translate to the target layout.
|
||||||
One could do that inside this function, or one could have the
|
One could do that inside this function, or one could have the
|
||||||
caller do it. It's more flexible to let the caller do it, though
|
caller do it. It's more flexible to let the caller do it, though
|
||||||
|
@ -426,6 +587,11 @@ os_ftruncate (p, fd, len)
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = fdbad (p, fd);
|
result = fdbad (p, fd);
|
||||||
|
if (p->ispipe[fd])
|
||||||
|
{
|
||||||
|
p->last_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
result = wrap (p, ftruncate (fdmap (p, fd), len));
|
result = wrap (p, ftruncate (fdmap (p, fd), len));
|
||||||
|
@ -441,6 +607,67 @@ os_truncate (p, file, len)
|
||||||
return wrap (p, truncate (file, len));
|
return wrap (p, truncate (file, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
os_pipe (p, filedes)
|
||||||
|
host_callback *p;
|
||||||
|
int *filedes;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* We deliberately don't use fd 0. It's probably stdin anyway. */
|
||||||
|
for (i = 1; i < MAX_CALLBACK_FDS; i++)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (p->fd_buddy[i] < 0)
|
||||||
|
for (j = i + 1; j < MAX_CALLBACK_FDS; j++)
|
||||||
|
if (p->fd_buddy[j] < 0)
|
||||||
|
{
|
||||||
|
/* Found two free fd:s. Set stat to allocated and mark
|
||||||
|
pipeness. */
|
||||||
|
p->fd_buddy[i] = i;
|
||||||
|
p->fd_buddy[j] = j;
|
||||||
|
p->ispipe[i] = j;
|
||||||
|
p->ispipe[j] = -i;
|
||||||
|
filedes[0] = i;
|
||||||
|
filedes[1] = j;
|
||||||
|
|
||||||
|
/* Poison the FD map to make bugs apparent. */
|
||||||
|
p->fdmap[i] = -1;
|
||||||
|
p->fdmap[j] = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p->last_errno = EMFILE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stub functions for pipe support. They should always be overridden in
|
||||||
|
targets using the pipe support, but that's up to the target. */
|
||||||
|
|
||||||
|
/* Called when the simulator says that the pipe at (reader, writer) is
|
||||||
|
now empty (so the writer should leave its waiting state). */
|
||||||
|
|
||||||
|
static void
|
||||||
|
os_pipe_empty (p, reader, writer)
|
||||||
|
host_callback *p;
|
||||||
|
int reader;
|
||||||
|
int writer;
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when the simulator says the pipe at (reader, writer) is now
|
||||||
|
non-empty (so the writer should wait). */
|
||||||
|
|
||||||
|
static void
|
||||||
|
os_pipe_nonempty (p, reader, writer)
|
||||||
|
host_callback *p;
|
||||||
|
int reader;
|
||||||
|
int writer;
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
os_shutdown (p)
|
os_shutdown (p)
|
||||||
host_callback *p;
|
host_callback *p;
|
||||||
|
@ -450,6 +677,13 @@ os_shutdown (p)
|
||||||
{
|
{
|
||||||
int do_close = 1;
|
int do_close = 1;
|
||||||
|
|
||||||
|
/* Zero out all pipe state. Don't call callbacks for non-empty
|
||||||
|
pipes; the target program has likely terminated at this point
|
||||||
|
or we're called at initialization time. */
|
||||||
|
p->ispipe[i] = 0;
|
||||||
|
p->pipe_buffer[i].size = 0;
|
||||||
|
p->pipe_buffer[i].buffer = NULL;
|
||||||
|
|
||||||
next = p->fd_buddy[i];
|
next = p->fd_buddy[i];
|
||||||
if (next < 0)
|
if (next < 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -604,6 +838,10 @@ host_callback default_callback =
|
||||||
os_ftruncate,
|
os_ftruncate,
|
||||||
os_truncate,
|
os_truncate,
|
||||||
|
|
||||||
|
os_pipe,
|
||||||
|
os_pipe_empty,
|
||||||
|
os_pipe_nonempty,
|
||||||
|
|
||||||
os_poll_quit,
|
os_poll_quit,
|
||||||
|
|
||||||
os_shutdown,
|
os_shutdown,
|
||||||
|
@ -619,6 +857,8 @@ host_callback default_callback =
|
||||||
|
|
||||||
{ 0, }, /* fdmap */
|
{ 0, }, /* fdmap */
|
||||||
{ -1, }, /* fd_buddy */
|
{ -1, }, /* fd_buddy */
|
||||||
|
{ 0, }, /* ispipe */
|
||||||
|
{ { 0, 0 }, }, /* pipe_buffer */
|
||||||
|
|
||||||
0, /* syscall_map */
|
0, /* syscall_map */
|
||||||
0, /* errno_map */
|
0, /* errno_map */
|
||||||
|
@ -628,6 +868,7 @@ host_callback default_callback =
|
||||||
|
|
||||||
/* Defaults expected to be overridden at initialization, where needed. */
|
/* Defaults expected to be overridden at initialization, where needed. */
|
||||||
BFD_ENDIAN_UNKNOWN, /* target_endian */
|
BFD_ENDIAN_UNKNOWN, /* target_endian */
|
||||||
|
4, /* target_sizeof_int */
|
||||||
|
|
||||||
HOST_CALLBACK_MAGIC,
|
HOST_CALLBACK_MAGIC,
|
||||||
};
|
};
|
||||||
|
|
|
@ -572,6 +572,33 @@ cb_syscall (cb, sc)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CB_SYS_pipe :
|
||||||
|
{
|
||||||
|
int p[2];
|
||||||
|
char *target_p = xcalloc (1, cb->target_sizeof_int * 2);
|
||||||
|
|
||||||
|
result = (*cb->pipe) (cb, p);
|
||||||
|
if (result != 0)
|
||||||
|
goto ErrorFinish;
|
||||||
|
|
||||||
|
cb_store_target_endian (cb, target_p, cb->target_sizeof_int, p[0]);
|
||||||
|
cb_store_target_endian (cb, target_p + cb->target_sizeof_int,
|
||||||
|
cb->target_sizeof_int, p[1]);
|
||||||
|
if ((*sc->write_mem) (cb, sc, sc->arg1, target_p,
|
||||||
|
cb->target_sizeof_int * 2)
|
||||||
|
!= cb->target_sizeof_int * 2)
|
||||||
|
{
|
||||||
|
/* Close the pipe fd:s. */
|
||||||
|
(*cb->close) (cb, p[0]);
|
||||||
|
(*cb->close) (cb, p[1]);
|
||||||
|
errcode = EFAULT;
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free (target_p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case CB_SYS_time :
|
case CB_SYS_time :
|
||||||
{
|
{
|
||||||
/* FIXME: May wish to change CB_SYS_time to something else.
|
/* FIXME: May wish to change CB_SYS_time to something else.
|
||||||
|
|
Loading…
Add table
Reference in a new issue