|
From: <sv...@va...> - 2005-12-28 00:57:52
|
Author: sewardj
Date: 2005-12-28 00:57:48 +0000 (Wed, 28 Dec 2005)
New Revision: 5454
Log:
Use new "Special" instruction support in vex to provide a fast
implementation of function wrapping, that does not require any client
requests. The dynamic net overhead of a function wrap is now two
extra basic blocks (of client code), which means we should be able to
do wrapping of frequently-called functions (eg pthread_mutex_lock)
without excessive (baseline) overheads.
Massively tidy up/restructure valgrind.h as a side effect.
Modified:
branches/FNWRAP/coregrind/coregrind.h
branches/FNWRAP/coregrind/m_replacemalloc/vg_replace_malloc.c
branches/FNWRAP/coregrind/m_scheduler/scheduler.c
branches/FNWRAP/coregrind/vg_preloaded.c
branches/FNWRAP/include/valgrind.h
branches/FNWRAP/memcheck/mac_replace_strmem.c
branches/FNWRAP/memcheck/memcheck.h
Modified: branches/FNWRAP/coregrind/coregrind.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/coregrind/coregrind.h 2005-12-27 16:40:35 UTC (rev 54=
53)
+++ branches/FNWRAP/coregrind/coregrind.h 2005-12-28 00:57:48 UTC (rev 54=
54)
@@ -66,8 +66,10 @@
unsigned long _qzz_res =3D 0;
va_list vargs;
va_start(vargs, format);
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, VG_USERREQ__INTERNAL_PRINTF,
- (unsigned long)format, (unsigned long)vargs, =
0, 0);
+ VALGRIND_DO_CLIENT_REQUEST(
+ _qzz_res, 0, VG_USERREQ__INTERNAL_PRINTF,
+ (unsigned long)format, (unsigned long)vargs, 0, 0
+ );
va_end(vargs);
return _qzz_res;
}
Modified: branches/FNWRAP/coregrind/m_replacemalloc/vg_replace_malloc.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/coregrind/m_replacemalloc/vg_replace_malloc.c 2005-12=
-27 16:40:35 UTC (rev 5453)
+++ branches/FNWRAP/coregrind/m_replacemalloc/vg_replace_malloc.c 2005-12=
-28 00:57:48 UTC (rev 5454)
@@ -461,8 +461,8 @@
=20
init_done =3D 1;
=20
- VALGRIND_MAGIC_SEQUENCE(res, -1, VG_USERREQ__GET_MALLOCFUNCS, &info,
- 0, 0, 0);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__GET_MALLOCFUNCS, &inf=
o,
+ 0, 0, 0);
}
=20
/*--------------------------------------------------------------------*/
Modified: branches/FNWRAP/coregrind/m_scheduler/scheduler.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/coregrind/m_scheduler/scheduler.c 2005-12-27 16:40:35=
UTC (rev 5453)
+++ branches/FNWRAP/coregrind/m_scheduler/scheduler.c 2005-12-28 00:57:48=
UTC (rev 5454)
@@ -1033,28 +1033,7 @@
zztid, O_CLREQ_RET, sizeof(UWord), f); \
} while (0)
=20
-#define SET_CLIENT_NRFLAG(zztid, zzflag) \
- do { VG_(threads)[zztid].arch.vex.guest_NRFLAG =3D (zzflag); \
- VG_TRACK( post_reg_write, \
- Vg_CoreClientReq, zztid, \
- offsetof(VexGuestArchState,guest_NRFLAG), \
- sizeof(UWord) ); \
- } while (0)
=20
-#define SET_CLIENT_NRADDR(zztid, zzaddr) \
- do { VG_(threads)[zztid].arch.vex.guest_NRADDR =3D (zzaddr); \
- VG_TRACK( post_reg_write, \
- Vg_CoreClientReq, zztid, \
- offsetof(VexGuestArchState,guest_NRADDR), \
- sizeof(UWord) ); \
- } while (0)
-
-#define GET_CLIENT_NRFLAG(zztid) \
- VG_(threads)[zztid].arch.vex.guest_NRFLAG
-#define GET_CLIENT_NRADDR(zztid) \
- VG_(threads)[zztid].arch.vex.guest_NRADDR
-
-
/* ---------------------------------------------------------------------
Handle client requests.
------------------------------------------------------------------ */
@@ -1099,10 +1078,6 @@
VG_(printf)("req no =3D 0x%llx, arg =3D %p\n", (ULong)req_no, arg)=
;
switch (req_no) {
=20
- case VG_USERREQ__GET_NRADDR:
- SET_CLREQ_RETVAL(tid, VG_(threads)[tid].arch.vex.guest_NRADDR);
- break;
-
case VG_USERREQ__CLIENT_CALL0: {
UWord (*f)(ThreadId) =3D (void*)arg[1];
if (f =3D=3D NULL)
Modified: branches/FNWRAP/coregrind/vg_preloaded.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/coregrind/vg_preloaded.c 2005-12-27 16:40:35 UTC (rev=
5453)
+++ branches/FNWRAP/coregrind/vg_preloaded.c 2005-12-28 00:57:48 UTC (rev=
5454)
@@ -61,8 +61,8 @@
extern void __libc_freeres(void);
__libc_freeres();
#endif
- VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
- VG_USERREQ__LIBC_FREERES_DONE, 0, 0, 0, 0);
+ VALGRIND_DO_CLIENT_REQUEST(res, 0 /* default */,
+ VG_USERREQ__LIBC_FREERES_DONE, 0, 0, 0, 0)=
;
/*NOTREACHED*/
*(int *)0 =3D 'x';
}
@@ -71,25 +71,26 @@
/*--- end ---*/
/*--------------------------------------------------------------------*/
=20
-#if 0
+#if 1
=20
#define PTH_FUNC(ret_ty, f, args...) \
- ret_ty VG_REDIRECT_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args); \
- ret_ty VG_REDIRECT_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args)
+ ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args); \
+ ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args)
=20
#include <stdio.h>
#include <pthread.h>
=20
-// pthread_create@GLIBC_2.0 - making it match this too causes loops.??
-// pthread_create@@GLIBC_2.1
-PTH_FUNC(int, pthreadZucreateZAZAGLIBCZu2Zd1, // pthread_create@@GLIBC_2=
.1
+// pthread_create
+PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
pthread_t *thread, const pthread_attr_t *attr,
void *(*start) (void *), void *arg)
{
- int ret;
+ int ret;
+ void* fn;
+ VALGRIND_GET_NRADDR(fn);
fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
=20
- CALL_ORIG_FN_4_UNCHECKED(ret, pthread_create, thread,attr,start,arg);
+ CALL_FN_W_WWWW(ret, fn, thread,attr,start,arg);
=20
fprintf(stderr, " -> %d >>\n", ret);
return ret;
@@ -99,10 +100,12 @@
PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
pthread_mutex_t *mutex)
{
- int ret;
+ int ret;
+ void* fn;
+ VALGRIND_GET_ORIG_FN(fn);
fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
=20
- CALL_ORIG_FN_1_UNCHECKED(ret, pthread_mutex_lock, mutex);
+ CALL_FN_W_W(ret, fn, mutex);
=20
fprintf(stderr, " -> %d >>\n", ret);
return ret;
@@ -113,9 +116,12 @@
pthread_mutex_t *mutex)
{
int ret;
+ void* fn;
+ VALGRIND_GET_ORIG_FN(fn);
+
fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
=20
- CALL_ORIG_FN_1_UNCHECKED(ret, pthread_mutex_unlock, mutex);
+ CALL_FN_W_W(ret, fn, mutex);
=20
fprintf(stderr, " -> %d >>\n", ret);
return ret;
Modified: branches/FNWRAP/include/valgrind.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/FNWRAP/include/valgrind.h 2005-12-27 16:40:35 UTC (rev 5453)
+++ branches/FNWRAP/include/valgrind.h 2005-12-28 00:57:48 UTC (rev 5454)
@@ -63,7 +63,7 @@
The resulting executables will still run without Valgrind, just a
little bit more slowly than they otherwise would, but otherwise
unchanged. When not running on valgrind, each client request
- consumes very few (eg. < 10) instructions, so the resulting performan=
ce
+ consumes very few (eg. 7) instructions, so the resulting performance
loss is negligible unless you plan to execute client requests
millions of times per second. Nevertheless, if that is still a
problem, you can compile with the NVALGRIND symbol defined (gcc
@@ -78,41 +78,69 @@
we can't use C++ style "//" comments nor the "asm" keyword (instead
use "__asm__"). */
=20
+/* Derive some tags indicating what the target architecture is. Note
+ that in this file we're using the compiler's CPP symbols for
+ identifying architectures, which are different to the ones we use
+ within the rest of Valgrind. Note, __powerpc__ is active for both
+ 32 and 64-bit PPC, whereas __powerpc64__ is only active for the
+ latter. */
+#undef ARCH_x86
+#undef ARCH_amd64
+#undef ARCH_ppc32
+#undef ARCH_ppc64
+
+#if defined(__i386__)
+# define ARCH_x86 1
+#elif defined(__x86_64__)
+# define ARCH_amd64 1
+#elif defined(__powerpc__) && !defined(__powerpc64__)
+# define ARCH_ppc32 1
+#elif defined(__powerpc__) && defined(__powerpc64__)
+# define ARCH_ppc64 1
+#endif
+
/* If we're not compiling for our target architecture, don't generate
- any inline asms. Note that in this file we're using the compiler's
- CPP symbols for identifying architectures, which are different to
- the ones we use within the rest of Valgrind. Note, __powerpc__ is
- active for both 32 and 64-bit PPC, whereas __powerpc64__ is only
- active for the latter. */
-#if !defined(__i386__) && !defined(__x86_64__) && !defined(__powerpc__)
-# ifndef NVALGRIND
-# define NVALGRIND 1
-# endif /* NVALGRIND */
+ any inline asms. */
+#if !defined(ARCH_x86) && !defined(ARCH_amd64) \
+ && !defined(ARCH_ppc32) && !defined(ARCH_ppc64)
+# if !defined(NVALGRIND)
+# define NVALGRIND 1
+# endif
#endif
=20
+
/* ------------------------------------------------------------------ */
-/* The architecture-specific part */
+/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */
+/* in here of use to end-users -- skip to the next section. */
/* ------------------------------------------------------------------ */
=20
-#ifdef NVALGRIND
+#if defined(NVALGRIND)
=20
/* Define NVALGRIND to completely remove the Valgrind magic sequence
- from the compiled code (analogous to NDEBUG's effects on assert()) */
-#define VALGRIND_MAGIC_SEQUENCE( \
- _zzq_rlval, _zzq_default, _zzq_request, =
\
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) =
\
- { \
- (_zzq_rlval) =3D (_zzq_default); \
+ from the compiled code (analogous to NDEBUG's effects on
+ assert()) */
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
+ { \
+ (_zzq_rlval) =3D (_zzq_default); \
}
=20
-#else /* NVALGRIND */
+#else /* ! NVALGRIND */
=20
-/* The following defines the magic code sequences which the JITter spots=
and
- handles magically. Don't look too closely at them; they will rot
- your brain. We must ensure that the default value gets put in the re=
turn
- slot, so that everything works when this is executed not under Valgri=
nd.
- Args are passed in a memory block, and so there's no intrinsic limit =
to
- the number that could be passed, but it's currently four.
+/* The following defines the magic code sequences which the JITter
+ spots and handles magically. Don't look too closely at them as
+ they will rot your brain.
+
+ The assembly code sequences for all architectures is in this one
+ file. This is because this file must be stand-alone, and we don't
+ want to have multiple files.
+
+ For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default
+ value gets put in the return slot, so that everything works when
+ this is executed not under Valgrind. Args are passed in a memory
+ block, and so there's no intrinsic limit to the number that could
+ be passed, but it's currently four.
=20
The macro args are:=20
_zzq_rlval result lvalue
@@ -120,126 +148,359 @@
_zzq_request request code
_zzq_arg1..4 request params
=20
- Nb: we put the assembly code sequences for all architectures in this =
one
- file. This is because this file must be stand-alone, and we don't wa=
nt
- to have multiple files.
+ The other two macros are used to support function wrapping, and are
+ a lot simpler. VALGRIND_GET_NRADDR returns the value of the
+ guest's NRADDR pseudo-register. VALGRIND_CALL_NOREDIR_* behaves
+ the same as the following on the guest, but guarantees that the
+ branch instruction will not be redirected: x86: call *%eax, amd64:
+ call *%rax, ppc32/ppc64: bctrl. VALGRIND_CALL_NOREDIR is just
+ text, not a complete inline asm, since it needs to be combined with
+ more magic inline asm stuff to be useful.
*/
=20
-#ifdef __x86_64__
-#define VALGRIND_MAGIC_SEQUENCE( \
- _zzq_rlval, _zzq_default, _zzq_request, \
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
- \
- { volatile unsigned long long _zzq_args[5]; \
- _zzq_args[0] =3D (volatile unsigned long long)(_zzq_request); \
- _zzq_args[1] =3D (volatile unsigned long long)(_zzq_arg1); \
- _zzq_args[2] =3D (volatile unsigned long long)(_zzq_arg2); \
- _zzq_args[3] =3D (volatile unsigned long long)(_zzq_arg3); \
- _zzq_args[4] =3D (volatile unsigned long long)(_zzq_arg4); \
- __asm__ volatile("roll $29, %%eax ; roll $3, %%eax\n\t" \
- "rorl $27, %%eax ; rorl $5, %%eax\n\t" \
- "roll $13, %%eax ; roll $19, %%eax" \
- : "=3Dd" (_zzq_rlval) \
- : "a" (&_zzq_args[0]), "0" (_zzq_default) \
- : "cc", "memory" \
- ); \
+/* ---------------------------- x86 ---------------------------- */
+
+#if defined(ARCH_x86)
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
+ { unsigned int _zzq_args[5]; \
+ _zzq_args[0] =3D (unsigned int)(_zzq_request); \
+ _zzq_args[1] =3D (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] =3D (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] =3D (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] =3D (unsigned int)(_zzq_arg4); \
+ __asm__ volatile(/* "Special" instruction preamble */ \
+ "roll $3, %%edi ; roll $13, %%edi\n\t" \
+ "roll $29, %%edi ; roll $19, %%edi\n\t" \
+ /* %EDX =3D client_request ( %EAX ) */ \
+ "xchgl %%ebx,%%ebx" \
+ : "=3Dd" (_zzq_rlval) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
}
-#endif /* __x86_64__ */
=20
-#ifdef __i386__
-#define VALGRIND_MAGIC_SEQUENCE( \
- _zzq_rlval, _zzq_default, _zzq_request, \
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
- \
- { unsigned int _zzq_args[5]; \
- _zzq_args[0] =3D (unsigned int)(_zzq_request); \
- _zzq_args[1] =3D (unsigned int)(_zzq_arg1); \
- _zzq_args[2] =3D (unsigned int)(_zzq_arg2); \
- _zzq_args[3] =3D (unsigned int)(_zzq_arg3); \
- _zzq_args[4] =3D (unsigned int)(_zzq_arg4); \
- __asm__ volatile("roll $29, %%eax ; roll $3, %%eax\n\t" \
- "rorl $27, %%eax ; rorl $5, %%eax\n\t" \
- "roll $13, %%eax ; roll $19, %%eax" \
- : "=3Dd" (_zzq_rlval) \
- : "a" (&_zzq_args[0]), "0" (_zzq_default) \
- : "cc", "memory" \
- ); \
+#define VALGRIND_GET_NRADDR(_zzq_rlval) \
+ { unsigned int __addr; \
+ __asm__ volatile("movl $0, %%eax\n\t" \
+ /* "Special" instruction preamble */ \
+ "roll $3, %%edi ; roll $13, %%edi\n\t" \
+ "roll $29, %%edi ; roll $19, %%edi\n\t" \
+ /* %EAX =3D guest_NRADDR */ \
+ "xchgl %%ecx,%%ecx" \
+ : "=3Da" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_rlval =3D (void*)__addr; \
}
-#endif /* __i386__ */
=20
-#if defined(__powerpc__) && !defined(__powerpc64__)
-#define VALGRIND_MAGIC_SEQUENCE( =
\
- _zzq_rlval, _zzq_default, _zzq_request, =
\
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) =
\
- =
\
- { volatile unsigned int _zzq_args[5]; =
\
- register unsigned int _zzq_tmp __asm__("r3"); =
\
- register volatile unsigned int *_zzq_ptr __asm__("r4"); =
\
- _zzq_args[0] =3D (volatile unsigned int)(_zzq_request); =
\
- _zzq_args[1] =3D (volatile unsigned int)(_zzq_arg1); =
\
- _zzq_args[2] =3D (volatile unsigned int)(_zzq_arg2); =
\
- _zzq_args[3] =3D (volatile unsigned int)(_zzq_arg3); =
\
- _zzq_args[4] =3D (volatile unsigned int)(_zzq_arg4); =
\
- _zzq_ptr =3D _zzq_args; =
\
- __asm__ volatile("tw 0,3,27\n\t" =
\
- "rlwinm 0,0,29,0,0\n\t" =
\
- "rlwinm 0,0,3,0,0\n\t" =
\
- "rlwinm 0,0,13,0,0\n\t" =
\
- "rlwinm 0,0,19,0,0\n\t" =
\
- "nop\n\t" =
\
- : "=3Dr" (_zzq_tmp) =
\
- : "0" (_zzq_default), "r" (_zzq_ptr) =
\
- : "memory"); =
\
- _zzq_rlval =3D (__typeof__(_zzq_rlval)) _zzq_tmp; =
\
+#define VALGRIND_CALL_NOREDIR_EAX \
+ /* "Special" instruction preamble */ \
+ "roll $3, %%edi ; roll $13, %%edi\n\t" \
+ "roll $29, %%edi ; roll $19, %%edi\n\t" \
+ /* call-noredir *%EAX */ \
+ "xchgl %%edx,%%edx\n\t"
+#endif /* ARCH_x86 */
+
+/* --------------------------- amd64 --------------------------- */
+
+#if defined(ARCH_amd64)
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
+ \
+ { volatile unsigned long long _zzq_args[5]; \
+ _zzq_args[0] =3D (volatile unsigned long long)(_zzq_request); \
+ _zzq_args[1] =3D (volatile unsigned long long)(_zzq_arg1); \
+ _zzq_args[2] =3D (volatile unsigned long long)(_zzq_arg2); \
+ _zzq_args[3] =3D (volatile unsigned long long)(_zzq_arg3); \
+ _zzq_args[4] =3D (volatile unsigned long long)(_zzq_arg4); \
+ __asm__ volatile("roll $29, %%eax ; roll $3, %%eax\n\t" \
+ "rorl $27, %%eax ; rorl $5, %%eax\n\t" \
+ "roll $13, %%eax ; roll $19, %%eax" \
+ : "=3Dd" (_zzq_rlval) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
}
-#endif /* __powerpc__ 32-bit only */
+#endif /* ARCH_amd64 */
=20
-#if defined(__powerpc__) && defined(__powerpc64__)
-#define VALGRIND_MAGIC_SEQUENCE( =
\
- _zzq_rlval, _zzq_default, _zzq_request, =
\
- _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) =
\
- =
\
- { volatile unsigned long long int _zzq_args[5]; =
\
- register unsigned long long int _zzq_tmp __asm__("r3"); =
\
- register volatile unsigned long long int *_zzq_ptr __asm__("r4"); =
\
- _zzq_args[0] =3D (volatile unsigned long long int)(_zzq_request); =
\
- _zzq_args[1] =3D (volatile unsigned long long int)(_zzq_arg1); =
\
- _zzq_args[2] =3D (volatile unsigned long long int)(_zzq_arg2); =
\
- _zzq_args[3] =3D (volatile unsigned long long int)(_zzq_arg3); =
\
- _zzq_args[4] =3D (volatile unsigned long long int)(_zzq_arg4); =
\
- _zzq_ptr =3D _zzq_args; =
\
- __asm__ volatile("tw 0,3,27\n\t" =
\
- "rotldi 0,0,61\n\t" =
\
- "rotldi 0,0,3\n\t" =
\
- "rotldi 0,0,13\n\t" =
\
- "rotldi 0,0,51\n\t" =
\
- "nop\n\t" =
\
- : "=3Dr" (_zzq_tmp) =
\
- : "0" (_zzq_default), "r" (_zzq_ptr) =
\
- : "memory"); =
\
- _zzq_rlval =3D (__typeof__(_zzq_rlval)) _zzq_tmp; =
\
+/* --------------------------- ppc32 --------------------------- */
+
+#if defined(ARCH_ppc32)
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
+ \
+ { volatile unsigned int _zzq_args[5]; \
+ register unsigned int _zzq_tmp __asm__("r3"); \
+ register volatile unsigned int *_zzq_ptr __asm__("r4"); \
+ _zzq_args[0] =3D (volatile unsigned int)(_zzq_request); \
+ _zzq_args[1] =3D (volatile unsigned int)(_zzq_arg1); \
+ _zzq_args[2] =3D (volatile unsigned int)(_zzq_arg2); \
+ _zzq_args[3] =3D (volatile unsigned int)(_zzq_arg3); \
+ _zzq_args[4] =3D (volatile unsigned int)(_zzq_arg4); \
+ _zzq_ptr =3D _zzq_args; \
+ __asm__ volatile("tw 0,3,27\n\t" \
+ "rlwinm 0,0,29,0,0\n\t" \
+ "rlwinm 0,0,3,0,0\n\t" \
+ "rlwinm 0,0,13,0,0\n\t" \
+ "rlwinm 0,0,19,0,0\n\t" \
+ "nop\n\t" \
+ : "=3Dr" (_zzq_tmp) \
+ : "0" (_zzq_default), "r" (_zzq_ptr) \
+ : "memory"); \
+ _zzq_rlval =3D (__typeof__(_zzq_rlval)) _zzq_tmp; \
}
-#endif /* __powerpc__ 64-bit only */
+#endif /* ARCH_ppc32 */
=20
+/* --------------------------- ppc64 --------------------------- */
+
+#if defined(ARCH_ppc64)
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
+ \
+ { volatile unsigned long long int _zzq_args[5]; \
+ register unsigned long long int _zzq_tmp __asm__("r3"); \
+ register volatile unsigned long long int *_zzq_ptr __asm__("r4"); \
+ _zzq_args[0] =3D (volatile unsigned long long int)(_zzq_request); =
\
+ _zzq_args[1] =3D (volatile unsigned long long int)(_zzq_arg1); \
+ _zzq_args[2] =3D (volatile unsigned long long int)(_zzq_arg2); \
+ _zzq_args[3] =3D (volatile unsigned long long int)(_zzq_arg3); \
+ _zzq_args[4] =3D (volatile unsigned long long int)(_zzq_arg4); \
+ _zzq_ptr =3D _zzq_args; \
+ __asm__ volatile("tw 0,3,27\n\t" \
+ "rotldi 0,0,61\n\t" \
+ "rotldi 0,0,3\n\t" \
+ "rotldi 0,0,13\n\t" \
+ "rotldi 0,0,51\n\t" \
+ "nop\n\t" \
+ : "=3Dr" (_zzq_tmp) \
+ : "0" (_zzq_default), "r" (_zzq_ptr) \
+ : "memory"); \
+ _zzq_rlval =3D (__typeof__(_zzq_rlval)) _zzq_tmp; \
+ }
+#endif /* ARCH_ppc64 */
+
/* Insert assembly code for other architectures here... */
=20
#endif /* NVALGRIND */
=20
=20
/* ------------------------------------------------------------------ */
-/* The architecture-independent part */
+/* ARCHITECTURE SPECIFICS for FUNCTION WRAPPING. This is all very */
+/* ugly. It's the least-worst tradeoff I can think of. */
/* ------------------------------------------------------------------ */
=20
+/* This section defines magic (a.k.a appalling-hack) macros for doing
+ guaranteed-no-redirection macros, so as to get from function
+ wrappers to the functions they are wrapping. The whole point is to
+ construct standard call sequences, but to do the call itself with a
+ special no-redirect call pseudo-instruction that the JIT
+ understands and handles specially. This section is long and
+ repetitious, and I can't see a way to make it shorter.
+
+ The naming scheme is as follows:
+
+ CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,WWWWW,WWWWWW,etc}
+
+ 'W' stands for "word" and 'v' for "void". Hence there are
+ different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
+ and for each, the possibility of returning a word-typed result, or
+ no result.
+*/
+
+/* Use these to write the name of your wrapper. NOTE: duplicates
+ VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
+
+#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \
+ _vgwZU_##soname##_##fnname
+
+#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \
+ _vgwZZ_##soname##_##fnname
+
+/* Use this macro from within a wrapper function to get the address of
+ the original function. Once you have that you can then use it in
+ one of the CALL_FN_ macros. */
+#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NRADDR(_lval)
+
+/* ---------------------------- x86 ---------------------------- */
+
+#if defined(ARCH_x86)
+
+/* These regs are trashed by the hidden call. No need to mention eax
+ as gcc can already see that, plus causes gcc to bomb. */
+#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
+
+#define CALL_FN_W_v(lval, fnptr) \
+ do { \
+ void* _fnptr =3D (fnptr); \
+ long _argvec[1]; \
+ long _res; \
+ _argvec[0] =3D (long)_fnptr; \
+ __asm__ volatile( \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ : /*out*/ "=3Da" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval =3D (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_v_v(fnptr) \
+ do { long _junk; CALL_FN_W_v(_junk,fnptr); } while (0)
+
+#define CALL_FN_W_W(lval, fnptr, arg1) \
+ do { \
+ void* _fnptr =3D (fnptr); \
+ long _argvec[2]; \
+ long _res; \
+ _argvec[0] =3D (long)_fnptr; \
+ _argvec[1] =3D (long)(arg1); \
+ __asm__ volatile( \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $4, %%esp\n" \
+ : /*out*/ "=3Da" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval =3D (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, fnptr, arg1,arg2) \
+ do { \
+ void* _fnptr =3D (fnptr); \
+ long _argvec[3]; \
+ long _res; \
+ _argvec[0] =3D (long)_fnptr; \
+ _argvec[1] =3D (long)(arg1); \
+ _argvec[2] =3D (long)(arg2); \
+ __asm__ volatile( \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $8, %%esp\n" \
+ : /*out*/ "=3Da" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval =3D (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, fnptr, arg1,arg2,arg3,arg4) \
+ do { \
+ void* _fnptr =3D (fnptr); \
+ long _argvec[5]; \
+ long _res; \
+ _argvec[0] =3D (long)_fnptr; \
+ _argvec[1] =3D (long)(arg1); \
+ _argvec[2] =3D (long)(arg2); \
+ _argvec[3] =3D (long)(arg3); \
+ _argvec[4] =3D (long)(arg4); \
+ __asm__ volatile( \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $16, %%esp\n" \
+ : /*out*/ "=3Da" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval =3D (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWWW(lval, fnptr, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ void* _fnptr =3D (fnptr); \
+ long _argvec[6]; \
+ long _res; \
+ _argvec[0] =3D (long)_fnptr; \
+ _argvec[1] =3D (long)(arg1); \
+ _argvec[2] =3D (long)(arg2); \
+ _argvec[3] =3D (long)(arg3); \
+ _argvec[4] =3D (long)(arg4); \
+ _argvec[5] =3D (long)(arg5); \
+ __asm__ volatile( \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $20, %%esp\n" \
+ : /*out*/ "=3Da" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval =3D (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWWWWW(lval, fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg=
7) \
+ do { \
+ void* _fnptr =3D (fnptr); \
+ long _argvec[8]; \
+ long _res; \
+ _argvec[0] =3D (long)_fnptr; \
+ _argvec[1] =3D (long)(arg1); \
+ _argvec[2] =3D (long)(arg2); \
+ _argvec[3] =3D (long)(arg3); \
+ _argvec[4] =3D (long)(arg4); \
+ _argvec[5] =3D (long)(arg5); \
+ _argvec[6] =3D (long)(arg6); \
+ _argvec[7] =3D (long)(arg7); \
+ __asm__ volatile( \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $28, %%esp\n" \
+ : /*out*/ "=3Da" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval =3D (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* ARCH_x86 */
+
+/* --------------------------- amd64 --------------------------- */
+
+/* --------------------------- ppc32 --------------------------- */
+
+/* --------------------------- ppc64 --------------------------- */
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */
+/* */
+/* ------------------------------------------------------------------ */
+
/* Some request codes. There are many more of these, but most are not
exposed to end-user view. These are the public ones, all of the
form 0x1000 + small_number.
=20
- Core ones are in the range 0x00000000--0x0000ffff. The non-public on=
es
- start at 0x2000.
+ Core ones are in the range 0x00000000--0x0000ffff. The non-public
+ ones start at 0x2000.
*/
=20
-/* These macros are used by tools -- they must be public, but don't embe=
d them
- * into other programs. */
+/* These macros are used by tools -- they must be public, but don't
+ embed them into other programs. */
#define VG_USERREQ_TOOL_BASE(a,b) \
((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
#define VG_IS_TOOL_USERREQ(a, b, v) \
@@ -248,24 +509,24 @@
typedef
enum { VG_USERREQ__RUNNING_ON_VALGRIND =3D 0x1001,
VG_USERREQ__DISCARD_TRANSLATIONS =3D 0x1002,
- VG_USERREQ__GET_NRADDR =3D 0x1003,
=20
- /* These allow any function to be called from the
- simulated CPU but run on the real CPU.
- Nb: the first arg passed to the function is always the Thre=
adId of
- the running thread! So CLIENT_CALL0 actually requires a 1 =
arg
+ /* These allow any function to be called from the simulated
+ CPU but run on the real CPU. Nb: the first arg passed to
+ the function is always the ThreadId of the running
+ thread! So CLIENT_CALL0 actually requires a 1 arg
function, etc. */
VG_USERREQ__CLIENT_CALL0 =3D 0x1101,
VG_USERREQ__CLIENT_CALL1 =3D 0x1102,
VG_USERREQ__CLIENT_CALL2 =3D 0x1103,
VG_USERREQ__CLIENT_CALL3 =3D 0x1104,
=20
- /* Can be useful in regression testing suites -- eg. can send
- Valgrind's output to /dev/null and still count errors. */
+ /* Can be useful in regression testing suites -- eg. can
+ send Valgrind's output to /dev/null and still count
+ errors. */
VG_USERREQ__COUNT_ERRORS =3D 0x1201,
=20
- /* These are useful and can be interpreted by any tool that tr=
acks
- malloc() et al, by using vg_replace_malloc.c. */
+ /* These are useful and can be interpreted by any tool that
+ tracks malloc() et al, by using vg_replace_malloc.c. */
VG_USERREQ__MALLOCLIKE_BLOCK =3D 0x1301,
VG_USERREQ__FREELIKE_BLOCK =3D 0x1302,
/* Memory pool support. */
@@ -284,19 +545,20 @@
VG_USERREQ__STACK_CHANGE =3D 0x1503,
} Vg_ClientRequest;
=20
-#ifndef __GNUC__
-#define __extension__
+#if !defined(__GNUC__)
+# define __extension__ /* */
#endif
=20
-/* Returns the number of Valgrinds this code is running under. That is,
- 0 if running natively, 1 if running under Valgrind, 2 if running unde=
r
- Valgrind which is running under another Valgrind, etc. */
-#define RUNNING_ON_VALGRIND __extension__ \
- ({unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0 /* returned if not */, \
- VG_USERREQ__RUNNING_ON_VALGRIND, \
- 0, 0, 0, 0); \
- _qzz_res; \
+/* Returns the number of Valgrinds this code is running under. That
+ is, 0 if running natively, 1 if running under Valgrind, 2 if
+ running under Valgrind which is running under another Valgrind,
+ etc. */
+#define RUNNING_ON_VALGRIND __extension__ \
+ ({unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* if not */, \
+ VG_USERREQ__RUNNING_ON_VALGRIND, \
+ 0, 0, 0, 0); \
+ _qzz_res; \
})
=20
=20
@@ -304,30 +566,22 @@
_qzz_len - 1]. Useful if you are debugging a JITter or some such,
since it provides a way to make sure valgrind will retranslate the
invalidated area. Returns no value. */
-#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__DISCARD_TRANSLATIONS, \
- _qzz_addr, _qzz_len, 0, 0); \
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__DISCARD_TRANSLATIONS, \
+ _qzz_addr, _qzz_len, 0, 0); \
}
=20
-/* Push an address onto this thread's stack of noredir addresses, so
- that the next entry by this thread into a redirected translation
- whose address is on top of the stack will instead to jump to the
- non-redirected version. Returns 0 if success, 1 if failure. */
-#define VALGRIND_GET_NRADDR __extension__ \
- ({unsigned long _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0/*native result*/, \
- VG_USERREQ__GET_NRADDR, \
- 0, 0, 0, 0); \
- (void*)_qzz_res; \
- })
=20
-#ifdef NVALGRIND
+/* These requests are for getting Valgrind itself to print something.
+ Possibly with a backtrace. This is a really ugly hack. */
=20
-#define VALGRIND_PRINTF(...)
-#define VALGRIND_PRINTF_BACKTRACE(...)
+#if defined(NVALGRIND)
=20
+# define VALGRIND_PRINTF(...)
+# define VALGRIND_PRINTF_BACKTRACE(...)
+
#else /* NVALGRIND */
=20
int VALGRIND_PRINTF(const char *format, ...)
@@ -339,7 +593,7 @@
unsigned long _qzz_res;
va_list vargs;
va_start(vargs, format);
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, VG_USERREQ__PRINTF,
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF,
(unsigned long)format, (unsigned long)vargs, =
0, 0);
va_end(vargs);
return (int)_qzz_res;
@@ -354,7 +608,7 @@
unsigned long _qzz_res;
va_list vargs;
va_start(vargs, format);
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, VG_USERREQ__PRINTF_BACKTRACE,
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF_BACKTRACE,
(unsigned long)format, (unsigned long)vargs, =
0, 0);
va_end(vargs);
return (int)_qzz_res;
@@ -362,54 +616,55 @@
=20
#endif /* NVALGRIND */
=20
+
/* These requests allow control to move from the simulated CPU to the
real CPU, calling an arbitary function */
-#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \
- ({unsigned long _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__CLIENT_CALL0, \
- _qyy_fn, \
- 0, 0, 0); \
- _qyy_res; \
+#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL0, \
+ _qyy_fn, \
+ 0, 0, 0); \
+ _qyy_res; \
})
=20
-#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \
- ({unsigned long _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__CLIENT_CALL1, \
- _qyy_fn, \
- _qyy_arg1, 0, 0); \
- _qyy_res; \
+#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL1, \
+ _qyy_fn, \
+ _qyy_arg1, 0, 0); \
+ _qyy_res; \
})
=20
-#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \
- ({unsigned long _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__CLIENT_CALL2, \
- _qyy_fn, \
- _qyy_arg1, _qyy_arg2, 0); \
- _qyy_res; \
+#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL2, \
+ _qyy_fn, \
+ _qyy_arg1, _qyy_arg2, 0); \
+ _qyy_res; \
})
=20
-#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3=
) \
- ({unsigned long _qyy_res; \
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, \
- VG_USERREQ__CLIENT_CALL3, \
- _qyy_fn, \
- _qyy_arg1, _qyy_arg2, _qyy_arg3); \
- _qyy_res; \
+#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3=
) \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL3, \
+ _qyy_fn, \
+ _qyy_arg1, _qyy_arg2, _qyy_arg3); \
+ _qyy_res; \
})
=20
=20
/* Counts the number of errors that have been recorded by a tool. Nb:
the tool must record the errors with VG_(maybe_record_error)() or
VG_(unique_error)() for them to be counted. */
-#define VALGRIND_COUNT_ERRORS =
\
- ({unsigned int _qyy_res; =
\
- VALGRIND_MAGIC_SEQUENCE(_qyy_res, 0 /* default return */, =
\
- VG_USERREQ__COUNT_ERRORS, =
\
- 0, 0, 0, 0); =
\
- _qyy_res; =
\
+#define VALGRIND_COUNT_ERRORS \
+ ({unsigned int _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__COUNT_ERRORS, \
+ 0, 0, 0, 0); \
+ _qyy_res; \
})
=20
/* Mark a block of memory as having been allocated by a malloc()-like
@@ -432,293 +687,86 @@
=20
Nb: block must be freed via a free()-like function specified
with VALGRIND_FREELIKE_BLOCK or mismatch errors will occur. */
-#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__MALLOCLIKE_BLOCK, \
- addr, sizeB, rzB, is_zeroed); \
+#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MALLOCLIKE_BLOCK, \
+ addr, sizeB, rzB, is_zeroed); \
}
=20
/* Mark a block of memory as having been freed by a free()-like function=
.
`rzB' is redzone size; it must match that given to
VALGRIND_MALLOCLIKE_BLOCK. Memory not freed will be detected by the =
leak
checker. Put it immediately after the point where the block is freed=
. */
-#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__FREELIKE_BLOCK, \
- addr, rzB, 0, 0); \
+#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__FREELIKE_BLOCK, \
+ addr, rzB, 0, 0); \
}
=20
/* Create a memory pool. */
-#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__CREATE_MEMPOOL, \
- pool, rzB, is_zeroed, 0); \
+#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__CREATE_MEMPOOL, \
+ pool, rzB, is_zeroed, 0); \
}
=20
/* Destroy a memory pool. */
-#define VALGRIND_DESTROY_MEMPOOL(pool) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__DESTROY_MEMPOOL, \
- pool, 0, 0, 0); \
+#define VALGRIND_DESTROY_MEMPOOL(pool) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__DESTROY_MEMPOOL, \
+ pool, 0, 0, 0); \
}
=20
/* Associate a piece of memory with a memory pool. */
-#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__MEMPOOL_ALLOC, \
- pool, addr, size, 0); \
+#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_ALLOC, \
+ pool, addr, size, 0); \
}
=20
/* Disassociate a piece of memory from a memory pool. */
-#define VALGRIND_MEMPOOL_FREE(pool, addr) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__MEMPOOL_FREE, \
- pool, addr, 0, 0); \
+#define VALGRIND_MEMPOOL_FREE(pool, addr) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_FREE, \
+ pool, addr, 0, 0); \
}
=20
/* Mark a piece of memory as being a stack. Returns a stack id. */
-#define VALGRIND_STACK_REGISTER(start, end) \
- ({unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__STACK_REGISTER, \
- start, end, 0, 0); \
- _qzz_res; \
+#define VALGRIND_STACK_REGISTER(start, end) \
+ ({unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_REGISTER, \
+ start, end, 0, 0); \
+ _qzz_res; \
})
=20
/* Unmark the piece of memory associated with a stack id as being a
stack. */
-#define VALGRIND_STACK_DEREGISTER(id) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__STACK_DEREGISTER, \
- id, 0, 0, 0); \
+#define VALGRIND_STACK_DEREGISTER(id) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_DEREGISTER, \
+ id, 0, 0, 0); \
}
=20
/* Change the start and end address of the stack id. */
-#define VALGRIND_STACK_CHANGE(id, start, end) \
- {unsigned int _qzz_res; \
- VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \
- VG_USERREQ__STACK_CHANGE, \
- id, start, end, 0); \
+#define VALGRIND_STACK_CHANGE(id, start, end) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_CHANGE, \
+ id, start, end, 0); \
}
=20
-/* ---------------------------------------------------------- */
-/* --- Hacky macros for writing function wrappers. --- */
-/* --- XXXXXXX DANGEROUS. DO NOT USE. XXXXXXXXXX --- */
-/* ---------------------------------------------------------- */
=20
-#define CALL_ORIG_FN_1_UNCHECKED(lval,fn,arg1) \
- do { \
- __typeof__(&(fn)) _fn =3D &(fn); \
- __typeof__(lval) _lval; \
- __typeof__(arg1) _arg1 =3D (arg1); \
- VALGRIND_PUSH_NRADDR_NO_CHECK(_fn); \
- _lval =3D (*_fn)(_arg1); \
- lval =3D _lval; \
- } while (0)
+#undef ARCH_x86
+#undef ARCH_amd64
+#undef ARCH_ppc32
+#undef ARCH_ppc64
=20
-#define CALL_ORIG_FN_4_UNCHECKED(lval,fn,arg1,arg2,arg3,arg4) \
- do { \
- __typeof__(&(fn)) _fn =3D &(fn); \
- __typeof__(lval) _lval; \
- __typeof__(arg1) _arg1 =3D (arg1); \
- __typeof__(arg2) _arg2 =3D (arg2); \
- __typeof__(arg3) _arg3 =3D (arg3); \
- __typeof__(arg4) _arg4 =3D (arg4); \
- VALGRIND_PUSH_NRADDR_NO_CHECK(_fn); \
- _lval =3D (*_fn)(_arg1,_arg2,_arg3,_arg4); \
- lval =3D _lval; \
- } while (0)
-
-/* ---------------------------------------------------------- */
-/* --- End-user functions for writing function wrappers. --- */
-/* ---------------------------------------------------------- */
-
-/* Use these to write the name of your wrapper. NOTE: duplicates
- VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
-
-#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \
- _vgwZU_##soname##_##fnname
-
-#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \
- _vgwZZ_##soname##_##fnname
-
-/* Use these inside the wrapper, to make calls to the function you are
- wrapping. You must use these - calling originals directly will get
- you a redirect-stack overflow in short order. Also, these force
- evaluation of all args before pushing the noredir-address, which is
- needed to make things work reliably.*/
-
-/* returns void, takes zero args */
-#define CALL_ORIG_VOIDFN_0(fn) \
- do { \
- __typeof__(&(fn)) _fn =3D &(fn); \
- VALGRIND_PUSH_NRADDR_AND_CHECK(_fn); \
- (*_fn)(); \
- } while (0)
-
-/* returns a value, takes one arg */
-#define CALL_ORIG_FN_1(lval,fn,arg1) \
- do { \
- __typeof__(&(fn)) _fn =3D &(fn); \
- __typeof__(lval) _lval; \
- __typeof__(arg1) _arg1 =3D (arg1); \
- VALGRIND_PUSH_NRADDR_AND_CHECK(_fn); \
- _lval =3D (*_fn)(_arg1); \
- lval =3...
[truncated message content] |