blob: fe3941a583301b452f81672197dd8561314d1c19 [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{
njndbf7ca72006-03-31 11:57:59 +00002359 PROF_EVENT(300, "make_aligned_word32_undefined");
sewardj5d28efc2005-04-21 22:16:29 +00002360
njn1d0825f2006-03-27 11:37:07 +00002361#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002362 make_mem_undefined(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002363#else
njneccf7c02009-01-19 23:42:45 +00002364 {
2365 UWord sm_off;
2366 SecMap* sm;
sewardj5d28efc2005-04-21 22:16:29 +00002367
njneccf7c02009-01-19 23:42:45 +00002368 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2369 PROF_EVENT(301, "make_aligned_word32_undefined-slow1");
2370 make_mem_undefined(a, 4);
2371 return;
2372 }
2373
2374 sm = get_secmap_for_writing_low(a);
2375 sm_off = SM_OFF(a);
2376 sm->vabits8[sm_off] = VA_BITS8_UNDEFINED;
2377 }
njn1d0825f2006-03-27 11:37:07 +00002378#endif
njn9b007f62003-04-07 14:40:25 +00002379}
2380
sewardj7cf4e6b2008-05-01 20:24:26 +00002381static INLINE
2382void make_aligned_word32_undefined_w_otag ( Addr a, UInt otag )
2383{
2384 make_aligned_word32_undefined(a);
2385 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2386 //// Set the origins for a+0 .. a+3
2387 { OCacheLine* line;
2388 UWord lineoff = oc_line_offset(a);
2389 if (OC_ENABLE_ASSERTIONS) {
2390 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2391 }
2392 line = find_OCacheLine( a );
2393 line->descr[lineoff] = 0xF;
2394 line->w32[lineoff] = otag;
2395 }
2396 //// END inlined, specialised version of MC_(helperc_b_store4)
2397}
sewardj5d28efc2005-04-21 22:16:29 +00002398
njn1d0825f2006-03-27 11:37:07 +00002399static INLINE
2400void make_aligned_word32_noaccess ( Addr a )
sewardj5d28efc2005-04-21 22:16:29 +00002401{
2402 PROF_EVENT(310, "make_aligned_word32_noaccess");
2403
njn1d0825f2006-03-27 11:37:07 +00002404#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002405 MC_(make_mem_noaccess)(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002406#else
njneccf7c02009-01-19 23:42:45 +00002407 {
2408 UWord sm_off;
2409 SecMap* sm;
sewardj5d28efc2005-04-21 22:16:29 +00002410
njneccf7c02009-01-19 23:42:45 +00002411 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2412 PROF_EVENT(311, "make_aligned_word32_noaccess-slow1");
2413 MC_(make_mem_noaccess)(a, 4);
2414 return;
sewardj7cf4e6b2008-05-01 20:24:26 +00002415 }
njneccf7c02009-01-19 23:42:45 +00002416
2417 sm = get_secmap_for_writing_low(a);
2418 sm_off = SM_OFF(a);
2419 sm->vabits8[sm_off] = VA_BITS8_NOACCESS;
2420
2421 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2422 //// Set the origins for a+0 .. a+3.
2423 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2424 OCacheLine* line;
2425 UWord lineoff = oc_line_offset(a);
2426 if (OC_ENABLE_ASSERTIONS) {
2427 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2428 }
2429 line = find_OCacheLine( a );
2430 line->descr[lineoff] = 0;
2431 }
2432 //// END inlined, specialised version of MC_(helperc_b_store4)
sewardj7cf4e6b2008-05-01 20:24:26 +00002433 }
njn1d0825f2006-03-27 11:37:07 +00002434#endif
sewardj5d28efc2005-04-21 22:16:29 +00002435}
2436
sewardj7cf4e6b2008-05-01 20:24:26 +00002437/*--------------------- 64-bit ---------------------*/
sewardj5d28efc2005-04-21 22:16:29 +00002438
njn9b007f62003-04-07 14:40:25 +00002439/* Nb: by "aligned" here we mean 8-byte aligned */
sewardj7cf4e6b2008-05-01 20:24:26 +00002440
2441static INLINE void make_aligned_word64_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002442{
njndbf7ca72006-03-31 11:57:59 +00002443 PROF_EVENT(320, "make_aligned_word64_undefined");
sewardj23eb2fd2005-04-22 16:29:19 +00002444
njn1d0825f2006-03-27 11:37:07 +00002445#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002446 make_mem_undefined(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002447#else
njneccf7c02009-01-19 23:42:45 +00002448 {
2449 UWord sm_off16;
2450 SecMap* sm;
sewardj23eb2fd2005-04-22 16:29:19 +00002451
njneccf7c02009-01-19 23:42:45 +00002452 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2453 PROF_EVENT(321, "make_aligned_word64_undefined-slow1");
2454 make_mem_undefined(a, 8);
2455 return;
2456 }
2457
2458 sm = get_secmap_for_writing_low(a);
2459 sm_off16 = SM_OFF_16(a);
2460 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_UNDEFINED;
2461 }
njn1d0825f2006-03-27 11:37:07 +00002462#endif
njn9b007f62003-04-07 14:40:25 +00002463}
2464
sewardj7cf4e6b2008-05-01 20:24:26 +00002465static INLINE
2466void make_aligned_word64_undefined_w_otag ( Addr a, UInt otag )
2467{
2468 make_aligned_word64_undefined(a);
2469 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2470 //// Set the origins for a+0 .. a+7
2471 { OCacheLine* line;
2472 UWord lineoff = oc_line_offset(a);
2473 tl_assert(lineoff >= 0
2474 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2475 line = find_OCacheLine( a );
2476 line->descr[lineoff+0] = 0xF;
2477 line->descr[lineoff+1] = 0xF;
2478 line->w32[lineoff+0] = otag;
2479 line->w32[lineoff+1] = otag;
2480 }
2481 //// END inlined, specialised version of MC_(helperc_b_store8)
2482}
sewardj23eb2fd2005-04-22 16:29:19 +00002483
njn1d0825f2006-03-27 11:37:07 +00002484static INLINE
2485void make_aligned_word64_noaccess ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002486{
sewardj23eb2fd2005-04-22 16:29:19 +00002487 PROF_EVENT(330, "make_aligned_word64_noaccess");
2488
njn1d0825f2006-03-27 11:37:07 +00002489#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002490 MC_(make_mem_noaccess)(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002491#else
njneccf7c02009-01-19 23:42:45 +00002492 {
2493 UWord sm_off16;
2494 SecMap* sm;
sewardj23eb2fd2005-04-22 16:29:19 +00002495
njneccf7c02009-01-19 23:42:45 +00002496 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2497 PROF_EVENT(331, "make_aligned_word64_noaccess-slow1");
2498 MC_(make_mem_noaccess)(a, 8);
2499 return;
2500 }
sewardj7cf4e6b2008-05-01 20:24:26 +00002501
njneccf7c02009-01-19 23:42:45 +00002502 sm = get_secmap_for_writing_low(a);
2503 sm_off16 = SM_OFF_16(a);
2504 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_NOACCESS;
2505
2506 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2507 //// Clear the origins for a+0 .. a+7.
2508 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2509 OCacheLine* line;
2510 UWord lineoff = oc_line_offset(a);
2511 tl_assert(lineoff >= 0
2512 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2513 line = find_OCacheLine( a );
2514 line->descr[lineoff+0] = 0;
2515 line->descr[lineoff+1] = 0;
2516 }
2517 //// END inlined, specialised version of MC_(helperc_b_store8)
sewardj7cf4e6b2008-05-01 20:24:26 +00002518 }
njn1d0825f2006-03-27 11:37:07 +00002519#endif
njn9b007f62003-04-07 14:40:25 +00002520}
2521
sewardj23eb2fd2005-04-22 16:29:19 +00002522
njn1d0825f2006-03-27 11:37:07 +00002523/*------------------------------------------------------------*/
2524/*--- Stack pointer adjustment ---*/
2525/*------------------------------------------------------------*/
2526
njneccf7c02009-01-19 23:42:45 +00002527#ifdef PERF_FAST_STACK
2528# define MAYBE_USED
2529#else
2530# define MAYBE_USED __attribute__((unused))
2531#endif
2532
sewardj7cf4e6b2008-05-01 20:24:26 +00002533/*--------------- adjustment by 4 bytes ---------------*/
2534
njneccf7c02009-01-19 23:42:45 +00002535MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002536static void VG_REGPARM(2) mc_new_mem_stack_4_w_ECU(Addr new_SP, UInt ecu)
2537{
2538 UInt otag = ecu | MC_OKIND_STACK;
2539 PROF_EVENT(110, "new_mem_stack_4");
2540 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2541 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2542 } else {
2543 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 4, otag );
2544 }
2545}
2546
njneccf7c02009-01-19 23:42:45 +00002547MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002548static void VG_REGPARM(1) mc_new_mem_stack_4(Addr new_SP)
2549{
2550 PROF_EVENT(110, "new_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002551 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002552 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njn1d0825f2006-03-27 11:37:07 +00002553 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002554 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 4 );
njn1d0825f2006-03-27 11:37:07 +00002555 }
2556}
2557
njneccf7c02009-01-19 23:42:45 +00002558MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002559static void VG_REGPARM(1) mc_die_mem_stack_4(Addr new_SP)
2560{
2561 PROF_EVENT(120, "die_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002562 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002563 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002564 } else {
njndbf7ca72006-03-31 11:57:59 +00002565 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-4, 4 );
njn1d0825f2006-03-27 11:37:07 +00002566 }
2567}
2568
sewardj7cf4e6b2008-05-01 20:24:26 +00002569/*--------------- adjustment by 8 bytes ---------------*/
2570
njneccf7c02009-01-19 23:42:45 +00002571MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002572static void VG_REGPARM(2) mc_new_mem_stack_8_w_ECU(Addr new_SP, UInt ecu)
2573{
2574 UInt otag = ecu | MC_OKIND_STACK;
2575 PROF_EVENT(111, "new_mem_stack_8");
2576 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2577 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2578 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2579 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2580 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2581 } else {
2582 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 8, otag );
2583 }
2584}
2585
njneccf7c02009-01-19 23:42:45 +00002586MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002587static void VG_REGPARM(1) mc_new_mem_stack_8(Addr new_SP)
2588{
2589 PROF_EVENT(111, "new_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002590 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002591 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
sewardj05a46732006-10-17 01:28:10 +00002592 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002593 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002594 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002595 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002596 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 8 );
njn1d0825f2006-03-27 11:37:07 +00002597 }
2598}
2599
njneccf7c02009-01-19 23:42:45 +00002600MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002601static void VG_REGPARM(1) mc_die_mem_stack_8(Addr new_SP)
2602{
2603 PROF_EVENT(121, "die_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002604 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002605 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002606 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002607 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
2608 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002609 } else {
njndbf7ca72006-03-31 11:57:59 +00002610 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-8, 8 );
njn1d0825f2006-03-27 11:37:07 +00002611 }
2612}
2613
sewardj7cf4e6b2008-05-01 20:24:26 +00002614/*--------------- adjustment by 12 bytes ---------------*/
2615
njneccf7c02009-01-19 23:42:45 +00002616MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002617static void VG_REGPARM(2) mc_new_mem_stack_12_w_ECU(Addr new_SP, UInt ecu)
2618{
2619 UInt otag = ecu | MC_OKIND_STACK;
2620 PROF_EVENT(112, "new_mem_stack_12");
2621 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2622 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2623 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2624 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2625 /* from previous test we don't have 8-alignment at offset +0,
2626 hence must have 8 alignment at offsets +4/-4. Hence safe to
2627 do 4 at +0 and then 8 at +4/. */
2628 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2629 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2630 } else {
2631 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 12, otag );
2632 }
2633}
2634
njneccf7c02009-01-19 23:42:45 +00002635MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002636static void VG_REGPARM(1) mc_new_mem_stack_12(Addr new_SP)
2637{
2638 PROF_EVENT(112, "new_mem_stack_12");
sewardj05a46732006-10-17 01:28:10 +00002639 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002640 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002641 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002642 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002643 /* from previous test we don't have 8-alignment at offset +0,
2644 hence must have 8 alignment at offsets +4/-4. Hence safe to
2645 do 4 at +0 and then 8 at +4/. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002646 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002647 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002648 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002649 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 12 );
njn1d0825f2006-03-27 11:37:07 +00002650 }
2651}
2652
njneccf7c02009-01-19 23:42:45 +00002653MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002654static void VG_REGPARM(1) mc_die_mem_stack_12(Addr new_SP)
2655{
2656 PROF_EVENT(122, "die_mem_stack_12");
2657 /* Note the -12 in the test */
sewardj43fcfd92006-10-17 23:14:42 +00002658 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP-12 )) {
2659 /* We have 8-alignment at -12, hence ok to do 8 at -12 and 4 at
2660 -4. */
njndbf7ca72006-03-31 11:57:59 +00002661 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2662 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
sewardj05a46732006-10-17 01:28:10 +00002663 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002664 /* We have 4-alignment at +0, but we don't have 8-alignment at
2665 -12. So we must have 8-alignment at -8. Hence do 4 at -12
2666 and then 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002667 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2668 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
njn1d0825f2006-03-27 11:37:07 +00002669 } else {
njndbf7ca72006-03-31 11:57:59 +00002670 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-12, 12 );
njn1d0825f2006-03-27 11:37:07 +00002671 }
2672}
2673
sewardj7cf4e6b2008-05-01 20:24:26 +00002674/*--------------- adjustment by 16 bytes ---------------*/
2675
njneccf7c02009-01-19 23:42:45 +00002676MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002677static void VG_REGPARM(2) mc_new_mem_stack_16_w_ECU(Addr new_SP, UInt ecu)
2678{
2679 UInt otag = ecu | MC_OKIND_STACK;
2680 PROF_EVENT(113, "new_mem_stack_16");
2681 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2682 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
2683 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2684 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2685 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2686 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2687 Hence do 4 at +0, 8 at +4, 4 at +12. */
2688 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2689 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2690 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2691 } else {
2692 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 16, otag );
2693 }
2694}
2695
njneccf7c02009-01-19 23:42:45 +00002696MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002697static void VG_REGPARM(1) mc_new_mem_stack_16(Addr new_SP)
2698{
2699 PROF_EVENT(113, "new_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002700 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002701 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002702 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002703 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002704 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002705 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2706 Hence do 4 at +0, 8 at +4, 4 at +12. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002707 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002708 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
2709 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
njn1d0825f2006-03-27 11:37:07 +00002710 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002711 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 16 );
njn1d0825f2006-03-27 11:37:07 +00002712 }
2713}
2714
njneccf7c02009-01-19 23:42:45 +00002715MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002716static void VG_REGPARM(1) mc_die_mem_stack_16(Addr new_SP)
2717{
2718 PROF_EVENT(123, "die_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002719 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002720 /* Have 8-alignment at +0, hence do 8 at -16 and 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002721 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2722 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002723 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002724 /* 8 alignment must be at -12. Do 4 at -16, 8 at -12, 4 at -4. */
njndbf7ca72006-03-31 11:57:59 +00002725 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2726 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2727 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002728 } else {
njndbf7ca72006-03-31 11:57:59 +00002729 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-16, 16 );
njn1d0825f2006-03-27 11:37:07 +00002730 }
2731}
2732
sewardj7cf4e6b2008-05-01 20:24:26 +00002733/*--------------- adjustment by 32 bytes ---------------*/
2734
njneccf7c02009-01-19 23:42:45 +00002735MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002736static void VG_REGPARM(2) mc_new_mem_stack_32_w_ECU(Addr new_SP, UInt ecu)
2737{
2738 UInt otag = ecu | MC_OKIND_STACK;
2739 PROF_EVENT(114, "new_mem_stack_32");
2740 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2741 /* Straightforward */
2742 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2743 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2744 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2745 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2746 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2747 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2748 +0,+28. */
2749 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2750 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2751 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2752 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+20, otag );
2753 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+28, otag );
2754 } else {
2755 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 32, otag );
2756 }
2757}
2758
njneccf7c02009-01-19 23:42:45 +00002759MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002760static void VG_REGPARM(1) mc_new_mem_stack_32(Addr new_SP)
2761{
2762 PROF_EVENT(114, "new_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002763 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002764 /* Straightforward */
sewardj7cf4e6b2008-05-01 20:24:26 +00002765 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2766 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002767 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2768 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
sewardj05a46732006-10-17 01:28:10 +00002769 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002770 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2771 +0,+28. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002772 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2773 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njndbf7ca72006-03-31 11:57:59 +00002774 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
2775 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+20 );
2776 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+28 );
njn1d0825f2006-03-27 11:37:07 +00002777 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002778 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 32 );
njn1d0825f2006-03-27 11:37:07 +00002779 }
2780}
2781
njneccf7c02009-01-19 23:42:45 +00002782MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002783static void VG_REGPARM(1) mc_die_mem_stack_32(Addr new_SP)
2784{
2785 PROF_EVENT(124, "die_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002786 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002787 /* Straightforward */
njndbf7ca72006-03-31 11:57:59 +00002788 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2789 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2790 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2791 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
sewardj05a46732006-10-17 01:28:10 +00002792 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002793 /* 8 alignment must be at -4 etc. Hence do 8 at -12,-20,-28 and
2794 4 at -32,-4. */
njndbf7ca72006-03-31 11:57:59 +00002795 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2796 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-28 );
2797 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-20 );
2798 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2799 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002800 } else {
njndbf7ca72006-03-31 11:57:59 +00002801 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-32, 32 );
njn1d0825f2006-03-27 11:37:07 +00002802 }
2803}
2804
sewardj7cf4e6b2008-05-01 20:24:26 +00002805/*--------------- adjustment by 112 bytes ---------------*/
2806
njneccf7c02009-01-19 23:42:45 +00002807MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002808static void VG_REGPARM(2) mc_new_mem_stack_112_w_ECU(Addr new_SP, UInt ecu)
2809{
2810 UInt otag = ecu | MC_OKIND_STACK;
2811 PROF_EVENT(115, "new_mem_stack_112");
2812 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2813 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2814 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2815 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2816 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2817 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2818 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2819 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2820 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2821 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2822 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2823 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2824 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2825 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2826 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2827 } else {
2828 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 112, otag );
2829 }
2830}
2831
njneccf7c02009-01-19 23:42:45 +00002832MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002833static void VG_REGPARM(1) mc_new_mem_stack_112(Addr new_SP)
2834{
2835 PROF_EVENT(115, "new_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002836 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002837 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2838 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002839 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2840 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2841 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2842 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2843 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2844 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2845 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2846 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2847 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2848 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2849 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002850 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
njn1d0825f2006-03-27 11:37:07 +00002851 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002852 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 112 );
njn1d0825f2006-03-27 11:37:07 +00002853 }
2854}
2855
njneccf7c02009-01-19 23:42:45 +00002856MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002857static void VG_REGPARM(1) mc_die_mem_stack_112(Addr new_SP)
2858{
2859 PROF_EVENT(125, "die_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002860 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002861 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2862 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2863 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2864 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2865 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2866 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2867 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2868 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2869 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2870 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2871 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2872 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2873 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2874 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002875 } else {
njndbf7ca72006-03-31 11:57:59 +00002876 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-112, 112 );
njn1d0825f2006-03-27 11:37:07 +00002877 }
2878}
2879
sewardj7cf4e6b2008-05-01 20:24:26 +00002880/*--------------- adjustment by 128 bytes ---------------*/
2881
njneccf7c02009-01-19 23:42:45 +00002882MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002883static void VG_REGPARM(2) mc_new_mem_stack_128_w_ECU(Addr new_SP, UInt ecu)
2884{
2885 UInt otag = ecu | MC_OKIND_STACK;
2886 PROF_EVENT(116, "new_mem_stack_128");
2887 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2888 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2889 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2890 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2891 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2892 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2893 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2894 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2895 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2896 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2897 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2898 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2899 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2900 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2901 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2902 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2903 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2904 } else {
2905 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 128, otag );
2906 }
2907}
2908
njneccf7c02009-01-19 23:42:45 +00002909MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002910static void VG_REGPARM(1) mc_new_mem_stack_128(Addr new_SP)
2911{
2912 PROF_EVENT(116, "new_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002913 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002914 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2915 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002916 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2917 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2918 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2919 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2920 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2921 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2922 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2923 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2924 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2925 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2926 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002927 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
2928 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
2929 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
njn1d0825f2006-03-27 11:37:07 +00002930 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002931 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 128 );
njn1d0825f2006-03-27 11:37:07 +00002932 }
2933}
2934
njneccf7c02009-01-19 23:42:45 +00002935MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002936static void VG_REGPARM(1) mc_die_mem_stack_128(Addr new_SP)
2937{
2938 PROF_EVENT(126, "die_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002939 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002940 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
2941 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
2942 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2943 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2944 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2945 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2946 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2947 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2948 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2949 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2950 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2951 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2952 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2953 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2954 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2955 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002956 } else {
njndbf7ca72006-03-31 11:57:59 +00002957 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-128, 128 );
njn1d0825f2006-03-27 11:37:07 +00002958 }
2959}
2960
sewardj7cf4e6b2008-05-01 20:24:26 +00002961/*--------------- adjustment by 144 bytes ---------------*/
2962
njneccf7c02009-01-19 23:42:45 +00002963MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002964static void VG_REGPARM(2) mc_new_mem_stack_144_w_ECU(Addr new_SP, UInt ecu)
2965{
2966 UInt otag = ecu | MC_OKIND_STACK;
2967 PROF_EVENT(117, "new_mem_stack_144");
2968 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2969 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2970 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2971 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2972 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2973 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2974 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2975 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2976 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2977 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2978 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2979 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2980 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2981 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2982 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2983 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2984 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2985 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
2986 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
2987 } else {
2988 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 144, otag );
2989 }
2990}
2991
njneccf7c02009-01-19 23:42:45 +00002992MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002993static void VG_REGPARM(1) mc_new_mem_stack_144(Addr new_SP)
2994{
2995 PROF_EVENT(117, "new_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00002996 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002997 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2998 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002999 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
3000 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
3001 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
3002 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
3003 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
3004 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
3005 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
3006 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
3007 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
3008 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
3009 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00003010 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
3011 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
3012 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
3013 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
3014 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
njn1d0825f2006-03-27 11:37:07 +00003015 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003016 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 144 );
njn1d0825f2006-03-27 11:37:07 +00003017 }
3018}
3019
njneccf7c02009-01-19 23:42:45 +00003020MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003021static void VG_REGPARM(1) mc_die_mem_stack_144(Addr new_SP)
3022{
3023 PROF_EVENT(127, "die_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00003024 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00003025 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
3026 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
3027 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
3028 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
3029 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
3030 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
3031 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
3032 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
3033 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
3034 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
3035 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
3036 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
3037 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
3038 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
3039 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
3040 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
3041 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
3042 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00003043 } else {
njndbf7ca72006-03-31 11:57:59 +00003044 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-144, 144 );
njn1d0825f2006-03-27 11:37:07 +00003045 }
3046}
3047
sewardj7cf4e6b2008-05-01 20:24:26 +00003048/*--------------- adjustment by 160 bytes ---------------*/
3049
njneccf7c02009-01-19 23:42:45 +00003050MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00003051static void VG_REGPARM(2) mc_new_mem_stack_160_w_ECU(Addr new_SP, UInt ecu)
3052{
3053 UInt otag = ecu | MC_OKIND_STACK;
3054 PROF_EVENT(118, "new_mem_stack_160");
3055 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
3056 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
3057 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
3058 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
3059 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
3060 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
3061 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
3062 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
3063 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
3064 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
3065 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
3066 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
3067 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
3068 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
3069 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
3070 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
3071 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
3072 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
3073 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
3074 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+144, otag );
3075 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+152, otag );
3076 } else {
3077 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 160, otag );
3078 }
3079}
3080
njneccf7c02009-01-19 23:42:45 +00003081MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003082static void VG_REGPARM(1) mc_new_mem_stack_160(Addr new_SP)
3083{
3084 PROF_EVENT(118, "new_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00003085 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003086 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
3087 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00003088 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
3089 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
3090 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
3091 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
3092 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
3093 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
3094 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
3095 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
3096 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
3097 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
3098 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00003099 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
3100 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
3101 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
3102 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
3103 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
3104 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+144 );
3105 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+152 );
njn1d0825f2006-03-27 11:37:07 +00003106 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003107 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 160 );
njn1d0825f2006-03-27 11:37:07 +00003108 }
3109}
3110
njneccf7c02009-01-19 23:42:45 +00003111MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003112static void VG_REGPARM(1) mc_die_mem_stack_160(Addr new_SP)
3113{
3114 PROF_EVENT(128, "die_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00003115 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00003116 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-160);
3117 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-152);
3118 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
3119 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
3120 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
3121 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
3122 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
3123 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
3124 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
3125 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
3126 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
3127 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
3128 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
3129 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
3130 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
3131 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
3132 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
3133 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
3134 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
3135 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00003136 } else {
njndbf7ca72006-03-31 11:57:59 +00003137 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-160, 160 );
njn1d0825f2006-03-27 11:37:07 +00003138 }
3139}
3140
sewardj7cf4e6b2008-05-01 20:24:26 +00003141/*--------------- adjustment by N bytes ---------------*/
3142
3143static void mc_new_mem_stack_w_ECU ( Addr a, SizeT len, UInt ecu )
3144{
3145 UInt otag = ecu | MC_OKIND_STACK;
3146 PROF_EVENT(115, "new_mem_stack_w_otag");
3147 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + a, len, otag );
3148}
3149
njn1d0825f2006-03-27 11:37:07 +00003150static void mc_new_mem_stack ( Addr a, SizeT len )
3151{
3152 PROF_EVENT(115, "new_mem_stack");
sewardj7cf4e6b2008-05-01 20:24:26 +00003153 make_mem_undefined ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00003154}
3155
3156static void mc_die_mem_stack ( Addr a, SizeT len )
3157{
3158 PROF_EVENT(125, "die_mem_stack");
njndbf7ca72006-03-31 11:57:59 +00003159 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00003160}
njn9b007f62003-04-07 14:40:25 +00003161
sewardj45d94cc2005-04-20 14:44:11 +00003162
njn1d0825f2006-03-27 11:37:07 +00003163/* The AMD64 ABI says:
3164
3165 "The 128-byte area beyond the location pointed to by %rsp is considered
3166 to be reserved and shall not be modified by signal or interrupt
3167 handlers. Therefore, functions may use this area for temporary data
3168 that is not needed across function calls. In particular, leaf functions
3169 may use this area for their entire stack frame, rather than adjusting
3170 the stack pointer in the prologue and epilogue. This area is known as
3171 red zone [sic]."
3172
3173 So after any call or return we need to mark this redzone as containing
3174 undefined values.
3175
3176 Consider this: we're in function f. f calls g. g moves rsp down
3177 modestly (say 16 bytes) and writes stuff all over the red zone, making it
3178 defined. g returns. f is buggy and reads from parts of the red zone
3179 that it didn't write on. But because g filled that area in, f is going
3180 to be picking up defined V bits and so any errors from reading bits of
3181 the red zone it didn't write, will be missed. The only solution I could
3182 think of was to make the red zone undefined when g returns to f.
3183
3184 This is in accordance with the ABI, which makes it clear the redzone
3185 is volatile across function calls.
3186
3187 The problem occurs the other way round too: f could fill the RZ up
3188 with defined values and g could mistakenly read them. So the RZ
3189 also needs to be nuked on function calls.
3190*/
sewardj7cf4e6b2008-05-01 20:24:26 +00003191
3192
3193/* Here's a simple cache to hold nia -> ECU mappings. It could be
3194 improved so as to have a lower miss rate. */
3195
3196static UWord stats__nia_cache_queries = 0;
3197static UWord stats__nia_cache_misses = 0;
3198
3199typedef
3200 struct { UWord nia0; UWord ecu0; /* nia0 maps to ecu0 */
3201 UWord nia1; UWord ecu1; } /* nia1 maps to ecu1 */
3202 WCacheEnt;
3203
3204#define N_NIA_TO_ECU_CACHE 511
3205
3206static WCacheEnt nia_to_ecu_cache[N_NIA_TO_ECU_CACHE];
3207
3208static void init_nia_to_ecu_cache ( void )
sewardj826ec492005-05-12 18:05:00 +00003209{
sewardj7cf4e6b2008-05-01 20:24:26 +00003210 UWord i;
3211 Addr zero_addr = 0;
3212 ExeContext* zero_ec;
3213 UInt zero_ecu;
3214 /* Fill all the slots with an entry for address zero, and the
3215 relevant otags accordingly. Hence the cache is initially filled
3216 with valid data. */
3217 zero_ec = VG_(make_depth_1_ExeContext_from_Addr)(zero_addr);
3218 tl_assert(zero_ec);
3219 zero_ecu = VG_(get_ECU_from_ExeContext)(zero_ec);
3220 tl_assert(VG_(is_plausible_ECU)(zero_ecu));
3221 for (i = 0; i < N_NIA_TO_ECU_CACHE; i++) {
3222 nia_to_ecu_cache[i].nia0 = zero_addr;
3223 nia_to_ecu_cache[i].ecu0 = zero_ecu;
3224 nia_to_ecu_cache[i].nia1 = zero_addr;
3225 nia_to_ecu_cache[i].ecu1 = zero_ecu;
3226 }
3227}
3228
3229static inline UInt convert_nia_to_ecu ( Addr nia )
3230{
3231 UWord i;
3232 UInt ecu;
3233 ExeContext* ec;
3234
3235 tl_assert( sizeof(nia_to_ecu_cache[0].nia1) == sizeof(nia) );
3236
3237 stats__nia_cache_queries++;
3238 i = nia % N_NIA_TO_ECU_CACHE;
3239 tl_assert(i >= 0 && i < N_NIA_TO_ECU_CACHE);
3240
3241 if (LIKELY( nia_to_ecu_cache[i].nia0 == nia ))
3242 return nia_to_ecu_cache[i].ecu0;
3243
3244 if (LIKELY( nia_to_ecu_cache[i].nia1 == nia )) {
3245# define SWAP(_w1,_w2) { UWord _t = _w1; _w1 = _w2; _w2 = _t; }
3246 SWAP( nia_to_ecu_cache[i].nia0, nia_to_ecu_cache[i].nia1 );
3247 SWAP( nia_to_ecu_cache[i].ecu0, nia_to_ecu_cache[i].ecu1 );
3248# undef SWAP
3249 return nia_to_ecu_cache[i].ecu0;
3250 }
3251
3252 stats__nia_cache_misses++;
3253 ec = VG_(make_depth_1_ExeContext_from_Addr)(nia);
3254 tl_assert(ec);
3255 ecu = VG_(get_ECU_from_ExeContext)(ec);
3256 tl_assert(VG_(is_plausible_ECU)(ecu));
3257
3258 nia_to_ecu_cache[i].nia1 = nia_to_ecu_cache[i].nia0;
3259 nia_to_ecu_cache[i].ecu1 = nia_to_ecu_cache[i].ecu0;
3260
3261 nia_to_ecu_cache[i].nia0 = nia;
3262 nia_to_ecu_cache[i].ecu0 = (UWord)ecu;
3263 return ecu;
3264}
3265
3266
3267/* Note that this serves both the origin-tracking and
3268 no-origin-tracking modes. We assume that calls to it are
3269 sufficiently infrequent that it isn't worth specialising for the
3270 with/without origin-tracking cases. */
3271void MC_(helperc_MAKE_STACK_UNINIT) ( Addr base, UWord len, Addr nia )
3272{
3273 UInt otag;
sewardj826ec492005-05-12 18:05:00 +00003274 tl_assert(sizeof(UWord) == sizeof(SizeT));
sewardj2a3a1a72005-05-12 23:25:43 +00003275 if (0)
barta0b6b2c2008-07-07 06:49:24 +00003276 VG_(printf)("helperc_MAKE_STACK_UNINIT (%#lx,%lu,nia=%#lx)\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00003277 base, len, nia );
3278
3279 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3280 UInt ecu = convert_nia_to_ecu ( nia );
3281 tl_assert(VG_(is_plausible_ECU)(ecu));
3282 otag = ecu | MC_OKIND_STACK;
3283 } else {
3284 tl_assert(nia == 0);
3285 otag = 0;
3286 }
sewardj2a3a1a72005-05-12 23:25:43 +00003287
3288# if 0
3289 /* Really slow version */
sewardj7cf4e6b2008-05-01 20:24:26 +00003290 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003291# endif
3292
3293# if 0
3294 /* Slow(ish) version, which is fairly easily seen to be correct.
3295 */
bart5dd8e6a2008-03-22 08:04:29 +00003296 if (LIKELY( VG_IS_8_ALIGNED(base) && len==128 )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003297 make_aligned_word64_undefined(base + 0, otag);
3298 make_aligned_word64_undefined(base + 8, otag);
3299 make_aligned_word64_undefined(base + 16, otag);
3300 make_aligned_word64_undefined(base + 24, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003301
sewardj7cf4e6b2008-05-01 20:24:26 +00003302 make_aligned_word64_undefined(base + 32, otag);
3303 make_aligned_word64_undefined(base + 40, otag);
3304 make_aligned_word64_undefined(base + 48, otag);
3305 make_aligned_word64_undefined(base + 56, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003306
sewardj7cf4e6b2008-05-01 20:24:26 +00003307 make_aligned_word64_undefined(base + 64, otag);
3308 make_aligned_word64_undefined(base + 72, otag);
3309 make_aligned_word64_undefined(base + 80, otag);
3310 make_aligned_word64_undefined(base + 88, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003311
sewardj7cf4e6b2008-05-01 20:24:26 +00003312 make_aligned_word64_undefined(base + 96, otag);
3313 make_aligned_word64_undefined(base + 104, otag);
3314 make_aligned_word64_undefined(base + 112, otag);
3315 make_aligned_word64_undefined(base + 120, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003316 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003317 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003318 }
3319# endif
3320
3321 /* Idea is: go fast when
3322 * 8-aligned and length is 128
3323 * the sm is available in the main primary map
njn1d0825f2006-03-27 11:37:07 +00003324 * the address range falls entirely with a single secondary map
3325 If all those conditions hold, just update the V+A bits by writing
3326 directly into the vabits array. (If the sm was distinguished, this
3327 will make a copy and then write to it.)
sewardj2a3a1a72005-05-12 23:25:43 +00003328 */
sewardj7cf4e6b2008-05-01 20:24:26 +00003329
bart5dd8e6a2008-03-22 08:04:29 +00003330 if (LIKELY( len == 128 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003331 /* Now we know the address range is suitably sized and aligned. */
3332 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003333 UWord a_hi = (UWord)(base + 128 - 1);
njn1d0825f2006-03-27 11:37:07 +00003334 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003335 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003336 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003337 SecMap* sm = get_secmap_for_writing_low(a_lo);
3338 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2a3a1a72005-05-12 23:25:43 +00003339 /* Now we know that the entire address range falls within a
3340 single secondary map, and that that secondary 'lives' in
3341 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003342 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003343 // Finally, we know that the range is entirely within one secmap.
3344 UWord v_off = SM_OFF(a_lo);
3345 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003346 p[ 0] = VA_BITS16_UNDEFINED;
3347 p[ 1] = VA_BITS16_UNDEFINED;
3348 p[ 2] = VA_BITS16_UNDEFINED;
3349 p[ 3] = VA_BITS16_UNDEFINED;
3350 p[ 4] = VA_BITS16_UNDEFINED;
3351 p[ 5] = VA_BITS16_UNDEFINED;
3352 p[ 6] = VA_BITS16_UNDEFINED;
3353 p[ 7] = VA_BITS16_UNDEFINED;
3354 p[ 8] = VA_BITS16_UNDEFINED;
3355 p[ 9] = VA_BITS16_UNDEFINED;
3356 p[10] = VA_BITS16_UNDEFINED;
3357 p[11] = VA_BITS16_UNDEFINED;
3358 p[12] = VA_BITS16_UNDEFINED;
3359 p[13] = VA_BITS16_UNDEFINED;
3360 p[14] = VA_BITS16_UNDEFINED;
3361 p[15] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003362 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3363 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3364 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3365 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3366 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3367 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3368 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3369 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3370 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3371 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3372 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3373 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3374 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3375 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3376 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3377 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3378 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3379 }
sewardj2a3a1a72005-05-12 23:25:43 +00003380 return;
njn1d0825f2006-03-27 11:37:07 +00003381 }
sewardj2a3a1a72005-05-12 23:25:43 +00003382 }
3383 }
3384
sewardj2e1a6772006-01-18 04:16:27 +00003385 /* 288 bytes (36 ULongs) is the magic value for ELF ppc64. */
bart5dd8e6a2008-03-22 08:04:29 +00003386 if (LIKELY( len == 288 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003387 /* Now we know the address range is suitably sized and aligned. */
3388 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003389 UWord a_hi = (UWord)(base + 288 - 1);
njn1d0825f2006-03-27 11:37:07 +00003390 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003391 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003392 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003393 SecMap* sm = get_secmap_for_writing_low(a_lo);
3394 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2e1a6772006-01-18 04:16:27 +00003395 /* Now we know that the entire address range falls within a
3396 single secondary map, and that that secondary 'lives' in
3397 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003398 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003399 // Finally, we know that the range is entirely within one secmap.
3400 UWord v_off = SM_OFF(a_lo);
3401 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003402 p[ 0] = VA_BITS16_UNDEFINED;
3403 p[ 1] = VA_BITS16_UNDEFINED;
3404 p[ 2] = VA_BITS16_UNDEFINED;
3405 p[ 3] = VA_BITS16_UNDEFINED;
3406 p[ 4] = VA_BITS16_UNDEFINED;
3407 p[ 5] = VA_BITS16_UNDEFINED;
3408 p[ 6] = VA_BITS16_UNDEFINED;
3409 p[ 7] = VA_BITS16_UNDEFINED;
3410 p[ 8] = VA_BITS16_UNDEFINED;
3411 p[ 9] = VA_BITS16_UNDEFINED;
3412 p[10] = VA_BITS16_UNDEFINED;
3413 p[11] = VA_BITS16_UNDEFINED;
3414 p[12] = VA_BITS16_UNDEFINED;
3415 p[13] = VA_BITS16_UNDEFINED;
3416 p[14] = VA_BITS16_UNDEFINED;
3417 p[15] = VA_BITS16_UNDEFINED;
3418 p[16] = VA_BITS16_UNDEFINED;
3419 p[17] = VA_BITS16_UNDEFINED;
3420 p[18] = VA_BITS16_UNDEFINED;
3421 p[19] = VA_BITS16_UNDEFINED;
3422 p[20] = VA_BITS16_UNDEFINED;
3423 p[21] = VA_BITS16_UNDEFINED;
3424 p[22] = VA_BITS16_UNDEFINED;
3425 p[23] = VA_BITS16_UNDEFINED;
3426 p[24] = VA_BITS16_UNDEFINED;
3427 p[25] = VA_BITS16_UNDEFINED;
3428 p[26] = VA_BITS16_UNDEFINED;
3429 p[27] = VA_BITS16_UNDEFINED;
3430 p[28] = VA_BITS16_UNDEFINED;
3431 p[29] = VA_BITS16_UNDEFINED;
3432 p[30] = VA_BITS16_UNDEFINED;
3433 p[31] = VA_BITS16_UNDEFINED;
3434 p[32] = VA_BITS16_UNDEFINED;
3435 p[33] = VA_BITS16_UNDEFINED;
3436 p[34] = VA_BITS16_UNDEFINED;
3437 p[35] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003438 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3439 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3440 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3441 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3442 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3443 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3444 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3445 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3446 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3447 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3448 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3449 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3450 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3451 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3452 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3453 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3454 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3455 set_aligned_word64_Origin_to_undef( base + 8 * 16, otag );
3456 set_aligned_word64_Origin_to_undef( base + 8 * 17, otag );
3457 set_aligned_word64_Origin_to_undef( base + 8 * 18, otag );
3458 set_aligned_word64_Origin_to_undef( base + 8 * 19, otag );
3459 set_aligned_word64_Origin_to_undef( base + 8 * 20, otag );
3460 set_aligned_word64_Origin_to_undef( base + 8 * 21, otag );
3461 set_aligned_word64_Origin_to_undef( base + 8 * 22, otag );
3462 set_aligned_word64_Origin_to_undef( base + 8 * 23, otag );
3463 set_aligned_word64_Origin_to_undef( base + 8 * 24, otag );
3464 set_aligned_word64_Origin_to_undef( base + 8 * 25, otag );
3465 set_aligned_word64_Origin_to_undef( base + 8 * 26, otag );
3466 set_aligned_word64_Origin_to_undef( base + 8 * 27, otag );
3467 set_aligned_word64_Origin_to_undef( base + 8 * 28, otag );
3468 set_aligned_word64_Origin_to_undef( base + 8 * 29, otag );
3469 set_aligned_word64_Origin_to_undef( base + 8 * 30, otag );
3470 set_aligned_word64_Origin_to_undef( base + 8 * 31, otag );
3471 set_aligned_word64_Origin_to_undef( base + 8 * 32, otag );
3472 set_aligned_word64_Origin_to_undef( base + 8 * 33, otag );
3473 set_aligned_word64_Origin_to_undef( base + 8 * 34, otag );
3474 set_aligned_word64_Origin_to_undef( base + 8 * 35, otag );
3475 }
sewardj2e1a6772006-01-18 04:16:27 +00003476 return;
njn1d0825f2006-03-27 11:37:07 +00003477 }
sewardj2e1a6772006-01-18 04:16:27 +00003478 }
3479 }
3480
sewardj2a3a1a72005-05-12 23:25:43 +00003481 /* else fall into slow case */
sewardj7cf4e6b2008-05-01 20:24:26 +00003482 MC_(make_mem_undefined_w_otag)(base, len, otag);
sewardj826ec492005-05-12 18:05:00 +00003483}
3484
3485
nethercote8b76fe52004-11-08 19:20:09 +00003486/*------------------------------------------------------------*/
3487/*--- Checking memory ---*/
3488/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00003489
sewardje4ccc012005-05-02 12:53:38 +00003490typedef
3491 enum {
3492 MC_Ok = 5,
3493 MC_AddrErr = 6,
3494 MC_ValueErr = 7
3495 }
3496 MC_ReadResult;
3497
3498
njn25e49d8e72002-09-23 09:36:25 +00003499/* Check permissions for address range. If inadequate permissions
3500 exist, *bad_addr is set to the offending address, so the caller can
3501 know what it is. */
3502
sewardjecf8e102003-07-12 12:11:39 +00003503/* Returns True if [a .. a+len) is not addressible. Otherwise,
3504 returns False, and if bad_addr is non-NULL, sets *bad_addr to
3505 indicate the lowest failing address. Functions below are
3506 similar. */
njndbf7ca72006-03-31 11:57:59 +00003507Bool MC_(check_mem_is_noaccess) ( Addr a, SizeT len, Addr* bad_addr )
sewardjecf8e102003-07-12 12:11:39 +00003508{
nethercote451eae92004-11-02 13:06:32 +00003509 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003510 UWord vabits2;
3511
njndbf7ca72006-03-31 11:57:59 +00003512 PROF_EVENT(60, "check_mem_is_noaccess");
sewardjecf8e102003-07-12 12:11:39 +00003513 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003514 PROF_EVENT(61, "check_mem_is_noaccess(loop)");
njn1d0825f2006-03-27 11:37:07 +00003515 vabits2 = get_vabits2(a);
3516 if (VA_BITS2_NOACCESS != vabits2) {
3517 if (bad_addr != NULL) *bad_addr = a;
sewardjecf8e102003-07-12 12:11:39 +00003518 return False;
3519 }
3520 a++;
3521 }
3522 return True;
3523}
3524
sewardj7cf4e6b2008-05-01 20:24:26 +00003525static Bool is_mem_addressable ( Addr a, SizeT len,
3526 /*OUT*/Addr* bad_addr )
njn25e49d8e72002-09-23 09:36:25 +00003527{
nethercote451eae92004-11-02 13:06:32 +00003528 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003529 UWord vabits2;
3530
njndbf7ca72006-03-31 11:57:59 +00003531 PROF_EVENT(62, "is_mem_addressable");
njn25e49d8e72002-09-23 09:36:25 +00003532 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003533 PROF_EVENT(63, "is_mem_addressable(loop)");
njn1d0825f2006-03-27 11:37:07 +00003534 vabits2 = get_vabits2(a);
3535 if (VA_BITS2_NOACCESS == vabits2) {
njn25e49d8e72002-09-23 09:36:25 +00003536 if (bad_addr != NULL) *bad_addr = a;
3537 return False;
3538 }
3539 a++;
3540 }
3541 return True;
3542}
3543
sewardj7cf4e6b2008-05-01 20:24:26 +00003544static MC_ReadResult is_mem_defined ( Addr a, SizeT len,
3545 /*OUT*/Addr* bad_addr,
3546 /*OUT*/UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003547{
nethercote451eae92004-11-02 13:06:32 +00003548 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003549 UWord vabits2;
njn25e49d8e72002-09-23 09:36:25 +00003550
njndbf7ca72006-03-31 11:57:59 +00003551 PROF_EVENT(64, "is_mem_defined");
3552 DEBUG("is_mem_defined\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003553
3554 if (otag) *otag = 0;
3555 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003556 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003557 PROF_EVENT(65, "is_mem_defined(loop)");
njn1d0825f2006-03-27 11:37:07 +00003558 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003559 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003560 // Error! Nb: Report addressability errors in preference to
3561 // definedness errors. And don't report definedeness errors unless
3562 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003563 if (bad_addr) {
3564 *bad_addr = a;
3565 }
3566 if (VA_BITS2_NOACCESS == vabits2) {
3567 return MC_AddrErr;
3568 }
3569 if (MC_(clo_mc_level) >= 2) {
3570 if (otag && MC_(clo_mc_level) == 3) {
3571 *otag = MC_(helperc_b_load1)( a );
3572 }
3573 return MC_ValueErr;
3574 }
njn25e49d8e72002-09-23 09:36:25 +00003575 }
3576 a++;
3577 }
nethercote8b76fe52004-11-08 19:20:09 +00003578 return MC_Ok;
njn25e49d8e72002-09-23 09:36:25 +00003579}
3580
3581
3582/* Check a zero-terminated ascii string. Tricky -- don't want to
3583 examine the actual bytes, to find the end, until we're sure it is
3584 safe to do so. */
3585
sewardj7cf4e6b2008-05-01 20:24:26 +00003586static Bool mc_is_defined_asciiz ( Addr a, Addr* bad_addr, UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003587{
njn1d0825f2006-03-27 11:37:07 +00003588 UWord vabits2;
3589
njndbf7ca72006-03-31 11:57:59 +00003590 PROF_EVENT(66, "mc_is_defined_asciiz");
3591 DEBUG("mc_is_defined_asciiz\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003592
3593 if (otag) *otag = 0;
3594 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003595 while (True) {
njndbf7ca72006-03-31 11:57:59 +00003596 PROF_EVENT(67, "mc_is_defined_asciiz(loop)");
njn1d0825f2006-03-27 11:37:07 +00003597 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003598 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003599 // Error! Nb: Report addressability errors in preference to
3600 // definedness errors. And don't report definedeness errors unless
3601 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003602 if (bad_addr) {
3603 *bad_addr = a;
3604 }
3605 if (VA_BITS2_NOACCESS == vabits2) {
3606 return MC_AddrErr;
3607 }
3608 if (MC_(clo_mc_level) >= 2) {
3609 if (otag && MC_(clo_mc_level) == 3) {
3610 *otag = MC_(helperc_b_load1)( a );
3611 }
3612 return MC_ValueErr;
3613 }
njn25e49d8e72002-09-23 09:36:25 +00003614 }
3615 /* Ok, a is safe to read. */
njn1d0825f2006-03-27 11:37:07 +00003616 if (* ((UChar*)a) == 0) {
sewardj45d94cc2005-04-20 14:44:11 +00003617 return MC_Ok;
njn1d0825f2006-03-27 11:37:07 +00003618 }
njn25e49d8e72002-09-23 09:36:25 +00003619 a++;
3620 }
3621}
3622
3623
3624/*------------------------------------------------------------*/
3625/*--- Memory event handlers ---*/
3626/*------------------------------------------------------------*/
3627
njn25e49d8e72002-09-23 09:36:25 +00003628static
njndbf7ca72006-03-31 11:57:59 +00003629void check_mem_is_addressable ( CorePart part, ThreadId tid, Char* s,
3630 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003631{
njn25e49d8e72002-09-23 09:36:25 +00003632 Addr bad_addr;
njndbf7ca72006-03-31 11:57:59 +00003633 Bool ok = is_mem_addressable ( base, size, &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003634
njn25e49d8e72002-09-23 09:36:25 +00003635 if (!ok) {
3636 switch (part) {
3637 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003638 MC_(record_memparam_error) ( tid, bad_addr,
3639 /*isAddrErr*/True, s, 0/*otag*/ );
njn25e49d8e72002-09-23 09:36:25 +00003640 break;
3641
njn25e49d8e72002-09-23 09:36:25 +00003642 case Vg_CoreSignal:
sewardj7ce71662008-05-02 10:33:15 +00003643 MC_(record_core_mem_error)( tid, /*isAddrErr*/True, s );
njn25e49d8e72002-09-23 09:36:25 +00003644 break;
3645
3646 default:
njndbf7ca72006-03-31 11:57:59 +00003647 VG_(tool_panic)("check_mem_is_addressable: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003648 }
3649 }
njn25e49d8e72002-09-23 09:36:25 +00003650}
3651
3652static
njndbf7ca72006-03-31 11:57:59 +00003653void check_mem_is_defined ( CorePart part, ThreadId tid, Char* s,
nethercote451eae92004-11-02 13:06:32 +00003654 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003655{
sewardj7cf4e6b2008-05-01 20:24:26 +00003656 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003657 Addr bad_addr;
sewardj7cf4e6b2008-05-01 20:24:26 +00003658 MC_ReadResult res = is_mem_defined ( base, size, &bad_addr, &otag );
sewardj45f4e7c2005-09-27 19:20:21 +00003659
nethercote8b76fe52004-11-08 19:20:09 +00003660 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003661 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj45f4e7c2005-09-27 19:20:21 +00003662
njn25e49d8e72002-09-23 09:36:25 +00003663 switch (part) {
3664 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003665 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3666 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003667 break;
3668
njn25e49d8e72002-09-23 09:36:25 +00003669 /* If we're being asked to jump to a silly address, record an error
3670 message before potentially crashing the entire system. */
3671 case Vg_CoreTranslate:
sewardj7ce71662008-05-02 10:33:15 +00003672 MC_(record_jump_error)( tid, bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003673 break;
3674
3675 default:
njndbf7ca72006-03-31 11:57:59 +00003676 VG_(tool_panic)("check_mem_is_defined: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003677 }
3678 }
njn25e49d8e72002-09-23 09:36:25 +00003679}
3680
3681static
njndbf7ca72006-03-31 11:57:59 +00003682void check_mem_is_defined_asciiz ( CorePart part, ThreadId tid,
njn5c004e42002-11-18 11:04:50 +00003683 Char* s, Addr str )
njn25e49d8e72002-09-23 09:36:25 +00003684{
nethercote8b76fe52004-11-08 19:20:09 +00003685 MC_ReadResult res;
njn5ab96ac2005-05-08 02:59:50 +00003686 Addr bad_addr = 0; // shut GCC up
sewardj7cf4e6b2008-05-01 20:24:26 +00003687 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003688
njnca82cc02004-11-22 17:18:48 +00003689 tl_assert(part == Vg_CoreSysCall);
sewardj7cf4e6b2008-05-01 20:24:26 +00003690 res = mc_is_defined_asciiz ( (Addr)str, &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00003691 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003692 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj7ce71662008-05-02 10:33:15 +00003693 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3694 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003695 }
njn25e49d8e72002-09-23 09:36:25 +00003696}
3697
njn25e49d8e72002-09-23 09:36:25 +00003698static
sewardj9c606bd2008-09-18 18:12:50 +00003699void mc_new_mem_startup( Addr a, SizeT len,
3700 Bool rr, Bool ww, Bool xx, ULong di_handle )
njn25e49d8e72002-09-23 09:36:25 +00003701{
njndbf7ca72006-03-31 11:57:59 +00003702 /* Ignore the permissions, just make it defined. Seems to work... */
njnba7b4582006-09-21 15:59:30 +00003703 // Because code is defined, initialised variables get put in the data
3704 // segment and are defined, and uninitialised variables get put in the
3705 // bss segment and are auto-zeroed (and so defined).
3706 //
3707 // It's possible that there will be padding between global variables.
3708 // This will also be auto-zeroed, and marked as defined by Memcheck. If
3709 // a program uses it, Memcheck will not complain. This is arguably a
3710 // false negative, but it's a grey area -- the behaviour is defined (the
3711 // padding is zeroed) but it's probably not what the user intended. And
3712 // we can't avoid it.
barta0b6b2c2008-07-07 06:49:24 +00003713 DEBUG("mc_new_mem_startup(%#lx, %llu, rr=%u, ww=%u, xx=%u)\n",
njndbf7ca72006-03-31 11:57:59 +00003714 a, (ULong)len, rr, ww, xx);
3715 MC_(make_mem_defined)(a, len);
njn25e49d8e72002-09-23 09:36:25 +00003716}
3717
3718static
sewardj9c606bd2008-09-18 18:12:50 +00003719void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
3720 ULong di_handle )
njn25e49d8e72002-09-23 09:36:25 +00003721{
njndbf7ca72006-03-31 11:57:59 +00003722 MC_(make_mem_defined)(a, len);
njn25e49d8e72002-09-23 09:36:25 +00003723}
3724
njncf45fd42004-11-24 16:30:22 +00003725static
3726void mc_post_mem_write(CorePart part, ThreadId tid, Addr a, SizeT len)
3727{
njndbf7ca72006-03-31 11:57:59 +00003728 MC_(make_mem_defined)(a, len);
njncf45fd42004-11-24 16:30:22 +00003729}
njn25e49d8e72002-09-23 09:36:25 +00003730
sewardj45d94cc2005-04-20 14:44:11 +00003731
njn25e49d8e72002-09-23 09:36:25 +00003732/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00003733/*--- Register event handlers ---*/
3734/*------------------------------------------------------------*/
3735
sewardj7cf4e6b2008-05-01 20:24:26 +00003736/* Try and get a nonzero origin for the guest state section of thread
3737 tid characterised by (offset,size). Return 0 if nothing to show
3738 for it. */
3739static UInt mb_get_origin_for_guest_offset ( ThreadId tid,
3740 Int offset, SizeT size )
3741{
3742 Int sh2off;
3743 UChar area[6];
3744 UInt otag;
3745 sh2off = MC_(get_otrack_shadow_offset)( offset, size );
3746 if (sh2off == -1)
3747 return 0; /* This piece of guest state is not tracked */
3748 tl_assert(sh2off >= 0);
3749 tl_assert(0 == (sh2off % 4));
3750 area[0] = 0x31;
3751 area[5] = 0x27;
3752 VG_(get_shadow_regs_area)( tid, &area[1], 2/*shadowno*/,sh2off,4 );
3753 tl_assert(area[0] == 0x31);
3754 tl_assert(area[5] == 0x27);
3755 otag = *(UInt*)&area[1];
3756 return otag;
3757}
3758
3759
sewardj45d94cc2005-04-20 14:44:11 +00003760/* When some chunk of guest state is written, mark the corresponding
3761 shadow area as valid. This is used to initialise arbitrarily large
sewardj62eae5f2006-01-17 01:58:24 +00003762 chunks of guest state, hence the _SIZE value, which has to be as
3763 big as the biggest guest state.
sewardj45d94cc2005-04-20 14:44:11 +00003764*/
3765static void mc_post_reg_write ( CorePart part, ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00003766 PtrdiffT offset, SizeT size)
njnd3040452003-05-19 15:04:06 +00003767{
sewardj05a46732006-10-17 01:28:10 +00003768# define MAX_REG_WRITE_SIZE 1408
cerion21082042005-12-06 19:07:08 +00003769 UChar area[MAX_REG_WRITE_SIZE];
3770 tl_assert(size <= MAX_REG_WRITE_SIZE);
njn1d0825f2006-03-27 11:37:07 +00003771 VG_(memset)(area, V_BITS8_DEFINED, size);
sewardj7cf4e6b2008-05-01 20:24:26 +00003772 VG_(set_shadow_regs_area)( tid, 1/*shadowNo*/,offset,size, area );
cerion21082042005-12-06 19:07:08 +00003773# undef MAX_REG_WRITE_SIZE
njnd3040452003-05-19 15:04:06 +00003774}
3775
sewardj45d94cc2005-04-20 14:44:11 +00003776static
3777void mc_post_reg_write_clientcall ( ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00003778 PtrdiffT offset, SizeT size, Addr f)
njnd3040452003-05-19 15:04:06 +00003779{
njncf45fd42004-11-24 16:30:22 +00003780 mc_post_reg_write(/*dummy*/0, tid, offset, size);
njnd3040452003-05-19 15:04:06 +00003781}
3782
sewardj45d94cc2005-04-20 14:44:11 +00003783/* Look at the definedness of the guest's shadow state for
3784 [offset, offset+len). If any part of that is undefined, record
3785 a parameter error.
3786*/
3787static void mc_pre_reg_read ( CorePart part, ThreadId tid, Char* s,
njnc4431bf2009-01-15 21:29:24 +00003788 PtrdiffT offset, SizeT size)
nethercote8b76fe52004-11-08 19:20:09 +00003789{
sewardj45d94cc2005-04-20 14:44:11 +00003790 Int i;
3791 Bool bad;
sewardj7cf4e6b2008-05-01 20:24:26 +00003792 UInt otag;
sewardj45d94cc2005-04-20 14:44:11 +00003793
3794 UChar area[16];
3795 tl_assert(size <= 16);
3796
sewardj7cf4e6b2008-05-01 20:24:26 +00003797 VG_(get_shadow_regs_area)( tid, area, 1/*shadowNo*/,offset,size );
sewardj45d94cc2005-04-20 14:44:11 +00003798
3799 bad = False;
3800 for (i = 0; i < size; i++) {
njn1d0825f2006-03-27 11:37:07 +00003801 if (area[i] != V_BITS8_DEFINED) {
sewardj2c27f702005-05-03 18:19:05 +00003802 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00003803 break;
3804 }
nethercote8b76fe52004-11-08 19:20:09 +00003805 }
3806
sewardj7cf4e6b2008-05-01 20:24:26 +00003807 if (!bad)
3808 return;
3809
3810 /* We've found some undefinedness. See if we can also find an
3811 origin for it. */
3812 otag = mb_get_origin_for_guest_offset( tid, offset, size );
sewardj7ce71662008-05-02 10:33:15 +00003813 MC_(record_regparam_error) ( tid, s, otag );
nethercote8b76fe52004-11-08 19:20:09 +00003814}
njnd3040452003-05-19 15:04:06 +00003815
njn25e49d8e72002-09-23 09:36:25 +00003816
sewardj6cf40ff2005-04-20 22:31:26 +00003817/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00003818/*--- Functions called directly from generated code: ---*/
3819/*--- Load/store handlers. ---*/
sewardj6cf40ff2005-04-20 22:31:26 +00003820/*------------------------------------------------------------*/
3821
njn1d0825f2006-03-27 11:37:07 +00003822/* Types: LOADV32, LOADV16, LOADV8 are:
sewardj6cf40ff2005-04-20 22:31:26 +00003823 UWord fn ( Addr a )
3824 so they return 32-bits on 32-bit machines and 64-bits on
3825 64-bit machines. Addr has the same size as a host word.
3826
njn1d0825f2006-03-27 11:37:07 +00003827 LOADV64 is always ULong fn ( Addr a )
sewardj6cf40ff2005-04-20 22:31:26 +00003828
njn1d0825f2006-03-27 11:37:07 +00003829 Similarly for STOREV8, STOREV16, STOREV32, the supplied vbits
3830 are a UWord, and for STOREV64 they are a ULong.
sewardj6cf40ff2005-04-20 22:31:26 +00003831*/
3832
sewardj7244e712008-05-02 12:35:48 +00003833/* If any part of '_a' indicated by the mask is 1, either '_a' is not
3834 naturally '_sz/8'-aligned, or it exceeds the range covered by the
3835 primary map. This is all very tricky (and important!), so let's
3836 work through the maths by hand (below), *and* assert for these
3837 values at startup. */
3838#define MASK(_szInBytes) \
3839 ( ~((0x10000UL-(_szInBytes)) | ((N_PRIMARY_MAP-1) << 16)) )
3840
3841/* MASK only exists so as to define this macro. */
3842#define UNALIGNED_OR_HIGH(_a,_szInBits) \
3843 ((_a) & MASK((_szInBits>>3)))
3844
3845/* On a 32-bit machine:
3846
3847 N_PRIMARY_BITS == 16, so
3848 N_PRIMARY_MAP == 0x10000, so
3849 N_PRIMARY_MAP-1 == 0xFFFF, so
3850 (N_PRIMARY_MAP-1) << 16 == 0xFFFF0000, and so
3851
3852 MASK(1) = ~ ( (0x10000 - 1) | 0xFFFF0000 )
3853 = ~ ( 0xFFFF | 0xFFFF0000 )
3854 = ~ 0xFFFF'FFFF
3855 = 0
3856
3857 MASK(2) = ~ ( (0x10000 - 2) | 0xFFFF0000 )
3858 = ~ ( 0xFFFE | 0xFFFF0000 )
3859 = ~ 0xFFFF'FFFE
3860 = 1
3861
3862 MASK(4) = ~ ( (0x10000 - 4) | 0xFFFF0000 )
3863 = ~ ( 0xFFFC | 0xFFFF0000 )
3864 = ~ 0xFFFF'FFFC
3865 = 3
3866
3867 MASK(8) = ~ ( (0x10000 - 8) | 0xFFFF0000 )
3868 = ~ ( 0xFFF8 | 0xFFFF0000 )
3869 = ~ 0xFFFF'FFF8
3870 = 7
3871
3872 Hence in the 32-bit case, "a & MASK(1/2/4/8)" is a nonzero value
3873 precisely when a is not 1/2/4/8-bytes aligned. And obviously, for
3874 the 1-byte alignment case, it is always a zero value, since MASK(1)
3875 is zero. All as expected.
3876
3877 On a 64-bit machine, it's more complex, since we're testing
3878 simultaneously for misalignment and for the address being at or
3879 above 32G:
3880
3881 N_PRIMARY_BITS == 19, so
3882 N_PRIMARY_MAP == 0x80000, so
3883 N_PRIMARY_MAP-1 == 0x7FFFF, so
3884 (N_PRIMARY_MAP-1) << 16 == 0x7FFFF'0000, and so
3885
3886 MASK(1) = ~ ( (0x10000 - 1) | 0x7FFFF'0000 )
3887 = ~ ( 0xFFFF | 0x7FFFF'0000 )
3888 = ~ 0x7FFFF'FFFF
3889 = 0xFFFF'FFF8'0000'0000
3890
3891 MASK(2) = ~ ( (0x10000 - 2) | 0x7FFFF'0000 )
3892 = ~ ( 0xFFFE | 0x7FFFF'0000 )
3893 = ~ 0x7FFFF'FFFE
3894 = 0xFFFF'FFF8'0000'0001
3895
3896 MASK(4) = ~ ( (0x10000 - 4) | 0x7FFFF'0000 )
3897 = ~ ( 0xFFFC | 0x7FFFF'0000 )
3898 = ~ 0x7FFFF'FFFC
3899 = 0xFFFF'FFF8'0000'0003
3900
3901 MASK(8) = ~ ( (0x10000 - 8) | 0x7FFFF'0000 )
3902 = ~ ( 0xFFF8 | 0x7FFFF'0000 )
3903 = ~ 0x7FFFF'FFF8
3904 = 0xFFFF'FFF8'0000'0007
3905*/
njn1d0825f2006-03-27 11:37:07 +00003906
3907
sewardj95448072004-11-22 20:19:51 +00003908/* ------------------------ Size = 8 ------------------------ */
3909
njn1d0825f2006-03-27 11:37:07 +00003910static INLINE
3911ULong mc_LOADV64 ( Addr a, Bool isBigEndian )
3912{
njn1d0825f2006-03-27 11:37:07 +00003913 PROF_EVENT(200, "mc_LOADV64");
3914
3915#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00003916 return mc_LOADVn_slow( a, 64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003917#else
njneccf7c02009-01-19 23:42:45 +00003918 {
3919 UWord sm_off16, vabits16;
3920 SecMap* sm;
sewardjf9d81612005-04-23 23:25:49 +00003921
njneccf7c02009-01-19 23:42:45 +00003922 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
3923 PROF_EVENT(201, "mc_LOADV64-slow1");
3924 return (ULong)mc_LOADVn_slow( a, 64, isBigEndian );
3925 }
njn1d0825f2006-03-27 11:37:07 +00003926
njneccf7c02009-01-19 23:42:45 +00003927 sm = get_secmap_for_reading_low(a);
3928 sm_off16 = SM_OFF_16(a);
3929 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
3930
3931 // Handle common case quickly: a is suitably aligned, is mapped, and
3932 // addressible.
3933 // Convert V bits from compact memory form to expanded register form.
3934 if (LIKELY(vabits16 == VA_BITS16_DEFINED)) {
3935 return V_BITS64_DEFINED;
3936 } else if (LIKELY(vabits16 == VA_BITS16_UNDEFINED)) {
3937 return V_BITS64_UNDEFINED;
3938 } else {
3939 /* Slow case: the 8 bytes are not all-defined or all-undefined. */
3940 PROF_EVENT(202, "mc_LOADV64-slow2");
3941 return mc_LOADVn_slow( a, 64, isBigEndian );
3942 }
njn1d0825f2006-03-27 11:37:07 +00003943 }
3944#endif
3945}
3946
3947VG_REGPARM(1) ULong MC_(helperc_LOADV64be) ( Addr a )
3948{
3949 return mc_LOADV64(a, True);
3950}
3951VG_REGPARM(1) ULong MC_(helperc_LOADV64le) ( Addr a )
3952{
3953 return mc_LOADV64(a, False);
3954}
sewardjf9d81612005-04-23 23:25:49 +00003955
sewardjf9d81612005-04-23 23:25:49 +00003956
njn1d0825f2006-03-27 11:37:07 +00003957static INLINE
njn4cf530b2006-04-06 13:33:48 +00003958void mc_STOREV64 ( Addr a, ULong vbits64, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00003959{
njn1d0825f2006-03-27 11:37:07 +00003960 PROF_EVENT(210, "mc_STOREV64");
3961
3962#ifndef PERF_FAST_STOREV
3963 // XXX: this slow case seems to be marginally faster than the fast case!
3964 // Investigate further.
njn4cf530b2006-04-06 13:33:48 +00003965 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003966#else
njn1d0825f2006-03-27 11:37:07 +00003967 {
njneccf7c02009-01-19 23:42:45 +00003968 UWord sm_off16, vabits16;
3969 SecMap* sm;
3970
3971 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
3972 PROF_EVENT(211, "mc_STOREV64-slow1");
3973 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
3974 return;
3975 }
3976
3977 sm = get_secmap_for_reading_low(a);
3978 sm_off16 = SM_OFF_16(a);
3979 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
3980
3981 if (LIKELY( !is_distinguished_sm(sm) &&
3982 (VA_BITS16_DEFINED == vabits16 ||
3983 VA_BITS16_UNDEFINED == vabits16) ))
3984 {
3985 /* Handle common case quickly: a is suitably aligned, */
3986 /* is mapped, and is addressible. */
3987 // Convert full V-bits in register to compact 2-bit form.
3988 if (V_BITS64_DEFINED == vbits64) {
3989 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_DEFINED;
3990 } else if (V_BITS64_UNDEFINED == vbits64) {
3991 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_UNDEFINED;
3992 } else {
3993 /* Slow but general case -- writing partially defined bytes. */
3994 PROF_EVENT(212, "mc_STOREV64-slow2");
3995 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
3996 }
njn1d0825f2006-03-27 11:37:07 +00003997 } else {
njneccf7c02009-01-19 23:42:45 +00003998 /* Slow but general case. */
3999 PROF_EVENT(213, "mc_STOREV64-slow3");
njn4cf530b2006-04-06 13:33:48 +00004000 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004001 }
njn1d0825f2006-03-27 11:37:07 +00004002 }
4003#endif
4004}
4005
njn4cf530b2006-04-06 13:33:48 +00004006VG_REGPARM(1) void MC_(helperc_STOREV64be) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00004007{
njn4cf530b2006-04-06 13:33:48 +00004008 mc_STOREV64(a, vbits64, True);
njn1d0825f2006-03-27 11:37:07 +00004009}
njn4cf530b2006-04-06 13:33:48 +00004010VG_REGPARM(1) void MC_(helperc_STOREV64le) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00004011{
njn4cf530b2006-04-06 13:33:48 +00004012 mc_STOREV64(a, vbits64, False);
njn1d0825f2006-03-27 11:37:07 +00004013}
sewardj95448072004-11-22 20:19:51 +00004014
sewardj95448072004-11-22 20:19:51 +00004015
4016/* ------------------------ Size = 4 ------------------------ */
4017
njn1d0825f2006-03-27 11:37:07 +00004018static INLINE
4019UWord mc_LOADV32 ( Addr a, Bool isBigEndian )
4020{
njn1d0825f2006-03-27 11:37:07 +00004021 PROF_EVENT(220, "mc_LOADV32");
4022
4023#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004024 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004025#else
njneccf7c02009-01-19 23:42:45 +00004026 {
4027 UWord sm_off, vabits8;
4028 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004029
njneccf7c02009-01-19 23:42:45 +00004030 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
4031 PROF_EVENT(221, "mc_LOADV32-slow1");
4032 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
4033 }
njn1d0825f2006-03-27 11:37:07 +00004034
njneccf7c02009-01-19 23:42:45 +00004035 sm = get_secmap_for_reading_low(a);
4036 sm_off = SM_OFF(a);
4037 vabits8 = sm->vabits8[sm_off];
4038
4039 // Handle common case quickly: a is suitably aligned, is mapped, and the
4040 // entire word32 it lives in is addressible.
4041 // Convert V bits from compact memory form to expanded register form.
4042 // For 64-bit platforms, set the high 32 bits of retval to 1 (undefined).
4043 // Almost certainly not necessary, but be paranoid.
4044 if (LIKELY(vabits8 == VA_BITS8_DEFINED)) {
4045 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_DEFINED);
4046 } else if (LIKELY(vabits8 == VA_BITS8_UNDEFINED)) {
4047 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_UNDEFINED);
4048 } else {
4049 /* Slow case: the 4 bytes are not all-defined or all-undefined. */
4050 PROF_EVENT(222, "mc_LOADV32-slow2");
4051 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
4052 }
njn1d0825f2006-03-27 11:37:07 +00004053 }
4054#endif
4055}
4056
4057VG_REGPARM(1) UWord MC_(helperc_LOADV32be) ( Addr a )
4058{
4059 return mc_LOADV32(a, True);
4060}
4061VG_REGPARM(1) UWord MC_(helperc_LOADV32le) ( Addr a )
4062{
4063 return mc_LOADV32(a, False);
4064}
sewardjc1a2cda2005-04-21 17:34:00 +00004065
sewardjc1a2cda2005-04-21 17:34:00 +00004066
njn1d0825f2006-03-27 11:37:07 +00004067static INLINE
njn4cf530b2006-04-06 13:33:48 +00004068void mc_STOREV32 ( Addr a, UWord vbits32, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004069{
njn1d0825f2006-03-27 11:37:07 +00004070 PROF_EVENT(230, "mc_STOREV32");
4071
4072#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004073 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004074#else
njneccf7c02009-01-19 23:42:45 +00004075 {
4076 UWord sm_off, vabits8;
4077 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004078
njneccf7c02009-01-19 23:42:45 +00004079 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
4080 PROF_EVENT(231, "mc_STOREV32-slow1");
4081 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004082 return;
njneccf7c02009-01-19 23:42:45 +00004083 }
4084
4085 sm = get_secmap_for_reading_low(a);
4086 sm_off = SM_OFF(a);
4087 vabits8 = sm->vabits8[sm_off];
4088
4089 // Cleverness: sometimes we don't have to write the shadow memory at
4090 // all, if we can tell that what we want to write is the same as what is
4091 // already there. The 64/16/8 bit cases also have cleverness at this
4092 // point, but it works a little differently to the code below.
4093 if (V_BITS32_DEFINED == vbits32) {
4094 if (vabits8 == (UInt)VA_BITS8_DEFINED) {
4095 return;
4096 } else if (!is_distinguished_sm(sm) && VA_BITS8_UNDEFINED == vabits8) {
4097 sm->vabits8[sm_off] = (UInt)VA_BITS8_DEFINED;
4098 } else {
4099 // not defined/undefined, or distinguished and changing state
4100 PROF_EVENT(232, "mc_STOREV32-slow2");
4101 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
4102 }
4103 } else if (V_BITS32_UNDEFINED == vbits32) {
4104 if (vabits8 == (UInt)VA_BITS8_UNDEFINED) {
4105 return;
4106 } else if (!is_distinguished_sm(sm) && VA_BITS8_DEFINED == vabits8) {
4107 sm->vabits8[sm_off] = (UInt)VA_BITS8_UNDEFINED;
4108 } else {
4109 // not defined/undefined, or distinguished and changing state
4110 PROF_EVENT(233, "mc_STOREV32-slow3");
4111 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
4112 }
njn1d0825f2006-03-27 11:37:07 +00004113 } else {
njneccf7c02009-01-19 23:42:45 +00004114 // Partially defined word
4115 PROF_EVENT(234, "mc_STOREV32-slow4");
njn4cf530b2006-04-06 13:33:48 +00004116 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004117 }
njn1d0825f2006-03-27 11:37:07 +00004118 }
njn1d0825f2006-03-27 11:37:07 +00004119#endif
4120}
4121
njn4cf530b2006-04-06 13:33:48 +00004122VG_REGPARM(2) void MC_(helperc_STOREV32be) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00004123{
njn4cf530b2006-04-06 13:33:48 +00004124 mc_STOREV32(a, vbits32, True);
njn1d0825f2006-03-27 11:37:07 +00004125}
njn4cf530b2006-04-06 13:33:48 +00004126VG_REGPARM(2) void MC_(helperc_STOREV32le) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00004127{
njn4cf530b2006-04-06 13:33:48 +00004128 mc_STOREV32(a, vbits32, False);
njn1d0825f2006-03-27 11:37:07 +00004129}
njn25e49d8e72002-09-23 09:36:25 +00004130
njn25e49d8e72002-09-23 09:36:25 +00004131
sewardj95448072004-11-22 20:19:51 +00004132/* ------------------------ Size = 2 ------------------------ */
4133
njn1d0825f2006-03-27 11:37:07 +00004134static INLINE
4135UWord mc_LOADV16 ( Addr a, Bool isBigEndian )
4136{
njn1d0825f2006-03-27 11:37:07 +00004137 PROF_EVENT(240, "mc_LOADV16");
4138
4139#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004140 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004141#else
njneccf7c02009-01-19 23:42:45 +00004142 {
4143 UWord sm_off, vabits8;
4144 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004145
njneccf7c02009-01-19 23:42:45 +00004146 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
4147 PROF_EVENT(241, "mc_LOADV16-slow1");
njn45e81252006-03-28 12:35:08 +00004148 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004149 }
njneccf7c02009-01-19 23:42:45 +00004150
4151 sm = get_secmap_for_reading_low(a);
4152 sm_off = SM_OFF(a);
4153 vabits8 = sm->vabits8[sm_off];
4154 // Handle common case quickly: a is suitably aligned, is mapped, and is
4155 // addressible.
4156 // Convert V bits from compact memory form to expanded register form
4157 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS16_DEFINED; }
4158 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS16_UNDEFINED; }
4159 else {
4160 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
4161 // the two sub-bytes.
4162 UChar vabits4 = extract_vabits4_from_vabits8(a, vabits8);
4163 if (vabits4 == VA_BITS4_DEFINED ) { return V_BITS16_DEFINED; }
4164 else if (vabits4 == VA_BITS4_UNDEFINED) { return V_BITS16_UNDEFINED; }
4165 else {
4166 /* Slow case: the two bytes are not all-defined or all-undefined. */
4167 PROF_EVENT(242, "mc_LOADV16-slow2");
4168 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
4169 }
4170 }
njn1d0825f2006-03-27 11:37:07 +00004171 }
4172#endif
4173}
4174
4175VG_REGPARM(1) UWord MC_(helperc_LOADV16be) ( Addr a )
4176{
4177 return mc_LOADV16(a, True);
4178}
4179VG_REGPARM(1) UWord MC_(helperc_LOADV16le) ( Addr a )
4180{
4181 return mc_LOADV16(a, False);
4182}
sewardjc1a2cda2005-04-21 17:34:00 +00004183
sewardjc1a2cda2005-04-21 17:34:00 +00004184
njn1d0825f2006-03-27 11:37:07 +00004185static INLINE
njn4cf530b2006-04-06 13:33:48 +00004186void mc_STOREV16 ( Addr a, UWord vbits16, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004187{
njn1d0825f2006-03-27 11:37:07 +00004188 PROF_EVENT(250, "mc_STOREV16");
4189
4190#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004191 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004192#else
njn1d0825f2006-03-27 11:37:07 +00004193 {
njneccf7c02009-01-19 23:42:45 +00004194 UWord sm_off, vabits8;
4195 SecMap* sm;
4196
4197 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
4198 PROF_EVENT(251, "mc_STOREV16-slow1");
4199 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
4200 return;
4201 }
4202
4203 sm = get_secmap_for_reading_low(a);
4204 sm_off = SM_OFF(a);
4205 vabits8 = sm->vabits8[sm_off];
4206 if (LIKELY( !is_distinguished_sm(sm) &&
4207 (VA_BITS8_DEFINED == vabits8 ||
4208 VA_BITS8_UNDEFINED == vabits8) ))
4209 {
4210 /* Handle common case quickly: a is suitably aligned, */
4211 /* is mapped, and is addressible. */
4212 // Convert full V-bits in register to compact 2-bit form.
4213 if (V_BITS16_DEFINED == vbits16) {
4214 insert_vabits4_into_vabits8( a, VA_BITS4_DEFINED ,
4215 &(sm->vabits8[sm_off]) );
4216 } else if (V_BITS16_UNDEFINED == vbits16) {
4217 insert_vabits4_into_vabits8( a, VA_BITS4_UNDEFINED,
4218 &(sm->vabits8[sm_off]) );
4219 } else {
4220 /* Slow but general case -- writing partially defined bytes. */
4221 PROF_EVENT(252, "mc_STOREV16-slow2");
4222 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
4223 }
njn1d0825f2006-03-27 11:37:07 +00004224 } else {
njneccf7c02009-01-19 23:42:45 +00004225 /* Slow but general case. */
4226 PROF_EVENT(253, "mc_STOREV16-slow3");
njn4cf530b2006-04-06 13:33:48 +00004227 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004228 }
njn1d0825f2006-03-27 11:37:07 +00004229 }
4230#endif
4231}
njn25e49d8e72002-09-23 09:36:25 +00004232
njn4cf530b2006-04-06 13:33:48 +00004233VG_REGPARM(2) void MC_(helperc_STOREV16be) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00004234{
njn4cf530b2006-04-06 13:33:48 +00004235 mc_STOREV16(a, vbits16, True);
njn1d0825f2006-03-27 11:37:07 +00004236}
njn4cf530b2006-04-06 13:33:48 +00004237VG_REGPARM(2) void MC_(helperc_STOREV16le) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00004238{
njn4cf530b2006-04-06 13:33:48 +00004239 mc_STOREV16(a, vbits16, False);
njn1d0825f2006-03-27 11:37:07 +00004240}
sewardj5d28efc2005-04-21 22:16:29 +00004241
njn25e49d8e72002-09-23 09:36:25 +00004242
sewardj95448072004-11-22 20:19:51 +00004243/* ------------------------ Size = 1 ------------------------ */
sewardj8cf88b72005-07-08 01:29:33 +00004244/* Note: endianness is irrelevant for size == 1 */
sewardj95448072004-11-22 20:19:51 +00004245
njnaf839f52005-06-23 03:27:57 +00004246VG_REGPARM(1)
njn1d0825f2006-03-27 11:37:07 +00004247UWord MC_(helperc_LOADV8) ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +00004248{
njn1d0825f2006-03-27 11:37:07 +00004249 PROF_EVENT(260, "mc_LOADV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004250
njn1d0825f2006-03-27 11:37:07 +00004251#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004252 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004253#else
njneccf7c02009-01-19 23:42:45 +00004254 {
4255 UWord sm_off, vabits8;
4256 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004257
njneccf7c02009-01-19 23:42:45 +00004258 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
4259 PROF_EVENT(261, "mc_LOADV8-slow1");
njn45e81252006-03-28 12:35:08 +00004260 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004261 }
njneccf7c02009-01-19 23:42:45 +00004262
4263 sm = get_secmap_for_reading_low(a);
4264 sm_off = SM_OFF(a);
4265 vabits8 = sm->vabits8[sm_off];
4266 // Convert V bits from compact memory form to expanded register form
4267 // Handle common case quickly: a is mapped, and the entire
4268 // word32 it lives in is addressible.
4269 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS8_DEFINED; }
4270 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS8_UNDEFINED; }
4271 else {
4272 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
4273 // the single byte.
4274 UChar vabits2 = extract_vabits2_from_vabits8(a, vabits8);
4275 if (vabits2 == VA_BITS2_DEFINED ) { return V_BITS8_DEFINED; }
4276 else if (vabits2 == VA_BITS2_UNDEFINED) { return V_BITS8_UNDEFINED; }
4277 else {
4278 /* Slow case: the byte is not all-defined or all-undefined. */
4279 PROF_EVENT(262, "mc_LOADV8-slow2");
4280 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
4281 }
4282 }
sewardjc1a2cda2005-04-21 17:34:00 +00004283 }
njn1d0825f2006-03-27 11:37:07 +00004284#endif
njn25e49d8e72002-09-23 09:36:25 +00004285}
4286
sewardjc1a2cda2005-04-21 17:34:00 +00004287
njnaf839f52005-06-23 03:27:57 +00004288VG_REGPARM(2)
njn4cf530b2006-04-06 13:33:48 +00004289void MC_(helperc_STOREV8) ( Addr a, UWord vbits8 )
njn25e49d8e72002-09-23 09:36:25 +00004290{
njn1d0825f2006-03-27 11:37:07 +00004291 PROF_EVENT(270, "mc_STOREV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004292
njn1d0825f2006-03-27 11:37:07 +00004293#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004294 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004295#else
njn1d0825f2006-03-27 11:37:07 +00004296 {
njneccf7c02009-01-19 23:42:45 +00004297 UWord sm_off, vabits8;
4298 SecMap* sm;
4299
4300 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
4301 PROF_EVENT(271, "mc_STOREV8-slow1");
4302 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
4303 return;
4304 }
4305
4306 sm = get_secmap_for_reading_low(a);
4307 sm_off = SM_OFF(a);
4308 vabits8 = sm->vabits8[sm_off];
4309 if (LIKELY
4310 ( !is_distinguished_sm(sm) &&
4311 ( (VA_BITS8_DEFINED == vabits8 || VA_BITS8_UNDEFINED == vabits8)
4312 || (VA_BITS2_NOACCESS != extract_vabits2_from_vabits8(a, vabits8))
4313 )
4314 )
4315 )
4316 {
4317 /* Handle common case quickly: a is mapped, the entire word32 it
4318 lives in is addressible. */
4319 // Convert full V-bits in register to compact 2-bit form.
4320 if (V_BITS8_DEFINED == vbits8) {
4321 insert_vabits2_into_vabits8( a, VA_BITS2_DEFINED,
4322 &(sm->vabits8[sm_off]) );
4323 } else if (V_BITS8_UNDEFINED == vbits8) {
4324 insert_vabits2_into_vabits8( a, VA_BITS2_UNDEFINED,
4325 &(sm->vabits8[sm_off]) );
4326 } else {
4327 /* Slow but general case -- writing partially defined bytes. */
4328 PROF_EVENT(272, "mc_STOREV8-slow2");
4329 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
4330 }
njn1d0825f2006-03-27 11:37:07 +00004331 } else {
njneccf7c02009-01-19 23:42:45 +00004332 /* Slow but general case. */
4333 PROF_EVENT(273, "mc_STOREV8-slow3");
njn4cf530b2006-04-06 13:33:48 +00004334 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004335 }
sewardjc1a2cda2005-04-21 17:34:00 +00004336 }
njn1d0825f2006-03-27 11:37:07 +00004337#endif
njn25e49d8e72002-09-23 09:36:25 +00004338}
4339
4340
sewardjc859fbf2005-04-22 21:10:28 +00004341/*------------------------------------------------------------*/
4342/*--- Functions called directly from generated code: ---*/
4343/*--- Value-check failure handlers. ---*/
4344/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004345
sewardj7cf4e6b2008-05-01 20:24:26 +00004346/* Call these ones when an origin is available ... */
4347VG_REGPARM(1)
4348void MC_(helperc_value_check0_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004349 MC_(record_cond_error) ( VG_(get_running_tid)(), (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004350}
4351
sewardj7cf4e6b2008-05-01 20:24:26 +00004352VG_REGPARM(1)
4353void MC_(helperc_value_check1_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004354 MC_(record_value_error) ( VG_(get_running_tid)(), 1, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004355}
4356
sewardj7cf4e6b2008-05-01 20:24:26 +00004357VG_REGPARM(1)
4358void MC_(helperc_value_check4_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004359 MC_(record_value_error) ( VG_(get_running_tid)(), 4, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004360}
4361
sewardj7cf4e6b2008-05-01 20:24:26 +00004362VG_REGPARM(1)
4363void MC_(helperc_value_check8_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004364 MC_(record_value_error) ( VG_(get_running_tid)(), 8, (UInt)origin );
sewardj11bcc4e2005-04-23 22:38:38 +00004365}
4366
sewardj7cf4e6b2008-05-01 20:24:26 +00004367VG_REGPARM(2)
4368void MC_(helperc_value_checkN_fail_w_o) ( HWord sz, UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004369 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, (UInt)origin );
sewardj7cf4e6b2008-05-01 20:24:26 +00004370}
4371
4372/* ... and these when an origin isn't available. */
4373
4374VG_REGPARM(0)
4375void MC_(helperc_value_check0_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004376 MC_(record_cond_error) ( VG_(get_running_tid)(), 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004377}
4378
4379VG_REGPARM(0)
4380void MC_(helperc_value_check1_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004381 MC_(record_value_error) ( VG_(get_running_tid)(), 1, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004382}
4383
4384VG_REGPARM(0)
4385void MC_(helperc_value_check4_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004386 MC_(record_value_error) ( VG_(get_running_tid)(), 4, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004387}
4388
4389VG_REGPARM(0)
4390void MC_(helperc_value_check8_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004391 MC_(record_value_error) ( VG_(get_running_tid)(), 8, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004392}
4393
4394VG_REGPARM(1)
4395void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) {
sewardj7ce71662008-05-02 10:33:15 +00004396 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, 0/*origin*/ );
sewardj95448072004-11-22 20:19:51 +00004397}
4398
njn25e49d8e72002-09-23 09:36:25 +00004399
sewardjc2c12c22006-03-08 13:20:09 +00004400/*------------------------------------------------------------*/
4401/*--- Metadata get/set functions, for client requests. ---*/
4402/*------------------------------------------------------------*/
4403
njn1d0825f2006-03-27 11:37:07 +00004404// Nb: this expands the V+A bits out into register-form V bits, even though
4405// they're in memory. This is for backward compatibility, and because it's
4406// probably what the user wants.
4407
4408/* Copy Vbits from/to address 'a'. Returns: 1 == OK, 2 == alignment
sewardjc2c12c22006-03-08 13:20:09 +00004409 error [no longer used], 3 == addressing error. */
njn718d3b12006-12-16 00:54:12 +00004410/* Nb: We used to issue various definedness/addressability errors from here,
4411 but we took them out because they ranged from not-very-helpful to
4412 downright annoying, and they complicated the error data structures. */
sewardjc2c12c22006-03-08 13:20:09 +00004413static Int mc_get_or_set_vbits_for_client (
4414 ThreadId tid,
njn1d0825f2006-03-27 11:37:07 +00004415 Addr a,
4416 Addr vbits,
4417 SizeT szB,
sewardjc2c12c22006-03-08 13:20:09 +00004418 Bool setting /* True <=> set vbits, False <=> get vbits */
4419)
4420{
sewardjc2c12c22006-03-08 13:20:09 +00004421 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00004422 Bool ok;
4423 UChar vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004424
njn1d0825f2006-03-27 11:37:07 +00004425 /* Check that arrays are addressible before doing any getting/setting. */
4426 for (i = 0; i < szB; i++) {
njn718d3b12006-12-16 00:54:12 +00004427 if (VA_BITS2_NOACCESS == get_vabits2(a + i) ||
4428 VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
njn1d0825f2006-03-27 11:37:07 +00004429 return 3;
sewardjc2c12c22006-03-08 13:20:09 +00004430 }
4431 }
njn1d0825f2006-03-27 11:37:07 +00004432
sewardjc2c12c22006-03-08 13:20:09 +00004433 /* Do the copy */
4434 if (setting) {
njn1d0825f2006-03-27 11:37:07 +00004435 /* setting */
4436 for (i = 0; i < szB; i++) {
4437 ok = set_vbits8(a + i, ((UChar*)vbits)[i]);
4438 tl_assert(ok);
sewardjc2c12c22006-03-08 13:20:09 +00004439 }
4440 } else {
4441 /* getting */
njn1d0825f2006-03-27 11:37:07 +00004442 for (i = 0; i < szB; i++) {
4443 ok = get_vbits8(a + i, &vbits8);
4444 tl_assert(ok);
njn1d0825f2006-03-27 11:37:07 +00004445 ((UChar*)vbits)[i] = vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004446 }
4447 // The bytes in vbits[] have now been set, so mark them as such.
njndbf7ca72006-03-31 11:57:59 +00004448 MC_(make_mem_defined)(vbits, szB);
njn1d0825f2006-03-27 11:37:07 +00004449 }
sewardjc2c12c22006-03-08 13:20:09 +00004450
4451 return 1;
4452}
sewardj05fe85e2005-04-27 22:46:36 +00004453
4454
4455/*------------------------------------------------------------*/
4456/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
4457/*------------------------------------------------------------*/
4458
4459/* For the memory leak detector, say whether an entire 64k chunk of
4460 address space is possibly in use, or not. If in doubt return
4461 True.
4462*/
4463static
4464Bool mc_is_within_valid_secondary ( Addr a )
4465{
4466 SecMap* sm = maybe_get_secmap_for ( a );
sewardj05a46732006-10-17 01:28:10 +00004467 if (sm == NULL || sm == &sm_distinguished[SM_DIST_NOACCESS]
sewardj7ce71662008-05-02 10:33:15 +00004468 || MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004469 /* Definitely not in use. */
4470 return False;
4471 } else {
4472 return True;
4473 }
4474}
4475
4476
4477/* For the memory leak detector, say whether or not a given word
4478 address is to be regarded as valid. */
4479static
4480Bool mc_is_valid_aligned_word ( Addr a )
4481{
4482 tl_assert(sizeof(UWord) == 4 || sizeof(UWord) == 8);
4483 if (sizeof(UWord) == 4) {
4484 tl_assert(VG_IS_4_ALIGNED(a));
4485 } else {
4486 tl_assert(VG_IS_8_ALIGNED(a));
4487 }
sewardj7cf4e6b2008-05-01 20:24:26 +00004488 if (is_mem_defined( a, sizeof(UWord), NULL, NULL) == MC_Ok
sewardj7ce71662008-05-02 10:33:15 +00004489 && !MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004490 return True;
4491 } else {
4492 return False;
4493 }
4494}
sewardja4495682002-10-21 07:29:59 +00004495
4496
nethercote996901a2004-08-03 13:29:09 +00004497/* Leak detector for this tool. We don't actually do anything, merely
sewardja4495682002-10-21 07:29:59 +00004498 run the generic leak detector with suitable parameters for this
nethercote996901a2004-08-03 13:29:09 +00004499 tool. */
njnb8dca862005-03-14 02:42:44 +00004500static void mc_detect_memory_leaks ( ThreadId tid, LeakCheckMode mode )
njn25e49d8e72002-09-23 09:36:25 +00004501{
njn1d0825f2006-03-27 11:37:07 +00004502 MC_(do_detect_memory_leaks) (
sewardj05fe85e2005-04-27 22:46:36 +00004503 tid,
4504 mode,
4505 mc_is_within_valid_secondary,
4506 mc_is_valid_aligned_word
4507 );
njn25e49d8e72002-09-23 09:36:25 +00004508}
4509
4510
sewardjc859fbf2005-04-22 21:10:28 +00004511/*------------------------------------------------------------*/
4512/*--- Initialisation ---*/
4513/*------------------------------------------------------------*/
4514
4515static void init_shadow_memory ( void )
4516{
4517 Int i;
4518 SecMap* sm;
4519
njn1d0825f2006-03-27 11:37:07 +00004520 tl_assert(V_BIT_UNDEFINED == 1);
4521 tl_assert(V_BIT_DEFINED == 0);
4522 tl_assert(V_BITS8_UNDEFINED == 0xFF);
4523 tl_assert(V_BITS8_DEFINED == 0);
4524
sewardjc859fbf2005-04-22 21:10:28 +00004525 /* Build the 3 distinguished secondaries */
sewardjc859fbf2005-04-22 21:10:28 +00004526 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004527 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_NOACCESS;
sewardjc859fbf2005-04-22 21:10:28 +00004528
njndbf7ca72006-03-31 11:57:59 +00004529 sm = &sm_distinguished[SM_DIST_UNDEFINED];
4530 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_UNDEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004531
njndbf7ca72006-03-31 11:57:59 +00004532 sm = &sm_distinguished[SM_DIST_DEFINED];
4533 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_DEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004534
4535 /* Set up the primary map. */
4536 /* These entries gradually get overwritten as the used address
4537 space expands. */
4538 for (i = 0; i < N_PRIMARY_MAP; i++)
4539 primary_map[i] = &sm_distinguished[SM_DIST_NOACCESS];
4540
sewardj05a46732006-10-17 01:28:10 +00004541 /* Auxiliary primary maps */
4542 init_auxmap_L1_L2();
4543
sewardjc859fbf2005-04-22 21:10:28 +00004544 /* auxmap_size = auxmap_used = 0;
4545 no ... these are statically initialised */
njn1d0825f2006-03-27 11:37:07 +00004546
4547 /* Secondary V bit table */
4548 secVBitTable = createSecVBitTable();
sewardjc859fbf2005-04-22 21:10:28 +00004549}
4550
4551
4552/*------------------------------------------------------------*/
4553/*--- Sanity check machinery (permanently engaged) ---*/
4554/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004555
njn51d827b2005-05-09 01:02:08 +00004556static Bool mc_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004557{
sewardj23eb2fd2005-04-22 16:29:19 +00004558 n_sanity_cheap++;
sewardjc1a2cda2005-04-21 17:34:00 +00004559 PROF_EVENT(490, "cheap_sanity_check");
sewardj7cf4e6b2008-05-01 20:24:26 +00004560 /* Check for sane operating level */
4561 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4562 return False;
4563 /* nothing else useful we can rapidly check */
jseward9800fd32004-01-04 23:08:04 +00004564 return True;
njn25e49d8e72002-09-23 09:36:25 +00004565}
4566
njn51d827b2005-05-09 01:02:08 +00004567static Bool mc_expensive_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004568{
sewardj05a46732006-10-17 01:28:10 +00004569 Int i;
4570 Word n_secmaps_found;
sewardj45d94cc2005-04-20 14:44:11 +00004571 SecMap* sm;
sewardj05a46732006-10-17 01:28:10 +00004572 HChar* errmsg;
sewardj23eb2fd2005-04-22 16:29:19 +00004573 Bool bad = False;
njn25e49d8e72002-09-23 09:36:25 +00004574
sewardj05a46732006-10-17 01:28:10 +00004575 if (0) VG_(printf)("expensive sanity check\n");
4576 if (0) return True;
4577
sewardj23eb2fd2005-04-22 16:29:19 +00004578 n_sanity_expensive++;
sewardjc1a2cda2005-04-21 17:34:00 +00004579 PROF_EVENT(491, "expensive_sanity_check");
4580
sewardj7cf4e6b2008-05-01 20:24:26 +00004581 /* Check for sane operating level */
4582 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4583 return False;
4584
njn1d0825f2006-03-27 11:37:07 +00004585 /* Check that the 3 distinguished SMs are still as they should be. */
njn25e49d8e72002-09-23 09:36:25 +00004586
njndbf7ca72006-03-31 11:57:59 +00004587 /* Check noaccess DSM. */
sewardj45d94cc2005-04-20 14:44:11 +00004588 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004589 for (i = 0; i < SM_CHUNKS; i++)
4590 if (sm->vabits8[i] != VA_BITS8_NOACCESS)
sewardj23eb2fd2005-04-22 16:29:19 +00004591 bad = True;
njn25e49d8e72002-09-23 09:36:25 +00004592
njndbf7ca72006-03-31 11:57:59 +00004593 /* Check undefined DSM. */
4594 sm = &sm_distinguished[SM_DIST_UNDEFINED];
njn1d0825f2006-03-27 11:37:07 +00004595 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004596 if (sm->vabits8[i] != VA_BITS8_UNDEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004597 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004598
njndbf7ca72006-03-31 11:57:59 +00004599 /* Check defined DSM. */
4600 sm = &sm_distinguished[SM_DIST_DEFINED];
njn1d0825f2006-03-27 11:37:07 +00004601 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004602 if (sm->vabits8[i] != VA_BITS8_DEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004603 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004604
sewardj23eb2fd2005-04-22 16:29:19 +00004605 if (bad) {
4606 VG_(printf)("memcheck expensive sanity: "
4607 "distinguished_secondaries have changed\n");
4608 return False;
4609 }
4610
njn1d0825f2006-03-27 11:37:07 +00004611 /* If we're not checking for undefined value errors, the secondary V bit
4612 * table should be empty. */
sewardj7cf4e6b2008-05-01 20:24:26 +00004613 if (MC_(clo_mc_level) == 1) {
njne2a9ad32007-09-17 05:30:48 +00004614 if (0 != VG_(OSetGen_Size)(secVBitTable))
njn1d0825f2006-03-27 11:37:07 +00004615 return False;
4616 }
4617
sewardj05a46732006-10-17 01:28:10 +00004618 /* check the auxiliary maps, very thoroughly */
4619 n_secmaps_found = 0;
4620 errmsg = check_auxmap_L1_L2_sanity( &n_secmaps_found );
4621 if (errmsg) {
4622 VG_(printf)("memcheck expensive sanity, auxmaps:\n\t%s", errmsg);
sewardj23eb2fd2005-04-22 16:29:19 +00004623 return False;
4624 }
4625
sewardj05a46732006-10-17 01:28:10 +00004626 /* n_secmaps_found is now the number referred to by the auxiliary
4627 primary map. Now add on the ones referred to by the main
4628 primary map. */
sewardj23eb2fd2005-04-22 16:29:19 +00004629 for (i = 0; i < N_PRIMARY_MAP; i++) {
sewardj05a46732006-10-17 01:28:10 +00004630 if (primary_map[i] == NULL) {
sewardj23eb2fd2005-04-22 16:29:19 +00004631 bad = True;
4632 } else {
sewardj05a46732006-10-17 01:28:10 +00004633 if (!is_distinguished_sm(primary_map[i]))
sewardj23eb2fd2005-04-22 16:29:19 +00004634 n_secmaps_found++;
4635 }
4636 }
4637
sewardj05a46732006-10-17 01:28:10 +00004638 /* check that the number of secmaps issued matches the number that
4639 are reachable (iow, no secmap leaks) */
njn1d0825f2006-03-27 11:37:07 +00004640 if (n_secmaps_found != (n_issued_SMs - n_deissued_SMs))
sewardj23eb2fd2005-04-22 16:29:19 +00004641 bad = True;
4642
4643 if (bad) {
4644 VG_(printf)("memcheck expensive sanity: "
4645 "apparent secmap leakage\n");
4646 return False;
4647 }
4648
sewardj23eb2fd2005-04-22 16:29:19 +00004649 if (bad) {
4650 VG_(printf)("memcheck expensive sanity: "
4651 "auxmap covers wrong address space\n");
4652 return False;
4653 }
4654
4655 /* there is only one pointer to each secmap (expensive) */
njn25e49d8e72002-09-23 09:36:25 +00004656
4657 return True;
4658}
sewardj45d94cc2005-04-20 14:44:11 +00004659
njn25e49d8e72002-09-23 09:36:25 +00004660/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00004661/*--- Command line args ---*/
njn25e49d8e72002-09-23 09:36:25 +00004662/*------------------------------------------------------------*/
4663
njn1d0825f2006-03-27 11:37:07 +00004664Bool MC_(clo_partial_loads_ok) = False;
sewardjfa4ca3b2007-11-30 17:19:36 +00004665Long MC_(clo_freelist_vol) = 10*1000*1000LL;
njn1d0825f2006-03-27 11:37:07 +00004666LeakCheckMode MC_(clo_leak_check) = LC_Summary;
4667VgRes MC_(clo_leak_resolution) = Vg_LowRes;
4668Bool MC_(clo_show_reachable) = False;
4669Bool MC_(clo_workaround_gcc296_bugs) = False;
sewardjeb0fa932007-11-30 21:41:40 +00004670Int MC_(clo_malloc_fill) = -1;
4671Int MC_(clo_free_fill) = -1;
sewardj7cf4e6b2008-05-01 20:24:26 +00004672Int MC_(clo_mc_level) = 2;
njn1d0825f2006-03-27 11:37:07 +00004673
4674static Bool mc_process_cmd_line_options(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00004675{
sewardj7cf4e6b2008-05-01 20:24:26 +00004676 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
4677
4678 /* Set MC_(clo_mc_level):
4679 1 = A bit tracking only
4680 2 = A and V bit tracking, but no V bit origins
4681 3 = A and V bit tracking, and V bit origins
4682
4683 Do this by inspecting --undef-value-errors= and
4684 --track-origins=. Reject the case --undef-value-errors=no
4685 --track-origins=yes as meaningless.
4686 */
4687 if (0 == VG_(strcmp)(arg, "--undef-value-errors=no")) {
4688 if (MC_(clo_mc_level) == 3)
4689 goto mc_level_error;
4690 MC_(clo_mc_level) = 1;
4691 return True;
4692 }
4693 if (0 == VG_(strcmp)(arg, "--undef-value-errors=yes")) {
4694 if (MC_(clo_mc_level) == 1)
4695 MC_(clo_mc_level) = 2;
4696 return True;
4697 }
4698 if (0 == VG_(strcmp)(arg, "--track-origins=no")) {
4699 if (MC_(clo_mc_level) == 3)
4700 MC_(clo_mc_level) = 2;
4701 return True;
4702 }
4703 if (0 == VG_(strcmp)(arg, "--track-origins=yes")) {
4704 if (MC_(clo_mc_level) == 1)
4705 goto mc_level_error;
4706 MC_(clo_mc_level) = 3;
4707 return True;
4708 }
4709
njn1d0825f2006-03-27 11:37:07 +00004710 VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok))
4711 else VG_BOOL_CLO(arg, "--show-reachable", MC_(clo_show_reachable))
4712 else VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",MC_(clo_workaround_gcc296_bugs))
4713
sewardjfa4ca3b2007-11-30 17:19:36 +00004714 else VG_BNUM_CLO(arg, "--freelist-vol", MC_(clo_freelist_vol),
4715 0, 10*1000*1000*1000LL)
njn1d0825f2006-03-27 11:37:07 +00004716
4717 else if (VG_CLO_STREQ(arg, "--leak-check=no"))
4718 MC_(clo_leak_check) = LC_Off;
4719 else if (VG_CLO_STREQ(arg, "--leak-check=summary"))
4720 MC_(clo_leak_check) = LC_Summary;
4721 else if (VG_CLO_STREQ(arg, "--leak-check=yes") ||
4722 VG_CLO_STREQ(arg, "--leak-check=full"))
4723 MC_(clo_leak_check) = LC_Full;
4724
4725 else if (VG_CLO_STREQ(arg, "--leak-resolution=low"))
4726 MC_(clo_leak_resolution) = Vg_LowRes;
4727 else if (VG_CLO_STREQ(arg, "--leak-resolution=med"))
4728 MC_(clo_leak_resolution) = Vg_MedRes;
4729 else if (VG_CLO_STREQ(arg, "--leak-resolution=high"))
4730 MC_(clo_leak_resolution) = Vg_HighRes;
4731
sewardj05a46732006-10-17 01:28:10 +00004732 else if (VG_CLO_STREQN(16,arg,"--ignore-ranges=")) {
4733 Int i;
4734 UChar* txt = (UChar*)(arg+16);
4735 Bool ok = parse_ignore_ranges(txt);
4736 if (!ok)
4737 return False;
4738 tl_assert(ignoreRanges.used >= 0);
4739 tl_assert(ignoreRanges.used < M_IGNORE_RANGES);
4740 for (i = 0; i < ignoreRanges.used; i++) {
4741 Addr s = ignoreRanges.start[i];
4742 Addr e = ignoreRanges.end[i];
4743 Addr limit = 0x4000000; /* 64M - entirely arbitrary limit */
4744 if (e <= s) {
4745 VG_(message)(Vg_DebugMsg,
4746 "ERROR: --ignore-ranges: end <= start in range:");
4747 VG_(message)(Vg_DebugMsg,
4748 " 0x%lx-0x%lx", s, e);
4749 return False;
4750 }
4751 if (e - s > limit) {
4752 VG_(message)(Vg_DebugMsg,
4753 "ERROR: --ignore-ranges: suspiciously large range:");
4754 VG_(message)(Vg_DebugMsg,
4755 " 0x%lx-0x%lx (size %ld)", s, e, (UWord)(e-s));
4756 return False;
4757 }
4758 }
4759 }
4760
sewardjeb0fa932007-11-30 21:41:40 +00004761 else VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00, 0xFF)
4762 else VG_BHEX_CLO(arg, "--free-fill", MC_(clo_free_fill), 0x00, 0xFF)
4763
njn1d0825f2006-03-27 11:37:07 +00004764 else
4765 return VG_(replacement_malloc_process_cmd_line_option)(arg);
4766
4767 return True;
sewardj7cf4e6b2008-05-01 20:24:26 +00004768 /*NOTREACHED*/
4769
4770 mc_level_error:
4771 VG_(message)(Vg_DebugMsg, "ERROR: --track-origins=yes has no effect "
4772 "when --undef-value-errors=no");
4773 return False;
njn25e49d8e72002-09-23 09:36:25 +00004774}
4775
njn51d827b2005-05-09 01:02:08 +00004776static void mc_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00004777{
njn1d0825f2006-03-27 11:37:07 +00004778 VG_(printf)(
4779" --leak-check=no|summary|full search for memory leaks at exit? [summary]\n"
4780" --leak-resolution=low|med|high how much bt merging in leak check [low]\n"
4781" --show-reachable=no|yes show reachable blocks in leak check? [no]\n"
4782" --undef-value-errors=no|yes check for undefined value errors [yes]\n"
sewardj7cf4e6b2008-05-01 20:24:26 +00004783" --track-origins=no|yes show origins of undefined values? [no]\n"
njn1d0825f2006-03-27 11:37:07 +00004784" --partial-loads-ok=no|yes too hard to explain here; see manual [no]\n"
sewardjfa4ca3b2007-11-30 17:19:36 +00004785" --freelist-vol=<number> volume of freed blocks queue [10000000]\n"
njn1d0825f2006-03-27 11:37:07 +00004786" --workaround-gcc296-bugs=no|yes self explanatory [no]\n"
sewardj05a46732006-10-17 01:28:10 +00004787" --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS] assume given addresses are OK\n"
sewardjeb0fa932007-11-30 21:41:40 +00004788" --malloc-fill=<hexnumber> fill malloc'd areas with given value\n"
4789" --free-fill=<hexnumber> fill free'd areas with given value\n"
njn1d0825f2006-03-27 11:37:07 +00004790 );
4791 VG_(replacement_malloc_print_usage)();
njn3e884182003-04-15 13:03:23 +00004792}
4793
njn51d827b2005-05-09 01:02:08 +00004794static void mc_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00004795{
njn1d0825f2006-03-27 11:37:07 +00004796 VG_(replacement_malloc_print_debug_usage)();
njn25e49d8e72002-09-23 09:36:25 +00004797}
4798
sewardjf3418c02005-11-08 14:10:24 +00004799
nethercote8b76fe52004-11-08 19:20:09 +00004800/*------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00004801/*--- Client blocks ---*/
nethercote8b76fe52004-11-08 19:20:09 +00004802/*------------------------------------------------------------*/
4803
4804/* Client block management:
4805
4806 This is managed as an expanding array of client block descriptors.
4807 Indices of live descriptors are issued to the client, so it can ask
4808 to free them later. Therefore we cannot slide live entries down
4809 over dead ones. Instead we must use free/inuse flags and scan for
4810 an empty slot at allocation time. This in turn means allocation is
4811 relatively expensive, so we hope this does not happen too often.
nethercote8b76fe52004-11-08 19:20:09 +00004812
sewardjedc75ab2005-03-15 23:30:32 +00004813 An unused block has start == size == 0
4814*/
nethercote8b76fe52004-11-08 19:20:09 +00004815
sewardj7ce71662008-05-02 10:33:15 +00004816/* type CGenBlock is defined in mc_include.h */
nethercote8b76fe52004-11-08 19:20:09 +00004817
4818/* This subsystem is self-initialising. */
sewardj56adc352008-05-02 11:25:17 +00004819static UWord cgb_size = 0;
4820static UWord cgb_used = 0;
njn695c16e2005-03-27 03:40:28 +00004821static CGenBlock* cgbs = NULL;
nethercote8b76fe52004-11-08 19:20:09 +00004822
4823/* Stats for this subsystem. */
sewardj56adc352008-05-02 11:25:17 +00004824static ULong cgb_used_MAX = 0; /* Max in use. */
4825static ULong cgb_allocs = 0; /* Number of allocs. */
4826static ULong cgb_discards = 0; /* Number of discards. */
4827static ULong cgb_search = 0; /* Number of searches. */
nethercote8b76fe52004-11-08 19:20:09 +00004828
4829
sewardj7ce71662008-05-02 10:33:15 +00004830/* Get access to the client block array. */
4831void MC_(get_ClientBlock_array)( /*OUT*/CGenBlock** blocks,
4832 /*OUT*/UWord* nBlocks )
4833{
4834 *blocks = cgbs;
4835 *nBlocks = cgb_used;
4836}
4837
4838
nethercote8b76fe52004-11-08 19:20:09 +00004839static
njn695c16e2005-03-27 03:40:28 +00004840Int alloc_client_block ( void )
nethercote8b76fe52004-11-08 19:20:09 +00004841{
sewardj56adc352008-05-02 11:25:17 +00004842 UWord i, sz_new;
nethercote8b76fe52004-11-08 19:20:09 +00004843 CGenBlock* cgbs_new;
4844
njn695c16e2005-03-27 03:40:28 +00004845 cgb_allocs++;
nethercote8b76fe52004-11-08 19:20:09 +00004846
njn695c16e2005-03-27 03:40:28 +00004847 for (i = 0; i < cgb_used; i++) {
4848 cgb_search++;
4849 if (cgbs[i].start == 0 && cgbs[i].size == 0)
nethercote8b76fe52004-11-08 19:20:09 +00004850 return i;
4851 }
4852
4853 /* Not found. Try to allocate one at the end. */
njn695c16e2005-03-27 03:40:28 +00004854 if (cgb_used < cgb_size) {
4855 cgb_used++;
4856 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004857 }
4858
4859 /* Ok, we have to allocate a new one. */
njn695c16e2005-03-27 03:40:28 +00004860 tl_assert(cgb_used == cgb_size);
4861 sz_new = (cgbs == NULL) ? 10 : (2 * cgb_size);
nethercote8b76fe52004-11-08 19:20:09 +00004862
sewardj9c606bd2008-09-18 18:12:50 +00004863 cgbs_new = VG_(malloc)( "mc.acb.1", sz_new * sizeof(CGenBlock) );
njn695c16e2005-03-27 03:40:28 +00004864 for (i = 0; i < cgb_used; i++)
4865 cgbs_new[i] = cgbs[i];
nethercote8b76fe52004-11-08 19:20:09 +00004866
njn695c16e2005-03-27 03:40:28 +00004867 if (cgbs != NULL)
4868 VG_(free)( cgbs );
4869 cgbs = cgbs_new;
nethercote8b76fe52004-11-08 19:20:09 +00004870
njn695c16e2005-03-27 03:40:28 +00004871 cgb_size = sz_new;
4872 cgb_used++;
4873 if (cgb_used > cgb_used_MAX)
4874 cgb_used_MAX = cgb_used;
4875 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004876}
4877
4878
4879static void show_client_block_stats ( void )
4880{
4881 VG_(message)(Vg_DebugMsg,
sewardj56adc352008-05-02 11:25:17 +00004882 "general CBs: %llu allocs, %llu discards, %llu maxinuse, %llu search",
njn695c16e2005-03-27 03:40:28 +00004883 cgb_allocs, cgb_discards, cgb_used_MAX, cgb_search
nethercote8b76fe52004-11-08 19:20:09 +00004884 );
4885}
4886
nethercote8b76fe52004-11-08 19:20:09 +00004887
sewardj7ce71662008-05-02 10:33:15 +00004888/*------------------------------------------------------------*/
4889/*--- Client requests ---*/
4890/*------------------------------------------------------------*/
nethercote8b76fe52004-11-08 19:20:09 +00004891
njn51d827b2005-05-09 01:02:08 +00004892static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
nethercote8b76fe52004-11-08 19:20:09 +00004893{
4894 Int i;
4895 Bool ok;
4896 Addr bad_addr;
4897
njnfc26ff92004-11-22 19:12:49 +00004898 if (!VG_IS_TOOL_USERREQ('M','C',arg[0])
sewardj7ce71662008-05-02 10:33:15 +00004899 && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
4900 && VG_USERREQ__FREELIKE_BLOCK != arg[0]
4901 && VG_USERREQ__CREATE_MEMPOOL != arg[0]
4902 && VG_USERREQ__DESTROY_MEMPOOL != arg[0]
4903 && VG_USERREQ__MEMPOOL_ALLOC != arg[0]
4904 && VG_USERREQ__MEMPOOL_FREE != arg[0]
4905 && VG_USERREQ__MEMPOOL_TRIM != arg[0]
4906 && VG_USERREQ__MOVE_MEMPOOL != arg[0]
4907 && VG_USERREQ__MEMPOOL_CHANGE != arg[0]
4908 && VG_USERREQ__MEMPOOL_EXISTS != arg[0])
nethercote8b76fe52004-11-08 19:20:09 +00004909 return False;
4910
4911 switch (arg[0]) {
njndbf7ca72006-03-31 11:57:59 +00004912 case VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE:
4913 ok = is_mem_addressable ( arg[1], arg[2], &bad_addr );
nethercote8b76fe52004-11-08 19:20:09 +00004914 if (!ok)
sewardj7ce71662008-05-02 10:33:15 +00004915 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00004916 *ret = ok ? (UWord)NULL : bad_addr;
sewardj8cf88b72005-07-08 01:29:33 +00004917 break;
nethercote8b76fe52004-11-08 19:20:09 +00004918
njndbf7ca72006-03-31 11:57:59 +00004919 case VG_USERREQ__CHECK_MEM_IS_DEFINED: {
nethercote8b76fe52004-11-08 19:20:09 +00004920 MC_ReadResult res;
sewardj7cf4e6b2008-05-01 20:24:26 +00004921 UInt otag = 0;
4922 res = is_mem_defined ( arg[1], arg[2], &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00004923 if (MC_AddrErr == res)
sewardj7ce71662008-05-02 10:33:15 +00004924 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00004925 else if (MC_ValueErr == res)
sewardj7ce71662008-05-02 10:33:15 +00004926 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/False, otag );
nethercote8b76fe52004-11-08 19:20:09 +00004927 *ret = ( res==MC_Ok ? (UWord)NULL : bad_addr );
sewardj8cf88b72005-07-08 01:29:33 +00004928 break;
nethercote8b76fe52004-11-08 19:20:09 +00004929 }
4930
4931 case VG_USERREQ__DO_LEAK_CHECK:
njnb8dca862005-03-14 02:42:44 +00004932 mc_detect_memory_leaks(tid, arg[1] ? LC_Summary : LC_Full);
sewardj8cf88b72005-07-08 01:29:33 +00004933 *ret = 0; /* return value is meaningless */
4934 break;
nethercote8b76fe52004-11-08 19:20:09 +00004935
njndbf7ca72006-03-31 11:57:59 +00004936 case VG_USERREQ__MAKE_MEM_NOACCESS:
4937 MC_(make_mem_noaccess) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00004938 *ret = -1;
4939 break;
nethercote8b76fe52004-11-08 19:20:09 +00004940
njndbf7ca72006-03-31 11:57:59 +00004941 case VG_USERREQ__MAKE_MEM_UNDEFINED:
sewardj7ce71662008-05-02 10:33:15 +00004942 make_mem_undefined_w_tid_and_okind ( arg[1], arg[2], tid,
4943 MC_OKIND_USER );
sewardjedc75ab2005-03-15 23:30:32 +00004944 *ret = -1;
sewardj8cf88b72005-07-08 01:29:33 +00004945 break;
nethercote8b76fe52004-11-08 19:20:09 +00004946
njndbf7ca72006-03-31 11:57:59 +00004947 case VG_USERREQ__MAKE_MEM_DEFINED:
4948 MC_(make_mem_defined) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00004949 *ret = -1;
nethercote8b76fe52004-11-08 19:20:09 +00004950 break;
4951
njndbf7ca72006-03-31 11:57:59 +00004952 case VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE:
4953 make_mem_defined_if_addressable ( arg[1], arg[2] );
sewardjfb1e9ad2006-03-10 13:41:58 +00004954 *ret = -1;
4955 break;
4956
sewardjedc75ab2005-03-15 23:30:32 +00004957 case VG_USERREQ__CREATE_BLOCK: /* describe a block */
sewardj8cf88b72005-07-08 01:29:33 +00004958 if (arg[1] != 0 && arg[2] != 0) {
4959 i = alloc_client_block();
4960 /* VG_(printf)("allocated %d %p\n", i, cgbs); */
4961 cgbs[i].start = arg[1];
4962 cgbs[i].size = arg[2];
sewardj9c606bd2008-09-18 18:12:50 +00004963 cgbs[i].desc = VG_(strdup)("mc.mhcr.1", (Char *)arg[3]);
sewardj39f34232007-11-09 23:02:28 +00004964 cgbs[i].where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
sewardj8cf88b72005-07-08 01:29:33 +00004965 *ret = i;
4966 } else
4967 *ret = -1;
4968 break;
sewardjedc75ab2005-03-15 23:30:32 +00004969
nethercote8b76fe52004-11-08 19:20:09 +00004970 case VG_USERREQ__DISCARD: /* discard */
njn695c16e2005-03-27 03:40:28 +00004971 if (cgbs == NULL
4972 || arg[2] >= cgb_used ||
sewardj8cf88b72005-07-08 01:29:33 +00004973 (cgbs[arg[2]].start == 0 && cgbs[arg[2]].size == 0)) {
sewardjedc75ab2005-03-15 23:30:32 +00004974 *ret = 1;
sewardj8cf88b72005-07-08 01:29:33 +00004975 } else {
4976 tl_assert(arg[2] >= 0 && arg[2] < cgb_used);
4977 cgbs[arg[2]].start = cgbs[arg[2]].size = 0;
4978 VG_(free)(cgbs[arg[2]].desc);
4979 cgb_discards++;
4980 *ret = 0;
4981 }
4982 break;
nethercote8b76fe52004-11-08 19:20:09 +00004983
sewardjc2c12c22006-03-08 13:20:09 +00004984 case VG_USERREQ__GET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00004985 *ret = mc_get_or_set_vbits_for_client
4986 ( tid, arg[1], arg[2], arg[3], False /* get them */ );
4987 break;
4988
4989 case VG_USERREQ__SET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00004990 *ret = mc_get_or_set_vbits_for_client
4991 ( tid, arg[1], arg[2], arg[3], True /* set them */ );
4992 break;
nethercote8b76fe52004-11-08 19:20:09 +00004993
njn1d0825f2006-03-27 11:37:07 +00004994 case VG_USERREQ__COUNT_LEAKS: { /* count leaked bytes */
4995 UWord** argp = (UWord**)arg;
4996 // MC_(bytes_leaked) et al were set by the last leak check (or zero
4997 // if no prior leak checks performed).
4998 *argp[1] = MC_(bytes_leaked) + MC_(bytes_indirect);
4999 *argp[2] = MC_(bytes_dubious);
5000 *argp[3] = MC_(bytes_reachable);
5001 *argp[4] = MC_(bytes_suppressed);
5002 // there is no argp[5]
5003 //*argp[5] = MC_(bytes_indirect);
njndbf7ca72006-03-31 11:57:59 +00005004 // XXX need to make *argp[1-4] defined
njn1d0825f2006-03-27 11:37:07 +00005005 *ret = 0;
5006 return True;
5007 }
5008 case VG_USERREQ__MALLOCLIKE_BLOCK: {
5009 Addr p = (Addr)arg[1];
5010 SizeT sizeB = arg[2];
5011 UInt rzB = arg[3];
5012 Bool is_zeroed = (Bool)arg[4];
5013
5014 MC_(new_block) ( tid, p, sizeB, /*ignored*/0, rzB, is_zeroed,
5015 MC_AllocCustom, MC_(malloc_list) );
5016 return True;
5017 }
5018 case VG_USERREQ__FREELIKE_BLOCK: {
5019 Addr p = (Addr)arg[1];
5020 UInt rzB = arg[2];
5021
5022 MC_(handle_free) ( tid, p, rzB, MC_AllocCustom );
5023 return True;
5024 }
5025
5026 case _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR: {
njn718d3b12006-12-16 00:54:12 +00005027 Char* s = (Char*)arg[1];
5028 Addr dst = (Addr) arg[2];
5029 Addr src = (Addr) arg[3];
5030 SizeT len = (SizeT)arg[4];
sewardj7ce71662008-05-02 10:33:15 +00005031 MC_(record_overlap_error)(tid, s, src, dst, len);
njn1d0825f2006-03-27 11:37:07 +00005032 return True;
5033 }
5034
5035 case VG_USERREQ__CREATE_MEMPOOL: {
5036 Addr pool = (Addr)arg[1];
5037 UInt rzB = arg[2];
5038 Bool is_zeroed = (Bool)arg[3];
5039
5040 MC_(create_mempool) ( pool, rzB, is_zeroed );
5041 return True;
5042 }
5043
5044 case VG_USERREQ__DESTROY_MEMPOOL: {
5045 Addr pool = (Addr)arg[1];
5046
5047 MC_(destroy_mempool) ( pool );
5048 return True;
5049 }
5050
5051 case VG_USERREQ__MEMPOOL_ALLOC: {
5052 Addr pool = (Addr)arg[1];
5053 Addr addr = (Addr)arg[2];
5054 UInt size = arg[3];
5055
5056 MC_(mempool_alloc) ( tid, pool, addr, size );
5057 return True;
5058 }
5059
5060 case VG_USERREQ__MEMPOOL_FREE: {
5061 Addr pool = (Addr)arg[1];
5062 Addr addr = (Addr)arg[2];
5063
5064 MC_(mempool_free) ( pool, addr );
5065 return True;
5066 }
5067
sewardj2c1c9df2006-07-28 00:06:37 +00005068 case VG_USERREQ__MEMPOOL_TRIM: {
5069 Addr pool = (Addr)arg[1];
5070 Addr addr = (Addr)arg[2];
5071 UInt size = arg[3];
5072
5073 MC_(mempool_trim) ( pool, addr, size );
5074 return True;
5075 }
5076
sewardjc740d762006-10-05 17:59:23 +00005077 case VG_USERREQ__MOVE_MEMPOOL: {
5078 Addr poolA = (Addr)arg[1];
5079 Addr poolB = (Addr)arg[2];
5080
5081 MC_(move_mempool) ( poolA, poolB );
5082 return True;
5083 }
5084
5085 case VG_USERREQ__MEMPOOL_CHANGE: {
5086 Addr pool = (Addr)arg[1];
5087 Addr addrA = (Addr)arg[2];
5088 Addr addrB = (Addr)arg[3];
5089 UInt size = arg[4];
5090
5091 MC_(mempool_change) ( pool, addrA, addrB, size );
5092 return True;
5093 }
5094
5095 case VG_USERREQ__MEMPOOL_EXISTS: {
5096 Addr pool = (Addr)arg[1];
5097
5098 *ret = (UWord) MC_(mempool_exists) ( pool );
5099 return True;
5100 }
5101
5102
nethercote8b76fe52004-11-08 19:20:09 +00005103 default:
njn1d0825f2006-03-27 11:37:07 +00005104 VG_(message)(Vg_UserMsg,
5105 "Warning: unknown memcheck client request code %llx",
5106 (ULong)arg[0]);
5107 return False;
nethercote8b76fe52004-11-08 19:20:09 +00005108 }
5109 return True;
5110}
njn25e49d8e72002-09-23 09:36:25 +00005111
5112/*------------------------------------------------------------*/
njn1d0825f2006-03-27 11:37:07 +00005113/*--- Crude profiling machinery. ---*/
5114/*------------------------------------------------------------*/
5115
5116// We track a number of interesting events (using PROF_EVENT)
5117// if MC_PROFILE_MEMORY is defined.
5118
5119#ifdef MC_PROFILE_MEMORY
5120
5121UInt MC_(event_ctr)[N_PROF_EVENTS];
5122HChar* MC_(event_ctr_name)[N_PROF_EVENTS];
5123
5124static void init_prof_mem ( void )
5125{
5126 Int i;
5127 for (i = 0; i < N_PROF_EVENTS; i++) {
5128 MC_(event_ctr)[i] = 0;
5129 MC_(event_ctr_name)[i] = NULL;
5130 }
5131}
5132
5133static void done_prof_mem ( void )
5134{
5135 Int i;
5136 Bool spaced = False;
5137 for (i = 0; i < N_PROF_EVENTS; i++) {
5138 if (!spaced && (i % 10) == 0) {
5139 VG_(printf)("\n");
5140 spaced = True;
5141 }
5142 if (MC_(event_ctr)[i] > 0) {
5143 spaced = False;
5144 VG_(printf)( "prof mem event %3d: %9d %s\n",
5145 i, MC_(event_ctr)[i],
5146 MC_(event_ctr_name)[i]
5147 ? MC_(event_ctr_name)[i] : "unnamed");
5148 }
5149 }
5150}
5151
5152#else
5153
5154static void init_prof_mem ( void ) { }
5155static void done_prof_mem ( void ) { }
5156
5157#endif
5158
sewardj7cf4e6b2008-05-01 20:24:26 +00005159
5160/*------------------------------------------------------------*/
5161/*--- Origin tracking stuff ---*/
5162/*------------------------------------------------------------*/
5163
5164/*--------------------------------------------*/
5165/*--- Origin tracking: load handlers ---*/
5166/*--------------------------------------------*/
5167
5168static INLINE UInt merge_origins ( UInt or1, UInt or2 ) {
5169 return or1 > or2 ? or1 : or2;
5170}
5171
5172UWord VG_REGPARM(1) MC_(helperc_b_load1)( Addr a ) {
5173 OCacheLine* line;
5174 UChar descr;
5175 UWord lineoff = oc_line_offset(a);
5176 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5177
5178 if (OC_ENABLE_ASSERTIONS) {
5179 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5180 }
5181
5182 line = find_OCacheLine( a );
5183
5184 descr = line->descr[lineoff];
5185 if (OC_ENABLE_ASSERTIONS) {
5186 tl_assert(descr < 0x10);
5187 }
5188
5189 if (LIKELY(0 == (descr & (1 << byteoff)))) {
5190 return 0;
5191 } else {
5192 return line->w32[lineoff];
5193 }
5194}
5195
5196UWord VG_REGPARM(1) MC_(helperc_b_load2)( Addr a ) {
5197 OCacheLine* line;
5198 UChar descr;
5199 UWord lineoff, byteoff;
5200
5201 if (UNLIKELY(a & 1)) {
5202 /* Handle misaligned case, slowly. */
5203 UInt oLo = (UInt)MC_(helperc_b_load1)( a + 0 );
5204 UInt oHi = (UInt)MC_(helperc_b_load1)( a + 1 );
5205 return merge_origins(oLo, oHi);
5206 }
5207
5208 lineoff = oc_line_offset(a);
5209 byteoff = a & 3; /* 0 or 2 */
5210
5211 if (OC_ENABLE_ASSERTIONS) {
5212 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5213 }
5214 line = find_OCacheLine( a );
5215
5216 descr = line->descr[lineoff];
5217 if (OC_ENABLE_ASSERTIONS) {
5218 tl_assert(descr < 0x10);
5219 }
5220
5221 if (LIKELY(0 == (descr & (3 << byteoff)))) {
5222 return 0;
5223 } else {
5224 return line->w32[lineoff];
5225 }
5226}
5227
5228UWord VG_REGPARM(1) MC_(helperc_b_load4)( Addr a ) {
5229 OCacheLine* line;
5230 UChar descr;
5231 UWord lineoff;
5232
5233 if (UNLIKELY(a & 3)) {
5234 /* Handle misaligned case, slowly. */
5235 UInt oLo = (UInt)MC_(helperc_b_load2)( a + 0 );
5236 UInt oHi = (UInt)MC_(helperc_b_load2)( a + 2 );
5237 return merge_origins(oLo, oHi);
5238 }
5239
5240 lineoff = oc_line_offset(a);
5241 if (OC_ENABLE_ASSERTIONS) {
5242 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5243 }
5244
5245 line = find_OCacheLine( a );
5246
5247 descr = line->descr[lineoff];
5248 if (OC_ENABLE_ASSERTIONS) {
5249 tl_assert(descr < 0x10);
5250 }
5251
5252 if (LIKELY(0 == descr)) {
5253 return 0;
5254 } else {
5255 return line->w32[lineoff];
5256 }
5257}
5258
5259UWord VG_REGPARM(1) MC_(helperc_b_load8)( Addr a ) {
5260 OCacheLine* line;
5261 UChar descrLo, descrHi, descr;
5262 UWord lineoff;
5263
5264 if (UNLIKELY(a & 7)) {
5265 /* Handle misaligned case, slowly. */
5266 UInt oLo = (UInt)MC_(helperc_b_load4)( a + 0 );
5267 UInt oHi = (UInt)MC_(helperc_b_load4)( a + 4 );
5268 return merge_origins(oLo, oHi);
5269 }
5270
5271 lineoff = oc_line_offset(a);
5272 if (OC_ENABLE_ASSERTIONS) {
5273 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5274 }
5275
5276 line = find_OCacheLine( a );
5277
5278 descrLo = line->descr[lineoff + 0];
5279 descrHi = line->descr[lineoff + 1];
5280 descr = descrLo | descrHi;
5281 if (OC_ENABLE_ASSERTIONS) {
5282 tl_assert(descr < 0x10);
5283 }
5284
5285 if (LIKELY(0 == descr)) {
5286 return 0; /* both 32-bit chunks are defined */
5287 } else {
5288 UInt oLo = descrLo == 0 ? 0 : line->w32[lineoff + 0];
5289 UInt oHi = descrHi == 0 ? 0 : line->w32[lineoff + 1];
5290 return merge_origins(oLo, oHi);
5291 }
5292}
5293
5294UWord VG_REGPARM(1) MC_(helperc_b_load16)( Addr a ) {
5295 UInt oLo = (UInt)MC_(helperc_b_load8)( a + 0 );
5296 UInt oHi = (UInt)MC_(helperc_b_load8)( a + 8 );
5297 UInt oBoth = merge_origins(oLo, oHi);
5298 return (UWord)oBoth;
5299}
5300
5301
5302/*--------------------------------------------*/
5303/*--- Origin tracking: store handlers ---*/
5304/*--------------------------------------------*/
5305
5306void VG_REGPARM(2) MC_(helperc_b_store1)( Addr a, UWord d32 ) {
5307 OCacheLine* line;
5308 UWord lineoff = oc_line_offset(a);
5309 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5310
5311 if (OC_ENABLE_ASSERTIONS) {
5312 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5313 }
5314
5315 line = find_OCacheLine( a );
5316
5317 if (d32 == 0) {
5318 line->descr[lineoff] &= ~(1 << byteoff);
5319 } else {
5320 line->descr[lineoff] |= (1 << byteoff);
5321 line->w32[lineoff] = d32;
5322 }
5323}
5324
5325void VG_REGPARM(2) MC_(helperc_b_store2)( Addr a, UWord d32 ) {
5326 OCacheLine* line;
5327 UWord lineoff, byteoff;
5328
5329 if (UNLIKELY(a & 1)) {
5330 /* Handle misaligned case, slowly. */
5331 MC_(helperc_b_store1)( a + 0, d32 );
5332 MC_(helperc_b_store1)( a + 1, d32 );
5333 return;
5334 }
5335
5336 lineoff = oc_line_offset(a);
5337 byteoff = a & 3; /* 0 or 2 */
5338
5339 if (OC_ENABLE_ASSERTIONS) {
5340 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5341 }
5342
5343 line = find_OCacheLine( a );
5344
5345 if (d32 == 0) {
5346 line->descr[lineoff] &= ~(3 << byteoff);
5347 } else {
5348 line->descr[lineoff] |= (3 << byteoff);
5349 line->w32[lineoff] = d32;
5350 }
5351}
5352
5353void VG_REGPARM(2) MC_(helperc_b_store4)( Addr a, UWord d32 ) {
5354 OCacheLine* line;
5355 UWord lineoff;
5356
5357 if (UNLIKELY(a & 3)) {
5358 /* Handle misaligned case, slowly. */
5359 MC_(helperc_b_store2)( a + 0, d32 );
5360 MC_(helperc_b_store2)( a + 2, d32 );
5361 return;
5362 }
5363
5364 lineoff = oc_line_offset(a);
5365 if (OC_ENABLE_ASSERTIONS) {
5366 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5367 }
5368
5369 line = find_OCacheLine( a );
5370
5371 if (d32 == 0) {
5372 line->descr[lineoff] = 0;
5373 } else {
5374 line->descr[lineoff] = 0xF;
5375 line->w32[lineoff] = d32;
5376 }
5377}
5378
5379void VG_REGPARM(2) MC_(helperc_b_store8)( Addr a, UWord d32 ) {
5380 OCacheLine* line;
5381 UWord lineoff;
5382
5383 if (UNLIKELY(a & 7)) {
5384 /* Handle misaligned case, slowly. */
5385 MC_(helperc_b_store4)( a + 0, d32 );
5386 MC_(helperc_b_store4)( a + 4, d32 );
5387 return;
5388 }
5389
5390 lineoff = oc_line_offset(a);
5391 if (OC_ENABLE_ASSERTIONS) {
5392 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5393 }
5394
5395 line = find_OCacheLine( a );
5396
5397 if (d32 == 0) {
5398 line->descr[lineoff + 0] = 0;
5399 line->descr[lineoff + 1] = 0;
5400 } else {
5401 line->descr[lineoff + 0] = 0xF;
5402 line->descr[lineoff + 1] = 0xF;
5403 line->w32[lineoff + 0] = d32;
5404 line->w32[lineoff + 1] = d32;
5405 }
5406}
5407
5408void VG_REGPARM(2) MC_(helperc_b_store16)( Addr a, UWord d32 ) {
5409 MC_(helperc_b_store8)( a + 0, d32 );
5410 MC_(helperc_b_store8)( a + 8, d32 );
5411}
5412
5413
5414/*--------------------------------------------*/
5415/*--- Origin tracking: sarp handlers ---*/
5416/*--------------------------------------------*/
5417
5418__attribute__((noinline))
5419static void ocache_sarp_Set_Origins ( Addr a, UWord len, UInt otag ) {
5420 if ((a & 1) && len >= 1) {
5421 MC_(helperc_b_store1)( a, otag );
5422 a++;
5423 len--;
5424 }
5425 if ((a & 2) && len >= 2) {
5426 MC_(helperc_b_store2)( a, otag );
5427 a += 2;
5428 len -= 2;
5429 }
5430 if (len >= 4)
5431 tl_assert(0 == (a & 3));
5432 while (len >= 4) {
5433 MC_(helperc_b_store4)( a, otag );
5434 a += 4;
5435 len -= 4;
5436 }
5437 if (len >= 2) {
5438 MC_(helperc_b_store2)( a, otag );
5439 a += 2;
5440 len -= 2;
5441 }
5442 if (len >= 1) {
5443 MC_(helperc_b_store1)( a, otag );
5444 a++;
5445 len--;
5446 }
5447 tl_assert(len == 0);
5448}
5449
5450__attribute__((noinline))
5451static void ocache_sarp_Clear_Origins ( Addr a, UWord len ) {
5452 if ((a & 1) && len >= 1) {
5453 MC_(helperc_b_store1)( a, 0 );
5454 a++;
5455 len--;
5456 }
5457 if ((a & 2) && len >= 2) {
5458 MC_(helperc_b_store2)( a, 0 );
5459 a += 2;
5460 len -= 2;
5461 }
5462 if (len >= 4)
5463 tl_assert(0 == (a & 3));
5464 while (len >= 4) {
5465 MC_(helperc_b_store4)( a, 0 );
5466 a += 4;
5467 len -= 4;
5468 }
5469 if (len >= 2) {
5470 MC_(helperc_b_store2)( a, 0 );
5471 a += 2;
5472 len -= 2;
5473 }
5474 if (len >= 1) {
5475 MC_(helperc_b_store1)( a, 0 );
5476 a++;
5477 len--;
5478 }
5479 tl_assert(len == 0);
5480}
5481
5482
njn1d0825f2006-03-27 11:37:07 +00005483/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00005484/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00005485/*------------------------------------------------------------*/
5486
njn51d827b2005-05-09 01:02:08 +00005487static void mc_post_clo_init ( void )
njn5c004e42002-11-18 11:04:50 +00005488{
sewardj71bc3cb2005-05-19 00:25:45 +00005489 /* If we've been asked to emit XML, mash around various other
5490 options so as to constrain the output somewhat. */
5491 if (VG_(clo_xml)) {
5492 /* Extract as much info as possible from the leak checker. */
njn1d0825f2006-03-27 11:37:07 +00005493 /* MC_(clo_show_reachable) = True; */
5494 MC_(clo_leak_check) = LC_Full;
sewardj71bc3cb2005-05-19 00:25:45 +00005495 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005496
5497 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
5498
5499 if (MC_(clo_mc_level) == 3) {
5500 /* We're doing origin tracking. */
5501# ifdef PERF_FAST_STACK
5502 VG_(track_new_mem_stack_4_w_ECU) ( mc_new_mem_stack_4_w_ECU );
5503 VG_(track_new_mem_stack_8_w_ECU) ( mc_new_mem_stack_8_w_ECU );
5504 VG_(track_new_mem_stack_12_w_ECU) ( mc_new_mem_stack_12_w_ECU );
5505 VG_(track_new_mem_stack_16_w_ECU) ( mc_new_mem_stack_16_w_ECU );
5506 VG_(track_new_mem_stack_32_w_ECU) ( mc_new_mem_stack_32_w_ECU );
5507 VG_(track_new_mem_stack_112_w_ECU) ( mc_new_mem_stack_112_w_ECU );
5508 VG_(track_new_mem_stack_128_w_ECU) ( mc_new_mem_stack_128_w_ECU );
5509 VG_(track_new_mem_stack_144_w_ECU) ( mc_new_mem_stack_144_w_ECU );
5510 VG_(track_new_mem_stack_160_w_ECU) ( mc_new_mem_stack_160_w_ECU );
5511# endif
5512 VG_(track_new_mem_stack_w_ECU) ( mc_new_mem_stack_w_ECU );
5513 } else {
5514 /* Not doing origin tracking */
5515# ifdef PERF_FAST_STACK
5516 VG_(track_new_mem_stack_4) ( mc_new_mem_stack_4 );
5517 VG_(track_new_mem_stack_8) ( mc_new_mem_stack_8 );
5518 VG_(track_new_mem_stack_12) ( mc_new_mem_stack_12 );
5519 VG_(track_new_mem_stack_16) ( mc_new_mem_stack_16 );
5520 VG_(track_new_mem_stack_32) ( mc_new_mem_stack_32 );
5521 VG_(track_new_mem_stack_112) ( mc_new_mem_stack_112 );
5522 VG_(track_new_mem_stack_128) ( mc_new_mem_stack_128 );
5523 VG_(track_new_mem_stack_144) ( mc_new_mem_stack_144 );
5524 VG_(track_new_mem_stack_160) ( mc_new_mem_stack_160 );
5525# endif
5526 VG_(track_new_mem_stack) ( mc_new_mem_stack );
5527 }
sewardj9d624d12008-05-02 13:35:29 +00005528
5529 /* This origin tracking cache is huge (~100M), so only initialise
5530 if we need it. */
5531 if (MC_(clo_mc_level) >= 3) {
5532 init_OCache();
sewardj77139802008-05-05 09:48:56 +00005533 tl_assert(ocacheL1 != NULL);
sewardj9d624d12008-05-02 13:35:29 +00005534 tl_assert(ocacheL2 != NULL);
5535 } else {
sewardj77139802008-05-05 09:48:56 +00005536 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005537 tl_assert(ocacheL2 == NULL);
5538 }
njn5c004e42002-11-18 11:04:50 +00005539}
5540
njn1d0825f2006-03-27 11:37:07 +00005541static void print_SM_info(char* type, int n_SMs)
5542{
5543 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005544 " memcheck: SMs: %s = %d (%ldk, %ldM)",
njn1d0825f2006-03-27 11:37:07 +00005545 type,
5546 n_SMs,
barta0b6b2c2008-07-07 06:49:24 +00005547 n_SMs * sizeof(SecMap) / 1024UL,
5548 n_SMs * sizeof(SecMap) / (1024 * 1024UL) );
njn1d0825f2006-03-27 11:37:07 +00005549}
5550
njn51d827b2005-05-09 01:02:08 +00005551static void mc_fini ( Int exitcode )
njn5c004e42002-11-18 11:04:50 +00005552{
njn1d0825f2006-03-27 11:37:07 +00005553 MC_(print_malloc_stats)();
sewardj23eb2fd2005-04-22 16:29:19 +00005554
njn1d0825f2006-03-27 11:37:07 +00005555 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5556 if (MC_(clo_leak_check) == LC_Off)
5557 VG_(message)(Vg_UserMsg,
5558 "For a detailed leak analysis, rerun with: --leak-check=yes");
5559
5560 VG_(message)(Vg_UserMsg,
5561 "For counts of detected errors, rerun with: -v");
5562 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005563
5564
sewardj7ce71662008-05-02 10:33:15 +00005565 if (MC_(any_value_errors) && !VG_(clo_xml) && VG_(clo_verbosity) >= 1
sewardj7cf4e6b2008-05-01 20:24:26 +00005566 && MC_(clo_mc_level) == 2) {
5567 VG_(message)(Vg_UserMsg,
5568 "Use --track-origins=yes to see where "
5569 "uninitialised values come from");
5570 }
5571
njn1d0825f2006-03-27 11:37:07 +00005572 if (MC_(clo_leak_check) != LC_Off)
5573 mc_detect_memory_leaks(1/*bogus ThreadId*/, MC_(clo_leak_check));
5574
5575 done_prof_mem();
sewardjae986ca2005-10-12 12:53:20 +00005576
sewardj45d94cc2005-04-20 14:44:11 +00005577 if (VG_(clo_verbosity) > 1) {
njn1d0825f2006-03-27 11:37:07 +00005578 SizeT max_secVBit_szB, max_SMs_szB, max_shmem_szB;
5579
sewardj45d94cc2005-04-20 14:44:11 +00005580 VG_(message)(Vg_DebugMsg,
sewardj23eb2fd2005-04-22 16:29:19 +00005581 " memcheck: sanity checks: %d cheap, %d expensive",
5582 n_sanity_cheap, n_sanity_expensive );
sewardj45d94cc2005-04-20 14:44:11 +00005583 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005584 " memcheck: auxmaps: %lld auxmap entries (%lldk, %lldM) in use",
sewardj05a46732006-10-17 01:28:10 +00005585 n_auxmap_L2_nodes,
5586 n_auxmap_L2_nodes * 64,
5587 n_auxmap_L2_nodes / 16 );
sewardj23eb2fd2005-04-22 16:29:19 +00005588 VG_(message)(Vg_DebugMsg,
sewardj05a46732006-10-17 01:28:10 +00005589 " memcheck: auxmaps_L1: %lld searches, %lld cmps, ratio %lld:10",
5590 n_auxmap_L1_searches, n_auxmap_L1_cmps,
5591 (10ULL * n_auxmap_L1_cmps)
5592 / (n_auxmap_L1_searches ? n_auxmap_L1_searches : 1)
5593 );
5594 VG_(message)(Vg_DebugMsg,
5595 " memcheck: auxmaps_L2: %lld searches, %lld nodes",
5596 n_auxmap_L2_searches, n_auxmap_L2_nodes
5597 );
sewardj23eb2fd2005-04-22 16:29:19 +00005598
njndbf7ca72006-03-31 11:57:59 +00005599 print_SM_info("n_issued ", n_issued_SMs);
5600 print_SM_info("n_deissued ", n_deissued_SMs);
5601 print_SM_info("max_noaccess ", max_noaccess_SMs);
5602 print_SM_info("max_undefined", max_undefined_SMs);
5603 print_SM_info("max_defined ", max_defined_SMs);
5604 print_SM_info("max_non_DSM ", max_non_DSM_SMs);
njn1d0825f2006-03-27 11:37:07 +00005605
5606 // Three DSMs, plus the non-DSM ones
5607 max_SMs_szB = (3 + max_non_DSM_SMs) * sizeof(SecMap);
5608 // The 3*sizeof(Word) bytes is the AVL node metadata size.
5609 // The 4*sizeof(Word) bytes is the malloc metadata size.
5610 // Hardwiring these sizes in sucks, but I don't see how else to do it.
5611 max_secVBit_szB = max_secVBit_nodes *
5612 (sizeof(SecVBitNode) + 3*sizeof(Word) + 4*sizeof(Word));
5613 max_shmem_szB = sizeof(primary_map) + max_SMs_szB + max_secVBit_szB;
sewardj23eb2fd2005-04-22 16:29:19 +00005614
5615 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005616 " memcheck: max sec V bit nodes: %d (%ldk, %ldM)",
njn1d0825f2006-03-27 11:37:07 +00005617 max_secVBit_nodes, max_secVBit_szB / 1024,
5618 max_secVBit_szB / (1024 * 1024));
5619 VG_(message)(Vg_DebugMsg,
5620 " memcheck: set_sec_vbits8 calls: %llu (new: %llu, updates: %llu)",
5621 sec_vbits_new_nodes + sec_vbits_updates,
5622 sec_vbits_new_nodes, sec_vbits_updates );
5623 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005624 " memcheck: max shadow mem size: %ldk, %ldM",
njn1d0825f2006-03-27 11:37:07 +00005625 max_shmem_szB / 1024, max_shmem_szB / (1024 * 1024));
sewardj7cf4e6b2008-05-01 20:24:26 +00005626
5627 if (MC_(clo_mc_level) >= 3) {
5628 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005629 " ocacheL1: %'12lu refs %'12lu misses (%'lu lossage)",
sewardj7cf4e6b2008-05-01 20:24:26 +00005630 stats_ocacheL1_find,
5631 stats_ocacheL1_misses,
5632 stats_ocacheL1_lossage );
5633 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005634 " ocacheL1: %'12lu at 0 %'12lu at 1",
sewardj7cf4e6b2008-05-01 20:24:26 +00005635 stats_ocacheL1_find - stats_ocacheL1_misses
5636 - stats_ocacheL1_found_at_1
5637 - stats_ocacheL1_found_at_N,
5638 stats_ocacheL1_found_at_1 );
5639 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005640 " ocacheL1: %'12lu at 2+ %'12lu move-fwds",
sewardj7cf4e6b2008-05-01 20:24:26 +00005641 stats_ocacheL1_found_at_N,
5642 stats_ocacheL1_movefwds );
5643 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005644 " ocacheL1: %'12lu sizeB %'12u useful",
sewardj7cf4e6b2008-05-01 20:24:26 +00005645 (UWord)sizeof(OCache),
5646 4 * OC_W32S_PER_LINE * OC_LINES_PER_SET * OC_N_SETS );
5647 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005648 " ocacheL2: %'12lu refs %'12lu misses",
sewardj7cf4e6b2008-05-01 20:24:26 +00005649 stats__ocacheL2_refs,
5650 stats__ocacheL2_misses );
5651 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005652 " ocacheL2: %'9lu max nodes %'9lu curr nodes",
sewardj7cf4e6b2008-05-01 20:24:26 +00005653 stats__ocacheL2_n_nodes_max,
5654 stats__ocacheL2_n_nodes );
5655 VG_(message)(Vg_DebugMsg,
barta0b6b2c2008-07-07 06:49:24 +00005656 " niacache: %'12lu refs %'12lu misses",
sewardj7cf4e6b2008-05-01 20:24:26 +00005657 stats__nia_cache_queries, stats__nia_cache_misses);
sewardj9d624d12008-05-02 13:35:29 +00005658 } else {
sewardj77139802008-05-05 09:48:56 +00005659 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005660 tl_assert(ocacheL2 == NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00005661 }
sewardj45d94cc2005-04-20 14:44:11 +00005662 }
5663
njn5c004e42002-11-18 11:04:50 +00005664 if (0) {
5665 VG_(message)(Vg_DebugMsg,
5666 "------ Valgrind's client block stats follow ---------------" );
nethercote8b76fe52004-11-08 19:20:09 +00005667 show_client_block_stats();
njn5c004e42002-11-18 11:04:50 +00005668 }
njn25e49d8e72002-09-23 09:36:25 +00005669}
5670
njn51d827b2005-05-09 01:02:08 +00005671static void mc_pre_clo_init(void)
5672{
5673 VG_(details_name) ("Memcheck");
5674 VG_(details_version) (NULL);
5675 VG_(details_description) ("a memory error detector");
5676 VG_(details_copyright_author)(
sewardj4d474d02008-02-11 11:34:59 +00005677 "Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.");
njn51d827b2005-05-09 01:02:08 +00005678 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj05a46732006-10-17 01:28:10 +00005679 VG_(details_avg_translation_sizeB) ( 556 );
njn51d827b2005-05-09 01:02:08 +00005680
5681 VG_(basic_tool_funcs) (mc_post_clo_init,
5682 MC_(instrument),
5683 mc_fini);
5684
sewardj81651dc2007-08-28 06:05:20 +00005685 VG_(needs_final_IR_tidy_pass) ( MC_(final_tidy) );
5686
5687
njn51d827b2005-05-09 01:02:08 +00005688 VG_(needs_core_errors) ();
sewardj7ce71662008-05-02 10:33:15 +00005689 VG_(needs_tool_errors) (MC_(eq_Error),
5690 MC_(pp_Error),
sewardj39f34232007-11-09 23:02:28 +00005691 True,/*show TIDs for errors*/
sewardj7ce71662008-05-02 10:33:15 +00005692 MC_(update_Error_extra),
5693 MC_(is_recognised_suppression),
5694 MC_(read_extra_suppression_info),
5695 MC_(error_matches_suppression),
5696 MC_(get_error_name),
5697 MC_(print_extra_suppression_info));
njn51d827b2005-05-09 01:02:08 +00005698 VG_(needs_libc_freeres) ();
njn1d0825f2006-03-27 11:37:07 +00005699 VG_(needs_command_line_options)(mc_process_cmd_line_options,
njn51d827b2005-05-09 01:02:08 +00005700 mc_print_usage,
5701 mc_print_debug_usage);
5702 VG_(needs_client_requests) (mc_handle_client_request);
5703 VG_(needs_sanity_checks) (mc_cheap_sanity_check,
5704 mc_expensive_sanity_check);
njn1d0825f2006-03-27 11:37:07 +00005705 VG_(needs_malloc_replacement) (MC_(malloc),
5706 MC_(__builtin_new),
5707 MC_(__builtin_vec_new),
5708 MC_(memalign),
5709 MC_(calloc),
5710 MC_(free),
5711 MC_(__builtin_delete),
5712 MC_(__builtin_vec_delete),
5713 MC_(realloc),
5714 MC_MALLOC_REDZONE_SZB );
njnca54af32006-04-16 10:25:43 +00005715 VG_(needs_xml_output) ();
njn51d827b2005-05-09 01:02:08 +00005716
njn1d0825f2006-03-27 11:37:07 +00005717 VG_(track_new_mem_startup) ( mc_new_mem_startup );
sewardj7cf4e6b2008-05-01 20:24:26 +00005718 VG_(track_new_mem_stack_signal)( make_mem_undefined_w_tid );
5719 VG_(track_new_mem_brk) ( make_mem_undefined_w_tid );
njn1d0825f2006-03-27 11:37:07 +00005720 VG_(track_new_mem_mmap) ( mc_new_mem_mmap );
njn51d827b2005-05-09 01:02:08 +00005721
njn1d0825f2006-03-27 11:37:07 +00005722 VG_(track_copy_mem_remap) ( MC_(copy_address_range_state) );
njn81623712005-10-07 04:48:37 +00005723
5724 // Nb: we don't do anything with mprotect. This means that V bits are
5725 // preserved if a program, for example, marks some memory as inaccessible
5726 // and then later marks it as accessible again.
5727 //
5728 // If an access violation occurs (eg. writing to read-only memory) we let
5729 // it fault and print an informative termination message. This doesn't
5730 // happen if the program catches the signal, though, which is bad. If we
5731 // had two A bits (for readability and writability) that were completely
5732 // distinct from V bits, then we could handle all this properly.
5733 VG_(track_change_mem_mprotect) ( NULL );
njn51d827b2005-05-09 01:02:08 +00005734
njndbf7ca72006-03-31 11:57:59 +00005735 VG_(track_die_mem_stack_signal)( MC_(make_mem_noaccess) );
5736 VG_(track_die_mem_brk) ( MC_(make_mem_noaccess) );
5737 VG_(track_die_mem_munmap) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005738
sewardj7cf4e6b2008-05-01 20:24:26 +00005739 /* Defer the specification of the new_mem_stack functions to the
5740 post_clo_init function, since we need to first parse the command
5741 line before deciding which set to use. */
njn51d827b2005-05-09 01:02:08 +00005742
sewardj7cf4e6b2008-05-01 20:24:26 +00005743# ifdef PERF_FAST_STACK
njn1d0825f2006-03-27 11:37:07 +00005744 VG_(track_die_mem_stack_4) ( mc_die_mem_stack_4 );
5745 VG_(track_die_mem_stack_8) ( mc_die_mem_stack_8 );
5746 VG_(track_die_mem_stack_12) ( mc_die_mem_stack_12 );
5747 VG_(track_die_mem_stack_16) ( mc_die_mem_stack_16 );
5748 VG_(track_die_mem_stack_32) ( mc_die_mem_stack_32 );
5749 VG_(track_die_mem_stack_112) ( mc_die_mem_stack_112 );
5750 VG_(track_die_mem_stack_128) ( mc_die_mem_stack_128 );
5751 VG_(track_die_mem_stack_144) ( mc_die_mem_stack_144 );
5752 VG_(track_die_mem_stack_160) ( mc_die_mem_stack_160 );
sewardj7cf4e6b2008-05-01 20:24:26 +00005753# endif
njn1d0825f2006-03-27 11:37:07 +00005754 VG_(track_die_mem_stack) ( mc_die_mem_stack );
njn51d827b2005-05-09 01:02:08 +00005755
njndbf7ca72006-03-31 11:57:59 +00005756 VG_(track_ban_mem_stack) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005757
njndbf7ca72006-03-31 11:57:59 +00005758 VG_(track_pre_mem_read) ( check_mem_is_defined );
5759 VG_(track_pre_mem_read_asciiz) ( check_mem_is_defined_asciiz );
5760 VG_(track_pre_mem_write) ( check_mem_is_addressable );
njn1d0825f2006-03-27 11:37:07 +00005761 VG_(track_post_mem_write) ( mc_post_mem_write );
njn51d827b2005-05-09 01:02:08 +00005762
sewardj7cf4e6b2008-05-01 20:24:26 +00005763 if (MC_(clo_mc_level) >= 2)
njn1d0825f2006-03-27 11:37:07 +00005764 VG_(track_pre_reg_read) ( mc_pre_reg_read );
njn51d827b2005-05-09 01:02:08 +00005765
njn1d0825f2006-03-27 11:37:07 +00005766 VG_(track_post_reg_write) ( mc_post_reg_write );
5767 VG_(track_post_reg_write_clientcall_return)( mc_post_reg_write_clientcall );
njn51d827b2005-05-09 01:02:08 +00005768
5769 init_shadow_memory();
sewardj3f94a7d2007-08-25 07:19:08 +00005770 MC_(malloc_list) = VG_(HT_construct)( "MC_(malloc_list)" );
5771 MC_(mempool_list) = VG_(HT_construct)( "MC_(mempool_list)" );
njn1d0825f2006-03-27 11:37:07 +00005772 init_prof_mem();
njn51d827b2005-05-09 01:02:08 +00005773
5774 tl_assert( mc_expensive_sanity_check() );
njn1d0825f2006-03-27 11:37:07 +00005775
5776 // {LOADV,STOREV}[8421] will all fail horribly if this isn't true.
5777 tl_assert(sizeof(UWord) == sizeof(Addr));
sewardj05a46732006-10-17 01:28:10 +00005778 // Call me paranoid. I don't care.
5779 tl_assert(sizeof(void*) == sizeof(Addr));
njn1d0825f2006-03-27 11:37:07 +00005780
5781 // BYTES_PER_SEC_VBIT_NODE must be a power of two.
5782 tl_assert(-1 != VG_(log2)(BYTES_PER_SEC_VBIT_NODE));
sewardj7cf4e6b2008-05-01 20:24:26 +00005783
sewardj9d624d12008-05-02 13:35:29 +00005784 /* This is small. Always initialise it. */
sewardj7cf4e6b2008-05-01 20:24:26 +00005785 init_nia_to_ecu_cache();
sewardj7244e712008-05-02 12:35:48 +00005786
sewardj77139802008-05-05 09:48:56 +00005787 /* We can't initialise ocacheL1/ocacheL2 yet, since we don't know
5788 if we need to, since the command line args haven't been
5789 processed yet. Hence defer it to mc_post_clo_init. */
5790 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005791 tl_assert(ocacheL2 == NULL);
5792
sewardj7244e712008-05-02 12:35:48 +00005793 /* Check some important stuff. See extensive comments above
5794 re UNALIGNED_OR_HIGH for background. */
5795# if VG_WORDSIZE == 4
5796 tl_assert(sizeof(void*) == 4);
5797 tl_assert(sizeof(Addr) == 4);
5798 tl_assert(sizeof(UWord) == 4);
5799 tl_assert(sizeof(Word) == 4);
5800 tl_assert(MAX_PRIMARY_ADDRESS == 0xFFFFFFFFUL);
5801 tl_assert(MASK(1) == 0UL);
5802 tl_assert(MASK(2) == 1UL);
5803 tl_assert(MASK(4) == 3UL);
5804 tl_assert(MASK(8) == 7UL);
5805# else
5806 tl_assert(VG_WORDSIZE == 8);
5807 tl_assert(sizeof(void*) == 8);
5808 tl_assert(sizeof(Addr) == 8);
5809 tl_assert(sizeof(UWord) == 8);
5810 tl_assert(sizeof(Word) == 8);
5811 tl_assert(MAX_PRIMARY_ADDRESS == 0x7FFFFFFFFULL);
5812 tl_assert(MASK(1) == 0xFFFFFFF800000000ULL);
5813 tl_assert(MASK(2) == 0xFFFFFFF800000001ULL);
5814 tl_assert(MASK(4) == 0xFFFFFFF800000003ULL);
5815 tl_assert(MASK(8) == 0xFFFFFFF800000007ULL);
5816# endif
njn51d827b2005-05-09 01:02:08 +00005817}
5818
sewardj45f4e7c2005-09-27 19:20:21 +00005819VG_DETERMINE_INTERFACE_VERSION(mc_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00005820
njn25e49d8e72002-09-23 09:36:25 +00005821/*--------------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00005822/*--- end mc_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005823/*--------------------------------------------------------------------*/