X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Fcommon%2Fcallback.c;h=8f2c76b1e41a15cad10ee29ee13b7cd43fa979ba;hb=1ce22eebea40573551c2db2e7c83951154d14c81;hp=98f791a0630ba2399084434c50c3dd67dfceb50a;hpb=9b51b3ddd35013772ef7121cce3ab7f69f2aefab;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/common/callback.c b/sim/common/callback.c index 98f791a063..8f2c76b1e4 100644 --- a/sim/common/callback.c +++ b/sim/common/callback.c @@ -1,12 +1,12 @@ /* Remote target callback routines. - Copyright 1995, 1996, 1997 Free Software Foundation, Inc. + Copyright 1995-2020 Free Software Foundation, Inc. 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 - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,8 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ /* This file provides a standard way for targets to talk to the host OS level. */ @@ -25,11 +24,7 @@ #include "config.h" #endif #include "ansidecl.h" -#ifdef ANSI_PROTOTYPES #include -#else -#include -#endif #include #ifdef HAVE_STDLIB_H #include @@ -41,119 +36,126 @@ #include #endif #endif +#ifdef HAVE_LIMITS_H +/* For PIPE_BUF. */ +#include +#endif #include #include #include #include #include -#include "callback.h" +#include "gdb/callback.h" #include "targ-vals.h" +/* For xmalloc. */ +#include "libiberty.h" #ifdef HAVE_UNISTD_H #include #endif +#ifndef PIPE_BUF +#define PIPE_BUF 512 +#endif + /* ??? 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 *, ...)); +void sim_cb_printf (host_callback *, const char *, ...); +void sim_cb_eprintf (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)); -static void os_error PARAMS ((host_callback *, const char *, ...)); -static int fdmap PARAMS ((host_callback *, int)); -static int fdbad PARAMS ((host_callback *, int)); -static int wrap PARAMS ((host_callback *, int)); -static int enosys 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; +static int +wrap (host_callback *p, int val) { p->last_errno = errno; return val; } -/* Return a value indicating the system call isn't present. */ - -static int -enosys (p, result) - host_callback *p; - int result; -{ -#ifdef ENOSYS - p->last_errno = ENOSYS; -#else - p->last_errno = EINVAL; -#endif - return result; -} - /* 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; +static int +fdbad (host_callback *p, int fd) { - if (fd < 0 || fd > MAX_CALLBACK_FDS || !p->fdopen[fd]) + if (fd < 0 || fd > MAX_CALLBACK_FDS || p->fd_buddy[fd] < 0) { - p->last_errno = EINVAL; + p->last_errno = EBADF; return -1; } return 0; } -static int -fdmap (p, fd) - host_callback *p; - int fd; +static int +fdmap (host_callback *p, int fd) { return p->fdmap[fd]; } -static int -os_close (p, fd) - host_callback *p; - int fd; +static int +os_close (host_callback *p, int fd) { int result; + int i, next; result = fdbad (p, fd); if (result) return result; - result = wrap (p, close (fdmap (p, fd))); - if(result == 0 && !p->alwaysopen[fd]) - p->fdopen[fd] = 0; + /* 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 + { + 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; return result; } @@ -164,8 +166,7 @@ os_close (p, fd) #if defined(__GO32__) || defined (_MSC_VER) static int -os_poll_quit (p) - host_callback *p; +os_poll_quit (host_callback *p) { #if defined(__GO32__) int kbhit (); @@ -181,7 +182,7 @@ os_poll_quit (p) { return 1; } - else + else { sim_cb_eprintf (p, "CTRL-A to quit, CTRL-B to quit harder\n"); } @@ -189,7 +190,7 @@ os_poll_quit (p) #endif #if defined (_MSC_VER) /* NB - this will not compile! */ - int k = win32pollquit(); + int k = win32pollquit (); if (k == 1) return 1; else if (k == 2) @@ -201,18 +202,15 @@ os_poll_quit (p) #define os_poll_quit 0 #endif /* defined(__GO32__) || defined(_MSC_VER) */ -static int -os_get_errno (p) - host_callback *p; +static int +os_get_errno (host_callback *p) { return cb_host_to_target_errno (p, p->last_errno); } -static int -os_isatty (p, fd) - host_callback *p; - int fd; +static int +os_isatty (host_callback *p, int fd) { int result; @@ -224,32 +222,25 @@ os_isatty (p, fd) return result; } -static int -os_lseek (p, fd, off, way) - host_callback *p; - int fd; - long off; - int way; +static int +os_lseek (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); + result = wrap (p, lseek (fdmap (p, fd), off, way)); return result; } -static int -os_open (p, name, flags) - host_callback *p; - const char *name; - int flags; +static int +os_open (host_callback *p, const char *name, int flags) { int i; for (i = 0; i < MAX_CALLBACK_FDS; i++) { - if (!p->fdopen[i]) + if (p->fd_buddy[i] < 0) { int f = open (name, cb_target_to_host_open (p, flags), 0644); if (f < 0) @@ -257,7 +248,7 @@ os_open (p, name, flags) p->last_errno = errno; return f; } - p->fdopen[i] = 1; + p->fd_buddy[i] = i; p->fdmap[i] = f; return i; } @@ -266,37 +257,67 @@ os_open (p, name, flags) return -1; } -static int -os_read (p, fd, buf, len) - host_callback *p; - int fd; - char *buf; - int len; +static int +os_read (host_callback *p, int fd, char *buf, int len) { int result; result = fdbad (p, fd); if (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)); return result; } -static int -os_read_stdin (p, buf, len) - host_callback *p; - char *buf; - int len; +static int +os_read_stdin (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; +static int +os_write (host_callback *p, int fd, const char *buf, int len) { int result; int real_fd; @@ -304,6 +325,49 @@ os_write (p, fd, buf, len) result = fdbad (p, fd); if (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); switch (real_fd) { @@ -320,109 +384,249 @@ os_write (p, fd, buf, len) return result; } -static int -os_write_stdout (p, buf, len) - host_callback *p; - const char *buf; - int len; +static int +os_write_stdout (host_callback *p ATTRIBUTE_UNUSED, const char *buf, int len) { - return fwrite(buf, 1, len, stdout); + return fwrite (buf, 1, len, stdout); } static void -os_flush_stdout (p) - host_callback *p; +os_flush_stdout (host_callback *p ATTRIBUTE_UNUSED) { fflush (stdout); } -static int -os_write_stderr (p, buf, len) - host_callback *p; - const char *buf; - int len; +static int +os_write_stderr (host_callback *p ATTRIBUTE_UNUSED, const char *buf, int len) { - return fwrite(buf, 1, len, stderr); + return fwrite (buf, 1, len, stderr); } static void -os_flush_stderr (p) - host_callback *p; +os_flush_stderr (host_callback *p ATTRIBUTE_UNUSED) { fflush (stderr); } -static int -os_rename (p, f1, f2) - host_callback *p; - const char *f1; - const char *f2; +static int +os_rename (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; +os_system (host_callback *p, const char *s) { return wrap (p, system (s)); } -static long -os_time (p, t) - host_callback *p; - long *t; +static long +os_time (host_callback *p, long *t) { return wrap (p, time (t)); } -static int -os_unlink (p, f1) - host_callback *p; - const char *f1; +static int +os_unlink (host_callback *p, const char *f1) { return wrap (p, unlink (f1)); } static int -os_stat (p, file, buf) - host_callback *p; - const char *file; - PTR buf; +os_stat (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; - PTR buf; +os_fstat (host_callback *p, int fd, struct stat *buf) { - return wrap (p, fstat (fd, buf)); + if (fdbad (p, fd)) + return -1; + + if (p->ispipe[fd]) + { +#if defined (HAVE_STRUCT_STAT_ST_ATIME) || defined (HAVE_STRUCT_STAT_ST_CTIME) || defined (HAVE_STRUCT_STAT_ST_MTIME) + time_t t = (*p->time) (p, NULL); +#endif + + /* 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. + 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)); } static int -os_shutdown (p) - host_callback *p; +os_lstat (host_callback *p, const char *file, struct stat *buf) +{ + /* NOTE: hpn/2004-12-12: Same issue here as with os_fstat. */ +#ifdef HAVE_LSTAT + return wrap (p, lstat (file, buf)); +#else + return wrap (p, stat (file, buf)); +#endif +} + +static int +os_ftruncate (host_callback *p, int fd, long len) +{ + int result; + + result = fdbad (p, fd); + if (p->ispipe[fd]) + { + p->last_errno = EINVAL; + return -1; + } + if (result) + return result; +#ifdef HAVE_FTRUNCATE + result = wrap (p, ftruncate (fdmap (p, fd), len)); +#else + p->last_errno = EINVAL; + result = -1; +#endif + return result; +} + +static int +os_truncate (host_callback *p, const char *file, long len) +{ +#ifdef HAVE_TRUNCATE + return wrap (p, truncate (file, len)); +#else + p->last_errno = EINVAL; + return -1; +#endif +} + +static int +os_pipe (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 (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 (host_callback *p, int reader, int writer) +{ +} + +static int +os_shutdown (host_callback *p) +{ + int i, next, j; for (i = 0; i < MAX_CALLBACK_FDS; i++) { - if (p->fdopen[i] && !p->alwaysopen[i]) { + 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]; + 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) + { + p->fd_buddy[i] = -1; + do_close = 0; + break; + } + } + while (j != i); + if (do_close) close (p->fdmap[i]); - p->fdopen[i] = 0; - } } return 1; } static int -os_init (p) - host_callback *p; +os_init (host_callback *p) { int i; @@ -430,9 +634,10 @@ os_init (p) for (i = 0; i < 3; i++) { p->fdmap[i] = i; - p->fdopen[i] = 1; - p->alwaysopen[i] = 1; + p->fd_buddy[i] = i - 1; } + p->fd_buddy[0] = MAX_CALLBACK_FDS; + p->fd_buddy[MAX_CALLBACK_FDS] = 2; p->syscall_map = cb_init_syscall_map; p->errno_map = cb_init_errno_map; @@ -441,27 +646,14 @@ os_init (p) return 1; } -/* DEPRECIATED */ +/* DEPRECATED */ /* VARARGS */ static void -#ifdef ANSI_PROTOTYPES -os_printf_filtered (host_callback *p, const char *format, ...) -#else -os_printf_filtered (p, va_alist) - host_callback *p; - va_dcl -#endif +os_printf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, format); -#else - char *format; - - va_start (args); - format = va_arg (args, char *); -#endif vfprintf (stdout, format, args); va_end (args); @@ -469,51 +661,27 @@ os_printf_filtered (p, va_alist) /* VARARGS */ static void -#ifdef ANSI_PROTOTYPES -os_vprintf_filtered (host_callback *p, const char *format, va_list args) -#else -os_vprintf_filtered (p, format, args) - host_callback *p; - const char *format; - va_list args; -#endif +os_vprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args) { vprintf (format, args); } /* VARARGS */ static void -#ifdef ANSI_PROTOTYPES -os_evprintf_filtered (host_callback *p, const char *format, va_list args) -#else -os_evprintf_filtered (p, format, args) - host_callback *p; - const char *format; - va_list args; -#endif +os_evprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args) { vfprintf (stderr, format, args); } /* VARARGS */ -static void -#ifdef ANSI_PROTOTYPES -os_error (host_callback *p, const char *format, ...) -#else -os_error (p, va_alist) - host_callback *p; - va_dcl +#ifdef __GNUC__ +__attribute__ ((__noreturn__)) #endif +static void +os_error (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...) { va_list args; -#ifdef ANSI_PROTOTYPES va_start (args, format); -#else - char *format; - - va_start (args); - format = va_arg (args, char *); -#endif vfprintf (stderr, format, args); fprintf (stderr, "\n"); @@ -543,6 +711,14 @@ host_callback default_callback = os_stat, os_fstat, + os_lstat, + + os_ftruncate, + os_truncate, + + os_pipe, + os_pipe_empty, + os_pipe_nonempty, os_poll_quit, @@ -558,15 +734,20 @@ host_callback default_callback = 0, /* last errno */ { 0, }, /* fdmap */ - { 0, }, /* fdopen */ - { 0, }, /* alwaysopen */ + { -1, }, /* fd_buddy */ + { 0, }, /* ispipe */ + { { 0, 0 }, }, /* pipe_buffer */ 0, /* syscall_map */ 0, /* errno_map */ 0, /* open_map */ 0, /* signal_map */ 0, /* stat_map */ - + + /* Defaults expected to be overridden at initialization, where needed. */ + BFD_ENDIAN_UNKNOWN, /* target_endian */ + 4, /* target_sizeof_int */ + HOST_CALLBACK_MAGIC, }; @@ -579,9 +760,7 @@ host_callback default_callback = 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_read_target_syscall_maps (host_callback *cb, const char *file) { CB_TARGET_DEFS_MAP *syscall_map, *errno_map, *open_map, *signal_map; const char *stat_map; @@ -616,22 +795,43 @@ cb_read_target_syscall_maps (cb, file) return CB_RC_OK; } +/* General utility functions to search a map for a value. */ + +static const CB_TARGET_DEFS_MAP * +cb_target_map_entry (const CB_TARGET_DEFS_MAP map[], int target_val) +{ + const CB_TARGET_DEFS_MAP *m; + + for (m = &map[0]; m->target_val != -1; ++m) + if (m->target_val == target_val) + return m; + + return NULL; +} + +static const CB_TARGET_DEFS_MAP * +cb_host_map_entry (const CB_TARGET_DEFS_MAP map[], int host_val) +{ + const CB_TARGET_DEFS_MAP *m; + + for (m = &map[0]; m->host_val != -1; ++m) + if (m->host_val == host_val) + return m; + + return NULL; +} + /* 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_to_host_syscall (host_callback *cb, int target_val) { - CB_TARGET_DEFS_MAP *m; + const CB_TARGET_DEFS_MAP *m = + cb_target_map_entry (cb->syscall_map, target_val); - for (m = &cb->syscall_map[0]; m->target_val != -1; ++m) - if (m->target_val == target_val) - return m->host_val; - - return -1; + return m ? m->host_val : -1; } /* FIXME: sort tables if large. @@ -641,20 +841,14 @@ cb_target_to_host_syscall (cb, target_val) /* 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_host_to_target_errno (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; + const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->errno_map, host_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; + return m ? m->target_val : 0; } /* Given a set of target bitmasks for the open system call, @@ -663,9 +857,7 @@ cb_host_to_target_errno (cb, host_val) to machine generate this function. */ int -cb_target_to_host_open (cb, target_val) - host_callback *cb; - int target_val; +cb_target_to_host_open (host_callback *cb, int target_val) { int host_val = 0; CB_TARGET_DEFS_MAP *m; @@ -698,17 +890,15 @@ cb_target_to_host_open (cb, target_val) return host_val; } -/* Utility for cb_host_to_target_stat to store values in the target's - stat struct. */ +/* Utility for e.g. cb_host_to_target_stat to store values in the target's + stat struct. -static void -store (p, size, val, big_p) - char *p; - int size; - long val; /* ??? must be as big as target word size */ - int big_p; + ??? The "val" must be as big as target word size. */ + +void +cb_store_target_endian (host_callback *cb, char *p, int size, long val) { - if (big_p) + if (cb->target_endian == BFD_ENDIAN_BIG) { p += size; while (size-- > 0) @@ -728,19 +918,21 @@ store (p, size, val, big_p) } /* 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. - BIG_P is non-zero if the target is big-endian. - The result is the size of the target's stat struct. */ + The result is the size of the target's stat struct, + or zero if an error occurred during the translation. */ int -cb_host_to_target_stat (cb, hs, ts, big_p) - host_callback *cb; - const struct stat *hs; - PTR ts; - int big_p; +cb_host_to_target_stat (host_callback *cb, const struct stat *hs, PTR ts) { const char *m = cb->stat_map; - char *p = ts; + char *p; + + if (hs == NULL) + ts = NULL; + p = ts; while (m) { @@ -751,28 +943,78 @@ cb_host_to_target_stat (cb, hs, ts, big_p) if (q == NULL) { /* FIXME: print error message */ - return; + return 0; } size = atoi (q + 1); if (size == 0) { /* FIXME: print error message */ - return; + return 0; } - if (strncmp (m, "st_dev", q - m) == 0) - store (p, size, hs->st_dev, big_p); - else if (strncmp (m, "st_ino", q - m) == 0) - store (p, size, hs->st_ino, big_p); - /* FIXME:wip */ - else - store (p, size, 0, big_p); /* unsupported field, store 0 */ + if (hs != NULL) + { + if (0) + ; + /* 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) \ + cb_store_target_endian (cb, p, size, hs->FLD) + +#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 + /* FIXME:wip */ + else + /* Unsupported field, store 0. */ + cb_store_target_endian (cb, p, size, 0); + } p += size; m = strchr (q, ':'); if (m) ++m; } + + return p - (char *) ts; } /* Cover functions to the vfprintf callbacks. @@ -803,3 +1045,72 @@ sim_cb_eprintf (host_callback *p, const char *fmt, ...) p->evprintf_filtered (p, fmt, ap); va_end (ap); } + +int +cb_is_stdin (host_callback *cb, int fd) +{ + return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 0; +} + +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; +} + +const char * +cb_host_str_syscall (host_callback *cb, int host_val) +{ + const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->syscall_map, host_val); + + return m ? m->name : NULL; +} + +const char * +cb_host_str_errno (host_callback *cb, int host_val) +{ + const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->errno_map, host_val); + + return m ? m->name : NULL; +} + +const char * +cb_host_str_signal (host_callback *cb, int host_val) +{ + const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->signal_map, host_val); + + return m ? m->name : NULL; +} + +const char * +cb_target_str_syscall (host_callback *cb, int target_val) +{ + const CB_TARGET_DEFS_MAP *m = + cb_target_map_entry (cb->syscall_map, target_val); + + return m ? m->name : NULL; +} + +const char * +cb_target_str_errno (host_callback *cb, int target_val) +{ + const CB_TARGET_DEFS_MAP *m = + cb_target_map_entry (cb->errno_map, target_val); + + return m ? m->name : NULL; +} + +const char * +cb_target_str_signal (host_callback *cb, int target_val) +{ + const CB_TARGET_DEFS_MAP *m = + cb_target_map_entry (cb->signal_map, target_val); + + return m ? m->name : NULL; +}