1999-04-16 03:35:26 +02:00
|
|
|
|
/* Remote target callback routines.
|
2010-01-01 11:03:36 +01:00
|
|
|
|
Copyright 1995, 1996, 1997, 2000, 2002, 2003, 2004, 2007, 2008, 2009, 2010
|
2004-05-10 18:18:03 +02:00
|
|
|
|
Free Software Foundation, Inc.
|
1999-04-16 03:35:26 +02:00
|
|
|
|
Contributed by Cygnus Solutions.
|
|
|
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2007-08-24 16:30:15 +02:00
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
1999-04-16 03:35:26 +02:00
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
2007-08-24 16:30:15 +02:00
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
/* This file provides a standard way for targets to talk to the host OS
|
|
|
|
|
level. */
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
2004-05-10 18:18:03 +02:00
|
|
|
|
#include "cconfig.h"
|
1999-04-16 03:35:26 +02:00
|
|
|
|
#endif
|
|
|
|
|
#include "ansidecl.h"
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#else
|
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
|
#include <strings.h>
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
2005-01-28 04:40:54 +01:00
|
|
|
|
#ifdef HAVE_LIMITS_H
|
|
|
|
|
/* For PIPE_BUF. */
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#endif
|
1999-04-16 03:35:26 +02:00
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
2002-06-09 17:45:54 +02:00
|
|
|
|
#include "gdb/callback.h"
|
1999-04-16 03:35:26 +02:00
|
|
|
|
#include "targ-vals.h"
|
2005-01-28 04:40:54 +01:00
|
|
|
|
/* For xmalloc. */
|
|
|
|
|
#include "libiberty.h"
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2005-04-29 16:48:03 +02:00
|
|
|
|
#ifndef PIPE_BUF
|
|
|
|
|
#define PIPE_BUF 512
|
|
|
|
|
#endif
|
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
/* ??? sim_cb_printf should be cb_printf, but until the callback support is
|
|
|
|
|
broken out of the simulator directory, these are here to not require
|
|
|
|
|
sim-utils.h. */
|
|
|
|
|
void sim_cb_printf PARAMS ((host_callback *, const char *, ...));
|
|
|
|
|
void sim_cb_eprintf PARAMS ((host_callback *, const char *, ...));
|
|
|
|
|
|
|
|
|
|
extern CB_TARGET_DEFS_MAP cb_init_syscall_map[];
|
|
|
|
|
extern CB_TARGET_DEFS_MAP cb_init_errno_map[];
|
|
|
|
|
extern CB_TARGET_DEFS_MAP cb_init_open_map[];
|
|
|
|
|
|
|
|
|
|
extern int system PARAMS ((const char *));
|
|
|
|
|
|
|
|
|
|
static int os_init PARAMS ((host_callback *));
|
|
|
|
|
static int os_shutdown PARAMS ((host_callback *));
|
|
|
|
|
static int os_unlink PARAMS ((host_callback *, const char *));
|
|
|
|
|
static long os_time PARAMS ((host_callback *, long *));
|
|
|
|
|
static int os_system PARAMS ((host_callback *, const char *));
|
|
|
|
|
static int os_rename PARAMS ((host_callback *, const char *, const char *));
|
|
|
|
|
static int os_write_stdout PARAMS ((host_callback *, const char *, int));
|
|
|
|
|
static void os_flush_stdout PARAMS ((host_callback *));
|
|
|
|
|
static int os_write_stderr PARAMS ((host_callback *, const char *, int));
|
|
|
|
|
static void os_flush_stderr PARAMS ((host_callback *));
|
|
|
|
|
static int os_write PARAMS ((host_callback *, int, const char *, int));
|
|
|
|
|
static int os_read_stdin PARAMS ((host_callback *, char *, int));
|
|
|
|
|
static int os_read PARAMS ((host_callback *, int, char *, int));
|
|
|
|
|
static int os_open PARAMS ((host_callback *, const char *, int));
|
|
|
|
|
static int os_lseek PARAMS ((host_callback *, int, long, int));
|
|
|
|
|
static int os_isatty PARAMS ((host_callback *, int));
|
|
|
|
|
static int os_get_errno PARAMS ((host_callback *));
|
|
|
|
|
static int os_close PARAMS ((host_callback *, int));
|
|
|
|
|
static void os_vprintf_filtered PARAMS ((host_callback *, const char *, va_list));
|
|
|
|
|
static void os_evprintf_filtered PARAMS ((host_callback *, const char *, va_list));
|
2009-01-07 00:39:28 +01:00
|
|
|
|
static void os_error PARAMS ((host_callback *, const char *, ...))
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
|
__attribute__ ((__noreturn__))
|
|
|
|
|
#endif
|
|
|
|
|
;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
static int fdmap PARAMS ((host_callback *, int));
|
|
|
|
|
static int fdbad PARAMS ((host_callback *, int));
|
|
|
|
|
static int wrap PARAMS ((host_callback *, int));
|
|
|
|
|
|
|
|
|
|
/* Set the callback copy of errno from what we see now. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
wrap (p, val)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int val;
|
|
|
|
|
{
|
|
|
|
|
p->last_errno = errno;
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure the FD provided is ok. If not, return non-zero
|
|
|
|
|
and set errno. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
fdbad (p, fd)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
{
|
2004-06-25 18:48:03 +02:00
|
|
|
|
if (fd < 0 || fd > MAX_CALLBACK_FDS || p->fd_buddy[fd] < 0)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
p->last_errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
fdmap (p, fd)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
{
|
|
|
|
|
return p->fdmap[fd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_close (p, fd)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
{
|
|
|
|
|
int result;
|
2004-06-25 18:48:03 +02:00
|
|
|
|
int i, next;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
result = fdbad (p, fd);
|
|
|
|
|
if (result)
|
|
|
|
|
return result;
|
2004-06-25 18:48:03 +02:00
|
|
|
|
/* If this file descripter has one or more buddies (originals /
|
|
|
|
|
duplicates from a dup), just remove it from the circular list. */
|
|
|
|
|
for (i = fd; (next = p->fd_buddy[i]) != fd; )
|
|
|
|
|
i = next;
|
|
|
|
|
if (fd != i)
|
|
|
|
|
p->fd_buddy[i] = p->fd_buddy[fd];
|
|
|
|
|
else
|
2005-01-28 04:40:54 +01:00
|
|
|
|
{
|
|
|
|
|
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)));
|
|
|
|
|
}
|
2004-06-25 18:48:03 +02:00
|
|
|
|
p->fd_buddy[fd] = -1;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* taken from gdb/util.c:notice_quit() - should be in a library */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(__GO32__) || defined (_MSC_VER)
|
|
|
|
|
static int
|
|
|
|
|
os_poll_quit (p)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
{
|
|
|
|
|
#if defined(__GO32__)
|
|
|
|
|
int kbhit ();
|
|
|
|
|
int getkey ();
|
|
|
|
|
if (kbhit ())
|
|
|
|
|
{
|
|
|
|
|
int k = getkey ();
|
|
|
|
|
if (k == 1)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else if (k == 2)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sim_cb_eprintf (p, "CTRL-A to quit, CTRL-B to quit harder\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#if defined (_MSC_VER)
|
|
|
|
|
/* NB - this will not compile! */
|
|
|
|
|
int k = win32pollquit();
|
|
|
|
|
if (k == 1)
|
|
|
|
|
return 1;
|
|
|
|
|
else if (k == 2)
|
|
|
|
|
return 1;
|
|
|
|
|
#endif
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
#define os_poll_quit 0
|
|
|
|
|
#endif /* defined(__GO32__) || defined(_MSC_VER) */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_get_errno (p)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
{
|
|
|
|
|
return cb_host_to_target_errno (p, p->last_errno);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_isatty (p, fd)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
result = fdbad (p, fd);
|
|
|
|
|
if (result)
|
|
|
|
|
return result;
|
|
|
|
|
result = wrap (p, isatty (fdmap (p, fd)));
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_lseek (p, fd, off, way)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
long off;
|
|
|
|
|
int way;
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
result = fdbad (p, fd);
|
|
|
|
|
if (result)
|
|
|
|
|
return result;
|
|
|
|
|
result = lseek (fdmap (p, fd), off, way);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_open (p, name, flags)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
const char *name;
|
|
|
|
|
int flags;
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < MAX_CALLBACK_FDS; i++)
|
|
|
|
|
{
|
2004-06-25 18:48:03 +02:00
|
|
|
|
if (p->fd_buddy[i] < 0)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int f = open (name, cb_target_to_host_open (p, flags), 0644);
|
|
|
|
|
if (f < 0)
|
|
|
|
|
{
|
|
|
|
|
p->last_errno = errno;
|
|
|
|
|
return f;
|
|
|
|
|
}
|
2004-06-25 18:48:03 +02:00
|
|
|
|
p->fd_buddy[i] = i;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
p->fdmap[i] = f;
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
p->last_errno = EMFILE;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_read (p, fd, buf, len)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
char *buf;
|
|
|
|
|
int len;
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
result = fdbad (p, fd);
|
|
|
|
|
if (result)
|
|
|
|
|
return result;
|
2005-01-28 04:40:54 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
result = wrap (p, read (fdmap (p, fd), buf, len));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_read_stdin (p, buf, len)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
char *buf;
|
|
|
|
|
int len;
|
|
|
|
|
{
|
|
|
|
|
return wrap (p, read (0, buf, len));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_write (p, fd, buf, len)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
const char *buf;
|
|
|
|
|
int len;
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
int real_fd;
|
|
|
|
|
|
|
|
|
|
result = fdbad (p, fd);
|
|
|
|
|
if (result)
|
|
|
|
|
return result;
|
2005-01-28 04:40:54 +01:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
real_fd = fdmap (p, fd);
|
|
|
|
|
switch (real_fd)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
result = wrap (p, write (real_fd, buf, len));
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
result = p->write_stdout (p, buf, len);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
result = p->write_stderr (p, buf, len);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_write_stdout (p, buf, len)
|
2000-02-08 21:54:27 +01:00
|
|
|
|
host_callback *p ATTRIBUTE_UNUSED;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
const char *buf;
|
|
|
|
|
int len;
|
|
|
|
|
{
|
|
|
|
|
return fwrite (buf, 1, len, stdout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
os_flush_stdout (p)
|
2000-02-08 21:54:27 +01:00
|
|
|
|
host_callback *p ATTRIBUTE_UNUSED;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
fflush (stdout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_write_stderr (p, buf, len)
|
2000-02-08 21:54:27 +01:00
|
|
|
|
host_callback *p ATTRIBUTE_UNUSED;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
const char *buf;
|
|
|
|
|
int len;
|
|
|
|
|
{
|
|
|
|
|
return fwrite (buf, 1, len, stderr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
os_flush_stderr (p)
|
2000-02-08 21:54:27 +01:00
|
|
|
|
host_callback *p ATTRIBUTE_UNUSED;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
fflush (stderr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_rename (p, f1, f2)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
const char *f1;
|
|
|
|
|
const char *f2;
|
|
|
|
|
{
|
|
|
|
|
return wrap (p, rename (f1, f2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_system (p, s)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
const char *s;
|
|
|
|
|
{
|
|
|
|
|
return wrap (p, system (s));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
|
os_time (p, t)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
long *t;
|
|
|
|
|
{
|
|
|
|
|
return wrap (p, time (t));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_unlink (p, f1)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
const char *f1;
|
|
|
|
|
{
|
|
|
|
|
return wrap (p, unlink (f1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_stat (p, file, buf)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
const char *file;
|
|
|
|
|
struct stat *buf;
|
|
|
|
|
{
|
|
|
|
|
/* ??? There is an issue of when to translate to the target layout.
|
|
|
|
|
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
|
|
|
|
|
I'm not sure the flexibility will ever be useful. */
|
|
|
|
|
return wrap (p, stat (file, buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_fstat (p, fd, buf)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
struct stat *buf;
|
|
|
|
|
{
|
|
|
|
|
if (fdbad (p, fd))
|
|
|
|
|
return -1;
|
2005-01-28 04:40:54 +01:00
|
|
|
|
|
|
|
|
|
if (p->ispipe[fd])
|
|
|
|
|
{
|
2005-02-21 22:59:54 +01:00
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_ATIME) || defined (HAVE_STRUCT_STAT_ST_CTIME) || defined (HAVE_STRUCT_STAT_ST_MTIME)
|
2005-01-28 04:40:54 +01:00
|
|
|
|
time_t t = (*p->time) (p, NULL);
|
2005-02-21 22:59:54 +01:00
|
|
|
|
#endif
|
2005-01-28 04:40:54 +01:00
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
/* ??? There is an issue of when to translate to the target layout.
|
|
|
|
|
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
|
|
|
|
|
I'm not sure the flexibility will ever be useful. */
|
|
|
|
|
return wrap (p, fstat (fdmap (p, fd), buf));
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-13 01:38:38 +01:00
|
|
|
|
static int
|
|
|
|
|
os_lstat (p, file, buf)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
const char *file;
|
|
|
|
|
struct stat *buf;
|
|
|
|
|
{
|
|
|
|
|
/* NOTE: hpn/2004-12-12: Same issue here as with os_fstat. */
|
2005-04-29 16:48:03 +02:00
|
|
|
|
#ifdef HAVE_LSTAT
|
2004-12-13 01:38:38 +01:00
|
|
|
|
return wrap (p, lstat (file, buf));
|
2005-04-29 16:48:03 +02:00
|
|
|
|
#else
|
|
|
|
|
return wrap (p, stat (file, buf));
|
|
|
|
|
#endif
|
2004-12-13 01:38:38 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-15 14:30:47 +02:00
|
|
|
|
static int
|
|
|
|
|
os_ftruncate (p, fd, len)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
int fd;
|
|
|
|
|
long len;
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
result = fdbad (p, fd);
|
2005-01-28 04:40:54 +01:00
|
|
|
|
if (p->ispipe[fd])
|
|
|
|
|
{
|
|
|
|
|
p->last_errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2003-10-15 14:30:47 +02:00
|
|
|
|
if (result)
|
|
|
|
|
return result;
|
2005-04-29 16:48:03 +02:00
|
|
|
|
#ifdef HAVE_FTRUNCATE
|
2003-10-15 14:30:47 +02:00
|
|
|
|
result = wrap (p, ftruncate (fdmap (p, fd), len));
|
2005-04-29 16:48:03 +02:00
|
|
|
|
#else
|
|
|
|
|
p->last_errno = EINVAL;
|
|
|
|
|
result = -1;
|
|
|
|
|
#endif
|
2003-10-15 14:30:47 +02:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_truncate (p, file, len)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
const char *file;
|
|
|
|
|
long len;
|
|
|
|
|
{
|
2005-04-29 16:48:03 +02:00
|
|
|
|
#ifdef HAVE_TRUNCATE
|
2003-10-21 22:41:43 +02:00
|
|
|
|
return wrap (p, truncate (file, len));
|
2005-04-29 16:48:03 +02:00
|
|
|
|
#else
|
|
|
|
|
p->last_errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
#endif
|
2003-10-15 14:30:47 +02:00
|
|
|
|
}
|
|
|
|
|
|
2005-01-28 04:40:54 +01:00
|
|
|
|
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;
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
static int
|
|
|
|
|
os_shutdown (p)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
{
|
2004-06-25 18:48:03 +02:00
|
|
|
|
int i, next, j;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
for (i = 0; i < MAX_CALLBACK_FDS; i++)
|
|
|
|
|
{
|
2004-06-25 18:48:03 +02:00
|
|
|
|
int do_close = 1;
|
|
|
|
|
|
2005-01-28 04:40:54 +01:00
|
|
|
|
/* 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;
|
|
|
|
|
|
2004-06-25 18:48:03 +02:00
|
|
|
|
next = p->fd_buddy[i];
|
|
|
|
|
if (next < 0)
|
|
|
|
|
continue;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
j = next;
|
|
|
|
|
if (j == MAX_CALLBACK_FDS)
|
|
|
|
|
do_close = 0;
|
|
|
|
|
next = p->fd_buddy[j];
|
|
|
|
|
p->fd_buddy[j] = -1;
|
|
|
|
|
/* At the initial call of os_init, we got -1, 0, 0, 0, ... */
|
|
|
|
|
if (next < 0)
|
|
|
|
|
{
|
2004-06-27 05:14:51 +02:00
|
|
|
|
p->fd_buddy[i] = -1;
|
2004-06-25 18:48:03 +02:00
|
|
|
|
do_close = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (j != i);
|
|
|
|
|
if (do_close)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
close (p->fdmap[i]);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
os_init (p)
|
|
|
|
|
host_callback *p;
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
os_shutdown (p);
|
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
|
{
|
|
|
|
|
p->fdmap[i] = i;
|
2004-06-25 18:48:03 +02:00
|
|
|
|
p->fd_buddy[i] = i - 1;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
}
|
2004-06-25 18:48:03 +02:00
|
|
|
|
p->fd_buddy[0] = MAX_CALLBACK_FDS;
|
|
|
|
|
p->fd_buddy[MAX_CALLBACK_FDS] = 2;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
p->syscall_map = cb_init_syscall_map;
|
|
|
|
|
p->errno_map = cb_init_errno_map;
|
|
|
|
|
p->open_map = cb_init_open_map;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-02 01:26:32 +02:00
|
|
|
|
/* DEPRECATED */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
/* VARARGS */
|
|
|
|
|
static void
|
2000-02-08 21:54:27 +01:00
|
|
|
|
os_printf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start (args, format);
|
|
|
|
|
|
|
|
|
|
vfprintf (stdout, format, args);
|
|
|
|
|
va_end (args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* VARARGS */
|
|
|
|
|
static void
|
2000-02-08 21:54:27 +01:00
|
|
|
|
os_vprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
vprintf (format, args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* VARARGS */
|
|
|
|
|
static void
|
2000-02-08 21:54:27 +01:00
|
|
|
|
os_evprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
vfprintf (stderr, format, args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* VARARGS */
|
|
|
|
|
static void
|
2000-02-08 21:54:27 +01:00
|
|
|
|
os_error (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start (args, format);
|
|
|
|
|
|
|
|
|
|
vfprintf (stderr, format, args);
|
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
host_callback default_callback =
|
|
|
|
|
{
|
|
|
|
|
os_close,
|
|
|
|
|
os_get_errno,
|
|
|
|
|
os_isatty,
|
|
|
|
|
os_lseek,
|
|
|
|
|
os_open,
|
|
|
|
|
os_read,
|
|
|
|
|
os_read_stdin,
|
|
|
|
|
os_rename,
|
|
|
|
|
os_system,
|
|
|
|
|
os_time,
|
|
|
|
|
os_unlink,
|
|
|
|
|
os_write,
|
|
|
|
|
os_write_stdout,
|
|
|
|
|
os_flush_stdout,
|
|
|
|
|
os_write_stderr,
|
|
|
|
|
os_flush_stderr,
|
|
|
|
|
|
|
|
|
|
os_stat,
|
|
|
|
|
os_fstat,
|
2004-12-13 01:38:38 +01:00
|
|
|
|
os_lstat,
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2003-10-15 14:30:47 +02:00
|
|
|
|
os_ftruncate,
|
|
|
|
|
os_truncate,
|
|
|
|
|
|
2005-01-28 04:40:54 +01:00
|
|
|
|
os_pipe,
|
|
|
|
|
os_pipe_empty,
|
|
|
|
|
os_pipe_nonempty,
|
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
os_poll_quit,
|
|
|
|
|
|
|
|
|
|
os_shutdown,
|
|
|
|
|
os_init,
|
|
|
|
|
|
|
|
|
|
os_printf_filtered, /* deprecated */
|
|
|
|
|
|
|
|
|
|
os_vprintf_filtered,
|
|
|
|
|
os_evprintf_filtered,
|
|
|
|
|
os_error,
|
|
|
|
|
|
|
|
|
|
0, /* last errno */
|
|
|
|
|
|
|
|
|
|
{ 0, }, /* fdmap */
|
2004-06-25 18:48:03 +02:00
|
|
|
|
{ -1, }, /* fd_buddy */
|
2005-01-28 04:40:54 +01:00
|
|
|
|
{ 0, }, /* ispipe */
|
|
|
|
|
{ { 0, 0 }, }, /* pipe_buffer */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
0, /* syscall_map */
|
|
|
|
|
0, /* errno_map */
|
|
|
|
|
0, /* open_map */
|
|
|
|
|
0, /* signal_map */
|
|
|
|
|
0, /* stat_map */
|
|
|
|
|
|
2005-01-28 04:28:40 +01:00
|
|
|
|
/* Defaults expected to be overridden at initialization, where needed. */
|
|
|
|
|
BFD_ENDIAN_UNKNOWN, /* target_endian */
|
2005-01-28 04:40:54 +01:00
|
|
|
|
4, /* target_sizeof_int */
|
2005-01-28 04:28:40 +01:00
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
HOST_CALLBACK_MAGIC,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Read in a file describing the target's system call values.
|
|
|
|
|
E.g. maybe someone will want to use something other than newlib.
|
|
|
|
|
This assumes that the basic system call recognition and value passing/
|
|
|
|
|
returning is supported. So maybe some coding/recompilation will be
|
|
|
|
|
necessary, but not as much.
|
|
|
|
|
|
|
|
|
|
If an error occurs, the existing mapping is not changed. */
|
|
|
|
|
|
|
|
|
|
CB_RC
|
|
|
|
|
cb_read_target_syscall_maps (cb, file)
|
|
|
|
|
host_callback *cb;
|
|
|
|
|
const char *file;
|
|
|
|
|
{
|
|
|
|
|
CB_TARGET_DEFS_MAP *syscall_map, *errno_map, *open_map, *signal_map;
|
|
|
|
|
const char *stat_map;
|
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
|
|
if ((f = fopen (file, "r")) == NULL)
|
|
|
|
|
return CB_RC_ACCESS;
|
|
|
|
|
|
|
|
|
|
/* ... read in and parse file ... */
|
|
|
|
|
|
|
|
|
|
fclose (f);
|
|
|
|
|
return CB_RC_NO_MEM; /* FIXME:wip */
|
|
|
|
|
|
|
|
|
|
/* Free storage allocated for any existing maps. */
|
|
|
|
|
if (cb->syscall_map)
|
|
|
|
|
free (cb->syscall_map);
|
|
|
|
|
if (cb->errno_map)
|
|
|
|
|
free (cb->errno_map);
|
|
|
|
|
if (cb->open_map)
|
|
|
|
|
free (cb->open_map);
|
|
|
|
|
if (cb->signal_map)
|
|
|
|
|
free (cb->signal_map);
|
|
|
|
|
if (cb->stat_map)
|
|
|
|
|
free ((PTR) cb->stat_map);
|
|
|
|
|
|
|
|
|
|
cb->syscall_map = syscall_map;
|
|
|
|
|
cb->errno_map = errno_map;
|
|
|
|
|
cb->open_map = open_map;
|
|
|
|
|
cb->signal_map = signal_map;
|
|
|
|
|
cb->stat_map = stat_map;
|
|
|
|
|
|
|
|
|
|
return CB_RC_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Translate the target's version of a syscall number to the host's.
|
|
|
|
|
This isn't actually the host's version, rather a canonical form.
|
|
|
|
|
??? Perhaps this should be renamed to ..._canon_syscall. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
cb_target_to_host_syscall (cb, target_val)
|
|
|
|
|
host_callback *cb;
|
|
|
|
|
int target_val;
|
|
|
|
|
{
|
|
|
|
|
CB_TARGET_DEFS_MAP *m;
|
|
|
|
|
|
|
|
|
|
for (m = &cb->syscall_map[0]; m->target_val != -1; ++m)
|
|
|
|
|
if (m->target_val == target_val)
|
|
|
|
|
return m->host_val;
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: sort tables if large.
|
|
|
|
|
Alternatively, an obvious improvement for errno conversion is
|
|
|
|
|
to machine generate a function with a large switch(). */
|
|
|
|
|
|
|
|
|
|
/* Translate the host's version of errno to the target's. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
cb_host_to_target_errno (cb, host_val)
|
|
|
|
|
host_callback *cb;
|
|
|
|
|
int host_val;
|
|
|
|
|
{
|
|
|
|
|
CB_TARGET_DEFS_MAP *m;
|
|
|
|
|
|
|
|
|
|
for (m = &cb->errno_map[0]; m->host_val; ++m)
|
|
|
|
|
if (m->host_val == host_val)
|
|
|
|
|
return m->target_val;
|
|
|
|
|
|
|
|
|
|
/* ??? Which error to return in this case is up for grabs.
|
|
|
|
|
Note that some missing values may have standard alternatives.
|
|
|
|
|
For now return 0 and require caller to deal with it. */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given a set of target bitmasks for the open system call,
|
|
|
|
|
return the host equivalent.
|
|
|
|
|
Mapping open flag values is best done by looping so there's no need
|
|
|
|
|
to machine generate this function. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
cb_target_to_host_open (cb, target_val)
|
|
|
|
|
host_callback *cb;
|
|
|
|
|
int target_val;
|
|
|
|
|
{
|
|
|
|
|
int host_val = 0;
|
|
|
|
|
CB_TARGET_DEFS_MAP *m;
|
|
|
|
|
|
|
|
|
|
for (m = &cb->open_map[0]; m->host_val != -1; ++m)
|
|
|
|
|
{
|
|
|
|
|
switch (m->target_val)
|
|
|
|
|
{
|
|
|
|
|
/* O_RDONLY can be (and usually is) 0 which needs to be treated
|
|
|
|
|
specially. */
|
|
|
|
|
case TARGET_O_RDONLY :
|
|
|
|
|
case TARGET_O_WRONLY :
|
|
|
|
|
case TARGET_O_RDWR :
|
|
|
|
|
if ((target_val & (TARGET_O_RDONLY | TARGET_O_WRONLY | TARGET_O_RDWR))
|
|
|
|
|
== m->target_val)
|
|
|
|
|
host_val |= m->host_val;
|
|
|
|
|
/* Handle the host/target differentiating between binary and
|
|
|
|
|
text mode. Only one case is of importance */
|
|
|
|
|
#if ! defined (TARGET_O_BINARY) && defined (O_BINARY)
|
|
|
|
|
host_val |= O_BINARY;
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
default :
|
|
|
|
|
if ((m->target_val & target_val) == m->target_val)
|
|
|
|
|
host_val |= m->host_val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return host_val;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-28 04:28:40 +01:00
|
|
|
|
/* Utility for e.g. cb_host_to_target_stat to store values in the target's
|
1999-04-16 03:35:26 +02:00
|
|
|
|
stat struct. */
|
|
|
|
|
|
2005-01-28 04:28:40 +01:00
|
|
|
|
void
|
|
|
|
|
cb_store_target_endian (cb, p, size, val)
|
|
|
|
|
host_callback *cb;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
char *p;
|
|
|
|
|
int size;
|
|
|
|
|
long val; /* ??? must be as big as target word size */
|
|
|
|
|
{
|
2005-01-28 04:28:40 +01:00
|
|
|
|
if (cb->target_endian == BFD_ENDIAN_BIG)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
p += size;
|
|
|
|
|
while (size-- > 0)
|
|
|
|
|
{
|
|
|
|
|
*--p = val;
|
|
|
|
|
val >>= 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (size-- > 0)
|
|
|
|
|
{
|
|
|
|
|
*p++ = val;
|
|
|
|
|
val >>= 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Translate a host's stat struct into a target's.
|
|
|
|
|
If HS is NULL, just compute the length of the buffer required,
|
|
|
|
|
TS is ignored.
|
|
|
|
|
|
|
|
|
|
The result is the size of the target's stat struct,
|
2002-02-11 00:11:37 +01:00
|
|
|
|
or zero if an error occurred during the translation. */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
cb_host_to_target_stat (cb, hs, ts)
|
|
|
|
|
host_callback *cb;
|
|
|
|
|
const struct stat *hs;
|
|
|
|
|
PTR ts;
|
|
|
|
|
{
|
|
|
|
|
const char *m = cb->stat_map;
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
if (hs == NULL)
|
|
|
|
|
ts = NULL;
|
|
|
|
|
p = ts;
|
|
|
|
|
|
|
|
|
|
while (m)
|
|
|
|
|
{
|
|
|
|
|
char *q = strchr (m, ',');
|
|
|
|
|
int size;
|
|
|
|
|
|
|
|
|
|
/* FIXME: Use sscanf? */
|
|
|
|
|
if (q == NULL)
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: print error message */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
size = atoi (q + 1);
|
|
|
|
|
if (size == 0)
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: print error message */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hs != NULL)
|
|
|
|
|
{
|
2004-12-04 00:34:55 +01:00
|
|
|
|
if (0)
|
* configure.in (SIM_CHECK_MEMBERS): Call for struct stat members
st_dev, st_ino, st_mode, st_nlink, st_uid, st_gid, st_rdev,
st_size, st_blksize, st_blocks, st_atime, st_mtime and st_ctime.
* aclocal.m4 (SIM_CHECK_MEMBER, SIM_CHECK_MEMBERS_1)
(SIM_CHECK_MEMBERS): New macros.
* callback.c (cb_host_to_target_stat): Use temporary macro ST_x
for struct stat member test and write. Add ST_x calls for each
struct stat member tested in configure.in. Wrap each ST_x call in
#ifdef of configure macro for that member.
* configure, config.in: Regenerate.
2004-12-03 20:36:53 +01:00
|
|
|
|
;
|
|
|
|
|
/* Defined here to avoid emacs indigestion on a lone "else". */
|
|
|
|
|
#undef ST_x
|
|
|
|
|
#define ST_x(FLD) \
|
|
|
|
|
else if (strncmp (m, #FLD, q - m) == 0) \
|
2005-01-28 04:28:40 +01:00
|
|
|
|
cb_store_target_endian (cb, p, size, hs->FLD)
|
* configure.in (SIM_CHECK_MEMBERS): Call for struct stat members
st_dev, st_ino, st_mode, st_nlink, st_uid, st_gid, st_rdev,
st_size, st_blksize, st_blocks, st_atime, st_mtime and st_ctime.
* aclocal.m4 (SIM_CHECK_MEMBER, SIM_CHECK_MEMBERS_1)
(SIM_CHECK_MEMBERS): New macros.
* callback.c (cb_host_to_target_stat): Use temporary macro ST_x
for struct stat member test and write. Add ST_x calls for each
struct stat member tested in configure.in. Wrap each ST_x call in
#ifdef of configure macro for that member.
* configure, config.in: Regenerate.
2004-12-03 20:36:53 +01:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_DEV
|
|
|
|
|
ST_x (st_dev);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_INO
|
|
|
|
|
ST_x (st_ino);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MODE
|
|
|
|
|
ST_x (st_mode);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_NLINK
|
|
|
|
|
ST_x (st_nlink);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_UID
|
|
|
|
|
ST_x (st_uid);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_GID
|
|
|
|
|
ST_x (st_gid);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_RDEV
|
|
|
|
|
ST_x (st_rdev);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_SIZE
|
|
|
|
|
ST_x (st_size);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
|
|
|
|
|
ST_x (st_blksize);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
|
|
|
|
|
ST_x (st_blocks);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_ATIME
|
|
|
|
|
ST_x (st_atime);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIME
|
|
|
|
|
ST_x (st_mtime);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_CTIME
|
|
|
|
|
ST_x (st_ctime);
|
|
|
|
|
#endif
|
|
|
|
|
#undef ST_x
|
1999-04-16 03:35:26 +02:00
|
|
|
|
/* FIXME:wip */
|
|
|
|
|
else
|
2005-01-28 04:28:40 +01:00
|
|
|
|
/* Unsupported field, store 0. */
|
|
|
|
|
cb_store_target_endian (cb, p, size, 0);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p += size;
|
|
|
|
|
m = strchr (q, ':');
|
|
|
|
|
if (m)
|
|
|
|
|
++m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p - (char *) ts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Cover functions to the vfprintf callbacks.
|
|
|
|
|
|
|
|
|
|
??? If one thinks of the callbacks as a subsystem onto itself [or part of
|
|
|
|
|
a larger "remote target subsystem"] with a well defined interface, then
|
|
|
|
|
one would think that the subsystem would provide these. However, until
|
|
|
|
|
one is allowed to create such a subsystem (with its own source tree
|
|
|
|
|
independent of any particular user), such a critter can't exist. Thus
|
|
|
|
|
these functions are here for the time being. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
sim_cb_printf (host_callback *p, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start (ap, fmt);
|
|
|
|
|
p->vprintf_filtered (p, fmt, ap);
|
|
|
|
|
va_end (ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
sim_cb_eprintf (host_callback *p, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start (ap, fmt);
|
|
|
|
|
p->evprintf_filtered (p, fmt, ap);
|
|
|
|
|
va_end (ap);
|
|
|
|
|
}
|
2007-10-11 20:40:29 +02:00
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
cb_is_stdin (host_callback *cb, int fd)
|
|
|
|
|
{
|
|
|
|
|
return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-11 20:44:07 +02:00
|
|
|
|
int
|
|
|
|
|
cb_is_stdout (host_callback *cb, int fd)
|
|
|
|
|
{
|
|
|
|
|
return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
cb_is_stderr (host_callback *cb, int fd)
|
|
|
|
|
{
|
|
|
|
|
return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 2;
|
|
|
|
|
}
|