Files
ftmemsim-valgrind/vg_mylibc.c
Julian Seward 30199fec47 In accordance with "build one to throw away, you will anyway (tm)",
throw away the old signals simulation and more or less start again
from scratch.  vg_signals.c is nearly a complete rewrite.  In fact
this is now the third generation of the signals simulation.

The purpose of this is to properly support signals in threads -- a
nightmare combination.  pthread_sigmask, pthread_kill and sigwait
are now alledged to work as POSIX requires.

In the process, throw away confusing and conceptually muddled old
implementation and replace with something which is more verbose but
conceptually cleaner, simpler and easier to argue is correct.

* When the client does sigaction/sigprocmask et al, the resulting
  changes are stored verbatim in SCSS -- the Static Client Signal State.
  So SCSS is the state the client believes the kernel is in.

* Every time SCSS changes, we recalculate the state the kernel
  *should* be in so that our signal simulation works.  This is the
  SKSS -- Static Kernel Signal State.  The kernel state is then
  updated accordingly.  By diffing the new and old SKSSs, the
  number of real system calls made is minimised.

* The dynamic state of the client's signals is stored in DCSS
  -- Dynamic Client Signal State.  This just records which signals
  are pending for which threads.

The big advantage of this scheme over the previous is that the SCSS ->
SKSS mapping is made explicit and gathered all in one place, rather
than spread out in a confusing way and done implicitly.  That makes it
all lot easier to decide if the mapping, which is really the heart of
the signals simulation, is correct or not.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@271
2002-05-15 21:13:39 +00:00

1243 lines
32 KiB
C

/*--------------------------------------------------------------------*/
/*--- Reimplementation of some C library stuff, to avoid depending ---*/
/*--- on libc.so. ---*/
/*--- vg_mylibc.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, an x86 protected-mode emulator
designed for debugging and profiling binaries on x86-Unixes.
Copyright (C) 2000-2002 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 LICENSE.
*/
#include "vg_include.h"
/* ---------------------------------------------------------------------
Really Actually DO system calls.
------------------------------------------------------------------ */
/* Ripped off from /usr/include/asm/unistd.h. */
static
UInt vg_do_syscall0 ( UInt syscallno )
{
UInt __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (syscallno) );
return __res;
}
static
UInt vg_do_syscall1 ( UInt syscallno, UInt arg1 )
{
UInt __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (syscallno),
"b" (arg1) );
return __res;
}
static
UInt vg_do_syscall2 ( UInt syscallno,
UInt arg1, UInt arg2 )
{
UInt __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (syscallno),
"b" (arg1),
"c" (arg2) );
return __res;
}
static
UInt vg_do_syscall3 ( UInt syscallno,
UInt arg1, UInt arg2, UInt arg3 )
{
UInt __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (syscallno),
"b" (arg1),
"c" (arg2),
"d" (arg3) );
return __res;
}
static
UInt vg_do_syscall4 ( UInt syscallno,
UInt arg1, UInt arg2, UInt arg3, UInt arg4 )
{
UInt __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (syscallno),
"b" (arg1),
"c" (arg2),
"d" (arg3),
"S" (arg4) );
return __res;
}
#if 0
static
UInt vg_do_syscall5 ( UInt syscallno,
UInt arg1, UInt arg2, UInt arg3, UInt arg4,
UInt arg5 )
{
UInt __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (syscallno),
"b" (arg1),
"c" (arg2),
"d" (arg3),
"S" (arg4),
"D" (arg5) );
return __res;
}
#endif
/* ---------------------------------------------------------------------
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_(ksigfillset)( vki_ksigset_t* set )
{
Int i;
if (set == NULL)
return -1;
for (i = 0; i < VKI_KNSIG_WORDS; i++)
set->ws[i] = 0xFFFFFFFF;
return 0;
}
Int VG_(ksigemptyset)( vki_ksigset_t* set )
{
Int i;
if (set == NULL)
return -1;
for (i = 0; i < VKI_KNSIG_WORDS; i++)
set->ws[i] = 0x0;
return 0;
}
Bool VG_(kisemptysigset)( vki_ksigset_t* set )
{
Int i;
vg_assert(set != NULL);
for (i = 0; i < VKI_KNSIG_WORDS; i++)
if (set->ws[i] != 0x0) return False;
return True;
}
Bool VG_(kisfullsigset)( vki_ksigset_t* set )
{
Int i;
vg_assert(set != NULL);
for (i = 0; i < VKI_KNSIG_WORDS; i++)
if (set->ws[i] != ~0x0) return False;
return True;
}
Int VG_(ksigaddset)( vki_ksigset_t* set, Int signum )
{
if (set == NULL)
return -1;
if (signum < 1 && signum > VKI_KNSIG)
return -1;
signum--;
set->ws[signum / VKI_KNSIG_BPW] |= (1 << (signum % VKI_KNSIG_BPW));
return 0;
}
Int VG_(ksigdelset)( vki_ksigset_t* set, Int signum )
{
if (set == NULL)
return -1;
if (signum < 1 && signum > VKI_KNSIG)
return -1;
signum--;
set->ws[signum / VKI_KNSIG_BPW] &= ~(1 << (signum % VKI_KNSIG_BPW));
return 0;
}
Int VG_(ksigismember) ( vki_ksigset_t* set, Int signum )
{
if (set == NULL)
return 0;
if (signum < 1 && signum > VKI_KNSIG)
return 0;
signum--;
if (1 & ((set->ws[signum / VKI_KNSIG_BPW]) >> (signum % VKI_KNSIG_BPW)))
return 1;
else
return 0;
}
/* Add all signals in src to dst. */
void VG_(ksigaddset_from_set)( vki_ksigset_t* dst, vki_ksigset_t* src )
{
Int i;
vg_assert(dst != NULL && src != NULL);
for (i = 0; i < VKI_KNSIG_WORDS; i++)
dst->ws[i] |= src->ws[i];
}
/* Remove all signals in src from dst. */
void VG_(ksigdelset_from_set)( vki_ksigset_t* dst, vki_ksigset_t* src )
{
Int i;
vg_assert(dst != NULL && src != NULL);
for (i = 0; i < VKI_KNSIG_WORDS; i++)
dst->ws[i] &= ~(src->ws[i]);
}
/* The functions sigaction, sigprocmask, sigpending and sigsuspend
return 0 on success and -1 on error.
*/
Int VG_(ksigprocmask)( Int how,
const vki_ksigset_t* set,
vki_ksigset_t* oldset)
{
Int res
= vg_do_syscall4(__NR_rt_sigprocmask,
how, (UInt)set, (UInt)oldset,
VKI_KNSIG_WORDS * VKI_BYTES_PER_WORD);
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(ksigaction) ( Int signum,
const vki_ksigaction* act,
vki_ksigaction* oldact)
{
Int res
= vg_do_syscall4(__NR_rt_sigaction,
signum, (UInt)act, (UInt)oldact,
VKI_KNSIG_WORDS * VKI_BYTES_PER_WORD);
/* VG_(printf)("res = %d\n",res); */
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(ksigaltstack)( const vki_kstack_t* ss, vki_kstack_t* oss )
{
Int res
= vg_do_syscall2(__NR_sigaltstack, (UInt)ss, (UInt)oss);
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(ksignal)(Int signum, void (*sighandler)(Int))
{
Int res;
vki_ksigaction sa;
sa.ksa_handler = sighandler;
sa.ksa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
sa.ksa_restorer = NULL;
res = VG_(ksigemptyset)( &sa.ksa_mask );
vg_assert(res == 0);
res = vg_do_syscall4(__NR_rt_sigaction,
signum, (UInt)(&sa), (UInt)NULL,
VKI_KNSIG_WORDS * VKI_BYTES_PER_WORD);
return VG_(is_kerror)(res) ? -1 : 0;
}
Int VG_(kill)( Int pid, Int signo )
{
Int res = vg_do_syscall2(__NR_kill, pid, signo);
return VG_(is_kerror)(res) ? -1 : 0;
}
/* ---------------------------------------------------------------------
mmap/munmap, exit, fcntl
------------------------------------------------------------------ */
/* Returns -1 on failure. */
void* VG_(mmap)( void* start, UInt length,
UInt prot, UInt flags, UInt fd, UInt offset)
{
Int res;
UInt args[6];
args[0] = (UInt)start;
args[1] = length;
args[2] = prot;
args[3] = flags;
args[4] = fd;
args[5] = offset;
res = vg_do_syscall1(__NR_mmap, (UInt)(&(args[0])) );
return VG_(is_kerror)(res) ? ((void*)(-1)) : (void*)res;
}
/* Returns -1 on failure. */
Int VG_(munmap)( void* start, Int length )
{
Int res = vg_do_syscall2(__NR_munmap, (UInt)start, (UInt)length );
return VG_(is_kerror)(res) ? -1 : 0;
}
void VG_(exit)( Int status )
{
(void)vg_do_syscall1(__NR_exit, (UInt)status );
/* Why are we still alive here? */
/*NOTREACHED*/
vg_assert(2+2 == 5);
}
/* Returns -1 on error. */
Int VG_(fcntl) ( Int fd, Int cmd, Int arg )
{
Int res = vg_do_syscall3(__NR_fcntl, fd, cmd, arg);
return VG_(is_kerror)(res) ? -1 : res;
}
/* Returns -1 on error. */
Int VG_(select)( Int n,
vki_fd_set* readfds,
vki_fd_set* writefds,
vki_fd_set* exceptfds,
struct vki_timeval * timeout )
{
Int res;
UInt args[5];
args[0] = n;
args[1] = (UInt)readfds;
args[2] = (UInt)writefds;
args[3] = (UInt)exceptfds;
args[4] = (UInt)timeout;
res = vg_do_syscall1(__NR_select, (UInt)(&(args[0])) );
return VG_(is_kerror)(res) ? -1 : res;
}
/* Returns -1 on error, 0 if ok, 1 if interrupted. */
Int VG_(nanosleep)( const struct vki_timespec *req,
struct vki_timespec *rem )
{
Int res;
res = vg_do_syscall2(__NR_nanosleep, (UInt)req, (UInt)rem);
if (res == -VKI_EINVAL) return -1;
if (res == -VKI_EINTR) return 1;
return 0;
}
void* VG_(brk) ( void* end_data_segment )
{
Int res;
res = vg_do_syscall1(__NR_brk, (UInt)end_data_segment);
return (void*)( VG_(is_kerror)(res) ? -1 : 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. */
/* Copy a string into the buffer. */
static void
myvprintf_str ( void(*send)(Char), Int flags, Int width, Char* str,
Bool capitalise )
{
# define MAYBE_TOUPPER(ch) (capitalise ? VG_(toupper)(ch) : (ch))
Int i, extra;
Int len = VG_(strlen)(str);
if (width == 0) {
for (i = 0; i < len; i++)
send(MAYBE_TOUPPER(str[i]));
return;
}
if (len > width) {
for (i = 0; i < width; i++)
send(MAYBE_TOUPPER(str[i]));
return;
}
extra = width - len;
if (flags & VG_MSG_LJUSTIFY) {
for (i = 0; i < extra; i++)
send(' ');
}
for (i = 0; i < len; i++)
send(MAYBE_TOUPPER(str[i]));
if (!(flags & VG_MSG_LJUSTIFY)) {
for (i = 0; i < extra; i++)
send(' ');
}
# undef MAYBE_TOUPPER
}
/* 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 void
myvprintf_int64 ( void(*send)(Char), Int flags, Int base, Int width, ULong p)
{
Char buf[40];
Int ind = 0;
Int i;
Bool neg = False;
Char *digits = "0123456789ABCDEF";
if (base < 2 || base > 16)
return;
if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
p = - (Long)p;
neg = True;
}
if (p == 0)
buf[ind++] = '0';
else {
while (p > 0) {
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. */
for (i = ind -1; i >= 0; i--)
send(buf[i]);
if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
for(; ind < width; ind++)
send((flags & VG_MSG_ZJUSTIFY) ? '0': ' ');
}
}
/* A simple vprintf(). */
void
VG_(vprintf) ( void(*send)(Char), const Char *format, va_list vargs )
{
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]);
continue;
}
i++;
/* A '%' has been found. Ignore a trailing %. */
if (format[i] == 0)
break;
if (format[i] == '%') {
/* `%%' is replaced by `%'. */
send('%');
continue;
}
flags = 0;
is_long = False;
width = 0; /* length of the field. */
/* 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)
myvprintf_int64(send, flags, 10, width,
(ULong)(va_arg (vargs, Long)));
else
myvprintf_int64(send, flags, 10, width,
(ULong)(va_arg (vargs, Int)));
break;
case 'u': /* %u */
if (is_long)
myvprintf_int64(send, flags, 10, width,
(ULong)(va_arg (vargs, ULong)));
else
myvprintf_int64(send, flags, 10, width,
(ULong)(va_arg (vargs, UInt)));
break;
case 'p': /* %p */
send('0');
send('x');
myvprintf_int64(send, flags, 16, width,
(ULong)((UInt)va_arg (vargs, void *)));
break;
case 'x': /* %x */
if (is_long)
myvprintf_int64(send, flags, 16, width,
(ULong)(va_arg (vargs, ULong)));
else
myvprintf_int64(send, flags, 16, width,
(ULong)(va_arg (vargs, UInt)));
break;
case 'c': /* %c */
send(va_arg (vargs, int));
break;
case 's': case 'S': { /* %s */
char *str = va_arg (vargs, char *);
if (str == (char*) 0) str = "(null)";
myvprintf_str(send, flags, width, str, format[i]=='S');
break;
}
default:
break;
}
}
}
/* 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_logfile_fd) >= 0)
VG_(write)
(VG_(clo_logfile_fd), 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;
}
void VG_(printf) ( const char *format, ... )
{
va_list vargs;
va_start(vargs,format);
n_myprintf_buf = 0;
myprintf_buf[n_myprintf_buf] = 0;
VG_(vprintf) ( add_to_myprintf_buf, format, vargs );
if (n_myprintf_buf > 0 && VG_(clo_logfile_fd) >= 0)
VG_(write)
( VG_(clo_logfile_fd), myprintf_buf, VG_(strlen)(myprintf_buf));
va_end(vargs);
}
/* A general replacement for sprintf(). */
static Char* vg_sprintf_ptr;
static void add_to_vg_sprintf_buf ( Char c )
{
*vg_sprintf_ptr++ = c;
}
void VG_(sprintf) ( Char* buf, Char *format, ... )
{
va_list vargs;
va_start(vargs,format);
vg_sprintf_ptr = buf;
VG_(vprintf) ( add_to_vg_sprintf_buf, format, vargs );
add_to_vg_sprintf_buf(0);
va_end(vargs);
}
/* ---------------------------------------------------------------------
Misc str* functions.
------------------------------------------------------------------ */
Bool VG_(isspace) ( Char c )
{
return (c == ' ' || c == '\n' || c == '\t' || c == 0);
}
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;
}
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;
}
}
void VG_(strncpy) ( Char* dest, const Char* src, Int ndest )
{
VG_(strncpy_safely)( dest, src, ndest+1 );
}
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_(toupper) ( Char c )
{
if (c >= 'a' && c <= 'z')
return c + ('A' - 'a');
else
return c;
}
Char* VG_(strdup) ( ArenaId aid, const Char* s )
{
Int i;
Int len = VG_(strlen)(s) + 1;
Char* res = VG_(malloc) (aid, len);
for (i = 0; i < len; i++)
res[i] = s[i];
return res;
}
/* ---------------------------------------------------------------------
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 stringMatch_wrk ( Char* pat, Char* str )
{
vg_assert(recDepth >= 0 && recDepth < 500);
recDepth++;
for (;;) {
switch (*pat) {
case '\0' : return (*str=='\0');
case '*' : do {
if (stringMatch_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_(stringMatch) ( Char* pat, Char* str )
{
Bool b;
recDepth = 0;
b = stringMatch_wrk ( pat, str );
/*
VG_(printf)("%s %s %s\n",
b?"TRUE ":"FALSE", pat, str);
*/
return b;
}
/* ---------------------------------------------------------------------
Assertery.
------------------------------------------------------------------ */
#define EMAIL_ADDR "jseward@acm.org"
void VG_(assert_fail) ( Char* expr, Char* file, Int line, Char* fn )
{
static Bool entered = False;
if (entered)
VG_(exit)(2);
entered = True;
VG_(printf)("\n%s: %s:%d (%s): Assertion `%s' failed.\n",
"valgrind", file, line, fn, expr );
VG_(pp_sched_status)();
VG_(printf)("Please report this bug to me at: %s\n\n", EMAIL_ADDR);
VG_(shutdown_logging)();
VG_(exit)(1);
}
void VG_(panic) ( Char* str )
{
VG_(printf)("\nvalgrind: the `impossible' happened:\n %s\n", str);
VG_(printf)("Basic block ctr is approximately %llu\n", VG_(bbs_done) );
VG_(pp_sched_status)();
VG_(printf)("Please report this bug to me at: %s\n\n", EMAIL_ADDR);
VG_(shutdown_logging)();
VG_(exit)(1);
}
#undef EMAIL_ADDR
/* ---------------------------------------------------------------------
Primitive support for reading files.
------------------------------------------------------------------ */
/* Returns -1 on failure. */
Int VG_(open_read) ( Char* pathname )
{
Int fd;
/* VG_(printf)("vg_open_read %s\n", pathname ); */
/* 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: */
const int O_RDONLY = 0; /* See /usr/include/bits/fcntl.h */
fd = vg_do_syscall3(__NR_open, (UInt)pathname, O_RDONLY, 0);
/* VG_(printf)("result = %d\n", fd); */
if (VG_(is_kerror)(fd)) fd = -1;
return fd;
}
/* Returns -1 on failure. */
static Int VG_(chmod_u_rw) ( Int fd )
{
Int res;
const int O_IRUSR_IWUSR = 000600; /* See /usr/include/cpio.h */
res = vg_do_syscall2(__NR_fchmod, fd, O_IRUSR_IWUSR);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
/* Returns -1 on failure. */
Int VG_(create_and_write) ( Char* pathname )
{
Int fd;
const int O_CR_AND_WR_ONLY = 0101; /* See /usr/include/bits/fcntl.h */
fd = vg_do_syscall3(__NR_open, (UInt)pathname, O_CR_AND_WR_ONLY, 0);
/* VG_(printf)("result = %d\n", fd); */
if (VG_(is_kerror)(fd)) {
fd = -1;
} else {
VG_(chmod_u_rw)(fd);
if (VG_(is_kerror)(fd)) {
fd = -1;
}
}
return fd;
}
/* Returns -1 on failure. */
Int VG_(open_write) ( Char* pathname )
{
Int fd;
const int O_WRONLY_AND_TRUNC = 01001; /* See /usr/include/bits/fcntl.h */
fd = vg_do_syscall3(__NR_open, (UInt)pathname, O_WRONLY_AND_TRUNC, 0);
/* VG_(printf)("result = %d\n", fd); */
if (VG_(is_kerror)(fd)) {
fd = -1;
}
return fd;
}
void VG_(close) ( Int fd )
{
vg_do_syscall1(__NR_close, fd);
}
Int VG_(read) ( Int fd, void* buf, Int count)
{
Int res;
/* res = read( fd, buf, count ); */
res = vg_do_syscall3(__NR_read, fd, (UInt)buf, count);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
Int VG_(write) ( Int fd, void* buf, Int count)
{
Int res;
/* res = write( fd, buf, count ); */
res = vg_do_syscall3(__NR_write, fd, (UInt)buf, count);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
Int VG_(stat) ( Char* file_name, struct vki_stat* buf )
{
Int res;
res = vg_do_syscall2(__NR_stat, (UInt)file_name, (UInt)buf);
return
VG_(is_kerror)(res) ? (-1) : 0;
}
/* Misc functions looking for a proper home. */
/* We do getenv without libc's help by snooping around in
VG_(client_env) 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;
}
/* You'd be amazed how many places need to know the current pid. */
Int VG_(getpid) ( void )
{
Int res;
/* res = getpid(); */
res = vg_do_syscall0(__NR_getpid);
return res;
}
/* Return -1 if error, else 0. NOTE does not indicate return code of
child! */
Int VG_(system) ( Char* cmd )
{
Int pid, res;
void* environ[1] = { NULL };
if (cmd == NULL)
return 1;
pid = vg_do_syscall0(__NR_fork);
if (VG_(is_kerror)(pid))
return -1;
if (pid == 0) {
/* child */
Char* argv[4];
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = cmd;
argv[3] = 0;
(void)vg_do_syscall3(__NR_execve,
(UInt)"/bin/sh", (UInt)argv, (UInt)&environ);
/* If we're still alive here, execve failed. */
return -1;
} else {
/* parent */
res = vg_do_syscall3(__NR_waitpid, pid, (UInt)NULL, 0);
if (VG_(is_kerror)(res)) {
return -1;
} else {
return 0;
}
}
}
/* ---------------------------------------------------------------------
Support for a millisecond-granularity counter using RDTSC.
------------------------------------------------------------------ */
static __inline__ ULong do_rdtsc_insn ( void )
{
ULong x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
}
/* 0 = pre-calibration, 1 = calibration, 2 = running */
static Int rdtsc_calibration_state = 0;
static ULong rdtsc_ticks_per_millisecond = 0; /* invalid value */
static struct vki_timeval rdtsc_cal_start_timeval;
static struct vki_timeval rdtsc_cal_end_timeval;
static ULong rdtsc_cal_start_raw;
static ULong rdtsc_cal_end_raw;
UInt VG_(read_millisecond_timer) ( void )
{
ULong rdtsc_now;
vg_assert(rdtsc_calibration_state == 2);
rdtsc_now = do_rdtsc_insn();
vg_assert(rdtsc_now > rdtsc_cal_end_raw);
rdtsc_now -= rdtsc_cal_end_raw;
rdtsc_now /= rdtsc_ticks_per_millisecond;
return (UInt)rdtsc_now;
}
void VG_(start_rdtsc_calibration) ( void )
{
Int res;
vg_assert(rdtsc_calibration_state == 0);
rdtsc_calibration_state = 1;
rdtsc_cal_start_raw = do_rdtsc_insn();
res = vg_do_syscall2(__NR_gettimeofday, (UInt)&rdtsc_cal_start_timeval,
(UInt)NULL);
vg_assert(!VG_(is_kerror)(res));
}
void VG_(end_rdtsc_calibration) ( void )
{
Int res, loops;
ULong cpu_clock_MHZ;
ULong cal_clock_ticks;
ULong cal_wallclock_microseconds;
ULong wallclock_start_microseconds;
ULong wallclock_end_microseconds;
struct vki_timespec req;
struct vki_timespec rem;
vg_assert(rdtsc_calibration_state == 1);
rdtsc_calibration_state = 2;
/* Try and delay for 20 milliseconds, so that we can at least have
some minimum level of accuracy. */
req.tv_sec = 0;
req.tv_nsec = 20 * 1000 * 1000;
loops = 0;
while (True) {
res = VG_(nanosleep)(&req, &rem);
vg_assert(res == 0 /*ok*/ || res == 1 /*interrupted*/);
if (res == 0)
break;
if (rem.tv_sec == 0 && rem.tv_nsec == 0)
break;
req = rem;
loops++;
if (loops > 100)
VG_(panic)("calibration nanosleep loop failed?!");
}
/* Now read both timers, and do the Math. */
rdtsc_cal_end_raw = do_rdtsc_insn();
res = vg_do_syscall2(__NR_gettimeofday, (UInt)&rdtsc_cal_end_timeval,
(UInt)NULL);
vg_assert(rdtsc_cal_end_raw > rdtsc_cal_start_raw);
cal_clock_ticks = rdtsc_cal_end_raw - rdtsc_cal_start_raw;
wallclock_start_microseconds
= (1000000ULL * (ULong)(rdtsc_cal_start_timeval.tv_sec))
+ (ULong)(rdtsc_cal_start_timeval.tv_usec);
wallclock_end_microseconds
= (1000000ULL * (ULong)(rdtsc_cal_end_timeval.tv_sec))
+ (ULong)(rdtsc_cal_end_timeval.tv_usec);
vg_assert(wallclock_end_microseconds > wallclock_start_microseconds);
cal_wallclock_microseconds
= wallclock_end_microseconds - wallclock_start_microseconds;
/* Since we just nanoslept for 20 ms ... */
vg_assert(cal_wallclock_microseconds >= 20000);
/* Now we know (roughly) that cal_clock_ticks on RDTSC take
cal_wallclock_microseconds elapsed time. Calculate the RDTSC
ticks-per-millisecond value. */
if (0)
VG_(printf)("%lld ticks in %lld microseconds\n",
cal_clock_ticks, cal_wallclock_microseconds );
rdtsc_ticks_per_millisecond
= cal_clock_ticks / (cal_wallclock_microseconds / 1000ULL);
cpu_clock_MHZ
= (1000ULL * rdtsc_ticks_per_millisecond) / 1000000ULL;
if (VG_(clo_verbosity) >= 1)
VG_(message)(Vg_UserMsg, "Estimated CPU clock rate is %d MHz",
(UInt)cpu_clock_MHZ);
if (cpu_clock_MHZ < 100 || cpu_clock_MHZ > 10000)
VG_(panic)("end_rdtsc_calibration: "
"estimated CPU MHz outside range 100 .. 10000");
/* Paranoia about division by zero later. */
vg_assert(rdtsc_ticks_per_millisecond != 0);
if (0)
VG_(printf)("ticks per millisecond %llu\n",
rdtsc_ticks_per_millisecond);
}
/* ---------------------------------------------------------------------
Primitive support for bagging memory via mmap.
------------------------------------------------------------------ */
void* VG_(get_memory_from_mmap) ( Int nBytes )
{
static UInt tot_alloc = 0;
void* p = VG_(mmap)( 0, nBytes,
VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, -1, 0 );
if (p != ((void*)(-1))) {
tot_alloc += (UInt)nBytes;
if (0)
VG_(printf)("get_memory_from_mmap: %d tot, %d req\n",
tot_alloc, nBytes);
return p;
}
VG_(printf)("vg_get_memory_from_mmap failed on request of %d\n",
nBytes);
VG_(panic)("vg_get_memory_from_mmap: out of memory! Fatal! Bye!\n");
}
/*--------------------------------------------------------------------*/
/*--- end vg_mylibc.c ---*/
/*--------------------------------------------------------------------*/