Files
ftmemsim-valgrind/coregrind/m_libcfile.c
Julian Seward 091ebb69f5 A major overhaul of all machinery to do with syscalls, but mostly of
the m_syscalls module.  Fundamentally the aim of the overhaul is to
clean up the logic and abstractions surrounding syscalls in order that
we can cleanly support ppc32 and other new targets.  Aims in detail:

* To further decouple the syscall PRE/POST wrappers from specifics of
  how those values are stored on a given platform.  The wrappers look
  the same as they did before, mostly (eg, references to ARGn and
  RES are unchanged), but now those macros refer to values in structs
  SyscallArgs and SyscallStatus (see priv_types_n_macros.h).

* Complete overhaul of the driver logic for syscalls.  The resulting
  logic is algorithmically identical to what we had before, but is
  more documented, and deals with moving arg/result data between
  platform specific representations and the canonical forms in
  structs SyscallArgs and SyscallStatus.

* Also as a result of this change, remove problems in the old logic
  due to assignments of RES in PRE wrappers trashing the ARGs whilst
  we still need to see them.

* Lots of other cleanups and documentation.  There is extensive
  commentary in syscalls-main.c.

The driver logic has been placed in its own file, syscalls-main.c.

New/deleted files in m_syscalls:

* syscalls.c is divided up into syscalls-main.c, containing driver
  logic, and syscalls-generic.c, containing generic Unix wrappers.

* priv_syscalls.h is chopped up into priv_types_n_macros.h
  and priv_syscalls-{generic,main}.h.

                           ------------

All the above changes are in m_syscalls.  However there is one
system-wide change as a result of all this.

The x86-linux assumption that syscall return values in the range -4095
.. -1 are errors and all others are values, has been done away with
everywhere.  Instead there is a new basic type SysRes which holds a
system call result in a platform-neutral way.

Everywhere that previously an Int would have held a system call
result, there is now a SysRes in its place.

                           ------------

Almost everything works on SuSE 9.1 (LinuxThreads) again.  NPTL will
still be majorly broken; I will commit fixes shortly.  AMD64 is also
totalled.  I will get to that too.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3849
2005-06-07 20:04:56 +00:00

421 lines
11 KiB
C

/*--------------------------------------------------------------------*/
/*--- File- and socket-related libc stuff. m_libcfile.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2005 Julian Seward
jseward@acm.org
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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#include "core.h"
#include "pub_core_libcbase.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcfile.h"
#include "pub_core_options.h"
#include "vki_unistd.h"
/* ---------------------------------------------------------------------
File stuff
------------------------------------------------------------------ */
static inline Bool fd_exists(Int fd)
{
struct vki_stat st;
return VG_(fstat)(fd, &st) == 0;
}
/* Move an fd into the Valgrind-safe range */
Int VG_(safe_fd)(Int oldfd)
{
Int newfd;
vg_assert(VG_(fd_hard_limit) != -1);
newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_(fd_hard_limit));
if (newfd != -1)
VG_(close)(oldfd);
VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC);
vg_assert(newfd >= VG_(fd_hard_limit));
return newfd;
}
/* Returns -1 on failure. */
Int VG_(open) ( const Char* pathname, Int flags, Int mode )
{
SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
return res.isError ? -1 : res.val;
}
void VG_(close) ( Int fd )
{
(void)VG_(do_syscall1)(__NR_close, fd);
}
Int VG_(read) ( Int fd, void* buf, Int count)
{
SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
return res.isError ? -1 : res.val;
}
Int VG_(write) ( Int fd, const void* buf, Int count)
{
SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
return res.isError ? -1 : res.val;
}
Int VG_(pipe) ( Int fd[2] )
{
SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
return res.isError ? -1 : 0;
}
OffT VG_(lseek) ( Int fd, OffT offset, Int whence)
{
SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
return res.isError ? (-1) : 0;
}
Int VG_(stat) ( Char* file_name, struct vki_stat* buf )
{
SysRes res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)buf);
return res.isError ? (-1) : 0;
}
Int VG_(fstat) ( Int fd, struct vki_stat* buf )
{
SysRes res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)buf);
return res.isError ? (-1) : 0;
}
Int VG_(dup2) ( Int oldfd, Int newfd )
{
SysRes res = VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
return res.isError ? (-1) : res.val;
}
Int VG_(rename) ( Char* old_name, Char* new_name )
{
SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
return res.isError ? (-1) : 0;
}
Int VG_(unlink) ( Char* file_name )
{
SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
return res.isError ? (-1) : 0;
}
/* Nb: we do not allow the Linux extension which malloc()s memory for the
buffer if buf==NULL, because we don't want Linux calling malloc() */
Char* VG_(getcwd) ( Char* buf, SizeT size )
{
SysRes res;
vg_assert(buf != NULL);
res = VG_(do_syscall2)(__NR_getcwd, (UWord)buf, size);
return res.isError ? ((Char*)NULL) : (Char*)res.val;
}
/* Alternative version that does allocate the memory. Easier to use. */
Bool VG_(getcwd_alloc) ( Char** out )
{
SizeT size = 4;
*out = NULL;
while (True) {
*out = VG_(malloc)(size);
if (NULL == VG_(getcwd)(*out, size)) {
VG_(free)(*out);
if (size > 65535)
return False;
size *= 2;
} else {
return True;
}
}
}
Int VG_(readlink) (Char* path, Char* buf, UInt bufsiz)
{
SysRes res;
/* res = readlink( path, buf, bufsiz ); */
res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
return res.isError ? -1 : res.val;
}
Int VG_(getdents) (UInt fd, struct vki_dirent *dirp, UInt count)
{
SysRes res;
/* res = getdents( fd, dirp, count ); */
res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
return res.isError ? -1 : res.val;
}
/* ---------------------------------------------------------------------
Socket-related stuff. This is very Linux-kernel specific.
------------------------------------------------------------------ */
static
Int parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port );
static
Int my_socket ( Int domain, Int type, Int protocol );
static
Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr,
Int addrlen );
static
UInt my_htonl ( UInt x )
{
return
(((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
| (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
}
static
UShort my_htons ( UShort x )
{
return
(((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
}
/* The main function.
Supplied string contains either an ip address "192.168.0.1" or
an ip address and port pair, "192.168.0.1:1500". Parse these,
and return:
-1 if there is a parse error
-2 if no parse error, but specified host:port cannot be opened
the relevant file (socket) descriptor, otherwise.
is used.
*/
Int VG_(connect_via_socket)( UChar* str )
{
Int sd, res;
struct vki_sockaddr_in servAddr;
UInt ip = 0;
UShort port = VG_CLO_DEFAULT_LOGPORT;
Bool ok = parse_inet_addr_and_port(str, &ip, &port);
if (!ok)
return -1;
//if (0)
// VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
// (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
// (ip >> 8) & 0xFF, ip & 0xFF,
// (UInt)port );
servAddr.sin_family = VKI_AF_INET;
servAddr.sin_addr.s_addr = my_htonl(ip);
servAddr.sin_port = my_htons(port);
/* create socket */
sd = my_socket(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
if (sd < 0) {
/* this shouldn't happen ... nevertheless */
return -2;
}
/* connect to server */
res = my_connect(sd, (struct vki_sockaddr_in *) &servAddr,
sizeof(servAddr));
if (res < 0) {
/* connection failed */
return -2;
}
return sd;
}
/* Let d = one or more digits. Accept either:
d.d.d.d or d.d.d.d:d
*/
Int parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port )
{
# define GET_CH ((*str) ? (*str++) : 0)
UInt ipa, i, j, c, any;
ipa = 0;
for (i = 0; i < 4; i++) {
j = 0;
any = 0;
while (1) {
c = GET_CH;
if (c < '0' || c > '9') break;
j = 10 * j + (int)(c - '0');
any = 1;
}
if (any == 0 || j > 255) goto syntaxerr;
ipa = (ipa << 8) + j;
if (i <= 2 && c != '.') goto syntaxerr;
}
if (c == 0 || c == ':')
*ip_addr = ipa;
if (c == 0) goto ok;
if (c != ':') goto syntaxerr;
j = 0;
any = 0;
while (1) {
c = GET_CH;
if (c < '0' || c > '9') break;
j = j * 10 + (int)(c - '0');
any = 1;
if (j > 65535) goto syntaxerr;
}
if (any == 0 || c != 0) goto syntaxerr;
if (j < 1024) goto syntaxerr;
*port = (UShort)j;
ok:
return 1;
syntaxerr:
return 0;
# undef GET_CH
}
static
Int my_socket ( Int domain, Int type, Int protocol )
{
# if defined(VGP_x86_linux)
SysRes res;
UWord args[3];
args[0] = domain;
args[1] = type;
args[2] = protocol;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
return res.isError ? -1 : res.val;
# else
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
I_die_here;
# endif
}
static
Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr,
Int addrlen )
{
# if defined(VGP_x86_linux)
SysRes res;
UWord args[3];
args[0] = sockfd;
args[1] = (UWord)serv_addr;
args[2] = addrlen;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
return res.isError ? -1 : res.val;
# else
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
I_die_here;
# endif
}
Int VG_(write_socket)( Int sd, void *msg, Int count )
{
/* This is actually send(). */
/* Requests not to send SIGPIPE on errors on stream oriented
sockets when the other end breaks the connection. The EPIPE
error is still returned. */
Int flags = VKI_MSG_NOSIGNAL;
# if defined(VGP_x86_linux)
SysRes res;
UWord args[4];
args[0] = sd;
args[1] = (UWord)msg;
args[2] = count;
args[3] = flags;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
return res.isError ? -1 : res.val;
# else
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
I_die_here;
# endif
}
Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
# if defined(VGP_x86_linux)
SysRes res;
UWord args[3];
args[0] = sd;
args[1] = (UWord)name;
args[2] = (UWord)namelen;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
return res.isError ? -1 : res.val;
# else
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
I_die_here;
# endif
}
Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
# if defined(VGP_x86_linux)
SysRes res;
UWord args[3];
args[0] = sd;
args[1] = (UWord)name;
args[2] = (UWord)namelen;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
return res.isError ? -1 : res.val;
# else
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
I_die_here;
# endif
}
Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
Int *optlen)
{
# if defined(VGP_x86_linux)
SysRes res;
UWord args[5];
args[0] = sd;
args[1] = level;
args[2] = optname;
args[3] = (UWord)optval;
args[4] = (UWord)optlen;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
return res.isError ? -1 : res.val;
# else
I_die_here;
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
# endif
}
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/