blob: 650696acf0e58f30448a677a7ec657117b36c290 [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Reimplementation of some C library stuff, to avoid depending ---*/
/*--- on libc.so. ---*/
/*--- vg_mylibc.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, an extensible x86 protected-mode
emulator for monitoring program execution on x86-Unixes.
Copyright (C) 2000-2004 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"
/* ---------------------------------------------------------------------
Wrappers around system calls, and other stuff, to do with signals.
------------------------------------------------------------------ */
/* sigemptyset, sigfullset, sigaddset and sigdelset return 0 on
success and -1 on error.
*/
Int VG_(sigfillset)( vki_sigset_t* set )
{
Int i;
if (set == NULL)
return -1;
for (i = 0; i < _VKI_NSIG_WORDS; i++)
set->sig[i] = ~(UWord)0x0;
return 0;
}
Int VG_(sigemptyset)( vki_sigset_t* set )
{
Int i;
if (set == NULL)
return -1;
for (i = 0; i < _VKI_NSIG_WORDS; i++)
set->sig[i] = 0x0;
return 0;
}
Bool VG_(isemptysigset)( vki_sigset_t* set )
{
Int i;
vg_assert(set != NULL);
for (i = 0; i < _VKI_NSIG_WORDS; i++)
if (set->sig[i] != 0x0) return False;
return True;
}
Bool VG_(isfullsigset)( vki_sigset_t* set )
{
Int i;
vg_assert(set != NULL);
for (i = 0; i < _VKI_NSIG_WORDS; i++)
if (set->sig[i] != ~(UWord)0x0) return False;
return True;
}
Int VG_(sigaddset)( vki_sigset_t* set, Int signum )
{
if (set == NULL)
return -1;
if (signum < 1 || signum > _VKI_NSIG)
return -1;
signum--;
set->sig[signum / _VKI_NSIG_BPW] |= (1 << (signum % _VKI_NSIG_BPW));
return 0;
}
Int VG_(sigdelset)( vki_sigset_t* set, Int signum )
{
if (set == NULL)
return -1;
if (signum < 1 || signum > _VKI_NSIG)
return -1;
signum--;
set->sig[signum / _VKI_NSIG_BPW] &= ~(1 << (signum % _VKI_NSIG_BPW));
return 0;
}
Int VG_(sigismember) ( vki_sigset_t* set, Int signum )
{
if (set == NULL)
return 0;
if (signum < 1 || signum > _VKI_NSIG)
return 0;
signum--;
if (1 & ((set->sig[signum / _VKI_NSIG_BPW]) >> (signum % _VKI_NSIG_BPW)))
return 1;
else
return 0;
}
/* Add all signals in src to dst. */
void VG_(sigaddset_from_set)( vki_sigset_t* dst, vki_sigset_t* src )
{
Int i;
vg_assert(dst != NULL && src != NULL);
for (i = 0; i < _VKI_NSIG_WORDS; i++)
dst->sig[i] |= src->sig[i];
}
/* Remove all signals in src from dst. */
void VG_(sigdelset_from_set)( vki_sigset_t* dst, vki_sigset_t* src )
{
Int i;
vg_assert(dst != NULL && src != NULL);
for (i = 0; i < _VKI_NSIG_WORDS; i++)
dst->sig[i] &= ~(src->sig[i]);
}
/* The functions sigaction, sigprocmask, sigpending and sigsuspend
return 0 on success and -1 on error.
*/
Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset)
{
Int res
= VG_(do_syscall)(__NR_rt_sigprocmask,
how, (UWord)set, (UWord)oldset,
_VKI_NSIG_WORDS * sizeof(UWord));
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(sigaction) ( Int signum, const struct vki_sigaction* act,
struct vki_sigaction* oldact)
{
Int res
= VG_(do_syscall)(__NR_rt_sigaction,
signum, (UWord)act, (UWord)oldact,
_VKI_NSIG_WORDS * sizeof(UWord));
/* VG_(printf)("res = %d\n",res); */
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(sigaltstack)( const vki_stack_t* ss, vki_stack_t* oss )
{
Int res = VG_(do_syscall)(__NR_sigaltstack, (UWord)ss, (UWord)oss);
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(sigtimedwait)( const vki_sigset_t *set, vki_siginfo_t *info,
const struct vki_timespec *timeout )
{
Int res = VG_(do_syscall)(__NR_rt_sigtimedwait, set, info, timeout, sizeof(*set));
return VG_(is_kerror)(res) ? -1 : res;
}
Int VG_(signal)(Int signum, void (*sighandler)(Int))
{
Int res;
struct vki_sigaction sa;
sa.ksa_handler = sighandler;
sa.sa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
sa.sa_restorer = NULL;
res = VG_(sigemptyset)( &sa.sa_mask );
vg_assert(res == 0);
res = VG_(do_syscall)(__NR_rt_sigaction,
signum, (UWord)&sa, (UWord)NULL,
_VKI_NSIG_WORDS * sizeof(UWord));
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(kill)( Int pid, Int signo )
{
Int res = VG_(do_syscall)(__NR_kill, pid, signo);
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(tkill)( Int tid, Int signo )
{
Int ret = -VKI_ENOSYS;
#ifdef __NR_tgkill
ret = VG_(do_syscall)(__NR_tgkill, VG_(main_pid), tid, signo);
#endif /* __NR_tgkill */
#ifdef __NR_tkill
if (ret == -VKI_ENOSYS)
ret = VG_(do_syscall)(__NR_tkill, tid, signo);
#endif /* __NR_tkill */
if (ret == -VKI_ENOSYS)
ret = VG_(do_syscall)(__NR_kill, tid, signo);
return VG_(is_kerror)(ret) ? -1 : 0;
}
Int VG_(sigpending) ( vki_sigset_t* set )
{
Int res = VG_(do_syscall)(__NR_sigpending, (UWord)set);
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(waitpid)(Int pid, Int *status, Int options)
{
Int ret = VG_(do_syscall)(__NR_wait4, pid, status, options, NULL);
return VG_(is_kerror)(ret) ? -1 : ret;
}
Int VG_(gettid)(void)
{
Int ret;
ret = VG_(do_syscall)(__NR_gettid);
if (ret == -VKI_ENOSYS) {
Char pid[16];
/*
* The gettid system call does not exist. The obvious assumption
* to make at this point would be that we are running on an older
* system where the getpid system call actually returns the ID of
* the current thread.
*
* Unfortunately it seems that there are some systems with a kernel
* where getpid has been changed to return the ID of the thread group
* leader but where the gettid system call has not yet been added.
*
* So instead of calling getpid here we use readlink to see where
* the /proc/self link is pointing...
*/
if ((ret = VG_(do_syscall)(__NR_readlink, "/proc/self", pid, sizeof(pid))) >= 0) {
pid[ret] = '\0';
ret = VG_(atoll)(pid);
}
}
return ret;
}
/* ---------------------------------------------------------------------
mmap/munmap, exit, fcntl
------------------------------------------------------------------ */
static Int munmap_inner(void *start, SizeT length)
{
return VG_(do_syscall)(__NR_munmap, (UWord)start, length );
}
static Addr mmap_inner(void *start, SizeT length, UInt prot, UInt flags,
UInt fd, OffT offset)
{
Int ret;
PLATFORM_DO_MMAP(ret, start, length, prot,
flags & ~(VKI_MAP_NOSYMS|VKI_MAP_CLIENT),
fd, offset);
return ret;
}
/* Returns -1 on failure. */
void* VG_(mmap)( void* start, SizeT length,
UInt prot, UInt flags, UInt sf_flags, UInt fd, OffT offset)
{
Addr res;
if (!(flags & VKI_MAP_FIXED)) {
start = (void *)VG_(find_map_space)((Addr)start, length, !!(flags & VKI_MAP_CLIENT));
flags |= VKI_MAP_FIXED;
}
if (start == 0)
return (void *)-1;
res = mmap_inner(start, length, prot, flags, fd, offset);
// Check it ended up in the right place.
if (!VG_(is_kerror)(res)) {
if (flags & VKI_MAP_CLIENT) {
vg_assert(VG_(client_base) <= res && res+length <= VG_(client_end));
} else {
vg_assert(VG_(valgrind_base) <= res && res+length-1 <= VG_(valgrind_last));
}
sf_flags |= SF_MMAP;
if ( flags & VKI_MAP_FIXED) sf_flags |= SF_FIXED;
if ( flags & VKI_MAP_SHARED) sf_flags |= SF_SHARED;
if (!(flags & VKI_MAP_ANONYMOUS)) sf_flags |= SF_FILE;
if (!(flags & VKI_MAP_CLIENT)) sf_flags |= SF_VALGRIND;
if ( flags & VKI_MAP_NOSYMS) sf_flags |= SF_NOSYMS;
VG_(map_fd_segment)(res, length, prot, sf_flags, fd, offset, NULL);
}
return VG_(is_kerror)(res) ? ((void*)(-1)) : (void*)res;
}
/* Returns -1 on failure. */
Int VG_(munmap)( void* start, SizeT length )
{
Int res = munmap_inner(start, length);
if (!VG_(is_kerror)(res))
VG_(unmap_range)((Addr)start, length);
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(mprotect)( void *start, SizeT length, UInt prot )
{
Int res = VG_(do_syscall)(__NR_mprotect, (UWord)start, length, prot );
if (!VG_(is_kerror)(res))
VG_(mprotect_range)((Addr)start, length, prot);
return VG_(is_kerror)(res) ? -1 : 0;
}
void VG_(exit)( Int status )
{
(void)VG_(do_syscall)(__NR_exit_group, status );
(void)VG_(do_syscall)(__NR_exit, status );
/* Why are we still alive here? */
/*NOTREACHED*/
*(volatile Int *)0 = 'x';
vg_assert(2+2 == 5);
}
/* Returns -1 on error. */
Int VG_(fcntl) ( Int fd, Int cmd, Int arg )
{
Int res = VG_(do_syscall)(__NR_fcntl, fd, cmd, arg);
return VG_(is_kerror)(res) ? -1 : res;
}
Int VG_(poll)( struct vki_pollfd *ufds, UInt nfds, Int timeout)
{
Int res = VG_(do_syscall)(__NR_poll, ufds, nfds, timeout);
return res;
}
/* ---------------------------------------------------------------------
printf implementation. The key function, vg_vprintf(), emits chars
into a caller-supplied function. Distantly derived from:
vprintf replacement for Checker.
Copyright 1993, 1994, 1995 Tristan Gingold
Written September 1993 Tristan Gingold
Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
(Checker itself was GPL'd.)
------------------------------------------------------------------ */
/* Some flags. */
#define VG_MSG_SIGNED 1 /* The value is signed. */
#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
/* Copy a string into the buffer. */
static UInt
myvprintf_str ( void(*send)(Char), Int flags, Int width, Char* str,
Bool capitalise )
{
# define MAYBE_TOUPPER(ch) (capitalise ? VG_(toupper)(ch) : (ch))
UInt ret = 0;
Int i, extra;
Int len = VG_(strlen)(str);
if (width == 0) {
ret += len;
for (i = 0; i < len; i++)
send(MAYBE_TOUPPER(str[i]));
return ret;
}
if (len > width) {
ret += width;
for (i = 0; i < width; i++)
send(MAYBE_TOUPPER(str[i]));
return ret;
}
extra = width - len;
if (flags & VG_MSG_LJUSTIFY) {
ret += extra;
for (i = 0; i < extra; i++)
send(' ');
}
ret += len;
for (i = 0; i < len; i++)
send(MAYBE_TOUPPER(str[i]));
if (!(flags & VG_MSG_LJUSTIFY)) {
ret += extra;
for (i = 0; i < extra; i++)
send(' ');
}
# undef MAYBE_TOUPPER
return ret;
}
/* Write P into the buffer according to these args:
* If SIGN is true, p is a signed.
* BASE is the base.
* If WITH_ZERO is true, '0' must be added.
* WIDTH is the width of the field.
*/
static UInt
myvprintf_int64 ( void(*send)(Char), Int flags, Int base, Int width, ULong p)
{
Char buf[40];
Int ind = 0;
Int i, nc = 0;
Bool neg = False;
Char *digits = "0123456789ABCDEF";
UInt ret = 0;
if (base < 2 || base > 16)
return ret;
if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
p = - (Long)p;
neg = True;
}
if (p == 0)
buf[ind++] = '0';
else {
while (p > 0) {
if (flags & VG_MSG_COMMA && 10 == base &&
0 == (ind-nc) % 3 && 0 != ind)
{
buf[ind++] = ',';
nc++;
}
buf[ind++] = digits[p % base];
p /= base;
}
}
if (neg)
buf[ind++] = '-';
if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
for(; ind < width; ind++) {
vg_assert(ind < 39);
buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
}
}
/* Reverse copy to buffer. */
ret += ind;
for (i = ind -1; i >= 0; i--) {
send(buf[i]);
}
if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
for(; ind < width; ind++) {
ret++;
send(' '); // Never pad with zeroes on RHS -- changes the value!
}
}
return ret;
}
/* A simple vprintf(). */
UInt
VG_(vprintf) ( void(*send)(Char), const Char *format, va_list vargs )
{
UInt ret = 0;
int i;
int flags;
int width;
Bool is_long;
/* We assume that vargs has already been initialised by the
caller, using va_start, and that the caller will similarly
clean up with va_end.
*/
for (i = 0; format[i] != 0; i++) {
if (format[i] != '%') {
send(format[i]);
ret++;
continue;
}
i++;
/* A '%' has been found. Ignore a trailing %. */
if (format[i] == 0)
break;
if (format[i] == '%') {
/* `%%' is replaced by `%'. */
send('%');
ret++;
continue;
}
flags = 0;
is_long = False;
width = 0; /* length of the field. */
if (format[i] == '(') {
flags |= VG_MSG_PAREN;
i++;
}
/* If ',' follows '%', commas will be inserted. */
if (format[i] == ',') {
flags |= VG_MSG_COMMA;
i++;
}
/* If '-' follows '%', justify on the left. */
if (format[i] == '-') {
flags |= VG_MSG_LJUSTIFY;
i++;
}
/* If '0' follows '%', pads will be inserted. */
if (format[i] == '0') {
flags |= VG_MSG_ZJUSTIFY;
i++;
}
/* Compute the field length. */
while (format[i] >= '0' && format[i] <= '9') {
width *= 10;
width += format[i++] - '0';
}
while (format[i] == 'l') {
i++;
is_long = True;
}
switch (format[i]) {
case 'd': /* %d */
flags |= VG_MSG_SIGNED;
if (is_long)
ret += myvprintf_int64(send, flags, 10, width,
(ULong)(va_arg (vargs, Long)));
else
ret += myvprintf_int64(send, flags, 10, width,
(ULong)(va_arg (vargs, Int)));
break;
case 'u': /* %u */
if (is_long)
ret += myvprintf_int64(send, flags, 10, width,
(ULong)(va_arg (vargs, ULong)));
else
ret += myvprintf_int64(send, flags, 10, width,
(ULong)(va_arg (vargs, UInt)));
break;
case 'p': /* %p */
ret += 2;
send('0');
send('x');
ret += myvprintf_int64(send, flags, 16, width,
(ULong)((UWord)va_arg (vargs, void *)));
break;
case 'x': /* %x */
if (is_long)
ret += myvprintf_int64(send, flags, 16, width,
(ULong)(va_arg (vargs, ULong)));
else
ret += myvprintf_int64(send, flags, 16, width,
(ULong)(va_arg (vargs, UInt)));
break;
case 'c': /* %c */
ret++;
send(va_arg (vargs, int));
break;
case 's': case 'S': { /* %s */
char *str = va_arg (vargs, char *);
if (str == (char*) 0) str = "(null)";
ret += myvprintf_str(send, flags, width, str, format[i]=='S');
break;
}
case 'y': { /* %y - print symbol */
Char buf[100];
Char *cp = buf;
Addr a = va_arg(vargs, Addr);
if (flags & VG_MSG_PAREN)
*cp++ = '(';
if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
if (flags & VG_MSG_PAREN) {
cp += VG_(strlen)(cp);
*cp++ = ')';
*cp = '\0';
}
ret += myvprintf_str(send, flags, width, buf, 0);
}
break;
}
default:
break;
}
}
return ret;
}
/* A general replacement for printf(). Note that only low-level
debugging info should be sent via here. The official route is to
to use vg_message(). This interface is deprecated.
*/
static char myprintf_buf[100];
static int n_myprintf_buf;
static void add_to_myprintf_buf ( Char c )
{
if (n_myprintf_buf >= 100-10 /*paranoia*/ ) {
if (VG_(clo_log_fd) >= 0) {
VG_(send_bytes_to_logging_sink)(
myprintf_buf, VG_(strlen)(myprintf_buf) );
}
n_myprintf_buf = 0;
myprintf_buf[n_myprintf_buf] = 0;
}
myprintf_buf[n_myprintf_buf++] = c;
myprintf_buf[n_myprintf_buf] = 0;
}
UInt VG_(printf) ( const char *format, ... )
{
UInt ret;
va_list vargs;
va_start(vargs,format);
n_myprintf_buf = 0;
myprintf_buf[n_myprintf_buf] = 0;
ret = VG_(vprintf) ( add_to_myprintf_buf, format, vargs );
if (n_myprintf_buf > 0 && VG_(clo_log_fd) >= 0) {
VG_(send_bytes_to_logging_sink)( myprintf_buf, n_myprintf_buf );
}
va_end(vargs);
return ret;
}
/* A general replacement for sprintf(). */
static Char *vg_sprintf_ptr;
static void add_to_vg_sprintf_buf ( Char c )
{
*vg_sprintf_ptr++ = c;
}
UInt VG_(sprintf) ( Char* buf, Char *format, ... )
{
Int ret;
va_list vargs;
vg_sprintf_ptr = buf;
va_start(vargs,format);
ret = VG_(vprintf) ( add_to_vg_sprintf_buf, format, vargs );
add_to_vg_sprintf_buf(0);
va_end(vargs);
vg_assert(VG_(strlen)(buf) == ret);
return ret;
}
/* ---------------------------------------------------------------------
Misc str* functions.
------------------------------------------------------------------ */
Bool VG_(isspace) ( Char c )
{
return (c == ' ' || c == '\n' || c == '\t' || c == 0);
}
Bool VG_(isdigit) ( Char c )
{
return (c >= '0' && c <= '9');
}
Int VG_(strlen) ( const Char* str )
{
Int i = 0;
while (str[i] != 0) i++;
return i;
}
Long VG_(atoll) ( Char* str )
{
Bool neg = False;
Long n = 0;
if (*str == '-') { str++; neg = True; };
while (*str >= '0' && *str <= '9') {
n = 10*n + (Long)(*str - '0');
str++;
}
if (neg) n = -n;
return n;
}
Long VG_(atoll16) ( Char* str )
{
Bool neg = False;
Long n = 0;
if (*str == '-') { str++; neg = True; };
while (True) {
if (*str >= '0' && *str <= '9') {
n = 16*n + (Long)(*str - '0');
}
else
if (*str >= 'A' && *str <= 'F') {
n = 16*n + (Long)((*str - 'A') + 10);
}
else
if (*str >= 'a' && *str <= 'f') {
n = 16*n + (Long)((*str - 'a') + 10);
}
else {
break;
}
str++;
}
if (neg) n = -n;
return n;
}
Long VG_(atoll36) ( UInt base, Char* str )
{
Bool neg = False;
Long n = 0;
vg_assert(base >= 2 && base <= 36);
if (*str == '-') { str++; neg = True; };
while (True) {
if (*str >= '0'
&& *str <= (Char)('9' - (10 - base))) {
n = base*n + (Long)(*str - '0');
}
else
if (base > 10 && *str >= 'A'
&& *str <= (Char)('Z' - (36 - base))) {
n = base*n + (Long)((*str - 'A') + 10);
}
else
if (base > 10 && *str >= 'a'
&& *str <= (Char)('z' - (36 - base))) {
n = base*n + (Long)((*str - 'a') + 10);
}
else {
break;
}
str++;
}
if (neg) n = -n;
return n;
}
Char* VG_(strcat) ( Char* dest, const Char* src )
{
Char* dest_orig = dest;
while (*dest) dest++;
while (*src) *dest++ = *src++;
*dest = 0;
return dest_orig;
}
Char* VG_(strncat) ( Char* dest, const Char* src, Int n )
{
Char* dest_orig = dest;
while (*dest) dest++;
while (*src && n > 0) { *dest++ = *src++; n--; }
*dest = 0;
return dest_orig;
}
Char* VG_(strpbrk) ( const Char* s, const Char* accept )
{
const Char* a;
while (*s) {
a = accept;
while (*a)
if (*a++ == *s)
return (Char *) s;
s++;
}
return NULL;
}
Char* VG_(strcpy) ( Char* dest, const Char* src )
{
Char* dest_orig = dest;
while (*src) *dest++ = *src++;
*dest = 0;
return dest_orig;
}
/* Copy bytes, not overrunning the end of dest and always ensuring
zero termination. */
void VG_(strncpy_safely) ( Char* dest, const Char* src, Int ndest )
{
Int i;
vg_assert(ndest > 0);
i = 0;
dest[i] = 0;
while (True) {
if (src[i] == 0) return;
if (i >= ndest-1) return;
dest[i] = src[i];
i++;
dest[i] = 0;
}
}
Char* VG_(strncpy) ( Char* dest, const Char* src, Int ndest )
{
Int i = 0;
while (True) {
if (i >= ndest) return dest; /* reached limit */
dest[i] = src[i];
if (src[i++] == 0) {
/* reached NUL; pad rest with zeroes as required */
while (i < ndest) dest[i++] = 0;
return dest;
}
}
}
Int VG_(strcmp) ( const Char* s1, const Char* s2 )
{
while (True) {
if (*s1 == 0 && *s2 == 0) return 0;
if (*s1 == 0) return -1;
if (*s2 == 0) return 1;
if (*(UChar*)s1 < *(UChar*)s2) return -1;
if (*(UChar*)s1 > *(UChar*)s2) return 1;
s1++; s2++;
}
}
Int VG_(strcmp_ws) ( const Char* s1, const Char* s2 )
{
while (True) {
if (VG_(isspace)(*s1) && VG_(isspace)(*s2)) return 0;
if (VG_(isspace)(*s1)) return -1;
if (VG_(isspace)(*s2)) return 1;
if (*(UChar*)s1 < *(UChar*)s2) return -1;
if (*(UChar*)s1 > *(UChar*)s2) return 1;
s1++; s2++;
}
}
Int VG_(strncmp) ( const Char* s1, const Char* s2, Int nmax )
{
Int n = 0;
while (True) {
if (n >= nmax) return 0;
if (*s1 == 0 && *s2 == 0) return 0;
if (*s1 == 0) return -1;
if (*s2 == 0) return 1;
if (*(UChar*)s1 < *(UChar*)s2) return -1;
if (*(UChar*)s1 > *(UChar*)s2) return 1;
s1++; s2++; n++;
}
}
Int VG_(strncmp_ws) ( const Char* s1, const Char* s2, Int nmax )
{
Int n = 0;
while (True) {
if (n >= nmax) return 0;
if (VG_(isspace)(*s1) && VG_(isspace)(*s2)) return 0;
if (VG_(isspace)(*s1)) return -1;
if (VG_(isspace)(*s2)) return 1;
if (*(UChar*)s1 < *(UChar*)s2) return -1;
if (*(UChar*)s1 > *(UChar*)s2) return 1;
s1++; s2++; n++;
}
}
Char* VG_(strstr) ( const Char* haystack, Char* needle )
{
Int n;
if (haystack == NULL)
return NULL;
n = VG_(strlen)(needle);
while (True) {
if (haystack[0] == 0)
return NULL;
if (VG_(strncmp)(haystack, needle, n) == 0)
return (Char*)haystack;
haystack++;
}
}
Char* VG_(strchr) ( const Char* s, Char c )
{
while (True) {
if (*s == c) return (Char*)s;
if (*s == 0) return NULL;
s++;
}
}
Char* VG_(strrchr) ( const Char* s, Char c )
{
Int n = VG_(strlen)(s);
while (--n > 0) {
if (s[n] == c) return (Char*)s + n;
}
return NULL;
}
void* VG_(memcpy) ( void *dest, const void *src, Int sz )
{
const Char *s = (const Char *)src;
Char *d = (Char *)dest;
vg_assert(sz >= 0);
while (sz--)
*d++ = *s++;
return dest;
}
void* VG_(memset) ( void *dest, Int c, Int sz )
{
Char *d = (Char *)dest;
vg_assert(sz >= 0);
while (sz--)
*d++ = c;
return dest;
}
Int VG_(memcmp) ( const void* s1, const void* s2, Int n )
{
Int res;
UChar a0;
UChar b0;
vg_assert(n >= 0);
while (n != 0) {
a0 = ((UChar *) s1)[0];
b0 = ((UChar *) s2)[0];
s1 += 1;
s2 += 1;
res = a0 - b0;
if (res != 0)
return res;
n -= 1;
}
return 0;
}
Char VG_(toupper) ( Char c )
{
if (c >= 'a' && c <= 'z')
return c + ('A' - 'a');
else
return c;
}
/* Inline just for the wrapper VG_(strdup) below */
__inline__ Char* VG_(arena_strdup) ( ArenaId aid, const Char* s )
{
Int i;
Int len;
Char* res;
if (s == NULL)
return NULL;
len = VG_(strlen)(s) + 1;
res = VG_(arena_malloc) (aid, len);
for (i = 0; i < len; i++)
res[i] = s[i];
return res;
}
/* Wrapper to avoid exposing tools to ArenaId's */
Char* VG_(strdup) ( const Char* s )
{
return VG_(arena_strdup) ( VG_AR_TOOL, s );
}
/* ---------------------------------------------------------------------
A simple string matching routine, purloined from Hugs98.
`*' matches any sequence of zero or more characters
`?' matches any single character exactly
`\c' matches the character c only (ignoring special chars)
c matches the character c only
------------------------------------------------------------------ */
/* Keep track of recursion depth. */
static Int recDepth;
static Bool string_match_wrk ( const Char* pat, const Char* str )
{
vg_assert(recDepth >= 0 && recDepth < 500);
recDepth++;
for (;;) {
switch (*pat) {
case '\0' : return (*str=='\0');
case '*' : do {
if (string_match_wrk(pat+1,str)) {
recDepth--;
return True;
}
} while (*str++);
recDepth--;
return False;
case '?' : if (*str++=='\0') {
recDepth--;
return False;
}
pat++;
break;
case '\\' : if (*++pat == '\0') {
recDepth--;
return False; /* spurious trailing \ in pattern */
}
/* falls through to ... */
default : if (*pat++ != *str++) {
recDepth--;
return False;
}
break;
}
}
}
Bool VG_(string_match) ( const Char* pat, const Char* str )
{
Bool b;
recDepth = 0;
b = string_match_wrk ( pat, str );
/*
VG_(printf)("%s %s %s\n",
b?"TRUE ":"FALSE", pat, str);
*/
return b;
}
/* ---------------------------------------------------------------------
Assertery.
------------------------------------------------------------------ */
/* Fake up an ExeContext which is of our actual real CPU state, so we
can print a stack trace. This isn't terribly useful in the case
where we were killed by a signal, since we just get a backtrace
into the signal handler. Also, it could be somewhat risky if we
actully got the panic/exception within the execontext/stack
dump/symtab code. But it's better than nothing. */
static inline ExeContext *get_real_execontext(Addr ret)
{
ExeContext *ec;
Addr sp, fp;
Addr stacktop, sigstack_low, sigstack_high;
ARCH_GET_REAL_STACK_PTR(sp);
ARCH_GET_REAL_FRAME_PTR(fp);
stacktop = VG_(valgrind_last);
VG_(get_sigstack_bounds)( &sigstack_low, &sigstack_high );
if (sp >= sigstack_low && sp < sigstack_high)
stacktop = sigstack_high;
ec = VG_(get_ExeContext2)(ret, fp, sp, stacktop);
return ec;
}
__attribute__ ((noreturn))
static void report_and_quit ( const Char* report, ExeContext *ec )
{
if (ec == NULL)
ec = get_real_execontext((Addr)__builtin_return_address(0));
VG_(pp_ExeContext)(ec);
VG_(pp_sched_status)();
VG_(printf)("\n");
VG_(printf)("Note: see also the FAQ.txt in the source distribution.\n");
VG_(printf)("It contains workarounds to several common problems.\n");
VG_(printf)("\n");
VG_(printf)("If that doesn't help, please report this bug to: %s\n\n",
report);
VG_(printf)("In the bug report, send all the above text, the valgrind\n");
VG_(printf)("version, and what Linux distro you are using. Thanks.\n\n");
VG_(exit)(1);
}
__attribute__ ((noreturn))
static void assert_fail ( const Char* expr, const Char* name, const Char* report,
const Char* file, Int line, const Char* fn )
{
static Bool entered = False;
if (entered)
VG_(exit)(2);
entered = True;
VG_(printf)("\n%s: %s:%d (%s): Assertion `%s' failed.\n",
name, file, line, fn, expr );
report_and_quit(report, NULL);
}
void VG_(skin_assert_fail) ( const Char* expr, const Char* file, Int line, const Char* fn )
{
assert_fail(expr, VG_(details).name, VG_(details).bug_reports_to,
file, line, fn);
}
void VG_(core_assert_fail) ( const Char* expr, const Char* file, Int line, const Char* fn )
{
assert_fail(expr, "valgrind", VG_BUGS_TO, file, line, fn);
}
__attribute__ ((noreturn))
static void panic ( Char* name, Char* report, Char* str, ExeContext *ec )
{
VG_(printf)("\n%s: the `impossible' happened:\n %s\n", name, str);
VG_(printf)("Basic block ctr is approximately %llu\n", VG_(bbs_done) );
report_and_quit(report, ec);
}
void VG_(core_panic) ( Char* str )
{
panic("valgrind", VG_BUGS_TO, str, NULL);
}
void VG_(core_panic_at) ( Char* str, ExeContext *ec )
{
panic("valgrind", VG_BUGS_TO, str, ec);
}
void VG_(skin_panic) ( Char* str )
{
panic(VG_(details).name, VG_(details).bug_reports_to, str, NULL);
}
/* ---------------------------------------------------------------------
Primitive support for reading files.
------------------------------------------------------------------ */
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 )
{
Int fd;
/* (old comment, not sure if it still applies NJN 2002-sep-09) */
/* This gets a segmentation fault if pathname isn't a valid file.
I don't know why. It seems like the call to open is getting
intercepted and messed with by glibc ... */
/* fd = open( pathname, O_RDONLY ); */
/* ... so we go direct to the horse's mouth, which seems to work
ok: */
fd = VG_(do_syscall)(__NR_open, (UWord)pathname, flags, mode);
/* VG_(printf)("result = %d\n", fd); */
/* return -ve error code */
return fd;
}
Int VG_(pipe) ( Int fd[2] )
{
Int ret = VG_(do_syscall)(__NR_pipe, fd);
return VG_(is_kerror)(ret) ? -1 : 0;
}
void VG_(close) ( Int fd )
{
VG_(do_syscall)(__NR_close, fd);
}
Int VG_(read) ( Int fd, void* buf, Int count)
{
Int res;
/* res = read( fd, buf, count ); */
res = VG_(do_syscall)(__NR_read, fd, (UWord)buf, count);
/* return -ERRNO on error */
return res;
}
Int VG_(write) ( Int fd, const void* buf, Int count)
{
Int res;
/* res = write( fd, buf, count ); */
res = VG_(do_syscall)(__NR_write, fd, (UWord)buf, count);
/* return -ERRNO on error */
return res;
}
OffT VG_(lseek) ( Int fd, OffT offset, Int whence)
{
Int res;
/* res = lseek( fd, offset, whence ); */
res = VG_(do_syscall)(__NR_lseek, fd, offset, whence);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
Int VG_(stat) ( Char* file_name, struct vki_stat* buf )
{
Int res;
res = VG_(do_syscall)(__NR_stat, (UWord)file_name, (UWord)buf);
return res; /* return -ve error */
}
Int VG_(fstat) ( Int fd, struct vki_stat* buf )
{
Int res;
res = VG_(do_syscall)(__NR_fstat, fd, (UWord)buf);
return VG_(is_kerror)(res) ? (-1) : 0;
}
Int VG_(dup2) ( Int oldfd, Int newfd )
{
Int res;
res = VG_(do_syscall)(__NR_dup2, oldfd, newfd);
return VG_(is_kerror)(res) ? (-1) : res;
}
Int VG_(rename) ( Char* old_name, Char* new_name )
{
Int res;
res = VG_(do_syscall)(__NR_rename, (UWord)old_name, (UWord)new_name);
return VG_(is_kerror)(res) ? (-1) : 0;
}
Int VG_(unlink) ( Char* file_name )
{
Int res;
res = VG_(do_syscall)(__NR_unlink, (UWord)file_name);
return VG_(is_kerror)(res) ? (-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 )
{
Int res;
vg_assert(buf != NULL);
res = VG_(do_syscall)(__NR_getcwd, (UWord)buf, size);
return VG_(is_kerror)(res) ? ((Char*)NULL) : (Char*)res;
}
/* 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;
}
}
}
/* ---------------------------------------------------------------------
Misc functions looking for a proper home.
------------------------------------------------------------------ */
/* clone the environment */
static Char **env_clone ( Char **oldenv )
{
Char **oldenvp;
Char **newenvp;
Char **newenv;
Int envlen;
for (oldenvp = oldenv; oldenvp && *oldenvp; oldenvp++);
envlen = oldenvp - oldenv + 1;
newenv = VG_(arena_malloc)(VG_AR_CORE, envlen * sizeof(Char **));
oldenvp = oldenv;
newenvp = newenv;
while (oldenvp && *oldenvp) {
*newenvp++ = *oldenvp++;
}
*newenvp = *oldenvp;
return newenv;
}
void VG_(env_unsetenv) ( Char **env, const Char *varname )
{
Char **from;
Char **to = NULL;
Int len = VG_(strlen)(varname);
for(from = to = env; from && *from; from++) {
if (!(VG_(strncmp)(varname, *from, len) == 0 && (*from)[len] == '=')) {
*to = *from;
to++;
}
}
*to = *from;
}
/* set the environment; returns the old env if a new one was allocated */
Char **VG_(env_setenv) ( Char ***envp, const Char* varname, const Char *val )
{
Char **env = (*envp);
Char **cpp;
Int len = VG_(strlen)(varname);
Char *valstr = VG_(arena_malloc)(VG_AR_CORE, len + VG_(strlen)(val) + 2);
Char **oldenv = NULL;
VG_(sprintf)(valstr, "%s=%s", varname, val);
for(cpp = env; cpp && *cpp; cpp++) {
if (VG_(strncmp)(varname, *cpp, len) == 0 && (*cpp)[len] == '=') {
*cpp = valstr;
return oldenv;
}
}
if (env == NULL) {
env = VG_(arena_malloc)(VG_AR_CORE, sizeof(Char **) * 2);
env[0] = valstr;
env[1] = NULL;
*envp = env;
} else {
Int envlen = (cpp-env) + 2;
Char **newenv = VG_(arena_malloc)(VG_AR_CORE, envlen * sizeof(Char **));
for(cpp = newenv; *env; )
*cpp++ = *env++;
*cpp++ = valstr;
*cpp++ = NULL;
oldenv = *envp;
*envp = newenv;
}
return oldenv;
}
/* We do getenv without libc's help by snooping around in
VG_(client_envp) as determined at startup time. */
Char *VG_(getenv)(Char *varname)
{
Int i, n;
n = VG_(strlen)(varname);
for (i = 0; VG_(client_envp)[i] != NULL; i++) {
Char* s = VG_(client_envp)[i];
if (VG_(strncmp)(varname, s, n) == 0 && s[n] == '=') {
return & s[n+1];
}
}
return NULL;
}
/* Support for getrlimit. */
Int VG_(getrlimit) (Int resource, struct vki_rlimit *rlim)
{
Int res;
/* res = getrlimit( resource, rlim ); */
res = VG_(do_syscall)(__NR_getrlimit, resource, (UWord)rlim);
if(VG_(is_kerror)(res)) res = -1;
return res;
}
/* Support for setrlimit. */
Int VG_(setrlimit) (Int resource, struct vki_rlimit *rlim)
{
Int res;
/* res = setrlimit( resource, rlim ); */
res = VG_(do_syscall)(__NR_setrlimit, resource, (UWord)rlim);
if(VG_(is_kerror)(res)) res = -1;
return res;
}
/* Support for getdents. */
Int VG_(getdents) (UInt fd, struct vki_dirent *dirp, UInt count)
{
Int res;
/* res = getdents( fd, dirp, count ); */
res = VG_(do_syscall)(__NR_getdents, fd, (UWord)dirp, count);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
/* Support for a readlink. */
Int VG_(readlink) (Char* path, Char* buf, UInt bufsiz)
{
Int res;
/* res = readlink( path, buf, bufsiz ); */
res = VG_(do_syscall)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
/* You'd be amazed how many places need to know the current pid. */
Int VG_(getpid) ( void )
{
Int res;
/* res = getpid(); */
res = VG_(do_syscall)(__NR_getpid);
return res;
}
Int VG_(getpgrp) ( void )
{
Int res;
/* res = getpgid(); */
res = VG_(do_syscall)(__NR_getpgrp);
return res;
}
Int VG_(getppid) ( void )
{
Int res;
res = VG_(do_syscall)(__NR_getppid);
return res;
}
Int VG_(setpgid) ( Int pid, Int pgrp )
{
return VG_(do_syscall)(__NR_setpgid, pid, pgrp);
}
/* Walk through a colon-separated environment variable, and remove the
entries which match remove_pattern. It slides everything down over
the removed entries, and pads the remaining space with '\0'. It
modifies the entries in place (in the client address space), but it
shouldn't matter too much, since we only do this just before an
execve().
This is also careful to mop up any excess ':'s, since empty strings
delimited by ':' are considered to be '.' in a path.
*/
static void mash_colon_env(Char *varp, const Char *remove_pattern)
{
Char *const start = varp;
Char *entry_start = varp;
Char *output = varp;
if (varp == NULL)
return;
while(*varp) {
if (*varp == ':') {
Char prev;
Bool match;
/* This is a bit subtle: we want to match against the entry
we just copied, because it may have overlapped with
itself, junking the original. */
prev = *output;
*output = '\0';
match = VG_(string_match)(remove_pattern, entry_start);
*output = prev;
if (match) {
output = entry_start;
varp++; /* skip ':' after removed entry */
} else
entry_start = output+1; /* entry starts after ':' */
}
*output++ = *varp++;
}
/* match against the last entry */
if (VG_(string_match)(remove_pattern, entry_start)) {
output = entry_start;
if (output > start) {
/* remove trailing ':' */
output--;
vg_assert(*output == ':');
}
}
/* pad out the left-overs with '\0' */
while(output < varp)
*output++ = '\0';
}
// Removes all the Valgrind-added stuff from the passed environment. Used
// when starting child processes, so they don't see that added stuff.
void VG_(env_remove_valgrind_env_stuff)(Char** envp)
{
Int i;
Char* ld_preload_str = NULL;
Char* ld_library_path_str = NULL;
Char* buf;
// Find LD_* variables
for (i = 0; envp[i] != NULL; i++) {
if (VG_(strncmp)(envp[i], "LD_PRELOAD=", 11) == 0)
ld_preload_str = &envp[i][11];
if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0)
ld_library_path_str = &envp[i][16];
}
buf = VG_(arena_malloc)(VG_AR_CORE, VG_(strlen)(VG_(libdir)) + 20);
// Remove Valgrind-specific entries from LD_*.
VG_(sprintf)(buf, "%s*/vg_inject.so", VG_(libdir));
mash_colon_env(ld_preload_str, buf);
VG_(sprintf)(buf, "%s*/vgpreload_*.so", VG_(libdir));
mash_colon_env(ld_preload_str, buf);
VG_(sprintf)(buf, "%s*", VG_(libdir));
mash_colon_env(ld_library_path_str, buf);
// Remove VALGRIND_CLO variable.
VG_(env_unsetenv)(envp, VALGRINDCLO);
// XXX if variable becomes empty, remove it completely?
VG_(arena_free)(VG_AR_CORE, buf);
}
/* Return -1 if error, else 0. NOTE does not indicate return code of
child! */
Int VG_(system) ( Char* cmd )
{
Int pid, res;
if (cmd == NULL)
return 1;
pid = VG_(do_syscall)(__NR_fork);
if (VG_(is_kerror)(pid))
return -1;
if (pid == 0) {
/* child */
static Char** envp = NULL;
Char* argv[4];
/* restore the DATA rlimit for the child */
VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
envp = env_clone(VG_(client_envp));
VG_(env_remove_valgrind_env_stuff)( envp );
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = cmd;
argv[3] = 0;
(void)VG_(do_syscall)(__NR_execve,
(UWord)"/bin/sh", (UWord)argv, (UWord)envp);
/* If we're still alive here, execve failed. */
VG_(exit)(1);
} else {
/* parent */
res = VG_(waitpid)(pid, NULL, 0);
if (VG_(is_kerror)(res)) {
return -1;
} else {
return 0;
}
}
}
/* ---------------------------------------------------------------------
Support for a millisecond-granularity timer.
------------------------------------------------------------------ */
UInt VG_(read_millisecond_timer) ( void )
{
static ULong base = 0;
struct vki_timeval tv_now;
ULong now;
Int res;
res = VG_(do_syscall)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL);
now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
if (base == 0)
base = now;
return (now - base) / 1000;
}
/* ---------------------------------------------------------------------
Primitive support for bagging memory via mmap.
------------------------------------------------------------------ */
void* VG_(get_memory_from_mmap) ( SizeT nBytes, Char* who )
{
static SizeT tot_alloc = 0;
void* p;
p = VG_(mmap)(0, nBytes,
VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 0, -1, 0);
if (p != ((void*)(-1))) {
vg_assert((void*)VG_(valgrind_base) <= p && p <= (void*)VG_(valgrind_last));
tot_alloc += nBytes;
if (0)
VG_(printf)(
"get_memory_from_mmap: %llu tot, %llu req = %p .. %p, caller %s\n",
(ULong)tot_alloc, (ULong)nBytes, p, ((char*)p) + nBytes - 1, who );
return p;
}
VG_(printf)("\n");
VG_(printf)("VG_(get_memory_from_mmap): %s's request for %llu bytes failed.\n",
who, (ULong)nBytes);
VG_(printf)("VG_(get_memory_from_mmap): %llu bytes already allocated.\n",
(ULong)tot_alloc);
VG_(printf)("\n");
VG_(printf)("Sorry. You could try using a tool that uses less memory;\n");
VG_(printf)("eg. addrcheck instead of memcheck.\n");
VG_(printf)("\n");
VG_(exit)(1);
}
/* ---------------------------------------------------------------------
Generally useful...
------------------------------------------------------------------ */
Int VG_(log2) ( Int x )
{
Int i;
/* Any more than 32 and we overflow anyway... */
for (i = 0; i < 32; i++) {
if (1 << i == x) return i;
}
return -1;
}
// Generic shell sort. Like stdlib.h's qsort().
void VG_(ssort)( void* base, SizeT nmemb, SizeT size,
Int (*compar)(void*, void*) )
{
Int incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
9841, 29524, 88573, 265720,
797161, 2391484 };
Int lo = 0;
Int hi = nmemb-1;
Int i, j, h, bigN, hp;
bigN = hi - lo + 1; if (bigN < 2) return;
hp = 0; while (hp < 14 && incs[hp] < bigN) hp++; hp--;
vg_assert(0 <= hp && hp < 14);
#define SORT \
for ( ; hp >= 0; hp--) { \
h = incs[hp]; \
for (i = lo + h; i <= hi; i++) { \
ASSIGN(v,0, a,i); \
j = i; \
while (COMPAR(a,(j-h), v,0) > 0) { \
ASSIGN(a,j, a,(j-h)); \
j = j - h; \
if (j <= (lo + h - 1)) break; \
} \
ASSIGN(a,j, v,0); \
} \
}
// Specialised cases
if (sizeof(ULong) == size) {
#define ASSIGN(dst, dsti, src, srci) \
(dst)[(dsti)] = (src)[(srci)];
#define COMPAR(dst, dsti, src, srci) \
compar( (void*)(& (dst)[(dsti)]), (void*)(& (src)[(srci)]) )
ULong* a = (ULong*)base;
ULong v[1];
SORT;
} else if (sizeof(UInt) == size) {
UInt* a = (UInt*)base;
UInt v[1];
SORT;
} else if (sizeof(UShort) == size) {
UShort* a = (UShort*)base;
UShort v[1];
SORT;
} else if (sizeof(UChar) == size) {
UChar* a = (UChar*)base;
UChar v[1];
SORT;
#undef ASSIGN
#undef COMPAR
// General case
} else {
char* a = base;
char v[size]; // will be at least 'size' bytes
#define ASSIGN(dst, dsti, src, srci) \
VG_(memcpy)( &dst[size*(dsti)], &src[size*(srci)], size );
#define COMPAR(dst, dsti, src, srci) \
compar( &dst[size*(dsti)], &src[size*(srci)] )
SORT;
#undef ASSIGN
#undef COMPAR
}
#undef SORT
}
/* ---------------------------------------------------------------------
Gruesome hackery for connecting to a logging server over the network.
This is all 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 )
{
Int res;
UWord args[3];
args[0] = domain;
args[1] = type;
args[2] = protocol;
res = VG_(do_syscall)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
if (VG_(is_kerror)(res))
res = -1;
return res;
}
static
Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr,
Int addrlen )
{
Int res;
UWord args[3];
args[0] = sockfd;
args[1] = (UWord)serv_addr;
args[2] = addrlen;
res = VG_(do_syscall)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
if (VG_(is_kerror)(res))
res = -1;
return res;
}
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;
Int res;
UWord args[4];
args[0] = sd;
args[1] = (UWord)msg;
args[2] = count;
args[3] = flags;
res = VG_(do_syscall)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
if (VG_(is_kerror)(res))
res = -1;
return res;
}
Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
Int res;
UWord args[3];
args[0] = sd;
args[1] = (UWord)name;
args[2] = (UWord)namelen;
res = VG_(do_syscall)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
if(VG_(is_kerror)(res))
res = -1;
return res;
}
Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
Int res;
UWord args[3];
args[0] = sd;
args[1] = (UWord)name;
args[2] = (UWord)namelen;
res = VG_(do_syscall)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
if(VG_(is_kerror)(res))
res = -1;
return res;
}
Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
Int *optlen)
{
Int res;
UWord args[5];
args[0] = sd;
args[1] = level;
args[2] = optname;
args[3] = (UWord)optval;
args[4] = (UWord)optlen;
res = VG_(do_syscall)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
if(VG_(is_kerror)(res))
res = -1;
return res;
}
/*--------------------------------------------------------------------*/
/*--- end vg_mylibc.c ---*/
/*--------------------------------------------------------------------*/