You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
1
(23) |
2
(40) |
3
(17) |
4
(10) |
|
5
(14) |
6
(41) |
7
(26) |
8
(23) |
9
(15) |
10
(25) |
11
(14) |
|
12
(23) |
13
(11) |
14
(18) |
15
(21) |
16
(18) |
17
(8) |
18
(14) |
|
19
(16) |
20
(15) |
21
(12) |
22
(11) |
23
(8) |
24
(11) |
25
(12) |
|
26
(9) |
27
(17) |
28
(31) |
29
(16) |
30
(10) |
31
(17) |
|
|
From: Bryan M. <om...@br...> - 2006-03-13 23:11:44
|
Looks OK to me but I have a question and the answer/clarification may
well belong inside:
I wrap a function, say memcpy for example.
program on sim cpu calls memcpy
|
V
redirected to my memcpy wrapper
|
V
wrapper does some stuff, possibly doing a client call or two
|
V
wrapper calls original function
Is this original function instrumented as normal - i.e. can I still
expect my dirty functions to be called etc or does the call and its
processing take place only on the real cpu?
If I used the wrapper to stop my dirty function processing whilst the
original function ran, how could I then update my state from the memory
and in particular, the registers that were touched during execution? I
see that there is the shadow stack for PPC but what about x86/x86_64 ?
Would a replacement function be a better solution instead in this case?
Have I possibly got the wrong end of the stick on this?
Thanks in advance,
Bryan "Brain Murders" Meredith
sv...@va... wrote:
> Author: sewardj
> Date: 2006-03-13 13:40:57 +0000 (Mon, 13 Mar 2006)
> New Revision: 5763
>
> Log:
> First pass at documenting how to use the function-wrapping facility.
>
> Modified:
> trunk/docs/xml/manual-core.xml
>
>
> /usr/local/etc/subversion//commit-email.pl: `/usr/local/bin/svnlook diff /home/svn/repos/valgrind -r 5763' failed with this output:
> Modified: trunk/docs/xml/manual-core.xml
> ===================================================================
> --- trunk/docs/xml/manual-core.xml 2006-03-12 19:28:34 UTC (rev 5762)
> +++ trunk/docs/xml/manual-core.xml 2006-03-13 13:40:57 UTC (rev 5763)
> @@ -1557,6 +1557,339 @@
>
>
>
> +<sect1 id="manual-core.wrapping" xreflabel="Function Wrapping">
> +<title>Function wrapping</title>
> +
> +<para>
> +Valgrind versions 3.2.0 and above and can do function wrapping on all
> +supported targets. In function wrapping, calls to some specified
> +function are intercepted and rerouted to a different, user-supplied
> +function. This can do whatever it likes, typically examining the
> +arguments, calling onwards to the original, and possibly examining the
> +result. Any number of different functions may be wrapped.</para>
> +
> +<para>
> +Function wrapping is useful for instrumenting an API in some way. For
> +example, wrapping functions in the POSIX pthreads API makes it
> +possible to notify Valgrind of thread status changes, and wrapping
> +functions in the MPI (message-passing) API allows notifying Valgrind
> +of memory status changes associated with message arrival/departure.
> +Such information is usually passed to Valgrind by using client
> +requests in the wrapper functions, although that is not of relevance
> +here.</para>
> +
> +<sect2 id="manual-core.wrapping.example" xreflabel="A Simple Example">
> +<title>A Simple Example</title>
> +
> +<para>Supposing we want to wrap some function</para>
> +
> +<programlisting><![CDATA[
> +int foo ( int x, int y ) { return x + y; }]]></programlisting>
> +
> +<para>
> +A wrapper is a function of identical type, but with a special name
> +which identifies it as the wrapper for foo. Wrappers need to include
> +supporting macros from valgrind.h. Here is a simple wrapper which
> +prints the arguments and return value:</para>
> +<programlisting><![CDATA[
> + #include <stdio.h>
> + #include "valgrind.h"
> + int I_WRAP_SONAME_FNNAME_ZU(NONE,foo)( int x, int y )
> + {
> + int result;
> + OrigFn fn;
> + VALGRIND_GET_ORIG_FN(fn);
> + printf("foo's wrapper: args %d %d\n", x, y);
> + CALL_FN_W_WW(result, fn, x,y);
> + printf("foo's wrapper: result %d\n", result);
> + return result;
> + }
> +]]></programlisting>
> +
> +<para>To become active, the wrapper merely needs to be present in a text
> +section somewhere in the same process' address space as the function
> +it wraps, and for its ELF symbol name to be visible to Valgrind. In
> +practice, this means either compiling to a .o and linking it in, or
> +compiling to a .so and LD_PRELOADing it in. The latter is more
> +convenient in that it doesn't require relinking.</para>
> +
> +<para>All wrappers have approximately the above form. There are three
> +crucial macros:</para>
> +
> +<para>I_WRAP_SONAME_FNNAME_ZU: this generates the real name of the wrapper.
> +This is an encoded name which Valgrind notices when reading symbol
> +table information. What it says is: I am the wrapper for any function
> +named "foo" which is found in an ELF shared object with an empty
> +("NONE") soname field. The specification mechanism is powerful in
> +that wildcards are allowed for both sonames and function names. More
> +details below.</para>
> +
> +<para>VALGRIND_GET_ORIG_FN: once in the the wrapper, the first priority is
> +to get hold of the address of the original (and any other supporting
> +information needed). This is stored in a value of opaque type OrigFn.
> +The information is acquired using VALGRIND_GET_ORIG_FN. It is crucial
> +to make this macro call before calling any other wrapped function
> +in the same thread.</para>
> +
> +<para>CALL_FN_W_WW: eventually we will want to call the function being
> +wrapped. Calling it directly does not work, since that just gets us
> +back to the wrapper and tends to kill the program in short order by
> +stack overflow. Instead, the result lvalue, OrigFn and arguments are
> +handed to one of a family of macros of the form CALL_FN_*. These
> +cause Valgrind to call the original and avoid recursion back to the
> +wrapper.</para>
> +</sect2>
> +
> +<sect2 id="manual-core.wrapping.specs" xreflabel="Wrapping Specifications">
> +<title>Wrapping Specifications</title>
> +
> +<para>This scheme has the advantage of being self-contained. A library of
> +wrappers can be compiled to object code in the normal way, and does
> +not rely on an external script telling Valgrind which wrappers pertain
> +to which originals.</para>
> +
> +<para>Each wrapper has a name which, in the most general case says: I am the
> +wrapper for any function whose name matches FNPATT and whose ELF
> +"soname" matches SOPATT. Both FNPATT and SOPATT may contain wildcards
> +(asterisks) and other characters (spaces, dots, @, etc) which are not
> +generally regarded as valid C identifier names.</para>
> +
> +<para>This flexibility is needed to write robust wrappers for POSIX pthread
> +functions, where typically we are not completely sure of either the
> +function name or the soname, or alternatively we want to wrap a whole
> +bunch of functions at once.</para>
> +
> +<para>For example, pthread_create() in GNU libpthread's is usually a
> +versioned symbol - one whose name ends in, eg, "@GLIBC_2.3". Hence we
> +are not sure what its real name is. We also want to cover any soname
> +of the form "libpthread.so*". So the header of the wrapper will be</para>
> +
> +<programlisting><![CDATA[
> +int I_WRAP_SONAME_FNNAME_ZZ(libpthreadZdsoZd0,pthreadZucreateZAZa)
> + ( ... formals ... )
> + { ... body ... }
> +]]></programlisting>
> +
> +<para>In order to write unusual characters as valid C function names, a
> +Z-encoding scheme is used. Names are written literally, except that
> +a capital Z acts as an escape character, with the following encoding:</para>
> +
> +<programlisting><![CDATA[
> + Za encodes *
> + Zp +
> + Zc :
> + Zd .
> + Zu _
> + Zh -
> + Zs (space)
> + ZA @
> + ZZ Z
> +]]></programlisting>
> +
> +<para>Hence libpthreadZdsoZd0 is an encoding of the soname "libpthread.so.0"
> +and "pthreadZucreateZAZa" is an encoding of the function name
> +"pthread_create@*".</para>
> +
> +<para>The macro I_WRAP_SONAME_FNNAME_ZZ constructs a wrapper name in which
> +both the soname (first component) and function name (second component)
> +are Z-encoded. Encoding the function name can be tiresome and is
> +often unnecessary, so a second macro, I_WRAP_SONAME_FNNAME_ZU, can be
> +used instead. The _ZU variant is also useful for writing wrappers for
> +C++ functions, in which the function name is usually already mangled
> +using some other convention in which Z plays an important role; having
> +to encode a second time quickly becomes confusing.</para>
> +
> +<para>Since the function name field may contain wildcards, it can be
> +anything, including just "*". The same is true for the soname.
> +However, some ELF objects - specifically, main executables - do not
> +have sonames. Any object lacking a soname is treated as if its soname
> +was "NONE", which is why the original example above had a name
> +I_WRAP_SONAME_FNNAME_ZU(NONE,foo).</para>
> +</sect2>
> +
> +<sect2 id="manual-core.wrapping.semantics" xreflabel="Wrapping Semantics">
> +<title>Wrapping Semantics</title>
> +
> +<para>The ability for a wrapper to replace an infinite family of functions
> +is powerful but brings complications in situations where ELF objects
> +appear and disappear (are dlopen'd and dlclose'd) on the fly.
> +Valgrind tries to maintain sensible behaviour in such situations.</para>
> +
> +<para>For example, suppose a process has dlopened (an ELF object with
> +soname) object1.so, which contains function1(). It starts to use
> +function1() immediately.</para>
> +
> +<para>After a while it dlopens wrappers.so, which contains a wrapper
> +for function1 in (soname) object1.so. All subsequent calls to
> +function1() are rerouted to the wrapper.</para>
> +
> +<para>If wrappers.so is later dlclose'd, calls to function1() are
> +naturally rerouted back to the original.</para>
> +
> +<para>Alternatively, if object1.so is dlclose'd but wrappers.so remains,
> +then the wrapper exported by wrapper.so becomes inactive, since there
> +is no way to get to it - there is no original to call any more. However,
> +Valgrind remembers that the wrapper is still present. If object1.so
> +eventually dlopen'd again, the wrapper will become active again.</para>
> +
> +<para>In short, valgrind inspects all code loading/unloading events to
> +ensure that the set of currently active wrappers remains consistent.</para>
> +
> +<para>A second possible problem is that of conflicting wrappers. It is
> +easily possible to load two or more wrappers, both of which claim
> +to be wrappers for some third function. In such cases Valgrind will
> +complain about conflicting wrappers when the second one appears, and
> +will honour only the first one.</para>
> +</sect2>
> +
> +<sect2 id="manual-core.wrapping.debugging" xreflabel="Debugging">
> +<title>Debugging</title>
> +
> +<para>Figuring out what's going on given the dynamic nature of wrapping
> +can be difficult. The --trace-redir=yes flag makes this possible
> +by showing the complete state of the redirection subsystem after
> +every mmap/munmap event affecting code (text).</para>
> +
> +<para>There are two central concepts:</para>
> +
> +<para>- A "redirection specification" is a binding of
> + a (soname pattern, fnname pattern) pair to a code address.
> + These bindings are created by writing functions with names
> + made with the I_WRAP_SONAME_FNNAME_{ZZ,_ZU} macros.</para>
> +
> +<para>- An "active redirection" is code-address to code-address binding
> + currently in effect.</para>
> +
> +<para>The state of the wrapping-and-redirection subsystem comprises a set of
> +specifications and a set of active bindings. The specifications are
> +acquired/discarded by watching all mmap/munmap events on code (text)
> +sections. The active binding set is (conceptually) recomputed from
> +the specifications, and all known symbol names, following any change
> +to the specification set.</para>
> +
> +<para>--trace-redir=yes shows the contents of both sets following any such
> +event.</para>
> +
> +<para>-v prints a line of text each time an active specification is
> +used for the first time.</para>
> +
> +<para>Hence for maximum debugging effectiveness you will need to use both
> +flags.</para>
> +
> +<para>One final comment. The function-wrapping facility is closely
> +tied to Valgrind's ability to replace (redirect) specified
> +functions, for example to redirect calls to malloc() to its
> +own implementation. Indeed, a replacement function can be
> +regarded as a wrapper function which does not call the original.
> +However, to make the implementation more robust, the two kinds
> +of interception (wrapping vs replacement) are treated differently.
> +</para>
> +
> +<para>--trace-redir=yes shows specifications and bindings for both
> +replacement and wrapper functions. To differentiate the
> +two, replacement bindings are printed using "R->" whereas
> +wraps are printed using "W->".</para>
> +</sect2>
> +
> +
> +<sect2 id="manual-core.wrapping.limitations-cf"
> + xreflabel="Limitations - control flow">
> +<title>Limitations - control flow</title>
> +
> +<para>For the most part, the function wrapping implementation is robust.
> +The only real caveat is that is is crucial, in a wrapper, get hold of
> +the OrigFn information using VALGRIND_GET_ORIG_FN before calling any
> +other wrapped function. Once you have the OrigFn, arbitrary
> +intercalling, recursion between, and longjumping out of wrappers
> +should work correctly. There is never any interaction between wrapped
> +functions and merely replaced functions (eg malloc), so you can call
> +malloc etc safely from within wrappers.</para>
> +
> +<para>The above comments are true for {x86,amd64,ppc32}-linux. On
> +ppc64-linux function wrapping is more fragile due to the (arguably
> +poorly designed) ppc64-linux ABI. This mandates the use of a shadow
> +stack which tracks entries/exits of both wrapper and replacment
> +functions. This gives two limitations: firstly, longjumping out of
> +wrappers will rapidly lead to disaster, since the shadow stack will
> +not get correctly cleared. Secondly, since the shadow stack has
> +finite size, recursion between wrapper/replacement functions is only
> +possible to a limited depth, beyond which Valgrind has to abort the
> +run. This depth is currently 16 calls.</para>
> +
> +<para>For all platforms ({x86,amd64,ppc32,ppc64}-linux) all the above
> +comments apply on a per-thread basis. In other words, wrapping is
> +thread-safe: each thread must individually observe the above
> +restrictions, but there is no need for any kind of inter-thread
> +cooperation.</para>
> +</sect2>
> +
> +
> +<sect2 id="manual-core.wrapping.limitations-sigs"
> + xreflabel="Limitations - original function signatures">
> +<title>Limitations - original function signatures</title>
> +
> +<para>As shown in the above example, to call the original you must use a
> +macro of the form CALL_FN_*. For technical reasons it is impossible
> +to create a single macro to deal with all argument types and numbers,
> +so a family of macros covering the most common cases is supplied. In
> +what follows, 'W' denotes a machine-word-typed value (a pointer or an
> +C 'long'), and 'v' denotes C's "void" type. The currently available
> +macros are:</para>
> +
> +<programlisting><![CDATA[
> + CALL_FN_v_v -- call an original of type void fn ( void )
> + CALL_FN_W_v -- call an original of type long fn ( void )
> +
> + CALL_FN_v_W -- void fn ( long )
> + CALL_FN_W_W -- long fn ( long )
> +
> + CALL_FN_v_WW -- void fn ( long, long )
> + CALL_FN_W_WW -- long fn ( long, long )
> +
> + CALL_FN_v_WWW -- void fn ( long, long, long )
> + CALL_FN_W_WWW -- long fn ( long, long, long )
> +
> + CALL_FN_W_WWWW -- long fn ( long, long, long, long )
> + CALL_FN_W_5W -- long fn ( long, long, long, long, long )
> + CALL_FN_W_6W -- long fn ( long, long, long, long, long, long )
> + and so on, up to
> + CALL_FN_W_12W
> +]]></programlisting>
> +
> +<para>The set of supported types can be expanded as needed. It is
> +regrettable that this limitation exists. Function wrapping has proven
> +difficult to implement, with a certain apparently unavoidable level of
> +ickyness. After several implementation attempts, the present
> +arrangement appears to be the least-worst tradeoff. At least it works
> +reliably in the presence of dynamic linking and dynamic code
> +loading/unloading.</para>
> +
> +<para>You should not attempt to wrap a function of one type signature with a
> +wrapper of a different type signature. Such trickery will surely lead
> +to crashes or strange behaviour. This is not of course a limitation
> +of the function wrapping implementation, merely a reflection of the
> +fact that it gives you sweeping powers to shoot yourself in the foot
> +if you are not careful. Imagine the instant havoc you could wreak by
> +writing a wrapper which matched any function name in any soname - in
> +effect, one which claimed to be a wrapper for all functions in the
> +process.</para>
> +</sect2>
> +
> +<sect2 id="manual-core.wrapping.examples" xreflabel="Examples">
> +<title>Examples</title>
> +
> +<para>In the source tree, memcheck/tests/wrap[1-8].c provide a series of
> +examples, ranging from very simple to quite advanced.</para>
> +
> +<para>auxprogs/libmpiwrap.c is an example of wrapping a big, complex API
> +(the MPI-2 interface). This file defines almost 300 different
> +wrappers.</para>
> +</sect2>
> +
> +</sect1>
> +
> +
> +
> <sect1 id="manual-core.install" xreflabel="Building and Installing">
> <title>Building and Installing</title>
>
>
> svnlook: Can't open directory '/tmp/svnlook.6': Not a directory
>
>
> -------------------------------------------------------
> This SF.Net email is sponsored by xPML, a groundbreaking scripting language
> that extends applications into web and mobile media. Attend the live webcast
> and join the prime developer group breaking into this new coding territory!
> http://sel.as-us.falkag.net/sel?cmd=k&kid0944&bid$1720&dat1642
> _______________________________________________
> Valgrind-developers mailing list
> Val...@li...
> https://lists.sourceforge.net/lists/listinfo/valgrind-developers
>
|
|
From: Bryan M. <br...@br...> - 2006-03-13 23:07:34
|
Looks OK to me but I have a question and the answer/clarification may
well belong inside:
I wrap a function, say memcpy for example.
program on sim cpu calls memcpy
|
V
redirected to my memcpy wrapper
|
V
wrapper does some stuff, possibly doing a client call or two
|
V
wrapper calls original function
Is this original function instrumented as normal - i.e. can I still
expect my dirty functions to be called etc or does the call and its
processing take place only on the real cpu?
If I used the wrapper to stop my dirty function processing whilst the
original function ran, how could I then update my state from the memory
and in particular, the registers that were touched during execution? I
see that there is the shadow stack for PPC but what about x86/x86_64 ?
Would a replacement function be a better solution instead in this case?
Have I possibly got the wrong end of the stick on this?
Thanks in advance,
Bryan "Brain Murders" Meredith
sv...@va... wrote:
> Author: sewardj
> Date: 2006-03-13 13:40:57 +0000 (Mon, 13 Mar 2006)
> New Revision: 5763
>
> Log:
> First pass at documenting how to use the function-wrapping facility.
>
> Modified:
> trunk/docs/xml/manual-core.xml
>
>
> /usr/local/etc/subversion//commit-email.pl: `/usr/local/bin/svnlook diff /home/svn/repos/valgrind -r 5763' failed with this output:
> Modified: trunk/docs/xml/manual-core.xml
> ===================================================================
> --- trunk/docs/xml/manual-core.xml 2006-03-12 19:28:34 UTC (rev 5762)
> +++ trunk/docs/xml/manual-core.xml 2006-03-13 13:40:57 UTC (rev 5763)
> @@ -1557,6 +1557,339 @@
>
>
>
> +<sect1 id="manual-core.wrapping" xreflabel="Function Wrapping">
> +<title>Function wrapping</title>
> +
> +<para>
> +Valgrind versions 3.2.0 and above and can do function wrapping on all
> +supported targets. In function wrapping, calls to some specified
> +function are intercepted and rerouted to a different, user-supplied
> +function. This can do whatever it likes, typically examining the
> +arguments, calling onwards to the original, and possibly examining the
> +result. Any number of different functions may be wrapped.</para>
> +
> +<para>
> +Function wrapping is useful for instrumenting an API in some way. For
> +example, wrapping functions in the POSIX pthreads API makes it
> +possible to notify Valgrind of thread status changes, and wrapping
> +functions in the MPI (message-passing) API allows notifying Valgrind
> +of memory status changes associated with message arrival/departure.
> +Such information is usually passed to Valgrind by using client
> +requests in the wrapper functions, although that is not of relevance
> +here.</para>
> +
> +<sect2 id="manual-core.wrapping.example" xreflabel="A Simple Example">
> +<title>A Simple Example</title>
> +
> +<para>Supposing we want to wrap some function</para>
> +
> +<programlisting><![CDATA[
> +int foo ( int x, int y ) { return x + y; }]]></programlisting>
> +
> +<para>
> +A wrapper is a function of identical type, but with a special name
> +which identifies it as the wrapper for foo. Wrappers need to include
> +supporting macros from valgrind.h. Here is a simple wrapper which
> +prints the arguments and return value:</para>
> +<programlisting><![CDATA[
> + #include <stdio.h>
> + #include "valgrind.h"
> + int I_WRAP_SONAME_FNNAME_ZU(NONE,foo)( int x, int y )
> + {
> + int result;
> + OrigFn fn;
> + VALGRIND_GET_ORIG_FN(fn);
> + printf("foo's wrapper: args %d %d\n", x, y);
> + CALL_FN_W_WW(result, fn, x,y);
> + printf("foo's wrapper: result %d\n", result);
> + return result;
> + }
> +]]></programlisting>
> +
> +<para>To become active, the wrapper merely needs to be present in a text
> +section somewhere in the same process' address space as the function
> +it wraps, and for its ELF symbol name to be visible to Valgrind. In
> +practice, this means either compiling to a .o and linking it in, or
> +compiling to a .so and LD_PRELOADing it in. The latter is more
> +convenient in that it doesn't require relinking.</para>
> +
> +<para>All wrappers have approximately the above form. There are three
> +crucial macros:</para>
> +
> +<para>I_WRAP_SONAME_FNNAME_ZU: this generates the real name of the wrapper.
> +This is an encoded name which Valgrind notices when reading symbol
> +table information. What it says is: I am the wrapper for any function
> +named "foo" which is found in an ELF shared object with an empty
> +("NONE") soname field. The specification mechanism is powerful in
> +that wildcards are allowed for both sonames and function names. More
> +details below.</para>
> +
> +<para>VALGRIND_GET_ORIG_FN: once in the the wrapper, the first priority is
> +to get hold of the address of the original (and any other supporting
> +information needed). This is stored in a value of opaque type OrigFn.
> +The information is acquired using VALGRIND_GET_ORIG_FN. It is crucial
> +to make this macro call before calling any other wrapped function
> +in the same thread.</para>
> +
> +<para>CALL_FN_W_WW: eventually we will want to call the function being
> +wrapped. Calling it directly does not work, since that just gets us
> +back to the wrapper and tends to kill the program in short order by
> +stack overflow. Instead, the result lvalue, OrigFn and arguments are
> +handed to one of a family of macros of the form CALL_FN_*. These
> +cause Valgrind to call the original and avoid recursion back to the
> +wrapper.</para>
> +</sect2>
> +
> +<sect2 id="manual-core.wrapping.specs" xreflabel="Wrapping Specifications">
> +<title>Wrapping Specifications</title>
> +
> +<para>This scheme has the advantage of being self-contained. A library of
> +wrappers can be compiled to object code in the normal way, and does
> +not rely on an external script telling Valgrind which wrappers pertain
> +to which originals.</para>
> +
> +<para>Each wrapper has a name which, in the most general case says: I am the
> +wrapper for any function whose name matches FNPATT and whose ELF
> +"soname" matches SOPATT. Both FNPATT and SOPATT may contain wildcards
> +(asterisks) and other characters (spaces, dots, @, etc) which are not
> +generally regarded as valid C identifier names.</para>
> +
> +<para>This flexibility is needed to write robust wrappers for POSIX pthread
> +functions, where typically we are not completely sure of either the
> +function name or the soname, or alternatively we want to wrap a whole
> +bunch of functions at once.</para>
> +
> +<para>For example, pthread_create() in GNU libpthread's is usually a
> +versioned symbol - one whose name ends in, eg, "@GLIBC_2.3". Hence we
> +are not sure what its real name is. We also want to cover any soname
> +of the form "libpthread.so*". So the header of the wrapper will be</para>
> +
> +<programlisting><![CDATA[
> +int I_WRAP_SONAME_FNNAME_ZZ(libpthreadZdsoZd0,pthreadZucreateZAZa)
> + ( ... formals ... )
> + { ... body ... }
> +]]></programlisting>
> +
> +<para>In order to write unusual characters as valid C function names, a
> +Z-encoding scheme is used. Names are written literally, except that
> +a capital Z acts as an escape character, with the following encoding:</para>
> +
> +<programlisting><![CDATA[
> + Za encodes *
> + Zp +
> + Zc :
> + Zd .
> + Zu _
> + Zh -
> + Zs (space)
> + ZA @
> + ZZ Z
> +]]></programlisting>
> +
> +<para>Hence libpthreadZdsoZd0 is an encoding of the soname "libpthread.so.0"
> +and "pthreadZucreateZAZa" is an encoding of the function name
> +"pthread_create@*".</para>
> +
> +<para>The macro I_WRAP_SONAME_FNNAME_ZZ constructs a wrapper name in which
> +both the soname (first component) and function name (second component)
> +are Z-encoded. Encoding the function name can be tiresome and is
> +often unnecessary, so a second macro, I_WRAP_SONAME_FNNAME_ZU, can be
> +used instead. The _ZU variant is also useful for writing wrappers for
> +C++ functions, in which the function name is usually already mangled
> +using some other convention in which Z plays an important role; having
> +to encode a second time quickly becomes confusing.</para>
> +
> +<para>Since the function name field may contain wildcards, it can be
> +anything, including just "*". The same is true for the soname.
> +However, some ELF objects - specifically, main executables - do not
> +have sonames. Any object lacking a soname is treated as if its soname
> +was "NONE", which is why the original example above had a name
> +I_WRAP_SONAME_FNNAME_ZU(NONE,foo).</para>
> +</sect2>
> +
> +<sect2 id="manual-core.wrapping.semantics" xreflabel="Wrapping Semantics">
> +<title>Wrapping Semantics</title>
> +
> +<para>The ability for a wrapper to replace an infinite family of functions
> +is powerful but brings complications in situations where ELF objects
> +appear and disappear (are dlopen'd and dlclose'd) on the fly.
> +Valgrind tries to maintain sensible behaviour in such situations.</para>
> +
> +<para>For example, suppose a process has dlopened (an ELF object with
> +soname) object1.so, which contains function1(). It starts to use
> +function1() immediately.</para>
> +
> +<para>After a while it dlopens wrappers.so, which contains a wrapper
> +for function1 in (soname) object1.so. All subsequent calls to
> +function1() are rerouted to the wrapper.</para>
> +
> +<para>If wrappers.so is later dlclose'd, calls to function1() are
> +naturally rerouted back to the original.</para>
> +
> +<para>Alternatively, if object1.so is dlclose'd but wrappers.so remains,
> +then the wrapper exported by wrapper.so becomes inactive, since there
> +is no way to get to it - there is no original to call any more. However,
> +Valgrind remembers that the wrapper is still present. If object1.so
> +eventually dlopen'd again, the wrapper will become active again.</para>
> +
> +<para>In short, valgrind inspects all code loading/unloading events to
> +ensure that the set of currently active wrappers remains consistent.</para>
> +
> +<para>A second possible problem is that of conflicting wrappers. It is
> +easily possible to load two or more wrappers, both of which claim
> +to be wrappers for some third function. In such cases Valgrind will
> +complain about conflicting wrappers when the second one appears, and
> +will honour only the first one.</para>
> +</sect2>
> +
> +<sect2 id="manual-core.wrapping.debugging" xreflabel="Debugging">
> +<title>Debugging</title>
> +
> +<para>Figuring out what's going on given the dynamic nature of wrapping
> +can be difficult. The --trace-redir=yes flag makes this possible
> +by showing the complete state of the redirection subsystem after
> +every mmap/munmap event affecting code (text).</para>
> +
> +<para>There are two central concepts:</para>
> +
> +<para>- A "redirection specification" is a binding of
> + a (soname pattern, fnname pattern) pair to a code address.
> + These bindings are created by writing functions with names
> + made with the I_WRAP_SONAME_FNNAME_{ZZ,_ZU} macros.</para>
> +
> +<para>- An "active redirection" is code-address to code-address binding
> + currently in effect.</para>
> +
> +<para>The state of the wrapping-and-redirection subsystem comprises a set of
> +specifications and a set of active bindings. The specifications are
> +acquired/discarded by watching all mmap/munmap events on code (text)
> +sections. The active binding set is (conceptually) recomputed from
> +the specifications, and all known symbol names, following any change
> +to the specification set.</para>
> +
> +<para>--trace-redir=yes shows the contents of both sets following any such
> +event.</para>
> +
> +<para>-v prints a line of text each time an active specification is
> +used for the first time.</para>
> +
> +<para>Hence for maximum debugging effectiveness you will need to use both
> +flags.</para>
> +
> +<para>One final comment. The function-wrapping facility is closely
> +tied to Valgrind's ability to replace (redirect) specified
> +functions, for example to redirect calls to malloc() to its
> +own implementation. Indeed, a replacement function can be
> +regarded as a wrapper function which does not call the original.
> +However, to make the implementation more robust, the two kinds
> +of interception (wrapping vs replacement) are treated differently.
> +</para>
> +
> +<para>--trace-redir=yes shows specifications and bindings for both
> +replacement and wrapper functions. To differentiate the
> +two, replacement bindings are printed using "R->" whereas
> +wraps are printed using "W->".</para>
> +</sect2>
> +
> +
> +<sect2 id="manual-core.wrapping.limitations-cf"
> + xreflabel="Limitations - control flow">
> +<title>Limitations - control flow</title>
> +
> +<para>For the most part, the function wrapping implementation is robust.
> +The only real caveat is that is is crucial, in a wrapper, get hold of
> +the OrigFn information using VALGRIND_GET_ORIG_FN before calling any
> +other wrapped function. Once you have the OrigFn, arbitrary
> +intercalling, recursion between, and longjumping out of wrappers
> +should work correctly. There is never any interaction between wrapped
> +functions and merely replaced functions (eg malloc), so you can call
> +malloc etc safely from within wrappers.</para>
> +
> +<para>The above comments are true for {x86,amd64,ppc32}-linux. On
> +ppc64-linux function wrapping is more fragile due to the (arguably
> +poorly designed) ppc64-linux ABI. This mandates the use of a shadow
> +stack which tracks entries/exits of both wrapper and replacment
> +functions. This gives two limitations: firstly, longjumping out of
> +wrappers will rapidly lead to disaster, since the shadow stack will
> +not get correctly cleared. Secondly, since the shadow stack has
> +finite size, recursion between wrapper/replacement functions is only
> +possible to a limited depth, beyond which Valgrind has to abort the
> +run. This depth is currently 16 calls.</para>
> +
> +<para>For all platforms ({x86,amd64,ppc32,ppc64}-linux) all the above
> +comments apply on a per-thread basis. In other words, wrapping is
> +thread-safe: each thread must individually observe the above
> +restrictions, but there is no need for any kind of inter-thread
> +cooperation.</para>
> +</sect2>
> +
> +
> +<sect2 id="manual-core.wrapping.limitations-sigs"
> + xreflabel="Limitations - original function signatures">
> +<title>Limitations - original function signatures</title>
> +
> +<para>As shown in the above example, to call the original you must use a
> +macro of the form CALL_FN_*. For technical reasons it is impossible
> +to create a single macro to deal with all argument types and numbers,
> +so a family of macros covering the most common cases is supplied. In
> +what follows, 'W' denotes a machine-word-typed value (a pointer or an
> +C 'long'), and 'v' denotes C's "void" type. The currently available
> +macros are:</para>
> +
> +<programlisting><![CDATA[
> + CALL_FN_v_v -- call an original of type void fn ( void )
> + CALL_FN_W_v -- call an original of type long fn ( void )
> +
> + CALL_FN_v_W -- void fn ( long )
> + CALL_FN_W_W -- long fn ( long )
> +
> + CALL_FN_v_WW -- void fn ( long, long )
> + CALL_FN_W_WW -- long fn ( long, long )
> +
> + CALL_FN_v_WWW -- void fn ( long, long, long )
> + CALL_FN_W_WWW -- long fn ( long, long, long )
> +
> + CALL_FN_W_WWWW -- long fn ( long, long, long, long )
> + CALL_FN_W_5W -- long fn ( long, long, long, long, long )
> + CALL_FN_W_6W -- long fn ( long, long, long, long, long, long )
> + and so on, up to
> + CALL_FN_W_12W
> +]]></programlisting>
> +
> +<para>The set of supported types can be expanded as needed. It is
> +regrettable that this limitation exists. Function wrapping has proven
> +difficult to implement, with a certain apparently unavoidable level of
> +ickyness. After several implementation attempts, the present
> +arrangement appears to be the least-worst tradeoff. At least it works
> +reliably in the presence of dynamic linking and dynamic code
> +loading/unloading.</para>
> +
> +<para>You should not attempt to wrap a function of one type signature with a
> +wrapper of a different type signature. Such trickery will surely lead
> +to crashes or strange behaviour. This is not of course a limitation
> +of the function wrapping implementation, merely a reflection of the
> +fact that it gives you sweeping powers to shoot yourself in the foot
> +if you are not careful. Imagine the instant havoc you could wreak by
> +writing a wrapper which matched any function name in any soname - in
> +effect, one which claimed to be a wrapper for all functions in the
> +process.</para>
> +</sect2>
> +
> +<sect2 id="manual-core.wrapping.examples" xreflabel="Examples">
> +<title>Examples</title>
> +
> +<para>In the source tree, memcheck/tests/wrap[1-8].c provide a series of
> +examples, ranging from very simple to quite advanced.</para>
> +
> +<para>auxprogs/libmpiwrap.c is an example of wrapping a big, complex API
> +(the MPI-2 interface). This file defines almost 300 different
> +wrappers.</para>
> +</sect2>
> +
> +</sect1>
> +
> +
> +
> <sect1 id="manual-core.install" xreflabel="Building and Installing">
> <title>Building and Installing</title>
>
>
> svnlook: Can't open directory '/tmp/svnlook.6': Not a directory
>
>
> -------------------------------------------------------
> This SF.Net email is sponsored by xPML, a groundbreaking scripting language
> that extends applications into web and mobile media. Attend the live webcast
> and join the prime developer group breaking into this new coding territory!
> http://sel.as-us.falkag.net/sel?cmd=k&kid0944&bid$1720&dat1642
> _______________________________________________
> Valgrind-developers mailing list
> Val...@li...
> https://lists.sourceforge.net/lists/listinfo/valgrind-developers
>
|
|
From: <sv...@va...> - 2006-03-13 21:26:41
|
Author: sewardj
Date: 2006-03-13 13:40:57 +0000 (Mon, 13 Mar 2006)
New Revision: 5763
Log:
First pass at documenting how to use the function-wrapping facility.
Modified:
trunk/docs/xml/manual-core.xml
/usr/local/etc/subversion//commit-email.pl: `/usr/local/bin/svnlook diff =
/home/svn/repos/valgrind -r 5763' failed with this output:
Modified: trunk/docs/xml/manual-core.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/docs/xml/manual-core.xml 2006-03-12 19:28:34 UTC (rev 5762)
+++ trunk/docs/xml/manual-core.xml 2006-03-13 13:40:57 UTC (rev 5763)
@@ -1557,6 +1557,339 @@
=20
=20
=20
+<sect1 id=3D"manual-core.wrapping" xreflabel=3D"Function Wrapping">
+<title>Function wrapping</title>
+
+<para>
+Valgrind versions 3.2.0 and above and can do function wrapping on all
+supported targets. In function wrapping, calls to some specified
+function are intercepted and rerouted to a different, user-supplied
+function. This can do whatever it likes, typically examining the
+arguments, calling onwards to the original, and possibly examining the
+result. Any number of different functions may be wrapped.</para>
+
+<para>
+Function wrapping is useful for instrumenting an API in some way. For
+example, wrapping functions in the POSIX pthreads API makes it
+possible to notify Valgrind of thread status changes, and wrapping
+functions in the MPI (message-passing) API allows notifying Valgrind
+of memory status changes associated with message arrival/departure.
+Such information is usually passed to Valgrind by using client
+requests in the wrapper functions, although that is not of relevance
+here.</para>
+
+<sect2 id=3D"manual-core.wrapping.example" xreflabel=3D"A Simple Example=
">
+<title>A Simple Example</title>
+
+<para>Supposing we want to wrap some function</para>
+
+<programlisting><![CDATA[
+int foo ( int x, int y ) { return x + y; }]]></programlisting>
+
+<para>
+A wrapper is a function of identical type, but with a special name
+which identifies it as the wrapper for foo. Wrappers need to include
+supporting macros from valgrind.h. Here is a simple wrapper which
+prints the arguments and return value:</para>
+<programlisting><![CDATA[
+ #include <stdio.h>
+ #include "valgrind.h"
+ int I_WRAP_SONAME_FNNAME_ZU(NONE,foo)( int x, int y )
+ {
+ int result;
+ OrigFn fn;
+ VALGRIND_GET_ORIG_FN(fn);
+ printf("foo's wrapper: args %d %d\n", x, y);
+ CALL_FN_W_WW(result, fn, x,y);
+ printf("foo's wrapper: result %d\n", result);
+ return result;
+ }
+]]></programlisting>
+
+<para>To become active, the wrapper merely needs to be present in a text
+section somewhere in the same process' address space as the function
+it wraps, and for its ELF symbol name to be visible to Valgrind. In
+practice, this means either compiling to a .o and linking it in, or
+compiling to a .so and LD_PRELOADing it in. The latter is more
+convenient in that it doesn't require relinking.</para>
+
+<para>All wrappers have approximately the above form. There are three
+crucial macros:</para>
+
+<para>I_WRAP_SONAME_FNNAME_ZU: this generates the real name of the wrapp=
er.
+This is an encoded name which Valgrind notices when reading symbol
+table information. What it says is: I am the wrapper for any function
+named "foo" which is found in an ELF shared object with an empty
+("NONE") soname field. The specification mechanism is powerful in
+that wildcards are allowed for both sonames and function names. More
+details below.</para>
+
+<para>VALGRIND_GET_ORIG_FN: once in the the wrapper, the first priority =
is
+to get hold of the address of the original (and any other supporting
+information needed). This is stored in a value of opaque type OrigFn.
+The information is acquired using VALGRIND_GET_ORIG_FN. It is crucial
+to make this macro call before calling any other wrapped function
+in the same thread.</para>
+
+<para>CALL_FN_W_WW: eventually we will want to call the function being
+wrapped. Calling it directly does not work, since that just gets us
+back to the wrapper and tends to kill the program in short order by
+stack overflow. Instead, the result lvalue, OrigFn and arguments are
+handed to one of a family of macros of the form CALL_FN_*. These
+cause Valgrind to call the original and avoid recursion back to the
+wrapper.</para>
+</sect2>
+
+<sect2 id=3D"manual-core.wrapping.specs" xreflabel=3D"Wrapping Specifica=
tions">
+<title>Wrapping Specifications</title>
+
+<para>This scheme has the advantage of being self-contained. A library =
of
+wrappers can be compiled to object code in the normal way, and does
+not rely on an external script telling Valgrind which wrappers pertain
+to which originals.</para>
+
+<para>Each wrapper has a name which, in the most general case says: I am=
the
+wrapper for any function whose name matches FNPATT and whose ELF
+"soname" matches SOPATT. Both FNPATT and SOPATT may contain wildcards
+(asterisks) and other characters (spaces, dots, @, etc) which are not=20
+generally regarded as valid C identifier names.</para>=20
+
+<para>This flexibility is needed to write robust wrappers for POSIX pthr=
ead
+functions, where typically we are not completely sure of either the
+function name or the soname, or alternatively we want to wrap a whole
+bunch of functions at once.</para>=20
+
+<para>For example, pthread_create() in GNU libpthread's is usually a
+versioned symbol - one whose name ends in, eg, "@GLIBC_2.3". Hence we
+are not sure what its real name is. We also want to cover any soname
+of the form "libpthread.so*". So the header of the wrapper will be</par=
a>
+
+<programlisting><![CDATA[
+int I_WRAP_SONAME_FNNAME_ZZ(libpthreadZdsoZd0,pthreadZucreateZAZa)
+ ( ... formals ... )
+ { ... body ... }
+]]></programlisting>
+
+<para>In order to write unusual characters as valid C function names, a
+Z-encoding scheme is used. Names are written literally, except that
+a capital Z acts as an escape character, with the following encoding:</p=
ara>
+
+<programlisting><![CDATA[
+ Za encodes *
+ Zp +
+ Zc :
+ Zd .
+ Zu _
+ Zh -
+ Zs (space)
+ ZA @
+ ZZ Z
+]]></programlisting>
+
+<para>Hence libpthreadZdsoZd0 is an encoding of the soname "libpthread.s=
o.0"
+and "pthreadZucreateZAZa" is an encoding of the function name
+"pthread_create@*".</para>
+
+<para>The macro I_WRAP_SONAME_FNNAME_ZZ constructs a wrapper name in whi=
ch
+both the soname (first component) and function name (second component)
+are Z-encoded. Encoding the function name can be tiresome and is
+often unnecessary, so a second macro, I_WRAP_SONAME_FNNAME_ZU, can be
+used instead. The _ZU variant is also useful for writing wrappers for
+C++ functions, in which the function name is usually already mangled
+using some other convention in which Z plays an important role; having
+to encode a second time quickly becomes confusing.</para>
+
+<para>Since the function name field may contain wildcards, it can be
+anything, including just "*". The same is true for the soname.
+However, some ELF objects - specifically, main executables - do not
+have sonames. Any object lacking a soname is treated as if its soname
+was "NONE", which is why the original example above had a name
+I_WRAP_SONAME_FNNAME_ZU(NONE,foo).</para>
+</sect2>
+
+<sect2 id=3D"manual-core.wrapping.semantics" xreflabel=3D"Wrapping Seman=
tics">
+<title>Wrapping Semantics</title>
+
+<para>The ability for a wrapper to replace an infinite family of functio=
ns
+is powerful but brings complications in situations where ELF objects
+appear and disappear (are dlopen'd and dlclose'd) on the fly.
+Valgrind tries to maintain sensible behaviour in such situations.</para>
+
+<para>For example, suppose a process has dlopened (an ELF object with
+soname) object1.so, which contains function1(). It starts to use
+function1() immediately.</para>
+
+<para>After a while it dlopens wrappers.so, which contains a wrapper
+for function1 in (soname) object1.so. All subsequent calls to=20
+function1() are rerouted to the wrapper.</para>
+
+<para>If wrappers.so is later dlclose'd, calls to function1() are=20
+naturally rerouted back to the original.</para>
+
+<para>Alternatively, if object1.so is dlclose'd but wrappers.so remains,
+then the wrapper exported by wrapper.so becomes inactive, since there
+is no way to get to it - there is no original to call any more. However=
,
+Valgrind remembers that the wrapper is still present. If object1.so
+eventually dlopen'd again, the wrapper will become active again.</para>
+
+<para>In short, valgrind inspects all code loading/unloading events to
+ensure that the set of currently active wrappers remains consistent.</pa=
ra>
+
+<para>A second possible problem is that of conflicting wrappers. It is=20
+easily possible to load two or more wrappers, both of which claim
+to be wrappers for some third function. In such cases Valgrind will
+complain about conflicting wrappers when the second one appears, and
+will honour only the first one.</para>
+</sect2>
+
+<sect2 id=3D"manual-core.wrapping.debugging" xreflabel=3D"Debugging">
+<title>Debugging</title>
+
+<para>Figuring out what's going on given the dynamic nature of wrapping
+can be difficult. The --trace-redir=3Dyes flag makes this possible
+by showing the complete state of the redirection subsystem after
+every mmap/munmap event affecting code (text).</para>
+
+<para>There are two central concepts:</para>
+
+<para>- A "redirection specification" is a binding of=20
+ a (soname pattern, fnname pattern) pair to a code address.
+ These bindings are created by writing functions with names
+ made with the I_WRAP_SONAME_FNNAME_{ZZ,_ZU} macros.</para>
+
+<para>- An "active redirection" is code-address to code-address binding
+ currently in effect.</para>
+
+<para>The state of the wrapping-and-redirection subsystem comprises a se=
t of
+specifications and a set of active bindings. The specifications are
+acquired/discarded by watching all mmap/munmap events on code (text)
+sections. The active binding set is (conceptually) recomputed from
+the specifications, and all known symbol names, following any change
+to the specification set.</para>
+
+<para>--trace-redir=3Dyes shows the contents of both sets following any =
such
+event.</para>
+
+<para>-v prints a line of text each time an active specification is=20
+used for the first time.</para>
+
+<para>Hence for maximum debugging effectiveness you will need to use bot=
h
+flags.</para>
+
+<para>One final comment. The function-wrapping facility is closely
+tied to Valgrind's ability to replace (redirect) specified
+functions, for example to redirect calls to malloc() to its
+own implementation. Indeed, a replacement function can be
+regarded as a wrapper function which does not call the original.
+However, to make the implementation more robust, the two kinds
+of interception (wrapping vs replacement) are treated differently.
+</para>
+
+<para>--trace-redir=3Dyes shows specifications and bindings for both
+replacement and wrapper functions. To differentiate the=20
+two, replacement bindings are printed using "R->" whereas=20
+wraps are printed using "W->".</para>
+</sect2>
+
+
+<sect2 id=3D"manual-core.wrapping.limitations-cf"=20
+ xreflabel=3D"Limitations - control flow">
+<title>Limitations - control flow</title>
+
+<para>For the most part, the function wrapping implementation is robust.
+The only real caveat is that is is crucial, in a wrapper, get hold of
+the OrigFn information using VALGRIND_GET_ORIG_FN before calling any
+other wrapped function. Once you have the OrigFn, arbitrary
+intercalling, recursion between, and longjumping out of wrappers
+should work correctly. There is never any interaction between wrapped
+functions and merely replaced functions (eg malloc), so you can call
+malloc etc safely from within wrappers.</para>
+
+<para>The above comments are true for {x86,amd64,ppc32}-linux. On
+ppc64-linux function wrapping is more fragile due to the (arguably
+poorly designed) ppc64-linux ABI. This mandates the use of a shadow
+stack which tracks entries/exits of both wrapper and replacment
+functions. This gives two limitations: firstly, longjumping out of
+wrappers will rapidly lead to disaster, since the shadow stack will
+not get correctly cleared. Secondly, since the shadow stack has
+finite size, recursion between wrapper/replacement functions is only
+possible to a limited depth, beyond which Valgrind has to abort the
+run. This depth is currently 16 calls.</para>
+
+<para>For all platforms ({x86,amd64,ppc32,ppc64}-linux) all the above
+comments apply on a per-thread basis. In other words, wrapping is
+thread-safe: each thread must individually observe the above
+restrictions, but there is no need for any kind of inter-thread
+cooperation.</para>
+</sect2>
+
+
+<sect2 id=3D"manual-core.wrapping.limitations-sigs"=20
+ xreflabel=3D"Limitations - original function signatures">
+<title>Limitations - original function signatures</title>
+
+<para>As shown in the above example, to call the original you must use a
+macro of the form CALL_FN_*. For technical reasons it is impossible
+to create a single macro to deal with all argument types and numbers,
+so a family of macros covering the most common cases is supplied. In
+what follows, 'W' denotes a machine-word-typed value (a pointer or an
+C 'long'), and 'v' denotes C's "void" type. The currently available
+macros are:</para>
+
+<programlisting><![CDATA[
+ CALL_FN_v_v -- call an original of type void fn ( void )
+ CALL_FN_W_v -- call an original of type long fn ( void )
+
+ CALL_FN_v_W -- void fn ( long )
+ CALL_FN_W_W -- long fn ( long )
+
+ CALL_FN_v_WW -- void fn ( long, long )
+ CALL_FN_W_WW -- long fn ( long, long )
+
+ CALL_FN_v_WWW -- void fn ( long, long, long )
+ CALL_FN_W_WWW -- long fn ( long, long, long )
+
+ CALL_FN_W_WWWW -- long fn ( long, long, long, long )
+ CALL_FN_W_5W -- long fn ( long, long, long, long, long )
+ CALL_FN_W_6W -- long fn ( long, long, long, long, long, long )
+ and so on, up to=20
+ CALL_FN_W_12W
+]]></programlisting>
+
+<para>The set of supported types can be expanded as needed. It is
+regrettable that this limitation exists. Function wrapping has proven
+difficult to implement, with a certain apparently unavoidable level of
+ickyness. After several implementation attempts, the present
+arrangement appears to be the least-worst tradeoff. At least it works
+reliably in the presence of dynamic linking and dynamic code
+loading/unloading.</para>
+
+<para>You should not attempt to wrap a function of one type signature wi=
th a
+wrapper of a different type signature. Such trickery will surely lead
+to crashes or strange behaviour. This is not of course a limitation
+of the function wrapping implementation, merely a reflection of the
+fact that it gives you sweeping powers to shoot yourself in the foot
+if you are not careful. Imagine the instant havoc you could wreak by
+writing a wrapper which matched any function name in any soname - in
+effect, one which claimed to be a wrapper for all functions in the
+process.</para>
+</sect2>
+
+<sect2 id=3D"manual-core.wrapping.examples" xreflabel=3D"Examples">
+<title>Examples</title>
+
+<para>In the source tree, memcheck/tests/wrap[1-8].c provide a series of
+examples, ranging from very simple to quite advanced.</para>
+
+<para>auxprogs/libmpiwrap.c is an example of wrapping a big, complex API
+(the MPI-2 interface). This file defines almost 300 different
+wrappers.</para>
+</sect2>
+
+</sect1>
+
+
+
<sect1 id=3D"manual-core.install" xreflabel=3D"Building and Installing">
<title>Building and Installing</title>
=20
svnlook: Can't open directory '/tmp/svnlook.6': Not a directory
|
|
From: <js...@ac...> - 2006-03-13 10:48:33
|
Nightly build on minnie ( SuSE 10.0, ppc32 ) started at 2006-03-13 02:00:01 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 194 tests, 11 stderr failures, 5 stdout failures ================= memcheck/tests/leak-cycle (stderr) memcheck/tests/leak-tree (stderr) memcheck/tests/leakotron (stdout) memcheck/tests/mempool (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/sigaltstack (stderr) memcheck/tests/stack_changes (stdout) memcheck/tests/stack_changes (stderr) memcheck/tests/xml1 (stderr) none/tests/faultstatus (stderr) none/tests/mremap (stderr) none/tests/ppc32/jm-fp (stdout) none/tests/ppc32/jm-fp (stderr) none/tests/ppc32/test_fx (stdout) none/tests/ppc32/test_fx (stderr) none/tests/ppc32/test_gx (stdout) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Last 20 lines of verbose log follow echo wrap6-wrap6.o: In function `_vgwZU_NONE_fn_9': /home/sewardj/Nightly/valgrind/memcheck/tests/wrap6.c:432: undefined reference to `CALL_FN_W_9W' wrap6-wrap6.o: In function `_vgwZU_NONE_fn_10': /home/sewardj/Nightly/valgrind/memcheck/tests/wrap6.c:471: undefined reference to `CALL_FN_W_10W' wrap6-wrap6.o: In function `_vgwZU_NONE_fn_11': /home/sewardj/Nightly/valgrind/memcheck/tests/wrap6.c:511: undefined reference to `CALL_FN_W_11W' wrap6-wrap6.o: In function `_vgwZU_NONE_fn_12': /home/sewardj/Nightly/valgrind/memcheck/tests/wrap6.c:553: undefined reference to `CALL_FN_W_12W' collect2: ld returned 1 exit status make[5]: *** [wrap6] Error 1 make[5]: Leaving directory `/home/sewardj/Nightly/valgrind/memcheck/tests' make[4]: *** [check-am] Error 2 make[4]: Leaving directory `/home/sewardj/Nightly/valgrind/memcheck/tests' make[3]: *** [check-recursive] Error 1 make[3]: Leaving directory `/home/sewardj/Nightly/valgrind/memcheck/tests' make[2]: *** [check-recursive] Error 1 make[2]: Leaving directory `/home/sewardj/Nightly/valgrind/memcheck' make[1]: *** [check-recursive] Error 1 make[1]: Leaving directory `/home/sewardj/Nightly/valgrind' make: *** [check] Error 2 ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Mon Mar 13 02:05:53 2006 --- new.short Mon Mar 13 02:16:07 2006 *************** *** 6,27 **** ! Last 20 lines of verbose log follow echo ! wrap6-wrap6.o: In function `_vgwZU_NONE_fn_9': ! /home/sewardj/Nightly/valgrind/memcheck/tests/wrap6.c:432: undefined reference to `CALL_FN_W_9W' ! wrap6-wrap6.o: In function `_vgwZU_NONE_fn_10': ! /home/sewardj/Nightly/valgrind/memcheck/tests/wrap6.c:471: undefined reference to `CALL_FN_W_10W' ! wrap6-wrap6.o: In function `_vgwZU_NONE_fn_11': ! /home/sewardj/Nightly/valgrind/memcheck/tests/wrap6.c:511: undefined reference to `CALL_FN_W_11W' ! wrap6-wrap6.o: In function `_vgwZU_NONE_fn_12': ! /home/sewardj/Nightly/valgrind/memcheck/tests/wrap6.c:553: undefined reference to `CALL_FN_W_12W' ! collect2: ld returned 1 exit status ! make[5]: *** [wrap6] Error 1 ! make[5]: Leaving directory `/home/sewardj/Nightly/valgrind/memcheck/tests' ! make[4]: *** [check-am] Error 2 ! make[4]: Leaving directory `/home/sewardj/Nightly/valgrind/memcheck/tests' ! make[3]: *** [check-recursive] Error 1 ! make[3]: Leaving directory `/home/sewardj/Nightly/valgrind/memcheck/tests' ! make[2]: *** [check-recursive] Error 1 ! make[2]: Leaving directory `/home/sewardj/Nightly/valgrind/memcheck' ! make[1]: *** [check-recursive] Error 1 ! make[1]: Leaving directory `/home/sewardj/Nightly/valgrind' ! make: *** [check] Error 2 --- 6,26 ---- ! Regression test results follow ! ! == 194 tests, 11 stderr failures, 5 stdout failures ================= ! memcheck/tests/leak-cycle (stderr) ! memcheck/tests/leak-tree (stderr) ! memcheck/tests/leakotron (stdout) ! memcheck/tests/mempool (stderr) ! memcheck/tests/pointer-trace (stderr) ! memcheck/tests/sigaltstack (stderr) ! memcheck/tests/stack_changes (stdout) ! memcheck/tests/stack_changes (stderr) ! memcheck/tests/xml1 (stderr) ! none/tests/faultstatus (stderr) ! none/tests/mremap (stderr) ! none/tests/ppc32/jm-fp (stdout) ! none/tests/ppc32/jm-fp (stderr) ! none/tests/ppc32/test_fx (stdout) ! none/tests/ppc32/test_fx (stderr) ! none/tests/ppc32/test_gx (stdout) ! |
|
From: <js...@ac...> - 2006-03-13 04:52:52
|
Nightly build on phoenix ( SuSE 10.0 ) started at 2006-03-13 03:30:01 GMT Checking out vex source tree ... done Building vex ... done Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 225 tests, 6 stderr failures, 0 stdout failures ================= memcheck/tests/leak-tree (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) none/tests/x86/faultstatus (stderr) none/tests/x86/int (stderr) |
|
From: <js...@ac...> - 2006-03-13 03:49:21
|
Nightly build on g5 ( YDL 4.0, ppc970 ) started at 2006-03-13 04:40:00 CET
Results differ from 24 hours ago
Checking out valgrind source tree ... done
Configuring valgrind ... done
Building valgrind ... done
Running regression tests ... failed
Regression test results follow
== 199 tests, 6 stderr failures, 2 stdout failures =================
memcheck/tests/leak-cycle (stderr)
memcheck/tests/leak-tree (stderr)
memcheck/tests/leakotron (stdout)
memcheck/tests/pointer-trace (stderr)
none/tests/faultstatus (stderr)
none/tests/fdleak_fcntl (stderr)
none/tests/mremap (stderr)
none/tests/ppc32/mftocrf (stdout)
=================================================
== Results from 24 hours ago ==
=================================================
Checking out valgrind source tree ... done
Configuring valgrind ... done
Building valgrind ... failed
Last 20 lines of verbose log follow echo
mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Get_count':
mpiwrap.c:866: warning: implicit declaration of function `CALL_FN_W_WWW'
mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Testall':
mpiwrap.c:1267: warning: implicit declaration of function `CALL_FN_W_WWWW'
mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Iprobe':
mpiwrap.c:1299: warning: implicit declaration of function `CALL_FN_W_5W'
mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Sendrecv':
mpiwrap.c:1372: warning: implicit declaration of function `CALL_FN_W_12W'
mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Gather':
mpiwrap.c:1499: warning: implicit declaration of function `CALL_FN_W_8W'
mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Accumulate':
mpiwrap.c:1953: warning: implicit declaration of function `CALL_FN_W_9W'
mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Type_create_darray':
mpiwrap.c:2190: warning: implicit declaration of function `CALL_FN_W_10W'
mpicc: No such file or directory
make[2]: *** [libmpiwrap.so] Error 1
make[2]: Leaving directory `/home/sewardj/Nightly/valgrind/auxprogs'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/sewardj/Nightly/valgrind'
make: *** [all] Error 2
=================================================
== Difference between 24 hours ago and now ==
=================================================
*** old.short Mon Mar 13 04:41:54 2006
--- new.short Mon Mar 13 04:49:16 2006
***************
*** 3,26 ****
Configuring valgrind ... done
! Building valgrind ... failed
- Last 20 lines of verbose log follow echo
- mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Get_count':
- mpiwrap.c:866: warning: implicit declaration of function `CALL_FN_W_WWW'
- mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Testall':
- mpiwrap.c:1267: warning: implicit declaration of function `CALL_FN_W_WWWW'
- mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Iprobe':
- mpiwrap.c:1299: warning: implicit declaration of function `CALL_FN_W_5W'
- mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Sendrecv':
- mpiwrap.c:1372: warning: implicit declaration of function `CALL_FN_W_12W'
- mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Gather':
- mpiwrap.c:1499: warning: implicit declaration of function `CALL_FN_W_8W'
- mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Accumulate':
- mpiwrap.c:1953: warning: implicit declaration of function `CALL_FN_W_9W'
- mpiwrap.c: In function `_vgwZU_libmpiZdsoZa_PMPI_Type_create_darray':
- mpiwrap.c:2190: warning: implicit declaration of function `CALL_FN_W_10W'
- mpicc: No such file or directory
- make[2]: *** [libmpiwrap.so] Error 1
- make[2]: Leaving directory `/home/sewardj/Nightly/valgrind/auxprogs'
- make[1]: *** [all-recursive] Error 1
- make[1]: Leaving directory `/home/sewardj/Nightly/valgrind'
- make: *** [all] Error 2
--- 3,18 ----
Configuring valgrind ... done
! Building valgrind ... done
! Running regression tests ... failed
!
! Regression test results follow
!
! == 199 tests, 6 stderr failures, 2 stdout failures =================
! memcheck/tests/leak-cycle (stderr)
! memcheck/tests/leak-tree (stderr)
! memcheck/tests/leakotron (stdout)
! memcheck/tests/pointer-trace (stderr)
! none/tests/faultstatus (stderr)
! none/tests/fdleak_fcntl (stderr)
! none/tests/mremap (stderr)
! none/tests/ppc32/mftocrf (stdout)
|
|
From: Tom H. <to...@co...> - 2006-03-13 03:44:19
|
Nightly build on dunsmere ( athlon, Fedora Core 4 ) started at 2006-03-13 03:30:07 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 227 tests, 8 stderr failures, 1 stdout failure ================= memcheck/tests/leak-tree (stderr) memcheck/tests/mempool (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) memcheck/tests/x86/sse1_memory (stdout) none/tests/x86/faultstatus (stderr) none/tests/x86/int (stderr) |
|
From: Tom H. <th...@cy...> - 2006-03-13 03:33:09
|
Nightly build on alvis ( i686, Red Hat 7.3 ) started at 2006-03-13 03:15:05 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 226 tests, 21 stderr failures, 1 stdout failure ================= memcheck/tests/addressable (stderr) memcheck/tests/badjump (stderr) memcheck/tests/describe-block (stderr) memcheck/tests/erringfds (stderr) memcheck/tests/leak-0 (stderr) memcheck/tests/leak-cycle (stderr) memcheck/tests/leak-regroot (stderr) memcheck/tests/leak-tree (stderr) memcheck/tests/match-overrun (stderr) memcheck/tests/mempool (stderr) memcheck/tests/partial_load_dflt (stderr) memcheck/tests/partial_load_ok (stderr) memcheck/tests/partiallydefinedeq (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/sigkill (stderr) memcheck/tests/stack_changes (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) memcheck/tests/x86/sse1_memory (stdout) memcheck/tests/xml1 (stderr) none/tests/x86/faultstatus (stderr) none/tests/x86/int (stderr) |
|
From: Tom H. <th...@cy...> - 2006-03-13 03:26:23
|
Nightly build on dellow ( x86_64, Fedora Core 4 ) started at 2006-03-13 03:10:09 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 249 tests, 5 stderr failures, 1 stdout failure ================= memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) memcheck/tests/x86/sse1_memory (stdout) none/tests/amd64/faultstatus (stderr) none/tests/x86/faultstatus (stderr) none/tests/x86/int (stderr) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 249 tests, 6 stderr failures, 1 stdout failure ================= memcheck/tests/pointer-trace (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) memcheck/tests/x86/sse1_memory (stdout) none/tests/amd64/faultstatus (stderr) none/tests/x86/faultstatus (stderr) none/tests/x86/int (stderr) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Mon Mar 13 03:18:59 2006 --- new.short Mon Mar 13 03:26:13 2006 *************** *** 8,11 **** ! == 249 tests, 6 stderr failures, 1 stdout failure ================= ! memcheck/tests/pointer-trace (stderr) memcheck/tests/x86/scalar (stderr) --- 8,10 ---- ! == 249 tests, 5 stderr failures, 1 stdout failure ================= memcheck/tests/x86/scalar (stderr) |
|
From: Tom H. <th...@cy...> - 2006-03-13 03:23:22
|
Nightly build on aston ( x86_64, Fedora Core 3 ) started at 2006-03-13 03:05:14 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 249 tests, 6 stderr failures, 1 stdout failure ================= memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) memcheck/tests/x86/sse1_memory (stdout) none/tests/amd64/faultstatus (stderr) none/tests/x86/faultstatus (stderr) none/tests/x86/int (stderr) |
|
From: Tom H. <th...@cy...> - 2006-03-13 03:17:45
|
Nightly build on gill ( x86_64, Fedora Core 2 ) started at 2006-03-13 03:00:04 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 249 tests, 7 stderr failures, 1 stdout failure ================= memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) memcheck/tests/x86/sse1_memory (stdout) none/tests/amd64/faultstatus (stderr) none/tests/fdleak_fcntl (stderr) none/tests/x86/faultstatus (stderr) none/tests/x86/int (stderr) |