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