|Valgrind 3.3 - Advanced Debugging and Profiling for GNU/Linux applications|
by J. Seward, N. Nethercote, J. Weidendorfer and the Valgrind Development Team
Paperback (6"x9"), 164 pages
RRP £12.95 ($19.95)
4.1 The Client Request mechanism
Valgrind has a trapdoor mechanism via which the client program can pass all manner of requests and queries to Valgrind and the current tool. Internally, this is used extensively to make malloc, free, etc, work, although you don't see that.
For your convenience, a subset of these so-called client requests is provided to allow you to tell Valgrind facts about the behaviour of your program, and also to make queries. In particular, your program can tell Valgrind about changes in memory range permissions that Valgrind would not otherwise know about, and so allows clients to get Valgrind to do arbitrary custom checks.
Clients need to include a header file to make this work. Which header file depends on which client requests you use. Some client requests are handled by the core, and are defined in the header file ‘valgrind/valgrind.h’. Tool-specific header files are named after the tool, e.g. ‘valgrind/memcheck.h’. All header files can be found in the ‘include/valgrind’ directory of wherever Valgrind was installed.
The macros in these header files have the magical property that they generate code in-line which Valgrind can spot. However, the code does nothing when not run on Valgrind, so you are not forced to run your program under Valgrind just because you use the macros in this file. Also, you are not required to link your program with any extra supporting libraries.
The code added to your binary has negligible performance impact: on x86, amd64, ppc32 and ppc64, the overhead is 6 simple integer instructions and is probably undetectable except in tight loops. However, if you really wish to compile out the client requests, you can compile with ‘-DNVALGRIND’ (analogous to ‘-DNDEBUG’'s effect on ‘assert()’).
You are encouraged to copy the ‘valgrind/*.h’ headers into your project's include directory, so your program doesn't have a compile-time dependency on Valgrind being installed. The Valgrind headers, unlike most of the rest of the code, are under a BSD-style license so you may include them without worrying about license incompatibility.
Here is a brief description of the macros available in ‘valgrind.h’, which work with more than one tool (see the tool-specific documentation for explanations of the tool-specific macros).
‘RUNNING_ON_VALGRIND’: Returns 1 if running on Valgrind, 0 if running on the real CPU. If you are running Valgrind on itself, returns the number of layers of Valgrind emulation you're running on.
‘VALGRIND_DISCARD_TRANSLATIONS’:Discards translations of code in the specified address range. Useful if you are debugging a JIT compiler or some other dynamic code generation system. After this call, attempts to execute code in the invalidated address range will cause Valgrind to make new translations of that code, which is probably the semantics you want. Note that code invalidations are expensive because finding all the relevant translations quickly is very difficult. So try not to call it often. Note that you can be clever about this: you only need to call it when an area which previously contained code is overwritten with new code. You can choose to write code into fresh memory, and just call this occasionally to discard large chunks of old code all at once. Alternatively, for transparent self-modifying-code support, use ‘--smc-check=all’, or run on ppc32/Linux or ppc64/Linux.
‘VALGRIND_COUNT_ERRORS’:Returns the number of errors found so far by Valgrind. Can be useful in test harness code when combined with the
--log-fd=-1option; this runs Valgrind silently, but the client program can detect when errors occur. Only useful for tools that report errors, e.g. it's useful for Memcheck, but for Cachegrind it will always return zero because Cachegrind doesn't report errors.
‘VALGRIND_MALLOCLIKE_BLOCK’:If your program manages its own memory instead of using the standard ‘malloc()’ / ‘new’ / ‘new’, tools that track information about heap blocks will not do nearly as good a job. For example, Memcheck won't detect nearly as many errors, and the error messages won't be as informative. To improve this situation, use this macro just after your custom allocator allocates some new memory. See the comments in ‘valgrind.h’ for information on how to use it.
‘VALGRIND_FREELIKE_BLOCK’:This should be used in conjunction with ‘VALGRIND_MALLOCLIKE_BLOCK’. Again, see ‘memcheck/memcheck.h’ for information on how to use it.
‘VALGRIND_CREATE_MEMPOOL’:This is similar to ‘VALGRIND_MALLOCLIKE_BLOCK’, but is tailored towards code that uses memory pools. See the comments in ‘valgrind.h’ for information on how to use it.
‘VALGRIND_DESTROY_MEMPOOL’:This should be used in conjunction with ‘VALGRIND_CREATE_MEMPOOL’. Again, see the comments in ‘valgrind.h’ for information on how to use it.
‘VALGRIND_MEMPOOL_ALLOC’:This should be used in conjunction with ‘VALGRIND_CREATE_MEMPOOL’. Again, see the comments in ‘valgrind.h’ for information on how to use it.
‘VALGRIND_MEMPOOL_FREE’:This should be used in conjunction with ‘VALGRIND_CREATE_MEMPOOL’. Again, see the comments in ‘valgrind.h’ for information on how to use it.
‘VALGRIND_NON_SIMD_CALL’:Executes a function of 0, 1, 2 or 3 args in the client program on the real CPU, not the virtual CPU that Valgrind normally runs code on. These are used in various ways internally to Valgrind. They might be useful to client programs.
Warning:Only use these if you really know what you are doing. They aren't entirely reliable, and can cause Valgrind to 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.
‘VALGRIND_PRINTF(format, ...)’:printf a message to the log file when running under Valgrind. Nothing is output if not running under Valgrind. Returns the number of characters output.
‘VALGRIND_PRINTF_BACKTRACE(format, ...)’:printf a message to the log file along with a stack backtrace when running under Valgrind. Nothing is output if not running under Valgrind. Returns the number of characters output.
‘VALGRIND_STACK_REGISTER(start, end)’:Registers a new stack. Informs Valgrind that the memory range between start and end is a unique stack. Returns a stack identifier that can be used with other ‘VALGRIND_STACK_*’ calls. Valgrind will use this information to determine if a change to the stack pointer is an item pushed onto the stack or a change over to a new stack. Use this if you're using a user-level thread package and are noticing spurious errors from Valgrind about uninitialized memory reads.
‘VALGRIND_STACK_DEREGISTER(id)’:Deregisters a previously registered stack. Informs Valgrind that previously registered memory range with stack id ‘id’ is no longer a stack.
‘VALGRIND_STACK_CHANGE(id, start, end)’:Changes a previously registered stack. Informs Valgrind that the previously registered stack with stack id ‘id’ has changed its start and end values. Use this if your user-level thread package implements stack growth.
Note that ‘valgrind.h’ is included by all the tool-specific header files (such as ‘memcheck.h’), so you don't need to include it in your client if you include a tool-specific header.
|ISBN 0954612051||Valgrind 3.3 - Advanced Debugging and Profiling for GNU/Linux applications||See the print edition|