From e32cdf4f2de1a8231e278e10a0616af0b0cda26f Mon Sep 17 00:00:00 2001 From: toole1 <toole1@6fbd10e7-183d-0410-a318-cb416676e4f2> Date: Tue, 30 Aug 2011 04:27:08 +0000 Subject: [PATCH] readding student version of monad git-svn-id: https://subversion.cs.illinois.edu/svn/cs225@4325 6fbd10e7-183d-0410-a318-cb416676e4f2 --- Makefile.proxy | 33 + config.ini | 18 + memcheck.h | 277 +++ monad | Bin 0 -> 236716 bytes monad_shared.cpp | 149 ++ monad_shared.h | 71 + pipestream.cpp | 328 ++++ pipestream.h | 105 + proxy.cpp | 663 +++++++ proxy.h | 221 +++ update.sh | 15 + util.cpp | 735 +++++++ util.h | 252 +++ valgrind.h | 4792 ++++++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 7659 insertions(+) create mode 100644 Makefile.proxy create mode 100644 config.ini create mode 100644 memcheck.h create mode 100755 monad create mode 100755 monad_shared.cpp create mode 100755 monad_shared.h create mode 100755 pipestream.cpp create mode 100644 pipestream.h create mode 100755 proxy.cpp create mode 100755 proxy.h create mode 100755 update.sh create mode 100644 util.cpp create mode 100644 util.h create mode 100644 valgrind.h diff --git a/Makefile.proxy b/Makefile.proxy new file mode 100644 index 0000000..de923a4 --- /dev/null +++ b/Makefile.proxy @@ -0,0 +1,33 @@ +CC = g++ +CFLAGS += -Wall +TESTEXE := proxy +# This order is necessary for security. Always include student code last! +TESTOBJS := $(TESTEXE).o util.o unit_tests.o monad_shared.o $(TESTOBJS) +OPTIMIZE := off + +ifeq ($(strip $(OPTIMIZE)),on) +CFLAGS += -O2 -DOPTIMIZE +else ifeq ($(strip $(OPTIMIZE)),off) +CFLAGS += -g -O0 +else +$(warning Invalid value specified for OPTIMIZE. Should be on or off) +CFLAGS += -g -O0 +endif + +ifndef ALL_TARGET +ALL_TARGET = all +all: $(TESTEXE) +endif + +$(TESTEXE): $(TESTOBJS) + $(CC) $(TESTOBJS) -o $@ + +.cpp.o: $(wildcard *.h) + $(CC) $(CFLAGS) -c $(@:.o=.cpp) -o $@ + +ifndef CLEAN_TARGET +CLEAN_TARGET = clean +.PHONY: clean +clean: + -rm -f *.o $(TESTEXE) +endif diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..8a95ec2 --- /dev/null +++ b/config.ini @@ -0,0 +1,18 @@ +[SVN Root] +:https://subversion.ews.illinois.edu/svn/sp11-cs225/ + +[Staff SVN] +:https://subversion.cs.illinois.edu/svn/cs225/ + +[Monad Files] +Makefile.proxy +memcheck.h +monad_shared.h +monad_shared.cpp +proxy.h +proxy.cpp +valgrind.h + +[Libraries] +util + diff --git a/memcheck.h b/memcheck.h new file mode 100644 index 0000000..bf95491 --- /dev/null +++ b/memcheck.h @@ -0,0 +1,277 @@ + +/* + ---------------------------------------------------------------- + + 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-2010 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 \ + {unsigned long _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__DO_LEAK_CHECK, \ + 0, 0, 0, 0, 0); \ + } + +/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */ +#define VALGRIND_DO_QUICK_LEAK_CHECK \ + {unsigned long _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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_res; \ + unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ + unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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_res; \ + unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ + unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__GET_VBITS, \ + (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) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__SET_VBITS, \ + (char*)(zza), (char*)(zzvbits), \ + (zznbytes), 0, 0 ) + +#endif + diff --git a/monad b/monad new file mode 100755 index 0000000000000000000000000000000000000000..d1bdcffaa08dc3bcd6d659c5a78b13424a298aa1 GIT binary patch literal 236716 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%0A!_(ZvX^9uiFO|g<GqVZ*lH@hjmG6SSE*>6g( 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Μ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	ahjjD}gPJH=RnxtB(9+9DH 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 literal 0 HcmV?d00001 diff --git a/monad_shared.cpp b/monad_shared.cpp new file mode 100755 index 0000000..eb9a908 --- /dev/null +++ b/monad_shared.cpp @@ -0,0 +1,149 @@ +#include <iostream> +#include "monad_shared.h" +#include "util.h" + +using namespace monad_shared; +using namespace util; +using std::cout; +using std::cerr; +using std::endl; + +namespace monad_shared +{ + +namespace version +{ +const char * official_name = "CS 225 Monad"; +const char * version_name = "awakening"; +const char * date = "15 July 2011"; +} + +const char * unit_test::pass_string = "~~PASSED~~"; + +void printInfo() +{ + cout << endl + << version::official_name << endl + << "Version " << version::version_name << endl + << "Released " << version::date << endl + << "Developed by Jack Toole Spring/Fall 2011" << endl + << "Copyright 2011 Jack Toole" << endl + << "Full rights granted to Jack Toole. Rights to use and modify granted to" << endl + << "University of Illinois Urbana-Champaign Computer Science Data Structures" << endl + << "instructors and course staff" << endl + << endl; +} + + +namespace output +{ + +// Set EXIT_IF_ERROR message +void set_error_message() +{ + SET_ERROR_MESSAGE("Oops! Something went wrong inside of me.\n" + "Please contact course staff with the following error details, and they'll figure it out:\n"); +} + +void header(const string & title) +{ + cout << title << "..." << endl + << "================================" << endl; +} + +void warning(const string & message) +{ + cerr << endl + << "********************************" + "********************************" << endl + << "WARNING!" << endl + << message << endl + << "********************************" + "********************************" << endl << endl; +} + + +void total_score(int32_t score) +{ + output::header("Total score (out of 100)"); + cout << "TOTAL SCORE: " << score << endl << endl; +} + +void testname(const unit_test & curr_test, int32_t max_testname_len, int32_t max_points_len) +{ + // Output test name + int32_t pos = 0; // keep track of cursor position + std::cout << curr_test.name << ' '; + pos += strlen(curr_test.name) + 1; + + if (curr_test.is_valgrind) + { + cout << "(valgrind) "; + pos += 11; + } + + if (pos % 2 == max_testname_len % 2) + { + cout << ' '; + pos++; + } + + while (pos < max_testname_len + 1) + { + cout << ". "; + pos += 2; + } + pos = 0; // reset column + + std::cout << "[" << curr_test.points << " pts] "; + pos += intlen(curr_test.points) + 7; + + while (pos < max_points_len + 7) + { + cout << ' '; + pos++; + } + + cout << "- "; +} + + +void detailed_info(const unit_test & curr_test) +{ + std::cout << "--------------------------------" << endl + << curr_test.name; + if (curr_test.is_valgrind) std::cout << " (run under valgrind)"; + std::cout << " [" << curr_test.points << " points]" << endl; + + const string & error = curr_test.errormsg; + const string & output = curr_test.output; + + if (curr_test.passed()) + std::cout << "Result: passed" << endl; + else + std::cout << "Result: FAILED: " << error << endl; + + if (curr_test.time < 0) + cout << "Took unknown time ("; + else + cout << "Took " << curr_test.time << "ms ("; + cout << curr_test.timeout << "ms timeout)" << endl; + + std::cout << "Output:" << endl + << "--------------------------------" << endl; + + // Tab the output over to distinguish it from the test case + if (output != "") + { + //std::cout << " "; + //replaceAllInternal(output,"\n","\n "); + std::cout << output; + if (output[output.length() - 1] != '\n') std::cout << endl; + } + + cout << endl; +} + +} // namespace output +} // namespace monad_shared + diff --git a/monad_shared.h b/monad_shared.h new file mode 100755 index 0000000..78236b0 --- /dev/null +++ b/monad_shared.h @@ -0,0 +1,71 @@ +#ifndef MONAD_SHARED +#define MONAD_SHARED + +#include "util.h" +#include "pipestream.h" + +namespace monad_shared +{ + + namespace version + { + extern const char * official_name; + extern const char * version_name; + extern const char * date; + } + + void printInfo(); + + struct unit_test + { + typedef std::string return_type; + typedef return_type (*function)(unit_test & this_test); + static const char * pass_string; + + std::string errormsg; + std::string output; + function func; + const char * name; + util::pipestream * checkstream; + long timeout; + long time; + int32_t points; + int32_t valgrind_flags; + int8_t mp_part; + bool is_valgrind; + + unit_test(int8_t MPpart_, + const char * name_, + unit_test::function func_, + int32_t points_, + long timeout_, + bool is_valgrind_) + : errormsg("message not set / proxy crashed"), + func(func_), + name(name_), + checkstream(NULL), + timeout(timeout_), + time(-1), + points(points_), + valgrind_flags(-1), + mp_part(MPpart_), + is_valgrind(is_valgrind_) { } + + bool passed() const + { + return errormsg == pass_string; + } + }; + + namespace output + { + void set_error_message(); + void header(const std::string & title); + void total_score(int32_t score); + void warning(const std::string & message); + void testname(const unit_test & curr_test, int32_t max_testname_len, int32_t max_points_len); + void detailed_info(const unit_test & curr_test); + } // namespace output +} + +#endif // MONAD_SHARED diff --git a/pipestream.cpp b/pipestream.cpp new file mode 100755 index 0000000..5bd64ce --- /dev/null +++ b/pipestream.cpp @@ -0,0 +1,328 @@ + +template <size_t buffersize> +sizedpipestream<buffersize>::sizedpipestream() + : wbufferpos(0), rbufferpos(buffersize), rbuffersize(buffersize), + maxopsize(-1), is_eof(false), enable_multiline_strings(true) +{ + // Give a compile time error if an invalid buffsize is specified + // This is necessary for much easier primitive reading/writing + // The buffer must be either 0 or at least large enough to hold any + // primitive (probably 8 or 16 bytes) + char buffer_size_must_be_0_or_over_16 + [(buffersize != 0 && buffersize < sizeof(intmax_t)) ? -1 : 1]; + buffer_size_must_be_0_or_over_16[0] = '\0'; + + // Create the pipe + pipe(fds); +} + +template <size_t buffersize> +sizedpipestream<buffersize>::~sizedpipestream() +{ + close(); +} + +template <size_t buffersize> +void sizedpipestream<buffersize>::close() +{ + close_write(); + close_read(); +} + +template <size_t buffersize> +void sizedpipestream<buffersize>::close_read() +{ + if (fds[READ_END] == -1) return; + ::close(fds[READ_END]); + fds[READ_END] = -1; +} + +template <size_t buffersize> +void sizedpipestream<buffersize>::close_write() +{ + if (fds[WRITE_END] == -1) return; + flush(); + ::close(fds[WRITE_END]); + fds[WRITE_END] = -1; +} + +template <size_t buffersize> +int sizedpipestream<buffersize>::steal_output(int fd) +{ + ::close(fd); + dup2(fds[WRITE_END], fd); + return 0; +} + +template <size_t buffersize> +int sizedpipestream<buffersize>::steal_input(int fd) +{ + ::close(fd); + dup2(fds[READ_END], fd); + return 0; +} + +template <size_t buffersize> +int sizedpipestream<buffersize>::get_read_fd() +{ + return fds[READ_END]; +} + +template <size_t buffersize> +int sizedpipestream<buffersize>::get_write_fd() +{ + return fds[WRITE_END]; +} + + +template <size_t buffersize> +void sizedpipestream<buffersize>::flush() +{ + if (buffersize == 0 || wbufferpos == 0 || fds[WRITE_END] == -1) + return; + + writen(fds[WRITE_END], &wbuffer[0], wbufferpos); + wbufferpos = 0; +} + +template <size_t buffersize> +int sizedpipestream<buffersize>::fill(size_t byte_count) +{ + if (buffersize == 0 || rbufferpos == 0 || fds[READ_END] == -1) + return -1; + + if (buffersize - rbufferpos < byte_count) + { + memmove(&rbuffer[0], &rbuffer[rbufferpos], rbuffersize - rbufferpos); + rbuffersize -= rbufferpos; + rbufferpos = 0; + } + + while (rbuffersize - rbufferpos < byte_count) + { + ssize_t read_count = ::read(fds[READ_END], + &rbuffer[rbuffersize], + buffersize - rbuffersize); + if (read_count == 0) return 0; + if (read_count == -1) + { + if (errno == EINTR) continue; + return -1; + } + rbuffersize += read_count; + } + + return rbuffersize - rbufferpos; +} + +template <size_t buffersize> +sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const string & str) +{ + if (buffersize == 0) + { + writen(fds[WRITE_END], str.c_str(), str.length()+1); + return *this; + } + + size_t len = str.length(); + for (size_t i = 0; i < len; i++) + { + if (wbufferpos == buffersize) flush(); + wbuffer[wbufferpos++] = str[i]; + } + if (wbufferpos == buffersize) flush(); + wbuffer[wbufferpos++] = '\0'; + return *this; +} + +template <size_t buffersize> +sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const char * str) +{ + if (buffersize == 0) + { + cout << "WRITING\n"; + writen(fds[WRITE_END], str, strlen(str)+1); + return *this; + } + + for (size_t i = 0; str[i] != '\0'; i++) + { + if (wbufferpos == buffersize) flush(); + wbuffer[wbufferpos++] = str[i]; + } + if (wbufferpos == buffersize) flush(); + wbuffer[wbufferpos++] = '\0'; + return *this; +} + +template <size_t buffersize> +sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(char * & str) +{ + size_t capacity = 4; + str = new char[capacity]; + size_t len = 0; + + int error = 0; + char c = '\0'; + do + { + error = read_primitive<char>(c); + if (len == maxopsize) continue; + + if (len == capacity) + { + char * temp = str; + str = new char[capacity*2]; + memcpy(str, temp, capacity); + capacity *= 2; + delete [] temp; + } + str[len++] = c; + + } while (error > 0 && c != '\0' && (enable_multiline_strings || c != '\n')); + + str[len-1] = '\0'; + + if (!enable_multiline_strings && len > 2 && str[len-2] == '\r') + str[len-2] = '\0'; + + maxopsize = -1; + return *this; +} + +template <size_t buffersize> +sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(string & str) +{ + char * cstr = NULL; + operator>>(cstr); + str = cstr; + delete [] cstr; + return *this; +} + +template <size_t buffersize> +sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<< + (pipestream_manip::enable_multiline_strings_t value) +{ + enable_multiline_strings = value.value; + return *this; +} + +template <size_t buffersize> +sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>> + (pipestream_manip::setmax_t max) +{ + maxopsize = max.max; + return *this; +} + +template <size_t buffersize> +inline bool sizedpipestream<buffersize>::eof() +{ return is_eof; } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const signed char & value) +{ return write_primitive(value); } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const signed short & value) +{ return write_primitive(value); } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const signed int & value) +{ return write_primitive(value); } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const signed long & value) +{ return write_primitive(value); } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const unsigned char & value) +{ return write_primitive(value); } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const unsigned short & value) +{ return write_primitive(value); } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const unsigned int & value) +{ return write_primitive(value); } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator<<(const unsigned long & value) +{ return write_primitive(value); } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(signed char & value) +{ read_primitive(value); return *this; } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(signed short & value) +{ read_primitive(value); return *this; } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(signed int & value) +{ read_primitive(value); return *this; } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(signed long & value) +{ read_primitive(value); return *this; } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(unsigned char & value) +{ read_primitive(value); return *this; } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(unsigned short & value) +{ read_primitive(value); return *this; } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(unsigned int & value) +{ read_primitive(value); return *this; } + +template <size_t buffersize> +inline sizedpipestream<buffersize> & sizedpipestream<buffersize>::operator>>(unsigned long & value) +{ read_primitive(value); return *this; } + +template <size_t buffersize> +template <typename T> +sizedpipestream<buffersize> & sizedpipestream<buffersize>::write_primitive(T value) +{ + if (fds[WRITE_END] == -1) return *this; + + if (buffersize == 0) + { + writen(fds[WRITE_END], &value, sizeof value); + return *this; + } + + if (buffersize - wbufferpos < sizeof value) + flush(); + + *reinterpret_cast<T*>(&wbuffer[wbufferpos]) = value; + wbufferpos += sizeof value; + return *this; +} + +template <size_t buffersize> +template <typename T> +int sizedpipestream<buffersize>::read_primitive(T & value) +{ + if (fds[READ_END] == -1) return -1; + + if (buffersize == 0) + return readn(fds[READ_END], &value, sizeof value); + + if (rbuffersize - rbufferpos < sizeof value) + { + int error = fill(sizeof value); + if (error == 0) is_eof = true; + if (error <= 0) return error; + } + + value = *reinterpret_cast<T*>(&rbuffer[rbufferpos]); + rbufferpos += sizeof value; + return sizeof value; +} + + diff --git a/pipestream.h b/pipestream.h new file mode 100644 index 0000000..a9c4248 --- /dev/null +++ b/pipestream.h @@ -0,0 +1,105 @@ +#ifndef PIPESTREAM_H +#define PIPESTREAM_H +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include "util.h" + +namespace util +{ + +namespace pipestream_manip { + struct setmax_t { + size_t max; + }; + + struct enable_multiline_strings_t { + bool value; + }; +} +inline pipestream_manip::setmax_t setmax(size_t max) +{ + pipestream_manip::setmax_t retval = { max }; + return retval; +} + +const pipestream_manip::enable_multiline_strings_t enable_multiline_strings = { true }; +const pipestream_manip::enable_multiline_strings_t disable_multiline_strings = { false }; + +template <size_t buffersize> +class sizedpipestream +{ + protected: + uint8_t wbuffer[buffersize+1]; // +1 to avoid 0 sized arrays + uint8_t rbuffer[buffersize+1]; + size_t wbufferpos; + size_t rbufferpos; + size_t rbuffersize; + size_t maxopsize; + int fds[2]; + bool is_eof; + bool enable_multiline_strings; + static const int READ_END = 0; + static const int WRITE_END = 1; + + public: + sizedpipestream(); + + ~sizedpipestream(); + void close(); + void close_read(); + void close_write(); + + bool eof(); + + void flush(); + int fill(size_t byte_count); + + int steal_output(int fd); + int steal_input(int fd); + + int get_read_fd(); + int get_write_fd(); + + sizedpipestream<buffersize> & operator<<(const string & str); + sizedpipestream<buffersize> & operator<<(const char * str); + sizedpipestream<buffersize> & operator<<(const signed char & value); + sizedpipestream<buffersize> & operator<<(const signed short & value); + sizedpipestream<buffersize> & operator<<(const signed int & value); + sizedpipestream<buffersize> & operator<<(const signed long & value); + sizedpipestream<buffersize> & operator<<(const unsigned char & value); + sizedpipestream<buffersize> & operator<<(const unsigned short & value); + sizedpipestream<buffersize> & operator<<(const unsigned int & value); + sizedpipestream<buffersize> & operator<<(const unsigned long & value); + + sizedpipestream<buffersize> & operator>>(string & str); + sizedpipestream<buffersize> & operator>>(char * & str); + sizedpipestream<buffersize> & operator>>( signed char & value); + sizedpipestream<buffersize> & operator>>( signed short & value); + sizedpipestream<buffersize> & operator>>( signed int & value); + sizedpipestream<buffersize> & operator>>( signed long & value); + sizedpipestream<buffersize> & operator>>(unsigned char & value); + sizedpipestream<buffersize> & operator>>(unsigned short & value); + sizedpipestream<buffersize> & operator>>(unsigned int & value); + sizedpipestream<buffersize> & operator>>(unsigned long & value); + + sizedpipestream<buffersize> & operator<<(pipestream_manip::enable_multiline_strings_t value); + sizedpipestream<buffersize> & operator>>(pipestream_manip::setmax_t max); + + protected: + template <typename T> + sizedpipestream<buffersize> & write_primitive(T value); + template <typename T> + int read_primitive(T & value); + + private: + sizedpipestream(sizedpipestream<buffersize> & other); + sizedpipestream<buffersize> & operator=(sizedpipestream<buffersize> & other); +}; + +typedef sizedpipestream<512> pipestream; + +#include "pipestream.cpp" + +} // namespace util +#endif diff --git a/proxy.cpp b/proxy.cpp new file mode 100755 index 0000000..709a5bd --- /dev/null +++ b/proxy.cpp @@ -0,0 +1,663 @@ +// proxy.cpp +// NOTE: This is a generic file. Actual unit tests are located in +// unit_tests.cpp. +// By Jack Toole for CS 225 spring 2011 + +// For strsignal: +#ifndef _GNU_SOURCE + #define _GNU_SOURCE +#endif + +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/time.h> + +#include <iomanip> + +#include "memcheck.h" +#include "monad_shared.h" +#include "pipestream.h" +#include "proxy.h" +#include "util.h" +#include "valgrind.h" + +using std::string; +using std::vector; +using std::pair; + +using namespace util; +using namespace monad_shared; + +namespace proxy +{ + vector<unit_test> * global_tests = NULL; + output_check_map * global_output_checks = NULL; +} + + +OUTPUT_CHECK(equals) +{ + return output == expected; +} + + +OUTPUT_CHECK(contains) +{ + return output.find(expected) != string::npos; +} + + +int main(int argc, char ** argv) +{ + using namespace proxy; + + // set up EXIT_IF_ERROR messages + output::set_error_message(); + + // Set up run-time environment + RunTimeEnvironment env(global_tests, global_output_checks); + + // Set up the tests + RunTests runner(argc, argv, env); + + // Execute + return runner.execute(); +} + + +namespace proxy { + +// class add_unit_test +add_unit_test::add_unit_test(int8_t MPpart, const char * name, unit_test::function func, + int32_t points_in_part, int32_t points_in_total, long timeout, + bool is_valgrind) +{ + assertMPpart(MPpart, name); + lazy_init_global_tests(); + int32_t points = get_points(points_in_total, points_in_part); + // Add to global tests vector + global_tests->push_back(unit_test(MPpart, name, func, points, timeout, is_valgrind)); +} + + +// Check to make global tests vector +void add_unit_test::lazy_init_global_tests() +{ + if (global_tests == NULL) + global_tests = new std::vector<unit_test>; +} + +// Check that test was legal to compile +void add_unit_test::assertMPpart(int8_t MPpart, const char * name) +{ + if (!MP_PART(MPpart)) + { + std::cerr << "Internal Error: unit tests should be surrounded by" << std::endl + << "#if MP_PART(partNumber) ... #endif" << std::endl + << name << "()" << " is defined for part " << (int)MPpart + << " but compiled for part " << MP_PART_NUMBER << std::endl; + exit(-2); + } +} + + +// Discriminate which points value to add +int32_t add_unit_test::get_points(int32_t points_in_total, int32_t points_in_part) +{ + #if MP_PART(NO_MP_PART) + return points_in_total; + #else + return points_in_part; + #endif +} + + + +// class add_output_check +add_output_check::add_output_check(const char * name, output_check func) +{ + if (global_output_checks == NULL) + global_output_checks = new output_check_map; + (*global_output_checks)[name] = func; +} + + + +// class Run_Time_Environment +RunTimeEnvironment::RunTimeEnvironment(vector<unit_test> *& init_tests, + output_check_map *& init_output_checks) + : itimer_number0(ITIMER_PROF), + itimer_number1(ITIMER_REAL), + timeout_signum0(SIGPROF), + timeout_signum1(SIGALRM), + max_output_length(8*1024), //arbitrary + single_test_passed_string("Result: passed"), + heap_tests(init_tests), + output_checks(init_output_checks) +{ + // Copy globals to the RunTimeEnvironment space + // And remove them from the global scope + static int8_t singleton = 0; + EXIT_IF_ERROR(singleton++ != 0, "There may only be one runtime environment"); + EXIT_IF_ERROR(heap_tests == NULL, "No test cases found"); + if (output_checks == NULL) + output_checks = new output_check_map; + + init_tests = NULL; + init_output_checks = NULL; +} + + +int RunTimeEnvironment::cleanup_globals() +{ + if (heap_tests != NULL) delete heap_tests; + if (output_checks != NULL) delete output_checks; + heap_tests = NULL; + output_checks = NULL; + return 0; +} + + + +// class RunTests +RunTests::RunTests(int argc, char ** argv, RunTimeEnvironment & env) + : environment(env) +{ + process_args(argc, argv); // sets up mode and test_arg + redirect_glibc_to_stderr(); +} + + +void RunTests::redirect_glibc_to_stderr() +{ + // Turn off glibc errors default write-to-terminal behaviour, because + // it does not get caught by stderr. This instead results in an abort. + // Unfortunately, this has still-reachable memory leaks under valgrind + if (RUNNING_ON_VALGRIND == 0) + setenv("LIBC_FATAL_STDERR_","1",1); + //setenv("MALLOC_CHECK_","2",1); +} + + +int32_t RunTests::execute() +{ + int32_t return_code = execute_by_mode(); + environment.cleanup_globals(); + return return_code; +} + + +int32_t RunTests::execute_by_mode() +{ + if (mode == SINGLE_TEST) + return run_single_test(test_arg); + else // if (mode == ALL_TESTS) + return run_all_tests(); +} + + +void RunTests::process_args(int argc, char ** argv) +{ + if (argc > 2) + { + cout << "Usage: " << argv[0] << "[testname]" << endl; + exit(0); + } + + if (argc == 2 && strcasecmp(argv[1], "--info") == 0) + { + printInfo(); + exit(0); + } + + if (argc == 1 || strcmp(argv[1], "all") == 0) + mode = ALL_TESTS; + else + { + mode = SINGLE_TEST; + test_arg = argv[1]; + } +} + + +int32_t RunTests::run_single_test(const char * testname) +{ + vector<unit_test> & tests = *environment.heap_tests; + + for (size_t test_i = 0; test_i < tests.size(); test_i++) + if (strcmp(tests[test_i].name, testname) == 0) + return run_single_test(tests[test_i]); + + cout << "Test not found" << endl; + exit(-1); +} + + +int32_t RunTests::run_single_test(unit_test & curr_test) +{ + cout << "Running " << curr_test.name << " [worth " + << curr_test.points << " points, output below]" << endl; + + bool is_parent_process = execute_test(curr_test, environment, false); + if (!is_parent_process) + return environment.cleanup_globals(); + + string & error = curr_test.errormsg; + + handle_single_test_output(curr_test.output); + + if (error == "") + error = "Unexpectedly Aborted"; + + if (curr_test.passed()) + cout << environment.single_test_passed_string << endl; + else + cout << "Result: FAILED:" << endl << error << endl; + + return curr_test.valgrind_flags; +} + + +void RunTests::handle_single_test_output(const string & output) +{ + if (output != "") + { + cout << output; + if (output[output.size()-1] != '\n') + cout << endl; + } +} + + +int RunTests::run_all_tests() +{ + vector<unit_test> & tests = *environment.heap_tests; + + output::header("Running tests"); + + int32_t points_sum = get_sum_points(); + int32_t max_testname_len = get_max_testname_length(); + int32_t max_points_len = get_max_points_length(); + + if (points_sum < 100) + output::warning("Unit test scores sum to " + to_string(points_sum) + + ", should be at least 100"); + + int32_t score = 0; + for (size_t test_i = 0; test_i < tests.size(); test_i++) + { + unit_test & curr_test = tests[test_i]; + output::testname(curr_test, max_testname_len, max_points_len); + + bool is_parent_process = execute_test(curr_test, environment, true); + // Check for the child process + // This is unfortunately necessary (instead of an exit) to clean up + // all the memory in use in main and the global space for valgrind + if (!is_parent_process) + return environment.cleanup_globals(); + + // Check for success + if (curr_test.passed()) + score += curr_test.points; + output_single_test_passfail(curr_test); + } + + cout << endl << endl; + output_detailed_info_if_any_failed(score); + output::total_score(score); + + return score; +} + +int32_t RunTests::get_sum_points() +{ + vector<unit_test> & tests = *environment.heap_tests; + int32_t points_sum = 0; + for (size_t test_i = 0; test_i < tests.size(); test_i++) + points_sum += tests[test_i].points; + return points_sum; +} + +int32_t RunTests::get_max_testname_length() +{ + vector<unit_test> & tests = *environment.heap_tests; + int32_t max_testname_len = 0; + for (size_t test_i = 0; test_i < tests.size(); test_i++) + { + int32_t currlen = strlen(tests[test_i].name) + (int)tests[test_i].is_valgrind * 11; // strlen(" (valgrind)"); + + if (currlen > max_testname_len) + max_testname_len = currlen; + } + return max_testname_len; +} + +int32_t RunTests::get_max_points_length() +{ + vector<unit_test> & tests = *environment.heap_tests; + int32_t max_points_len = 0; + for (size_t test_i = 0; test_i < tests.size(); test_i++) + { + if (tests[test_i].points >= 100) + max_points_len = 3; + else if (tests[test_i].points >= 10) + max_points_len = 2; + } + return max_points_len; +} + +void RunTests::output_detailed_info_if_any_failed(int32_t score) +{ + vector<unit_test> & tests = *environment.heap_tests; + + bool any_failed = false; + for (size_t test_i = 0; test_i < tests.size(); test_i++) + if (!tests[test_i].passed()) + any_failed = true; + + if (any_failed) + output_detailed_tests_info(score); +} + + +void RunTests::output_detailed_tests_info(int32_t score) +{ + output::total_score(score); + cout << endl << endl; + + output::header("Detailed test output"); + + vector<unit_test> & tests = *environment.heap_tests; + for (size_t test_i = 0; test_i < tests.size(); test_i++) + if (!tests[test_i].passed()) + output::detailed_info(tests[test_i]); + + cout << endl << "--------------------------------" << endl; +} + + +void RunTests::output_single_test_passfail(const unit_test & curr_test) +{ + if (curr_test.passed()) + std::cout << "passed" << endl; + else + std::cout << "FAILED: " << curr_test.errormsg << endl; +} + +test_execution::test_execution(unit_test & _test, RunTimeEnvironment & env, bool enable_valgrind_call) + : test(_test), environment(env) +{ + do_valgrind = enable_valgrind_call && test.is_valgrind; + if (!do_valgrind) + test.checkstream = new pipestream; +} + +void test_execution::child() +{ + fmsg_pipe.close_read(); + cout_pipe.close_read(); + nums_pipe.close_read(); + + // Redirect stdout/stderr to pipe + cout_pipe.steal_output(STDOUT_FILENO); + cout_pipe.steal_output(STDERR_FILENO); + + if (do_valgrind) + { + child_valgrind(); + } + else // if (!test.is_valgrind) + { + child_test(); + } +} + +void test_execution::parent() +{ + fmsg_pipe.close_write(); + cout_pipe.close_write(); + nums_pipe.close_write(); + if (test.checkstream != NULL) + test.checkstream->close_write(); + + // Read stdout/stderr pipe while process is running + cout_pipe >> setmax(environment.max_output_length) >> test.output; + cout_pipe.close_read(); +} + +void test_execution::after_success(int8_t return_code) +{ + if (do_valgrind) + after_valgrind_success(return_code); + else + after_test_success(); +} + +void test_execution::after_failure(int8_t signal_number) +{ + fmsg_pipe.close_read(); + nums_pipe.close_read(); + if (environment.is_timeout_signal(signal_number)) + { + test.errormsg = string("Timed out") + " (" + to_string(test.timeout) + "ms)"; + test.time = test.timeout; + } + else + test.errormsg = strsignal(signal_number); +} + + +bool RunTests::execute_test(unit_test & test, RunTimeEnvironment & environment, bool enable_valgrind_call) +{ + cout << std::flush; + test_execution executor(test, environment, enable_valgrind_call); + return fork_execute(executor); +} + +template <typename F> +bool fork_execute(F & executor) +{ + // Fork + pid_t process_id; + process_id = fork(); + EXIT_IF_ERROR(process_id < 0, "Could not fork application"); + + if (process_id == 0) + { + executor.child(); + // Unfortunately necessary to use a return stack instead of + // exit() to get rid of valgrind errors + // (which is important if we use valgrind ./proxy recursively) + return false; // previously exit(0); + } + else // if (process_id > 0) + { + executor.parent(); + + int child_status; + pid_t ws = waitpid(process_id, &child_status, 0); //should return immediately + EXIT_IF_ERROR(ws == -1); + + if (WIFEXITED(child_status)) /* exit code in child_status */ + executor.after_success(WEXITSTATUS(child_status)); + else if (WIFSIGNALED(child_status)) /* killed */ + executor.after_failure(WTERMSIG(child_status)); + else + executor.after_failure(SIGSTOP); + + return true; + } +} + + +void test_execution::child_valgrind() +{ + // We're giving up control to valgrind, so we can't + // Use anything but the cout pipe now + fmsg_pipe.close_write(); + nums_pipe.close_write(); + + start_timeout(); + exec("valgrind", "--trace-children=yes", /*"--log-fd=-1",*/ "-q", "./proxy", test.name, NULL); +} + + +void test_execution::child_test() +{ + test.checkstream->close_read(); + // Execute test + start_timeout(); + string * error_msg = new unit_test::return_type(test.func(test)); // execute function + long test_time = end_timeout(); + + // Write failure message to pipe + fmsg_pipe << *error_msg; + fmsg_pipe.close(); + + // write time and valgrind flags to pipe + bool test_failed = (*error_msg != unit_test::pass_string); + delete error_msg; + delete test.checkstream; + environment.cleanup_globals(); + int32_t valgrind_flags = get_valgrind_flags(test_failed); + nums_pipe << test_time; + nums_pipe << valgrind_flags; + nums_pipe.close(); +} + + +void test_execution::after_valgrind_success(int8_t return_code) +{ + fmsg_pipe.close_read(); + nums_pipe.close_read(); + + size_t last_endl = findNthLast(test.output, '\n', 2); + if (last_endl == string::npos) + test.errormsg = "Test did not complete"; + else + { + test.errormsg = test.output.substr(last_endl + 1, + test.output.length() - last_endl - 2); + + if (test.errormsg == "") + test.errormsg = "Exception Thrown / Aborted"; + + test.valgrind_flags = return_code; + if (test.errormsg == environment.single_test_passed_string) + test.errormsg = get_valgrind_string(test.valgrind_flags); + } +} + + +void test_execution::after_test_success() +{ + fmsg_pipe >> test.errormsg; + fmsg_pipe.close(); + nums_pipe >> test.time; + nums_pipe >> test.valgrind_flags; + nums_pipe.close(); + + // Check for output's correctness, if that was a condition of passing + if (test.passed()) + { + while (!test.checkstream->eof()) + { + string checkname; + string checkstr; + *test.checkstream >> checkname; + if (test.checkstream->eof()) break; + *test.checkstream >> checkstr; + if (test.checkstream->eof()) break; + + output_check check_function = (*environment.output_checks)[checkname]; + if (check_function == NULL) + { + cerr << "Internal Error: in test " << test.name << ": " + << checkname << " is not a registered OUTPUT_CHECK function" << endl; + exit(-2); + } + + if (!check_function(test.output, checkstr)) + test.errormsg = "Incorrect Terminal Output"; + } + } + delete test.checkstream; +} + + +int32_t get_valgrind_flags(bool test_failed) +{ + // Check for valgrind errors or leaks (if running under valgrind) + unsigned long errors = 0; + unsigned long leaked = 0; + unsigned long dubious = 0; + unsigned long reachable = 0; + unsigned long suppressed = 0; + + errors = VALGRIND_COUNT_ERRORS; + VALGRIND_DO_LEAK_CHECK; //QUICK + VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed); + + return bitflags(test_failed, errors, leaked, dubious, reachable); +} + + +const char * get_valgrind_string(int32_t flags) +{ + if (flags == 0) return unit_test::pass_string; + + bool test_failed = bitflag(flags, 0); + bool errors = bitflag(flags, 1); + bool leaked = bitflag(flags, 2); + bool dubious = bitflag(flags, 3); + bool reachable = bitflag(flags, 4); + + if (test_failed) return "Test failed (see output)"; + if (errors) return "Invalid read/write errors"; + if (leaked) return "Directly lost memory leaks"; + if (dubious) return "Possibly lost memory leaks"; + if (reachable) return "Still-reachable memory leaks"; + return "Unknown memory errors"; +} + + +void test_execution::start_timeout() +{ + struct itimerval timeout; + timeout.it_interval.tv_sec = 0; + timeout.it_interval.tv_usec = 0; + timeout.it_value.tv_sec = test.timeout/1000; + timeout.it_value.tv_usec = (test.timeout%1000) * 1000; + + EXIT_IF_ERROR(setitimer(environment.itimer_number0, &timeout, NULL)); + + // second real time signal in case the student calls a blocking call + timeout.it_value.tv_sec *= 10; + EXIT_IF_ERROR(setitimer(environment.itimer_number1, &timeout, NULL)); +} + + +long test_execution::end_timeout() +{ + struct itimerval timeout; + timeout.it_interval.tv_sec = 0; + timeout.it_interval.tv_usec = 0; + timeout.it_value.tv_sec = 0; + timeout.it_value.tv_usec = 0; + struct itimerval remaining; + + EXIT_IF_ERROR(setitimer(environment.itimer_number0, &timeout, &remaining)); + EXIT_IF_ERROR(setitimer(environment.itimer_number1, &timeout, NULL)); + + // There seems to be a strange -1 error here. I may just be tired, + // but I can't figure out why right now + long time = test.timeout - remaining.it_value.tv_sec*1000 - remaining.it_value.tv_usec/1000; + return (time < 0) ? 0 : time; +} + + + +} // namespace proxy + diff --git a/proxy.h b/proxy.h new file mode 100755 index 0000000..b88ab4f --- /dev/null +++ b/proxy.h @@ -0,0 +1,221 @@ +// proxy.h +// NOTE: This is a generic file. Actual unit tests are located in +// unit_tests.cpp. +// By Jack Toole for CS 225 spring 2011 + +#ifndef MONAD_PROXY_H +#define MONAD_PROXY_H + +#include <map> +#include <string> +#include <vector> +#include <iostream> +#include <utility> +#include "pipestream.h" +#include "monad_shared.h" + +#define NO_MP_PART -1 +#include "_mp_part_number.h" +#define MP_PART(x) (MP_PART_NUMBER == (x) || MP_PART_NUMBER == NO_MP_PART) + +namespace proxy +{ + using namespace monad_shared; + + class RunTests; + typedef bool (*output_check)(const std::string &, const std::string &); + + extern std::vector<unit_test> * global_tests; + typedef std::map<std::string, output_check, util::ci_less> output_check_map; + extern output_check_map * global_output_checks; + + class add_unit_test + { + public: + add_unit_test(int8_t MPpart, const char * name, unit_test::function func, + int32_t points_in_part, int32_t points_in_total, long timeout, + bool is_valgrind); + + private: + void lazy_init_global_tests(); + void assertMPpart(int8_t MPpart, const char * name); + int32_t get_points(int32_t points_in_total, int32_t points_in_part); + }; + + class add_output_check + { + public: + add_output_check(const char * name, output_check func); + }; + + enum mode_t + { + SINGLE_TEST, + MP_PART_TESTS, + ALL_TESTS + }; + + struct RunTimeEnvironment + { + public: + const int itimer_number0; + const int itimer_number1; + const int timeout_signum0; + const int timeout_signum1; + const size_t max_output_length; + const char * single_test_passed_string; + std::vector<unit_test> * heap_tests; + output_check_map * output_checks; + int32_t cleanup_globals(); + + RunTimeEnvironment(std::vector<unit_test> *& init_tests, + output_check_map *& init_output_checks); + + bool is_timeout_signal(int8_t signal_number) + { + return signal_number == timeout_signum0 || + signal_number == timeout_signum1; + } + + private: + RunTimeEnvironment(const RunTimeEnvironment & other); + RunTimeEnvironment & operator=(RunTimeEnvironment & other); + }; + + class RunTests + { + private: + RunTimeEnvironment & environment; + mode_t mode; + const char * test_arg; + int8_t mp_part; + + public: + RunTests(int argc, char ** argv, RunTimeEnvironment & env); + int execute(); + private: + void redirect_glibc_to_stderr(); + void process_args(int argc, char ** argv); + + protected: + int32_t execute_by_mode(); + int32_t run_single_test(const char * testname); + int32_t run_single_test(unit_test & curr_test); + void handle_single_test_output(const std::string & output); + void output_single_test_passfail(const unit_test & curr_test); + + int32_t run_all_tests(); + int32_t get_sum_points(); + int32_t get_max_testname_length(); + int32_t get_max_points_length(); + void output_detailed_info_if_any_failed(int32_t score); + void output_detailed_tests_info(int32_t score); + + bool execute_test(unit_test & test, RunTimeEnvironment & environment, bool enable_valgrind_call); + + private: + RunTests(const RunTests & other); + RunTests & operator=(const RunTests & other); + }; + + template <typename F> + bool fork_execute(F & executor); + + class test_execution + { + private: + util::pipestream fmsg_pipe; // For error messages + util::pipestream cout_pipe; // For stdout/stderr + util::pipestream nums_pipe; // for numbers: time, valgrind + unit_test & test; + RunTimeEnvironment & environment; + bool do_valgrind; + + public: + test_execution(unit_test & _test, RunTimeEnvironment & env, bool enable_valgrind_call); + void before(); + void parent(); + void child(); + void after_success(int8_t return_code); + void after_failure(int8_t signal_number); + + private: + void child_test(); + void child_valgrind(); + void after_test_success(); + void after_valgrind_success(int8_t return_code); + void start_timeout(); + long end_timeout(); + + private: + test_execution(const test_execution & other); + test_execution & operator=(const test_execution & other); + }; + + + const char * get_valgrind_string(int32_t flags); + int32_t get_valgrind_flags(bool test_failed); + int32_t bitflags(unsigned long a, unsigned long b = 0, unsigned long c = 0, + unsigned long d = 0, unsigned long e = 0); + bool bitflag(int32_t flags, int32_t num); + +} // namespace proxy + +using std::cout; +using std::cerr; +using std::endl; + +#define UNIT_TEST(MPpart,func,pointsInPart,pointsInTotal,timeout) \ + proxy::unit_test::return_type \ + func(proxy::unit_test & this_test); \ + proxy::add_unit_test \ + func##_adder(MPpart, #func, func, pointsInPart, \ + pointsInTotal, timeout, false); \ + proxy::unit_test::return_type \ + func(proxy::unit_test & this_test) + +#define VALGRIND_TEST(MPpart,func,pointsInPart,pointsInTotal,timeout) \ + proxy::unit_test::return_type \ + func(proxy::unit_test & this_test); \ + proxy::add_unit_test \ + func##_adder(MPpart, #func, func, pointsInPart, \ + pointsInTotal, timeout, true); \ + proxy::unit_test::return_type \ + func(proxy::unit_test & this_test) + +#define OUTPUT_CHECK(func) \ + bool output_check_##func(const std::string & output, const std::string & expected); \ + proxy::add_output_check \ + output_check_##func##_adder(#func, output_check_##func); \ + bool output_check_##func(const std::string & output, const std::string & expected) + +#define STRINGIFY1(p) #p +#define STR(p) STRINGIFY1(p) + +#define FAIL(error) return std::string(__FILE__ ":" STR(__LINE__) ": ") + (error) + +#define PASS return monad_shared::unit_test::pass_string; + +#define ASSERT(expr) if (!(expr)) \ + FAIL("Assertion (" #expr ") failed") + +#define ASSERT_OUTPUT(checkFunc, str) \ + *this_test.checkstream << #checkFunc << str; + +namespace proxy { + +inline int32_t bitflags(unsigned long a, unsigned long b, unsigned long c, + unsigned long d, unsigned long e) +{ + return ((int)(a != 0)) | (((int)(b != 0)) << 1) | + (((int)(c != 0)) << 2) | (((int)(d != 0)) << 3) | + (((int)(e != 0)) << 4) ; +} + +inline bool bitflag(int32_t flags, int32_t num) +{ + return (flags & (1 << num)) != 0; +} + +} +#endif diff --git a/update.sh b/update.sh new file mode 100755 index 0000000..79f944b --- /dev/null +++ b/update.sh @@ -0,0 +1,15 @@ +cp ../monad_dev/monad . +cp ../monad_dev/valgrind.h . +cp ../monad_dev/memcheck.h . +cp ../monad_dev/Makefile.proxy . +cp ../monad_dev/config.ini . +cp ../monad_dev/memcheck.h . +cp ../monad_dev/monad_shared.cpp . +cp ../monad_dev/monad_shared.h . +cp ../monad_dev/pipestream.cpp . +cp ../monad_dev/pipestream.h . +cp ../monad_dev/proxy.cpp . +cp ../monad_dev/proxy.h . +cp ../monad_dev/util.cpp . +cp ../monad_dev/util.h . +cp ../monad_dev/valgrind.h . diff --git a/util.cpp b/util.cpp new file mode 100644 index 0000000..84572d3 --- /dev/null +++ b/util.cpp @@ -0,0 +1,735 @@ +// CS 225 util.h +// Created Spring 2011 by Jack Toole + +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <iostream> +#include "util.h" + +extern char ** environ; // man 7 environ + +namespace util +{ + +namespace internal +{ +const char * error_prefix = ""; + +template<typename StrType> +void exit_if_error_output(const char * file, int32_t line, StrType message) +{ + if (util::internal::error_prefix != NULL) + cerr << util::internal::error_prefix; + cerr << file << ":" << line << ": " << message; + if (errno != 0) + cerr << ": " << strerror(errno); + cerr << endl; + exit(-1); +} + +} + +void SET_ERROR_MESSAGE(const char * message) +{ + internal::error_prefix = message; +} + +// originally from stackoverflow.com user plinth +// http://stackoverflow.com/questions/2180079/how-can-i-copy-a-file-on-unix-using-c +// Modified by Jack Toole +int8_t exec(int redirect_fd, const char * command, + const char * arg1, + const char * arg2, + const char * arg3, + const char * arg4, + const char * arg5, + const char * arg6) +{ + int childExitStatus; + pid_t pid; + + // For debugging: +#if 0 + cerr << "exec(" << command << ' ' + << ((arg1!=NULL)?arg1:"-") << ' ' + << ((arg2!=NULL)?arg2:"-") << ' ' + << ((arg3!=NULL)?arg3:"-") << ' ' + << ((arg4!=NULL)?arg4:"-") << ' ' + << ((arg5!=NULL)?arg5:"-") << ' ' + << ((arg6!=NULL)?arg6:"-") << ' ' + << ')' << endl; +#endif + + // avoid self destruction errors from closing then trying to duplicate output + // you can't redirect to what's already there + if (redirect_fd == STDOUT_FILENO || redirect_fd == STDERR_FILENO) + redirect_fd = STDOUT_FILENO; + + // Save timer values :) + // These are preserved across the parent, but not inherited by the child + // let's change that + struct itimerval remaining_real; + struct itimerval remaining_virtual; + struct itimerval remaining_prof; + EXIT_IF_ERROR(getitimer(ITIMER_REAL, &remaining_real)); + EXIT_IF_ERROR(getitimer(ITIMER_VIRTUAL, &remaining_virtual)); + EXIT_IF_ERROR(getitimer(ITIMER_PROF, &remaining_prof)); + + pid = fork(); + + if (pid == 0) /* child */ + { + + // Restore timers + EXIT_IF_ERROR(setitimer(ITIMER_REAL, &remaining_real, NULL)); + EXIT_IF_ERROR(setitimer(ITIMER_VIRTUAL, &remaining_virtual, NULL)); + EXIT_IF_ERROR(setitimer(ITIMER_PROF, &remaining_prof, NULL)); + + if (redirect_fd == -1) + { + int devnull_fd = open("/dev/null", O_WRONLY | O_NONBLOCK); + close(STDOUT_FILENO); + close(STDERR_FILENO); + dup2(devnull_fd, STDOUT_FILENO); + dup2(devnull_fd, STDERR_FILENO); + close(devnull_fd); + } + else if (redirect_fd != STDOUT_FILENO) + { + close(STDOUT_FILENO); + close(STDERR_FILENO); + dup2(redirect_fd, STDOUT_FILENO); + dup2(redirect_fd, STDERR_FILENO); + } + + // Sanitize the environment + char path[] = "PATH=/bin/:/usr/bin:/usr/local/bin"; + char * newenv[] = { path, NULL }; + environ = newenv; + + // Swap out child process image with the command, searching + // in the specified path + execlp(command, command, arg1, arg2, arg3, arg4, arg5, arg6, NULL); + + // An error occured + cerr << "command = " << command << endl; + cerr << "execT(" << '\"' << command << '\"'; + if (arg1 != NULL) cerr << ", \"" << arg1 << "\""; + if (arg2 != NULL) cerr << ", \"" << arg2 << "\""; + if (arg3 != NULL) cerr << ", \"" << arg3 << "\""; + if (arg4 != NULL) cerr << ", \"" << arg4 << "\""; + if (arg5 != NULL) cerr << ", \"" << arg5 << "\""; + if (arg6 != NULL) cerr << ", \"" << arg6 << "\""; + cerr << ") failed: " << strerror(errno) << endl; + exit(-1); + } + else if (pid < 0) + { + /* error - couldn't start process - you decide how to handle */ + return -1; + } + else + { + /* parent - wait for child - this has all error handling, you + * could just call wait() as long as you are only expecting to + * have one child process at a time. + */ + pid_t ws = waitpid( pid, &childExitStatus, 0); + if (ws == -1) + { /* error - handle as you wish */ + //cout << "exec error: " << __LINE__ << endl; + return -1; + } + + if (WIFEXITED(childExitStatus)) /* exit code in childExitStatus */ + { + int8_t status = WEXITSTATUS(childExitStatus); /* zero is normal exit */ + /* handle non-zero as you wish */ + return status; + } + else if (WIFSIGNALED(childExitStatus)) /* killed */ + { + kill(getpid(), WTERMSIG(childExitStatus)); + return -1; + } + else if (WIFSTOPPED(childExitStatus)) /* stopped */ + { + //cout << "exec error: " << __LINE__ << endl; + return -1; + } + else + return -1; + } +} + + +void assertExists(const string & path, int exit_code /* = -1 */) +{ + if (!exists(path)) + { + cerr << "Error: " << path << " does not exist." << endl; + exit(exit_code); + } +} + +bool exists(const string & path) +{ + // Try stat-ing it + struct stat st; + if (stat(path.c_str(), &st) != 0) return false; + + // Check for read permission + if ((st.st_mode & S_IRUSR) == 0) return false; + + // Check for correct file/directory nature + if (path[path.length()-1] != '/') return S_ISREG(st.st_mode); + + // Otherwise we want a directory + if ((st.st_mode & S_IXUSR) == 0) return false; + return S_ISDIR(st.st_mode); +} + + +mode_t permissions(const string & path) +{ + // Try stat-ing it + struct stat st; + if (stat(path.c_str(), &st) != 0) return -1; + + // Check for read permission + if ((st.st_mode & S_IRUSR) == 0) return -1; + + return (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); +} + + +void forceRemoveDir(string dir) +{ + size_t len = dir.length(); + if (dir[len-1] == '/') dir[len-1] = '\0'; + EXIT_IF_ERROR(exec("rm","-rf",dir.c_str()) != 0); + if (dir[len-1] == '\0') dir[len-1] = '/'; +} + + +string getcwdstr() +{ + int len = 256; + char * buffer = new char[len]; + + char * ret = getcwd(&buffer[0], len - 1); + while (ret == NULL && errno == ERANGE) + { + len *= 2; + + delete buffer; + buffer = new char[len]; + + ret = getcwd(&buffer[0], len - 1); + } + + EXIT_IF_ERROR(ret == NULL); + + string cwdstr(buffer); + delete buffer; + + return cwdstr; +} + + +void copyFile(const string & source, const string & dest) +{ + assertExists(source); + vector<string> folders = tokenize(dest, '/'); + string currdir = ""; + for (size_t i = 0; i < folders.size() - 1; i++) + { + currdir += folders[i] + '/'; + if (!exists(currdir)) + exec("mkdir", currdir.c_str()); + } + exec("cp", source.c_str(), dest.c_str()); +} + +void copyFiles(const string & sourceFolder, const string & destFolder, const vector<string> & files) +{ + assertExists(destFolder); + for (size_t i = 0; i < files.size(); i++) + { + string sourceFile = sourceFolder + files[i]; + assertExists(sourceFile); + copyFile(sourceFile, destFolder); + } +} + + +void protectFiles(const string & folder, const vector<string> & files) +{ +#if 0 // (debug) + for (size_t i = 0; i < files.size(); i++) + { + string file = folder + files[i]; + assertExists(file); + + if (chmod(file.c_str(), S_IRUSR) != 0) + { + perror("chmod failed"); + exit(-1); + } + } +#endif +} + +void protectDir(const string & dir) +{ + // (debug) EXIT_IF_ERROR(exec("/bin/chmod", "-R", "ugoa-w", dir.c_str()) != 0); +} + +// Originally from Simon Biber +// http://bytes.com/topic/c/answers/545614-list-files-current-directory +vector<string> getFilesInDir(const string & dir) +{ + vector<string> files; + DIR * dirp = opendir(dir.c_str()); + if (dirp == NULL) return files; + + struct dirent * ent = readdir(dirp); + while (ent != NULL) + { + // TODO (toole1) finish this + ent = readdir(dirp); + } + + closedir(dirp); + return files; +} + +void linkDirs(const string & sourceFolder, const string & destFolder, const vector<string> & dirs) +{ + assertExists(destFolder); + for (size_t i = 0; i < dirs.size(); i++) + { + string source = sourceFolder + dirs[i]; + string target = destFolder + dirs[i]; + + // Check for redundant monad/ directory + // This allows the monad/ dir to be safely renamed + if (replaceFirst(source, "/../monad/","/")) + replaceFirst(target, "/monad/","/"); + + assertExists(destFolder + source + '/'); + + if (symlink(source.c_str(), target.c_str()) != 0) + { + cerr << "symlink failed: " << target << ": "; + perror(NULL); + exit(-1); + } + } +} + + +bool replaceFirst(string & str, const string & toreplace, const string & with) +{ + size_t i = str.find(toreplace); + if (i != string::npos) + { + str.replace(i,toreplace.length(),with); + return true; + } + return false; +} + +size_t replaceAll(string & str, const string & toreplace, const string & with) +{ + size_t i = str.find(toreplace); + size_t count = 0; + + while (i != string::npos) + { + str.replace(i,toreplace.length(),with); + i = str.find(toreplace, i + with.length()); + count++; + } + + return count; +} + +size_t replaceAllInternal(string & str, const string & toreplace, const string & with) +{ + size_t i = str.find(toreplace); + size_t count = 0; + + while ((i != string::npos) && (i != str.length() - toreplace.length())) + { + str.replace(i,toreplace.length(),with); + i = str.find(toreplace, i + with.length()); + count++; + } + + return count; +} + + +size_t findNthLast(const string & str, char c, size_t n) +{ + if (str.length() == 0) return string::npos; + size_t i = str.length() - 1; + + do + { + if (str[i] == c) n--; + if (n == 0) return i; + } while (i-- != 0); + + return string::npos; +} + + +string read_string_from_FILE(FILE * file, size_t max_length /* = -1 */) +{ + vector<char> v; + v.reserve(256); + + while (true) + { + int nextchar = fgetc(file); + if (nextchar == '\0' || nextchar == EOF) + break; + if (v.size() < max_length) + v.push_back(nextchar); + } + + if (v.size() == max_length) + { + v.push_back('.'); + v.push_back('.'); + v.push_back('.'); + } + + v.push_back('\0'); + + return string(&v[0]); +} + +void write_string_to_FILE(FILE * file, const char * str) +{ + fflush(file); + size_t i = 0; + do + { +// cout << (int)str[i] << ' '; + fputc(str[i], file); + + // We use a do-while because we want the \0 to be written to the stream + // for sending multiple strings + } while (str[i++] != 0); + +// cout << endl; + + fflush(file); +} + + + +/** +* +* +**/ + +string readFile(const string & filename) +{ + ifstream file; + file.open(filename.c_str()); + if (!file.good()) + return ""; + + stringbuf linebuf; + file.get(linebuf, '\0'); + linebuf.pubsync(); + return linebuf.str(); +} + + +void readConfig(const string & testsFolder, FileMap & map, const string & discriminator /* = "" */) +{ + string file; + if (testsFolder == "" || testsFolder[testsFolder.length()-1] == '/') + file = testsFolder + "config.ini"; + else + file = testsFolder; + readFileGeneric(file, &map, NULL, discriminator); +} + +void readFile(const string & file, vector<string> & lines) +{ + readFileGeneric(file, NULL, &lines); +} + +void readFileGeneric(const string & filename, FileMap * map, vector<string> * lines, const string & discriminator /* = "" */) +{ + ifstream infile; + istream * fileptr; + if (filename == "/dev/stdin") + fileptr = &cin; + else + { + fileptr = &infile; + infile.open(filename.c_str(), fstream::in); + } + istream & file = *fileptr; + + vector<string> * section = NULL; + if (map != NULL) section = &(*map)[""]; + else section = lines; + + while ((file.good() && file.peek() == '\n') || file.peek() == '\r') + file.get(); // get '\n' + + while (file.good()) + { + // Read a line - A lot of code, I know, right? + stringbuf linebuf; + file.get(linebuf); + while ((file.good() && file.peek() == '\n') || file.peek() == '\r') + file.get(); // get '\n' + if (linebuf.in_avail() == 0) continue; + linebuf.pubsync(); + string line = linebuf.str(); + int len = line.length(); + if (line[len-1] == '\r') + line.replace(--len,1,""); + + if (len == 0 || line[0] == ';') continue; // skip comments + + if (map != NULL) + { + // Update the section + if (line[0] == '[' && line[len-1] == ']') + { + section = &(*map)[line.substr(1, len - 2)]; + continue; + } + else if (line[0] == '[' || line[len-1] == ']') + { + cout << "config.ini: Format error: " << line << endl; + exit(-1); + } + } + + // Or add the line/file to the section + size_t delim_pos = line.find_first_of("?:"); + if (delim_pos == string::npos || map == NULL) + section->push_back(line); + else if ((line[delim_pos] == ':' && (delim_pos == 0 || discriminator == "")) || + line.compare(0, delim_pos, discriminator) == 0) + section->push_back(line.substr(delim_pos+1, line.size()-delim_pos-1)); + } + + if (filename != "/dev/stdin") + infile.close(); +} + + +char * processOptions(int argc, char ** argv, OptionsMap & opts, vector<string> & args) +{ + for (int arg_i = 1; arg_i < argc; arg_i++) + { + char * currarg = argv[arg_i]; + + if (strncmp(currarg, "--", 2) == 0) //long option + { + bool value, invert; + size_t string_i; + + if (strncasecmp(currarg+2, "no", 2) == 0) + { + invert = true; + string_i = 4; + } + else + { + invert = false; + string_i = 2; + } + + size_t equals_i = string_i; + while (currarg[equals_i] != '\0' && currarg[equals_i] != '=') + equals_i++; + if (currarg[equals_i] == '=') + currarg[equals_i++] = '\0'; + + OptionsMap::iterator option = opts.find(currarg+string_i); + + if (option == opts.end()) + { + cerr << "Unknown option: " << currarg << endl; + return currarg; + } + + char valuechar = tolower(currarg[equals_i]); + if (valuechar == 'o') valuechar = tolower(currarg[equals_i+1]) + 1; + switch (valuechar) + { + case '\0' : value = true; break; + case 'f'+1 : value = false; break; //off: see 'o' above + case 'n' : value = false; break; + case 'n'+1 : value = true; break; //on: contrast 'n': see 'o' above + case 't' : value = true; break; + case 'y' : value = true; break; + default: + cerr << "Unknown option value: " << currarg << endl; + return currarg; + } + + (*option).second = value ^ invert; + } // "--" + + else if (currarg[0] == '-') //string of single char options + { + for (size_t c = 1; currarg[c] != '\0'; c++) + { + OptionsMap::iterator option = opts.find(string(1,currarg[c])); + if (option == opts.end()) + { + cerr << "Unknown option: -" << currarg[c] << endl; + currarg[1] = currarg[c]; + currarg[2] = '\0'; + return currarg; + } + (*option).second = true; + } + } + + else //positional argument + args.push_back(currarg); + } + + return NULL; +} + + + +void makeLower(string & str) +{ + for (size_t i = 0; i < str.length(); i++) + { + str[i] = tolower(str[i]); + } +} + +string toLower(const string & str) +{ + string s(str); + makeLower(s); + return s; +} + + + +/** +* A wrapper function which writes a buffer to a file. +**/ +ssize_t writeBytesToFile(signed int fileDescriptor, const char * buffer, unsigned int bufferLength) { + return writen(fileDescriptor, buffer, bufferLength); +} + + +// From Steven's Unix Net Programming +// http://www.kohala.com/start/ +/* Write "n" bytes to a descriptor. */ +ssize_t writen(int fd, const void *vptr, size_t n) +{ + size_t nleft; + ssize_t nwritten; + const int8_t * ptr; + + ptr = static_cast<const int8_t*>(vptr); + nleft = n; + while (nleft > 0) { + if ( (nwritten = ::write(fd, ptr, nleft)) <= 0) { + if (errno == EINTR) + nwritten = 0; /* and call write() again */ + else + return -1; /* error */ + } + + nleft -= nwritten; + ptr += nwritten; + } + return n; +} + + + + +// From Steven's Unix Net Programming +// http://www.kohala.com/start/ +/* Read "n" bytes from a descriptor. */ +ssize_t readn(int fd, void *vptr, size_t n) +{ + size_t nleft; + ssize_t nread; + int8_t * ptr; + + ptr = static_cast<int8_t*>(vptr); + nleft = n; + while (nleft > 0) { + if ( (nread = ::read(fd, ptr, nleft)) < 0) { + if (errno == EINTR) + nread = 0; /* and call read() again */ + else + return -1; + } + else if (nread == 0) + break; /* EOF */ + + nleft -= nread; + ptr += nread; + } + return n - nleft; /* return >= 0 */ +} + + +void rename_main(const string & file, const string & newname) +{ + if (newname[0] != '_') + { + cerr << "INTERNAL ERROR: " __FILE__ << ":" << __LINE__ + << "newname argument to rename_main must begin with an underscore to ensure replacement safety" << endl; + exit(-2); + } + assertExists(file); + exec( "sed", "-i", + ( "s/int[\\r\\n \\t][\\r\\n \\t]*main(.*)/int " + newname + + "(int argc, char ** argv)/" ).c_str(), + file.c_str() ); +} + +vector<string> tokenize(const string & str, char delim) +{ + vector<string> args; + + size_t start = 0; + size_t end; + for (end = str.find(delim); end != string::npos; end = str.find(delim, start)) + { + args.push_back(str.substr(start, end - start)); + start = end+1; + } + args.push_back(str.substr(start, str.size() - start)); + + return args; +} + +} // namespace util + diff --git a/util.h b/util.h new file mode 100644 index 0000000..0fcb14e --- /dev/null +++ b/util.h @@ -0,0 +1,252 @@ +#ifndef UTIL_H +#define UTIL_H + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <fstream> +#include <iostream> +#include <map> +#include <sstream> +#include <string> +#include <vector> + +namespace util +{ +using namespace std; + +namespace internal +{ +extern const char * error_prefix; +} + +/************************************************************************/ +/* Comparator for case-insensitive comparison in STL assos. containers */ +/* From Abhay: */ +/* http://stackoverflow.com/questions/1801892/making-mapfind-operation-case-insensitive */ +/************************************************************************/ +struct ci_less : std::binary_function<std::string, std::string, bool> +{ + // case-independent (ci) compare_less binary function + struct nocase_compare : public std::binary_function<unsigned char,unsigned char,bool> + { + bool operator() (const unsigned char& c1, const unsigned char& c2) const + { + return tolower (c1) < tolower (c2); + } + }; + bool operator() (const std::string & s1, const std::string & s2) const + { + return std::lexicographical_compare + (s1.begin (), s1.end (), // source range + s2.begin (), s2.end (), // dest range + nocase_compare ()); // comparison + } +}; + + + +/** +* Here we create a useful and easily understanable alias for the map. +**/ +typedef map<string, vector<string>, ci_less> FileMap; +typedef map<string, bool, ci_less> OptionsMap; + + + +// EXEC() +int8_t exec(int redirect_fd, const char * command, + const char * arg1 = NULL, + const char * arg2 = NULL, + const char * arg3 = NULL, + const char * arg4 = NULL, + const char * arg5 = NULL, + const char * arg6 = NULL); + +inline +int8_t exec(const char * command, + const char * arg1 = NULL, + const char * arg2 = NULL, + const char * arg3 = NULL, + const char * arg4 = NULL, + const char * arg5 = NULL, + const char * arg6 = NULL) +{ return exec(STDOUT_FILENO, command, arg1, arg2, arg3, arg4, arg5, arg6); } + + +// FILESYSTEM FUNCTIONS +void assertExists(const string & path, int exit_code = -1); +bool exists(const string & path); +mode_t permissions(const string & path); +void forceRemoveDir(string dir); +string getcwdstr(); + +void copyFile(const string & source, const string & dest); +void copyFiles(const string & sourceFolder, const string & destFolder, const vector<string> & files); +void protectFiles(const string & folder, const vector<string> & files); +void protectDir(const string & dir); +void linkDirs(const string & sourceFolder, const string & destFolder, const vector<string> & dirs); +vector<string> getFilesInDir(const string & dir); + +// STRING REPLACEMENT +bool replaceFirst(string & str, const string & toreplace, const string & with); +size_t replaceAll (string & str, const string & toreplace, const string & with); +size_t replaceAllInternal(string & str, const string & toreplace, const string & with); +size_t findNthLast(const string & str, char c, size_t n); +vector<string> tokenize(const string & str, char delim); + + +// IO OPERATIONS +string read_string_from_FILE(FILE * file, size_t max_length = -1); +void write_string_to_FILE(FILE * file, const char * str); +ssize_t writeBytesToFile(signed int fileDescriptor, const char * buffer, unsigned int bufferLength); +ssize_t writen(int fd, const void *vptr, size_t n); +ssize_t write(int fd, const string & str); +ssize_t write(int fd, int val); +ssize_t write(int fd, long val); +ssize_t readn(int fd, void *vptr, size_t n); +ssize_t read(int fd, int & val); +ssize_t read(int fd, long & val); + + +// STRING TYPE OPERATIONS +template <typename T> +string to_string(const T & value); +int intlen(unsigned int a); +void makeLower(string & str); +string toLower(const string & str); + + +// CONFIGURATION +void readConfig(const string & testsFolder, FileMap & map, const string & discriminator = ""); +void readFile(const string & file, vector<string> & lines); +string readFile(const string & filename); +void readFileGeneric(const string & file, FileMap * map, vector<string> * lines, const string & discriminator = ""); +char * processOptions(int argc, char ** argv, OptionsMap & opts, vector<string> & args); + + +// AUTOGRADER + + +// STUDENT CODE COMPILATION FUNCTIONS +void rename_main(const string & file, const string & newname); + + +// MACROS +void SET_ERROR_MESSAGE(const char * message); + +#define STRINGIFY1(p) #p +#define STR(p) STRINGIFY1(p) + +namespace internal +{ +template<typename StrType> +void exit_if_error_output(const char * file, int32_t line, StrType message); +} + +#define EXIT_IF_ERROR2(statement_check, message) \ + do { \ + errno = 0; \ + if ((statement_check) || errno != 0) \ + util::internal::exit_if_error_output(__FILE__, __LINE__, message); \ + } while (0) + +#define EXIT_IF_ERROR1(statement_check) \ + EXIT_IF_ERROR2(statement_check, #statement_check) + +// Crazy hack for overloading! +// Arg counting from: +// http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/ +// Overloading tips: +// http://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros +#define EXIT_IF_ERROR_THIRD_ARG(a, b, c, ...) c + +#define EXIT_IF_ERROR(...) \ + EXIT_IF_ERROR_THIRD_ARG(__VA_ARGS__, \ + EXIT_IF_ERROR2, \ + EXIT_IF_ERROR1, 0) (__VA_ARGS__) + + +// INLINE IMPLEMENTATIONS +// Originally by radu +// http://notfaq.wordpress.com/2006/08/30/c-convert-int-to-string/ +template <typename T> +inline string to_string(const T & value) +{ + stringstream ss; + ss << value; + return ss.str(); +} + +inline int intlen(unsigned int a) +{ + int len = 1; + a /= 10; + + while (a != 0) + { + a = a/10; + len++; + } + return len; +} + +inline ssize_t write(int fd, const string & str) +{ + return writen(fd, str.c_str(), str.length()+1); +} + +inline ssize_t write(int fd, int val) +{ + return writen(fd, &val, sizeof val); +} + +inline ssize_t write(int fd, long val) +{ + return writen(fd, &val, sizeof val); +} + +inline ssize_t read(int fd, int & val) +{ + return readn(fd, &val, sizeof val); +} + +inline ssize_t read(int fd, long & val) +{ + return readn(fd, &val, sizeof val); +} + +template <typename T, typename C, typename BinaryOp> +T accumulate(const C & collect, BinaryOp op, T init) +{ + typename C::const_iterator it = collect.begin(); + typename C::const_iterator end = collect.end(); + while (it != end) + init = init + *it++; + return init; +} + +#if 0 +template <typename C> +class collection_view<C> +{ + public: + class iterator + { + C::iterator it; + public: + + +} + +template <typename T, C> +Collection<T> transform(C collection, UnaryOperator op) +#endif + +} // namespace util + +#endif diff --git a/valgrind.h b/valgrind.h new file mode 100644 index 0000000..0bae0aa --- /dev/null +++ b/valgrind.h @@ -0,0 +1,4792 @@ +/* -*- 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-2010 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__ 6 + + +#include <stdarg.h> + +/* 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_ppc64_aix5 +#undef PLAT_ppc32_aix5 +#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 + +#if defined(_AIX) && defined(__64BIT__) +# define PLAT_ppc64_aix5 1 +#elif defined(_AIX) && !defined(__64BIT__) +# define PLAT_ppc32_aix5 1 +#elif 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 +#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. */ +/* ------------------------------------------------------------------ */ + +#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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + { \ + (_zzq_rlval) = (_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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + { 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_rlval = _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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _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 \ + } \ + _zzq_rlval = _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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + { 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_rlval = _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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { 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_rlval = _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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { unsigned long long int _zzq_args[6]; \ + register unsigned long long int _zzq_result __asm__("r3"); \ + register unsigned long long int* _zzq_ptr __asm__("r4"); \ + _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(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1" \ + : "=r" (_zzq_result) \ + : "0" (_zzq_default), "r" (_zzq_ptr) \ + : "cc", "memory"); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + register unsigned long long int __addr __asm__("r3"); \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2" \ + : "=r" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4" \ + : "=r" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { 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_rlval = _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 */ + +/* ------------------------ ppc32-aix5 ------------------------- */ + +#if defined(PLAT_ppc32_aix5) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + unsigned int r2; /* what tocptr do we need? */ + } + 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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { unsigned int _zzq_args[7]; \ + register unsigned int _zzq_result; \ + register 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_args[6] = (unsigned int)(_zzq_default); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 4,%1\n\t" \ + "lwz 3, 24(4)\n\t" \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" \ + : "=b" (_zzq_result) \ + : "b" (_zzq_ptr) \ + : "r3", "r4", "cc", "memory"); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + register unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "r3", "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "r3", "cc", "memory" \ + ); \ + _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_ppc32_aix5 */ + +/* ------------------------ ppc64-aix5 ------------------------- */ + +#if defined(PLAT_ppc64_aix5) + +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( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { unsigned long long int _zzq_args[7]; \ + register unsigned long long int _zzq_result; \ + register unsigned long long int* _zzq_ptr; \ + _zzq_args[0] = (unsigned int long long)(_zzq_request); \ + _zzq_args[1] = (unsigned int long long)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int long long)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int long long)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int long long)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int long long)(_zzq_arg5); \ + _zzq_args[6] = (unsigned int long long)(_zzq_default); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 4,%1\n\t" \ + "ld 3, 48(4)\n\t" \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" \ + : "=b" (_zzq_result) \ + : "b" (_zzq_ptr) \ + : "r3", "r4", "cc", "memory"); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + register unsigned long long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "r3", "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "r3", "cc", "memory" \ + ); \ + _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_aix5 */ + +/* 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. */ + +/* 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(_vgwZU_,soname,_,fnname) + +#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ + VG_CONCAT4(_vgwZZ_,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) + +/* 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" + +/* 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( \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "subl $12, %%esp\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $16, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $16, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $16, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $16, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $32, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $32, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $32, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $32, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $48, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $48, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $48, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_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( \ + "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 \ + "addl $48, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + 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 + + +/* 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, ppc32-aix5, ppc64-aix5); 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 \ + "subq $128,%%rsp\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "subq $128,%%rsp\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $8, %%rsp\n" \ + "addq $136,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $16, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $24, %%rsp\n" \ + "addq $136,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $32, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $40, %%rsp\n" \ + "addq $136,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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 \ + "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 \ + "addq $48, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "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" + +/* 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( \ + "mr 11,%1\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "addi 1,1,16\n\t" \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "addi 1,1,16\n\t" \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "addi 1,1,32\n\t" \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_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( \ + "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 \ + "addi 1,1,32\n\t" \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + 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" + +/* 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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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+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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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 */ \ + "addi 1,1,128" /* restore frame */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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 */ \ + "addi 1,1,128" /* restore frame */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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 */ \ + "addi 1,1,144" /* restore frame */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "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 */ \ + "addi 1,1,144" /* restore frame */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + 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" + +/* 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( \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "mov %0, r0\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( \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "mov %0, r0\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( \ + "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 \ + "mov %0, r0\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( \ + "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 \ + "mov %0, r0\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( \ + "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 \ + "mov %0, r0" \ + : /*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( \ + "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 \ + "add sp, sp, #4 \n\t" \ + "mov %0, r0" \ + : /*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( \ + "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 \ + "add sp, sp, #8 \n\t" \ + "mov %0, r0" \ + : /*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( \ + "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 \ + "add sp, sp, #12 \n\t" \ + "mov %0, r0" \ + : /*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( \ + "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 \ + "add sp, sp, #16 \n\t" \ + "mov %0, r0" \ + : /*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( \ + "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 \ + "add sp, sp, #20 \n\t" \ + "mov %0, r0" \ + : /*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( \ + "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 \ + "add sp, sp, #24 \n\t" \ + "mov %0, r0" \ + : /*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( \ + "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 \ + "add sp, sp, #28 \n\t" \ + "mov %0, r0" \ + : /*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( \ + "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 \ + "add sp, sp, #32 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_arm_linux */ + +/* ------------------------ ppc32-aix5 ------------------------- */ + +#if defined(PLAT_ppc32_aix5) + +/* 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" + +/* Expand the stack frame, copying enough info that unwinding + still works. Trashes r3. */ + +#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ + "addi 1,1,-" #_n_fr "\n\t" \ + "lwz 3," #_n_fr "(1)\n\t" \ + "stw 3,0(1)\n\t" + +#define VG_CONTRACT_FRAME_BY(_n_fr) \ + "addi 1,1," #_n_fr "\n\t" + +/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned + long) == 4. */ + +#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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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+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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(64) \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,56(1)\n\t" \ + /* args1-8 */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(64) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(64) \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,60(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,56(1)\n\t" \ + /* args1-8 */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(64) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(72) \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,64(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,60(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,56(1)\n\t" \ + /* args1-8 */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(72) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(72) \ + /* arg12 */ \ + "lwz 3,48(11)\n\t" \ + "stw 3,68(1)\n\t" \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,64(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,60(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,56(1)\n\t" \ + /* args1-8 */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(72) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc32_aix5 */ + +/* ------------------------ ppc64-aix5 ------------------------- */ + +#if defined(PLAT_ppc64_aix5) + +/* 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" + +/* Expand the stack frame, copying enough info that unwinding + still works. Trashes r3. */ + +#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ + "addi 1,1,-" #_n_fr "\n\t" \ + "ld 3," #_n_fr "(1)\n\t" \ + "std 3,0(1)\n\t" + +#define VG_CONTRACT_FRAME_BY(_n_fr) \ + "addi 1,1," #_n_fr "\n\t" + +/* These CALL_FN_ macros assume that on ppc64-aix5, 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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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+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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "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 */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(128) \ + /* 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 */ \ + VG_CONTRACT_FRAME_BY(128) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(128) \ + /* 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 */ \ + VG_CONTRACT_FRAME_BY(128) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(144) \ + /* 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 */ \ + VG_CONTRACT_FRAME_BY(144) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*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[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( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(144) \ + /* 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 */ \ + VG_CONTRACT_FRAME_BY(144) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc64_aix5 */ + + +/* ------------------------------------------------------------------ */ +/* 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, + + /* 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__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 + } Vg_ClientRequest; + +#if !defined(__GNUC__) +# define __extension__ /* */ +#endif + + +/* + * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind + * client request and whose value equals the client request result. + */ + +#if defined(NVALGRIND) + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + (_zzq_default) + +#else /*defined(NVALGRIND)*/ + +#if defined(_MSC_VER) + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + (vg_VALGRIND_DO_CLIENT_REQUEST_EXPR((uintptr_t)(_zzq_default), \ + (_zzq_request), (uintptr_t)(_zzq_arg1), (uintptr_t)(_zzq_arg2), \ + (uintptr_t)(_zzq_arg3), (uintptr_t)(_zzq_arg4), \ + (uintptr_t)(_zzq_arg5))) + +static __inline unsigned +vg_VALGRIND_DO_CLIENT_REQUEST_EXPR(uintptr_t _zzq_default, + unsigned _zzq_request, uintptr_t _zzq_arg1, + uintptr_t _zzq_arg2, uintptr_t _zzq_arg3, + uintptr_t _zzq_arg4, uintptr_t _zzq_arg5) +{ + unsigned _zzq_rlval; + VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request, + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5); + return _zzq_rlval; +} + +#else /*defined(_MSC_VER)*/ + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + (__extension__({unsigned int _zzq_rlval; \ + VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + _zzq_rlval; \ + })) + +#endif /*defined(_MSC_VER)*/ + +#endif /*defined(NVALGRIND)*/ + + +/* 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 \ + 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) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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 "**<pid>** " part at the + start and the backtrace (if present). */ + +#if defined(NVALGRIND) + +# define VALGRIND_PRINTF(...) +# define VALGRIND_PRINTF_BACKTRACE(...) + +#else /* NVALGRIND */ + +#if !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, ...) +{ + unsigned long _qzz_res; + va_list vargs; + va_start(vargs, format); +#if defined(_MSC_VER) + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, + VG_USERREQ__PRINTF_VALIST_BY_REF, + (uintptr_t)format, + (uintptr_t)&vargs, + 0, 0, 0); +#else + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, + VG_USERREQ__PRINTF_VALIST_BY_REF, + (unsigned long)format, + (unsigned long)&vargs, + 0, 0, 0); +#endif + va_end(vargs); + return (int)_qzz_res; +} + +#if !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, ...) +{ + unsigned long _qzz_res; + va_list vargs; + va_start(vargs, format); +#if defined(_MSC_VER) + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, + (uintptr_t)format, + (uintptr_t)&vargs, + 0, 0, 0); +#else + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 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) \ + __extension__ \ + ({unsigned long _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__CLIENT_CALL0, \ + _qyy_fn, \ + 0, 0, 0, 0); \ + _qyy_res; \ + }) + +#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ + __extension__ \ + ({unsigned long _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__CLIENT_CALL1, \ + _qyy_fn, \ + _qyy_arg1, 0, 0, 0); \ + _qyy_res; \ + }) + +#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ + __extension__ \ + ({unsigned long _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__CLIENT_CALL2, \ + _qyy_fn, \ + _qyy_arg1, _qyy_arg2, 0, 0); \ + _qyy_res; \ + }) + +#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ + __extension__ \ + ({unsigned long _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__CLIENT_CALL3, \ + _qyy_fn, \ + _qyy_arg1, _qyy_arg2, \ + _qyy_arg3, 0); \ + _qyy_res; \ + }) + + +/* 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 \ + __extension__ \ + ({unsigned int _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__COUNT_ERRORS, \ + 0, 0, 0, 0, 0); \ + _qyy_res; \ + }) + +/* 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. + + In many cases, these two 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. + + Note: there is currently no VALGRIND_REALLOCLIKE_BLOCK client request; it + has to be emulated with MALLOCLIKE/FREELIKE and memory copying. + + Ignored if addr == 0. +*/ +#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MALLOCLIKE_BLOCK, \ + addr, sizeB, rzB, is_zeroed, 0); \ + } + +/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. + Ignored if addr == 0. +*/ +#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__FREELIKE_BLOCK, \ + addr, rzB, 0, 0, 0); \ + } + +/* Create a memory pool. */ +#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__CREATE_MEMPOOL, \ + pool, rzB, is_zeroed, 0, 0); \ + } + +/* Destroy a memory pool. */ +#define VALGRIND_DESTROY_MEMPOOL(pool) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_ALLOC, \ + pool, addr, size, 0, 0); \ + } + +/* Disassociate a piece of memory from a memory pool. */ +#define VALGRIND_MEMPOOL_FREE(pool, addr) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_FREE, \ + pool, addr, 0, 0, 0); \ + } + +/* Disassociate any pieces outside a particular range. */ +#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_CHANGE, \ + pool, addrA, addrB, size, 0); \ + } + +/* Return 1 if a mempool exists, else 0. */ +#define VALGRIND_MEMPOOL_EXISTS(pool) \ + __extension__ \ + ({unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_EXISTS, \ + pool, 0, 0, 0, 0); \ + _qzz_res; \ + }) + +/* Mark a piece of memory as being a stack. Returns a stack id. */ +#define VALGRIND_STACK_REGISTER(start, end) \ + __extension__ \ + ({unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__STACK_REGISTER, \ + start, end, 0, 0, 0); \ + _qzz_res; \ + }) + +/* Unmark the piece of memory associated with a stack id as being a + stack. */ +#define VALGRIND_STACK_DEREGISTER(id) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + 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 int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MAP_IP_TO_SRCLOC, \ + addr, buf64, 0, 0, 0); \ + } + + +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64_linux +#undef PLAT_arm_linux +#undef PLAT_ppc32_aix5 +#undef PLAT_ppc64_aix5 + +#endif /* __VALGRIND_H */ -- GitLab