blob: 6f70836bfda3904213dadca37e99a3594e57491c [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- The core/tool interface. pub_tool_tooliface.h ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2005 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 VexGuestLayout
/* ------------------------------------------------------------------ */
/* The interface version */
/* The version number indicates binary-incompatible changes to the
interface; if the core and tool versions don't match, Valgrind
will abort. */
#define VG_CORE_INTERFACE_VERSION 9
typedef struct _ToolInfo {
Int sizeof_ToolInfo;
Int interface_version;
/* Initialise tool. Must do the following:
- initialise the `details' struct, via the VG_(details_*)() functions
- register any helpers called by generated code
May do the following:
- initialise the `needs' struct to indicate certain requirements, via
the VG_(needs_*)() functions
- initialize all the tool's entrypoints via the VG_(init_*)() functions
- register any tool-specific profiling events
- any other tool-specific initialisation
*/
void (*tl_pre_clo_init) ( void );
} ToolInfo;
extern const ToolInfo VG_(tool_info);
/* Every tool must include this macro somewhere, exactly once. */
#define VG_DETERMINE_INTERFACE_VERSION(pre_clo_init) \
const ToolInfo VG_(tool_info) = { \
.sizeof_ToolInfo = sizeof(ToolInfo), \
.interface_version = VG_CORE_INTERFACE_VERSION, \
.tl_pre_clo_init = pre_clo_init, \
};
/* ------------------------------------------------------------------ */
/* Basic tool functions */
/* The tool_instrument function is passed as a callback to
LibVEX_Translate. VgInstrumentClosure 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... Note that orig_addr_noredir is not necessarily the
// same as the address of the first instruction in the IR, due to
// function redirection.
IRBB*(*instrument)(VgCallbackClosure*,
IRBB* bb_in,
VexGuestLayout*, VexGuestExtents*,
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 100
/* 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 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_basic_block_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 orig_addr which was passed to
// to instrument() 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_basic_block_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.
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 data symbols? */
extern void VG_(needs_data_syms) ( void );
/* Does the tool need shadow memory allocated? */
extern void VG_(needs_shadow_memory)( 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 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 );
/* ------------------------------------------------------------------ */
/* 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, Vg_CorePThread, 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
*/
void VG_(track_new_mem_startup) (void(*f)(Addr a, SizeT len,
Bool rr, Bool ww, Bool xx));
void VG_(track_new_mem_stack_signal)(void(*f)(Addr a, SizeT len));
void VG_(track_new_mem_brk) (void(*f)(Addr a, SizeT len));
void VG_(track_new_mem_mmap) (void(*f)(Addr a, SizeT len,
Bool rr, Bool ww, Bool xx));
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.
*/
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, OffT guest_state_offset,
SizeT size));
void VG_(track_post_reg_write)(void(*f)(CorePart part, ThreadId tid,
OffT 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, OffT guest_state_offset, SizeT size, Addr f));
/* Scheduler events (not exhaustive) */
void VG_(track_thread_run)(void(*f)(ThreadId tid));
/* Thread events (not exhaustive)
Called during thread create, before the new thread has run any
instructions (or touched any memory).
*/
void VG_(track_post_thread_create)(void(*f)(ThreadId tid, ThreadId child));
void VG_(track_post_thread_join) (void(*f)(ThreadId joiner, ThreadId joinee));
/* Mutex events (not exhaustive)
"void *mutex" is really a pthread_mutex *
Called before a thread can block while waiting for a mutex (called
regardless of whether the thread will block or not). */
void VG_(track_pre_mutex_lock)(void(*f)(ThreadId tid, void* mutex));
/* Called once the thread actually holds the mutex (always paired with
pre_mutex_lock). */
void VG_(track_post_mutex_lock)(void(*f)(ThreadId tid, void* mutex));
/* Called after a thread has released a mutex (no need for a corresponding
pre_mutex_unlock, because unlocking can't block). */
void VG_(track_post_mutex_unlock)(void(*f)(ThreadId tid, void* mutex));
/* 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));
/* Others... condition variables...
...
*/
#endif // __PUB_TOOL_TOOLIFACE_H
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/