blob: 3c069bfff2fd6cb2f6aee7a57a591ebc581c4e09 [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00003/*--- MemCheck: Maintain bitmaps of memory, tracking the ---*/
4/*--- accessibility (A) and validity (V) status of each byte. ---*/
njn25cac76cb2002-09-23 11:21:57 +00005/*--- mc_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00006/*--------------------------------------------------------------------*/
7
8/*
nethercote137bc552003-11-14 17:47:54 +00009 This file is part of MemCheck, a heavyweight Valgrind tool for
njnc9539842002-10-02 13:26:35 +000010 detecting memory errors.
njn25e49d8e72002-09-23 09:36:25 +000011
sewardj4d474d02008-02-11 11:34:59 +000012 Copyright (C) 2000-2008 Julian Seward
njn25e49d8e72002-09-23 09:36:25 +000013 jseward@acm.org
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file COPYING.
31*/
32
njnc7561b92005-06-19 01:24:32 +000033#include "pub_tool_basics.h"
njn4802b382005-06-11 04:58:29 +000034#include "pub_tool_aspacemgr.h"
njn1d0825f2006-03-27 11:37:07 +000035#include "pub_tool_hashtable.h" // For mc_include.h
njn97405b22005-06-02 03:39:33 +000036#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000037#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf536bbb2005-06-13 04:21:38 +000039#include "pub_tool_machine.h"
njnc7561b92005-06-19 01:24:32 +000040#include "pub_tool_mallocfree.h"
41#include "pub_tool_options.h"
njn1d0825f2006-03-27 11:37:07 +000042#include "pub_tool_oset.h"
njnc7561b92005-06-19 01:24:32 +000043#include "pub_tool_replacemalloc.h"
44#include "pub_tool_tooliface.h"
45#include "pub_tool_threadstate.h"
46
47#include "mc_include.h"
48#include "memcheck.h" /* for client requests */
njn25e49d8e72002-09-23 09:36:25 +000049
sewardjc1a2cda2005-04-21 17:34:00 +000050
njn1d0825f2006-03-27 11:37:07 +000051/* Set to 1 to do a little more sanity checking */
sewardj23eb2fd2005-04-22 16:29:19 +000052#define VG_DEBUG_MEMORY 0
sewardjc1a2cda2005-04-21 17:34:00 +000053
njn25e49d8e72002-09-23 09:36:25 +000054#define DEBUG(fmt, args...) //VG_(printf)(fmt, ## args)
55
sewardj7cf4e6b2008-05-01 20:24:26 +000056static void ocache_sarp_Set_Origins ( Addr, UWord, UInt ); /* fwds */
57static void ocache_sarp_Clear_Origins ( Addr, UWord ); /* fwds */
58
njn25e49d8e72002-09-23 09:36:25 +000059
njn25e49d8e72002-09-23 09:36:25 +000060/*------------------------------------------------------------*/
njn1d0825f2006-03-27 11:37:07 +000061/*--- Fast-case knobs ---*/
62/*------------------------------------------------------------*/
63
64// Comment these out to disable the fast cases (don't just set them to zero).
65
66#define PERF_FAST_LOADV 1
67#define PERF_FAST_STOREV 1
68
69#define PERF_FAST_SARP 1
70
71#define PERF_FAST_STACK 1
72#define PERF_FAST_STACK2 1
73
sewardj7cf4e6b2008-05-01 20:24:26 +000074/* Change this to 1 to enable assertions on origin tracking cache fast
75 paths */
76#define OC_ENABLE_ASSERTIONS 0
77
78
njn1d0825f2006-03-27 11:37:07 +000079/*------------------------------------------------------------*/
sewardj77139802008-05-05 09:48:56 +000080/*--- Comments on the origin tracking implementation ---*/
81/*------------------------------------------------------------*/
82
83/* See detailed comment entitled
84 AN OVERVIEW OF THE ORIGIN TRACKING IMPLEMENTATION
85 which is contained further on in this file. */
86
87
88/*------------------------------------------------------------*/
njn1d0825f2006-03-27 11:37:07 +000089/*--- V bits and A bits ---*/
90/*------------------------------------------------------------*/
91
92/* Conceptually, every byte value has 8 V bits, which track whether Memcheck
93 thinks the corresponding value bit is defined. And every memory byte
94 has an A bit, which tracks whether Memcheck thinks the program can access
95 it safely. So every N-bit register is shadowed with N V bits, and every
96 memory byte is shadowed with 8 V bits and one A bit.
97
98 In the implementation, we use two forms of compression (compressed V bits
99 and distinguished secondary maps) to avoid the 9-bit-per-byte overhead
100 for memory.
101
102 Memcheck also tracks extra information about each heap block that is
103 allocated, for detecting memory leaks and other purposes.
104*/
105
106/*------------------------------------------------------------*/
sewardj45d94cc2005-04-20 14:44:11 +0000107/*--- Basic A/V bitmap representation. ---*/
njn25e49d8e72002-09-23 09:36:25 +0000108/*------------------------------------------------------------*/
109
njn1d0825f2006-03-27 11:37:07 +0000110/* All reads and writes are checked against a memory map (a.k.a. shadow
111 memory), which records the state of all memory in the process.
112
113 On 32-bit machines the memory map is organised as follows.
114 The top 16 bits of an address are used to index into a top-level
115 map table, containing 65536 entries. Each entry is a pointer to a
116 second-level map, which records the accesibililty and validity
117 permissions for the 65536 bytes indexed by the lower 16 bits of the
118 address. Each byte is represented by two bits (details are below). So
119 each second-level map contains 16384 bytes. This two-level arrangement
120 conveniently divides the 4G address space into 64k lumps, each size 64k
121 bytes.
122
123 All entries in the primary (top-level) map must point to a valid
124 secondary (second-level) map. Since many of the 64kB chunks will
njndbf7ca72006-03-31 11:57:59 +0000125 have the same status for every bit -- ie. noaccess (for unused
126 address space) or entirely addressable and defined (for code segments) --
127 there are three distinguished secondary maps, which indicate 'noaccess',
128 'undefined' and 'defined'. For these uniform 64kB chunks, the primary
129 map entry points to the relevant distinguished map. In practice,
130 typically more than half of the addressable memory is represented with
131 the 'undefined' or 'defined' distinguished secondary map, so it gives a
132 good saving. It also lets us set the V+A bits of large address regions
133 quickly in set_address_range_perms().
njn1d0825f2006-03-27 11:37:07 +0000134
135 On 64-bit machines it's more complicated. If we followed the same basic
136 scheme we'd have a four-level table which would require too many memory
137 accesses. So instead the top-level map table has 2^19 entries (indexed
138 using bits 16..34 of the address); this covers the bottom 32GB. Any
139 accesses above 32GB are handled with a slow, sparse auxiliary table.
140 Valgrind's address space manager tries very hard to keep things below
141 this 32GB barrier so that performance doesn't suffer too much.
142
143 Note that this file has a lot of different functions for reading and
144 writing shadow memory. Only a couple are strictly necessary (eg.
145 get_vabits2 and set_vabits2), most are just specialised for specific
146 common cases to improve performance.
147
148 Aside: the V+A bits are less precise than they could be -- we have no way
149 of marking memory as read-only. It would be great if we could add an
150 extra state VA_BITSn_READONLY. But then we'd have 5 different states,
151 which requires 2.3 bits to hold, and there's no way to do that elegantly
152 -- we'd have to double up to 4 bits of metadata per byte, which doesn't
153 seem worth it.
154*/
sewardjc859fbf2005-04-22 21:10:28 +0000155
sewardj45d94cc2005-04-20 14:44:11 +0000156/* --------------- Basic configuration --------------- */
sewardj95448072004-11-22 20:19:51 +0000157
sewardj23eb2fd2005-04-22 16:29:19 +0000158/* Only change this. N_PRIMARY_MAP *must* be a power of 2. */
sewardj21f7ff42005-04-28 10:32:02 +0000159
sewardje4ccc012005-05-02 12:53:38 +0000160#if VG_WORDSIZE == 4
sewardj21f7ff42005-04-28 10:32:02 +0000161
162/* cover the entire address space */
163# define N_PRIMARY_BITS 16
164
165#else
166
sewardj34483bc2005-09-28 11:50:20 +0000167/* Just handle the first 32G fast and the rest via auxiliary
sewardj7244e712008-05-02 12:35:48 +0000168 primaries. If you change this, Memcheck will assert at startup.
169 See the definition of UNALIGNED_OR_HIGH for extensive comments. */
sewardj34483bc2005-09-28 11:50:20 +0000170# define N_PRIMARY_BITS 19
sewardj21f7ff42005-04-28 10:32:02 +0000171
172#endif
173
sewardj45d94cc2005-04-20 14:44:11 +0000174
sewardjc1a2cda2005-04-21 17:34:00 +0000175/* Do not change this. */
sewardje4ccc012005-05-02 12:53:38 +0000176#define N_PRIMARY_MAP ( ((UWord)1) << N_PRIMARY_BITS)
sewardjc1a2cda2005-04-21 17:34:00 +0000177
178/* Do not change this. */
sewardj23eb2fd2005-04-22 16:29:19 +0000179#define MAX_PRIMARY_ADDRESS (Addr)((((Addr)65536) * N_PRIMARY_MAP)-1)
180
181
sewardj45d94cc2005-04-20 14:44:11 +0000182/* --------------- Secondary maps --------------- */
njn25e49d8e72002-09-23 09:36:25 +0000183
njn1d0825f2006-03-27 11:37:07 +0000184// Each byte of memory conceptually has an A bit, which indicates its
185// addressability, and 8 V bits, which indicates its definedness.
186//
187// But because very few bytes are partially defined, we can use a nice
188// compression scheme to reduce the size of shadow memory. Each byte of
189// memory has 2 bits which indicates its state (ie. V+A bits):
190//
njndbf7ca72006-03-31 11:57:59 +0000191// 00: noaccess (unaddressable but treated as fully defined)
192// 01: undefined (addressable and fully undefined)
193// 10: defined (addressable and fully defined)
194// 11: partdefined (addressable and partially defined)
njn1d0825f2006-03-27 11:37:07 +0000195//
njndbf7ca72006-03-31 11:57:59 +0000196// In the "partdefined" case, we use a secondary table to store the V bits.
197// Each entry in the secondary-V-bits table maps a byte address to its 8 V
198// bits.
njn1d0825f2006-03-27 11:37:07 +0000199//
200// We store the compressed V+A bits in 8-bit chunks, ie. the V+A bits for
201// four bytes (32 bits) of memory are in each chunk. Hence the name
202// "vabits8". This lets us get the V+A bits for four bytes at a time
203// easily (without having to do any shifting and/or masking), and that is a
204// very common operation. (Note that although each vabits8 chunk
205// is 8 bits in size, it represents 32 bits of memory.)
206//
207// The representation is "inverse" little-endian... each 4 bytes of
208// memory is represented by a 1 byte value, where:
209//
210// - the status of byte (a+0) is held in bits [1..0]
211// - the status of byte (a+1) is held in bits [3..2]
212// - the status of byte (a+2) is held in bits [5..4]
213// - the status of byte (a+3) is held in bits [7..6]
214//
215// It's "inverse" because endianness normally describes a mapping from
216// value bits to memory addresses; in this case the mapping is inverted.
217// Ie. instead of particular value bits being held in certain addresses, in
218// this case certain addresses are represented by particular value bits.
219// See insert_vabits2_into_vabits8() for an example.
220//
221// But note that we don't compress the V bits stored in registers; they
222// need to be explicit to made the shadow operations possible. Therefore
223// when moving values between registers and memory we need to convert
224// between the expanded in-register format and the compressed in-memory
225// format. This isn't so difficult, it just requires careful attention in a
226// few places.
227
228// These represent eight bits of memory.
229#define VA_BITS2_NOACCESS 0x0 // 00b
njndbf7ca72006-03-31 11:57:59 +0000230#define VA_BITS2_UNDEFINED 0x1 // 01b
231#define VA_BITS2_DEFINED 0x2 // 10b
232#define VA_BITS2_PARTDEFINED 0x3 // 11b
njn1d0825f2006-03-27 11:37:07 +0000233
234// These represent 16 bits of memory.
235#define VA_BITS4_NOACCESS 0x0 // 00_00b
njndbf7ca72006-03-31 11:57:59 +0000236#define VA_BITS4_UNDEFINED 0x5 // 01_01b
237#define VA_BITS4_DEFINED 0xa // 10_10b
njn1d0825f2006-03-27 11:37:07 +0000238
239// These represent 32 bits of memory.
240#define VA_BITS8_NOACCESS 0x00 // 00_00_00_00b
njndbf7ca72006-03-31 11:57:59 +0000241#define VA_BITS8_UNDEFINED 0x55 // 01_01_01_01b
242#define VA_BITS8_DEFINED 0xaa // 10_10_10_10b
njn1d0825f2006-03-27 11:37:07 +0000243
244// These represent 64 bits of memory.
245#define VA_BITS16_NOACCESS 0x0000 // 00_00_00_00b x 2
njndbf7ca72006-03-31 11:57:59 +0000246#define VA_BITS16_UNDEFINED 0x5555 // 01_01_01_01b x 2
247#define VA_BITS16_DEFINED 0xaaaa // 10_10_10_10b x 2
njn1d0825f2006-03-27 11:37:07 +0000248
249
250#define SM_CHUNKS 16384
251#define SM_OFF(aaa) (((aaa) & 0xffff) >> 2)
252#define SM_OFF_16(aaa) (((aaa) & 0xffff) >> 3)
253
254// Paranoia: it's critical for performance that the requested inlining
255// occurs. So try extra hard.
256#define INLINE inline __attribute__((always_inline))
257
258static INLINE Addr start_of_this_sm ( Addr a ) {
259 return (a & (~SM_MASK));
260}
261static INLINE Bool is_start_of_sm ( Addr a ) {
262 return (start_of_this_sm(a) == a);
263}
264
njn25e49d8e72002-09-23 09:36:25 +0000265typedef
266 struct {
njn1d0825f2006-03-27 11:37:07 +0000267 UChar vabits8[SM_CHUNKS];
njn25e49d8e72002-09-23 09:36:25 +0000268 }
269 SecMap;
270
njn1d0825f2006-03-27 11:37:07 +0000271// 3 distinguished secondary maps, one for no-access, one for
272// accessible but undefined, and one for accessible and defined.
273// Distinguished secondaries may never be modified.
274#define SM_DIST_NOACCESS 0
njndbf7ca72006-03-31 11:57:59 +0000275#define SM_DIST_UNDEFINED 1
276#define SM_DIST_DEFINED 2
njnb8dca862005-03-14 02:42:44 +0000277
sewardj45d94cc2005-04-20 14:44:11 +0000278static SecMap sm_distinguished[3];
njnb8dca862005-03-14 02:42:44 +0000279
njn1d0825f2006-03-27 11:37:07 +0000280static INLINE Bool is_distinguished_sm ( SecMap* sm ) {
sewardj45d94cc2005-04-20 14:44:11 +0000281 return sm >= &sm_distinguished[0] && sm <= &sm_distinguished[2];
282}
njnb8dca862005-03-14 02:42:44 +0000283
njn1d0825f2006-03-27 11:37:07 +0000284// Forward declaration
285static void update_SM_counts(SecMap* oldSM, SecMap* newSM);
286
sewardj45d94cc2005-04-20 14:44:11 +0000287/* dist_sm points to one of our three distinguished secondaries. Make
288 a copy of it so that we can write to it.
289*/
290static SecMap* copy_for_writing ( SecMap* dist_sm )
291{
292 SecMap* new_sm;
293 tl_assert(dist_sm == &sm_distinguished[0]
njn1d0825f2006-03-27 11:37:07 +0000294 || dist_sm == &sm_distinguished[1]
295 || dist_sm == &sm_distinguished[2]);
njnb8dca862005-03-14 02:42:44 +0000296
sewardj45f4e7c2005-09-27 19:20:21 +0000297 new_sm = VG_(am_shadow_alloc)(sizeof(SecMap));
298 if (new_sm == NULL)
299 VG_(out_of_memory_NORETURN)( "memcheck:allocate new SecMap",
300 sizeof(SecMap) );
sewardj45d94cc2005-04-20 14:44:11 +0000301 VG_(memcpy)(new_sm, dist_sm, sizeof(SecMap));
njn1d0825f2006-03-27 11:37:07 +0000302 update_SM_counts(dist_sm, new_sm);
sewardj45d94cc2005-04-20 14:44:11 +0000303 return new_sm;
304}
njnb8dca862005-03-14 02:42:44 +0000305
njn1d0825f2006-03-27 11:37:07 +0000306/* --------------- Stats --------------- */
307
njndbf7ca72006-03-31 11:57:59 +0000308static Int n_issued_SMs = 0;
309static Int n_deissued_SMs = 0;
310static Int n_noaccess_SMs = N_PRIMARY_MAP; // start with many noaccess DSMs
311static Int n_undefined_SMs = 0;
312static Int n_defined_SMs = 0;
313static Int n_non_DSM_SMs = 0;
314static Int max_noaccess_SMs = 0;
315static Int max_undefined_SMs = 0;
316static Int max_defined_SMs = 0;
317static Int max_non_DSM_SMs = 0;
njn1d0825f2006-03-27 11:37:07 +0000318
sewardj05a46732006-10-17 01:28:10 +0000319/* # searches initiated in auxmap_L1, and # base cmps required */
320static ULong n_auxmap_L1_searches = 0;
321static ULong n_auxmap_L1_cmps = 0;
322/* # of searches that missed in auxmap_L1 and therefore had to
323 be handed to auxmap_L2. And the number of nodes inserted. */
324static ULong n_auxmap_L2_searches = 0;
325static ULong n_auxmap_L2_nodes = 0;
326
njn1d0825f2006-03-27 11:37:07 +0000327static Int n_sanity_cheap = 0;
328static Int n_sanity_expensive = 0;
329
330static Int n_secVBit_nodes = 0;
331static Int max_secVBit_nodes = 0;
332
333static void update_SM_counts(SecMap* oldSM, SecMap* newSM)
334{
njndbf7ca72006-03-31 11:57:59 +0000335 if (oldSM == &sm_distinguished[SM_DIST_NOACCESS ]) n_noaccess_SMs --;
336 else if (oldSM == &sm_distinguished[SM_DIST_UNDEFINED]) n_undefined_SMs--;
337 else if (oldSM == &sm_distinguished[SM_DIST_DEFINED ]) n_defined_SMs --;
338 else { n_non_DSM_SMs --;
339 n_deissued_SMs ++; }
njn1d0825f2006-03-27 11:37:07 +0000340
njndbf7ca72006-03-31 11:57:59 +0000341 if (newSM == &sm_distinguished[SM_DIST_NOACCESS ]) n_noaccess_SMs ++;
342 else if (newSM == &sm_distinguished[SM_DIST_UNDEFINED]) n_undefined_SMs++;
343 else if (newSM == &sm_distinguished[SM_DIST_DEFINED ]) n_defined_SMs ++;
344 else { n_non_DSM_SMs ++;
345 n_issued_SMs ++; }
njn1d0825f2006-03-27 11:37:07 +0000346
njndbf7ca72006-03-31 11:57:59 +0000347 if (n_noaccess_SMs > max_noaccess_SMs ) max_noaccess_SMs = n_noaccess_SMs;
348 if (n_undefined_SMs > max_undefined_SMs) max_undefined_SMs = n_undefined_SMs;
349 if (n_defined_SMs > max_defined_SMs ) max_defined_SMs = n_defined_SMs;
350 if (n_non_DSM_SMs > max_non_DSM_SMs ) max_non_DSM_SMs = n_non_DSM_SMs;
njn1d0825f2006-03-27 11:37:07 +0000351}
sewardj45d94cc2005-04-20 14:44:11 +0000352
353/* --------------- Primary maps --------------- */
354
355/* The main primary map. This covers some initial part of the address
sewardj23eb2fd2005-04-22 16:29:19 +0000356 space, addresses 0 .. (N_PRIMARY_MAP << 16)-1. The rest of it is
sewardj45d94cc2005-04-20 14:44:11 +0000357 handled using the auxiliary primary map.
358*/
sewardj23eb2fd2005-04-22 16:29:19 +0000359static SecMap* primary_map[N_PRIMARY_MAP];
sewardj45d94cc2005-04-20 14:44:11 +0000360
361
362/* An entry in the auxiliary primary map. base must be a 64k-aligned
363 value, and sm points at the relevant secondary map. As with the
364 main primary map, the secondary may be either a real secondary, or
sewardj05a46732006-10-17 01:28:10 +0000365 one of the three distinguished secondaries. DO NOT CHANGE THIS
366 LAYOUT: the first word has to be the key for OSet fast lookups.
sewardj45d94cc2005-04-20 14:44:11 +0000367*/
368typedef
369 struct {
sewardj23eb2fd2005-04-22 16:29:19 +0000370 Addr base;
sewardj45d94cc2005-04-20 14:44:11 +0000371 SecMap* sm;
372 }
373 AuxMapEnt;
374
sewardj05a46732006-10-17 01:28:10 +0000375/* Tunable parameter: How big is the L1 queue? */
376#define N_AUXMAP_L1 24
sewardj45d94cc2005-04-20 14:44:11 +0000377
sewardj05a46732006-10-17 01:28:10 +0000378/* Tunable parameter: How far along the L1 queue to insert
379 entries resulting from L2 lookups? */
380#define AUXMAP_L1_INSERT_IX 12
sewardj45d94cc2005-04-20 14:44:11 +0000381
sewardj05a46732006-10-17 01:28:10 +0000382static struct {
383 Addr base;
384 AuxMapEnt* ent; // pointer to the matching auxmap_L2 node
385 }
386 auxmap_L1[N_AUXMAP_L1];
387
388static OSet* auxmap_L2 = NULL;
389
390static void init_auxmap_L1_L2 ( void )
sewardj45d94cc2005-04-20 14:44:11 +0000391{
sewardj05a46732006-10-17 01:28:10 +0000392 Int i;
393 for (i = 0; i < N_AUXMAP_L1; i++) {
394 auxmap_L1[i].base = 0;
395 auxmap_L1[i].ent = NULL;
sewardj45d94cc2005-04-20 14:44:11 +0000396 }
397
sewardj05a46732006-10-17 01:28:10 +0000398 tl_assert(0 == offsetof(AuxMapEnt,base));
399 tl_assert(sizeof(Addr) == sizeof(void*));
njne2a9ad32007-09-17 05:30:48 +0000400 auxmap_L2 = VG_(OSetGen_Create)( /*keyOff*/ offsetof(AuxMapEnt,base),
401 /*fastCmp*/ NULL,
sewardj9c606bd2008-09-18 18:12:50 +0000402 VG_(malloc), "mc.iaLL.1", VG_(free) );
sewardj05fe85e2005-04-27 22:46:36 +0000403}
404
sewardj05a46732006-10-17 01:28:10 +0000405/* Check representation invariants; if OK return NULL; else a
406 descriptive bit of text. Also return the number of
407 non-distinguished secondary maps referred to from the auxiliary
408 primary maps. */
sewardj05fe85e2005-04-27 22:46:36 +0000409
sewardj05a46732006-10-17 01:28:10 +0000410static HChar* check_auxmap_L1_L2_sanity ( Word* n_secmaps_found )
sewardj05fe85e2005-04-27 22:46:36 +0000411{
sewardj05a46732006-10-17 01:28:10 +0000412 Word i, j;
413 /* On a 32-bit platform, the L2 and L1 tables should
414 both remain empty forever.
sewardj05fe85e2005-04-27 22:46:36 +0000415
sewardj05a46732006-10-17 01:28:10 +0000416 On a 64-bit platform:
417 In the L2 table:
418 all .base & 0xFFFF == 0
419 all .base > MAX_PRIMARY_ADDRESS
420 In the L1 table:
421 all .base & 0xFFFF == 0
422 all (.base > MAX_PRIMARY_ADDRESS
423 .base & 0xFFFF == 0
424 and .ent points to an AuxMapEnt with the same .base)
425 or
426 (.base == 0 and .ent == NULL)
427 */
428 *n_secmaps_found = 0;
429 if (sizeof(void*) == 4) {
430 /* 32-bit platform */
njne2a9ad32007-09-17 05:30:48 +0000431 if (VG_(OSetGen_Size)(auxmap_L2) != 0)
sewardj05a46732006-10-17 01:28:10 +0000432 return "32-bit: auxmap_L2 is non-empty";
433 for (i = 0; i < N_AUXMAP_L1; i++)
434 if (auxmap_L1[i].base != 0 || auxmap_L1[i].ent != NULL)
435 return "32-bit: auxmap_L1 is non-empty";
436 } else {
437 /* 64-bit platform */
438 UWord elems_seen = 0;
439 AuxMapEnt *elem, *res;
440 AuxMapEnt key;
441 /* L2 table */
njne2a9ad32007-09-17 05:30:48 +0000442 VG_(OSetGen_ResetIter)(auxmap_L2);
443 while ( (elem = VG_(OSetGen_Next)(auxmap_L2)) ) {
sewardj05a46732006-10-17 01:28:10 +0000444 elems_seen++;
445 if (0 != (elem->base & (Addr)0xFFFF))
446 return "64-bit: nonzero .base & 0xFFFF in auxmap_L2";
447 if (elem->base <= MAX_PRIMARY_ADDRESS)
448 return "64-bit: .base <= MAX_PRIMARY_ADDRESS in auxmap_L2";
449 if (elem->sm == NULL)
450 return "64-bit: .sm in _L2 is NULL";
451 if (!is_distinguished_sm(elem->sm))
452 (*n_secmaps_found)++;
453 }
454 if (elems_seen != n_auxmap_L2_nodes)
455 return "64-bit: disagreement on number of elems in _L2";
456 /* Check L1-L2 correspondence */
457 for (i = 0; i < N_AUXMAP_L1; i++) {
458 if (auxmap_L1[i].base == 0 && auxmap_L1[i].ent == NULL)
459 continue;
460 if (0 != (auxmap_L1[i].base & (Addr)0xFFFF))
461 return "64-bit: nonzero .base & 0xFFFF in auxmap_L1";
462 if (auxmap_L1[i].base <= MAX_PRIMARY_ADDRESS)
463 return "64-bit: .base <= MAX_PRIMARY_ADDRESS in auxmap_L1";
464 if (auxmap_L1[i].ent == NULL)
465 return "64-bit: .ent is NULL in auxmap_L1";
466 if (auxmap_L1[i].ent->base != auxmap_L1[i].base)
467 return "64-bit: _L1 and _L2 bases are inconsistent";
468 /* Look it up in auxmap_L2. */
469 key.base = auxmap_L1[i].base;
470 key.sm = 0;
njne2a9ad32007-09-17 05:30:48 +0000471 res = VG_(OSetGen_Lookup)(auxmap_L2, &key);
sewardj05a46732006-10-17 01:28:10 +0000472 if (res == NULL)
473 return "64-bit: _L1 .base not found in _L2";
474 if (res != auxmap_L1[i].ent)
475 return "64-bit: _L1 .ent disagrees with _L2 entry";
476 }
477 /* Check L1 contains no duplicates */
478 for (i = 0; i < N_AUXMAP_L1; i++) {
479 if (auxmap_L1[i].base == 0)
480 continue;
481 for (j = i+1; j < N_AUXMAP_L1; j++) {
482 if (auxmap_L1[j].base == 0)
483 continue;
484 if (auxmap_L1[j].base == auxmap_L1[i].base)
485 return "64-bit: duplicate _L1 .base entries";
486 }
487 }
488 }
489 return NULL; /* ok */
490}
491
492static void insert_into_auxmap_L1_at ( Word rank, AuxMapEnt* ent )
493{
494 Word i;
495 tl_assert(ent);
496 tl_assert(rank >= 0 && rank < N_AUXMAP_L1);
497 for (i = N_AUXMAP_L1-1; i > rank; i--)
498 auxmap_L1[i] = auxmap_L1[i-1];
499 auxmap_L1[rank].base = ent->base;
500 auxmap_L1[rank].ent = ent;
501}
502
503static INLINE AuxMapEnt* maybe_find_in_auxmap ( Addr a )
504{
505 AuxMapEnt key;
506 AuxMapEnt* res;
507 Word i;
508
509 tl_assert(a > MAX_PRIMARY_ADDRESS);
510 a &= ~(Addr)0xFFFF;
511
512 /* First search the front-cache, which is a self-organising
513 list containing the most popular entries. */
514
bart5dd8e6a2008-03-22 08:04:29 +0000515 if (LIKELY(auxmap_L1[0].base == a))
sewardj05a46732006-10-17 01:28:10 +0000516 return auxmap_L1[0].ent;
bart5dd8e6a2008-03-22 08:04:29 +0000517 if (LIKELY(auxmap_L1[1].base == a)) {
sewardj05a46732006-10-17 01:28:10 +0000518 Addr t_base = auxmap_L1[0].base;
519 AuxMapEnt* t_ent = auxmap_L1[0].ent;
520 auxmap_L1[0].base = auxmap_L1[1].base;
521 auxmap_L1[0].ent = auxmap_L1[1].ent;
522 auxmap_L1[1].base = t_base;
523 auxmap_L1[1].ent = t_ent;
524 return auxmap_L1[0].ent;
sewardj45d94cc2005-04-20 14:44:11 +0000525 }
526
sewardj05a46732006-10-17 01:28:10 +0000527 n_auxmap_L1_searches++;
sewardj45d94cc2005-04-20 14:44:11 +0000528
sewardj05a46732006-10-17 01:28:10 +0000529 for (i = 0; i < N_AUXMAP_L1; i++) {
530 if (auxmap_L1[i].base == a) {
531 break;
532 }
533 }
534 tl_assert(i >= 0 && i <= N_AUXMAP_L1);
sewardj45d94cc2005-04-20 14:44:11 +0000535
sewardj05a46732006-10-17 01:28:10 +0000536 n_auxmap_L1_cmps += (ULong)(i+1);
sewardj45d94cc2005-04-20 14:44:11 +0000537
sewardj05a46732006-10-17 01:28:10 +0000538 if (i < N_AUXMAP_L1) {
539 if (i > 0) {
540 Addr t_base = auxmap_L1[i-1].base;
541 AuxMapEnt* t_ent = auxmap_L1[i-1].ent;
542 auxmap_L1[i-1].base = auxmap_L1[i-0].base;
543 auxmap_L1[i-1].ent = auxmap_L1[i-0].ent;
544 auxmap_L1[i-0].base = t_base;
545 auxmap_L1[i-0].ent = t_ent;
546 i--;
547 }
548 return auxmap_L1[i].ent;
549 }
550
551 n_auxmap_L2_searches++;
552
553 /* First see if we already have it. */
554 key.base = a;
555 key.sm = 0;
556
njne2a9ad32007-09-17 05:30:48 +0000557 res = VG_(OSetGen_Lookup)(auxmap_L2, &key);
sewardj05a46732006-10-17 01:28:10 +0000558 if (res)
559 insert_into_auxmap_L1_at( AUXMAP_L1_INSERT_IX, res );
560 return res;
561}
562
563static AuxMapEnt* find_or_alloc_in_auxmap ( Addr a )
564{
565 AuxMapEnt *nyu, *res;
566
567 /* First see if we already have it. */
568 res = maybe_find_in_auxmap( a );
bart5dd8e6a2008-03-22 08:04:29 +0000569 if (LIKELY(res))
sewardj05a46732006-10-17 01:28:10 +0000570 return res;
571
572 /* Ok, there's no entry in the secondary map, so we'll have
573 to allocate one. */
574 a &= ~(Addr)0xFFFF;
575
njne2a9ad32007-09-17 05:30:48 +0000576 nyu = (AuxMapEnt*) VG_(OSetGen_AllocNode)( auxmap_L2, sizeof(AuxMapEnt) );
sewardj05a46732006-10-17 01:28:10 +0000577 tl_assert(nyu);
578 nyu->base = a;
579 nyu->sm = &sm_distinguished[SM_DIST_NOACCESS];
njne2a9ad32007-09-17 05:30:48 +0000580 VG_(OSetGen_Insert)( auxmap_L2, nyu );
sewardj05a46732006-10-17 01:28:10 +0000581 insert_into_auxmap_L1_at( AUXMAP_L1_INSERT_IX, nyu );
582 n_auxmap_L2_nodes++;
583 return nyu;
sewardj45d94cc2005-04-20 14:44:11 +0000584}
585
sewardj45d94cc2005-04-20 14:44:11 +0000586/* --------------- SecMap fundamentals --------------- */
587
njn1d0825f2006-03-27 11:37:07 +0000588// In all these, 'low' means it's definitely in the main primary map,
589// 'high' means it's definitely in the auxiliary table.
590
591static INLINE SecMap** get_secmap_low_ptr ( Addr a )
592{
593 UWord pm_off = a >> 16;
594# if VG_DEBUG_MEMORY >= 1
595 tl_assert(pm_off < N_PRIMARY_MAP);
596# endif
597 return &primary_map[ pm_off ];
598}
599
600static INLINE SecMap** get_secmap_high_ptr ( Addr a )
601{
602 AuxMapEnt* am = find_or_alloc_in_auxmap(a);
603 return &am->sm;
604}
605
606static SecMap** get_secmap_ptr ( Addr a )
607{
608 return ( a <= MAX_PRIMARY_ADDRESS
609 ? get_secmap_low_ptr(a)
610 : get_secmap_high_ptr(a));
611}
612
njna7c7ebd2006-03-28 12:51:02 +0000613static INLINE SecMap* get_secmap_for_reading_low ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000614{
615 return *get_secmap_low_ptr(a);
616}
617
njna7c7ebd2006-03-28 12:51:02 +0000618static INLINE SecMap* get_secmap_for_reading_high ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000619{
620 return *get_secmap_high_ptr(a);
621}
622
njna7c7ebd2006-03-28 12:51:02 +0000623static INLINE SecMap* get_secmap_for_writing_low(Addr a)
njn1d0825f2006-03-27 11:37:07 +0000624{
625 SecMap** p = get_secmap_low_ptr(a);
bart5dd8e6a2008-03-22 08:04:29 +0000626 if (UNLIKELY(is_distinguished_sm(*p)))
njn1d0825f2006-03-27 11:37:07 +0000627 *p = copy_for_writing(*p);
628 return *p;
629}
630
njna7c7ebd2006-03-28 12:51:02 +0000631static INLINE SecMap* get_secmap_for_writing_high ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000632{
633 SecMap** p = get_secmap_high_ptr(a);
bart5dd8e6a2008-03-22 08:04:29 +0000634 if (UNLIKELY(is_distinguished_sm(*p)))
njn1d0825f2006-03-27 11:37:07 +0000635 *p = copy_for_writing(*p);
636 return *p;
637}
638
sewardj45d94cc2005-04-20 14:44:11 +0000639/* Produce the secmap for 'a', either from the primary map or by
640 ensuring there is an entry for it in the aux primary map. The
641 secmap may be a distinguished one as the caller will only want to
642 be able to read it.
643*/
sewardj05a46732006-10-17 01:28:10 +0000644static INLINE SecMap* get_secmap_for_reading ( Addr a )
sewardj45d94cc2005-04-20 14:44:11 +0000645{
njn1d0825f2006-03-27 11:37:07 +0000646 return ( a <= MAX_PRIMARY_ADDRESS
njna7c7ebd2006-03-28 12:51:02 +0000647 ? get_secmap_for_reading_low (a)
648 : get_secmap_for_reading_high(a) );
sewardj45d94cc2005-04-20 14:44:11 +0000649}
650
651/* Produce the secmap for 'a', either from the primary map or by
652 ensuring there is an entry for it in the aux primary map. The
653 secmap may not be a distinguished one, since the caller will want
654 to be able to write it. If it is a distinguished secondary, make a
655 writable copy of it, install it, and return the copy instead. (COW
656 semantics).
657*/
njna7c7ebd2006-03-28 12:51:02 +0000658static SecMap* get_secmap_for_writing ( Addr a )
sewardj45d94cc2005-04-20 14:44:11 +0000659{
njn1d0825f2006-03-27 11:37:07 +0000660 return ( a <= MAX_PRIMARY_ADDRESS
njna7c7ebd2006-03-28 12:51:02 +0000661 ? get_secmap_for_writing_low (a)
662 : get_secmap_for_writing_high(a) );
njn1d0825f2006-03-27 11:37:07 +0000663}
664
665/* If 'a' has a SecMap, produce it. Else produce NULL. But don't
666 allocate one if one doesn't already exist. This is used by the
667 leak checker.
668*/
669static SecMap* maybe_get_secmap_for ( Addr a )
670{
sewardj45d94cc2005-04-20 14:44:11 +0000671 if (a <= MAX_PRIMARY_ADDRESS) {
njna7c7ebd2006-03-28 12:51:02 +0000672 return get_secmap_for_reading_low(a);
sewardj45d94cc2005-04-20 14:44:11 +0000673 } else {
njn1d0825f2006-03-27 11:37:07 +0000674 AuxMapEnt* am = maybe_find_in_auxmap(a);
675 return am ? am->sm : NULL;
sewardj45d94cc2005-04-20 14:44:11 +0000676 }
677}
678
njn1d0825f2006-03-27 11:37:07 +0000679/* --------------- Fundamental functions --------------- */
680
681static INLINE
682void insert_vabits2_into_vabits8 ( Addr a, UChar vabits2, UChar* vabits8 )
683{
684 UInt shift = (a & 3) << 1; // shift by 0, 2, 4, or 6
685 *vabits8 &= ~(0x3 << shift); // mask out the two old bits
686 *vabits8 |= (vabits2 << shift); // mask in the two new bits
687}
688
689static INLINE
690void insert_vabits4_into_vabits8 ( Addr a, UChar vabits4, UChar* vabits8 )
691{
692 UInt shift;
693 tl_assert(VG_IS_2_ALIGNED(a)); // Must be 2-aligned
694 shift = (a & 2) << 1; // shift by 0 or 4
695 *vabits8 &= ~(0xf << shift); // mask out the four old bits
696 *vabits8 |= (vabits4 << shift); // mask in the four new bits
697}
698
699static INLINE
700UChar extract_vabits2_from_vabits8 ( Addr a, UChar vabits8 )
701{
702 UInt shift = (a & 3) << 1; // shift by 0, 2, 4, or 6
703 vabits8 >>= shift; // shift the two bits to the bottom
704 return 0x3 & vabits8; // mask out the rest
705}
706
707static INLINE
708UChar extract_vabits4_from_vabits8 ( Addr a, UChar vabits8 )
709{
710 UInt shift;
711 tl_assert(VG_IS_2_ALIGNED(a)); // Must be 2-aligned
712 shift = (a & 2) << 1; // shift by 0 or 4
713 vabits8 >>= shift; // shift the four bits to the bottom
714 return 0xf & vabits8; // mask out the rest
715}
716
717// Note that these four are only used in slow cases. The fast cases do
718// clever things like combine the auxmap check (in
719// get_secmap_{read,writ}able) with alignment checks.
720
721// *** WARNING! ***
722// Any time this function is called, if it is possible that vabits2
njndbf7ca72006-03-31 11:57:59 +0000723// is equal to VA_BITS2_PARTDEFINED, then the corresponding entry in the
njn1d0825f2006-03-27 11:37:07 +0000724// sec-V-bits table must also be set!
725static INLINE
726void set_vabits2 ( Addr a, UChar vabits2 )
727{
njna7c7ebd2006-03-28 12:51:02 +0000728 SecMap* sm = get_secmap_for_writing(a);
njn1d0825f2006-03-27 11:37:07 +0000729 UWord sm_off = SM_OFF(a);
730 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
731}
732
733static INLINE
734UChar get_vabits2 ( Addr a )
735{
njna7c7ebd2006-03-28 12:51:02 +0000736 SecMap* sm = get_secmap_for_reading(a);
njn1d0825f2006-03-27 11:37:07 +0000737 UWord sm_off = SM_OFF(a);
738 UChar vabits8 = sm->vabits8[sm_off];
739 return extract_vabits2_from_vabits8(a, vabits8);
740}
741
sewardjf2184912006-05-03 22:13:57 +0000742// *** WARNING! ***
743// Any time this function is called, if it is possible that any of the
744// 4 2-bit fields in vabits8 are equal to VA_BITS2_PARTDEFINED, then the
745// corresponding entry(s) in the sec-V-bits table must also be set!
746static INLINE
747UChar get_vabits8_for_aligned_word32 ( Addr a )
748{
749 SecMap* sm = get_secmap_for_reading(a);
750 UWord sm_off = SM_OFF(a);
751 UChar vabits8 = sm->vabits8[sm_off];
752 return vabits8;
753}
754
755static INLINE
756void set_vabits8_for_aligned_word32 ( Addr a, UChar vabits8 )
757{
758 SecMap* sm = get_secmap_for_writing(a);
759 UWord sm_off = SM_OFF(a);
760 sm->vabits8[sm_off] = vabits8;
761}
762
763
njn1d0825f2006-03-27 11:37:07 +0000764// Forward declarations
765static UWord get_sec_vbits8(Addr a);
766static void set_sec_vbits8(Addr a, UWord vbits8);
767
768// Returns False if there was an addressability error.
769static INLINE
770Bool set_vbits8 ( Addr a, UChar vbits8 )
771{
772 Bool ok = True;
773 UChar vabits2 = get_vabits2(a);
774 if ( VA_BITS2_NOACCESS != vabits2 ) {
775 // Addressable. Convert in-register format to in-memory format.
776 // Also remove any existing sec V bit entry for the byte if no
777 // longer necessary.
njndbf7ca72006-03-31 11:57:59 +0000778 if ( V_BITS8_DEFINED == vbits8 ) { vabits2 = VA_BITS2_DEFINED; }
779 else if ( V_BITS8_UNDEFINED == vbits8 ) { vabits2 = VA_BITS2_UNDEFINED; }
780 else { vabits2 = VA_BITS2_PARTDEFINED;
njn1d0825f2006-03-27 11:37:07 +0000781 set_sec_vbits8(a, vbits8); }
782 set_vabits2(a, vabits2);
783
784 } else {
785 // Unaddressable! Do nothing -- when writing to unaddressable
786 // memory it acts as a black hole, and the V bits can never be seen
787 // again. So we don't have to write them at all.
788 ok = False;
789 }
790 return ok;
791}
792
793// Returns False if there was an addressability error. In that case, we put
794// all defined bits into vbits8.
795static INLINE
796Bool get_vbits8 ( Addr a, UChar* vbits8 )
797{
798 Bool ok = True;
799 UChar vabits2 = get_vabits2(a);
800
801 // Convert the in-memory format to in-register format.
njndbf7ca72006-03-31 11:57:59 +0000802 if ( VA_BITS2_DEFINED == vabits2 ) { *vbits8 = V_BITS8_DEFINED; }
803 else if ( VA_BITS2_UNDEFINED == vabits2 ) { *vbits8 = V_BITS8_UNDEFINED; }
804 else if ( VA_BITS2_NOACCESS == vabits2 ) {
njn1d0825f2006-03-27 11:37:07 +0000805 *vbits8 = V_BITS8_DEFINED; // Make V bits defined!
806 ok = False;
807 } else {
njndbf7ca72006-03-31 11:57:59 +0000808 tl_assert( VA_BITS2_PARTDEFINED == vabits2 );
njn1d0825f2006-03-27 11:37:07 +0000809 *vbits8 = get_sec_vbits8(a);
810 }
811 return ok;
812}
813
814
815/* --------------- Secondary V bit table ------------ */
816
817// This table holds the full V bit pattern for partially-defined bytes
njndbf7ca72006-03-31 11:57:59 +0000818// (PDBs) that are represented by VA_BITS2_PARTDEFINED in the main shadow
819// memory.
njn1d0825f2006-03-27 11:37:07 +0000820//
821// Note: the nodes in this table can become stale. Eg. if you write a PDB,
822// then overwrite the same address with a fully defined byte, the sec-V-bit
823// node will not necessarily be removed. This is because checking for
824// whether removal is necessary would slow down the fast paths.
825//
826// To avoid the stale nodes building up too much, we periodically (once the
827// table reaches a certain size) garbage collect (GC) the table by
828// traversing it and evicting any "sufficiently stale" nodes, ie. nodes that
829// are stale and haven't been touched for a certain number of collections.
830// If more than a certain proportion of nodes survived, we increase the
831// table size so that GCs occur less often.
832//
833// (So this a bit different to a traditional GC, where you definitely want
834// to remove any dead nodes. It's more like we have a resizable cache and
835// we're trying to find the right balance how many elements to evict and how
836// big to make the cache.)
837//
838// This policy is designed to avoid bad table bloat in the worst case where
839// a program creates huge numbers of stale PDBs -- we would get this bloat
840// if we had no GC -- while handling well the case where a node becomes
841// stale but shortly afterwards is rewritten with a PDB and so becomes
842// non-stale again (which happens quite often, eg. in perf/bz2). If we just
843// remove all stale nodes as soon as possible, we just end up re-adding a
844// lot of them in later again. The "sufficiently stale" approach avoids
845// this. (If a program has many live PDBs, performance will just suck,
846// there's no way around that.)
847
848static OSet* secVBitTable;
849
850// Stats
851static ULong sec_vbits_new_nodes = 0;
852static ULong sec_vbits_updates = 0;
853
854// This must be a power of two; this is checked in mc_pre_clo_init().
855// The size chosen here is a trade-off: if the nodes are bigger (ie. cover
856// a larger address range) they take more space but we can get multiple
857// partially-defined bytes in one if they are close to each other, reducing
858// the number of total nodes. In practice sometimes they are clustered (eg.
859// perf/bz2 repeatedly writes then reads more than 20,000 in a contiguous
860// row), but often not. So we choose something intermediate.
861#define BYTES_PER_SEC_VBIT_NODE 16
862
863// We make the table bigger if more than this many nodes survive a GC.
864#define MAX_SURVIVOR_PROPORTION 0.5
865
866// Each time we make the table bigger, we increase it by this much.
867#define TABLE_GROWTH_FACTOR 2
868
869// This defines "sufficiently stale" -- any node that hasn't been touched in
870// this many GCs will be removed.
871#define MAX_STALE_AGE 2
872
873// We GC the table when it gets this many nodes in it, ie. it's effectively
874// the table size. It can change.
875static Int secVBitLimit = 1024;
876
877// The number of GCs done, used to age sec-V-bit nodes for eviction.
878// Because it's unsigned, wrapping doesn't matter -- the right answer will
879// come out anyway.
880static UInt GCs_done = 0;
881
882typedef
883 struct {
884 Addr a;
885 UChar vbits8[BYTES_PER_SEC_VBIT_NODE];
886 UInt last_touched;
887 }
888 SecVBitNode;
889
890static OSet* createSecVBitTable(void)
891{
njne2a9ad32007-09-17 05:30:48 +0000892 return VG_(OSetGen_Create)( offsetof(SecVBitNode, a),
893 NULL, // use fast comparisons
sewardj9c606bd2008-09-18 18:12:50 +0000894 VG_(malloc), "mc.cSVT.1 (sec VBit table)",
895 VG_(free) );
njn1d0825f2006-03-27 11:37:07 +0000896}
897
898static void gcSecVBitTable(void)
899{
900 OSet* secVBitTable2;
901 SecVBitNode* n;
902 Int i, n_nodes = 0, n_survivors = 0;
903
904 GCs_done++;
905
906 // Create the new table.
907 secVBitTable2 = createSecVBitTable();
908
909 // Traverse the table, moving fresh nodes into the new table.
njne2a9ad32007-09-17 05:30:48 +0000910 VG_(OSetGen_ResetIter)(secVBitTable);
911 while ( (n = VG_(OSetGen_Next)(secVBitTable)) ) {
njn1d0825f2006-03-27 11:37:07 +0000912 Bool keep = False;
913 if ( (GCs_done - n->last_touched) <= MAX_STALE_AGE ) {
914 // Keep node if it's been touched recently enough (regardless of
915 // freshness/staleness).
916 keep = True;
917 } else {
918 // Keep node if any of its bytes are non-stale. Using
919 // get_vabits2() for the lookup is not very efficient, but I don't
920 // think it matters.
921 for (i = 0; i < BYTES_PER_SEC_VBIT_NODE; i++) {
njndbf7ca72006-03-31 11:57:59 +0000922 if (VA_BITS2_PARTDEFINED == get_vabits2(n->a + i)) {
njn1d0825f2006-03-27 11:37:07 +0000923 keep = True; // Found a non-stale byte, so keep
924 break;
925 }
926 }
927 }
928
929 if ( keep ) {
930 // Insert a copy of the node into the new table.
931 SecVBitNode* n2 =
njne2a9ad32007-09-17 05:30:48 +0000932 VG_(OSetGen_AllocNode)(secVBitTable2, sizeof(SecVBitNode));
njn1d0825f2006-03-27 11:37:07 +0000933 *n2 = *n;
njne2a9ad32007-09-17 05:30:48 +0000934 VG_(OSetGen_Insert)(secVBitTable2, n2);
njn1d0825f2006-03-27 11:37:07 +0000935 }
936 }
937
938 // Get the before and after sizes.
njne2a9ad32007-09-17 05:30:48 +0000939 n_nodes = VG_(OSetGen_Size)(secVBitTable);
940 n_survivors = VG_(OSetGen_Size)(secVBitTable2);
njn1d0825f2006-03-27 11:37:07 +0000941
942 // Destroy the old table, and put the new one in its place.
njne2a9ad32007-09-17 05:30:48 +0000943 VG_(OSetGen_Destroy)(secVBitTable);
njn1d0825f2006-03-27 11:37:07 +0000944 secVBitTable = secVBitTable2;
945
946 if (VG_(clo_verbosity) > 1) {
947 Char percbuf[6];
948 VG_(percentify)(n_survivors, n_nodes, 1, 6, percbuf);
949 VG_(message)(Vg_DebugMsg, "memcheck GC: %d nodes, %d survivors (%s)",
950 n_nodes, n_survivors, percbuf);
951 }
952
953 // Increase table size if necessary.
954 if (n_survivors > (secVBitLimit * MAX_SURVIVOR_PROPORTION)) {
955 secVBitLimit *= TABLE_GROWTH_FACTOR;
956 if (VG_(clo_verbosity) > 1)
957 VG_(message)(Vg_DebugMsg, "memcheck GC: increase table size to %d",
958 secVBitLimit);
959 }
960}
961
962static UWord get_sec_vbits8(Addr a)
963{
964 Addr aAligned = VG_ROUNDDN(a, BYTES_PER_SEC_VBIT_NODE);
965 Int amod = a % BYTES_PER_SEC_VBIT_NODE;
njne2a9ad32007-09-17 05:30:48 +0000966 SecVBitNode* n = VG_(OSetGen_Lookup)(secVBitTable, &aAligned);
njn1d0825f2006-03-27 11:37:07 +0000967 UChar vbits8;
968 tl_assert2(n, "get_sec_vbits8: no node for address %p (%p)\n", aAligned, a);
969 // Shouldn't be fully defined or fully undefined -- those cases shouldn't
970 // make it to the secondary V bits table.
971 vbits8 = n->vbits8[amod];
972 tl_assert(V_BITS8_DEFINED != vbits8 && V_BITS8_UNDEFINED != vbits8);
973 return vbits8;
974}
975
976static void set_sec_vbits8(Addr a, UWord vbits8)
977{
978 Addr aAligned = VG_ROUNDDN(a, BYTES_PER_SEC_VBIT_NODE);
979 Int i, amod = a % BYTES_PER_SEC_VBIT_NODE;
njne2a9ad32007-09-17 05:30:48 +0000980 SecVBitNode* n = VG_(OSetGen_Lookup)(secVBitTable, &aAligned);
njn1d0825f2006-03-27 11:37:07 +0000981 // Shouldn't be fully defined or fully undefined -- those cases shouldn't
982 // make it to the secondary V bits table.
983 tl_assert(V_BITS8_DEFINED != vbits8 && V_BITS8_UNDEFINED != vbits8);
984 if (n) {
985 n->vbits8[amod] = vbits8; // update
986 n->last_touched = GCs_done;
987 sec_vbits_updates++;
988 } else {
989 // New node: assign the specific byte, make the rest invalid (they
990 // should never be read as-is, but be cautious).
njne2a9ad32007-09-17 05:30:48 +0000991 n = VG_(OSetGen_AllocNode)(secVBitTable, sizeof(SecVBitNode));
njn1d0825f2006-03-27 11:37:07 +0000992 n->a = aAligned;
993 for (i = 0; i < BYTES_PER_SEC_VBIT_NODE; i++) {
994 n->vbits8[i] = V_BITS8_UNDEFINED;
995 }
996 n->vbits8[amod] = vbits8;
997 n->last_touched = GCs_done;
998
999 // Do a table GC if necessary. Nb: do this before inserting the new
1000 // node, to avoid erroneously GC'ing the new node.
njne2a9ad32007-09-17 05:30:48 +00001001 if (secVBitLimit == VG_(OSetGen_Size)(secVBitTable)) {
njn1d0825f2006-03-27 11:37:07 +00001002 gcSecVBitTable();
1003 }
1004
1005 // Insert the new node.
njne2a9ad32007-09-17 05:30:48 +00001006 VG_(OSetGen_Insert)(secVBitTable, n);
njn1d0825f2006-03-27 11:37:07 +00001007 sec_vbits_new_nodes++;
1008
njne2a9ad32007-09-17 05:30:48 +00001009 n_secVBit_nodes = VG_(OSetGen_Size)(secVBitTable);
njn1d0825f2006-03-27 11:37:07 +00001010 if (n_secVBit_nodes > max_secVBit_nodes)
1011 max_secVBit_nodes = n_secVBit_nodes;
1012 }
1013}
sewardj45d94cc2005-04-20 14:44:11 +00001014
1015/* --------------- Endianness helpers --------------- */
1016
1017/* Returns the offset in memory of the byteno-th most significant byte
1018 in a wordszB-sized word, given the specified endianness. */
njn1d0825f2006-03-27 11:37:07 +00001019static INLINE UWord byte_offset_w ( UWord wordszB, Bool bigendian,
sewardj45d94cc2005-04-20 14:44:11 +00001020 UWord byteno ) {
1021 return bigendian ? (wordszB-1-byteno) : byteno;
1022}
1023
sewardj05a46732006-10-17 01:28:10 +00001024
1025/* --------------- Ignored address ranges --------------- */
1026
1027#define M_IGNORE_RANGES 4
1028
1029typedef
1030 struct {
1031 Int used;
1032 Addr start[M_IGNORE_RANGES];
1033 Addr end[M_IGNORE_RANGES];
1034 }
1035 IgnoreRanges;
1036
1037static IgnoreRanges ignoreRanges;
1038
sewardj7ce71662008-05-02 10:33:15 +00001039INLINE Bool MC_(in_ignored_range) ( Addr a )
sewardj05a46732006-10-17 01:28:10 +00001040{
1041 Int i;
bart5dd8e6a2008-03-22 08:04:29 +00001042 if (LIKELY(ignoreRanges.used == 0))
sewardj05a46732006-10-17 01:28:10 +00001043 return False;
1044 for (i = 0; i < ignoreRanges.used; i++) {
1045 if (a >= ignoreRanges.start[i] && a < ignoreRanges.end[i])
1046 return True;
1047 }
1048 return False;
1049}
1050
1051
1052/* Parse a 32- or 64-bit hex number, including leading 0x, from string
1053 starting at *ppc, putting result in *result, and return True. Or
1054 fail, in which case *ppc and *result are undefined, and return
1055 False. */
1056
1057static Bool isHex ( UChar c )
1058{
1059 return ((c >= '0' && c <= '9')
1060 || (c >= 'a' && c <= 'f')
1061 || (c >= 'A' && c <= 'F'));
1062}
1063
1064static UInt fromHex ( UChar c )
1065{
1066 if (c >= '0' && c <= '9')
1067 return (UInt)c - (UInt)'0';
1068 if (c >= 'a' && c <= 'f')
1069 return 10 + (UInt)c - (UInt)'a';
1070 if (c >= 'A' && c <= 'F')
1071 return 10 + (UInt)c - (UInt)'A';
1072 /*NOTREACHED*/
1073 tl_assert(0);
1074 return 0;
1075}
1076
1077static Bool parse_Addr ( UChar** ppc, Addr* result )
1078{
1079 Int used, limit = 2 * sizeof(Addr);
1080 if (**ppc != '0')
1081 return False;
1082 (*ppc)++;
1083 if (**ppc != 'x')
1084 return False;
1085 (*ppc)++;
1086 *result = 0;
1087 used = 0;
1088 while (isHex(**ppc)) {
1089 UInt d = fromHex(**ppc);
1090 tl_assert(d < 16);
1091 *result = ((*result) << 4) | fromHex(**ppc);
1092 (*ppc)++;
1093 used++;
1094 if (used > limit) return False;
1095 }
1096 if (used == 0)
1097 return False;
1098 return True;
1099}
1100
1101/* Parse two such numbers separated by a dash, or fail. */
1102
1103static Bool parse_range ( UChar** ppc, Addr* result1, Addr* result2 )
1104{
1105 Bool ok = parse_Addr(ppc, result1);
1106 if (!ok)
1107 return False;
1108 if (**ppc != '-')
1109 return False;
1110 (*ppc)++;
1111 ok = parse_Addr(ppc, result2);
1112 if (!ok)
1113 return False;
1114 return True;
1115}
1116
1117/* Parse a set of ranges separated by commas into 'ignoreRanges', or
1118 fail. */
1119
1120static Bool parse_ignore_ranges ( UChar* str0 )
1121{
1122 Addr start, end;
1123 Bool ok;
1124 UChar* str = str0;
1125 UChar** ppc = &str;
1126 ignoreRanges.used = 0;
1127 while (1) {
1128 ok = parse_range(ppc, &start, &end);
1129 if (!ok)
1130 return False;
1131 if (ignoreRanges.used >= M_IGNORE_RANGES)
1132 return False;
1133 ignoreRanges.start[ignoreRanges.used] = start;
1134 ignoreRanges.end[ignoreRanges.used] = end;
1135 ignoreRanges.used++;
1136 if (**ppc == 0)
1137 return True;
1138 if (**ppc != ',')
1139 return False;
1140 (*ppc)++;
1141 }
1142 /*NOTREACHED*/
1143 return False;
1144}
1145
1146
sewardj45d94cc2005-04-20 14:44:11 +00001147/* --------------- Load/store slow cases. --------------- */
1148
1149static
njn1d0825f2006-03-27 11:37:07 +00001150#ifndef PERF_FAST_LOADV
1151INLINE
1152#endif
njn45e81252006-03-28 12:35:08 +00001153ULong mc_LOADVn_slow ( Addr a, SizeT nBits, Bool bigendian )
sewardj45d94cc2005-04-20 14:44:11 +00001154{
njn1d0825f2006-03-27 11:37:07 +00001155 /* Make up a 64-bit result V word, which contains the loaded data for
sewardjf3d57dd2005-04-22 20:23:27 +00001156 valid addresses and Defined for invalid addresses. Iterate over
1157 the bytes in the word, from the most significant down to the
1158 least. */
njn1d0825f2006-03-27 11:37:07 +00001159 ULong vbits64 = V_BITS64_UNDEFINED;
njn45e81252006-03-28 12:35:08 +00001160 SizeT szB = nBits / 8;
njn1d0825f2006-03-27 11:37:07 +00001161 SSizeT i = szB-1; // Must be signed
sewardj45d94cc2005-04-20 14:44:11 +00001162 SizeT n_addrs_bad = 0;
1163 Addr ai;
njn1d0825f2006-03-27 11:37:07 +00001164 Bool partial_load_exemption_applies;
1165 UChar vbits8;
1166 Bool ok;
sewardj45d94cc2005-04-20 14:44:11 +00001167
sewardjc1a2cda2005-04-21 17:34:00 +00001168 PROF_EVENT(30, "mc_LOADVn_slow");
sewardj05a46732006-10-17 01:28:10 +00001169
1170 /* ------------ BEGIN semi-fast cases ------------ */
1171 /* These deal quickly-ish with the common auxiliary primary map
1172 cases on 64-bit platforms. Are merely a speedup hack; can be
1173 omitted without loss of correctness/functionality. Note that in
1174 both cases the "sizeof(void*) == 8" causes these cases to be
1175 folded out by compilers on 32-bit platforms. These are derived
1176 from LOADV64 and LOADV32.
1177 */
bart5dd8e6a2008-03-22 08:04:29 +00001178 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001179 && nBits == 64 && VG_IS_8_ALIGNED(a))) {
1180 SecMap* sm = get_secmap_for_reading(a);
1181 UWord sm_off16 = SM_OFF_16(a);
1182 UWord vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
bart5dd8e6a2008-03-22 08:04:29 +00001183 if (LIKELY(vabits16 == VA_BITS16_DEFINED))
sewardj05a46732006-10-17 01:28:10 +00001184 return V_BITS64_DEFINED;
bart5dd8e6a2008-03-22 08:04:29 +00001185 if (LIKELY(vabits16 == VA_BITS16_UNDEFINED))
sewardj05a46732006-10-17 01:28:10 +00001186 return V_BITS64_UNDEFINED;
1187 /* else fall into the slow case */
1188 }
bart5dd8e6a2008-03-22 08:04:29 +00001189 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001190 && nBits == 32 && VG_IS_4_ALIGNED(a))) {
1191 SecMap* sm = get_secmap_for_reading(a);
1192 UWord sm_off = SM_OFF(a);
1193 UWord vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00001194 if (LIKELY(vabits8 == VA_BITS8_DEFINED))
sewardj05a46732006-10-17 01:28:10 +00001195 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_DEFINED);
bart5dd8e6a2008-03-22 08:04:29 +00001196 if (LIKELY(vabits8 == VA_BITS8_UNDEFINED))
sewardj05a46732006-10-17 01:28:10 +00001197 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_UNDEFINED);
1198 /* else fall into slow case */
1199 }
1200 /* ------------ END semi-fast cases ------------ */
1201
njn45e81252006-03-28 12:35:08 +00001202 tl_assert(nBits == 64 || nBits == 32 || nBits == 16 || nBits == 8);
sewardj45d94cc2005-04-20 14:44:11 +00001203
njn1d0825f2006-03-27 11:37:07 +00001204 for (i = szB-1; i >= 0; i--) {
sewardjc1a2cda2005-04-21 17:34:00 +00001205 PROF_EVENT(31, "mc_LOADVn_slow(loop)");
njn45e81252006-03-28 12:35:08 +00001206 ai = a + byte_offset_w(szB, bigendian, i);
njn1d0825f2006-03-27 11:37:07 +00001207 ok = get_vbits8(ai, &vbits8);
1208 if (!ok) n_addrs_bad++;
1209 vbits64 <<= 8;
1210 vbits64 |= vbits8;
sewardj45d94cc2005-04-20 14:44:11 +00001211 }
1212
sewardj0ded7a42005-11-08 02:25:37 +00001213 /* This is a hack which avoids producing errors for code which
1214 insists in stepping along byte strings in aligned word-sized
1215 chunks, and there is a partially defined word at the end. (eg,
1216 optimised strlen). Such code is basically broken at least WRT
1217 semantics of ANSI C, but sometimes users don't have the option
1218 to fix it, and so this option is provided. Note it is now
1219 defaulted to not-engaged.
1220
1221 A load from a partially-addressible place is allowed if:
1222 - the command-line flag is set
1223 - it's a word-sized, word-aligned load
1224 - at least one of the addresses in the word *is* valid
1225 */
1226 partial_load_exemption_applies
njn1d0825f2006-03-27 11:37:07 +00001227 = MC_(clo_partial_loads_ok) && szB == VG_WORDSIZE
sewardj0ded7a42005-11-08 02:25:37 +00001228 && VG_IS_WORD_ALIGNED(a)
1229 && n_addrs_bad < VG_WORDSIZE;
1230
1231 if (n_addrs_bad > 0 && !partial_load_exemption_applies)
sewardj7ce71662008-05-02 10:33:15 +00001232 MC_(record_address_error)( VG_(get_running_tid)(), a, szB, False );
sewardj45d94cc2005-04-20 14:44:11 +00001233
njn1d0825f2006-03-27 11:37:07 +00001234 return vbits64;
sewardj45d94cc2005-04-20 14:44:11 +00001235}
1236
1237
njn1d0825f2006-03-27 11:37:07 +00001238static
1239#ifndef PERF_FAST_STOREV
1240INLINE
1241#endif
njn45e81252006-03-28 12:35:08 +00001242void mc_STOREVn_slow ( Addr a, SizeT nBits, ULong vbytes, Bool bigendian )
sewardj45d94cc2005-04-20 14:44:11 +00001243{
njn45e81252006-03-28 12:35:08 +00001244 SizeT szB = nBits / 8;
njn1d0825f2006-03-27 11:37:07 +00001245 SizeT i, n_addrs_bad = 0;
1246 UChar vbits8;
sewardj45d94cc2005-04-20 14:44:11 +00001247 Addr ai;
njn1d0825f2006-03-27 11:37:07 +00001248 Bool ok;
sewardj45d94cc2005-04-20 14:44:11 +00001249
sewardjc1a2cda2005-04-21 17:34:00 +00001250 PROF_EVENT(35, "mc_STOREVn_slow");
sewardj05a46732006-10-17 01:28:10 +00001251
1252 /* ------------ BEGIN semi-fast cases ------------ */
1253 /* These deal quickly-ish with the common auxiliary primary map
1254 cases on 64-bit platforms. Are merely a speedup hack; can be
1255 omitted without loss of correctness/functionality. Note that in
1256 both cases the "sizeof(void*) == 8" causes these cases to be
1257 folded out by compilers on 32-bit platforms. These are derived
1258 from STOREV64 and STOREV32.
1259 */
bart5dd8e6a2008-03-22 08:04:29 +00001260 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001261 && nBits == 64 && VG_IS_8_ALIGNED(a))) {
1262 SecMap* sm = get_secmap_for_reading(a);
1263 UWord sm_off16 = SM_OFF_16(a);
1264 UWord vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
bart5dd8e6a2008-03-22 08:04:29 +00001265 if (LIKELY( !is_distinguished_sm(sm) &&
sewardj05a46732006-10-17 01:28:10 +00001266 (VA_BITS16_DEFINED == vabits16 ||
1267 VA_BITS16_UNDEFINED == vabits16) )) {
1268 /* Handle common case quickly: a is suitably aligned, */
1269 /* is mapped, and is addressible. */
1270 // Convert full V-bits in register to compact 2-bit form.
bart5dd8e6a2008-03-22 08:04:29 +00001271 if (LIKELY(V_BITS64_DEFINED == vbytes)) {
sewardj05a46732006-10-17 01:28:10 +00001272 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_DEFINED;
1273 return;
1274 } else if (V_BITS64_UNDEFINED == vbytes) {
1275 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_UNDEFINED;
1276 return;
1277 }
1278 /* else fall into the slow case */
1279 }
1280 /* else fall into the slow case */
1281 }
bart5dd8e6a2008-03-22 08:04:29 +00001282 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001283 && nBits == 32 && VG_IS_4_ALIGNED(a))) {
1284 SecMap* sm = get_secmap_for_reading(a);
1285 UWord sm_off = SM_OFF(a);
1286 UWord vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00001287 if (LIKELY( !is_distinguished_sm(sm) &&
sewardj05a46732006-10-17 01:28:10 +00001288 (VA_BITS8_DEFINED == vabits8 ||
1289 VA_BITS8_UNDEFINED == vabits8) )) {
1290 /* Handle common case quickly: a is suitably aligned, */
1291 /* is mapped, and is addressible. */
1292 // Convert full V-bits in register to compact 2-bit form.
bart5dd8e6a2008-03-22 08:04:29 +00001293 if (LIKELY(V_BITS32_DEFINED == (vbytes & 0xFFFFFFFF))) {
sewardj05a46732006-10-17 01:28:10 +00001294 sm->vabits8[sm_off] = VA_BITS8_DEFINED;
1295 return;
1296 } else if (V_BITS32_UNDEFINED == (vbytes & 0xFFFFFFFF)) {
1297 sm->vabits8[sm_off] = VA_BITS8_UNDEFINED;
1298 return;
1299 }
1300 /* else fall into the slow case */
1301 }
1302 /* else fall into the slow case */
1303 }
1304 /* ------------ END semi-fast cases ------------ */
1305
njn45e81252006-03-28 12:35:08 +00001306 tl_assert(nBits == 64 || nBits == 32 || nBits == 16 || nBits == 8);
sewardj45d94cc2005-04-20 14:44:11 +00001307
1308 /* Dump vbytes in memory, iterating from least to most significant
njn718d3b12006-12-16 00:54:12 +00001309 byte. At the same time establish addressibility of the location. */
sewardj45d94cc2005-04-20 14:44:11 +00001310 for (i = 0; i < szB; i++) {
sewardjc1a2cda2005-04-21 17:34:00 +00001311 PROF_EVENT(36, "mc_STOREVn_slow(loop)");
njn45e81252006-03-28 12:35:08 +00001312 ai = a + byte_offset_w(szB, bigendian, i);
njn1d0825f2006-03-27 11:37:07 +00001313 vbits8 = vbytes & 0xff;
1314 ok = set_vbits8(ai, vbits8);
1315 if (!ok) n_addrs_bad++;
sewardj45d94cc2005-04-20 14:44:11 +00001316 vbytes >>= 8;
1317 }
1318
1319 /* If an address error has happened, report it. */
1320 if (n_addrs_bad > 0)
sewardj7ce71662008-05-02 10:33:15 +00001321 MC_(record_address_error)( VG_(get_running_tid)(), a, szB, True );
sewardj45d94cc2005-04-20 14:44:11 +00001322}
1323
1324
njn25e49d8e72002-09-23 09:36:25 +00001325/*------------------------------------------------------------*/
1326/*--- Setting permissions over address ranges. ---*/
1327/*------------------------------------------------------------*/
1328
njn1d0825f2006-03-27 11:37:07 +00001329static void set_address_range_perms ( Addr a, SizeT lenT, UWord vabits16,
1330 UWord dsm_num )
sewardj23eb2fd2005-04-22 16:29:19 +00001331{
njn1d0825f2006-03-27 11:37:07 +00001332 UWord sm_off, sm_off16;
1333 UWord vabits2 = vabits16 & 0x3;
1334 SizeT lenA, lenB, len_to_next_secmap;
1335 Addr aNext;
sewardjae986ca2005-10-12 12:53:20 +00001336 SecMap* sm;
njn1d0825f2006-03-27 11:37:07 +00001337 SecMap** sm_ptr;
sewardjae986ca2005-10-12 12:53:20 +00001338 SecMap* example_dsm;
1339
sewardj23eb2fd2005-04-22 16:29:19 +00001340 PROF_EVENT(150, "set_address_range_perms");
1341
njn1d0825f2006-03-27 11:37:07 +00001342 /* Check the V+A bits make sense. */
njndbf7ca72006-03-31 11:57:59 +00001343 tl_assert(VA_BITS16_NOACCESS == vabits16 ||
1344 VA_BITS16_UNDEFINED == vabits16 ||
1345 VA_BITS16_DEFINED == vabits16);
sewardj23eb2fd2005-04-22 16:29:19 +00001346
njn1d0825f2006-03-27 11:37:07 +00001347 // This code should never write PDBs; ensure this. (See comment above
1348 // set_vabits2().)
njndbf7ca72006-03-31 11:57:59 +00001349 tl_assert(VA_BITS2_PARTDEFINED != vabits2);
njn1d0825f2006-03-27 11:37:07 +00001350
1351 if (lenT == 0)
sewardj23eb2fd2005-04-22 16:29:19 +00001352 return;
1353
njn1d0825f2006-03-27 11:37:07 +00001354 if (lenT > 100 * 1000 * 1000) {
1355 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
1356 Char* s = "unknown???";
njndbf7ca72006-03-31 11:57:59 +00001357 if (vabits16 == VA_BITS16_NOACCESS ) s = "noaccess";
1358 if (vabits16 == VA_BITS16_UNDEFINED) s = "undefined";
1359 if (vabits16 == VA_BITS16_DEFINED ) s = "defined";
njn1d0825f2006-03-27 11:37:07 +00001360 VG_(message)(Vg_UserMsg, "Warning: set address range perms: "
tom2a836b52008-07-18 08:38:44 +00001361 "large range [0x%lx, 0x%lx) (%s)",
1362 a, a + lenT, s);
sewardj23eb2fd2005-04-22 16:29:19 +00001363 }
1364 }
1365
njn1d0825f2006-03-27 11:37:07 +00001366#ifndef PERF_FAST_SARP
sewardj23eb2fd2005-04-22 16:29:19 +00001367 /*------------------ debug-only case ------------------ */
njn1d0825f2006-03-27 11:37:07 +00001368 {
1369 // Endianness doesn't matter here because all bytes are being set to
1370 // the same value.
1371 // Nb: We don't have to worry about updating the sec-V-bits table
1372 // after these set_vabits2() calls because this code never writes
njndbf7ca72006-03-31 11:57:59 +00001373 // VA_BITS2_PARTDEFINED values.
njn1d0825f2006-03-27 11:37:07 +00001374 SizeT i;
1375 for (i = 0; i < lenT; i++) {
1376 set_vabits2(a + i, vabits2);
1377 }
1378 return;
njn25e49d8e72002-09-23 09:36:25 +00001379 }
njn1d0825f2006-03-27 11:37:07 +00001380#endif
sewardj23eb2fd2005-04-22 16:29:19 +00001381
1382 /*------------------ standard handling ------------------ */
sewardj23eb2fd2005-04-22 16:29:19 +00001383
njn1d0825f2006-03-27 11:37:07 +00001384 /* Get the distinguished secondary that we might want
sewardj23eb2fd2005-04-22 16:29:19 +00001385 to use (part of the space-compression scheme). */
njn1d0825f2006-03-27 11:37:07 +00001386 example_dsm = &sm_distinguished[dsm_num];
1387
1388 // We have to handle ranges covering various combinations of partial and
1389 // whole sec-maps. Here is how parts 1, 2 and 3 are used in each case.
1390 // Cases marked with a '*' are common.
1391 //
1392 // TYPE PARTS USED
1393 // ---- ----------
1394 // * one partial sec-map (p) 1
1395 // - one whole sec-map (P) 2
1396 //
1397 // * two partial sec-maps (pp) 1,3
1398 // - one partial, one whole sec-map (pP) 1,2
1399 // - one whole, one partial sec-map (Pp) 2,3
1400 // - two whole sec-maps (PP) 2,2
1401 //
1402 // * one partial, one whole, one partial (pPp) 1,2,3
1403 // - one partial, two whole (pPP) 1,2,2
1404 // - two whole, one partial (PPp) 2,2,3
1405 // - three whole (PPP) 2,2,2
1406 //
1407 // * one partial, N-2 whole, one partial (pP...Pp) 1,2...2,3
1408 // - one partial, N-1 whole (pP...PP) 1,2...2,2
1409 // - N-1 whole, one partial (PP...Pp) 2,2...2,3
1410 // - N whole (PP...PP) 2,2...2,3
1411
1412 // Break up total length (lenT) into two parts: length in the first
1413 // sec-map (lenA), and the rest (lenB); lenT == lenA + lenB.
1414 aNext = start_of_this_sm(a) + SM_SIZE;
1415 len_to_next_secmap = aNext - a;
1416 if ( lenT <= len_to_next_secmap ) {
1417 // Range entirely within one sec-map. Covers almost all cases.
1418 PROF_EVENT(151, "set_address_range_perms-single-secmap");
1419 lenA = lenT;
1420 lenB = 0;
1421 } else if (is_start_of_sm(a)) {
1422 // Range spans at least one whole sec-map, and starts at the beginning
1423 // of a sec-map; skip to Part 2.
1424 PROF_EVENT(152, "set_address_range_perms-startof-secmap");
1425 lenA = 0;
1426 lenB = lenT;
1427 goto part2;
sewardj23eb2fd2005-04-22 16:29:19 +00001428 } else {
njn1d0825f2006-03-27 11:37:07 +00001429 // Range spans two or more sec-maps, first one is partial.
1430 PROF_EVENT(153, "set_address_range_perms-multiple-secmaps");
1431 lenA = len_to_next_secmap;
1432 lenB = lenT - lenA;
1433 }
1434
1435 //------------------------------------------------------------------------
1436 // Part 1: Deal with the first sec_map. Most of the time the range will be
1437 // entirely within a sec_map and this part alone will suffice. Also,
1438 // doing it this way lets us avoid repeatedly testing for the crossing of
1439 // a sec-map boundary within these loops.
1440 //------------------------------------------------------------------------
1441
1442 // If it's distinguished, make it undistinguished if necessary.
1443 sm_ptr = get_secmap_ptr(a);
1444 if (is_distinguished_sm(*sm_ptr)) {
1445 if (*sm_ptr == example_dsm) {
1446 // Sec-map already has the V+A bits that we want, so skip.
1447 PROF_EVENT(154, "set_address_range_perms-dist-sm1-quick");
1448 a = aNext;
1449 lenA = 0;
sewardj23eb2fd2005-04-22 16:29:19 +00001450 } else {
njn1d0825f2006-03-27 11:37:07 +00001451 PROF_EVENT(155, "set_address_range_perms-dist-sm1");
1452 *sm_ptr = copy_for_writing(*sm_ptr);
sewardj23eb2fd2005-04-22 16:29:19 +00001453 }
1454 }
njn1d0825f2006-03-27 11:37:07 +00001455 sm = *sm_ptr;
sewardj23eb2fd2005-04-22 16:29:19 +00001456
njn1d0825f2006-03-27 11:37:07 +00001457 // 1 byte steps
sewardj23eb2fd2005-04-22 16:29:19 +00001458 while (True) {
sewardj23eb2fd2005-04-22 16:29:19 +00001459 if (VG_IS_8_ALIGNED(a)) break;
njn1d0825f2006-03-27 11:37:07 +00001460 if (lenA < 1) break;
1461 PROF_EVENT(156, "set_address_range_perms-loop1a");
1462 sm_off = SM_OFF(a);
1463 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1464 a += 1;
1465 lenA -= 1;
1466 }
1467 // 8-aligned, 8 byte steps
sewardj23eb2fd2005-04-22 16:29:19 +00001468 while (True) {
njn1d0825f2006-03-27 11:37:07 +00001469 if (lenA < 8) break;
1470 PROF_EVENT(157, "set_address_range_perms-loop8a");
1471 sm_off16 = SM_OFF_16(a);
1472 ((UShort*)(sm->vabits8))[sm_off16] = vabits16;
1473 a += 8;
1474 lenA -= 8;
1475 }
1476 // 1 byte steps
1477 while (True) {
1478 if (lenA < 1) break;
1479 PROF_EVENT(158, "set_address_range_perms-loop1b");
1480 sm_off = SM_OFF(a);
1481 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1482 a += 1;
1483 lenA -= 1;
sewardj23eb2fd2005-04-22 16:29:19 +00001484 }
1485
njn1d0825f2006-03-27 11:37:07 +00001486 // We've finished the first sec-map. Is that it?
1487 if (lenB == 0)
sewardj23eb2fd2005-04-22 16:29:19 +00001488 return;
1489
njn1d0825f2006-03-27 11:37:07 +00001490 //------------------------------------------------------------------------
1491 // Part 2: Fast-set entire sec-maps at a time.
1492 //------------------------------------------------------------------------
1493 part2:
1494 // 64KB-aligned, 64KB steps.
1495 // Nb: we can reach here with lenB < SM_SIZE
sewardj23eb2fd2005-04-22 16:29:19 +00001496 while (True) {
njn1d0825f2006-03-27 11:37:07 +00001497 if (lenB < SM_SIZE) break;
1498 tl_assert(is_start_of_sm(a));
1499 PROF_EVENT(159, "set_address_range_perms-loop64K");
1500 sm_ptr = get_secmap_ptr(a);
1501 if (!is_distinguished_sm(*sm_ptr)) {
1502 PROF_EVENT(160, "set_address_range_perms-loop64K-free-dist-sm");
1503 // Free the non-distinguished sec-map that we're replacing. This
1504 // case happens moderately often, enough to be worthwhile.
1505 VG_(am_munmap_valgrind)((Addr)*sm_ptr, sizeof(SecMap));
1506 }
1507 update_SM_counts(*sm_ptr, example_dsm);
1508 // Make the sec-map entry point to the example DSM
1509 *sm_ptr = example_dsm;
1510 lenB -= SM_SIZE;
1511 a += SM_SIZE;
1512 }
sewardj23eb2fd2005-04-22 16:29:19 +00001513
njn1d0825f2006-03-27 11:37:07 +00001514 // We've finished the whole sec-maps. Is that it?
1515 if (lenB == 0)
1516 return;
1517
1518 //------------------------------------------------------------------------
1519 // Part 3: Finish off the final partial sec-map, if necessary.
1520 //------------------------------------------------------------------------
1521
1522 tl_assert(is_start_of_sm(a) && lenB < SM_SIZE);
1523
1524 // If it's distinguished, make it undistinguished if necessary.
1525 sm_ptr = get_secmap_ptr(a);
1526 if (is_distinguished_sm(*sm_ptr)) {
1527 if (*sm_ptr == example_dsm) {
1528 // Sec-map already has the V+A bits that we want, so stop.
1529 PROF_EVENT(161, "set_address_range_perms-dist-sm2-quick");
1530 return;
1531 } else {
1532 PROF_EVENT(162, "set_address_range_perms-dist-sm2");
1533 *sm_ptr = copy_for_writing(*sm_ptr);
1534 }
1535 }
1536 sm = *sm_ptr;
1537
1538 // 8-aligned, 8 byte steps
1539 while (True) {
1540 if (lenB < 8) break;
1541 PROF_EVENT(163, "set_address_range_perms-loop8b");
1542 sm_off16 = SM_OFF_16(a);
1543 ((UShort*)(sm->vabits8))[sm_off16] = vabits16;
1544 a += 8;
1545 lenB -= 8;
1546 }
1547 // 1 byte steps
1548 while (True) {
1549 if (lenB < 1) return;
1550 PROF_EVENT(164, "set_address_range_perms-loop1c");
1551 sm_off = SM_OFF(a);
1552 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1553 a += 1;
1554 lenB -= 1;
1555 }
sewardj23eb2fd2005-04-22 16:29:19 +00001556}
sewardj45d94cc2005-04-20 14:44:11 +00001557
sewardjc859fbf2005-04-22 21:10:28 +00001558
1559/* --- Set permissions for arbitrary address ranges --- */
njn25e49d8e72002-09-23 09:36:25 +00001560
njndbf7ca72006-03-31 11:57:59 +00001561void MC_(make_mem_noaccess) ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001562{
njndbf7ca72006-03-31 11:57:59 +00001563 PROF_EVENT(40, "MC_(make_mem_noaccess)");
1564 DEBUG("MC_(make_mem_noaccess)(%p, %lu)\n", a, len);
njn1d0825f2006-03-27 11:37:07 +00001565 set_address_range_perms ( a, len, VA_BITS16_NOACCESS, SM_DIST_NOACCESS );
sewardj7cf4e6b2008-05-01 20:24:26 +00001566 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1567 ocache_sarp_Clear_Origins ( a, len );
njn25e49d8e72002-09-23 09:36:25 +00001568}
1569
sewardj7cf4e6b2008-05-01 20:24:26 +00001570static void make_mem_undefined ( Addr a, SizeT len )
1571{
1572 PROF_EVENT(41, "make_mem_undefined");
1573 DEBUG("make_mem_undefined(%p, %lu)\n", a, len);
1574 set_address_range_perms ( a, len, VA_BITS16_UNDEFINED, SM_DIST_UNDEFINED );
1575}
1576
1577void MC_(make_mem_undefined_w_otag) ( Addr a, SizeT len, UInt otag )
njn25e49d8e72002-09-23 09:36:25 +00001578{
njndbf7ca72006-03-31 11:57:59 +00001579 PROF_EVENT(41, "MC_(make_mem_undefined)");
1580 DEBUG("MC_(make_mem_undefined)(%p, %lu)\n", a, len);
1581 set_address_range_perms ( a, len, VA_BITS16_UNDEFINED, SM_DIST_UNDEFINED );
sewardj7cf4e6b2008-05-01 20:24:26 +00001582 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1583 ocache_sarp_Set_Origins ( a, len, otag );
njn25e49d8e72002-09-23 09:36:25 +00001584}
1585
sewardj7cf4e6b2008-05-01 20:24:26 +00001586static
1587void make_mem_undefined_w_tid_and_okind ( Addr a, SizeT len,
1588 ThreadId tid, UInt okind )
1589{
1590 UInt ecu;
1591 ExeContext* here;
1592 /* VG_(record_ExeContext) checks for validity of tid, and asserts
1593 if it is invalid. So no need to do it here. */
1594 tl_assert(okind <= 3);
1595 here = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ );
1596 tl_assert(here);
1597 ecu = VG_(get_ECU_from_ExeContext)(here);
1598 tl_assert(VG_(is_plausible_ECU)(ecu));
1599 MC_(make_mem_undefined_w_otag) ( a, len, ecu | okind );
1600}
1601
1602static
1603void make_mem_undefined_w_tid ( Addr a, SizeT len, ThreadId tid ) {
1604 make_mem_undefined_w_tid_and_okind ( a, len, tid, MC_OKIND_UNKNOWN );
1605}
1606
1607
njndbf7ca72006-03-31 11:57:59 +00001608void MC_(make_mem_defined) ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001609{
njndbf7ca72006-03-31 11:57:59 +00001610 PROF_EVENT(42, "MC_(make_mem_defined)");
1611 DEBUG("MC_(make_mem_defined)(%p, %lu)\n", a, len);
1612 set_address_range_perms ( a, len, VA_BITS16_DEFINED, SM_DIST_DEFINED );
sewardj7cf4e6b2008-05-01 20:24:26 +00001613 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1614 ocache_sarp_Clear_Origins ( a, len );
njn25e49d8e72002-09-23 09:36:25 +00001615}
1616
sewardjfb1e9ad2006-03-10 13:41:58 +00001617/* For each byte in [a,a+len), if the byte is addressable, make it be
1618 defined, but if it isn't addressible, leave it alone. In other
njndbf7ca72006-03-31 11:57:59 +00001619 words a version of MC_(make_mem_defined) that doesn't mess with
sewardjfb1e9ad2006-03-10 13:41:58 +00001620 addressibility. Low-performance implementation. */
njndbf7ca72006-03-31 11:57:59 +00001621static void make_mem_defined_if_addressable ( Addr a, SizeT len )
sewardjfb1e9ad2006-03-10 13:41:58 +00001622{
1623 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00001624 UChar vabits2;
njndbf7ca72006-03-31 11:57:59 +00001625 DEBUG("make_mem_defined_if_addressable(%p, %llu)\n", a, (ULong)len);
sewardjfb1e9ad2006-03-10 13:41:58 +00001626 for (i = 0; i < len; i++) {
njn1d0825f2006-03-27 11:37:07 +00001627 vabits2 = get_vabits2( a+i );
bart5dd8e6a2008-03-22 08:04:29 +00001628 if (LIKELY(VA_BITS2_NOACCESS != vabits2)) {
njndbf7ca72006-03-31 11:57:59 +00001629 set_vabits2(a+i, VA_BITS2_DEFINED);
sewardj7cf4e6b2008-05-01 20:24:26 +00001630 if (UNLIKELY(MC_(clo_mc_level) >= 3)) {
1631 MC_(helperc_b_store1)( a+i, 0 ); /* clear the origin tag */
1632 }
njn1d0825f2006-03-27 11:37:07 +00001633 }
sewardjfb1e9ad2006-03-10 13:41:58 +00001634 }
1635}
1636
njn9b007f62003-04-07 14:40:25 +00001637
sewardj45f4e7c2005-09-27 19:20:21 +00001638/* --- Block-copy permissions (needed for implementing realloc() and
1639 sys_mremap). --- */
sewardjc859fbf2005-04-22 21:10:28 +00001640
njn1d0825f2006-03-27 11:37:07 +00001641void MC_(copy_address_range_state) ( Addr src, Addr dst, SizeT len )
sewardjc859fbf2005-04-22 21:10:28 +00001642{
sewardj45f4e7c2005-09-27 19:20:21 +00001643 SizeT i, j;
sewardjf2184912006-05-03 22:13:57 +00001644 UChar vabits2, vabits8;
1645 Bool aligned, nooverlap;
sewardjc859fbf2005-04-22 21:10:28 +00001646
njn1d0825f2006-03-27 11:37:07 +00001647 DEBUG("MC_(copy_address_range_state)\n");
1648 PROF_EVENT(50, "MC_(copy_address_range_state)");
sewardj45f4e7c2005-09-27 19:20:21 +00001649
sewardjf2184912006-05-03 22:13:57 +00001650 if (len == 0 || src == dst)
sewardj45f4e7c2005-09-27 19:20:21 +00001651 return;
1652
sewardjf2184912006-05-03 22:13:57 +00001653 aligned = VG_IS_4_ALIGNED(src) && VG_IS_4_ALIGNED(dst);
1654 nooverlap = src+len <= dst || dst+len <= src;
sewardj45f4e7c2005-09-27 19:20:21 +00001655
sewardjf2184912006-05-03 22:13:57 +00001656 if (nooverlap && aligned) {
1657
1658 /* Vectorised fast case, when no overlap and suitably aligned */
1659 /* vector loop */
1660 i = 0;
1661 while (len >= 4) {
1662 vabits8 = get_vabits8_for_aligned_word32( src+i );
1663 set_vabits8_for_aligned_word32( dst+i, vabits8 );
bart5dd8e6a2008-03-22 08:04:29 +00001664 if (LIKELY(VA_BITS8_DEFINED == vabits8
sewardjf2184912006-05-03 22:13:57 +00001665 || VA_BITS8_UNDEFINED == vabits8
1666 || VA_BITS8_NOACCESS == vabits8)) {
1667 /* do nothing */
1668 } else {
1669 /* have to copy secondary map info */
1670 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+0 ))
1671 set_sec_vbits8( dst+i+0, get_sec_vbits8( src+i+0 ) );
1672 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+1 ))
1673 set_sec_vbits8( dst+i+1, get_sec_vbits8( src+i+1 ) );
1674 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+2 ))
1675 set_sec_vbits8( dst+i+2, get_sec_vbits8( src+i+2 ) );
1676 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+3 ))
1677 set_sec_vbits8( dst+i+3, get_sec_vbits8( src+i+3 ) );
1678 }
1679 i += 4;
1680 len -= 4;
1681 }
1682 /* fixup loop */
1683 while (len >= 1) {
njn1d0825f2006-03-27 11:37:07 +00001684 vabits2 = get_vabits2( src+i );
1685 set_vabits2( dst+i, vabits2 );
njndbf7ca72006-03-31 11:57:59 +00001686 if (VA_BITS2_PARTDEFINED == vabits2) {
njn1d0825f2006-03-27 11:37:07 +00001687 set_sec_vbits8( dst+i, get_sec_vbits8( src+i ) );
1688 }
sewardjf2184912006-05-03 22:13:57 +00001689 i++;
1690 len--;
1691 }
1692
1693 } else {
1694
1695 /* We have to do things the slow way */
1696 if (src < dst) {
1697 for (i = 0, j = len-1; i < len; i++, j--) {
1698 PROF_EVENT(51, "MC_(copy_address_range_state)(loop)");
1699 vabits2 = get_vabits2( src+j );
1700 set_vabits2( dst+j, vabits2 );
1701 if (VA_BITS2_PARTDEFINED == vabits2) {
1702 set_sec_vbits8( dst+j, get_sec_vbits8( src+j ) );
1703 }
1704 }
1705 }
1706
1707 if (src > dst) {
1708 for (i = 0; i < len; i++) {
1709 PROF_EVENT(52, "MC_(copy_address_range_state)(loop)");
1710 vabits2 = get_vabits2( src+i );
1711 set_vabits2( dst+i, vabits2 );
1712 if (VA_BITS2_PARTDEFINED == vabits2) {
1713 set_sec_vbits8( dst+i, get_sec_vbits8( src+i ) );
1714 }
1715 }
sewardj45f4e7c2005-09-27 19:20:21 +00001716 }
sewardjc859fbf2005-04-22 21:10:28 +00001717 }
sewardjf2184912006-05-03 22:13:57 +00001718
sewardjc859fbf2005-04-22 21:10:28 +00001719}
1720
1721
sewardj7cf4e6b2008-05-01 20:24:26 +00001722/*------------------------------------------------------------*/
1723/*--- Origin tracking stuff - cache basics ---*/
1724/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00001725
sewardj77139802008-05-05 09:48:56 +00001726/* AN OVERVIEW OF THE ORIGIN TRACKING IMPLEMENTATION
1727 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sewardj7cf4e6b2008-05-01 20:24:26 +00001728
1729 Note that this implementation draws inspiration from the "origin
1730 tracking by value piggybacking" scheme described in "Tracking Bad
1731 Apples: Reporting the Origin of Null and Undefined Value Errors"
1732 (Michael Bond, Nicholas Nethercote, Stephen Kent, Samuel Guyer,
1733 Kathryn McKinley, OOPSLA07, Montreal, Oct 2007) but in fact it is
1734 implemented completely differently.
1735
sewardj77139802008-05-05 09:48:56 +00001736 Origin tags and ECUs -- about the shadow values
1737 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1738
1739 This implementation tracks the defining point of all uninitialised
1740 values using so called "origin tags", which are 32-bit integers,
1741 rather than using the values themselves to encode the origins. The
1742 latter, so-called value piggybacking", is what the OOPSLA07 paper
sewardj7cf4e6b2008-05-01 20:24:26 +00001743 describes.
1744
1745 Origin tags, as tracked by the machinery below, are 32-bit unsigned
sewardj77139802008-05-05 09:48:56 +00001746 ints (UInts), regardless of the machine's word size. Each tag
1747 comprises an upper 30-bit ECU field and a lower 2-bit
1748 'kind' field. The ECU field is a number given out by m_execontext
1749 and has a 1-1 mapping with ExeContext*s. An ECU can be used
1750 directly as an origin tag (otag), but in fact we want to put
1751 additional information 'kind' field to indicate roughly where the
1752 tag came from. This helps print more understandable error messages
1753 for the user -- it has no other purpose. In summary:
1754
1755 * Both ECUs and origin tags are represented as 32-bit words
1756
1757 * m_execontext and the core-tool interface deal purely in ECUs.
1758 They have no knowledge of origin tags - that is a purely
1759 Memcheck-internal matter.
1760
1761 * all valid ECUs have the lowest 2 bits zero and at least
1762 one of the upper 30 bits nonzero (see VG_(is_plausible_ECU))
1763
1764 * to convert from an ECU to an otag, OR in one of the MC_OKIND_
1765 constants defined in mc_include.h.
1766
1767 * to convert an otag back to an ECU, AND it with ~3
1768
1769 One important fact is that no valid otag is zero. A zero otag is
1770 used by the implementation to indicate "no origin", which could
1771 mean that either the value is defined, or it is undefined but the
1772 implementation somehow managed to lose the origin.
1773
1774 The ECU used for memory created by malloc etc is derived from the
1775 stack trace at the time the malloc etc happens. This means the
1776 mechanism can show the exact allocation point for heap-created
1777 uninitialised values.
1778
1779 In contrast, it is simply too expensive to create a complete
1780 backtrace for each stack allocation. Therefore we merely use a
1781 depth-1 backtrace for stack allocations, which can be done once at
1782 translation time, rather than N times at run time. The result of
1783 this is that, for stack created uninitialised values, Memcheck can
1784 only show the allocating function, and not what called it.
1785 Furthermore, compilers tend to move the stack pointer just once at
1786 the start of the function, to allocate all locals, and so in fact
1787 the stack origin almost always simply points to the opening brace
1788 of the function. Net result is, for stack origins, the mechanism
1789 can tell you in which function the undefined value was created, but
1790 that's all. Users will need to carefully check all locals in the
1791 specified function.
1792
1793 Shadowing registers and memory
1794 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1795
1796 Memory is shadowed using a two level cache structure (ocacheL1 and
1797 ocacheL2). Memory references are first directed to ocacheL1. This
1798 is a traditional 2-way set associative cache with 32-byte lines and
1799 approximate LRU replacement within each set.
1800
1801 A naive implementation would require storing one 32 bit otag for
1802 each byte of memory covered, a 4:1 space overhead. Instead, there
1803 is one otag for every 4 bytes of memory covered, plus a 4-bit mask
1804 that shows which of the 4 bytes have that shadow value and which
1805 have a shadow value of zero (indicating no origin). Hence a lot of
1806 space is saved, but the cost is that only one different origin per
1807 4 bytes of address space can be represented. This is a source of
1808 imprecision, but how much of a problem it really is remains to be
1809 seen.
1810
1811 A cache line that contains all zeroes ("no origins") contains no
1812 useful information, and can be ejected from the L1 cache "for
1813 free", in the sense that a read miss on the L1 causes a line of
1814 zeroes to be installed. However, ejecting a line containing
1815 nonzeroes risks losing origin information permanently. In order to
1816 prevent such lossage, ejected nonzero lines are placed in a
1817 secondary cache (ocacheL2), which is an OSet (AVL tree) of cache
1818 lines. This can grow arbitrarily large, and so should ensure that
1819 Memcheck runs out of memory in preference to losing useful origin
1820 info due to cache size limitations.
1821
1822 Shadowing registers is a bit tricky, because the shadow values are
1823 32 bits, regardless of the size of the register. That gives a
1824 problem for registers smaller than 32 bits. The solution is to
1825 find spaces in the guest state that are unused, and use those to
1826 shadow guest state fragments smaller than 32 bits. For example, on
1827 ppc32/64, each vector register is 16 bytes long. If 4 bytes of the
1828 shadow are allocated for the register's otag, then there are still
1829 12 bytes left over which could be used to shadow 3 other values.
1830
1831 This implies there is some non-obvious mapping from guest state
1832 (start,length) pairs to the relevant shadow offset (for the origin
1833 tags). And it is unfortunately guest-architecture specific. The
1834 mapping is contained in mc_machine.c, which is quite lengthy but
1835 straightforward.
1836
1837 Instrumenting the IR
1838 ~~~~~~~~~~~~~~~~~~~~
1839
1840 Instrumentation is largely straightforward, and done by the
1841 functions schemeE and schemeS in mc_translate.c. These generate
1842 code for handling the origin tags of expressions (E) and statements
1843 (S) respectively. The rather strange names are a reference to the
1844 "compilation schemes" shown in Simon Peyton Jones' book "The
1845 Implementation of Functional Programming Languages" (Prentice Hall,
1846 1987, see
1847 http://research.microsoft.com/~simonpj/papers/slpj-book-1987/index.htm).
1848
1849 schemeS merely arranges to move shadow values around the guest
1850 state to track the incoming IR. schemeE is largely trivial too.
1851 The only significant point is how to compute the otag corresponding
1852 to binary (or ternary, quaternary, etc) operator applications. The
1853 rule is simple: just take whichever value is larger (32-bit
1854 unsigned max). Constants get the special value zero. Hence this
1855 rule always propagates a nonzero (known) otag in preference to a
1856 zero (unknown, or more likely, value-is-defined) tag, as we want.
1857 If two different undefined values are inputs to a binary operator
1858 application, then which is propagated is arbitrary, but that
1859 doesn't matter, since the program is erroneous in using either of
1860 the values, and so there's no point in attempting to propagate
1861 both.
1862
1863 Since constants are abstracted to (otag) zero, much of the
1864 instrumentation code can be folded out without difficulty by the
1865 generic post-instrumentation IR cleanup pass, using these rules:
1866 Max32U(0,x) -> x, Max32U(x,0) -> x, Max32(x,y) where x and y are
1867 constants is evaluated at JIT time. And the resulting dead code
1868 removal. In practice this causes surprisingly few Max32Us to
1869 survive through to backend code generation.
1870
1871 Integration with the V-bits machinery
1872 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1873
1874 This is again largely straightforward. Mostly the otag and V bits
1875 stuff are independent. The only point of interaction is when the V
1876 bits instrumenter creates a call to a helper function to report an
1877 uninitialised value error -- in that case it must first use schemeE
1878 to get hold of the origin tag expression for the value, and pass
1879 that to the helper too.
1880
1881 There is the usual stuff to do with setting address range
1882 permissions. When memory is painted undefined, we must also know
1883 the origin tag to paint with, which involves some tedious plumbing,
1884 particularly to do with the fast case stack handlers. When memory
1885 is painted defined or noaccess then the origin tags must be forced
1886 to zero.
1887
1888 One of the goals of the implementation was to ensure that the
1889 non-origin tracking mode isn't slowed down at all. To do this,
1890 various functions to do with memory permissions setting (again,
1891 mostly pertaining to the stack) are duplicated for the with- and
1892 without-otag case.
1893
1894 Dealing with stack redzones, and the NIA cache
1895 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1896
1897 This is one of the few non-obvious parts of the implementation.
1898
1899 Some ABIs (amd64-ELF, ppc64-ELF, ppc32/64-XCOFF) define a small
1900 reserved area below the stack pointer, that can be used as scratch
1901 space by compiler generated code for functions. In the Memcheck
1902 sources this is referred to as the "stack redzone". The important
1903 thing here is that such redzones are considered volatile across
1904 function calls and returns. So Memcheck takes care to mark them as
1905 undefined for each call and return, on the afflicted platforms.
1906 Past experience shows this is essential in order to get reliable
1907 messages about uninitialised values that come from the stack.
1908
1909 So the question is, when we paint a redzone undefined, what origin
1910 tag should we use for it? Consider a function f() calling g(). If
1911 we paint the redzone using an otag derived from the ExeContext of
1912 the CALL/BL instruction in f, then any errors in g causing it to
1913 use uninitialised values that happen to lie in the redzone, will be
1914 reported as having their origin in f. Which is highly confusing.
1915
1916 The same applies for returns: if, on a return, we paint the redzone
1917 using a origin tag derived from the ExeContext of the RET/BLR
1918 instruction in g, then any later errors in f causing it to use
1919 uninitialised values in the redzone, will be reported as having
1920 their origin in g. Which is just as confusing.
1921
1922 To do it right, in both cases we need to use an origin tag which
1923 pertains to the instruction which dynamically follows the CALL/BL
1924 or RET/BLR. In short, one derived from the NIA - the "next
1925 instruction address".
1926
1927 To make this work, Memcheck's redzone-painting helper,
1928 MC_(helperc_MAKE_STACK_UNINIT), now takes a third argument, the
1929 NIA. It converts the NIA to a 1-element ExeContext, and uses that
1930 ExeContext's ECU as the basis for the otag used to paint the
1931 redzone. The expensive part of this is converting an NIA into an
1932 ECU, since this happens once for every call and every return. So
1933 we use a simple 511-line, 2-way set associative cache
1934 (nia_to_ecu_cache) to cache the mappings, and that knocks most of
1935 the cost out.
1936
1937 Further background comments
1938 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
sewardj7cf4e6b2008-05-01 20:24:26 +00001939
1940 > Question: why is otag a UInt? Wouldn't a UWord be better? Isn't
1941 > it really just the address of the relevant ExeContext?
1942
1943 Well, it's not the address, but a value which has a 1-1 mapping
1944 with ExeContexts, and is guaranteed not to be zero, since zero
1945 denotes (to memcheck) "unknown origin or defined value". So these
sewardj77139802008-05-05 09:48:56 +00001946 UInts are just numbers starting at 4 and incrementing by 4; each
1947 ExeContext is given a number when it is created. (*** NOTE this
1948 confuses otags and ECUs; see comments above ***).
sewardj7cf4e6b2008-05-01 20:24:26 +00001949
1950 Making these otags 32-bit regardless of the machine's word size
1951 makes the 64-bit implementation easier (next para). And it doesn't
1952 really limit us in any way, since for the tags to overflow would
sewardj77139802008-05-05 09:48:56 +00001953 require that the program somehow caused 2^30-1 different
sewardj7cf4e6b2008-05-01 20:24:26 +00001954 ExeContexts to be created, in which case it is probably in deep
1955 trouble. Not to mention V will have soaked up many tens of
1956 gigabytes of memory merely to store them all.
1957
1958 So having 64-bit origins doesn't really buy you anything, and has
1959 the following downsides:
1960
1961 Suppose that instead, an otag is a UWord. This would mean that, on
1962 a 64-bit target,
1963
1964 1. It becomes hard to shadow any element of guest state which is
1965 smaller than 8 bytes. To do so means you'd need to find some
1966 8-byte-sized hole in the guest state which you don't want to
1967 shadow, and use that instead to hold the otag. On ppc64, the
1968 condition code register(s) are split into 20 UChar sized pieces,
1969 all of which need to be tracked (guest_XER_SO .. guest_CR7_0)
1970 and so that would entail finding 160 bytes somewhere else in the
1971 guest state.
1972
1973 Even on x86, I want to track origins for %AH .. %DH (bits 15:8
1974 of %EAX .. %EDX) that are separate from %AL .. %DL (bits 7:0 of
1975 same) and so I had to look for 4 untracked otag-sized areas in
1976 the guest state to make that possible.
1977
1978 The same problem exists of course when origin tags are only 32
1979 bits, but it's less extreme.
1980
1981 2. (More compelling) it doubles the size of the origin shadow
1982 memory. Given that the shadow memory is organised as a fixed
1983 size cache, and that accuracy of tracking is limited by origins
1984 falling out the cache due to space conflicts, this isn't good.
1985
1986 > Another question: is the origin tracking perfect, or are there
1987 > cases where it fails to determine an origin?
1988
1989 It is imperfect for at least for the following reasons, and
1990 probably more:
1991
1992 * Insufficient capacity in the origin cache. When a line is
1993 evicted from the cache it is gone forever, and so subsequent
1994 queries for the line produce zero, indicating no origin
1995 information. Interestingly, a line containing all zeroes can be
1996 evicted "free" from the cache, since it contains no useful
1997 information, so there is scope perhaps for some cleverer cache
sewardj77139802008-05-05 09:48:56 +00001998 management schemes. (*** NOTE, with the introduction of the
1999 second level origin tag cache, ocacheL2, this is no longer a
2000 problem. ***)
sewardj7cf4e6b2008-05-01 20:24:26 +00002001
2002 * The origin cache only stores one otag per 32-bits of address
2003 space, plus 4 bits indicating which of the 4 bytes has that tag
2004 and which are considered defined. The result is that if two
2005 undefined bytes in the same word are stored in memory, the first
2006 stored byte's origin will be lost and replaced by the origin for
2007 the second byte.
2008
2009 * Nonzero origin tags for defined values. Consider a binary
2010 operator application op(x,y). Suppose y is undefined (and so has
2011 a valid nonzero origin tag), and x is defined, but erroneously
2012 has a nonzero origin tag (defined values should have tag zero).
2013 If the erroneous tag has a numeric value greater than y's tag,
2014 then the rule for propagating origin tags though binary
2015 operations, which is simply to take the unsigned max of the two
2016 tags, will erroneously propagate x's tag rather than y's.
2017
2018 * Some obscure uses of x86/amd64 byte registers can cause lossage
2019 or confusion of origins. %AH .. %DH are treated as different
2020 from, and unrelated to, their parent registers, %EAX .. %EDX.
2021 So some wierd sequences like
2022
2023 movb undefined-value, %AH
2024 movb defined-value, %AL
2025 .. use %AX or %EAX ..
2026
2027 will cause the origin attributed to %AH to be ignored, since %AL,
2028 %AX, %EAX are treated as the same register, and %AH as a
2029 completely separate one.
2030
2031 But having said all that, it actually seems to work fairly well in
2032 practice.
2033*/
2034
2035static UWord stats_ocacheL1_find = 0;
2036static UWord stats_ocacheL1_found_at_1 = 0;
2037static UWord stats_ocacheL1_found_at_N = 0;
2038static UWord stats_ocacheL1_misses = 0;
2039static UWord stats_ocacheL1_lossage = 0;
2040static UWord stats_ocacheL1_movefwds = 0;
2041
2042static UWord stats__ocacheL2_refs = 0;
2043static UWord stats__ocacheL2_misses = 0;
2044static UWord stats__ocacheL2_n_nodes_max = 0;
2045
2046/* Cache of 32-bit values, one every 32 bits of address space */
2047
2048#define OC_BITS_PER_LINE 5
2049#define OC_W32S_PER_LINE (1 << (OC_BITS_PER_LINE - 2))
2050
2051static INLINE UWord oc_line_offset ( Addr a ) {
2052 return (a >> 2) & (OC_W32S_PER_LINE - 1);
2053}
2054static INLINE Bool is_valid_oc_tag ( Addr tag ) {
2055 return 0 == (tag & ((1 << OC_BITS_PER_LINE) - 1));
2056}
2057
2058#define OC_LINES_PER_SET 2
2059
2060#define OC_N_SET_BITS 20
2061#define OC_N_SETS (1 << OC_N_SET_BITS)
2062
2063/* These settings give:
2064 64 bit host: ocache: 100,663,296 sizeB 67,108,864 useful
2065 32 bit host: ocache: 92,274,688 sizeB 67,108,864 useful
2066*/
2067
2068#define OC_MOVE_FORWARDS_EVERY_BITS 7
2069
2070
2071typedef
2072 struct {
2073 Addr tag;
2074 UInt w32[OC_W32S_PER_LINE];
2075 UChar descr[OC_W32S_PER_LINE];
2076 }
2077 OCacheLine;
2078
2079/* Classify and also sanity-check 'line'. Return 'e' (empty) if not
2080 in use, 'n' (nonzero) if it contains at least one valid origin tag,
2081 and 'z' if all the represented tags are zero. */
2082static UChar classify_OCacheLine ( OCacheLine* line )
2083{
2084 UWord i;
2085 if (line->tag == 1/*invalid*/)
2086 return 'e'; /* EMPTY */
2087 tl_assert(is_valid_oc_tag(line->tag));
2088 for (i = 0; i < OC_W32S_PER_LINE; i++) {
2089 tl_assert(0 == ((~0xF) & line->descr[i]));
2090 if (line->w32[i] > 0 && line->descr[i] > 0)
2091 return 'n'; /* NONZERO - contains useful info */
2092 }
2093 return 'z'; /* ZERO - no useful info */
2094}
2095
2096typedef
2097 struct {
2098 OCacheLine line[OC_LINES_PER_SET];
2099 }
2100 OCacheSet;
2101
2102typedef
2103 struct {
2104 OCacheSet set[OC_N_SETS];
2105 }
2106 OCache;
2107
sewardj77139802008-05-05 09:48:56 +00002108static OCache* ocacheL1 = NULL;
2109static UWord ocacheL1_event_ctr = 0;
sewardj7cf4e6b2008-05-01 20:24:26 +00002110
2111static void init_ocacheL2 ( void ); /* fwds */
2112static void init_OCache ( void )
2113{
2114 UWord line, set;
sewardj9d624d12008-05-02 13:35:29 +00002115 tl_assert(MC_(clo_mc_level) >= 3);
sewardj77139802008-05-05 09:48:56 +00002116 tl_assert(ocacheL1 == NULL);
2117 ocacheL1 = VG_(am_shadow_alloc)(sizeof(OCache));
2118 if (ocacheL1 == NULL) {
2119 VG_(out_of_memory_NORETURN)( "memcheck:allocating ocacheL1",
sewardj9d624d12008-05-02 13:35:29 +00002120 sizeof(OCache) );
2121 }
sewardj77139802008-05-05 09:48:56 +00002122 tl_assert(ocacheL1 != NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00002123 for (set = 0; set < OC_N_SETS; set++) {
2124 for (line = 0; line < OC_LINES_PER_SET; line++) {
sewardj77139802008-05-05 09:48:56 +00002125 ocacheL1->set[set].line[line].tag = 1/*invalid*/;
sewardj7cf4e6b2008-05-01 20:24:26 +00002126 }
2127 }
2128 init_ocacheL2();
2129}
2130
2131static void moveLineForwards ( OCacheSet* set, UWord lineno )
2132{
2133 OCacheLine tmp;
2134 stats_ocacheL1_movefwds++;
2135 tl_assert(lineno > 0 && lineno < OC_LINES_PER_SET);
2136 tmp = set->line[lineno-1];
2137 set->line[lineno-1] = set->line[lineno];
2138 set->line[lineno] = tmp;
2139}
2140
2141static void zeroise_OCacheLine ( OCacheLine* line, Addr tag ) {
2142 UWord i;
2143 for (i = 0; i < OC_W32S_PER_LINE; i++) {
2144 line->w32[i] = 0; /* NO ORIGIN */
2145 line->descr[i] = 0; /* REALLY REALLY NO ORIGIN! */
2146 }
2147 line->tag = tag;
2148}
2149
2150//////////////////////////////////////////////////////////////
2151//// OCache backing store
2152
2153static OSet* ocacheL2 = NULL;
2154
sewardj9c606bd2008-09-18 18:12:50 +00002155static void* ocacheL2_malloc ( HChar* cc, SizeT szB ) {
2156 return VG_(malloc)(cc, szB);
sewardj7cf4e6b2008-05-01 20:24:26 +00002157}
2158static void ocacheL2_free ( void* v ) {
2159 VG_(free)( v );
2160}
2161
2162/* Stats: # nodes currently in tree */
2163static UWord stats__ocacheL2_n_nodes = 0;
2164
2165static void init_ocacheL2 ( void )
2166{
2167 tl_assert(!ocacheL2);
2168 tl_assert(sizeof(Word) == sizeof(Addr)); /* since OCacheLine.tag :: Addr */
2169 tl_assert(0 == offsetof(OCacheLine,tag));
2170 ocacheL2
2171 = VG_(OSetGen_Create)( offsetof(OCacheLine,tag),
2172 NULL, /* fast cmp */
sewardj9c606bd2008-09-18 18:12:50 +00002173 ocacheL2_malloc, "mc.ioL2", ocacheL2_free );
sewardj7cf4e6b2008-05-01 20:24:26 +00002174 tl_assert(ocacheL2);
2175 stats__ocacheL2_n_nodes = 0;
2176}
2177
2178/* Find line with the given tag in the tree, or NULL if not found. */
2179static OCacheLine* ocacheL2_find_tag ( Addr tag )
2180{
2181 OCacheLine* line;
2182 tl_assert(is_valid_oc_tag(tag));
2183 stats__ocacheL2_refs++;
2184 line = VG_(OSetGen_Lookup)( ocacheL2, &tag );
2185 return line;
2186}
2187
2188/* Delete the line with the given tag from the tree, if it is present, and
2189 free up the associated memory. */
2190static void ocacheL2_del_tag ( Addr tag )
2191{
2192 OCacheLine* line;
2193 tl_assert(is_valid_oc_tag(tag));
2194 stats__ocacheL2_refs++;
2195 line = VG_(OSetGen_Remove)( ocacheL2, &tag );
2196 if (line) {
2197 VG_(OSetGen_FreeNode)(ocacheL2, line);
2198 tl_assert(stats__ocacheL2_n_nodes > 0);
2199 stats__ocacheL2_n_nodes--;
2200 }
2201}
2202
2203/* Add a copy of the given line to the tree. It must not already be
2204 present. */
2205static void ocacheL2_add_line ( OCacheLine* line )
2206{
2207 OCacheLine* copy;
2208 tl_assert(is_valid_oc_tag(line->tag));
2209 copy = VG_(OSetGen_AllocNode)( ocacheL2, sizeof(OCacheLine) );
2210 tl_assert(copy);
2211 *copy = *line;
2212 stats__ocacheL2_refs++;
2213 VG_(OSetGen_Insert)( ocacheL2, copy );
2214 stats__ocacheL2_n_nodes++;
2215 if (stats__ocacheL2_n_nodes > stats__ocacheL2_n_nodes_max)
2216 stats__ocacheL2_n_nodes_max = stats__ocacheL2_n_nodes;
2217}
2218
2219////
2220//////////////////////////////////////////////////////////////
2221
2222__attribute__((noinline))
2223static OCacheLine* find_OCacheLine_SLOW ( Addr a )
2224{
2225 OCacheLine *victim, *inL2;
2226 UChar c;
2227 UWord line;
2228 UWord setno = (a >> OC_BITS_PER_LINE) & (OC_N_SETS - 1);
2229 UWord tagmask = ~((1 << OC_BITS_PER_LINE) - 1);
2230 UWord tag = a & tagmask;
2231 tl_assert(setno >= 0 && setno < OC_N_SETS);
2232
2233 /* we already tried line == 0; skip therefore. */
2234 for (line = 1; line < OC_LINES_PER_SET; line++) {
sewardj77139802008-05-05 09:48:56 +00002235 if (ocacheL1->set[setno].line[line].tag == tag) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002236 if (line == 1) {
2237 stats_ocacheL1_found_at_1++;
2238 } else {
2239 stats_ocacheL1_found_at_N++;
2240 }
sewardj77139802008-05-05 09:48:56 +00002241 if (UNLIKELY(0 == (ocacheL1_event_ctr++
sewardj7cf4e6b2008-05-01 20:24:26 +00002242 & ((1<<OC_MOVE_FORWARDS_EVERY_BITS)-1)))) {
sewardj77139802008-05-05 09:48:56 +00002243 moveLineForwards( &ocacheL1->set[setno], line );
sewardj7cf4e6b2008-05-01 20:24:26 +00002244 line--;
2245 }
sewardj77139802008-05-05 09:48:56 +00002246 return &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002247 }
2248 }
2249
2250 /* A miss. Use the last slot. Implicitly this means we're
2251 ejecting the line in the last slot. */
2252 stats_ocacheL1_misses++;
2253 tl_assert(line == OC_LINES_PER_SET);
2254 line--;
2255 tl_assert(line > 0);
2256
2257 /* First, move the to-be-ejected line to the L2 cache. */
sewardj77139802008-05-05 09:48:56 +00002258 victim = &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002259 c = classify_OCacheLine(victim);
2260 switch (c) {
2261 case 'e':
2262 /* the line is empty (has invalid tag); ignore it. */
2263 break;
2264 case 'z':
2265 /* line contains zeroes. We must ensure the backing store is
2266 updated accordingly, either by copying the line there
2267 verbatim, or by ensuring it isn't present there. We
2268 chosse the latter on the basis that it reduces the size of
2269 the backing store. */
2270 ocacheL2_del_tag( victim->tag );
2271 break;
2272 case 'n':
2273 /* line contains at least one real, useful origin. Copy it
2274 to the backing store. */
2275 stats_ocacheL1_lossage++;
2276 inL2 = ocacheL2_find_tag( victim->tag );
2277 if (inL2) {
2278 *inL2 = *victim;
2279 } else {
2280 ocacheL2_add_line( victim );
2281 }
2282 break;
2283 default:
2284 tl_assert(0);
2285 }
2286
2287 /* Now we must reload the L1 cache from the backing tree, if
2288 possible. */
2289 tl_assert(tag != victim->tag); /* stay sane */
2290 inL2 = ocacheL2_find_tag( tag );
2291 if (inL2) {
2292 /* We're in luck. It's in the L2. */
sewardj77139802008-05-05 09:48:56 +00002293 ocacheL1->set[setno].line[line] = *inL2;
sewardj7cf4e6b2008-05-01 20:24:26 +00002294 } else {
2295 /* Missed at both levels of the cache hierarchy. We have to
2296 declare it as full of zeroes (unknown origins). */
2297 stats__ocacheL2_misses++;
sewardj77139802008-05-05 09:48:56 +00002298 zeroise_OCacheLine( &ocacheL1->set[setno].line[line], tag );
sewardj7cf4e6b2008-05-01 20:24:26 +00002299 }
2300
2301 /* Move it one forwards */
sewardj77139802008-05-05 09:48:56 +00002302 moveLineForwards( &ocacheL1->set[setno], line );
sewardj7cf4e6b2008-05-01 20:24:26 +00002303 line--;
2304
sewardj77139802008-05-05 09:48:56 +00002305 return &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002306}
2307
2308static INLINE OCacheLine* find_OCacheLine ( Addr a )
2309{
2310 UWord setno = (a >> OC_BITS_PER_LINE) & (OC_N_SETS - 1);
2311 UWord tagmask = ~((1 << OC_BITS_PER_LINE) - 1);
2312 UWord tag = a & tagmask;
2313
2314 stats_ocacheL1_find++;
2315
2316 if (OC_ENABLE_ASSERTIONS) {
2317 tl_assert(setno >= 0 && setno < OC_N_SETS);
2318 tl_assert(0 == (tag & (4 * OC_W32S_PER_LINE - 1)));
2319 }
2320
sewardj77139802008-05-05 09:48:56 +00002321 if (LIKELY(ocacheL1->set[setno].line[0].tag == tag)) {
2322 return &ocacheL1->set[setno].line[0];
sewardj7cf4e6b2008-05-01 20:24:26 +00002323 }
2324
2325 return find_OCacheLine_SLOW( a );
2326}
2327
2328static INLINE void set_aligned_word64_Origin_to_undef ( Addr a, UInt otag )
2329{
2330 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2331 //// Set the origins for a+0 .. a+7
2332 { OCacheLine* line;
2333 UWord lineoff = oc_line_offset(a);
2334 if (OC_ENABLE_ASSERTIONS) {
2335 tl_assert(lineoff >= 0
2336 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2337 }
2338 line = find_OCacheLine( a );
2339 line->descr[lineoff+0] = 0xF;
2340 line->descr[lineoff+1] = 0xF;
2341 line->w32[lineoff+0] = otag;
2342 line->w32[lineoff+1] = otag;
2343 }
2344 //// END inlined, specialised version of MC_(helperc_b_store8)
2345}
2346
2347
2348/*------------------------------------------------------------*/
2349/*--- Aligned fast case permission setters, ---*/
2350/*--- for dealing with stacks ---*/
2351/*------------------------------------------------------------*/
2352
2353/*--------------------- 32-bit ---------------------*/
2354
2355/* Nb: by "aligned" here we mean 4-byte aligned */
2356
2357static INLINE void make_aligned_word32_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002358{
njn1d0825f2006-03-27 11:37:07 +00002359 UWord sm_off;
sewardjae986ca2005-10-12 12:53:20 +00002360 SecMap* sm;
2361
njndbf7ca72006-03-31 11:57:59 +00002362 PROF_EVENT(300, "make_aligned_word32_undefined");
sewardj5d28efc2005-04-21 22:16:29 +00002363
njn1d0825f2006-03-27 11:37:07 +00002364#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002365 make_mem_undefined(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002366#else
bart5dd8e6a2008-03-22 08:04:29 +00002367 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
njndbf7ca72006-03-31 11:57:59 +00002368 PROF_EVENT(301, "make_aligned_word32_undefined-slow1");
sewardj7cf4e6b2008-05-01 20:24:26 +00002369 make_mem_undefined(a, 4);
sewardj5d28efc2005-04-21 22:16:29 +00002370 return;
2371 }
2372
njna7c7ebd2006-03-28 12:51:02 +00002373 sm = get_secmap_for_writing_low(a);
njn1d0825f2006-03-27 11:37:07 +00002374 sm_off = SM_OFF(a);
njndbf7ca72006-03-31 11:57:59 +00002375 sm->vabits8[sm_off] = VA_BITS8_UNDEFINED;
njn1d0825f2006-03-27 11:37:07 +00002376#endif
njn9b007f62003-04-07 14:40:25 +00002377}
2378
sewardj7cf4e6b2008-05-01 20:24:26 +00002379static INLINE
2380void make_aligned_word32_undefined_w_otag ( Addr a, UInt otag )
2381{
2382 make_aligned_word32_undefined(a);
2383 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2384 //// Set the origins for a+0 .. a+3
2385 { OCacheLine* line;
2386 UWord lineoff = oc_line_offset(a);
2387 if (OC_ENABLE_ASSERTIONS) {
2388 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2389 }
2390 line = find_OCacheLine( a );
2391 line->descr[lineoff] = 0xF;
2392 line->w32[lineoff] = otag;
2393 }
2394 //// END inlined, specialised version of MC_(helperc_b_store4)
2395}
sewardj5d28efc2005-04-21 22:16:29 +00002396
njn1d0825f2006-03-27 11:37:07 +00002397static INLINE
2398void make_aligned_word32_noaccess ( Addr a )
sewardj5d28efc2005-04-21 22:16:29 +00002399{
njn1d0825f2006-03-27 11:37:07 +00002400 UWord sm_off;
sewardjae986ca2005-10-12 12:53:20 +00002401 SecMap* sm;
2402
sewardj5d28efc2005-04-21 22:16:29 +00002403 PROF_EVENT(310, "make_aligned_word32_noaccess");
2404
njn1d0825f2006-03-27 11:37:07 +00002405#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002406 MC_(make_mem_noaccess)(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002407#else
bart5dd8e6a2008-03-22 08:04:29 +00002408 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
sewardj5d28efc2005-04-21 22:16:29 +00002409 PROF_EVENT(311, "make_aligned_word32_noaccess-slow1");
njndbf7ca72006-03-31 11:57:59 +00002410 MC_(make_mem_noaccess)(a, 4);
sewardj5d28efc2005-04-21 22:16:29 +00002411 return;
2412 }
2413
njna7c7ebd2006-03-28 12:51:02 +00002414 sm = get_secmap_for_writing_low(a);
njn1d0825f2006-03-27 11:37:07 +00002415 sm_off = SM_OFF(a);
2416 sm->vabits8[sm_off] = VA_BITS8_NOACCESS;
sewardj7cf4e6b2008-05-01 20:24:26 +00002417
2418 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2419 //// Set the origins for a+0 .. a+3.
2420 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2421 OCacheLine* line;
2422 UWord lineoff = oc_line_offset(a);
2423 if (OC_ENABLE_ASSERTIONS) {
2424 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2425 }
2426 line = find_OCacheLine( a );
2427 line->descr[lineoff] = 0;
2428 }
2429 //// END inlined, specialised version of MC_(helperc_b_store4)
njn1d0825f2006-03-27 11:37:07 +00002430#endif
sewardj5d28efc2005-04-21 22:16:29 +00002431}
2432
sewardj7cf4e6b2008-05-01 20:24:26 +00002433/*--------------------- 64-bit ---------------------*/
sewardj5d28efc2005-04-21 22:16:29 +00002434
njn9b007f62003-04-07 14:40:25 +00002435/* Nb: by "aligned" here we mean 8-byte aligned */
sewardj7cf4e6b2008-05-01 20:24:26 +00002436
2437static INLINE void make_aligned_word64_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002438{
njn1d0825f2006-03-27 11:37:07 +00002439 UWord sm_off16;
sewardjae986ca2005-10-12 12:53:20 +00002440 SecMap* sm;
2441
njndbf7ca72006-03-31 11:57:59 +00002442 PROF_EVENT(320, "make_aligned_word64_undefined");
sewardj23eb2fd2005-04-22 16:29:19 +00002443
njn1d0825f2006-03-27 11:37:07 +00002444#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002445 make_mem_undefined(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002446#else
bart5dd8e6a2008-03-22 08:04:29 +00002447 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
njndbf7ca72006-03-31 11:57:59 +00002448 PROF_EVENT(321, "make_aligned_word64_undefined-slow1");
sewardj7cf4e6b2008-05-01 20:24:26 +00002449 make_mem_undefined(a, 8);
sewardj23eb2fd2005-04-22 16:29:19 +00002450 return;
2451 }
2452
njna7c7ebd2006-03-28 12:51:02 +00002453 sm = get_secmap_for_writing_low(a);
njn1d0825f2006-03-27 11:37:07 +00002454 sm_off16 = SM_OFF_16(a);
njndbf7ca72006-03-31 11:57:59 +00002455 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_UNDEFINED;
njn1d0825f2006-03-27 11:37:07 +00002456#endif
njn9b007f62003-04-07 14:40:25 +00002457}
2458
sewardj7cf4e6b2008-05-01 20:24:26 +00002459static INLINE
2460void make_aligned_word64_undefined_w_otag ( Addr a, UInt otag )
2461{
2462 make_aligned_word64_undefined(a);
2463 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2464 //// Set the origins for a+0 .. a+7
2465 { OCacheLine* line;
2466 UWord lineoff = oc_line_offset(a);
2467 tl_assert(lineoff >= 0
2468 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2469 line = find_OCacheLine( a );
2470 line->descr[lineoff+0] = 0xF;
2471 line->descr[lineoff+1] = 0xF;
2472 line->w32[lineoff+0] = otag;
2473 line->w32[lineoff+1] = otag;
2474 }
2475 //// END inlined, specialised version of MC_(helperc_b_store8)
2476}
sewardj23eb2fd2005-04-22 16:29:19 +00002477
njn1d0825f2006-03-27 11:37:07 +00002478static INLINE
2479void make_aligned_word64_noaccess ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002480{
njn1d0825f2006-03-27 11:37:07 +00002481 UWord sm_off16;
sewardjae986ca2005-10-12 12:53:20 +00002482 SecMap* sm;
2483
sewardj23eb2fd2005-04-22 16:29:19 +00002484 PROF_EVENT(330, "make_aligned_word64_noaccess");
2485
njn1d0825f2006-03-27 11:37:07 +00002486#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002487 MC_(make_mem_noaccess)(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002488#else
bart5dd8e6a2008-03-22 08:04:29 +00002489 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
sewardj23eb2fd2005-04-22 16:29:19 +00002490 PROF_EVENT(331, "make_aligned_word64_noaccess-slow1");
njndbf7ca72006-03-31 11:57:59 +00002491 MC_(make_mem_noaccess)(a, 8);
sewardj23eb2fd2005-04-22 16:29:19 +00002492 return;
2493 }
2494
njna7c7ebd2006-03-28 12:51:02 +00002495 sm = get_secmap_for_writing_low(a);
njn1d0825f2006-03-27 11:37:07 +00002496 sm_off16 = SM_OFF_16(a);
2497 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_NOACCESS;
sewardj7cf4e6b2008-05-01 20:24:26 +00002498
2499 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2500 //// Clear the origins for a+0 .. a+7.
2501 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2502 OCacheLine* line;
2503 UWord lineoff = oc_line_offset(a);
2504 tl_assert(lineoff >= 0
2505 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2506 line = find_OCacheLine( a );
2507 line->descr[lineoff+0] = 0;
2508 line->descr[lineoff+1] = 0;
2509 }
2510 //// END inlined, specialised version of MC_(helperc_b_store8)
njn1d0825f2006-03-27 11:37:07 +00002511#endif
njn9b007f62003-04-07 14:40:25 +00002512}
2513
sewardj23eb2fd2005-04-22 16:29:19 +00002514
njn1d0825f2006-03-27 11:37:07 +00002515/*------------------------------------------------------------*/
2516/*--- Stack pointer adjustment ---*/
2517/*------------------------------------------------------------*/
2518
sewardj7cf4e6b2008-05-01 20:24:26 +00002519/*--------------- adjustment by 4 bytes ---------------*/
2520
2521static void VG_REGPARM(2) mc_new_mem_stack_4_w_ECU(Addr new_SP, UInt ecu)
2522{
2523 UInt otag = ecu | MC_OKIND_STACK;
2524 PROF_EVENT(110, "new_mem_stack_4");
2525 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2526 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2527 } else {
2528 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 4, otag );
2529 }
2530}
2531
njn1d0825f2006-03-27 11:37:07 +00002532static void VG_REGPARM(1) mc_new_mem_stack_4(Addr new_SP)
2533{
2534 PROF_EVENT(110, "new_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002535 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002536 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njn1d0825f2006-03-27 11:37:07 +00002537 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002538 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 4 );
njn1d0825f2006-03-27 11:37:07 +00002539 }
2540}
2541
2542static void VG_REGPARM(1) mc_die_mem_stack_4(Addr new_SP)
2543{
2544 PROF_EVENT(120, "die_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002545 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002546 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002547 } else {
njndbf7ca72006-03-31 11:57:59 +00002548 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-4, 4 );
njn1d0825f2006-03-27 11:37:07 +00002549 }
2550}
2551
sewardj7cf4e6b2008-05-01 20:24:26 +00002552/*--------------- adjustment by 8 bytes ---------------*/
2553
2554static void VG_REGPARM(2) mc_new_mem_stack_8_w_ECU(Addr new_SP, UInt ecu)
2555{
2556 UInt otag = ecu | MC_OKIND_STACK;
2557 PROF_EVENT(111, "new_mem_stack_8");
2558 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2559 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2560 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2561 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2562 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2563 } else {
2564 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 8, otag );
2565 }
2566}
2567
njn1d0825f2006-03-27 11:37:07 +00002568static void VG_REGPARM(1) mc_new_mem_stack_8(Addr new_SP)
2569{
2570 PROF_EVENT(111, "new_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002571 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002572 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
sewardj05a46732006-10-17 01:28:10 +00002573 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002574 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002575 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002576 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002577 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 8 );
njn1d0825f2006-03-27 11:37:07 +00002578 }
2579}
2580
2581static void VG_REGPARM(1) mc_die_mem_stack_8(Addr new_SP)
2582{
2583 PROF_EVENT(121, "die_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002584 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002585 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002586 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002587 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
2588 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002589 } else {
njndbf7ca72006-03-31 11:57:59 +00002590 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-8, 8 );
njn1d0825f2006-03-27 11:37:07 +00002591 }
2592}
2593
sewardj7cf4e6b2008-05-01 20:24:26 +00002594/*--------------- adjustment by 12 bytes ---------------*/
2595
2596static void VG_REGPARM(2) mc_new_mem_stack_12_w_ECU(Addr new_SP, UInt ecu)
2597{
2598 UInt otag = ecu | MC_OKIND_STACK;
2599 PROF_EVENT(112, "new_mem_stack_12");
2600 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2601 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2602 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2603 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2604 /* from previous test we don't have 8-alignment at offset +0,
2605 hence must have 8 alignment at offsets +4/-4. Hence safe to
2606 do 4 at +0 and then 8 at +4/. */
2607 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2608 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2609 } else {
2610 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 12, otag );
2611 }
2612}
2613
njn1d0825f2006-03-27 11:37:07 +00002614static void VG_REGPARM(1) mc_new_mem_stack_12(Addr new_SP)
2615{
2616 PROF_EVENT(112, "new_mem_stack_12");
sewardj05a46732006-10-17 01:28:10 +00002617 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002618 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002619 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002620 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002621 /* from previous test we don't have 8-alignment at offset +0,
2622 hence must have 8 alignment at offsets +4/-4. Hence safe to
2623 do 4 at +0 and then 8 at +4/. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002624 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002625 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002626 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002627 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 12 );
njn1d0825f2006-03-27 11:37:07 +00002628 }
2629}
2630
2631static void VG_REGPARM(1) mc_die_mem_stack_12(Addr new_SP)
2632{
2633 PROF_EVENT(122, "die_mem_stack_12");
2634 /* Note the -12 in the test */
sewardj43fcfd92006-10-17 23:14:42 +00002635 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP-12 )) {
2636 /* We have 8-alignment at -12, hence ok to do 8 at -12 and 4 at
2637 -4. */
njndbf7ca72006-03-31 11:57:59 +00002638 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2639 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
sewardj05a46732006-10-17 01:28:10 +00002640 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002641 /* We have 4-alignment at +0, but we don't have 8-alignment at
2642 -12. So we must have 8-alignment at -8. Hence do 4 at -12
2643 and then 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002644 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2645 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
njn1d0825f2006-03-27 11:37:07 +00002646 } else {
njndbf7ca72006-03-31 11:57:59 +00002647 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-12, 12 );
njn1d0825f2006-03-27 11:37:07 +00002648 }
2649}
2650
sewardj7cf4e6b2008-05-01 20:24:26 +00002651/*--------------- adjustment by 16 bytes ---------------*/
2652
2653static void VG_REGPARM(2) mc_new_mem_stack_16_w_ECU(Addr new_SP, UInt ecu)
2654{
2655 UInt otag = ecu | MC_OKIND_STACK;
2656 PROF_EVENT(113, "new_mem_stack_16");
2657 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2658 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
2659 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2660 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2661 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2662 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2663 Hence do 4 at +0, 8 at +4, 4 at +12. */
2664 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2665 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2666 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2667 } else {
2668 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 16, otag );
2669 }
2670}
2671
njn1d0825f2006-03-27 11:37:07 +00002672static void VG_REGPARM(1) mc_new_mem_stack_16(Addr new_SP)
2673{
2674 PROF_EVENT(113, "new_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002675 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002676 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002677 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002678 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002679 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002680 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2681 Hence do 4 at +0, 8 at +4, 4 at +12. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002682 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002683 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
2684 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
njn1d0825f2006-03-27 11:37:07 +00002685 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002686 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 16 );
njn1d0825f2006-03-27 11:37:07 +00002687 }
2688}
2689
2690static void VG_REGPARM(1) mc_die_mem_stack_16(Addr new_SP)
2691{
2692 PROF_EVENT(123, "die_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002693 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002694 /* Have 8-alignment at +0, hence do 8 at -16 and 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002695 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2696 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002697 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002698 /* 8 alignment must be at -12. Do 4 at -16, 8 at -12, 4 at -4. */
njndbf7ca72006-03-31 11:57:59 +00002699 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2700 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2701 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002702 } else {
njndbf7ca72006-03-31 11:57:59 +00002703 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-16, 16 );
njn1d0825f2006-03-27 11:37:07 +00002704 }
2705}
2706
sewardj7cf4e6b2008-05-01 20:24:26 +00002707/*--------------- adjustment by 32 bytes ---------------*/
2708
2709static void VG_REGPARM(2) mc_new_mem_stack_32_w_ECU(Addr new_SP, UInt ecu)
2710{
2711 UInt otag = ecu | MC_OKIND_STACK;
2712 PROF_EVENT(114, "new_mem_stack_32");
2713 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2714 /* Straightforward */
2715 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2716 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2717 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2718 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2719 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2720 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2721 +0,+28. */
2722 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2723 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2724 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2725 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+20, otag );
2726 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+28, otag );
2727 } else {
2728 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 32, otag );
2729 }
2730}
2731
njn1d0825f2006-03-27 11:37:07 +00002732static void VG_REGPARM(1) mc_new_mem_stack_32(Addr new_SP)
2733{
2734 PROF_EVENT(114, "new_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002735 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002736 /* Straightforward */
sewardj7cf4e6b2008-05-01 20:24:26 +00002737 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2738 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002739 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2740 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
sewardj05a46732006-10-17 01:28:10 +00002741 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002742 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2743 +0,+28. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002744 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2745 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njndbf7ca72006-03-31 11:57:59 +00002746 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
2747 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+20 );
2748 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+28 );
njn1d0825f2006-03-27 11:37:07 +00002749 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002750 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 32 );
njn1d0825f2006-03-27 11:37:07 +00002751 }
2752}
2753
2754static void VG_REGPARM(1) mc_die_mem_stack_32(Addr new_SP)
2755{
2756 PROF_EVENT(124, "die_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002757 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002758 /* Straightforward */
njndbf7ca72006-03-31 11:57:59 +00002759 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2760 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2761 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2762 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
sewardj05a46732006-10-17 01:28:10 +00002763 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002764 /* 8 alignment must be at -4 etc. Hence do 8 at -12,-20,-28 and
2765 4 at -32,-4. */
njndbf7ca72006-03-31 11:57:59 +00002766 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2767 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-28 );
2768 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-20 );
2769 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2770 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002771 } else {
njndbf7ca72006-03-31 11:57:59 +00002772 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-32, 32 );
njn1d0825f2006-03-27 11:37:07 +00002773 }
2774}
2775
sewardj7cf4e6b2008-05-01 20:24:26 +00002776/*--------------- adjustment by 112 bytes ---------------*/
2777
2778static void VG_REGPARM(2) mc_new_mem_stack_112_w_ECU(Addr new_SP, UInt ecu)
2779{
2780 UInt otag = ecu | MC_OKIND_STACK;
2781 PROF_EVENT(115, "new_mem_stack_112");
2782 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2783 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2784 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2785 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2786 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2787 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2788 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2789 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2790 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2791 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2792 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2793 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2794 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2795 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2796 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2797 } else {
2798 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 112, otag );
2799 }
2800}
2801
njn1d0825f2006-03-27 11:37:07 +00002802static void VG_REGPARM(1) mc_new_mem_stack_112(Addr new_SP)
2803{
2804 PROF_EVENT(115, "new_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002805 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002806 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2807 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002808 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2809 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2810 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2811 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2812 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2813 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2814 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2815 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2816 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2817 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2818 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002819 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
njn1d0825f2006-03-27 11:37:07 +00002820 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002821 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 112 );
njn1d0825f2006-03-27 11:37:07 +00002822 }
2823}
2824
2825static void VG_REGPARM(1) mc_die_mem_stack_112(Addr new_SP)
2826{
2827 PROF_EVENT(125, "die_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002828 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002829 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2830 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2831 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2832 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2833 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2834 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2835 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2836 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2837 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2838 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2839 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2840 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2841 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2842 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002843 } else {
njndbf7ca72006-03-31 11:57:59 +00002844 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-112, 112 );
njn1d0825f2006-03-27 11:37:07 +00002845 }
2846}
2847
sewardj7cf4e6b2008-05-01 20:24:26 +00002848/*--------------- adjustment by 128 bytes ---------------*/
2849
2850static void VG_REGPARM(2) mc_new_mem_stack_128_w_ECU(Addr new_SP, UInt ecu)
2851{
2852 UInt otag = ecu | MC_OKIND_STACK;
2853 PROF_EVENT(116, "new_mem_stack_128");
2854 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2855 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2856 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2857 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2858 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2859 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2860 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2861 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2862 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2863 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2864 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2865 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2866 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2867 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2868 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2869 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2870 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2871 } else {
2872 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 128, otag );
2873 }
2874}
2875
njn1d0825f2006-03-27 11:37:07 +00002876static void VG_REGPARM(1) mc_new_mem_stack_128(Addr new_SP)
2877{
2878 PROF_EVENT(116, "new_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002879 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002880 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2881 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002882 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2883 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2884 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2885 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2886 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2887 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2888 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2889 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2890 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2891 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2892 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002893 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
2894 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
2895 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
njn1d0825f2006-03-27 11:37:07 +00002896 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002897 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 128 );
njn1d0825f2006-03-27 11:37:07 +00002898 }
2899}
2900
2901static void VG_REGPARM(1) mc_die_mem_stack_128(Addr new_SP)
2902{
2903 PROF_EVENT(126, "die_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002904 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002905 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
2906 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
2907 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2908 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2909 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2910 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2911 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2912 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2913 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2914 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2915 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2916 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2917 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2918 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2919 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2920 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002921 } else {
njndbf7ca72006-03-31 11:57:59 +00002922 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-128, 128 );
njn1d0825f2006-03-27 11:37:07 +00002923 }
2924}
2925
sewardj7cf4e6b2008-05-01 20:24:26 +00002926/*--------------- adjustment by 144 bytes ---------------*/
2927
2928static void VG_REGPARM(2) mc_new_mem_stack_144_w_ECU(Addr new_SP, UInt ecu)
2929{
2930 UInt otag = ecu | MC_OKIND_STACK;
2931 PROF_EVENT(117, "new_mem_stack_144");
2932 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2933 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2934 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2935 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2936 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2937 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2938 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2939 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2940 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2941 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2942 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2943 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2944 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2945 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2946 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2947 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2948 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2949 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
2950 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
2951 } else {
2952 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 144, otag );
2953 }
2954}
2955
njn1d0825f2006-03-27 11:37:07 +00002956static void VG_REGPARM(1) mc_new_mem_stack_144(Addr new_SP)
2957{
2958 PROF_EVENT(117, "new_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00002959 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002960 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2961 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002962 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2963 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2964 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2965 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2966 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2967 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2968 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2969 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2970 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2971 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2972 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002973 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
2974 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
2975 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
2976 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
2977 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
njn1d0825f2006-03-27 11:37:07 +00002978 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002979 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 144 );
njn1d0825f2006-03-27 11:37:07 +00002980 }
2981}
2982
2983static void VG_REGPARM(1) mc_die_mem_stack_144(Addr new_SP)
2984{
2985 PROF_EVENT(127, "die_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00002986 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002987 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
2988 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
2989 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
2990 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
2991 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2992 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2993 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2994 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2995 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2996 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2997 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2998 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2999 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
3000 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
3001 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
3002 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
3003 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
3004 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00003005 } else {
njndbf7ca72006-03-31 11:57:59 +00003006 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-144, 144 );
njn1d0825f2006-03-27 11:37:07 +00003007 }
3008}
3009
sewardj7cf4e6b2008-05-01 20:24:26 +00003010/*--------------- adjustment by 160 bytes ---------------*/
3011
3012static void VG_REGPARM(2) mc_new_mem_stack_160_w_ECU(Addr new_SP, UInt ecu)
3013{
3014 UInt otag = ecu | MC_OKIND_STACK;
3015 PROF_EVENT(118, "new_mem_stack_160");
3016 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
3017 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
3018 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
3019 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
3020 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
3021 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
3022 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
3023 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
3024 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
3025 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
3026 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
3027 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
3028 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
3029 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
3030 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
3031 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
3032 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
3033 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
3034 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
3035 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+144, otag );
3036 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+152, otag );
3037 } else {
3038 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 160, otag );
3039 }
3040}
3041
njn1d0825f2006-03-27 11:37:07 +00003042static void VG_REGPARM(1) mc_new_mem_stack_160(Addr new_SP)
3043{
3044 PROF_EVENT(118, "new_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00003045 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003046 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
3047 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00003048 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
3049 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
3050 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
3051 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
3052 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
3053 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
3054 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
3055 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
3056 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
3057 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
3058 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00003059 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
3060 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
3061 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
3062 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
3063 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
3064 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+144 );
3065 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+152 );
njn1d0825f2006-03-27 11:37:07 +00003066 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003067 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 160 );
njn1d0825f2006-03-27 11:37:07 +00003068 }
3069}
3070
3071static void VG_REGPARM(1) mc_die_mem_stack_160(Addr new_SP)
3072{
3073 PROF_EVENT(128, "die_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00003074 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00003075 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-160);
3076 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-152);
3077 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
3078 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
3079 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
3080 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
3081 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
3082 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
3083 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
3084 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
3085 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
3086 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
3087 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
3088 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
3089 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
3090 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
3091 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
3092 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
3093 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
3094 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00003095 } else {
njndbf7ca72006-03-31 11:57:59 +00003096 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-160, 160 );
njn1d0825f2006-03-27 11:37:07 +00003097 }
3098}
3099
sewardj7cf4e6b2008-05-01 20:24:26 +00003100/*--------------- adjustment by N bytes ---------------*/
3101
3102static void mc_new_mem_stack_w_ECU ( Addr a, SizeT len, UInt ecu )
3103{
3104 UInt otag = ecu | MC_OKIND_STACK;
3105 PROF_EVENT(115, "new_mem_stack_w_otag");
3106 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + a, len, otag );
3107}
3108
njn1d0825f2006-03-27 11:37:07 +00003109static void mc_new_mem_stack ( Addr a, SizeT len )
3110{
3111 PROF_EVENT(115, "new_mem_stack");
sewardj7cf4e6b2008-05-01 20:24:26 +00003112 make_mem_undefined ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00003113}
3114
3115static void mc_die_mem_stack ( Addr a, SizeT len )
3116{
3117 PROF_EVENT(125, "die_mem_stack");
njndbf7ca72006-03-31 11:57:59 +00003118 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00003119}
njn9b007f62003-04-07 14:40:25 +00003120
sewardj45d94cc2005-04-20 14:44:11 +00003121
njn1d0825f2006-03-27 11:37:07 +00003122/* The AMD64 ABI says:
3123
3124 "The 128-byte area beyond the location pointed to by %rsp is considered
3125 to be reserved and shall not be modified by signal or interrupt
3126 handlers. Therefore, functions may use this area for temporary data
3127 that is not needed across function calls. In particular, leaf functions
3128 may use this area for their entire stack frame, rather than adjusting
3129 the stack pointer in the prologue and epilogue. This area is known as
3130 red zone [sic]."
3131
3132 So after any call or return we need to mark this redzone as containing
3133 undefined values.
3134
3135 Consider this: we're in function f. f calls g. g moves rsp down
3136 modestly (say 16 bytes) and writes stuff all over the red zone, making it
3137 defined. g returns. f is buggy and reads from parts of the red zone
3138 that it didn't write on. But because g filled that area in, f is going
3139 to be picking up defined V bits and so any errors from reading bits of
3140 the red zone it didn't write, will be missed. The only solution I could
3141 think of was to make the red zone undefined when g returns to f.
3142
3143 This is in accordance with the ABI, which makes it clear the redzone
3144 is volatile across function calls.
3145
3146 The problem occurs the other way round too: f could fill the RZ up
3147 with defined values and g could mistakenly read them. So the RZ
3148 also needs to be nuked on function calls.
3149*/
sewardj7cf4e6b2008-05-01 20:24:26 +00003150
3151
3152/* Here's a simple cache to hold nia -> ECU mappings. It could be
3153 improved so as to have a lower miss rate. */
3154
3155static UWord stats__nia_cache_queries = 0;
3156static UWord stats__nia_cache_misses = 0;
3157
3158typedef
3159 struct { UWord nia0; UWord ecu0; /* nia0 maps to ecu0 */
3160 UWord nia1; UWord ecu1; } /* nia1 maps to ecu1 */
3161 WCacheEnt;
3162
3163#define N_NIA_TO_ECU_CACHE 511
3164
3165static WCacheEnt nia_to_ecu_cache[N_NIA_TO_ECU_CACHE];
3166
3167static void init_nia_to_ecu_cache ( void )
sewardj826ec492005-05-12 18:05:00 +00003168{
sewardj7cf4e6b2008-05-01 20:24:26 +00003169 UWord i;
3170 Addr zero_addr = 0;
3171 ExeContext* zero_ec;
3172 UInt zero_ecu;
3173 /* Fill all the slots with an entry for address zero, and the
3174 relevant otags accordingly. Hence the cache is initially filled
3175 with valid data. */
3176 zero_ec = VG_(make_depth_1_ExeContext_from_Addr)(zero_addr);
3177 tl_assert(zero_ec);
3178 zero_ecu = VG_(get_ECU_from_ExeContext)(zero_ec);
3179 tl_assert(VG_(is_plausible_ECU)(zero_ecu));
3180 for (i = 0; i < N_NIA_TO_ECU_CACHE; i++) {
3181 nia_to_ecu_cache[i].nia0 = zero_addr;
3182 nia_to_ecu_cache[i].ecu0 = zero_ecu;
3183 nia_to_ecu_cache[i].nia1 = zero_addr;
3184 nia_to_ecu_cache[i].ecu1 = zero_ecu;
3185 }
3186}
3187
3188static inline UInt convert_nia_to_ecu ( Addr nia )
3189{
3190 UWord i;
3191 UInt ecu;
3192 ExeContext* ec;
3193
3194 tl_assert( sizeof(nia_to_ecu_cache[0].nia1) == sizeof(nia) );
3195
3196 stats__nia_cache_queries++;
3197 i = nia % N_NIA_TO_ECU_CACHE;
3198 tl_assert(i >= 0 && i < N_NIA_TO_ECU_CACHE);
3199
3200 if (LIKELY( nia_to_ecu_cache[i].nia0 == nia ))
3201 return nia_to_ecu_cache[i].ecu0;
3202
3203 if (LIKELY( nia_to_ecu_cache[i].nia1 == nia )) {
3204# define SWAP(_w1,_w2) { UWord _t = _w1; _w1 = _w2; _w2 = _t; }
3205 SWAP( nia_to_ecu_cache[i].nia0, nia_to_ecu_cache[i].nia1 );
3206 SWAP( nia_to_ecu_cache[i].ecu0, nia_to_ecu_cache[i].ecu1 );
3207# undef SWAP
3208 return nia_to_ecu_cache[i].ecu0;
3209 }
3210
3211 stats__nia_cache_misses++;
3212 ec = VG_(make_depth_1_ExeContext_from_Addr)(nia);
3213 tl_assert(ec);
3214 ecu = VG_(get_ECU_from_ExeContext)(ec);
3215 tl_assert(VG_(is_plausible_ECU)(ecu));
3216
3217 nia_to_ecu_cache[i].nia1 = nia_to_ecu_cache[i].nia0;
3218 nia_to_ecu_cache[i].ecu1 = nia_to_ecu_cache[i].ecu0;
3219
3220 nia_to_ecu_cache[i].nia0 = nia;
3221 nia_to_ecu_cache[i].ecu0 = (UWord)ecu;
3222 return ecu;
3223}
3224
3225
3226/* Note that this serves both the origin-tracking and
3227 no-origin-tracking modes. We assume that calls to it are
3228 sufficiently infrequent that it isn't worth specialising for the
3229 with/without origin-tracking cases. */
3230void MC_(helperc_MAKE_STACK_UNINIT) ( Addr base, UWord len, Addr nia )
3231{
3232 UInt otag;
sewardj826ec492005-05-12 18:05:00 +00003233 tl_assert(sizeof(UWord) == sizeof(SizeT));
sewardj2a3a1a72005-05-12 23:25:43 +00003234 if (0)
barta0b6b2c2008-07-07 06:49:24 +00003235 VG_(printf)("helperc_MAKE_STACK_UNINIT (%#lx,%lu,nia=%#lx)\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00003236 base, len, nia );
3237
3238 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3239 UInt ecu = convert_nia_to_ecu ( nia );
3240 tl_assert(VG_(is_plausible_ECU)(ecu));
3241 otag = ecu | MC_OKIND_STACK;
3242 } else {
3243 tl_assert(nia == 0);
3244 otag = 0;
3245 }
sewardj2a3a1a72005-05-12 23:25:43 +00003246
3247# if 0
3248 /* Really slow version */
sewardj7cf4e6b2008-05-01 20:24:26 +00003249 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003250# endif
3251
3252# if 0
3253 /* Slow(ish) version, which is fairly easily seen to be correct.
3254 */
bart5dd8e6a2008-03-22 08:04:29 +00003255 if (LIKELY( VG_IS_8_ALIGNED(base) && len==128 )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003256 make_aligned_word64_undefined(base + 0, otag);
3257 make_aligned_word64_undefined(base + 8, otag);
3258 make_aligned_word64_undefined(base + 16, otag);
3259 make_aligned_word64_undefined(base + 24, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003260
sewardj7cf4e6b2008-05-01 20:24:26 +00003261 make_aligned_word64_undefined(base + 32, otag);
3262 make_aligned_word64_undefined(base + 40, otag);
3263 make_aligned_word64_undefined(base + 48, otag);
3264 make_aligned_word64_undefined(base + 56, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003265
sewardj7cf4e6b2008-05-01 20:24:26 +00003266 make_aligned_word64_undefined(base + 64, otag);
3267 make_aligned_word64_undefined(base + 72, otag);
3268 make_aligned_word64_undefined(base + 80, otag);
3269 make_aligned_word64_undefined(base + 88, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003270
sewardj7cf4e6b2008-05-01 20:24:26 +00003271 make_aligned_word64_undefined(base + 96, otag);
3272 make_aligned_word64_undefined(base + 104, otag);
3273 make_aligned_word64_undefined(base + 112, otag);
3274 make_aligned_word64_undefined(base + 120, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003275 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003276 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003277 }
3278# endif
3279
3280 /* Idea is: go fast when
3281 * 8-aligned and length is 128
3282 * the sm is available in the main primary map
njn1d0825f2006-03-27 11:37:07 +00003283 * the address range falls entirely with a single secondary map
3284 If all those conditions hold, just update the V+A bits by writing
3285 directly into the vabits array. (If the sm was distinguished, this
3286 will make a copy and then write to it.)
sewardj2a3a1a72005-05-12 23:25:43 +00003287 */
sewardj7cf4e6b2008-05-01 20:24:26 +00003288
bart5dd8e6a2008-03-22 08:04:29 +00003289 if (LIKELY( len == 128 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003290 /* Now we know the address range is suitably sized and aligned. */
3291 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003292 UWord a_hi = (UWord)(base + 128 - 1);
njn1d0825f2006-03-27 11:37:07 +00003293 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003294 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003295 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003296 SecMap* sm = get_secmap_for_writing_low(a_lo);
3297 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2a3a1a72005-05-12 23:25:43 +00003298 /* Now we know that the entire address range falls within a
3299 single secondary map, and that that secondary 'lives' in
3300 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003301 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003302 // Finally, we know that the range is entirely within one secmap.
3303 UWord v_off = SM_OFF(a_lo);
3304 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003305 p[ 0] = VA_BITS16_UNDEFINED;
3306 p[ 1] = VA_BITS16_UNDEFINED;
3307 p[ 2] = VA_BITS16_UNDEFINED;
3308 p[ 3] = VA_BITS16_UNDEFINED;
3309 p[ 4] = VA_BITS16_UNDEFINED;
3310 p[ 5] = VA_BITS16_UNDEFINED;
3311 p[ 6] = VA_BITS16_UNDEFINED;
3312 p[ 7] = VA_BITS16_UNDEFINED;
3313 p[ 8] = VA_BITS16_UNDEFINED;
3314 p[ 9] = VA_BITS16_UNDEFINED;
3315 p[10] = VA_BITS16_UNDEFINED;
3316 p[11] = VA_BITS16_UNDEFINED;
3317 p[12] = VA_BITS16_UNDEFINED;
3318 p[13] = VA_BITS16_UNDEFINED;
3319 p[14] = VA_BITS16_UNDEFINED;
3320 p[15] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003321 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3322 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3323 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3324 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3325 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3326 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3327 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3328 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3329 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3330 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3331 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3332 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3333 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3334 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3335 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3336 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3337 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3338 }
sewardj2a3a1a72005-05-12 23:25:43 +00003339 return;
njn1d0825f2006-03-27 11:37:07 +00003340 }
sewardj2a3a1a72005-05-12 23:25:43 +00003341 }
3342 }
3343
sewardj2e1a6772006-01-18 04:16:27 +00003344 /* 288 bytes (36 ULongs) is the magic value for ELF ppc64. */
bart5dd8e6a2008-03-22 08:04:29 +00003345 if (LIKELY( len == 288 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003346 /* Now we know the address range is suitably sized and aligned. */
3347 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003348 UWord a_hi = (UWord)(base + 288 - 1);
njn1d0825f2006-03-27 11:37:07 +00003349 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003350 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003351 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003352 SecMap* sm = get_secmap_for_writing_low(a_lo);
3353 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2e1a6772006-01-18 04:16:27 +00003354 /* Now we know that the entire address range falls within a
3355 single secondary map, and that that secondary 'lives' in
3356 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003357 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003358 // Finally, we know that the range is entirely within one secmap.
3359 UWord v_off = SM_OFF(a_lo);
3360 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003361 p[ 0] = VA_BITS16_UNDEFINED;
3362 p[ 1] = VA_BITS16_UNDEFINED;
3363 p[ 2] = VA_BITS16_UNDEFINED;
3364 p[ 3] = VA_BITS16_UNDEFINED;
3365 p[ 4] = VA_BITS16_UNDEFINED;
3366 p[ 5] = VA_BITS16_UNDEFINED;
3367 p[ 6] = VA_BITS16_UNDEFINED;
3368 p[ 7] = VA_BITS16_UNDEFINED;
3369 p[ 8] = VA_BITS16_UNDEFINED;
3370 p[ 9] = VA_BITS16_UNDEFINED;
3371 p[10] = VA_BITS16_UNDEFINED;
3372 p[11] = VA_BITS16_UNDEFINED;
3373 p[12] = VA_BITS16_UNDEFINED;
3374 p[13] = VA_BITS16_UNDEFINED;
3375 p[14] = VA_BITS16_UNDEFINED;
3376 p[15] = VA_BITS16_UNDEFINED;
3377 p[16] = VA_BITS16_UNDEFINED;
3378 p[17] = VA_BITS16_UNDEFINED;
3379 p[18] = VA_BITS16_UNDEFINED;
3380 p[19] = VA_BITS16_UNDEFINED;
3381 p[20] = VA_BITS16_UNDEFINED;
3382 p[21] = VA_BITS16_UNDEFINED;
3383 p[22] = VA_BITS16_UNDEFINED;
3384 p[23] = VA_BITS16_UNDEFINED;
3385 p[24] = VA_BITS16_UNDEFINED;
3386 p[25] = VA_BITS16_UNDEFINED;
3387 p[26] = VA_BITS16_UNDEFINED;
3388 p[27] = VA_BITS16_UNDEFINED;
3389 p[28] = VA_BITS16_UNDEFINED;
3390 p[29] = VA_BITS16_UNDEFINED;
3391 p[30] = VA_BITS16_UNDEFINED;
3392 p[31] = VA_BITS16_UNDEFINED;
3393 p[32] = VA_BITS16_UNDEFINED;
3394 p[33] = VA_BITS16_UNDEFINED;
3395 p[34] = VA_BITS16_UNDEFINED;
3396 p[35] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003397 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3398 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3399 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3400 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3401 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3402 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3403 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3404 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3405 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3406 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3407 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3408 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3409 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3410 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3411 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3412 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3413 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3414 set_aligned_word64_Origin_to_undef( base + 8 * 16, otag );
3415 set_aligned_word64_Origin_to_undef( base + 8 * 17, otag );
3416 set_aligned_word64_Origin_to_undef( base + 8 * 18, otag );
3417 set_aligned_word64_Origin_to_undef( base + 8 * 19, otag );
3418 set_aligned_word64_Origin_to_undef( base + 8 * 20, otag );
3419 set_aligned_word64_Origin_to_undef( base + 8 * 21, otag );
3420 set_aligned_word64_Origin_to_undef( base + 8 * 22, otag );
3421 set_aligned_word64_Origin_to_undef( base + 8 * 23, otag );
3422 set_aligned_word64_Origin_to_undef( base + 8 * 24, otag );
3423 set_aligned_word64_Origin_to_undef( base + 8 * 25, otag );
3424 set_aligned_word64_Origin_to_undef( base + 8 * 26, otag );
3425 set_aligned_word64_Origin_to_undef( base + 8 * 27, otag );
3426 set_aligned_word64_Origin_to_undef( base + 8 * 28, otag );
3427 set_aligned_word64_Origin_to_undef( base + 8 * 29, otag );
3428 set_aligned_word64_Origin_to_undef( base + 8 * 30, otag );
3429 set_aligned_word64_Origin_to_undef( base + 8 * 31, otag );
3430 set_aligned_word64_Origin_to_undef( base + 8 * 32, otag );
3431 set_aligned_word64_Origin_to_undef( base + 8 * 33, otag );
3432 set_aligned_word64_Origin_to_undef( base + 8 * 34, otag );
3433 set_aligned_word64_Origin_to_undef( base + 8 * 35, otag );
3434 }
sewardj2e1a6772006-01-18 04:16:27 +00003435 return;
njn1d0825f2006-03-27 11:37:07 +00003436 }
sewardj2e1a6772006-01-18 04:16:27 +00003437 }
3438 }
3439
sewardj2a3a1a72005-05-12 23:25:43 +00003440 /* else fall into slow case */
sewardj7cf4e6b2008-05-01 20:24:26 +00003441 MC_(make_mem_undefined_w_otag)(base, len, otag);
sewardj826ec492005-05-12 18:05:00 +00003442}
3443
3444
nethercote8b76fe52004-11-08 19:20:09 +00003445/*------------------------------------------------------------*/
3446/*--- Checking memory ---*/
3447/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00003448
sewardje4ccc012005-05-02 12:53:38 +00003449typedef
3450 enum {
3451 MC_Ok = 5,
3452 MC_AddrErr = 6,
3453 MC_ValueErr = 7
3454 }
3455 MC_ReadResult;
3456
3457
njn25e49d8e72002-09-23 09:36:25 +00003458/* Check permissions for address range. If inadequate permissions
3459 exist, *bad_addr is set to the offending address, so the caller can
3460 know what it is. */
3461
sewardjecf8e102003-07-12 12:11:39 +00003462/* Returns True if [a .. a+len) is not addressible. Otherwise,
3463 returns False, and if bad_addr is non-NULL, sets *bad_addr to
3464 indicate the lowest failing address. Functions below are
3465 similar. */
njndbf7ca72006-03-31 11:57:59 +00003466Bool MC_(check_mem_is_noaccess) ( Addr a, SizeT len, Addr* bad_addr )
sewardjecf8e102003-07-12 12:11:39 +00003467{
nethercote451eae92004-11-02 13:06:32 +00003468 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003469 UWord vabits2;
3470
njndbf7ca72006-03-31 11:57:59 +00003471 PROF_EVENT(60, "check_mem_is_noaccess");
sewardjecf8e102003-07-12 12:11:39 +00003472 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003473 PROF_EVENT(61, "check_mem_is_noaccess(loop)");
njn1d0825f2006-03-27 11:37:07 +00003474 vabits2 = get_vabits2(a);
3475 if (VA_BITS2_NOACCESS != vabits2) {
3476 if (bad_addr != NULL) *bad_addr = a;
sewardjecf8e102003-07-12 12:11:39 +00003477 return False;
3478 }
3479 a++;
3480 }
3481 return True;
3482}
3483
sewardj7cf4e6b2008-05-01 20:24:26 +00003484static Bool is_mem_addressable ( Addr a, SizeT len,
3485 /*OUT*/Addr* bad_addr )
njn25e49d8e72002-09-23 09:36:25 +00003486{
nethercote451eae92004-11-02 13:06:32 +00003487 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003488 UWord vabits2;
3489
njndbf7ca72006-03-31 11:57:59 +00003490 PROF_EVENT(62, "is_mem_addressable");
njn25e49d8e72002-09-23 09:36:25 +00003491 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003492 PROF_EVENT(63, "is_mem_addressable(loop)");
njn1d0825f2006-03-27 11:37:07 +00003493 vabits2 = get_vabits2(a);
3494 if (VA_BITS2_NOACCESS == vabits2) {
njn25e49d8e72002-09-23 09:36:25 +00003495 if (bad_addr != NULL) *bad_addr = a;
3496 return False;
3497 }
3498 a++;
3499 }
3500 return True;
3501}
3502
sewardj7cf4e6b2008-05-01 20:24:26 +00003503static MC_ReadResult is_mem_defined ( Addr a, SizeT len,
3504 /*OUT*/Addr* bad_addr,
3505 /*OUT*/UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003506{
nethercote451eae92004-11-02 13:06:32 +00003507 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003508 UWord vabits2;
njn25e49d8e72002-09-23 09:36:25 +00003509
njndbf7ca72006-03-31 11:57:59 +00003510 PROF_EVENT(64, "is_mem_defined");
3511 DEBUG("is_mem_defined\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003512
3513 if (otag) *otag = 0;
3514 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003515 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003516 PROF_EVENT(65, "is_mem_defined(loop)");
njn1d0825f2006-03-27 11:37:07 +00003517 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003518 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003519 // Error! Nb: Report addressability errors in preference to
3520 // definedness errors. And don't report definedeness errors unless
3521 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003522 if (bad_addr) {
3523 *bad_addr = a;
3524 }
3525 if (VA_BITS2_NOACCESS == vabits2) {
3526 return MC_AddrErr;
3527 }
3528 if (MC_(clo_mc_level) >= 2) {
3529 if (otag && MC_(clo_mc_level) == 3) {
3530 *otag = MC_(helperc_b_load1)( a );
3531 }
3532 return MC_ValueErr;
3533 }
njn25e49d8e72002-09-23 09:36:25 +00003534 }
3535 a++;
3536 }
nethercote8b76fe52004-11-08 19:20:09 +00003537 return MC_Ok;
njn25e49d8e72002-09-23 09:36:25 +00003538}
3539
3540
3541/* Check a zero-terminated ascii string. Tricky -- don't want to
3542 examine the actual bytes, to find the end, until we're sure it is
3543 safe to do so. */
3544
sewardj7cf4e6b2008-05-01 20:24:26 +00003545static Bool mc_is_defined_asciiz ( Addr a, Addr* bad_addr, UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003546{
njn1d0825f2006-03-27 11:37:07 +00003547 UWord vabits2;
3548
njndbf7ca72006-03-31 11:57:59 +00003549 PROF_EVENT(66, "mc_is_defined_asciiz");
3550 DEBUG("mc_is_defined_asciiz\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003551
3552 if (otag) *otag = 0;
3553 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003554 while (True) {
njndbf7ca72006-03-31 11:57:59 +00003555 PROF_EVENT(67, "mc_is_defined_asciiz(loop)");
njn1d0825f2006-03-27 11:37:07 +00003556 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003557 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003558 // Error! Nb: Report addressability errors in preference to
3559 // definedness errors. And don't report definedeness errors unless
3560 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003561 if (bad_addr) {
3562 *bad_addr = a;
3563 }
3564 if (VA_BITS2_NOACCESS == vabits2) {
3565 return MC_AddrErr;
3566 }
3567 if (MC_(clo_mc_level) >= 2) {
3568 if (otag && MC_(clo_mc_level) == 3) {
3569 *otag = MC_(helperc_b_load1)( a );
3570 }
3571 return MC_ValueErr;
3572 }
njn25e49d8e72002-09-23 09:36:25 +00003573 }
3574 /* Ok, a is safe to read. */
njn1d0825f2006-03-27 11:37:07 +00003575 if (* ((UChar*)a) == 0) {
sewardj45d94cc2005-04-20 14:44:11 +00003576 return MC_Ok;
njn1d0825f2006-03-27 11:37:07 +00003577 }
njn25e49d8e72002-09-23 09:36:25 +00003578 a++;
3579 }
3580}
3581
3582
3583/*------------------------------------------------------------*/
3584/*--- Memory event handlers ---*/
3585/*------------------------------------------------------------*/
3586
njn25e49d8e72002-09-23 09:36:25 +00003587static
njndbf7ca72006-03-31 11:57:59 +00003588void check_mem_is_addressable ( CorePart part, ThreadId tid, Char* s,
3589 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003590{
njn25e49d8e72002-09-23 09:36:25 +00003591 Addr bad_addr;
njndbf7ca72006-03-31 11:57:59 +00003592 Bool ok = is_mem_addressable ( base, size, &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003593
njn25e49d8e72002-09-23 09:36:25 +00003594 if (!ok) {
3595 switch (part) {
3596 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003597 MC_(record_memparam_error) ( tid, bad_addr,
3598 /*isAddrErr*/True, s, 0/*otag*/ );
njn25e49d8e72002-09-23 09:36:25 +00003599 break;
3600
njn25e49d8e72002-09-23 09:36:25 +00003601 case Vg_CoreSignal:
sewardj7ce71662008-05-02 10:33:15 +00003602 MC_(record_core_mem_error)( tid, /*isAddrErr*/True, s );
njn25e49d8e72002-09-23 09:36:25 +00003603 break;
3604
3605 default:
njndbf7ca72006-03-31 11:57:59 +00003606 VG_(tool_panic)("check_mem_is_addressable: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003607 }
3608 }
njn25e49d8e72002-09-23 09:36:25 +00003609}
3610
3611static
njndbf7ca72006-03-31 11:57:59 +00003612void check_mem_is_defined ( CorePart part, ThreadId tid, Char* s,
nethercote451eae92004-11-02 13:06:32 +00003613 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003614{
sewardj7cf4e6b2008-05-01 20:24:26 +00003615 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003616 Addr bad_addr;
sewardj7cf4e6b2008-05-01 20:24:26 +00003617 MC_ReadResult res = is_mem_defined ( base, size, &bad_addr, &otag );
sewardj45f4e7c2005-09-27 19:20:21 +00003618
nethercote8b76fe52004-11-08 19:20:09 +00003619 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003620 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj45f4e7c2005-09-27 19:20:21 +00003621
njn25e49d8e72002-09-23 09:36:25 +00003622 switch (part) {
3623 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003624 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3625 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003626 break;
3627
njn25e49d8e72002-09-23 09:36:25 +00003628 /* If we're being asked to jump to a silly address, record an error
3629 message before potentially crashing the entire system. */
3630 case Vg_CoreTranslate:
sewardj7ce71662008-05-02 10:33:15 +00003631 MC_(record_jump_error)( tid, bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003632 break;
3633
3634 default:
njndbf7ca72006-03-31 11:57:59 +00003635 VG_(tool_panic)("check_mem_is_defined: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003636 }
3637 }
njn25e49d8e72002-09-23 09:36:25 +00003638}
3639
3640static
njndbf7ca72006-03-31 11:57:59 +00003641void check_mem_is_defined_asciiz ( CorePart part, ThreadId tid,
njn5c004e42002-11-18 11:04:50 +00003642 Char* s, Addr str )
njn25e49d8e72002-09-23 09:36:25 +00003643{
nethercote8b76fe52004-11-08 19:20:09 +00003644 MC_ReadResult res;
njn5ab96ac2005-05-08 02:59:50 +00003645 Addr bad_addr = 0; // shut GCC up
sewardj7cf4e6b2008-05-01 20:24:26 +00003646 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003647
njnca82cc02004-11-22 17:18:48 +00003648 tl_assert(part == Vg_CoreSysCall);
sewardj7cf4e6b2008-05-01 20:24:26 +00003649 res = mc_is_defined_asciiz ( (Addr)str, &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00003650 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003651 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj7ce71662008-05-02 10:33:15 +00003652 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3653 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003654 }
njn25e49d8e72002-09-23 09:36:25 +00003655}
3656
njn25e49d8e72002-09-23 09:36:25 +00003657static
sewardj9c606bd2008-09-18 18:12:50 +00003658void mc_new_mem_startup( Addr a, SizeT len,
3659 Bool rr, Bool ww, Bool xx, ULong di_handle )
njn25e49d8e72002-09-23 09:36:25 +00003660{
njndbf7ca72006-03-31 11:57:59 +00003661 /* Ignore the permissions, just make it defined. Seems to work... */
njnba7b4582006-09-21 15:59:30 +00003662 // Because code is defined, initialised variables get put in the data
3663 // segment and are defined, and uninitialised variables get put in the
3664 // bss segment and are auto-zeroed (and so defined).
3665 //
3666 // It's possible that there will be padding between global variables.
3667 // This will also be auto-zeroed, and marked as defined by Memcheck. If
3668 // a program uses it, Memcheck will not complain. This is arguably a
3669 // false negative, but it's a grey area -- the behaviour is defined (the
3670 // padding is zeroed) but it's probably not what the user intended. And
3671 // we can't avoid it.
barta0b6b2c2008-07-07 06:49:24 +00003672 DEBUG("mc_new_mem_startup(%#lx, %llu, rr=%u, ww=%u, xx=%u)\n",
njndbf7ca72006-03-31 11:57:59 +00003673 a, (ULong)len, rr, ww, xx);
3674 MC_(make_mem_defined)(a, len);
njn25e49d8e72002-09-23 09:36:25 +00003675}
3676
3677static
sewardj9c606bd2008-09-18 18:12:50 +00003678void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
3679 ULong di_handle )
njn25e49d8e72002-09-23 09:36:25 +00003680{
njndbf7ca72006-03-31 11:57:59 +00003681 MC_(make_mem_defined)(a, len);
njn25e49d8e72002-09-23 09:36:25 +00003682}
3683
njncf45fd42004-11-24 16:30:22 +00003684static
3685void mc_post_mem_write(CorePart part, ThreadId tid, Addr a, SizeT len)
3686{
njndbf7ca72006-03-31 11:57:59 +00003687 MC_(make_mem_defined)(a, len);
njncf45fd42004-11-24 16:30:22 +00003688}
njn25e49d8e72002-09-23 09:36:25 +00003689
sewardj45d94cc2005-04-20 14:44:11 +00003690
njn25e49d8e72002-09-23 09:36:25 +00003691/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00003692/*--- Register event handlers ---*/
3693/*------------------------------------------------------------*/
3694
sewardj7cf4e6b2008-05-01 20:24:26 +00003695/* Try and get a nonzero origin for the guest state section of thread
3696 tid characterised by (offset,size). Return 0 if nothing to show
3697 for it. */
3698static UInt mb_get_origin_for_guest_offset ( ThreadId tid,
3699 Int offset, SizeT size )
3700{
3701 Int sh2off;
3702 UChar area[6];
3703 UInt otag;
3704 sh2off = MC_(get_otrack_shadow_offset)( offset, size );
3705 if (sh2off == -1)
3706 return 0; /* This piece of guest state is not tracked */
3707 tl_assert(sh2off >= 0);
3708 tl_assert(0 == (sh2off % 4));
3709 area[0] = 0x31;
3710 area[5] = 0x27;
3711 VG_(get_shadow_regs_area)( tid, &area[1], 2/*shadowno*/,sh2off,4 );
3712 tl_assert(area[0] == 0x31);
3713 tl_assert(area[5] == 0x27);
3714 otag = *(UInt*)&area[1];
3715 return otag;
3716}
3717
3718
sewardj45d94cc2005-04-20 14:44:11 +00003719/* When some chunk of guest state is written, mark the corresponding
3720 shadow area as valid. This is used to initialise arbitrarily large
sewardj62eae5f2006-01-17 01:58:24 +00003721 chunks of guest state, hence the _SIZE value, which has to be as
3722 big as the biggest guest state.
sewardj45d94cc2005-04-20 14:44:11 +00003723*/
3724static void mc_post_reg_write ( CorePart part, ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00003725 PtrdiffT offset, SizeT size)
njnd3040452003-05-19 15:04:06 +00003726{
sewardj05a46732006-10-17 01:28:10 +00003727# define MAX_REG_WRITE_SIZE 1408
cerion21082042005-12-06 19:07:08 +00003728 UChar area[MAX_REG_WRITE_SIZE];
3729 tl_assert(size <= MAX_REG_WRITE_SIZE);
njn1d0825f2006-03-27 11:37:07 +00003730 VG_(memset)(area, V_BITS8_DEFINED, size);
sewardj7cf4e6b2008-05-01 20:24:26 +00003731 VG_(set_shadow_regs_area)( tid, 1/*shadowNo*/,offset,size, area );
cerion21082042005-12-06 19:07:08 +00003732# undef MAX_REG_WRITE_SIZE
njnd3040452003-05-19 15:04:06 +00003733}
3734
sewardj45d94cc2005-04-20 14:44:11 +00003735static
3736void mc_post_reg_write_clientcall ( ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00003737 PtrdiffT offset, SizeT size, Addr f)
njnd3040452003-05-19 15:04:06 +00003738{
njncf45fd42004-11-24 16:30:22 +00003739 mc_post_reg_write(/*dummy*/0, tid, offset, size);
njnd3040452003-05-19 15:04:06 +00003740}
3741
sewardj45d94cc2005-04-20 14:44:11 +00003742/* Look at the definedness of the guest's shadow state for
3743 [offset, offset+len). If any part of that is undefined, record
3744 a parameter error.
3745*/
3746static void mc_pre_reg_read ( CorePart part, ThreadId tid, Char* s,
njnc4431bf2009-01-15 21:29:24 +00003747 PtrdiffT offset, SizeT size)
nethercote8b76fe52004-11-08 19:20:09 +00003748{
sewardj45d94cc2005-04-20 14:44:11 +00003749 Int i;
3750 Bool bad;
sewardj7cf4e6b2008-05-01 20:24:26 +00003751 UInt otag;
sewardj45d94cc2005-04-20 14:44:11 +00003752
3753 UChar area[16];
3754 tl_assert(size <= 16);
3755
sewardj7cf4e6b2008-05-01 20:24:26 +00003756 VG_(get_shadow_regs_area)( tid, area, 1/*shadowNo*/,offset,size );
sewardj45d94cc2005-04-20 14:44:11 +00003757
3758 bad = False;
3759 for (i = 0; i < size; i++) {
njn1d0825f2006-03-27 11:37:07 +00003760 if (area[i] != V_BITS8_DEFINED) {
sewardj2c27f702005-05-03 18:19:05 +00003761 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00003762 break;
3763 }
nethercote8b76fe52004-11-08 19:20:09 +00003764 }
3765
sewardj7cf4e6b2008-05-01 20:24:26 +00003766 if (!bad)
3767 return;
3768
3769 /* We've found some undefinedness. See if we can also find an
3770 origin for it. */
3771 otag = mb_get_origin_for_guest_offset( tid, offset, size );
sewardj7ce71662008-05-02 10:33:15 +00003772 MC_(record_regparam_error) ( tid, s, otag );
nethercote8b76fe52004-11-08 19:20:09 +00003773}
njnd3040452003-05-19 15:04:06 +00003774
njn25e49d8e72002-09-23 09:36:25 +00003775
sewardj6cf40ff2005-04-20 22:31:26 +00003776/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00003777/*--- Functions called directly from generated code: ---*/
3778/*--- Load/store handlers. ---*/
sewardj6cf40ff2005-04-20 22:31:26 +00003779/*------------------------------------------------------------*/
3780
njn1d0825f2006-03-27 11:37:07 +00003781/* Types: LOADV32, LOADV16, LOADV8 are:
sewardj6cf40ff2005-04-20 22:31:26 +00003782 UWord fn ( Addr a )
3783 so they return 32-bits on 32-bit machines and 64-bits on
3784 64-bit machines. Addr has the same size as a host word.
3785
njn1d0825f2006-03-27 11:37:07 +00003786 LOADV64 is always ULong fn ( Addr a )
sewardj6cf40ff2005-04-20 22:31:26 +00003787
njn1d0825f2006-03-27 11:37:07 +00003788 Similarly for STOREV8, STOREV16, STOREV32, the supplied vbits
3789 are a UWord, and for STOREV64 they are a ULong.
sewardj6cf40ff2005-04-20 22:31:26 +00003790*/
3791
sewardj7244e712008-05-02 12:35:48 +00003792/* If any part of '_a' indicated by the mask is 1, either '_a' is not
3793 naturally '_sz/8'-aligned, or it exceeds the range covered by the
3794 primary map. This is all very tricky (and important!), so let's
3795 work through the maths by hand (below), *and* assert for these
3796 values at startup. */
3797#define MASK(_szInBytes) \
3798 ( ~((0x10000UL-(_szInBytes)) | ((N_PRIMARY_MAP-1) << 16)) )
3799
3800/* MASK only exists so as to define this macro. */
3801#define UNALIGNED_OR_HIGH(_a,_szInBits) \
3802 ((_a) & MASK((_szInBits>>3)))
3803
3804/* On a 32-bit machine:
3805
3806 N_PRIMARY_BITS == 16, so
3807 N_PRIMARY_MAP == 0x10000, so
3808 N_PRIMARY_MAP-1 == 0xFFFF, so
3809 (N_PRIMARY_MAP-1) << 16 == 0xFFFF0000, and so
3810
3811 MASK(1) = ~ ( (0x10000 - 1) | 0xFFFF0000 )
3812 = ~ ( 0xFFFF | 0xFFFF0000 )
3813 = ~ 0xFFFF'FFFF
3814 = 0
3815
3816 MASK(2) = ~ ( (0x10000 - 2) | 0xFFFF0000 )
3817 = ~ ( 0xFFFE | 0xFFFF0000 )
3818 = ~ 0xFFFF'FFFE
3819 = 1
3820
3821 MASK(4) = ~ ( (0x10000 - 4) | 0xFFFF0000 )
3822 = ~ ( 0xFFFC | 0xFFFF0000 )
3823 = ~ 0xFFFF'FFFC
3824 = 3
3825
3826 MASK(8) = ~ ( (0x10000 - 8) | 0xFFFF0000 )
3827 = ~ ( 0xFFF8 | 0xFFFF0000 )
3828 = ~ 0xFFFF'FFF8
3829 = 7
3830
3831 Hence in the 32-bit case, "a & MASK(1/2/4/8)" is a nonzero value
3832 precisely when a is not 1/2/4/8-bytes aligned. And obviously, for
3833 the 1-byte alignment case, it is always a zero value, since MASK(1)
3834 is zero. All as expected.
3835
3836 On a 64-bit machine, it's more complex, since we're testing
3837 simultaneously for misalignment and for the address being at or
3838 above 32G:
3839
3840 N_PRIMARY_BITS == 19, so
3841 N_PRIMARY_MAP == 0x80000, so
3842 N_PRIMARY_MAP-1 == 0x7FFFF, so
3843 (N_PRIMARY_MAP-1) << 16 == 0x7FFFF'0000, and so
3844
3845 MASK(1) = ~ ( (0x10000 - 1) | 0x7FFFF'0000 )
3846 = ~ ( 0xFFFF | 0x7FFFF'0000 )
3847 = ~ 0x7FFFF'FFFF
3848 = 0xFFFF'FFF8'0000'0000
3849
3850 MASK(2) = ~ ( (0x10000 - 2) | 0x7FFFF'0000 )
3851 = ~ ( 0xFFFE | 0x7FFFF'0000 )
3852 = ~ 0x7FFFF'FFFE
3853 = 0xFFFF'FFF8'0000'0001
3854
3855 MASK(4) = ~ ( (0x10000 - 4) | 0x7FFFF'0000 )
3856 = ~ ( 0xFFFC | 0x7FFFF'0000 )
3857 = ~ 0x7FFFF'FFFC
3858 = 0xFFFF'FFF8'0000'0003
3859
3860 MASK(8) = ~ ( (0x10000 - 8) | 0x7FFFF'0000 )
3861 = ~ ( 0xFFF8 | 0x7FFFF'0000 )
3862 = ~ 0x7FFFF'FFF8
3863 = 0xFFFF'FFF8'0000'0007
3864*/
njn1d0825f2006-03-27 11:37:07 +00003865
3866
sewardj95448072004-11-22 20:19:51 +00003867/* ------------------------ Size = 8 ------------------------ */
3868
njn1d0825f2006-03-27 11:37:07 +00003869static INLINE
3870ULong mc_LOADV64 ( Addr a, Bool isBigEndian )
3871{
3872 UWord sm_off16, vabits16;
3873 SecMap* sm;
3874
3875 PROF_EVENT(200, "mc_LOADV64");
3876
3877#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00003878 return mc_LOADVn_slow( a, 64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003879#else
bart5dd8e6a2008-03-22 08:04:29 +00003880 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
njn1d0825f2006-03-27 11:37:07 +00003881 PROF_EVENT(201, "mc_LOADV64-slow1");
njn45e81252006-03-28 12:35:08 +00003882 return (ULong)mc_LOADVn_slow( a, 64, isBigEndian );
sewardjf9d81612005-04-23 23:25:49 +00003883 }
3884
njna7c7ebd2006-03-28 12:51:02 +00003885 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003886 sm_off16 = SM_OFF_16(a);
3887 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
3888
3889 // Handle common case quickly: a is suitably aligned, is mapped, and
3890 // addressible.
3891 // Convert V bits from compact memory form to expanded register form.
bart5dd8e6a2008-03-22 08:04:29 +00003892 if (LIKELY(vabits16 == VA_BITS16_DEFINED)) {
njn1d0825f2006-03-27 11:37:07 +00003893 return V_BITS64_DEFINED;
bart5dd8e6a2008-03-22 08:04:29 +00003894 } else if (LIKELY(vabits16 == VA_BITS16_UNDEFINED)) {
njn1d0825f2006-03-27 11:37:07 +00003895 return V_BITS64_UNDEFINED;
3896 } else {
njndbf7ca72006-03-31 11:57:59 +00003897 /* Slow case: the 8 bytes are not all-defined or all-undefined. */
njn1d0825f2006-03-27 11:37:07 +00003898 PROF_EVENT(202, "mc_LOADV64-slow2");
njn45e81252006-03-28 12:35:08 +00003899 return mc_LOADVn_slow( a, 64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003900 }
3901#endif
3902}
3903
3904VG_REGPARM(1) ULong MC_(helperc_LOADV64be) ( Addr a )
3905{
3906 return mc_LOADV64(a, True);
3907}
3908VG_REGPARM(1) ULong MC_(helperc_LOADV64le) ( Addr a )
3909{
3910 return mc_LOADV64(a, False);
3911}
sewardjf9d81612005-04-23 23:25:49 +00003912
sewardjf9d81612005-04-23 23:25:49 +00003913
njn1d0825f2006-03-27 11:37:07 +00003914static INLINE
njn4cf530b2006-04-06 13:33:48 +00003915void mc_STOREV64 ( Addr a, ULong vbits64, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00003916{
3917 UWord sm_off16, vabits16;
3918 SecMap* sm;
3919
3920 PROF_EVENT(210, "mc_STOREV64");
3921
3922#ifndef PERF_FAST_STOREV
3923 // XXX: this slow case seems to be marginally faster than the fast case!
3924 // Investigate further.
njn4cf530b2006-04-06 13:33:48 +00003925 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003926#else
bart5dd8e6a2008-03-22 08:04:29 +00003927 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
njn1d0825f2006-03-27 11:37:07 +00003928 PROF_EVENT(211, "mc_STOREV64-slow1");
njn4cf530b2006-04-06 13:33:48 +00003929 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003930 return;
sewardjf9d81612005-04-23 23:25:49 +00003931 }
3932
njna7c7ebd2006-03-28 12:51:02 +00003933 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003934 sm_off16 = SM_OFF_16(a);
3935 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
3936
bart5dd8e6a2008-03-22 08:04:29 +00003937 if (LIKELY( !is_distinguished_sm(sm) &&
njndbf7ca72006-03-31 11:57:59 +00003938 (VA_BITS16_DEFINED == vabits16 ||
3939 VA_BITS16_UNDEFINED == vabits16) ))
njn1d0825f2006-03-27 11:37:07 +00003940 {
3941 /* Handle common case quickly: a is suitably aligned, */
3942 /* is mapped, and is addressible. */
3943 // Convert full V-bits in register to compact 2-bit form.
njn4cf530b2006-04-06 13:33:48 +00003944 if (V_BITS64_DEFINED == vbits64) {
njndbf7ca72006-03-31 11:57:59 +00003945 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_DEFINED;
njn4cf530b2006-04-06 13:33:48 +00003946 } else if (V_BITS64_UNDEFINED == vbits64) {
njndbf7ca72006-03-31 11:57:59 +00003947 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_UNDEFINED;
njn1d0825f2006-03-27 11:37:07 +00003948 } else {
3949 /* Slow but general case -- writing partially defined bytes. */
3950 PROF_EVENT(212, "mc_STOREV64-slow2");
njn4cf530b2006-04-06 13:33:48 +00003951 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003952 }
3953 } else {
3954 /* Slow but general case. */
3955 PROF_EVENT(213, "mc_STOREV64-slow3");
njn4cf530b2006-04-06 13:33:48 +00003956 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003957 }
3958#endif
3959}
3960
njn4cf530b2006-04-06 13:33:48 +00003961VG_REGPARM(1) void MC_(helperc_STOREV64be) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00003962{
njn4cf530b2006-04-06 13:33:48 +00003963 mc_STOREV64(a, vbits64, True);
njn1d0825f2006-03-27 11:37:07 +00003964}
njn4cf530b2006-04-06 13:33:48 +00003965VG_REGPARM(1) void MC_(helperc_STOREV64le) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00003966{
njn4cf530b2006-04-06 13:33:48 +00003967 mc_STOREV64(a, vbits64, False);
njn1d0825f2006-03-27 11:37:07 +00003968}
sewardj95448072004-11-22 20:19:51 +00003969
sewardj95448072004-11-22 20:19:51 +00003970
3971/* ------------------------ Size = 4 ------------------------ */
3972
njn1d0825f2006-03-27 11:37:07 +00003973static INLINE
3974UWord mc_LOADV32 ( Addr a, Bool isBigEndian )
3975{
3976 UWord sm_off, vabits8;
3977 SecMap* sm;
3978
3979 PROF_EVENT(220, "mc_LOADV32");
3980
3981#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00003982 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003983#else
bart5dd8e6a2008-03-22 08:04:29 +00003984 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
njn1d0825f2006-03-27 11:37:07 +00003985 PROF_EVENT(221, "mc_LOADV32-slow1");
njn45e81252006-03-28 12:35:08 +00003986 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
sewardjc1a2cda2005-04-21 17:34:00 +00003987 }
3988
njna7c7ebd2006-03-28 12:51:02 +00003989 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003990 sm_off = SM_OFF(a);
3991 vabits8 = sm->vabits8[sm_off];
3992
3993 // Handle common case quickly: a is suitably aligned, is mapped, and the
3994 // entire word32 it lives in is addressible.
3995 // Convert V bits from compact memory form to expanded register form.
3996 // For 64-bit platforms, set the high 32 bits of retval to 1 (undefined).
3997 // Almost certainly not necessary, but be paranoid.
bart5dd8e6a2008-03-22 08:04:29 +00003998 if (LIKELY(vabits8 == VA_BITS8_DEFINED)) {
njn1d0825f2006-03-27 11:37:07 +00003999 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_DEFINED);
bart5dd8e6a2008-03-22 08:04:29 +00004000 } else if (LIKELY(vabits8 == VA_BITS8_UNDEFINED)) {
njn1d0825f2006-03-27 11:37:07 +00004001 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_UNDEFINED);
4002 } else {
njndbf7ca72006-03-31 11:57:59 +00004003 /* Slow case: the 4 bytes are not all-defined or all-undefined. */
njn1d0825f2006-03-27 11:37:07 +00004004 PROF_EVENT(222, "mc_LOADV32-slow2");
njn45e81252006-03-28 12:35:08 +00004005 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004006 }
4007#endif
4008}
4009
4010VG_REGPARM(1) UWord MC_(helperc_LOADV32be) ( Addr a )
4011{
4012 return mc_LOADV32(a, True);
4013}
4014VG_REGPARM(1) UWord MC_(helperc_LOADV32le) ( Addr a )
4015{
4016 return mc_LOADV32(a, False);
4017}
sewardjc1a2cda2005-04-21 17:34:00 +00004018
sewardjc1a2cda2005-04-21 17:34:00 +00004019
njn1d0825f2006-03-27 11:37:07 +00004020static INLINE
njn4cf530b2006-04-06 13:33:48 +00004021void mc_STOREV32 ( Addr a, UWord vbits32, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004022{
4023 UWord sm_off, vabits8;
4024 SecMap* sm;
4025
4026 PROF_EVENT(230, "mc_STOREV32");
4027
4028#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004029 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004030#else
bart5dd8e6a2008-03-22 08:04:29 +00004031 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
njn1d0825f2006-03-27 11:37:07 +00004032 PROF_EVENT(231, "mc_STOREV32-slow1");
njn4cf530b2006-04-06 13:33:48 +00004033 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004034 return;
sewardjc1a2cda2005-04-21 17:34:00 +00004035 }
4036
njna7c7ebd2006-03-28 12:51:02 +00004037 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00004038 sm_off = SM_OFF(a);
4039 vabits8 = sm->vabits8[sm_off];
4040
njn1d0825f2006-03-27 11:37:07 +00004041 // Cleverness: sometimes we don't have to write the shadow memory at
4042 // all, if we can tell that what we want to write is the same as what is
sewardjb6a4ece2008-05-03 05:24:57 +00004043 // already there. The 64/16/8 bit cases also have cleverness at this
4044 // point, but it works a little differently to the code below.
njn4cf530b2006-04-06 13:33:48 +00004045 if (V_BITS32_DEFINED == vbits32) {
njndbf7ca72006-03-31 11:57:59 +00004046 if (vabits8 == (UInt)VA_BITS8_DEFINED) {
njn1d0825f2006-03-27 11:37:07 +00004047 return;
njndbf7ca72006-03-31 11:57:59 +00004048 } else if (!is_distinguished_sm(sm) && VA_BITS8_UNDEFINED == vabits8) {
4049 sm->vabits8[sm_off] = (UInt)VA_BITS8_DEFINED;
njn1d0825f2006-03-27 11:37:07 +00004050 } else {
njndbf7ca72006-03-31 11:57:59 +00004051 // not defined/undefined, or distinguished and changing state
njn1d0825f2006-03-27 11:37:07 +00004052 PROF_EVENT(232, "mc_STOREV32-slow2");
njn4cf530b2006-04-06 13:33:48 +00004053 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004054 }
njn4cf530b2006-04-06 13:33:48 +00004055 } else if (V_BITS32_UNDEFINED == vbits32) {
njndbf7ca72006-03-31 11:57:59 +00004056 if (vabits8 == (UInt)VA_BITS8_UNDEFINED) {
njn1d0825f2006-03-27 11:37:07 +00004057 return;
njndbf7ca72006-03-31 11:57:59 +00004058 } else if (!is_distinguished_sm(sm) && VA_BITS8_DEFINED == vabits8) {
4059 sm->vabits8[sm_off] = (UInt)VA_BITS8_UNDEFINED;
njn1d0825f2006-03-27 11:37:07 +00004060 } else {
njndbf7ca72006-03-31 11:57:59 +00004061 // not defined/undefined, or distinguished and changing state
njn1d0825f2006-03-27 11:37:07 +00004062 PROF_EVENT(233, "mc_STOREV32-slow3");
njn4cf530b2006-04-06 13:33:48 +00004063 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004064 }
4065 } else {
4066 // Partially defined word
4067 PROF_EVENT(234, "mc_STOREV32-slow4");
njn4cf530b2006-04-06 13:33:48 +00004068 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004069 }
njn1d0825f2006-03-27 11:37:07 +00004070#endif
4071}
4072
njn4cf530b2006-04-06 13:33:48 +00004073VG_REGPARM(2) void MC_(helperc_STOREV32be) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00004074{
njn4cf530b2006-04-06 13:33:48 +00004075 mc_STOREV32(a, vbits32, True);
njn1d0825f2006-03-27 11:37:07 +00004076}
njn4cf530b2006-04-06 13:33:48 +00004077VG_REGPARM(2) void MC_(helperc_STOREV32le) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00004078{
njn4cf530b2006-04-06 13:33:48 +00004079 mc_STOREV32(a, vbits32, False);
njn1d0825f2006-03-27 11:37:07 +00004080}
njn25e49d8e72002-09-23 09:36:25 +00004081
njn25e49d8e72002-09-23 09:36:25 +00004082
sewardj95448072004-11-22 20:19:51 +00004083/* ------------------------ Size = 2 ------------------------ */
4084
njn1d0825f2006-03-27 11:37:07 +00004085static INLINE
4086UWord mc_LOADV16 ( Addr a, Bool isBigEndian )
4087{
4088 UWord sm_off, vabits8;
4089 SecMap* sm;
4090
4091 PROF_EVENT(240, "mc_LOADV16");
4092
4093#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004094 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004095#else
bart5dd8e6a2008-03-22 08:04:29 +00004096 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
njn1d0825f2006-03-27 11:37:07 +00004097 PROF_EVENT(241, "mc_LOADV16-slow1");
njn45e81252006-03-28 12:35:08 +00004098 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
sewardjc1a2cda2005-04-21 17:34:00 +00004099 }
4100
njna7c7ebd2006-03-28 12:51:02 +00004101 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00004102 sm_off = SM_OFF(a);
4103 vabits8 = sm->vabits8[sm_off];
4104 // Handle common case quickly: a is suitably aligned, is mapped, and is
4105 // addressible.
4106 // Convert V bits from compact memory form to expanded register form
njndbf7ca72006-03-31 11:57:59 +00004107 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS16_DEFINED; }
4108 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS16_UNDEFINED; }
njn1d0825f2006-03-27 11:37:07 +00004109 else {
njndbf7ca72006-03-31 11:57:59 +00004110 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
njn1d0825f2006-03-27 11:37:07 +00004111 // the two sub-bytes.
4112 UChar vabits4 = extract_vabits4_from_vabits8(a, vabits8);
njndbf7ca72006-03-31 11:57:59 +00004113 if (vabits4 == VA_BITS4_DEFINED ) { return V_BITS16_DEFINED; }
4114 else if (vabits4 == VA_BITS4_UNDEFINED) { return V_BITS16_UNDEFINED; }
njn1d0825f2006-03-27 11:37:07 +00004115 else {
njndbf7ca72006-03-31 11:57:59 +00004116 /* Slow case: the two bytes are not all-defined or all-undefined. */
njn1d0825f2006-03-27 11:37:07 +00004117 PROF_EVENT(242, "mc_LOADV16-slow2");
njn45e81252006-03-28 12:35:08 +00004118 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004119 }
4120 }
4121#endif
4122}
4123
4124VG_REGPARM(1) UWord MC_(helperc_LOADV16be) ( Addr a )
4125{
4126 return mc_LOADV16(a, True);
4127}
4128VG_REGPARM(1) UWord MC_(helperc_LOADV16le) ( Addr a )
4129{
4130 return mc_LOADV16(a, False);
4131}
sewardjc1a2cda2005-04-21 17:34:00 +00004132
sewardjc1a2cda2005-04-21 17:34:00 +00004133
njn1d0825f2006-03-27 11:37:07 +00004134static INLINE
njn4cf530b2006-04-06 13:33:48 +00004135void mc_STOREV16 ( Addr a, UWord vbits16, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004136{
4137 UWord sm_off, vabits8;
4138 SecMap* sm;
4139
4140 PROF_EVENT(250, "mc_STOREV16");
4141
4142#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004143 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004144#else
bart5dd8e6a2008-03-22 08:04:29 +00004145 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
njn1d0825f2006-03-27 11:37:07 +00004146 PROF_EVENT(251, "mc_STOREV16-slow1");
njn4cf530b2006-04-06 13:33:48 +00004147 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004148 return;
sewardjc1a2cda2005-04-21 17:34:00 +00004149 }
4150
njna7c7ebd2006-03-28 12:51:02 +00004151 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00004152 sm_off = SM_OFF(a);
4153 vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00004154 if (LIKELY( !is_distinguished_sm(sm) &&
njndbf7ca72006-03-31 11:57:59 +00004155 (VA_BITS8_DEFINED == vabits8 ||
4156 VA_BITS8_UNDEFINED == vabits8) ))
njn1d0825f2006-03-27 11:37:07 +00004157 {
4158 /* Handle common case quickly: a is suitably aligned, */
4159 /* is mapped, and is addressible. */
4160 // Convert full V-bits in register to compact 2-bit form.
njn4cf530b2006-04-06 13:33:48 +00004161 if (V_BITS16_DEFINED == vbits16) {
njndbf7ca72006-03-31 11:57:59 +00004162 insert_vabits4_into_vabits8( a, VA_BITS4_DEFINED ,
njn1d0825f2006-03-27 11:37:07 +00004163 &(sm->vabits8[sm_off]) );
njn4cf530b2006-04-06 13:33:48 +00004164 } else if (V_BITS16_UNDEFINED == vbits16) {
njndbf7ca72006-03-31 11:57:59 +00004165 insert_vabits4_into_vabits8( a, VA_BITS4_UNDEFINED,
njn1d0825f2006-03-27 11:37:07 +00004166 &(sm->vabits8[sm_off]) );
4167 } else {
4168 /* Slow but general case -- writing partially defined bytes. */
4169 PROF_EVENT(252, "mc_STOREV16-slow2");
njn4cf530b2006-04-06 13:33:48 +00004170 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004171 }
4172 } else {
4173 /* Slow but general case. */
4174 PROF_EVENT(253, "mc_STOREV16-slow3");
njn4cf530b2006-04-06 13:33:48 +00004175 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004176 }
4177#endif
4178}
njn25e49d8e72002-09-23 09:36:25 +00004179
njn4cf530b2006-04-06 13:33:48 +00004180VG_REGPARM(2) void MC_(helperc_STOREV16be) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00004181{
njn4cf530b2006-04-06 13:33:48 +00004182 mc_STOREV16(a, vbits16, True);
njn1d0825f2006-03-27 11:37:07 +00004183}
njn4cf530b2006-04-06 13:33:48 +00004184VG_REGPARM(2) void MC_(helperc_STOREV16le) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00004185{
njn4cf530b2006-04-06 13:33:48 +00004186 mc_STOREV16(a, vbits16, False);
njn1d0825f2006-03-27 11:37:07 +00004187}
sewardj5d28efc2005-04-21 22:16:29 +00004188
njn25e49d8e72002-09-23 09:36:25 +00004189
sewardj95448072004-11-22 20:19:51 +00004190/* ------------------------ Size = 1 ------------------------ */
sewardj8cf88b72005-07-08 01:29:33 +00004191/* Note: endianness is irrelevant for size == 1 */
sewardj95448072004-11-22 20:19:51 +00004192
njnaf839f52005-06-23 03:27:57 +00004193VG_REGPARM(1)
njn1d0825f2006-03-27 11:37:07 +00004194UWord MC_(helperc_LOADV8) ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +00004195{
njn1d0825f2006-03-27 11:37:07 +00004196 UWord sm_off, vabits8;
sewardjae986ca2005-10-12 12:53:20 +00004197 SecMap* sm;
4198
njn1d0825f2006-03-27 11:37:07 +00004199 PROF_EVENT(260, "mc_LOADV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004200
njn1d0825f2006-03-27 11:37:07 +00004201#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004202 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004203#else
bart5dd8e6a2008-03-22 08:04:29 +00004204 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
njn1d0825f2006-03-27 11:37:07 +00004205 PROF_EVENT(261, "mc_LOADV8-slow1");
njn45e81252006-03-28 12:35:08 +00004206 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
sewardjc1a2cda2005-04-21 17:34:00 +00004207 }
4208
njna7c7ebd2006-03-28 12:51:02 +00004209 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00004210 sm_off = SM_OFF(a);
4211 vabits8 = sm->vabits8[sm_off];
4212 // Convert V bits from compact memory form to expanded register form
4213 // Handle common case quickly: a is mapped, and the entire
4214 // word32 it lives in is addressible.
njndbf7ca72006-03-31 11:57:59 +00004215 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS8_DEFINED; }
4216 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS8_UNDEFINED; }
njn1d0825f2006-03-27 11:37:07 +00004217 else {
njndbf7ca72006-03-31 11:57:59 +00004218 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
njn1d0825f2006-03-27 11:37:07 +00004219 // the single byte.
4220 UChar vabits2 = extract_vabits2_from_vabits8(a, vabits8);
njndbf7ca72006-03-31 11:57:59 +00004221 if (vabits2 == VA_BITS2_DEFINED ) { return V_BITS8_DEFINED; }
4222 else if (vabits2 == VA_BITS2_UNDEFINED) { return V_BITS8_UNDEFINED; }
njn1d0825f2006-03-27 11:37:07 +00004223 else {
njndbf7ca72006-03-31 11:57:59 +00004224 /* Slow case: the byte is not all-defined or all-undefined. */
njn1d0825f2006-03-27 11:37:07 +00004225 PROF_EVENT(262, "mc_LOADV8-slow2");
njn45e81252006-03-28 12:35:08 +00004226 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004227 }
sewardjc1a2cda2005-04-21 17:34:00 +00004228 }
njn1d0825f2006-03-27 11:37:07 +00004229#endif
njn25e49d8e72002-09-23 09:36:25 +00004230}
4231
sewardjc1a2cda2005-04-21 17:34:00 +00004232
njnaf839f52005-06-23 03:27:57 +00004233VG_REGPARM(2)
njn4cf530b2006-04-06 13:33:48 +00004234void MC_(helperc_STOREV8) ( Addr a, UWord vbits8 )
njn25e49d8e72002-09-23 09:36:25 +00004235{
njn1d0825f2006-03-27 11:37:07 +00004236 UWord sm_off, vabits8;
sewardjae986ca2005-10-12 12:53:20 +00004237 SecMap* sm;
4238
njn1d0825f2006-03-27 11:37:07 +00004239 PROF_EVENT(270, "mc_STOREV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004240
njn1d0825f2006-03-27 11:37:07 +00004241#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004242 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004243#else
bart5dd8e6a2008-03-22 08:04:29 +00004244 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
njn1d0825f2006-03-27 11:37:07 +00004245 PROF_EVENT(271, "mc_STOREV8-slow1");
njn4cf530b2006-04-06 13:33:48 +00004246 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
sewardjc1a2cda2005-04-21 17:34:00 +00004247 return;
4248 }
4249
njna7c7ebd2006-03-28 12:51:02 +00004250 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00004251 sm_off = SM_OFF(a);
4252 vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00004253 if (LIKELY
njn1d0825f2006-03-27 11:37:07 +00004254 ( !is_distinguished_sm(sm) &&
njndbf7ca72006-03-31 11:57:59 +00004255 ( (VA_BITS8_DEFINED == vabits8 || VA_BITS8_UNDEFINED == vabits8)
njn1d0825f2006-03-27 11:37:07 +00004256 || (VA_BITS2_NOACCESS != extract_vabits2_from_vabits8(a, vabits8))
4257 )
4258 )
4259 )
4260 {
sewardjc1a2cda2005-04-21 17:34:00 +00004261 /* Handle common case quickly: a is mapped, the entire word32 it
4262 lives in is addressible. */
njn1d0825f2006-03-27 11:37:07 +00004263 // Convert full V-bits in register to compact 2-bit form.
njn4cf530b2006-04-06 13:33:48 +00004264 if (V_BITS8_DEFINED == vbits8) {
njndbf7ca72006-03-31 11:57:59 +00004265 insert_vabits2_into_vabits8( a, VA_BITS2_DEFINED,
njn1d0825f2006-03-27 11:37:07 +00004266 &(sm->vabits8[sm_off]) );
njn4cf530b2006-04-06 13:33:48 +00004267 } else if (V_BITS8_UNDEFINED == vbits8) {
njndbf7ca72006-03-31 11:57:59 +00004268 insert_vabits2_into_vabits8( a, VA_BITS2_UNDEFINED,
njn1d0825f2006-03-27 11:37:07 +00004269 &(sm->vabits8[sm_off]) );
4270 } else {
4271 /* Slow but general case -- writing partially defined bytes. */
4272 PROF_EVENT(272, "mc_STOREV8-slow2");
njn4cf530b2006-04-06 13:33:48 +00004273 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004274 }
sewardjc1a2cda2005-04-21 17:34:00 +00004275 } else {
njn1d0825f2006-03-27 11:37:07 +00004276 /* Slow but general case. */
4277 PROF_EVENT(273, "mc_STOREV8-slow3");
njn4cf530b2006-04-06 13:33:48 +00004278 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
sewardjc1a2cda2005-04-21 17:34:00 +00004279 }
njn1d0825f2006-03-27 11:37:07 +00004280#endif
njn25e49d8e72002-09-23 09:36:25 +00004281}
4282
4283
sewardjc859fbf2005-04-22 21:10:28 +00004284/*------------------------------------------------------------*/
4285/*--- Functions called directly from generated code: ---*/
4286/*--- Value-check failure handlers. ---*/
4287/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004288
sewardj7cf4e6b2008-05-01 20:24:26 +00004289/* Call these ones when an origin is available ... */
4290VG_REGPARM(1)
4291void MC_(helperc_value_check0_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004292 MC_(record_cond_error) ( VG_(get_running_tid)(), (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004293}
4294
sewardj7cf4e6b2008-05-01 20:24:26 +00004295VG_REGPARM(1)
4296void MC_(helperc_value_check1_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004297 MC_(record_value_error) ( VG_(get_running_tid)(), 1, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004298}
4299
sewardj7cf4e6b2008-05-01 20:24:26 +00004300VG_REGPARM(1)
4301void MC_(helperc_value_check4_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004302 MC_(record_value_error) ( VG_(get_running_tid)(), 4, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004303}
4304
sewardj7cf4e6b2008-05-01 20:24:26 +00004305VG_REGPARM(1)
4306void MC_(helperc_value_check8_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004307 MC_(record_value_error) ( VG_(get_running_tid)(), 8, (UInt)origin );
sewardj11bcc4e2005-04-23 22:38:38 +00004308}
4309
sewardj7cf4e6b2008-05-01 20:24:26 +00004310VG_REGPARM(2)
4311void MC_(helperc_value_checkN_fail_w_o) ( HWord sz, UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004312 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, (UInt)origin );
sewardj7cf4e6b2008-05-01 20:24:26 +00004313}
4314
4315/* ... and these when an origin isn't available. */
4316
4317VG_REGPARM(0)
4318void MC_(helperc_value_check0_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004319 MC_(record_cond_error) ( VG_(get_running_tid)(), 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004320}
4321
4322VG_REGPARM(0)
4323void MC_(helperc_value_check1_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004324 MC_(record_value_error) ( VG_(get_running_tid)(), 1, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004325}
4326
4327VG_REGPARM(0)
4328void MC_(helperc_value_check4_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004329 MC_(record_value_error) ( VG_(get_running_tid)(), 4, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004330}
4331
4332VG_REGPARM(0)
4333void MC_(helperc_value_check8_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004334 MC_(record_value_error) ( VG_(get_running_tid)(), 8, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004335}
4336
4337VG_REGPARM(1)
4338void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) {
sewardj7ce71662008-05-02 10:33:15 +00004339 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, 0/*origin*/ );
sewardj95448072004-11-22 20:19:51 +00004340}
4341
njn25e49d8e72002-09-23 09:36:25 +00004342
sewardjc2c12c22006-03-08 13:20:09 +00004343/*------------------------------------------------------------*/
4344/*--- Metadata get/set functions, for client requests. ---*/
4345/*------------------------------------------------------------*/
4346
njn1d0825f2006-03-27 11:37:07 +00004347// Nb: this expands the V+A bits out into register-form V bits, even though
4348// they're in memory. This is for backward compatibility, and because it's
4349// probably what the user wants.
4350
4351/* Copy Vbits from/to address 'a'. Returns: 1 == OK, 2 == alignment
sewardjc2c12c22006-03-08 13:20:09 +00004352 error [no longer used], 3 == addressing error. */
njn718d3b12006-12-16 00:54:12 +00004353/* Nb: We used to issue various definedness/addressability errors from here,
4354 but we took them out because they ranged from not-very-helpful to
4355 downright annoying, and they complicated the error data structures. */
sewardjc2c12c22006-03-08 13:20:09 +00004356static Int mc_get_or_set_vbits_for_client (
4357 ThreadId tid,
njn1d0825f2006-03-27 11:37:07 +00004358 Addr a,
4359 Addr vbits,
4360 SizeT szB,
sewardjc2c12c22006-03-08 13:20:09 +00004361 Bool setting /* True <=> set vbits, False <=> get vbits */
4362)
4363{
sewardjc2c12c22006-03-08 13:20:09 +00004364 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00004365 Bool ok;
4366 UChar vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004367
njn1d0825f2006-03-27 11:37:07 +00004368 /* Check that arrays are addressible before doing any getting/setting. */
4369 for (i = 0; i < szB; i++) {
njn718d3b12006-12-16 00:54:12 +00004370 if (VA_BITS2_NOACCESS == get_vabits2(a + i) ||
4371 VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
njn1d0825f2006-03-27 11:37:07 +00004372 return 3;
sewardjc2c12c22006-03-08 13:20:09 +00004373 }
4374 }
njn1d0825f2006-03-27 11:37:07 +00004375
sewardjc2c12c22006-03-08 13:20:09 +00004376 /* Do the copy */
4377 if (setting) {
njn1d0825f2006-03-27 11:37:07 +00004378 /* setting */
4379 for (i = 0; i < szB; i++) {
4380 ok = set_vbits8(a + i, ((UChar*)vbits)[i]);
4381 tl_assert(ok);
sewardjc2c12c22006-03-08 13:20:09 +00004382 }
4383 } else {
4384 /* getting */
njn1d0825f2006-03-27 11:37:07 +00004385 for (i = 0; i < szB; i++) {
4386 ok = get_vbits8(a + i, &vbits8);
4387 tl_assert(ok);
njn1d0825f2006-03-27 11:37:07 +00004388 ((UChar*)vbits)[i] = vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004389 }
4390 // The bytes in vbits[] have now been set, so mark them as such.
njndbf7ca72006-03-31 11:57:59 +00004391 MC_(make_mem_defined)(vbits, szB);
njn1d0825f2006-03-27 11:37:07 +00004392 }
sewardjc2c12c22006-03-08 13:20:09 +00004393
4394 return 1;
4395}
sewardj05fe85e2005-04-27 22:46:36 +00004396
4397
4398/*------------------------------------------------------------*/
4399/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
4400/*------------------------------------------------------------*/
4401
4402/* For the memory leak detector, say whether an entire 64k chunk of
4403 address space is possibly in use, or not. If in doubt return
4404 True.
4405*/
4406static
4407Bool mc_is_within_valid_secondary ( Addr a )
4408{
4409 SecMap* sm = maybe_get_secmap_for ( a );
sewardj05a46732006-10-17 01:28:10 +00004410 if (sm == NULL || sm == &sm_distinguished[SM_DIST_NOACCESS]
sewardj7ce71662008-05-02 10:33:15 +00004411 || MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004412 /* Definitely not in use. */
4413 return False;
4414 } else {
4415 return True;
4416 }
4417}
4418
4419
4420/* For the memory leak detector, say whether or not a given word
4421 address is to be regarded as valid. */
4422static
4423Bool mc_is_valid_aligned_word ( Addr a )
4424{
4425 tl_assert(sizeof(UWord) == 4 || sizeof(UWord) == 8);
4426 if (sizeof(UWord) == 4) {
4427 tl_assert(VG_IS_4_ALIGNED(a));
4428 } else {
4429 tl_assert(VG_IS_8_ALIGNED(a));
4430 }
sewardj7cf4e6b2008-05-01 20:24:26 +00004431 if (is_mem_defined( a, sizeof(UWord), NULL, NULL) == MC_Ok
sewardj7ce71662008-05-02 10:33:15 +00004432 && !MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004433 return True;
4434 } else {
4435 return False;
4436 }
4437}
sewardja4495682002-10-21 07:29:59 +00004438
4439
nethercote996901a2004-08-03 13:29:09 +00004440/* Leak detector for this tool. We don't actually do anything, merely
sewardja4495682002-10-21 07:29:59 +00004441 run the generic leak detector with suitable parameters for this
nethercote996901a2004-08-03 13:29:09 +00004442 tool. */
njnb8dca862005-03-14 02:42:44 +00004443static void mc_detect_memory_leaks ( ThreadId tid, LeakCheckMode mode )
njn25e49d8e72002-09-23 09:36:25 +00004444{
njn1d0825f2006-03-27 11:37:07 +00004445 MC_(do_detect_memory_leaks) (
sewardj05fe85e2005-04-27 22:46:36 +00004446 tid,
4447 mode,
4448 mc_is_within_valid_secondary,
4449 mc_is_valid_aligned_word
4450 );
njn25e49d8e72002-09-23 09:36:25 +00004451}
4452
4453
sewardjc859fbf2005-04-22 21:10:28 +00004454/*------------------------------------------------------------*/
4455/*--- Initialisation ---*/
4456/*------------------------------------------------------------*/
4457
4458static void init_shadow_memory ( void )
4459{
4460 Int i;
4461 SecMap* sm;
4462
njn1d0825f2006-03-27 11:37:07 +00004463 tl_assert(V_BIT_UNDEFINED == 1);
4464 tl_assert(V_BIT_DEFINED == 0);
4465 tl_assert(V_BITS8_UNDEFINED == 0xFF);
4466 tl_assert(V_BITS8_DEFINED == 0);
4467
sewardjc859fbf2005-04-22 21:10:28 +00004468 /* Build the 3 distinguished secondaries */
sewardjc859fbf2005-04-22 21:10:28 +00004469 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004470 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_NOACCESS;
sewardjc859fbf2005-04-22 21:10:28 +00004471
njndbf7ca72006-03-31 11:57:59 +00004472 sm = &sm_distinguished[SM_DIST_UNDEFINED];
4473 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_UNDEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004474
njndbf7ca72006-03-31 11:57:59 +00004475 sm = &sm_distinguished[SM_DIST_DEFINED];
4476 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_DEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004477
4478 /* Set up the primary map. */
4479 /* These entries gradually get overwritten as the used address
4480 space expands. */
4481 for (i = 0; i < N_PRIMARY_MAP; i++)
4482 primary_map[i] = &sm_distinguished[SM_DIST_NOACCESS];
4483
sewardj05a46732006-10-17 01:28:10 +00004484 /* Auxiliary primary maps */
4485 init_auxmap_L1_L2();
4486
sewardjc859fbf2005-04-22 21:10:28 +00004487 /* auxmap_size = auxmap_used = 0;
4488 no ... these are statically initialised */
njn1d0825f2006-03-27 11:37:07 +00004489
4490 /* Secondary V bit table */
4491 secVBitTable = createSecVBitTable();
sewardjc859fbf2005-04-22 21:10:28 +00004492}
4493
4494
4495/*------------------------------------------------------------*/
4496/*--- Sanity check machinery (permanently engaged) ---*/
4497/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004498
njn51d827b2005-05-09 01:02:08 +00004499static Bool mc_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004500{
sewardj23eb2fd2005-04-22 16:29:19 +00004501 n_sanity_cheap++;
sewardjc1a2cda2005-04-21 17:34:00 +00004502 PROF_EVENT(490, "cheap_sanity_check");
sewardj7cf4e6b2008-05-01 20:24:26 +00004503 /* Check for sane operating level */
4504 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4505 return False;
4506 /* nothing else useful we can rapidly check */
jseward9800fd32004-01-04 23:08:04 +00004507 return True;
njn25e49d8e72002-09-23 09:36:25 +00004508}
4509
njn51d827b2005-05-09 01:02:08 +00004510static Bool mc_expensive_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004511{
sewardj05a46732006-10-17 01:28:10 +00004512 Int i;
4513 Word n_secmaps_found;
sewardj45d94cc2005-04-20 14:44:11 +00004514 SecMap* sm;
sewardj05a46732006-10-17 01:28:10 +00004515 HChar* errmsg;
sewardj23eb2fd2005-04-22 16:29:19 +00004516 Bool bad = False;
njn25e49d8e72002-09-23 09:36:25 +00004517
sewardj05a46732006-10-17 01:28:10 +00004518 if (0) VG_(printf)("expensive sanity check\n");
4519 if (0) return True;
4520
sewardj23eb2fd2005-04-22 16:29:19 +00004521 n_sanity_expensive++;
sewardjc1a2cda2005-04-21 17:34:00 +00004522 PROF_EVENT(491, "expensive_sanity_check");
4523
sewardj7cf4e6b2008-05-01 20:24:26 +00004524 /* Check for sane operating level */
4525 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4526 return False;
4527
njn1d0825f2006-03-27 11:37:07 +00004528 /* Check that the 3 distinguished SMs are still as they should be. */
njn25e49d8e72002-09-23 09:36:25 +00004529
njndbf7ca72006-03-31 11:57:59 +00004530 /* Check noaccess DSM. */
sewardj45d94cc2005-04-20 14:44:11 +00004531 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004532 for (i = 0; i < SM_CHUNKS; i++)
4533 if (sm->vabits8[i] != VA_BITS8_NOACCESS)
sewardj23eb2fd2005-04-22 16:29:19 +00004534 bad = True;
njn25e49d8e72002-09-23 09:36:25 +00004535
njndbf7ca72006-03-31 11:57:59 +00004536 /* Check undefined DSM. */
4537 sm = &sm_distinguished[SM_DIST_UNDEFINED];
njn1d0825f2006-03-27 11:37:07 +00004538 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004539 if (sm->vabits8[i] != VA_BITS8_UNDEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004540 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004541
njndbf7ca72006-03-31 11:57:59 +00004542 /* Check defined DSM. */
4543 sm = &sm_distinguished[SM_DIST_DEFINED];
njn1d0825f2006-03-27 11:37:07 +00004544 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004545 if (sm->vabits8[i] != VA_BITS8_DEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004546 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004547
sewardj23eb2fd2005-04-22 16:29:19 +00004548 if (bad) {
4549 VG_(printf)("memcheck expensive sanity: "
4550 "distinguished_secondaries have changed\n");
4551 return False;
4552 }
4553
njn1d0825f2006-03-27 11:37:07 +00004554 /* If we're not checking for undefined value errors, the secondary V bit
4555 * table should be empty. */
sewardj7cf4e6b2008-05-01 20:24:26 +00004556 if (MC_(clo_mc_level) == 1) {
njne2a9ad32007-09-17 05:30:48 +00004557 if (0 != VG_(OSetGen_Size)(secVBitTable))
njn1d0825f2006-03-27 11:37:07 +00004558 return False;
4559 }
4560
sewardj05a46732006-10-17 01:28:10 +00004561 /* check the auxiliary maps, very thoroughly */
4562 n_secmaps_found = 0;
4563 errmsg = check_auxmap_L1_L2_sanity( &n_secmaps_found );
4564 if (errmsg) {
4565 VG_(printf)("memcheck expensive sanity, auxmaps:\n\t%s", errmsg);
sewardj23eb2fd2005-04-22 16:29:19 +00004566 return False;
4567 }
4568
sewardj05a46732006-10-17 01:28:10 +00004569 /* n_secmaps_found is now the number referred to by the auxiliary
4570 primary map. Now add on the ones referred to by the main
4571 primary map. */
sewardj23eb2fd2005-04-22 16:29:19 +00004572 for (i = 0; i < N_PRIMARY_MAP; i++) {
sewardj05a46732006-10-17 01:28:10 +00004573 if (primary_map[i] == NULL) {
sewardj23eb2fd2005-04-22 16:29:19 +00004574 bad = True;
4575 } else {
sewardj05a46732006-10-17 01:28:10 +00004576 if (!is_distinguished_sm(primary_map[i]))
sewardj23eb2fd2005-04-22 16:29:19 +00004577 n_secmaps_found++;
4578 }
4579 }
4580
sewardj05a46732006-10-17 01:28:10 +00004581 /* check that the number of secmaps issued matches the number that
4582 are reachable (iow, no secmap leaks) */
njn1d0825f2006-03-27 11:37:07 +00004583 if (n_secmaps_found != (n_issued_SMs - n_deissued_SMs))
sewardj23eb2fd2005-04-22 16:29:19 +00004584 bad = True;
4585
4586 if (bad) {
4587 VG_(printf)("memcheck expensive sanity: "
4588 "apparent secmap leakage\n");
4589 return False;
4590 }
4591
sewardj23eb2fd2005-04-22 16:29:19 +00004592 if (bad) {
4593 VG_(printf)("memcheck expensive sanity: "
4594 "auxmap covers wrong address space\n");
4595 return False;
4596 }
4597
4598 /* there is only one pointer to each secmap (expensive) */
njn25e49d8e72002-09-23 09:36:25 +00004599
4600 return True;
4601}
sewardj45d94cc2005-04-20 14:44:11 +00004602
njn25e49d8e72002-09-23 09:36:25 +00004603/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00004604/*--- Command line args ---*/
njn25e49d8e72002-09-23 09:36:25 +00004605/*------------------------------------------------------------*/
4606
njn1d0825f2006-03-27 11:37:07 +00004607Bool MC_(clo_partial_loads_ok) = False;
sewardjfa4ca3b2007-11-30 17:19:36 +00004608Long MC_(clo_freelist_vol) = 10*1000*1000LL;
njn1d0825f2006-03-27 11:37:07 +00004609LeakCheckMode MC_(clo_leak_check) = LC_Summary;
4610VgRes MC_(clo_leak_resolution) = Vg_LowRes;
4611Bool MC_(clo_show_reachable) = False;
4612Bool MC_(clo_workaround_gcc296_bugs) = False;
sewardjeb0fa932007-11-30 21:41:40 +00004613Int MC_(clo_malloc_fill) = -1;
4614Int MC_(clo_free_fill) = -1;
sewardj7cf4e6b2008-05-01 20:24:26 +00004615Int MC_(clo_mc_level) = 2;
njn1d0825f2006-03-27 11:37:07 +00004616
4617static Bool mc_process_cmd_line_options(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00004618{
sewardj7cf4e6b2008-05-01 20:24:26 +00004619 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
4620
4621 /* Set MC_(clo_mc_level):
4622 1 = A bit tracking only
4623 2 = A and V bit tracking, but no V bit origins
4624 3 = A and V bit tracking, and V bit origins
4625
4626 Do this by inspecting --undef-value-errors= and
4627 --track-origins=. Reject the case --undef-value-errors=no
4628 --track-origins=yes as meaningless.
4629 */
4630 if (0 == VG_(strcmp)(arg, "--undef-value-errors=no")) {
4631 if (MC_(clo_mc_level) == 3)
4632 goto mc_level_error;
4633 MC_(clo_mc_level) = 1;
4634 return True;
4635 }
4636 if (0 == VG_(strcmp)(arg, "--undef-value-errors=yes")) {
4637 if (MC_(clo_mc_level) == 1)
4638 MC_(clo_mc_level) = 2;
4639 return True;
4640 }
4641 if (0 == VG_(strcmp)(arg, "--track-origins=no")) {
4642 if (MC_(clo_mc_level) == 3)
4643 MC_(clo_mc_level) = 2;
4644 return True;
4645 }
4646 if (0 == VG_(strcmp)(arg, "--track-origins=yes")) {
4647 if (MC_(clo_mc_level) == 1)
4648 goto mc_level_error;
4649 MC_(clo_mc_level) = 3;
4650 return True;
4651 }
4652
njn1d0825f2006-03-27 11:37:07 +00004653 VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok))
4654 else VG_BOOL_CLO(arg, "--show-reachable", MC_(clo_show_reachable))
4655 else VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",MC_(clo_workaround_gcc296_bugs))
4656
sewardjfa4ca3b2007-11-30 17:19:36 +00004657 else VG_BNUM_CLO(arg, "--freelist-vol", MC_(clo_freelist_vol),
4658 0, 10*1000*1000*1000LL)
njn1d0825f2006-03-27 11:37:07 +00004659
4660 else if (VG_CLO_STREQ(arg, "--leak-check=no"))
4661 MC_(clo_leak_check) = LC_Off;
4662 else if (VG_CLO_STREQ(arg, "--leak-check=summary"))
4663 MC_(clo_leak_check) = LC_Summary;
4664 else if (VG_CLO_STREQ(arg, "--leak-check=yes") ||
4665 VG_CLO_STREQ(arg, "--leak-check=full"))
4666 MC_(clo_leak_check) = LC_Full;
4667
4668 else if (VG_CLO_STREQ(arg, "--leak-resolution=low"))
4669 MC_(clo_leak_resolution) = Vg_LowRes;
4670 else if (VG_CLO_STREQ(arg, "--leak-resolution=med"))
4671 MC_(clo_leak_resolution) = Vg_MedRes;
4672 else if (VG_CLO_STREQ(arg, "--leak-resolution=high"))
4673 MC_(clo_leak_resolution) = Vg_HighRes;
4674
sewardj05a46732006-10-17 01:28:10 +00004675 else if (VG_CLO_STREQN(16,arg,"--ignore-ranges=")) {
4676 Int i;
4677 UChar* txt = (UChar*)(arg+16);
4678 Bool ok = parse_ignore_ranges(txt);
4679 if (!ok)
4680 return False;
4681 tl_assert(ignoreRanges.used >= 0);
4682 tl_assert(ignoreRanges.used < M_IGNORE_RANGES);
4683 for (i = 0; i < ignoreRanges.used; i++) {
4684 Addr s = ignoreRanges.start[i];
4685 Addr e = ignoreRanges.end[i];
4686 Addr limit = 0x4000000; /* 64M - entirely arbitrary limit */
4687 if (e <= s) {
4688 VG_(message)(Vg_DebugMsg,
4689 "ERROR: --ignore-ranges: end <= start in range:");
4690 VG_(message)(Vg_DebugMsg,
4691 " 0x%lx-0x%lx", s, e);
4692 return False;
4693 }
4694 if (e - s > limit) {
4695 VG_(message)(Vg_DebugMsg,
4696 "ERROR: --ignore-ranges: suspiciously large range:");
4697 VG_(message)(Vg_DebugMsg,
4698 " 0x%lx-0x%lx (size %ld)", s, e, (UWord)(e-s));
4699 return False;
4700 }
4701 }
4702 }
4703
sewardjeb0fa932007-11-30 21:41:40 +00004704 else VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00, 0xFF)
4705 else VG_BHEX_CLO(arg, "--free-fill", MC_(clo_free_fill), 0x00, 0xFF)
4706
njn1d0825f2006-03-27 11:37:07 +00004707 else
4708 return VG_(replacement_malloc_process_cmd_line_option)(arg);
4709
4710 return True;
sewardj7cf4e6b2008-05-01 20:24:26 +00004711 /*NOTREACHED*/
4712
4713 mc_level_error:
4714 VG_(message)(Vg_DebugMsg, "ERROR: --track-origins=yes has no effect "
4715 "when --undef-value-errors=no");
4716 return False;
njn25e49d8e72002-09-23 09:36:25 +00004717}
4718
njn51d827b2005-05-09 01:02:08 +00004719static void mc_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00004720{
njn1d0825f2006-03-27 11:37:07 +00004721 VG_(printf)(
4722" --leak-check=no|summary|full search for memory leaks at exit? [summary]\n"
4723" --leak-resolution=low|med|high how much bt merging in leak check [low]\n"
4724" --show-reachable=no|yes show reachable blocks in leak check? [no]\n"
4725" --undef-value-errors=no|yes check for undefined value errors [yes]\n"
sewardj7cf4e6b2008-05-01 20:24:26 +00004726" --track-origins=no|yes show origins of undefined values? [no]\n"
njn1d0825f2006-03-27 11:37:07 +00004727" --partial-loads-ok=no|yes too hard to explain here; see manual [no]\n"
sewardjfa4ca3b2007-11-30 17:19:36 +00004728" --freelist-vol=<number> volume of freed blocks queue [10000000]\n"
njn1d0825f2006-03-27 11:37:07 +00004729" --workaround-gcc296-bugs=no|yes self explanatory [no]\n"
sewardj05a46732006-10-17 01:28:10 +00004730" --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS] assume given addresses are OK\n"
sewardjeb0fa932007-11-30 21:41:40 +00004731" --malloc-fill=<hexnumber> fill malloc'd areas with given value\n"
4732" --free-fill=<hexnumber> fill free'd areas with given value\n"
njn1d0825f2006-03-27 11:37:07 +00004733 );
4734 VG_(replacement_malloc_print_usage)();
njn3e884182003-04-15 13:03:23 +00004735}
4736
njn51d827b2005-05-09 01:02:08 +00004737static void mc_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00004738{
njn1d0825f2006-03-27 11:37:07 +00004739 VG_(replacement_malloc_print_debug_usage)();
njn25e49d8e72002-09-23 09:36:25 +00004740}
4741
sewardjf3418c02005-11-08 14:10:24 +00004742
nethercote8b76fe52004-11-08 19:20:09 +00004743/*------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00004744/*--- Client blocks ---*/
nethercote8b76fe52004-11-08 19:20:09 +00004745/*------------------------------------------------------------*/
4746
4747/* Client block management:
4748
4749 This is managed as an expanding array of client block descriptors.
4750 Indices of live descriptors are issued to the client, so it can ask
4751 to free them later. Therefore we cannot slide live entries down
4752 over dead ones. Instead we must use free/inuse flags and scan for
4753 an empty slot at allocation time. This in turn means allocation is
4754 relatively expensive, so we hope this does not happen too often.
nethercote8b76fe52004-11-08 19:20:09 +00004755
sewardjedc75ab2005-03-15 23:30:32 +00004756 An unused block has start == size == 0
4757*/
nethercote8b76fe52004-11-08 19:20:09 +00004758
sewardj7ce71662008-05-02 10:33:15 +00004759/* type CGenBlock is defined in mc_include.h */
nethercote8b76fe52004-11-08 19:20:09 +00004760
4761/* This subsystem is self-initialising. */
sewardj56adc352008-05-02 11:25:17 +00004762static UWord cgb_size = 0;
4763static UWord cgb_used = 0;
njn695c16e2005-03-27 03:40:28 +00004764static CGenBlock* cgbs = NULL;
nethercote8b76fe52004-11-08 19:20:09 +00004765
4766/* Stats for this subsystem. */
sewardj56adc352008-05-02 11:25:17 +00004767static ULong cgb_used_MAX = 0; /* Max in use. */
4768static ULong cgb_allocs = 0; /* Number of allocs. */
4769static ULong cgb_discards = 0; /* Number of discards. */
4770static ULong cgb_search = 0; /* Number of searches. */
nethercote8b76fe52004-11-08 19:20:09 +00004771
4772
sewardj7ce71662008-05-02 10:33:15 +00004773/* Get access to the client block array. */
4774void MC_(get_ClientBlock_array)( /*OUT*/CGenBlock** blocks,
4775 /*OUT*/UWord* nBlocks )
4776{
4777 *blocks = cgbs;
4778 *nBlocks = cgb_used;
4779}
4780
4781
nethercote8b76fe52004-11-08 19:20:09 +00004782static
njn695c16e2005-03-27 03:40:28 +00004783Int alloc_client_block ( void )
nethercote8b76fe52004-11-08 19:20:09 +00004784{
sewardj56adc352008-05-02 11:25:17 +00004785 UWord i, sz_new;
nethercote8b76fe52004-11-08 19:20:09 +00004786 CGenBlock* cgbs_new;
4787
njn695c16e2005-03-27 03:40:28 +00004788 cgb_allocs++;
nethercote8b76fe52004-11-08 19:20:09 +00004789
njn695c16e2005-03-27 03:40:28 +00004790 for (i = 0; i < cgb_used; i++) {
4791 cgb_search++;
4792 if (cgbs[i].start == 0 && cgbs[i].size == 0)
nethercote8b76fe52004-11-08 19:20:09 +00004793 return i;
4794 }
4795
4796 /* Not found. Try to allocate one at the end. */
njn695c16e2005-03-27 03:40:28 +00004797 if (cgb_used < cgb_size) {
4798 cgb_used++;
4799 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004800 }
4801
4802 /* Ok, we have to allocate a new one. */
njn695c16e2005-03-27 03:40:28 +00004803 tl_assert(cgb_used == cgb_size);
4804 sz_new = (cgbs == NULL) ? 10 : (2 * cgb_size);
nethercote8b76fe52004-11-08 19:20:09 +00004805
sewardj9c606bd2008-09-18 18:12:50 +00004806 cgbs_new = VG_(malloc)( "mc.acb.1", sz_new * sizeof(CGenBlock) );
njn695c16e2005-03-27 03:40:28 +00004807 for (i = 0; i < cgb_used; i++)
4808 cgbs_new[i] = cgbs[i];
nethercote8b76fe52004-11-08 19:20:09 +00004809
njn695c16e2005-03-27 03:40:28 +00004810 if (cgbs != NULL)
4811 VG_(free)( cgbs );
4812 cgbs = cgbs_new;
nethercote8b76fe52004-11-08 19:20:09 +00004813
njn695c16e2005-03-27 03:40:28 +00004814 cgb_size = sz_new;
4815 cgb_used++;
4816 if (cgb_used > cgb_used_MAX)
4817 cgb_used_MAX = cgb_used;
4818 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004819}
4820
4821
4822static void show_client_block_stats ( void )
4823{
4824 VG_(message)(Vg_DebugMsg,
sewardj56adc352008-05-02 11:25:17 +00004825 "general CBs: %llu allocs, %llu discards, %llu maxinuse, %llu search",
njn695c16e2005-03-27 03:40:28 +00004826 cgb_allocs, cgb_discards, cgb_used_MAX, cgb_search
nethercote8b76fe52004-11-08 19:20:09 +00004827 );
4828}
4829
nethercote8b76fe52004-11-08 19:20:09 +00004830
sewardj7ce71662008-05-02 10:33:15 +00004831/*------------------------------------------------------------*/
4832/*--- Client requests ---*/
4833/*------------------------------------------------------------*/
nethercote8b76fe52004-11-08 19:20:09 +00004834
njn51d827b2005-05-09 01:02:08 +00004835static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
nethercote8b76fe52004-11-08 19:20:09 +00004836{
4837 Int i;
4838 Bool ok;
4839 Addr bad_addr;
4840
njnfc26ff92004-11-22 19:12:49 +00004841 if (!VG_IS_TOOL_USERREQ('M','C',arg[0])
sewardj7ce71662008-05-02 10:33:15 +00004842 && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
4843 && VG_USERREQ__FREELIKE_BLOCK != arg[0]
4844 && VG_USERREQ__CREATE_MEMPOOL != arg[0]
4845 && VG_USERREQ__DESTROY_MEMPOOL != arg[0]
4846 && VG_USERREQ__MEMPOOL_ALLOC != arg[0]
4847 && VG_USERREQ__MEMPOOL_FREE != arg[0]
4848 && VG_USERREQ__MEMPOOL_TRIM != arg[0]
4849 && VG_USERREQ__MOVE_MEMPOOL != arg[0]
4850 && VG_USERREQ__MEMPOOL_CHANGE != arg[0]
4851 && VG_USERREQ__MEMPOOL_EXISTS != arg[0])
nethercote8b76fe52004-11-08 19:20:09 +00004852 return False;
4853
4854 switch (arg[0]) {
njndbf7ca72006-03-31 11:57:59 +00004855 case VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE:
4856 ok = is_mem_addressable ( arg[1], arg[2], &bad_addr );
nethercote8b76fe52004-11-08 19:20:09 +00004857 if (!ok)
sewardj7ce71662008-05-02 10:33:15 +00004858 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00004859 *ret = ok ? (UWord)NULL : bad_addr;
sewardj8cf88b72005-07-08 01:29:33 +00004860 break;
nethercote8b76fe52004-11-08 19:20:09 +00004861
njndbf7ca72006-03-31 11:57:59 +00004862 case VG_USERREQ__CHECK_MEM_IS_DEFINED: {
nethercote8b76fe52004-11-08 19:20:09 +00004863 MC_ReadResult res;
sewardj7cf4e6b2008-05-01 20:24:26 +00004864 UInt otag = 0;
4865 res = is_mem_defined ( arg[1], arg[2], &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00004866 if (MC_AddrErr == res)
sewardj7ce71662008-05-02 10:33:15 +00004867 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00004868 else if (MC_ValueErr == res)
sewardj7ce71662008-05-02 10:33:15 +00004869 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/False, otag );
nethercote8b76fe52004-11-08 19:20:09 +00004870 *ret = ( res==MC_Ok ? (UWord)NULL : bad_addr );
sewardj8cf88b72005-07-08 01:29:33 +00004871 break;
nethercote8b76fe52004-11-08 19:20:09 +00004872 }
4873
4874 case VG_USERREQ__DO_LEAK_CHECK:
njnb8dca862005-03-14 02:42:44 +00004875 mc_detect_memory_leaks(tid, arg[1] ? LC_Summary : LC_Full);
sewardj8cf88b72005-07-08 01:29:33 +00004876 *ret = 0; /* return value is meaningless */
4877 break;
nethercote8b76fe52004-11-08 19:20:09 +00004878
njndbf7ca72006-03-31 11:57:59 +00004879 case VG_USERREQ__MAKE_MEM_NOACCESS:
4880 MC_(make_mem_noaccess) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00004881 *ret = -1;
4882 break;
nethercote8b76fe52004-11-08 19:20:09 +00004883
njndbf7ca72006-03-31 11:57:59 +00004884 case VG_USERREQ__MAKE_MEM_UNDEFINED:
sewardj7ce71662008-05-02 10:33:15 +00004885 make_mem_undefined_w_tid_and_okind ( arg[1], arg[2], tid,
4886 MC_OKIND_USER );
sewardjedc75ab2005-03-15 23:30:32 +00004887 *ret = -1;
sewardj8cf88b72005-07-08 01:29:33 +00004888 break;
nethercote8b76fe52004-11-08 19:20:09 +00004889
njndbf7ca72006-03-31 11:57:59 +00004890 case VG_USERREQ__MAKE_MEM_DEFINED:
4891 MC_(make_mem_defined) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00004892 *ret = -1;
nethercote8b76fe52004-11-08 19:20:09 +00004893 break;
4894
njndbf7ca72006-03-31 11:57:59 +00004895 case VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE:
4896 make_mem_defined_if_addressable ( arg[1], arg[2] );
sewardjfb1e9ad2006-03-10 13:41:58 +00004897 *ret = -1;
4898 break;
4899
sewardjedc75ab2005-03-15 23:30:32 +00004900 case VG_USERREQ__CREATE_BLOCK: /* describe a block */
sewardj8cf88b72005-07-08 01:29:33 +00004901 if (arg[1] != 0 && arg[2] != 0) {
4902 i = alloc_client_block();
4903 /* VG_(printf)("allocated %d %p\n", i, cgbs); */
4904 cgbs[i].start = arg[1];
4905 cgbs[i].size = arg[2];
sewardj9c606bd2008-09-18 18:12:50 +00004906 cgbs[i].desc = VG_(strdup)("mc.mhcr.1", (Char *)arg[3]);
sewardj39f34232007-11-09 23:02:28 +00004907 cgbs[i].where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
sewardj8cf88b72005-07-08 01:29:33 +00004908 *ret = i;
4909 } else
4910 *ret = -1;
4911 break;
sewardjedc75ab2005-03-15 23:30:32 +00004912
nethercote8b76fe52004-11-08 19:20:09 +00004913 case VG_USERREQ__DISCARD: /* discard */
njn695c16e2005-03-27 03:40:28 +00004914 if (cgbs == NULL
4915 || arg[2] >= cgb_used ||
sewardj8cf88b72005-07-08 01:29:33 +00004916 (cgbs[arg[2]].start == 0 && cgbs[arg[2]].size == 0)) {
sewardjedc75ab2005-03-15 23:30:32 +00004917 *ret = 1;
sewardj8cf88b72005-07-08 01:29:33 +00004918 } else {
4919 tl_assert(arg[2] >= 0 && arg[2] < cgb_used);
4920 cgbs[arg[2]].start = cgbs[arg[2]].size = 0;
4921 VG_(free)(cgbs[arg[2]].desc);
4922 cgb_discards++;
4923 *ret = 0;
4924 }
4925 break;
nethercote8b76fe52004-11-08 19:20:09 +00004926
sewardjc2c12c22006-03-08 13:20:09 +00004927 case VG_USERREQ__GET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00004928 *ret = mc_get_or_set_vbits_for_client
4929 ( tid, arg[1], arg[2], arg[3], False /* get them */ );
4930 break;
4931
4932 case VG_USERREQ__SET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00004933 *ret = mc_get_or_set_vbits_for_client
4934 ( tid, arg[1], arg[2], arg[3], True /* set them */ );
4935 break;
nethercote8b76fe52004-11-08 19:20:09 +00004936
njn1d0825f2006-03-27 11:37:07 +00004937 case VG_USERREQ__COUNT_LEAKS: { /* count leaked bytes */
4938 UWord** argp = (UWord**)arg;
4939 // MC_(bytes_leaked) et al were set by the last leak check (or zero
4940 // if no prior leak checks performed).
4941 *argp[1] = MC_(bytes_leaked) + MC_(bytes_indirect);
4942 *argp[2] = MC_(bytes_dubious);
4943 *argp[3] = MC_(bytes_reachable);
4944 *argp[4] = MC_(bytes_suppressed);
4945 // there is no argp[5]
4946 //*argp[5] = MC_(bytes_indirect);
njndbf7ca72006-03-31 11:57:59 +00004947 // XXX need to make *argp[1-4] defined
njn1d0825f2006-03-27 11:37:07 +00004948 *ret = 0;
4949 return True;
4950 }
4951 case VG_USERREQ__MALLOCLIKE_BLOCK: {
4952 Addr p = (Addr)arg[1];
4953 SizeT sizeB = arg[2];
4954 UInt rzB = arg[3];
4955 Bool is_zeroed = (Bool)arg[4];
4956
4957 MC_(new_block) ( tid, p, sizeB, /*ignored*/0, rzB, is_zeroed,
4958 MC_AllocCustom, MC_(malloc_list) );
4959 return True;
4960 }
4961 case VG_USERREQ__FREELIKE_BLOCK: {
4962 Addr p = (Addr)arg[1];
4963 UInt rzB = arg[2];
4964
4965 MC_(handle_free) ( tid, p, rzB, MC_AllocCustom );
4966 return True;
4967 }
4968
4969 case _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR: {
njn718d3b12006-12-16 00:54:12 +00004970 Char* s = (Char*)arg[1];
4971 Addr dst = (Addr) arg[2];
4972 Addr src = (Addr) arg[3];
4973 SizeT len = (SizeT)arg[4];
sewardj7ce71662008-05-02 10:33:15 +00004974 MC_(record_overlap_error)(tid, s, src, dst, len);
njn1d0825f2006-03-27 11:37:07 +00004975 return True;
4976 }
4977
4978 case VG_USERREQ__CREATE_MEMPOOL: {
4979 Addr pool = (Addr)arg[1];
4980 UInt rzB = arg[2];
4981 Bool is_zeroed = (Bool)arg[3];
4982
4983 MC_(create_mempool) ( pool, rzB, is_zeroed );
4984 return True;
4985 }
4986
4987 case VG_USERREQ__DESTROY_MEMPOOL: {
4988 Addr pool = (Addr)arg[1];
4989
4990 MC_(destroy_mempool) ( pool );
4991 return True;
4992 }
4993
4994 case VG_USERREQ__MEMPOOL_ALLOC: {
4995 Addr pool = (Addr)arg[1];
4996 Addr addr = (Addr)arg[2];
4997 UInt size = arg[3];
4998
4999 MC_(mempool_alloc) ( tid, pool, addr, size );
5000 return True;
5001 }
5002
5003 case VG_USERREQ__MEMPOOL_FREE: {
5004 Addr pool = (Addr)arg[1];
5005 Addr addr = (Addr)arg[2];
5006
5007 MC_(mempool_free) ( pool, addr );
5008 return True;
5009 }
5010
sewardj2c1c9df2006-07-28 00:06:37 +00005011 case VG_USERREQ__MEMPOOL_TRIM: {
5012 Addr pool = (Addr)arg[1];
5013 Addr addr = (Addr)arg[2];
5014 UInt size = arg[3];
5015
5016 MC_(mempool_trim) ( pool, addr, size );
5017 return True;
5018 }
5019
sewardjc740d762006-10-05 17:59:23 +00005020 case VG_USERREQ__MOVE_MEMPOOL: {
5021 Addr poolA = (Addr)arg[1];
5022 Addr poolB = (Addr)arg[2];
5023
5024 MC_(move_mempool) ( poolA, poolB );
5025 return True;
5026 }
5027
5028 case VG_USERREQ__MEMPOOL_CHANGE: {
5029 Addr pool = (Addr)arg[1];
5030 Addr addrA = (Addr)arg[2];
5031 Addr addrB = (Addr)arg[3];
5032 UInt size = arg[4];
5033
5034 MC_(mempool_change) ( pool, addrA, addrB, size );
5035 return True;
5036 }
5037
5038 case VG_USERREQ__MEMPOOL_EXISTS: {
5039 Addr pool = (Addr)arg[1];
5040
5041 *ret = (UWord) MC_(mempool_exists) ( pool );
5042 return True;
5043 }
5044
5045
nethercote8b76fe52004-11-08 19:20:09 +00005046 default:
njn1d0825f2006-03-27 11:37:07 +00005047 VG_(message)(Vg_UserMsg,
5048 "Warning: unknown memcheck client request code %llx",
5049 (ULong)arg[0]);
5050 return False;
nethercote8b76fe52004-11-08 19:20:09 +00005051 }
5052 return True;
5053}
njn25e49d8e72002-09-23 09:36:25 +00005054
5055/*------------------------------------------------------------*/
njn1d0825f2006-03-27 11:37:07 +00005056/*--- Crude profiling machinery. ---*/
5057/*------------------------------------------------------------*/
5058
5059// We track a number of interesting events (using PROF_EVENT)
5060// if MC_PROFILE_MEMORY is defined.
5061
5062#ifdef MC_PROFILE_MEMORY
5063
5064UInt MC_(event_ctr)[N_PROF_EVENTS];
5065HChar* MC_(event_ctr_name)[N_PROF_EVENTS];
5066
5067static void init_prof_mem ( void )
5068{
5069 Int i;
5070 for (i = 0; i < N_PROF_EVENTS; i++) {
5071 MC_(event_ctr)[i] = 0;
5072 MC_(event_ctr_name)[i] = NULL;
5073 }
5074}
5075
5076static void done_prof_mem ( void )
5077{
5078 Int i;
5079 Bool spaced = False;
5080 for (i = 0; i < N_PROF_EVENTS; i++) {
5081 if (!spaced && (i % 10) == 0) {
5082 VG_(printf)("\n");
5083 spaced = True;
5084 }
5085 if (MC_(event_ctr)[i] > 0) {
5086 spaced = False;
5087 VG_(printf)( "prof mem event %3d: %9d %s\n",
5088 i, MC_(event_ctr)[i],
5089 MC_(event_ctr_name)[i]
5090 ? MC_(event_ctr_name)[i] : "unnamed");
5091 }
5092 }
5093}
5094
5095#else
5096
5097static void init_prof_mem ( void ) { }
5098static void done_prof_mem ( void ) { }
5099
5100#endif
5101
sewardj7cf4e6b2008-05-01 20:24:26 +00005102
5103/*------------------------------------------------------------*/
5104/*--- Origin tracking stuff ---*/
5105/*------------------------------------------------------------*/
5106
5107/*--------------------------------------------*/
5108/*--- Origin tracking: load handlers ---*/
5109/*--------------------------------------------*/
5110
5111static INLINE UInt merge_origins ( UInt or1, UInt or2 ) {
5112 return or1 > or2 ? or1 : or2;
5113}
5114
5115UWord VG_REGPARM(1) MC_(helperc_b_load1)( Addr a ) {
5116 OCacheLine* line;
5117 UChar descr;
5118 UWord lineoff = oc_line_offset(a);
5119 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5120
5121 if (OC_ENABLE_ASSERTIONS) {
5122 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5123 }
5124
5125 line = find_OCacheLine( a );
5126
5127 descr = line->descr[lineoff];
5128 if (OC_ENABLE_ASSERTIONS) {
5129 tl_assert(descr < 0x10);
5130 }
5131
5132 if (LIKELY(0 == (descr & (1 << byteoff)))) {
5133 return 0;
5134 } else {
5135 return line->w32[lineoff];
5136 }
5137}
5138
5139UWord VG_REGPARM(1) MC_(helperc_b_load2)( Addr a ) {
5140 OCacheLine* line;
5141 UChar descr;
5142 UWord lineoff, byteoff;
5143
5144 if (UNLIKELY(a & 1)) {
5145 /* Handle misaligned case, slowly. */
5146 UInt oLo = (UInt)MC_(helperc_b_load1)( a + 0 );
5147 UInt oHi = (UInt)MC_(helperc_b_load1)( a + 1 );
5148 return merge_origins(oLo, oHi);
5149 }
5150
5151 lineoff = oc_line_offset(a);
5152 byteoff = a & 3; /* 0 or 2 */
5153
5154 if (OC_ENABLE_ASSERTIONS) {
5155 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5156 }
5157 line = find_OCacheLine( a );
5158
5159 descr = line->descr[lineoff];
5160 if (OC_ENABLE_ASSERTIONS) {
5161 tl_assert(descr < 0x10);
5162 }
5163
5164 if (LIKELY(0 == (descr & (3 << byteoff)))) {
5165 return 0;
5166 } else {
5167 return line->w32[lineoff];
5168 }
5169}
5170
5171UWord VG_REGPARM(1) MC_(helperc_b_load4)( Addr a ) {
5172 OCacheLine* line;
5173 UChar descr;
5174 UWord lineoff;
5175
5176 if (UNLIKELY(a & 3)) {
5177 /* Handle misaligned case, slowly. */
5178 UInt oLo = (UInt)MC_(helperc_b_load2)( a + 0 );
5179 UInt oHi = (UInt)MC_(helperc_b_load2)( a + 2 );
5180 return merge_origins(oLo, oHi);
5181 }
5182
5183 lineoff = oc_line_offset(a);
5184 if (OC_ENABLE_ASSERTIONS) {
5185 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5186 }
5187
5188 line = find_OCacheLine( a );
5189
5190 descr = line->descr[lineoff];
5191 if (OC_ENABLE_ASSERTIONS) {
5192 tl_assert(descr < 0x10);
5193 }
5194
5195 if (LIKELY(0 == descr)) {
5196 return 0;
5197 } else {
5198 return line->w32[lineoff];
5199 }
5200}
5201
5202UWord VG_REGPARM(1) MC_(helperc_b_load8)( Addr a ) {
5203 OCacheLine* line;
5204 UChar descrLo, descrHi, descr;
5205 UWord lineoff;
5206
5207 if (UNLIKELY(a & 7)) {
5208 /* Handle misaligned case, slowly. */
5209 UInt oLo = (UInt)MC_(helperc_b_load4)( a + 0 );
5210 UInt oHi = (UInt)MC_(helperc_b_load4)( a + 4 );
5211 return merge_origins(oLo, oHi);
5212 }
5213
5214 lineoff = oc_line_offset(a);
5215 if (OC_ENABLE_ASSERTIONS) {
5216 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5217 }
5218
5219 line = find_OCacheLine( a );
5220
5221 descrLo = line->descr[lineoff + 0];
5222 descrHi = line->descr[lineoff + 1];
5223 descr = descrLo | descrHi;
5224 if (OC_ENABLE_ASSERTIONS) {
5225 tl_assert(descr < 0x10);
5226 }
5227
5228 if (LIKELY(0 == descr)) {
5229 return 0; /* both 32-bit chunks are defined */
5230 } else {
5231 UInt oLo = descrLo == 0 ? 0 : line->w32[lineoff + 0];
5232 UInt oHi = descrHi == 0 ? 0 : line->w32[lineoff + 1];
5233 return merge_origins(oLo, oHi);
5234 }
5235}
5236
5237UWord VG_REGPARM(1) MC_(helperc_b_load16)( Addr a ) {
5238 UInt oLo = (UInt)MC_(helperc_b_load8)( a + 0 );
5239 UInt oHi = (UInt)MC_(helperc_b_load8)( a + 8 );
5240 UInt oBoth = merge_origins(oLo, oHi);
5241 return (UWord)oBoth;
5242}
5243
5244
5245/*--------------------------------------------*/
5246/*--- Origin tracking: store handlers ---*/
5247/*--------------------------------------------*/
5248
5249void VG_REGPARM(2) MC_(helperc_b_store1)( Addr a, UWord d32 ) {
5250 OCacheLine* line;
5251 UWord lineoff = oc_line_offset(a);
5252 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5253
5254 if (OC_ENABLE_ASSERTIONS) {
5255 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5256 }
5257
5258 line = find_OCacheLine( a );
5259
5260 if (d32 == 0) {
5261 line->descr[lineoff] &= ~(1 << byteoff);
5262 } else {
5263 line->descr[lineoff] |= (1 << byteoff);
5264 line->w32[lineoff] = d32;
5265 }
5266}
5267
5268void VG_REGPARM(2) MC_(helperc_b_store2)( Addr a, UWord d32 ) {
5269 OCacheLine* line;
5270 UWord lineoff, byteoff;
5271
5272 if (UNLIKELY(a & 1)) {
5273 /* Handle misaligned case, slowly. */
5274 MC_(helperc_b_store1)( a + 0, d32 );
5275 MC_(helperc_b_store1)( a + 1, d32 );
5276 return;
5277 }
5278
5279 lineoff = oc_line_offset(a);
5280 byteoff = a & 3; /* 0 or 2 */
5281
5282 if (OC_ENABLE_ASSERTIONS) {
5283 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5284 }
5285
5286 line = find_OCacheLine( a );
5287
5288 if (d32 == 0) {
5289 line->descr[lineoff] &= ~(3 << byteoff);
5290 } else {
5291 line->descr[lineoff] |= (3 << byteoff);
5292 line->w32[lineoff] = d32;
5293 }
5294}
5295
5296void VG_REGPARM(2) MC_(helperc_b_store4)( Addr a, UWord d32 ) {
5297 OCacheLine* line;
5298 UWord lineoff;
5299
5300 if (UNLIKELY(a & 3)) {
5301 /* Handle misaligned case, slowly. */
5302 MC_(helperc_b_store2)( a + 0, d32 );
5303 MC_(helperc_b_store2)( a + 2, d32 );
5304 return;
5305 }
5306
5307 lineoff = oc_line_offset(a);
5308 if (OC_ENABLE_ASSERTIONS) {
5309 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5310 }
5311
5312 line = find_OCacheLine( a );
5313
5314 if (d32 == 0) {
5315 line->descr[lineoff] = 0;
5316 } else {
5317 line->descr[lineoff] = 0xF;
5318 line->w32[lineoff] = d32;
5319 }
5320}
5321
5322void VG_REGPARM(2) MC_(helperc_b_store8)( Addr a, UWord d32 ) {
5323 OCacheLine* line;
5324 UWord lineoff;
5325
5326 if (UNLIKELY(a & 7)) {
5327 /* Handle misaligned case, slowly. */
5328 MC_(helperc_b_store4)( a + 0, d32 );
5329 MC_(helperc_b_store4)( a + 4, d32 );
5330 return;
5331 }
5332
5333 lineoff = oc_line_offset(a);
5334 if (OC_ENABLE_ASSERTIONS) {
5335 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5336 }
5337
5338 line = find_OCacheLine( a );
5339
5340 if (d32 == 0) {
5341 line->descr[lineoff + 0] = 0;
5342 line->descr[lineoff + 1] = 0;
5343 } else {
5344 line->descr[lineoff + 0] = 0xF;
5345 line->descr[lineoff + 1] = 0xF;
5346 line->w32[lineoff + 0] = d32;
5347 line->w32[lineoff + 1] = d32;
5348 }
5349}
5350
5351void VG_REGPARM(2) MC_(helperc_b_store16)( Addr a, UWord d32 ) {
5352 MC_(helperc_b_store8)( a + 0, d32 );
5353 MC_(helperc_b_store8)( a + 8, d32 );
5354}
5355
5356
5357/*--------------------------------------------*/
5358/*--- Origin tracking: sarp handlers ---*/
5359/*--------------------------------------------*/
5360
5361__attribute__((noinline))
5362static void ocache_sarp_Set_Origins ( Addr a, UWord len, UInt otag ) {
5363 if ((a & 1) && len >= 1) {
5364 MC_(helperc_b_store1)( a, otag );
5365 a++;
5366 len--;
5367 }
5368 if ((a & 2) && len >= 2) {
5369 MC_(helperc_b_store2)( a, otag );
5370 a += 2;
5371 len -= 2;
5372 }
5373 if (len >= 4)
5374 tl_assert(0 == (a & 3));
5375 while (len >= 4) {
5376 MC_(helperc_b_store4)( a, otag );
5377 a += 4;
5378 len -= 4;
5379 }
5380 if (len >= 2) {
5381 MC_(helperc_b_store2)( a, otag );
5382 a += 2;
5383 len -= 2;
5384 }
5385 if (len >= 1) {
5386 MC_(helperc_b_store1)( a, otag );
5387 a++;
5388 len--;
5389 }
5390 tl_assert(len == 0);
5391}
5392
5393__attribute__((noinline))
5394static void ocache_sarp_Clear_Origins ( Addr a, UWord len ) {
5395 if ((a & 1) && len >= 1) {
5396 MC_(helperc_b_store1)( a, 0 );
5397 a++;
5398 len--;
5399 }
5400 if ((a & 2) && len >= 2) {
5401 MC_(helperc_b_store2)( a, 0 );
5402 a += 2;
5403 len -= 2;
5404 }
5405 if (len >= 4)
5406 tl_assert(0 == (a & 3));
5407 while (len >= 4) {
5408 MC_(helperc_b_store4)( a, 0 );
5409 a += 4;
5410 len -= 4;
5411 }
5412 if (len >= 2) {
5413 MC_(helperc_b_store2)( a, 0 );
5414 a += 2;
5415 len -= 2;
5416 }
5417 if (len >= 1) {
5418 MC_(helperc_b_store1)( a, 0 );
5419 a++;
5420 len--;
5421 }
5422 tl_assert(len == 0);
5423}
5424
5425
njn1d0825f2006-03-27 11:37:07 +00005426/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00005427/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00005428/*------------------------------------------------------------*/
5429
njn51d827b2005-05-09 01:02:08 +00005430static void mc_post_clo_init ( void )
njn5c004e42002-11-18 11:04:50 +00005431{
sewardj71bc3cb2005-05-19 00:25:45 +00005432 /* If we've been asked to emit XML, mash around various other
5433 options so as to constrain the output somewhat. */
5434 if (VG_(clo_xml)) {
5435 /* Extract as much info as possible from the leak checker. */
njn1d0825f2006-03-27 11:37:07 +00005436 /* MC_(clo_show_reachable) = True; */
5437 MC_(clo_leak_check) = LC_Full;
sewardj71bc3cb2005-05-19 00:25:45 +00005438 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005439
5440 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
5441
5442 if (MC_(clo_mc_level) == 3) {
5443 /* We're doing origin tracking. */
5444# ifdef PERF_FAST_STACK
5445 VG_(track_new_mem_stack_4_w_ECU) ( mc_new_mem_stack_4_w_ECU );
5446 VG_(track_new_mem_stack_8_w_ECU) ( mc_new_mem_stack_8_w_ECU );
5447 VG_(track_new_mem_stack_12_w_ECU) ( mc_new_mem_stack_12_w_ECU );
5448 VG_(track_new_mem_stack_16_w_ECU) ( mc_new_mem_stack_16_w_ECU );
5449 VG_(track_new_mem_stack_32_w_ECU) ( mc_new_mem_stack_32_w_ECU );
5450 VG_(track_new_mem_stack_112_w_ECU) ( mc_new_mem_stack_112_w_ECU );
5451 VG_(track_new_mem_stack_128_w_ECU) ( mc_new_mem_stack_128_w_ECU );
5452 VG_(track_new_mem_stack_144_w_ECU) ( mc_new_mem_stack_144_w_ECU );
5453 VG_(track_new_mem_stack_160_w_ECU) ( mc_new_mem_stack_160_w_ECU );
5454# endif
5455 VG_(track_new_mem_stack_w_ECU) ( mc_new_mem_stack_w_ECU );
5456 } else {
5457 /* Not doing origin tracking */
5458# ifdef PERF_FAST_STACK
5459 VG_(track_new_mem_stack_4) ( mc_new_mem_stack_4 );
5460 VG_(track_new_mem_stack_8) ( mc_new_mem_stack_8 );
5461 VG_(track_new_mem_stack_12) ( mc_new_mem_stack_12 );
5462 VG_(track_new_mem_stack_16) ( mc_new_mem_stack_16 );
5463 VG_(track_new_mem_stack_32) ( mc_new_mem_stack_32 );
5464 VG_(track_new_mem_stack_112) ( mc_new_mem_stack_112 );
5465 VG_(track_new_mem_stack_128) ( mc_new_mem_stack_128 );
5466 VG_(track_new_mem_stack_144) ( mc_new_mem_stack_144 );
5467 VG_(track_new_mem_stack_160) ( mc_new_mem_stack_160 );
5468# endif
5469 VG_(track_new_mem_stack) ( mc_new_mem_stack );
5470 }
sewardj9d624d12008-05-02 13:35:29 +00005471
5472 /* This origin tracking cache is huge (~100M), so only initialise
5473 if we need it. */
5474 if (MC_(clo_mc_level) >= 3) {
5475 init_OCache();
sewardj77139802008-05-05 09:48:56 +00005476 tl_assert(ocacheL1 != NULL);
sewardj9d624d12008-05-02 13:35:29 +00005477 tl_assert(ocacheL2 != NULL);
5478 } else {
sewardj77139802008-05-05 09:48:56 +00005479 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005480 tl_assert(ocacheL2 == NULL);
5481 }
njn5c004e42002-11-18 11:04:50 +00005482}
5483
njn1d0825f2006-03-27 11:37:07 +00005484static void print_SM_info(char* type, int n_SMs)
5485{
5486 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005487 " memcheck: SMs: %s = %d (%ldk, %ldM)",
njn1d0825f2006-03-27 11:37:07 +00005488 type,
5489 n_SMs,
barta0b6b2c2008-07-07 06:49:24 +00005490 n_SMs * sizeof(SecMap) / 1024UL,
5491 n_SMs * sizeof(SecMap) / (1024 * 1024UL) );
njn1d0825f2006-03-27 11:37:07 +00005492}
5493
njn51d827b2005-05-09 01:02:08 +00005494static void mc_fini ( Int exitcode )
njn5c004e42002-11-18 11:04:50 +00005495{
njn1d0825f2006-03-27 11:37:07 +00005496 MC_(print_malloc_stats)();
sewardj23eb2fd2005-04-22 16:29:19 +00005497
njn1d0825f2006-03-27 11:37:07 +00005498 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5499 if (MC_(clo_leak_check) == LC_Off)
5500 VG_(message)(Vg_UserMsg,
5501 "For a detailed leak analysis, rerun with: --leak-check=yes");
5502
5503 VG_(message)(Vg_UserMsg,
5504 "For counts of detected errors, rerun with: -v");
5505 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005506
5507
sewardj7ce71662008-05-02 10:33:15 +00005508 if (MC_(any_value_errors) && !VG_(clo_xml) && VG_(clo_verbosity) >= 1
sewardj7cf4e6b2008-05-01 20:24:26 +00005509 && MC_(clo_mc_level) == 2) {
5510 VG_(message)(Vg_UserMsg,
5511 "Use --track-origins=yes to see where "
5512 "uninitialised values come from");
5513 }
5514
njn1d0825f2006-03-27 11:37:07 +00005515 if (MC_(clo_leak_check) != LC_Off)
5516 mc_detect_memory_leaks(1/*bogus ThreadId*/, MC_(clo_leak_check));
5517
5518 done_prof_mem();
sewardjae986ca2005-10-12 12:53:20 +00005519
sewardj45d94cc2005-04-20 14:44:11 +00005520 if (VG_(clo_verbosity) > 1) {
njn1d0825f2006-03-27 11:37:07 +00005521 SizeT max_secVBit_szB, max_SMs_szB, max_shmem_szB;
5522
sewardj45d94cc2005-04-20 14:44:11 +00005523 VG_(message)(Vg_DebugMsg,
sewardj23eb2fd2005-04-22 16:29:19 +00005524 " memcheck: sanity checks: %d cheap, %d expensive",
5525 n_sanity_cheap, n_sanity_expensive );
sewardj45d94cc2005-04-20 14:44:11 +00005526 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005527 " memcheck: auxmaps: %lld auxmap entries (%lldk, %lldM) in use",
sewardj05a46732006-10-17 01:28:10 +00005528 n_auxmap_L2_nodes,
5529 n_auxmap_L2_nodes * 64,
5530 n_auxmap_L2_nodes / 16 );
sewardj23eb2fd2005-04-22 16:29:19 +00005531 VG_(message)(Vg_DebugMsg,
sewardj05a46732006-10-17 01:28:10 +00005532 " memcheck: auxmaps_L1: %lld searches, %lld cmps, ratio %lld:10",
5533 n_auxmap_L1_searches, n_auxmap_L1_cmps,
5534 (10ULL * n_auxmap_L1_cmps)
5535 / (n_auxmap_L1_searches ? n_auxmap_L1_searches : 1)
5536 );
5537 VG_(message)(Vg_DebugMsg,
5538 " memcheck: auxmaps_L2: %lld searches, %lld nodes",
5539 n_auxmap_L2_searches, n_auxmap_L2_nodes
5540 );
sewardj23eb2fd2005-04-22 16:29:19 +00005541
njndbf7ca72006-03-31 11:57:59 +00005542 print_SM_info("n_issued ", n_issued_SMs);
5543 print_SM_info("n_deissued ", n_deissued_SMs);
5544 print_SM_info("max_noaccess ", max_noaccess_SMs);
5545 print_SM_info("max_undefined", max_undefined_SMs);
5546 print_SM_info("max_defined ", max_defined_SMs);
5547 print_SM_info("max_non_DSM ", max_non_DSM_SMs);
njn1d0825f2006-03-27 11:37:07 +00005548
5549 // Three DSMs, plus the non-DSM ones
5550 max_SMs_szB = (3 + max_non_DSM_SMs) * sizeof(SecMap);
5551 // The 3*sizeof(Word) bytes is the AVL node metadata size.
5552 // The 4*sizeof(Word) bytes is the malloc metadata size.
5553 // Hardwiring these sizes in sucks, but I don't see how else to do it.
5554 max_secVBit_szB = max_secVBit_nodes *
5555 (sizeof(SecVBitNode) + 3*sizeof(Word) + 4*sizeof(Word));
5556 max_shmem_szB = sizeof(primary_map) + max_SMs_szB + max_secVBit_szB;
sewardj23eb2fd2005-04-22 16:29:19 +00005557
5558 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005559 " memcheck: max sec V bit nodes: %d (%ldk, %ldM)",
njn1d0825f2006-03-27 11:37:07 +00005560 max_secVBit_nodes, max_secVBit_szB / 1024,
5561 max_secVBit_szB / (1024 * 1024));
5562 VG_(message)(Vg_DebugMsg,
5563 " memcheck: set_sec_vbits8 calls: %llu (new: %llu, updates: %llu)",
5564 sec_vbits_new_nodes + sec_vbits_updates,
5565 sec_vbits_new_nodes, sec_vbits_updates );
5566 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005567 " memcheck: max shadow mem size: %ldk, %ldM",
njn1d0825f2006-03-27 11:37:07 +00005568 max_shmem_szB / 1024, max_shmem_szB / (1024 * 1024));
sewardj7cf4e6b2008-05-01 20:24:26 +00005569
5570 if (MC_(clo_mc_level) >= 3) {
5571 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005572 " ocacheL1: %'12lu refs %'12lu misses (%'lu lossage)",
sewardj7cf4e6b2008-05-01 20:24:26 +00005573 stats_ocacheL1_find,
5574 stats_ocacheL1_misses,
5575 stats_ocacheL1_lossage );
5576 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005577 " ocacheL1: %'12lu at 0 %'12lu at 1",
sewardj7cf4e6b2008-05-01 20:24:26 +00005578 stats_ocacheL1_find - stats_ocacheL1_misses
5579 - stats_ocacheL1_found_at_1
5580 - stats_ocacheL1_found_at_N,
5581 stats_ocacheL1_found_at_1 );
5582 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005583 " ocacheL1: %'12lu at 2+ %'12lu move-fwds",
sewardj7cf4e6b2008-05-01 20:24:26 +00005584 stats_ocacheL1_found_at_N,
5585 stats_ocacheL1_movefwds );
5586 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005587 " ocacheL1: %'12lu sizeB %'12u useful",
sewardj7cf4e6b2008-05-01 20:24:26 +00005588 (UWord)sizeof(OCache),
5589 4 * OC_W32S_PER_LINE * OC_LINES_PER_SET * OC_N_SETS );
5590 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005591 " ocacheL2: %'12lu refs %'12lu misses",
sewardj7cf4e6b2008-05-01 20:24:26 +00005592 stats__ocacheL2_refs,
5593 stats__ocacheL2_misses );
5594 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005595 " ocacheL2: %'9lu max nodes %'9lu curr nodes",
sewardj7cf4e6b2008-05-01 20:24:26 +00005596 stats__ocacheL2_n_nodes_max,
5597 stats__ocacheL2_n_nodes );
5598 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005599 " niacache: %'12lu refs %'12lu misses",
sewardj7cf4e6b2008-05-01 20:24:26 +00005600 stats__nia_cache_queries, stats__nia_cache_misses);
sewardj9d624d12008-05-02 13:35:29 +00005601 } else {
sewardj77139802008-05-05 09:48:56 +00005602 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005603 tl_assert(ocacheL2 == NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00005604 }
sewardj45d94cc2005-04-20 14:44:11 +00005605 }
5606
njn5c004e42002-11-18 11:04:50 +00005607 if (0) {
5608 VG_(message)(Vg_DebugMsg,
5609 "------ Valgrind's client block stats follow ---------------" );
nethercote8b76fe52004-11-08 19:20:09 +00005610 show_client_block_stats();
njn5c004e42002-11-18 11:04:50 +00005611 }
njn25e49d8e72002-09-23 09:36:25 +00005612}
5613
njn51d827b2005-05-09 01:02:08 +00005614static void mc_pre_clo_init(void)
5615{
5616 VG_(details_name) ("Memcheck");
5617 VG_(details_version) (NULL);
5618 VG_(details_description) ("a memory error detector");
5619 VG_(details_copyright_author)(
sewardj4d474d02008-02-11 11:34:59 +00005620 "Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.");
njn51d827b2005-05-09 01:02:08 +00005621 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj05a46732006-10-17 01:28:10 +00005622 VG_(details_avg_translation_sizeB) ( 556 );
njn51d827b2005-05-09 01:02:08 +00005623
5624 VG_(basic_tool_funcs) (mc_post_clo_init,
5625 MC_(instrument),
5626 mc_fini);
5627
sewardj81651dc2007-08-28 06:05:20 +00005628 VG_(needs_final_IR_tidy_pass) ( MC_(final_tidy) );
5629
5630
njn51d827b2005-05-09 01:02:08 +00005631 VG_(needs_core_errors) ();
sewardj7ce71662008-05-02 10:33:15 +00005632 VG_(needs_tool_errors) (MC_(eq_Error),
5633 MC_(pp_Error),
sewardj39f34232007-11-09 23:02:28 +00005634 True,/*show TIDs for errors*/
sewardj7ce71662008-05-02 10:33:15 +00005635 MC_(update_Error_extra),
5636 MC_(is_recognised_suppression),
5637 MC_(read_extra_suppression_info),
5638 MC_(error_matches_suppression),
5639 MC_(get_error_name),
5640 MC_(print_extra_suppression_info));
njn51d827b2005-05-09 01:02:08 +00005641 VG_(needs_libc_freeres) ();
njn1d0825f2006-03-27 11:37:07 +00005642 VG_(needs_command_line_options)(mc_process_cmd_line_options,
njn51d827b2005-05-09 01:02:08 +00005643 mc_print_usage,
5644 mc_print_debug_usage);
5645 VG_(needs_client_requests) (mc_handle_client_request);
5646 VG_(needs_sanity_checks) (mc_cheap_sanity_check,
5647 mc_expensive_sanity_check);
njn1d0825f2006-03-27 11:37:07 +00005648 VG_(needs_malloc_replacement) (MC_(malloc),
5649 MC_(__builtin_new),
5650 MC_(__builtin_vec_new),
5651 MC_(memalign),
5652 MC_(calloc),
5653 MC_(free),
5654 MC_(__builtin_delete),
5655 MC_(__builtin_vec_delete),
5656 MC_(realloc),
5657 MC_MALLOC_REDZONE_SZB );
njnca54af32006-04-16 10:25:43 +00005658 VG_(needs_xml_output) ();
njn51d827b2005-05-09 01:02:08 +00005659
njn1d0825f2006-03-27 11:37:07 +00005660 VG_(track_new_mem_startup) ( mc_new_mem_startup );
sewardj7cf4e6b2008-05-01 20:24:26 +00005661 VG_(track_new_mem_stack_signal)( make_mem_undefined_w_tid );
5662 VG_(track_new_mem_brk) ( make_mem_undefined_w_tid );
njn1d0825f2006-03-27 11:37:07 +00005663 VG_(track_new_mem_mmap) ( mc_new_mem_mmap );
njn51d827b2005-05-09 01:02:08 +00005664
njn1d0825f2006-03-27 11:37:07 +00005665 VG_(track_copy_mem_remap) ( MC_(copy_address_range_state) );
njn81623712005-10-07 04:48:37 +00005666
5667 // Nb: we don't do anything with mprotect. This means that V bits are
5668 // preserved if a program, for example, marks some memory as inaccessible
5669 // and then later marks it as accessible again.
5670 //
5671 // If an access violation occurs (eg. writing to read-only memory) we let
5672 // it fault and print an informative termination message. This doesn't
5673 // happen if the program catches the signal, though, which is bad. If we
5674 // had two A bits (for readability and writability) that were completely
5675 // distinct from V bits, then we could handle all this properly.
5676 VG_(track_change_mem_mprotect) ( NULL );
njn51d827b2005-05-09 01:02:08 +00005677
njndbf7ca72006-03-31 11:57:59 +00005678 VG_(track_die_mem_stack_signal)( MC_(make_mem_noaccess) );
5679 VG_(track_die_mem_brk) ( MC_(make_mem_noaccess) );
5680 VG_(track_die_mem_munmap) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005681
sewardj7cf4e6b2008-05-01 20:24:26 +00005682 /* Defer the specification of the new_mem_stack functions to the
5683 post_clo_init function, since we need to first parse the command
5684 line before deciding which set to use. */
njn51d827b2005-05-09 01:02:08 +00005685
sewardj7cf4e6b2008-05-01 20:24:26 +00005686# ifdef PERF_FAST_STACK
njn1d0825f2006-03-27 11:37:07 +00005687 VG_(track_die_mem_stack_4) ( mc_die_mem_stack_4 );
5688 VG_(track_die_mem_stack_8) ( mc_die_mem_stack_8 );
5689 VG_(track_die_mem_stack_12) ( mc_die_mem_stack_12 );
5690 VG_(track_die_mem_stack_16) ( mc_die_mem_stack_16 );
5691 VG_(track_die_mem_stack_32) ( mc_die_mem_stack_32 );
5692 VG_(track_die_mem_stack_112) ( mc_die_mem_stack_112 );
5693 VG_(track_die_mem_stack_128) ( mc_die_mem_stack_128 );
5694 VG_(track_die_mem_stack_144) ( mc_die_mem_stack_144 );
5695 VG_(track_die_mem_stack_160) ( mc_die_mem_stack_160 );
sewardj7cf4e6b2008-05-01 20:24:26 +00005696# endif
njn1d0825f2006-03-27 11:37:07 +00005697 VG_(track_die_mem_stack) ( mc_die_mem_stack );
njn51d827b2005-05-09 01:02:08 +00005698
njndbf7ca72006-03-31 11:57:59 +00005699 VG_(track_ban_mem_stack) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005700
njndbf7ca72006-03-31 11:57:59 +00005701 VG_(track_pre_mem_read) ( check_mem_is_defined );
5702 VG_(track_pre_mem_read_asciiz) ( check_mem_is_defined_asciiz );
5703 VG_(track_pre_mem_write) ( check_mem_is_addressable );
njn1d0825f2006-03-27 11:37:07 +00005704 VG_(track_post_mem_write) ( mc_post_mem_write );
njn51d827b2005-05-09 01:02:08 +00005705
sewardj7cf4e6b2008-05-01 20:24:26 +00005706 if (MC_(clo_mc_level) >= 2)
njn1d0825f2006-03-27 11:37:07 +00005707 VG_(track_pre_reg_read) ( mc_pre_reg_read );
njn51d827b2005-05-09 01:02:08 +00005708
njn1d0825f2006-03-27 11:37:07 +00005709 VG_(track_post_reg_write) ( mc_post_reg_write );
5710 VG_(track_post_reg_write_clientcall_return)( mc_post_reg_write_clientcall );
njn51d827b2005-05-09 01:02:08 +00005711
5712 init_shadow_memory();
sewardj3f94a7d2007-08-25 07:19:08 +00005713 MC_(malloc_list) = VG_(HT_construct)( "MC_(malloc_list)" );
5714 MC_(mempool_list) = VG_(HT_construct)( "MC_(mempool_list)" );
njn1d0825f2006-03-27 11:37:07 +00005715 init_prof_mem();
njn51d827b2005-05-09 01:02:08 +00005716
5717 tl_assert( mc_expensive_sanity_check() );
njn1d0825f2006-03-27 11:37:07 +00005718
5719 // {LOADV,STOREV}[8421] will all fail horribly if this isn't true.
5720 tl_assert(sizeof(UWord) == sizeof(Addr));
sewardj05a46732006-10-17 01:28:10 +00005721 // Call me paranoid. I don't care.
5722 tl_assert(sizeof(void*) == sizeof(Addr));
njn1d0825f2006-03-27 11:37:07 +00005723
5724 // BYTES_PER_SEC_VBIT_NODE must be a power of two.
5725 tl_assert(-1 != VG_(log2)(BYTES_PER_SEC_VBIT_NODE));
sewardj7cf4e6b2008-05-01 20:24:26 +00005726
sewardj9d624d12008-05-02 13:35:29 +00005727 /* This is small. Always initialise it. */
sewardj7cf4e6b2008-05-01 20:24:26 +00005728 init_nia_to_ecu_cache();
sewardj7244e712008-05-02 12:35:48 +00005729
sewardj77139802008-05-05 09:48:56 +00005730 /* We can't initialise ocacheL1/ocacheL2 yet, since we don't know
5731 if we need to, since the command line args haven't been
5732 processed yet. Hence defer it to mc_post_clo_init. */
5733 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005734 tl_assert(ocacheL2 == NULL);
5735
sewardj7244e712008-05-02 12:35:48 +00005736 /* Check some important stuff. See extensive comments above
5737 re UNALIGNED_OR_HIGH for background. */
5738# if VG_WORDSIZE == 4
5739 tl_assert(sizeof(void*) == 4);
5740 tl_assert(sizeof(Addr) == 4);
5741 tl_assert(sizeof(UWord) == 4);
5742 tl_assert(sizeof(Word) == 4);
5743 tl_assert(MAX_PRIMARY_ADDRESS == 0xFFFFFFFFUL);
5744 tl_assert(MASK(1) == 0UL);
5745 tl_assert(MASK(2) == 1UL);
5746 tl_assert(MASK(4) == 3UL);
5747 tl_assert(MASK(8) == 7UL);
5748# else
5749 tl_assert(VG_WORDSIZE == 8);
5750 tl_assert(sizeof(void*) == 8);
5751 tl_assert(sizeof(Addr) == 8);
5752 tl_assert(sizeof(UWord) == 8);
5753 tl_assert(sizeof(Word) == 8);
5754 tl_assert(MAX_PRIMARY_ADDRESS == 0x7FFFFFFFFULL);
5755 tl_assert(MASK(1) == 0xFFFFFFF800000000ULL);
5756 tl_assert(MASK(2) == 0xFFFFFFF800000001ULL);
5757 tl_assert(MASK(4) == 0xFFFFFFF800000003ULL);
5758 tl_assert(MASK(8) == 0xFFFFFFF800000007ULL);
5759# endif
njn51d827b2005-05-09 01:02:08 +00005760}
5761
sewardj45f4e7c2005-09-27 19:20:21 +00005762VG_DETERMINE_INTERFACE_VERSION(mc_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00005763
njn25e49d8e72002-09-23 09:36:25 +00005764/*--------------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00005765/*--- end mc_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005766/*--------------------------------------------------------------------*/