diff options
Diffstat (limited to 'include/.svn')
40 files changed, 8611 insertions, 0 deletions
diff --git a/include/.svn/dir-prop-base b/include/.svn/dir-prop-base new file mode 100644 index 0000000..c344368 --- /dev/null +++ b/include/.svn/dir-prop-base @@ -0,0 +1,8 @@ +K 10 +svn:ignore +V 38 +Makefile.in +Makefile +tool.h +valgrind.h +END diff --git a/include/.svn/entries b/include/.svn/entries new file mode 100644 index 0000000..7f0f628 --- /dev/null +++ b/include/.svn/entries @@ -0,0 +1,442 @@ +8 + +dir +9703 +svn://svn.valgrind.org/valgrind/trunk/include +svn://svn.valgrind.org/valgrind + + + +2009-04-30T05:23:22.182900Z +9700 +njn +has-props + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +a5019735-40e9-0310-863c-91ae7b9d1cf9 + +pub_tool_vki.h +file + + + + +2009-03-13T17:30:10.000000Z +8c0df23baf33da26840760d758d9045b +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_options.h +file + + + + +2009-03-13T17:30:10.000000Z +86b1b3974b7f58ee7fa3c44c1f903dfa +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_hashtable.h +file + + + + +2009-03-13T17:30:10.000000Z +a3b8d051b833c480c137a4edfad36958 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_aspacemgr.h +file + + + + +2009-03-13T17:30:10.000000Z +4ecf208eea211774d1bbd9864cdf7743 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_machine.h +file + + + + +2009-03-13T17:30:10.000000Z +95e8e0473517c37c55579dad517694c9 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_libcbase.h +file + + + + +2009-03-13T17:30:10.000000Z +1d0bac6294ceefc80b5c9d58d7b27369 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_basics_asm.h +file + + + + +2009-04-30T16:43:59.000000Z +8ff719c2299ba39f01a779d67b54eb58 +2009-04-24T04:57:07.028318Z +9601 +njn + +pub_tool_cpuid.h +file + + + + +2009-03-13T17:30:10.000000Z +b5f4eed0320ee5682727fa6c640e858c +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_tooliface.h +file + + + + +2009-03-13T17:30:10.000000Z +764813639dfc11934392fe4d2e73e993 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_seqmatch.h +file + + + + +2009-03-13T17:30:10.000000Z +4d9283faf4350f2fb2f8541d1863e6cd +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_clreq.h +file + + + + +2009-03-13T17:30:10.000000Z +4ae6e4f917a160ad4485384c464ffe8a +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_threadstate.h +file + + + + +2009-03-13T17:30:10.000000Z +359cc0a78af71ec69d02508cbe897f58 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_clientstate.h +file + + + + +2009-03-13T17:30:10.000000Z +70f7717a93645dae31d8d146d2bd1169 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_vkiscnums.h +file + + + + +2009-03-13T17:30:10.000000Z +0302afd0234e0764f5557decd2548fd1 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_stacktrace.h +file + + + + +2009-03-13T17:30:10.000000Z +3192155a184517799e8b0ca100694c82 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_sparsewa.h +file + + + + +2009-03-13T17:30:10.000000Z +e527dad02f04fc93db02388361a92c0e +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_libcprint.h +file + + + + +2009-04-30T16:43:59.000000Z +22571e17a647bcd48765ddf2f6cfe500 +2009-04-30T04:17:45.496239Z +9693 +njn + +pub_tool_execontext.h +file + + + + +2009-03-13T17:30:10.000000Z +2bdb1c23f24375f69d4cde5cd46edc39 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_libcassert.h +file + + + + +2009-03-13T17:30:10.000000Z +d65d5859175e57e7eff56c383b5e431a +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_libcproc.h +file + + + + +2009-03-13T17:30:10.000000Z +44340a7ee527423a7d7f170b576c23a7 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_wordfm.h +file + + + + +2009-03-13T17:30:10.000000Z +98d950ed66b67627ac30dd56e13a1e0b +2009-03-10T22:02:09.669944Z +9344 +njn +has-props + +pub_tool_errormgr.h +file + + + + +2009-03-13T17:30:10.000000Z +010abc7e891425aff3905c7aba8d281e +2009-03-10T22:02:09.669944Z +9344 +njn + +vki +dir + +pub_tool_signals.h +file + + + + +2009-03-13T17:30:10.000000Z +514b83cf57f4319e5a98fe84b66f9c44 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_debuginfo.h +file + + + + +2009-03-13T17:30:10.000000Z +40e2b13a6023dc68be40e0a6305e5b74 +2009-03-10T22:02:09.669944Z +9344 +njn + +valgrind.h +file + + + + +2009-04-30T16:43:59.000000Z +f562afeb8973591fa41b46a0667f0009 +2009-04-22T22:42:10.255420Z +9580 +sewardj +has-props + +pub_tool_replacemalloc.h +file + + + + +2009-03-13T17:30:10.000000Z +b9789db48287d26f144105711141ddc2 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_basics.h +file + + + + +2009-04-30T16:43:59.000000Z +77c531e7628c6db35c29d12af5a83043 +2009-04-24T04:57:07.028318Z +9601 +njn + +pub_tool_redir.h +file + + + + +2009-03-13T17:30:10.000000Z +228612233618db51771d95eba93d9f0e +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_xarray.h +file + + + + +2009-03-13T17:30:10.000000Z +a6c6bb6ba595696ce82c8f9634aac49c +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_libcsignal.h +file + + + + +2009-03-13T17:30:10.000000Z +9290e85a737bf052598334941719d888 +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_mallocfree.h +file + + + + +2009-04-30T16:43:59.000000Z +aaf6d5f22425aea9aa9a228a2ae3567f +2009-03-15T23:25:38.213170Z +9416 +njn + +pub_tool_libcfile.h +file + + + + +2009-03-13T17:30:10.000000Z +00fcd9b8d4c5ab5675022d3a09a0501e +2009-03-10T22:02:09.669944Z +9344 +njn + +pub_tool_oset.h +file + + + + +2009-04-30T16:43:59.000000Z +abafe3130a5f81588bc7ac5dc9d2c1f5 +2009-04-26T07:15:58.034266Z +9634 +bart + +Makefile.am +file + + + + +2009-03-13T17:30:10.000000Z +43988b1cd4881956b04dd5567ad6cc30 +2008-12-12T08:07:49.045161Z +8816 +sewardj +has-props + diff --git a/include/.svn/format b/include/.svn/format new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/include/.svn/format @@ -0,0 +1 @@ +8 diff --git a/include/.svn/prop-base/Makefile.am.svn-base b/include/.svn/prop-base/Makefile.am.svn-base new file mode 100644 index 0000000..df54a06 --- /dev/null +++ b/include/.svn/prop-base/Makefile.am.svn-base @@ -0,0 +1,9 @@ +K 13 +svn:eol-style +V 6 +native +K 12 +svn:keywords +V 23 +author date id revision +END diff --git a/include/.svn/prop-base/pub_tool_wordfm.h.svn-base b/include/.svn/prop-base/pub_tool_wordfm.h.svn-base new file mode 100644 index 0000000..3160658 --- /dev/null +++ b/include/.svn/prop-base/pub_tool_wordfm.h.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mergeinfo +V 0 + +END diff --git a/include/.svn/prop-base/valgrind.h.svn-base b/include/.svn/prop-base/valgrind.h.svn-base new file mode 100644 index 0000000..df54a06 --- /dev/null +++ b/include/.svn/prop-base/valgrind.h.svn-base @@ -0,0 +1,9 @@ +K 13 +svn:eol-style +V 6 +native +K 12 +svn:keywords +V 23 +author date id revision +END diff --git a/include/.svn/text-base/Makefile.am.svn-base b/include/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..e73f5cd --- /dev/null +++ b/include/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,39 @@ + +SUBDIRS = vki + +incincdir = $(includedir)/valgrind + +incinc_HEADERS = \ + pub_tool_basics.h \ + pub_tool_basics_asm.h \ + pub_tool_aspacemgr.h \ + pub_tool_clientstate.h \ + pub_tool_clreq.h \ + pub_tool_cpuid.h \ + pub_tool_debuginfo.h \ + pub_tool_errormgr.h \ + pub_tool_execontext.h \ + pub_tool_hashtable.h \ + pub_tool_libcbase.h \ + pub_tool_libcassert.h \ + pub_tool_libcfile.h \ + pub_tool_libcprint.h \ + pub_tool_libcproc.h \ + pub_tool_libcsignal.h \ + pub_tool_machine.h \ + pub_tool_mallocfree.h \ + pub_tool_options.h \ + pub_tool_oset.h \ + pub_tool_redir.h \ + pub_tool_replacemalloc.h \ + pub_tool_seqmatch.h \ + pub_tool_signals.h \ + pub_tool_sparsewa.h \ + pub_tool_stacktrace.h \ + pub_tool_threadstate.h \ + pub_tool_tooliface.h \ + pub_tool_vki.h \ + pub_tool_vkiscnums.h \ + pub_tool_wordfm.h \ + pub_tool_xarray.h \ + valgrind.h diff --git a/include/.svn/text-base/pub_tool_aspacemgr.h.svn-base b/include/.svn/text-base/pub_tool_aspacemgr.h.svn-base new file mode 100644 index 0000000..f84dfa6 --- /dev/null +++ b/include/.svn/text-base/pub_tool_aspacemgr.h.svn-base @@ -0,0 +1,158 @@ + +/*--------------------------------------------------------------------*/ +/*--- Address space manager. pub_tool_aspacemgr.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_ASPACEMGR_H +#define __PUB_TOOL_ASPACEMGR_H + + +//-------------------------------------------------------------- +// Definition of address-space segments + +/* Describes segment kinds. */ +typedef + enum { + SkFree, // unmapped space + SkAnonC, // anonymous mapping belonging to the client + SkAnonV, // anonymous mapping belonging to valgrind + SkFileC, // file mapping belonging to the client + SkFileV, // file mapping belonging to valgrind + SkShmC, // shared memory segment belonging to the client + SkResvn // reservation + } + SegKind; + +/* Describes how a reservation segment can be resized. */ +typedef + enum { + SmLower, // lower end can move up + SmFixed, // cannot be shrunk + SmUpper // upper end can move down + } + ShrinkMode; + +/* Describes a segment. Invariants: + + kind == SkFree: + // the only meaningful fields are .start and .end + + kind == SkAnon{C,V}: + // smode==SmFixed + // there's no associated file: + dev==ino==foff = 0, fnidx == -1 + // segment may have permissions + + kind == SkFile{C,V}: + // smode==SmFixed + moveLo == moveHi == NotMovable, maxlen == 0 + // there is an associated file + // segment may have permissions + + kind == SkShmC: + // smode==SmFixed + // there's no associated file: + dev==ino==foff = 0, fnidx == -1 + // segment may have permissions + + kind == SkResvn + // the segment may be resized if required + // there's no associated file: + dev==ino==foff = 0, fnidx == -1 + // segment has no permissions + hasR==hasW==hasX==anyTranslated == False + + Also: anyTranslated==True is only allowed in SkFileV and SkAnonV + (viz, not allowed to make translations from non-client areas) +*/ +typedef + struct { + SegKind kind; + /* Extent (SkFree, SkAnon{C,V}, SkFile{C,V}, SkResvn) */ + Addr start; // lowest address in range + Addr end; // highest address in range + /* Shrinkable? (SkResvn only) */ + ShrinkMode smode; + /* Associated file (SkFile{C,V} only) */ + ULong dev; + ULong ino; + Off64T offset; + UInt mode; + Int fnIdx; // file name table index, if name is known + /* Permissions (SkAnon{C,V}, SkFile{C,V} only) */ + Bool hasR; + Bool hasW; + Bool hasX; + Bool hasT; // True --> translations have (or MAY have) + // been taken from this segment + Bool isCH; // True --> is client heap (SkAnonC ONLY) + /* Admin */ + Bool mark; + } + NSegment; + + +/* Collect up the start addresses of all non-free, non-resvn segments. + The interface is a bit strange in order to avoid potential + segment-creation races caused by dynamic allocation of the result + buffer *starts. + + The function first computes how many entries in the result + buffer *starts will be needed. If this number <= nStarts, + they are placed in starts[0..], and the number is returned. + If nStarts is not large enough, nothing is written to + starts[0..], and the negation of the size is returned. + + Correct use of this function may mean calling it multiple times in + order to establish a suitably-sized buffer. */ +extern Int VG_(am_get_segment_starts)( Addr* starts, Int nStarts ); + + +// See pub_core_aspacemgr.h for description. +extern NSegment const * VG_(am_find_nsegment) ( Addr a ); + +// See pub_core_aspacemgr.h for description. +extern HChar* VG_(am_get_filename)( NSegment const * ); + +// See pub_core_aspacemgr.h for description. +extern Bool VG_(am_is_valid_for_client) ( Addr start, SizeT len, + UInt prot ); + +// See pub_core_aspacemgr.h for description. +/* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */ +extern void* VG_(am_shadow_alloc)(SizeT size); + +/* Unmap the given address range and update the segment array + accordingly. This fails if the range isn't valid for valgrind. */ +extern SysRes VG_(am_munmap_valgrind)( Addr start, SizeT length ); + +#endif // __PUB_TOOL_ASPACEMGR_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_basics.h.svn-base b/include/.svn/text-base/pub_tool_basics.h.svn-base new file mode 100644 index 0000000..9bff837 --- /dev/null +++ b/include/.svn/text-base/pub_tool_basics.h.svn-base @@ -0,0 +1,214 @@ + +/*--------------------------------------------------------------------*/ +/*--- Header included by every tool C file. pub_tool_basics.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_BASICS_H +#define __PUB_TOOL_BASICS_H + +//-------------------------------------------------------------------- +// PURPOSE: This header should be imported by every single C file in +// tools. It contains the basic types and other things needed everywhere. +// There is no corresponding C file because this isn't a module +// containing executable code, it's all just declarations. +//-------------------------------------------------------------------- + +/* --------------------------------------------------------------------- + Other headers to include + ------------------------------------------------------------------ */ + +// VEX defines Char, UChar, Short, UShort, Int, UInt, Long, ULong, +// Addr32, Addr64, HWord, HChar, Bool, False and True. +#include "libvex_basictypes.h" + +// For varargs types +#include <stdarg.h> + +/* For HAVE_BUILTIN_EXPECT */ +#include "config.h" + + +/* --------------------------------------------------------------------- + symbol prefixing + ------------------------------------------------------------------ */ + +// All symbols externally visible from Valgrind are prefixed +// as specified here to avoid namespace conflict problems. +// +// VG_ is for symbols exported from modules. ML_ (module-local) is +// for symbols which are not intended to be visible outside modules, +// but which cannot be declared as C 'static's since they need to be +// visible across C files within a given module. It is a mistake for +// a ML_ name to appear in a pub_core_*.h or pub_tool_*.h file. +// Likewise it is a mistake for a VG_ name to appear in a priv_*.h +// file. + +#define VGAPPEND(str1,str2) str1##str2 + +#define VG_(str) VGAPPEND(vgPlain_, str) +#define ML_(str) VGAPPEND(vgModuleLocal_, str) + + +/* --------------------------------------------------------------------- + builtin types + ------------------------------------------------------------------ */ + +// By choosing the right types, we can get these right for 32-bit and 64-bit +// platforms without having to do any conditional compilation or anything. +// POSIX references: +// - http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html +// - http://www.opengroup.org/onlinepubs/009695399/basedefs/stddef.h.html +// +// Size in bits on: 32-bit archs 64-bit archs +// ------------ ------------ +typedef unsigned long UWord; // 32 64 +typedef signed long Word; // 32 64 + +// Addr is for holding an address. AddrH was intended to be "Addr on the +// host", for the notional case where host word size != guest word size. +// But since the assumption that host arch == guest arch has become so +// deeply wired in, it's a pretty pointless distinction now. +typedef UWord Addr; // 32 64 +typedef UWord AddrH; // 32 64 + +// Our equivalents of POSIX 'size_t' and 'ssize_t': +// - size_t is an "unsigned integer type of the result of the sizeof operator". +// - ssize_t is "used for a count of bytes or an error indication". +typedef UWord SizeT; // 32 64 +typedef Word SSizeT; // 32 64 + +// Our equivalent of POSIX 'ptrdiff_t': +// - ptrdiff_t is a "signed integer type of the result of subtracting two +// pointers". +// We use it for memory offsets, eg. the offset into a memory block. +typedef Word PtrdiffT; // 32 64 + +// Our equivalent of POSIX 'off_t': +// - off_t is "used for file sizes". +// At one point we were using it for memory offsets, but PtrdiffT should be +// used in those cases. +typedef Word OffT; // 32 64 +typedef Long Off64T; // 64 64 + +#if !defined(NULL) +# define NULL ((void*)0) +#endif + +/* This is just too useful to not have around the place somewhere. */ +typedef struct { UWord uw1; UWord uw2; } UWordPair; + + +/* --------------------------------------------------------------------- + non-builtin types + ------------------------------------------------------------------ */ + +// These probably shouldn't be here, but moving them to their logical +// modules results in a lot more #includes... + +/* ThreadIds are simply indices into the VG_(threads)[] array. */ +typedef UInt ThreadId; + +/* An abstraction of syscall return values. + Linux: + When .isError == False, + res holds the return value, and err is zero. + When .isError == True, + err holds the error code, and res is zero. + + AIX: + res is the POSIX result of the syscall. + err is the corresponding errno value. + isError === err==0 + + Unlike on Linux, it is possible for 'err' to be nonzero (thus an + error has occurred), nevertheless 'res' is also nonzero. AIX + userspace does not appear to consistently inspect 'err' to + determine whether or not an error has occurred. For example, + sys_open() will return -1 for 'val' if a file cannot be opened, + as well as the relevant errno value in 'err', but AIX userspace + then consults 'val' to figure out if the syscall failed, rather + than looking at 'err'. Hence we need to represent them both. +*/ +typedef + struct { + UWord res; + UWord err; + Bool isError; + } + SysRes; + + +/* --------------------------------------------------------------------- + Miscellaneous (word size, endianness, regparmness, stringification) + ------------------------------------------------------------------ */ + +/* Word size: this is going to be either 4 or 8. */ +// It should probably be in m_machine. +#define VG_WORDSIZE VEX_HOST_WORDSIZE + +/* Endianness */ +#undef VG_BIGENDIAN +#undef VG_LITTLEENDIAN + +#if defined(VGA_x86) || defined(VGA_amd64) +# define VG_LITTLEENDIAN 1 +#elif defined(VGA_ppc32) || defined(VGA_ppc64) +# define VG_BIGENDIAN 1 +#endif + +/* Regparmness */ +#if defined(VGA_x86) +# define VG_REGPARM(n) __attribute__((regparm(n))) +#elif defined(VGA_amd64) || defined(VGA_ppc32) || defined(VGA_ppc64) +# define VG_REGPARM(n) /* */ +#else +# error Unknown arch +#endif + +/* Macro games */ +#define VG_STRINGIFZ(__str) #__str +#define VG_STRINGIFY(__str) VG_STRINGIFZ(__str) + +// Where to send bug reports to. +#define VG_BUGS_TO "www.valgrind.org" + +/* Branch prediction hints. */ +#if HAVE_BUILTIN_EXPECT +# define LIKELY(x) __builtin_expect(!!(x), 1) +# define UNLIKELY(x) __builtin_expect((x), 0) +#else +# define LIKELY(x) (x) +# define UNLIKELY(x) (x) +#endif + + +#endif /* __PUB_TOOL_BASICS_H */ + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_basics_asm.h.svn-base b/include/.svn/text-base/pub_tool_basics_asm.h.svn-base new file mode 100644 index 0000000..201c1b5 --- /dev/null +++ b/include/.svn/text-base/pub_tool_basics_asm.h.svn-base @@ -0,0 +1,58 @@ + +/*--------------------------------------------------------------------*/ +/*--- Header imported directly by every tool asm file. ---*/ +/*--- pub_tool_basics_asm.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_BASICS_ASM_H +#define __PUB_TOOL_BASICS_ASM_H + +// See pub_tool_basics.h for the purpose of these macros. +// +// Note that although the macros here (which are used in asm files) have the +// same name as those in pub_tool_basics.h (which are used in C files), they +// have different definitions. Actually, on Linux the definitions are the +// same, but on Darwin they are different. The reason is that C names on +// Darwin always get a '_' prepended to them by the compiler. But in order to +// refer to them from asm code, we have to add the '_' ourselves. Having two +// versions of these macros makes that difference transparent, so we can use +// VG_/ML_ in both asm and C files. +// +// Note also that the exact prefixes used have to match those used in +// pub_tool_basics.h. + +#define VGAPPEND(str1,str2) str1##str2 + +#define VG_(str) VGAPPEND(vgPlain_, str) +#define ML_(str) VGAPPEND(vgModuleLocal_, str) + +#endif /* __PUB_TOOL_BASICS_ASM_H */ + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_clientstate.h.svn-base b/include/.svn/text-base/pub_tool_clientstate.h.svn-base new file mode 100644 index 0000000..9a47fcc --- /dev/null +++ b/include/.svn/text-base/pub_tool_clientstate.h.svn-base @@ -0,0 +1,70 @@ + +/*--------------------------------------------------------------------*/ +/*--- Misc client state info pub_tool_clientstate.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_CLIENTSTATE_H +#define __PUB_TOOL_CLIENTSTATE_H + +/* Note, this header requires pub_{core,tool}_xarray.h to be + included ahead of it. */ + +// Command line pieces, after they have been extracted from argv in +// m_main.main(). These are all NULL-terminated vectors. + +/* Args for the client. */ +extern XArray* /* of HChar* */ VG_(args_for_client); + +/* Args for V. This is the concatenation of the following: + - contents of ~/.valgrindrc + - contents of $VALGRIND_OPTS + - contents of ./.valgrindrc + - args from the command line + in the stated order. + + Only the last of these is passed onwards to child Valgrinds at + client sys_execve, since the children will re-acquire the first 3 + categories for themselves. Therefore we also record the number of + these no-pass-at-execve arguments -- that is what + VG_(args_for_valgrind_noexecpass) is. */ +extern XArray* /* of HChar* */ VG_(args_for_valgrind); + +/* Number of leading args in VG_(args_for_valgrind) not to pass on at + exec time. */ +extern Int VG_(args_for_valgrind_noexecpass); + +/* The name of the client executable, as specified on the command + line. */ +extern HChar* VG_(args_the_exename); + + +#endif // __PUB_TOOL_CLIENTSTATE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_clreq.h.svn-base b/include/.svn/text-base/pub_tool_clreq.h.svn-base new file mode 100644 index 0000000..f200d12 --- /dev/null +++ b/include/.svn/text-base/pub_tool_clreq.h.svn-base @@ -0,0 +1,40 @@ + +/*--------------------------------------------------------------------*/ +/*--- Client requests. pub_tool_clreq.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_CLREQ_H +#define __PUB_TOOL_CLREQ_H + +#include "valgrind.h" + +#endif // __PUB_TOOL_CLREQ_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_cpuid.h.svn-base b/include/.svn/text-base/pub_tool_cpuid.h.svn-base new file mode 100644 index 0000000..9e994c5 --- /dev/null +++ b/include/.svn/text-base/pub_tool_cpuid.h.svn-base @@ -0,0 +1,46 @@ + +/*--------------------------------------------------------------------*/ +/*--- Interface to CPUID. pub_tool_cpuid.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_CPUID_H +#define __PUB_TOOL_CPUID_H + +#if defined(VGA_x86) || defined(VGA_amd64) +extern Bool VG_(has_cpuid) ( void ); + +extern void VG_(cpuid) ( UInt eax, + UInt* eax_ret, UInt* ebx_ret, + UInt* ecx_ret, UInt* edx_ret ); +#endif + +#endif // __PUB_TOOL_CPUID_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_debuginfo.h.svn-base b/include/.svn/text-base/pub_tool_debuginfo.h.svn-base new file mode 100644 index 0000000..e5ad9f7 --- /dev/null +++ b/include/.svn/text-base/pub_tool_debuginfo.h.svn-base @@ -0,0 +1,236 @@ + +/*--------------------------------------------------------------------*/ +/*--- DebugInfo. pub_tool_debuginfo.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_DEBUGINFO_H +#define __PUB_TOOL_DEBUGINFO_H + +/*====================================================================*/ +/*=== Obtaining debug information ===*/ +/*====================================================================*/ + +/* Get the file/function/line number of the instruction at address + 'a'. For these four, if debug info for the address is found, it + copies the info into the buffer/UInt and returns True. If not, it + returns False and nothing is copied. VG_(get_fnname) always + demangles C++ function names. VG_(get_fnname_w_offset) is the + same, except it appends "+N" to symbol names to indicate offsets. */ +extern Bool VG_(get_filename) ( Addr a, Char* filename, Int n_filename ); +extern Bool VG_(get_fnname) ( Addr a, Char* fnname, Int n_fnname ); +extern Bool VG_(get_linenum) ( Addr a, UInt* linenum ); +extern Bool VG_(get_fnname_w_offset) + ( Addr a, Char* fnname, Int n_fnname ); + +/* This one is the most general. It gives filename, line number and + optionally directory name. filename and linenum may not be NULL. + dirname may be NULL, meaning that the caller does not want + directory name info, in which case dirname_available must also be + NULL. If dirname is non-null, directory info is written to it, if + it is available; if not available, '\0' is written to the first + byte. In either case *dirname_available is set to indicate whether + or not directory information was available. + + Returned value indicates whether any filename/line info could be + found. */ +extern Bool VG_(get_filename_linenum) + ( Addr a, + /*OUT*/Char* filename, Int n_filename, + /*OUT*/Char* dirname, Int n_dirname, + /*OUT*/Bool* dirname_available, + /*OUT*/UInt* linenum ); + +/* Succeeds only if we find from debug info that 'a' is the address of the + first instruction in a function -- as opposed to VG_(get_fnname) which + succeeds if we find from debug info that 'a' is the address of any + instruction in a function. Use this to instrument the start of + a particular function. Nb: if an executable/shared object is stripped + of its symbols, this function will not be able to recognise function + entry points within it. */ +extern Bool VG_(get_fnname_if_entry) ( Addr a, Char* fnname, Int n_fnname ); + +typedef + enum { + Vg_FnNameNormal, // A normal function. + Vg_FnNameMain, // "main" + Vg_FnNameBelowMain // Something below "main", eg. __libc_start_main. + } Vg_FnNameKind; // Such names are often filtered. + +/* Indicates what kind of fnname it is. */ +extern Vg_FnNameKind VG_(get_fnname_kind) ( Char* name ); + +/* Like VG_(get_fnname_kind), but takes a code address. */ +extern Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( Addr ip ); + +/* Looks up data_addr in the collection of data symbols, and if found + puts its name (or as much as will fit) into dname[0 .. n_dname-1], + which is guaranteed to be zero terminated. Also data_addr's offset + from the symbol start is put into *offset. */ +extern Bool VG_(get_datasym_and_offset)( Addr data_addr, + /*OUT*/Char* dname, Int n_dname, + /*OUT*/PtrdiffT* offset ); + +/* Try to form some description of data_addr by looking at the DWARF3 + debug info we have. This considers all global variables, and all + frames in the stacks of all threads. Result (or as much as will + fit) is put into into dname{1,2}[0 .. n_dname-1] and is guaranteed + to be zero terminated. */ +extern Bool VG_(get_data_description)( /*OUT*/Char* dname1, + /*OUT*/Char* dname2, + Int n_dname, + Addr data_addr ); + +/* Succeeds if the address is within a shared object or the main executable. + It doesn't matter if debug info is present or not. */ +extern Bool VG_(get_objname) ( Addr a, Char* objname, Int n_objname ); + +/* Puts into 'buf' info about the code address %eip: the address, function + name (if known) and filename/line number (if known), like this: + + 0x4001BF05: realloc (vg_replace_malloc.c:339) + + 'n_buf' gives length of 'buf'. Returns 'buf'. +*/ +extern Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf); + + +/* Get an XArray of StackBlock which describe the stack (auto) blocks + for this ip. The caller is expected to free the XArray at some + point. If 'arrays_only' is True, only array-typed blocks are + returned; otherwise blocks of all types are returned. */ + +typedef + struct { + PtrdiffT base; /* offset from sp or fp */ + SizeT szB; /* size in bytes */ + Bool spRel; /* True => sp-rel, False => fp-rel */ + Bool isVec; /* does block have an array type, or not? */ + HChar name[16]; /* first 15 chars of name (asciiz) */ + } + StackBlock; + +extern void* /* really, XArray* of StackBlock */ + VG_(di_get_stack_blocks_at_ip)( Addr ip, Bool arrays_only ); + + +/* Get an array of GlobalBlock which describe the global blocks owned + by the shared object characterised by the given di_handle. Asserts + if the handle is invalid. The caller is responsible for freeing + the array at some point. If 'arrays_only' is True, only + array-typed blocks are returned; otherwise blocks of all types are + returned. */ + +typedef + struct { + Addr addr; + SizeT szB; + Bool isVec; /* does block have an array type, or not? */ + HChar name[16]; /* first 15 chars of name (asciiz) */ + HChar soname[16]; /* first 15 chars of name (asciiz) */ + } + GlobalBlock; + +extern void* /* really, XArray* of GlobalBlock */ +VG_(di_get_global_blocks_from_dihandle) ( ULong di_handle, + Bool arrays_only ); + + +/*====================================================================*/ +/*=== Obtaining segment information ===*/ +/*====================================================================*/ + +/* A way to get information about what segments are mapped */ +typedef struct _DebugInfo DebugInfo; + +/* Returns NULL if the DebugInfo isn't found. It doesn't matter if + debug info is present or not. */ +extern DebugInfo* VG_(find_seginfo) ( Addr a ); + +/* Fish bits out of DebugInfos. */ +extern Addr VG_(seginfo_get_text_avma)( const DebugInfo *di ); +extern SizeT VG_(seginfo_get_text_size)( const DebugInfo *di ); +extern Addr VG_(seginfo_get_plt_avma) ( const DebugInfo *di ); +extern SizeT VG_(seginfo_get_plt_size) ( const DebugInfo *di ); +extern Addr VG_(seginfo_get_gotplt_avma)( const DebugInfo *di ); +extern SizeT VG_(seginfo_get_gotplt_size)( const DebugInfo *di ); +extern const UChar* VG_(seginfo_soname) ( const DebugInfo *di ); +extern const UChar* VG_(seginfo_filename) ( const DebugInfo *di ); +extern PtrdiffT VG_(seginfo_get_text_bias)( const DebugInfo *di ); + +/* Function for traversing the seginfo list. When called with NULL it + returns the first element; otherwise it returns the given element's + successor. */ +extern const DebugInfo* VG_(next_seginfo) ( const DebugInfo *di ); + +/* Functions for traversing all the symbols in a DebugInfo. _howmany + tells how many there are. _getidx retrieves the n'th, for n in 0 + .. _howmany-1. You may not modify the function name thereby + acquired; if you want to do so, first strdup it. */ +extern Int VG_(seginfo_syms_howmany) ( const DebugInfo *di ); +extern void VG_(seginfo_syms_getidx) ( const DebugInfo *di, + Int idx, + /*OUT*/Addr* avma, + /*OUT*/Addr* tocptr, + /*OUT*/UInt* size, + /*OUT*/HChar** name, + /*OUT*/Bool* isText ); + +/* A simple enumeration to describe the 'kind' of various kinds of + segments that arise from the mapping of object files. */ +typedef + enum { + Vg_SectUnknown, + Vg_SectText, + Vg_SectData, + Vg_SectBSS, + Vg_SectGOT, + Vg_SectPLT, + Vg_SectGOTPLT, + Vg_SectOPD + } + VgSectKind; + +/* Convert a VgSectKind to a string, which must be copied if you want + to change it. */ +extern +const HChar* VG_(pp_SectKind)( VgSectKind kind ); + +/* Given an address 'a', make a guess of which section of which object + it comes from. If name is non-NULL, then the last n_name-1 + characters of the object's name is put in name[0 .. n_name-2], and + name[n_name-1] is set to zero (guaranteed zero terminated). */ +extern +VgSectKind VG_(seginfo_sect_kind)( /*OUT*/UChar* name, SizeT n_name, + Addr a); + + +#endif // __PUB_TOOL_DEBUGINFO_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_errormgr.h.svn-base b/include/.svn/text-base/pub_tool_errormgr.h.svn-base new file mode 100644 index 0000000..0d22c1b --- /dev/null +++ b/include/.svn/text-base/pub_tool_errormgr.h.svn-base @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------*/ +/*--- ErrorMgr: management of errors and suppressions. ---*/ +/*--- pub_tool_errormgr.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_ERRORMGR_H +#define __PUB_TOOL_ERRORMGR_H + +#include "pub_tool_execontext.h" + +/* ------------------------------------------------------------------ */ +/* Error records contain enough info to generate an error report. The idea + is that (typically) the same few points in the program generate thousands + of errors, and we don't want to spew out a fresh error message for each + one. Instead, we use these structures to common up duplicates. +*/ + +typedef + Int /* Do not make this unsigned! */ + ErrorKind; + +/* The tool-relevant parts of an Error are: + kind: what kind of error; must be in the range (0..) + addr: use is optional. 0 by default. + string: use is optional. NULL by default. + extra: use is optional. NULL by default. void* so it's extensible. +*/ +typedef + struct _Error + Error; + +/* Useful in VG_(tdict).tool_error_matches_suppression(), + * VG_(tdict).tool_pp_Error(), etc */ +ExeContext* VG_(get_error_where) ( Error* err ); +ErrorKind VG_(get_error_kind) ( Error* err ); +Addr VG_(get_error_address) ( Error* err ); +Char* VG_(get_error_string) ( Error* err ); +void* VG_(get_error_extra) ( Error* err ); + +/* Call this when an error occurs. It will be recorded if it hasn't been + seen before. If it has, the existing error record will have its count + incremented. + + 'tid' can be found as for VG_(record_ExeContext)(). The `extra' field can + be stack-allocated; it will be copied by the core if needed (but it + won't be copied if it's NULL). + + If no 'a', 's' or 'extra' of interest needs to be recorded, just use + NULL for them. */ +extern void VG_(maybe_record_error) ( ThreadId tid, ErrorKind ekind, + Addr a, Char* s, void* extra ); + +/* Similar to VG_(maybe_record_error)(), except this one doesn't record the + error -- useful for errors that can only happen once. The errors can be + suppressed, though. Return value is True if it was suppressed. + 'print_error' dictates whether to print the error, which is a bit of a + hack that's useful sometimes if you just want to know if the error would + be suppressed without possibly printing it. 'count_error' dictates + whether to add the error in the error total count (another mild hack). */ +extern Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, + Addr a, Char* s, void* extra, + ExeContext* where, Bool print_error, + Bool allow_GDB_attach, Bool count_error ); + +/* Gets a non-blank, non-comment line of at most nBuf chars from fd. + Skips leading spaces on the line. Returns True if EOF was hit instead. + Useful for reading in extra tool-specific suppression lines. */ +extern Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf ); + + +/* ------------------------------------------------------------------ */ +/* Suppressions describe errors which we want to suppress, ie, not + show the user, usually because it is caused by a problem in a library + which we can't fix, replace or work around. Suppressions are read from + a file at startup time. This gives flexibility so that new + suppressions can be added to the file as and when needed. +*/ +typedef + Int /* Do not make this unsigned! */ + SuppKind; + +/* The tool-relevant parts of a suppression are: + kind: what kind of suppression; must be in the range (0..) + string: use is optional. NULL by default. + extra: use is optional. NULL by default. void* so it's extensible. +*/ +typedef + struct _Supp + Supp; + +/* Useful in VG_(tdict).tool_error_matches_suppression() */ +SuppKind VG_(get_supp_kind) ( Supp* su ); +Char* VG_(get_supp_string) ( Supp* su ); +void* VG_(get_supp_extra) ( Supp* su ); + +/* Must be used in VG_(recognised_suppression)() */ +void VG_(set_supp_kind) ( Supp* su, SuppKind suppkind ); +/* May be used in VG_(read_extra_suppression_info)() */ +void VG_(set_supp_string) ( Supp* su, Char* string ); +void VG_(set_supp_extra) ( Supp* su, void* extra ); + + +#endif // __PUB_TOOL_ERRORMGR_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_execontext.h.svn-base b/include/.svn/text-base/pub_tool_execontext.h.svn-base new file mode 100644 index 0000000..3506026 --- /dev/null +++ b/include/.svn/text-base/pub_tool_execontext.h.svn-base @@ -0,0 +1,117 @@ +/*--------------------------------------------------------------------*/ +/*--- ExeContexts: long-lived stack traces. pub_tool_execontext.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_EXECONTEXT_H +#define __PUB_TOOL_EXECONTEXT_H + +// It's an abstract type. +typedef + struct _ExeContext + ExeContext; + +// Resolution type used to decide how closely to compare two errors for +// equality. +typedef + enum { Vg_LowRes, Vg_MedRes, Vg_HighRes } + VgRes; + +// Take a snapshot of the client's stack. Search our collection of +// ExeContexts to see if we already have it, and if not, allocate a +// new one. Either way, return a pointer to the context. Context size +// controlled by --num-callers option. +// +// This should only be used for long-lived stack traces. If you want a +// short-lived stack trace, use VG_(get_StackTrace)(). +// +// If called from generated code, use VG_(get_running_tid)() to get the +// current ThreadId. If called from non-generated code, the current +// ThreadId should be passed in by the core. The initial IP value to +// use is adjusted by first_ip_delta before the stack is unwound. +// A safe value to pass is zero. +// +// See comments in pub_tool_stacktrace.h for precise definition of +// the meaning of the code addresses in the returned ExeContext. +extern +ExeContext* VG_(record_ExeContext) ( ThreadId tid, Word first_ip_delta ); + +// Trivial version of VG_(record_ExeContext), which just records the +// thread's current program counter but does not do any stack +// unwinding. This is useful in some rare cases when we suspect the +// stack might be outside mapped storage, and so unwinding +// might cause a segfault. In this case we can at least safely +// produce a one-element stack trace, which is better than nothing. +extern +ExeContext* VG_(record_depth_1_ExeContext)( ThreadId tid ); + +// Apply a function to every element in the ExeContext. The parameter 'n' +// gives the index of the passed ip. Doesn't go below main() unless +// --show-below-main=yes is set. +extern void VG_(apply_ExeContext)( void(*action)(UInt n, Addr ip), + ExeContext* ec, UInt n_ips ); + +// Compare two ExeContexts. Number of callers considered depends on `res': +// Vg_LowRes: 2 +// Vg_MedRes: 4 +// Vg_HighRes: all +extern Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 ); + +// Print an ExeContext. +extern void VG_(pp_ExeContext) ( ExeContext* ec ); + +// Get the 32-bit unique reference number for this ExeContext +// (the "ExeContext Unique"). Guaranteed to be nonzero and to be a +// multiple of four (iow, the lowest two bits are guaranteed to +// be zero, so that callers can store other information there. +extern UInt VG_(get_ECU_from_ExeContext)( ExeContext* e ); + +// How many entries (frames) in this ExeContext? +extern Int VG_(get_ExeContext_n_ips)( ExeContext* e ); + +// Find the ExeContext that has the given ECU, if any. +// NOTE: very slow. Do not call often. +extern ExeContext* VG_(get_ExeContext_from_ECU)( UInt uniq ); + +// Make an ExeContext containing just 'a', and nothing else +ExeContext* VG_(make_depth_1_ExeContext_from_Addr)( Addr a ); + +// Is this a plausible-looking ECU ? Catches some obvious stupid +// cases, but does not guarantee that the ECU is really valid, that +// is, has an associated ExeContext. +static inline Bool VG_(is_plausible_ECU)( UInt ecu ) { + return (ecu > 0) && ((ecu & 3) == 0); +} + +// Make an ExeContext containing exactly the specified stack frames. +ExeContext* VG_(make_ExeContext_from_StackTrace)( Addr* ips, UInt n_ips ); + +#endif // __PUB_TOOL_EXECONTEXT_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_hashtable.h.svn-base b/include/.svn/text-base/pub_tool_hashtable.h.svn-base new file mode 100644 index 0000000..6348799 --- /dev/null +++ b/include/.svn/text-base/pub_tool_hashtable.h.svn-base @@ -0,0 +1,100 @@ + +/*--------------------------------------------------------------------*/ +/*--- A hash table implementation. pub_tool_hashtable.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2005-2009 Nicholas Nethercote + njn@valgrind.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_HASHTABLE_H +#define __PUB_TOOL_HASHTABLE_H + +/* Generic type for a separately-chained hash table. Via a kind of dodgy + C-as-C++ style inheritance, tools can extend the VgHashNode type, so long + as the first two fields match the sizes of these two fields. Requires + a bit of casting by the tool. */ + +// Problems with this data structure: +// - Separate chaining gives bad cache behaviour. Hash tables with linear +// probing give better cache behaviour. + +typedef + struct _VgHashNode { + struct _VgHashNode * next; + UWord key; + } + VgHashNode; + +typedef struct _VgHashTable * VgHashTable; + +/* Make a new table. Allocates the memory with VG_(calloc)(), so can + be freed with VG_(free)(). The table starts small but will + periodically be expanded. This is transparent to the users of this + module. */ +extern VgHashTable VG_(HT_construct) ( HChar* name ); + +/* Count the number of nodes in a table. */ +extern Int VG_(HT_count_nodes) ( VgHashTable table ); + +/* Add a node to the table. */ +extern void VG_(HT_add_node) ( VgHashTable t, void* node ); + +/* Looks up a VgHashNode in the table. Returns NULL if not found. */ +extern void* VG_(HT_lookup) ( VgHashTable table, UWord key ); + +/* Removes a VgHashNode from the table. Returns NULL if not found. */ +extern void* VG_(HT_remove) ( VgHashTable table, UWord key ); + +/* Allocates a suitably-sized array, copies all the hashtable elements + into it, then returns both the array and the size of it. This is + used by the memory-leak detector. The array must be freed with + VG_(free). */ +extern VgHashNode** VG_(HT_to_array) ( VgHashTable t, /*OUT*/ UInt* n_elems ); + +/* Reset the table's iterator to point to the first element. */ +extern void VG_(HT_ResetIter) ( VgHashTable table ); + +/* Return the element pointed to by the iterator and move on to the + next one. Returns NULL if the last one has been passed, or if + HT_ResetIter() has not been called previously. Asserts if the + table has been modified (HT_add_node, HT_remove) since + HT_ResetIter. This guarantees that callers cannot screw up by + modifying the table whilst iterating over it (and is necessary to + make the implementation safe; specifically we must guarantee that + the table will not get resized whilst iteration is happening. + Since resizing only happens as a result of calling HT_add_node, + disallowing HT_add_node during iteration should give the required + assurance. */ +extern void* VG_(HT_Next) ( VgHashTable table ); + +/* Destroy a table. */ +extern void VG_(HT_destruct) ( VgHashTable t ); + + +#endif // __PUB_TOOL_HASHTABLE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_libcassert.h.svn-base b/include/.svn/text-base/pub_tool_libcassert.h.svn-base new file mode 100644 index 0000000..6e4f69a --- /dev/null +++ b/include/.svn/text-base/pub_tool_libcassert.h.svn-base @@ -0,0 +1,64 @@ + +/*--------------------------------------------------------------------*/ +/*--- Assertions, etc. pub_tool_libcassert.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_LIBCBASSERT_H +#define __PUB_TOOL_LIBCBASSERT_H + +#define tl_assert(expr) \ + ((void) ((expr) ? 0 : \ + (VG_(assert_fail) (/*isCore?*/False, #expr, \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + ""), \ + 0))) + +#define tl_assert2(expr, format, args...) \ + ((void) ((expr) ? 0 : \ + (VG_(assert_fail) (/*isCore?*/False, #expr, \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + format, ##args), \ + 0))) + +__attribute__ ((__noreturn__)) +extern void VG_(exit)( Int status ); + +/* Prints a panic message, appends newline and bug reporting info, aborts. */ +__attribute__ ((__noreturn__)) +extern void VG_(tool_panic) ( Char* str ); + +__attribute__ ((__noreturn__)) +extern void VG_(assert_fail) ( Bool isCore, const Char* expr, const Char* file, + Int line, const Char* fn, + const HChar* format, ... ); + +#endif // __PUB_TOOL_LIBCBASSERT_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_libcbase.h.svn-base b/include/.svn/text-base/pub_tool_libcbase.h.svn-base new file mode 100644 index 0000000..4e627be --- /dev/null +++ b/include/.svn/text-base/pub_tool_libcbase.h.svn-base @@ -0,0 +1,151 @@ + +/*--------------------------------------------------------------------*/ +/*--- Standalone libc stuff. pub_tool_libcbase.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_LIBCBASE_H +#define __PUB_TOOL_LIBCBASE_H + +/* --------------------------------------------------------------------- + Char functions. + ------------------------------------------------------------------ */ + +extern Bool VG_(isspace) ( Char c ); +extern Bool VG_(isdigit) ( Char c ); + +/* --------------------------------------------------------------------- + Converting strings to numbers + ------------------------------------------------------------------ */ + +// Convert strings to numbers according to various bases. Leading +// whitespace is ignored. A subsequent '-' or '+' is accepted. For strtoll16, +// accepts an initial "0x" or "0X" prefix, but only if it's followed by a +// hex digit (if not, the '0' will be read and then it will stop on the +// "x"/"X".) If 'endptr' isn't NULL, it gets filled in with the first +// non-digit char. Returns 0 if no number could be converted, and 'endptr' +// is set to the start of the string. None of them test that the number +// fits into 64 bits. +// +// Nb: if you're wondering why we don't just have a single VG_(strtoll) which +// takes a base, it's because I wanted it to assert if it was given a bogus +// base (the standard glibc one sets 'errno' in this case). But +// m_libcbase.c doesn't import any code, not even vg_assert. --njn +// +// Nb: we also don't provide VG_(atoll*); these functions are worse than +// useless because they don't do any error checking and so accept malformed +// numbers and non-numbers -- eg. "123xyz" gives 123, and "foo" gives 0! +// If you really want that behaviour, you can use "VG_(strtoll10)(str, NULL)". +extern Long VG_(strtoll10) ( Char* str, Char** endptr ); +extern Long VG_(strtoll16) ( Char* str, Char** endptr ); + +// Convert a string to a double. After leading whitespace is ignored, a +// '+' or '-' is allowed, and then it accepts a non-empty sequence of +// decimal digits possibly containing a '.'. Hexadecimal floats are not +// accepted, nor are "fancy" floats (eg. "3.4e-5", "NAN"). +extern double VG_(strtod) ( Char* str, Char** endptr ); + +/* --------------------------------------------------------------------- + String functions and macros + ------------------------------------------------------------------ */ + +/* Use this for normal null-termination-style string comparison. */ +#define VG_STREQ(s1,s2) ( (s1 != NULL && s2 != NULL \ + && VG_(strcmp)((s1),(s2))==0) ? True : False ) +#define VG_STREQN(n,s1,s2) ( (s1 != NULL && s2 != NULL \ + && VG_(strncmp)((s1),(s2),(n))==0) ? True : False ) + +extern SizeT VG_(strlen) ( const Char* str ); +extern Char* VG_(strcat) ( Char* dest, const Char* src ); +extern Char* VG_(strncat) ( Char* dest, const Char* src, SizeT n ); +extern Char* VG_(strpbrk) ( const Char* s, const Char* accpt ); +extern Char* VG_(strcpy) ( Char* dest, const Char* src ); +extern Char* VG_(strncpy) ( Char* dest, const Char* src, SizeT ndest ); +extern Int VG_(strcmp) ( const Char* s1, const Char* s2 ); +extern Int VG_(strncmp) ( const Char* s1, const Char* s2, SizeT nmax ); +extern Char* VG_(strstr) ( const Char* haystack, Char* needle ); +extern Char* VG_(strchr) ( const Char* s, Char c ); +extern Char* VG_(strrchr) ( const Char* s, Char c ); +extern SizeT VG_(strspn) ( const Char* s, const Char* accept ); +extern SizeT VG_(strcspn) ( const Char* s, const char* reject ); + +/* Like strncpy(), but if 'src' is longer than 'ndest' inserts a '\0' as the + last character. */ +extern void VG_(strncpy_safely) ( Char* dest, const Char* src, SizeT ndest ); + +/* --------------------------------------------------------------------- + mem* functions + ------------------------------------------------------------------ */ + +extern void* VG_(memcpy) ( void *d, const void *s, SizeT sz ); +extern void* VG_(memmove)( void *d, const void *s, SizeT sz ); +extern void* VG_(memset) ( void *s, Int c, SizeT sz ); +extern Int VG_(memcmp) ( const void* s1, const void* s2, SizeT n ); + +/* --------------------------------------------------------------------- + Address computation helpers + ------------------------------------------------------------------ */ + +// Check if an address/whatever is aligned +#define VG_IS_2_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)0x1))) +#define VG_IS_4_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)0x3))) +#define VG_IS_8_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)0x7))) +#define VG_IS_16_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)0xf))) +#define VG_IS_WORD_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)(sizeof(Addr)-1)))) +#define VG_IS_PAGE_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)(VKI_PAGE_SIZE-1)))) + +// 'a' -- the alignment -- must be a power of 2. +// The latter two require the vki-*.h header to be imported also. +#define VG_ROUNDDN(p, a) ((Addr)(p) & ~((Addr)(a)-1)) +#define VG_ROUNDUP(p, a) VG_ROUNDDN((p)+(a)-1, (a)) +#define VG_PGROUNDDN(p) VG_ROUNDDN(p, VKI_PAGE_SIZE) +#define VG_PGROUNDUP(p) VG_ROUNDUP(p, VKI_PAGE_SIZE) + +/* --------------------------------------------------------------------- + Misc useful functions + ------------------------------------------------------------------ */ + +/* Like qsort(). The name VG_(ssort) is for historical reasons -- it used + * to be a shell sort, but is now a quicksort. */ +extern void VG_(ssort)( void* base, SizeT nmemb, SizeT size, + Int (*compar)(void*, void*) ); + +/* Returns the base-2 logarithm of x. Returns -1 if x is not a power + of two. Nb: VG_(log2)(1) == 0. */ +extern Int VG_(log2) ( UInt x ); + +// A pseudo-random number generator returning a random UInt. If pSeed +// is NULL, it uses its own seed, which starts at zero. If pSeed is +// non-NULL, it uses and updates whatever pSeed points at. +extern UInt VG_(random) ( /*MOD*/UInt* pSeed ); +#define VG_RAND_MAX (1ULL << 32) + +#endif // __PUB_TOOL_LIBCBASE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_libcfile.h.svn-base b/include/.svn/text-base/pub_tool_libcfile.h.svn-base new file mode 100644 index 0000000..f870109 --- /dev/null +++ b/include/.svn/text-base/pub_tool_libcfile.h.svn-base @@ -0,0 +1,91 @@ + +/*--------------------------------------------------------------------*/ +/*--- File/socket-related libc stuff. pub_tool_libcfile.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_LIBCFILE_H +#define __PUB_TOOL_LIBCFILE_H + +/* --------------------------------------------------------------------- + File-related functions. + ------------------------------------------------------------------ */ + +/* To use this file you must first include pub_tool_vki.h. */ + +/* Note that VG_(stat) and VG_(fstat) write to a 'struct vg_stat*' and + not a 'struct vki_stat*' or a 'struct vki_stat64*'. 'struct + vg_stat*' is not the same as either of the vki_ versions. No + specific vki_stat{,64} kernel structure will work and is + consistently available on different architectures on Linux, so we + have to use this 'struct vg_stat' impedance-matching type + instead. */ +struct vg_stat { + ULong st_dev; + ULong st_ino; + ULong st_nlink; + UInt st_mode; + UInt st_uid; + UInt st_gid; + ULong st_rdev; + Long st_size; + ULong st_blksize; + ULong st_blocks; + ULong st_atime; + ULong st_atime_nsec; + ULong st_mtime; + ULong st_mtime_nsec; + ULong st_ctime; + ULong st_ctime_nsec; +}; + +extern SysRes VG_(open) ( const Char* pathname, Int flags, Int mode ); +extern void VG_(close) ( Int fd ); +extern Int VG_(read) ( Int fd, void* buf, Int count); +extern Int VG_(write) ( Int fd, const void* buf, Int count); +extern Int VG_(pipe) ( Int fd[2] ); +extern OffT VG_(lseek) ( Int fd, OffT offset, Int whence ); + +extern SysRes VG_(stat) ( Char* file_name, struct vg_stat* buf ); +extern Int VG_(fstat) ( Int fd, struct vg_stat* buf ); +extern SysRes VG_(dup) ( Int oldfd ); +extern SysRes VG_(dup2) ( Int oldfd, Int newfd ); +extern Int VG_(rename) ( Char* old_name, Char* new_name ); +extern Int VG_(unlink) ( Char* file_name ); + +extern Int VG_(readlink)( Char* path, Char* buf, UInt bufsize ); +extern Int VG_(getdents)( UInt fd, struct vki_dirent *dirp, UInt count ); + +/* Copy the working directory at startup into buf[0 .. size-1], or return + False if buf is too small. */ +extern Bool VG_(get_startup_wd) ( Char* buf, SizeT size ); + +#endif // __PUB_TOOL_LIBCFILE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_libcprint.h.svn-base b/include/.svn/text-base/pub_tool_libcprint.h.svn-base new file mode 100644 index 0000000..b3386b2 --- /dev/null +++ b/include/.svn/text-base/pub_tool_libcprint.h.svn-base @@ -0,0 +1,111 @@ + +/*--------------------------------------------------------------------*/ +/*--- Printing libc stuff. pub_tool_libcprint.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_LIBCPRINT_H +#define __PUB_TOOL_LIBCPRINT_H + + +/* Enable compile-time format string checking by gcc. + This feature is supported since at least gcc version 2.95. + For more information about the format attribute, see also + http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html. + */ + +#if defined(__GNUC__) +#define PRINTF_CHECK(x, y) __attribute__((format(__printf__, x, y))) +#else +#define PRINTF_CHECK(x, y) +#endif + + +/* --------------------------------------------------------------------- + Basic printing + ------------------------------------------------------------------ */ + +/* Note that they all output to the file descriptor given by the + * --log-fd/--log-file/--log-socket argument, which defaults to 2 (stderr). + * Hence no need for VG_(fprintf)(). + */ +extern UInt VG_(printf) ( const HChar *format, ... ) PRINTF_CHECK(1, 2); +extern UInt VG_(vprintf) ( const HChar *format, va_list vargs ) PRINTF_CHECK(1, 0); +extern UInt VG_(sprintf) ( Char* buf, const HChar* format, ... ) PRINTF_CHECK(2, 3); +extern UInt VG_(vsprintf) ( Char* buf, const HChar* format, va_list vargs ) PRINTF_CHECK(2, 0); +extern UInt VG_(snprintf) ( Char* buf, Int size, + const HChar *format, ... ) PRINTF_CHECK(3, 4); +extern UInt VG_(vsnprintf)( Char* buf, Int size, + const HChar *format, va_list vargs ) PRINTF_CHECK(3, 0); + +// Percentify n/m with d decimal places. Includes the '%' symbol at the end. +// Right justifies in 'buf'. +extern void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[]); + +/* --------------------------------------------------------------------- + Messages for the user + ------------------------------------------------------------------ */ + +/* No, really. I _am_ that strange. */ +#define OINK(nnn) VG_(message)(Vg_DebugMsg, "OINK %d",nnn) + +/* Print a message prefixed by "??<pid>?? "; '?' depends on the VgMsgKind. + Should be used for all user output. */ + +typedef + enum { Vg_UserMsg, /* '?' == '=' */ + Vg_DebugMsg, /* '?' == '-' */ + Vg_DebugExtraMsg, /* '?' == '+' */ + Vg_ClientMsg /* '?' == '*' */ + } + VgMsgKind; + +/* Send a single-part message. Appends a newline. The format + specification may contain any ISO C format specifier or %t. + No attempt is made to let the compiler verify consistency of the + format string and the argument list. */ +extern UInt VG_(message_no_f_c)( VgMsgKind kind, const HChar* format, ... ); +/* Send a single-part message. Appends a newline. The format + specification may contain any ISO C format specifier. The gcc compiler + will verify consistency of the format string and the argument list. */ +extern UInt VG_(message)( VgMsgKind kind, const HChar* format, ... ) + PRINTF_CHECK(2, 3); + +extern UInt VG_(vmessage)( VgMsgKind kind, const HChar* format, va_list vargs ) + PRINTF_CHECK(2, 0); + +// Short-cuts for VG_(message)(). +#define VG_UMSG( format, args... ) VG_(message)(Vg_UserMsg, format, ##args) +#define VG_DMSG( format, args... ) VG_(message)(Vg_DebugMsg, format, ##args) +#define VG_EMSG( format, args... ) VG_(message)(Vg_DebugExtraMsg, \ + format, ##args) + +#endif // __PUB_TOOL_LIBCPRINT_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_libcproc.h.svn-base b/include/.svn/text-base/pub_tool_libcproc.h.svn-base new file mode 100644 index 0000000..cd668b1 --- /dev/null +++ b/include/.svn/text-base/pub_tool_libcproc.h.svn-base @@ -0,0 +1,95 @@ + +/*--------------------------------------------------------------------*/ +/*--- Process-related libc stuff pub_tool_libcproc.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_LIBCPROC_H +#define __PUB_TOOL_LIBCPROC_H + +/* --------------------------------------------------------------------- + Command-line and environment stuff + ------------------------------------------------------------------ */ + +/* Client environment. */ +extern Char** VG_(client_envp); + +/* Looks up VG_(client_envp) */ +extern Char* VG_(getenv) ( Char* name ); + +/* Path to all our library/aux files */ +extern const Char *VG_(libdir); + +/* --------------------------------------------------------------------- + Important syscalls + ------------------------------------------------------------------ */ + +extern Int VG_(waitpid)( Int pid, Int *status, Int options ); +extern Int VG_(system) ( Char* cmd ); +extern Int VG_(fork) ( void); +extern void VG_(execv) ( Char* filename, Char** argv ); + +/* --------------------------------------------------------------------- + Resource limits + ------------------------------------------------------------------ */ + +extern Int VG_(getrlimit) ( Int resource, struct vki_rlimit *rlim ); +extern Int VG_(setrlimit) ( Int resource, const struct vki_rlimit *rlim ); + +/* --------------------------------------------------------------------- + pids, etc + ------------------------------------------------------------------ */ + +extern Int VG_(gettid) ( void ); +extern Int VG_(getpid) ( void ); +extern Int VG_(getppid) ( void ); +extern Int VG_(getpgrp) ( void ); +extern Int VG_(geteuid) ( void ); +extern Int VG_(getegid) ( void ); + +/* --------------------------------------------------------------------- + Timing + ------------------------------------------------------------------ */ + +// Returns the number of milliseconds passed since the progam started +// (roughly; it gets initialised partway through Valgrind's initialisation +// steps). +extern UInt VG_(read_millisecond_timer) ( void ); + +/* --------------------------------------------------------------------- + atfork + ------------------------------------------------------------------ */ + +typedef void (*vg_atfork_t)(ThreadId); +extern void VG_(atfork)(vg_atfork_t pre, vg_atfork_t parent, vg_atfork_t child); + + +#endif // __PUB_TOOL_LIBCPROC_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_libcsignal.h.svn-base b/include/.svn/text-base/pub_tool_libcsignal.h.svn-base new file mode 100644 index 0000000..d8aa0f5 --- /dev/null +++ b/include/.svn/text-base/pub_tool_libcsignal.h.svn-base @@ -0,0 +1,47 @@ + +/*--------------------------------------------------------------------*/ +/*--- Signal-related libc stuff. pub_tool_libcsignal.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_LIBCBSIGNAL_H +#define __PUB_TOOL_LIBCBSIGNAL_H + +/* Note that these use the vki_ (kernel) structure + definitions, which are different in places from those that glibc + defines. Since we're operating right at the kernel interface, glibc's view + of the world is entirely irrelevant. */ + +/* --- Mess with the kernel's sig state --- */ +extern Int VG_(sigprocmask) ( Int how, const vki_sigset_t* set, + vki_sigset_t* oldset ); + +#endif // __PUB_TOOL_LIBCBSIGNAL_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_machine.h.svn-base b/include/.svn/text-base/pub_tool_machine.h.svn-base new file mode 100644 index 0000000..7301d51 --- /dev/null +++ b/include/.svn/text-base/pub_tool_machine.h.svn-base @@ -0,0 +1,137 @@ + +/*--------------------------------------------------------------------*/ +/*--- Machine-related stuff. pub_tool_machine.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_MACHINE_H +#define __PUB_TOOL_MACHINE_H + +#if defined(VGP_x86_linux) +# define VG_MIN_INSTR_SZB 1 // min length of native instruction +# define VG_MAX_INSTR_SZB 16 // max length of native instruction +# define VG_CLREQ_SZB 14 // length of a client request, may + // be larger than VG_MAX_INSTR_SZB +# define VG_STACK_REDZONE_SZB 0 // number of addressable bytes below %RSP +#elif defined(VGP_amd64_linux) +# define VG_MIN_INSTR_SZB 1 +# define VG_MAX_INSTR_SZB 16 +# define VG_CLREQ_SZB 19 +# define VG_STACK_REDZONE_SZB 128 +#elif defined(VGP_ppc32_linux) +# define VG_MIN_INSTR_SZB 4 +# define VG_MAX_INSTR_SZB 4 +# define VG_CLREQ_SZB 20 +# define VG_STACK_REDZONE_SZB 0 +#elif defined(VGP_ppc64_linux) +# define VG_MIN_INSTR_SZB 4 +# define VG_MAX_INSTR_SZB 4 +# define VG_CLREQ_SZB 20 +# define VG_STACK_REDZONE_SZB 288 // number of addressable bytes below R1 + // from 64-bit PowerPC ELF ABI Supplement 1.7 +#elif defined(VGP_ppc32_aix5) +# define VG_MIN_INSTR_SZB 4 +# define VG_MAX_INSTR_SZB 4 +# define VG_CLREQ_SZB 20 + /* The PowerOpen ABI actually says 220 bytes, but that is not an + 8-aligned number, and frequently forces Memcheck's + mc_{new,die}_mem_stack_N routines into slow cases by losing + 8-alignment of the area to be messed with. So let's just say + 224 instead. Gdb has a similar kludge. */ +# define VG_STACK_REDZONE_SZB 224 +#elif defined(VGP_ppc64_aix5) +# define VG_MIN_INSTR_SZB 4 +# define VG_MAX_INSTR_SZB 4 +# define VG_CLREQ_SZB 20 +# define VG_STACK_REDZONE_SZB 288 // is this right? +#else +# error Unknown platform +#endif + +// Guest state accessors +extern Addr VG_(get_SP) ( ThreadId tid ); +extern Addr VG_(get_IP) ( ThreadId tid ); +extern Addr VG_(get_FP) ( ThreadId tid ); +extern Addr VG_(get_LR) ( ThreadId tid ); + +extern void VG_(set_SP) ( ThreadId tid, Addr sp ); +extern void VG_(set_IP) ( ThreadId tid, Addr ip ); + +// For get/set, 'area' is where the asked-for guest state will be copied +// into/from. If shadowNo == 0, the real (non-shadow) guest state is +// accessed. If shadowNo == 1, the first shadow area is accessed, and +// if shadowNo == 2, the second shadow area is accessed. This gives a +// completely general way to read/modify a thread's guest register state +// providing you know the offsets you need. +void +VG_(get_shadow_regs_area) ( ThreadId tid, + /*DST*/UChar* dst, + /*SRC*/Int shadowNo, PtrdiffT offset, SizeT size ); +void +VG_(set_shadow_regs_area) ( ThreadId tid, + /*DST*/Int shadowNo, PtrdiffT offset, SizeT size, + /*SRC*/const UChar* src ); + +// Sets the shadow values for the syscall return value register(s). +// This is platform specific. +void VG_(set_syscall_return_shadows) ( ThreadId tid, + /* shadow vals for the result */ + UWord s1res, UWord s2res, + /* shadow vals for the error val */ + UWord s1err, UWord s2err ); + +// Apply a function 'f' to all the general purpose registers in all the +// current threads. +// This is very Memcheck-specific -- it's used to find the roots when +// doing leak checking. +extern void VG_(apply_to_GP_regs)(void (*f)(UWord val)); + +// This iterator lets you inspect each live thread's stack bounds. +// Returns False at the end. 'tid' is the iterator and you can only +// safely change it by making calls to these functions. +extern void VG_(thread_stack_reset_iter) ( /*OUT*/ThreadId* tid ); +extern Bool VG_(thread_stack_next) ( /*MOD*/ThreadId* tid, + /*OUT*/Addr* stack_min, + /*OUT*/Addr* stack_max ); + +// Returns .client_stack_highest_word for the given thread +extern Addr VG_(thread_get_stack_max) ( ThreadId tid ); + +// Returns how many bytes have been allocated for the stack of the given thread +extern Addr VG_(thread_get_stack_size) ( ThreadId tid ); + +// Given a pointer to a function as obtained by "& functionname" in C, +// produce a pointer to the actual entry point for the function. For +// most platforms it's the identity function. Unfortunately, on +// ppc64-linux it isn't (sigh). +extern void* VG_(fnptr_to_fnentry)( void* ); + +#endif // __PUB_TOOL_MACHINE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_mallocfree.h.svn-base b/include/.svn/text-base/pub_tool_mallocfree.h.svn-base new file mode 100644 index 0000000..efab2c2 --- /dev/null +++ b/include/.svn/text-base/pub_tool_mallocfree.h.svn-base @@ -0,0 +1,58 @@ + +/*--------------------------------------------------------------------*/ +/*--- MallocFree: high-level memory management. ---*/ +/*--- pub_tool_mallocfree.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_MALLOCFREE_H +#define __PUB_TOOL_MALLOCFREE_H + +// These can be for allocating memory used by tools. +// Nb: the allocators *always succeed* -- they never return NULL (Valgrind +// will abort if they can't allocate the memory). +extern void* VG_(malloc) ( HChar* cc, SizeT nbytes ); +extern void VG_(free) ( void* p ); +extern void* VG_(calloc) ( HChar* cc, SizeT n, SizeT bytes_per_elem ); +extern void* VG_(realloc) ( HChar* cc, void* p, SizeT size ); +extern Char* VG_(strdup) ( HChar* cc, const Char* s ); + +// Returns the usable size of a heap-block. It's the asked-for size plus +// possibly some more due to rounding up. +extern SizeT VG_(malloc_usable_size)( void* p ); + +// TODO: move somewhere else +// Call here to bomb the system when out of memory (mmap anon fails) +__attribute__((noreturn)) +extern void VG_(out_of_memory_NORETURN) ( HChar* who, SizeT szB ); + +#endif // __PUB_TOOL_MALLOCFREE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ + diff --git a/include/.svn/text-base/pub_tool_options.h.svn-base b/include/.svn/text-base/pub_tool_options.h.svn-base new file mode 100644 index 0000000..cab2101 --- /dev/null +++ b/include/.svn/text-base/pub_tool_options.h.svn-base @@ -0,0 +1,198 @@ + +/*--------------------------------------------------------------------*/ +/*--- Command line options. pub_tool_options.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_OPTIONS_H +#define __PUB_TOOL_OPTIONS_H + +#include "libvex.h" // for VexControl + + +// Higher-level command-line option recognisers; use in if/else chains. +// Note that they assign a value to the 'qq_var' argument. So often they +// can be used like this: +// +// if VG_STR_CLO(arg, "--foo", clo_foo) { } +// +// But if you want to do further checking or processing, you can do this: +// +// if VG_STR_CLO(arg, "--foo", clo_foo) { <further checking or processing> } +// +// They use GNU statement expressions to do the qq_var assignment within a +// conditional expression. + +// String argument, eg. --foo=yes or --foo=no +#define VG_BOOL_CLO(qq_arg, qq_option, qq_var) \ + (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ + ({ \ + Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + if VG_STREQ(val, "yes") (qq_var) = True; \ + else if VG_STREQ(val, "no") (qq_var) = False; \ + True; \ + }) \ + ) + +// String argument, eg. --foo=bar +#define VG_STR_CLO(qq_arg, qq_option, qq_var) \ + (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ + ({ \ + Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + (qq_var) = val; \ + True; \ + }) \ + ) + +// Unbounded integer arg, eg. --foo=10 +#define VG_INT_CLO(qq_arg, qq_option, qq_var) \ + (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ + ({ \ + Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + Char* s; \ + Long n = VG_(strtoll10)( val, &s ); \ + (qq_var) = n; \ + /* Check for non-numeralness, or overflow. */ \ + if ('\0' != s[0] || (qq_var) != n) VG_(err_bad_option)(qq_arg); \ + True; \ + }) \ + ) + +// Bounded integer arg, eg. --foo=10 ; if the value exceeds the bounds it +// causes an abort. 'qq_base' can be 10 or 16. +#define VG_BINTN_CLO(qq_base, qq_arg, qq_option, qq_var, qq_lo, qq_hi) \ + (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ + ({ \ + Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + Char* s; \ + Long n = VG_(strtoll##qq_base)( val, &s ); \ + (qq_var) = n; \ + /* Check for non-numeralness, or overflow. */ \ + /* Nb: it will overflow if qq_var is unsigned and qq_val is negative! */ \ + if ('\0' != s[0] || (qq_var) != n) VG_(err_bad_option)(qq_arg); \ + /* Check bounds. */ \ + if ((qq_var) < (qq_lo) || (qq_var) > (qq_hi)) { \ + VG_(message)(Vg_UserMsg, \ + "'%s' argument must be between %lld and %lld", \ + (qq_option), (Long)(qq_lo), (Long)(qq_hi)); \ + VG_(err_bad_option)(qq_arg); \ + } \ + True; \ + }) \ + ) + +// Bounded decimal integer arg, eg. --foo=100 +#define VG_BINT_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \ + VG_BINTN_CLO(10, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi)) + +// Bounded hexadecimal integer arg, eg. --foo=0x1fa8 +#define VG_BHEX_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \ + VG_BINTN_CLO(16, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi)) + +// Double (decimal) arg, eg. --foo=4.6 +// XXX: there's not VG_BDBL_CLO because we don't have a good way of printing +// floats at the moment! +#define VG_DBL_CLO(qq_arg, qq_option, qq_var) \ + (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ + ({ \ + Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + Char* s; \ + double n = VG_(strtod)( val, &s ); \ + (qq_var) = n; \ + /* Check for non-numeralness */ \ + if ('\0' != s[0]) VG_(err_bad_option)(qq_arg); \ + True; \ + }) \ + ) + +// Arg whose value is denoted by the exact presence of the given string; +// if it matches, qq_var is assigned the value in qq_val. +#define VG_XACT_CLO(qq_arg, qq_option, qq_var, qq_val) \ + (VG_STREQ((qq_arg), (qq_option)) && \ + ({ \ + (qq_var) = (qq_val); \ + True; \ + }) \ + ) + +/* Verbosity level: 0 = silent, 1 (default), > 1 = more verbose. */ +extern Int VG_(clo_verbosity); + +/* Emit all messages as XML? default: NO */ +/* If clo_xml is set, various other options are set in a non-default + way. See vg_main.c and mc_main.c. */ +extern Bool VG_(clo_xml); + +/* An arbitrary user-supplied string which is copied into the + XML output, in between <usercomment> tags. */ +extern HChar* VG_(clo_xml_user_comment); + +/* Vex iropt control. Tool-visible so tools can make Vex optimise + less aggressively if that is needed (callgrind needs this). */ +extern VexControl VG_(clo_vex_control); + +/* Number of parents of a backtrace. Default: 8. */ +extern Int VG_(clo_backtrace_size); + +/* Continue stack traces below main()? Default: NO */ +extern Bool VG_(clo_show_below_main); + + +/* Call this if a recognised option was bad for some reason. Note: + don't use it just because an option was unrecognised -- return + 'False' from VG_(tdict).tool_process_cmd_line_option) to indicate that -- + use it if eg. an option was given an inappropriate argument. + This function prints an error message, then shuts down the entire system. + It returns a Bool so it can be used in the _CLO_ macros. */ +__attribute__((noreturn)) +extern void VG_(err_bad_option) ( Char* opt ); + +/* Used to expand file names. "option_name" is the option name, eg. + "--log-file". 'format' is what follows, eg. "cachegrind.out.%p". In + 'format': + - "%p" is replaced with PID. + - "%q{QUAL}" is replaced with the environment variable $QUAL. If $QUAL + isn't set, we abort. If the "{QUAL}" part is malformed, we abort. + - "%%" is replaced with "%". + Anything else after '%' causes an abort. + If the format specifies a relative file name, it's put in the program's + initial working directory. If it specifies an absolute file name (ie. + starts with '/') then it is put there. + + Note that "option_name" has no effect on the returned string: the + returned string depends only on "format" and the PIDs and + environment variables that it references (if any). "option_name" is + merely used in printing error messages, if an error message needs + to be printed due to malformedness of the "format" argument. +*/ +extern Char* VG_(expand_file_name)(Char* option_name, Char* format); + +#endif // __PUB_TOOL_OPTIONS_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_oset.h.svn-base b/include/.svn/text-base/pub_tool_oset.h.svn-base new file mode 100644 index 0000000..687d34f --- /dev/null +++ b/include/.svn/text-base/pub_tool_oset.h.svn-base @@ -0,0 +1,259 @@ + +/*--------------------------------------------------------------------*/ +/*--- OSet: a fast data structure with no dups. pub_tool_oset.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2005-2009 Nicholas Nethercote + njn@valgrind.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_OSET_H +#define __PUB_TOOL_OSET_H + +// This module implements an ordered set, a data structure with fast +// (eg. amortised log(n) or better) insertion, lookup and deletion of +// elements. It does not allow duplicates, and will assert if you insert a +// duplicate to an OSet. +// +// It has two interfaces. +// +// - The "OSetWord_" interface provides an easier-to-use interface for the +// case where you just want to store UWord-sized values. The user +// provides the allocation and deallocation functions, and possibly a +// comparison function. +// +// - The "OSetGen_" interface provides a totally generic interface, which +// allows any kind of structure to be put into the set. The user provides +// the allocation and deallocation functions. Also, each element has a +// key, which the lookup is done with. The key may be the whole element +// (eg. in an OSet of integers, each integer serves both as an element and +// a key), or it may be only part of it (eg. if the key is a single field +// in a struct). The user can provide a function that compares an element +// with a key; this is very flexible, and with the right comparison +// function even a (non-overlapping) interval list can be created. But +// the cost of calling a function for every comparison can be high during +// lookup. If no comparison function is provided, we assume that keys are +// (signed or unsigned) words, and that the key is the first word in each +// element. This fast comparison is suitable for an OSet containing +// structs where the first element is an Addr, for example. +// +// Each OSet interface also has an iterator, which makes it simple to +// traverse all the nodes in order. Note that the iterator maintains state +// and so is non-reentrant. +// +// Note that once you insert an element into an OSet, if you modify any part +// of it looked at by your cmp() function, this may cause incorrect +// behaviour as the sorted order maintained will be wrong. + +/*--------------------------------------------------------------------*/ +/*--- Types ---*/ +/*--------------------------------------------------------------------*/ + +typedef struct _OSet OSet; + +// - Cmp: returns -1, 0 or 1 if key is <, == or > elem. +// - Alloc: allocates a chunk of memory. +// - Free: frees a chunk of memory allocated with Alloc. + +typedef Word (*OSetCmp_t) ( const void* key, const void* elem ); +typedef void* (*OSetAlloc_t) ( HChar* ec, SizeT szB ); +typedef void (*OSetFree_t) ( void* p ); + +/*--------------------------------------------------------------------*/ +/*--- Creating and destroying OSets (UWord) ---*/ +/*--------------------------------------------------------------------*/ + +// * Create: allocates and initialises the OSet. Arguments: +// - alloc The allocation function used internally for allocating the +// OSet and all its nodes. +// - free The deallocation function used internally for freeing nodes +// called by VG_(OSetWord_Destroy)(). +// +// * CreateWithCmp: like Create, but you specify your own comparison +// function. +// +// * Destroy: frees all nodes in the table, plus the memory used by +// the table itself. The passed-in function is called on each node first +// to allow the destruction of any attached resources; if NULL it is not +// called. + +extern OSet* VG_(OSetWord_Create) ( OSetAlloc_t alloc, HChar* ec, + OSetFree_t _free ); +extern void VG_(OSetWord_Destroy) ( OSet* os ); + +/*--------------------------------------------------------------------*/ +/*--- Operations on OSets (UWord) ---*/ +/*--------------------------------------------------------------------*/ + +// In everything that follows, the parameter 'key' is always the *address* +// of the key, and 'elem' is *address* of the elem, as are the return values +// of the functions that return elems. +// +// * Size: The number of elements in the set. +// +// * Contains: Determines if the value is in the set. +// +// * Insert: Inserts a new element into the set. Duplicates are forbidden, +// and will cause assertion failures. +// +// * Remove: Removes the value from the set, if present. Returns a Bool +// indicating if the value was removed. +// +// * ResetIter: Each OSet has an iterator. This resets it to point to the +// first element in the OSet. +// +// * Next: Copies the next value according to the OSet's iterator into &val, +// advances the iterator by one, and returns True; the elements are +// visited in increasing order of unsigned words (UWord). Or, returns +// False if the iterator has reached the set's end. +// +// You can thus iterate in order through a set like this: +// +// Word val; +// VG_(OSetWord_ResetIter)(oset); +// while ( VG_(OSetWord_Next)(oset, &val) ) { +// ... do stuff with 'val' ... +// } +// +// Note that iterators are cleared any time an element is inserted or +// removed from the OSet, to avoid possible mayhem caused by the iterator +// getting out of sync with the OSet's contents. "Cleared" means that +// they will return False if VG_(OSetWord_Next)() is called without an +// intervening call to VG_(OSetWord_ResetIter)(). + +extern Word VG_(OSetWord_Size) ( OSet* os ); +extern void VG_(OSetWord_Insert) ( OSet* os, UWord val ); +extern Bool VG_(OSetWord_Contains) ( OSet* os, UWord val ); +extern Bool VG_(OSetWord_Remove) ( OSet* os, UWord val ); +extern void VG_(OSetWord_ResetIter) ( OSet* os ); +extern Bool VG_(OSetWord_Next) ( OSet* os, /*OUT*/UWord* val ); + + +/*--------------------------------------------------------------------*/ +/*--- Creating and destroying OSets and OSet members (Gen) ---*/ +/*--------------------------------------------------------------------*/ + +// * Create: allocates and initialises the OSet. Arguments: +// - keyOff The offset of the key within the element. +// - cmp The comparison function between keys and elements, or NULL +// if the OSet should use fast comparisons. +// - alloc The allocation function used for allocating the OSet itself; +// it's also called for each invocation of +// VG_(OSetGen_AllocNode)(). +// - free The deallocation function used by VG_(OSetGen_FreeNode)() and +// VG_(OSetGen_Destroy)(). +// +// If cmp is NULL, keyOff must be zero. This is checked. +// +// * Destroy: frees all nodes in the table, plus the memory used by +// the table itself. The passed-in function is called on each node first +// to allow the destruction of any attached resources; if NULL it is not +// called. +// +// * AllocNode: Allocate and zero memory for a node to go into the OSet. +// Uses the alloc function given to VG_(OSetGen_Create)() to allocated a +// node which is big enough for both an element and the OSet metadata. +// Not all elements in one OSet have to be the same size. +// +// Note that the element allocated will be at most word-aligned, which may +// be less aligned than the element type would normally be. +// +// * FreeNode: Deallocate a node allocated with OSetGen_AllocNode(). Using +// a deallocation function (such as VG_(free)()) directly will likely +// lead to assertions in Valgrind's allocator. + +extern OSet* VG_(OSetGen_Create) ( PtrdiffT keyOff, OSetCmp_t cmp, + OSetAlloc_t alloc, HChar* ec, + OSetFree_t _free ); +extern void VG_(OSetGen_Destroy) ( OSet* os ); +extern void* VG_(OSetGen_AllocNode) ( OSet* os, SizeT elemSize ); +extern void VG_(OSetGen_FreeNode) ( OSet* os, void* elem ); + +/*--------------------------------------------------------------------*/ +/*--- Operations on OSets (Gen) ---*/ +/*--------------------------------------------------------------------*/ + +// In everything that follows, the parameter 'key' is always the *address* +// of the key, and 'elem' is *address* of the elem, as are the return values +// of the functions that return elems. +// +// * Size: The number of elements in the set. +// +// * Insert: Inserts a new element into the set. Note that 'elem' must +// have been allocated using VG_(OSetGen_AllocNode)(), otherwise you will +// get assertion failures about "bad magic". Duplicates are forbidden, +// and will also cause assertion failures. +// +// * Contains: Determines if any element in the OSet matches the key. +// +// * Lookup: Returns a pointer to the element matching the key, if there is +// one, otherwise returns NULL. +// +// * LookupWithCmp: Like Lookup, but you specify the comparison function, +// which overrides the OSet's normal one. +// +// * Remove: Removes the element matching the key, if there is one. Returns +// NULL if no element matches the key. +// +// * ResetIter: Each OSet has an iterator. This resets it to point to the +// first element in the OSet. +// +// * Next: Returns a pointer to the element pointed to by the OSet's +// iterator, and advances the iterator by one; the elements are visited +// in order. Or, returns NULL if the iterator has reached the OSet's end. +// +// You can thus iterate in order through a set like this: +// +// VG_(OSetGen_ResetIter)(oset); +// while ( (elem = VG_(OSetGen_Next)(oset)) ) { +// ... do stuff with 'elem' ... +// } +// +// Note that iterators are cleared any time an element is inserted or +// removed from the OSet, to avoid possible mayhem caused by the iterator +// getting out of sync with the OSet's contents. "Cleared" means that +// they will return NULL if VG_(OSetGen_Next)() is called without an +// intervening call to VG_(OSetGen_ResetIter)(). + +extern Word VG_(OSetGen_Size) ( const OSet* os ); +extern void VG_(OSetGen_Insert) ( OSet* os, void* elem ); +extern Bool VG_(OSetGen_Contains) ( const OSet* os, const void* key ); +extern void* VG_(OSetGen_Lookup) ( const OSet* os, const void* key ); +extern void* VG_(OSetGen_LookupWithCmp)( OSet* os, + const void* key, OSetCmp_t cmp ); +extern void* VG_(OSetGen_Remove) ( OSet* os, const void* key ); +extern void VG_(OSetGen_ResetIter) ( OSet* os ); +extern void* VG_(OSetGen_Next) ( OSet* os ); + +// set up 'oset' for iteration so that the first key subsequently +// produced VG_(OSetGen_Next) is the smallest key in the map +// >= start_at. Naturally ">=" is defined by the comparison +// function supplied to VG_(OSetGen_Create). +extern void VG_(OSetGen_ResetIterAt) ( OSet* oset, const void* key ); + +#endif // __PUB_TOOL_OSET_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_redir.h.svn-base b/include/.svn/text-base/pub_tool_redir.h.svn-base new file mode 100644 index 0000000..a249fb2 --- /dev/null +++ b/include/.svn/text-base/pub_tool_redir.h.svn-base @@ -0,0 +1,205 @@ + +/*--------------------------------------------------------------------*/ +/*--- Redirections, etc. pub_tool_redir.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_REDIR_H +#define __PUB_TOOL_REDIR_H + +/* The following macros facilitate function replacement and wrapping. + + Function wrapping and function replacement are similar but not + identical. + + A replacement for some function F simply diverts all calls to F + to the stated replacement. There is no way to get back to F itself + from the replacement. + + A wrapper for a function F causes all calls to F to instead go to + the wrapper. However, from inside the wrapper, it is possible + (with some difficulty) to get to F itself. + + You may notice that replacement is a special case of wrapping, in + which the call to the original is omitted. For implementation + reasons, though, it is important to use the following macros + correctly: in particular, if you want to write a replacement, make + sure you use the VG_REPLACE_FN_ macros and not the VG_WRAP_FN_ + macros. + + Replacement + ~~~~~~~~~~~ + To write a replacement function, do this: + + ret_type + VG_REPLACE_FUNCTION_ZU(zEncodedSoname,fnname) ( .. args .. ) + { + ... body ... + } + + zEncodedSoname should be a Z-encoded soname (see below for Z-encoding + details) and fnname should be an unencoded fn name. The resulting name is + + _vgrZU_zEncodedSoname_fnname + + The "_vgrZU_" is a prefix that gets discarded upon decoding. + + It is also possible to write + + ret_type + VG_REPLACE_FUNCTION_ZZ(zEncodedSoname,zEncodedFnname) ( .. args .. ) + { + ... body ... + } + + which means precisely the same, but the function name is also + Z-encoded. This can sometimes be necessary. In this case the + resulting function name is + + _vgrZZ_zEncodedSoname_zEncodedFnname + + When it sees this either such name, the core's symbol-table reading + machinery and redirection machinery first Z-decode the soname and + if necessary the fnname. They are encoded so that they may include + arbitrary characters, and in particular they may contain '*', which + acts as a wildcard. + + They then will conspire to cause calls to any function matching + 'fnname' in any object whose soname matches 'soname' to actually be + routed to this function. This is used in Valgrind to define dozens + of replacements of malloc, free, etc. + + The soname must be a Z-encoded bit of text because sonames can + contain dots etc which are not valid symbol names. The function + name may or may not be Z-encoded: to include wildcards it has to be, + but Z-encoding C++ function names which are themselves already mangled + using Zs in some way is tedious and error prone, so the _ZU variant + allows them not to be Z-encoded. + + Note that the soname "NONE" is specially interpreted to match any + shared object which doesn't have a soname. + + Note also that the replacement function should probably (must be?) in + client space, so it runs on the simulated CPU. So it must be in + either vgpreload_<tool>.so or vgpreload_core.so. It also only works + with functions in shared objects, I think. + + It is important that the Z-encoded names contain no unencoded + underscores, since the intercept-handlers in m_redir.c detect the + end of the soname by looking for the first trailing underscore. + + Wrapping + ~~~~~~~~ + This is identical to replacement, except that you should use the + macro names + + VG_WRAP_FUNCTION_ZU + VG_WRAP_FUNCTION_ZZ + + instead. + + Z-encoding + ~~~~~~~~~~ + Z-encoding details: the scheme is like GHC's. It is just about + readable enough to make a preprocessor unnecessary. First the + "_vgrZU_" or "_vgrZZ_" prefix is added, and then the following + characters are transformed. + + * --> Za (asterisk) + + --> Zp (plus) + : --> Zc (colon) + . --> Zd (dot) + _ --> Zu (underscore) + - --> Zh (hyphen) + (space) --> Zs (space) + @ --> ZA (at) + Z --> ZZ (Z) + ( --> ZL (left) + ) --> ZR (right) + + Everything else is left unchanged. +*/ + +/* If you change these, the code in VG_(maybe_Z_demangle) needs to be + changed accordingly. NOTE: duplicates + I_{WRAP,REPLACE}_SONAME_FNNAME_Z{U,Z} in valgrind.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 VG_REPLACE_FUNCTION_ZU(soname,fnname) VG_CONCAT4(_vgrZU_,soname,_,fnname) +#define VG_REPLACE_FUNCTION_ZZ(soname,fnname) VG_CONCAT4(_vgrZZ_,soname,_,fnname) + +#define VG_WRAP_FUNCTION_ZU(soname,fnname) VG_CONCAT4(_vgwZU_,soname,_,fnname) +#define VG_WRAP_FUNCTION_ZZ(soname,fnname) VG_CONCAT4(_vgwZZ_,soname,_,fnname) + +/* --------- Some handy Z-encoded names. --------- */ + +/* --- Soname of the standard C library. --- */ + +#if defined(VGO_linux) +# define VG_Z_LIBC_SONAME libcZdsoZa // libc.so* +#elif defined(VGP_ppc32_aix5) + /* AIX has both /usr/lib/libc.a and /usr/lib/libc_r.a. */ +# define VG_Z_LIBC_SONAME libcZaZdaZLshrZdoZR // libc*.a(shr.o) +#elif defined(VGP_ppc64_aix5) +# define VG_Z_LIBC_SONAME libcZaZdaZLshrZu64ZdoZR // libc*.a(shr_64.o) +#else +# error "Unknown platform" +#endif + +/* --- Soname of the GNU C++ library. --- */ + +// DDD: this one and those below should probably be conditionally compiled, +// as should all the redirects in the tools that use them. +#define VG_Z_LIBSTDCXX_SONAME libstdcZpZpZa // libstdc++* + +/* --- Soname of XLC's C++ library. --- */ + +/* AIX: xlC's C++ runtime library is called libC.a, and the + interesting symbols appear to be in ansicore_32.o or ansicore_64.o + respectively. */ +#if defined(VGP_ppc32_aix5) +# define VG_Z_LIBC_DOT_A libCZdaZLansicoreZu32ZdoZR // libC.a(ansicore_32.o) +#elif defined(VGP_ppc64_aix5) +# define VG_Z_LIBC_DOT_A libCZdaZLansicoreZu64ZdoZR // libC.a(ansicore_64.o) +#endif + +/* --- Sonames for Linux ELF linkers. --- */ + +#define VG_Z_LD_LINUX_SO_2 ldZhlinuxZdsoZd2 // ld-linux.so.2 +#define VG_Z_LD_LINUX_X86_64_SO_2 ldZhlinuxZhx86Zh64ZdsoZd2 // ld-linux-x86-64.so.2 +#define VG_Z_LD64_SO_1 ld64ZdsoZd1 // ld64.so.1 +#define VG_Z_LD_SO_1 ldZdsoZd1 // ld.so.1 + + +#endif // __PUB_TOOL_REDIR_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_replacemalloc.h.svn-base b/include/.svn/text-base/pub_tool_replacemalloc.h.svn-base new file mode 100644 index 0000000..9cb2e9e --- /dev/null +++ b/include/.svn/text-base/pub_tool_replacemalloc.h.svn-base @@ -0,0 +1,74 @@ + +/*--------------------------------------------------------------------*/ +/*--- Malloc replacement. pub_tool_replacemalloc.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_REPLACEMALLOC_H +#define __PUB_TOOL_REPLACEMALLOC_H + +/* If a tool replaces malloc() et al, the easiest way to do so is to + link libreplacemalloc_toolpreload.o into its vgpreload_*.so file, and + use the functions declared below. You can do it from scratch, + though, if you enjoy that sort of thing. */ + +/* Can be called from VG_(tdict).malloc_malloc et al to do the actual + * alloc/freeing. */ +extern void* VG_(cli_malloc) ( SizeT align, SizeT nbytes ); +extern void VG_(cli_free) ( void* p ); + +/* If a tool uses deferred freeing (e.g. memcheck to catch accesses to + freed memory) it can maintain number and total size of queued blocks + in these variable to provide more accurate statistics about client + memory usage. Currently used by mallinfo(). */ +extern Long VG_(free_queue_volume); +extern Long VG_(free_queue_length); + +/* Check if an address is within a range, allowing for redzones at edges */ +extern Bool VG_(addr_is_in_block)( Addr a, Addr start, + SizeT size, SizeT rz_szB ); + +/* ------------------------------------------------------------------ */ +/* Some options that can be used by a tool if malloc() et al are replaced. + The tool should call the functions in the appropriate places to give + control over these aspects of Valgrind's version of malloc(). */ + +/* DEBUG: print malloc details? default: NO */ +extern Bool VG_(clo_trace_malloc); +/* Minimum alignment in functions that don't specify alignment explicitly. + default: VG_MIN_MALLOC_SZB */ +extern UInt VG_(clo_alignment); + +extern Bool VG_(replacement_malloc_process_cmd_line_option) ( Char* arg ); +extern void VG_(replacement_malloc_print_usage) ( void ); +extern void VG_(replacement_malloc_print_debug_usage) ( void ); + +#endif // __PUB_TOOL_REPLACEMALLOC_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_seqmatch.h.svn-base b/include/.svn/text-base/pub_tool_seqmatch.h.svn-base new file mode 100644 index 0000000..a1763b7 --- /dev/null +++ b/include/.svn/text-base/pub_tool_seqmatch.h.svn-base @@ -0,0 +1,91 @@ + +/*--------------------------------------------------------------------*/ +/*--- A simple sequence matching facility. ---*/ +/*--- pub_tool_seqmatch.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2008-2009 OpenWorks Ltd + info@open-works.co.uk + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_SEQMATCH_H +#define __PUB_TOOL_SEQMATCH_H + +/* Perform totally abstractified sequence matching, of an input + sequence against a pattern sequence. The pattern sequence may + include '*' elements (matches any number of anything) and '?' + elements (matches exactly one element). '*' patterns are matched + frugally, meaning that they are "assigned" the minimum amount of + input needed to make the match work. + + This routine is recursive. The recursion depth is equal to the + number of '*' elements in the pattern. There is no guard against + excessive recursion. This function has no global state and so is + thread-safe and re-entrant. (It needs to be, since m_errormgr will + effectively construct two simultaneous calls to it, once to match + at the frame level, and whilst that is happening, once at the + function/object-name level.) + + When matchAll is True, the entire input sequence must match the + pattern, else the match fails. When False, it's ok for some tail + of the input sequence to be unused -- so we're only matching a + prefix. + + The pattern array is starts at 'patt' and consists of 'nPatt' + elements each of size 'szbPatt'. For the initial call, pass a + value of zero to 'ixPatt'. + + Ditto for input/nInput/szbInput/ixInput. + + pIsStar should return True iff the pointed-to pattern element is + conceptually a '*'. + + pIsQuery should return True iff the pointed-to-pattern element is + conceptually a '?'. + + pattEQinp takes a pointer to a pattern element and a pointer to an + input element. It should return True iff they are considered + equal. Note that the pattern element is guaranteed to be neither + (conceptually) '*' nor '?', so it must be a literal (in the sense + that all the input sequence elements are literal). +*/ +Bool VG_(generic_match) ( + Bool matchAll, + void* patt, SizeT szbPatt, UWord nPatt, UWord ixPatt, + void* input, SizeT szbInput, UWord nInput, UWord ixInput, + Bool (*pIsStar)(void*), + Bool (*pIsQuery)(void*), + Bool (*pattEQinp)(void*,void*) + ); + +/* Mini-regexp function. Searches for 'pat' in 'str'. Supports + meta-symbols '*' and '?'. There is no way to escape meta-symbols + in the pattern. */ +Bool VG_(string_match) ( const Char* pat, const Char* str ); + +#endif // __PUB_TOOL_SEQMATCH_H + +/*--------------------------------------------------------------------*/ +/*--- end pub_tool_seqmatch.h ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_signals.h.svn-base b/include/.svn/text-base/pub_tool_signals.h.svn-base new file mode 100644 index 0000000..bb96018 --- /dev/null +++ b/include/.svn/text-base/pub_tool_signals.h.svn-base @@ -0,0 +1,47 @@ + +/*--------------------------------------------------------------------*/ +/*--- Signals stuff. pub_tool_signals.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_SIGNALS_H +#define __PUB_TOOL_SIGNALS_H + +// Register an interest in apparently internal faults; used code which +// wanders around dangerous memory (ie, leakcheck). The catcher is +// not expected to return. +// +// It's frustrating that we need this header for a single function used +// only by Memcheck during leak checking. We should find a way to remove +// the need for this file. +extern void VG_(set_fault_catcher)(void (*catcher)(Int sig, Addr addr)); + +#endif // __PUB_TOOL_SIGNALS_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_sparsewa.h.svn-base b/include/.svn/text-base/pub_tool_sparsewa.h.svn-base new file mode 100644 index 0000000..29bb336 --- /dev/null +++ b/include/.svn/text-base/pub_tool_sparsewa.h.svn-base @@ -0,0 +1,99 @@ + +/*--------------------------------------------------------------------*/ +/*--- An sparse array (of words) implementation. ---*/ +/*--- pub_tool_sparsewa.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2008-2009 OpenWorks Ltd + info@open-works.co.uk + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_SPARSEWA_H +#define __PUB_TOOL_SPARSEWA_H + +//-------------------------------------------------------------------- +// PURPOSE: (see coregrind/pub_core_sparsewa.h for details) +//-------------------------------------------------------------------- + +///////////////////////////////////////////////////////// +// // +// SparseWA: Interface // +// // +///////////////////////////////////////////////////////// + +// This interface is a very cut-down version of WordFM. +// If you understand how to use WordFM then it should be +// trivial to use SparseWA. + +typedef struct _SparseWA SparseWA; /* opaque */ + +// Create a new one, using the specified allocator/deallocator +SparseWA* VG_(newSWA) ( void*(*alloc_nofail)(HChar* cc, SizeT), + HChar* cc, + void(*dealloc)(void*) ); + +// Delete one, and free all associated storage +void VG_(deleteSWA) ( SparseWA* swa ); + +// Add the binding key -> val to this swa. Any existing binding is +// overwritten. Returned Bool is True iff a previous binding existed. +Bool VG_(addToSWA) ( SparseWA* swa, UWord key, UWord val ); + +// Delete key from swa, returning associated key and val if found. +// Note: returning associated key is stupid (it can only be the +// key you just specified). This behaviour is retained to make it +// easier to migrate from WordFM. Returned Bool is True iff +// the key was actually bound in the mapping. +Bool VG_(delFromSWA) ( SparseWA* swa, + /*OUT*/UWord* oldK, /*OUT*/UWord* oldV, + UWord key ); + +// Indexes swa at 'key' (or, if you like, looks up 'key' in the +// mapping), and returns the associated value, if any, in *valP. For +// compatibility with WordFM, 'key' is also returned in *keyP. Returned +// Bool is True iff a binding for 'key' actually existed. +Bool VG_(lookupSWA) ( SparseWA* swa, + /*OUT*/UWord* keyP, /*OUT*/UWord* valP, + UWord key ); + +// Set up 'swa' for iteration. +void VG_(initIterSWA) ( SparseWA* swa ); + +// Get the next key/val pair. Behaviour undefined (highly likely +// to segfault) if 'swa' has been modified since initIterSWA was +// called. Returned Bool is False iff there are no more pairs +// that can be extracted. +Bool VG_(nextIterSWA)( SparseWA* swa, + /*OUT*/UWord* keyP, /*OUT*/UWord* valP ); + +// How many elements are there in 'swa'? NOTE: dangerous in the +// sense that this is not an O(1) operation but rather O(N), +// since it involves walking the whole tree. +UWord VG_(sizeSWA) ( SparseWA* swa ); + +#endif // __PUB_TOOL_SPARSEWA_H + +/*--------------------------------------------------------------------*/ +/*--- end pub_tool_sparsewa.h ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_stacktrace.h.svn-base b/include/.svn/text-base/pub_tool_stacktrace.h.svn-base new file mode 100644 index 0000000..f17758b --- /dev/null +++ b/include/.svn/text-base/pub_tool_stacktrace.h.svn-base @@ -0,0 +1,82 @@ +/*--------------------------------------------------------------------*/ +/*--- Stack traces: getting, traversing, printing. ---*/ +/*--- tool_stacktrace.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_STACKTRACE_H +#define __PUB_TOOL_STACKTRACE_H + +// The basic stack trace type: just an array of code addresses. +typedef Addr* StackTrace; + +// Walks the stack to get instruction pointers from the top stack frames +// for thread 'tid'. Maximum of 'n_ips' addresses put into 'ips'; +// 0 is the top of the stack, 1 is its caller, etc. Everything from +// ips[return_value] onwards is undefined and should not be read. +// The initial IP value to use is adjusted by first_ip_delta before +// the stack is unwound. A safe value to pass is zero. +// +// The specific meaning of the returned addresses is: +// +// [0] is the IP of thread 'tid' +// [1] points to the last byte of the call instruction that called [0]. +// [2] points to the last byte of the call instruction that called [1]. +// etc etc +// +// Hence ips[0 .. return_value-1] should all point to currently +// 'active' (in the sense of a stack of unfinished function calls) +// instructions. [0] points to the start of an arbitrary instruction.# +// [1 ..] point to the last byte of a chain of call instructions. +// +// If sps and fps are non-NULL, the corresponding frame-pointer and +// stack-pointer values for each frame are stored there. + +extern UInt VG_(get_StackTrace) ( ThreadId tid, + /*OUT*/StackTrace ips, UInt n_ips, + /*OUT*/StackTrace sps, + /*OUT*/StackTrace fps, + Word first_ip_delta ); + +// Apply a function to every element in the StackTrace. The parameter 'n' +// gives the index of the passed ip. Doesn't go below main() unless +// --show-below-main=yes is set. +extern void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip), + StackTrace ips, UInt n_ips ); + +// Print a StackTrace. +extern void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips ); + +// Gets and immediately prints a StackTrace. Just a bit simpler than +// calling VG_(get_StackTrace)() then VG_(pp_StackTrace)(). +extern void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips ); + +#endif // __PUB_TOOL_STACKTRACE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_threadstate.h.svn-base b/include/.svn/text-base/pub_tool_threadstate.h.svn-base new file mode 100644 index 0000000..d572e87 --- /dev/null +++ b/include/.svn/text-base/pub_tool_threadstate.h.svn-base @@ -0,0 +1,53 @@ + +/*--------------------------------------------------------------------*/ +/*--- The thread state. pub_tool_threadstate.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_THREADSTATE_H +#define __PUB_TOOL_THREADSTATE_H + +/* The maximum number of pthreads that we support. This is + deliberately not very high since our implementation of some of the + scheduler algorithms is surely O(N) in the number of threads, since + that's simple, at least. And (in practice) we hope that most + programs do not need many threads. */ +#define VG_N_THREADS 300 + +/* Special magic value for an invalid ThreadId. It corresponds to + LinuxThreads using zero as the initial value for + pthread_mutex_t.__m_owner and pthread_cond_t.__c_waiting. */ +#define VG_INVALID_THREADID ((ThreadId)(0)) + +/* Get the TID of the thread which currently has the CPU. */ +extern ThreadId VG_(get_running_tid) ( void ); + +#endif // __PUB_TOOL_THREADSTATE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_tooliface.h.svn-base b/include/.svn/text-base/pub_tool_tooliface.h.svn-base new file mode 100644 index 0000000..3a7c391 --- /dev/null +++ b/include/.svn/text-base/pub_tool_tooliface.h.svn-base @@ -0,0 +1,643 @@ + +/*--------------------------------------------------------------------*/ +/*--- The core/tool interface. pub_tool_tooliface.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_TOOLIFACE_H +#define __PUB_TOOL_TOOLIFACE_H + +#include "pub_tool_errormgr.h" // for Error, Supp +#include "libvex.h" // for all Vex stuff + +/* ------------------------------------------------------------------ */ +/* The interface version */ + +/* Initialise tool. Must do the following: + - initialise the `details' struct, via the VG_(details_*)() functions + - register the basic tool functions, via VG_(basic_tool_funcs)(). + May do the following: + - initialise the `needs' struct to indicate certain requirements, via + the VG_(needs_*)() functions + - any other tool-specific initialisation +*/ +extern void (*VG_(tl_pre_clo_init)) ( void ); + +/* Every tool must include this macro somewhere, exactly once. The + interface version is no longer relevant, but we kept the same name + to avoid requiring changes to tools. +*/ +#define VG_DETERMINE_INTERFACE_VERSION(pre_clo_init) \ + void (*VG_(tl_pre_clo_init)) ( void ) = pre_clo_init; + +/* ------------------------------------------------------------------ */ +/* Basic tool functions */ + +/* The tool_instrument function is passed as a callback to + LibVEX_Translate. VgCallbackClosure carries additional info + which the instrumenter might like to know, but which is opaque to + Vex. +*/ +typedef + struct { + Addr64 nraddr; /* non-redirected guest address */ + Addr64 readdr; /* redirected guest address */ + ThreadId tid; /* tid requesting translation */ + } + VgCallbackClosure; + +extern void VG_(basic_tool_funcs)( + // Do any initialisation that can only be done after command line + // processing. + void (*post_clo_init)(void), + + // Instrument a basic block. Must be a true function, ie. the same + // input always results in the same output, because basic blocks + // can be retranslated, unless you're doing something really + // strange. Anyway, the arguments. Mostly they are straightforward + // except for the distinction between redirected and non-redirected + // guest code addresses, which is important to understand. + // + // VgCallBackClosure* closure contains extra arguments passed + // from Valgrind to the instrumenter, which Vex doesn't know about. + // You are free to look inside this structure. + // + // * closure->tid is the ThreadId of the thread requesting the + // translation. Not sure why this is here; perhaps callgrind + // uses it. + // + // * closure->nraddr is the non-redirected guest address of the + // start of the translation. In other words, the translation is + // being constructed because the guest program jumped to + // closure->nraddr but no translation of it was found. + // + // * closure->readdr is the redirected guest address, from which + // the translation was really made. + // + // To clarify this, consider what happens when, in Memcheck, the + // first call to malloc() happens. The guest program will be + // trying to jump to malloc() in libc; hence ->nraddr will contain + // that address. However, Memcheck intercepts and replaces + // malloc, hence ->readdr will be the address of Memcheck's + // malloc replacement in + // coregrind/m_replacemalloc/vg_replacemalloc.c. It follows + // that the first IMark in the translation will be labelled as + // from ->readdr rather than ->nraddr. + // + // Since most functions are not redirected, the majority of the + // time ->nraddr will be the same as ->readdr. However, you + // cannot assume this: if your tool has metadata associated + // with code addresses it will get into deep trouble if it does + // make this assumption. + // + // IRSB* sb_in is the incoming superblock to be instrumented, + // in flat IR form. + // + // VexGuestLayout* layout contains limited info on the layout of + // the guest state: where the stack pointer and program counter + // are, and which fields should be regarded as 'always defined'. + // Memcheck uses this. + // + // VexGuestExtents* vge points to a structure which states the + // precise byte ranges of original code from which this translation + // was made (there may be up to three different ranges involved). + // Note again that these are the real addresses from which the code + // came. And so it should be the case that closure->readdr is the + // same as vge->base[0]; indeed Cachegrind contains this assertion. + // + // Tools which associate shadow data with code addresses + // (cachegrind, callgrind) need to be particularly clear about + // whether they are making the association with redirected or + // non-redirected code addresses. Both approaches are viable + // but you do need to understand what's going on. See comments + // below on discard_basic_block_info(). + // + // IRType gWordTy and IRType hWordTy contain the types of native + // words on the guest (simulated) and host (real) CPUs. They will + // by either Ity_I32 or Ity_I64. So far we have never built a + // cross-architecture Valgrind so they should always be the same. + // + /* --- Further comments about the IR that your --- */ + /* --- instrumentation function will receive. --- */ + /* + In the incoming IRSB, the IR for each instruction begins with an + IRStmt_IMark, which states the address and length of the + instruction from which this IR came. This makes it easy for + profiling-style tools to know precisely which guest code + addresses are being executed. + + However, before the first IRStmt_IMark, there may be other IR + statements -- a preamble. In most cases this preamble is empty, + but when it isn't, what it contains is some supporting IR that + the JIT uses to ensure control flow works correctly. This + preamble does not modify any architecturally defined guest state + (registers or memory) and so does not contain anything that will + be of interest to your tool. + + You should therefore + + (1) copy any IR preceding the first IMark verbatim to the start + of the output IRSB. + + (2) not try to instrument it or modify it in any way. + + For the record, stuff that may be in the preamble at + present is: + + - A self-modifying-code check has been requested for this block. + The preamble will contain instructions to checksum the block, + compare against the expected value, and exit the dispatcher + requesting a discard (hence forcing a retranslation) if they + don't match. + + - This block is known to be the entry point of a wrapper of some + function F. In this case the preamble contains code to write + the address of the original F (the fn being wrapped) into a + 'hidden' guest state register _NRADDR. The wrapper can later + read this register using a client request and make a + non-redirected call to it using another client-request-like + magic macro. + + - For platforms that use the AIX ABI (including ppc64-linux), it + is necessary to have a preamble even for replacement functions + (not just for wrappers), because it is necessary to switch the + R2 register (constant-pool pointer) to a different value when + swizzling the program counter. + + Hence the preamble pushes both R2 and LR (the return address) + on a small 16-entry stack in the guest state and sets R2 to an + appropriate value for the wrapper/replacement fn. LR is then + set so that the wrapper/replacement fn returns to a magic IR + stub which restores R2 and LR and returns. + + It's all hugely ugly and fragile. And it places a stringent + requirement on m_debuginfo to find out the correct R2 (toc + pointer) value for the wrapper/replacement function. So much + so that m_redir will refuse to honour a redirect-to-me request + if it cannot find (by asking m_debuginfo) a plausible R2 value + for 'me'. + + Because this mechanism maintains a shadow stack of (R2,LR) + pairs in the guest state, it will fail if the + wrapper/redirection function, or anything it calls, longjumps + out past the wrapper, because then the magic return stub will + not be run and so the shadow stack will not be popped. So it + will quickly fill up. Fortunately none of this applies to + {x86,amd64,ppc32}-linux; on those platforms, wrappers can + longjump and recurse arbitrarily and everything should work + fine. + + Note that copying the preamble verbatim may cause complications + for your instrumenter if you shadow IR temporaries. See big + comment in MC_(instrument) in memcheck/mc_translate.c for + details. + */ + IRSB*(*instrument)(VgCallbackClosure* closure, + IRSB* sb_in, + VexGuestLayout* layout, + VexGuestExtents* vge, + IRType gWordTy, + IRType hWordTy), + + // Finish up, print out any results, etc. `exitcode' is program's exit + // code. The shadow can be found with VG_(get_exit_status_shadow)(). + void (*fini)(Int) +); + +/* ------------------------------------------------------------------ */ +/* Details */ + +/* Default value for avg_translations_sizeB (in bytes), indicating typical + code expansion of about 6:1. */ +#define VG_DEFAULT_TRANS_SIZEB 172 + +/* Information used in the startup message. `name' also determines the + string used for identifying suppressions in a suppression file as + belonging to this tool. `version' can be NULL, in which case (not + surprisingly) no version info is printed; this mechanism is designed for + tools distributed with Valgrind that share a version number with + Valgrind. Other tools not distributed as part of Valgrind should + probably have their own version number. */ +extern void VG_(details_name) ( Char* name ); +extern void VG_(details_version) ( Char* version ); +extern void VG_(details_description) ( Char* description ); +extern void VG_(details_copyright_author) ( Char* copyright_author ); + +/* Average size of a translation, in bytes, so that the translation + storage machinery can allocate memory appropriately. Not critical, + setting is optional. */ +extern void VG_(details_avg_translation_sizeB) ( UInt size ); + +/* String printed if an `tl_assert' assertion fails or VG_(tool_panic) + is called. Should probably be an email address. */ +extern void VG_(details_bug_reports_to) ( Char* bug_reports_to ); + +/* ------------------------------------------------------------------ */ +/* Needs */ + +/* Should __libc_freeres() be run? Bugs in it can crash the tool. */ +extern void VG_(needs_libc_freeres) ( void ); + +/* Want to have errors detected by Valgrind's core reported? Includes: + - pthread API errors (many; eg. unlocking a non-locked mutex) + [currently disabled] + - invalid file descriptors to syscalls like read() and write() + - bad signal numbers passed to sigaction() + - attempt to install signal handler for SIGKILL or SIGSTOP */ +extern void VG_(needs_core_errors) ( void ); + +/* Booleans that indicate extra operations are defined; if these are True, + the corresponding template functions (given below) must be defined. A + lot like being a member of a type class. */ + +/* Want to report errors from tool? This implies use of suppressions, too. */ +extern void VG_(needs_tool_errors) ( + // Identify if two errors are equal, or equal enough. `res' indicates how + // close is "close enough". `res' should be passed on as necessary, eg. if + // the Error's `extra' part contains an ExeContext, `res' should be + // passed to VG_(eq_ExeContext)() if the ExeContexts are considered. Other + // than that, probably don't worry about it unless you have lots of very + // similar errors occurring. + Bool (*eq_Error)(VgRes res, Error* e1, Error* e2), + + // Print error context. + void (*pp_Error)(Error* err), + + // Should the core indicate which ThreadId each error comes from? + Bool show_ThreadIDs_for_errors, + + // Should fill in any details that could be postponed until after the + // decision whether to ignore the error (ie. details not affecting the + // result of VG_(tdict).tool_eq_Error()). This saves time when errors + // are ignored. + // Yuk. + // Return value: must be the size of the `extra' part in bytes -- used by + // the core to make a copy. + UInt (*update_extra)(Error* err), + + // Return value indicates recognition. If recognised, must set skind using + // VG_(set_supp_kind)(). + Bool (*recognised_suppression)(Char* name, Supp* su), + + // Read any extra info for this suppression kind. Most likely for filling + // in the `extra' and `string' parts (with VG_(set_supp_{extra, string})()) + // of a suppression if necessary. Should return False if a syntax error + // occurred, True otherwise. + Bool (*read_extra_suppression_info)(Int fd, Char* buf, Int nBuf, Supp* su), + + // This should just check the kinds match and maybe some stuff in the + // `string' and `extra' field if appropriate (using VG_(get_supp_*)() to + // get the relevant suppression parts). + Bool (*error_matches_suppression)(Error* err, Supp* su), + + // This should return the suppression name, for --gen-suppressions, or NULL + // if that error type cannot be suppressed. This is the inverse of + // VG_(tdict).tool_recognised_suppression(). + Char* (*get_error_name)(Error* err), + + // This should print any extra info for the error, for --gen-suppressions, + // including the newline. This is the inverse of + // VG_(tdict).tool_read_extra_suppression_info(). + void (*print_extra_suppression_info)(Error* err) +); + +/* Is information kept by the tool about specific instructions or + translations? (Eg. for cachegrind there are cost-centres for every + instruction, stored in a per-translation fashion.) If so, the info + may have to be discarded when translations are unloaded (eg. due to + .so unloading, or otherwise at the discretion of m_transtab, eg + when the table becomes too full) to avoid stale information being + reused for new translations. */ +extern void VG_(needs_superblock_discards) ( + // Discard any information that pertains to specific translations + // or instructions within the address range given. There are two + // possible approaches. + // - If info is being stored at a per-translation level, use orig_addr + // to identify which translation is being discarded. Each translation + // will be discarded exactly once. + // This orig_addr will match the closure->nraddr which was passed to + // to instrument() (see extensive comments above) when this + // translation was made. Note that orig_addr won't necessarily be + // the same as the first address in "extents". + // - If info is being stored at a per-instruction level, you can get + // the address range(s) being discarded by stepping through "extents". + // Note that any single instruction may belong to more than one + // translation, and so could be covered by the "extents" of more than + // one call to this function. + // Doing it the first way (as eg. Cachegrind does) is probably easier. + void (*discard_superblock_info)(Addr64 orig_addr, VexGuestExtents extents) +); + +/* Tool defines its own command line options? */ +extern void VG_(needs_command_line_options) ( + // Return True if option was recognised. Presumably sets some state to + // record the option as well. Nb: tools can assume that the argv will + // never disappear. So they can, for example, store a pointer to a string + // within an option, rather than having to make a copy. + Bool (*process_cmd_line_option)(Char* argv), + + // Print out command line usage for options for normal tool operation. + void (*print_usage)(void), + + // Print out command line usage for options for debugging the tool. + void (*print_debug_usage)(void) +); + +/* Tool defines its own client requests? */ +extern void VG_(needs_client_requests) ( + // If using client requests, the number of the first request should be equal + // to VG_USERREQ_TOOL_BASE('X', 'Y'), where 'X' and 'Y' form a suitable two + // character identification for the string. The second and subsequent + // requests should follow. + // + // This function should use the VG_IS_TOOL_USERREQ macro (in + // include/valgrind.h) to first check if it's a request for this tool. Then + // should handle it if it's recognised (and return True), or return False if + // not recognised. arg_block[0] holds the request number, any further args + // from the request are in arg_block[1..]. 'ret' is for the return value... + // it should probably be filled, if only with 0. + Bool (*handle_client_request)(ThreadId tid, UWord* arg_block, UWord* ret) +); + +/* Tool does stuff before and/or after system calls? */ +// Nb: If either of the pre_ functions malloc() something to return, the +// corresponding post_ function had better free() it! +extern void VG_(needs_syscall_wrapper) ( + void (* pre_syscall)(ThreadId tid, UInt syscallno), + void (*post_syscall)(ThreadId tid, UInt syscallno, SysRes res) +); + +/* Are tool-state sanity checks performed? */ +// Can be useful for ensuring a tool's correctness. cheap_sanity_check() +// is called very frequently; expensive_sanity_check() is called less +// frequently and can be more involved. +extern void VG_(needs_sanity_checks) ( + Bool(*cheap_sanity_check)(void), + Bool(*expensive_sanity_check)(void) +); + +/* Do we need to see variable type and location information? */ +extern void VG_(needs_var_info) ( void ); + +/* Does the tool replace malloc() and friends with its own versions? + This has to be combined with the use of a vgpreload_<tool>.so module + or it won't work. See massif/Makefile.am for how to build it. */ +// The 'p' prefix avoids GCC complaints about overshadowing global names. +extern void VG_(needs_malloc_replacement)( + void* (*pmalloc) ( ThreadId tid, SizeT n ), + void* (*p__builtin_new) ( ThreadId tid, SizeT n ), + void* (*p__builtin_vec_new) ( ThreadId tid, SizeT n ), + void* (*pmemalign) ( ThreadId tid, SizeT align, SizeT n ), + void* (*pcalloc) ( ThreadId tid, SizeT nmemb, SizeT size1 ), + void (*pfree) ( ThreadId tid, void* p ), + void (*p__builtin_delete) ( ThreadId tid, void* p ), + void (*p__builtin_vec_delete) ( ThreadId tid, void* p ), + void* (*prealloc) ( ThreadId tid, void* p, SizeT new_size ), + SizeT (*pmalloc_usable_size) ( ThreadId tid, void* p), + SizeT client_malloc_redzone_szB +); + +/* Can the tool do XML output? This is a slight misnomer, because the tool + * is not requesting the core to do anything, rather saying "I can handle + * it". */ +extern void VG_(needs_xml_output)( void ); + +/* Does the tool want to have one final pass over the IR after tree + building but before instruction selection? If so specify the + function here. */ +extern void VG_(needs_final_IR_tidy_pass) ( IRSB*(*final_tidy)(IRSB*) ); + + +/* ------------------------------------------------------------------ */ +/* Core events to track */ + +/* Part of the core from which this call was made. Useful for determining + what kind of error message should be emitted. */ +typedef + enum { Vg_CoreStartup=1, Vg_CoreSignal, Vg_CoreSysCall, + Vg_CoreTranslate, Vg_CoreClientReq } + CorePart; + +/* Events happening in core to track. To be notified, pass a callback + function to the appropriate function. To ignore an event, don't do + anything (the default is for events to be ignored). + + Note that most events aren't passed a ThreadId. If the event is one called + from generated code (eg. new_mem_stack_*), you can use + VG_(get_running_tid)() to find it. Otherwise, it has to be passed in, + as in pre_mem_read, and so the event signature will require changing. + + Memory events (Nb: to track heap allocation/freeing, a tool must replace + malloc() et al. See above how to do this.) + + These ones occur at startup, upon some signals, and upon some syscalls. + + For new_mem_brk and new_mem_stack_signal, the supplied ThreadId + indicates the thread for whom the new memory is being allocated. + + For new_mem_startup and new_mem_mmap, the di_handle argument is a + handle which can be used to retrieve debug info associated with the + mapping or allocation (because it is of a file that Valgrind has + decided to read debug info from). If the value is zero, there is + no associated debug info. If the value exceeds zero, it can be + supplied as an argument to selected queries in m_debuginfo. +*/ +void VG_(track_new_mem_startup) (void(*f)(Addr a, SizeT len, + Bool rr, Bool ww, Bool xx, + ULong di_handle)); +void VG_(track_new_mem_stack_signal)(void(*f)(Addr a, SizeT len, ThreadId tid)); +void VG_(track_new_mem_brk) (void(*f)(Addr a, SizeT len, ThreadId tid)); +void VG_(track_new_mem_mmap) (void(*f)(Addr a, SizeT len, + Bool rr, Bool ww, Bool xx, + ULong di_handle)); + +void VG_(track_copy_mem_remap) (void(*f)(Addr from, Addr to, SizeT len)); +void VG_(track_change_mem_mprotect) (void(*f)(Addr a, SizeT len, + Bool rr, Bool ww, Bool xx)); +void VG_(track_die_mem_stack_signal)(void(*f)(Addr a, SizeT len)); +void VG_(track_die_mem_brk) (void(*f)(Addr a, SizeT len)); +void VG_(track_die_mem_munmap) (void(*f)(Addr a, SizeT len)); + +/* These ones are called when SP changes. A tool could track these itself + (except for ban_mem_stack) but it's much easier to use the core's help. + + The specialised ones are called in preference to the general one, if they + are defined. These functions are called a lot if they are used, so + specialising can optimise things significantly. If any of the + specialised cases are defined, the general case must be defined too. + + Nb: all the specialised ones must use the VG_REGPARM(n) attribute. + + For the _new functions, a tool may specify with with-ECU + (ExeContext Unique) or without-ECU version for each size, but not + both. If the with-ECU version is supplied, then the core will + arrange to pass, as the ecu argument, a 32-bit int which uniquely + identifies the instruction moving the stack pointer down. This + 32-bit value is as obtained from VG_(get_ECU_from_ExeContext). + VG_(get_ExeContext_from_ECU) can then be used to retrieve the + associated depth-1 ExeContext for the location. All this + complexity is provided to support origin tracking in Memcheck. +*/ +void VG_(track_new_mem_stack_4_w_ECU) (VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_8_w_ECU) (VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_12_w_ECU) (VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_16_w_ECU) (VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_32_w_ECU) (VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_112_w_ECU)(VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_128_w_ECU)(VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_144_w_ECU)(VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_160_w_ECU)(VG_REGPARM(2) void(*f)(Addr new_ESP, UInt ecu)); +void VG_(track_new_mem_stack_w_ECU) (void(*f)(Addr a, SizeT len, + UInt ecu)); + +void VG_(track_new_mem_stack_4) (VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack_8) (VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack_12) (VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack_16) (VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack_32) (VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack_112)(VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack_128)(VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack_144)(VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack_160)(VG_REGPARM(1) void(*f)(Addr new_ESP)); +void VG_(track_new_mem_stack) (void(*f)(Addr a, SizeT len)); + +void VG_(track_die_mem_stack_4) (VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack_8) (VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack_12) (VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack_16) (VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack_32) (VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack_112)(VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack_128)(VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack_144)(VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack_160)(VG_REGPARM(1) void(*f)(Addr die_ESP)); +void VG_(track_die_mem_stack) (void(*f)(Addr a, SizeT len)); + +/* Used for redzone at end of thread stacks */ +void VG_(track_ban_mem_stack) (void(*f)(Addr a, SizeT len)); + +/* These ones occur around syscalls, signal handling, etc */ +void VG_(track_pre_mem_read) (void(*f)(CorePart part, ThreadId tid, + Char* s, Addr a, SizeT size)); +void VG_(track_pre_mem_read_asciiz)(void(*f)(CorePart part, ThreadId tid, + Char* s, Addr a)); +void VG_(track_pre_mem_write) (void(*f)(CorePart part, ThreadId tid, + Char* s, Addr a, SizeT size)); +void VG_(track_post_mem_write) (void(*f)(CorePart part, ThreadId tid, + Addr a, SizeT size)); + +/* Register events. Use VG_(set_shadow_state_area)() to set the shadow regs + for these events. */ +void VG_(track_pre_reg_read) (void(*f)(CorePart part, ThreadId tid, + Char* s, PtrdiffT guest_state_offset, + SizeT size)); +void VG_(track_post_reg_write)(void(*f)(CorePart part, ThreadId tid, + PtrdiffT guest_state_offset, + SizeT size)); + +/* This one is called for malloc() et al if they are replaced by a tool. */ +void VG_(track_post_reg_write_clientcall_return)( + void(*f)(ThreadId tid, PtrdiffT guest_state_offset, SizeT size, Addr f)); + + +/* Scheduler events (not exhaustive) */ + +/* Called when 'tid' starts or stops running client code blocks. + Gives the total dispatched block count at that event. Note, this + is not the same as 'tid' holding the BigLock (the lock that ensures + that only one thread runs at a time): a thread can hold the lock + for other purposes (making translations, etc) yet not be running + client blocks. Obviously though, a thread must hold the lock in + order to run client code blocks, so the times bracketed by + 'start_client_code'..'stop_client_code' are a subset of the times + when thread 'tid' holds the cpu lock. +*/ +void VG_(track_start_client_code)( + void(*f)(ThreadId tid, ULong blocks_dispatched) + ); +void VG_(track_stop_client_code)( + void(*f)(ThreadId tid, ULong blocks_dispatched) + ); + + +/* Thread events (not exhaustive) + + ll_create: low level thread creation. Called before the new thread + has run any instructions (or touched any memory). In fact, called + immediately before the new thread has come into existence; the new + thread can be assumed to exist when notified by this call. + + ll_exit: low level thread exit. Called after the exiting thread + has run its last instruction. + + The _ll_ part makes it clear these events are not to do with + pthread_create or pthread_exit/pthread_join (etc), which are a + higher level abstraction synthesised by libpthread. What you can + be sure of from _ll_create/_ll_exit is the absolute limits of each + thread's lifetime, and hence be assured that all memory references + made by the thread fall inside the _ll_create/_ll_exit pair. This + is important for tools that need a 100% accurate account of which + thread is responsible for every memory reference in the process. + + pthread_create/join/exit do not give this property. Calls/returns + to/from them happen arbitrarily far away from the relevant + low-level thread create/quit event. In general a few hundred + instructions; hence a few hundred(ish) memory references could get + misclassified each time. + + pre_thread_first_insn: is called when the thread is all set up and + ready to go (stack in place, etc) but has not executed its first + instruction yet. Gives threading tools a chance to ask questions + about the thread (eg, what is its initial client stack pointer) + that are not easily answered at pre_thread_ll_create time. + + For a given thread, the call sequence is: + ll_create (in the parent's context) + first_insn (in the child's context) + ll_exit (in the child's context) +*/ +void VG_(track_pre_thread_ll_create) (void(*f)(ThreadId tid, ThreadId child)); +void VG_(track_pre_thread_first_insn)(void(*f)(ThreadId tid)); +void VG_(track_pre_thread_ll_exit) (void(*f)(ThreadId tid)); + + +/* Signal events (not exhaustive) + + ... pre_send_signal, post_send_signal ... + + Called before a signal is delivered; `alt_stack' indicates if it is + delivered on an alternative stack. */ +void VG_(track_pre_deliver_signal) (void(*f)(ThreadId tid, Int sigNo, + Bool alt_stack)); +/* Called after a signal is delivered. Nb: unfortunately, if the signal + handler longjmps, this won't be called. */ +void VG_(track_post_deliver_signal)(void(*f)(ThreadId tid, Int sigNo)); + +#endif // __PUB_TOOL_TOOLIFACE_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_vki.h.svn-base b/include/.svn/text-base/pub_tool_vki.h.svn-base new file mode 100644 index 0000000..75da646 --- /dev/null +++ b/include/.svn/text-base/pub_tool_vki.h.svn-base @@ -0,0 +1,62 @@ + +/*--------------------------------------------------------------------*/ +/*--- Top level for kernel interface declarations. ---*/ +/*--- pub_tool_vki.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + Copyright (C) 2005-2009 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2006-2009 OpenWorks LLP + info@open-works.co.uk + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +/* This file defines types and constants for the kernel interface, and to + make that clear everything is prefixed VKI_/vki_. + + This file is merely a top-level "steering" file, which pulls in the + correct bits for the relevant platform. You should not directly + #include any file in include/vki; instead #include only this one or + pub_core_vki.h. +*/ + +#ifndef __PUB_TOOL_VKI_H +#define __PUB_TOOL_VKI_H + +#if defined(VGO_linux) +# include "vki/vki-linux.h" +#elif defined(VGP_ppc32_aix5) +# include "vki/vki-ppc32-aix5.h" +#elif defined(VGP_ppc64_aix5) +# include "vki/vki-ppc64-aix5.h" +#else +# error Unknown Plat/OS +#endif + +#endif // __PUB_TOOL_VKI_H + +/*--------------------------------------------------------------------*/ +/*--- end pub_tool_vki.h ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_vkiscnums.h.svn-base b/include/.svn/text-base/pub_tool_vkiscnums.h.svn-base new file mode 100644 index 0000000..147a761 --- /dev/null +++ b/include/.svn/text-base/pub_tool_vkiscnums.h.svn-base @@ -0,0 +1,88 @@ + +/*--------------------------------------------------------------------*/ +/*--- Top level for kernel interface system call numbers. ---*/ +/*--- pub_tool_vkiscnums.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2005-2009 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2006-2009 OpenWorks LLP + info@open-works.co.uk + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +/* This file defines the system call numbers. + + On Linux they are a bunch of #define'd constants of the form + __NR_name, and this file must contain nothing else, since it will + be included in assembly code (m_trampoline.S). + + On AIX the __NR_name consts are renamings of global variables which + tell us the number for each syscall. This elaboration is necessary + because on AIX the syscall numbers are not constant; they can be + different for each process (in principle; in practice they rarely + change). 32- and 64-bit AIX5 share a common "implementation". + + This file is merely a top-level "steering" file, which pulls in the + correct bits for the relevant platform. You should not directly + #include any file in include/vki; instead #include only this one or + pub_core_vkiscnums.h. +*/ + +#ifndef __PUB_TOOL_VKISCNUMS_H +#define __PUB_TOOL_VKISCNUMS_H + +#if defined(VGP_x86_linux) +# include "vki/vki-scnums-x86-linux.h" + +#elif defined(VGP_amd64_linux) +# include "vki/vki-scnums-amd64-linux.h" + +#elif defined(VGP_ppc32_linux) +# include "vki/vki-scnums-ppc32-linux.h" + +#elif defined(VGP_ppc64_linux) +# include "vki/vki-scnums-ppc64-linux.h" + +#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) +# include "vki/vki-scnums-aix5.h" + +/* Make it possible to include this file in assembly sources. */ +#if !defined(VG_IN_ASSEMBLY_SOURCE) + +/* Look up the name of a syscall, using the bindings previously + created by VG_(aix5_register_syscall), for the purposes of making + error messages. */ +extern UChar* VG_(aix5_sysno_to_sysname)( Int sysno ); + +#endif /* !defined(VG_IN_ASSEMBLY_SOURCE) */ + +#else +# error Unknown platform +#endif + +#endif // __PUB_TOOL_VKISCNUMS_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_wordfm.h.svn-base b/include/.svn/text-base/pub_tool_wordfm.h.svn-base new file mode 100644 index 0000000..57c57db --- /dev/null +++ b/include/.svn/text-base/pub_tool_wordfm.h.svn-base @@ -0,0 +1,220 @@ + +/*--------------------------------------------------------------------*/ +/*--- An AVL tree based finite map for word keys and word values. ---*/ +/*--- Inspired by Haskell's "FiniteMap" library. ---*/ +/*--- pub_tool_wordfm.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2007-2009 Julian Seward + jseward@acm.org + + This code is based on previous work by Nicholas Nethercote + (coregrind/m_oset.c) which is + + Copyright (C) 2005-2009 Nicholas Nethercote + njn@valgrind.org + + which in turn was derived partially from: + + AVL C library + Copyright (C) 2000,2002 Daniel Nagy + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + [...] + + (taken from libavl-0.4/debian/copyright) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_WORDFM_H +#define __PUB_TOOL_WORDFM_H + +//------------------------------------------------------------------// +//--- WordFM ---// +//--- Public interface ---// +//------------------------------------------------------------------// + +/* As of r7409 (15 Feb 08), all these word-based abstractions (WordFM, + WordSet, WordBag) now operate on unsigned words (UWord), whereas + they previously operated on signed words (Word). This became a + problem, when using unboxed comparisons (when kCmp == NULL), with + the introduction of VG_(initIterAtFM), which allows iteration over + parts of mappings. Iterating over a mapping in increasing order of + signed Word keys is not what callers expect when iterating through + maps whose keys represent addresses (Addr) since Addr is unsigned, + and causes logical problems and assertion failures. */ + +typedef struct _WordFM WordFM; /* opaque */ + +/* Allocate and initialise a WordFM. If kCmp is non-NULL, elements in + the set are ordered according to the ordering specified by kCmp, + which becomes obvious if you use VG_(initIterFM), + VG_(initIterAtFM), VG_(nextIterFM), VG_(doneIterFM) to iterate over + sections of the map, or the whole thing. If kCmp is NULL then the + ordering used is unsigned word ordering (UWord) on the key + values. */ +WordFM* VG_(newFM) ( void* (*alloc_nofail)( HChar* cc, SizeT ), + HChar* cc, + void (*dealloc)(void*), + Word (*kCmp)(UWord,UWord) ); + +/* Free up the FM. If kFin is non-NULL, it is applied to keys + before the FM is deleted; ditto with vFin for vals. */ +void VG_(deleteFM) ( WordFM*, void(*kFin)(UWord), void(*vFin)(UWord) ); + +/* Add (k,v) to fm. If a binding for k already exists, it is updated + to map to this new v. In that case we should really return the + previous v so that caller can finalise it. Oh well. Returns + True if a binding for k already exists. */ +Bool VG_(addToFM) ( WordFM* fm, UWord k, UWord v ); + +// Delete key from fm, returning associated key and val if found +Bool VG_(delFromFM) ( WordFM* fm, + /*OUT*/UWord* oldK, /*OUT*/UWord* oldV, UWord key ); + +// Look up in fm, assigning found key & val at spec'd addresses +Bool VG_(lookupFM) ( WordFM* fm, + /*OUT*/UWord* keyP, /*OUT*/UWord* valP, UWord key ); + +// Find the closest key values bracketing the given key, assuming the +// given key is not present in the map. minKey and maxKey are the +// minimum and maximum possible key values. The resulting bracket +// values are returned in *kMinP and *kMaxP. It follows that if fm is +// empty then the returned values are simply minKey and maxKey. +// +// For convenience the associated value fields are also returned +// through *vMinP and *vMaxP. To make that possible in the general +// case, the caller must supply via minVal and maxVal, the value +// fields associated with minKey and maxKey. +// +// If the operation was successful (that is, the given key is not +// present), True is returned. If the given key is in fact present, +// False is returned, and *kMinP, *vMinP, *kMaxP and *vMaxP are +// undefined. Any of kMinP, vMinP, kMaxP and vMaxP may be safely +// supplied as NULL. +Bool VG_(findBoundsFM)( WordFM* fm, + /*OUT*/UWord* kMinP, /*OUT*/UWord* vMinP, + /*OUT*/UWord* kMaxP, /*OUT*/UWord* vMaxP, + UWord minKey, UWord minVal, + UWord maxKey, UWord maxVal, + UWord key ); + +// How many elements are there in fm? NOTE: dangerous in the +// sense that this is not an O(1) operation but rather O(N), +// since it involves walking the whole tree. +UWord VG_(sizeFM) ( WordFM* fm ); + +// Is fm empty? This at least is an O(1) operation. +// Code is present in m_wordfm.c but commented out due to no +// current usage. Un-comment (and TEST IT) if required. +//Bool VG_(isEmptyFM)( WordFM* fm ); + +// set up FM for iteration +void VG_(initIterFM) ( WordFM* fm ); + +// set up FM for iteration so that the first key subsequently produced +// by VG_(nextIterFM) is the smallest key in the map >= start_at. +// Naturally ">=" is defined by the comparison function supplied to +// VG_(newFM), as documented above. +void VG_(initIterAtFM) ( WordFM* fm, UWord start_at ); + +// get next key/val pair. Will assert if fm has been modified +// or looked up in since initIterFM/initIterWithStartFM was called. +Bool VG_(nextIterFM) ( WordFM* fm, + /*OUT*/UWord* pKey, /*OUT*/UWord* pVal ); + +// clear the I'm iterating flag +void VG_(doneIterFM) ( WordFM* fm ); + +// Deep copy a FM. If dopyK is NULL, keys are copied verbatim. +// If non-null, dopyK is applied to each key to generate the +// version in the new copy. In that case, if the argument to dopyK +// is non-NULL but the result is NULL, it is assumed that dopyK +// could not allocate memory, in which case the copy is abandoned +// and NULL is returned. Ditto with dopyV for values. +WordFM* VG_(dopyFM) ( WordFM* fm, + UWord(*dopyK)(UWord), UWord(*dopyV)(UWord) ); + +// admin: what's the 'common' allocation size (for tree nodes?) +SizeT VG_(getNodeSizeFM)( void ); + +//------------------------------------------------------------------// +//--- end WordFM ---// +//--- Public interface ---// +//------------------------------------------------------------------// + +//------------------------------------------------------------------// +//--- WordBag (unboxed words only) ---// +//--- Public interface ---// +//------------------------------------------------------------------// + +typedef struct _WordBag WordBag; /* opaque */ + +/* Allocate and initialise a WordBag */ +WordBag* VG_(newBag) ( void* (*alloc_nofail)( HChar* cc, SizeT ), + HChar* cc, + void (*dealloc)(void*) ); + +/* Free up the Bag. */ +void VG_(deleteBag) ( WordBag* ); + +/* Add a word. */ +void VG_(addToBag)( WordBag*, UWord ); + +/* Find out how many times the given word exists in the bag. */ +UWord VG_(elemBag) ( WordBag*, UWord ); + +/* Delete a word from the bag. */ +Bool VG_(delFromBag)( WordBag*, UWord ); + +/* Is the bag empty? */ +Bool VG_(isEmptyBag)( WordBag* ); + +/* Does the bag have exactly one element? */ +Bool VG_(isSingletonTotalBag)( WordBag* ); + +/* Return an arbitrary element from the bag. */ +UWord VG_(anyElementOfBag)( WordBag* ); + +/* How many different / total elements are in the bag? */ +UWord VG_(sizeUniqueBag)( WordBag* ); /* fast */ +UWord VG_(sizeTotalBag)( WordBag* ); /* warning: slow */ + +/* Iterating over the elements of a bag. */ +void VG_(initIterBag)( WordBag* ); +Bool VG_(nextIterBag)( WordBag*, /*OUT*/UWord* pVal, /*OUT*/UWord* pCount ); +void VG_(doneIterBag)( WordBag* ); + +//------------------------------------------------------------------// +//--- end WordBag (unboxed words only) ---// +//--- Public interface ---// +//------------------------------------------------------------------// + +#endif /* ! __PUB_TOOL_WORDFM_H */ + +/*--------------------------------------------------------------------*/ +/*--- end pub_tool_wordfm.h ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/pub_tool_xarray.h.svn-base b/include/.svn/text-base/pub_tool_xarray.h.svn-base new file mode 100644 index 0000000..111f63a --- /dev/null +++ b/include/.svn/text-base/pub_tool_xarray.h.svn-base @@ -0,0 +1,115 @@ + +/*--------------------------------------------------------------------*/ +/*--- An expandable array implementation. pub_tool_xarray.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2007-2009 OpenWorks LLP + info@open-works.co.uk + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PUB_TOOL_XARRAY_H +#define __PUB_TOOL_XARRAY_H + +//-------------------------------------------------------------------- +// PURPOSE: Provides a simple but useful structure, which is an array +// in which elements can be added at the end. The array is expanded +// as needed by multiplying its size by a constant factor (usually 2). +// This gives amortised O(1) insertion cost, and, following sorting, +// the usual O(log N) binary search cost. Arbitrary element sizes +// are allowed; the comparison function for sort/lookup can be changed +// at any time, and duplicates (modulo the comparison function) are +// allowed. +//-------------------------------------------------------------------- + + +/* It's an abstract type. Bwaha. */ +typedef struct _XArray XArray; + +/* Create new XArray, using given allocation and free function, and + for elements of the specified size. Alloc fn must not fail (that + is, if it returns it must have succeeded.) */ +extern XArray* VG_(newXA) ( void*(*alloc_fn)(HChar*,SizeT), + HChar* cc, + void(*free_fn)(void*), + Word elemSzB ); + +/* Free all memory associated with an XArray. */ +extern void VG_(deleteXA) ( XArray* ); + +/* Set the comparison function for this XArray. This clears an + internal 'array is sorted' flag, which means you must call sortXA + before making further queries with lookupXA. */ +extern void VG_(setCmpFnXA) ( XArray*, Int (*compar)(void*,void*) ); + +/* Add an element to an XArray. Element is copied into the XArray. + Index at which it was added is returned. Note this will be + invalidated if the array is later sortXA'd. */ +extern Word VG_(addToXA) ( XArray*, void* elem ); + +/* Add a sequence of bytes to an XArray of bytes. Asserts if nbytes + is negative or the array's element size is not 1. Returns the + index at which the first byte was added. */ +extern Word VG_(addBytesToXA) ( XArray* xao, void* bytesV, Word nbytes ); + +/* Sort an XArray using its comparison function, if set; else bomb. + Probably not a stable sort w.r.t. equal elements module cmpFn. */ +extern void VG_(sortXA) ( XArray* ); + +/* Lookup (by binary search) 'key' in the array. Set *first to be the + index of the first, and *last to be the index of the last matching + value found. If any values are found, return True, else return + False, and don't change *first or *last. Bomb if the array is not + sorted. */ +extern Bool VG_(lookupXA) ( XArray*, void* key, + /*OUT*/Word* first, /*OUT*/Word* last ); + +/* How elements are there in this XArray now? */ +extern Word VG_(sizeXA) ( XArray* ); + +/* Index into the XArray. Checks bounds and bombs if the index is + invalid. What this returns is the address of the specified element + in the array, not (of course) the element itself. Note that the + element may get moved by subsequent addToXAs/sortXAs, so you should + copy it out immediately and not regard its address as unchanging. + Note also that indexXA will of course not return NULL if it + succeeds. */ +extern void* VG_(indexXA) ( XArray*, Word ); + +/* Drop the last n elements of an XArray. Bombs if there are less + than n elements in the array. */ +extern void VG_(dropTailXA) ( XArray*, Word ); + +/* Make a new, completely independent copy of the given XArray, using + the existing allocation function to allocate the new space. + Returns NULL if the allocation function didn't manage to allocate + space (but did return NULL rather than merely abort.) Space for + the clone (and all additions to it) is billed to 'cc' unless that + is NULL, in which case the parent's cost-center is used. */ +extern XArray* VG_(cloneXA)( HChar* cc, XArray* xa ); + +#endif // __PUB_TOOL_XARRAY_H + +/*--------------------------------------------------------------------*/ +/*--- end pub_tool_xarray.h ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/.svn/text-base/valgrind.h.svn-base b/include/.svn/text-base/valgrind.h.svn-base new file mode 100644 index 0000000..5b4b8af --- /dev/null +++ b/include/.svn/text-base/valgrind.h.svn-base @@ -0,0 +1,3937 @@ +/* -*- 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-2009 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 + +#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). */ +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64_linux +#undef PLAT_ppc32_aix5 +#undef PLAT_ppc64_aix5 + +#if !defined(_AIX) && defined(__i386__) +# define PLAT_x86_linux 1 +#elif !defined(_AIX) && defined(__x86_64__) +# define PLAT_amd64_linux 1 +#elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__) +# define PLAT_ppc32_linux 1 +#elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__) +# define PLAT_ppc64_linux 1 +#elif defined(_AIX) && defined(__64BIT__) +# define PLAT_ppc64_aix5 1 +#elif defined(_AIX) && !defined(__64BIT__) +# define PLAT_ppc32_aix5 1 +#endif + + +/* If we're not compiling for our target platform, don't generate + any inline asms. */ +#if !defined(PLAT_x86_linux) && !defined(PLAT_amd64_linux) \ + && !defined(PLAT_ppc32_linux) && !defined(PLAT_ppc64_linux) \ + && !defined(PLAT_ppc32_aix5) && !defined(PLAT_ppc64_aix5) +# 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 ------------------------- */ + +#if defined(PLAT_x86_linux) + +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 */ + +/* ------------------------ amd64-linux ------------------------ */ + +#if defined(PLAT_amd64_linux) + +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 */ + +/* ------------------------ 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 */ + +/* ------------------------ 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. */ + +#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ + _vgwZU_##soname##_##fnname + +#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ + _vgwZZ_##soname##_##fnname + +/* Use this macro from within a wrapper function to 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) + +/* ------------------------- x86-linux ------------------------- */ + +#if defined(PLAT_x86_linux) + +/* 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( \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $4, %%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( \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $8, %%esp\n" \ + : /*out*/ "=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( \ + "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 $12, %%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( \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $20, %%esp\n" \ + : /*out*/ "=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( \ + "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 $24, %%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( \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $28, %%esp\n" \ + : /*out*/ "=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( \ + "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 $36, %%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( \ + "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 $40, %%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( \ + "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 $44, %%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 */ + +/* ------------------------ amd64-linux ------------------------ */ + +#if defined(PLAT_amd64_linux) + +/* 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" + +/* 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( \ + "subq $128,%%rsp\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + : /*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( \ + "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" \ + : /*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( \ + "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" \ + : /*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( \ + "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" \ + : /*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( \ + "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" \ + : /*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( \ + "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" \ + : /*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( \ + "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 */ \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CALL_NOREDIR_RAX \ + : /*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( \ + "subq $128,%%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 $128,%%rsp\n\t" \ + : /*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( \ + "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" \ + : /*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( \ + "subq $128,%%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 $128,%%rsp\n\t" \ + : /*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( \ + "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" \ + : /*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( \ + "subq $128,%%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 $128,%%rsp\n\t" \ + : /*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( \ + "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" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_amd64_linux */ + +/* ------------------------ 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 */ + +/* ------------------------ 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. */ + VG_USERREQ__PRINTF = 0x1401, + VG_USERREQ__PRINTF_BACKTRACE = 0x1402, + + /* 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 + } Vg_ClientRequest; + +#if !defined(__GNUC__) +# define __extension__ /* */ +#endif + +/* Returns the number of Valgrinds this code is running under. That + is, 0 if running natively, 1 if running under Valgrind, 2 if + running under Valgrind which is running under another Valgrind, + etc. */ +#define RUNNING_ON_VALGRIND __extension__ \ + ({unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* if not */, \ + VG_USERREQ__RUNNING_ON_VALGRIND, \ + 0, 0, 0, 0, 0); \ + _qzz_res; \ + }) + + +/* 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. */ + +#if defined(NVALGRIND) + +# define VALGRIND_PRINTF(...) +# define VALGRIND_PRINTF_BACKTRACE(...) + +#else /* NVALGRIND */ + +/* 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__)); +static int +VALGRIND_PRINTF(const char *format, ...) +{ + unsigned long _qzz_res; + va_list vargs; + va_start(vargs, format); + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF, + (unsigned long)format, (unsigned long)vargs, + 0, 0, 0); + va_end(vargs); + return (int)_qzz_res; +} + +static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) + __attribute__((format(__printf__, 1, 2), __unused__)); +static int +VALGRIND_PRINTF_BACKTRACE(const char *format, ...) +{ + unsigned long _qzz_res; + va_list vargs; + va_start(vargs, format); + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF_BACKTRACE, + (unsigned long)format, (unsigned long)vargs, + 0, 0, 0); + 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; \ + }) + +/* Mark a block of memory as having been allocated by a malloc()-like + function. `addr' is the start of the usable block (ie. after any + redzone) `rzB' is redzone size if the allocator can apply redzones; + use '0' if not. Adding redzones makes it more likely Valgrind will spot + block overruns. `is_zeroed' indicates if the memory is zeroed, as it is + for calloc(). Put it immediately after the point where a block is + allocated. + + If you're using Memcheck: If you're allocating memory via superblocks, + and then handing out small chunks of each superblock, if you don't have + redzones on your small blocks, it's worth marking the superblock with + VALGRIND_MAKE_MEM_NOACCESS when it's created, so that block overruns are + detected. But if you can put redzones on, it's probably better to not do + this, so that messages for small overruns are described in terms of the + small block rather than the superblock (but if you have a big overrun + that skips over a redzone, you could miss an error this way). See + memcheck/tests/custom_alloc.c for an example. + + WARNING: if your allocator uses malloc() or 'new' to allocate + superblocks, rather than mmap() or brk(), this will not work properly -- + you'll likely get assertion failures during leak detection. This is + because Valgrind doesn't like seeing overlapping heap blocks. Sorry. + + Nb: block must be freed via a free()-like function specified + with VALGRIND_FREELIKE_BLOCK or mismatch errors will occur. */ +#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MALLOCLIKE_BLOCK, \ + addr, sizeB, rzB, is_zeroed, 0); \ + } + +/* Mark a block of memory as having been freed by a free()-like function. + `rzB' is redzone size; it must match that given to + VALGRIND_MALLOCLIKE_BLOCK. Memory not freed will be detected by the leak + checker. Put it immediately after the point where the block is freed. */ +#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ + {unsigned int _qzz_res; \ + VALGRIND_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); \ + } + + +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64_linux +#undef PLAT_ppc32_aix5 +#undef PLAT_ppc64_aix5 + +#endif /* __VALGRIND_H */ |