diff options
author | Doug Evans <dje@google.com> | 1997-11-17 23:09:08 +0000 |
---|---|---|
committer | Doug Evans <dje@google.com> | 1997-11-17 23:09:08 +0000 |
commit | f7abc1ca0cbae80f1910de13c969816d14d8acb2 (patch) | |
tree | 6007dc93c2633dd0a79e3286e96b2c6f31077acb /sim/common/syscall.c | |
parent | 891703e5e87f5868b72d95c889cb6b6f27089014 (diff) | |
download | gdb-f7abc1ca0cbae80f1910de13c969816d14d8acb2.zip gdb-f7abc1ca0cbae80f1910de13c969816d14d8acb2.tar.gz gdb-f7abc1ca0cbae80f1910de13c969816d14d8acb2.tar.bz2 |
* Make-common.in (DEP, COMMON_DEP_CFLAGS): Define.
(LIB_OBJS): Add syscall.o.
(gentmap): Pass $(NL_TARGET) to $(CC).
(syscall.o): Add rule for.
(sim_main_headers): Add $(SIM_EXTRA_DEPS).
(sim-bits.o): Depend on $(sim-n-bits_h).
(sim-load.o): Depend on callback.h.
* Make-common.in (cgen-*.o): Update dependencies, mem-ops.h renamed to
cgen-mem.h, sem-ops.h renamed to cgen-ops.h.
* cgen-mem.h, cgen-ops.h: New files.
* aclocal.m4 (--enable-sim-scache): Pass -DWITH_SCACHE=0 for "=no".
* Makefile.in (nltvals.def): Depend on gennltvals.sh.
Rewrite build rule.
* callback.c: #include string.h or strings.h.
#include sys/types.h and sys/stat.h.
(cb_init_syscall_map,cb_init_errno_map,cb_init_open_map): Declare.
(enosys): New function.
(os_get_errno,os_open): Update.
(os_stat,os_fstat): New functions.
(os_init): Initialize syscall_map, errno_map, open_map.
(default_callback): Add entries for os_stat, os_fstat, syscall_map,
errno_map, open_map, signal_map, stat_map.
(cb_read_target_syscall_maps): New function.
(cb_target_to_host_syscall): New function.
(cb_host_to_target_errno): Renamed from host_to_target_errno.
(cb_target_to_host_open): Renamed from target_to_host_open.
(store): New function.
(cb_host_to_target_stat): New function.
* gentmap.c (sys_tdefs): New global.
(gen_targ_vals_h): Output target syscall numbers.
(gen_targ_map_c): Update. Output target syscall translation map.
* gentvals.sh: New first argument `target'. Preface table with
#ifdef NL_TARGET_$target if non-null target passed.
* gennltvals.sh: New file.
* nltvals.def: Regenerated.
Diffstat (limited to 'sim/common/syscall.c')
-rw-r--r-- | sim/common/syscall.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/sim/common/syscall.c b/sim/common/syscall.c new file mode 100644 index 0000000..4bbb0c5 --- /dev/null +++ b/sim/common/syscall.c @@ -0,0 +1,306 @@ +/* Remote target system call support. + Copyright 1997 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 + (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 + 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. */ + +/* This interface isn't intended to be specific to any particular kind + of remote (hardware, simulator, whatever). As such, support for it + (e.g. sim/common/callback.c) should *not* live in the simulator source + tree, nor should it live in the gdb source tree. K&R C must be + supported. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#ifdef ANSI_PROTOTYPES +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <time.h> +#include "callback.h" +#include "remote-sim.h" +#include "targ-vals.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* When doing file read/writes, do this many bytes at a time. */ +#define FILE_XFR_SIZE 4096 + +/* Maximum length of a path name. */ +#ifndef MAX_PATH_LEN +#define MAX_PATH_LEN 1024 +#endif + +/* Utility of cb_syscall to fetch a path name from the target. + The result is 0 for success or a target errno value. */ + +static int +get_path (cb, sc, buf, buflen, addr) + host_callback *cb; + CB_SYSCALL *sc; + char *buf; + int buflen; + long addr; +{ + char *p, *pend; + + for (p = buf, pend = buf + buflen; p < pend; ++p, ++addr) + { + /* No, it isn't expected that this would cause one transaction with + the remote target for each byte. The target could send the + path name along with the syscall request, and cache the file + name somewhere. */ + unsigned int count = (*sc->read_mem) (cb, sc, addr, p, 1); + + if (count != 1) + return TARGET_EINVAL; + if (*p == 0) + break; + } + if (p == pend) + return TARGET_ENAMETOOLONG; + return 0; +} + +/* Perform a system call on behalf of the target. */ + +CB_RC +cb_syscall (cb, sc) + host_callback *cb; + CB_SYSCALL *sc; +{ + /* ??? Need to consider target word size. */ + long result = 0, errcode = 0; + + switch (cb_target_to_host_syscall (cb, sc->func)) + { +#if 0 /* FIXME: wip */ + case CB_SYS_argvlen : + { + /* Compute how much space is required to store the argv,envp + strings so that the program can allocate the space and then + call SYS_argv to fetch the values. */ + int addr_size = cb->addr_size; + int argc,envc,arglen,envlen; + const char **argv = cb->init_argv; + const char **envp = cb->init_envp; + + argc = arglen = 0; + if (argv) + { + for ( ; argv[argc]; ++argc) + arglen += strlen (argv[argc]) + 1; + } + envc = envlen = 0; + if (envp) + { + for ( ; envp[envc]; ++envc) + envlen += strlen (envp[envc]) + 1; + } + result = arglen + envlen; + break; + } + + case CB_SYS_argv : + { + /* Pointer to target's buffer. */ + SIM_ADDR tbuf = sc->arg1; + /* Buffer size. */ + int bufsize = sc->arg2; + /* Q is the target address of where all the strings go. */ + SIM_ADDR q; + int word_size = cb->word_size; + int i,argc,envc,len; + const char **argv = cb->init_argv; + const char **envp = cb->init_envp; + + argc = 0; + if (argv) + { + for ( ; argv[argc]; ++argc) + { + int len = strlen (argv[argc]); + int written = (*sc->write_mem) (cb, sc, tbuf, argv[argc], len + 1); + if (written != len) + { + result = -1; + errcode = TARGET_EINVAL; + goto FinishSyscall; + } + tbuf = len + 1; + } + } + if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1) + { + result = -1; + errcode = TARGET_EINVAL; + goto FinishSyscall; + } + tbuf++; + envc = 0; + if (envp) + { + for ( ; envp[envc]; ++envc) + { + int len = strlen (envp[envc]); + int written = (*sc->write_mem) (cb, sc, tbuf, envp[envc], len + 1); + if (written != len) + { + result = -1; + errcode = TARGET_EINVAL; + goto FinishSyscall; + } + tbuf = len + 1; + } + } + if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1) + { + result = -1; + errcode = TARGET_EINVAL; + goto FinishSyscall; + } + result = argc; + sc->result2 = envc; + break; + } +#endif /* wip */ + + case CB_SYS_exit : + /* Caller must catch and handle. */ + break; + + case CB_SYS_open : + { + char path[MAX_PATH_LEN]; + int errcode; + + errcode = get_path (cb, sc, path, MAX_PATH_LEN, sc->arg1); + if (errcode != 0) + { + result = -1; + errcode = errcode; + goto FinishSyscall; + } + result = (*cb->open) (cb, path, sc->arg2 /*, sc->arg3*/); + } + break; + + case CB_SYS_close : + result = (*cb->close) (cb, sc->arg1); + break; + + case CB_SYS_read : + { + /* ??? Perfect handling of error conditions may require only one + call to cb->read. One can't assume all the data is + contiguously stored in host memory so that would require + malloc'ing/free'ing the space. Maybe later. */ + char buf[FILE_XFR_SIZE]; + int fd = sc->arg1; + SIM_ADDR addr = sc->arg2; + size_t count = sc->arg3; + size_t bytes_read = 0; + int bytes_written; + + while (count > 0) + { + result = (int) (*cb->read) (cb, fd, buf, + count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE); + if (result == -1) + goto FinishSyscall; + bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result); + if (bytes_written != result) + { + result = -1; + errcode = TARGET_EINVAL; + goto FinishSyscall; + } + bytes_read += result; + count -= result; + addr += result; + } + result = bytes_read; + } + break; + + case CB_SYS_write : + { + /* ??? Perfect handling of error conditions may require only one + call to cb->write. One can't assume all the data is + contiguously stored in host memory so that would require + malloc'ing/free'ing the space. Maybe later. */ + char buf[FILE_XFR_SIZE]; + int fd = sc->arg1; + SIM_ADDR addr = sc->arg2; + size_t count = sc->arg3; + int bytes_read; + size_t bytes_written = 0; + + while (count > 0) + { + int bytes_to_read = count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE; + bytes_read = (*sc->read_mem) (cb, sc, addr, buf, bytes_to_read); + if (bytes_read != bytes_to_read) + { + result = -1; + errcode = TARGET_EINVAL; + goto FinishSyscall; + } + if (fd == 1) + result = (int) (*cb->write_stdout) (cb, buf, bytes_read); + else + result = (int) (*cb->write) (cb, fd, buf, bytes_read); + if (result == -1) + goto FinishSyscall; + bytes_written += result; + count -= result; + addr += result; + } + result = bytes_written; + } + break; + + default : + result = -1; +#ifdef TARGET_ENOSYS + errcode = TARGET_ENOSYS; +#else + errcode = TARGET_EINVAL; +#endif + break; + } + + FinishSyscall: + sc->result = result; + if (errcode == 0) + sc->errcode = (*cb->get_errno) (cb); + else + sc->errcode = errcode; + + return CB_RC_OK; +} |