xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/callback.c (revision 889f3bb010ad20d396fb291b89f202288dac2c87)
198b9484cSchristos /* Remote target callback routines.
2*889f3bb0Schristos    Copyright 1995-2024 Free Software Foundation, Inc.
398b9484cSchristos    Contributed by Cygnus Solutions.
498b9484cSchristos 
598b9484cSchristos    This file is part of GDB.
698b9484cSchristos 
798b9484cSchristos    This program is free software; you can redistribute it and/or modify
898b9484cSchristos    it under the terms of the GNU General Public License as published by
998b9484cSchristos    the Free Software Foundation; either version 3 of the License, or
1098b9484cSchristos    (at your option) any later version.
1198b9484cSchristos 
1298b9484cSchristos    This program is distributed in the hope that it will be useful,
1398b9484cSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1498b9484cSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1598b9484cSchristos    GNU General Public License for more details.
1698b9484cSchristos 
1798b9484cSchristos    You should have received a copy of the GNU General Public License
1898b9484cSchristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1998b9484cSchristos 
2098b9484cSchristos /* This file provides a standard way for targets to talk to the host OS
2198b9484cSchristos    level.  */
2298b9484cSchristos 
23924795e6Schristos /* This must come before any other includes.  */
24924795e6Schristos #include "defs.h"
25924795e6Schristos 
2698b9484cSchristos #include <errno.h>
2798b9484cSchristos #include <fcntl.h>
28924795e6Schristos /* For PIPE_BUF.  */
29924795e6Schristos #include <limits.h>
30924795e6Schristos #include <signal.h>
31924795e6Schristos #include <stdarg.h>
32924795e6Schristos #include <stdint.h>
33924795e6Schristos #include <stdio.h>
34924795e6Schristos #include <stdlib.h>
35924795e6Schristos #include <string.h>
3698b9484cSchristos #include <time.h>
3798b9484cSchristos #include <unistd.h>
38924795e6Schristos #include <sys/stat.h>
39924795e6Schristos #include <sys/types.h>
40924795e6Schristos 
41924795e6Schristos #include "ansidecl.h"
42924795e6Schristos /* For xmalloc.  */
43924795e6Schristos #include "libiberty.h"
44924795e6Schristos 
45924795e6Schristos #include "sim/callback.h"
4698b9484cSchristos 
4798b9484cSchristos #ifndef PIPE_BUF
4898b9484cSchristos #define PIPE_BUF 512
4998b9484cSchristos #endif
5098b9484cSchristos 
5198b9484cSchristos extern CB_TARGET_DEFS_MAP cb_init_syscall_map[];
5298b9484cSchristos extern CB_TARGET_DEFS_MAP cb_init_errno_map[];
53924795e6Schristos extern CB_TARGET_DEFS_MAP cb_init_signal_map[];
5498b9484cSchristos extern CB_TARGET_DEFS_MAP cb_init_open_map[];
5598b9484cSchristos 
5698b9484cSchristos /* Make sure the FD provided is ok.  If not, return non-zero
5798b9484cSchristos    and set errno. */
5898b9484cSchristos 
5998b9484cSchristos static int
609d1da10bSchristos fdbad (host_callback *p, int fd)
6198b9484cSchristos {
6298b9484cSchristos   if (fd < 0 || fd > MAX_CALLBACK_FDS || p->fd_buddy[fd] < 0)
6398b9484cSchristos     {
6498b9484cSchristos       p->last_errno = EBADF;
6598b9484cSchristos       return -1;
6698b9484cSchristos     }
6798b9484cSchristos   return 0;
6898b9484cSchristos }
6998b9484cSchristos 
7098b9484cSchristos static int
719d1da10bSchristos fdmap (host_callback *p, int fd)
7298b9484cSchristos {
7398b9484cSchristos   return p->fdmap[fd];
7498b9484cSchristos }
7598b9484cSchristos 
7698b9484cSchristos static int
779d1da10bSchristos os_close (host_callback *p, int fd)
7898b9484cSchristos {
7998b9484cSchristos   int result;
8098b9484cSchristos   int i, next;
8198b9484cSchristos 
8298b9484cSchristos   result = fdbad (p, fd);
8398b9484cSchristos   if (result)
8498b9484cSchristos     return result;
8598b9484cSchristos   /* If this file descripter has one or more buddies (originals /
8698b9484cSchristos      duplicates from a dup), just remove it from the circular list.  */
8798b9484cSchristos   for (i = fd; (next = p->fd_buddy[i]) != fd; )
8898b9484cSchristos     i = next;
8998b9484cSchristos   if (fd != i)
9098b9484cSchristos     p->fd_buddy[i] = p->fd_buddy[fd];
9198b9484cSchristos   else
9298b9484cSchristos     {
9398b9484cSchristos       if (p->ispipe[fd])
9498b9484cSchristos 	{
9598b9484cSchristos 	  int other = p->ispipe[fd];
9698b9484cSchristos 	  int reader, writer;
9798b9484cSchristos 
9898b9484cSchristos 	  if (other > 0)
9998b9484cSchristos 	    {
10098b9484cSchristos 	      /* Closing the read side.  */
10198b9484cSchristos 	      reader = fd;
10298b9484cSchristos 	      writer = other;
10398b9484cSchristos 	    }
10498b9484cSchristos 	  else
10598b9484cSchristos 	    {
10698b9484cSchristos 	      /* Closing the write side.  */
10798b9484cSchristos 	      writer = fd;
10898b9484cSchristos 	      reader = -other;
10998b9484cSchristos 	    }
11098b9484cSchristos 
11198b9484cSchristos 	  /* If there was data in the buffer, make a last "now empty"
11298b9484cSchristos 	     call, then deallocate data.  */
11398b9484cSchristos 	  if (p->pipe_buffer[writer].buffer != NULL)
11498b9484cSchristos 	    {
11598b9484cSchristos 	      (*p->pipe_empty) (p, reader, writer);
11698b9484cSchristos 	      free (p->pipe_buffer[writer].buffer);
11798b9484cSchristos 	      p->pipe_buffer[writer].buffer = NULL;
11898b9484cSchristos 	    }
11998b9484cSchristos 
12098b9484cSchristos 	  /* Clear pipe data for this side.  */
12198b9484cSchristos 	  p->pipe_buffer[fd].size = 0;
12298b9484cSchristos 	  p->ispipe[fd] = 0;
12398b9484cSchristos 
12498b9484cSchristos 	  /* If this was the first close, mark the other side as the
12598b9484cSchristos 	     only remaining side.  */
12698b9484cSchristos 	  if (fd != abs (other))
12798b9484cSchristos 	    p->ispipe[abs (other)] = -other;
12898b9484cSchristos 	  p->fd_buddy[fd] = -1;
12998b9484cSchristos 	  return 0;
13098b9484cSchristos 	}
13198b9484cSchristos 
132924795e6Schristos       result = close (fdmap (p, fd));
133924795e6Schristos       p->last_errno = errno;
13498b9484cSchristos     }
13598b9484cSchristos   p->fd_buddy[fd] = -1;
13698b9484cSchristos 
13798b9484cSchristos   return result;
13898b9484cSchristos }
13998b9484cSchristos 
14098b9484cSchristos 
14198b9484cSchristos /* taken from gdb/util.c:notice_quit() - should be in a library */
14298b9484cSchristos 
14398b9484cSchristos 
144924795e6Schristos #if defined(_MSC_VER)
14598b9484cSchristos static int
1469d1da10bSchristos os_poll_quit (host_callback *p)
14798b9484cSchristos {
14898b9484cSchristos   /* NB - this will not compile! */
14998b9484cSchristos   int k = win32pollquit ();
15098b9484cSchristos   if (k == 1)
15198b9484cSchristos     return 1;
15298b9484cSchristos   else if (k == 2)
15398b9484cSchristos     return 1;
15498b9484cSchristos   return 0;
15598b9484cSchristos }
15698b9484cSchristos #else
15798b9484cSchristos #define os_poll_quit 0
158924795e6Schristos #endif /* defined(_MSC_VER) */
15998b9484cSchristos 
16098b9484cSchristos static int
1619d1da10bSchristos os_get_errno (host_callback *p)
16298b9484cSchristos {
16398b9484cSchristos   return cb_host_to_target_errno (p, p->last_errno);
16498b9484cSchristos }
16598b9484cSchristos 
16698b9484cSchristos 
16798b9484cSchristos static int
1689d1da10bSchristos os_isatty (host_callback *p, int fd)
16998b9484cSchristos {
17098b9484cSchristos   int result;
17198b9484cSchristos 
17298b9484cSchristos   result = fdbad (p, fd);
17398b9484cSchristos   if (result)
17498b9484cSchristos     return result;
17598b9484cSchristos 
176924795e6Schristos   result = isatty (fdmap (p, fd));
177924795e6Schristos   p->last_errno = errno;
17898b9484cSchristos   return result;
17998b9484cSchristos }
18098b9484cSchristos 
181924795e6Schristos static int64_t
182924795e6Schristos os_lseek (host_callback *p, int fd, int64_t off, int way)
18398b9484cSchristos {
184924795e6Schristos   int64_t result;
18598b9484cSchristos 
18698b9484cSchristos   result = fdbad (p, fd);
18798b9484cSchristos   if (result)
18898b9484cSchristos     return result;
189924795e6Schristos 
190924795e6Schristos   result = lseek (fdmap (p, fd), off, way);
191924795e6Schristos   p->last_errno = errno;
19298b9484cSchristos   return result;
19398b9484cSchristos }
19498b9484cSchristos 
19598b9484cSchristos static int
1969d1da10bSchristos os_open (host_callback *p, const char *name, int flags)
19798b9484cSchristos {
19898b9484cSchristos   int i;
19998b9484cSchristos   for (i = 0; i < MAX_CALLBACK_FDS; i++)
20098b9484cSchristos     {
20198b9484cSchristos       if (p->fd_buddy[i] < 0)
20298b9484cSchristos 	{
20398b9484cSchristos 	  int f = open (name, cb_target_to_host_open (p, flags), 0644);
20498b9484cSchristos 	  if (f < 0)
20598b9484cSchristos 	    {
20698b9484cSchristos 	      p->last_errno = errno;
20798b9484cSchristos 	      return f;
20898b9484cSchristos 	    }
20998b9484cSchristos 	  p->fd_buddy[i] = i;
21098b9484cSchristos 	  p->fdmap[i] = f;
21198b9484cSchristos 	  return i;
21298b9484cSchristos 	}
21398b9484cSchristos     }
21498b9484cSchristos   p->last_errno = EMFILE;
21598b9484cSchristos   return -1;
21698b9484cSchristos }
21798b9484cSchristos 
21898b9484cSchristos static int
2199d1da10bSchristos os_read (host_callback *p, int fd, char *buf, int len)
22098b9484cSchristos {
22198b9484cSchristos   int result;
22298b9484cSchristos 
22398b9484cSchristos   result = fdbad (p, fd);
22498b9484cSchristos   if (result)
22598b9484cSchristos     return result;
22698b9484cSchristos   if (p->ispipe[fd])
22798b9484cSchristos     {
22898b9484cSchristos       int writer = p->ispipe[fd];
22998b9484cSchristos 
23098b9484cSchristos       /* Can't read from the write-end.  */
23198b9484cSchristos       if (writer < 0)
23298b9484cSchristos 	{
23398b9484cSchristos 	  p->last_errno = EBADF;
23498b9484cSchristos 	  return -1;
23598b9484cSchristos 	}
23698b9484cSchristos 
23798b9484cSchristos       /* Nothing to read if nothing is written.  */
23898b9484cSchristos       if (p->pipe_buffer[writer].size == 0)
23998b9484cSchristos 	return 0;
24098b9484cSchristos 
24198b9484cSchristos       /* Truncate read request size to buffer size minus what's already
24298b9484cSchristos          read.  */
24398b9484cSchristos       if (len > p->pipe_buffer[writer].size - p->pipe_buffer[fd].size)
24498b9484cSchristos 	len = p->pipe_buffer[writer].size - p->pipe_buffer[fd].size;
24598b9484cSchristos 
24698b9484cSchristos       memcpy (buf, p->pipe_buffer[writer].buffer + p->pipe_buffer[fd].size,
24798b9484cSchristos 	      len);
24898b9484cSchristos 
24998b9484cSchristos       /* Account for what we just read.  */
25098b9484cSchristos       p->pipe_buffer[fd].size += len;
25198b9484cSchristos 
25298b9484cSchristos       /* If we've read everything, empty and deallocate the buffer and
25398b9484cSchristos 	 signal buffer-empty to client.  (This isn't expected to be a
25498b9484cSchristos 	 hot path in the simulator, so we don't hold on to the buffer.)  */
25598b9484cSchristos       if (p->pipe_buffer[fd].size == p->pipe_buffer[writer].size)
25698b9484cSchristos 	{
25798b9484cSchristos 	  free (p->pipe_buffer[writer].buffer);
25898b9484cSchristos 	  p->pipe_buffer[writer].buffer = NULL;
25998b9484cSchristos 	  p->pipe_buffer[fd].size = 0;
26098b9484cSchristos 	  p->pipe_buffer[writer].size = 0;
26198b9484cSchristos 	  (*p->pipe_empty) (p, fd, writer);
26298b9484cSchristos 	}
26398b9484cSchristos 
26498b9484cSchristos       return len;
26598b9484cSchristos     }
26698b9484cSchristos 
267924795e6Schristos   result = read (fdmap (p, fd), buf, len);
268924795e6Schristos   p->last_errno = errno;
26998b9484cSchristos   return result;
27098b9484cSchristos }
27198b9484cSchristos 
27298b9484cSchristos static int
2739d1da10bSchristos os_read_stdin (host_callback *p, char *buf, int len)
27498b9484cSchristos {
275924795e6Schristos   int result;
276924795e6Schristos 
277924795e6Schristos   result = read (0, buf, len);
278924795e6Schristos   p->last_errno = errno;
279924795e6Schristos   return result;
28098b9484cSchristos }
28198b9484cSchristos 
28298b9484cSchristos static int
2839d1da10bSchristos os_write (host_callback *p, int fd, const char *buf, int len)
28498b9484cSchristos {
28598b9484cSchristos   int result;
28698b9484cSchristos   int real_fd;
28798b9484cSchristos 
28898b9484cSchristos   result = fdbad (p, fd);
28998b9484cSchristos   if (result)
29098b9484cSchristos     return result;
29198b9484cSchristos 
29298b9484cSchristos   if (p->ispipe[fd])
29398b9484cSchristos     {
29498b9484cSchristos       int reader = -p->ispipe[fd];
29598b9484cSchristos 
29698b9484cSchristos       /* Can't write to the read-end.  */
29798b9484cSchristos       if (reader < 0)
29898b9484cSchristos 	{
29998b9484cSchristos 	  p->last_errno = EBADF;
30098b9484cSchristos 	  return -1;
30198b9484cSchristos 	}
30298b9484cSchristos 
30398b9484cSchristos       /* Can't write to pipe with closed read end.
30498b9484cSchristos 	 FIXME: We should send a SIGPIPE.  */
30598b9484cSchristos       if (reader == fd)
30698b9484cSchristos 	{
30798b9484cSchristos 	  p->last_errno = EPIPE;
30898b9484cSchristos 	  return -1;
30998b9484cSchristos 	}
31098b9484cSchristos 
31198b9484cSchristos       /* As a sanity-check, we bail out it the buffered contents is much
31298b9484cSchristos 	 larger than the size of the buffer on the host.  We don't want
31398b9484cSchristos 	 to run out of memory in the simulator due to a target program
31498b9484cSchristos 	 bug if we can help it.  Unfortunately, regarding the value that
31598b9484cSchristos 	 reaches the simulated program, it's no use returning *less*
31698b9484cSchristos 	 than the requested amount, because cb_syscall loops calling
31798b9484cSchristos 	 this function until the whole amount is done.  */
31898b9484cSchristos       if (p->pipe_buffer[fd].size + len > 10 * PIPE_BUF)
31998b9484cSchristos 	{
32098b9484cSchristos 	  p->last_errno = EFBIG;
32198b9484cSchristos 	  return -1;
32298b9484cSchristos 	}
32398b9484cSchristos 
32498b9484cSchristos       p->pipe_buffer[fd].buffer
32598b9484cSchristos 	= xrealloc (p->pipe_buffer[fd].buffer, p->pipe_buffer[fd].size + len);
32698b9484cSchristos       memcpy (p->pipe_buffer[fd].buffer + p->pipe_buffer[fd].size,
32798b9484cSchristos 	      buf, len);
32898b9484cSchristos       p->pipe_buffer[fd].size += len;
32998b9484cSchristos 
33098b9484cSchristos       (*p->pipe_nonempty) (p, reader, fd);
33198b9484cSchristos       return len;
33298b9484cSchristos     }
33398b9484cSchristos 
33498b9484cSchristos   real_fd = fdmap (p, fd);
33598b9484cSchristos   switch (real_fd)
33698b9484cSchristos     {
33798b9484cSchristos     default:
338924795e6Schristos       result = write (real_fd, buf, len);
339924795e6Schristos       p->last_errno = errno;
34098b9484cSchristos       break;
34198b9484cSchristos     case 1:
34298b9484cSchristos       result = p->write_stdout (p, buf, len);
34398b9484cSchristos       break;
34498b9484cSchristos     case 2:
34598b9484cSchristos       result = p->write_stderr (p, buf, len);
34698b9484cSchristos       break;
34798b9484cSchristos     }
34898b9484cSchristos   return result;
34998b9484cSchristos }
35098b9484cSchristos 
35198b9484cSchristos static int
3529d1da10bSchristos os_write_stdout (host_callback *p ATTRIBUTE_UNUSED, const char *buf, int len)
35398b9484cSchristos {
35498b9484cSchristos   return fwrite (buf, 1, len, stdout);
35598b9484cSchristos }
35698b9484cSchristos 
35798b9484cSchristos static void
3589d1da10bSchristos os_flush_stdout (host_callback *p ATTRIBUTE_UNUSED)
35998b9484cSchristos {
36098b9484cSchristos   fflush (stdout);
36198b9484cSchristos }
36298b9484cSchristos 
36398b9484cSchristos static int
3649d1da10bSchristos os_write_stderr (host_callback *p ATTRIBUTE_UNUSED, const char *buf, int len)
36598b9484cSchristos {
36698b9484cSchristos   return fwrite (buf, 1, len, stderr);
36798b9484cSchristos }
36898b9484cSchristos 
36998b9484cSchristos static void
3709d1da10bSchristos os_flush_stderr (host_callback *p ATTRIBUTE_UNUSED)
37198b9484cSchristos {
37298b9484cSchristos   fflush (stderr);
37398b9484cSchristos }
37498b9484cSchristos 
37598b9484cSchristos static int
3769d1da10bSchristos os_rename (host_callback *p, const char *f1, const char *f2)
37798b9484cSchristos {
378924795e6Schristos   int result;
379924795e6Schristos 
380924795e6Schristos   result = rename (f1, f2);
381924795e6Schristos   p->last_errno = errno;
382924795e6Schristos   return result;
38398b9484cSchristos }
38498b9484cSchristos 
38598b9484cSchristos 
38698b9484cSchristos static int
3879d1da10bSchristos os_system (host_callback *p, const char *s)
38898b9484cSchristos {
389924795e6Schristos   int result;
390924795e6Schristos 
391924795e6Schristos   result = system (s);
392924795e6Schristos   p->last_errno = errno;
393924795e6Schristos   return result;
39498b9484cSchristos }
39598b9484cSchristos 
396924795e6Schristos static int64_t
397924795e6Schristos os_time (host_callback *p)
39898b9484cSchristos {
399924795e6Schristos   int64_t result;
400acd0381cSchristos 
401924795e6Schristos   result = time (NULL);
402924795e6Schristos   p->last_errno = errno;
403924795e6Schristos   return result;
40498b9484cSchristos }
40598b9484cSchristos 
40698b9484cSchristos 
40798b9484cSchristos static int
4089d1da10bSchristos os_unlink (host_callback *p, const char *f1)
40998b9484cSchristos {
410924795e6Schristos   int result;
411924795e6Schristos 
412924795e6Schristos   result = unlink (f1);
413924795e6Schristos   p->last_errno = errno;
414924795e6Schristos   return result;
41598b9484cSchristos }
41698b9484cSchristos 
41798b9484cSchristos static int
4189d1da10bSchristos os_stat (host_callback *p, const char *file, struct stat *buf)
41998b9484cSchristos {
420924795e6Schristos   int result;
421924795e6Schristos 
42298b9484cSchristos   /* ??? There is an issue of when to translate to the target layout.
42398b9484cSchristos      One could do that inside this function, or one could have the
42498b9484cSchristos      caller do it.  It's more flexible to let the caller do it, though
42598b9484cSchristos      I'm not sure the flexibility will ever be useful.  */
426924795e6Schristos   result = stat (file, buf);
427924795e6Schristos   p->last_errno = errno;
428924795e6Schristos   return result;
42998b9484cSchristos }
43098b9484cSchristos 
43198b9484cSchristos static int
4329d1da10bSchristos os_fstat (host_callback *p, int fd, struct stat *buf)
43398b9484cSchristos {
434924795e6Schristos   int result;
435924795e6Schristos 
43698b9484cSchristos   if (fdbad (p, fd))
43798b9484cSchristos     return -1;
43898b9484cSchristos 
43998b9484cSchristos   if (p->ispipe[fd])
44098b9484cSchristos     {
44198b9484cSchristos #if defined (HAVE_STRUCT_STAT_ST_ATIME) || defined (HAVE_STRUCT_STAT_ST_CTIME) || defined (HAVE_STRUCT_STAT_ST_MTIME)
442924795e6Schristos       time_t t = (*p->time) (p);
44398b9484cSchristos #endif
44498b9484cSchristos 
44598b9484cSchristos       /* We have to fake the struct stat contents, since the pipe is
44698b9484cSchristos 	 made up in the simulator.  */
44798b9484cSchristos       memset (buf, 0, sizeof (*buf));
44898b9484cSchristos 
44998b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_MODE
45098b9484cSchristos       buf->st_mode = S_IFIFO;
45198b9484cSchristos #endif
45298b9484cSchristos 
45398b9484cSchristos       /* If more accurate tracking than current-time is needed (for
45498b9484cSchristos 	 example, on GNU/Linux we get accurate numbers), the p->time
45598b9484cSchristos 	 callback (which may be something other than os_time) should
45698b9484cSchristos 	 happen for each read and write, and we'd need to keep track of
45798b9484cSchristos 	 atime, ctime and mtime.  */
45898b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_ATIME
45998b9484cSchristos       buf->st_atime = t;
46098b9484cSchristos #endif
46198b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_CTIME
46298b9484cSchristos       buf->st_ctime = t;
46398b9484cSchristos #endif
46498b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_MTIME
46598b9484cSchristos       buf->st_mtime = t;
46698b9484cSchristos #endif
46798b9484cSchristos       return 0;
46898b9484cSchristos     }
46998b9484cSchristos 
47098b9484cSchristos   /* ??? There is an issue of when to translate to the target layout.
47198b9484cSchristos      One could do that inside this function, or one could have the
47298b9484cSchristos      caller do it.  It's more flexible to let the caller do it, though
47398b9484cSchristos      I'm not sure the flexibility will ever be useful.  */
474924795e6Schristos   result = fstat (fdmap (p, fd), buf);
475924795e6Schristos   p->last_errno = errno;
476924795e6Schristos   return result;
47798b9484cSchristos }
47898b9484cSchristos 
47998b9484cSchristos static int
4809d1da10bSchristos os_lstat (host_callback *p, const char *file, struct stat *buf)
48198b9484cSchristos {
482924795e6Schristos   int result;
483924795e6Schristos 
48498b9484cSchristos   /* NOTE: hpn/2004-12-12: Same issue here as with os_fstat.  */
48598b9484cSchristos #ifdef HAVE_LSTAT
486924795e6Schristos   result = lstat (file, buf);
48798b9484cSchristos #else
488924795e6Schristos   result = stat (file, buf);
48998b9484cSchristos #endif
490924795e6Schristos   p->last_errno = errno;
491924795e6Schristos   return result;
49298b9484cSchristos }
49398b9484cSchristos 
49498b9484cSchristos static int
495924795e6Schristos os_ftruncate (host_callback *p, int fd, int64_t len)
49698b9484cSchristos {
49798b9484cSchristos   int result;
49898b9484cSchristos 
49998b9484cSchristos   result = fdbad (p, fd);
50098b9484cSchristos   if (p->ispipe[fd])
50198b9484cSchristos     {
50298b9484cSchristos       p->last_errno = EINVAL;
50398b9484cSchristos       return -1;
50498b9484cSchristos     }
50598b9484cSchristos   if (result)
50698b9484cSchristos     return result;
50798b9484cSchristos #ifdef HAVE_FTRUNCATE
508924795e6Schristos   result = ftruncate (fdmap (p, fd), len);
509924795e6Schristos   p->last_errno = errno;
51098b9484cSchristos #else
51198b9484cSchristos   p->last_errno = EINVAL;
51298b9484cSchristos   result = -1;
51398b9484cSchristos #endif
51498b9484cSchristos   return result;
51598b9484cSchristos }
51698b9484cSchristos 
51798b9484cSchristos static int
518924795e6Schristos os_truncate (host_callback *p, const char *file, int64_t len)
51998b9484cSchristos {
52098b9484cSchristos #ifdef HAVE_TRUNCATE
521924795e6Schristos   int result;
522924795e6Schristos 
523924795e6Schristos   result = truncate (file, len);
524924795e6Schristos   p->last_errno = errno;
525924795e6Schristos   return result;
52698b9484cSchristos #else
52798b9484cSchristos   p->last_errno = EINVAL;
52898b9484cSchristos   return -1;
52998b9484cSchristos #endif
53098b9484cSchristos }
53198b9484cSchristos 
53298b9484cSchristos static int
533924795e6Schristos os_getpid (host_callback *p)
534924795e6Schristos {
535924795e6Schristos   int result;
536924795e6Schristos 
537924795e6Schristos   result = getpid ();
538924795e6Schristos   /* POSIX says getpid always succeeds.  */
539924795e6Schristos   p->last_errno = 0;
540924795e6Schristos   return result;
541924795e6Schristos }
542924795e6Schristos 
543924795e6Schristos static int
544924795e6Schristos os_kill (host_callback *p, int pid, int signum)
545924795e6Schristos {
546924795e6Schristos #ifdef HAVE_KILL
547924795e6Schristos   int result;
548924795e6Schristos 
549924795e6Schristos   result = kill (pid, signum);
550924795e6Schristos   p->last_errno = errno;
551924795e6Schristos   return result;
552924795e6Schristos #else
553924795e6Schristos   p->last_errno = ENOSYS;
554924795e6Schristos   return -1;
555924795e6Schristos #endif
556924795e6Schristos }
557924795e6Schristos 
558924795e6Schristos static int
5599d1da10bSchristos os_pipe (host_callback *p, int *filedes)
56098b9484cSchristos {
56198b9484cSchristos   int i;
56298b9484cSchristos 
56398b9484cSchristos   /* We deliberately don't use fd 0.  It's probably stdin anyway.  */
56498b9484cSchristos   for (i = 1; i < MAX_CALLBACK_FDS; i++)
56598b9484cSchristos     {
56698b9484cSchristos       int j;
56798b9484cSchristos 
56898b9484cSchristos       if (p->fd_buddy[i] < 0)
56998b9484cSchristos 	for (j = i + 1; j < MAX_CALLBACK_FDS; j++)
57098b9484cSchristos 	  if (p->fd_buddy[j] < 0)
57198b9484cSchristos 	    {
57298b9484cSchristos 	      /* Found two free fd:s.  Set stat to allocated and mark
57398b9484cSchristos 		 pipeness.  */
57498b9484cSchristos 	      p->fd_buddy[i] = i;
57598b9484cSchristos 	      p->fd_buddy[j] = j;
57698b9484cSchristos 	      p->ispipe[i] = j;
57798b9484cSchristos 	      p->ispipe[j] = -i;
57898b9484cSchristos 	      filedes[0] = i;
57998b9484cSchristos 	      filedes[1] = j;
58098b9484cSchristos 
58198b9484cSchristos 	      /* Poison the FD map to make bugs apparent.  */
58298b9484cSchristos 	      p->fdmap[i] = -1;
58398b9484cSchristos 	      p->fdmap[j] = -1;
58498b9484cSchristos 	      return 0;
58598b9484cSchristos 	    }
58698b9484cSchristos     }
58798b9484cSchristos 
58898b9484cSchristos   p->last_errno = EMFILE;
58998b9484cSchristos   return -1;
59098b9484cSchristos }
59198b9484cSchristos 
59298b9484cSchristos /* Stub functions for pipe support.  They should always be overridden in
59398b9484cSchristos    targets using the pipe support, but that's up to the target.  */
59498b9484cSchristos 
59598b9484cSchristos /* Called when the simulator says that the pipe at (reader, writer) is
59698b9484cSchristos    now empty (so the writer should leave its waiting state).  */
59798b9484cSchristos 
59898b9484cSchristos static void
5999d1da10bSchristos os_pipe_empty (host_callback *p, int reader, int writer)
60098b9484cSchristos {
60198b9484cSchristos }
60298b9484cSchristos 
60398b9484cSchristos /* Called when the simulator says the pipe at (reader, writer) is now
60498b9484cSchristos    non-empty (so the writer should wait).  */
60598b9484cSchristos 
60698b9484cSchristos static void
6079d1da10bSchristos os_pipe_nonempty (host_callback *p, int reader, int writer)
60898b9484cSchristos {
60998b9484cSchristos }
61098b9484cSchristos 
61198b9484cSchristos static int
6129d1da10bSchristos os_shutdown (host_callback *p)
61398b9484cSchristos {
61498b9484cSchristos   int i, next, j;
61598b9484cSchristos   for (i = 0; i < MAX_CALLBACK_FDS; i++)
61698b9484cSchristos     {
61798b9484cSchristos       int do_close = 1;
61898b9484cSchristos 
61998b9484cSchristos       /* Zero out all pipe state.  Don't call callbacks for non-empty
62098b9484cSchristos 	 pipes; the target program has likely terminated at this point
62198b9484cSchristos 	 or we're called at initialization time.  */
62298b9484cSchristos       p->ispipe[i] = 0;
62398b9484cSchristos       p->pipe_buffer[i].size = 0;
62498b9484cSchristos       p->pipe_buffer[i].buffer = NULL;
62598b9484cSchristos 
62698b9484cSchristos       next = p->fd_buddy[i];
62798b9484cSchristos       if (next < 0)
62898b9484cSchristos 	continue;
62998b9484cSchristos       do
63098b9484cSchristos 	{
63198b9484cSchristos 	  j = next;
63298b9484cSchristos 	  if (j == MAX_CALLBACK_FDS)
63398b9484cSchristos 	    do_close = 0;
63498b9484cSchristos 	  next = p->fd_buddy[j];
63598b9484cSchristos 	  p->fd_buddy[j] = -1;
63698b9484cSchristos 	  /* At the initial call of os_init, we got -1, 0, 0, 0, ...  */
63798b9484cSchristos 	  if (next < 0)
63898b9484cSchristos 	    {
63998b9484cSchristos 	      p->fd_buddy[i] = -1;
64098b9484cSchristos 	      do_close = 0;
64198b9484cSchristos 	      break;
64298b9484cSchristos 	    }
64398b9484cSchristos 	}
64498b9484cSchristos       while (j != i);
64598b9484cSchristos       if (do_close)
64698b9484cSchristos 	close (p->fdmap[i]);
64798b9484cSchristos     }
64898b9484cSchristos   return 1;
64998b9484cSchristos }
65098b9484cSchristos 
65198b9484cSchristos static int
6529d1da10bSchristos os_init (host_callback *p)
65398b9484cSchristos {
65498b9484cSchristos   int i;
65598b9484cSchristos 
65698b9484cSchristos   os_shutdown (p);
65798b9484cSchristos   for (i = 0; i < 3; i++)
65898b9484cSchristos     {
65998b9484cSchristos       p->fdmap[i] = i;
66098b9484cSchristos       p->fd_buddy[i] = i - 1;
66198b9484cSchristos     }
66298b9484cSchristos   p->fd_buddy[0] = MAX_CALLBACK_FDS;
66398b9484cSchristos   p->fd_buddy[MAX_CALLBACK_FDS] = 2;
66498b9484cSchristos 
66598b9484cSchristos   p->syscall_map = cb_init_syscall_map;
66698b9484cSchristos   p->errno_map = cb_init_errno_map;
667924795e6Schristos   p->signal_map = cb_init_signal_map;
66898b9484cSchristos   p->open_map = cb_init_open_map;
66998b9484cSchristos 
67098b9484cSchristos   return 1;
67198b9484cSchristos }
67298b9484cSchristos 
67398b9484cSchristos /* DEPRECATED */
67498b9484cSchristos 
67598b9484cSchristos /* VARARGS */
676924795e6Schristos static void ATTRIBUTE_PRINTF (2, 3)
67798b9484cSchristos os_printf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...)
67898b9484cSchristos {
67998b9484cSchristos   va_list args;
68098b9484cSchristos   va_start (args, format);
68198b9484cSchristos 
68298b9484cSchristos   vfprintf (stdout, format, args);
68398b9484cSchristos   va_end (args);
68498b9484cSchristos }
68598b9484cSchristos 
68698b9484cSchristos /* VARARGS */
687924795e6Schristos static void ATTRIBUTE_PRINTF (2, 0)
68898b9484cSchristos os_vprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args)
68998b9484cSchristos {
69098b9484cSchristos   vprintf (format, args);
69198b9484cSchristos }
69298b9484cSchristos 
69398b9484cSchristos /* VARARGS */
694924795e6Schristos static void ATTRIBUTE_PRINTF (2, 0)
69598b9484cSchristos os_evprintf_filtered (host_callback *p ATTRIBUTE_UNUSED, const char *format, va_list args)
69698b9484cSchristos {
69798b9484cSchristos   vfprintf (stderr, format, args);
69898b9484cSchristos }
69998b9484cSchristos 
70098b9484cSchristos /* VARARGS */
701924795e6Schristos static void ATTRIBUTE_PRINTF (2, 3) ATTRIBUTE_NORETURN
70298b9484cSchristos os_error (host_callback *p ATTRIBUTE_UNUSED, const char *format, ...)
70398b9484cSchristos {
70498b9484cSchristos   va_list args;
70598b9484cSchristos   va_start (args, format);
70698b9484cSchristos 
70798b9484cSchristos   vfprintf (stderr, format, args);
70898b9484cSchristos   fprintf (stderr, "\n");
70998b9484cSchristos 
71098b9484cSchristos   va_end (args);
71198b9484cSchristos   exit (1);
71298b9484cSchristos }
71398b9484cSchristos 
71498b9484cSchristos host_callback default_callback =
71598b9484cSchristos {
71698b9484cSchristos   os_close,
71798b9484cSchristos   os_get_errno,
71898b9484cSchristos   os_isatty,
71998b9484cSchristos   os_lseek,
72098b9484cSchristos   os_open,
72198b9484cSchristos   os_read,
72298b9484cSchristos   os_read_stdin,
72398b9484cSchristos   os_rename,
72498b9484cSchristos   os_system,
72598b9484cSchristos   os_time,
72698b9484cSchristos   os_unlink,
72798b9484cSchristos   os_write,
72898b9484cSchristos   os_write_stdout,
72998b9484cSchristos   os_flush_stdout,
73098b9484cSchristos   os_write_stderr,
73198b9484cSchristos   os_flush_stderr,
73298b9484cSchristos 
73398b9484cSchristos   os_stat,
73498b9484cSchristos   os_fstat,
73598b9484cSchristos   os_lstat,
73698b9484cSchristos 
73798b9484cSchristos   os_ftruncate,
73898b9484cSchristos   os_truncate,
73998b9484cSchristos 
740924795e6Schristos   os_getpid,
741924795e6Schristos   os_kill,
742924795e6Schristos 
74398b9484cSchristos   os_pipe,
74498b9484cSchristos   os_pipe_empty,
74598b9484cSchristos   os_pipe_nonempty,
74698b9484cSchristos 
74798b9484cSchristos   os_poll_quit,
74898b9484cSchristos 
74998b9484cSchristos   os_shutdown,
75098b9484cSchristos   os_init,
75198b9484cSchristos 
75298b9484cSchristos   os_printf_filtered,  /* deprecated */
75398b9484cSchristos 
75498b9484cSchristos   os_vprintf_filtered,
75598b9484cSchristos   os_evprintf_filtered,
75698b9484cSchristos   os_error,
75798b9484cSchristos 
75898b9484cSchristos   0, 		/* last errno */
75998b9484cSchristos 
76098b9484cSchristos   { 0, },	/* fdmap */
76198b9484cSchristos   { -1, },	/* fd_buddy */
76298b9484cSchristos   { 0, },	/* ispipe */
76398b9484cSchristos   { { 0, 0 }, }, /* pipe_buffer */
76498b9484cSchristos 
76598b9484cSchristos   0, /* syscall_map */
76698b9484cSchristos   0, /* errno_map */
76798b9484cSchristos   0, /* open_map */
76898b9484cSchristos   0, /* signal_map */
76998b9484cSchristos   0, /* stat_map */
77098b9484cSchristos 
77198b9484cSchristos   /* Defaults expected to be overridden at initialization, where needed.  */
77298b9484cSchristos   BFD_ENDIAN_UNKNOWN, /* target_endian */
773924795e6Schristos   NULL, /* argv */
774924795e6Schristos   NULL, /* envp */
77598b9484cSchristos   4, /* target_sizeof_int */
77698b9484cSchristos 
77798b9484cSchristos   HOST_CALLBACK_MAGIC,
77898b9484cSchristos };
77998b9484cSchristos 
78098b9484cSchristos /* Read in a file describing the target's system call values.
78198b9484cSchristos    E.g. maybe someone will want to use something other than newlib.
78298b9484cSchristos    This assumes that the basic system call recognition and value passing/
78398b9484cSchristos    returning is supported.  So maybe some coding/recompilation will be
78498b9484cSchristos    necessary, but not as much.
78598b9484cSchristos 
78698b9484cSchristos    If an error occurs, the existing mapping is not changed.  */
78798b9484cSchristos 
78898b9484cSchristos CB_RC
7899d1da10bSchristos cb_read_target_syscall_maps (host_callback *cb, const char *file)
79098b9484cSchristos {
79198b9484cSchristos   CB_TARGET_DEFS_MAP *syscall_map, *errno_map, *open_map, *signal_map;
79298b9484cSchristos   const char *stat_map;
79398b9484cSchristos   FILE *f;
79498b9484cSchristos 
79598b9484cSchristos   if ((f = fopen (file, "r")) == NULL)
79698b9484cSchristos     return CB_RC_ACCESS;
79798b9484cSchristos 
79898b9484cSchristos   /* ... read in and parse file ... */
79998b9484cSchristos 
80098b9484cSchristos   fclose (f);
80198b9484cSchristos   return CB_RC_NO_MEM; /* FIXME:wip */
80298b9484cSchristos 
80398b9484cSchristos   /* Free storage allocated for any existing maps.  */
80498b9484cSchristos   if (cb->syscall_map)
80598b9484cSchristos     free (cb->syscall_map);
80698b9484cSchristos   if (cb->errno_map)
80798b9484cSchristos     free (cb->errno_map);
80898b9484cSchristos   if (cb->open_map)
80998b9484cSchristos     free (cb->open_map);
81098b9484cSchristos   if (cb->signal_map)
81198b9484cSchristos     free (cb->signal_map);
81298b9484cSchristos   if (cb->stat_map)
813924795e6Schristos     free ((void *) cb->stat_map);
81498b9484cSchristos 
81598b9484cSchristos   cb->syscall_map = syscall_map;
81698b9484cSchristos   cb->errno_map = errno_map;
81798b9484cSchristos   cb->open_map = open_map;
81898b9484cSchristos   cb->signal_map = signal_map;
81998b9484cSchristos   cb->stat_map = stat_map;
82098b9484cSchristos 
82198b9484cSchristos   return CB_RC_OK;
82298b9484cSchristos }
82398b9484cSchristos 
8247a93e43bSchristos /* General utility functions to search a map for a value.  */
8257a93e43bSchristos 
8267a93e43bSchristos static const CB_TARGET_DEFS_MAP *
8277a93e43bSchristos cb_target_map_entry (const CB_TARGET_DEFS_MAP map[], int target_val)
8287a93e43bSchristos {
8297a93e43bSchristos   const CB_TARGET_DEFS_MAP *m;
8307a93e43bSchristos 
8317a93e43bSchristos   for (m = &map[0]; m->target_val != -1; ++m)
8327a93e43bSchristos     if (m->target_val == target_val)
8337a93e43bSchristos       return m;
8347a93e43bSchristos 
8357a93e43bSchristos   return NULL;
8367a93e43bSchristos }
8377a93e43bSchristos 
8387a93e43bSchristos static const CB_TARGET_DEFS_MAP *
8397a93e43bSchristos cb_host_map_entry (const CB_TARGET_DEFS_MAP map[], int host_val)
8407a93e43bSchristos {
8417a93e43bSchristos   const CB_TARGET_DEFS_MAP *m;
8427a93e43bSchristos 
8437a93e43bSchristos   for (m = &map[0]; m->host_val != -1; ++m)
8447a93e43bSchristos     if (m->host_val == host_val)
8457a93e43bSchristos       return m;
8467a93e43bSchristos 
8477a93e43bSchristos   return NULL;
8487a93e43bSchristos }
8497a93e43bSchristos 
85098b9484cSchristos /* Translate the target's version of a syscall number to the host's.
85198b9484cSchristos    This isn't actually the host's version, rather a canonical form.
85298b9484cSchristos    ??? Perhaps this should be renamed to ..._canon_syscall.  */
85398b9484cSchristos 
85498b9484cSchristos int
8559d1da10bSchristos cb_target_to_host_syscall (host_callback *cb, int target_val)
85698b9484cSchristos {
8577a93e43bSchristos   const CB_TARGET_DEFS_MAP *m =
8587a93e43bSchristos     cb_target_map_entry (cb->syscall_map, target_val);
85998b9484cSchristos 
8607a93e43bSchristos   return m ? m->host_val : -1;
86198b9484cSchristos }
86298b9484cSchristos 
86398b9484cSchristos /* FIXME: sort tables if large.
86498b9484cSchristos    Alternatively, an obvious improvement for errno conversion is
86598b9484cSchristos    to machine generate a function with a large switch().  */
86698b9484cSchristos 
86798b9484cSchristos /* Translate the host's version of errno to the target's.  */
86898b9484cSchristos 
86998b9484cSchristos int
8709d1da10bSchristos cb_host_to_target_errno (host_callback *cb, int host_val)
87198b9484cSchristos {
8727a93e43bSchristos   const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->errno_map, host_val);
87398b9484cSchristos 
87498b9484cSchristos   /* ??? Which error to return in this case is up for grabs.
87598b9484cSchristos      Note that some missing values may have standard alternatives.
87698b9484cSchristos      For now return 0 and require caller to deal with it.  */
8777a93e43bSchristos   return m ? m->target_val : 0;
87898b9484cSchristos }
87998b9484cSchristos 
88098b9484cSchristos /* Given a set of target bitmasks for the open system call,
88198b9484cSchristos    return the host equivalent.
88298b9484cSchristos    Mapping open flag values is best done by looping so there's no need
88398b9484cSchristos    to machine generate this function.  */
88498b9484cSchristos 
88598b9484cSchristos int
8869d1da10bSchristos cb_target_to_host_open (host_callback *cb, int target_val)
88798b9484cSchristos {
88898b9484cSchristos   int host_val = 0;
88998b9484cSchristos   CB_TARGET_DEFS_MAP *m;
890924795e6Schristos   int o_rdonly = 0;
891924795e6Schristos   int o_wronly = 0;
892924795e6Schristos   int o_rdwr = 0;
893924795e6Schristos   int o_binary = 0;
894924795e6Schristos   int o_rdwrmask;
895924795e6Schristos 
896924795e6Schristos   /* O_RDONLY can be (and usually is) 0 which needs to be treated specially.  */
897924795e6Schristos   for (m = &cb->open_map[0]; m->host_val != -1; ++m)
898924795e6Schristos     {
899924795e6Schristos       if (!strcmp (m->name, "O_RDONLY"))
900924795e6Schristos 	o_rdonly = m->target_val;
901924795e6Schristos       else if (!strcmp (m->name, "O_WRONLY"))
902924795e6Schristos 	o_wronly = m->target_val;
903924795e6Schristos       else if (!strcmp (m->name, "O_RDWR"))
904924795e6Schristos 	o_rdwr = m->target_val;
905924795e6Schristos       else if (!strcmp (m->name, "O_BINARY"))
906924795e6Schristos 	o_binary = m->target_val;
907924795e6Schristos     }
908924795e6Schristos   o_rdwrmask = o_rdonly | o_wronly | o_rdwr;
90998b9484cSchristos 
91098b9484cSchristos   for (m = &cb->open_map[0]; m->host_val != -1; ++m)
91198b9484cSchristos     {
912924795e6Schristos       if (m->target_val == o_rdonly || m->target_val == o_wronly
913924795e6Schristos 	  || m->target_val == o_rdwr)
91498b9484cSchristos 	{
915924795e6Schristos 	  if ((target_val & o_rdwrmask) == m->target_val)
91698b9484cSchristos 	    host_val |= m->host_val;
91798b9484cSchristos 	  /* Handle the host/target differentiating between binary and
91898b9484cSchristos              text mode.  Only one case is of importance */
919924795e6Schristos #ifdef O_BINARY
920924795e6Schristos 	  if (o_binary == 0)
92198b9484cSchristos 	    host_val |= O_BINARY;
92298b9484cSchristos #endif
923924795e6Schristos 	}
924924795e6Schristos       else
925924795e6Schristos 	{
92698b9484cSchristos 	  if ((m->target_val & target_val) == m->target_val)
92798b9484cSchristos 	    host_val |= m->host_val;
92898b9484cSchristos 	}
92998b9484cSchristos     }
93098b9484cSchristos 
93198b9484cSchristos   return host_val;
93298b9484cSchristos }
93398b9484cSchristos 
934924795e6Schristos /* Translate the target's version of a signal number to the host's.
935924795e6Schristos    This isn't actually the host's version, rather a canonical form.
936924795e6Schristos    ??? Perhaps this should be renamed to ..._canon_signal.  */
937924795e6Schristos 
938924795e6Schristos int
939924795e6Schristos cb_target_to_host_signal (host_callback *cb, int target_val)
940924795e6Schristos {
941924795e6Schristos   const CB_TARGET_DEFS_MAP *m =
942924795e6Schristos     cb_target_map_entry (cb->signal_map, target_val);
943924795e6Schristos 
944924795e6Schristos   return m ? m->host_val : -1;
945924795e6Schristos }
946924795e6Schristos 
94798b9484cSchristos /* Utility for e.g. cb_host_to_target_stat to store values in the target's
9489d1da10bSchristos    stat struct.
9499d1da10bSchristos 
9509d1da10bSchristos    ??? The "val" must be as big as target word size.  */
95198b9484cSchristos 
95298b9484cSchristos void
9539d1da10bSchristos cb_store_target_endian (host_callback *cb, char *p, int size, long val)
95498b9484cSchristos {
95598b9484cSchristos   if (cb->target_endian == BFD_ENDIAN_BIG)
95698b9484cSchristos     {
95798b9484cSchristos       p += size;
95898b9484cSchristos       while (size-- > 0)
95998b9484cSchristos 	{
96098b9484cSchristos 	  *--p = val;
96198b9484cSchristos 	  val >>= 8;
96298b9484cSchristos 	}
96398b9484cSchristos     }
96498b9484cSchristos   else
96598b9484cSchristos     {
96698b9484cSchristos       while (size-- > 0)
96798b9484cSchristos 	{
96898b9484cSchristos 	  *p++ = val;
96998b9484cSchristos 	  val >>= 8;
97098b9484cSchristos 	}
97198b9484cSchristos     }
97298b9484cSchristos }
97398b9484cSchristos 
97498b9484cSchristos /* Translate a host's stat struct into a target's.
97598b9484cSchristos    If HS is NULL, just compute the length of the buffer required,
97698b9484cSchristos    TS is ignored.
97798b9484cSchristos 
97898b9484cSchristos    The result is the size of the target's stat struct,
97998b9484cSchristos    or zero if an error occurred during the translation.  */
98098b9484cSchristos 
98198b9484cSchristos int
982924795e6Schristos cb_host_to_target_stat (host_callback *cb, const struct stat *hs, void *ts)
98398b9484cSchristos {
98498b9484cSchristos   const char *m = cb->stat_map;
98598b9484cSchristos   char *p;
98698b9484cSchristos 
98798b9484cSchristos   if (hs == NULL)
98898b9484cSchristos     ts = NULL;
98998b9484cSchristos   p = ts;
99098b9484cSchristos 
99198b9484cSchristos   while (m)
99298b9484cSchristos     {
99398b9484cSchristos       char *q = strchr (m, ',');
99498b9484cSchristos       int size;
99598b9484cSchristos 
99698b9484cSchristos       /* FIXME: Use sscanf? */
99798b9484cSchristos       if (q == NULL)
99898b9484cSchristos 	{
99998b9484cSchristos 	  /* FIXME: print error message */
100098b9484cSchristos 	  return 0;
100198b9484cSchristos 	}
100298b9484cSchristos       size = atoi (q + 1);
100398b9484cSchristos       if (size == 0)
100498b9484cSchristos 	{
100598b9484cSchristos 	  /* FIXME: print error message */
100698b9484cSchristos 	  return 0;
100798b9484cSchristos 	}
100898b9484cSchristos 
100998b9484cSchristos       if (hs != NULL)
101098b9484cSchristos 	{
101198b9484cSchristos 	  if (0)
101298b9484cSchristos 	    ;
101398b9484cSchristos 	  /* Defined here to avoid emacs indigestion on a lone "else".  */
101498b9484cSchristos #undef ST_x
101598b9484cSchristos #define ST_x(FLD)					\
101698b9484cSchristos 	  else if (strncmp (m, #FLD, q - m) == 0)	\
101798b9484cSchristos 	    cb_store_target_endian (cb, p, size, hs->FLD)
101898b9484cSchristos 
101998b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_DEV
102098b9484cSchristos 	  ST_x (st_dev);
102198b9484cSchristos #endif
102298b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_INO
102398b9484cSchristos 	  ST_x (st_ino);
102498b9484cSchristos #endif
102598b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_MODE
102698b9484cSchristos 	  ST_x (st_mode);
102798b9484cSchristos #endif
102898b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_NLINK
102998b9484cSchristos 	  ST_x (st_nlink);
103098b9484cSchristos #endif
103198b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_UID
103298b9484cSchristos 	  ST_x (st_uid);
103398b9484cSchristos #endif
103498b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_GID
103598b9484cSchristos 	  ST_x (st_gid);
103698b9484cSchristos #endif
103798b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_RDEV
103898b9484cSchristos 	  ST_x (st_rdev);
103998b9484cSchristos #endif
104098b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_SIZE
104198b9484cSchristos 	  ST_x (st_size);
104298b9484cSchristos #endif
104398b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
104498b9484cSchristos 	  ST_x (st_blksize);
104598b9484cSchristos #endif
104698b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
104798b9484cSchristos 	  ST_x (st_blocks);
104898b9484cSchristos #endif
104998b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_ATIME
105098b9484cSchristos 	  ST_x (st_atime);
105198b9484cSchristos #endif
105298b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_MTIME
105398b9484cSchristos 	  ST_x (st_mtime);
105498b9484cSchristos #endif
105598b9484cSchristos #ifdef HAVE_STRUCT_STAT_ST_CTIME
105698b9484cSchristos 	  ST_x (st_ctime);
105798b9484cSchristos #endif
105898b9484cSchristos #undef ST_x
105998b9484cSchristos 	  /* FIXME:wip */
106098b9484cSchristos 	  else
106198b9484cSchristos 	    /* Unsupported field, store 0.  */
106298b9484cSchristos 	    cb_store_target_endian (cb, p, size, 0);
106398b9484cSchristos 	}
106498b9484cSchristos 
106598b9484cSchristos       p += size;
106698b9484cSchristos       m = strchr (q, ':');
106798b9484cSchristos       if (m)
106898b9484cSchristos 	++m;
106998b9484cSchristos     }
107098b9484cSchristos 
107198b9484cSchristos   return p - (char *) ts;
107298b9484cSchristos }
107398b9484cSchristos 
107498b9484cSchristos int
107598b9484cSchristos cb_is_stdin (host_callback *cb, int fd)
107698b9484cSchristos {
107798b9484cSchristos   return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 0;
107898b9484cSchristos }
107998b9484cSchristos 
108098b9484cSchristos int
108198b9484cSchristos cb_is_stdout (host_callback *cb, int fd)
108298b9484cSchristos {
108398b9484cSchristos   return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 1;
108498b9484cSchristos }
108598b9484cSchristos 
108698b9484cSchristos int
108798b9484cSchristos cb_is_stderr (host_callback *cb, int fd)
108898b9484cSchristos {
108998b9484cSchristos   return fdbad (cb, fd) ? 0 : fdmap (cb, fd) == 2;
109098b9484cSchristos }
10917a93e43bSchristos 
10927a93e43bSchristos const char *
10937a93e43bSchristos cb_host_str_syscall (host_callback *cb, int host_val)
10947a93e43bSchristos {
10957a93e43bSchristos   const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->syscall_map, host_val);
10967a93e43bSchristos 
10977a93e43bSchristos   return m ? m->name : NULL;
10987a93e43bSchristos }
10997a93e43bSchristos 
11007a93e43bSchristos const char *
11017a93e43bSchristos cb_host_str_errno (host_callback *cb, int host_val)
11027a93e43bSchristos {
11037a93e43bSchristos   const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->errno_map, host_val);
11047a93e43bSchristos 
11057a93e43bSchristos   return m ? m->name : NULL;
11067a93e43bSchristos }
11077a93e43bSchristos 
11087a93e43bSchristos const char *
11097a93e43bSchristos cb_host_str_signal (host_callback *cb, int host_val)
11107a93e43bSchristos {
11117a93e43bSchristos   const CB_TARGET_DEFS_MAP *m = cb_host_map_entry (cb->signal_map, host_val);
11127a93e43bSchristos 
11137a93e43bSchristos   return m ? m->name : NULL;
11147a93e43bSchristos }
11157a93e43bSchristos 
11167a93e43bSchristos const char *
11177a93e43bSchristos cb_target_str_syscall (host_callback *cb, int target_val)
11187a93e43bSchristos {
11197a93e43bSchristos   const CB_TARGET_DEFS_MAP *m =
11207a93e43bSchristos     cb_target_map_entry (cb->syscall_map, target_val);
11217a93e43bSchristos 
11227a93e43bSchristos   return m ? m->name : NULL;
11237a93e43bSchristos }
11247a93e43bSchristos 
11257a93e43bSchristos const char *
11267a93e43bSchristos cb_target_str_errno (host_callback *cb, int target_val)
11277a93e43bSchristos {
11287a93e43bSchristos   const CB_TARGET_DEFS_MAP *m =
11297a93e43bSchristos     cb_target_map_entry (cb->errno_map, target_val);
11307a93e43bSchristos 
11317a93e43bSchristos   return m ? m->name : NULL;
11327a93e43bSchristos }
11337a93e43bSchristos 
11347a93e43bSchristos const char *
11357a93e43bSchristos cb_target_str_signal (host_callback *cb, int target_val)
11367a93e43bSchristos {
11377a93e43bSchristos   const CB_TARGET_DEFS_MAP *m =
11387a93e43bSchristos     cb_target_map_entry (cb->signal_map, target_val);
11397a93e43bSchristos 
11407a93e43bSchristos   return m ? m->name : NULL;
11417a93e43bSchristos }
1142