#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ansidecl.h"
#include "libiberty.h"
#ifdef ANSI_PROTOTYPES
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "gdb/callback.h"
#include "targ-vals.h"
#ifndef ENOSYS
#define ENOSYS EINVAL
#endif
#ifndef ENAMETOOLONG
#define ENAMETOOLONG EINVAL
#endif
#ifndef MAX_PATH_LEN
#define MAX_PATH_LEN 1024
#endif
#define FILE_XFR_SIZE 4096
#define TWORD long
#define TADDR unsigned long
static int
get_string (cb, sc, buf, buflen, addr)
host_callback *cb;
CB_SYSCALL *sc;
char *buf;
int buflen;
TADDR addr;
{
char *p, *pend;
for (p = buf, pend = buf + buflen; p < pend; ++p, ++addr)
{
unsigned int count = (*sc->read_mem) (cb, sc, addr, p, 1);
if (count != 1)
return EINVAL;
if (*p == 0)
break;
}
if (p == pend)
return ENAMETOOLONG;
return 0;
}
static int
get_path (cb, sc, addr, bufp)
host_callback *cb;
CB_SYSCALL *sc;
TADDR addr;
char **bufp;
{
char *buf = xmalloc (MAX_PATH_LEN);
int result;
result = get_string (cb, sc, buf, MAX_PATH_LEN, addr);
if (result == 0)
*bufp = buf;
else
free (buf);
return result;
}
CB_RC
cb_syscall (cb, sc)
host_callback *cb;
CB_SYSCALL *sc;
{
TWORD result = 0, errcode = 0;
if (sc->magic != CB_SYSCALL_MAGIC)
abort ();
switch (cb_target_to_host_syscall (cb, sc->func))
{
#if 0
case CB_SYS_argvlen :
{
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 :
{
TADDR tbuf = sc->arg1;
int bufsize = sc->arg2;
TADDR 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 = EINVAL;
goto FinishSyscall;
}
tbuf = len + 1;
}
}
if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
{
result = -1;
errcode = 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 = EINVAL;
goto FinishSyscall;
}
tbuf = len + 1;
}
}
if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
{
result = -1;
errcode = EINVAL;
goto FinishSyscall;
}
result = argc;
sc->result2 = envc;
break;
}
#endif
case CB_SYS_exit :
break;
case CB_SYS_open :
{
char *path;
errcode = get_path (cb, sc, sc->arg1, &path);
if (errcode != 0)
{
result = -1;
goto FinishSyscall;
}
result = (*cb->open) (cb, path, sc->arg2 );
free (path);
if (result < 0)
goto ErrorFinish;
}
break;
case CB_SYS_close :
result = (*cb->close) (cb, sc->arg1);
if (result < 0)
goto ErrorFinish;
break;
case CB_SYS_read :
{
char buf[FILE_XFR_SIZE];
int fd = sc->arg1;
TADDR addr = sc->arg2;
size_t count = sc->arg3;
size_t bytes_read = 0;
int bytes_written;
while (count > 0)
{
if (fd == 0)
result = (int) (*cb->read_stdin) (cb, buf,
(count < FILE_XFR_SIZE
? count : FILE_XFR_SIZE));
else
result = (int) (*cb->read) (cb, fd, buf,
(count < FILE_XFR_SIZE
? count : FILE_XFR_SIZE));
if (result == -1)
goto ErrorFinish;
if (result == 0)
break;
bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result);
if (bytes_written != result)
{
result = -1;
errcode = EINVAL;
goto FinishSyscall;
}
bytes_read += result;
count -= result;
addr += result;
if (result != FILE_XFR_SIZE)
break;
}
result = bytes_read;
}
break;
case CB_SYS_write :
{
char buf[FILE_XFR_SIZE];
int fd = sc->arg1;
TADDR 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 = EINVAL;
goto FinishSyscall;
}
if (fd == 1)
{
result = (int) (*cb->write_stdout) (cb, buf, bytes_read);
(*cb->flush_stdout) (cb);
}
else if (fd == 2)
{
result = (int) (*cb->write_stderr) (cb, buf, bytes_read);
(*cb->flush_stderr) (cb);
}
else
result = (int) (*cb->write) (cb, fd, buf, bytes_read);
if (result == -1)
goto ErrorFinish;
bytes_written += result;
count -= result;
addr += result;
}
result = bytes_written;
}
break;
case CB_SYS_lseek :
{
int fd = sc->arg1;
unsigned long offset = sc->arg2;
int whence = sc->arg3;
result = (*cb->lseek) (cb, fd, offset, whence);
if (result < 0)
goto ErrorFinish;
}
break;
case CB_SYS_unlink :
{
char *path;
errcode = get_path (cb, sc, sc->arg1, &path);
if (errcode != 0)
{
result = -1;
goto FinishSyscall;
}
result = (*cb->unlink) (cb, path);
free (path);
if (result < 0)
goto ErrorFinish;
}
break;
case CB_SYS_stat :
{
char *path,*buf;
int buflen;
struct stat statbuf;
TADDR addr = sc->arg2;
errcode = get_path (cb, sc, sc->arg1, &path);
if (errcode != 0)
{
result = -1;
goto FinishSyscall;
}
result = (*cb->stat) (cb, path, &statbuf);
free (path);
if (result < 0)
goto ErrorFinish;
buflen = cb_host_to_target_stat (cb, NULL, NULL);
buf = xmalloc (buflen);
if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
{
free (buf);
errcode = ENOSYS;
result = -1;
goto FinishSyscall;
}
if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
{
free (buf);
errcode = EINVAL;
result = -1;
goto FinishSyscall;
}
free (buf);
}
break;
case CB_SYS_fstat :
{
char *buf;
int buflen;
struct stat statbuf;
TADDR addr = sc->arg2;
result = (*cb->fstat) (cb, sc->arg1, &statbuf);
if (result < 0)
goto ErrorFinish;
buflen = cb_host_to_target_stat (cb, NULL, NULL);
buf = xmalloc (buflen);
if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
{
free (buf);
errcode = ENOSYS;
result = -1;
goto FinishSyscall;
}
if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
{
free (buf);
errcode = EINVAL;
result = -1;
goto FinishSyscall;
}
free (buf);
}
break;
case CB_SYS_time :
{
time_t t = (*cb->time) (cb, (time_t *) 0);
result = t;
}
break;
case CB_SYS_chdir :
case CB_SYS_chmod :
case CB_SYS_utime :
default :
result = -1;
errcode = ENOSYS;
break;
}
FinishSyscall:
sc->result = result;
if (errcode == 0)
sc->errcode = 0;
else
sc->errcode = cb_host_to_target_errno (cb, errcode);
return CB_RC_OK;
ErrorFinish:
sc->result = result;
sc->errcode = (*cb->get_errno) (cb);
return CB_RC_OK;
}