diff options
Diffstat (limited to 'coregrind/m_libcfile.c')
-rw-r--r-- | coregrind/m_libcfile.c | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c new file mode 100644 index 0000000..d60c552 --- /dev/null +++ b/coregrind/m_libcfile.c @@ -0,0 +1,858 @@ + +/*--------------------------------------------------------------------*/ +/*--- File- and socket-related libc stuff. m_libcfile.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 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 "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcfile.h" +#include "pub_core_libcprint.h" // VG_(sprintf) +#include "pub_core_libcproc.h" // VG_(getpid), VG_(getppid) +#include "pub_core_xarray.h" +#include "pub_core_clientstate.h" // VG_(fd_hard_limit) +#include "pub_core_syscall.h" + +/* --------------------------------------------------------------------- + File stuff + ------------------------------------------------------------------ */ + +static inline Bool fd_exists(Int fd) +{ + struct vg_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); + + /* Set the close-on-exec flag for this fd. */ + VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC); + + vg_assert(newfd >= VG_(fd_hard_limit)); + return newfd; +} + +/* Given a file descriptor, attempt to deduce its filename. To do + this, we use /proc/self/fd/<FD>. If this doesn't point to a file, + or if it doesn't exist, we return False. */ +Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf ) +{ +# if defined(VGO_linux) + HChar tmp[64]; + VG_(sprintf)(tmp, "/proc/self/fd/%d", fd); + VG_(memset)(buf, 0, n_buf); + if (VG_(readlink)(tmp, buf, n_buf) > 0 && buf[0] == '/') + return True; + else + return False; +# elif defined(VGO_aix5) + I_die_here; /* maybe just return False? */ + return False; +# else +# error "need fd-to-filename for this OS" +# endif +} + +SysRes VG_(open) ( const Char* pathname, Int flags, Int mode ) +{ + SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode); + return res; +} + +void VG_(close) ( Int fd ) +{ + (void)VG_(do_syscall1)(__NR_close, fd); +} + +Int VG_(read) ( Int fd, void* buf, Int count) +{ + Int ret; + SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count); + if (res.isError) { + ret = - (Int)(Word)res.err; + vg_assert(ret < 0); + } else { + ret = (Int)(Word)res.res; + vg_assert(ret >= 0); + } + return ret; +} + +Int VG_(write) ( Int fd, const void* buf, Int count) +{ + Int ret; + SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count); + if (res.isError) { + ret = - (Int)(Word)res.err; + vg_assert(ret < 0); + } else { + ret = (Int)(Word)res.res; + vg_assert(ret >= 0); + } + return ret; +} + +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) : res.res; + /* if you change the error-reporting conventions of this, also + change VG_(pread) and all other usage points. */ +} + + +/* stat/fstat support. It's uggerly. We have impedance-match into a + 'struct vg_stat' in order to have a single structure that callers + can use consistently on all platforms. */ + +#define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \ + do { \ + (_p_vgstat)->st_dev = (ULong)( (_p_vkistat)->st_dev ); \ + (_p_vgstat)->st_ino = (ULong)( (_p_vkistat)->st_ino ); \ + (_p_vgstat)->st_nlink = (ULong)( (_p_vkistat)->st_nlink ); \ + (_p_vgstat)->st_mode = (UInt)( (_p_vkistat)->st_mode ); \ + (_p_vgstat)->st_uid = (UInt)( (_p_vkistat)->st_uid ); \ + (_p_vgstat)->st_gid = (UInt)( (_p_vkistat)->st_gid ); \ + (_p_vgstat)->st_rdev = (ULong)( (_p_vkistat)->st_rdev ); \ + (_p_vgstat)->st_size = (Long)( (_p_vkistat)->st_size ); \ + (_p_vgstat)->st_blksize = (ULong)( (_p_vkistat)->st_blksize ); \ + (_p_vgstat)->st_blocks = (ULong)( (_p_vkistat)->st_blocks ); \ + (_p_vgstat)->st_atime = (ULong)( (_p_vkistat)->st_atime ); \ + (_p_vgstat)->st_atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \ + (_p_vgstat)->st_mtime = (ULong)( (_p_vkistat)->st_mtime ); \ + (_p_vgstat)->st_mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \ + (_p_vgstat)->st_ctime = (ULong)( (_p_vkistat)->st_ctime ); \ + (_p_vgstat)->st_ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \ + } while (0) + +SysRes VG_(stat) ( Char* file_name, struct vg_stat* vgbuf ) +{ + SysRes res; + VG_(memset)(vgbuf, 0, sizeof(*vgbuf)); +# if defined(VGO_linux) +# if defined(__NR_stat64) + { struct vki_stat64 buf64; + res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64); + if (!(res.isError && res.err == VKI_ENOSYS)) { + /* Success, or any failure except ENOSYS */ + if (!res.isError) + TRANSLATE_TO_vg_stat(vgbuf, &buf64); + return res; + } + } +# endif /* if defined(__NR_stat64) */ + { struct vki_stat buf; + res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf); + if (!res.isError) + TRANSLATE_TO_vg_stat(vgbuf, &buf); + return res; + } +# elif defined(VGO_aix5) + { struct vki_stat buf; + res = VG_(do_syscall4)(__NR_AIX5_statx, + (UWord)file_name, + (UWord)&buf, + sizeof(struct vki_stat), + VKI_STX_NORMAL); + if (!res.isError) { + VG_(memset)(vgbuf, 0, sizeof(*vgbuf)); + vgbuf->st_dev = (ULong)buf.st_dev; + vgbuf->st_ino = (ULong)buf.st_ino; + vgbuf->st_mode = (UInt)buf.st_mode; + vgbuf->st_uid = (UInt)buf.st_uid; + vgbuf->st_gid = (UInt)buf.st_gid; + vgbuf->st_size = (Long)buf.st_size; + } + return res; + } +# else +# error Unknown OS +# endif +} + +Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf ) +{ + SysRes res; + VG_(memset)(vgbuf, 0, sizeof(*vgbuf)); +# if defined(VGO_linux) +# if defined(__NR_fstat64) + { struct vki_stat64 buf64; + res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64); + if (!(res.isError && res.err == VKI_ENOSYS)) { + /* Success, or any failure except ENOSYS */ + if (!res.isError) + TRANSLATE_TO_vg_stat(vgbuf, &buf64); + return res.isError ? (-1) : 0; + } + } +# endif /* if defined(__NR_fstat64) */ + { struct vki_stat buf; + res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf); + if (!res.isError) + TRANSLATE_TO_vg_stat(vgbuf, &buf); + return res.isError ? (-1) : 0; + } +# elif defined(VGO_aix5) + I_die_here; +# else +# error Unknown OS +# endif +} + +#undef TRANSLATE_TO_vg_stat + + +Long VG_(fsize) ( Int fd ) +{ + struct vg_stat buf; + Int res = VG_(fstat)( fd, &buf ); + return (res == -1) ? (-1LL) : buf.st_size; +} + +Bool VG_(is_dir) ( HChar* f ) +{ + struct vg_stat buf; + SysRes res = VG_(stat)(f, &buf); + return res.isError ? False + : VKI_S_ISDIR(buf.st_mode) ? True : False; +} + +SysRes VG_(dup) ( Int oldfd ) +{ + return VG_(do_syscall1)(__NR_dup, oldfd); +} + +SysRes VG_(dup2) ( Int oldfd, Int newfd ) +{ +# if defined(VGO_linux) + return VG_(do_syscall2)(__NR_dup2, oldfd, newfd); +# elif defined(VGO_aix5) + I_die_here; +# else +# error Unknown OS +# endif +} + +/* Returns -1 on error. */ +Int VG_(fcntl) ( Int fd, Int cmd, Int arg ) +{ + SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg); + return res.isError ? -1 : res.res; +} + +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; +} + +/* The working directory at startup. AIX doesn't provide an easy + system call to do getcwd, but fortunately we don't need arbitrary + getcwd support. All that is really needed is to note the cwd at + process startup. Hence VG_(record_startup_wd) notes it (in a + platform dependent way) and VG_(get_startup_wd) produces the noted + value. Hence: */ +static HChar startup_wd[VKI_PATH_MAX]; +static Bool startup_wd_acquired = False; + +/* Record the process' working directory at startup. Is intended to + be called exactly once, at startup, before the working directory + changes. Return True for success, False for failure, so that the + caller can bomb out suitably without creating module cycles if + there is a problem. */ +Bool VG_(record_startup_wd) ( void ) +{ + const Int szB = sizeof(startup_wd); + vg_assert(!startup_wd_acquired); + vg_assert(szB >= 512 && szB <= 16384/*let's say*/); /* stay sane */ + VG_(memset)(startup_wd, 0, szB); +# if defined(VGO_linux) + /* Simple: just ask the kernel */ + { SysRes res + = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1); + vg_assert(startup_wd[szB-1] == 0); + if (res.isError) { + return False; + } else { + startup_wd_acquired = True; + return True; + } + } +# elif defined(VGO_aix5) + /* We can't ask the kernel, so instead rely on launcher-aix5.c to + tell us the startup path. Note the env var is keyed to the + parent's PID, not ours, since our parent is the launcher + process. */ + { Char envvar[100]; + Char* wd = NULL; + VG_(memset)(envvar, 0, sizeof(envvar)); + VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY", + (Int)VG_(getppid)()); + wd = VG_(getenv)( envvar ); + if (wd == NULL || (1+VG_(strlen)(wd) >= szB)) + return False; + VG_(strncpy_safely)(startup_wd, wd, szB); + vg_assert(startup_wd[szB-1] == 0); + startup_wd_acquired = True; + return True; + } +# else +# error Unknown OS +# endif +} + +/* Copy the previously acquired startup_wd into buf[0 .. size-1], + or return False if buf isn't big enough. */ +Bool VG_(get_startup_wd) ( Char* buf, SizeT size ) +{ + vg_assert(startup_wd_acquired); + vg_assert(startup_wd[ sizeof(startup_wd)-1 ] == 0); + if (1+VG_(strlen)(startup_wd) >= size) + return False; + VG_(strncpy_safely)(buf, startup_wd, size); + 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.res; +} + +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.res; +} + +/* Check accessibility of a file. Returns zero for access granted, + nonzero otherwise. */ +Int VG_(access) ( HChar* path, Bool irusr, Bool iwusr, Bool ixusr ) +{ +# if defined(VGO_linux) + /* Very annoyingly, I cannot find any definition for R_OK et al in + the kernel interfaces. Therefore I reluctantly resort to + hardwiring in these magic numbers that I determined by + experimentation. */ + UWord w = (irusr ? 4/*R_OK*/ : 0) + | (iwusr ? 2/*W_OK*/ : 0) + | (ixusr ? 1/*X_OK*/ : 0); + SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w); + return res.isError ? 1 : 0; +# elif defined(VGO_aix5) + UWord w = (irusr ? VKI_R_OK : 0) + | (iwusr ? VKI_W_OK : 0) + | (ixusr ? VKI_X_OK : 0); + SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w); + return res.isError ? 1 : 0; +# else +# error "Don't know how to do VG_(access) on this OS" +# endif +} + +/* + Emulate the normal Unix permissions checking algorithm. + + If owner matches, then use the owner permissions, else + if group matches, then use the group permissions, else + use other permissions. + + Note that we can't deal properly with SUID/SGID. By default + (allow_setuid == False), we refuse to run them (otherwise the + executable may misbehave if it doesn't have the permissions it + thinks it does). However, the caller may indicate that setuid + executables are allowed, for example if we are going to exec them + but not trace into them (iow, client sys_execve when + clo_trace_children == False). + + If VKI_EACCES is returned (iow, permission was refused), then + *is_setuid is set to True iff permission was refused because the + executable is setuid. +*/ +/* returns: 0 = success, non-0 is failure */ +Int VG_(check_executable)(/*OUT*/Bool* is_setuid, + HChar* f, Bool allow_setuid) +{ + struct vg_stat st; + SysRes res = VG_(stat)(f, &st); + + if (is_setuid) + *is_setuid = False; + + if (res.isError) { + return res.err; + } + + if ( (st.st_mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) { + if (is_setuid) + *is_setuid = True; + return VKI_EACCES; + } + + if (VG_(geteuid)() == st.st_uid) { + if (!(st.st_mode & VKI_S_IXUSR)) + return VKI_EACCES; + } else { + Int grpmatch = 0; + + if (VG_(getegid)() == st.st_gid) + grpmatch = 1; + else { + UInt groups[32]; + Int ngrp = VG_(getgroups)(32, groups); + Int i; + /* ngrp will be -1 if VG_(getgroups) failed. */ + for (i = 0; i < ngrp; i++) { + if (groups[i] == st.st_gid) { + grpmatch = 1; + break; + } + } + } + + if (grpmatch) { + if (!(st.st_mode & VKI_S_IXGRP)) { + return VKI_EACCES; + } + } else if (!(st.st_mode & VKI_S_IXOTH)) { + return VKI_EACCES; + } + } + + return 0; +} + +SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset ) +{ + OffT off = VG_(lseek)( fd, (OffT)offset, VKI_SEEK_SET); + if (off < 0) + return VG_(mk_SysRes_Error)( VKI_EINVAL ); + return VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count ); +} + +/* Create and open (-rw------) a tmp file name incorporating said arg. + Returns -1 on failure, else the fd of the file. If fullname is + non-NULL, the file's name is written into it. The number of bytes + written is guaranteed not to exceed 64+strlen(part_of_name). */ + +Int VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname ) +{ + HChar buf[200]; + Int n, tries, fd; + UInt seed; + SysRes sres; + + vg_assert(part_of_name); + n = VG_(strlen)(part_of_name); + vg_assert(n > 0 && n < 100); + + seed = (VG_(getpid)() << 9) ^ VG_(getppid)(); + + tries = 0; + while (True) { + if (tries > 10) + return -1; + VG_(sprintf)( buf, "/tmp/valgrind_%s_%08x", + part_of_name, VG_(random)( &seed )); + if (0) + VG_(printf)("VG_(mkstemp): trying: %s\n", buf); + + sres = VG_(open)(buf, + VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC, + VKI_S_IRUSR|VKI_S_IWUSR); + if (sres.isError) + continue; + /* VG_(safe_fd) doesn't return if it fails. */ + fd = VG_(safe_fd)( sres.res ); + if (fullname) + VG_(strcpy)( fullname, buf ); + return fd; + } + /* NOTREACHED */ +} + + +/* --------------------------------------------------------------------- + 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, +# if defined(VGO_linux) + struct vki_sockaddr_in* serv_addr, +# else + void* serv_addr, +# endif + Int addrlen ); + +UInt VG_(htonl) ( UInt x ) +{ +# if defined(VG_BIGENDIAN) + return x; +# else + return + (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8) + | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24); +# endif +} + +UInt VG_(ntohl) ( UInt x ) +{ +# if defined(VG_BIGENDIAN) + return x; +# else + return + (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8) + | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24); +# endif +} + +UShort VG_(htons) ( UShort x ) +{ +# if defined(VG_BIGENDIAN) + return x; +# else + return + (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8); +# endif +} + +UShort VG_(ntohs) ( UShort x ) +{ +# if defined(VG_BIGENDIAN) + return x; +# else + return + (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8); +# endif +} + + +/* 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 ) +{ +#if defined(VGO_aix5) + I_die_here; +#else /* Yay, Linux */ + 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 = VG_(htonl)(ip); + servAddr.sin_port = VG_(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; +#endif +} + + +/* Let d = one or more digits. Accept either: + d.d.d.d or d.d.d.d:d +*/ +static 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) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_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.res; + +#elif defined(VGP_amd64_linux) + SysRes res; + res = VG_(do_syscall3)(__NR_socket, domain, type, protocol ); + return res.isError ? -1 : res.res; + +#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) + I_die_here; + +#else +# error Unknown arch +#endif +} + +static +Int my_connect ( Int sockfd, +# if defined(VGO_linux) + struct vki_sockaddr_in* serv_addr, +# else + void* serv_addr, +# endif + Int addrlen ) +{ +#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_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.res; + +#elif defined(VGP_amd64_linux) + SysRes res; + res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen); + return res.isError ? -1 : res.res; + +#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) + I_die_here; + +#else +# error Unknown arch +#endif +} + +Int VG_(write_socket)( Int sd, void *msg, Int count ) +{ + /* This is actually send(). */ + /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on + errors on stream oriented sockets when the other end breaks the + connection. The EPIPE error is still returned. */ + +#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) + SysRes res; + UWord args[4]; + args[0] = sd; + args[1] = (UWord)msg; + args[2] = count; + args[3] = VKI_MSG_NOSIGNAL; + res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args); + return res.isError ? -1 : res.res; + +#elif defined(VGP_amd64_linux) + SysRes res; + res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg, + count, VKI_MSG_NOSIGNAL, 0,0); + return res.isError ? -1 : res.res; + +#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) + I_die_here; + +#else +# error Unknown arch +#endif +} + +Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen) +{ +#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_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.res; + +#elif defined(VGP_amd64_linux) + SysRes res; + res = VG_(do_syscall3)( __NR_getsockname, + (UWord)sd, (UWord)name, (UWord)namelen ); + return res.isError ? -1 : res.res; + +#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) + I_die_here; + +#else +# error Unknown arch +#endif +} + +Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen) +{ +#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_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.res; + +#elif defined(VGP_amd64_linux) + SysRes res; + res = VG_(do_syscall3)( __NR_getpeername, + (UWord)sd, (UWord)name, (UWord)namelen ); + return res.isError ? -1 : res.res; + +#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) + I_die_here; + +#else +# error Unknown arch +#endif +} + +Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval, + Int *optlen) +{ +#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_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.res; + +#elif defined(VGP_amd64_linux) + SysRes res; + res = VG_(do_syscall5)( __NR_getsockopt, + (UWord)sd, (UWord)level, (UWord)optname, + (UWord)optval, (UWord)optlen ); + return res.isError ? -1 : res.res; + +#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) + I_die_here; + +#else +# error Unknown arch +#endif +} + + + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ + |