Index: ps/trunk/libraries/source/valgrind/include/memcheck.h =================================================================== --- ps/trunk/libraries/source/valgrind/include/memcheck.h (revision 25932) +++ ps/trunk/libraries/source/valgrind/include/memcheck.h (nonexistent) @@ -1,287 +0,0 @@ - -/* - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (memcheck.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of MemCheck, a heavyweight Valgrind tool for - detecting memory errors. - - Copyright (C) 2000-2012 Julian Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (memcheck.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - - -#ifndef __MEMCHECK_H -#define __MEMCHECK_H - - -/* This file is for inclusion into client (your!) code. - - You can use these macros to manipulate and query memory permissions - inside your own programs. - - See comment near the top of valgrind.h on how to use them. -*/ - -#include "valgrind.h" - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. */ -typedef - enum { - VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'), - VG_USERREQ__MAKE_MEM_UNDEFINED, - VG_USERREQ__MAKE_MEM_DEFINED, - VG_USERREQ__DISCARD, - VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, - VG_USERREQ__CHECK_MEM_IS_DEFINED, - VG_USERREQ__DO_LEAK_CHECK, - VG_USERREQ__COUNT_LEAKS, - - VG_USERREQ__GET_VBITS, - VG_USERREQ__SET_VBITS, - - VG_USERREQ__CREATE_BLOCK, - - VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, - - /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */ - VG_USERREQ__COUNT_LEAK_BLOCKS, - - /* This is just for memcheck's internal use - don't use it */ - _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR - = VG_USERREQ_TOOL_BASE('M','C') + 256 - } Vg_MemCheckClientRequest; - - - -/* Client-code macros to manipulate the state of memory. */ - -/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__MAKE_MEM_NOACCESS, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Similarly, mark memory at _qzz_addr as addressable but undefined - for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__MAKE_MEM_UNDEFINED, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Similarly, mark memory at _qzz_addr as addressable and defined - for _qzz_len bytes. */ -#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__MAKE_MEM_DEFINED, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is - not altered: bytes which are addressable are marked as defined, - but those which are not addressable are left unchanged. */ -#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Create a block-description handle. The description is an ascii - string which is included in any messages pertaining to addresses - within the specified memory range. Has no other effect on the - properties of the memory range. */ -#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CREATE_BLOCK, \ - (_qzz_addr), (_qzz_len), (_qzz_desc), \ - 0, 0) - -/* Discard a block-description-handle. Returns 1 for an - invalid handle, 0 for a valid handle. */ -#define VALGRIND_DISCARD(_qzz_blkindex) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__DISCARD, \ - 0, (_qzz_blkindex), 0, 0, 0) - - -/* Client-code macros to check the state of memory. */ - -/* Check that memory at _qzz_addr is addressable for _qzz_len bytes. - If suitable addressibility is not established, Valgrind prints an - error message and returns the address of the first offending byte. - Otherwise it returns zero. */ -#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Check that memory at _qzz_addr is addressable and defined for - _qzz_len bytes. If suitable addressibility and definedness are not - established, Valgrind prints an error message and returns the - address of the first offending byte. Otherwise it returns zero. */ -#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__CHECK_MEM_IS_DEFINED, \ - (_qzz_addr), (_qzz_len), 0, 0, 0) - -/* Use this macro to force the definedness and addressibility of an - lvalue to be checked. If suitable addressibility and definedness - are not established, Valgrind prints an error message and returns - the address of the first offending byte. Otherwise it returns - zero. */ -#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) \ - VALGRIND_CHECK_MEM_IS_DEFINED( \ - (volatile unsigned char *)&(__lvalue), \ - (unsigned long)(sizeof (__lvalue))) - - -/* Do a full memory leak check (like --leak-check=full) mid-execution. */ -#define VALGRIND_DO_LEAK_CHECK \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ - 0, 0, 0, 0, 0) - -/* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for - which there was an increase in leaked bytes or leaked nr of blocks - since the previous leak search. */ -#define VALGRIND_DO_ADDED_LEAK_CHECK \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ - 0, 1, 0, 0, 0) - -/* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with - increased or decreased leaked bytes/blocks since previous leak - search. */ -#define VALGRIND_DO_CHANGED_LEAK_CHECK \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ - 0, 2, 0, 0, 0) - -/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */ -#define VALGRIND_DO_QUICK_LEAK_CHECK \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ - 1, 0, 0, 0, 0) - -/* Return number of leaked, dubious, reachable and suppressed bytes found by - all previous leak checks. They must be lvalues. */ -#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed) \ - /* For safety on 64-bit platforms we assign the results to private - unsigned long variables, then assign these to the lvalues the user - specified, which works no matter what type 'leaked', 'dubious', etc - are. We also initialise '_qzz_leaked', etc because - VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as - defined. */ \ - { \ - unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ - unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ - VALGRIND_DO_CLIENT_REQUEST_STMT( \ - VG_USERREQ__COUNT_LEAKS, \ - &_qzz_leaked, &_qzz_dubious, \ - &_qzz_reachable, &_qzz_suppressed, 0); \ - leaked = _qzz_leaked; \ - dubious = _qzz_dubious; \ - reachable = _qzz_reachable; \ - suppressed = _qzz_suppressed; \ - } - -/* Return number of leaked, dubious, reachable and suppressed bytes found by - all previous leak checks. They must be lvalues. */ -#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \ - /* For safety on 64-bit platforms we assign the results to private - unsigned long variables, then assign these to the lvalues the user - specified, which works no matter what type 'leaked', 'dubious', etc - are. We also initialise '_qzz_leaked', etc because - VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as - defined. */ \ - { \ - unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ - unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ - VALGRIND_DO_CLIENT_REQUEST_STMT( \ - VG_USERREQ__COUNT_LEAK_BLOCKS, \ - &_qzz_leaked, &_qzz_dubious, \ - &_qzz_reachable, &_qzz_suppressed, 0); \ - leaked = _qzz_leaked; \ - dubious = _qzz_dubious; \ - reachable = _qzz_reachable; \ - suppressed = _qzz_suppressed; \ - } - - -/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it - into the provided zzvbits array. Return values: - 0 if not running on valgrind - 1 success - 2 [previously indicated unaligned arrays; these are now allowed] - 3 if any parts of zzsrc/zzvbits are not addressable. - The metadata is not copied in cases 0, 2 or 3 so it should be - impossible to segfault your system by using this call. -*/ -#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__GET_VBITS, \ - (const char*)(zza), \ - (char*)(zzvbits), \ - (zznbytes), 0, 0) - -/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it - from the provided zzvbits array. Return values: - 0 if not running on valgrind - 1 success - 2 [previously indicated unaligned arrays; these are now allowed] - 3 if any parts of zza/zzvbits are not addressable. - The metadata is not copied in cases 0, 2 or 3 so it should be - impossible to segfault your system by using this call. -*/ -#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__SET_VBITS, \ - (const char*)(zza), \ - (const char*)(zzvbits), \ - (zznbytes), 0, 0 ) - -#endif - Index: ps/trunk/libraries/source/valgrind/include/valgrind.h =================================================================== --- ps/trunk/libraries/source/valgrind/include/valgrind.h (revision 25932) +++ ps/trunk/libraries/source/valgrind/include/valgrind.h (nonexistent) @@ -1,4840 +0,0 @@ -/* -*- c -*- - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (valgrind.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of Valgrind, a dynamic binary instrumentation - framework. - - Copyright (C) 2000-2012 Julian Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (valgrind.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - - -/* This file is for inclusion into client (your!) code. - - You can use these macros to manipulate and query Valgrind's - execution inside your own programs. - - 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. 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 - -DNVALGRIND) so that client requests are not even compiled in. */ - -#ifndef __VALGRIND_H -#define __VALGRIND_H - - -/* ------------------------------------------------------------------ */ -/* VERSION NUMBER OF VALGRIND */ -/* ------------------------------------------------------------------ */ - -/* Specify Valgrind's version number, so that user code can - conditionally compile based on our version number. Note that these - were introduced at version 3.6 and so do not exist in version 3.5 - or earlier. The recommended way to use them to check for "version - X.Y or later" is (eg) - -#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ - && (__VALGRIND_MAJOR__ > 3 \ - || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) -*/ -#define __VALGRIND_MAJOR__ 3 -#define __VALGRIND_MINOR__ 8 - - -#include - -/* Nb: this file might be included in a file compiled with -ansi. So - we can't use C++ style "//" comments nor the "asm" keyword (instead - use "__asm__"). */ - -/* Derive some tags indicating what the target platform 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 (on Linux, that is). - - Misc note: how to find out what's predefined in gcc by default: - gcc -Wp,-dM somefile.c -*/ -#undef PLAT_x86_darwin -#undef PLAT_amd64_darwin -#undef PLAT_x86_win32 -#undef PLAT_x86_linux -#undef PLAT_amd64_linux -#undef PLAT_ppc32_linux -#undef PLAT_ppc64_linux -#undef PLAT_arm_linux -#undef PLAT_s390x_linux -#undef PLAT_mips32_linux - - -#if defined(__APPLE__) && defined(__i386__) -# define PLAT_x86_darwin 1 -#elif defined(__APPLE__) && defined(__x86_64__) -# define PLAT_amd64_darwin 1 -#elif defined(__MINGW32__) || defined(__CYGWIN32__) \ - || (defined(_WIN32) && defined(_M_IX86)) -# define PLAT_x86_win32 1 -#elif defined(__linux__) && defined(__i386__) -# define PLAT_x86_linux 1 -#elif defined(__linux__) && defined(__x86_64__) -# define PLAT_amd64_linux 1 -#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) -# define PLAT_ppc32_linux 1 -#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) -# define PLAT_ppc64_linux 1 -#elif defined(__linux__) && defined(__arm__) -# define PLAT_arm_linux 1 -#elif defined(__linux__) && defined(__s390__) && defined(__s390x__) -# define PLAT_s390x_linux 1 -#elif defined(__linux__) && defined(__mips__) -# define PLAT_mips32_linux 1 -#else -/* If we're not compiling for our target platform, don't generate - any inline asms. */ -# if !defined(NVALGRIND) -# define NVALGRIND 1 -# endif -#endif - - -/* ------------------------------------------------------------------ */ -/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ -/* in here of use to end-users -- skip to the next section. */ -/* ------------------------------------------------------------------ */ - -/* - * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client - * request. Accepts both pointers and integers as arguments. - * - * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind - * client request that does not return a value. - - * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind - * client request and whose value equals the client request result. Accepts - * both pointers and integers as arguments. Note that such calls are not - * necessarily pure functions -- they may have side effects. - */ - -#define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ - _zzq_request, _zzq_arg1, _zzq_arg2, \ - _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ - (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ - (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) - -#define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ - _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ - (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) - -#if defined(NVALGRIND) - -/* Define NVALGRIND to completely remove the Valgrind magic sequence - from the compiled code (analogous to NDEBUG's effects on - assert()) */ -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - (_zzq_default) - -#else /* ! NVALGRIND */ - -/* 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 five. - - The macro args are: - _zzq_rlval result lvalue - _zzq_default default value (result returned when running on real CPU) - _zzq_request request code - _zzq_arg1..5 request params - - The other two macros are used to support function wrapping, and are - a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the - guest's NRADDR pseudo-register and whatever other information is - needed to safely run the call original from the wrapper: on - ppc64-linux, the R2 value at the divert point is also needed. This - information is abstracted into a user-visible type, OrigFn. - - 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: - branch-and-link-to-r11. 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. -*/ - -/* ------------------------- x86-{linux,darwin} ---------------- */ - -#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ - || (defined(PLAT_x86_win32) && defined(__GNUC__)) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "roll $3, %%edi ; roll $13, %%edi\n\t" \ - "roll $29, %%edi ; roll $19, %%edi\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EDX = client_request ( %EAX ) */ \ - "xchgl %%ebx,%%ebx" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EAX = guest_NRADDR */ \ - "xchgl %%ecx,%%ecx" \ - : "=a" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_EAX \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%EAX */ \ - "xchgl %%edx,%%edx\n\t" -#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */ - -/* ------------------------- x86-Win32 ------------------------- */ - -#if defined(PLAT_x86_win32) && !defined(__GNUC__) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#if defined(_MSC_VER) - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - __asm rol edi, 3 __asm rol edi, 13 \ - __asm rol edi, 29 __asm rol edi, 19 - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ - (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ - (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ - (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) - -static __inline uintptr_t -valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, - uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, - uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, - uintptr_t _zzq_arg5) -{ - volatile uintptr_t _zzq_args[6]; - volatile unsigned int _zzq_result; - _zzq_args[0] = (uintptr_t)(_zzq_request); - _zzq_args[1] = (uintptr_t)(_zzq_arg1); - _zzq_args[2] = (uintptr_t)(_zzq_arg2); - _zzq_args[3] = (uintptr_t)(_zzq_arg3); - _zzq_args[4] = (uintptr_t)(_zzq_arg4); - _zzq_args[5] = (uintptr_t)(_zzq_arg5); - __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default - __SPECIAL_INSTRUCTION_PREAMBLE - /* %EDX = client_request ( %EAX ) */ - __asm xchg ebx,ebx - __asm mov _zzq_result, edx - } - return _zzq_result; -} - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EAX = guest_NRADDR */ \ - __asm xchg ecx,ecx \ - __asm mov __addr, eax \ - } \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_EAX ERROR - -#else -#error Unsupported compiler. -#endif - -#endif /* PLAT_x86_win32 */ - -/* ------------------------ amd64-{linux,darwin} --------------- */ - -#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ - "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({ volatile unsigned long long int _zzq_args[6]; \ - volatile unsigned long long int _zzq_result; \ - _zzq_args[0] = (unsigned long long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %RDX = client_request ( %RAX ) */ \ - "xchgq %%rbx,%%rbx" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %RAX = guest_NRADDR */ \ - "xchgq %%rcx,%%rcx" \ - : "=a" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_RAX \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%RAX */ \ - "xchgq %%rdx,%%rdx\n\t" -#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */ - -/* ------------------------ ppc32-linux ------------------------ */ - -#if defined(PLAT_ppc32_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ - "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({ unsigned int _zzq_args[6]; \ - unsigned int _zzq_result; \ - unsigned int* _zzq_ptr; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 3,%1\n\t" /*default*/ \ - "mr 4,%2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" /*result*/ \ - : "=b" (_zzq_result) \ - : "b" (_zzq_default), "b" (_zzq_ptr) \ - : "cc", "memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" -#endif /* PLAT_ppc32_linux */ - -/* ------------------------ ppc64-linux ------------------------ */ - -#if defined(PLAT_ppc64_linux) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - unsigned long long int r2; /* what tocptr do we need? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ - "rotldi 0,0,61 ; rotldi 0,0,51\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({ unsigned long long int _zzq_args[6]; \ - unsigned long long int _zzq_result; \ - unsigned long long int* _zzq_ptr; \ - _zzq_args[0] = (unsigned long long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 3,%1\n\t" /*default*/ \ - "mr 4,%2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" /*result*/ \ - : "=b" (_zzq_result) \ - : "b" (_zzq_default), "b" (_zzq_ptr) \ - : "cc", "memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned long long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR_GPR2 */ \ - "or 4,4,4\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->r2 = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" - -#endif /* PLAT_ppc64_linux */ - -/* ------------------------- arm-linux ------------------------- */ - -#if defined(PLAT_arm_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ - "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile("mov r3, %1\n\t" /*default*/ \ - "mov r4, %2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* R3 = client_request ( R4 ) */ \ - "orr r10, r10, r10\n\t" \ - "mov %0, r3" /*result*/ \ - : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ - : "cc","memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* R3 = guest_NRADDR */ \ - "orr r11, r11, r11\n\t" \ - "mov %0, r3" \ - : "=r" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R4 */ \ - "orr r12, r12, r12\n\t" - -#endif /* PLAT_arm_linux */ - -/* ------------------------ s390x-linux ------------------------ */ - -#if defined(PLAT_s390x_linux) - -typedef - struct { - unsigned long long int nraddr; /* where's the code? */ - } - OrigFn; - -/* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific - * code. This detection is implemented in platform specific toIR.c - * (e.g. VEX/priv/guest_s390_decoder.c). - */ -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "lr 15,15\n\t" \ - "lr 1,1\n\t" \ - "lr 2,2\n\t" \ - "lr 3,3\n\t" - -#define __CLIENT_REQUEST_CODE "lr 2,2\n\t" -#define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" -#define __CALL_NO_REDIR_CODE "lr 4,4\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({volatile unsigned long long int _zzq_args[6]; \ - volatile unsigned long long int _zzq_result; \ - _zzq_args[0] = (unsigned long long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ - __asm__ volatile(/* r2 = args */ \ - "lgr 2,%1\n\t" \ - /* r3 = default */ \ - "lgr 3,%2\n\t" \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - __CLIENT_REQUEST_CODE \ - /* results = r3 */ \ - "lgr %0, 3\n\t" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "2", "3", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - __GET_NR_CONTEXT_CODE \ - "lgr %0, 3\n\t" \ - : "=a" (__addr) \ - : \ - : "cc", "3", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_R1 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - __CALL_NO_REDIR_CODE - -#endif /* PLAT_s390x_linux */ - -/* ------------------------- mips32-linux ---------------- */ - -#if defined(PLAT_mips32_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -/* .word 0x342 - * .word 0x742 - * .word 0xC2 - * .word 0x4C2*/ -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "srl $0, $0, 13\n\t" \ - "srl $0, $0, 29\n\t" \ - "srl $0, $0, 3\n\t" \ - "srl $0, $0, 19\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({ volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile("move $11, %1\n\t" /*default*/ \ - "move $12, %2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* T3 = client_request ( T4 ) */ \ - "or $13, $13, $13\n\t" \ - "move %0, $11\n\t" /*result*/ \ - : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ - : "cc","memory", "t3", "t4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %t9 = guest_NRADDR */ \ - "or $14, $14, $14\n\t" \ - "move %0, $11" /*result*/ \ - : "=r" (__addr) \ - : \ - : "cc", "memory" , "t3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_T9 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%t9 */ \ - "or $15, $15, $15\n\t" -#endif /* PLAT_mips32_linux */ - -/* Insert assembly code for other platforms here... */ - -#endif /* NVALGRIND */ - - -/* ------------------------------------------------------------------ */ -/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ -/* ugly. It's the least-worst tradeoff I can think of. */ -/* ------------------------------------------------------------------ */ - -/* 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,5W,6W,7W,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. NOTE also: inserts - the default behaviour equivalance class tag "0000" into the name. - See pub_tool_redir.h for details -- normally you don't need to - think about this, though. */ - -/* Use an extra level of macroisation so as to ensure the soname/fnname - args are fully macro-expanded before pasting them together. */ -#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd - -#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ - VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) - -#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ - VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) - -/* Use this macro from within a wrapper function to collect the - context (address and possibly other info) of the original function. - Once you have that you can then use it in one of the CALL_FN_ - macros. The type of the argument _lval is OrigFn. */ -#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) - -/* Also provide end-user facilities for function replacement, rather - than wrapping. A replacement function differs from a wrapper in - that it has no way to get hold of the original function being - called, and hence no way to call onwards to it. In a replacement - function, VALGRIND_GET_ORIG_FN always returns zero. */ - -#define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ - VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) - -#define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ - VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) - -/* Derivatives of the main macros below, for calling functions - returning void. */ - -#define CALL_FN_v_v(fnptr) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_v(_junk,fnptr); } while (0) - -#define CALL_FN_v_W(fnptr, arg1) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_W(_junk,fnptr,arg1); } while (0) - -#define CALL_FN_v_WW(fnptr, arg1,arg2) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) - -#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) - -#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) - -#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) - -#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) - -#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) - -/* ------------------------- x86-{linux,darwin} ---------------- */ - -#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) - -/* 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" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "movl %%esp,%%edi\n\t" \ - "andl $0xfffffff0,%%esp\n\t" -#define VALGRIND_RESTORE_STACK \ - "movl %%edi,%%esp\n\t" - -/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\n\t" \ - "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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "pushl 32(%%eax)\n\t" \ - "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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\n\t" \ - "pushl 44(%%eax)\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "pushl 48(%%eax)\n\t" \ - "pushl 44(%%eax)\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "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 \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_x86_linux || PLAT_x86_darwin */ - -/* ------------------------ amd64-{linux,darwin} --------------- */ - -#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) - -/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ - "rdi", "r8", "r9", "r10", "r11" - -/* This is all pretty complex. It's so as to make stack unwinding - work reliably. See bug 243270. The basic problem is the sub and - add of 128 of %rsp in all of the following macros. If gcc believes - the CFA is in %rsp, then unwinding may fail, because what's at the - CFA is not what gcc "expected" when it constructs the CFIs for the - places where the macros are instantiated. - - But we can't just add a CFI annotation to increase the CFA offset - by 128, to match the sub of 128 from %rsp, because we don't know - whether gcc has chosen %rsp as the CFA at that point, or whether it - has chosen some other register (eg, %rbp). In the latter case, - adding a CFI annotation to change the CFA offset is simply wrong. - - So the solution is to get hold of the CFA using - __builtin_dwarf_cfa(), put it in a known register, and add a - CFI annotation to say what the register is. We choose %rbp for - this (perhaps perversely), because: - - (1) %rbp is already subject to unwinding. If a new register was - chosen then the unwinder would have to unwind it in all stack - traces, which is expensive, and - - (2) %rbp is already subject to precise exception updates in the - JIT. If a new register was chosen, we'd have to have precise - exceptions for it too, which reduces performance of the - generated code. - - However .. one extra complication. We can't just whack the result - of __builtin_dwarf_cfa() into %rbp and then add %rbp to the - list of trashed registers at the end of the inline assembly - fragments; gcc won't allow %rbp to appear in that list. Hence - instead we need to stash %rbp in %r15 for the duration of the asm, - and say that %r15 is trashed instead. gcc seems happy to go with - that. - - Oh .. and this all needs to be conditionalised so that it is - unchanged from before this commit, when compiled with older gccs - that don't support __builtin_dwarf_cfa. Furthermore, since - this header file is freestanding, it has to be independent of - config.h, and so the following conditionalisation cannot depend on - configure time checks. - - Although it's not clear from - 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', - this expression excludes Darwin. - .cfi directives in Darwin assembly appear to be completely - different and I haven't investigated how they work. - - For even more entertainment value, note we have to use the - completely undocumented __builtin_dwarf_cfa(), which appears to - really compute the CFA, whereas __builtin_frame_address(0) claims - to but actually doesn't. See - https://bugs.kde.org/show_bug.cgi?id=243270#c47 -*/ -#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) -# define __FRAME_POINTER \ - ,"r"(__builtin_dwarf_cfa()) -# define VALGRIND_CFI_PROLOGUE \ - "movq %%rbp, %%r15\n\t" \ - "movq %2, %%rbp\n\t" \ - ".cfi_remember_state\n\t" \ - ".cfi_def_cfa rbp, 0\n\t" -# define VALGRIND_CFI_EPILOGUE \ - "movq %%r15, %%rbp\n\t" \ - ".cfi_restore_state\n\t" -#else -# define __FRAME_POINTER -# define VALGRIND_CFI_PROLOGUE -# define VALGRIND_CFI_EPILOGUE -#endif - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "movq %%rsp,%%r14\n\t" \ - "andq $0xfffffffffffffff0,%%rsp\n\t" -#define VALGRIND_RESTORE_STACK \ - "movq %%r14,%%rsp\n\t" - -/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned - long) == 8. */ - -/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ - macros. In order not to trash the stack redzone, we need to drop - %rsp by 128 before the hidden call, and restore afterwards. The - nastyness is that it is only by luck that the stack still appears - to be unwindable during the hidden call - since then the behaviour - of any routine using this macro does not match what the CFI data - says. Sigh. - - Why is this important? Imagine that a wrapper has a stack - allocated local, and passes to the hidden call, a pointer to it. - Because gcc does not know about the hidden call, it may allocate - that local in the redzone. Unfortunately the hidden call may then - trash it before it comes to use it. So we must step clear of the - redzone, for the duration of the hidden call, to make it safe. - - Probably the same problem afflicts the other redzone-style ABIs too - (ppc64-linux); but for those, the stack is - self describing (none of this CFI nonsense) so at least messing - with the stack pointer doesn't give a danger of non-unwindable - stack. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 88(%%rax)\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 96(%%rax)\n\t" \ - "pushq 88(%%rax)\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */ - -/* ------------------------ ppc32-linux ------------------------ */ - -#if defined(PLAT_ppc32_linux) - -/* This is useful for finding out about the on-stack stuff: - - extern int f9 ( int,int,int,int,int,int,int,int,int ); - extern int f10 ( int,int,int,int,int,int,int,int,int,int ); - extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); - extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); - - int g9 ( void ) { - return f9(11,22,33,44,55,66,77,88,99); - } - int g10 ( void ) { - return f10(11,22,33,44,55,66,77,88,99,110); - } - int g11 ( void ) { - return f11(11,22,33,44,55,66,77,88,99,110,121); - } - int g12 ( void ) { - return f12(11,22,33,44,55,66,77,88,99,110,121,132); - } -*/ - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "mr 28,1\n\t" \ - "rlwinm 1,1,0,0,27\n\t" -#define VALGRIND_RESTORE_STACK \ - "mr 1,28\n\t" - -/* These CALL_FN_ macros assume that on ppc32-linux, - sizeof(unsigned long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-16\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-16\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-32\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,16(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - _argvec[12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-32\n\t" \ - /* arg12 */ \ - "lwz 3,48(11)\n\t" \ - "stw 3,20(1)\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,16(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc32_linux */ - -/* ------------------------ ppc64-linux ------------------------ */ - -#if defined(PLAT_ppc64_linux) - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "mr 28,1\n\t" \ - "rldicr 1,1,0,59\n\t" -#define VALGRIND_RESTORE_STACK \ - "mr 1,28\n\t" - -/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned - long) == 8. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+0]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+1]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+2]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+3]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+4]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+5]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+6]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+7]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+8]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+9]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+10]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+11]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+12]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - _argvec[2+12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg12 */ \ - "ld 3,96(11)\n\t" \ - "std 3,136(1)\n\t" \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc64_linux */ - -/* ------------------------- arm-linux ------------------------- */ - -#if defined(PLAT_arm_linux) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -/* This is a bit tricky. We store the original stack pointer in r10 - as it is callee-saves. gcc doesn't allow the use of r11 for some - reason. Also, we can't directly "bic" the stack pointer in thumb - mode since r13 isn't an allowed register number in that context. - So use r4 as a temporary, since that is about to get trashed - anyway, just after each use of this macro. Side effect is we need - to be very careful about any future changes, since - VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ -#define VALGRIND_ALIGN_STACK \ - "mov r10, sp\n\t" \ - "mov r4, sp\n\t" \ - "bic r4, r4, #7\n\t" \ - "mov sp, r4\n\t" -#define VALGRIND_RESTORE_STACK \ - "mov sp, r10\n\t" - -/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "push {r0} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "push {r0, r1} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "push {r0, r1, r2} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "push {r0, r1, r2, r3} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #40] \n\t" \ - "push {r0} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #40] \n\t" \ - "ldr r1, [%1, #44] \n\t" \ - "push {r0, r1} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #40] \n\t" \ - "ldr r1, [%1, #44] \n\t" \ - "ldr r2, [%1, #48] \n\t" \ - "push {r0, r1, r2} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_arm_linux */ - -/* ------------------------- s390x-linux ------------------------- */ - -#if defined(PLAT_s390x_linux) - -/* Similar workaround as amd64 (see above), but we use r11 as frame - pointer and save the old r11 in r7. r11 might be used for - argvec, therefore we copy argvec in r1 since r1 is clobbered - after the call anyway. */ -#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) -# define __FRAME_POINTER \ - ,"d"(__builtin_dwarf_cfa()) -# define VALGRIND_CFI_PROLOGUE \ - ".cfi_remember_state\n\t" \ - "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ - "lgr 7,11\n\t" \ - "lgr 11,%2\n\t" \ - ".cfi_def_cfa r11, 0\n\t" -# define VALGRIND_CFI_EPILOGUE \ - "lgr 11, 7\n\t" \ - ".cfi_restore_state\n\t" -#else -# define __FRAME_POINTER -# define VALGRIND_CFI_PROLOGUE \ - "lgr 1,%1\n\t" -# define VALGRIND_CFI_EPILOGUE -#endif - -/* Nb: On s390 the stack pointer is properly aligned *at all times* - according to the s390 GCC maintainer. (The ABI specification is not - precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and - VALGRIND_RESTORE_STACK are not defined here. */ - -/* These regs are trashed by the hidden call. Note that we overwrite - r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the - function a proper return address. All others are ABI defined call - clobbers. */ -#define __CALLER_SAVED_REGS "0","1","2","3","4","5","14", \ - "f0","f1","f2","f3","f4","f5","f6","f7" - -/* Nb: Although r11 is modified in the asm snippets below (inside - VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for - two reasons: - (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not - modified - (2) GCC will complain that r11 cannot appear inside a clobber section, - when compiled with -O -fno-omit-frame-pointer - */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 1, 0(1)\n\t" /* target->r1 */ \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -/* The call abi has the arguments in r2-r6 and stack */ -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1, arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-168\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,168\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-176\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,176\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-184\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,184\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-192\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,192\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-200\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,200\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10, arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-208\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "mvc 200(8,15), 88(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,208\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - _argvec[12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-216\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "mvc 200(8,15), 88(1)\n\t" \ - "mvc 208(8,15), 96(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "lgr %0, 2\n\t" \ - "aghi 15,216\n\t" \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - - -#endif /* PLAT_s390x_linux */ - -/* ------------------------- mips-linux ------------------------- */ - -#if defined(PLAT_mips32_linux) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ -"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ -"$25", "$31" - -/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16\n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $a0, 4(%1) \n\t" /* arg1*/ \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 24\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 24 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 32\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "nop\n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 32 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 32\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 32 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 40\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 40 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 40\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 36(%1) \n\t" \ - "sw $a0, 32($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 40 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 48\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 36(%1) \n\t" \ - "sw $a0, 32($sp) \n\t" \ - "lw $a0, 40(%1) \n\t" \ - "sw $a0, 36($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 48 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 48\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 36(%1) \n\t" \ - "sw $a0, 32($sp) \n\t" \ - "lw $a0, 40(%1) \n\t" \ - "sw $a0, 36($sp) \n\t" \ - "lw $a0, 44(%1) \n\t" \ - "sw $a0, 40($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 48 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $gp, 0($sp) \n\t" \ - "sw $ra, 4($sp) \n\t" \ - "lw $a0, 20(%1) \n\t" \ - "subu $sp, $sp, 56\n\t" \ - "sw $a0, 16($sp) \n\t" \ - "lw $a0, 24(%1) \n\t" \ - "sw $a0, 20($sp) \n\t" \ - "lw $a0, 28(%1) \n\t" \ - "sw $a0, 24($sp) \n\t" \ - "lw $a0, 32(%1) \n\t" \ - "sw $a0, 28($sp) \n\t" \ - "lw $a0, 36(%1) \n\t" \ - "sw $a0, 32($sp) \n\t" \ - "lw $a0, 40(%1) \n\t" \ - "sw $a0, 36($sp) \n\t" \ - "lw $a0, 44(%1) \n\t" \ - "sw $a0, 40($sp) \n\t" \ - "lw $a0, 48(%1) \n\t" \ - "sw $a0, 44($sp) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2, 12(%1) \n\t" \ - "lw $a3, 16(%1) \n\t" \ - "lw $t9, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $sp, $sp, 56 \n\t" \ - "lw $gp, 0($sp) \n\t" \ - "lw $ra, 4($sp) \n\t" \ - "addu $sp, $sp, 8 \n\t" \ - "move %0, $v0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_mips32_linux */ - - -/* ------------------------------------------------------------------ */ -/* 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. - - Core ones are in the range 0x00000000--0x0000ffff. The non-public - ones start at 0x2000. -*/ - -/* 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) \ - (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. */ -typedef - enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, - VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, - - /* 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 = 0x1101, - VG_USERREQ__CLIENT_CALL1 = 0x1102, - VG_USERREQ__CLIENT_CALL2 = 0x1103, - VG_USERREQ__CLIENT_CALL3 = 0x1104, - - /* Can be useful in regression testing suites -- eg. can - send Valgrind's output to /dev/null and still count - errors. */ - VG_USERREQ__COUNT_ERRORS = 0x1201, - - /* Allows a string (gdb monitor command) to be passed to the tool - Used for interaction with vgdb/gdb */ - VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, - - /* 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 = 0x1301, - VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, - VG_USERREQ__FREELIKE_BLOCK = 0x1302, - /* Memory pool support. */ - VG_USERREQ__CREATE_MEMPOOL = 0x1303, - VG_USERREQ__DESTROY_MEMPOOL = 0x1304, - VG_USERREQ__MEMPOOL_ALLOC = 0x1305, - VG_USERREQ__MEMPOOL_FREE = 0x1306, - VG_USERREQ__MEMPOOL_TRIM = 0x1307, - VG_USERREQ__MOVE_MEMPOOL = 0x1308, - VG_USERREQ__MEMPOOL_CHANGE = 0x1309, - VG_USERREQ__MEMPOOL_EXISTS = 0x130a, - - /* Allow printfs to valgrind log. */ - /* The first two pass the va_list argument by value, which - assumes it is the same size as or smaller than a UWord, - which generally isn't the case. Hence are deprecated. - The second two pass the vargs by reference and so are - immune to this problem. */ - /* both :: char* fmt, va_list vargs (DEPRECATED) */ - VG_USERREQ__PRINTF = 0x1401, - VG_USERREQ__PRINTF_BACKTRACE = 0x1402, - /* both :: char* fmt, va_list* vargs */ - VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, - - /* Stack support. */ - VG_USERREQ__STACK_REGISTER = 0x1501, - VG_USERREQ__STACK_DEREGISTER = 0x1502, - VG_USERREQ__STACK_CHANGE = 0x1503, - - /* Wine support */ - VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, - - /* Querying of debug info. */ - VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, - - /* Disable/enable error reporting level. Takes a single - Word arg which is the delta to this thread's error - disablement indicator. Hence 1 disables or further - disables errors, and -1 moves back towards enablement. - Other values are not allowed. */ - VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801 - } Vg_ClientRequest; - -#if !defined(__GNUC__) -# define __extension__ /* */ -#endif - - -/* 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 \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ - VG_USERREQ__RUNNING_ON_VALGRIND, \ - 0, 0, 0, 0, 0) \ - - -/* Discard translation of code in the range [_qzz_addr .. _qzz_addr + - _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) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ - _qzz_addr, _qzz_len, 0, 0, 0) - - -/* These requests are for getting Valgrind itself to print something. - Possibly with a backtrace. This is a really ugly hack. The return value - is the number of characters printed, excluding the "**** " part at the - start and the backtrace (if present). */ - -#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) -/* Modern GCC will optimize the static routine out if unused, - and unused attribute will shut down warnings about it. */ -static int VALGRIND_PRINTF(const char *format, ...) - __attribute__((format(__printf__, 1, 2), __unused__)); -#endif -static int -#if defined(_MSC_VER) -__inline -#endif -VALGRIND_PRINTF(const char *format, ...) -{ -#if defined(NVALGRIND) - return 0; -#else /* NVALGRIND */ -#if defined(_MSC_VER) - uintptr_t _qzz_res; -#else - unsigned long _qzz_res; -#endif - va_list vargs; - va_start(vargs, format); -#if defined(_MSC_VER) - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_VALIST_BY_REF, - (uintptr_t)format, - (uintptr_t)&vargs, - 0, 0, 0); -#else - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_VALIST_BY_REF, - (unsigned long)format, - (unsigned long)&vargs, - 0, 0, 0); -#endif - va_end(vargs); - return (int)_qzz_res; -#endif /* NVALGRIND */ -} - -#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) -static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) - __attribute__((format(__printf__, 1, 2), __unused__)); -#endif -static int -#if defined(_MSC_VER) -__inline -#endif -VALGRIND_PRINTF_BACKTRACE(const char *format, ...) -{ -#if defined(NVALGRIND) - return 0; -#else /* NVALGRIND */ -#if defined(_MSC_VER) - uintptr_t _qzz_res; -#else - unsigned long _qzz_res; -#endif - va_list vargs; - va_start(vargs, format); -#if defined(_MSC_VER) - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, - (uintptr_t)format, - (uintptr_t)&vargs, - 0, 0, 0); -#else - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, - (unsigned long)format, - (unsigned long)&vargs, - 0, 0, 0); -#endif - va_end(vargs); - return (int)_qzz_res; -#endif /* NVALGRIND */ -} - - -/* These requests allow control to move from the simulated CPU to the - real CPU, calling an arbitary function. - - Note that the current ThreadId is inserted as the first argument. - So this call: - - VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) - - requires f to have this signature: - - Word f(Word tid, Word arg1, Word arg2) - - where "Word" is a word-sized type. - - Note that these client requests are not entirely reliable. For example, - if you call a function with them that subsequently calls printf(), - there's a high chance Valgrind will crash. Generally, your prospects of - these working are made higher if the called function does not refer to - any global variables, and does not refer to any libc or other functions - (printf et al). Any kind of entanglement with libc or dynamic linking is - likely to have a bad outcome, for tricky reasons which we've grappled - with a lot in the past. -*/ -#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL0, \ - _qyy_fn, \ - 0, 0, 0, 0) - -#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL1, \ - _qyy_fn, \ - _qyy_arg1, 0, 0, 0) - -#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL2, \ - _qyy_fn, \ - _qyy_arg1, _qyy_arg2, 0, 0) - -#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL3, \ - _qyy_fn, \ - _qyy_arg1, _qyy_arg2, \ - _qyy_arg3, 0) - - -/* 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)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - 0 /* default return */, \ - VG_USERREQ__COUNT_ERRORS, \ - 0, 0, 0, 0, 0) - -/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing - when heap blocks are allocated in order to give accurate results. This - happens automatically for the standard allocator functions such as - malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, - delete[], etc. - - But if your program uses a custom allocator, this doesn't automatically - happen, and Valgrind will not do as well. For example, if you allocate - superblocks with mmap() and then allocates chunks of the superblocks, all - Valgrind's observations will be at the mmap() level and it won't know that - the chunks should be considered separate entities. In Memcheck's case, - that means you probably won't get heap block overrun detection (because - there won't be redzones marked as unaddressable) and you definitely won't - get any leak detection. - - The following client requests allow a custom allocator to be annotated so - that it can be handled accurately by Valgrind. - - VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated - by a malloc()-like function. For Memcheck (an illustrative case), this - does two things: - - - It records that the block has been allocated. This means any addresses - within the block mentioned in error messages will be - identified as belonging to the block. It also means that if the block - isn't freed it will be detected by the leak checker. - - - It marks the block as being addressable and undefined (if 'is_zeroed' is - not set), or addressable and defined (if 'is_zeroed' is set). This - controls how accesses to the block by the program are handled. - - 'addr' is the start of the usable block (ie. after any - redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator - can apply redzones -- these are blocks of padding at the start and end of - each block. Adding redzones is recommended as it makes it much more likely - Valgrind will spot block overruns. `is_zeroed' indicates if the memory is - zeroed (or filled with another predictable value), as is the case for - calloc(). - - VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a - heap block -- that will be used by the client program -- is allocated. - It's best to put it at the outermost level of the allocator if possible; - for example, if you have a function my_alloc() which calls - internal_alloc(), and the client request is put inside internal_alloc(), - stack traces relating to the heap block will contain entries for both - my_alloc() and internal_alloc(), which is probably not what you want. - - For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out - custom blocks from within a heap block, B, that has been allocated with - malloc/calloc/new/etc, then block B will be *ignored* during leak-checking - -- the custom blocks will take precedence. - - VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For - Memcheck, it does two things: - - - It records that the block has been deallocated. This assumes that the - block was annotated as having been allocated via - VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - - - It marks the block as being unaddressable. - - VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a - heap block is deallocated. - - VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For - Memcheck, it does four things: - - - It records that the size of a block has been changed. This assumes that - the block was annotated as having been allocated via - VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - - - If the block shrunk, it marks the freed memory as being unaddressable. - - - If the block grew, it marks the new area as undefined and defines a red - zone past the end of the new block. - - - The V-bits of the overlap between the old and the new block are preserved. - - VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block - and before deallocation of the old block. - - In many cases, these three client requests will not be enough to get your - allocator working well with Memcheck. More specifically, if your allocator - writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call - will be necessary to mark the memory as addressable just before the zeroing - occurs, otherwise you'll get a lot of invalid write errors. For example, - you'll need to do this if your allocator recycles freed blocks, but it - zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). - Alternatively, if your allocator reuses freed blocks for allocator-internal - data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. - - Really, what's happening is a blurring of the lines between the client - program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the - memory should be considered unaddressable to the client program, but the - allocator knows more than the rest of the client program and so may be able - to safely access it. Extra client requests are necessary for Valgrind to - understand the distinction between the allocator and the rest of the - program. - - Ignored if addr == 0. -*/ -#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ - addr, sizeB, rzB, is_zeroed, 0) - -/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. - Ignored if addr == 0. -*/ -#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ - addr, oldSizeB, newSizeB, rzB, 0) - -/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. - Ignored if addr == 0. -*/ -#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ - addr, rzB, 0, 0, 0) - -/* Create a memory pool. */ -#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ - pool, rzB, is_zeroed, 0, 0) - -/* Destroy a memory pool. */ -#define VALGRIND_DESTROY_MEMPOOL(pool) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ - pool, 0, 0, 0, 0) - -/* Associate a piece of memory with a memory pool. */ -#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ - pool, addr, size, 0, 0) - -/* Disassociate a piece of memory from a memory pool. */ -#define VALGRIND_MEMPOOL_FREE(pool, addr) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ - pool, addr, 0, 0, 0) - -/* Disassociate any pieces outside a particular range. */ -#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ - pool, addr, size, 0, 0) - -/* Resize and/or move a piece associated with a memory pool. */ -#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ - poolA, poolB, 0, 0, 0) - -/* Resize and/or move a piece associated with a memory pool. */ -#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ - pool, addrA, addrB, size, 0) - -/* Return 1 if a mempool exists, else 0. */ -#define VALGRIND_MEMPOOL_EXISTS(pool) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__MEMPOOL_EXISTS, \ - pool, 0, 0, 0, 0) - -/* Mark a piece of memory as being a stack. Returns a stack id. */ -#define VALGRIND_STACK_REGISTER(start, end) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__STACK_REGISTER, \ - start, end, 0, 0, 0) - -/* Unmark the piece of memory associated with a stack id as being a - stack. */ -#define VALGRIND_STACK_DEREGISTER(id) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ - id, 0, 0, 0, 0) - -/* Change the start and end address of the stack id. */ -#define VALGRIND_STACK_CHANGE(id, start, end) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ - id, start, end, 0, 0) - -/* Load PDB debug info for Wine PE image_map. */ -#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ - fd, ptr, total_size, delta, 0) - -/* Map a code address to a source file name and line number. buf64 - must point to a 64-byte buffer in the caller's address space. The - result will be dumped in there and is guaranteed to be zero - terminated. If no info is found, the first byte is set to zero. */ -#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__MAP_IP_TO_SRCLOC, \ - addr, buf64, 0, 0, 0) - -/* Disable error reporting for this thread. Behaves in a stack like - way, so you can safely call this multiple times provided that - VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times - to re-enable reporting. The first call of this macro disables - reporting. Subsequent calls have no effect except to increase the - number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable - reporting. Child threads do not inherit this setting from their - parents -- they are always created with reporting enabled. */ -#define VALGRIND_DISABLE_ERROR_REPORTING \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ - 1, 0, 0, 0, 0) - -/* Re-enable error reporting, as per comments on - VALGRIND_DISABLE_ERROR_REPORTING. */ -#define VALGRIND_ENABLE_ERROR_REPORTING \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ - -1, 0, 0, 0, 0) - -#undef PLAT_x86_darwin -#undef PLAT_amd64_darwin -#undef PLAT_x86_win32 -#undef PLAT_x86_linux -#undef PLAT_amd64_linux -#undef PLAT_ppc32_linux -#undef PLAT_ppc64_linux -#undef PLAT_arm_linux -#undef PLAT_s390x_linux -#undef PLAT_mips32_linux - -#endif /* __VALGRIND_H */ Index: ps/trunk/libraries/source/valgrind/include/callgrind.h =================================================================== --- ps/trunk/libraries/source/valgrind/include/callgrind.h (revision 25932) +++ ps/trunk/libraries/source/valgrind/include/callgrind.h (nonexistent) @@ -1,129 +0,0 @@ - -/* - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (callgrind.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of callgrind, a valgrind tool for cache simulation - and call tree tracing. - - Copyright (C) 2003-2012 Josef Weidendorfer. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (callgrind.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - -#ifndef __CALLGRIND_H -#define __CALLGRIND_H - -#include "valgrind.h" - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. - - The identification ('C','T') for Callgrind has historical - reasons: it was called "Calltree" before. Besides, ('C','G') would - clash with cachegrind. - */ - -typedef - enum { - VG_USERREQ__DUMP_STATS = VG_USERREQ_TOOL_BASE('C','T'), - VG_USERREQ__ZERO_STATS, - VG_USERREQ__TOGGLE_COLLECT, - VG_USERREQ__DUMP_STATS_AT, - VG_USERREQ__START_INSTRUMENTATION, - VG_USERREQ__STOP_INSTRUMENTATION - } Vg_CallgrindClientRequest; - -/* Dump current state of cost centers, and zero them afterwards */ -#define CALLGRIND_DUMP_STATS \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DUMP_STATS, \ - 0, 0, 0, 0, 0) - -/* Dump current state of cost centers, and zero them afterwards. - The argument is appended to a string stating the reason which triggered - the dump. This string is written as a description field into the - profile data dump. */ -#define CALLGRIND_DUMP_STATS_AT(pos_str) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DUMP_STATS_AT, \ - pos_str, 0, 0, 0, 0) - -/* Zero cost centers */ -#define CALLGRIND_ZERO_STATS \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ZERO_STATS, \ - 0, 0, 0, 0, 0) - -/* Toggles collection state. - The collection state specifies whether the happening of events - should be noted or if they are to be ignored. Events are noted - by increment of counters in a cost center */ -#define CALLGRIND_TOGGLE_COLLECT \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__TOGGLE_COLLECT, \ - 0, 0, 0, 0, 0) - -/* Start full callgrind instrumentation if not already switched on. - When cache simulation is done, it will flush the simulated cache; - this will lead to an artifical cache warmup phase afterwards with - cache misses which would not have happened in reality. */ -#define CALLGRIND_START_INSTRUMENTATION \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__START_INSTRUMENTATION, \ - 0, 0, 0, 0, 0) - -/* Stop full callgrind instrumentation if not already switched off. - This flushes Valgrinds translation cache, and does no additional - instrumentation afterwards, which effectivly will run at the same - speed as the "none" tool (ie. at minimal slowdown). - Use this to bypass Callgrind aggregation for uninteresting code parts. - To start Callgrind in this mode to ignore the setup phase, use - the option "--instr-atstart=no". */ -#define CALLGRIND_STOP_INSTRUMENTATION \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STOP_INSTRUMENTATION, \ - 0, 0, 0, 0, 0) - -#endif /* __CALLGRIND_H */ Index: ps/trunk/build/premake/extern_libs5.lua =================================================================== --- ps/trunk/build/premake/extern_libs5.lua (revision 25932) +++ ps/trunk/build/premake/extern_libs5.lua (revision 25933) @@ -1,736 +1,743 @@ -- this file provides project_add_extern_libs, which takes care of the -- dirty details of adding the libraries' include and lib paths. -- -- TYPICAL TASK: add new library. Instructions: -- 1) add a new extern_lib_defs entry -- 2) add library name to extern_libs tables in premake.lua for all 'projects' that want to use it -- directory in which OS-specific library subdirectories reside. if os.istarget("macosx") then libraries_dir = rootdir.."/libraries/osx/" elseif os.istarget("windows") then libraries_dir = rootdir.."/libraries/win32/" else -- No Unix-specific libs yet (use source directory instead!) end -- directory for shared, bundled libraries libraries_source_dir = rootdir.."/libraries/source/" third_party_source_dir = rootdir.."/source/third_party/" local function add_default_lib_paths(extern_lib) libdirs { libraries_dir .. extern_lib .. "/lib" } end local function add_source_lib_paths(extern_lib) libdirs { libraries_source_dir .. extern_lib .. "/lib" } end local function add_default_include_paths(extern_lib) sysincludedirs { libraries_dir .. extern_lib .. "/include" } end local function add_source_include_paths(extern_lib) sysincludedirs { libraries_source_dir .. extern_lib .. "/include" } end local function add_third_party_include_paths(extern_lib) sysincludedirs { third_party_source_dir .. extern_lib .. "/include" } end pkgconfig = require "pkgconfig" local function add_delayload(name, suffix, def) if def["no_delayload"] then return end -- currently only supported by VC; nothing to do on other platforms. if not os.istarget("windows") then return end -- no extra debug version; use same library in all configs if suffix == "" then linkoptions { "/DELAYLOAD:"..name..".dll" } -- extra debug version available; use in debug config else local dbg_cmd = "/DELAYLOAD:" .. name .. suffix .. ".dll" local cmd = "/DELAYLOAD:" .. name .. ".dll" filter "Debug" linkoptions { dbg_cmd } filter "Release" linkoptions { cmd } filter { } end end local function add_default_links(def) -- careful: make sure to only use *_names when on the correct platform. local names = {} if os.istarget("windows") then if def.win_names then names = def.win_names end elseif _OPTIONS["android"] and def.android_names then names = def.android_names elseif os.istarget("linux") and def.linux_names then names = def.linux_names elseif os.istarget("macosx") and (def.osx_names or def.osx_frameworks) then if def.osx_names then names = def.osx_names end -- OS X "Frameworks" are added to the links as "name.framework" if def.osx_frameworks then for i,name in pairs(def.osx_frameworks) do links { name .. ".framework" } end end elseif os.istarget("bsd") and def.bsd_names then names = def.bsd_names elseif def.unix_names then names = def.unix_names end local suffix = "d" -- library is overriding default suffix (typically "" to indicate there is none) if def["dbg_suffix"] then suffix = def["dbg_suffix"] end -- non-Windows doesn't have the distinction of debug vs. release libraries -- (to be more specific, they do, but the two are binary compatible; -- usually only one type - debug or release - is installed at a time). if not os.istarget("windows") then suffix = "" end for i,name in pairs(names) do filter "Debug" links { name .. suffix } filter "Release" links { name } filter { } add_delayload(name, suffix, def) end end -- Library definitions -- In a perfect world, libraries would have a common installation template, -- i.e. location of include directory, naming convention for .lib, etc. -- this table provides a means of working around each library's differences. -- -- The basic approach is defining two functions per library: -- -- 1. compile_settings -- This function should set all settings requred during the compile-phase like -- includedirs, defines etc... -- -- 2. link_settings -- This function should set all settings required during the link-phase like -- libdirs, linkflag etc... -- -- The main reason for separating those settings is different linking behaviour -- on osx and xcode. For more details, read the comment in project_add_extern_libs. -- -- There are some helper functions for the most common tasks. You should use them -- if they can be used in your situation to make the definitions more consistent and -- use their default beviours as a guideline. -- -- -- add_default_lib_paths(extern_lib) -- Description: Add '//lib'to the libpaths -- Parameters: -- * extern_lib: to be used in the libpath. -- -- add_default_include_paths(extern_lib) -- Description: Add '//include' to the includepaths -- Parameters: -- * extern_lib: to be used in the libpath. -- -- add_default_links -- Description: Adds links to libraries and configures delayloading. -- If the *_names parameter for a plattform is missing, no linking will be done -- on that plattform. -- The default assumptions are: -- * debug import library and DLL are distinguished with a "d" suffix -- * the library should be marked for delay-loading. -- Parameters: -- * win_names: table of import library / DLL names (no extension) when -- running on Windows. -- * unix_names: as above; shared object names when running on non-Windows. -- * osx_names, osx_frameworks: for OS X specifically; if any of those is -- specified, unix_names is ignored. Using both is possible if needed. -- * osx_names: as above. -- * osx_frameworks: as above, for system libraries that need to be linked -- as "name.framework". -- * bsd_names: as above; for BSD specifically (overrides unix_names if both are -- specified) -- * linux_names: ditto for Linux (overrides unix_names if both given) -- * dbg_suffix: changes the debug suffix from the above default. -- can be "" to indicate the library doesn't have a debug build; -- in that case, the same library (without suffix) is used in -- all build configurations. -- * no_delayload: indicate the library is not to be delay-loaded. -- this is necessary for some libraries that do not support it, -- e.g. Xerces (which is so stupid as to export variables). extern_lib_defs = { boost = { compile_settings = function() if os.istarget("windows") then -- Force the autolink to use the vc141 libs. defines { 'BOOST_LIB_TOOLSET="vc141"' } add_default_include_paths("boost") elseif os.istarget("macosx") then -- Suppress all the Boost warnings on OS X by including it as a system directory buildoptions { "-isystem../" .. libraries_dir .. "boost/include" } end -- TODO: This actually applies to most libraries we use on BSDs, make this a global setting. if os.istarget("bsd") then sysincludedirs { "/usr/local/include" } end end, link_settings = function() if os.istarget("windows") or os.istarget("macosx") then if os.istarget("windows") then defines { 'BOOST_LIB_TOOLSET="vc141"' } end add_default_lib_paths("boost") end add_default_links({ -- The following are not strictly link dependencies on all systems, but -- are included for compatibility with different versions of Boost android_names = { "boost_filesystem-gcc-mt", "boost_system-gcc-mt" }, unix_names = { os.findlib("boost_filesystem-mt") and "boost_filesystem-mt" or "boost_filesystem", os.findlib("boost_system-mt") and "boost_system-mt" or "boost_system" }, osx_names = { "boost_filesystem", "boost_system" }, }) end, }, comsuppw = { link_settings = function() add_default_links({ win_names = { "comsuppw" }, dbg_suffix = "d", no_delayload = 1, }) end, }, cxxtest = { compile_settings = function() sysincludedirs { libraries_source_dir .. "cxxtest-4.4" } end, }, enet = { compile_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_include_paths("enet") end end, link_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_lib_paths("enet") end add_default_links({ win_names = { "enet" }, unix_names = { "enet" }, }) end, }, fcollada = { compile_settings = function() add_source_include_paths("fcollada") end, link_settings = function() add_source_lib_paths("fcollada") if os.istarget("windows") then filter "Debug" links { "FColladaD" } filter "Release" links { "FCollada" } filter { } else filter "Debug" links { "FColladaSD" } filter "Release" links { "FColladaSR" } filter { } end end, }, fmt = { compile_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_include_paths("fmt") end -- With Linux & BSD, we assume that fmt is installed in a standard location. -- -- It would be nice to not assume, and to instead use pkgconfig: however that -- requires fmt 5.3.0 or greater. -- -- Unfortunately (at the time of writing) only 69 out of 95 (~72.6%) of distros -- that provide a fmt package meet this, according to -- https://repology.org/badge/vertical-allrepos/fmt.svg?minversion=5.3 -- -- Whilst that might seem like a healthy majority, this does not include the 2018 -- Long Term Support and 2019.10 releases of Ubuntu - not only popular and widely -- used as-is, but which are also used as a base for other popular distros (e.g. -- Mint). -- -- When fmt 5.3 (or better) becomes more widely used, then we can safely use the -- following line: -- pkgconfig.add_includes("fmt") end, link_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_lib_paths("fmt") end if os.istarget("windows") then add_default_links({ win_names = { "fmt" }, dbg_suffix = "d", no_delayload = 1, }) else add_default_links({ unix_names = { "fmt" }, }) -- See comment above as to why this is commented out. -- pkgconfig.add_links("fmt") end end }, gloox = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("gloox") else -- Support GLOOX_CONFIG for overriding the default (pkg-config --cflags gloox) -- i.e. on OSX where it gets set in update-workspaces.sh pkgconfig.add_includes("gloox", os.getenv("GLOOX_CONFIG")) end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("gloox") add_default_links({ win_names = { "gloox-1.0" }, no_delayload = 1, }) else pkgconfig.add_links("gloox", os.getenv("GLOOX_CONFIG")) if os.istarget("macosx") then -- Manually add gnutls dependencies, those are not present in gloox's pkg-config add_default_lib_paths("nettle") add_default_lib_paths("gmp") add_default_links({ osx_names = { "nettle", "hogweed", "gmp" }, }) end end end, }, iconv = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("iconv") defines { "HAVE_ICONV_CONST" } defines { "ICONV_CONST=const" } defines { "LIBICONV_STATIC" } elseif os.istarget("macosx") then add_default_include_paths("iconv") defines { "LIBICONV_STATIC" } elseif os.getversion().description == "FreeBSD" then -- On FreeBSD you need this flag to tell it to use the BSD libc iconv defines { "LIBICONV_PLUG" } end end, link_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_lib_paths("iconv") end add_default_links({ win_names = { "libiconv" }, osx_names = { "iconv" }, dbg_suffix = "", no_delayload = 1, }) -- glibc (used on Linux and GNU/kFreeBSD) has iconv end, }, icu = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("icu") else -- Support ICU_CONFIG for overriding the default (pkg-config --cflags icu-i18n) -- i.e. on OSX where it gets set in update-workspaces.sh pkgconfig.add_includes("icu-i18n", os.getenv("ICU_CONFIG"), "--cppflags") end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("icu") add_default_links({ win_names = { "icuuc", "icuin" }, dbg_suffix = "", no_delayload = 1, }) else pkgconfig.add_links("icu-i18n", os.getenv("ICU_CONFIG"), "--ldflags-searchpath --ldflags-libsonly --ldflags-system") end end, }, libcurl = { compile_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_include_paths("libcurl") end end, link_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_lib_paths("libcurl") end add_default_links({ win_names = { "libcurl" }, unix_names = { "curl" }, osx_names = { "curl", "z" }, osx_frameworks = { "Security" } }) end, }, libpng = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("libpng") else -- Support LIBPNG_CONFIG for overriding the default (pkg-config --cflags libpng) -- i.e. on OSX where it gets set in update-workspaces.sh pkgconfig.add_includes("libpng", os.getenv("LIBPNG_CONFIG")) end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("libpng") add_default_links({ win_names = { "libpng16" }, }) else pkgconfig.add_links("libpng", os.getenv("LIBPNG_CONFIG"), "--ldflags") end end, }, libsodium = { compile_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_include_paths("libsodium") end end, link_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_lib_paths("libsodium") end add_default_links({ win_names = { "libsodium" }, unix_names = { "sodium" }, }) end, }, libxml2 = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("libxml2") else -- Support XML2_CONFIG for overriding the default (pkg-config --cflags libxml-2.0) -- i.e. on OSX where it gets set in update-workspaces.sh pkgconfig.add_includes("libxml-2.0", os.getenv("XML2_CONFIG")) end if os.istarget("macosx") then -- libxml2 needs _REENTRANT or __MT__ for thread support; -- OS X doesn't get either set by default, so do it manually defines { "_REENTRANT" } end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("libxml2") filter "Debug" links { "libxml2" } filter "Release" links { "libxml2" } filter { } else pkgconfig.add_links("libxml-2.0", os.getenv("XML2_CONFIG")) end end, }, miniupnpc = { compile_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_include_paths("miniupnpc") end end, link_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_lib_paths("miniupnpc") end add_default_links({ win_names = { "miniupnpc" }, unix_names = { "miniupnpc" }, }) end, }, nvtt = { compile_settings = function() if not _OPTIONS["with-system-nvtt"] then add_source_include_paths("nvtt") end defines { "NVTT_SHARED=1" } end, link_settings = function() if not _OPTIONS["with-system-nvtt"] then add_source_lib_paths("nvtt") end add_default_links({ win_names = { "nvtt" }, unix_names = { "nvcore", "nvmath", "nvimage", "nvtt" }, osx_names = { "bc6h", "bc7", "nvcore", "nvimage", "nvmath", "nvthread", "nvtt", "squish" }, dbg_suffix = "", -- for performance we always use the release-mode version }) end, }, openal = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("openal") end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("openal") end add_default_links({ win_names = { "openal32" }, unix_names = { "openal" }, osx_frameworks = { "OpenAL" }, dbg_suffix = "", no_delayload = 1, -- delayload seems to cause errors on startup }) end, }, opengl = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("opengl") end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("opengl") end if _OPTIONS["gles"] then add_default_links({ unix_names = { "GLESv2" }, dbg_suffix = "", }) else add_default_links({ win_names = { "opengl32", "gdi32" }, unix_names = { "GL" }, osx_frameworks = { "OpenGL" }, dbg_suffix = "", no_delayload = 1, -- delayload seems to cause errors on startup }) end end, }, sdl = { compile_settings = function() if os.istarget("windows") then includedirs { libraries_dir .. "sdl2/include/SDL" } elseif not _OPTIONS["android"] then -- Support SDL2_CONFIG for overriding the default (pkg-config sdl2) -- i.e. on OSX where it gets set in update-workspaces.sh pkgconfig.add_includes("sdl2", os.getenv("SDL2_CONFIG")) end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("sdl2") elseif not _OPTIONS["android"] then pkgconfig.add_links("sdl2", os.getenv("SDL2_CONFIG")) end end, }, spidermonkey = { compile_settings = function() if _OPTIONS["with-system-mozjs"] then if not _OPTIONS["android"] then pkgconfig.add_includes("mozjs-78") end else if os.istarget("windows") then include_dir = "include-win32" buildoptions { "/FI\"js/RequiredDefines.h\"" } else include_dir = "include-unix" end filter "Debug" sysincludedirs { libraries_source_dir.."spidermonkey/"..include_dir.."-debug" } defines { "DEBUG" } filter "Release" sysincludedirs { libraries_source_dir.."spidermonkey/"..include_dir.."-release" } filter { } end end, link_settings = function() if _OPTIONS["with-system-mozjs"] then if _OPTIONS["android"] then links { "mozjs-78" } else pkgconfig.add_links("mozjs-78") end else filter { "Debug", "action:vs*" } links { "mozjs78-ps-debug" } links { "mozjs78-ps-rust-debug" } filter { "Debug", "action:not vs*" } links { "mozjs78-ps-debug" } links { "mozjs78-ps-rust" } filter { "Release" } links { "mozjs78-ps-release" } links { "mozjs78-ps-rust" } filter { } add_source_lib_paths("spidermonkey") end end, }, tinygettext = { compile_settings = function() add_third_party_include_paths("tinygettext") end, }, valgrind = { compile_settings = function() - add_source_include_paths("valgrind") + -- Optional dependency + -- + -- valgrind doesn't support windows: + -- https://valgrind.org/info/platforms.html + if _OPTIONS["with-valgrind"] and not os.istarget("windows") then + pkgconfig.add_includes("valgrind") + defines { "CONFIG2_VALGRIND=1" } + end end, }, vorbis = { compile_settings = function() if os.istarget("windows") then add_default_include_paths("vorbis") elseif os.istarget("macosx") then add_default_include_paths("libogg") add_default_include_paths("vorbis") end end, link_settings = function() if os.istarget("windows") then add_default_lib_paths("vorbis") elseif os.istarget("macosx") then add_default_lib_paths("libogg") add_default_lib_paths("vorbis") end -- TODO: We need to force linking with these as currently -- they need to be loaded explicitly on execution if os.getversion().description == "OpenBSD" then add_default_links({ unix_names = { "ogg", "vorbis" }, }) end add_default_links({ win_names = { "libvorbisfile" }, unix_names = { "vorbisfile" }, osx_names = { "vorbis", "vorbisenc", "vorbisfile", "ogg" }, }) end, }, wxwidgets = { compile_settings = function() if os.istarget("windows") then includedirs { libraries_dir.."wxwidgets/include/msvc" } add_default_include_paths("wxwidgets") else -- wxwidgets does not come with a definition file for pkg-config, -- so we have to use wxwidgets' own config tool wx_config_path = os.getenv("WX_CONFIG") or "wx-config" pkgconfig.add_includes(nil, wx_config_path, "--unicode=yes --cxxflags") end end, link_settings = function() if os.istarget("windows") then libdirs { libraries_dir.."wxwidgets/lib/vc_lib" } else wx_config_path = os.getenv("WX_CONFIG") or "wx-config" pkgconfig.add_links(nil, wx_config_path, "--unicode=yes --libs std,gl") end end, }, x11 = { compile_settings = function() if not os.istarget("windows") and not os.istarget("macosx") then pkgconfig.add_includes("x11") end end, link_settings = function() if not os.istarget("windows") and not os.istarget("macosx") then pkgconfig.add_links("x11") end end, }, zlib = { compile_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_include_paths("zlib") end end, link_settings = function() if os.istarget("windows") or os.istarget("macosx") then add_default_lib_paths("zlib") end add_default_links({ win_names = { "zlib1" }, unix_names = { "z" }, no_delayload = 1, }) end, }, } -- add a set of external libraries to the project; takes care of -- include / lib path and linking against the import library. -- extern_libs: table of library names [string] -- target_type: String defining the projects kind [string] function project_add_extern_libs(extern_libs, target_type) for i,extern_lib in pairs(extern_libs) do local def = extern_lib_defs[extern_lib] assert(def, "external library " .. extern_lib .. " not defined") if def.compile_settings then def.compile_settings() end -- Linking to external libraries will only be done in the main executable and not in the -- static libraries. Premake would silently skip linking into static libraries for some -- actions anyway (e.g. vs2010). -- On osx using xcode, if this linking would be defined in the static libraries, it would fail to -- link if only dylibs are available. If both *.a and *.dylib are available, it would link statically. -- I couldn't find any problems with that approach. if target_type ~= "StaticLib" and def.link_settings then def.link_settings() end end end Index: ps/trunk/build/premake/premake5.lua =================================================================== --- ps/trunk/build/premake/premake5.lua (revision 25932) +++ ps/trunk/build/premake/premake5.lua (revision 25933) @@ -1,1475 +1,1476 @@ newoption { trigger = "android", description = "Use non-working Android cross-compiling mode" } newoption { trigger = "atlas", description = "Include Atlas scenario editor projects" } newoption { trigger = "coverage", description = "Enable code coverage data collection (GCC only)" } newoption { trigger = "gles", description = "Use non-working OpenGL ES 2.0 mode" } newoption { trigger = "icc", description = "Use Intel C++ Compiler (Linux only; should use either \"--cc icc\" or --without-pch too, and then set CXX=icpc before calling make)" } newoption { trigger = "jenkins-tests", description = "Configure CxxTest to use the XmlPrinter runner which produces Jenkins-compatible output" } newoption { trigger = "minimal-flags", description = "Only set compiler/linker flags that are really needed. Has no effect on Windows builds" } newoption { trigger = "outpath", description = "Location for generated project files" } newoption { trigger = "with-system-mozjs", description = "Search standard paths for libmozjs60, instead of using bundled copy" } newoption { trigger = "with-system-nvtt", description = "Search standard paths for nvidia-texture-tools library, instead of using bundled copy" } +newoption { trigger = "with-valgrind", description = "Enable Valgrind support (non-Windows only)" } newoption { trigger = "without-audio", description = "Disable use of OpenAL/Ogg/Vorbis APIs" } newoption { trigger = "without-lobby", description = "Disable the use of gloox and the multiplayer lobby" } newoption { trigger = "without-miniupnpc", description = "Disable use of miniupnpc for port forwarding" } newoption { trigger = "without-nvtt", description = "Disable use of NVTT" } newoption { trigger = "without-pch", description = "Disable generation and usage of precompiled headers" } newoption { trigger = "without-tests", description = "Disable generation of test projects" } -- Linux/BSD specific options newoption { trigger = "prefer-local-libs", description = "Prefer locally built libs. Any local libraries used must also be listed within a file within /etc/ld.so.conf.d so the dynamic linker can find them at runtime." } -- OS X specific options newoption { trigger = "macosx-version-min", description = "Set minimum required version of the OS X API, the build will possibly fail if an older SDK is used, while newer API functions will be weakly linked (i.e. resolved at runtime)" } newoption { trigger = "sysroot", description = "Set compiler system root path, used for building against a non-system SDK. For example /usr/local becomes SYSROOT/user/local" } -- Windows specific options newoption { trigger = "build-shared-glooxwrapper", description = "Rebuild glooxwrapper DLL for Windows. Requires the same compiler version that gloox was built with" } newoption { trigger = "use-shared-glooxwrapper", description = "Use prebuilt glooxwrapper DLL for Windows" } newoption { trigger = "large-address-aware", description = "Make the executable large address aware. Do not use for development, in order to spot memory issues easily" } -- Install options newoption { trigger = "bindir", description = "Directory for executables (typically '/usr/games'); default is to be relocatable" } newoption { trigger = "datadir", description = "Directory for data files (typically '/usr/share/games/0ad'); default is ../data/ relative to executable" } newoption { trigger = "libdir", description = "Directory for libraries (typically '/usr/lib/games/0ad'); default is ./ relative to executable" } -- Root directory of project checkout relative to this .lua file rootdir = "../.." dofile("extern_libs5.lua") -- detect compiler for non-Windows if os.istarget("macosx") then cc = "clang" elseif os.istarget("linux") and _OPTIONS["icc"] then cc = "icc" elseif os.istarget("bsd") and os.getversion().description == "FreeBSD" then cc = "clang" elseif not os.istarget("windows") then cc = os.getenv("CC") if cc == nil or cc == "" then local hasgcc = os.execute("which gcc > .gccpath") local f = io.open(".gccpath", "r") local gccpath = f:read("*line") f:close() os.execute("rm .gccpath") if gccpath == nil then cc = "clang" else cc = "gcc" end end end -- detect CPU architecture (simplistic, currently only supports x86, amd64 and ARM) arch = "x86" if _OPTIONS["android"] then arch = "arm" elseif os.istarget("windows") then if os.getenv("PROCESSOR_ARCHITECTURE") == "amd64" or os.getenv("PROCESSOR_ARCHITEW6432") == "amd64" then arch = "amd64" end else arch = os.getenv("HOSTTYPE") if arch == "x86_64" or arch == "amd64" then arch = "amd64" else os.execute(cc .. " -dumpmachine > .gccmachine.tmp") local f = io.open(".gccmachine.tmp", "r") local machine = f:read("*line") f:close() if string.find(machine, "x86_64") == 1 or string.find(machine, "amd64") == 1 then arch = "amd64" elseif string.find(machine, "i.86") == 1 then arch = "x86" elseif string.find(machine, "arm") == 1 then arch = "arm" elseif string.find(machine, "aarch64") == 1 then arch = "aarch64" elseif string.find(machine, "e2k") == 1 then arch = "e2k" elseif string.find(machine, "ppc64") == 1 or string.find(machine, "powerpc64") == 1 then arch = "ppc64" else print("WARNING: Cannot determine architecture from GCC, assuming x86") end end end -- Test whether we need to link libexecinfo. -- This is mostly the case on musl systems, as well as on BSD systems : only glibc provides the -- backtrace symbols we require in the libc, for other libcs we use the libexecinfo library. local link_execinfo = false if os.istarget("bsd") then link_execinfo = true elseif os.istarget("linux") then local _, link_errorCode = os.outputof(cc .. " ./tests/execinfo.c -o /dev/null") if link_errorCode ~= 0 then link_execinfo = true end end -- Set up the Workspace workspace "pyrogenesis" targetdir(rootdir.."/binaries/system") libdirs(rootdir.."/binaries/system") if not _OPTIONS["outpath"] then error("You must specify the 'outpath' parameter") end location(_OPTIONS["outpath"]) configurations { "Release", "Debug" } source_root = rootdir.."/source/" -- default for most projects - overridden by local in others -- Rationale: projects should not have any additional include paths except for -- those required by external libraries. Instead, we should always write the -- full relative path, e.g. #include "maths/Vector3d.h". This avoids confusion -- ("which file is meant?") and avoids enormous include path lists. -- projects: engine static libs, main exe, atlas, atlas frontends, test. -------------------------------------------------------------------------------- -- project helper functions -------------------------------------------------------------------------------- function project_set_target(project_name) -- Note: On Windows, ".exe" is added on the end, on unices the name is used directly local obj_dir_prefix = _OPTIONS["outpath"].."/obj/"..project_name.."_" filter "Debug" objdir(obj_dir_prefix.."Debug") targetsuffix("_dbg") filter "Release" objdir(obj_dir_prefix.."Release") filter { } end function project_set_build_flags() editandcontinue "Off" if not _OPTIONS["minimal-flags"] then symbols "On" end if cc ~= "icc" and (os.istarget("windows") or not _OPTIONS["minimal-flags"]) then -- adds the -Wall compiler flag warnings "Extra" -- this causes far too many warnings/remarks on ICC end -- disable Windows debug heap, since it makes malloc/free hugely slower when -- running inside a debugger if os.istarget("windows") then debugenvs { "_NO_DEBUG_HEAP=1" } end filter "Debug" defines { "DEBUG" } filter "Release" if os.istarget("windows") or not _OPTIONS["minimal-flags"] then optimize "Speed" end defines { "NDEBUG", "CONFIG_FINAL=1" } filter { } if _OPTIONS["gles"] then defines { "CONFIG2_GLES=1" } end if _OPTIONS["without-audio"] then defines { "CONFIG2_AUDIO=0" } end if _OPTIONS["without-nvtt"] then defines { "CONFIG2_NVTT=0" } end if _OPTIONS["without-lobby"] then defines { "CONFIG2_LOBBY=0" } end if _OPTIONS["without-miniupnpc"] then defines { "CONFIG2_MINIUPNPC=0" } end -- required for the lowlevel library. must be set from all projects that use it, otherwise it assumes it is -- being used as a DLL (which is currently not the case in 0ad) defines { "LIB_STATIC_LINK" } -- Enable C++17 standard. filter "action:vs*" buildoptions { "/std:c++17" } filter "action:not vs*" buildoptions { "-std=c++17" } filter {} -- various platform-specific build flags if os.istarget("windows") then flags { "MultiProcessorCompile" } -- Since KB4088875 Windows 7 has a soft requirement for SSE2. -- Windows 8+ and Firefox ESR52 make it hard requirement. -- Finally since VS2012 it's enabled implicitely when not set. vectorextensions "SSE2" -- use native wchar_t type (not typedef to unsigned short) nativewchar "on" else -- *nix -- TODO, FIXME: This check is incorrect because it means that some additional flags will be added inside the "else" branch if the -- compiler is ICC and minimal-flags is specified (ticket: #2994) if cc == "icc" and not _OPTIONS["minimal-flags"] then buildoptions { "-w1", -- "-Wabi", -- "-Wp64", -- complains about OBJECT_TO_JSVAL which is annoying "-Wpointer-arith", "-Wreturn-type", -- "-Wshadow", "-Wuninitialized", "-Wunknown-pragmas", "-Wunused-function", "-wd1292" -- avoid lots of 'attribute "__nonnull__" ignored' } filter "Debug" buildoptions { "-O0" } -- ICC defaults to -O2 filter { } if os.istarget("macosx") then linkoptions { "-multiply_defined","suppress" } end else -- exclude most non-essential build options for minimal-flags if not _OPTIONS["minimal-flags"] then buildoptions { -- enable most of the standard warnings "-Wno-switch", -- enumeration value not handled in switch (this is sometimes useful, but results in lots of noise) "-Wno-reorder", -- order of initialization list in constructors (lots of noise) "-Wno-invalid-offsetof", -- offsetof on non-POD types (see comment in renderer/PatchRData.cpp) "-Wextra", "-Wno-missing-field-initializers", -- (this is common in external headers we can't fix) -- add some other useful warnings that need to be enabled explicitly "-Wunused-parameter", "-Wredundant-decls", -- (useful for finding some multiply-included header files) -- "-Wformat=2", -- (useful sometimes, but a bit noisy, so skip it by default) -- "-Wcast-qual", -- (useful for checking const-correctness, but a bit noisy, so skip it by default) "-Wnon-virtual-dtor", -- (sometimes noisy but finds real bugs) "-Wundef", -- (useful for finding macro name typos) -- enable security features (stack checking etc) that shouldn't have -- a significant effect on performance and can catch bugs "-fstack-protector-all", "-U_FORTIFY_SOURCE", -- (avoid redefinition warning if already defined) "-D_FORTIFY_SOURCE=2", -- always enable strict aliasing (useful in debug builds because of the warnings) "-fstrict-aliasing", -- don't omit frame pointers (for now), because performance will be impacted -- negatively by the way this breaks profilers more than it will be impacted -- positively by the optimisation "-fno-omit-frame-pointer" } if not _OPTIONS["without-pch"] then buildoptions { -- do something (?) so that ccache can handle compilation with PCH enabled -- (ccache 3.1+ also requires CCACHE_SLOPPINESS=time_macros for this to work) "-fpch-preprocess" } end if os.istarget("linux") or os.istarget("bsd") then buildoptions { "-fPIC" } linkoptions { "-Wl,--no-undefined", "-Wl,--as-needed", "-Wl,-z,relro" } end if arch == "x86" then buildoptions { -- To support intrinsics like __sync_bool_compare_and_swap on x86 -- we need to set -march to something that supports them (i686). -- We use pentium3 to also enable other features like mmx and sse, -- while tuning for generic to have good performance on every -- supported CPU. -- Note that all these features are already supported on amd64. "-march=pentium3 -mtune=generic" } end end if arch == "arm" then -- disable warnings about va_list ABI change and use -- compile-time flags for futher configuration. buildoptions { "-Wno-psabi" } if _OPTIONS["android"] then -- Android uses softfp, so we should too. buildoptions { "-mfloat-abi=softfp" } end end if _OPTIONS["coverage"] then buildoptions { "-fprofile-arcs", "-ftest-coverage" } links { "gcov" } end -- MacOS 10.12 only supports processors with SSE 4.1, so enable that. if os.istarget("macosx") then buildoptions { "-msse4.1" } end -- Check if SDK path should be used if _OPTIONS["sysroot"] then buildoptions { "-isysroot " .. _OPTIONS["sysroot"] } linkoptions { "-Wl,-syslibroot," .. _OPTIONS["sysroot"] } end -- On OS X, sometimes we need to specify the minimum API version to use if _OPTIONS["macosx-version-min"] then buildoptions { "-mmacosx-version-min=" .. _OPTIONS["macosx-version-min"] } -- clang and llvm-gcc look at mmacosx-version-min to determine link target -- and CRT version, and use it to set the macosx_version_min linker flag linkoptions { "-mmacosx-version-min=" .. _OPTIONS["macosx-version-min"] } end -- Only libc++ is supported on MacOS if os.istarget("macosx") then buildoptions { "-stdlib=libc++" } linkoptions { "-stdlib=libc++" } end end buildoptions { -- Hide symbols in dynamic shared objects by default, for efficiency and for equivalence with -- Windows - they should be exported explicitly with __attribute__ ((visibility ("default"))) "-fvisibility=hidden" } if _OPTIONS["bindir"] then defines { "INSTALLED_BINDIR=" .. _OPTIONS["bindir"] } end if _OPTIONS["datadir"] then defines { "INSTALLED_DATADIR=" .. _OPTIONS["datadir"] } end if _OPTIONS["libdir"] then defines { "INSTALLED_LIBDIR=" .. _OPTIONS["libdir"] } end if os.istarget("linux") or os.istarget("bsd") then if _OPTIONS["prefer-local-libs"] then libdirs { "/usr/local/lib" } end -- To use our local shared libraries, they need to be found in the -- runtime dynamic linker path. Add their path to -rpath. if _OPTIONS["libdir"] then linkoptions {"-Wl,-rpath," .. _OPTIONS["libdir"] } else -- On FreeBSD we need to allow use of $ORIGIN if os.istarget("bsd") then linkoptions { "-Wl,-z,origin" } end -- Adding the executable path and taking care of correct escaping if _ACTION == "gmake" then linkoptions { "-Wl,-rpath,'$$ORIGIN'" } elseif _ACTION == "codeblocks" then linkoptions { "-Wl,-R\\\\$$$ORIGIN" } end end end end end -- create a project and set the attributes that are common to all projects. function project_create(project_name, target_type) project(project_name) language "C++" kind(target_type) filter "action:vs2017" toolset "v141_xp" filter {} filter "action:vs*" buildoptions "/utf-8" filter {} project_set_target(project_name) project_set_build_flags() end -- OSX creates a .app bundle if the project type of the main application is set to "WindowedApp". -- We don't want this because this bundle would be broken (it lacks all the resources and external dependencies, Info.plist etc...) -- Windows opens a console in the background if it's set to ConsoleApp, which is not what we want. -- I didn't check if this setting matters for linux, but WindowedApp works there. function get_main_project_target_type() if _OPTIONS["android"] then return "SharedLib" elseif os.istarget("macosx") then return "ConsoleApp" else return "WindowedApp" end end -- source_root: rel_source_dirs and rel_include_dirs are relative to this directory -- rel_source_dirs: A table of subdirectories. All source files in these directories are added. -- rel_include_dirs: A table of subdirectories to be included. -- extra_params: table including zero or more of the following: -- * no_pch: If specified, no precompiled headers are used for this project. -- * pch_dir: If specified, this directory will be used for precompiled headers instead of the default -- /pch//. -- * extra_files: table of filenames (relative to source_root) to add to project -- * extra_links: table of library names to add to link step function project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) for i,v in pairs(rel_source_dirs) do local prefix = source_root..v.."/" files { prefix.."*.cpp", prefix.."*.h", prefix.."*.inl", prefix.."*.js", prefix.."*.asm", prefix.."*.mm" } end -- Put the project-specific PCH directory at the start of the -- include path, so '#include "precompiled.h"' will look in -- there first local pch_dir if not extra_params["pch_dir"] then pch_dir = source_root .. "pch/" .. project().name .. "/" else pch_dir = extra_params["pch_dir"] end includedirs { pch_dir } -- Precompiled Headers -- rationale: we need one PCH per static lib, since one global header would -- increase dependencies. To that end, we can either include them as -- "projectdir/precompiled.h", or add "source/PCH/projectdir" to the -- include path and put the PCH there. The latter is better because -- many projects contain several dirs and it's unclear where there the -- PCH should be stored. This way is also a bit easier to use in that -- source files always include "precompiled.h". -- Notes: -- * Visual Assist manages to use the project include path and can -- correctly open these files from the IDE. -- * precompiled.cpp (needed to "Create" the PCH) also goes in -- the abovementioned dir. if (not _OPTIONS["without-pch"] and not extra_params["no_pch"]) then filter "action:vs*" pchheader("precompiled.h") filter "action:xcode*" pchheader("../"..pch_dir.."precompiled.h") filter { "action:not vs*", "action:not xcode*" } pchheader(pch_dir.."precompiled.h") filter {} pchsource(pch_dir.."precompiled.cpp") defines { "CONFIG_ENABLE_PCH=1" } files { pch_dir.."precompiled.h", pch_dir.."precompiled.cpp" } else defines { "CONFIG_ENABLE_PCH=0" } flags { "NoPCH" } end -- next is source root dir, for absolute (nonrelative) includes -- (e.g. "lib/precompiled.h") includedirs { source_root } for i,v in pairs(rel_include_dirs) do includedirs { source_root .. v } end if extra_params["extra_files"] then for i,v in pairs(extra_params["extra_files"]) do -- .rc files are only needed on Windows if path.getextension(v) ~= ".rc" or os.istarget("windows") then files { source_root .. v } end end end if extra_params["extra_links"] then links { extra_params["extra_links"] } end end -- Add command-line options to set up the manifest dependencies for Windows -- (See lib/sysdep/os/win/manifest.cpp) function project_add_manifest() linkoptions { "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df'\"" } end -------------------------------------------------------------------------------- -- engine static libraries -------------------------------------------------------------------------------- -- the engine is split up into several static libraries. this eases separate -- distribution of those components, reduces dependencies a bit, and can -- also speed up builds. -- more to the point, it is necessary to efficiently support a separate -- test executable that also includes much of the game code. -- names of all static libs created. automatically added to the -- main app project later (see explanation at end of this file) static_lib_names = {} static_lib_names_debug = {} static_lib_names_release = {} -- set up one of the static libraries into which the main engine code is split. -- extra_params: -- no_default_link: If specified, linking won't be done by default. -- For the rest of extra_params, see project_add_contents(). -- note: rel_source_dirs and rel_include_dirs are relative to global source_root. function setup_static_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) local target_type = "StaticLib" project_create(project_name, target_type) project_add_contents(source_root, rel_source_dirs, {}, extra_params) project_add_extern_libs(extern_libs, target_type) if not extra_params["no_default_link"] then table.insert(static_lib_names, project_name) end -- Deactivate Run Time Type Information. Performance of dynamic_cast is very poor. -- The exception to this principle is Atlas UI, which is not a static library. rtti "off" if os.istarget("macosx") and _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end end function setup_third_party_static_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) setup_static_lib_project(project_name, rel_source_dirs, extern_libs, extra_params) includedirs { source_root .. "third_party/" .. project_name .. "/include/" } end function setup_shared_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) local target_type = "SharedLib" project_create(project_name, target_type) project_add_contents(source_root, rel_source_dirs, {}, extra_params) project_add_extern_libs(extern_libs, target_type) if not extra_params["no_default_link"] then table.insert(static_lib_names, project_name) end if os.istarget("windows") then links { "delayimp" } elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end end -- this is where the source tree is chopped up into static libs. -- can be changed very easily; just copy+paste a new setup_static_lib_project, -- or remove existing ones. static libs are automagically added to -- main_exe link step. function setup_all_libs () -- relative to global source_root. local source_dirs = {} -- names of external libraries used (see libraries_dir comment) local extern_libs = {} source_dirs = { "network", } extern_libs = { "spidermonkey", "enet", "sdl", "boost", -- dragged in via server->simulation.h->random and NetSession.h->lockfree "fmt", } if not _OPTIONS["without-miniupnpc"] then table.insert(extern_libs, "miniupnpc") end setup_static_lib_project("network", source_dirs, extern_libs, {}) source_dirs = { "rlinterface", } extern_libs = { "boost", -- dragged in via simulation.h and scriptinterface.h "fmt", "spidermonkey", } setup_static_lib_project("rlinterface", source_dirs, extern_libs, { no_pch = 1 }) source_dirs = { "third_party/tinygettext/src", } extern_libs = { "iconv", "boost", "fmt", } setup_third_party_static_lib_project("tinygettext", source_dirs, extern_libs, { } ) -- it's an external library and we don't want to modify its source to fix warnings, so we just disable them to avoid noise in the compile output filter "action:vs*" buildoptions { "/wd4127", "/wd4309", "/wd4800", "/wd4100", "/wd4996", "/wd4099", "/wd4503" } filter {} if not _OPTIONS["without-lobby"] then source_dirs = { "lobby", "lobby/scripting", "i18n", "third_party/encryption" } extern_libs = { "spidermonkey", "boost", "enet", "gloox", "icu", "iconv", "libsodium", "tinygettext", "fmt", } setup_static_lib_project("lobby", source_dirs, extern_libs, {}) if _OPTIONS["use-shared-glooxwrapper"] and not _OPTIONS["build-shared-glooxwrapper"] then table.insert(static_lib_names_debug, "glooxwrapper_dbg") table.insert(static_lib_names_release, "glooxwrapper") else source_dirs = { "lobby/glooxwrapper", } extern_libs = { "boost", "gloox", "fmt", } if _OPTIONS["build-shared-glooxwrapper"] then setup_shared_lib_project("glooxwrapper", source_dirs, extern_libs, {}) else setup_static_lib_project("glooxwrapper", source_dirs, extern_libs, {}) end end else source_dirs = { "lobby/scripting", "third_party/encryption" } extern_libs = { "spidermonkey", "boost", "libsodium", "fmt", } setup_static_lib_project("lobby", source_dirs, extern_libs, {}) files { source_root.."lobby/Globals.cpp" } end source_dirs = { "simulation2", "simulation2/components", "simulation2/helpers", "simulation2/scripting", "simulation2/serialization", "simulation2/system", "simulation2/testcomponents", } extern_libs = { "boost", "opengl", "spidermonkey", "fmt", } setup_static_lib_project("simulation2", source_dirs, extern_libs, {}) source_dirs = { "scriptinterface", "scriptinterface/third_party" } extern_libs = { "boost", "spidermonkey", "valgrind", "sdl", "fmt", } setup_static_lib_project("scriptinterface", source_dirs, extern_libs, {}) source_dirs = { "ps", "ps/scripting", "network/scripting", "ps/GameSetup", "ps/XMB", "ps/XML", "soundmanager", "soundmanager/data", "soundmanager/items", "soundmanager/scripting", "maths", "maths/scripting", "i18n", "i18n/scripting", } extern_libs = { "spidermonkey", "sdl", -- key definitions "libxml2", "opengl", "zlib", "boost", "enet", "libcurl", "tinygettext", "icu", "iconv", "libsodium", "fmt", } if not _OPTIONS["without-audio"] then table.insert(extern_libs, "openal") table.insert(extern_libs, "vorbis") end setup_static_lib_project("engine", source_dirs, extern_libs, {}) source_dirs = { "graphics", "graphics/scripting", "renderer", "renderer/scripting", "third_party/mikktspace", "third_party/ogre3d_preprocessor" } extern_libs = { "opengl", "sdl", -- key definitions "spidermonkey", -- for graphics/scripting "boost", "fmt", "icu", } if not _OPTIONS["without-nvtt"] then table.insert(extern_libs, "nvtt") end setup_static_lib_project("graphics", source_dirs, extern_libs, {}) source_dirs = { "tools/atlas/GameInterface", "tools/atlas/GameInterface/Handlers" } extern_libs = { "boost", "sdl", -- key definitions "opengl", "spidermonkey", "fmt", } setup_static_lib_project("atlas", source_dirs, extern_libs, {}) source_dirs = { "gui", "gui/ObjectTypes", "gui/ObjectBases", "gui/Scripting", "gui/SettingTypes", "i18n" } extern_libs = { "spidermonkey", "sdl", -- key definitions "opengl", "boost", "enet", "tinygettext", "icu", "iconv", "fmt", } if not _OPTIONS["without-audio"] then table.insert(extern_libs, "openal") end setup_static_lib_project("gui", source_dirs, extern_libs, {}) source_dirs = { "lib", "lib/adts", "lib/allocators", "lib/external_libraries", "lib/file", "lib/file/archive", "lib/file/common", "lib/file/io", "lib/file/vfs", "lib/pch", "lib/posix", "lib/res", "lib/res/graphics", "lib/sysdep", "lib/tex" } extern_libs = { "boost", "sdl", "openal", "opengl", "libpng", "zlib", "valgrind", "cxxtest", "fmt", } -- CPU architecture-specific if arch == "amd64" then table.insert(source_dirs, "lib/sysdep/arch/amd64"); table.insert(source_dirs, "lib/sysdep/arch/x86_x64"); elseif arch == "x86" then table.insert(source_dirs, "lib/sysdep/arch/ia32"); table.insert(source_dirs, "lib/sysdep/arch/x86_x64"); elseif arch == "arm" then table.insert(source_dirs, "lib/sysdep/arch/arm"); elseif arch == "aarch64" then table.insert(source_dirs, "lib/sysdep/arch/aarch64"); elseif arch == "e2k" then table.insert(source_dirs, "lib/sysdep/arch/e2k"); elseif arch == "ppc64" then table.insert(source_dirs, "lib/sysdep/arch/ppc64"); end -- OS-specific sysdep_dirs = { linux = { "lib/sysdep/os/linux", "lib/sysdep/os/unix" }, -- note: RC file must be added to main_exe project. -- note: don't add "lib/sysdep/os/win/aken.cpp" because that must be compiled with the DDK. windows = { "lib/sysdep/os/win", "lib/sysdep/os/win/wposix", "lib/sysdep/os/win/whrt" }, macosx = { "lib/sysdep/os/osx", "lib/sysdep/os/unix" }, bsd = { "lib/sysdep/os/bsd", "lib/sysdep/os/unix", "lib/sysdep/os/unix/x" }, } for i,v in pairs(sysdep_dirs[os.target()]) do table.insert(source_dirs, v); end if os.istarget("linux") then if _OPTIONS["android"] then table.insert(source_dirs, "lib/sysdep/os/android") else table.insert(source_dirs, "lib/sysdep/os/unix/x") end end -- On OSX, disable precompiled headers because C++ files and Objective-C++ files are -- mixed in this project. To fix that, we would need per-file basis configuration which -- is not yet supported by the gmake action in premake. We should look into using gmake2. extra_params = {} if os.istarget("macosx") then extra_params = { no_pch = 1 } end -- runtime-library-specific if _ACTION == "vs2017" then table.insert(source_dirs, "lib/sysdep/rtl/msc"); else table.insert(source_dirs, "lib/sysdep/rtl/gcc"); end setup_static_lib_project("lowlevel", source_dirs, extern_libs, extra_params) -- Third-party libraries that are built as part of the main project, -- not built externally and then linked source_dirs = { "third_party/mongoose", } extern_libs = { } setup_static_lib_project("mongoose", source_dirs, extern_libs, { no_pch = 1 }) -- CxxTest mock function support extern_libs = { "boost", "cxxtest", } -- 'real' implementations, to be linked against the main executable -- (files are added manually and not with setup_static_lib_project -- because not all files in the directory are included) setup_static_lib_project("mocks_real", {}, extern_libs, { no_default_link = 1, no_pch = 1 }) files { "mocks/*.h", source_root.."mocks/*_real.cpp" } -- 'test' implementations, to be linked against the test executable setup_static_lib_project("mocks_test", {}, extern_libs, { no_default_link = 1, no_pch = 1 }) files { source_root.."mocks/*.h", source_root.."mocks/*_test.cpp" } end -------------------------------------------------------------------------------- -- main EXE -------------------------------------------------------------------------------- -- used for main EXE as well as test used_extern_libs = { "opengl", "sdl", "libpng", "zlib", "spidermonkey", "libxml2", "boost", "cxxtest", "comsuppw", "enet", "libcurl", "tinygettext", "icu", "iconv", "libsodium", "fmt", "valgrind", } if not os.istarget("windows") and not _OPTIONS["android"] and not os.istarget("macosx") then -- X11 should only be linked on *nix table.insert(used_extern_libs, "x11") end if not _OPTIONS["without-audio"] then table.insert(used_extern_libs, "openal") table.insert(used_extern_libs, "vorbis") end if not _OPTIONS["without-nvtt"] then table.insert(used_extern_libs, "nvtt") end if not _OPTIONS["without-lobby"] then table.insert(used_extern_libs, "gloox") end if not _OPTIONS["without-miniupnpc"] then table.insert(used_extern_libs, "miniupnpc") end -- Bundles static libs together with main.cpp and builds game executable. function setup_main_exe () local target_type = get_main_project_target_type() project_create("pyrogenesis", target_type) filter "system:not macosx" linkgroups 'On' filter {} links { "mocks_real" } local extra_params = { extra_files = { "main.cpp" }, no_pch = 1 } project_add_contents(source_root, {}, {}, extra_params) project_add_extern_libs(used_extern_libs, target_type) dependson { "Collada" } rtti "off" -- Platform Specifics if os.istarget("windows") then files { source_root.."lib/sysdep/os/win/icon.rc" } -- from "lowlevel" static lib; must be added here to be linked in files { source_root.."lib/sysdep/os/win/error_dialog.rc" } linkoptions { -- wraps main thread in a __try block(see wseh.cpp). replace with mainCRTStartup if that's undesired. "/ENTRY:wseh_EntryPoint", -- see wstartup.h "/INCLUDE:_wstartup_InitAndRegisterShutdown", -- allow manual unload of delay-loaded DLLs "/DELAY:UNLOAD", } -- allow the executable to use more than 2GB of RAM. -- this should not be enabled during development, so that memory issues are easily spotted. if _OPTIONS["large-address-aware"] then linkoptions { "/LARGEADDRESSAWARE" } end -- see manifest.cpp project_add_manifest() elseif os.istarget("linux") or os.istarget("bsd") then if not _OPTIONS["android"] and not (os.getversion().description == "OpenBSD") then links { "rt" } end if _OPTIONS["android"] then -- NDK's STANDALONE-TOOLCHAIN.html says this is required linkoptions { "-Wl,--fix-cortex-a8" } links { "log" } end if link_execinfo then links { "execinfo" } end if os.istarget("linux") or os.getversion().description == "GNU/kFreeBSD" then links { -- Dynamic libraries (needed for linking for gold) "dl", } end -- Threading support buildoptions { "-pthread" } if not _OPTIONS["android"] then linkoptions { "-pthread" } end -- For debug_resolve_symbol filter "Debug" linkoptions { "-rdynamic" } filter { } elseif os.istarget("macosx") then links { "pthread" } links { "ApplicationServices.framework", "Cocoa.framework", "CoreFoundation.framework" } if _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end end end -------------------------------------------------------------------------------- -- atlas -------------------------------------------------------------------------------- -- setup a typical Atlas component project -- extra_params, rel_source_dirs and rel_include_dirs: as in project_add_contents; function setup_atlas_project(project_name, target_type, rel_source_dirs, rel_include_dirs, extern_libs, extra_params) local source_root = rootdir.."/source/tools/atlas/" .. project_name .. "/" project_create(project_name, target_type) -- if not specified, the default for atlas pch files is in the project root. if not extra_params["pch_dir"] then extra_params["pch_dir"] = source_root end project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) project_add_extern_libs(extern_libs, target_type) -- Platform Specifics if os.istarget("windows") then -- Link to required libraries links { "winmm", "delayimp" } elseif os.istarget("linux") or os.istarget("bsd") then if os.getversion().description == "FreeBSD" then buildoptions { "-fPIC" } linkoptions { "-fPIC" } else buildoptions { "-rdynamic", "-fPIC" } linkoptions { "-fPIC", "-rdynamic" } end -- warnings triggered by wxWidgets buildoptions { "-Wno-unused-local-typedefs" } end end -- build all Atlas component projects function setup_atlas_projects() setup_atlas_project("AtlasObject", "StaticLib", { -- src ".", "../../../third_party/jsonspirit" },{ -- include "../../../third_party/jsonspirit" },{ -- extern_libs "boost", "iconv", "libxml2" },{ -- extra_params no_pch = 1 }) atlas_src = { "ActorEditor", "CustomControls/Buttons", "CustomControls/Canvas", "CustomControls/ColorDialog", "CustomControls/DraggableListCtrl", "CustomControls/EditableListCtrl", "CustomControls/FileHistory", "CustomControls/HighResTimer", "CustomControls/MapDialog", "CustomControls/MapResizeDialog", "CustomControls/SnapSplitterWindow", "CustomControls/VirtualDirTreeCtrl", "CustomControls/Windows", "General", "General/VideoRecorder", "Misc", "ScenarioEditor", "ScenarioEditor/Sections/Common", "ScenarioEditor/Sections/Cinema", "ScenarioEditor/Sections/Environment", "ScenarioEditor/Sections/Map", "ScenarioEditor/Sections/Object", "ScenarioEditor/Sections/Player", "ScenarioEditor/Sections/Terrain", "ScenarioEditor/Tools", "ScenarioEditor/Tools/Common", } atlas_extra_links = { "AtlasObject" } atlas_extern_libs = { "boost", "comsuppw", "iconv", "libxml2", "sdl", -- key definitions "wxwidgets", "zlib", } if not os.istarget("windows") and not os.istarget("macosx") then -- X11 should only be linked on *nix table.insert(atlas_extern_libs, "x11") end setup_atlas_project("AtlasUI", "SharedLib", atlas_src, { -- include "..", "CustomControls", "Misc", "../../../third_party/jsonspirit" }, atlas_extern_libs, { -- extra_params pch_dir = rootdir.."/source/tools/atlas/AtlasUI/Misc/", no_pch = false, extra_links = atlas_extra_links, extra_files = { "Misc/atlas.rc" } }) end -- Atlas 'frontend' tool-launching projects function setup_atlas_frontend_project (project_name) local target_type = get_main_project_target_type() project_create(project_name, target_type) local source_root = rootdir.."/source/tools/atlas/AtlasFrontends/" files { source_root..project_name..".cpp" } if os.istarget("windows") then files { source_root..project_name..".rc" } end includedirs { source_root .. ".." } -- Platform Specifics if os.istarget("windows") then -- see manifest.cpp project_add_manifest() else -- Non-Windows, = Unix links { "AtlasObject" } end links { "AtlasUI" } end function setup_atlas_frontends() setup_atlas_frontend_project("ActorEditor") end -------------------------------------------------------------------------------- -- collada -------------------------------------------------------------------------------- function setup_collada_project(project_name, target_type, rel_source_dirs, rel_include_dirs, extern_libs, extra_params) project_create(project_name, target_type) local source_root = source_root.."collada/" extra_params["pch_dir"] = source_root project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) project_add_extern_libs(extern_libs, target_type) -- Platform Specifics if os.istarget("windows") then characterset "MBCS" elseif os.istarget("linux") then defines { "LINUX" } links { "dl", } -- FCollada is not aliasing-safe, so disallow dangerous optimisations -- (TODO: It'd be nice to fix FCollada, but that looks hard) buildoptions { "-fno-strict-aliasing" } if os.getversion().description ~= "FreeBSD" then buildoptions { "-rdynamic" } linkoptions { "-rdynamic" } end elseif os.istarget("bsd") then if os.getversion().description == "OpenBSD" then links { "c", } end if os.getversion().description == "GNU/kFreeBSD" then links { "dl", } end buildoptions { "-fno-strict-aliasing" } buildoptions { "-rdynamic" } linkoptions { "-rdynamic" } elseif os.istarget("macosx") then -- define MACOS-something? buildoptions { "-fno-strict-aliasing" } -- On OSX, fcollada uses a few utility functions from coreservices links { "CoreServices.framework" } end end -- build all Collada component projects function setup_collada_projects() setup_collada_project("Collada", "SharedLib", { -- src "." },{ -- include },{ -- extern_libs "fcollada", "iconv", "libxml2" },{ -- extra_params }) end -------------------------------------------------------------------------------- -- tests -------------------------------------------------------------------------------- function setup_tests() local cxxtest = require "cxxtest" if os.istarget("windows") then cxxtest.setpath(rootdir.."/build/bin/cxxtestgen.exe") else cxxtest.setpath(rootdir.."/libraries/source/cxxtest-4.4/bin/cxxtestgen") end local runner = "ErrorPrinter" if _OPTIONS["jenkins-tests"] then runner = "XmlPrinter" end local includefiles = { -- Precompiled headers - the header is added to all generated .cpp files -- note that the header isn't actually precompiled here, only #included -- so that the build stage can use it as a precompiled header. "precompiled.h", -- This is required to build against SDL 2.0.4 on Windows. "lib/external_libraries/libsdl.h", } cxxtest.init(source_root, true, runner, includefiles) local target_type = get_main_project_target_type() project_create("test", target_type) -- Find header files in 'test' subdirectories local all_files = os.matchfiles(source_root .. "**/tests/*.h") local test_files = {} for i,v in pairs(all_files) do -- Don't include sysdep tests on the wrong sys -- Don't include Atlas tests unless Atlas is being built if not (string.find(v, "/sysdep/os/win/") and not os.istarget("windows")) and not (string.find(v, "/tools/atlas/") and not _OPTIONS["atlas"]) and not (string.find(v, "/sysdep/arch/x86_x64/") and ((arch ~= "amd64") or (arch ~= "x86"))) then table.insert(test_files, v) end end cxxtest.configure_project(test_files) filter "system:not macosx" linkgroups 'On' filter {} links { static_lib_names } filter "Debug" links { static_lib_names_debug } filter "Release" links { static_lib_names_release } filter { } links { "mocks_test" } if _OPTIONS["atlas"] then links { "AtlasObject" } end extra_params = { extra_files = { "test_setup.cpp" }, } project_add_contents(source_root, {}, {}, extra_params) project_add_extern_libs(used_extern_libs, target_type) dependson { "Collada" } rtti "off" -- TODO: should fix the duplication between this OS-specific linking -- code, and the similar version in setup_main_exe if os.istarget("windows") then -- from "lowlevel" static lib; must be added here to be linked in files { source_root.."lib/sysdep/os/win/error_dialog.rc" } -- see wstartup.h linkoptions { "/INCLUDE:_wstartup_InitAndRegisterShutdown" } -- Enables console for the TEST project on Windows linkoptions { "/SUBSYSTEM:CONSOLE" } project_add_manifest() elseif os.istarget("linux") or os.istarget("bsd") then if link_execinfo then links { "execinfo" } end if not _OPTIONS["android"] and not (os.getversion().description == "OpenBSD") then links { "rt" } end if _OPTIONS["android"] then -- NDK's STANDALONE-TOOLCHAIN.html says this is required linkoptions { "-Wl,--fix-cortex-a8" } end if os.istarget("linux") or os.getversion().description == "GNU/kFreeBSD" then links { -- Dynamic libraries (needed for linking for gold) "dl", } end -- Threading support buildoptions { "-pthread" } if not _OPTIONS["android"] then linkoptions { "-pthread" } end -- For debug_resolve_symbol filter "Debug" linkoptions { "-rdynamic" } filter { } includedirs { source_root .. "pch/test/" } elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } end end -- must come first, so that VC sets it as the default project and therefore -- allows running via F5 without the "where is the EXE" dialog. setup_main_exe() setup_all_libs() -- add the static libs to the main EXE project. only now (after -- setup_all_libs has run) are the lib names known. cannot move -- setup_main_exe to run after setup_all_libs (see comment above). -- we also don't want to hardcode the names - that would require more -- work when changing the static lib breakdown. project("pyrogenesis") -- Set the main project active links { static_lib_names } filter "Debug" links { static_lib_names_debug } filter "Release" links { static_lib_names_release } filter { } if _OPTIONS["atlas"] then setup_atlas_projects() setup_atlas_frontends() end setup_collada_projects() if not _OPTIONS["without-tests"] then setup_tests() end Index: ps/trunk/source/lib/config2.h =================================================================== --- ps/trunk/source/lib/config2.h (revision 25932) +++ ps/trunk/source/lib/config2.h (revision 25933) @@ -1,89 +1,94 @@ /* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * compile-time configuration for isolated spots */ #ifndef INCLUDED_CONFIG2 #define INCLUDED_CONFIG2 // rationale: a centralized header makes it much easier to see what all // can be changed. it is assumed that only a few modules will need // configuration choices, so rebuilding them all is acceptable. // use config.h when settings must apply to the entire project. // allow use of RDTSC for raw tick counts (otherwise, the slower but // more reliable on MP systems wall-clock will be used). #ifndef CONFIG2_TIMER_ALLOW_RDTSC # define CONFIG2_TIMER_ALLOW_RDTSC 1 #endif // this enables/disables the actual checking done by OverrunProtector // (quite slow, entailing mprotect() before/after each access). // define to 1 here or in the relevant module if you suspect mem corruption. // we provide this option because OverrunProtector requires some changes to // the object being wrapped, and we want to leave those intact but not // significantly slow things down except when needed. #ifndef CONFIG2_ALLOCATORS_OVERRUN_PROTECTION # define CONFIG2_ALLOCATORS_OVERRUN_PROTECTION 0 #endif #ifndef CONFIG2_FILE_ENABLE_AIO // work around a bug introduced in Linux 2.6.38 // (http://www.wildfiregames.com/forum/index.php?showtopic=14561&view=findpost&p=217710) // OpenBSD doesn't provide aio.h so we disable its use # if OS_LINUX || OS_OPENBSD # define CONFIG2_FILE_ENABLE_AIO 0 # else # define CONFIG2_FILE_ENABLE_AIO 1 # endif #endif // build in OpenGL ES 2.0 mode, instead of the default mode designed for // GL 1.1 + extensions. // this disables various features that are not supported by GLES. #ifndef CONFIG2_GLES # define CONFIG2_GLES 0 #endif // allow use of OpenAL/Ogg/Vorbis APIs #ifndef CONFIG2_AUDIO # define CONFIG2_AUDIO 1 #endif // allow use of NVTT #ifndef CONFIG2_NVTT # define CONFIG2_NVTT 1 #endif // allow use of lobby #ifndef CONFIG2_LOBBY # define CONFIG2_LOBBY 1 #endif // allow use of miniupnpc #ifndef CONFIG2_MINIUPNPC # define CONFIG2_MINIUPNPC 1 #endif +// default disable valgrind +#ifndef CONFIG2_VALGRIND +# define CONFIG2_VALGRIND 0 +#endif + #endif // #ifndef INCLUDED_CONFIG2 Index: ps/trunk/source/lib/sysdep/os/bsd/bcpu.cpp =================================================================== --- ps/trunk/source/lib/sysdep/os/bsd/bcpu.cpp (revision 25932) +++ ps/trunk/source/lib/sysdep/os/bsd/bcpu.cpp (revision 25933) @@ -1,125 +1,130 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "precompiled.h" #include "lib/sysdep/os_cpu.h" #include "lib/alignment.h" #include "lib/bits.h" +#include "lib/config2.h" #include "lib/module_init.h" -#include "valgrind.h" +#if CONFIG2_VALGRIND +# include "valgrind.h" +#endif #include #include size_t os_cpu_NumProcessors() { static size_t numProcessors; if(numProcessors == 0) { +#if CONFIG2_VALGRIND // Valgrind reports the number of real CPUs, but only emulates a single CPU. // That causes problems when we expect all those CPUs to be distinct, so // just pretend there's only one CPU if (RUNNING_ON_VALGRIND) numProcessors = 1; else +#endif { long res = sysconf(_SC_NPROCESSORS_CONF); ENSURE(res != -1); numProcessors = (size_t)res; } } return numProcessors; } uintptr_t os_cpu_ProcessorMask() { static uintptr_t processorMask; if(!processorMask) processorMask = bit_mask(os_cpu_NumProcessors()); return processorMask; } size_t os_cpu_PageSize() { static size_t pageSize; if(!pageSize) pageSize = (size_t)sysconf(_SC_PAGESIZE); return pageSize; } size_t os_cpu_LargePageSize() { // assume they're unsupported. return 0; } size_t os_cpu_QueryMemorySize() { size_t memorySize = 0; size_t len = sizeof(memorySize); // Argh, the API doesn't seem to be const-correct /*const*/ int mib[2] = { CTL_HW, HW_PHYSMEM }; sysctl(mib, 2, &memorySize, &len, 0, 0); memorySize /= MiB; return memorySize; } size_t os_cpu_MemoryAvailable() { size_t memoryAvailable = 0; size_t len = sizeof(memoryAvailable); // Argh, the API doesn't seem to be const-correct /*const*/ int mib[2] = { CTL_HW, HW_USERMEM }; sysctl(mib, 2, &memoryAvailable, &len, 0, 0); memoryAvailable /= MiB; return memoryAvailable; } uintptr_t os_cpu_SetThreadAffinityMask(uintptr_t UNUSED(processorMask)) { // not yet implemented return os_cpu_ProcessorMask(); } Status os_cpu_CallByEachCPU(OsCpuCallback cb, uintptr_t cbData) { for(size_t processor = 0; processor < os_cpu_NumProcessors(); processor++) { const uintptr_t processorMask = uintptr_t(1) << processor; os_cpu_SetThreadAffinityMask(processorMask); cb(processor, cbData); } return INFO::OK; } Index: ps/trunk/source/lib/sysdep/os/linux/lcpu.cpp =================================================================== --- ps/trunk/source/lib/sysdep/os/linux/lcpu.cpp (revision 25932) +++ ps/trunk/source/lib/sysdep/os/linux/lcpu.cpp (revision 25933) @@ -1,197 +1,200 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "precompiled.h" #include "lib/sysdep/os_cpu.h" #include "lib/alignment.h" #include "lib/bits.h" +#include "lib/config2.h" #include "lib/module_init.h" -#if OS_LINUX -#include "valgrind.h" +#if CONFIG2_VALGRIND +# include "valgrind.h" #endif size_t os_cpu_NumProcessors() { static size_t numProcessors; if(numProcessors == 0) { +#if CONFIG2_VALGRIND // Valgrind reports the number of real CPUs, but only emulates a single CPU. // That causes problems when we expect all those CPUs to be distinct, so // just pretend there's only one CPU if (RUNNING_ON_VALGRIND) numProcessors = 1; else +#endif { long res = sysconf(_SC_NPROCESSORS_CONF); ENSURE(res != -1); numProcessors = (size_t)res; } } return numProcessors; } uintptr_t os_cpu_ProcessorMask() { static uintptr_t processorMask; if(!processorMask) processorMask = bit_mask(os_cpu_NumProcessors()); return processorMask; } size_t os_cpu_PageSize() { static size_t pageSize; if(!pageSize) pageSize = (size_t)sysconf(_SC_PAGESIZE); return pageSize; } size_t os_cpu_LargePageSize() { // assume they're unsupported. return 0; } size_t os_cpu_QueryMemorySize() { const uint64_t memorySize = (uint64_t)sysconf(_SC_PHYS_PAGES) * os_cpu_PageSize(); return size_t(memorySize / MiB); } size_t os_cpu_MemoryAvailable() { const uint64_t memoryAvailableBytes = (uint64_t)sysconf(_SC_AVPHYS_PAGES) * os_cpu_PageSize(); const size_t memoryAvailable = size_t(memoryAvailableBytes / MiB); return memoryAvailable; } #if OS_ANDROID // the current Android NDK (r7-crystax-4) doesn't support sched_setaffinity, // so provide a stub implementation instead uintptr_t os_cpu_SetThreadAffinityMask(uintptr_t UNUSED(processorMask)) { // not yet implemented return os_cpu_ProcessorMask(); } #else // glibc __CPU_SETSIZE=1024 is smaller than required on some Linux (4096), // but the CONFIG_NR_CPUS in a header may not reflect the actual kernel, // so we have to detect the limit at runtime. // (see http://trac.wildfiregames.com/ticket/547 for additional information) static size_t maxCpus; static bool IsMaxCpusSufficient() { const size_t setSize = CPU_ALLOC_SIZE(maxCpus); cpu_set_t* set = CPU_ALLOC(maxCpus); ENSURE(set); const int ret = sched_getaffinity(0, setSize, set); CPU_FREE(set); if(ret == 0) return true; ENSURE(errno == EINVAL); return false; } static Status DetectMaxCpus() { // the most I have ever heard of is CONFIG_NR_CPUS=4096, // and even that limit should be enough for years and years. for(maxCpus = 64; maxCpus <= 65536; maxCpus *= 2) { if(IsMaxCpusSufficient()) return INFO::OK; } return ERR::FAIL; } uintptr_t os_cpu_SetThreadAffinityMask(uintptr_t processorMask) { static ModuleInitState maxCpusInitState; (void)ModuleInit(&maxCpusInitState, DetectMaxCpus); const size_t setSize = CPU_ALLOC_SIZE(maxCpus); cpu_set_t* set = CPU_ALLOC(maxCpus); ENSURE(set); uintptr_t previousProcessorMask = 0; { int ret = sched_getaffinity(0, setSize, set); ENSURE(ret == 0); for(size_t processor = 0; processor < os_cpu_NumProcessors(); processor++) { if(CPU_ISSET_S(processor, setSize, set)) previousProcessorMask |= uintptr_t(1) << processor; } } CPU_ZERO_S(setSize, set); for(size_t processor = 0; processor < os_cpu_NumProcessors(); processor++) { if(IsBitSet(processorMask, processor)) CPU_SET_S(processor, setSize, set); } int ret = sched_setaffinity(0, setSize, set); ENSURE(ret == 0); // (The process gets migrated immediately by the setaffinity call) CPU_FREE(set); return previousProcessorMask; } #endif Status os_cpu_CallByEachCPU(OsCpuCallback cb, uintptr_t cbData) { const uintptr_t previousAffinity = os_cpu_SetThreadAffinityMask(os_cpu_ProcessorMask()); for(size_t processor = 0; processor < os_cpu_NumProcessors(); processor++) { const uintptr_t processorMask = uintptr_t(1) << processor; os_cpu_SetThreadAffinityMask(processorMask); cb(processor, cbData); } (void)os_cpu_SetThreadAffinityMask(previousAffinity); return INFO::OK; } Index: ps/trunk/source/scriptinterface/ScriptExceptions.cpp =================================================================== --- ps/trunk/source/scriptinterface/ScriptExceptions.cpp (revision 25932) +++ ps/trunk/source/scriptinterface/ScriptExceptions.cpp (revision 25933) @@ -1,109 +1,105 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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. * * 0 A.D. 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 0 A.D. If not, see . */ #include "precompiled.h" #include "ScriptExceptions.h" #include "ps/CLogger.h" #include "ps/CStr.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptRequest.h" bool ScriptException::IsPending(const ScriptRequest& rq) { return JS_IsExceptionPending(rq.cx); } bool ScriptException::CatchPending(const ScriptRequest& rq) { if (!JS_IsExceptionPending(rq.cx)) return false; JS::RootedValue excn(rq.cx); ENSURE(JS_GetPendingException(rq.cx, &excn)); JS_ClearPendingException(rq.cx); if (excn.isUndefined()) { LOGERROR("JavaScript error: (undefined)"); return true; } // As of SM45/52, there is no way to recover a stack in case the thrown thing is not an Error object. if (!excn.isObject()) { CStr error; Script::FromJSVal(rq, excn, error); LOGERROR("JavaScript error: %s", error); return true; } JS::RootedObject excnObj(rq.cx, &excn.toObject()); JSErrorReport* report = JS_ErrorFromException(rq.cx, excnObj); if (!report) { CStr error; Script::FromJSVal(rq, excn, error); LOGERROR("JavaScript error: %s", error); return true; } std::stringstream msg; msg << "JavaScript error: "; if (report->filename) { msg << report->filename; msg << " line " << report->lineno << "\n"; } msg << report->message().c_str(); JS::RootedObject stackObj(rq.cx, ExceptionStackOrNull(excnObj)); JS::RootedValue stackVal(rq.cx, JS::ObjectOrNullValue(stackObj)); if (!stackVal.isNull()) { std::string stackText; ScriptFunction::Call(rq, stackVal, "toString", stackText); std::istringstream stream(stackText); for (std::string line; std::getline(stream, line);) msg << "\n " << line; } LOGERROR("%s", msg.str().c_str()); - - // When running under Valgrind, print more information in the error message - // VALGRIND_PRINTF_BACKTRACE("->"); - return true; } void ScriptException::Raise(const ScriptRequest& rq, const char* format, ...) { va_list ap; va_start(ap, format); // SM is single-threaded, so a static thread_local buffer needs no locking. thread_local static char buffer[256]; vsprintf_s(buffer, ARRAY_SIZE(buffer), format, ap); va_end(ap); // Rather annoyingly, there are no va_list versions of this function, hence the preformatting above. JS_ReportErrorUTF8(rq.cx, "%s", buffer); } Index: ps/trunk/source/scriptinterface/ScriptInterface.cpp =================================================================== --- ps/trunk/source/scriptinterface/ScriptInterface.cpp (revision 25932) +++ ps/trunk/source/scriptinterface/ScriptInterface.cpp (revision 25933) @@ -1,706 +1,704 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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. * * 0 A.D. 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 0 A.D. If not, see . */ #include "precompiled.h" #include "FunctionWrapper.h" #include "ScriptContext.h" #include "ScriptExtraHeaders.h" #include "ScriptInterface.h" #include "ScriptStats.h" #include "StructuredClone.h" #include "lib/debug.h" #include "lib/utf8.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/Profile.h" #include "ps/utf16string.h" #include #include #define BOOST_MULTI_INDEX_DISABLE_SERIALIZATION #include #include #include #include #include #include #include -#include "valgrind.h" - /** * @file * Abstractions of various SpiderMonkey features. * Engine code should be using functions of these interfaces rather than * directly accessing the underlying JS api. */ struct ScriptInterface_impl { ScriptInterface_impl(const char* nativeScopeName, const std::shared_ptr& context); ~ScriptInterface_impl(); // Take care to keep this declaration before heap rooted members. Destructors of heap rooted // members have to be called before the context destructor. std::shared_ptr m_context; friend ScriptRequest; private: JSContext* m_cx; JS::PersistentRootedObject m_glob; // global scope object public: boost::rand48* m_rng; JS::PersistentRootedObject m_nativeScope; // native function scope object }; /** * Constructor for ScriptRequest - here because it needs access into ScriptInterface_impl. */ ScriptRequest::ScriptRequest(const ScriptInterface& scriptInterface) : cx(scriptInterface.m->m_cx), glob(scriptInterface.m->m_glob), nativeScope(scriptInterface.m->m_nativeScope), m_ScriptInterface(scriptInterface) { m_FormerRealm = JS::EnterRealm(cx, scriptInterface.m->m_glob); } ScriptRequest::~ScriptRequest() { JS::LeaveRealm(cx, m_FormerRealm); } ScriptRequest::ScriptRequest(JSContext* cx) : ScriptRequest(ScriptInterface::CmptPrivate::GetScriptInterface(cx)) { } JS::Value ScriptRequest::globalValue() const { return JS::ObjectValue(*glob); } const ScriptInterface& ScriptRequest::GetScriptInterface() const { return m_ScriptInterface; } namespace { JSClassOps global_classops = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS, &global_classops }; // Functions in the global namespace: bool print(JSContext* cx, uint argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); ScriptRequest rq(cx); for (uint i = 0; i < args.length(); ++i) { std::wstring str; if (!Script::FromJSVal(rq, args[i], str)) return false; debug_printf("%s", utf8_from_wstring(str).c_str()); } fflush(stdout); args.rval().setUndefined(); return true; } bool logmsg(JSContext* cx, uint argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); if (args.length() < 1) { args.rval().setUndefined(); return true; } ScriptRequest rq(cx); std::wstring str; if (!Script::FromJSVal(rq, args[0], str)) return false; LOGMESSAGE("%s", utf8_from_wstring(str)); args.rval().setUndefined(); return true; } bool warn(JSContext* cx, uint argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); if (args.length() < 1) { args.rval().setUndefined(); return true; } ScriptRequest rq(cx); std::wstring str; if (!Script::FromJSVal(rq, args[0], str)) return false; LOGWARNING("%s", utf8_from_wstring(str)); args.rval().setUndefined(); return true; } bool error(JSContext* cx, uint argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); if (args.length() < 1) { args.rval().setUndefined(); return true; } ScriptRequest rq(cx); std::wstring str; if (!Script::FromJSVal(rq, args[0], str)) return false; LOGERROR("%s", utf8_from_wstring(str)); args.rval().setUndefined(); return true; } JS::Value deepcopy(const ScriptRequest& rq, JS::HandleValue val) { if (val.isNullOrUndefined()) { ScriptException::Raise(rq, "deepcopy requires one argument."); return JS::UndefinedValue(); } JS::RootedValue ret(rq.cx, Script::DeepCopy(rq, val)); if (ret.isNullOrUndefined()) { ScriptException::Raise(rq, "deepcopy StructureClone copy failed."); return JS::UndefinedValue(); } return ret; } JS::Value deepfreeze(const ScriptInterface& scriptInterface, JS::HandleValue val) { ScriptRequest rq(scriptInterface); if (!val.isObject()) { ScriptException::Raise(rq, "deepfreeze requires exactly one object as an argument."); return JS::UndefinedValue(); } Script::FreezeObject(rq, val, true); return val; } void ProfileStart(const std::string& regionName) { const char* name = "(ProfileStart)"; typedef boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::no_locking > StringFlyweight; if (!regionName.empty()) name = StringFlyweight(regionName).get().c_str(); if (CProfileManager::IsInitialised() && Threading::IsMainThread()) g_Profiler.StartScript(name); g_Profiler2.RecordRegionEnter(name); } void ProfileStop() { if (CProfileManager::IsInitialised() && Threading::IsMainThread()) g_Profiler.Stop(); g_Profiler2.RecordRegionLeave(); } void ProfileAttribute(const std::string& attr) { const char* name = "(ProfileAttribute)"; typedef boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::no_locking > StringFlyweight; if (!attr.empty()) name = StringFlyweight(attr).get().c_str(); g_Profiler2.RecordAttribute("%s", name); } // Math override functions: // boost::uniform_real is apparently buggy in Boost pre-1.47 - for integer generators // it returns [min,max], not [min,max). The bug was fixed in 1.47. // We need consistent behaviour, so manually implement the correct version: static double generate_uniform_real(boost::rand48& rng, double min, double max) { while (true) { double n = (double)(rng() - rng.min()); double d = (double)(rng.max() - rng.min()) + 1.0; ENSURE(d > 0 && n >= 0 && n <= d); double r = n / d * (max - min) + min; if (r < max) return r; } } } // anonymous namespace bool ScriptInterface::MathRandom(double& nbr) const { if (m->m_rng == nullptr) return false; nbr = generate_uniform_real(*(m->m_rng), 0.0, 1.0); return true; } bool ScriptInterface::Math_random(JSContext* cx, uint argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); double r; if (!ScriptInterface::CmptPrivate::GetScriptInterface(cx).MathRandom(r)) return false; args.rval().setNumber(r); return true; } ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const std::shared_ptr& context) : m_context(context), m_cx(context->GetGeneralJSContext()), m_glob(context->GetGeneralJSContext()), m_nativeScope(context->GetGeneralJSContext()) { JS::RealmCreationOptions creationOpt; // Keep JIT code during non-shrinking GCs. This brings a quite big performance improvement. creationOpt.setPreserveJitCode(true); // Enable uneval creationOpt.setToSourceEnabled(true); JS::RealmOptions opt(creationOpt, JS::RealmBehaviors{}); m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt); JSAutoRealm autoRealm(m_cx, m_glob); ENSURE(JS::InitRealmStandardClasses(m_cx)); JS_DefineProperty(m_cx, m_glob, "global", m_glob, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); // These first 4 actually use CallArgs & thus don't use ScriptFunction JS_DefineFunction(m_cx, m_glob, "print", ::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, m_glob, "log", ::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, m_glob, "warn", ::warn, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, m_glob, "error", ::error, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); ScriptFunction::Register(m_cx, m_glob, "clone"); ScriptFunction::Register(m_cx, m_glob, "deepfreeze"); m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); ScriptFunction::Register<&ProfileStart>(m_cx, m_nativeScope, "ProfileStart"); ScriptFunction::Register<&ProfileStop>(m_cx, m_nativeScope, "ProfileStop"); ScriptFunction::Register<&ProfileAttribute>(m_cx, m_nativeScope, "ProfileAttribute"); m_context->RegisterRealm(JS::GetObjectRealmOrNull(m_glob)); } ScriptInterface_impl::~ScriptInterface_impl() { m_context->UnRegisterRealm(JS::GetObjectRealmOrNull(m_glob)); } ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName, const std::shared_ptr& context) : m(std::make_unique(nativeScopeName, context)) { // Profiler stats table isn't thread-safe, so only enable this on the main thread if (Threading::IsMainThread()) { if (g_ScriptStatsTable) g_ScriptStatsTable->Add(this, debugName); } ScriptRequest rq(this); m_CmptPrivate.pScriptInterface = this; JS::SetRealmPrivate(JS::GetObjectRealmOrNull(rq.glob), (void*)&m_CmptPrivate); } ScriptInterface::~ScriptInterface() { if (Threading::IsMainThread()) { if (g_ScriptStatsTable) g_ScriptStatsTable->Remove(this); } } const ScriptInterface& ScriptInterface::CmptPrivate::GetScriptInterface(JSContext *cx) { CmptPrivate* pCmptPrivate = (CmptPrivate*)JS::GetRealmPrivate(JS::GetCurrentRealmOrNull(cx)); ENSURE(pCmptPrivate); return *pCmptPrivate->pScriptInterface; } void* ScriptInterface::CmptPrivate::GetCBData(JSContext *cx) { CmptPrivate* pCmptPrivate = (CmptPrivate*)JS::GetRealmPrivate(JS::GetCurrentRealmOrNull(cx)); return pCmptPrivate ? pCmptPrivate->pCBData : nullptr; } void ScriptInterface::SetCallbackData(void* pCBData) { m_CmptPrivate.pCBData = pCBData; } template <> void* ScriptInterface::ObjectFromCBData(const ScriptRequest& rq) { return ScriptInterface::CmptPrivate::GetCBData(rq.cx); } bool ScriptInterface::LoadGlobalScripts() { // Ignore this failure in tests if (!g_VFS) return false; // Load and execute *.js in the global scripts directory VfsPaths pathnames; vfs::GetPathnames(g_VFS, L"globalscripts/", L"*.js", pathnames); for (const VfsPath& path : pathnames) if (!LoadGlobalScriptFile(path)) { LOGERROR("LoadGlobalScripts: Failed to load script %s", path.string8()); return false; } return true; } bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng) { ScriptRequest rq(this); JS::RootedValue math(rq.cx); JS::RootedObject global(rq.cx, rq.glob); if (JS_GetProperty(rq.cx, global, "Math", &math) && math.isObject()) { JS::RootedObject mathObj(rq.cx, &math.toObject()); JS::RootedFunction random(rq.cx, JS_DefineFunction(rq.cx, mathObj, "random", Math_random, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)); if (random) { m->m_rng = &rng; return true; } } ScriptException::CatchPending(rq); LOGERROR("ReplaceNondeterministicRNG: failed to replace Math.random"); return false; } JSContext* ScriptInterface::GetGeneralJSContext() const { return m->m_context->GetGeneralJSContext(); } std::shared_ptr ScriptInterface::GetContext() const { return m->m_context; } void ScriptInterface::CallConstructor(JS::HandleValue ctor, JS::HandleValueArray argv, JS::MutableHandleValue out) const { ScriptRequest rq(this); if (!ctor.isObject()) { LOGERROR("CallConstructor: ctor is not an object"); out.setNull(); return; } JS::RootedObject ctorObj(rq.cx, &ctor.toObject()); out.setObjectOrNull(JS_New(rq.cx, ctorObj, argv)); } void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) { ScriptRequest rq(this); std::string typeName = clasp->name; if (m_CustomObjectTypes.find(typeName) != m_CustomObjectTypes.end()) { // This type already exists throw PSERROR_Scripting_DefineType_AlreadyExists(); } JS::RootedObject global(rq.cx, rq.glob); JS::RootedObject obj(rq.cx, JS_InitClass(rq.cx, global, nullptr, clasp, constructor, minArgs, // Constructor, min args ps, fs, // Properties, methods static_ps, static_fs)); // Constructor properties, methods if (obj == nullptr) { ScriptException::CatchPending(rq); throw PSERROR_Scripting_DefineType_CreationFailed(); } CustomType& type = m_CustomObjectTypes[typeName]; type.m_Prototype.init(rq.cx, obj); type.m_Class = clasp; type.m_Constructor = constructor; } JSObject* ScriptInterface::CreateCustomObject(const std::string& typeName) const { std::map::const_iterator it = m_CustomObjectTypes.find(typeName); if (it == m_CustomObjectTypes.end()) throw PSERROR_Scripting_TypeDoesNotExist(); ScriptRequest rq(this); JS::RootedObject prototype(rq.cx, it->second.m_Prototype.get()); return JS_NewObjectWithGivenProto(rq.cx, it->second.m_Class, prototype); } bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool replace, bool constant, bool enumerate) { ScriptRequest rq(this); JS::RootedObject global(rq.cx, rq.glob); bool found; if (!JS_HasProperty(rq.cx, global, name, &found)) return false; if (found) { JS::Rooted desc(rq.cx); if (!JS_GetOwnPropertyDescriptor(rq.cx, global, name, &desc)) return false; if (!desc.writable()) { if (!replace) { ScriptException::Raise(rq, "SetGlobal \"%s\" called multiple times", name); return false; } // This is not supposed to happen, unless the user has called SetProperty with constant = true on the global object // instead of using SetGlobal. if (!desc.configurable()) { ScriptException::Raise(rq, "The global \"%s\" is permanent and cannot be hotloaded", name); return false; } LOGMESSAGE("Hotloading new value for global \"%s\".", name); ENSURE(JS_DeleteProperty(rq.cx, global, name)); } } uint attrs = 0; if (constant) attrs |= JSPROP_READONLY; if (enumerate) attrs |= JSPROP_ENUMERATE; return JS_DefineProperty(rq.cx, global, name, value, attrs); } bool ScriptInterface::GetGlobalProperty(const ScriptRequest& rq, const std::string& name, JS::MutableHandleValue out) { // Try to get the object as a property of the global object. JS::RootedObject global(rq.cx, rq.glob); if (!JS_GetProperty(rq.cx, global, name.c_str(), out)) { out.set(JS::NullHandleValue); return false; } if (!out.isNullOrUndefined()) return true; // Some objects, such as const definitions, or Class definitions, are hidden inside closures. // We must fetch those from the correct lexical scope. //JS::RootedValue glob(cx); JS::RootedObject lexical_environment(rq.cx, JS_GlobalLexicalEnvironment(rq.glob)); if (!JS_GetProperty(rq.cx, lexical_environment, name.c_str(), out)) { out.set(JS::NullHandleValue); return false; } if (!out.isNullOrUndefined()) return true; out.set(JS::NullHandleValue); return false; } bool ScriptInterface::SetPrototype(JS::HandleValue objVal, JS::HandleValue protoVal) { ScriptRequest rq(this); if (!objVal.isObject() || !protoVal.isObject()) return false; JS::RootedObject obj(rq.cx, &objVal.toObject()); JS::RootedObject proto(rq.cx, &protoVal.toObject()); return JS_SetPrototype(rq.cx, obj, proto); } bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& code) const { ScriptRequest rq(this); JS::RootedObject global(rq.cx, rq.glob); // CompileOptions does not copy the contents of the filename string pointer. // Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary. std::string filenameStr = filename.string8(); JS::CompileOptions options(rq.cx); // Set the line to 0 because CompileFunction silently adds a `(function() {` as the first line, // and errors get misreported. // TODO: it would probably be better to not implicitly introduce JS scopes. options.setFileAndLine(filenameStr.c_str(), 0); options.setIsRunOnce(false); JS::SourceText src; ENSURE(src.init(rq.cx, code.c_str(), code.length(), JS::SourceOwnership::Borrowed)); JS::RootedObjectVector emptyScopeChain(rq.cx); JS::RootedFunction func(rq.cx, JS::CompileFunction(rq.cx, emptyScopeChain, options, NULL, 0, NULL, src)); if (func == nullptr) { ScriptException::CatchPending(rq); return false; } JS::RootedValue rval(rq.cx); if (JS_CallFunction(rq.cx, nullptr, func, JS::HandleValueArray::empty(), &rval)) return true; ScriptException::CatchPending(rq); return false; } bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::string& code) const { ScriptRequest rq(this); // CompileOptions does not copy the contents of the filename string pointer. // Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary. std::string filenameStr = filename.string8(); JS::RootedValue rval(rq.cx); JS::CompileOptions opts(rq.cx); opts.setFileAndLine(filenameStr.c_str(), 1); JS::SourceText src; ENSURE(src.init(rq.cx, code.c_str(), code.length(), JS::SourceOwnership::Borrowed)); if (JS::Evaluate(rq.cx, opts, src, &rval)) return true; ScriptException::CatchPending(rq); return false; } bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const { ScriptRequest rq(this); if (!VfsFileExists(path)) { LOGERROR("File '%s' does not exist", path.string8()); return false; } CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR("Failed to load file '%s': %s", path.string8(), GetErrorString(ret)); return false; } CStr code = file.DecodeUTF8(); // assume it's UTF-8 uint lineNo = 1; // CompileOptions does not copy the contents of the filename string pointer. // Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary. std::string filenameStr = path.string8(); JS::RootedValue rval(rq.cx); JS::CompileOptions opts(rq.cx); opts.setFileAndLine(filenameStr.c_str(), lineNo); JS::SourceText src; ENSURE(src.init(rq.cx, code.c_str(), code.length(), JS::SourceOwnership::Borrowed)); if (JS::Evaluate(rq.cx, opts, src, &rval)) return true; ScriptException::CatchPending(rq); return false; } bool ScriptInterface::Eval(const char* code) const { ScriptRequest rq(this); JS::RootedValue rval(rq.cx); JS::CompileOptions opts(rq.cx); opts.setFileAndLine("(eval)", 1); JS::SourceText src; ENSURE(src.init(rq.cx, code, strlen(code), JS::SourceOwnership::Borrowed)); if (JS::Evaluate(rq.cx, opts, src, &rval)) return true; ScriptException::CatchPending(rq); return false; } bool ScriptInterface::Eval(const char* code, JS::MutableHandleValue rval) const { ScriptRequest rq(this); JS::CompileOptions opts(rq.cx); opts.setFileAndLine("(eval)", 1); JS::SourceText src; ENSURE(src.init(rq.cx, code, strlen(code), JS::SourceOwnership::Borrowed)); if (JS::Evaluate(rq.cx, opts, src, rval)) return true; ScriptException::CatchPending(rq); return false; } Index: ps/trunk/source/simulation2/tests/test_Serializer.h =================================================================== --- ps/trunk/source/simulation2/tests/test_Serializer.h (revision 25932) +++ ps/trunk/source/simulation2/tests/test_Serializer.h (revision 25933) @@ -1,940 +1,947 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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. * * 0 A.D. 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 0 A.D. If not, see . */ #include "lib/self_test.h" #include "simulation2/serialization/DebugSerializer.h" #include "simulation2/serialization/HashSerializer.h" #include "simulation2/serialization/StdSerializer.h" #include "simulation2/serialization/StdDeserializer.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptInterface.h" #include "graphics/MapReader.h" #include "graphics/Terrain.h" #include "graphics/TerrainTextureManager.h" +#include "lib/config2.h" #include "lib/timer.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/Loader.h" #include "ps/XML/Xeromyces.h" #include "simulation2/Simulation2.h" -#include "callgrind.h" +#if CONFIG2_VALGRIND +# include "callgrind.h" +#endif #include #define TS_ASSERT_STREAM(stream, len, buffer) \ TS_ASSERT_EQUALS(stream.str().length(), (size_t)len); \ TS_ASSERT_SAME_DATA(stream.str().data(), buffer, len) #define TSM_ASSERT_STREAM(m, stream, len, buffer) \ TSM_ASSERT_EQUALS(m, stream.str().length(), (size_t)len); \ TSM_ASSERT_SAME_DATA(m, stream.str().data(), buffer, len) class TestSerializer : public CxxTest::TestSuite { public: void serialize_types(ISerializer& serialize) { serialize.NumberI8_Unbounded("i8", (signed char)-123); serialize.NumberU8_Unbounded("u8", (unsigned char)255); serialize.NumberI16_Unbounded("i16", -12345); serialize.NumberU16_Unbounded("u16", 56789); serialize.NumberI32_Unbounded("i32", -123); serialize.NumberU32_Unbounded("u32", (unsigned)-123); serialize.NumberFloat_Unbounded("float", 1e+30f); serialize.NumberDouble_Unbounded("double", 1e+300); serialize.NumberFixed_Unbounded("fixed", fixed::FromFloat(1234.5f)); serialize.Bool("t", true); serialize.Bool("f", false); serialize.StringASCII("string", "example", 0, 255); serialize.StringASCII("string 2", "example\"\\\"", 0, 255); serialize.StringASCII("string 3", "example\n\ntest", 0, 255); wchar_t testw[] = { 't', 0xEA, 's', 't', 0 }; serialize.String("string 4", testw, 0, 255); serialize.RawBytes("raw bytes", (const u8*)"\0\1\2\3\x0f\x10", 6); } void test_Debug_basic() { ScriptInterface script("Test", "Test", g_ScriptContext); std::stringstream stream; CDebugSerializer serialize(script, stream); serialize.NumberI32_Unbounded("x", -123); serialize.NumberU32_Unbounded("y", 1234); serialize.NumberI32("z", 12345, 0, 65535); TS_ASSERT_STR_EQUALS(stream.str(), "x: -123\ny: 1234\nz: 12345\n"); } void test_Debug_floats() { ScriptInterface script("Test", "Test", g_ScriptContext); std::stringstream stream; CDebugSerializer serialize(script, stream); serialize.NumberFloat_Unbounded("x", 1e4f); serialize.NumberFloat_Unbounded("x", 1e-4f); serialize.NumberFloat_Unbounded("x", 1e5f); serialize.NumberFloat_Unbounded("x", 1e-5f); serialize.NumberFloat_Unbounded("x", 1e6f); serialize.NumberFloat_Unbounded("x", 1e-6f); serialize.NumberFloat_Unbounded("x", 1e10f); serialize.NumberFloat_Unbounded("x", 1e-10f); serialize.NumberDouble_Unbounded("x", 1e4); serialize.NumberDouble_Unbounded("x", 1e-4); serialize.NumberDouble_Unbounded("x", 1e5); serialize.NumberDouble_Unbounded("x", 1e-5); serialize.NumberDouble_Unbounded("x", 1e6); serialize.NumberDouble_Unbounded("x", 1e-6); serialize.NumberDouble_Unbounded("x", 1e10); serialize.NumberDouble_Unbounded("x", 1e-10); serialize.NumberDouble_Unbounded("x", 1e100); serialize.NumberDouble_Unbounded("x", 1e-100); serialize.NumberFixed_Unbounded("x", fixed::FromDouble(1e4)); TS_ASSERT_STR_EQUALS(stream.str(), "x: 10000\nx: 9.9999997e-05\nx: 100000\nx: 9.9999997e-06\nx: 1000000\nx: 1e-06\nx: 1e+10\nx: 1e-10\n" "x: 10000\nx: 0.0001\nx: 100000\nx: 1.0000000000000001e-05\nx: 1000000\nx: 9.9999999999999995e-07\nx: 10000000000\nx: 1e-10\nx: 1e+100\nx: 1e-100\n" "x: 10000\n" ); } void test_Debug_types() { ScriptInterface script("Test", "Test", g_ScriptContext); std::stringstream stream; CDebugSerializer serialize(script, stream); serialize.Comment("comment"); serialize_types(serialize); TS_ASSERT_STR_EQUALS(stream.str(), "# comment\n" "i8: -123\n" "u8: 255\n" "i16: -12345\n" "u16: 56789\n" "i32: -123\n" "u32: 4294967173\n" "float: 1e+30\n" "double: 1.0000000000000001e+300\n" "fixed: 1234.5\n" "t: true\n" "f: false\n" "string: \"example\"\n" "string 2: \"example\\\"\\\\\\\"\"\n" // C-escaped form of: "example\"\\\"" "string 3: \"example\\n\\ntest\"\n" "string 4: \"t\xC3\xAAst\"\n" "raw bytes: (6 bytes) 00 01 02 03 0f 10\n" ); } void test_Std_basic() { ScriptInterface script("Test", "Test", g_ScriptContext); std::stringstream stream; CStdSerializer serialize(script, stream); serialize.NumberI32_Unbounded("x", -123); serialize.NumberU32_Unbounded("y", 1234); serialize.NumberI32("z", 12345, 0, 65535); TS_ASSERT_STREAM(stream, 12, "\x85\xff\xff\xff" "\xd2\x04\x00\x00" "\x39\x30\x00\x00"); CStdDeserializer deserialize(script, stream); int32_t n; deserialize.NumberI32_Unbounded("x", n); TS_ASSERT_EQUALS(n, -123); deserialize.NumberI32_Unbounded("y", n); TS_ASSERT_EQUALS(n, 1234); deserialize.NumberI32("z", n, 0, 65535); TS_ASSERT_EQUALS(n, 12345); // NOTE: Don't use good() here - it fails due to a bug in older libc++ versions TS_ASSERT(!stream.bad() && !stream.fail()); TS_ASSERT_EQUALS(stream.peek(), EOF); } void test_Std_types() { ScriptInterface script("Test", "Test", g_ScriptContext); std::stringstream stream; CStdSerializer serialize(script, stream); serialize_types(serialize); CStdDeserializer deserialize(script, stream); int8_t i8v; uint8_t u8v; int16_t i16v; uint16_t u16v; int32_t i32v; uint32_t u32v; float flt; double dbl; fixed fxd; bool bl; std::string str; std::wstring wstr; u8 cbuf[256]; deserialize.NumberI8_Unbounded("i8", i8v); TS_ASSERT_EQUALS(i8v, -123); deserialize.NumberU8_Unbounded("u8", u8v); TS_ASSERT_EQUALS(u8v, 255); deserialize.NumberI16_Unbounded("i16", i16v); TS_ASSERT_EQUALS(i16v, -12345); deserialize.NumberU16_Unbounded("u16", u16v); TS_ASSERT_EQUALS(u16v, 56789); deserialize.NumberI32_Unbounded("i32", i32v); TS_ASSERT_EQUALS(i32v, -123); deserialize.NumberU32_Unbounded("u32", u32v); TS_ASSERT_EQUALS(u32v, 4294967173u); deserialize.NumberFloat_Unbounded("float", flt); TS_ASSERT_EQUALS(flt, 1e+30f); deserialize.NumberDouble_Unbounded("double", dbl); TS_ASSERT_EQUALS(dbl, 1e+300); deserialize.NumberFixed_Unbounded("fixed", fxd); TS_ASSERT_EQUALS(fxd.ToDouble(), 1234.5); deserialize.Bool("t", bl); TS_ASSERT_EQUALS(bl, true); deserialize.Bool("f", bl); TS_ASSERT_EQUALS(bl, false); deserialize.StringASCII("string", str, 0, 255); TS_ASSERT_STR_EQUALS(str, "example"); deserialize.StringASCII("string 2", str, 0, 255); TS_ASSERT_STR_EQUALS(str, "example\"\\\""); deserialize.StringASCII("string 3", str, 0, 255); TS_ASSERT_STR_EQUALS(str, "example\n\ntest"); wchar_t testw[] = { 't', 0xEA, 's', 't', 0 }; deserialize.String("string 4", wstr, 0, 255); TS_ASSERT_WSTR_EQUALS(wstr, testw); cbuf[6] = 0x42; // sentinel deserialize.RawBytes("raw bytes", cbuf, 6); TS_ASSERT_SAME_DATA(cbuf, (const u8*)"\0\1\2\3\x0f\x10\x42", 7); // NOTE: Don't use good() here - it fails due to a bug in older libc++ versions TS_ASSERT(!stream.bad() && !stream.fail()); TS_ASSERT_EQUALS(stream.peek(), EOF); } void test_Hash_basic() { ScriptInterface script("Test", "Test", g_ScriptContext); CHashSerializer serialize(script); serialize.NumberI32_Unbounded("x", -123); serialize.NumberU32_Unbounded("y", 1234); serialize.NumberI32("z", 12345, 0, 65535); TS_ASSERT_EQUALS(serialize.GetHashLength(), (size_t)16); TS_ASSERT_SAME_DATA(serialize.ComputeHash(), "\xa0\x3a\xe5\x3e\x9b\xd7\xfb\x11\x88\x35\xc6\xfb\xb9\x94\xa9\x72", 16); // echo -en "\x85\xff\xff\xff\xd2\x04\x00\x00\x39\x30\x00\x00" | openssl md5 -binary | xxd -p | perl -pe 's/(..)/\\x$1/g' } void test_Hash_stream() { ScriptInterface script("Test", "Test", g_ScriptContext); CHashSerializer hashSerialize(script); hashSerialize.NumberI32_Unbounded("x", -123); hashSerialize.NumberU32_Unbounded("y", 1234); hashSerialize.NumberI32("z", 12345, 0, 65535); ISerializer& serialize = hashSerialize; { CStdSerializer streamSerialize(script, serialize.GetStream()); streamSerialize.NumberI32_Unbounded("x2", -456); streamSerialize.NumberU32_Unbounded("y2", 5678); streamSerialize.NumberI32("z2", 45678, 0, 65535); } TS_ASSERT_EQUALS(hashSerialize.GetHashLength(), (size_t)16); TS_ASSERT_SAME_DATA(hashSerialize.ComputeHash(), "\x5c\xff\x33\xd1\x72\xdd\x6d\x77\xa8\xd4\xa1\xf6\x84\xcc\xaa\x10", 16); // echo -en "\x85\xff\xff\xff\xd2\x04\x00\x00\x39\x30\x00\x00\x38\xfe\xff\xff\x2e\x16\x00\x00\x6e\xb2\x00\x00" | openssl md5 -binary | xxd -p | perl -pe 's/(..)/\\x$1/g' } void test_bounds() { ScriptInterface script("Test", "Test", g_ScriptContext); std::stringstream stream; CDebugSerializer serialize(script, stream); serialize.NumberI32("x", 16, -16, 16); serialize.NumberI32("x", -16, -16, 16); TS_ASSERT_THROWS(serialize.NumberI32("x", 99, -16, 16), const PSERROR_Serialize_OutOfBounds&); TS_ASSERT_THROWS(serialize.NumberI32("x", -17, -16, 16), const PSERROR_Serialize_OutOfBounds&); } // TODO: test exceptions more thoroughly void helper_script_roundtrip(const char* msg, const char* input, const char* expected, size_t expstreamlen = 0, const char* expstream = NULL, const char* debug = NULL) { ScriptInterface script("Test", "Test", g_ScriptContext); ScriptRequest rq(script); JS::RootedValue obj(rq.cx); TSM_ASSERT(msg, script.Eval(input, &obj)); if (debug) { std::stringstream dbgstream; CDebugSerializer serialize(script, dbgstream); serialize.ScriptVal("script", &obj); TS_ASSERT_STR_EQUALS(dbgstream.str(), debug); } std::stringstream stream; CStdSerializer serialize(script, stream); serialize.ScriptVal("script", &obj); if (expstream) { TSM_ASSERT_STREAM(msg, stream, expstreamlen, expstream); } CStdDeserializer deserialize(script, stream); JS::RootedValue newobj(rq.cx); deserialize.ScriptVal("script", &newobj); // NOTE: Don't use good() here - it fails due to a bug in older libc++ versions TSM_ASSERT(msg, !stream.bad() && !stream.fail()); TSM_ASSERT_EQUALS(msg, stream.peek(), EOF); std::stringstream stream2; CStdSerializer serialize2(script, stream2); CStdDeserializer deserialize2(script, stream2); // Round-trip the deserialized value again. This helps ensure prototypes are correctly deserialized. serialize2.ScriptVal("script2", &newobj); deserialize2.ScriptVal("script2", &newobj); std::string source; TSM_ASSERT(msg, ScriptFunction::Call(rq, newobj, "toSource", source)); TS_ASSERT_STR_EQUALS(source, expected); } void test_script_basic() { helper_script_roundtrip("Object", "({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", /* expected: */ "({x:123, y:[1, 1.5, \"2\", \"test\", (void 0), null, true, false]})", /* expected stream: */ 116, "\x03" // SCRIPT_TYPE_OBJECT "\x02\0\0\0" // num props "\x01\x01\0\0\0" "x" // "x" "\x05" // SCRIPT_TYPE_INT "\x7b\0\0\0" // 123 "\x01\x01\0\0\0" "y" // "y" "\x02" // SCRIPT_TYPE_ARRAY "\x08\0\0\0" // array length "\x08\0\0\0" // num props "\x01\x01\0\0\0" "0" // "0" "\x05" "\x01\0\0\0" // SCRIPT_TYPE_INT 1 "\x01\x01\0\0\0" "1" // "1" "\x06" "\0\0\0\0\0\0\xf8\x3f" // SCRIPT_TYPE_DOUBLE 1.5 "\x01\x01\0\0\0" "2" // "2" "\x04" "\x01\x01\0\0\0" "2" // SCRIPT_TYPE_STRING "2" "\x01\x01\0\0\0" "3" // "3" "\x04" "\x01\x04\0\0\0" "test" // SCRIPT_TYPE_STRING "test" "\x01\x01\0\0\0" "4" // "4" "\x00" // SCRIPT_TYPE_VOID "\x01\x01\0\0\0" "5" // "5" "\x01" // SCRIPT_TYPE_NULL "\x01\x01\0\0\0" "6" // "6" "\x07" "\x01" // SCRIPT_TYPE_BOOLEAN true "\x01\x01\0\0\0" "7" // "7" "\x07" "\x00", // SCRIPT_TYPE_BOOLEAN false /* expected debug: */ "script: {\n" " \"x\": 123,\n" " \"y\": [\n" " 1,\n" " 1.5,\n" " \"2\",\n" " \"test\",\n" " null,\n" " null,\n" " true,\n" " false\n" " ]\n" "}\n" ); } void test_script_unicode() { helper_script_roundtrip("unicode", "({" "'x': \"\\x01\\x80\\xff\\u0100\\ud7ff\", " "'y': \"\\ue000\\ufffd\"" "})", /* expected: */ "({" "x:\"\\x01\\x80\\xFF\\u0100\\uD7FF\", " "y:\"\\uE000\\uFFFD\"" "})"); // Disabled since we no longer do the UTF-8 conversion that rejects invalid characters // TS_ASSERT_THROWS(helper_script_roundtrip("invalid chars 1", "(\"\\ud7ff\\ud800\")", "..."), PSERROR_Serialize_InvalidCharInString); // TS_ASSERT_THROWS(helper_script_roundtrip("invalid chars 2", "(\"\\udfff\")", "..."), PSERROR_Serialize_InvalidCharInString); // TS_ASSERT_THROWS(helper_script_roundtrip("invalid chars 3", "(\"\\uffff\")", "..."), PSERROR_Serialize_InvalidCharInString); // TS_ASSERT_THROWS(helper_script_roundtrip("invalid chars 4", "(\"\\ud800\\udc00\")" /* U+10000 */, "..."), PSERROR_Serialize_InvalidCharInString); helper_script_roundtrip("unicode", "\"\\ud800\\uffff\"", "(new String(\"\\uD800\\uFFFF\"))"); } void test_script_objects() { helper_script_roundtrip("Number", "[1, new Number('2.0'), 3]", "[1, (new Number(2)), 3]"); helper_script_roundtrip("Number with props", "var n=new Number('2.0'); n.foo='bar'; n", "(new Number(2))"); helper_script_roundtrip("String", "['test1', new String('test2'), 'test3']", "[\"test1\", (new String(\"test2\")), \"test3\"]"); helper_script_roundtrip("String with props", "var s=new String('test'); s.foo='bar'; s", "(new String(\"test\"))"); helper_script_roundtrip("Boolean", "[new Boolean('true'), false]", "[(new Boolean(true)), false]"); helper_script_roundtrip("Boolean with props", "var b=new Boolean('true'); b.foo='bar'; b", "(new Boolean(true))"); } void test_script_fancy_objects() { // This asserts that objects are deserialized with their correct prototypes. helper_script_roundtrip("Custom Object", "" "function customObj() { this.a = this.customFunc.name; };" "customObj.prototype.customFunc = function customFunc(){};" "new customObj();", "({a:\"customFunc\"})"); helper_script_roundtrip("Custom Class", "" "class customObj {" " constructor() { this.a = this.customFunc.name; }" " customFunc(){};" "}; new customObj();", "({a:\"customFunc\"})"); helper_script_roundtrip("Custom Class with Serialize/Deserialize()", "" "class customObj {" " constructor() { this.a = this.customFunc.name; }" " Serialize() { return { 'foo': 'bar' }; }" " Deserialize(data) { this.foo = data.foo; }" " customFunc(){};" "}; new customObj();", "({a:\"customFunc\", foo:\"bar\"})"); helper_script_roundtrip("Custom Class with null serialize & deserialize()", "" "class customObj {" " constructor() { this.a = this.customFunc.name; }" " Deserialize(data) { this.test = 'test'; };" " customFunc(){};" "}; customObj.prototype.Serialize=null;" "new customObj();", "({a:\"customFunc\", test:\"test\"})"); helper_script_roundtrip("Custom Class with arguments but still works", "" "class customObj {" " constructor(test) { this.a = test; }" " Serialize() { return { 'data': this.a }; };" " Deserialize(data) { this.a = data.data; };" "}; new customObj(4);", "({a:4})"); } void test_script_objects_properties() { helper_script_roundtrip("Object with null in prop name", "({\"foo\\0bar\":1})", "({\'foo\\x00bar\':1})"); } void test_script_typed_arrays_simple() { helper_script_roundtrip("Int8Array", "var arr=new Int8Array(8);" "for(var i=0; iMount(L"", DataDir() / "mods" / "public" / "", VFS_MOUNT_MUST_EXIST)); TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir() / "_testcache" / "", 0, VFS_MAX_PRIORITY)); // Need some stuff for terrain movement costs: // (TODO: this ought to be independent of any graphics code) new CTerrainTextureManager; g_TexMan.LoadTerrainTextures(); CTerrain terrain; CSimulation2 sim2(NULL, g_ScriptContext, &terrain); sim2.LoadDefaultScripts(); sim2.ResetState(); std::unique_ptr mapReader = std::make_unique(); LDR_BeginRegistering(); mapReader->LoadMap(L"maps/skirmishes/Greek Acropolis (2).pmp", *sim2.GetScriptInterface().GetContext(), JS::UndefinedHandleValue, &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &sim2, &sim2.GetSimContext(), -1, false); LDR_EndRegistering(); TS_ASSERT_OK(LDR_NonprogressiveLoad()); sim2.Update(0); { std::stringstream str; std::string hash; sim2.SerializeState(str); sim2.ComputeStateHash(hash, false); debug_printf("\n"); debug_printf("# size = %d\n", (int)str.str().length()); debug_printf("# hash = "); for (size_t i = 0; i < hash.size(); ++i) debug_printf("%02x", (unsigned int)(u8)hash[i]); debug_printf("\n"); } double t = timer_Time(); +#if CONFIG2_VALGRIND CALLGRIND_START_INSTRUMENTATION; +#endif size_t reps = 128; for (size_t i = 0; i < reps; ++i) { std::string hash; sim2.ComputeStateHash(hash, false); } +#if CONFIG2_VALGRIND CALLGRIND_STOP_INSTRUMENTATION; +#endif t = timer_Time() - t; debug_printf("# time = %f (%f/%d)\n", t/reps, t, (int)reps); // Shut down the world delete &g_TexMan; g_VFS.reset(); DeleteDirectory(DataDir()/"_testcache"); CXeromyces::Terminate(); } };