/*--------------------------------------------------------------------*/ /*--- 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; } Long VG_(atoll36) ( Char* str ) { Bool neg = False; Long n = 0; if (*str == '-') { str++; neg = True; }; while (True) { if (*str >= '0' && *str <= '9') { n = 36*n + (Long)(*str - '0'); } else if (*str >= 'A' && *str <= 'Z') { n = 36*n + (Long)((*str - 'A') + 10); } else if (*str >= 'a' && *str <= 'z') { n = 36*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; } } 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 < 250); 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 ---*/ /*--------------------------------------------------------------------*/