blob: 40d832504987e36f2ba483a4dfa8805f55df0857 [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Stuff relating to tool data structures. ---*/
/*--- m_tooliface.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2013 Nicholas Nethercote
njn@valgrind.org
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#include "pub_core_basics.h"
#include "pub_core_tooliface.h"
#include "pub_core_transtab.h" /* VG_(ok_to_discard_translations) */
// The core/tool dictionary of functions (initially zeroed, as we want it)
VgToolInterface VG_(tdict);
/*--------------------------------------------------------------------*/
/* Setting basic functions */
void VG_(basic_tool_funcs)(
void(*post_clo_init)(void),
IRSB*(*instrument)(VgCallbackClosure*, IRSB*,
const VexGuestLayout*, const VexGuestExtents*,
const VexArchInfo*, IRType, IRType),
void(*fini)(Int)
)
{
VG_(tdict).tool_post_clo_init = post_clo_init;
VG_(tdict).tool_instrument = instrument;
VG_(tdict).tool_fini = fini;
}
/*--------------------------------------------------------------------*/
/* Setting details */
/* Init with default values. */
VgDetails VG_(details) = {
.name = NULL,
.version = NULL,
.description = NULL,
.copyright_author = NULL,
.bug_reports_to = NULL,
.avg_translation_sizeB = VG_DEFAULT_TRANS_SIZEB,
};
/* Use macro because they're so repetitive */
#define DETAILS(type, detail) \
extern void VG_(details_##detail)(type detail) \
{ \
VG_(details).detail = detail; \
}
DETAILS(const HChar*, name)
DETAILS(const HChar*, version)
DETAILS(const HChar*, description)
DETAILS(const HChar*, copyright_author)
DETAILS(const HChar*, bug_reports_to)
DETAILS(UInt, avg_translation_sizeB)
/*--------------------------------------------------------------------*/
/* Setting needs */
VgNeeds VG_(needs) = {
.core_errors = False,
.tool_errors = False,
.libc_freeres = False,
.superblock_discards = False,
.command_line_options = False,
.client_requests = False,
.syscall_wrapper = False,
.sanity_checks = False,
.print_stats = False,
.info_location = False,
.var_info = False,
.malloc_replacement = False,
.xml_output = False,
.final_IR_tidy_pass = False
};
/* static */
Bool VG_(sanity_check_needs)(const HChar** failmsg)
{
Bool any_new_mem_stack_N, any_new_mem_stack_N_w_ECU;
Bool any_new_mem_stack_w_conflicting_otags;
Bool any_die_mem_stack_N;
#define CHECK_NOT(var, value) \
if ((var)==(value)) { \
*failmsg = "Tool error: '" #var "' not initialised\n"; \
return False; \
}
/* Ones that must be set */
CHECK_NOT(VG_(details).name, NULL);
/* Nb: .version can be NULL */
CHECK_NOT(VG_(details).description, NULL);
CHECK_NOT(VG_(details).copyright_author, NULL);
CHECK_NOT(VG_(details).bug_reports_to, NULL);
/* Check that new_mem_stack is defined if any new_mem_stack_N
are. */
any_new_mem_stack_N
= VG_(tdict).track_new_mem_stack_4 ||
VG_(tdict).track_new_mem_stack_8 ||
VG_(tdict).track_new_mem_stack_12 ||
VG_(tdict).track_new_mem_stack_16 ||
VG_(tdict).track_new_mem_stack_32 ||
VG_(tdict).track_new_mem_stack_112 ||
VG_(tdict).track_new_mem_stack_128 ||
VG_(tdict).track_new_mem_stack_144 ||
VG_(tdict).track_new_mem_stack_160;
if (any_new_mem_stack_N && ! VG_(tdict).track_new_mem_stack) {
*failmsg = "Tool error: one of the specialised 'new_mem_stack_N'\n"
" events tracked, but not the generic 'new_mem_stack' one.\n"
" 'new_mem_stack' should be defined\n";
return False;
}
/* Check that new_mem_stack_w_ECU is defined if any
new_mem_stack_N_w_ECU are. */
any_new_mem_stack_N_w_ECU
= VG_(tdict).track_new_mem_stack_4_w_ECU ||
VG_(tdict).track_new_mem_stack_8_w_ECU ||
VG_(tdict).track_new_mem_stack_12_w_ECU ||
VG_(tdict).track_new_mem_stack_16_w_ECU ||
VG_(tdict).track_new_mem_stack_32_w_ECU ||
VG_(tdict).track_new_mem_stack_112_w_ECU ||
VG_(tdict).track_new_mem_stack_128_w_ECU ||
VG_(tdict).track_new_mem_stack_144_w_ECU ||
VG_(tdict).track_new_mem_stack_160_w_ECU;
if (any_new_mem_stack_N_w_ECU && ! VG_(tdict).track_new_mem_stack_w_ECU) {
*failmsg = "Tool error: one of the specialised 'new_mem_stack_N_w_ECU'\n"
" events tracked, but not the generic 'new_mem_stack_w_ECU' one.\n"
" 'new_mem_stack_w_ECU' should be defined\n";
return False;
}
/* Check that in no cases are both with- and without-otag versions of the
same new_mem_stack_ function defined. */
any_new_mem_stack_w_conflicting_otags
= (VG_(tdict).track_new_mem_stack_4 && VG_(tdict).track_new_mem_stack_4_w_ECU) ||
(VG_(tdict).track_new_mem_stack_8 && VG_(tdict).track_new_mem_stack_8_w_ECU) ||
(VG_(tdict).track_new_mem_stack_12 && VG_(tdict).track_new_mem_stack_12_w_ECU) ||
(VG_(tdict).track_new_mem_stack_16 && VG_(tdict).track_new_mem_stack_16_w_ECU) ||
(VG_(tdict).track_new_mem_stack_32 && VG_(tdict).track_new_mem_stack_32_w_ECU) ||
(VG_(tdict).track_new_mem_stack_112 && VG_(tdict).track_new_mem_stack_112_w_ECU) ||
(VG_(tdict).track_new_mem_stack_128 && VG_(tdict).track_new_mem_stack_128_w_ECU) ||
(VG_(tdict).track_new_mem_stack_144 && VG_(tdict).track_new_mem_stack_144_w_ECU) ||
(VG_(tdict).track_new_mem_stack_160 && VG_(tdict).track_new_mem_stack_160_w_ECU) ||
(VG_(tdict).track_new_mem_stack && VG_(tdict).track_new_mem_stack_w_ECU);
if (any_new_mem_stack_w_conflicting_otags) {
*failmsg = "Tool error: tool supplies both a 'new_mem_stack_N' and a\n"
" 'new_mem_stack_N_w_ECU' function for some N (or none),\n"
" but you can only have one or the other (not both)\n";
return False;
}
/* Check that die_mem_stack is defined if any die_mem_stack_N
are. */
any_die_mem_stack_N
= VG_(tdict).track_die_mem_stack_4 ||
VG_(tdict).track_die_mem_stack_8 ||
VG_(tdict).track_die_mem_stack_12 ||
VG_(tdict).track_die_mem_stack_16 ||
VG_(tdict).track_die_mem_stack_32 ||
VG_(tdict).track_die_mem_stack_112 ||
VG_(tdict).track_die_mem_stack_128 ||
VG_(tdict).track_die_mem_stack_144 ||
VG_(tdict).track_die_mem_stack_160;
if (any_die_mem_stack_N && ! VG_(tdict).track_die_mem_stack) {
*failmsg = "Tool error: one of the specialised 'die_mem_stack_N'\n"
" events tracked, but not the generic 'die_mem_stack' one.\n"
" 'die_mem_stack' should be defined\n";
return False;
}
return True;
#undef CHECK_NOT
}
/* Use macro because they're so repetitive */
#define NEEDS(need) \
extern void VG_(needs_##need)(void) \
{ \
VG_(needs).need = True; \
}
// These ones don't require any tool-supplied functions
NEEDS(libc_freeres)
NEEDS(core_errors)
NEEDS(var_info)
void VG_(needs_superblock_discards)(
void (*discard)(Addr, VexGuestExtents)
)
{
VG_(needs).superblock_discards = True;
VG_(tdict).tool_discard_superblock_info = discard;
}
void VG_(needs_tool_errors)(
Bool (*eq) (VgRes, const Error*, const Error*),
void (*before_pp) (const Error*),
void (*pp) (const Error*),
Bool show_TIDs,
UInt (*update) (const Error*),
Bool (*recog) (const HChar*, Supp*),
Bool (*read_extra) (Int, HChar**, SizeT*, Int*, Supp*),
Bool (*matches) (const Error*, const Supp*),
const HChar* (*name) (const Error*),
SizeT (*get_xtra_si)(const Error*,/*OUT*/HChar*,Int),
SizeT (*print_xtra_su)(const Supp*,/*OUT*/HChar*,Int),
void (*update_xtra_su)(const Error*, const Supp*)
)
{
VG_(needs).tool_errors = True;
VG_(tdict).tool_eq_Error = eq;
VG_(tdict).tool_before_pp_Error = before_pp;
VG_(tdict).tool_pp_Error = pp;
VG_(tdict).tool_show_ThreadIDs_for_errors = show_TIDs;
VG_(tdict).tool_update_extra = update;
VG_(tdict).tool_recognised_suppression = recog;
VG_(tdict).tool_read_extra_suppression_info = read_extra;
VG_(tdict).tool_error_matches_suppression = matches;
VG_(tdict).tool_get_error_name = name;
VG_(tdict).tool_get_extra_suppression_info = get_xtra_si;
VG_(tdict).tool_print_extra_suppression_use = print_xtra_su;
VG_(tdict).tool_update_extra_suppression_use = update_xtra_su;
}
void VG_(needs_command_line_options)(
Bool (*process)(const HChar*),
void (*usage)(void),
void (*debug_usage)(void)
)
{
VG_(needs).command_line_options = True;
VG_(tdict).tool_process_cmd_line_option = process;
VG_(tdict).tool_print_usage = usage;
VG_(tdict).tool_print_debug_usage = debug_usage;
}
/* The tool's function for handling client requests. */
static Bool (*tool_handle_client_request_func)(ThreadId, UWord *, UWord *);
static Bool wrap_tool_handle_client_request(ThreadId tid, UWord *arg1,
UWord *arg2)
{
Bool ret;
VG_(ok_to_discard_translations) = True;
ret = tool_handle_client_request_func(tid, arg1, arg2);
VG_(ok_to_discard_translations) = False;
return ret;
}
void VG_(needs_client_requests)(
Bool (*handle)(ThreadId, UWord*, UWord*)
)
{
VG_(needs).client_requests = True;
tool_handle_client_request_func = handle; /* Stash away */
/* Register the wrapper function */
VG_(tdict).tool_handle_client_request = wrap_tool_handle_client_request;
}
void VG_(needs_syscall_wrapper)(
void(*pre) (ThreadId, UInt, UWord*, UInt),
void(*post)(ThreadId, UInt, UWord*, UInt, SysRes res)
)
{
VG_(needs).syscall_wrapper = True;
VG_(tdict).tool_pre_syscall = pre;
VG_(tdict).tool_post_syscall = post;
}
void VG_(needs_sanity_checks)(
Bool(*cheap)(void),
Bool(*expen)(void)
)
{
VG_(needs).sanity_checks = True;
VG_(tdict).tool_cheap_sanity_check = cheap;
VG_(tdict).tool_expensive_sanity_check = expen;
}
void VG_(needs_print_stats) (
void (*print_stats)(void)
)
{
VG_(needs).print_stats = True;
VG_(tdict).tool_print_stats = print_stats;
}
void VG_(needs_info_location) (
void (*info_location)(Addr)
)
{
VG_(needs).info_location = True;
VG_(tdict).tool_info_location = info_location;
}
void VG_(needs_malloc_replacement)(
void* (*malloc) ( ThreadId, SizeT ),
void* (*__builtin_new) ( ThreadId, SizeT ),
void* (*__builtin_vec_new) ( ThreadId, SizeT ),
void* (*memalign) ( ThreadId, SizeT, SizeT ),
void* (*calloc) ( ThreadId, SizeT, SizeT ),
void (*free) ( ThreadId, void* ),
void (*__builtin_delete) ( ThreadId, void* ),
void (*__builtin_vec_delete) ( ThreadId, void* ),
void* (*realloc) ( ThreadId, void*, SizeT ),
SizeT (*malloc_usable_size) ( ThreadId, void* ),
SizeT client_malloc_redzone_szB
)
{
VG_(needs).malloc_replacement = True;
VG_(tdict).tool_malloc = malloc;
VG_(tdict).tool___builtin_new = __builtin_new;
VG_(tdict).tool___builtin_vec_new = __builtin_vec_new;
VG_(tdict).tool_memalign = memalign;
VG_(tdict).tool_calloc = calloc;
VG_(tdict).tool_free = free;
VG_(tdict).tool___builtin_delete = __builtin_delete;
VG_(tdict).tool___builtin_vec_delete = __builtin_vec_delete;
VG_(tdict).tool_realloc = realloc;
VG_(tdict).tool_malloc_usable_size = malloc_usable_size;
VG_(tdict).tool_client_redzone_szB = client_malloc_redzone_szB;
}
void VG_(needs_xml_output)( void )
{
VG_(needs).xml_output = True;
}
void VG_(needs_final_IR_tidy_pass)(
IRSB*(*final_tidy)(IRSB*)
)
{
VG_(needs).final_IR_tidy_pass = True;
VG_(tdict).tool_final_IR_tidy_pass = final_tidy;
}
/*--------------------------------------------------------------------*/
/* Tracked events. Digit 'n' on DEFn is the REGPARMness. */
#define DEF0(fn, args...) \
void VG_(fn)(void(*f)(args)) { \
VG_(tdict).fn = f; \
}
#define DEF1(fn, args...) \
void VG_(fn)(VG_REGPARM(1) void(*f)(args)) { \
VG_(tdict).fn = f; \
}
#define DEF2(fn, args...) \
void VG_(fn)(VG_REGPARM(2) void(*f)(args)) { \
VG_(tdict).fn = f; \
}
DEF0(track_new_mem_startup, Addr, SizeT, Bool, Bool, Bool, ULong)
DEF0(track_new_mem_stack_signal, Addr, SizeT, UInt)
DEF0(track_new_mem_brk, Addr, SizeT, UInt)
DEF0(track_new_mem_mmap, Addr, SizeT, Bool, Bool, Bool, ULong)
DEF0(track_copy_mem_remap, Addr, Addr, SizeT)
DEF0(track_change_mem_mprotect, Addr, SizeT, Bool, Bool, Bool)
DEF0(track_die_mem_stack_signal, Addr, SizeT)
DEF0(track_die_mem_brk, Addr, SizeT)
DEF0(track_die_mem_munmap, Addr, SizeT)
DEF2(track_new_mem_stack_4_w_ECU, Addr, UInt)
DEF2(track_new_mem_stack_8_w_ECU, Addr, UInt)
DEF2(track_new_mem_stack_12_w_ECU, Addr, UInt)
DEF2(track_new_mem_stack_16_w_ECU, Addr, UInt)
DEF2(track_new_mem_stack_32_w_ECU, Addr, UInt)
DEF2(track_new_mem_stack_112_w_ECU, Addr, UInt)
DEF2(track_new_mem_stack_128_w_ECU, Addr, UInt)
DEF2(track_new_mem_stack_144_w_ECU, Addr, UInt)
DEF2(track_new_mem_stack_160_w_ECU, Addr, UInt)
DEF0(track_new_mem_stack_w_ECU, Addr, SizeT, UInt)
DEF1(track_new_mem_stack_4, Addr)
DEF1(track_new_mem_stack_8, Addr)
DEF1(track_new_mem_stack_12, Addr)
DEF1(track_new_mem_stack_16, Addr)
DEF1(track_new_mem_stack_32, Addr)
DEF1(track_new_mem_stack_112, Addr)
DEF1(track_new_mem_stack_128, Addr)
DEF1(track_new_mem_stack_144, Addr)
DEF1(track_new_mem_stack_160, Addr)
DEF0(track_new_mem_stack, Addr, SizeT)
DEF1(track_die_mem_stack_4, Addr)
DEF1(track_die_mem_stack_8, Addr)
DEF1(track_die_mem_stack_12, Addr)
DEF1(track_die_mem_stack_16, Addr)
DEF1(track_die_mem_stack_32, Addr)
DEF1(track_die_mem_stack_112, Addr)
DEF1(track_die_mem_stack_128, Addr)
DEF1(track_die_mem_stack_144, Addr)
DEF1(track_die_mem_stack_160, Addr)
DEF0(track_die_mem_stack, Addr, SizeT)
DEF0(track_ban_mem_stack, Addr, SizeT)
DEF0(track_pre_mem_read, CorePart, ThreadId, const HChar*, Addr, SizeT)
DEF0(track_pre_mem_read_asciiz, CorePart, ThreadId, const HChar*, Addr)
DEF0(track_pre_mem_write, CorePart, ThreadId, const HChar*, Addr, SizeT)
DEF0(track_post_mem_write, CorePart, ThreadId, Addr, SizeT)
DEF0(track_pre_reg_read, CorePart, ThreadId, const HChar*, PtrdiffT, SizeT)
DEF0(track_post_reg_write, CorePart, ThreadId, PtrdiffT, SizeT)
DEF0(track_post_reg_write_clientcall_return, ThreadId, PtrdiffT, SizeT, Addr)
DEF0(track_start_client_code, ThreadId, ULong)
DEF0(track_stop_client_code, ThreadId, ULong)
DEF0(track_pre_thread_ll_create, ThreadId, ThreadId)
DEF0(track_pre_thread_first_insn, ThreadId)
DEF0(track_pre_thread_ll_exit, ThreadId)
DEF0(track_pre_deliver_signal, ThreadId, Int sigNo, Bool)
DEF0(track_post_deliver_signal, ThreadId, Int sigNo)
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/