blob: 17963853e461b78219ec5103f9580448b15aaaf3 [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Intercepts for various libc functions we want to capture ---*/
/*--- (mostly for threading purposes). vg_intercept.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, an extensible x86 protected-mode
emulator for monitoring program execution on x86-Unixes.
Copyright (C) 2000-2003 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.
*/
/* ---------------------------------------------------------------------
ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU. It is
intended for various reasons as drop-in replacements for libc
functions. These functions have global visibility (obviously) and
have no prototypes in vg_include.h, since they are not intended to
be called from within Valgrind.
------------------------------------------------------------------ */
/* General idea (2003-Apr-26) is that master implementations of
selected functions are done as VGR_(fnname). Then we route
all calls to the master, both here and in vg_libpthread.c.
This means we no longer have to rely on the semantics of weak
symbols, which seems to have changed in glibc >= 2.3.2 in such
a way as to make the previous interception scheme stop working.
*/
/* Sidestep the normal check which disallows using valgrind.h
directly. */
#define __VALGRIND_SOMESKIN_H
#include "valgrind.h"
#include "vg_include.h"
#include "vg_kerneliface.h"
/* This has some nasty duplication of stuff from vg_libpthread.c */
#include <errno.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <asm/ipc.h> /* for ipc_kludge */
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/uio.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* --------------------------------------------------------------- */
/* Just start up Valgrind if it's not already going. VG_(startup)()
detects and ignores second and subsequent calls. */
/* We need this guy -- it's in valgrind.so. */
extern void VG_(startup) ( void );
static __inline__
void ensure_valgrind ( char* caller )
{
VG_(startup)();
}
static __inline__
int is_kerror ( int res )
{
if (res >= -4095 && res <= -1)
return 1;
else
return 0;
}
/* --------------------------------------------------------------- */
/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
Returns 0 (none) if not running on Valgrind. */
static
int get_pt_trace_level ( void )
{
int res;
VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
0, 0, 0, 0);
return res;
}
static
void cat_n_send ( char* pre, char* msg )
{
char buf[1000];
if (get_pt_trace_level() >= 0) {
snprintf(buf, sizeof(buf), "%s%s", pre, msg );
buf[sizeof(buf)-1] = '\0';
VALGRIND_NON_SIMD_CALL2(VG_(message), Vg_UserMsg, buf);
}
}
static
void my_exit ( int arg )
{
VG_(do_syscall)(__NR_exit_group, arg);
VG_(do_syscall)(__NR_exit, arg);
}
static
void my_assert_fail ( const Char* expr, const Char* file, Int line, const Char* fn )
{
char buf[1000];
static Bool entered = False;
if (entered)
my_exit(2);
entered = True;
sprintf(buf, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
"valgrind", file, line, fn, expr );
cat_n_send ( "", buf );
sprintf(buf, "Please report this bug to me at: %s\n\n",
VG_EMAIL_ADDR);
cat_n_send ( "", buf );
my_exit(1);
}
#define MY__STRING(__str) #__str
#define my_assert(expr) \
((void) ((expr) ? 0 : \
(my_assert_fail (MY__STRING(expr), \
__FILE__, __LINE__, \
__PRETTY_FUNCTION__), 0)))
/* --------------------------------------------------------------- */
static __inline__
void __my_pthread_testcancel(void)
{
int res;
ensure_valgrind("__my_pthread_testcancel");
VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
VG_USERREQ__TESTCANCEL,
0, 0, 0, 0);
my_assert(res == 0);
}
/* ---------------------------------------------------------------------
Hook for running __libc_freeres once the program exits.
------------------------------------------------------------------ */
void VG_(__libc_freeres_wrapper)( void )
{
int res;
#ifndef __UCLIBC__
extern void __libc_freeres(void);
__libc_freeres();
#endif
VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
VG_USERREQ__LIBC_FREERES_DONE, 0, 0, 0, 0);
/*NOTREACHED*/
vg_assert(12345+54321 == 999999);
}
/* ---------------------------------------------------------------------
Useful for skins that want to replace certain functions
------------------------------------------------------------------ */
Bool VG_(is_running_on_simd_CPU)(void)
{
return VG_(running_on_simd_CPU);
}
/*--------------------------------------------------------------------*/
/*--- end vg_intercept.c ---*/
/*--------------------------------------------------------------------*/