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