1024598e40c84666cc311a42c256bbf880db3ac99sewardj 2024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--------------------------------------------------------------------*/ 3024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--- Ptrcheck: a pointer-use checker. ---*/ 4024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--- This file checks heap accesses. ---*/ 5024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--- h_main.c ---*/ 6024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--------------------------------------------------------------------*/ 7024598e40c84666cc311a42c256bbf880db3ac99sewardj 8024598e40c84666cc311a42c256bbf880db3ac99sewardj/* 9024598e40c84666cc311a42c256bbf880db3ac99sewardj This file is part of Ptrcheck, a Valgrind tool for checking pointer 10024598e40c84666cc311a42c256bbf880db3ac99sewardj use in programs. 11024598e40c84666cc311a42c256bbf880db3ac99sewardj 12024598e40c84666cc311a42c256bbf880db3ac99sewardj Initial version (Annelid): 13024598e40c84666cc311a42c256bbf880db3ac99sewardj 14ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes Copyright (C) 2003-2017 Nicholas Nethercote 15024598e40c84666cc311a42c256bbf880db3ac99sewardj njn@valgrind.org 16024598e40c84666cc311a42c256bbf880db3ac99sewardj 17024598e40c84666cc311a42c256bbf880db3ac99sewardj Valgrind-3.X port: 18024598e40c84666cc311a42c256bbf880db3ac99sewardj 19ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes Copyright (C) 2008-2017 OpenWorks Ltd 20024598e40c84666cc311a42c256bbf880db3ac99sewardj info@open-works.co.uk 21024598e40c84666cc311a42c256bbf880db3ac99sewardj 22024598e40c84666cc311a42c256bbf880db3ac99sewardj This program is free software; you can redistribute it and/or 23024598e40c84666cc311a42c256bbf880db3ac99sewardj modify it under the terms of the GNU General Public License as 24024598e40c84666cc311a42c256bbf880db3ac99sewardj published by the Free Software Foundation; either version 2 of the 25024598e40c84666cc311a42c256bbf880db3ac99sewardj License, or (at your option) any later version. 26024598e40c84666cc311a42c256bbf880db3ac99sewardj 27024598e40c84666cc311a42c256bbf880db3ac99sewardj This program is distributed in the hope that it will be useful, but 28024598e40c84666cc311a42c256bbf880db3ac99sewardj WITHOUT ANY WARRANTY; without even the implied warranty of 29024598e40c84666cc311a42c256bbf880db3ac99sewardj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30024598e40c84666cc311a42c256bbf880db3ac99sewardj General Public License for more details. 31024598e40c84666cc311a42c256bbf880db3ac99sewardj 32024598e40c84666cc311a42c256bbf880db3ac99sewardj You should have received a copy of the GNU General Public License 33024598e40c84666cc311a42c256bbf880db3ac99sewardj along with this program; if not, write to the Free Software 34024598e40c84666cc311a42c256bbf880db3ac99sewardj Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 35024598e40c84666cc311a42c256bbf880db3ac99sewardj 02111-1307, USA. 36024598e40c84666cc311a42c256bbf880db3ac99sewardj 37024598e40c84666cc311a42c256bbf880db3ac99sewardj The GNU General Public License is contained in the file COPYING. 38024598e40c84666cc311a42c256bbf880db3ac99sewardj*/ 39024598e40c84666cc311a42c256bbf880db3ac99sewardj 40024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_basics.h" 41024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_libcbase.h" 42024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_libcprint.h" 43024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_libcassert.h" 44024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_mallocfree.h" 45024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_execontext.h" 46024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_hashtable.h" 47024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_tooliface.h" 48024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_replacemalloc.h" 49024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_options.h" 50024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_execontext.h" 51024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_aspacemgr.h" // VG_(am_shadow_malloc) 52024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_vki.h" // VKI_MAX_PAGE_SIZE 53024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_machine.h" // VG_({get,set}_shadow_regs_area) et al 54024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_debuginfo.h" // VG_(get_fnname) 55024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_threadstate.h" // VG_(get_running_tid) 56024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_oset.h" 57024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_vkiscnums.h" 58024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_machine.h" 59024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_wordfm.h" 60024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pub_tool_xarray.h" 61024598e40c84666cc311a42c256bbf880db3ac99sewardj 62024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "pc_common.h" 63024598e40c84666cc311a42c256bbf880db3ac99sewardj 64024598e40c84666cc311a42c256bbf880db3ac99sewardj//#include "h_list.h" 65024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "h_main.h" 66024598e40c84666cc311a42c256bbf880db3ac99sewardj 67024598e40c84666cc311a42c256bbf880db3ac99sewardj#include "sg_main.h" // sg_instrument_*, and struct _SGEnv 68024598e40c84666cc311a42c256bbf880db3ac99sewardj 69024598e40c84666cc311a42c256bbf880db3ac99sewardj 70024598e40c84666cc311a42c256bbf880db3ac99sewardj 71024598e40c84666cc311a42c256bbf880db3ac99sewardj/*------------------------------------------------------------*/ 72024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--- Debug/trace options ---*/ 73024598e40c84666cc311a42c256bbf880db3ac99sewardj/*------------------------------------------------------------*/ 74024598e40c84666cc311a42c256bbf880db3ac99sewardj 75024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic ULong stats__client_mallocs = 0; 76024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic ULong stats__client_frees = 0; 77024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic ULong stats__segs_allocd = 0; 78024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic ULong stats__segs_recycled = 0; 79024598e40c84666cc311a42c256bbf880db3ac99sewardj 80024598e40c84666cc311a42c256bbf880db3ac99sewardj 81024598e40c84666cc311a42c256bbf880db3ac99sewardj////////////////////////////////////////////////////////////// 82024598e40c84666cc311a42c256bbf880db3ac99sewardj// // 83024598e40c84666cc311a42c256bbf880db3ac99sewardj// Segments low level storage // 84024598e40c84666cc311a42c256bbf880db3ac99sewardj// // 85024598e40c84666cc311a42c256bbf880db3ac99sewardj////////////////////////////////////////////////////////////// 86024598e40c84666cc311a42c256bbf880db3ac99sewardj 87024598e40c84666cc311a42c256bbf880db3ac99sewardj// NONPTR, UNKNOWN, BOTTOM defined in h_main.h since 88024598e40c84666cc311a42c256bbf880db3ac99sewardj// pc_common.c needs to see them, for error processing 89024598e40c84666cc311a42c256bbf880db3ac99sewardj 90024598e40c84666cc311a42c256bbf880db3ac99sewardj// we only start recycling segs when this many exist 91024598e40c84666cc311a42c256bbf880db3ac99sewardj#define N_FREED_SEGS (1 * 1000 * 1000) 92024598e40c84666cc311a42c256bbf880db3ac99sewardj 93024598e40c84666cc311a42c256bbf880db3ac99sewardjstruct _Seg { 94024598e40c84666cc311a42c256bbf880db3ac99sewardj Addr addr; 95024598e40c84666cc311a42c256bbf880db3ac99sewardj SizeT szB; /* may be zero */ 96024598e40c84666cc311a42c256bbf880db3ac99sewardj ExeContext* ec; /* where malloc'd or freed */ 97024598e40c84666cc311a42c256bbf880db3ac99sewardj /* When 1, indicates block is in use. Otherwise, used to form a 98024598e40c84666cc311a42c256bbf880db3ac99sewardj linked list of freed blocks, running from oldest freed block to 99024598e40c84666cc311a42c256bbf880db3ac99sewardj the most recently freed block. */ 100024598e40c84666cc311a42c256bbf880db3ac99sewardj struct _Seg* nextfree; 101024598e40c84666cc311a42c256bbf880db3ac99sewardj}; 102024598e40c84666cc311a42c256bbf880db3ac99sewardj 103024598e40c84666cc311a42c256bbf880db3ac99sewardj// Determines if 'a' is before, within, or after seg's range. Sets 'cmp' to 104024598e40c84666cc311a42c256bbf880db3ac99sewardj// -1/0/1 accordingly. Sets 'n' to the number of bytes before/within/after. 105024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid Seg__cmp(Seg* seg, Addr a, Int* cmp, UWord* n) 106024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 107024598e40c84666cc311a42c256bbf880db3ac99sewardj if (a < seg->addr) { 108024598e40c84666cc311a42c256bbf880db3ac99sewardj *cmp = -1; 109024598e40c84666cc311a42c256bbf880db3ac99sewardj *n = seg->addr - a; 110024598e40c84666cc311a42c256bbf880db3ac99sewardj } else if (a < seg->addr + seg->szB && seg->szB > 0) { 111024598e40c84666cc311a42c256bbf880db3ac99sewardj *cmp = 0; 112024598e40c84666cc311a42c256bbf880db3ac99sewardj *n = a - seg->addr; 113024598e40c84666cc311a42c256bbf880db3ac99sewardj } else { 114024598e40c84666cc311a42c256bbf880db3ac99sewardj *cmp = 1; 115024598e40c84666cc311a42c256bbf880db3ac99sewardj *n = a - (seg->addr + seg->szB); 116024598e40c84666cc311a42c256bbf880db3ac99sewardj } 117024598e40c84666cc311a42c256bbf880db3ac99sewardj} 118024598e40c84666cc311a42c256bbf880db3ac99sewardj 119f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/*inline*/ Bool Seg__is_freed(Seg* seg) 120024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 121024598e40c84666cc311a42c256bbf880db3ac99sewardj if (!is_known_segment(seg)) 122024598e40c84666cc311a42c256bbf880db3ac99sewardj return False; 123024598e40c84666cc311a42c256bbf880db3ac99sewardj else 124024598e40c84666cc311a42c256bbf880db3ac99sewardj return seg->nextfree != (Seg*)1; 125024598e40c84666cc311a42c256bbf880db3ac99sewardj} 126024598e40c84666cc311a42c256bbf880db3ac99sewardj 127024598e40c84666cc311a42c256bbf880db3ac99sewardjExeContext* Seg__where(Seg* seg) 128024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 129024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(is_known_segment(seg)); 130024598e40c84666cc311a42c256bbf880db3ac99sewardj return seg->ec; 131024598e40c84666cc311a42c256bbf880db3ac99sewardj} 132024598e40c84666cc311a42c256bbf880db3ac99sewardj 133024598e40c84666cc311a42c256bbf880db3ac99sewardjSizeT Seg__size(Seg* seg) 134024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 135024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(is_known_segment(seg)); 136024598e40c84666cc311a42c256bbf880db3ac99sewardj return seg->szB; 137024598e40c84666cc311a42c256bbf880db3ac99sewardj} 138024598e40c84666cc311a42c256bbf880db3ac99sewardj 139024598e40c84666cc311a42c256bbf880db3ac99sewardjAddr Seg__addr(Seg* seg) 140024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 141024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(is_known_segment(seg)); 142024598e40c84666cc311a42c256bbf880db3ac99sewardj return seg->addr; 143024598e40c84666cc311a42c256bbf880db3ac99sewardj} 144024598e40c84666cc311a42c256bbf880db3ac99sewardj 145024598e40c84666cc311a42c256bbf880db3ac99sewardj 146024598e40c84666cc311a42c256bbf880db3ac99sewardj#define N_SEGS_PER_GROUP 10000 147024598e40c84666cc311a42c256bbf880db3ac99sewardj 148024598e40c84666cc311a42c256bbf880db3ac99sewardjtypedef 149024598e40c84666cc311a42c256bbf880db3ac99sewardj struct _SegGroup { 150024598e40c84666cc311a42c256bbf880db3ac99sewardj struct _SegGroup* admin; 151024598e40c84666cc311a42c256bbf880db3ac99sewardj UWord nextfree; /* 0 .. N_SEGS_PER_GROUP */ 152024598e40c84666cc311a42c256bbf880db3ac99sewardj Seg segs[N_SEGS_PER_GROUP]; 153024598e40c84666cc311a42c256bbf880db3ac99sewardj } 154024598e40c84666cc311a42c256bbf880db3ac99sewardj SegGroup; 155024598e40c84666cc311a42c256bbf880db3ac99sewardj 156024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic SegGroup* group_list = NULL; 157024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic UWord nFreeSegs = 0; 158024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic Seg* freesegs_youngest = NULL; 159024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic Seg* freesegs_oldest = NULL; 160024598e40c84666cc311a42c256bbf880db3ac99sewardj 161024598e40c84666cc311a42c256bbf880db3ac99sewardj 162024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic SegGroup* new_SegGroup ( void ) { 163024598e40c84666cc311a42c256bbf880db3ac99sewardj SegGroup* g = VG_(malloc)("pc.h_main.nTG.1", sizeof(SegGroup)); 164024598e40c84666cc311a42c256bbf880db3ac99sewardj VG_(memset)(g, 0, sizeof(*g)); 165024598e40c84666cc311a42c256bbf880db3ac99sewardj return g; 166024598e40c84666cc311a42c256bbf880db3ac99sewardj} 167024598e40c84666cc311a42c256bbf880db3ac99sewardj 168024598e40c84666cc311a42c256bbf880db3ac99sewardj/* Get a completely new Seg */ 169024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic Seg* new_Seg ( void ) 170024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 171024598e40c84666cc311a42c256bbf880db3ac99sewardj Seg* teg; 172024598e40c84666cc311a42c256bbf880db3ac99sewardj SegGroup* g; 173024598e40c84666cc311a42c256bbf880db3ac99sewardj if (group_list == NULL) { 174024598e40c84666cc311a42c256bbf880db3ac99sewardj g = new_SegGroup(); 175024598e40c84666cc311a42c256bbf880db3ac99sewardj g->admin = NULL; 176024598e40c84666cc311a42c256bbf880db3ac99sewardj group_list = g; 177024598e40c84666cc311a42c256bbf880db3ac99sewardj } 178024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(group_list->nextfree <= N_SEGS_PER_GROUP); 179024598e40c84666cc311a42c256bbf880db3ac99sewardj if (group_list->nextfree == N_SEGS_PER_GROUP) { 180024598e40c84666cc311a42c256bbf880db3ac99sewardj g = new_SegGroup(); 181024598e40c84666cc311a42c256bbf880db3ac99sewardj g->admin = group_list; 182024598e40c84666cc311a42c256bbf880db3ac99sewardj group_list = g; 183024598e40c84666cc311a42c256bbf880db3ac99sewardj } 184024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(group_list->nextfree < N_SEGS_PER_GROUP); 185024598e40c84666cc311a42c256bbf880db3ac99sewardj teg = &group_list->segs[ group_list->nextfree ]; 186024598e40c84666cc311a42c256bbf880db3ac99sewardj group_list->nextfree++; 187024598e40c84666cc311a42c256bbf880db3ac99sewardj stats__segs_allocd++; 188024598e40c84666cc311a42c256bbf880db3ac99sewardj return teg; 189024598e40c84666cc311a42c256bbf880db3ac99sewardj} 190024598e40c84666cc311a42c256bbf880db3ac99sewardj 191024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic Seg* get_Seg_for_malloc ( void ) 192024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 193024598e40c84666cc311a42c256bbf880db3ac99sewardj Seg* seg; 194024598e40c84666cc311a42c256bbf880db3ac99sewardj if (nFreeSegs < N_FREED_SEGS) { 195024598e40c84666cc311a42c256bbf880db3ac99sewardj seg = new_Seg(); 196024598e40c84666cc311a42c256bbf880db3ac99sewardj seg->nextfree = (Seg*)1; 197024598e40c84666cc311a42c256bbf880db3ac99sewardj return seg; 198024598e40c84666cc311a42c256bbf880db3ac99sewardj } 199024598e40c84666cc311a42c256bbf880db3ac99sewardj /* else recycle the oldest Seg in the free list */ 200024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_youngest); 201024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_oldest); 202024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_youngest != freesegs_oldest); 203024598e40c84666cc311a42c256bbf880db3ac99sewardj seg = freesegs_oldest; 204024598e40c84666cc311a42c256bbf880db3ac99sewardj freesegs_oldest = seg->nextfree; 205024598e40c84666cc311a42c256bbf880db3ac99sewardj nFreeSegs--; 206024598e40c84666cc311a42c256bbf880db3ac99sewardj seg->nextfree = (Seg*)1; 207024598e40c84666cc311a42c256bbf880db3ac99sewardj stats__segs_recycled++; 208024598e40c84666cc311a42c256bbf880db3ac99sewardj return seg; 209024598e40c84666cc311a42c256bbf880db3ac99sewardj} 210024598e40c84666cc311a42c256bbf880db3ac99sewardj 211024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic void set_Seg_freed ( Seg* seg ) 212024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 213024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(seg); 214024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(!Seg__is_freed(seg)); 215024598e40c84666cc311a42c256bbf880db3ac99sewardj if (nFreeSegs == 0) { 216024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_oldest == NULL); 217024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_youngest == NULL); 218024598e40c84666cc311a42c256bbf880db3ac99sewardj seg->nextfree = NULL; 219024598e40c84666cc311a42c256bbf880db3ac99sewardj freesegs_youngest = seg; 220024598e40c84666cc311a42c256bbf880db3ac99sewardj freesegs_oldest = seg; 221024598e40c84666cc311a42c256bbf880db3ac99sewardj nFreeSegs++; 222024598e40c84666cc311a42c256bbf880db3ac99sewardj } else { 223024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_youngest); 224024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_oldest); 225024598e40c84666cc311a42c256bbf880db3ac99sewardj if (nFreeSegs == 1) { 226024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_youngest == freesegs_oldest); 227024598e40c84666cc311a42c256bbf880db3ac99sewardj } else { 228024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_youngest != freesegs_oldest); 229024598e40c84666cc311a42c256bbf880db3ac99sewardj } 230024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(freesegs_youngest->nextfree == NULL); 231024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(seg != freesegs_youngest && seg != freesegs_oldest); 232024598e40c84666cc311a42c256bbf880db3ac99sewardj seg->nextfree = NULL; 233024598e40c84666cc311a42c256bbf880db3ac99sewardj freesegs_youngest->nextfree = seg; 234024598e40c84666cc311a42c256bbf880db3ac99sewardj freesegs_youngest = seg; 235024598e40c84666cc311a42c256bbf880db3ac99sewardj nFreeSegs++; 236024598e40c84666cc311a42c256bbf880db3ac99sewardj } 237024598e40c84666cc311a42c256bbf880db3ac99sewardj} 238024598e40c84666cc311a42c256bbf880db3ac99sewardj 2399520845eeeb59e9eafa5c6fb0d68b4a392e94f41sewardjstatic WordFM* addr_to_seg_map = NULL; /* GuestAddr -> Seg* */ 240024598e40c84666cc311a42c256bbf880db3ac99sewardj 241024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic void addr_to_seg_map_ENSURE_INIT ( void ) 242024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 243024598e40c84666cc311a42c256bbf880db3ac99sewardj if (UNLIKELY(addr_to_seg_map == NULL)) { 244024598e40c84666cc311a42c256bbf880db3ac99sewardj addr_to_seg_map = VG_(newFM)( VG_(malloc), "pc.h_main.attmEI.1", 2459520845eeeb59e9eafa5c6fb0d68b4a392e94f41sewardj VG_(free), NULL/*unboxedcmp*/ ); 246024598e40c84666cc311a42c256bbf880db3ac99sewardj } 247024598e40c84666cc311a42c256bbf880db3ac99sewardj} 248024598e40c84666cc311a42c256bbf880db3ac99sewardj 249024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic Seg* find_Seg_by_addr ( Addr ga ) 250024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 251024598e40c84666cc311a42c256bbf880db3ac99sewardj UWord keyW, valW; 252024598e40c84666cc311a42c256bbf880db3ac99sewardj addr_to_seg_map_ENSURE_INIT(); 253024598e40c84666cc311a42c256bbf880db3ac99sewardj if (VG_(lookupFM)( addr_to_seg_map, &keyW, &valW, (UWord)ga )) { 254024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(keyW == ga); 255024598e40c84666cc311a42c256bbf880db3ac99sewardj return (Seg*)valW; 256024598e40c84666cc311a42c256bbf880db3ac99sewardj } else { 257024598e40c84666cc311a42c256bbf880db3ac99sewardj return NULL; 258024598e40c84666cc311a42c256bbf880db3ac99sewardj } 259024598e40c84666cc311a42c256bbf880db3ac99sewardj} 260024598e40c84666cc311a42c256bbf880db3ac99sewardj 261024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic void bind_addr_to_Seg ( Addr ga, Seg* seg ) 262024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 263024598e40c84666cc311a42c256bbf880db3ac99sewardj Bool b; 264024598e40c84666cc311a42c256bbf880db3ac99sewardj addr_to_seg_map_ENSURE_INIT(); 265024598e40c84666cc311a42c256bbf880db3ac99sewardj b = VG_(addToFM)( addr_to_seg_map, (UWord)ga, (UWord)seg ); 266024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(!b); /* else ga is already bound */ 267024598e40c84666cc311a42c256bbf880db3ac99sewardj} 268024598e40c84666cc311a42c256bbf880db3ac99sewardj 269024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic void unbind_addr_from_Seg ( Addr ga ) 270024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 271024598e40c84666cc311a42c256bbf880db3ac99sewardj Bool b; 272024598e40c84666cc311a42c256bbf880db3ac99sewardj UWord keyW, valW; 273024598e40c84666cc311a42c256bbf880db3ac99sewardj addr_to_seg_map_ENSURE_INIT(); 274024598e40c84666cc311a42c256bbf880db3ac99sewardj b = VG_(delFromFM)( addr_to_seg_map, &keyW, &valW, (UWord)ga ); 275024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(b); /* else ga was not already bound */ 276024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(keyW == ga); 277024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(valW != 0); 278024598e40c84666cc311a42c256bbf880db3ac99sewardj} 279024598e40c84666cc311a42c256bbf880db3ac99sewardj 280024598e40c84666cc311a42c256bbf880db3ac99sewardj 281024598e40c84666cc311a42c256bbf880db3ac99sewardj////////////////////////////////////////////////////////////// 282024598e40c84666cc311a42c256bbf880db3ac99sewardj////////////////////////////////////////////////////////////// 283024598e40c84666cc311a42c256bbf880db3ac99sewardj////////////////////////////////////////////////////////////// 284024598e40c84666cc311a42c256bbf880db3ac99sewardj 285024598e40c84666cc311a42c256bbf880db3ac99sewardj// Returns the added heap segment 286024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic Seg* add_new_segment ( ThreadId tid, Addr p, SizeT size ) 287024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 288024598e40c84666cc311a42c256bbf880db3ac99sewardj Seg* seg = get_Seg_for_malloc(); 289024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(seg != (Seg*)1); /* since we're using 1 as a special value */ 290024598e40c84666cc311a42c256bbf880db3ac99sewardj seg->addr = p; 291024598e40c84666cc311a42c256bbf880db3ac99sewardj seg->szB = size; 292024598e40c84666cc311a42c256bbf880db3ac99sewardj seg->ec = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ ); 293024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(!Seg__is_freed(seg)); 294024598e40c84666cc311a42c256bbf880db3ac99sewardj 295024598e40c84666cc311a42c256bbf880db3ac99sewardj bind_addr_to_Seg(p, seg); 296024598e40c84666cc311a42c256bbf880db3ac99sewardj 297024598e40c84666cc311a42c256bbf880db3ac99sewardj return seg; 298024598e40c84666cc311a42c256bbf880db3ac99sewardj} 299024598e40c84666cc311a42c256bbf880db3ac99sewardj 300024598e40c84666cc311a42c256bbf880db3ac99sewardj 301024598e40c84666cc311a42c256bbf880db3ac99sewardj 302024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic 303024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid* alloc_and_new_mem_heap ( ThreadId tid, 304024598e40c84666cc311a42c256bbf880db3ac99sewardj SizeT size, SizeT alignment, Bool is_zeroed ) 305024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 306024598e40c84666cc311a42c256bbf880db3ac99sewardj Addr p; 307024598e40c84666cc311a42c256bbf880db3ac99sewardj 308024598e40c84666cc311a42c256bbf880db3ac99sewardj if ( ((SSizeT)size) < 0) return NULL; 309024598e40c84666cc311a42c256bbf880db3ac99sewardj 310024598e40c84666cc311a42c256bbf880db3ac99sewardj p = (Addr)VG_(cli_malloc)(alignment, size); 311024598e40c84666cc311a42c256bbf880db3ac99sewardj if (is_zeroed) VG_(memset)((void*)p, 0, size); 312024598e40c84666cc311a42c256bbf880db3ac99sewardj 313024598e40c84666cc311a42c256bbf880db3ac99sewardj add_new_segment( tid, p, size ); 314024598e40c84666cc311a42c256bbf880db3ac99sewardj 315024598e40c84666cc311a42c256bbf880db3ac99sewardj stats__client_mallocs++; 316024598e40c84666cc311a42c256bbf880db3ac99sewardj return (void*)p; 317024598e40c84666cc311a42c256bbf880db3ac99sewardj} 318024598e40c84666cc311a42c256bbf880db3ac99sewardj 319024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic void die_and_free_mem_heap ( ThreadId tid, Seg* seg ) 320024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 321024598e40c84666cc311a42c256bbf880db3ac99sewardj // Empty and free the actual block 322024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(!Seg__is_freed(seg)); 323024598e40c84666cc311a42c256bbf880db3ac99sewardj 324024598e40c84666cc311a42c256bbf880db3ac99sewardj VG_(cli_free)( (void*)seg->addr ); 325024598e40c84666cc311a42c256bbf880db3ac99sewardj 326024598e40c84666cc311a42c256bbf880db3ac99sewardj // Remember where freed 327024598e40c84666cc311a42c256bbf880db3ac99sewardj seg->ec = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ ); 328024598e40c84666cc311a42c256bbf880db3ac99sewardj 329024598e40c84666cc311a42c256bbf880db3ac99sewardj set_Seg_freed(seg); 330024598e40c84666cc311a42c256bbf880db3ac99sewardj unbind_addr_from_Seg( seg->addr ); 331024598e40c84666cc311a42c256bbf880db3ac99sewardj 332024598e40c84666cc311a42c256bbf880db3ac99sewardj stats__client_frees++; 333024598e40c84666cc311a42c256bbf880db3ac99sewardj} 334024598e40c84666cc311a42c256bbf880db3ac99sewardj 335024598e40c84666cc311a42c256bbf880db3ac99sewardjstatic void handle_free_heap( ThreadId tid, void* p ) 336024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 337024598e40c84666cc311a42c256bbf880db3ac99sewardj Seg* seg = find_Seg_by_addr( (Addr)p ); 338024598e40c84666cc311a42c256bbf880db3ac99sewardj if (!seg) { 339024598e40c84666cc311a42c256bbf880db3ac99sewardj /* freeing a block that wasn't malloc'd. Ignore. */ 340024598e40c84666cc311a42c256bbf880db3ac99sewardj return; 341024598e40c84666cc311a42c256bbf880db3ac99sewardj } 342024598e40c84666cc311a42c256bbf880db3ac99sewardj die_and_free_mem_heap( tid, seg ); 343024598e40c84666cc311a42c256bbf880db3ac99sewardj} 344024598e40c84666cc311a42c256bbf880db3ac99sewardj 345024598e40c84666cc311a42c256bbf880db3ac99sewardj 346024598e40c84666cc311a42c256bbf880db3ac99sewardj/*------------------------------------------------------------*/ 347024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--- malloc() et al replacements ---*/ 348024598e40c84666cc311a42c256bbf880db3ac99sewardj/*------------------------------------------------------------*/ 349024598e40c84666cc311a42c256bbf880db3ac99sewardj 350024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid* h_replace_malloc ( ThreadId tid, SizeT n ) 351024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 352024598e40c84666cc311a42c256bbf880db3ac99sewardj return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment), 353024598e40c84666cc311a42c256bbf880db3ac99sewardj /*is_zeroed*/False ); 354024598e40c84666cc311a42c256bbf880db3ac99sewardj} 355024598e40c84666cc311a42c256bbf880db3ac99sewardj 356024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid* h_replace___builtin_new ( ThreadId tid, SizeT n ) 357024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 358024598e40c84666cc311a42c256bbf880db3ac99sewardj return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment), 359024598e40c84666cc311a42c256bbf880db3ac99sewardj /*is_zeroed*/False ); 360024598e40c84666cc311a42c256bbf880db3ac99sewardj} 361024598e40c84666cc311a42c256bbf880db3ac99sewardj 362024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid* h_replace___builtin_vec_new ( ThreadId tid, SizeT n ) 363024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 364024598e40c84666cc311a42c256bbf880db3ac99sewardj return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment), 365024598e40c84666cc311a42c256bbf880db3ac99sewardj /*is_zeroed*/False ); 366024598e40c84666cc311a42c256bbf880db3ac99sewardj} 367024598e40c84666cc311a42c256bbf880db3ac99sewardj 368024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid* h_replace_memalign ( ThreadId tid, SizeT align, SizeT n ) 369024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 370024598e40c84666cc311a42c256bbf880db3ac99sewardj return alloc_and_new_mem_heap ( tid, n, align, 371024598e40c84666cc311a42c256bbf880db3ac99sewardj /*is_zeroed*/False ); 372024598e40c84666cc311a42c256bbf880db3ac99sewardj} 373024598e40c84666cc311a42c256bbf880db3ac99sewardj 374024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid* h_replace_calloc ( ThreadId tid, SizeT nmemb, SizeT size1 ) 375024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 376024598e40c84666cc311a42c256bbf880db3ac99sewardj return alloc_and_new_mem_heap ( tid, nmemb*size1, VG_(clo_alignment), 377024598e40c84666cc311a42c256bbf880db3ac99sewardj /*is_zeroed*/True ); 378024598e40c84666cc311a42c256bbf880db3ac99sewardj} 379024598e40c84666cc311a42c256bbf880db3ac99sewardj 380024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid h_replace_free ( ThreadId tid, void* p ) 381024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 382024598e40c84666cc311a42c256bbf880db3ac99sewardj // Should arguably check here if p.vseg matches the segID of the 383024598e40c84666cc311a42c256bbf880db3ac99sewardj // pointed-to block... unfortunately, by this stage, we don't know what 384024598e40c84666cc311a42c256bbf880db3ac99sewardj // p.vseg is, because we don't know the address of p (the p here is a 385024598e40c84666cc311a42c256bbf880db3ac99sewardj // copy, and we've lost the address of its source). To do so would 386024598e40c84666cc311a42c256bbf880db3ac99sewardj // require passing &p in, which would require rewriting part of 387024598e40c84666cc311a42c256bbf880db3ac99sewardj // vg_replace_malloc.c... argh. 388024598e40c84666cc311a42c256bbf880db3ac99sewardj // 389024598e40c84666cc311a42c256bbf880db3ac99sewardj // However, Memcheck does free checking, and will catch almost all 390024598e40c84666cc311a42c256bbf880db3ac99sewardj // violations this checking would have caught. (Would only miss if we 391024598e40c84666cc311a42c256bbf880db3ac99sewardj // unluckily passed an unrelated pointer to the very start of a heap 392024598e40c84666cc311a42c256bbf880db3ac99sewardj // block that was unrelated to that block. This is very unlikely!) So 393024598e40c84666cc311a42c256bbf880db3ac99sewardj // we haven't lost much. 394024598e40c84666cc311a42c256bbf880db3ac99sewardj 395024598e40c84666cc311a42c256bbf880db3ac99sewardj handle_free_heap(tid, p); 396024598e40c84666cc311a42c256bbf880db3ac99sewardj} 397024598e40c84666cc311a42c256bbf880db3ac99sewardj 398024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid h_replace___builtin_delete ( ThreadId tid, void* p ) 399024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 400024598e40c84666cc311a42c256bbf880db3ac99sewardj handle_free_heap(tid, p); 401024598e40c84666cc311a42c256bbf880db3ac99sewardj} 402024598e40c84666cc311a42c256bbf880db3ac99sewardj 403024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid h_replace___builtin_vec_delete ( ThreadId tid, void* p ) 404024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 405024598e40c84666cc311a42c256bbf880db3ac99sewardj handle_free_heap(tid, p); 406024598e40c84666cc311a42c256bbf880db3ac99sewardj} 407024598e40c84666cc311a42c256bbf880db3ac99sewardj 408024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid* h_replace_realloc ( ThreadId tid, void* p_old, SizeT new_size ) 409024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 410024598e40c84666cc311a42c256bbf880db3ac99sewardj Seg* seg; 411024598e40c84666cc311a42c256bbf880db3ac99sewardj 412024598e40c84666cc311a42c256bbf880db3ac99sewardj /* First try and find the block. */ 413024598e40c84666cc311a42c256bbf880db3ac99sewardj seg = find_Seg_by_addr( (Addr)p_old ); 414024598e40c84666cc311a42c256bbf880db3ac99sewardj if (!seg) 415024598e40c84666cc311a42c256bbf880db3ac99sewardj return NULL; 416024598e40c84666cc311a42c256bbf880db3ac99sewardj 417024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(seg->addr == (Addr)p_old); 418024598e40c84666cc311a42c256bbf880db3ac99sewardj 419024598e40c84666cc311a42c256bbf880db3ac99sewardj if (new_size <= seg->szB) { 420024598e40c84666cc311a42c256bbf880db3ac99sewardj /* new size is smaller: allocate, copy from old to new */ 421024598e40c84666cc311a42c256bbf880db3ac99sewardj Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size); 422024598e40c84666cc311a42c256bbf880db3ac99sewardj VG_(memcpy)((void*)p_new, p_old, new_size); 423024598e40c84666cc311a42c256bbf880db3ac99sewardj 424024598e40c84666cc311a42c256bbf880db3ac99sewardj /* Free old memory */ 425024598e40c84666cc311a42c256bbf880db3ac99sewardj die_and_free_mem_heap( tid, seg ); 426024598e40c84666cc311a42c256bbf880db3ac99sewardj 427024598e40c84666cc311a42c256bbf880db3ac99sewardj /* This has to be after die_and_free_mem_heap, otherwise the 428024598e40c84666cc311a42c256bbf880db3ac99sewardj former succeeds in shorting out the new block, not the 429024598e40c84666cc311a42c256bbf880db3ac99sewardj old, in the case when both are on the same list. */ 430024598e40c84666cc311a42c256bbf880db3ac99sewardj add_new_segment ( tid, p_new, new_size ); 431024598e40c84666cc311a42c256bbf880db3ac99sewardj 432024598e40c84666cc311a42c256bbf880db3ac99sewardj return (void*)p_new; 433024598e40c84666cc311a42c256bbf880db3ac99sewardj } else { 434024598e40c84666cc311a42c256bbf880db3ac99sewardj /* new size is bigger: allocate, copy from old to new */ 435024598e40c84666cc311a42c256bbf880db3ac99sewardj Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size); 436024598e40c84666cc311a42c256bbf880db3ac99sewardj VG_(memcpy)((void*)p_new, p_old, seg->szB); 437024598e40c84666cc311a42c256bbf880db3ac99sewardj 438024598e40c84666cc311a42c256bbf880db3ac99sewardj /* Free old memory */ 439024598e40c84666cc311a42c256bbf880db3ac99sewardj die_and_free_mem_heap( tid, seg ); 440024598e40c84666cc311a42c256bbf880db3ac99sewardj 441024598e40c84666cc311a42c256bbf880db3ac99sewardj /* This has to be after die_and_free_mem_heap, otherwise the 442024598e40c84666cc311a42c256bbf880db3ac99sewardj former succeeds in shorting out the new block, not the old, 443024598e40c84666cc311a42c256bbf880db3ac99sewardj in the case when both are on the same list. NB jrs 444024598e40c84666cc311a42c256bbf880db3ac99sewardj 2008-Sept-11: not sure if this comment is valid/correct any 445024598e40c84666cc311a42c256bbf880db3ac99sewardj more -- I suspect not. */ 446024598e40c84666cc311a42c256bbf880db3ac99sewardj add_new_segment ( tid, p_new, new_size ); 447024598e40c84666cc311a42c256bbf880db3ac99sewardj 448024598e40c84666cc311a42c256bbf880db3ac99sewardj return (void*)p_new; 449024598e40c84666cc311a42c256bbf880db3ac99sewardj } 450024598e40c84666cc311a42c256bbf880db3ac99sewardj} 451024598e40c84666cc311a42c256bbf880db3ac99sewardj 4528b140dee891a850c09d27f316df913acc7d7bae7njnSizeT h_replace_malloc_usable_size ( ThreadId tid, void* p ) 4538b140dee891a850c09d27f316df913acc7d7bae7njn{ 4548b140dee891a850c09d27f316df913acc7d7bae7njn Seg* seg = find_Seg_by_addr( (Addr)p ); 4558b140dee891a850c09d27f316df913acc7d7bae7njn 4568b140dee891a850c09d27f316df913acc7d7bae7njn // There may be slop, but pretend there isn't because only the asked-for 4578b140dee891a850c09d27f316df913acc7d7bae7njn // area will have been shadowed properly. 4588b140dee891a850c09d27f316df913acc7d7bae7njn return ( seg ? seg->szB : 0 ); 4598b140dee891a850c09d27f316df913acc7d7bae7njn} 4608b140dee891a850c09d27f316df913acc7d7bae7njn 461024598e40c84666cc311a42c256bbf880db3ac99sewardj 462f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/*--------------------------------------------------------------------*/ 463f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/*--- Instrumentation ---*/ 464f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/*--------------------------------------------------------------------*/ 465024598e40c84666cc311a42c256bbf880db3ac99sewardj 466f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/* The h_ instrumenter that follows is complex, since it deals with 467f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj shadow value computation. 468024598e40c84666cc311a42c256bbf880db3ac99sewardj 469f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj It also needs to generate instrumentation for the sg_ side of 470f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj things. That's relatively straightforward. However, rather than 471f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj confuse the code herein any further, we simply delegate the problem 472f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj to sg_main.c, by using the four functions 473f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj sg_instrument_{init,fini,IRStmt,final_jump}. These four completely 474f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj abstractify the sg_ instrumentation. See comments in sg_main.c's 475f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj instrumentation section for further details. */ 476024598e40c84666cc311a42c256bbf880db3ac99sewardj 477024598e40c84666cc311a42c256bbf880db3ac99sewardj 478f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/* Carries info about a particular tmp. The tmp's number is not 479f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj recorded, as this is implied by (equal to) its index in the tmpMap 480f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj in PCEnv. The tmp's type is also not recorded, as this is present 481f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj in PCEnv.sb->tyenv. 482024598e40c84666cc311a42c256bbf880db3ac99sewardj 483f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj When .kind is NonShad, .shadow may give the identity of the temp 484f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj currently holding the associated shadow value, or it may be 485f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRTemp_INVALID if code to compute the shadow has not yet been 486f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj emitted. 487024598e40c84666cc311a42c256bbf880db3ac99sewardj 488f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj When .kind is Shad tmp holds a shadow value, and so .shadow must be 489f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRTemp_INVALID, since it is illogical for a shadow tmp itself to be 490f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj shadowed. 491f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj*/ 492f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardjtypedef 493f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj enum { NonShad=1, Shad=2 } 494f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj TempKind; 495024598e40c84666cc311a42c256bbf880db3ac99sewardj 496f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardjtypedef 497f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj struct { 498f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj TempKind kind; 499f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRTemp shadow; 500f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj } 501f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj TempMapEnt; 502024598e40c84666cc311a42c256bbf880db3ac99sewardj 503024598e40c84666cc311a42c256bbf880db3ac99sewardj 504024598e40c84666cc311a42c256bbf880db3ac99sewardj 505f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/* Carries around state during Ptrcheck instrumentation. */ 506f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardjtypedef 507f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj struct { 508f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj /* MODIFIED: the superblock being constructed. IRStmts are 509f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj added. */ 510f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRSB* sb; 511f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj Bool trace; 512024598e40c84666cc311a42c256bbf880db3ac99sewardj 513f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj /* MODIFIED: a table [0 .. #temps_in_sb-1] which gives the 514f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj current kind and possibly shadow temps for each temp in the 515f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRSB being constructed. Note that it does not contain the 516f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj type of each tmp. If you want to know the type, look at the 517f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj relevant entry in sb->tyenv. It follows that at all times 518f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj during the instrumentation process, the valid indices for 519f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj tmpMap and sb->tyenv are identical, being 0 .. N-1 where N is 520f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj total number of NonShad and Shad temps allocated so far. 521024598e40c84666cc311a42c256bbf880db3ac99sewardj 522f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj The reason for this strange split (types in one place, all 523f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj other info in another) is that we need the types to be 524f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj attached to sb so as to make it possible to do 525f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj "typeOfIRExpr(mce->bb->tyenv, ...)" at various places in the 526f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj instrumentation process. 527024598e40c84666cc311a42c256bbf880db3ac99sewardj 528f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj Note that only integer temps of the guest word size are 529f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj shadowed, since it is impossible (or meaningless) to hold a 530f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj pointer in any other type of temp. */ 531f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj XArray* /* of TempMapEnt */ qmpMap; 532024598e40c84666cc311a42c256bbf880db3ac99sewardj 533f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj /* READONLY: the host word type. Needed for constructing 534f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj arguments of type 'HWord' to be passed to helper functions. 535f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj Ity_I32 or Ity_I64 only. */ 536f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRType hWordTy; 537024598e40c84666cc311a42c256bbf880db3ac99sewardj 538f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj /* READONLY: the guest word type, Ity_I32 or Ity_I64 only. */ 539f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRType gWordTy; 540024598e40c84666cc311a42c256bbf880db3ac99sewardj 541f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj /* READONLY: the guest state size, so we can generate shadow 542f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj offsets correctly. */ 543f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj Int guest_state_sizeB; 544024598e40c84666cc311a42c256bbf880db3ac99sewardj } 545f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj PCEnv; 546024598e40c84666cc311a42c256bbf880db3ac99sewardj 547f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/* SHADOW TMP MANAGEMENT. Shadow tmps are allocated lazily (on 548f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj demand), as they are encountered. This is for two reasons. 549024598e40c84666cc311a42c256bbf880db3ac99sewardj 550f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj (1) (less important reason): Many original tmps are unused due to 551f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj initial IR optimisation, and we do not want to spaces in tables 552f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj tracking them. 553024598e40c84666cc311a42c256bbf880db3ac99sewardj 554f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj Shadow IRTemps are therefore allocated on demand. pce.tmpMap is a 555f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj table indexed [0 .. n_types-1], which gives the current shadow for 556f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj each original tmp, or INVALID_IRTEMP if none is so far assigned. 557f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj It is necessary to support making multiple assignments to a shadow 558f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj -- specifically, after testing a shadow for definedness, it needs 559f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj to be made defined. But IR's SSA property disallows this. 560024598e40c84666cc311a42c256bbf880db3ac99sewardj 561f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj (2) (more important reason): Therefore, when a shadow needs to get 562f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj a new value, a new temporary is created, the value is assigned to 563f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj that, and the tmpMap is updated to reflect the new binding. 564024598e40c84666cc311a42c256bbf880db3ac99sewardj 565f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj A corollary is that if the tmpMap maps a given tmp to 566f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRTemp_INVALID and we are hoping to read that shadow tmp, it means 567f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj there's a read-before-write error in the original tmps. The IR 568f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj sanity checker should catch all such anomalies, however. 569f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj*/ 570024598e40c84666cc311a42c256bbf880db3ac99sewardj 571f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/* Create a new IRTemp of type 'ty' and kind 'kind', and add it to 572f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj both the table in pce->sb and to our auxiliary mapping. Note that 573f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj newTemp may cause pce->tmpMap to resize, hence previous results 574f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj from VG_(indexXA)(pce->tmpMap) are invalidated. */ 575f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardjstatic IRTemp newTemp ( PCEnv* pce, IRType ty, TempKind kind ) 576f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj{ 577f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj Word newIx; 578f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj TempMapEnt ent; 579f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRTemp tmp = newIRTemp(pce->sb->tyenv, ty); 580f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj ent.kind = kind; 581f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj ent.shadow = IRTemp_INVALID; 582f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj newIx = VG_(addToXA)( pce->qmpMap, &ent ); 583f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj tl_assert(newIx == (Word)tmp); 584f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj return tmp; 585f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj} 586024598e40c84666cc311a42c256bbf880db3ac99sewardj 587024598e40c84666cc311a42c256bbf880db3ac99sewardj/*------------------------------------------------------------*/ 588f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/*--- Constructing IR fragments ---*/ 589024598e40c84666cc311a42c256bbf880db3ac99sewardj/*------------------------------------------------------------*/ 590024598e40c84666cc311a42c256bbf880db3ac99sewardj 591f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj/* add stmt to a bb */ 592f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardjstatic /*inline*/ void stmt ( HChar cat, PCEnv* pce, IRStmt* st ) { 593f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj if (pce->trace) { 594f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj VG_(printf)(" %c: ", cat); 595f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj ppIRStmt(st); 596f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj VG_(printf)("\n"); 597f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj } 598f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj addStmtToIRSB(pce->sb, st); 599024598e40c84666cc311a42c256bbf880db3ac99sewardj} 600024598e40c84666cc311a42c256bbf880db3ac99sewardj 601f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardjstatic IRTemp for_sg__newIRTemp_cb ( IRType ty, void* opaque ) 602f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj{ 603f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj PCEnv* pce = (PCEnv*)opaque; 604f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj return newTemp( pce, ty, NonShad ); 605f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj} 606024598e40c84666cc311a42c256bbf880db3ac99sewardj 607024598e40c84666cc311a42c256bbf880db3ac99sewardj 608f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardjIRSB* h_instrument ( VgCallbackClosure* closure, 609f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRSB* sbIn, 6103c0c94777f547bcb5eadbe8cb4328debf0f51875florian const VexGuestLayout* layout, 6113c0c94777f547bcb5eadbe8cb4328debf0f51875florian const VexGuestExtents* vge, 6123c0c94777f547bcb5eadbe8cb4328debf0f51875florian const VexArchInfo* archinfo_host, 613f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj IRType gWordTy, IRType hWordTy ) 614f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj{ 615f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj Bool verboze = 0||False; 616f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj Int i /*, j*/; 617f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj PCEnv pce; 618f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj struct _SGEnv* sgenv; 619024598e40c84666cc311a42c256bbf880db3ac99sewardj 620f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj if (gWordTy != hWordTy) { 621f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj /* We don't currently support this case. */ 622f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj VG_(tool_panic)("host/guest word size mismatch"); 623f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj } 624024598e40c84666cc311a42c256bbf880db3ac99sewardj 625024598e40c84666cc311a42c256bbf880db3ac99sewardj /* Check we're not completely nuts */ 626024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sizeof(UWord) == sizeof(void*)); 627024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sizeof(Word) == sizeof(void*)); 628024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sizeof(Addr) == sizeof(void*)); 629024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sizeof(ULong) == 8); 630024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sizeof(Long) == 8); 631f466eef8e53aafcb617997e1ca18b7c829168db8florian tl_assert(sizeof(Addr) == sizeof(void*)); 632024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sizeof(UInt) == 4); 633024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sizeof(Int) == 4); 634024598e40c84666cc311a42c256bbf880db3ac99sewardj 635e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj /* Set up the running environment. Both .sb and .tmpMap are 636e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj modified as we go along. Note that tmps are added to both 637e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj .sb->tyenv and .tmpMap together, so the valid index-set for 638e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj those two arrays should always be identical. */ 639e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj VG_(memset)(&pce, 0, sizeof(pce)); 640e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj pce.sb = deepCopyIRSBExceptStmts(sbIn); 641024598e40c84666cc311a42c256bbf880db3ac99sewardj pce.trace = verboze; 642024598e40c84666cc311a42c256bbf880db3ac99sewardj pce.hWordTy = hWordTy; 643024598e40c84666cc311a42c256bbf880db3ac99sewardj pce.gWordTy = gWordTy; 644024598e40c84666cc311a42c256bbf880db3ac99sewardj pce.guest_state_sizeB = layout->total_sizeB; 645024598e40c84666cc311a42c256bbf880db3ac99sewardj 646e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj pce.qmpMap = VG_(newXA)( VG_(malloc), "pc.h_instrument.1", VG_(free), 647e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj sizeof(TempMapEnt)); 648e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj for (i = 0; i < sbIn->tyenv->types_used; i++) { 649e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj TempMapEnt ent; 650e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj ent.kind = NonShad; 651e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj ent.shadow = IRTemp_INVALID; 652e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj VG_(addToXA)( pce.qmpMap, &ent ); 653e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj } 654e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj tl_assert( VG_(sizeXA)( pce.qmpMap ) == sbIn->tyenv->types_used ); 655e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj 656e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj /* Also set up for the sg_ instrumenter. See comments at the top 657e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj of this instrumentation section for details. The two parameters 658e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj constitute a closure, which sg_ can use to correctly generate 659e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj new IRTemps as needed. */ 660e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj sgenv = sg_instrument_init( for_sg__newIRTemp_cb, 661e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj (void*)&pce ); 662024598e40c84666cc311a42c256bbf880db3ac99sewardj 663024598e40c84666cc311a42c256bbf880db3ac99sewardj /* Copy verbatim any IR preamble preceding the first IMark */ 664024598e40c84666cc311a42c256bbf880db3ac99sewardj 665024598e40c84666cc311a42c256bbf880db3ac99sewardj i = 0; 666024598e40c84666cc311a42c256bbf880db3ac99sewardj while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) { 667024598e40c84666cc311a42c256bbf880db3ac99sewardj IRStmt* st = sbIn->stmts[i]; 668024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(st); 669024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(isFlatIRStmt(st)); 670024598e40c84666cc311a42c256bbf880db3ac99sewardj stmt( 'C', &pce, sbIn->stmts[i] ); 671024598e40c84666cc311a42c256bbf880db3ac99sewardj i++; 672024598e40c84666cc311a42c256bbf880db3ac99sewardj } 673024598e40c84666cc311a42c256bbf880db3ac99sewardj 674024598e40c84666cc311a42c256bbf880db3ac99sewardj /* Iterate over the remaining stmts to generate instrumentation. */ 675024598e40c84666cc311a42c256bbf880db3ac99sewardj 676024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sbIn->stmts_used > 0); 677024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(i >= 0); 678024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(i < sbIn->stmts_used); 679024598e40c84666cc311a42c256bbf880db3ac99sewardj tl_assert(sbIn->stmts[i]->tag == Ist_IMark); 680024598e40c84666cc311a42c256bbf880db3ac99sewardj 681024598e40c84666cc311a42c256bbf880db3ac99sewardj for (/*use current i*/; i < sbIn->stmts_used; i++) { 682024598e40c84666cc311a42c256bbf880db3ac99sewardj /* generate sg_ instrumentation for this stmt */ 683e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj sg_instrument_IRStmt( sgenv, pce.sb, sbIn->stmts[i], 684024598e40c84666cc311a42c256bbf880db3ac99sewardj layout, gWordTy, hWordTy ); 685f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj 686f5b019fb45b52a26fefa40b8fa5b518f0686dd99sewardj stmt( 'C', &pce, sbIn->stmts[i] ); 687024598e40c84666cc311a42c256bbf880db3ac99sewardj } 688024598e40c84666cc311a42c256bbf880db3ac99sewardj 689024598e40c84666cc311a42c256bbf880db3ac99sewardj /* generate sg_ instrumentation for the final jump */ 690e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj sg_instrument_final_jump( sgenv, pce.sb, sbIn->next, sbIn->jumpkind, 691024598e40c84666cc311a42c256bbf880db3ac99sewardj layout, gWordTy, hWordTy ); 692024598e40c84666cc311a42c256bbf880db3ac99sewardj 693024598e40c84666cc311a42c256bbf880db3ac99sewardj /* and finalise .. */ 694024598e40c84666cc311a42c256bbf880db3ac99sewardj sg_instrument_fini( sgenv ); 695024598e40c84666cc311a42c256bbf880db3ac99sewardj 696e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj /* If this fails, there's been some serious snafu with tmp management, 697e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj that should be investigated. */ 698e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj tl_assert( VG_(sizeXA)( pce.qmpMap ) == pce.sb->tyenv->types_used ); 699e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj VG_(deleteXA)( pce.qmpMap ); 700e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj 701e6451332ee19f6d70821bf8e24781ff8868bdb3csewardj return pce.sb; 702024598e40c84666cc311a42c256bbf880db3ac99sewardj} 703024598e40c84666cc311a42c256bbf880db3ac99sewardj 704024598e40c84666cc311a42c256bbf880db3ac99sewardj 705024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--------------------------------------------------------------------*/ 706024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--- Finalisation ---*/ 707024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--------------------------------------------------------------------*/ 708024598e40c84666cc311a42c256bbf880db3ac99sewardj 709024598e40c84666cc311a42c256bbf880db3ac99sewardjvoid h_fini ( Int exitcode ) 710024598e40c84666cc311a42c256bbf880db3ac99sewardj{ 7112d9e874b7a628ada216f09cc4f065798c65fffa4sewardj if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) { 7122d9e874b7a628ada216f09cc4f065798c65fffa4sewardj VG_(message)(Vg_UserMsg, 7132d9e874b7a628ada216f09cc4f065798c65fffa4sewardj "For counts of detected and suppressed errors, " 7142d9e874b7a628ada216f09cc4f065798c65fffa4sewardj "rerun with: -v\n"); 7152d9e874b7a628ada216f09cc4f065798c65fffa4sewardj } 7162d9e874b7a628ada216f09cc4f065798c65fffa4sewardj 7172d9e874b7a628ada216f09cc4f065798c65fffa4sewardj if (VG_(clo_stats)) { 718024598e40c84666cc311a42c256bbf880db3ac99sewardj VG_(message)(Vg_DebugMsg, 719c1bc9d1214d8c057eb2e96f3e96454688e5488c4sewardj " h_: %'10llu client allocs, %'10llu client frees\n", 720024598e40c84666cc311a42c256bbf880db3ac99sewardj stats__client_mallocs, stats__client_frees); 721024598e40c84666cc311a42c256bbf880db3ac99sewardj VG_(message)(Vg_DebugMsg, 722c1bc9d1214d8c057eb2e96f3e96454688e5488c4sewardj " h_: %'10llu Segs allocd, %'10llu Segs recycled\n", 723024598e40c84666cc311a42c256bbf880db3ac99sewardj stats__segs_allocd, stats__segs_recycled); 724024598e40c84666cc311a42c256bbf880db3ac99sewardj } 725024598e40c84666cc311a42c256bbf880db3ac99sewardj} 726024598e40c84666cc311a42c256bbf880db3ac99sewardj 727024598e40c84666cc311a42c256bbf880db3ac99sewardj 728024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--------------------------------------------------------------------*/ 729024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--- end h_main.c ---*/ 730024598e40c84666cc311a42c256bbf880db3ac99sewardj/*--------------------------------------------------------------------*/ 731